@tyvm/knowhow 0.0.128 → 0.0.130

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 (183) hide show
  1. package/package.json +5 -4
  2. package/scripts/cache-miss-debug.ts +365 -0
  3. package/src/agents/base/base.ts +159 -59
  4. package/src/agents/tools/execCommand.ts +26 -6
  5. package/src/agents/tools/index.ts +1 -0
  6. package/src/agents/tools/list.ts +2 -0
  7. package/src/agents/tools/minimal/callTool.ts +45 -0
  8. package/src/agents/tools/minimal/definitions.ts +50 -0
  9. package/src/agents/tools/minimal/index.ts +3 -0
  10. package/src/agents/tools/minimal/inspectTools.ts +27 -0
  11. package/src/agents/tools/skills.ts +79 -0
  12. package/src/chat/modules/AgentModule.ts +111 -9
  13. package/src/cli.ts +4 -0
  14. package/src/clients/anthropic.ts +59 -1
  15. package/src/clients/contextLimits.ts +9 -0
  16. package/src/clients/index.ts +6 -0
  17. package/src/clients/meta.ts +18 -0
  18. package/src/clients/openai.ts +28 -5
  19. package/src/clients/pricing/anthropic.ts +13 -0
  20. package/src/clients/pricing/fireworks.ts +18 -12
  21. package/src/clients/pricing/index.ts +1 -0
  22. package/src/clients/pricing/meta.ts +12 -0
  23. package/src/clients/pricing/openai.ts +16 -0
  24. package/src/clients/pricing/xai.ts +3 -0
  25. package/src/clients/types.ts +27 -4
  26. package/src/clients/xai.ts +2 -2
  27. package/src/commands/agent.ts +19 -0
  28. package/src/commands/behaviors.ts +47 -0
  29. package/src/commands/services.ts +7 -3
  30. package/src/commands/skills.ts +71 -0
  31. package/src/index.ts +2 -0
  32. package/src/plugins/PluginBase.ts +0 -2
  33. package/src/plugins/SkillsPlugin.ts +11 -124
  34. package/src/plugins/language.ts +0 -1
  35. package/src/plugins/plugins.ts +24 -13
  36. package/src/plugins/types.ts +8 -2
  37. package/src/processors/MinimalToolsMessageProcessor.ts +113 -0
  38. package/src/processors/TokenCompressor.ts +21 -4
  39. package/src/processors/index.ts +7 -1
  40. package/src/services/AgentSyncFs.ts +49 -0
  41. package/src/services/AgentSyncKnowhowWeb.ts +1 -1
  42. package/src/services/BehaviorsService.ts +432 -0
  43. package/src/services/KnowhowClient.ts +62 -1
  44. package/src/services/LazyToolsService.ts +12 -0
  45. package/src/services/MinimalToolsService.ts +167 -0
  46. package/src/services/SkillsService.ts +622 -0
  47. package/src/services/Tools.ts +11 -0
  48. package/src/services/index.ts +9 -2
  49. package/src/services/modules/types.ts +2 -0
  50. package/src/worker.ts +7 -0
  51. package/tests/processors/TokenCompressor.test.ts +45 -0
  52. package/tests/unit/services/MinimalToolsService.test.ts +424 -0
  53. package/ts_build/package.json +5 -4
  54. package/ts_build/src/agents/base/base.d.ts +13 -2
  55. package/ts_build/src/agents/base/base.js +91 -35
  56. package/ts_build/src/agents/base/base.js.map +1 -1
  57. package/ts_build/src/agents/tools/execCommand.d.ts +1 -1
  58. package/ts_build/src/agents/tools/execCommand.js +18 -5
  59. package/ts_build/src/agents/tools/execCommand.js.map +1 -1
  60. package/ts_build/src/agents/tools/index.d.ts +1 -0
  61. package/ts_build/src/agents/tools/index.js +1 -0
  62. package/ts_build/src/agents/tools/index.js.map +1 -1
  63. package/ts_build/src/agents/tools/list.js +2 -0
  64. package/ts_build/src/agents/tools/list.js.map +1 -1
  65. package/ts_build/src/agents/tools/minimal/callTool.d.ts +5 -0
  66. package/ts_build/src/agents/tools/minimal/callTool.js +28 -0
  67. package/ts_build/src/agents/tools/minimal/callTool.js.map +1 -0
  68. package/ts_build/src/agents/tools/minimal/definitions.d.ts +4 -0
  69. package/ts_build/src/agents/tools/minimal/definitions.js +46 -0
  70. package/ts_build/src/agents/tools/minimal/definitions.js.map +1 -0
  71. package/ts_build/src/agents/tools/minimal/index.d.ts +3 -0
  72. package/ts_build/src/agents/tools/minimal/index.js +20 -0
  73. package/ts_build/src/agents/tools/minimal/index.js.map +1 -0
  74. package/ts_build/src/agents/tools/minimal/inspectTools.d.ts +2 -0
  75. package/ts_build/src/agents/tools/minimal/inspectTools.js +15 -0
  76. package/ts_build/src/agents/tools/minimal/inspectTools.js.map +1 -0
  77. package/ts_build/src/agents/tools/skills.d.ts +33 -0
  78. package/ts_build/src/agents/tools/skills.js +62 -0
  79. package/ts_build/src/agents/tools/skills.js.map +1 -0
  80. package/ts_build/src/chat/modules/AgentModule.d.ts +2 -0
  81. package/ts_build/src/chat/modules/AgentModule.js +77 -2
  82. package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
  83. package/ts_build/src/chat/modules/CustomCommandsModule.d.ts +1 -1
  84. package/ts_build/src/cli.js +4 -0
  85. package/ts_build/src/cli.js.map +1 -1
  86. package/ts_build/src/clients/anthropic.d.ts +2 -0
  87. package/ts_build/src/clients/anthropic.js +35 -0
  88. package/ts_build/src/clients/anthropic.js.map +1 -1
  89. package/ts_build/src/clients/contextLimits.js +8 -0
  90. package/ts_build/src/clients/contextLimits.js.map +1 -1
  91. package/ts_build/src/clients/index.d.ts +1 -0
  92. package/ts_build/src/clients/index.js +6 -0
  93. package/ts_build/src/clients/index.js.map +1 -1
  94. package/ts_build/src/clients/meta.d.ts +4 -0
  95. package/ts_build/src/clients/meta.js +15 -0
  96. package/ts_build/src/clients/meta.js.map +1 -0
  97. package/ts_build/src/clients/openai.d.ts +1 -0
  98. package/ts_build/src/clients/openai.js +25 -5
  99. package/ts_build/src/clients/openai.js.map +1 -1
  100. package/ts_build/src/clients/pricing/anthropic.d.ts +4 -0
  101. package/ts_build/src/clients/pricing/anthropic.js +12 -0
  102. package/ts_build/src/clients/pricing/anthropic.js.map +1 -1
  103. package/ts_build/src/clients/pricing/fireworks.d.ts +2 -5
  104. package/ts_build/src/clients/pricing/fireworks.js +13 -11
  105. package/ts_build/src/clients/pricing/fireworks.js.map +1 -1
  106. package/ts_build/src/clients/pricing/index.d.ts +1 -0
  107. package/ts_build/src/clients/pricing/index.js +5 -2
  108. package/ts_build/src/clients/pricing/index.js.map +1 -1
  109. package/ts_build/src/clients/pricing/meta.d.ts +6 -0
  110. package/ts_build/src/clients/pricing/meta.js +8 -0
  111. package/ts_build/src/clients/pricing/meta.js.map +1 -0
  112. package/ts_build/src/clients/pricing/openai.d.ts +3 -0
  113. package/ts_build/src/clients/pricing/openai.js +15 -0
  114. package/ts_build/src/clients/pricing/openai.js.map +1 -1
  115. package/ts_build/src/clients/pricing/xai.d.ts +1 -0
  116. package/ts_build/src/clients/pricing/xai.js +3 -0
  117. package/ts_build/src/clients/pricing/xai.js.map +1 -1
  118. package/ts_build/src/clients/types.d.ts +6 -1
  119. package/ts_build/src/clients/xai.js +1 -1
  120. package/ts_build/src/clients/xai.js.map +1 -1
  121. package/ts_build/src/commands/agent.js +16 -0
  122. package/ts_build/src/commands/agent.js.map +1 -1
  123. package/ts_build/src/commands/behaviors.d.ts +2 -0
  124. package/ts_build/src/commands/behaviors.js +43 -0
  125. package/ts_build/src/commands/behaviors.js.map +1 -0
  126. package/ts_build/src/commands/services.js +4 -2
  127. package/ts_build/src/commands/services.js.map +1 -1
  128. package/ts_build/src/commands/skills.d.ts +2 -0
  129. package/ts_build/src/commands/skills.js +61 -0
  130. package/ts_build/src/commands/skills.js.map +1 -0
  131. package/ts_build/src/index.d.ts +2 -0
  132. package/ts_build/src/index.js +5 -1
  133. package/ts_build/src/index.js.map +1 -1
  134. package/ts_build/src/plugins/PluginBase.d.ts +0 -2
  135. package/ts_build/src/plugins/PluginBase.js.map +1 -1
  136. package/ts_build/src/plugins/SkillsPlugin.d.ts +1 -6
  137. package/ts_build/src/plugins/SkillsPlugin.js +6 -135
  138. package/ts_build/src/plugins/SkillsPlugin.js.map +1 -1
  139. package/ts_build/src/plugins/language.js.map +1 -1
  140. package/ts_build/src/plugins/plugins.d.ts +4 -1
  141. package/ts_build/src/plugins/plugins.js +17 -11
  142. package/ts_build/src/plugins/plugins.js.map +1 -1
  143. package/ts_build/src/plugins/types.d.ts +3 -2
  144. package/ts_build/src/processors/MinimalToolsMessageProcessor.d.ts +7 -0
  145. package/ts_build/src/processors/MinimalToolsMessageProcessor.js +61 -0
  146. package/ts_build/src/processors/MinimalToolsMessageProcessor.js.map +1 -0
  147. package/ts_build/src/processors/TokenCompressor.js +5 -2
  148. package/ts_build/src/processors/TokenCompressor.js.map +1 -1
  149. package/ts_build/src/processors/index.d.ts +2 -1
  150. package/ts_build/src/processors/index.js +3 -1
  151. package/ts_build/src/processors/index.js.map +1 -1
  152. package/ts_build/src/services/AgentSyncFs.d.ts +2 -0
  153. package/ts_build/src/services/AgentSyncFs.js +30 -0
  154. package/ts_build/src/services/AgentSyncFs.js.map +1 -1
  155. package/ts_build/src/services/AgentSyncKnowhowWeb.js +1 -1
  156. package/ts_build/src/services/BehaviorsService.d.ts +46 -0
  157. package/ts_build/src/services/BehaviorsService.js +358 -0
  158. package/ts_build/src/services/BehaviorsService.js.map +1 -0
  159. package/ts_build/src/services/KnowhowClient.d.ts +9 -1
  160. package/ts_build/src/services/KnowhowClient.js +20 -0
  161. package/ts_build/src/services/KnowhowClient.js.map +1 -1
  162. package/ts_build/src/services/LazyToolsService.js.map +1 -1
  163. package/ts_build/src/services/MinimalToolsService.d.ts +14 -0
  164. package/ts_build/src/services/MinimalToolsService.js +80 -0
  165. package/ts_build/src/services/MinimalToolsService.js.map +1 -0
  166. package/ts_build/src/services/SkillsService.d.ts +53 -0
  167. package/ts_build/src/services/SkillsService.js +478 -0
  168. package/ts_build/src/services/SkillsService.js.map +1 -0
  169. package/ts_build/src/services/Tools.d.ts +2 -0
  170. package/ts_build/src/services/Tools.js.map +1 -1
  171. package/ts_build/src/services/index.d.ts +4 -0
  172. package/ts_build/src/services/index.js +9 -2
  173. package/ts_build/src/services/index.js.map +1 -1
  174. package/ts_build/src/services/modules/index.d.ts +4 -2
  175. package/ts_build/src/services/modules/types.d.ts +2 -0
  176. package/ts_build/src/types.d.ts +8 -0
  177. package/ts_build/src/worker.js +5 -0
  178. package/ts_build/src/worker.js.map +1 -1
  179. package/ts_build/tests/processors/TokenCompressor.test.js +27 -0
  180. package/ts_build/tests/processors/TokenCompressor.test.js.map +1 -1
  181. package/ts_build/tests/unit/services/MinimalToolsService.test.d.ts +1 -0
  182. package/ts_build/tests/unit/services/MinimalToolsService.test.js +320 -0
  183. package/ts_build/tests/unit/services/MinimalToolsService.test.js.map +1 -0
