@hybridaione/hybridclaw 0.2.2 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +70 -0
- package/.husky/pre-commit +1 -0
- package/CHANGELOG.md +85 -0
- package/CONTRIBUTING.md +33 -0
- package/README.md +41 -16
- package/SECURITY.md +17 -0
- package/biome.json +35 -0
- package/config.example.json +71 -8
- package/container/package-lock.json +2 -2
- package/container/package.json +1 -1
- package/container/src/approval-policy.ts +1303 -0
- package/container/src/browser-tools.ts +431 -136
- package/container/src/extensions.ts +36 -12
- package/container/src/hybridai-client.ts +34 -13
- package/container/src/index.ts +451 -109
- package/container/src/ipc.ts +5 -3
- package/container/src/token-usage.ts +20 -10
- package/container/src/tools.ts +599 -225
- package/container/src/types.ts +32 -2
- package/container/src/web-fetch.ts +89 -32
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +10 -2
- package/dist/agent.js.map +1 -1
- package/dist/audit-cli.d.ts.map +1 -1
- package/dist/audit-cli.js +4 -2
- package/dist/audit-cli.js.map +1 -1
- package/dist/audit-events.d.ts.map +1 -1
- package/dist/audit-events.js +53 -3
- package/dist/audit-events.js.map +1 -1
- package/dist/audit-trail.d.ts.map +1 -1
- package/dist/audit-trail.js +17 -8
- package/dist/audit-trail.js.map +1 -1
- package/dist/channels/discord/attachments.d.ts.map +1 -1
- package/dist/channels/discord/attachments.js +14 -7
- package/dist/channels/discord/attachments.js.map +1 -1
- package/dist/channels/discord/debounce.d.ts +9 -0
- package/dist/channels/discord/debounce.d.ts.map +1 -0
- package/dist/channels/discord/debounce.js +20 -0
- package/dist/channels/discord/debounce.js.map +1 -0
- package/dist/channels/discord/delivery.d.ts +4 -1
- package/dist/channels/discord/delivery.d.ts.map +1 -1
- package/dist/channels/discord/delivery.js +19 -3
- package/dist/channels/discord/delivery.js.map +1 -1
- package/dist/channels/discord/human-delay.d.ts +16 -0
- package/dist/channels/discord/human-delay.d.ts.map +1 -0
- package/dist/channels/discord/human-delay.js +29 -0
- package/dist/channels/discord/human-delay.js.map +1 -0
- package/dist/channels/discord/inbound.d.ts +4 -0
- package/dist/channels/discord/inbound.d.ts.map +1 -1
- package/dist/channels/discord/inbound.js +45 -4
- package/dist/channels/discord/inbound.js.map +1 -1
- package/dist/channels/discord/mentions.d.ts.map +1 -1
- package/dist/channels/discord/mentions.js +16 -4
- package/dist/channels/discord/mentions.js.map +1 -1
- package/dist/channels/discord/presence.d.ts +33 -0
- package/dist/channels/discord/presence.d.ts.map +1 -0
- package/dist/channels/discord/presence.js +111 -0
- package/dist/channels/discord/presence.js.map +1 -0
- package/dist/channels/discord/rate-limiter.d.ts +14 -0
- package/dist/channels/discord/rate-limiter.d.ts.map +1 -0
- package/dist/channels/discord/rate-limiter.js +49 -0
- package/dist/channels/discord/rate-limiter.js.map +1 -0
- package/dist/channels/discord/reactions.d.ts +38 -0
- package/dist/channels/discord/reactions.d.ts.map +1 -0
- package/dist/channels/discord/reactions.js +151 -0
- package/dist/channels/discord/reactions.js.map +1 -0
- package/dist/channels/discord/runtime.d.ts +6 -3
- package/dist/channels/discord/runtime.d.ts.map +1 -1
- package/dist/channels/discord/runtime.js +621 -125
- package/dist/channels/discord/runtime.js.map +1 -1
- package/dist/channels/discord/stream.d.ts +4 -1
- package/dist/channels/discord/stream.d.ts.map +1 -1
- package/dist/channels/discord/stream.js +16 -8
- package/dist/channels/discord/stream.js.map +1 -1
- package/dist/channels/discord/tool-actions.d.ts.map +1 -1
- package/dist/channels/discord/tool-actions.js +24 -12
- package/dist/channels/discord/tool-actions.js.map +1 -1
- package/dist/channels/discord/typing.d.ts +15 -0
- package/dist/channels/discord/typing.d.ts.map +1 -0
- package/dist/channels/discord/typing.js +106 -0
- package/dist/channels/discord/typing.js.map +1 -0
- package/dist/chunk.d.ts.map +1 -1
- package/dist/chunk.js +4 -2
- package/dist/chunk.js.map +1 -1
- package/dist/cli.js +47 -22
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +19 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +103 -18
- package/dist/config.js.map +1 -1
- package/dist/container-runner.d.ts.map +1 -1
- package/dist/container-runner.js +58 -26
- package/dist/container-runner.js.map +1 -1
- package/dist/container-setup.d.ts.map +1 -1
- package/dist/container-setup.js +10 -9
- package/dist/container-setup.js.map +1 -1
- package/dist/conversation.d.ts +2 -2
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +1 -1
- package/dist/conversation.js.map +1 -1
- package/dist/db.d.ts +118 -2
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +1568 -50
- package/dist/db.js.map +1 -1
- package/dist/delegation-manager.d.ts.map +1 -1
- package/dist/delegation-manager.js +3 -2
- package/dist/delegation-manager.js.map +1 -1
- package/dist/gateway-client.d.ts +2 -2
- package/dist/gateway-client.d.ts.map +1 -1
- package/dist/gateway-client.js +10 -4
- package/dist/gateway-client.js.map +1 -1
- package/dist/gateway-service.d.ts +3 -3
- package/dist/gateway-service.d.ts.map +1 -1
- package/dist/gateway-service.js +563 -73
- package/dist/gateway-service.js.map +1 -1
- package/dist/gateway-types.d.ts +24 -0
- package/dist/gateway-types.d.ts.map +1 -1
- package/dist/gateway-types.js.map +1 -1
- package/dist/gateway.js +179 -24
- package/dist/gateway.js.map +1 -1
- package/dist/health.d.ts.map +1 -1
- package/dist/health.js +20 -10
- package/dist/health.js.map +1 -1
- package/dist/heartbeat.d.ts +4 -0
- package/dist/heartbeat.d.ts.map +1 -1
- package/dist/heartbeat.js +48 -20
- package/dist/heartbeat.js.map +1 -1
- package/dist/hybridai-bots.d.ts.map +1 -1
- package/dist/hybridai-bots.js +4 -2
- package/dist/hybridai-bots.js.map +1 -1
- package/dist/instruction-approval-audit.d.ts.map +1 -1
- package/dist/instruction-approval-audit.js.map +1 -1
- package/dist/instruction-integrity.d.ts.map +1 -1
- package/dist/instruction-integrity.js +8 -2
- package/dist/instruction-integrity.js.map +1 -1
- package/dist/ipc.d.ts.map +1 -1
- package/dist/ipc.js +6 -1
- package/dist/ipc.js.map +1 -1
- package/dist/logger.js.map +1 -1
- package/dist/memory-consolidation.d.ts +17 -0
- package/dist/memory-consolidation.d.ts.map +1 -0
- package/dist/memory-consolidation.js +25 -0
- package/dist/memory-consolidation.js.map +1 -0
- package/dist/memory-service.d.ts +200 -0
- package/dist/memory-service.d.ts.map +1 -0
- package/dist/memory-service.js +294 -0
- package/dist/memory-service.js.map +1 -0
- package/dist/mount-security.d.ts.map +1 -1
- package/dist/mount-security.js +31 -7
- package/dist/mount-security.js.map +1 -1
- package/dist/observability-ingest.d.ts.map +1 -1
- package/dist/observability-ingest.js +32 -11
- package/dist/observability-ingest.js.map +1 -1
- package/dist/onboarding.d.ts.map +1 -1
- package/dist/onboarding.js +32 -9
- package/dist/onboarding.js.map +1 -1
- package/dist/proactive-policy.d.ts.map +1 -1
- package/dist/proactive-policy.js +2 -1
- package/dist/proactive-policy.js.map +1 -1
- package/dist/prompt-hooks.d.ts.map +1 -1
- package/dist/prompt-hooks.js +9 -7
- package/dist/prompt-hooks.js.map +1 -1
- package/dist/runtime-config.d.ts +98 -1
- package/dist/runtime-config.d.ts.map +1 -1
- package/dist/runtime-config.js +477 -23
- package/dist/runtime-config.js.map +1 -1
- package/dist/scheduled-task-runner.d.ts +1 -0
- package/dist/scheduled-task-runner.d.ts.map +1 -1
- package/dist/scheduled-task-runner.js +29 -10
- package/dist/scheduled-task-runner.js.map +1 -1
- package/dist/scheduler.d.ts +43 -4
- package/dist/scheduler.d.ts.map +1 -1
- package/dist/scheduler.js +530 -56
- package/dist/scheduler.js.map +1 -1
- package/dist/session-export.d.ts +26 -0
- package/dist/session-export.d.ts.map +1 -0
- package/dist/session-export.js +149 -0
- package/dist/session-export.js.map +1 -0
- package/dist/session-maintenance.d.ts.map +1 -1
- package/dist/session-maintenance.js +75 -13
- package/dist/session-maintenance.js.map +1 -1
- package/dist/session-transcripts.d.ts.map +1 -1
- package/dist/session-transcripts.js.map +1 -1
- package/dist/side-effects.d.ts.map +1 -1
- package/dist/side-effects.js +14 -2
- package/dist/side-effects.js.map +1 -1
- package/dist/skills-guard.d.ts.map +1 -1
- package/dist/skills-guard.js +893 -130
- package/dist/skills-guard.js.map +1 -1
- package/dist/skills.d.ts +5 -0
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +29 -15
- package/dist/skills.js.map +1 -1
- package/dist/token-efficiency.d.ts.map +1 -1
- package/dist/token-efficiency.js.map +1 -1
- package/dist/tui.js +92 -11
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts +146 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +24 -1
- package/dist/types.js.map +1 -1
- package/dist/update.d.ts.map +1 -1
- package/dist/update.js +42 -14
- package/dist/update.js.map +1 -1
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +49 -9
- package/dist/workspace.js.map +1 -1
- package/docs/chat.html +9 -3
- package/docs/index.html +37 -13
- package/package.json +8 -2
- package/src/agent.ts +16 -3
- package/src/audit-cli.ts +44 -16
- package/src/audit-events.ts +69 -5
- package/src/audit-trail.ts +41 -15
- package/src/channels/discord/attachments.ts +81 -27
- package/src/channels/discord/debounce.ts +25 -0
- package/src/channels/discord/delivery.ts +57 -13
- package/src/channels/discord/human-delay.ts +48 -0
- package/src/channels/discord/inbound.ts +66 -7
- package/src/channels/discord/mentions.ts +42 -18
- package/src/channels/discord/presence.ts +148 -0
- package/src/channels/discord/rate-limiter.ts +58 -0
- package/src/channels/discord/reactions.ts +211 -0
- package/src/channels/discord/runtime.ts +1048 -182
- package/src/channels/discord/stream.ts +73 -27
- package/src/channels/discord/tool-actions.ts +78 -37
- package/src/channels/discord/typing.ts +140 -0
- package/src/chunk.ts +12 -4
- package/src/cli.ts +141 -56
- package/src/config.ts +192 -34
- package/src/container-runner.ts +132 -42
- package/src/container-setup.ts +57 -22
- package/src/conversation.ts +9 -7
- package/src/db.ts +2217 -84
- package/src/delegation-manager.ts +6 -2
- package/src/gateway-client.ts +41 -17
- package/src/gateway-service.ts +1019 -201
- package/src/gateway-types.ts +33 -0
- package/src/gateway.ts +321 -48
- package/src/health.ts +66 -26
- package/src/heartbeat.ts +84 -22
- package/src/hybridai-bots.ts +14 -5
- package/src/instruction-approval-audit.ts +4 -1
- package/src/instruction-integrity.ts +30 -9
- package/src/ipc.ts +23 -5
- package/src/logger.ts +4 -1
- package/src/memory-consolidation.ts +41 -0
- package/src/memory-service.ts +606 -0
- package/src/mount-security.ts +58 -13
- package/src/observability-ingest.ts +134 -35
- package/src/onboarding.ts +126 -35
- package/src/proactive-policy.ts +3 -1
- package/src/prompt-hooks.ts +40 -17
- package/src/runtime-config.ts +1114 -99
- package/src/scheduled-task-runner.ts +63 -11
- package/src/scheduler.ts +683 -60
- package/src/session-export.ts +196 -0
- package/src/session-maintenance.ts +125 -22
- package/src/session-transcripts.ts +12 -3
- package/src/side-effects.ts +28 -5
- package/src/skills-guard.ts +1067 -219
- package/src/skills.ts +163 -65
- package/src/token-efficiency.ts +31 -9
- package/src/tui.ts +166 -25
- package/src/types.ts +195 -2
- package/src/update.ts +79 -23
- package/src/workspace.ts +63 -11
- package/tests/approval-policy.test.ts +224 -0
- package/tests/discord.basic.test.ts +82 -2
- package/tests/discord.human-presence.test.ts +85 -0
- package/tests/gateway-service.media-routing.test.ts +8 -2
- package/tests/memory-service.test.ts +1114 -0
- package/tests/token-efficiency.basic.test.ts +8 -2
- package/vitest.e2e.config.ts +3 -1
- package/vitest.integration.config.ts +3 -1
- package/vitest.live.config.ts +3 -1
- package/vitest.unit.config.ts +9 -0
package/src/tui.ts
CHANGED
|
@@ -2,17 +2,23 @@
|
|
|
2
2
|
* HybridClaw TUI — thin client for the gateway API.
|
|
3
3
|
* Usage: npm run tui
|
|
4
4
|
*/
|
|
5
|
-
import readline from 'readline';
|
|
5
|
+
import readline from 'node:readline';
|
|
6
6
|
|
|
7
|
-
import { APP_VERSION, GATEWAY_BASE_URL, HYBRIDAI_BASE_URL, HYBRIDAI_CHATBOT_ID, HYBRIDAI_MODEL } from './config.js';
|
|
8
7
|
import {
|
|
8
|
+
APP_VERSION,
|
|
9
|
+
GATEWAY_BASE_URL,
|
|
10
|
+
HYBRIDAI_BASE_URL,
|
|
11
|
+
HYBRIDAI_CHATBOT_ID,
|
|
12
|
+
HYBRIDAI_MODEL,
|
|
13
|
+
} from './config.js';
|
|
14
|
+
import {
|
|
15
|
+
type GatewayChatResult,
|
|
16
|
+
type GatewayCommandResult,
|
|
17
|
+
gatewayChat,
|
|
9
18
|
gatewayChatStream,
|
|
10
19
|
gatewayCommand,
|
|
11
|
-
gatewayChat,
|
|
12
20
|
gatewayStatus,
|
|
13
21
|
renderGatewayCommand,
|
|
14
|
-
type GatewayChatResult,
|
|
15
|
-
type GatewayCommandResult,
|
|
16
22
|
} from './gateway-client.js';
|
|
17
23
|
import { logger } from './logger.js';
|
|
18
24
|
|
|
@@ -53,7 +59,10 @@ function inferThemeFromColorFgBg(): TuiTheme | null {
|
|
|
53
59
|
const raw = process.env.COLORFGBG;
|
|
54
60
|
if (!raw) return null;
|
|
55
61
|
|
|
56
|
-
const parts = raw
|
|
62
|
+
const parts = raw
|
|
63
|
+
.split(/[;:]/)
|
|
64
|
+
.map((part) => part.trim())
|
|
65
|
+
.filter(Boolean);
|
|
57
66
|
if (parts.length === 0) return null;
|
|
58
67
|
|
|
59
68
|
const bg = Number.parseInt(parts[parts.length - 1], 10);
|
|
@@ -64,7 +73,14 @@ function inferThemeFromColorFgBg(): TuiTheme | null {
|
|
|
64
73
|
}
|
|
65
74
|
|
|
66
75
|
function resolveTuiTheme(): TuiTheme {
|
|
67
|
-
const override = (
|
|
76
|
+
const override = (
|
|
77
|
+
process.env.HYBRIDCLAW_THEME ||
|
|
78
|
+
process.env.HYBRIDCLAW_TUI_THEME ||
|
|
79
|
+
process.env.TUI_THEME ||
|
|
80
|
+
''
|
|
81
|
+
)
|
|
82
|
+
.trim()
|
|
83
|
+
.toLowerCase();
|
|
68
84
|
if (override === 'light' || override === 'dark') return override;
|
|
69
85
|
return inferThemeFromColorFgBg() || 'dark';
|
|
70
86
|
}
|
|
@@ -87,6 +103,84 @@ const TOOL_PREVIEW_MAX_CHARS = 140;
|
|
|
87
103
|
|
|
88
104
|
let activeRunAbortController: AbortController | null = null;
|
|
89
105
|
|
|
106
|
+
function findPendingApprovalRequestId(
|
|
107
|
+
result: GatewayChatResult,
|
|
108
|
+
): string | null {
|
|
109
|
+
const executions = result.toolExecutions || [];
|
|
110
|
+
for (let i = executions.length - 1; i >= 0; i -= 1) {
|
|
111
|
+
const execution = executions[i];
|
|
112
|
+
if (execution.approvalDecision !== 'required') continue;
|
|
113
|
+
if (!execution.approvalRequestId) continue;
|
|
114
|
+
return execution.approvalRequestId;
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function mapApprovalSelectionToCommand(
|
|
120
|
+
selection: string,
|
|
121
|
+
requestId: string,
|
|
122
|
+
): string | null {
|
|
123
|
+
const normalized = selection.trim().toLowerCase().replace(/\s+/g, ' ');
|
|
124
|
+
if (!normalized) return null;
|
|
125
|
+
|
|
126
|
+
if (
|
|
127
|
+
normalized === '1' ||
|
|
128
|
+
normalized === 'yes' ||
|
|
129
|
+
normalized === 'y' ||
|
|
130
|
+
normalized === 'once'
|
|
131
|
+
) {
|
|
132
|
+
return `yes ${requestId}`;
|
|
133
|
+
}
|
|
134
|
+
if (
|
|
135
|
+
normalized === '2' ||
|
|
136
|
+
normalized === 'session' ||
|
|
137
|
+
normalized === 'yes for session' ||
|
|
138
|
+
normalized === 'for session'
|
|
139
|
+
) {
|
|
140
|
+
return `yes ${requestId} for session`;
|
|
141
|
+
}
|
|
142
|
+
if (
|
|
143
|
+
normalized === '3' ||
|
|
144
|
+
normalized === 'agent' ||
|
|
145
|
+
normalized === 'yes for agent' ||
|
|
146
|
+
normalized === 'for agent'
|
|
147
|
+
) {
|
|
148
|
+
return `yes ${requestId} for agent`;
|
|
149
|
+
}
|
|
150
|
+
if (
|
|
151
|
+
normalized === '4' ||
|
|
152
|
+
normalized === 'no' ||
|
|
153
|
+
normalized === 'n' ||
|
|
154
|
+
normalized === 'skip'
|
|
155
|
+
) {
|
|
156
|
+
return `skip ${requestId}`;
|
|
157
|
+
}
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async function promptApprovalSelection(
|
|
162
|
+
rl: readline.Interface,
|
|
163
|
+
requestId: string,
|
|
164
|
+
): Promise<string | null> {
|
|
165
|
+
console.log(
|
|
166
|
+
` ${BOLD}${GOLD}Approval options${RESET} ${MUTED}(request ${requestId})${RESET}`,
|
|
167
|
+
);
|
|
168
|
+
console.log(` ${TEAL}1${RESET} yes (once)`);
|
|
169
|
+
console.log(` ${TEAL}2${RESET} yes for session`);
|
|
170
|
+
console.log(` ${TEAL}3${RESET} yes for agent`);
|
|
171
|
+
console.log(` ${TEAL}4${RESET} no / skip`);
|
|
172
|
+
const answer = await new Promise<string>((resolve) => {
|
|
173
|
+
rl.question(` ${MUTED}Select 1-4 (Enter to skip):${RESET} `, resolve);
|
|
174
|
+
});
|
|
175
|
+
const command = mapApprovalSelectionToCommand(answer, requestId);
|
|
176
|
+
if (answer.trim() && !command) {
|
|
177
|
+
printInfo(
|
|
178
|
+
`Unrecognized selection "${answer.trim()}". You can reply manually with yes/skip and the request id.`,
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
return command;
|
|
182
|
+
}
|
|
183
|
+
|
|
90
184
|
function printBanner(): void {
|
|
91
185
|
const T = TEAL;
|
|
92
186
|
const N = NAVY;
|
|
@@ -124,12 +218,18 @@ function printBanner(): void {
|
|
|
124
218
|
console.log();
|
|
125
219
|
for (const line of logo) console.log(line);
|
|
126
220
|
console.log();
|
|
127
|
-
console.log(
|
|
221
|
+
console.log(
|
|
222
|
+
` \u{1F99E} ${BOLD}${TEAL}H y b r i d ${GOLD}C l a w${RESET} ${MUTED}v${APP_VERSION}${RESET}`,
|
|
223
|
+
);
|
|
128
224
|
console.log(`${MUTED} Powered by HybridAI${RESET}`);
|
|
129
225
|
console.log();
|
|
130
|
-
console.log(
|
|
226
|
+
console.log(
|
|
227
|
+
` ${MUTED}Model:${RESET} ${TEAL}${HYBRIDAI_MODEL}${RESET}${MUTED} | Bot:${RESET} ${GOLD}${HYBRIDAI_CHATBOT_ID || 'unset'}${RESET}`,
|
|
228
|
+
);
|
|
131
229
|
console.log(` ${MUTED}Gateway:${RESET} ${TEAL}${GATEWAY_BASE_URL}${RESET}`);
|
|
132
|
-
console.log(
|
|
230
|
+
console.log(
|
|
231
|
+
` ${MUTED}HybridAI:${RESET} ${TEAL}${HYBRIDAI_BASE_URL}${RESET}`,
|
|
232
|
+
);
|
|
133
233
|
console.log();
|
|
134
234
|
}
|
|
135
235
|
|
|
@@ -162,12 +262,18 @@ function printError(text: string): void {
|
|
|
162
262
|
}
|
|
163
263
|
|
|
164
264
|
function printInfo(text: string): void {
|
|
165
|
-
console.log(
|
|
265
|
+
console.log();
|
|
266
|
+
for (const line of text.split('\n')) {
|
|
267
|
+
console.log(` ${GOLD}${line}${RESET}`);
|
|
268
|
+
}
|
|
269
|
+
console.log();
|
|
166
270
|
}
|
|
167
271
|
|
|
168
272
|
function printToolUsage(tools: string[]): void {
|
|
169
273
|
if (tools.length === 0) return;
|
|
170
|
-
console.log(
|
|
274
|
+
console.log(
|
|
275
|
+
` ${MUTED}${JELLYFISH} tools:${RESET} ${GREEN}${tools.join(', ')}${RESET}`,
|
|
276
|
+
);
|
|
171
277
|
}
|
|
172
278
|
|
|
173
279
|
function printGatewayCommandResult(result: GatewayCommandResult): void {
|
|
@@ -190,7 +296,7 @@ function spinner(): {
|
|
|
190
296
|
const clearLine = () => process.stdout.write('\r\x1b[2K');
|
|
191
297
|
const render = () => {
|
|
192
298
|
clearLine();
|
|
193
|
-
|
|
299
|
+
process.stdout.write(`\r${TEAL}thinking${dots[i % dots.length]}${RESET}`);
|
|
194
300
|
i++;
|
|
195
301
|
};
|
|
196
302
|
const interval = setInterval(render, 350);
|
|
@@ -203,7 +309,9 @@ function spinner(): {
|
|
|
203
309
|
addTool: (toolName: string, preview?: string) => {
|
|
204
310
|
clearLine();
|
|
205
311
|
const previewText = preview ? ` ${MUTED}${preview}${RESET}` : '';
|
|
206
|
-
process.stdout.write(
|
|
312
|
+
process.stdout.write(
|
|
313
|
+
` ${JELLYFISH} ${TEAL}${toolName}${RESET}${previewText}\n`,
|
|
314
|
+
);
|
|
207
315
|
transientToolLines++;
|
|
208
316
|
render();
|
|
209
317
|
},
|
|
@@ -234,7 +342,10 @@ async function runGatewayCommand(args: string[]): Promise<void> {
|
|
|
234
342
|
}
|
|
235
343
|
}
|
|
236
344
|
|
|
237
|
-
async function handleSlashCommand(
|
|
345
|
+
async function handleSlashCommand(
|
|
346
|
+
input: string,
|
|
347
|
+
rl: readline.Interface,
|
|
348
|
+
): Promise<boolean> {
|
|
238
349
|
const parts = input.slice(1).trim().split(/\s+/).filter(Boolean);
|
|
239
350
|
const cmd = (parts[0] || '').toLowerCase();
|
|
240
351
|
|
|
@@ -248,6 +359,7 @@ async function handleSlashCommand(input: string, rl: readline.Interface): Promis
|
|
|
248
359
|
console.log(`\n ${GOLD}Goodbye!${RESET}\n`);
|
|
249
360
|
rl.close();
|
|
250
361
|
process.exit(0);
|
|
362
|
+
return true;
|
|
251
363
|
case 'bots':
|
|
252
364
|
await runGatewayCommand(['bot', 'list']);
|
|
253
365
|
return true;
|
|
@@ -282,7 +394,10 @@ async function handleSlashCommand(input: string, rl: readline.Interface): Promis
|
|
|
282
394
|
return true;
|
|
283
395
|
case 'stop':
|
|
284
396
|
case 'abort':
|
|
285
|
-
if (
|
|
397
|
+
if (
|
|
398
|
+
activeRunAbortController &&
|
|
399
|
+
!activeRunAbortController.signal.aborted
|
|
400
|
+
) {
|
|
286
401
|
activeRunAbortController.abort();
|
|
287
402
|
printInfo('Stopping current request...');
|
|
288
403
|
} else {
|
|
@@ -294,7 +409,10 @@ async function handleSlashCommand(input: string, rl: readline.Interface): Promis
|
|
|
294
409
|
}
|
|
295
410
|
}
|
|
296
411
|
|
|
297
|
-
async function processMessage(
|
|
412
|
+
async function processMessage(
|
|
413
|
+
content: string,
|
|
414
|
+
rl: readline.Interface,
|
|
415
|
+
): Promise<void> {
|
|
298
416
|
const s = spinner();
|
|
299
417
|
const abortController = new AbortController();
|
|
300
418
|
activeRunAbortController = abortController;
|
|
@@ -325,11 +443,17 @@ async function processMessage(content: string): Promise<void> {
|
|
|
325
443
|
stream: true,
|
|
326
444
|
},
|
|
327
445
|
(event) => {
|
|
328
|
-
if (
|
|
446
|
+
if (
|
|
447
|
+
event.type !== 'tool' ||
|
|
448
|
+
event.phase !== 'start' ||
|
|
449
|
+
!event.toolName
|
|
450
|
+
)
|
|
451
|
+
return;
|
|
329
452
|
const preview = (event.preview || '').replace(/\s+/g, ' ').trim();
|
|
330
|
-
const previewText =
|
|
331
|
-
|
|
332
|
-
|
|
453
|
+
const previewText =
|
|
454
|
+
preview.length > TOOL_PREVIEW_MAX_CHARS
|
|
455
|
+
? `${preview.slice(0, TOOL_PREVIEW_MAX_CHARS - 1)}…`
|
|
456
|
+
: preview;
|
|
333
457
|
toolNames.add(event.toolName);
|
|
334
458
|
s.addTool(event.toolName, previewText || undefined);
|
|
335
459
|
},
|
|
@@ -361,7 +485,10 @@ async function processMessage(content: string): Promise<void> {
|
|
|
361
485
|
printToolUsage(Array.from(toolNames));
|
|
362
486
|
}
|
|
363
487
|
|
|
364
|
-
if (
|
|
488
|
+
if (
|
|
489
|
+
(result.error || '').includes('aborted') ||
|
|
490
|
+
(result.error || '').includes('Interrupted')
|
|
491
|
+
) {
|
|
365
492
|
return;
|
|
366
493
|
}
|
|
367
494
|
|
|
@@ -371,6 +498,16 @@ async function processMessage(content: string): Promise<void> {
|
|
|
371
498
|
}
|
|
372
499
|
|
|
373
500
|
printResponse(result.result || 'No response.');
|
|
501
|
+
const pendingApprovalId = findPendingApprovalRequestId(result);
|
|
502
|
+
if (pendingApprovalId) {
|
|
503
|
+
const approvalCommand = await promptApprovalSelection(
|
|
504
|
+
rl,
|
|
505
|
+
pendingApprovalId,
|
|
506
|
+
);
|
|
507
|
+
if (approvalCommand) {
|
|
508
|
+
await processMessage(approvalCommand, rl);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
374
511
|
} catch (err) {
|
|
375
512
|
s.stop();
|
|
376
513
|
if (abortController.signal.aborted) return;
|
|
@@ -399,7 +536,8 @@ async function main(): Promise<void> {
|
|
|
399
536
|
if (process.stdin.isTTY) process.stdin.setRawMode(true);
|
|
400
537
|
process.stdin.on('keypress', (_str, key) => {
|
|
401
538
|
if (key?.name !== 'escape') return;
|
|
402
|
-
if (!activeRunAbortController || activeRunAbortController.signal.aborted)
|
|
539
|
+
if (!activeRunAbortController || activeRunAbortController.signal.aborted)
|
|
540
|
+
return;
|
|
403
541
|
activeRunAbortController.abort();
|
|
404
542
|
});
|
|
405
543
|
|
|
@@ -423,7 +561,7 @@ async function main(): Promise<void> {
|
|
|
423
561
|
return;
|
|
424
562
|
}
|
|
425
563
|
}
|
|
426
|
-
await processMessage(input);
|
|
564
|
+
await processMessage(input, rl);
|
|
427
565
|
rl.prompt();
|
|
428
566
|
})
|
|
429
567
|
.catch((err) => {
|
|
@@ -446,7 +584,10 @@ async function main(): Promise<void> {
|
|
|
446
584
|
rl.on('line', (line) => {
|
|
447
585
|
pendingInputLines.push(line);
|
|
448
586
|
if (pendingInputTimer) clearTimeout(pendingInputTimer);
|
|
449
|
-
pendingInputTimer = setTimeout(
|
|
587
|
+
pendingInputTimer = setTimeout(
|
|
588
|
+
flushPendingInput,
|
|
589
|
+
TUI_MULTILINE_PASTE_DEBOUNCE_MS,
|
|
590
|
+
);
|
|
450
591
|
});
|
|
451
592
|
|
|
452
593
|
rl.on('close', () => {
|
package/src/types.ts
CHANGED
|
@@ -59,7 +59,16 @@ export interface ContainerInput {
|
|
|
59
59
|
gatewayApiToken?: string;
|
|
60
60
|
model: string;
|
|
61
61
|
channelId: string;
|
|
62
|
-
scheduledTasks?: {
|
|
62
|
+
scheduledTasks?: {
|
|
63
|
+
id: number;
|
|
64
|
+
cronExpr: string;
|
|
65
|
+
runAt: string | null;
|
|
66
|
+
everyMs: number | null;
|
|
67
|
+
prompt: string;
|
|
68
|
+
enabled: number;
|
|
69
|
+
lastRun: string | null;
|
|
70
|
+
createdAt: string;
|
|
71
|
+
}[];
|
|
63
72
|
allowedTools?: string[];
|
|
64
73
|
blockedTools?: string[];
|
|
65
74
|
media?: MediaContextItem[];
|
|
@@ -73,6 +82,20 @@ export interface ToolExecution {
|
|
|
73
82
|
isError?: boolean;
|
|
74
83
|
blocked?: boolean;
|
|
75
84
|
blockedReason?: string;
|
|
85
|
+
approvalTier?: 'green' | 'yellow' | 'red';
|
|
86
|
+
approvalBaseTier?: 'green' | 'yellow' | 'red';
|
|
87
|
+
approvalDecision?:
|
|
88
|
+
| 'auto'
|
|
89
|
+
| 'implicit'
|
|
90
|
+
| 'approved_once'
|
|
91
|
+
| 'approved_session'
|
|
92
|
+
| 'approved_agent'
|
|
93
|
+
| 'promoted'
|
|
94
|
+
| 'required'
|
|
95
|
+
| 'denied';
|
|
96
|
+
approvalActionKey?: string;
|
|
97
|
+
approvalReason?: string;
|
|
98
|
+
approvalRequestId?: string;
|
|
76
99
|
}
|
|
77
100
|
|
|
78
101
|
export interface ToolProgressEvent {
|
|
@@ -108,6 +131,7 @@ export interface ContainerOutput {
|
|
|
108
131
|
toolExecutions?: ToolExecution[];
|
|
109
132
|
tokenUsage?: TokenUsageStats;
|
|
110
133
|
error?: string;
|
|
134
|
+
effectiveUserPrompt?: string;
|
|
111
135
|
sideEffects?: {
|
|
112
136
|
schedules?: ScheduleSideEffect[];
|
|
113
137
|
delegations?: DelegationSideEffect[];
|
|
@@ -115,7 +139,13 @@ export interface ContainerOutput {
|
|
|
115
139
|
}
|
|
116
140
|
|
|
117
141
|
export type ScheduleSideEffect =
|
|
118
|
-
| {
|
|
142
|
+
| {
|
|
143
|
+
action: 'add';
|
|
144
|
+
cronExpr?: string;
|
|
145
|
+
runAt?: string;
|
|
146
|
+
everyMs?: number;
|
|
147
|
+
prompt: string;
|
|
148
|
+
}
|
|
119
149
|
| { action: 'remove'; taskId: number };
|
|
120
150
|
|
|
121
151
|
export interface DelegationTaskSpec {
|
|
@@ -162,6 +192,167 @@ export interface StoredMessage {
|
|
|
162
192
|
created_at: string;
|
|
163
193
|
}
|
|
164
194
|
|
|
195
|
+
export interface SemanticMemoryEntry {
|
|
196
|
+
id: number;
|
|
197
|
+
session_id: string;
|
|
198
|
+
role: string;
|
|
199
|
+
source: string;
|
|
200
|
+
scope: string;
|
|
201
|
+
metadata: Record<string, unknown>;
|
|
202
|
+
content: string;
|
|
203
|
+
confidence: number;
|
|
204
|
+
embedding: number[] | null;
|
|
205
|
+
source_message_id: number | null;
|
|
206
|
+
created_at: string;
|
|
207
|
+
accessed_at: string;
|
|
208
|
+
access_count: number;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export interface StructuredMemoryEntry {
|
|
212
|
+
agent_id: string;
|
|
213
|
+
key: string;
|
|
214
|
+
value: unknown;
|
|
215
|
+
version: number;
|
|
216
|
+
updated_at: string;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export enum KnowledgeEntityType {
|
|
220
|
+
Person = 'person',
|
|
221
|
+
Organization = 'organization',
|
|
222
|
+
Project = 'project',
|
|
223
|
+
Concept = 'concept',
|
|
224
|
+
Event = 'event',
|
|
225
|
+
Location = 'location',
|
|
226
|
+
Document = 'document',
|
|
227
|
+
Tool = 'tool',
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface KnowledgeEntityCustomType {
|
|
231
|
+
custom: string;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export type KnowledgeEntityTypeValue =
|
|
235
|
+
| KnowledgeEntityType
|
|
236
|
+
| KnowledgeEntityCustomType;
|
|
237
|
+
|
|
238
|
+
export enum KnowledgeRelationType {
|
|
239
|
+
WorksAt = 'works_at',
|
|
240
|
+
KnowsAbout = 'knows_about',
|
|
241
|
+
RelatedTo = 'related_to',
|
|
242
|
+
DependsOn = 'depends_on',
|
|
243
|
+
OwnedBy = 'owned_by',
|
|
244
|
+
CreatedBy = 'created_by',
|
|
245
|
+
LocatedIn = 'located_in',
|
|
246
|
+
PartOf = 'part_of',
|
|
247
|
+
Uses = 'uses',
|
|
248
|
+
Produces = 'produces',
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export interface KnowledgeRelationCustomType {
|
|
252
|
+
custom: string;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export type KnowledgeRelationTypeValue =
|
|
256
|
+
| KnowledgeRelationType
|
|
257
|
+
| KnowledgeRelationCustomType;
|
|
258
|
+
|
|
259
|
+
export interface KnowledgeEntity {
|
|
260
|
+
id: string;
|
|
261
|
+
entity_type: KnowledgeEntityTypeValue;
|
|
262
|
+
name: string;
|
|
263
|
+
properties: Record<string, unknown>;
|
|
264
|
+
created_at: string;
|
|
265
|
+
updated_at: string;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export interface KnowledgeRelation {
|
|
269
|
+
source: string;
|
|
270
|
+
relation: KnowledgeRelationTypeValue;
|
|
271
|
+
target: string;
|
|
272
|
+
properties: Record<string, unknown>;
|
|
273
|
+
confidence: number;
|
|
274
|
+
created_at: string;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export interface KnowledgeGraphPattern {
|
|
278
|
+
source?: string;
|
|
279
|
+
relation?: KnowledgeRelationTypeValue;
|
|
280
|
+
target?: string;
|
|
281
|
+
max_depth?: number;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export interface KnowledgeGraphMatch {
|
|
285
|
+
source: KnowledgeEntity;
|
|
286
|
+
relation: KnowledgeRelation;
|
|
287
|
+
target: KnowledgeEntity;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export interface CanonicalSessionMessage {
|
|
291
|
+
role: string;
|
|
292
|
+
content: string;
|
|
293
|
+
session_id: string;
|
|
294
|
+
channel_id: string | null;
|
|
295
|
+
created_at: string;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export interface CanonicalSession {
|
|
299
|
+
canonical_id: string;
|
|
300
|
+
agent_id: string;
|
|
301
|
+
user_id: string;
|
|
302
|
+
messages: CanonicalSessionMessage[];
|
|
303
|
+
compaction_cursor: number;
|
|
304
|
+
compacted_summary: string | null;
|
|
305
|
+
message_count: number;
|
|
306
|
+
created_at: string;
|
|
307
|
+
updated_at: string;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export interface CanonicalSessionContext {
|
|
311
|
+
summary: string | null;
|
|
312
|
+
recent_messages: CanonicalSessionMessage[];
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export type UsageWindow = 'daily' | 'monthly' | 'all';
|
|
316
|
+
|
|
317
|
+
export interface UsageTotals {
|
|
318
|
+
total_input_tokens: number;
|
|
319
|
+
total_output_tokens: number;
|
|
320
|
+
total_tokens: number;
|
|
321
|
+
total_cost_usd: number;
|
|
322
|
+
call_count: number;
|
|
323
|
+
total_tool_calls: number;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export interface UsageModelAggregate {
|
|
327
|
+
model: string;
|
|
328
|
+
total_input_tokens: number;
|
|
329
|
+
total_output_tokens: number;
|
|
330
|
+
total_tokens: number;
|
|
331
|
+
total_cost_usd: number;
|
|
332
|
+
call_count: number;
|
|
333
|
+
total_tool_calls: number;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export interface UsageAgentAggregate {
|
|
337
|
+
agent_id: string;
|
|
338
|
+
total_input_tokens: number;
|
|
339
|
+
total_output_tokens: number;
|
|
340
|
+
total_tokens: number;
|
|
341
|
+
total_cost_usd: number;
|
|
342
|
+
call_count: number;
|
|
343
|
+
total_tool_calls: number;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export interface UsageDailyAggregate {
|
|
347
|
+
day: string;
|
|
348
|
+
total_input_tokens: number;
|
|
349
|
+
total_output_tokens: number;
|
|
350
|
+
total_tokens: number;
|
|
351
|
+
total_cost_usd: number;
|
|
352
|
+
call_count: number;
|
|
353
|
+
total_tool_calls: number;
|
|
354
|
+
}
|
|
355
|
+
|
|
165
356
|
export interface ScheduledTask {
|
|
166
357
|
id: number;
|
|
167
358
|
session_id: string;
|
|
@@ -172,6 +363,8 @@ export interface ScheduledTask {
|
|
|
172
363
|
prompt: string;
|
|
173
364
|
enabled: number;
|
|
174
365
|
last_run: string | null;
|
|
366
|
+
last_status: string | null;
|
|
367
|
+
consecutive_errors: number;
|
|
175
368
|
created_at: string;
|
|
176
369
|
}
|
|
177
370
|
|