@tyvm/knowhow 0.0.144 → 0.0.145
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/bin/knowhow.js +22 -20
- package/package.json +1 -1
- package/scripts/migrate-usage-json.js +147 -0
- package/src/agents/base/base.ts +65 -10
- package/src/agents/tools/patch.ts +84 -2
- package/src/agents/tools/textSearch.ts +98 -3
- package/src/chat/modules/AgentModule.ts +129 -6
- package/src/chat/modules/SessionsModule.ts +6 -0
- package/src/chat/types.ts +14 -0
- package/src/chat.ts +11 -0
- package/src/cli.ts +2 -0
- package/src/clients/anthropic.ts +56 -1
- package/src/clients/contextLimits.ts +40 -0
- package/src/clients/gemini.ts +59 -5
- package/src/clients/http.ts +85 -4
- package/src/clients/index.ts +4 -0
- package/src/clients/openai.ts +179 -31
- package/src/clients/pricing/fireworks.ts +50 -1
- package/src/clients/pricing/index.ts +1 -1
- package/src/clients/pricing/models.ts +3 -1
- package/src/clients/pricing/openai.ts +2 -2
- package/src/clients/pricing/qwen.ts +80 -0
- package/src/clients/qwen.ts +16 -0
- package/src/clients/types.ts +69 -1
- package/src/clients/xai.ts +73 -4
- package/src/commands/agent.ts +20 -1
- package/src/index.ts +9 -0
- package/src/processors/Base64ImageDetector.ts +46 -7
- package/src/processors/GemmaToolProcessor.ts +163 -0
- package/src/processors/index.ts +1 -0
- package/src/services/AgentSyncFs.ts +37 -0
- package/src/services/SessionManager.ts +14 -0
- package/src/services/Tools.ts +3 -0
- package/src/services/modules/computerUse.ts +216 -0
- package/src/services/modules/index.ts +47 -9
- package/src/services/modules/types.ts +23 -1
- package/src/types.ts +3 -0
- package/tests/clients/contextLimits.test.ts +4 -0
- package/tests/clients/openai.images.test.ts +105 -0
- package/tests/clients/pricing.test.ts +6 -0
- package/tests/compressor/usageBase64.json +159 -0
- package/tests/compressor/usageBase64.test.ts +175 -0
- package/tests/patching/fixtures/transcript-mangles/agent-sync-fs-nested-catch.json +9 -0
- package/tests/patching/fixtures/transcript-mangles/automation-functions-crossed.json +9 -0
- package/tests/patching/fixtures/transcript-mangles/fruit-ninja-confirmed-retirement.json +8 -0
- package/tests/patching/patchFileOutput.test.ts +112 -1
- package/tests/patching/transcriptMangleRegression.test.ts +125 -0
- package/tests/processors/Base64ImageDetector.test.ts +36 -1
- package/ts_build/package.json +1 -1
- package/ts_build/src/agents/base/base.d.ts +8 -1
- package/ts_build/src/agents/base/base.js +37 -3
- package/ts_build/src/agents/base/base.js.map +1 -1
- package/ts_build/src/agents/tools/patch.d.ts +1 -0
- package/ts_build/src/agents/tools/patch.js +35 -2
- package/ts_build/src/agents/tools/patch.js.map +1 -1
- package/ts_build/src/agents/tools/textSearch.js +56 -2
- package/ts_build/src/agents/tools/textSearch.js.map +1 -1
- package/ts_build/src/chat/modules/AgentModule.d.ts +14 -1
- package/ts_build/src/chat/modules/AgentModule.js +73 -5
- package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
- package/ts_build/src/chat/modules/SessionsModule.js +4 -0
- package/ts_build/src/chat/modules/SessionsModule.js.map +1 -1
- package/ts_build/src/chat/types.d.ts +11 -0
- package/ts_build/src/chat.js +7 -0
- package/ts_build/src/chat.js.map +1 -1
- package/ts_build/src/cli.d.ts +2 -1
- package/ts_build/src/cli.js +1 -0
- package/ts_build/src/cli.js.map +1 -1
- package/ts_build/src/clients/anthropic.js +28 -1
- package/ts_build/src/clients/anthropic.js.map +1 -1
- package/ts_build/src/clients/contextLimits.js +25 -0
- package/ts_build/src/clients/contextLimits.js.map +1 -1
- package/ts_build/src/clients/gemini.js +48 -4
- package/ts_build/src/clients/gemini.js.map +1 -1
- package/ts_build/src/clients/http.d.ts +2 -0
- package/ts_build/src/clients/http.js +66 -9
- package/ts_build/src/clients/http.js.map +1 -1
- package/ts_build/src/clients/index.d.ts +1 -0
- package/ts_build/src/clients/index.js +4 -0
- package/ts_build/src/clients/index.js.map +1 -1
- package/ts_build/src/clients/openai.d.ts +6 -1
- package/ts_build/src/clients/openai.js +131 -33
- package/ts_build/src/clients/openai.js.map +1 -1
- package/ts_build/src/clients/pricing/fireworks.d.ts +4 -1
- package/ts_build/src/clients/pricing/fireworks.js +33 -1
- package/ts_build/src/clients/pricing/fireworks.js.map +1 -1
- package/ts_build/src/clients/pricing/index.d.ts +1 -1
- package/ts_build/src/clients/pricing/index.js +6 -2
- package/ts_build/src/clients/pricing/index.js.map +1 -1
- package/ts_build/src/clients/pricing/models.d.ts +2 -1
- package/ts_build/src/clients/pricing/models.js +4 -1
- package/ts_build/src/clients/pricing/models.js.map +1 -1
- package/ts_build/src/clients/pricing/openai.js +2 -2
- package/ts_build/src/clients/pricing/openai.js.map +1 -1
- package/ts_build/src/clients/pricing/qwen.d.ts +5 -0
- package/ts_build/src/clients/pricing/qwen.js +30 -0
- package/ts_build/src/clients/pricing/qwen.js.map +1 -0
- package/ts_build/src/clients/qwen.d.ts +4 -0
- package/ts_build/src/clients/qwen.js +15 -0
- package/ts_build/src/clients/qwen.js.map +1 -0
- package/ts_build/src/clients/types.d.ts +12 -0
- package/ts_build/src/clients/xai.d.ts +1 -0
- package/ts_build/src/clients/xai.js +56 -9
- package/ts_build/src/clients/xai.js.map +1 -1
- package/ts_build/src/commands/agent.js +10 -1
- package/ts_build/src/commands/agent.js.map +1 -1
- package/ts_build/src/index.d.ts +2 -0
- package/ts_build/src/index.js +1 -0
- package/ts_build/src/index.js.map +1 -1
- package/ts_build/src/processors/Base64ImageDetector.js +22 -3
- package/ts_build/src/processors/Base64ImageDetector.js.map +1 -1
- package/ts_build/src/processors/GemmaToolProcessor.d.ts +14 -0
- package/ts_build/src/processors/GemmaToolProcessor.js +97 -0
- package/ts_build/src/processors/GemmaToolProcessor.js.map +1 -0
- package/ts_build/src/processors/index.d.ts +1 -0
- package/ts_build/src/processors/index.js +3 -1
- package/ts_build/src/processors/index.js.map +1 -1
- package/ts_build/src/services/AgentSyncFs.js +17 -0
- package/ts_build/src/services/AgentSyncFs.js.map +1 -1
- package/ts_build/src/services/SessionManager.js +12 -0
- package/ts_build/src/services/SessionManager.js.map +1 -1
- package/ts_build/src/services/Tools.d.ts +2 -0
- package/ts_build/src/services/Tools.js.map +1 -1
- package/ts_build/src/services/modules/computerUse.d.ts +163 -0
- package/ts_build/src/services/modules/computerUse.js +3 -0
- package/ts_build/src/services/modules/computerUse.js.map +1 -0
- package/ts_build/src/services/modules/index.d.ts +1 -0
- package/ts_build/src/services/modules/index.js +23 -6
- package/ts_build/src/services/modules/index.js.map +1 -1
- package/ts_build/src/services/modules/types.d.ts +4 -0
- package/ts_build/src/types.d.ts +3 -0
- package/ts_build/src/types.js.map +1 -1
- package/ts_build/src/workers/tools/index.d.ts +1 -1
- package/ts_build/tests/clients/contextLimits.test.js +2 -0
- package/ts_build/tests/clients/contextLimits.test.js.map +1 -1
- package/ts_build/tests/clients/openai.images.test.d.ts +1 -0
- package/ts_build/tests/clients/openai.images.test.js +94 -0
- package/ts_build/tests/clients/openai.images.test.js.map +1 -0
- package/ts_build/tests/clients/pricing.test.js +4 -0
- package/ts_build/tests/clients/pricing.test.js.map +1 -1
- package/ts_build/tests/compressor/usageBase64.test.d.ts +1 -0
- package/ts_build/tests/compressor/usageBase64.test.js +109 -0
- package/ts_build/tests/compressor/usageBase64.test.js.map +1 -0
- package/ts_build/tests/patching/patchFileOutput.test.js +82 -0
- package/ts_build/tests/patching/patchFileOutput.test.js.map +1 -1
- package/ts_build/tests/patching/transcriptMangleRegression.test.d.ts +1 -0
- package/ts_build/tests/patching/transcriptMangleRegression.test.js +104 -0
- package/ts_build/tests/patching/transcriptMangleRegression.test.js.map +1 -0
- package/ts_build/tests/processors/Base64ImageDetector.test.js +24 -0
- package/ts_build/tests/processors/Base64ImageDetector.test.js.map +1 -1
- package/x-home.png +0 -0
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
CustomVariables,
|
|
28
28
|
XmlToolCallProcessor,
|
|
29
29
|
HarmonyToolProcessor,
|
|
30
|
+
GemmaToolProcessor,
|
|
30
31
|
Base64ImageProcessor,
|
|
31
32
|
MinimalToolsMessageProcessor,
|
|
32
33
|
} from "../../processors/index";
|
|
@@ -339,7 +340,34 @@ export class AgentModule extends BaseChatModule {
|
|
|
339
340
|
}
|
|
340
341
|
);
|
|
341
342
|
|
|
342
|
-
|
|
343
|
+
// Determine the default agent from context (set by chat.ts from config.chat.defaultAgent)
|
|
344
|
+
// falling back to "Patcher" if not configured.
|
|
345
|
+
const context = this.chatService?.getContext();
|
|
346
|
+
const defaultAgentName = context?.defaultAgent ?? "Patcher";
|
|
347
|
+
await this.handleAgentCommand([defaultAgentName]);
|
|
348
|
+
|
|
349
|
+
// Apply defaultModel and defaultProvider if configured
|
|
350
|
+
const defaultModel = context?.defaultModel;
|
|
351
|
+
const defaultProvider = context?.defaultProvider;
|
|
352
|
+
if (defaultModel || defaultProvider) {
|
|
353
|
+
const selectedAgent = context?.selectedAgent;
|
|
354
|
+
if (selectedAgent) {
|
|
355
|
+
if (defaultModel) {
|
|
356
|
+
selectedAgent.setModel(defaultModel);
|
|
357
|
+
selectedAgent.setModelPreferences([
|
|
358
|
+
{ model: defaultModel, provider: defaultProvider as any },
|
|
359
|
+
]);
|
|
360
|
+
}
|
|
361
|
+
if (defaultProvider) {
|
|
362
|
+
selectedAgent.setProvider(defaultProvider as any);
|
|
363
|
+
}
|
|
364
|
+
// Refresh context model/provider display
|
|
365
|
+
if (context) {
|
|
366
|
+
if (defaultModel) context.currentModel = defaultModel;
|
|
367
|
+
if (defaultProvider) context.currentProvider = defaultProvider;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
343
371
|
}
|
|
344
372
|
|
|
345
373
|
async handleAgentCommand(args: string[]): Promise<void> {
|
|
@@ -682,6 +710,11 @@ export class AgentModule extends BaseChatModule {
|
|
|
682
710
|
messageId: session.knowhowMessageId,
|
|
683
711
|
chatHistory: [],
|
|
684
712
|
run: false, // Don't run yet, we need to set up event listeners first
|
|
713
|
+
// Restore the exact model/provider/reasoning the original run used.
|
|
714
|
+
model: session.model,
|
|
715
|
+
provider: session.provider,
|
|
716
|
+
reasoningEffort: session.reasoningEffort,
|
|
717
|
+
summarizeReasoning: session.summarizeReasoning,
|
|
685
718
|
});
|
|
686
719
|
|
|
687
720
|
// After resume finishes, revert to normal chat (non-agent mode) so the
|
|
@@ -758,6 +791,10 @@ export class AgentModule extends BaseChatModule {
|
|
|
758
791
|
run?: boolean; // whether to run immediately
|
|
759
792
|
taskId?: string; // optional pre-generated taskId
|
|
760
793
|
parentTaskId?: string; // taskId of the parent agent that spawned this task
|
|
794
|
+
// Reasoning settings to restore (e.g. on resume). When provided these take
|
|
795
|
+
// precedence over the module-level CLI defaults.
|
|
796
|
+
reasoningEffort?: CompletionOptions["reasoning_effort"];
|
|
797
|
+
summarizeReasoning?: boolean;
|
|
761
798
|
}) {
|
|
762
799
|
const { input, chatHistory = [], agentName } = options;
|
|
763
800
|
const agentContext = services().Agents.getAgentContext();
|
|
@@ -841,8 +878,15 @@ export class AgentModule extends BaseChatModule {
|
|
|
841
878
|
|
|
842
879
|
// Set up session update listener
|
|
843
880
|
const threadUpdateHandler = async (threadState: any) => {
|
|
844
|
-
this.updateSession(taskId, agent.getThreads());
|
|
845
881
|
taskInfo.totalCost = agent.getTotalCostUsd();
|
|
882
|
+
// Capture the live run configuration so it's persisted for an exact
|
|
883
|
+
// resume (including mid-run model/provider fallbacks).
|
|
884
|
+
taskInfo.model = agent.getModel();
|
|
885
|
+
taskInfo.provider = agent.getProvider();
|
|
886
|
+
taskInfo.reasoningEffort = agent.getReasoningEffort?.();
|
|
887
|
+
taskInfo.summarizeReasoning = agent.getSummarizeReasoning?.();
|
|
888
|
+
// updateSession pulls the (mutated) taskInfo from the registry.
|
|
889
|
+
this.updateSession(taskId, agent.getThreads());
|
|
846
890
|
};
|
|
847
891
|
agent.agentEvents.on(agent.eventTypes.threadUpdate, threadUpdateHandler);
|
|
848
892
|
|
|
@@ -854,6 +898,13 @@ export class AgentModule extends BaseChatModule {
|
|
|
854
898
|
// Initialize new task
|
|
855
899
|
await agent.newTask(taskId);
|
|
856
900
|
|
|
901
|
+
// Record the parent task id on the agent so self-referential tools
|
|
902
|
+
// (e.g. replyToParent) can resolve who spawned this agent without
|
|
903
|
+
// relying solely on reading metadata.json off disk.
|
|
904
|
+
if (options.parentTaskId) {
|
|
905
|
+
agent.setParentTaskId(options.parentTaskId);
|
|
906
|
+
}
|
|
907
|
+
|
|
857
908
|
if (options.model) {
|
|
858
909
|
console.log("Setting model:", options.model);
|
|
859
910
|
agent.setModel(options.model);
|
|
@@ -862,11 +913,28 @@ export class AgentModule extends BaseChatModule {
|
|
|
862
913
|
]);
|
|
863
914
|
}
|
|
864
915
|
|
|
865
|
-
//
|
|
866
|
-
|
|
867
|
-
|
|
916
|
+
// Restore the provider explicitly (e.g. on resume) so the agent talks to
|
|
917
|
+
// the same client the original run used, not the model's default provider.
|
|
918
|
+
if (options.provider) {
|
|
919
|
+
agent.setProvider(options.provider as any);
|
|
868
920
|
}
|
|
869
|
-
|
|
921
|
+
|
|
922
|
+
// Apply reasoning settings to the agent. Explicit per-task settings
|
|
923
|
+
// (e.g. restored from a resumed task's metadata) take precedence over
|
|
924
|
+
// the module-level CLI defaults so a /resume keeps the same reasoning
|
|
925
|
+
// effort the original run used.
|
|
926
|
+
const effectiveReasoningEffort =
|
|
927
|
+
options.reasoningEffort !== undefined
|
|
928
|
+
? options.reasoningEffort
|
|
929
|
+
: this.reasoningEffort;
|
|
930
|
+
if (effectiveReasoningEffort !== undefined) {
|
|
931
|
+
agent.setReasoningEffort(effectiveReasoningEffort);
|
|
932
|
+
}
|
|
933
|
+
agent.setSummarizeReasoning(
|
|
934
|
+
options.summarizeReasoning !== undefined
|
|
935
|
+
? options.summarizeReasoning
|
|
936
|
+
: this.summarizeReasoning
|
|
937
|
+
);
|
|
870
938
|
|
|
871
939
|
// Set up message processors like in original startAgent
|
|
872
940
|
|
|
@@ -908,6 +976,7 @@ export class AgentModule extends BaseChatModule {
|
|
|
908
976
|
agent.messageProcessor.setProcessors("post_call", [
|
|
909
977
|
new XmlToolCallProcessor().createProcessor(),
|
|
910
978
|
new HarmonyToolProcessor().createProcessor(),
|
|
979
|
+
new GemmaToolProcessor().createProcessor(),
|
|
911
980
|
]);
|
|
912
981
|
|
|
913
982
|
agent.messageProcessor.setProcessors("pre_tools", [
|
|
@@ -1118,6 +1187,50 @@ export class AgentModule extends BaseChatModule {
|
|
|
1118
1187
|
return threads;
|
|
1119
1188
|
}
|
|
1120
1189
|
|
|
1190
|
+
/**
|
|
1191
|
+
* Load the persisted run settings (model / provider / reasoning) for a task
|
|
1192
|
+
* from local FS metadata, so a headless --resume can restore the exact
|
|
1193
|
+
* configuration the original run used instead of falling back to agent
|
|
1194
|
+
* defaults. Returns an empty object when no local metadata is found (e.g.
|
|
1195
|
+
* remote-only tasks).
|
|
1196
|
+
*/
|
|
1197
|
+
public async loadTaskSettings(
|
|
1198
|
+
taskId: string,
|
|
1199
|
+
messageId?: string
|
|
1200
|
+
): Promise<{
|
|
1201
|
+
model?: string;
|
|
1202
|
+
provider?: string;
|
|
1203
|
+
reasoningEffort?: CompletionOptions["reasoning_effort"];
|
|
1204
|
+
summarizeReasoning?: boolean;
|
|
1205
|
+
agentName?: string;
|
|
1206
|
+
}> {
|
|
1207
|
+
const localMetadataPath = path.join(
|
|
1208
|
+
".knowhow",
|
|
1209
|
+
"processes",
|
|
1210
|
+
"agents",
|
|
1211
|
+
taskId,
|
|
1212
|
+
"metadata.json"
|
|
1213
|
+
);
|
|
1214
|
+
|
|
1215
|
+
if (!messageId && fs.existsSync(localMetadataPath)) {
|
|
1216
|
+
try {
|
|
1217
|
+
const raw = await fsPromises.readFile(localMetadataPath, "utf-8");
|
|
1218
|
+
const metadata = JSON.parse(raw);
|
|
1219
|
+
return {
|
|
1220
|
+
model: metadata.model,
|
|
1221
|
+
provider: metadata.provider,
|
|
1222
|
+
reasoningEffort: metadata.reasoningEffort,
|
|
1223
|
+
summarizeReasoning: metadata.summarizeReasoning,
|
|
1224
|
+
agentName: metadata.agentName,
|
|
1225
|
+
};
|
|
1226
|
+
} catch (e) {
|
|
1227
|
+
console.warn(`⚠️ Failed to parse local metadata for settings: ${e.message}`);
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
return {};
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1121
1234
|
/**
|
|
1122
1235
|
* Resume an agent from a set of existing message threads
|
|
1123
1236
|
* Used by the CLI --resume flag to continue crashed/failed tasks
|
|
@@ -1129,6 +1242,11 @@ export class AgentModule extends BaseChatModule {
|
|
|
1129
1242
|
messageId?: string;
|
|
1130
1243
|
taskId?: string;
|
|
1131
1244
|
interactive?: boolean;
|
|
1245
|
+
// Restore the exact model/provider/reasoning the original run used.
|
|
1246
|
+
model?: string;
|
|
1247
|
+
provider?: string;
|
|
1248
|
+
reasoningEffort?: CompletionOptions["reasoning_effort"];
|
|
1249
|
+
summarizeReasoning?: boolean;
|
|
1132
1250
|
}): Promise<{ taskCompleted: Promise<string> }> {
|
|
1133
1251
|
const { agentName, input, threads, messageId, taskId } = options;
|
|
1134
1252
|
|
|
@@ -1189,6 +1307,11 @@ export class AgentModule extends BaseChatModule {
|
|
|
1189
1307
|
// remote task identified by taskId.
|
|
1190
1308
|
syncRemote: !messageId && !!taskId,
|
|
1191
1309
|
run: false,
|
|
1310
|
+
// Restore the model/provider/reasoning captured from the task metadata.
|
|
1311
|
+
model: options.model,
|
|
1312
|
+
provider: options.provider,
|
|
1313
|
+
reasoningEffort: options.reasoningEffort,
|
|
1314
|
+
summarizeReasoning: options.summarizeReasoning,
|
|
1192
1315
|
});
|
|
1193
1316
|
|
|
1194
1317
|
// Interactive (chat REPL) resume: route through the attached chat loop so the
|
|
@@ -396,6 +396,12 @@ export class SessionsModule extends BaseChatModule {
|
|
|
396
396
|
threads: normalizedThreads,
|
|
397
397
|
input: additionalContext?.trim() || initialInput || "",
|
|
398
398
|
interactive: true,
|
|
399
|
+
// Restore the exact model/provider/reasoning the run used so
|
|
400
|
+
// resuming doesn't silently drop back to agent defaults.
|
|
401
|
+
model: metadata.model,
|
|
402
|
+
provider: metadata.provider,
|
|
403
|
+
reasoningEffort: metadata.reasoningEffort,
|
|
404
|
+
summarizeReasoning: metadata.summarizeReasoning,
|
|
399
405
|
});
|
|
400
406
|
return;
|
|
401
407
|
} catch (e: any) {
|
package/src/chat/types.ts
CHANGED
|
@@ -10,6 +10,9 @@ export interface ChatContext {
|
|
|
10
10
|
debugMode?: boolean;
|
|
11
11
|
agentMode?: boolean;
|
|
12
12
|
currentAgent?: string;
|
|
13
|
+
defaultAgent?: string;
|
|
14
|
+
defaultModel?: string;
|
|
15
|
+
defaultProvider?: string;
|
|
13
16
|
promptText?: string;
|
|
14
17
|
searchMode?: boolean;
|
|
15
18
|
voiceMode?: boolean;
|
|
@@ -94,6 +97,12 @@ export interface TaskInfo {
|
|
|
94
97
|
endTime?: number;
|
|
95
98
|
totalCost: number;
|
|
96
99
|
sessionFile?: string;
|
|
100
|
+
// Model/provider/reasoning actually used for this run, so a resume can
|
|
101
|
+
// restore the exact configuration instead of falling back to agent defaults.
|
|
102
|
+
model?: string;
|
|
103
|
+
provider?: string;
|
|
104
|
+
reasoningEffort?: "none" | "low" | "medium" | "high";
|
|
105
|
+
summarizeReasoning?: boolean;
|
|
97
106
|
}
|
|
98
107
|
|
|
99
108
|
export interface ChatSession {
|
|
@@ -111,6 +120,11 @@ export interface ChatSession {
|
|
|
111
120
|
threads: any[][];
|
|
112
121
|
currentThread: number;
|
|
113
122
|
lastUpdated: number;
|
|
123
|
+
// Persisted run configuration for exact resume restoration.
|
|
124
|
+
model?: string;
|
|
125
|
+
provider?: string;
|
|
126
|
+
reasoningEffort?: "none" | "low" | "medium" | "high";
|
|
127
|
+
summarizeReasoning?: boolean;
|
|
114
128
|
}
|
|
115
129
|
|
|
116
130
|
export interface ChatHistory {
|
package/src/chat.ts
CHANGED
|
@@ -54,6 +54,17 @@ async function main(initialCommand?: string) {
|
|
|
54
54
|
// Create chat service with plugins
|
|
55
55
|
const chatService = new CliChatService(config.plugins?.enabled ?? []);
|
|
56
56
|
|
|
57
|
+
// ── Default Agent / Model / Provider ──────────────────────────────────────
|
|
58
|
+
// If chat config specifies defaults, inject them into the context so
|
|
59
|
+
// AgentModule can pick them up during initialize().
|
|
60
|
+
if (config.chat?.defaultAgent || config.chat?.defaultModel || config.chat?.defaultProvider) {
|
|
61
|
+
chatService.setContext({
|
|
62
|
+
defaultAgent: config.chat?.defaultAgent,
|
|
63
|
+
defaultModel: config.chat?.defaultModel,
|
|
64
|
+
defaultProvider: config.chat?.defaultProvider,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
57
68
|
// ── Renderer ──────────────────────────────────────────────────────────────
|
|
58
69
|
// Load a custom renderer if configured, otherwise use the default
|
|
59
70
|
// ConsoleRenderer (already the default inside AgentModule).
|
package/src/cli.ts
CHANGED
package/src/clients/anthropic.ts
CHANGED
|
@@ -245,6 +245,18 @@ export class GenericAnthropicClient implements GenericClient {
|
|
|
245
245
|
|
|
246
246
|
transformMessages(messages: Message[], longTtl = false): MessageParam[] {
|
|
247
247
|
const toolCalls = messages.flatMap((msg) => msg.tool_calls || []);
|
|
248
|
+
// Map each tool_call id → the thinking blocks captured on the assistant
|
|
249
|
+
// message that produced it, so we can re-inject them before the tool_use.
|
|
250
|
+
const thinkingByCallId: { [id: string]: any[] } = {};
|
|
251
|
+
for (const m of messages) {
|
|
252
|
+
if (m.role !== "assistant" || !m.tool_calls?.length) continue;
|
|
253
|
+
const details = (m as any)._reasoning_details;
|
|
254
|
+
if (details?.provider === "anthropic" && Array.isArray(details.items)) {
|
|
255
|
+
// Attach to the FIRST tool_call of this assistant turn (thinking blocks
|
|
256
|
+
// must precede the first tool_use in the turn).
|
|
257
|
+
thinkingByCallId[m.tool_calls[0].id] = details.items;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
248
260
|
const claudeMessages: MessageParam[] = messages
|
|
249
261
|
.filter((msg) => msg.role !== "system")
|
|
250
262
|
.filter((msg) => msg.content || msg.role === "tool")
|
|
@@ -258,9 +270,14 @@ export class GenericAnthropicClient implements GenericClient {
|
|
|
258
270
|
JSON.stringify(msg, null, 2)
|
|
259
271
|
);
|
|
260
272
|
} else {
|
|
273
|
+
// Re-inject any captured thinking / redacted_thinking blocks
|
|
274
|
+
// (verbatim, with signature/data) BEFORE the tool_use block, as
|
|
275
|
+
// Anthropic requires for reasoning continuity across tool turns.
|
|
276
|
+
const thinkingBlocks = thinkingByCallId[msg.tool_call_id] ?? [];
|
|
261
277
|
toolMessages.push({
|
|
262
278
|
role: "assistant",
|
|
263
279
|
content: [
|
|
280
|
+
...thinkingBlocks,
|
|
264
281
|
{
|
|
265
282
|
type: "tool_use",
|
|
266
283
|
id: msg.tool_call_id,
|
|
@@ -440,8 +457,42 @@ export class GenericAnthropicClient implements GenericClient {
|
|
|
440
457
|
console.log("no content in Anthropic response", response);
|
|
441
458
|
}
|
|
442
459
|
|
|
460
|
+
// Capture thinking / redacted_thinking blocks verbatim (with their
|
|
461
|
+
// signature / data) so they can be round-tripped unmodified on the next
|
|
462
|
+
// tool-use turn. Anthropic REQUIRES thinking blocks from the assistant
|
|
463
|
+
// message to be passed back, complete and unmodified, when returning tool
|
|
464
|
+
// results — otherwise reasoning continuity and prompt-cache hits are lost.
|
|
465
|
+
const thinkingBlocks = response.content.filter(
|
|
466
|
+
(c) => c.type === "thinking" || c.type === "redacted_thinking"
|
|
467
|
+
);
|
|
468
|
+
const reasoningDetails =
|
|
469
|
+
thinkingBlocks.length > 0
|
|
470
|
+
? { provider: "anthropic", items: thinkingBlocks }
|
|
471
|
+
: undefined;
|
|
472
|
+
// Extract a human-readable summary from thinking blocks (when present).
|
|
473
|
+
const reasoningSummary = thinkingBlocks
|
|
474
|
+
.map((b) => ("thinking" in b ? (b as any).thinking : ""))
|
|
475
|
+
.filter(Boolean)
|
|
476
|
+
.join("\n") || undefined;
|
|
477
|
+
|
|
478
|
+
// Determine which resulting choice should carry the thinking blocks. They
|
|
479
|
+
// are re-injected before the first tool_use on the next turn, so prefer
|
|
480
|
+
// the first tool_use block; if there are no tool calls, fall back to the
|
|
481
|
+
// first (text) block. This keeps a single copy that transformMessages can
|
|
482
|
+
// reliably find via the assistant message's tool_calls.
|
|
483
|
+
const nonThinking = response.content.filter(
|
|
484
|
+
(c) => c.type !== "thinking" && c.type !== "redacted_thinking"
|
|
485
|
+
);
|
|
486
|
+
const firstToolUseIdx = nonThinking.findIndex((c) => c.type === "tool_use");
|
|
487
|
+
const carryIdx = firstToolUseIdx >= 0 ? firstToolUseIdx : 0;
|
|
488
|
+
|
|
443
489
|
return {
|
|
444
|
-
choices:
|
|
490
|
+
choices: nonThinking.map((c, idx) => {
|
|
491
|
+
// Only the FIRST resulting assistant message carries the thinking
|
|
492
|
+
// blocks (Anthropic requires a single thinking block sequence at the
|
|
493
|
+
// start of the assistant turn); attaching to every choice would
|
|
494
|
+
// duplicate them once the messages are re-transformed.
|
|
495
|
+
const carryReasoning = idx === carryIdx;
|
|
445
496
|
if (c.type === "tool_use") {
|
|
446
497
|
return {
|
|
447
498
|
message: {
|
|
@@ -457,6 +508,8 @@ export class GenericAnthropicClient implements GenericClient {
|
|
|
457
508
|
},
|
|
458
509
|
},
|
|
459
510
|
],
|
|
511
|
+
...(carryReasoning && reasoningDetails && { _reasoning_details: reasoningDetails }),
|
|
512
|
+
...(carryReasoning && reasoningSummary && { reasoning_summary: reasoningSummary }),
|
|
460
513
|
},
|
|
461
514
|
};
|
|
462
515
|
} else {
|
|
@@ -465,6 +518,8 @@ export class GenericAnthropicClient implements GenericClient {
|
|
|
465
518
|
role: "assistant",
|
|
466
519
|
content: "text" in c ? c.text : c.type,
|
|
467
520
|
tool_calls: [],
|
|
521
|
+
...(carryReasoning && reasoningDetails && { _reasoning_details: reasoningDetails }),
|
|
522
|
+
...(carryReasoning && reasoningSummary && { reasoning_summary: reasoningSummary }),
|
|
468
523
|
},
|
|
469
524
|
};
|
|
470
525
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Models, EmbeddingModels } from "../types";
|
|
2
|
+
import { FireworksModels } from "./pricing/fireworks";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Context window limits (in tokens) for all supported models.
|
|
@@ -207,6 +208,45 @@ export const ContextLimits: Record<string, number> = {
|
|
|
207
208
|
[Models.xai.GrokImagineImage]: 0,
|
|
208
209
|
[Models.xai.GrokImagineVideo]: 0,
|
|
209
210
|
[Models.xai.Grok2Image1212]: 0,
|
|
211
|
+
|
|
212
|
+
// ─── Fireworks AI ──────────────────────────────────────────────────────────
|
|
213
|
+
// Moonshot AI (Kimi) — context windows per fireworks.ai/pricing
|
|
214
|
+
[FireworksModels.KimiK3]: 131_072,
|
|
215
|
+
[FireworksModels.KimiK2p7Code]: 131_072,
|
|
216
|
+
[FireworksModels.KimiK2_6]: 131_072,
|
|
217
|
+
[FireworksModels.KimiK2_5]: 131_072,
|
|
218
|
+
|
|
219
|
+
// MiniMax
|
|
220
|
+
[FireworksModels.MinimaxM3]: 1_000_000,
|
|
221
|
+
[FireworksModels.MinimaxM2_7]: 1_000_000,
|
|
222
|
+
[FireworksModels.MinimaxM2_5]: 1_000_000,
|
|
223
|
+
|
|
224
|
+
// Qwen
|
|
225
|
+
[FireworksModels.Qwen3p7Plus]: 131_072,
|
|
226
|
+
[FireworksModels.Qwen3_6Plus]: 131_072,
|
|
227
|
+
[FireworksModels.Qwen3p6Plus]: 131_072,
|
|
228
|
+
[FireworksModels.Qwen3Vl30bA3bThinking]: 32_768,
|
|
229
|
+
[FireworksModels.Qwen3Vl30bA3bInstruct]: 32_768,
|
|
230
|
+
[FireworksModels.Qwen3_8b]: 131_072,
|
|
231
|
+
|
|
232
|
+
// Z.ai (GLM)
|
|
233
|
+
[FireworksModels.Glm5p2]: 131_072,
|
|
234
|
+
[FireworksModels.Glm5p1]: 131_072,
|
|
235
|
+
[FireworksModels.Glm5]: 131_072,
|
|
236
|
+
[FireworksModels.Glm4_7]: 131_072,
|
|
237
|
+
|
|
238
|
+
// DeepSeek AI
|
|
239
|
+
[FireworksModels.DeepseekV4Pro]: 163_840,
|
|
240
|
+
[FireworksModels.DeepseekV4Flash]: 163_840,
|
|
241
|
+
[FireworksModels.DeepseekV3_2]: 163_840,
|
|
242
|
+
[FireworksModels.DeepseekV3_1]: 163_840,
|
|
243
|
+
|
|
244
|
+
// OpenAI OSS
|
|
245
|
+
[FireworksModels.GptOss120b]: 131_072,
|
|
246
|
+
|
|
247
|
+
// Fireworks embedding/reranker models — 40k context
|
|
248
|
+
[FireworksModels.Qwen3Embedding8b]: 40_960,
|
|
249
|
+
[FireworksModels.Qwen3Reranker8b]: 40_960,
|
|
210
250
|
};
|
|
211
251
|
|
|
212
252
|
/** Default fallback context window limit (tokens) used when a model is not found. */
|
package/src/clients/gemini.ts
CHANGED
|
@@ -225,17 +225,44 @@ export class GenericGeminiClient implements GenericClient {
|
|
|
225
225
|
msg.tool_calls &&
|
|
226
226
|
msg.tool_calls.length > 0
|
|
227
227
|
) {
|
|
228
|
+
// Look up any captured thoughtSignatures for this assistant message so
|
|
229
|
+
// we can re-attach them to the matching functionCall part (required by
|
|
230
|
+
// Gemini 3 to preserve reasoning continuity across tool-use turns).
|
|
231
|
+
const details = (msg as any)._reasoning_details;
|
|
232
|
+
const sigByCallId: { [id: string]: string } = {};
|
|
233
|
+
const standaloneThoughtSigs: string[] = [];
|
|
234
|
+
if (details && details.provider === "gemini" && Array.isArray(details.items)) {
|
|
235
|
+
for (const item of details.items) {
|
|
236
|
+
if (item?.kind === "functionCall" && item.callId) {
|
|
237
|
+
sigByCallId[item.callId] = item.thoughtSignature;
|
|
238
|
+
} else if (item?.kind === "thoughtSignature" && item.thoughtSignature) {
|
|
239
|
+
standaloneThoughtSigs.push(item.thoughtSignature);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
228
243
|
for (const toolCall of msg.tool_calls) {
|
|
229
|
-
|
|
244
|
+
const callPart: any = {
|
|
230
245
|
functionCall: {
|
|
231
246
|
name: toolCall.function.name,
|
|
232
247
|
// Google expects arguments as a parsed object, not a string
|
|
233
248
|
args: JSON.parse(toolCall.function.arguments || "{}"),
|
|
234
249
|
},
|
|
235
|
-
}
|
|
250
|
+
};
|
|
251
|
+
if (sigByCallId[toolCall.id]) {
|
|
252
|
+
callPart.thoughtSignature = sigByCallId[toolCall.id];
|
|
253
|
+
}
|
|
254
|
+
parts.push(callPart);
|
|
236
255
|
// Store the tool call to potentially link with a future tool response message
|
|
237
256
|
assistantToolCalls[toolCall.id] = toolCall;
|
|
238
257
|
}
|
|
258
|
+
// Re-attach any standalone thought-part signatures onto the leading
|
|
259
|
+
// text part(s) so reasoning-only thoughts are also round-tripped.
|
|
260
|
+
for (let s = 0; s < standaloneThoughtSigs.length; s++) {
|
|
261
|
+
const p: any = parts[s];
|
|
262
|
+
if (p && "text" in p && !p.thoughtSignature) {
|
|
263
|
+
p.thoughtSignature = standaloneThoughtSigs[s];
|
|
264
|
+
}
|
|
265
|
+
}
|
|
239
266
|
}
|
|
240
267
|
|
|
241
268
|
if (parts.length > 0) {
|
|
@@ -499,24 +526,51 @@ export class GenericGeminiClient implements GenericClient {
|
|
|
499
526
|
return { message };
|
|
500
527
|
}
|
|
501
528
|
|
|
529
|
+
// Capture Gemini thoughtSignatures so they can be round-tripped on the
|
|
530
|
+
// next turn. Gemini 3 REQUIRES these to be echoed back on the matching
|
|
531
|
+
// functionCall part or it returns a 400 "Thought signature is not
|
|
532
|
+
// valid" on the 2nd+ tool-calling turn. We key them by tool-call id
|
|
533
|
+
// (and also keep any standalone thought-part signatures in order).
|
|
534
|
+
const reasoningItems: any[] = [];
|
|
535
|
+
|
|
502
536
|
candidate?.content?.parts?.forEach((part) => {
|
|
503
537
|
if ("text" in part && typeof part.text === "string") {
|
|
504
538
|
textContent += part.text; // Concatenate text parts
|
|
539
|
+
if ((part as any).thoughtSignature) {
|
|
540
|
+
reasoningItems.push({
|
|
541
|
+
kind: "thoughtSignature",
|
|
542
|
+
thoughtSignature: (part as any).thoughtSignature,
|
|
543
|
+
});
|
|
544
|
+
}
|
|
505
545
|
} else if ("functionCall" in part && part.functionCall) {
|
|
546
|
+
const callId =
|
|
547
|
+
part.functionCall.id ||
|
|
548
|
+
`fc_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
506
549
|
message.tool_calls.push({
|
|
507
|
-
id:
|
|
508
|
-
part.functionCall.id ||
|
|
509
|
-
`fc_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
550
|
+
id: callId,
|
|
510
551
|
type: "function",
|
|
511
552
|
function: {
|
|
512
553
|
name: part.functionCall.name,
|
|
513
554
|
arguments: JSON.stringify(part.functionCall.args || {}),
|
|
514
555
|
},
|
|
515
556
|
});
|
|
557
|
+
if ((part as any).thoughtSignature) {
|
|
558
|
+
reasoningItems.push({
|
|
559
|
+
kind: "functionCall",
|
|
560
|
+
callId,
|
|
561
|
+
thoughtSignature: (part as any).thoughtSignature,
|
|
562
|
+
});
|
|
563
|
+
}
|
|
516
564
|
}
|
|
517
565
|
});
|
|
518
566
|
|
|
519
567
|
message.content = textContent || null;
|
|
568
|
+
if (reasoningItems.length > 0) {
|
|
569
|
+
(message as any)._reasoning_details = {
|
|
570
|
+
provider: "gemini",
|
|
571
|
+
items: reasoningItems,
|
|
572
|
+
};
|
|
573
|
+
}
|
|
520
574
|
|
|
521
575
|
return { message };
|
|
522
576
|
}) || []; // Handle case with no candidates
|