@@ -0,0 +1,79 @@
1
+ import { ToolsService } from "../../services/Tools";
2
+ import { services } from "../../services";
3
+
4
+ /**
5
+ * List all skills currently loaded in memory.
6
+ * Returns a formatted string of name: description lines.
7
+ */
8
+ export async function listSkills(this: ToolsService): Promise<string> {
9
+ const toolService =
10
+ this instanceof ToolsService ? (this as ToolsService) : services().Tools;
11
+
12
+ const { Behaviors } = toolService.getContext();
13
+
14
+ const skills = Behaviors.listSkills();
15
+ if (skills.length === 0) {
16
+ return "No skills available. Run `knowhow behaviors download --skills-only` to fetch skills.";
17
+ }
18
+ return skills.map((s) => `- ${s.name}: ${s.description}`).join("\n");
19
+ }
20
+
21
+ /**
22
+ * Load full instructions for a named skill from memory.
23
+ */
24
+ export async function loadSkill(
25
+ this: ToolsService,
26
+ name: string
27
+ ): Promise<string> {
28
+ const toolService =
29
+ this instanceof ToolsService ? (this as ToolsService) : services().Tools;
30
+
31
+ const { Behaviors } = toolService.getContext();
32
+
33
+ const skill = Behaviors.findSkill(name);
34
+ if (!skill) {
35
+ const names = Behaviors.listSkills()
36
+ .map((s) => s.name)
37
+ .join(", ");
38
+ return `Skill "${name}" not found. Available skills: ${names || "none"}`;
39
+ }
40
+ return `## Skill: ${skill.name}\n\n${skill.instructions}`;
41
+ }
42
+
43
+ /** Tool definitions for listSkills + loadSkill */
44
+ export const skillsToolDefinitions = [
45
+ {
46
+ type: "function" as const,
47
+ function: {
48
+ name: "listSkills",
49
+ description:
50
+ "List all available skills by name and description. Call this to discover what skills are available before loading one.",
51
+ parameters: {
52
+ type: "object" as const,
53
+ positional: true,
54
+ properties: {} as Record<string, never>,
55
+ required: [] as string[],
56
+ },
57
+ },
58
+ },
59
+ {
60
+ type: "function" as const,
61
+ function: {
62
+ name: "loadSkill",
63
+ description:
64
+ "Load the full instructions for a named skill. Use this when you need to follow a specific skill's guidance.",
65
+ parameters: {
66
+ type: "object" as const,
67
+ positional: true,
68
+ properties: {
69
+ name: {
70
+ type: "string",
71
+ description:
72
+ "The skill name to load (must match exactly or approximately)",
73
+ },
74
+ },
75
+ required: ["name"] as string[],
76
+ },
77
+ },
78
+ },
79
+ ];
@@ -18,7 +18,7 @@ import { BaseChatModule } from "./BaseChatModule";
18
18
  import { services } from "../../services/index";
