@tyvm/knowhow 0.0.128 → 0.0.129

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.
Files changed (109) hide show
  1. package/package.json +2 -1
  2. package/scripts/cache-miss-debug.ts +365 -0
  3. package/src/agents/base/base.ts +119 -54
  4. package/src/agents/tools/execCommand.ts +26 -6
  5. package/src/agents/tools/minimal/callTool.ts +45 -0
  6. package/src/agents/tools/minimal/definitions.ts +50 -0
  7. package/src/agents/tools/minimal/index.ts +3 -0
  8. package/src/agents/tools/minimal/inspectTools.ts +27 -0
  9. package/src/chat/modules/AgentModule.ts +27 -8
  10. package/src/clients/contextLimits.ts +9 -0
  11. package/src/clients/index.ts +6 -0
  12. package/src/clients/meta.ts +18 -0
  13. package/src/clients/pricing/anthropic.ts +13 -0
  14. package/src/clients/pricing/fireworks.ts +18 -12
  15. package/src/clients/pricing/index.ts +1 -0
  16. package/src/clients/pricing/meta.ts +12 -0
  17. package/src/clients/pricing/openai.ts +13 -0
  18. package/src/clients/pricing/xai.ts +3 -0
  19. package/src/commands/services.ts +1 -1
  20. package/src/processors/MinimalToolsMessageProcessor.ts +113 -0
  21. package/src/processors/TokenCompressor.ts +21 -4
  22. package/src/processors/index.ts +7 -1
  23. package/src/services/AgentSyncFs.ts +49 -0
  24. package/src/services/AgentSyncKnowhowWeb.ts +1 -1
  25. package/src/services/KnowhowClient.ts +1 -1
  26. package/src/services/LazyToolsService.ts +12 -0
  27. package/src/services/MinimalToolsService.ts +167 -0
  28. package/src/services/Tools.ts +9 -0
  29. package/src/services/index.ts +1 -0
  30. package/src/worker.ts +7 -0
  31. package/tests/processors/TokenCompressor.test.ts +45 -0
  32. package/tests/unit/services/MinimalToolsService.test.ts +424 -0
  33. package/ts_build/package.json +2 -1
  34. package/ts_build/src/agents/base/base.d.ts +4 -1
  35. package/ts_build/src/agents/base/base.js +62 -31
  36. package/ts_build/src/agents/base/base.js.map +1 -1
  37. package/ts_build/src/agents/tools/execCommand.d.ts +1 -1
  38. package/ts_build/src/agents/tools/execCommand.js +18 -5
  39. package/ts_build/src/agents/tools/execCommand.js.map +1 -1
  40. package/ts_build/src/agents/tools/minimal/callTool.d.ts +5 -0
  41. package/ts_build/src/agents/tools/minimal/callTool.js +28 -0
  42. package/ts_build/src/agents/tools/minimal/callTool.js.map +1 -0
  43. package/ts_build/src/agents/tools/minimal/definitions.d.ts +4 -0
  44. package/ts_build/src/agents/tools/minimal/definitions.js +46 -0
  45. package/ts_build/src/agents/tools/minimal/definitions.js.map +1 -0
  46. package/ts_build/src/agents/tools/minimal/index.d.ts +3 -0
  47. package/ts_build/src/agents/tools/minimal/index.js +20 -0
  48. package/ts_build/src/agents/tools/minimal/index.js.map +1 -0
  49. package/ts_build/src/agents/tools/minimal/inspectTools.d.ts +2 -0
  50. package/ts_build/src/agents/tools/minimal/inspectTools.js +15 -0
  51. package/ts_build/src/agents/tools/minimal/inspectTools.js.map +1 -0
  52. package/ts_build/src/chat/modules/AgentModule.js +8 -2
  53. package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
  54. package/ts_build/src/clients/contextLimits.js +8 -0
  55. package/ts_build/src/clients/contextLimits.js.map +1 -1
  56. package/ts_build/src/clients/index.d.ts +1 -0
  57. package/ts_build/src/clients/index.js +6 -0
  58. package/ts_build/src/clients/index.js.map +1 -1
  59. package/ts_build/src/clients/meta.d.ts +4 -0
  60. package/ts_build/src/clients/meta.js +15 -0
  61. package/ts_build/src/clients/meta.js.map +1 -0
  62. package/ts_build/src/clients/pricing/anthropic.d.ts +4 -0
  63. package/ts_build/src/clients/pricing/anthropic.js +12 -0
  64. package/ts_build/src/clients/pricing/anthropic.js.map +1 -1
  65. package/ts_build/src/clients/pricing/fireworks.d.ts +2 -5
  66. package/ts_build/src/clients/pricing/fireworks.js +13 -11
  67. package/ts_build/src/clients/pricing/fireworks.js.map +1 -1
  68. package/ts_build/src/clients/pricing/index.d.ts +1 -0
  69. package/ts_build/src/clients/pricing/index.js +5 -2
  70. package/ts_build/src/clients/pricing/index.js.map +1 -1
  71. package/ts_build/src/clients/pricing/meta.d.ts +6 -0
  72. package/ts_build/src/clients/pricing/meta.js +8 -0
  73. package/ts_build/src/clients/pricing/meta.js.map +1 -0
  74. package/ts_build/src/clients/pricing/openai.d.ts +3 -0
  75. package/ts_build/src/clients/pricing/openai.js +12 -0
  76. package/ts_build/src/clients/pricing/openai.js.map +1 -1
  77. package/ts_build/src/clients/pricing/xai.d.ts +1 -0
  78. package/ts_build/src/clients/pricing/xai.js +3 -0
  79. package/ts_build/src/clients/pricing/xai.js.map +1 -1
  80. package/ts_build/src/commands/services.js.map +1 -1
  81. package/ts_build/src/processors/MinimalToolsMessageProcessor.d.ts +7 -0
  82. package/ts_build/src/processors/MinimalToolsMessageProcessor.js +61 -0
  83. package/ts_build/src/processors/MinimalToolsMessageProcessor.js.map +1 -0
  84. package/ts_build/src/processors/TokenCompressor.js +5 -2
  85. package/ts_build/src/processors/TokenCompressor.js.map +1 -1
  86. package/ts_build/src/processors/index.d.ts +2 -1
  87. package/ts_build/src/processors/index.js +3 -1
  88. package/ts_build/src/processors/index.js.map +1 -1
  89. package/ts_build/src/services/AgentSyncFs.d.ts +2 -0
  90. package/ts_build/src/services/AgentSyncFs.js +30 -0
  91. package/ts_build/src/services/AgentSyncFs.js.map +1 -1
  92. package/ts_build/src/services/AgentSyncKnowhowWeb.js +1 -1
  93. package/ts_build/src/services/KnowhowClient.d.ts +1 -1
  94. package/ts_build/src/services/LazyToolsService.js.map +1 -1
  95. package/ts_build/src/services/MinimalToolsService.d.ts +14 -0
  96. package/ts_build/src/services/MinimalToolsService.js +80 -0
  97. package/ts_build/src/services/MinimalToolsService.js.map +1 -0
  98. package/ts_build/src/services/Tools.js.map +1 -1
  99. package/ts_build/src/services/index.d.ts +1 -0
  100. package/ts_build/src/services/index.js +1 -0
  101. package/ts_build/src/services/index.js.map +1 -1
  102. package/ts_build/src/types.d.ts +8 -0
  103. package/ts_build/src/worker.js +5 -0
  104. package/ts_build/src/worker.js.map +1 -1
  105. package/ts_build/tests/processors/TokenCompressor.test.js +27 -0
  106. package/ts_build/tests/processors/TokenCompressor.test.js.map +1 -1
  107. package/ts_build/tests/unit/services/MinimalToolsService.test.d.ts +1 -0
  108. package/ts_build/tests/unit/services/MinimalToolsService.test.js +320 -0
  109. package/ts_build/tests/unit/services/MinimalToolsService.test.js.map +1 -0
