Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
0110c33
feat: add controls management
aleskalfas Apr 12, 2025
6da66c1
feat: add controls to chat filters
aleskalfas Apr 13, 2025
c2d7ece
feat: add controls to messages
PetrBulanek Apr 15, 2025
bfabf4e
fixup! Merge branch 'main' into fix/34-keyboard-controls
PetrBulanek Apr 17, 2025
a58524b
fixup! fixup! Merge branch 'main' into fix/34-keyboard-controls
PetrBulanek Apr 17, 2025
c6eff5c
feat: refactor input into separate component
PetrBulanek Apr 22, 2025
dfa60ac
feat: add basic Textare fork
PetrBulanek May 7, 2025
742becb
feat: rewrite Textarea as class in TypeScript
PetrBulanek May 7, 2025
ac5cc3b
fixup! feat: rewrite Textarea as class in TypeScript
PetrBulanek May 7, 2025
770b700
feat: control textarea with keyboard
PetrBulanek May 8, 2025
6c053a9
fixup! feat: control textarea with keyboard
PetrBulanek May 8, 2025
d33c58a
refactor: simplify textarea component
PetrBulanek May 8, 2025
ee06b92
fixup! refactor: simplify textarea component
PetrBulanek May 9, 2025
cecb81c
fixup! fixup! refactor: simplify textarea component
PetrBulanek May 9, 2025
8ae1f68
fixup! fixup! fixup! refactor: simplify textarea component
PetrBulanek May 12, 2025
a1bbca8
feat: add HelpBar component
PetrBulanek May 14, 2025
8c029dc
fixup! feat: add HelpBar component
PetrBulanek May 14, 2025
57c523e
chore: bump framework version
aleskalfas May 14, 2025
4a25751
fix(ui): prevent immediate event emitting
aleskalfas May 16, 2025
8f542e7
fix: chat filter
aleskalfas May 16, 2025
74b8b3f
feat: chat monitor basic controls
aleskalfas May 17, 2025
b1a7463
feat: finished integration
aleskalfas Jun 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions examples/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"baseUrl": "..",
"rootDir": "..",
},
"exclude": [
"../tests",
"../**/*.test.ts"
]
}
7 changes: 7 additions & 0 deletions examples/ui/chat-monitor/chat-monitor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ChatMonitor } from "../../../src/ui/chat-monitor/chat-monitor.js";
import { getLogger } from "../helpers/log.js";

new ChatMonitor(
{ kind: "screen", title: "Runtime Chat Interface" },
getLogger(true),
);
122 changes: 122 additions & 0 deletions examples/ui/chat-monitor/filter/filter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import blessed from "neo-blessed";
import { ChatFilter } from "../../../../src/ui/chat-monitor/filter/filter.js";
import { ControlsManager } from "../../../../src/ui/controls/controls-manager.js";
import {
NavigationDescription,
NavigationDirection,
} from "../../../../src/ui/controls/navigation.js";
import { agentId } from "../../../../src/ui/config.js";
import { stringToAgent } from "../../../../src/agents/agent-id.js";
import { keyActionListenerFactory } from "../../../../src/ui/controls/key-bindings.js";
import { getLogger } from "../../helpers/log.js";

const logger = getLogger(true);
const screen = blessed.screen({ title: "Chat filter" });
const controlsManager = new ControlsManager(screen, logger);
controlsManager.updateKeyActions(controlsManager.screen.id, {
kind: "exclusive",
actions: [
{
key: "C-c",
action: {
description: NavigationDescription.EXIT_APP,
listener: keyActionListenerFactory(() => {
process.exit(0);
}),
},
},
{
key: "enter",
action: {
description: NavigationDescription.IN_OUT,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.IN);
}),
},
},
{
key: "escape",
action: {
description: NavigationDescription.IN_OUT,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.OUT);
}),
},
},
{
key: "left",
action: {
description: NavigationDescription.LEFT_RIGHT,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.LEFT);
}),
},
},
{
key: "right",
action: {
description: NavigationDescription.LEFT_RIGHT,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.RIGHT);
}),
},
},
{
key: "up",
action: {
description: NavigationDescription.UP_DOWN,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.UP);
}),
},
},
{
key: "down",
action: {
description: NavigationDescription.UP_DOWN,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.DOWN);
}),
},
},
{
key: "tab",
action: {
description: NavigationDescription.NEXT_PREV,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.NEXT);
}),
},
},
{
key: "S-tab",
action: {
description: NavigationDescription.NEXT_PREV,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.PREVIOUS);
}),
},
},
],
});

const filter = new ChatFilter(
{
kind: "parent",
parent: controlsManager.screen,
controlsManager,
},
logger,
);
controlsManager.focus(filter.container.id);