19
19
  import { BaseAgent } from "../../agents/index";
20
20
  import { ChatCommand, ChatMode, ChatContext, ChatService } from "../types";
21
- import { Message } from "../../clients/types";
21
+ import { Message, CompletionOptions } from "../../clients/types";
22
22
  import { ChatInteraction } from "../../types";
23
23
  import { Marked } from "../../utils/index";
24
24
  import { TokenCompressor } from "../../processors/TokenCompressor";
@@ -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";
@@ -51,6 +52,11 @@ export class AgentModule extends BaseChatModule {
51
52
  /** Currently active synced agent watcher (for FS or Web agents) */
52
53
  private activeSyncedWatcher: SyncedAgentWatcher | undefined;
53
54
 
55
+ /** Reasoning effort to apply to agents started from this module */
56
+ private reasoningEffort: CompletionOptions["reasoning_effort"] | undefined = undefined;
57
+ /** Whether to request a reasoning summary from supporting models */
58
+ private summarizeReasoning: boolean = true;
59
+
54
60
  /** Stored wire params for rewireAgentRendering */
55
61
  private _wireAgentEvents: EventService | undefined;
56
62
  private _wireTaskId: string | undefined;
@@ -124,14 +130,89 @@ export class AgentModule extends BaseChatModule {
124
130
  },
125
131
  {
126
132
  name: "poke",
127
- description: "Interrupt the agent's current tool call or AI completion, so it can continue with the next step",
133
+ description:
134
+ "Interrupt the agent's current tool call or AI completion, so it can continue with the next step",
128
135
  modes: ["agent:attached"],
129
136
  handler: async (args: string[]): Promise<void> => {
130
137
  if (this.attachedAgent) {
131
138
  const message = args.length > 0 ? args.join(" ") : undefined;
132
139
  this.attachedAgent.interrupt(message);
133
- console.log("Agent interrupted — it will continue with the next step.");
140
+ console.log(
141
+ "Agent interrupted — it will continue with the next step."
142
+ );
143
+ }
144
+ },
145
+ },
146
+ {
147
+ name: "reasoning_effort",
148
+ description:
149
+ "Set the reasoning effort for the agent (none, low, medium, high). Use 'none' to disable thinking on models that support it.",
150
+ handler: async (args: string[]): Promise<void> => {
151
+ const validEfforts: CompletionOptions["reasoning_effort"][] = [
152
+ "none",
153
+ "low",
154
+ "medium",
155
+ "high",
156
+ ];
157
+ const effort = args[0] as CompletionOptions["reasoning_effort"];
158
+ if (!effort || !validEfforts.includes(effort)) {
159
+ console.log(
160
+ `Current reasoning effort: ${this.reasoningEffort ?? "(not set — model default)"}`
161
+ );
162
+ console.log(
163
+ `Usage: /reasoning_effort <${validEfforts.join("|")}>`
164
+ );
165
+ return;
134
166
  }
167
+ this.reasoningEffort = effort;
168
+ const agent = (this.chatService?.getContext()?.selectedAgent as BaseAgent);
169
+ if (agent) agent.setReasoningEffort(effort);
170
+ console.log(`Reasoning effort set to: ${effort}`);
171
+ },
172
+ },
173
+ {
174
+ name: "effort",
175
+ description: "Alias for /reasoning_effort",
176
+ handler: async (args: string[]): Promise<void> => {
177
+ const validEfforts: CompletionOptions["reasoning_effort"][] = [
178
+ "none",
179
+ "low",
180
+ "medium",
181
+ "high",
182
+ ];
183
+ const effort = args[0] as CompletionOptions["reasoning_effort"];
184
+ if (!effort || !validEfforts.includes(effort)) {
185
+ console.log(
186
+ `Current reasoning effort: ${this.reasoningEffort ?? "(not set — model default)"}`
187
+ );
188
+ console.log(
189
+ `Usage: /effort <${validEfforts.join("|")}>`
190
+ );
191
+ return;
192
+ }
193
+ this.reasoningEffort = effort;
194
+ const agent = (this.chatService?.getContext()?.selectedAgent as BaseAgent);
195
+ if (agent) agent.setReasoningEffort(effort);
196
+ console.log(`Reasoning effort set to: ${effort}`);
197
+ },
198
+ },
199
+ {
200
+ name: "reasoning_summary",
201
+ description:
202
+ "Toggle whether the agent displays a reasoning summary (true/false). Supported by reasoning models only.",
203
+ handler: async (args: string[]): Promise<void> => {
204
+ const val = args[0];
205
+ if (val !== "true" && val !== "false") {
206
+ console.log(
207
+ `Current reasoning summary: ${this.summarizeReasoning}`
208
+ );
209
+ console.log(`Usage: /reasoning_summary <true|false>`);
210
+ return;
211
+ }
212
+ this.summarizeReasoning = val === "true";
213
+ const agent = (this.chatService?.getContext()?.selectedAgent as BaseAgent);
214
+ if (agent) agent.setSummarizeReasoning(this.summarizeReasoning);
215
+ console.log(`Reasoning summary set to: ${this.summarizeReasoning}`);
135
216
  },
136
217
  },
137
218
  {
@@ -531,10 +612,14 @@ export class AgentModule extends BaseChatModule {
531
612
  const threads = session.threads || [];
532
613
  // Guard against sessions saved with a flat Message[] instead of Message[][]
533
614
  // (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] : [];
615
+ const normalizedThreads: Message[][] =
616
+ threads.length > 0 && !Array.isArray(threads[0])
617
+ ? [threads as unknown as Message[]]
618
+ : (threads as Message[][]);
619
+ const lastThread =
620
+ normalizedThreads.length > 0
621
+ ? normalizedThreads[normalizedThreads.length - 1]
622
+ : [];
538
623
  const resumeMessages = [...lastThread];
539
624
 
540
625
  // Append the resume prompt to the last user message (or add a new one)
@@ -548,7 +633,9 @@ export class AgentModule extends BaseChatModule {
548
633
  const actualIndex = lastThread.length - 1 - reversedIndex;
549
634
  resumeMessages[actualIndex] = {
550
635
  ...resumeMessages[actualIndex],
551
- content: resumeMessages[actualIndex].content + `\n\n<Workflow>[RESUME CONTEXT]: ${resumePrompt}</Workflow>`,
636
+ content:
637
+ resumeMessages[actualIndex].content +
638
+ `\n\n<Workflow>[RESUME CONTEXT]: ${resumePrompt}</Workflow>`,
552
639
  };
553
640
  }
554
641
 
@@ -584,7 +671,12 @@ export class AgentModule extends BaseChatModule {
584
671
  }
585
672
  });
586
673
 
587
- await this.attachedAgentChatLoop(taskId, agent, resumePrompt, resumeMessages);
674
+ await this.attachedAgentChatLoop(
675
+ taskId,
676
+ agent,
677
+ resumePrompt,
678
+ resumeMessages
679
+ );
588
680
  } catch (error) {
589
681
  console.error(
590
682
  `Failed to resume session ${sessionId}:`,
@@ -739,6 +831,12 @@ export class AgentModule extends BaseChatModule {
739
831
  ]);
740
832
  }