@@ -259,7 +259,7 @@ const execWithTimeout = async (
259
259
  // Public tool
260
260
  export async function execCommand(
261
261
  command: string,
262
- timeout?: number,
262
+ timeout?: number | string,
263
263
  continueInBackground?: boolean,
264
264
  logFileName?: string
265
265
  ): Promise<string> {
@@ -272,17 +272,37 @@ export async function execCommand(
272
272
  this instanceof ToolsService ? this : services().Tools
273
273
  ) as ToolsService;
274
274
 
275
+ // Coerce timeout to a number. Agents (and some tool-call serializers) often
276
+ // pass numeric arguments as strings (e.g. "120000"). Node's exec()/setTimeout
277
+ // reject non-integer values with "The value of \"timeout\" is out of range.
278
+ // It must be an unsigned integer", so normalize here before any use.
279
+ let normalizedTimeout: number | undefined;
280
+ const rawTimeout = typeof timeout === "string" ? Number(timeout.trim()) : timeout;
281
+ if (typeof rawTimeout !== "number" || !Number.isFinite(rawTimeout)) {
282
+ normalizedTimeout = undefined;
283
+ } else if (rawTimeout === -1) {
284
+ // -1 is the sentinel for "wait indefinitely" — leave as-is.
285
+ normalizedTimeout = -1;
286
+ } else {
287
+ // Clamp to a non-negative integer so the underlying APIs never throw.
288
+ normalizedTimeout = Math.max(0, Math.floor(rawTimeout));
289
+ }
290
+
275
291
  // Detect suspiciously small timeout values — agents often pass seconds instead of ms.
276
292
  // Any value < 100 is almost certainly a mistake (100ms is still very fast for a shell cmd).
277
293
  // We auto-correct to seconds and include a warning in the output so the agent learns.
278
- let correctedTimeout = timeout;
294
+ let correctedTimeout = normalizedTimeout;
279
295
  let timeoutWarning = "";
280
- if (timeout !== undefined && timeout !== -1 && timeout < 100) {
281
- correctedTimeout = timeout * 1000;
296
+ if (
297
+ normalizedTimeout !== undefined &&
298
+ normalizedTimeout !== -1 &&
299
+ normalizedTimeout < 100
300
+ ) {
301
+ correctedTimeout = normalizedTimeout * 1000;
282
302
  timeoutWarning =
283
- `⚠️ Warning: timeout was ${timeout}ms which is extremely small and likely a mistake. ` +
303
+ `⚠️ Warning: timeout was ${normalizedTimeout}ms which is extremely small and likely a mistake. ` +
284
304
  `The timeout unit is milliseconds, not seconds. ` +
285
- `Auto-corrected to ${correctedTimeout}ms (${timeout}s).\n\n`;
305
+ `Auto-corrected to ${correctedTimeout}ms (${normalizedTimeout}s).\n\n`;
286
306
  }
287
307
 
288
308
  const context = toolService.getContext();
@@ -0,0 +1,45 @@
1
+ import { minimatch } from "minimatch";
2
+ import { MinimalToolsService } from "../../../services/MinimalToolsService";
3
+ import { ToolsService } from "../../../services/Tools";
4
+
5
+ /**
6
+ * Calls any tool by name with the given args.
7
+ * This is the escape hatch that lets agents call tools outside the base tool set
8
+ * without changing the `tools:` array sent to the AI (preserving cache stability).
9
+ */
10
+ export async function callTool(
11
+ this: ToolsService,
12
+ args: { name: string; args: Record<string, any> }
13
+ ): Promise<any> {
14
+ const service = this as unknown as MinimalToolsService;
15
+ const { name, args: toolArgs } = args;
16
+
17
+ const allTools = service.getAllTools ? service.getAllTools() : service.getTools();
18
+
19
+ // Fuzzy match: exact, endsWith, or glob
20
+ const matchedTool =
21
+ allTools.find((t) => t.function.name === name) ||
22
+ allTools.find((t) => t.function.name.endsWith(name)) ||
23
+ allTools.find((t) => minimatch(t.function.name, name, { nocase: true }));
24
+
25
+ if (!matchedTool) {
26
+ const available = allTools.map((t) => t.function.name).join(", ");
27
+ return `Error: Tool "${name}" not found. Use inspectTools() to browse available tools. Available: ${available}`;
28
+ }
29
+
30
+ const toolName = matchedTool.function.name;
31
+
32
+ // Build a synthetic ToolCall object and delegate to the base callTool
33
+ const syntheticToolCall = {
34
+ id: `call_minimal_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`,
35
+ type: "function" as const,
36
+ function: {
37
+ name: toolName,
38
+ arguments: JSON.stringify(toolArgs),
39
+ },
40
+ };
41
+
42
+ // Use base ToolsService.callTool with the matched tool name allowed
43
+ const result = await service.callToolByName(syntheticToolCall, toolName);
44
+ return result;
45
+ }
@@ -0,0 +1,50 @@
1
+ import { Tool } from "../../../clients/types";
2
+
3
+ export const callToolDefinition: Tool = {
4
+ type: "function",
5
+ function: {
6
+ name: "callTool",
7
+ description:
8
+ "Call any available tool by name with the given arguments. Use listStoredToolResponses + inspectTools to discover available tools and their argument schemas before calling. This is the primary way to call tools that are not in the base tool set.",
9
+ parameters: {
10
+ type: "object",
11
+ positional: false,
12
+ properties: {
13
+ name: {
14
+ type: "string",
15
+ description: "The name of the tool to call.",
16
+ },
17
+ args: {
18
+ type: "object",
19
+ description:
20
+ "The arguments to pass to the tool. Should match the tool's parameter schema.",
21
+ },
22
+ },
23
+ required: ["name", "args"],
24
+ },
25
+ },
26
+ };
27
+
28
+ export const inspectToolsDefinition: Tool = {
29
+ type: "function",
30
+ function: {
31
+ name: "inspectTools",
32
+ description:
33
+ "Get the full schema/definition for tools matching the given glob patterns. Use this to discover what arguments a tool needs before calling it via callTool. Example patterns: ['read*'] finds tools starting with 'read', ['*File'] finds tools ending with 'File'.",
34
+ parameters: {
35
+ type: "object",
36
+ positional: true,
37
+ properties: {
38
+ patterns: {
39
+ type: "array",
40
+ items: { type: "string" },
41
+ description:
42
+ "Array of glob patterns to filter tool names. If omitted, returns all available tools.",
43
+ },
44
+ },
45
+ required: [],
46
+ },
47
+ },
48
+ };
49
+
50
+ export const minimalDefinitions = [callToolDefinition, inspectToolsDefinition];
@@ -0,0 +1,3 @@
1
+ export * from "./callTool";
2
+ export * from "./inspectTools";
3
+ export * from "./definitions";
@@ -0,0 +1,27 @@
1
+ import { minimatch } from "minimatch";
2
+ import { MinimalToolsService } from "../../../services/MinimalToolsService";
3
+ import { ToolsService } from "../../../services/Tools";
4
+
5
+ /**
6
+ * Returns the full tool definitions (schema) for all tools matching the given patterns.
7
+ * Used by agents to discover argument shapes before calling via callTool.
8
+ */
9
+ export function inspectTools(
10
+ this: ToolsService,
11
+ patterns?: string[]
12
+ ): object[] {
13
+ const service = this as unknown as MinimalToolsService;
14
+ const allTools = service.getAllTools ? service.getAllTools() : service.getTools();
15
+
16
+ if (!patterns || patterns.length === 0) {
17
+ return allTools.map((t) => t.function);
18
+ }
19
+
20
+ return allTools
21
+ .filter((t) =>
22
+ patterns.some((pattern) =>
23
+ minimatch(t.function.name, pattern, { nocase: true })
24
+ )
25
+ )
26
+ .map((t) => t.function);
27
+ }
@@ -28,6 +28,7 @@ import {
28
28
  XmlToolCallProcessor,
29
29
  HarmonyToolProcessor,
30
30
  Base64ImageProcessor,
31
+ MinimalToolsMessageProcessor,
31
32
  } from "../../processors/index";
32
33
  import { TaskInfo } from "../types";
33
34
  import { createAgent, agentConstructors, AgentName } from "../../agents";
@@ -124,13 +125,16 @@ export class AgentModule extends BaseChatModule {
124
125
  },
125
126
  {
126
127
  name: "poke",
127
- description: "Interrupt the agent's current tool call or AI completion, so it can continue with the next step",
128
+ description:
129
+ "Interrupt the agent's current tool call or AI completion, so it can continue with the next step",
128
130
  modes: ["agent:attached"],
129
131
  handler: async (args: string[]): Promise<void> => {
130
132
  if (this.attachedAgent) {
131
133
  const message = args.length > 0 ? args.join(" ") : undefined;
132
134
  this.attachedAgent.interrupt(message);
133
- console.log("Agent interrupted — it will continue with the next step.");
135
+ console.log(
136
+ "Agent interrupted — it will continue with the next step."
137
+ );
134
138
  }
135
139
  },
136
140
  },
@@ -531,10 +535,14 @@ export class AgentModule extends BaseChatModule {
531
535
  const threads = session.threads || [];
532
536
  // Guard against sessions saved with a flat Message[] instead of Message[][]
533
537
  // (a bug where threadUpdate emitted a single thread instead of all threads)
534
- const normalizedThreads: Message[][] = threads.length > 0 && !Array.isArray(threads[0])
535
- ? [threads as unknown as Message[]]
536
- : threads as Message[][];
537
- const lastThread = normalizedThreads.length > 0 ? normalizedThreads[normalizedThreads.length - 1] : [];
538
+ const normalizedThreads: Message[][] =
539
+ threads.length > 0 && !Array.isArray(threads[0])
540
+ ? [threads as unknown as Message[]]
541
+ : (threads as Message[][]);
542
+ const lastThread =
543
+ normalizedThreads.length > 0
544
+ ? normalizedThreads[normalizedThreads.length - 1]
545
+ : [];
538
546
  const resumeMessages = [...lastThread];
539
547
 
540
548
  // Append the resume prompt to the last user message (or add a new one)
@@ -548,7 +556,9 @@ export class AgentModule extends BaseChatModule {
548
556
  const actualIndex = lastThread.length - 1 - reversedIndex;
549
557
  resumeMessages[actualIndex] = {
550
558
  ...resumeMessages[actualIndex],
551
- content: resumeMessages[actualIndex].content + `\n\n<Workflow>[RESUME CONTEXT]: ${resumePrompt}</Workflow>`,
559
+ content:
560
+ resumeMessages[actualIndex].content +
561
+ `\n\n<Workflow>[RESUME CONTEXT]: ${resumePrompt}</Workflow>`,
552
562
  };
553
563
  }
554
564
 
@@ -584,7 +594,12 @@ export class AgentModule extends BaseChatModule {
584
594
  }
585
595
  });
586
596
 
587
- await this.attachedAgentChatLoop(taskId, agent, resumePrompt, resumeMessages);
597
+ await this.attachedAgentChatLoop(
598
+ taskId,
599
+ agent,
600
+ resumePrompt,
601
+ resumeMessages
602
+ );
588
603
  } catch (error) {
589
604
  console.error(
590
605
  `Failed to resume session ${sessionId}:`,
@@ -781,6 +796,10 @@ export class AgentModule extends BaseChatModule {
781
796
  new HarmonyToolProcessor().createProcessor(),
782
797
  ]);
783
798
 
799
+ agent.messageProcessor.setProcessors("pre_tools", [
800
+ new MinimalToolsMessageProcessor().createProcessor(),
801
+ ]);
802
+
784
803
  agent.messageProcessor.setProcessors("post_tools", [
785
804
  new Base64ImageProcessor(agent.tools).createProcessor(),
786
805
  ...caching,
@@ -10,6 +10,9 @@ import { Models, EmbeddingModels } from "../types";
10
10
  */
11
11
  export const ContextLimits: Record<string, number> = {
12
12
  // ─── OpenAI ───────────────────────────────────────────────────────────────
13
+ [Models.openai.GPT_56_Sol]: 1_000_000,
14
+ [Models.openai.GPT_56_Terra]: 1_000_000,
15
+ [Models.openai.GPT_56_Luna]: 1_000_000,
13
16
  [Models.openai.GPT_55]: 1_000_000,
14
17
  [Models.openai.GPT_54]: 1_000_000,
15
18
  [Models.openai.GPT_54_Mini]: 400_000,
@@ -83,6 +86,11 @@ export const ContextLimits: Record<string, number> = {
83
86
  // ─── Anthropic ────────────────────────────────────────────────────────────
84
87
  [Models.anthropic.Opus4_8Fast]: 1_000_000,
85
88
  [Models.anthropic.Opus4_8]: 1_000_000,
89
+ // Claude 5 generation (launched 2026-06-09, 1M context window)
90
+ [Models.anthropic.Fable5]: 1_000_000,
91
+ [Models.anthropic.Sonnet5]: 1_000_000,
92
+ [Models.anthropic.Mythos5]: 1_000_000,
93
+ [Models.anthropic.MythosPreview]: 1_000_000,
86
94
  [Models.anthropic.Opus4_7]: 1_000_000,
87
95
  [Models.anthropic.Opus4_6]: 1_000_000,
88
96
  [Models.anthropic.Opus4_6Fast]: 1_000_000,
@@ -166,6 +174,7 @@ export const ContextLimits: Record<string, number> = {
166
174
  [Models.xai.GrokBeta]: 131_072,
167
175
  [Models.xai.GrokVisionBeta]: 131_072,
168
176
  [Models.xai.Grok4_1_Fast]: 2_000_000,
177
+ [Models.xai.Grok4_5]: 500_000,
169
178
  [Models.xai.Grok4Fast]: 2_000_000,
170
179
  [Models.xai.Grok4FastNonReasoning]: 2_000_000,
171
180
  // xAI image/video models — no text context window
@@ -41,6 +41,7 @@ import {
41
41
  XaiImagePricing,
42
42
  XaiVideoPricing,
43
43
  } from "./pricing/xai";
44
+ import { MetaTextPricing } from "./pricing/meta";
44
45
  import type {
45
46
  ModelPricing,
46
47
  ModelType,
@@ -56,6 +57,7 @@ import { GenericMistralClient } from "./mistral";
56
57
  import { GitHubCopilotClient } from "./copilot";
57
58
  import { GenericLlamaClient } from "./llama";
58
59
  import { GenericFireworksClient } from "./fireworks";
60
+ import { GenericMetaClient } from "./meta";
59
61
  export {
60
62
  OpenAiTextPricing,
61
63
  AnthropicTextPricing,
@@ -100,6 +102,7 @@ const BUILT_IN_PROVIDER_REGISTRY: Record<string, ProviderRegistryEntry> = {
100
102
  "github-copilot": { clientClass: GitHubCopilotClient },
101
103
  llama: { clientClass: GenericLlamaClient },
102
104
  fireworks: { clientClass: GenericFireworksClient },
105
+ meta: { clientClass: GenericMetaClient },
103
106
  knowhow: {
104
107
  createClient: (entry: ModelProvider) => {
105
108
  const jwt = loadKnowhowJwt();
@@ -130,6 +133,7 @@ const DEFAULT_PROVIDERS: ModelProvider[] = [
130
133
  { provider: "github-copilot", envKey: "GITHUB_COPILOT_TOKEN" },
131
134
  { provider: "llama", envKey: "LLAMA_API_KEY" },
132
135
  { provider: "fireworks", envKey: "FIREWORKS_API_KEY" },
136
+ { provider: "meta", envKey: "META_API_KEY" },
133
137
  ];
134
138
 
135
139
  export class AIClient {
@@ -1021,6 +1025,7 @@ export class AIClient {
1021
1025
  ...GeminiPricing,
1022
1026
  ...XaiTextPricing,
1023
1027
  ...FireworksTextPricing,
1028
+ ...MetaTextPricing,
1024
1029
  };
1025
1030
  const allImagePricing: Record<string, ModelPricing> = {
1026
1031
  ...XaiImagePricing,
@@ -1066,3 +1071,4 @@ export * from "./mistral";
1066
1071
  export * from "./llama";
1067
1072
  export * from "./copilot";
1068
1073
  export * from "./fireworks";
1074
+ export * from "./meta";
@@ -0,0 +1,18 @@
1
+ import { HttpClient } from "./http";
2
+ import { MetaTextPricing } from "./pricing/meta";
3
+
4
+ /**
5
+ * Meta Model API client — OpenAI-compatible API
6
+ * https://api.meta.ai
7
+ * Drop-in compatible with the OpenAI SDK (Responses + Chat Completions) and
8
+ * the Anthropic SDK (Messages API). Serves Meta's Muse Spark model with a
9
+ * 1,048,576 token context window.
10
+ * Set env var META_API_KEY to enable.
11
+ */
12
+ export class GenericMetaClient extends HttpClient {
13
+ constructor(apiKey = process.env.META_API_KEY) {
14
+ super("https://api.meta.ai");
15
+ if (apiKey) this.setJwt(apiKey);
16
+ this.setPrices(MetaTextPricing);
17
+ }
18
+ }
@@ -9,6 +9,10 @@ import { completions, ModelCatalogEntry, ModelPricing } from "./types";
9
9
 
10
10
  export const AnthropicModels = {
11
11
  // Active models
12
+ Fable5: "claude-fable-5",
13
+ Sonnet5: "claude-sonnet-5",
14
+ Mythos5: "claude-mythos-5",
15
+ MythosPreview: "claude-mythos-preview",
12
16
  Opus4_8: "claude-opus-4-8",
13
17
  Opus4_8Fast: "claude-opus-4-8-fast",
14
18
  Opus4_7: "claude-opus-4-7",
@@ -39,6 +43,8 @@ export const AnthropicModels = {
39
43
 
40
44
  export const AnthropicTextModels: string[] = [
41
45
  AnthropicModels.Opus4_8,
46
+ AnthropicModels.Fable5,
47
+ AnthropicModels.Sonnet5,
42
48
  AnthropicModels.Opus4_7,
43
49
  AnthropicModels.Opus4_6,
44
50
  AnthropicModels.Sonnet4_6,
@@ -51,6 +57,8 @@ export const AnthropicTextModels: string[] = [
51
57
  // Models in our catalog but not yet publicly available
52
58
  export const AnthropicLimitedAvailabilityModels: string[] = [
53
59
  AnthropicModels.Opus4_8Fast, // fast mode pricing
60
+ AnthropicModels.Mythos5, // invitation-only (Project Glasswing)
61
+ AnthropicModels.MythosPreview, // invitation-only (defensive cybersecurity)
54
62
  AnthropicModels.Opus4_6Fast, // 404 – not publicly available yet
55
63
  ];
56
64
 
@@ -80,6 +88,11 @@ const AnthropicAllModels: string[] = [
80
88
  export const AnthropicTextPricing: Record<string, ModelPricing> = {
81
89
  [AnthropicModels.Opus4_8]: { input: 5.0, cache_write: 6.25, cache_hit: 0.5, output: 25.0 },
82
90
  [AnthropicModels.Opus4_8Fast]: { input: 10.0, cache_write: 12.5, cache_hit: 1.0, output: 50.0, limitedAvailability: true },
91
+ // Claude 5 generation (launched 2026-06-09)
92
+ [AnthropicModels.Fable5]: { input: 10.0, cache_write: 12.5, cache_hit: 1.0, output: 50.0 },
93
+ [AnthropicModels.Sonnet5]: { input: 3.0, cache_write: 3.75, cache_hit: 0.3, output: 15.0 },
94
+ [AnthropicModels.Mythos5]: { input: 10.0, cache_write: 12.5, cache_hit: 1.0, output: 50.0, limitedAvailability: true },
95
+ [AnthropicModels.MythosPreview]: { input: 10.0, cache_write: 12.5, cache_hit: 1.0, output: 50.0, limitedAvailability: true },
83
96
  [AnthropicModels.Opus4_7]: { input: 5.0, cache_write: 6.25, cache_hit: 0.5, output: 25.0 },
84
97
  [AnthropicModels.Opus4_6]: { input: 5.0, cache_write: 6.25, cache_hit: 0.5, output: 25.0 },
85
98
  [AnthropicModels.Opus4_6Fast]: { input: 30.0, cache_write: 37.5, cache_hit: 3.0, output: 150.0, limitedAvailability: true },
@@ -1,8 +1,10 @@
1
+ import { ModelPricing } from "./types";
2
+
1
3
  /**
2
4
  * Fireworks AI pricing (USD per 1M tokens)
3
5
  * Source: https://fireworks.ai/pricing
4
6
  */
5
- export const FireworksTextPricing: Record<string, { input: number; output: number; cache_hit?: number }> = {
7
+ export const FireworksTextPricing: Record<string, ModelPricing> = {
6
8
  // Moonshot AI
7
9
  "accounts/fireworks/models/kimi-k2p7-code": { input: 0.95, cache_hit: 0.19, output: 4.0 },
8
10
  "accounts/fireworks/models/kimi-k2-6": { input: 0.95, cache_hit: 0.16, output: 4.0 },
@@ -14,22 +16,26 @@ export const FireworksTextPricing: Record<string, { input: number; output: numbe
14
16
  "accounts/fireworks/models/minimax-m2-5": { input: 0.30, cache_hit: 0.03, output: 1.20 },
15
17
 
16
18
  // Qwen
17
- "accounts/fireworks/models/qwen3-6-plus": { input: 0.50, cache_hit: 0.10, output: 3.0 },
18
- "accounts/fireworks/models/qwen3p6-plus": { input: 0.50, cache_hit: 0.10, output: 3.0 },
19
- "accounts/fireworks/models/qwen3-vl-30b-a3b-thinking": { input: 0.15, cache_hit: 0.08, output: 0.60 },
20
- "accounts/fireworks/models/qwen3-vl-30b-a3b-instruct": { input: 0.15, cache_hit: 0.08, output: 0.60 },
21
- "accounts/fireworks/models/qwen3-8b": { input: 0.20, cache_hit: 0.10, output: 0.20 },
19
+ "accounts/fireworks/models/qwen3p7-plus": { input: 0.40, cache_hit: 0.08, output: 1.60 },
20
+
21
+ // Deprecated QWEN Models
22
+ "accounts/fireworks/models/qwen3-6-plus": { input: 0.50, cache_hit: 0.10, output: 3.0, deprecated: true},
23
+ "accounts/fireworks/models/qwen3p6-plus": { input: 0.50, cache_hit: 0.10, output: 3.0, deprecated: true},
24
+ "accounts/fireworks/models/qwen3-vl-30b-a3b-thinking": { input: 0.15, cache_hit: 0.08, output: 0.60, deprecated: true},
25
+ "accounts/fireworks/models/qwen3-vl-30b-a3b-instruct": { input: 0.15, cache_hit: 0.08, output: 0.60, deprecated: true},
26
+ "accounts/fireworks/models/qwen3-8b": { input: 0.20, cache_hit: 0.10, output: 0.20, deprecated: true},
22
27
 
23
28
  // Z.ai
24
29
  "accounts/fireworks/models/glm-5p2": { input: 1.40, cache_hit: 0.26, output: 4.40 },
25
- "accounts/fireworks/models/glm-5-2": { input: 1.40, cache_hit: 0.26, output: 4.40 },
26
- "accounts/fireworks/models/glm-5-1": { input: 1.40, cache_hit: 0.26, output: 4.40 },
27
- "accounts/fireworks/models/glm-5": { input: 1.00, cache_hit: 0.20, output: 3.20 },
28
- "accounts/fireworks/models/glm-4-7": { input: 0.60, cache_hit: 0.30, output: 2.20 },
30
+ "accounts/fireworks/models/glm-5p1": { input: 1.40, cache_hit: 0.26, output: 4.40 },
31
+ "accounts/fireworks/models/glm-5": { input: 1.00, cache_hit: 0.20, output: 3.20, deprecated: true },
32
+ "accounts/fireworks/models/glm-4-7": { input: 0.60, cache_hit: 0.30, output: 2.20, deprecated: true},
29
33
 
30
34
  // DeepSeek AI
31
- "accounts/fireworks/models/deepseek-v3-2": { input: 0.56, cache_hit: 0.28, output: 1.68 },
32
- "accounts/fireworks/models/deepseek-v3-1": { input: 0.56, cache_hit: 0.28, output: 1.68 },
35
+ "accounts/fireworks/models/deepseek-v4-pro": { input: 1.74, cache_hit: 0.15, output: 3.48 },
36
+ "accounts/fireworks/models/deepseek-v4-flash": { input: 0.14, cache_hit: 0.03, output: 0.28 },
37
+ "accounts/fireworks/models/deepseek-v3-2": { input: 0.56, cache_hit: 0.28, output: 1.68, deprecated: true },
38
+ "accounts/fireworks/models/deepseek-v3-1": { input: 0.56, cache_hit: 0.28, output: 1.68, deprecated: true },
33
39
 
34
40
  // OpenAI OSS
35
41
  "accounts/fireworks/models/gpt-oss-120b": { input: 0.15, cache_hit: 0.01, output: 0.60 },
@@ -36,6 +36,7 @@ export { OpenRouterTextPricing } from "./openrouter";
36
36
  export { LlamaTextPricing } from "./llama";
37
37
  export { CopilotTextPricing, CopilotModelMultipliers } from "./copilot";
38
38
  export { FireworksTextPricing } from "./fireworks";
39
+ export { MetaTextPricing, MetaWebSearchPricingPer1000Queries } from "./meta";
39
40
 
40
41
  // ─── Combined catalog ─────────────────────────────────────────────────────────
41
42
  export { ALL_MODEL_CATALOG, USAGE_MARKUP_PERCENT } from "./models";
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Meta Model API pricing (USD per 1M tokens)
3
+ * Source: Meta Model API docs — https://api.meta.ai
4
+ * New accounts start with $20 in free credits.
5
+ */
6
+ export const MetaTextPricing: Record<string, { input: number; output: number; cached_input?: number }> = {
7
+ "muse-spark-1.1": { input: 1.25, output: 4.25, cached_input: 0.15 },
8
+ };
9
+
10
+ // Web search grounding is billed per 1,000 search queries ($2.50/1,000),
11
+ // not per-token, so it isn't represented in the per-token pricing map above.
12
+ export const MetaWebSearchPricingPer1000Queries = 2.5;
@@ -16,6 +16,9 @@ import {
16
16
  // ─── Model IDs ────────────────────────────────────────────────────────────────
17
17
 
18
18
  export const OpenAiModels = {
19
+ GPT_56_Sol: "gpt-5.6-sol",
20
+ GPT_56_Terra: "gpt-5.6-terra",
21
+ GPT_56_Luna: "gpt-5.6-luna",
19
22
  GPT_55: "gpt-5.5",
20
23
  GPT_55_Pro: "gpt-5.5-pro",
21
24
  GPT_54: "gpt-5.4",
@@ -95,6 +98,9 @@ export const OpenAiEmbeddingModels: Record<string, string> = {
95
98
 
96
99
  export const OpenAiReasoningModels: string[] = [
97
100
  OpenAiModels.GPT_5,
101
+ OpenAiModels.GPT_56_Sol,
102
+ OpenAiModels.GPT_56_Terra,
103
+ OpenAiModels.GPT_56_Luna,
98
104
  OpenAiModels.GPT_5_Pro,
99
105
  OpenAiModels.GPT_5_Mini,
100
106
  OpenAiModels.GPT_5_Nano,
@@ -125,6 +131,9 @@ export const OpenAiChatModels: string[] = [
125
131
  OpenAiModels.GPT_41,
126
132
  OpenAiModels.GPT_41_Mini,
127
133
  OpenAiModels.GPT_41_Nano,
134
+ OpenAiModels.GPT_56_Sol,
135
+ OpenAiModels.GPT_56_Terra,
136
+ OpenAiModels.GPT_56_Luna,
128
137
  OpenAiModels.GPT_54,
129
138
  OpenAiModels.GPT_54_Mini,
130
139
  OpenAiModels.GPT_55,
@@ -218,6 +227,10 @@ export const OpenAiSearchModels: string[] = [
218
227
  // ─── Pricing (USD per 1M tokens) ──────────────────────────────────────────────
219
228
 
220
229
  export const OpenAiTextPricing: Record<string, ModelPricing> = {
230
+ // gpt-5.6 series — short context / long context pricing
231
+ [OpenAiModels.GPT_56_Sol]: { input: 5.0, cached_input: 0.5, cache_write: 6.25, output: 30.0, input_gt_200k: 10.0, output_gt_200k: 45.0 },
232
+ [OpenAiModels.GPT_56_Terra]: { input: 2.5, cached_input: 0.25, cache_write: 3.125, output: 15.0, input_gt_200k: 5.0, output_gt_200k: 22.5 },
233
+ [OpenAiModels.GPT_56_Luna]: { input: 1.0, cached_input: 0.10, cache_write: 1.25, output: 6.0, input_gt_200k: 2.0, output_gt_200k: 9.0 },
221
234
  [OpenAiModels.GPT_55]: { input: 5.0, cached_input: 0.5, output: 30.0 },
222
235
  [OpenAiModels.GPT_55_Pro]: { input: 30.0, cached_input: 0, output: 180.0, reasoningLevels: ["medium", "high", "xhigh"] },
223
236
  [OpenAiModels.GPT_54]: { input: 2.5, cached_input: 0.25, output: 15.0 },
@@ -10,6 +10,7 @@ export const XaiModels = {
10
10
  Grok_4_20_Reasoning: "grok-4.20-0309-reasoning",
11
11
  Grok_4_20_NonReasoning: "grok-4.20-0309-non-reasoning",
12
12
  Grok_4_20_MultiAgent: "grok-4.20-multi-agent-0309",
13
+ Grok4_5: "grok-4.5",
13
14
  Grok4_1_Fast_Reasoning: "grok-4-1-fast-reasoning",
14
15
  Grok4_1_Fast_NonReasoning: "grok-4-1-fast-non-reasoning",
15
16
  GrokCodeFast: "grok-code-fast-1",
@@ -44,6 +45,7 @@ export const XaiTextModels: string[] = [
44
45
  XaiModels.Grok_4_20_Reasoning, XaiModels.Grok_4_20_NonReasoning,
45
46
  XaiModels.Grok_4_20_MultiAgent,
46
47
  XaiModels.Grok4_1_Fast_Reasoning, XaiModels.Grok4_1_Fast_NonReasoning,
48
+ XaiModels.Grok4_5,
47
49
  XaiModels.GrokCodeFast, XaiModels.Grok4,
48
50
  XaiModels.Grok3Beta, XaiModels.Grok3MiniBeta, XaiModels.Grok3FastBeta, XaiModels.Grok3MiniFastBeta,
49
51
  ];
@@ -87,6 +89,7 @@ export const XaiTextPricing: Record<string, ModelPricing> = {
87
89
  [XaiModels.Grok_4_20_MultiAgent]: { input: 2.0, cache_hit: 0.20, output: 6.0, reasoningLevels: ["low", "medium", "high", "xhigh"], useResponsesApi: true },
88
90
  [XaiModels.Grok4_1_Fast_Reasoning]: { input: 0.2, cache_hit: 0.05, output: 0.5, useResponsesApi: true },
89
91
  [XaiModels.Grok4_1_Fast_NonReasoning]: { input: 0.2, cache_hit: 0.05, output: 0.5, useResponsesApi: true },
92
+ [XaiModels.Grok4_5]: { input: 2.0, cache_hit: 0.50, output: 6.0 },
90
93
  [XaiModels.GrokCodeFast]: { input: 0.2, cache_hit: 0.02, output: 1.5 },
91
94
  [XaiModels.Grok4]: { input: 3.0, output: 15.0 },
92
95
  [XaiModels.Grok3Beta]: { input: 3.0, output: 15.0 },
@@ -1,6 +1,6 @@
1
1
  import { includedTools } from "../agents/tools/list";
2
2
  import * as allTools from "../agents/tools";
3
- import { LazyToolsService, services } from "../services";
3
+ import { LazyToolsService, services, MinimalToolsService } from "../services";
4
4
  import { agents } from "../agents";
5
5
  import { ModulesService } from "../services/modules";
6
6
 
@@ -0,0 +1,113 @@
1
+ import { Message, ToolCall } from "../clients/types";
2
+ import { MessageProcessorFunction } from "../services/MessageProcessor";
3
+
4
+ /**
5
+ * MinimalToolsMessageProcessor
6
+ *
7
+ * Works with MinimalToolsService to unwrap `callTool(name, args)` invocations
8
+ * in the message history, rewriting them as if the real tool had been called
9
+ * directly.
10
+ *
11
+ * This is registered on the `pre_tools` lifecycle so it runs right before tool
12
+ * calls are dispatched. It rewrites the last assistant message's tool_calls so
13
+ * that:
14
+ * callTool({ name: "readFile", args: { filePath: "..." } })
15
+ * becomes:
16
+ * readFile({ filePath: "..." })
17
+ *
18
+ * This means:
19
+ * 1. The `tools:` array sent to the AI never needs to change (cache stable).
20
+ * 2. The agent terminates correctly when callTool("finalAnswer", ...) is called,
21
+ * because after transformation the required tool name matches.
22
+ * 3. The conversation history looks clean — the model sees native tool calls in
23
+ * subsequent turns rather than nested callTool wrappers.
24
+ */
25
+ export class MinimalToolsMessageProcessor {
26
+ /**
27
+ * Unwraps a single callTool ToolCall into the real underlying ToolCall.
28
+ * Returns null if this is not a callTool invocation.
29
+ */
30
+ private unwrapCallTool(toolCall: ToolCall): ToolCall | null {
31
+ if (toolCall.function.name !== "callTool") {
32
+ return null;
33
+ }
34
+
35
+ let parsed: { name?: string; args?: Record<string, any> };
36
+ try {
37
+ parsed =
38
+ typeof toolCall.function.arguments === "string"
39
+ ? JSON.parse(toolCall.function.arguments)
40
+ : toolCall.function.arguments;
41
+ } catch {
42
+ return null;
43
+ }
44
+
45
+ const { name, args } = parsed;
46
+ if (!name || typeof name !== "string") {
47
+ return null;
48
+ }
49
+
50
+ return {
51
+ id: toolCall.id,
52
+ type: "function",
53
+ function: {
54
+ name,
55
+ arguments: JSON.stringify(args ?? {}),
56
+ },
57
+ };
58
+ }
59
+
60
+ /**
61
+ * Processes the modified messages array in-place:
62
+ * - Finds assistant messages whose tool_calls contain callTool invocations.
63
+ * - Replaces those callTool entries with the real underlying tool calls.
64
+ *
65
+ * Only the most-recent assistant message (the one just added by the AI) is
66
+ * rewritten — older messages are left untouched so caching is not affected.
67
+ */
68
+ private processMessages(
69
+ _originalMessages: Message[],
70
+ modifiedMessages: Message[]
71
+ ): void {
72
+ // Walk backwards to find the last assistant message with tool_calls
73
+ for (let i = modifiedMessages.length - 1; i >= 0; i--) {
74
+ const msg = modifiedMessages[i];
75
+ if (msg.role !== "assistant" || !msg.tool_calls?.length) {
76
+ continue;
77
+ }
78
+
79
+ let didUnwrap = false;
80
+ const newToolCalls: ToolCall[] = msg.tool_calls.map((tc) => {
81
+ const unwrapped = this.unwrapCallTool(tc);
82
+ if (unwrapped) {
83
+ didUnwrap = true;
84
+ return unwrapped;
85
+ }
86
+ return tc;
87
+ });
88
+
89
+ if (didUnwrap) {
90
+ msg.tool_calls = newToolCalls;
91
+ }
92
+
93
+ // Only process the last assistant message
94
+ break;
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Returns a MessageProcessorFunction suitable for registering on the
100
+ * `pre_tools` lifecycle of a MessageProcessor.
101
+ */
102
+ createProcessor(): MessageProcessorFunction {
103
+ return (
104
+ originalMessages: Message[],
105
+ modifiedMessages: Message[]
106
+ ): void => {
107
+ this.processMessages(originalMessages, modifiedMessages);
108
+ };
109
+ }
110
+ }
111
+
112
+ export const globalMinimalToolsMessageProcessor =
113
+ new MinimalToolsMessageProcessor();