@tyvm/knowhow 0.0.146 → 0.0.148
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/autodoc/cli-reference.md +36 -7
- package/bin/knowhow.js +8 -6
- package/package.json +1 -1
- package/src/agents/base/base.ts +51 -23
- package/src/agents/historyRollback.ts +36 -0
- package/src/agents/tools/execCommand.ts +102 -320
- package/src/agents/tools/list.ts +2 -2
- package/src/agents/tools/startAgentTask.ts +91 -34
- package/src/ai.ts +4 -1
- package/src/auth/browserLogin.ts +9 -3
- package/src/auth/keyAuth.ts +115 -0
- package/src/auth/keyManager.ts +166 -0
- package/src/chat/CliChatService.ts +23 -2
- package/src/chat/modules/AgentModule.ts +114 -33
- package/src/chat/modules/AskModule.ts +2 -0
- package/src/chat/modules/BaseChatModule.ts +0 -1
- package/src/chat/modules/CustomCommandsModule.ts +2 -0
- package/src/chat/modules/InternalChatModule.ts +7 -0
- package/src/chat/modules/RemoteSyncModule.ts +4 -0
- package/src/chat/modules/RendererModule.ts +2 -0
- package/src/chat/modules/SearchModule.ts +2 -0
- package/src/chat/modules/SessionsModule.ts +103 -34
- package/src/chat/modules/SetupModule.ts +2 -0
- package/src/chat/modules/ShellCommandModule.ts +2 -0
- package/src/chat/modules/SystemModule.ts +2 -0
- package/src/chat/modules/ToolCommandModule.ts +102 -0
- package/src/chat/modules/index.ts +1 -0
- package/src/chat/types.ts +3 -1
- package/src/cli.ts +10 -3
- package/src/clients/http.ts +67 -7
- package/src/clients/index.ts +4 -0
- package/src/commands/agent.ts +1 -38
- package/src/commands/agents.ts +455 -60
- package/src/commands/misc.ts +3 -2
- package/src/commands/processes.ts +138 -0
- package/src/commands/services.ts +23 -1
- package/src/index.ts +1 -0
- package/src/login.ts +89 -28
- package/src/processes/ProcessManager.ts +95 -0
- package/src/processes/managedProcessShim.ts +115 -0
- package/src/services/AgentService.ts +2 -0
- package/src/services/AgentSyncFs.ts +77 -1
- package/src/services/AgentSyncKnowhowWeb.ts +22 -4
- package/src/services/BehaviorsService.ts +2 -0
- package/src/services/DockerService.ts +2 -0
- package/src/services/EmbeddingService.ts +2 -0
- package/src/services/EmbeddingsService.ts +3 -0
- package/src/services/ExtensionsService.ts +25 -0
- package/src/services/KnowhowClient.ts +68 -7
- package/src/services/LazyToolsService.ts +24 -20
- package/src/services/Mcp.ts +2 -0
- package/src/services/McpServer.ts +2 -0
- package/src/services/MessageProcessor.ts +2 -0
- package/src/services/MinimalToolsService.ts +2 -0
- package/src/services/SessionManager.ts +5 -0
- package/src/services/SkillsService.ts +2 -0
- package/src/services/SyncedAgentWatcher.ts +2 -0
- package/src/services/SyncerService.ts +23 -8
- package/src/services/TaskRegistry.ts +2 -0
- package/src/services/Tools.ts +12 -0
- package/src/services/index.ts +6 -0
- package/src/services/modules/index.ts +10 -1
- package/src/services/modules/types.ts +4 -0
- package/src/types.ts +2 -0
- package/src/util/Trace.ts +1 -1
- package/src/utils/http.ts +18 -2
- package/tests/unit/agents/historyRollback.test.ts +53 -0
- package/tests/unit/auth/keyAuth.test.ts +102 -0
- package/tests/unit/auth/keyManager.test.ts +67 -0
- package/tests/unit/chat/ToolCommandModule.test.ts +71 -0
- package/tests/unit/chat/historyCommandArgs.test.ts +37 -0
- package/tests/unit/commands/agents.test.ts +111 -0
- package/tests/unit/login.test.ts +119 -0
- package/tests/unit/services/AgentSyncKnowhowWeb.test.ts +38 -0
- package/tests/unit/services/LazyToolsService.test.ts +53 -0
- package/tests/unit/services/SessionManager.test.ts +43 -0
- package/tests/unit/services/SyncerService.test.ts +45 -0
- package/tests/unit/util/Trace.test.ts +119 -0
- package/tests/unit/utils/http.test.ts +43 -0
- package/ts_build/package.json +1 -1
- package/ts_build/src/agents/base/base.d.ts +2 -1
- package/ts_build/src/agents/base/base.js +47 -14
- package/ts_build/src/agents/base/base.js.map +1 -1
- package/ts_build/src/agents/historyRollback.d.ts +2 -0
- package/ts_build/src/agents/historyRollback.js +22 -0
- package/ts_build/src/agents/historyRollback.js.map +1 -0
- package/ts_build/src/agents/tools/execCommand.d.ts +4 -1
- package/ts_build/src/agents/tools/execCommand.js +100 -223
- package/ts_build/src/agents/tools/execCommand.js.map +1 -1
- package/ts_build/src/agents/tools/list.js +2 -2
- package/ts_build/src/agents/tools/list.js.map +1 -1
- package/ts_build/src/agents/tools/startAgentTask.d.ts +16 -1
- package/ts_build/src/agents/tools/startAgentTask.js +71 -28
- package/ts_build/src/agents/tools/startAgentTask.js.map +1 -1
- package/ts_build/src/ai.js +2 -1
- package/ts_build/src/ai.js.map +1 -1
- package/ts_build/src/auth/browserLogin.d.ts +1 -0
- package/ts_build/src/auth/browserLogin.js +5 -2
- package/ts_build/src/auth/browserLogin.js.map +1 -1
- package/ts_build/src/auth/keyAuth.d.ts +5 -0
- package/ts_build/src/auth/keyAuth.js +79 -0
- package/ts_build/src/auth/keyAuth.js.map +1 -0
- package/ts_build/src/auth/keyManager.d.ts +14 -0
- package/ts_build/src/auth/keyManager.js +145 -0
- package/ts_build/src/auth/keyManager.js.map +1 -0
- package/ts_build/src/chat/CliChatService.d.ts +6 -0
- package/ts_build/src/chat/CliChatService.js +17 -2
- package/ts_build/src/chat/CliChatService.js.map +1 -1
- package/ts_build/src/chat/modules/AgentModule.d.ts +13 -1
- package/ts_build/src/chat/modules/AgentModule.js +83 -24
- package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
- package/ts_build/src/chat/modules/AskModule.js +12 -2
- package/ts_build/src/chat/modules/AskModule.js.map +1 -1
- package/ts_build/src/chat/modules/BaseChatModule.js.map +1 -1
- package/ts_build/src/chat/modules/CustomCommandsModule.js +12 -2
- package/ts_build/src/chat/modules/CustomCommandsModule.js.map +1 -1
- package/ts_build/src/chat/modules/InternalChatModule.d.ts +1 -0
- package/ts_build/src/chat/modules/InternalChatModule.js +21 -2
- package/ts_build/src/chat/modules/InternalChatModule.js.map +1 -1
- package/ts_build/src/chat/modules/RemoteSyncModule.js +19 -2
- package/ts_build/src/chat/modules/RemoteSyncModule.js.map +1 -1
- package/ts_build/src/chat/modules/RendererModule.js +17 -2
- package/ts_build/src/chat/modules/RendererModule.js.map +1 -1
- package/ts_build/src/chat/modules/SearchModule.js +12 -2
- package/ts_build/src/chat/modules/SearchModule.js.map +1 -1
- package/ts_build/src/chat/modules/SessionsModule.d.ts +6 -0
- package/ts_build/src/chat/modules/SessionsModule.js +113 -18
- package/ts_build/src/chat/modules/SessionsModule.js.map +1 -1
- package/ts_build/src/chat/modules/SetupModule.js +17 -2
- package/ts_build/src/chat/modules/SetupModule.js.map +1 -1
- package/ts_build/src/chat/modules/ShellCommandModule.js +12 -2
- package/ts_build/src/chat/modules/ShellCommandModule.js.map +1 -1
- package/ts_build/src/chat/modules/SystemModule.js +12 -2
- package/ts_build/src/chat/modules/SystemModule.js.map +1 -1
- package/ts_build/src/chat/modules/ToolCommandModule.d.ts +10 -0
- package/ts_build/src/chat/modules/ToolCommandModule.js +86 -0
- package/ts_build/src/chat/modules/ToolCommandModule.js.map +1 -0
- package/ts_build/src/chat/modules/index.d.ts +1 -0
- package/ts_build/src/chat/modules/index.js +3 -1
- package/ts_build/src/chat/modules/index.js.map +1 -1
- package/ts_build/src/chat/types.d.ts +3 -1
- package/ts_build/src/cli.js +7 -3
- package/ts_build/src/cli.js.map +1 -1
- package/ts_build/src/clients/http.d.ts +4 -0
- package/ts_build/src/clients/http.js +68 -6
- package/ts_build/src/clients/http.js.map +1 -1
- package/ts_build/src/clients/index.js +23 -4
- package/ts_build/src/clients/index.js.map +1 -1
- package/ts_build/src/commands/agent.js +1 -21
- package/ts_build/src/commands/agent.js.map +1 -1
- package/ts_build/src/commands/agents.d.ts +2 -1
- package/ts_build/src/commands/agents.js +216 -23
- package/ts_build/src/commands/agents.js.map +1 -1
- package/ts_build/src/commands/misc.js +3 -2
- package/ts_build/src/commands/misc.js.map +1 -1
- package/ts_build/src/commands/processes.d.ts +2 -0
- package/ts_build/src/commands/processes.js +213 -0
- package/ts_build/src/commands/processes.js.map +1 -0
- package/ts_build/src/commands/services.js +11 -1
- package/ts_build/src/commands/services.js.map +1 -1
- package/ts_build/src/index.d.ts +1 -0
- package/ts_build/src/index.js +1 -0
- package/ts_build/src/index.js.map +1 -1
- package/ts_build/src/login.d.ts +1 -1
- package/ts_build/src/login.js +53 -15
- package/ts_build/src/login.js.map +1 -1
- package/ts_build/src/processes/ProcessManager.d.ts +51 -0
- package/ts_build/src/processes/ProcessManager.js +160 -0
- package/ts_build/src/processes/ProcessManager.js.map +1 -0
- package/ts_build/src/processes/managedProcessShim.d.ts +1 -0
- package/ts_build/src/processes/managedProcessShim.js +161 -0
- package/ts_build/src/processes/managedProcessShim.js.map +1 -0
- package/ts_build/src/services/AgentService.js +18 -2
- package/ts_build/src/services/AgentService.js.map +1 -1
- package/ts_build/src/services/AgentSyncFs.d.ts +3 -0
- package/ts_build/src/services/AgentSyncFs.js +68 -16
- package/ts_build/src/services/AgentSyncFs.js.map +1 -1
- package/ts_build/src/services/AgentSyncKnowhowWeb.d.ts +2 -0
- package/ts_build/src/services/AgentSyncKnowhowWeb.js +28 -6
- package/ts_build/src/services/AgentSyncKnowhowWeb.js.map +1 -1
- package/ts_build/src/services/BehaviorsService.js +12 -2
- package/ts_build/src/services/BehaviorsService.js.map +1 -1
- package/ts_build/src/services/DockerService.js +20 -8
- package/ts_build/src/services/DockerService.js.map +1 -1
- package/ts_build/src/services/EmbeddingService.js +16 -2
- package/ts_build/src/services/EmbeddingService.js.map +1 -1
- package/ts_build/src/services/EmbeddingsService.js +12 -2
- package/ts_build/src/services/EmbeddingsService.js.map +1 -1
- package/ts_build/src/services/ExtensionsService.d.ts +10 -0
- package/ts_build/src/services/ExtensionsService.js +17 -0
- package/ts_build/src/services/ExtensionsService.js.map +1 -0
- package/ts_build/src/services/KnowhowClient.d.ts +7 -2
- package/ts_build/src/services/KnowhowClient.js +108 -10
- package/ts_build/src/services/KnowhowClient.js.map +1 -1
- package/ts_build/src/services/LazyToolsService.d.ts +2 -0
- package/ts_build/src/services/LazyToolsService.js +26 -9
- package/ts_build/src/services/LazyToolsService.js.map +1 -1
- package/ts_build/src/services/Mcp.js +12 -2
- package/ts_build/src/services/Mcp.js.map +1 -1
- package/ts_build/src/services/McpServer.js +17 -2
- package/ts_build/src/services/McpServer.js.map +1 -1
- package/ts_build/src/services/MessageProcessor.js +16 -2
- package/ts_build/src/services/MessageProcessor.js.map +1 -1
- package/ts_build/src/services/MinimalToolsService.js +16 -2
- package/ts_build/src/services/MinimalToolsService.js.map +1 -1
- package/ts_build/src/services/SessionManager.js +19 -2
- package/ts_build/src/services/SessionManager.js.map +1 -1
- package/ts_build/src/services/SkillsService.js +16 -2
- package/ts_build/src/services/SkillsService.js.map +1 -1
- package/ts_build/src/services/SyncedAgentWatcher.js +16 -2
- package/ts_build/src/services/SyncedAgentWatcher.js.map +1 -1
- package/ts_build/src/services/SyncerService.d.ts +1 -0
- package/ts_build/src/services/SyncerService.js +27 -5
- package/ts_build/src/services/SyncerService.js.map +1 -1
- package/ts_build/src/services/TaskRegistry.js +12 -2
- package/ts_build/src/services/TaskRegistry.js.map +1 -1
- package/ts_build/src/services/Tools.d.ts +1 -0
- package/ts_build/src/services/Tools.js +19 -2
- package/ts_build/src/services/Tools.js.map +1 -1
- package/ts_build/src/services/index.d.ts +5 -0
- package/ts_build/src/services/index.js +7 -2
- package/ts_build/src/services/index.js.map +1 -1
- package/ts_build/src/services/modules/index.d.ts +4 -1
- package/ts_build/src/services/modules/index.js +6 -1
- package/ts_build/src/services/modules/index.js.map +1 -1
- package/ts_build/src/services/modules/types.d.ts +3 -0
- package/ts_build/src/types.d.ts +1 -0
- package/ts_build/src/types.js.map +1 -1
- package/ts_build/src/util/Trace.d.ts +1 -3
- package/ts_build/src/utils/http.d.ts +6 -2
- package/ts_build/src/utils/http.js +8 -2
- package/ts_build/src/utils/http.js.map +1 -1
- package/ts_build/tests/unit/agents/historyRollback.test.d.ts +1 -0
- package/ts_build/tests/unit/agents/historyRollback.test.js +42 -0
- package/ts_build/tests/unit/agents/historyRollback.test.js.map +1 -0
- package/ts_build/tests/unit/auth/keyAuth.test.d.ts +1 -0
- package/ts_build/tests/unit/auth/keyAuth.test.js +77 -0
- package/ts_build/tests/unit/auth/keyAuth.test.js.map +1 -0
- package/ts_build/tests/unit/auth/keyManager.test.d.ts +1 -0
- package/ts_build/tests/unit/auth/keyManager.test.js +52 -0
- package/ts_build/tests/unit/auth/keyManager.test.js.map +1 -0
- package/ts_build/tests/unit/chat/ToolCommandModule.test.d.ts +1 -0
- package/ts_build/tests/unit/chat/ToolCommandModule.test.js +61 -0
- package/ts_build/tests/unit/chat/ToolCommandModule.test.js.map +1 -0
- package/ts_build/tests/unit/chat/historyCommandArgs.test.d.ts +1 -0
- package/ts_build/tests/unit/chat/historyCommandArgs.test.js +29 -0
- package/ts_build/tests/unit/chat/historyCommandArgs.test.js.map +1 -0
- package/ts_build/tests/unit/commands/agents.test.d.ts +1 -0
- package/ts_build/tests/unit/commands/agents.test.js +119 -0
- package/ts_build/tests/unit/commands/agents.test.js.map +1 -0
- package/ts_build/tests/unit/login.test.d.ts +1 -0
- package/ts_build/tests/unit/login.test.js +97 -0
- package/ts_build/tests/unit/login.test.js.map +1 -0
- package/ts_build/tests/unit/services/AgentSyncKnowhowWeb.test.d.ts +1 -0
- package/ts_build/tests/unit/services/AgentSyncKnowhowWeb.test.js +32 -0
- package/ts_build/tests/unit/services/AgentSyncKnowhowWeb.test.js.map +1 -0
- package/ts_build/tests/unit/services/LazyToolsService.test.d.ts +1 -0
- package/ts_build/tests/unit/services/LazyToolsService.test.js +47 -0
- package/ts_build/tests/unit/services/LazyToolsService.test.js.map +1 -0
- package/ts_build/tests/unit/services/SessionManager.test.d.ts +1 -0
- package/ts_build/tests/unit/services/SessionManager.test.js +72 -0
- package/ts_build/tests/unit/services/SessionManager.test.js.map +1 -0
- package/ts_build/tests/unit/services/SyncerService.test.d.ts +1 -0
- package/ts_build/tests/unit/services/SyncerService.test.js +40 -0
- package/ts_build/tests/unit/services/SyncerService.test.js.map +1 -0
- package/ts_build/tests/unit/util/Trace.test.d.ts +1 -0
- package/ts_build/tests/unit/util/Trace.test.js +107 -0
- package/ts_build/tests/unit/util/Trace.test.js.map +1 -0
- package/ts_build/tests/unit/utils/http.test.d.ts +1 -0
- package/ts_build/tests/unit/utils/http.test.js +69 -0
- package/ts_build/tests/unit/utils/http.test.js.map +1 -0
|
@@ -5,11 +5,13 @@
|
|
|
5
5
|
* Command semantics:
|
|
6
6
|
* /attach <taskId> - Attach to a RUNNING session (in-memory, filesystem, or web).
|
|
7
7
|
* If the task is completed, the user is told to use /resume instead.
|
|
8
|
-
* /resume <taskId>
|
|
8
|
+
* /resume <taskId> [--rollback N] - Continue the same saved task.
|
|
9
|
+
* /fork <taskId> [--rollback N] - Start a new task from saved history.
|
|
9
10
|
* /sessions - List sessions that can be attached to or resumed.
|
|
10
11
|
* /logs [N] - Show the last N messages from the currently attached agent.
|
|
11
12
|
*/
|
|
12
13
|
import { BaseChatModule } from "./BaseChatModule";
|
|
14
|
+
import { TraceAll } from "../../util/Trace";
|
|
13
15
|
import { ChatCommand, ChatMode, ChatContext } from "../types";
|
|
14
16
|
import { AgentModule } from "./AgentModule";
|
|
15
17
|
import {
|
|
@@ -24,6 +26,33 @@ import { Marked } from "../../utils/index";
|
|
|
24
26
|
import * as fs from "fs";
|
|
25
27
|
import * as path from "path";
|
|
26
28
|
|
|
29
|
+
export function parseHistoryCommandArgs(args: string[]): {
|
|
30
|
+
id?: string;
|
|
31
|
+
rollback: number;
|
|
32
|
+
showAll: boolean;
|
|
33
|
+
} {
|
|
34
|
+
let id: string | undefined;
|
|
35
|
+
let rollback = 0;
|
|
36
|
+
let showAll = false;
|
|
37
|
+
for (let i = 0; i < args.length; i++) {
|
|
38
|
+
if (args[i] === "--all") {
|
|
39
|
+
showAll = true;
|
|
40
|
+
} else if (args[i] === "--rollback") {
|
|
41
|
+
const value = args[++i];
|
|
42
|
+
rollback = Number(value);
|
|
43
|
+
if (!Number.isInteger(rollback) || rollback < 0) {
|
|
44
|
+
throw new Error("--rollback must be a non-negative integer");
|
|
45
|
+
}
|
|
46
|
+
} else if (!id) {
|
|
47
|
+
id = args[i];
|
|
48
|
+
} else {
|
|
49
|
+
throw new Error(`Unexpected argument: ${args[i]}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { id, rollback, showAll };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@TraceAll()
|
|
27
56
|
export class SessionsModule extends BaseChatModule {
|
|
28
57
|
name = "sessions";
|
|
29
58
|
description = "Session and attachment management";
|
|
@@ -49,6 +78,12 @@ export class SessionsModule extends BaseChatModule {
|
|
|
49
78
|
"Resume a completed/saved session with optional additional context",
|
|
50
79
|
handler: this.handleResumeCommand.bind(this),
|
|
51
80
|
},
|
|
81
|
+
{
|
|
82
|
+
name: "fork",
|
|
83
|
+
description:
|
|
84
|
+
"Fork a saved session into a new task; use --rollback N to discard recent agent interactions",
|
|
85
|
+
handler: this.handleForkCommand.bind(this),
|
|
86
|
+
},
|
|
52
87
|
{
|
|
53
88
|
name: "sessions",
|
|
54
89
|
description:
|
|
@@ -305,10 +340,17 @@ export class SessionsModule extends BaseChatModule {
|
|
|
305
340
|
|
|
306
341
|
async handleResumeCommand(args: string[]): Promise<void> {
|
|
307
342
|
const sessionManager = this.agentModule.getSessionManager();
|
|
343
|
+
let parsed;
|
|
344
|
+
try {
|
|
345
|
+
parsed = parseHistoryCommandArgs(args);
|
|
346
|
+
} catch (error: any) {
|
|
347
|
+
console.error(`Usage: /resume <taskId> [--rollback N] [--all]\n${error.message}`);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
308
350
|
|
|
309
|
-
if (
|
|
351
|
+
if (!parsed.id) {
|
|
310
352
|
// Interactive: show saved sessions for selection
|
|
311
|
-
const showAll =
|
|
353
|
+
const showAll = parsed.showAll;
|
|
312
354
|
const allSessions = sessionManager.listAvailableSessions();
|
|
313
355
|
const savedSessions = showAll ? allSessions : allSessions.slice(0, 10);
|
|
314
356
|
if (savedSessions.length === 0) {
|
|
@@ -328,18 +370,32 @@ export class SessionsModule extends BaseChatModule {
|
|
|
328
370
|
);
|
|
329
371
|
|
|
330
372
|
if (selectedId) {
|
|
331
|
-
await this.resumeById(selectedId);
|
|
373
|
+
await this.resumeById(selectedId, parsed.rollback);
|
|
332
374
|
}
|
|
333
375
|
return;
|
|
334
376
|
}
|
|
335
377
|
|
|
336
|
-
await this.resumeById(
|
|
378
|
+
await this.resumeById(parsed.id, parsed.rollback);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
async handleForkCommand(args: string[]): Promise<void> {
|
|
382
|
+
let parsed;
|
|
383
|
+
try {
|
|
384
|
+
parsed = parseHistoryCommandArgs(args);
|
|
385
|
+
} catch (error: any) {
|
|
386
|
+
console.error(`Usage: /fork <taskId> [--rollback N]\n${error.message}`);
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
if (!parsed.id) {
|
|
390
|
+
console.error("Usage: /fork <taskId> [--rollback N]");
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
await this.resumeById(parsed.id, parsed.rollback, true);
|
|
337
394
|
}
|
|
338
395
|
|
|
339
|
-
private async resumeById(id: string): Promise<void> {
|
|
396
|
+
private async resumeById(id: string, rollback = 0, fork = false): Promise<void> {
|
|
340
397
|
const sessionManager = this.agentModule.getSessionManager();
|
|
341
398
|
|
|
342
|
-
// Check saved sessions first
|
|
343
399
|
try {
|
|
344
400
|
const session = sessionManager.loadSession(id);
|
|
345
401
|
if (session) {
|
|
@@ -349,34 +405,46 @@ export class SessionsModule extends BaseChatModule {
|
|
|
349
405
|
console.log(` Status : ${session.status}`);
|
|
350
406
|
|
|
351
407
|
const additionalContext = await this.chatService?.getInput(
|
|
352
|
-
|
|
353
|
-
);
|
|
354
|
-
await this.agentModule.resumeSession(
|
|
355
|
-
id,
|
|
356
|
-
additionalContext?.trim() || undefined
|
|
408
|
+
`Add any additional context for ${fork ? "forking" : "resuming"} this session (or press Enter to skip): `
|
|
357
409
|
);
|
|
410
|
+
if (fork) {
|
|
411
|
+
const result = await this.agentModule.resumeFromMessages({
|
|
412
|
+
agentName: session.agentName,
|
|
413
|
+
threads: session.threads,
|
|
414
|
+
input: additionalContext?.trim() || session.initialInput,
|
|
415
|
+
interactive: true,
|
|
416
|
+
rollback,
|
|
417
|
+
fork: true,
|
|
418
|
+
model: session.model,
|
|
419
|
+
provider: session.provider,
|
|
420
|
+
reasoningEffort: session.reasoningEffort,
|
|
421
|
+
summarizeReasoning: session.summarizeReasoning,
|
|
422
|
+
enabledTools: session.enabledTools,
|
|
423
|
+
});
|
|
424
|
+
console.log(`🌿 Forked ${id} into new task ${result.taskId}`);
|
|
425
|
+
} else {
|
|
426
|
+
await this.agentModule.resumeSession(
|
|
427
|
+
id,
|
|
428
|
+
additionalContext?.trim() || undefined,
|
|
429
|
+
rollback
|
|
430
|
+
);
|
|
431
|
+
}
|
|
358
432
|
return;
|
|
359
433
|
}
|
|
360
|
-
} catch {
|
|
434
|
+
} catch (e: any) {
|
|
435
|
+
if (e?.message?.includes("rollback")) throw e;
|
|
361
436
|
// not found as a saved session
|
|
362
437
|
}
|
|
363
438
|
|
|
364
|
-
// Check filesystem agent (may have metadata with threads)
|
|
365
439
|
const fsAgentPath = path.join(".knowhow", "processes", "agents", id);
|
|
366
440
|
if (fs.existsSync(fsAgentPath)) {
|
|
367
|
-
// Try to load threads from metadata.json and resume
|
|
368
441
|
const metadataPath = path.join(fsAgentPath, "metadata.json");
|
|
369
442
|
if (fs.existsSync(metadataPath)) {
|
|
370
443
|
try {
|
|
371
|
-
const
|
|
372
|
-
const metadata = JSON.parse(raw);
|
|
444
|
+
const metadata = JSON.parse(fs.readFileSync(metadataPath, "utf-8"));
|
|
373
445
|
const threads: any[] = metadata.threads || [];
|
|
374
446
|
const agentName = metadata.agentName || "Developer";
|
|
375
|
-
|
|
376
|
-
// Try to get initialInput from the saved session file (more complete)
|
|
377
|
-
// since metadata.json doesn't always store it
|
|
378
|
-
const savedSession = sessionManager.loadSession(id);
|
|
379
|
-
const initialInput = savedSession?.initialInput || metadata.initialInput || metadata.prompt || "";
|
|
447
|
+
const initialInput = metadata.initialInput || metadata.prompt || "";
|
|
380
448
|
|
|
381
449
|
console.log(`\n📋 Found task in filesystem: ${id}`);
|
|
382
450
|
console.log(` Agent : ${agentName}`);
|
|
@@ -384,30 +452,33 @@ export class SessionsModule extends BaseChatModule {
|
|
|
384
452
|
console.log(` Status : ${metadata.status || "unknown"}`);
|
|
385
453
|
|
|
386
454
|
const additionalContext = await this.chatService?.getInput(
|
|
387
|
-
|
|
455
|
+
`Add any additional context for ${fork ? "forking" : "resuming"} this session (or press Enter to skip): `
|
|
388
456
|
);
|
|
389
|
-
|
|
390
|
-
// Normalize threads: if flat Message[] (old buggy format), wrap in array
|
|
391
457
|
const normalizedThreads = threads.length > 0 && !Array.isArray(threads[0])
|
|
392
458
|
? [threads]
|
|
393
459
|
: threads;
|
|
394
|
-
|
|
395
|
-
await this.agentModule.resumeFromMessages({
|
|
460
|
+
const result = await this.agentModule.resumeFromMessages({
|
|
396
461
|
agentName,
|
|
397
|
-
|
|
462
|
+
remoteTaskId: fork
|
|
463
|
+
? undefined
|
|
464
|
+
: metadata.remoteTaskId || metadata.knowhowTaskId,
|
|
465
|
+
taskId: fork ? undefined : id,
|
|
398
466
|
threads: normalizedThreads,
|
|
399
|
-
input: additionalContext?.trim() || initialInput
|
|
467
|
+
input: additionalContext?.trim() || initialInput,
|
|
400
468
|
interactive: true,
|
|
401
|
-
|
|
402
|
-
|
|
469
|
+
rollback,
|
|
470
|
+
fork,
|
|
403
471
|
model: metadata.model,
|
|
404
472
|
provider: metadata.provider,
|
|
405
473
|
reasoningEffort: metadata.reasoningEffort,
|
|
406
474
|
summarizeReasoning: metadata.summarizeReasoning,
|
|
475
|
+
enabledTools: metadata.enabledTools,
|
|
407
476
|
});
|
|
477
|
+
if (fork) console.log(`🌿 Forked ${id} into new task ${result.taskId}`);
|
|
408
478
|
return;
|
|
409
479
|
} catch (e: any) {
|
|
410
480
|
console.error(`⚠️ Failed to load metadata for task ${id}: ${e.message}`);
|
|
481
|
+
return;
|
|
411
482
|
}
|
|
412
483
|
}
|
|
413
484
|
console.log(
|
|
@@ -417,9 +488,7 @@ export class SessionsModule extends BaseChatModule {
|
|
|
417
488
|
return;
|
|
418
489
|
}
|
|
419
490
|
|
|
420
|
-
console.log(
|
|
421
|
-
`Session "${id}" not found. Use /sessions to list available sessions.`
|
|
422
|
-
);
|
|
491
|
+
console.log(`Session "${id}" not found. Use /sessions to list available sessions.`);
|
|
423
492
|
}
|
|
424
493
|
|
|
425
494
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { services } from "../../services";
|
|
2
|
+
import { TraceAll } from "../../util/Trace";
|
|
2
3
|
import { login } from "../../login";
|
|
3
4
|
import { ask } from "../../utils";
|
|
4
5
|
import { CliChatService } from "../CliChatService";
|
|
@@ -6,6 +7,7 @@ import { ChatCommand, ChatMode } from "../types";
|
|
|
6
7
|
import { AgentModule } from "./AgentModule";
|
|
7
8
|
import { BaseChatModule } from "./BaseChatModule";
|
|
8
9
|
|
|
10
|
+
@TraceAll()
|
|
9
11
|
export class SetupModule extends BaseChatModule {
|
|
10
12
|
name = "setup";
|
|
11
13
|
description = "Setup commands";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseChatModule } from "./BaseChatModule";
|
|
2
|
+
import { TraceAll } from "../../util/Trace";
|
|
2
3
|
import { ChatCommand, ChatContext, CommandResult } from "../types";
|
|
3
4
|
import { execSync } from "child_process";
|
|
4
5
|
|
|
@@ -7,6 +8,7 @@ import { execSync } from "child_process";
|
|
|
7
8
|
* /! - Execute command and display output in console (interactive if needed)
|
|
8
9
|
* /!! - Execute command and send output to the AI agent
|
|
9
10
|
*/
|
|
11
|
+
@TraceAll()
|
|
10
12
|
export class ShellCommandModule extends BaseChatModule {
|
|
11
13
|
name = "shell-command";
|
|
12
14
|
description = "Execute shell commands with /! and /!!";
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { BaseChatModule } from "./BaseChatModule";
|
|
2
|
+
import { TraceAll } from "../../util/Trace";
|
|
2
3
|
import { CliChatService } from "../CliChatService";
|
|
3
4
|
import { ChatCommand, ChatMode, ChatContext } from "../types";
|
|
4
5
|
import { ask } from "../../utils";
|
|
5
6
|
import { services } from "../../services";
|
|
6
7
|
import { Models } from "../../types";
|
|
7
8
|
|
|
9
|
+
@TraceAll()
|
|
8
10
|
export class SystemModule extends BaseChatModule {
|
|
9
11
|
name = "system";
|
|
10
12
|
description = "System commands for model, provider, debug, and clear";
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { ToolCall } from "../../clients/types";
|
|
2
|
+
import { services } from "../../services";
|
|
3
|
+
import { BaseChatModule } from "./BaseChatModule";
|
|
4
|
+
import { ChatCommand, ChatContext, CommandResult } from "../types";
|
|
5
|
+
|
|
6
|
+
/** Execute registered tools directly from interactive chat. */
|
|
7
|
+
export class ToolCommandModule extends BaseChatModule {
|
|
8
|
+
name = "tool-command";
|
|
9
|
+
description = "Execute a tool with /tool";
|
|
10
|
+
|
|
11
|
+
public getCommands(): ChatCommand[] {
|
|
12
|
+
return [
|
|
13
|
+
{
|
|
14
|
+
name: "tool",
|
|
15
|
+
description: "Execute a tool call from JSON",
|
|
16
|
+
handler: (args: string[]) => this.handleToolCommand(args),
|
|
17
|
+
},
|
|
18
|
+
];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
private async handleToolCommand(args: string[]): Promise<CommandResult> {
|
|
22
|
+
const input = args.join(" ").trim();
|
|
23
|
+
if (!input) {
|
|
24
|
+
console.log('Usage: /tool {"name":"toolName","arguments":{"key":"value"}}');
|
|
25
|
+
return { handled: true };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let toolCall: ToolCall;
|
|
29
|
+
try {
|
|
30
|
+
toolCall = this.parseToolCall(input);
|
|
31
|
+
} catch (error: any) {
|
|
32
|
+
console.error(`Invalid tool call JSON: ${error.message}`);
|
|
33
|
+
return { handled: true };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const tools = this.chatService.getTools() || services().Tools;
|
|
37
|
+
if (!tools) {
|
|
38
|
+
console.error("Tool execution failed: no tool service is available");
|
|
39
|
+
return { handled: true };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const context = this.chatService.getContext();
|
|
44
|
+
const result = await tools.callTool(
|
|
45
|
+
toolCall,
|
|
46
|
+
tools.getFunctionNames(),
|
|
47
|
+
{
|
|
48
|
+
caller: context.selectedAgent,
|
|
49
|
+
taskId: context.activeAgentTaskId,
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const toolError = result.toolMessages?.find(
|
|
54
|
+
(message: any) => message.name === "error"
|
|
55
|
+
);
|
|
56
|
+
if (toolError) {
|
|
57
|
+
console.error(`Tool execution failed: ${toolError.content}`);
|
|
58
|
+
} else {
|
|
59
|
+
const output = result.functionResp;
|
|
60
|
+
console.log(
|
|
61
|
+
typeof output === "object"
|
|
62
|
+
? JSON.stringify(output, null, 2)
|
|
63
|
+
: String(output)
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
} catch (error: any) {
|
|
67
|
+
console.error(`Tool execution failed: ${error.message || String(error)}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return { handled: true };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private parseToolCall(input: string): ToolCall {
|
|
74
|
+
const parsed = JSON.parse(input);
|
|
75
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
76
|
+
throw new Error("expected a JSON object");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const fn = parsed.function || parsed;
|
|
80
|
+
if (!fn || typeof fn.name !== "string" || !fn.name.trim()) {
|
|
81
|
+
throw new Error('expected a non-empty "name" (or "function.name")');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const args = fn.arguments === undefined ? {} : fn.arguments;
|
|
85
|
+
if (typeof args !== "string" && (args === null || typeof args !== "object")) {
|
|
86
|
+
throw new Error('"arguments" must be a JSON object, array, or JSON string');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
id: typeof parsed.id === "string" ? parsed.id : `chat_tool_${Date.now()}`,
|
|
91
|
+
type: "function",
|
|
92
|
+
function: {
|
|
93
|
+
name: fn.name,
|
|
94
|
+
arguments: typeof args === "string" ? args : JSON.stringify(args),
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async handleInput(input: string, context: ChatContext): Promise<boolean> {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -4,4 +4,5 @@ export { AgentModule } from './AgentModule';
|
|
|
4
4
|
export { VoiceModule } from './VoiceModule';
|
|
5
5
|
export { InternalChatModule } from './InternalChatModule';
|
|
6
6
|
export { ShellCommandModule } from './ShellCommandModule';
|
|
7
|
+
export { ToolCommandModule } from './ToolCommandModule';
|
|
7
8
|
export { RendererModule } from './RendererModule';
|
package/src/chat/types.ts
CHANGED
|
@@ -45,7 +45,7 @@ export interface CommandResult {
|
|
|
45
45
|
export interface ChatCommand {
|
|
46
46
|
name: string;
|
|
47
47
|
description: string;
|
|
48
|
-
handler: (args: string[]) => Promise<void | CommandResult>;
|
|
48
|
+
handler: (args: string[], chatService?: ChatService) => Promise<void | CommandResult>;
|
|
49
49
|
modes?: string[]; // Commands can specify which modes they're available in
|
|
50
50
|
}
|
|
51
51
|
|
|
@@ -104,6 +104,7 @@ export interface TaskInfo {
|
|
|
104
104
|
provider?: string;
|
|
105
105
|
reasoningEffort?: ReasoningEffort;
|
|
106
106
|
summarizeReasoning?: boolean;
|
|
107
|
+
enabledTools?: string[];
|
|
107
108
|
}
|
|
108
109
|
|
|
109
110
|
export interface ChatSession {
|
|
@@ -126,6 +127,7 @@ export interface ChatSession {
|
|
|
126
127
|
provider?: string;
|
|
127
128
|
reasoningEffort?: ReasoningEffort;
|
|
128
129
|
summarizeReasoning?: boolean;
|
|
130
|
+
enabledTools?: string[];
|
|
129
131
|
}
|
|
130
132
|
|
|
131
133
|
export interface ChatHistory {
|
package/src/cli.ts
CHANGED
|
@@ -62,6 +62,7 @@ import { addSkillsCommand } from "./commands/skills";
|
|
|
62
62
|
import { addAgentsCommand } from "./commands/agents";
|
|
63
63
|
import { addHashCommand } from "./commands/hash";
|
|
64
64
|
import { addSandboxCommand } from "./commands/sandbox";
|
|
65
|
+
import { addProcessesCommand } from "./commands/processes";
|
|
65
66
|
|
|
66
67
|
// Handle unhandled promise rejections gracefully — particularly from MCP SDK
|
|
67
68
|
// which fires errors via event emitters that can bypass Promise.allSettled.
|
|
@@ -128,18 +129,24 @@ async function main() {
|
|
|
128
129
|
addReplayCommand(program);
|
|
129
130
|
addBehaviorsCommand(program);
|
|
130
131
|
addSkillsCommand(program);
|
|
131
|
-
addAgentsCommand(program);
|
|
132
|
+
addAgentsCommand(program, getChatService);
|
|
132
133
|
addHashCommand(program);
|
|
133
134
|
addSandboxCommand(program);
|
|
135
|
+
addProcessesCommand(program);
|
|
134
136
|
|
|
135
137
|
// Load global modules early (before parse) so they can register CLI subcommands.
|
|
136
138
|
// We pass only the Program in context — no services are spun up at this stage.
|
|
137
139
|
// Each module's command action is responsible for calling setupServices() as needed.
|
|
138
140
|
try {
|
|
139
141
|
const globalConfig = await getGlobalConfig();
|
|
142
|
+
const globalModules = [...new Set(globalConfig.modules || [])];
|
|
143
|
+
const localModules = [...new Set(config.modules || [])];
|
|
144
|
+
// Local modules take precedence: if a module appears in both global and
|
|
145
|
+
// local configs, use the local version so it resolves against local
|
|
146
|
+
// node_modules first. This prevents duplicate command registration errors.
|
|
140
147
|
const allModulePaths = [
|
|
141
|
-
...(
|
|
142
|
-
...
|
|
148
|
+
...globalModules.filter((m) => !localModules.includes(m)),
|
|
149
|
+
...localModules,
|
|
143
150
|
];
|
|
144
151
|
if (allModulePaths.length) {
|
|
145
152
|
const earlyModulesService = new ModulesService();
|
package/src/clients/http.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import http from "../utils/http";
|
|
1
|
+
import http, { HTTP_UNAUTHORIZED_HANDLER, RefreshableHeaders } from "../utils/http";
|
|
2
2
|
import {
|
|
3
3
|
GenericClient,
|
|
4
4
|
CompletionOptions,
|
|
@@ -17,16 +17,72 @@ export interface HttpClientOptions {
|
|
|
17
17
|
extra_body?: Record<string, any>;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Optional callback that, when set, is called whenever a 401 is received
|
|
22
|
+
* (reactive refresh) or whenever `needsRefresh()` returns true before a
|
|
23
|
+
* request (proactive refresh). Override this in a subclass or set it
|
|
24
|
+
* directly on an instance:
|
|
25
|
+
*
|
|
26
|
+
* client.refreshToken = async () => { const newJwt = await ...; client.setJwt(newJwt); };
|
|
27
|
+
*/
|
|
28
|
+
export type RefreshTokenFn = () => Promise<void>;
|
|
29
|
+
|
|
20
30
|
export class HttpClient implements GenericClient {
|
|
21
31
|
/** Timeout in milliseconds for HTTP requests. Default: 30000 (30s). Use 0 to disable. */
|
|
22
32
|
private timeout: number;
|
|
23
|
-
private headers:
|
|
33
|
+
private headers: RefreshableHeaders;
|
|
24
34
|
private extra_body: Record<string, any>;
|
|
25
35
|
/** Optional pricing table: model id → per-million-token prices */
|
|
26
36
|
private pricingMap: Record<string, ModelPricing> = {};
|
|
27
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Override this to provide automatic token refresh. Called reactively on
|
|
40
|
+
* 401 responses (via HTTP_UNAUTHORIZED_HANDLER) and proactively before
|
|
41
|
+
* each request when `needsRefresh()` returns true.
|
|
42
|
+
*
|
|
43
|
+
* The implementation should obtain a new token and call `this.setJwt()`
|
|
44
|
+
* (or `this.setKey()`) before returning.
|
|
45
|
+
*/
|
|
46
|
+
refreshToken: RefreshTokenFn | undefined = undefined;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Override this to provide proactive expiry detection. When it returns
|
|
50
|
+
* `true`, `refreshToken()` is called before the next outgoing request.
|
|
51
|
+
* The default implementation decodes the JWT `exp` claim (< 5 min window).
|
|
52
|
+
*/
|
|
53
|
+
needsRefresh(): boolean {
|
|
54
|
+
const authHeader = (this.headers as Record<string, string>)["Authorization"];
|
|
55
|
+
if (!authHeader) return false;
|
|
56
|
+
const token = authHeader.startsWith("Bearer ") ? authHeader.slice(7) : authHeader;
|
|
57
|
+
try {
|
|
58
|
+
const parts = token.split(".");
|
|
59
|
+
if (parts.length !== 3) return false;
|
|
60
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
|
|
61
|
+
return typeof payload.exp === "number" && payload.exp * 1000 - Date.now() < 5 * 60 * 1000;
|
|
62
|
+
} catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Call before each outgoing request to proactively refresh an expiring
|
|
69
|
+
* token. No-ops when no `refreshToken` hook is set.
|
|
70
|
+
*/
|
|
71
|
+
private async refreshIfNeeded(): Promise<void> {
|
|
72
|
+
if (this.refreshToken && this.needsRefresh()) {
|
|
73
|
+
await this.refreshToken();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
28
77
|
constructor(private baseUrl: string, options: HttpClientOptions = {}) {
|
|
29
78
|
this.headers = options.headers ?? {};
|
|
79
|
+
// Wire the reactive 401 handler so the low-level http util can retry once
|
|
80
|
+
// after a token refresh without callers needing to do anything extra.
|
|
81
|
+
Object.defineProperty(this.headers, HTTP_UNAUTHORIZED_HANDLER, {
|
|
82
|
+
enumerable: false,
|
|
83
|
+
configurable: true,
|
|
84
|
+
get: () => this.refreshToken ? () => this.refreshToken!() : undefined,
|
|
85
|
+
});
|
|
30
86
|
this.timeout = options.timeout ?? 30000;
|
|
31
87
|
this.extra_body = options.extra_body ?? {};
|
|
32
88
|
}
|
|
@@ -69,10 +125,8 @@ export class HttpClient implements GenericClient {
|
|
|
69
125
|
}
|
|
70
126
|
|
|
71
127
|
setJwt(jwt: string) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
Authorization: `Bearer ${jwt}`,
|
|
75
|
-
};
|
|
128
|
+
// Mutate in-place to preserve the HTTP_UNAUTHORIZED_HANDLER symbol property.
|
|
129
|
+
this.headers.Authorization = `Bearer ${jwt}`;
|
|
76
130
|
}
|
|
77
131
|
|
|
78
132
|
setBaseUrl(baseUrl: string) {
|
|
@@ -163,7 +217,8 @@ export class HttpClient implements GenericClient {
|
|
|
163
217
|
if (options.timeout !== undefined) this.timeout = options.timeout;
|
|
164
218
|
if (options.extra_body !== undefined) this.extra_body = options.extra_body;
|
|
165
219
|
if (options.headers) {
|
|
166
|
-
|
|
220
|
+
// Mutate in-place to preserve the HTTP_UNAUTHORIZED_HANDLER symbol property.
|
|
221
|
+
Object.assign(this.headers, options.headers);
|
|
167
222
|
}
|
|
168
223
|
}
|
|
169
224
|
|
|
@@ -183,6 +238,7 @@ export class HttpClient implements GenericClient {
|
|
|
183
238
|
async createChatCompletion(
|
|
184
239
|
options: CompletionOptions
|
|
185
240
|
): Promise<CompletionResponse> {
|
|
241
|
+
await this.refreshIfNeeded();
|
|
186
242
|
return this.withRetry(async () => {
|
|
187
243
|
const body = {
|
|
188
244
|
...options,
|
|
@@ -232,6 +288,7 @@ export class HttpClient implements GenericClient {
|
|
|
232
288
|
async *createChatCompletionStream(
|
|
233
289
|
options: CompletionOptions
|
|
234
290
|
): AsyncGenerator<StreamChunk> {
|
|
291
|
+
await this.refreshIfNeeded();
|
|
235
292
|
const body = {
|
|
236
293
|
...options,
|
|
237
294
|
model: options.model,
|
|
@@ -316,6 +373,7 @@ export class HttpClient implements GenericClient {
|
|
|
316
373
|
options: CompletionOptions,
|
|
317
374
|
store = false
|
|
318
375
|
): Promise<CompletionResponse> {
|
|
376
|
+
await this.refreshIfNeeded();
|
|
319
377
|
return this.withRetry(async () => {
|
|
320
378
|
// Extract system messages as instructions
|
|
321
379
|
const systemMessages = options.messages.filter((m) => m.role === "system");
|
|
@@ -484,6 +542,7 @@ export class HttpClient implements GenericClient {
|
|
|
484
542
|
}
|
|
485
543
|
|
|
486
544
|
async createEmbedding(options: EmbeddingOptions): Promise<EmbeddingResponse> {
|
|
545
|
+
await this.refreshIfNeeded();
|
|
487
546
|
return this.withRetry(async () => {
|
|
488
547
|
const response = await http.post(
|
|
489
548
|
`${this.baseUrl}/v1/embeddings`,
|
|
@@ -511,6 +570,7 @@ export class HttpClient implements GenericClient {
|
|
|
511
570
|
}
|
|
512
571
|
|
|
513
572
|
async getModels(type = "all") {
|
|
573
|
+
await this.refreshIfNeeded();
|
|
514
574
|
return this.withRetry(async () => {
|
|
515
575
|
const response = await http.get(`${this.baseUrl}/v1/models?type=${type}`, {
|
|
516
576
|
headers: this.headers as Record<string, string>,
|
package/src/clients/index.ts
CHANGED
|
@@ -59,6 +59,7 @@ import { GenericLlamaClient } from "./llama";
|
|
|
59
59
|
import { GenericFireworksClient } from "./fireworks";
|
|
60
60
|
import { GenericMetaClient } from "./meta";
|
|
61
61
|
import { GenericQwenClient } from "./qwen";
|
|
62
|
+
import { TraceAll } from "../util/Trace";
|
|
62
63
|
export {
|
|
63
64
|
OpenAiTextPricing,
|
|
64
65
|
AnthropicTextPricing,
|
|
@@ -139,6 +140,7 @@ const DEFAULT_PROVIDERS: ModelProvider[] = [
|
|
|
139
140
|
{ provider: "qwen", envKey: "QWEN_CLOUD_API_KEY" },
|
|
140
141
|
];
|
|
141
142
|
|
|
143
|
+
@TraceAll()
|
|
142
144
|
export class AIClient {
|
|
143
145
|
clients: Record<string, GenericClient> = {};
|
|
144
146
|
|
|
@@ -526,12 +528,14 @@ export class AIClient {
|
|
|
526
528
|
}
|
|
527
529
|
|
|
528
530
|
providerHasModel(provider: string, model: string): boolean {
|
|
531
|
+
if (!provider) return false;
|
|
529
532
|
const models = this.clientModels[provider];
|
|
530
533
|
if (!models) return false;
|
|
531
534
|
return models.includes(model);
|
|
532
535
|
}
|
|
533
536
|
|
|
534
537
|
findModel(modelPrefix: string) {
|
|
538
|
+
if (!modelPrefix) return undefined;
|
|
535
539
|
for (const provider of Object.keys(this.clientModels)) {
|
|
536
540
|
const models = this.clientModels[provider] as string[];
|
|
537
541
|
const foundModel = models.find((m) => m.startsWith(modelPrefix));
|
package/src/commands/agent.ts
CHANGED
|
@@ -55,7 +55,7 @@ export function addAgentCommand(program: Command, getChatService: () => any): vo
|
|
|
55
55
|
"AI provider (openai, anthropic, google, xai)"
|
|
56
56
|
)
|
|
57
57
|
.option("--model <model>", "Specific model for the provider")
|
|
58
|
-
.option("--agent-name <name>", "Which agent to use
|
|
58
|
+
.option("--agent-name <name>", "Which agent to use (default: Patcher)")
|
|
59
59
|
.option(
|
|
60
60
|
"--reasoning-effort <effort>",
|
|
61
61
|
`Reasoning effort: ${REASONING_EFFORTS.join(", ")}. Individual models support different subsets.`
|
|
@@ -94,10 +94,6 @@ export function addAgentCommand(program: Command, getChatService: () => any): vo
|
|
|
94
94
|
)
|
|
95
95
|
.option("--prompt-file <path>", "Custom prompt template file with {text}")
|
|
96
96
|
.option("--input <text>", "Task input (fallback to stdin if not provided)")
|
|
97
|
-
.option(
|
|
98
|
-
"--resume",
|
|
99
|
-
"Resume a previously started task using the --task-id (local FS or remote)"
|
|
100
|
-
)
|
|
101
97
|
.option(
|
|
102
98
|
"--renderer <name>",
|
|
103
99
|
"Renderer to use: basic, compact, fancy, or a path/package (default: from config or basic)"
|
|
@@ -124,39 +120,6 @@ export function addAgentCommand(program: Command, getChatService: () => any): vo
|
|
|
124
120
|
|
|
125
121
|
const agentModule = new AgentModule();
|
|
126
122
|
|
|
127
|
-
if (options.resume) {
|
|
128
|
-
const threads = await agentModule.loadThreadsForTask(
|
|
129
|
-
options.taskId,
|
|
130
|
-
options.messageId
|
|
131
|
-
);
|
|
132
|
-
// Restore the exact model/provider/reasoning the original run used
|
|
133
|
-
// (falls back to agent defaults when not persisted / remote-only).
|
|
134
|
-
const savedSettings = await agentModule.loadTaskSettings(
|
|
135
|
-
options.taskId,
|
|
136
|
-
options.messageId
|
|
137
|
-
);
|
|
138
|
-
const resumeInput =
|
|
139
|
-
options.input || "Please continue from where you left off.";
|
|
140
|
-
|
|
141
|
-
await agentModule.initialize(chatService);
|
|
142
|
-
const { taskCompleted: resumed } =
|
|
143
|
-
await agentModule.resumeFromMessages({
|
|
144
|
-
agentName:
|
|
145
|
-
options.agentName || savedSettings.agentName || "Patcher",
|
|
146
|
-
input: resumeInput,
|
|
147
|
-
threads,
|
|
148
|
-
messageId: options.messageId,
|
|
149
|
-
taskId: options.taskId,
|
|
150
|
-
// CLI-provided model/provider still win over persisted ones.
|
|
151
|
-
model: options.model || savedSettings.model,
|
|
152
|
-
provider: options.provider || savedSettings.provider,
|
|
153
|
-
reasoningEffort: savedSettings.reasoningEffort,
|
|
154
|
-
summarizeReasoning: savedSettings.summarizeReasoning,
|
|
155
|
-
});
|
|
156
|
-
await resumed;
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
123
|
let input = options.input;
|
|
161
124
|
|
|
162
125
|
if (!input && !options.promptFile) {
|