filter.addRole(agentId(stringToAgent(`supervisor:boss[1]:1`)));
filter.addRole(agentId(stringToAgent(`operator:historical_sites_search[1]:1`)));
filter.addRole(agentId(stringToAgent(`operator:historical_sites_search[1]:2`)));
filter.addRole(agentId(stringToAgent(`operator:sports_events_search[1]:1`)));
filter.addRole(
agentId(stringToAgent(`operator:restaurant_recommendations[1]:1`)),
);
filter.addRole(
agentId(stringToAgent(`operator:restaurant_recommendations[1]:2`)),
);
109 changes: 109 additions & 0 deletions examples/ui/chat-monitor/filter/message-type-filter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import blessed from "neo-blessed";
import { MessageTypeFilter } from "../../../../src/ui/chat-monitor/filter/message-type-filter.js";
import { ControlsManager } from "../../../../src/ui/controls/controls-manager.js";
import {
NavigationDescription,
NavigationDirection,
} from "../../../../src/ui/controls/navigation.js";
import { getLogger } from "../../helpers/log.js";
import { keyActionListenerFactory } from "../../../../src/ui/controls/key-bindings.js";

const logger = getLogger(true);
const screen = blessed.screen({ title: "Message type filter" });
const controlsManager = new ControlsManager(screen, logger);
controlsManager.updateKeyActions(controlsManager.screen.id, {
kind: "exclusive",
actions: [
{
key: "C-c",
action: {
description: NavigationDescription.EXIT_APP,
listener: keyActionListenerFactory(() => {
process.exit(0);
}),
},
},
{
key: "enter",
action: {
description: NavigationDescription.IN_OUT,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.IN);
}),
},
},
{
key: "escape",
action: {
description: NavigationDescription.IN_OUT,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.OUT);
}),
},
},
{
key: "left",
action: {
description: NavigationDescription.LEFT_RIGHT,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.LEFT);
}),
},
},
{
key: "right",
action: {
description: NavigationDescription.LEFT_RIGHT,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.RIGHT);
}),
},
},
{
key: "up",
action: {
description: NavigationDescription.UP_DOWN,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.UP);
}),
},
},
{
key: "down",
action: {
description: NavigationDescription.UP_DOWN,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.DOWN);
}),
},
},
{
key: "tab",
action: {
description: NavigationDescription.NEXT_PREV,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.NEXT);
}),
},
},
{
key: "S-tab",
action: {
description: NavigationDescription.NEXT_PREV,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.PREVIOUS);
}),
},
},
],
});

const filter = new MessageTypeFilter(
{
kind: "parent",
parent: controlsManager.screen,
controlsManager,
},
logger,
);
controlsManager.focus(filter.container.id);
121 changes: 121 additions & 0 deletions examples/ui/chat-monitor/filter/role-filter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import blessed from "neo-blessed";
import { ControlsManager } from "../../../../src/ui/controls/controls-manager.js";
import {
NavigationDescription,
NavigationDirection,
} from "../../../../src/ui/controls/navigation.js";
import { agentId } from "../../../../src/ui/config.js";
import { stringToAgent } from "../../../../src/agents/agent-id.js";
import { RoleFilter } from "../../../../src/ui/chat-monitor/filter/role-filter.js";
import { getLogger } from "../../helpers/log.js";
import { keyActionListenerFactory } from "../../../../src/ui/controls/key-bindings.js";

const logger = getLogger(true);
const screen = blessed.screen({ title: "Role filter" });
const controlsManager = new ControlsManager(screen, logger);
controlsManager.updateKeyActions(controlsManager.screen.id, {
kind: "exclusive",
actions: [
{
key: "C-c",
action: {
description: NavigationDescription.EXIT_APP,
listener: keyActionListenerFactory(() => {
process.exit(0);
}),
},
},
{
key: "enter",
action: {
description: NavigationDescription.IN_OUT,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.IN);
}),
},
},
{
key: "escape",
action: {
description: NavigationDescription.IN_OUT,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.OUT);
}),
},
},
{
key: "left",
action: {
description: NavigationDescription.LEFT_RIGHT,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.LEFT);
}),
},
},
{
key: "right",
action: {
description: NavigationDescription.LEFT_RIGHT,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.RIGHT);
}),
},
},
{
key: "up",
action: {
description: NavigationDescription.UP_DOWN,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.UP);
}),
},
},
{
key: "down",
action: {
description: NavigationDescription.UP_DOWN,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.DOWN);
}),
},
},
{
key: "tab",
action: {
description: NavigationDescription.NEXT_PREV,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.NEXT);
}),
},
},
{
key: "S-tab",
action: {
description: NavigationDescription.NEXT_PREV,
listener: keyActionListenerFactory(() => {
controlsManager.navigate(NavigationDirection.PREVIOUS);
}),
},
},
],
});
const filter = new RoleFilter(
{
kind: "parent",
parent: controlsManager.screen,
controlsManager,
},
logger,
);
controlsManager.focus(filter.container.id);

filter.addRole(agentId(stringToAgent(`supervisor:boss[1]:1`)));
filter.addRole(agentId(stringToAgent(`operator:historical_sites_search[1]:1`)));
filter.addRole(agentId(stringToAgent(`operator:historical_sites_search[1]:2`)));
filter.addRole(agentId(stringToAgent(`operator:sports_events_search[1]:1`)));
filter.addRole(
agentId(stringToAgent(`operator:restaurant_recommendations[1]:1`)),
);
filter.addRole(
agentId(stringToAgent(`operator:restaurant_recommendations[1]:2`)),
);
Loading