741
833
 
834
+ // Apply module-level reasoning settings to the agent
835
+ if (this.reasoningEffort !== undefined) {
836
+ agent.setReasoningEffort(this.reasoningEffort);
837
+ }
838
+ agent.setSummarizeReasoning(this.summarizeReasoning);
839
+
742
840
  // Set up message processors like in original startAgent
743
841
 
744
842
  // Register an override for askHuman to use CLI input method
@@ -781,6 +879,10 @@ export class AgentModule extends BaseChatModule {
781
879
  new HarmonyToolProcessor().createProcessor(),
782
880
  ]);
783
881
 
882
+ agent.messageProcessor.setProcessors("pre_tools", [
883
+ new MinimalToolsMessageProcessor().createProcessor(),
884
+ ]);
885
+
784
886
  agent.messageProcessor.setProcessors("post_tools", [
785
887
  new Base64ImageProcessor(agent.tools).createProcessor(),
786
888
  ...caching,
package/src/cli.ts CHANGED
@@ -38,6 +38,8 @@ import {
38
38
  } from "./commands/misc";
39
39
  import { addConvertCommand } from "./commands/convert";
40
40
  import { addReplayCommand } from "./commands/replay";
41
+ import { addBehaviorsCommand } from "./commands/behaviors";
42
+ import { addSkillsCommand } from "./commands/skills";
41
43
 
42
44
  // Handle unhandled promise rejections gracefully — particularly from MCP SDK
43
45
  // which fires errors via event emitters that can bypass Promise.allSettled.
@@ -102,6 +104,8 @@ async function main() {
102
104
  addMcpCommands(program);
103
105
  addConvertCommand(program);
104
106
  addReplayCommand(program);
107
+ addBehaviorsCommand(program);
108
+ addSkillsCommand(program);
105
109
 
106
110
  // Load global modules early (before parse) so they can register CLI subcommands.
107
111
  // We pass only the Program in context — no services are spun up at this stage.
@@ -1,6 +1,6 @@
1
1
  import Anthropic from "@anthropic-ai/sdk";
2
2
  import { wait } from "../utils";
3
- import { AnthropicTextPricing } from "./pricing";
3
+ import { AnthropicTextPricing, AnthropicModels } from "./pricing";
4
4
  import { ContextLimits } from "./contextLimits";
5
5
  import { ModelModality } from "./types";
6
6
  import { Models } from "../types";
@@ -24,6 +24,16 @@ import {
24
24
 
25
25
  type MessageParam = Anthropic.MessageParam;
26
26
  type Usage = Anthropic.Usage;
27
+ type ThinkingParam = Anthropic.Messages.ThinkingConfigParam;
28
+
29
+ const alwaysOnModels: readonly string[] = [
30
+ AnthropicModels.Sonnet5, AnthropicModels.Fable5,
31
+ AnthropicModels.Mythos5, AnthropicModels.MythosPreview,
32
+ ];
33
+ const optInModels: readonly string[] = [
34
+ AnthropicModels.Opus4_8, AnthropicModels.Opus4_7,
35
+ AnthropicModels.Opus4_6, AnthropicModels.Sonnet4_6,
36
+ ];
27
37
 
28
38
  export class GenericAnthropicClient implements GenericClient {
29
39
  private client: Anthropic;
@@ -48,6 +58,36 @@ export class GenericAnthropicClient implements GenericClient {
48
58
  }
49
59
  }
50
60
 
61
+ /**
62
+ * Determine the Anthropic `thinking` param from CompletionOptions.
63
+ * Returns undefined if the model does not support thinking.
64
+ */
65
+ getThinkingParam(
66
+ model: string,
67
+ reasoning_effort?: CompletionOptions["reasoning_effort"],
68
+ reasoning_summary?: boolean,
69
+ ): ThinkingParam | undefined {
70
+ const effortIsNone = reasoning_effort === "none";
71
+ const withSummary = reasoning_summary ? ({ display: "summarized" } as const) : {};
72
+
73
+ if (alwaysOnModels.includes(model)) {
74
+ return effortIsNone
75
+ ? { type: "disabled" }
76
+ : { type: "adaptive", ...withSummary };
77
+ }
78
+
79
+ if (optInModels.includes(model)) {
80
+ // Only enable when explicitly requested (not "none" and not undefined).
81
+ if (!effortIsNone && reasoning_effort !== undefined) {
82
+ return { type: "adaptive", ...withSummary };
83
+ }
84
+ return undefined;
85
+ }
86
+
87
+ // Model does not support thinking.
88
+ return undefined;
89
+ }
90
+
51
91
  /**
52
92
  * Clean JSON Schema for Anthropic API compatibility.
53
93
  * Removes unsupported fields like additionalProperties, $ref, $defs, positional.
@@ -360,6 +400,13 @@ export class GenericAnthropicClient implements GenericClient {
360
400
  options: CompletionOptions
361
401
  ): Promise<CompletionResponse> {
362
402
  const longTtl = !!options.long_ttl_cache;
403
+
404
+ const thinkingParam = this.getThinkingParam(
405
+ options.model,
406
+ options.reasoning_effort,
407
+ options.reasoning_summary,
408
+ );
409
+
363
410
  const systemMessage = options.messages
364
411
  .filter((msg) => msg.role === "system")
365
412
  .map((msg) => msg.content || "")
@@ -382,6 +429,7 @@ export class GenericAnthropicClient implements GenericClient {
382
429
  ]
383
430
  : undefined,
384
431
  max_tokens: options.max_tokens || 8000,
432
+ ...(thinkingParam && { thinking: thinkingParam }),
385
433
  ...(tools.length && {
386
434
  tool_choice: { type: "auto" },
387
435
  tools,
@@ -431,6 +479,16 @@ export class GenericAnthropicClient implements GenericClient {
431
479
  total_tokens: (response.usage.input_tokens ?? 0) + (response.usage.output_tokens ?? 0),
432
480
  cache_creation_input_tokens: response.usage.cache_creation_input_tokens ?? 0,
433
481
  cache_read_input_tokens: response.usage.cache_read_input_tokens ?? 0,
482
+ ...((response.usage as any).thinking_input_tokens != null ||
483
+ (response.usage as any).output_tokens_details?.thinking_tokens != null
484
+ ? {
485
+ output_tokens_details: {
486
+ thinking_tokens:
487
+ (response.usage as any).thinking_input_tokens ??
488
+ (response.usage as any).output_tokens_details?.thinking_tokens ?? 0,
489
+ },
490
+ }
491
+ : {}),
434
492
  } : undefined,
435
493
  usd_cost: this.calculateCost(options.model, response.usage),
436
494
  };
@@ -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
+ }
@@ -107,7 +107,11 @@ export class GenericOpenAiClient implements GenericClient {
107
107
  }
108
108
 
109
109
  resolveReasoningEffort(options: CompletionOptions): "low" | "medium" | "high" {
110
- return options.reasoning_effort ?? this.detectReasoningEffort(options.messages);
110
+ const effort = options.reasoning_effort ?? this.detectReasoningEffort(options.messages);
111
+ // "none" is not a valid SDK ReasoningEffort — callers that need "none" should
112
+ // check isReasoningDisabled() separately and skip the reasoning params.
113
+ if (effort === "none") return "low";
114
+ return effort;
111
115
  }
112
116
 
113
117
  /**
@@ -116,7 +120,8 @@ export class GenericOpenAiClient implements GenericClient {
116
120
  * If the requested level is not supported, picks the lowest supported level.
117
121
  */
118
122
  resolveReasoningEffortForModel(options: CompletionOptions): string {
119
- const requested = options.reasoning_effort ?? this.detectReasoningEffort(options.messages);
123
+ const raw = options.reasoning_effort ?? this.detectReasoningEffort(options.messages);
124
+ const requested = raw === "none" ? "none" : raw;
120
125
  const pricing = OpenAiTextPricing[options.model];
121
126
  const supportedLevels = pricing?.reasoningLevels;
122
127
  if (!supportedLevels || supportedLevels.length === 0) {
@@ -130,6 +135,11 @@ export class GenericOpenAiClient implements GenericClient {
130
135
  return supportedLevels[0];
131
136
  }
132
137
 
138
+ /** Returns true when the caller explicitly requested thinking/reasoning to be disabled. */
139
+ isReasoningDisabled(options: CompletionOptions): boolean {
140
+ return options.reasoning_effort === "none";
141
+ }
142
+
133
143
  async createChatCompletion(
134
144
  options: CompletionOptions
135
145
  ): Promise<CompletionResponse> {
@@ -154,7 +164,7 @@ export class GenericOpenAiClient implements GenericClient {
154
164
  model: options.model,
155
165
  messages: openaiMessages,
156
166
  max_tokens: options.max_tokens,
157
- ...(OpenAiReasoningModels.includes(options.model) && {
167
+ ...(OpenAiReasoningModels.includes(options.model) && !this.isReasoningDisabled(options) && {
158
168
  max_tokens: undefined,
159
169
  max_completion_tokens: Math.max(options.max_tokens ?? 0, 16_000),
160
170
  reasoning_effort: this.resolveReasoningEffort(options),
@@ -186,6 +196,11 @@ export class GenericOpenAiClient implements GenericClient {
186
196
  prompt_tokens_details: {
187
197
  cached_tokens: response.usage.prompt_tokens_details?.cached_tokens ?? 0,
188
198
  },
199
+ ...(response.usage.completion_tokens_details?.reasoning_tokens != null && {
200
+ output_tokens_details: {
201
+ reasoning_tokens: response.usage.completion_tokens_details.reasoning_tokens,
202
+ },
203
+ }),
189
204
  } : undefined,
190
205
  usd_cost: usdCost,
191
206
  };
@@ -350,9 +365,12 @@ export class GenericOpenAiClient implements GenericClient {
350
365
  input,
351
366
  ...(instructions && { instructions }),
352
367
  // Don't limit max_output_tokens for Responses API - codex truncates tool call arguments when limited
353
- ...(OpenAiReasoningModels.includes(options.model) && {
368
+ ...(OpenAiReasoningModels.includes(options.model) && !this.isReasoningDisabled(options) && {
354
369
  max_output_tokens: Math.max(options.max_tokens || 0, 16000),
355
- reasoning: { effort: this.resolveReasoningEffortForModel(options) },
370
+ reasoning: {
371
+ effort: this.resolveReasoningEffortForModel(options),
372
+ ...(options.reasoning_summary && { summary: "auto" }),
373
+ },
356
374
  }),
357
375
  ...(tools?.length && {
358
376
  tools,
@@ -372,6 +390,11 @@ export class GenericOpenAiClient implements GenericClient {
372
390
  cached_tokens:
373
391
  response.usage.input_tokens_details?.cached_tokens ?? 0,
374
392
  },
393
+ ...((response.usage as any).output_tokens_details?.reasoning_tokens != null && {
394
+ output_tokens_details: {
395
+ reasoning_tokens: (response.usage as any).output_tokens_details.reasoning_tokens,
396
+ },
397
+ }),
375
398
  }
376
399
  : undefined;
377
400
 
@@ -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";