@synergenius/flowweaver-pack-weaver 0.6.0 → 0.7.0

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 (196) hide show
  1. package/dist/bot/ai-client.d.ts +1 -0
  2. package/dist/bot/ai-client.d.ts.map +1 -1
  3. package/dist/bot/ai-client.js +52 -1
  4. package/dist/bot/ai-client.js.map +1 -1
  5. package/dist/bot/audit-logger.d.ts +5 -0
  6. package/dist/bot/audit-logger.d.ts.map +1 -0
  7. package/dist/bot/audit-logger.js +42 -0
  8. package/dist/bot/audit-logger.js.map +1 -0
  9. package/dist/bot/audit-store.d.ts +13 -0
  10. package/dist/bot/audit-store.d.ts.map +1 -0
  11. package/dist/bot/audit-store.js +59 -0
  12. package/dist/bot/audit-store.js.map +1 -0
  13. package/dist/bot/cli-provider.d.ts +1 -0
  14. package/dist/bot/cli-provider.d.ts.map +1 -1
  15. package/dist/bot/cli-provider.js +86 -22
  16. package/dist/bot/cli-provider.js.map +1 -1
  17. package/dist/bot/cli-stream-parser.d.ts +11 -0
  18. package/dist/bot/cli-stream-parser.d.ts.map +1 -0
  19. package/dist/bot/cli-stream-parser.js +53 -0
  20. package/dist/bot/cli-stream-parser.js.map +1 -0
  21. package/dist/bot/design-checker.d.ts +24 -0
  22. package/dist/bot/design-checker.d.ts.map +1 -0
  23. package/dist/bot/design-checker.js +269 -0
  24. package/dist/bot/design-checker.js.map +1 -0
  25. package/dist/bot/file-validator.d.ts +5 -2
  26. package/dist/bot/file-validator.d.ts.map +1 -1
  27. package/dist/bot/file-validator.js +14 -7
  28. package/dist/bot/file-validator.js.map +1 -1
  29. package/dist/bot/fw-api.d.ts +8 -0
  30. package/dist/bot/fw-api.d.ts.map +1 -0
  31. package/dist/bot/fw-api.js +12 -0
  32. package/dist/bot/fw-api.js.map +1 -0
  33. package/dist/bot/runner.d.ts +2 -1
  34. package/dist/bot/runner.d.ts.map +1 -1
  35. package/dist/bot/runner.js +8 -0
  36. package/dist/bot/runner.js.map +1 -1
  37. package/dist/bot/step-executor.d.ts +3 -2
  38. package/dist/bot/step-executor.d.ts.map +1 -1
  39. package/dist/bot/step-executor.js +9 -30
  40. package/dist/bot/step-executor.js.map +1 -1
  41. package/dist/bot/system-prompt.d.ts +13 -1
  42. package/dist/bot/system-prompt.d.ts.map +1 -1
  43. package/dist/bot/system-prompt.js +28 -22
  44. package/dist/bot/system-prompt.js.map +1 -1
  45. package/dist/bot/types.d.ts +9 -1
  46. package/dist/bot/types.d.ts.map +1 -1
  47. package/dist/cli-bridge.d.ts.map +1 -1
  48. package/dist/cli-bridge.js +2 -1
  49. package/dist/cli-bridge.js.map +1 -1
  50. package/dist/cli-handlers.d.ts +4 -2
  51. package/dist/cli-handlers.d.ts.map +1 -1
  52. package/dist/cli-handlers.js +199 -92
  53. package/dist/cli-handlers.js.map +1 -1
  54. package/dist/docs/docs/weaver-config.md +8 -14
  55. package/dist/docs/weaver-config.md +8 -14
  56. package/dist/node-types/approval-gate.d.ts.map +1 -1
  57. package/dist/node-types/approval-gate.js +4 -0
  58. package/dist/node-types/approval-gate.js.map +1 -1
  59. package/dist/node-types/exec-validate-retry.d.ts.map +1 -1
  60. package/dist/node-types/exec-validate-retry.js +33 -7
  61. package/dist/node-types/exec-validate-retry.js.map +1 -1
  62. package/dist/node-types/execute-plan.js +1 -1
  63. package/dist/node-types/execute-plan.js.map +1 -1
  64. package/dist/node-types/genesis-validate-proposal.d.ts.map +1 -1
  65. package/dist/node-types/genesis-validate-proposal.js +23 -0
  66. package/dist/node-types/genesis-validate-proposal.js.map +1 -1
  67. package/dist/node-types/git-ops.d.ts.map +1 -1
  68. package/dist/node-types/git-ops.js +2 -0
  69. package/dist/node-types/git-ops.js.map +1 -1
  70. package/dist/node-types/plan-task.d.ts.map +1 -1
  71. package/dist/node-types/plan-task.js +9 -1
  72. package/dist/node-types/plan-task.js.map +1 -1
  73. package/dist/node-types/send-notify.d.ts.map +1 -1
  74. package/dist/node-types/send-notify.js +4 -1
  75. package/dist/node-types/send-notify.js.map +1 -1
  76. package/dist/node-types/validate-result.d.ts +2 -2
  77. package/dist/node-types/validate-result.d.ts.map +1 -1
  78. package/dist/node-types/validate-result.js +2 -2
  79. package/dist/node-types/validate-result.js.map +1 -1
  80. package/dist/templates/index.d.ts +2 -4
  81. package/dist/templates/index.d.ts.map +1 -1
  82. package/dist/templates/index.js +1 -3
  83. package/dist/templates/index.js.map +1 -1
  84. package/dist/templates/weaver-bot-template.d.ts +9 -1
  85. package/dist/templates/weaver-bot-template.d.ts.map +1 -1
  86. package/dist/templates/weaver-bot-template.js.map +1 -1
  87. package/dist/workflows/index.d.ts +0 -1
  88. package/dist/workflows/index.d.ts.map +1 -1
  89. package/dist/workflows/index.js +0 -1
  90. package/dist/workflows/index.js.map +1 -1
  91. package/dist/workflows/weaver-bot-batch.d.ts +4 -1
  92. package/dist/workflows/weaver-bot-batch.d.ts.map +1 -1
  93. package/dist/workflows/weaver-bot-batch.js +1 -1
  94. package/dist/workflows/weaver-bot-batch.js.map +1 -1
  95. package/dist/workflows/weaver-bot.d.ts +4 -1
  96. package/dist/workflows/weaver-bot.d.ts.map +1 -1
  97. package/dist/workflows/weaver-bot.js +1 -1
  98. package/dist/workflows/weaver-bot.js.map +1 -1
  99. package/flowweaver.manifest.json +10 -10
  100. package/package.json +4 -3
  101. package/src/bot/agent-provider.ts +273 -0
  102. package/src/bot/ai-client.ts +109 -0
  103. package/src/bot/approvals.ts +273 -0
  104. package/src/bot/audit-logger.ts +45 -0
  105. package/src/bot/audit-store.ts +69 -0
  106. package/src/bot/bot-agent-channel.ts +99 -0
  107. package/src/bot/cli-provider.ts +169 -0
  108. package/src/bot/cli-stream-parser.ts +59 -0
  109. package/src/bot/cost-store.ts +92 -0
  110. package/src/bot/cost-tracker.ts +72 -0
  111. package/src/bot/cron-parser.ts +153 -0
  112. package/src/bot/cron-scheduler.ts +48 -0
  113. package/src/bot/dashboard.ts +658 -0
  114. package/src/bot/design-checker.ts +327 -0
  115. package/src/bot/file-lock.ts +73 -0
  116. package/src/bot/file-validator.ts +41 -0
  117. package/src/bot/file-watcher.ts +103 -0
  118. package/src/bot/fw-api.ts +18 -0
  119. package/src/bot/genesis-prompt-context.ts +135 -0
  120. package/src/bot/genesis-store.ts +180 -0
  121. package/src/bot/index.ts +127 -0
  122. package/src/bot/notifications.ts +263 -0
  123. package/src/bot/pipeline-runner.ts +324 -0
  124. package/src/bot/provider-registry.ts +236 -0
  125. package/src/bot/run-store.ts +169 -0
  126. package/src/bot/runner.ts +311 -0
  127. package/src/bot/session-state.ts +73 -0
  128. package/src/bot/steering.ts +44 -0
  129. package/src/bot/step-executor.ts +34 -0
  130. package/src/bot/system-prompt.ts +280 -0
  131. package/src/bot/task-queue.ts +111 -0
  132. package/src/bot/types.ts +571 -0
  133. package/src/bot/utils.ts +17 -0
  134. package/src/bot/watch-daemon.ts +203 -0
  135. package/src/bot/web-approval.ts +240 -0
  136. package/src/cli-bridge.ts +41 -0
  137. package/src/cli-handlers.ts +1271 -0
  138. package/src/docs/weaver-config.md +135 -0
  139. package/src/index.ts +173 -0
  140. package/src/mcp-tools.ts +274 -0
  141. package/src/node-types/abort-task.ts +31 -0
  142. package/src/node-types/approval-gate.ts +75 -0
  143. package/src/node-types/bot-report.ts +82 -0
  144. package/src/node-types/build-context.ts +65 -0
  145. package/src/node-types/detect-provider.ts +75 -0
  146. package/src/node-types/exec-validate-retry.ts +175 -0
  147. package/src/node-types/execute-plan.ts +130 -0
  148. package/src/node-types/execute-target.ts +267 -0
  149. package/src/node-types/fix-errors.ts +68 -0
  150. package/src/node-types/genesis-apply-retry.ts +138 -0
  151. package/src/node-types/genesis-apply.ts +96 -0
  152. package/src/node-types/genesis-approve.ts +73 -0
  153. package/src/node-types/genesis-check-stabilize.ts +37 -0
  154. package/src/node-types/genesis-check-threshold.ts +34 -0
  155. package/src/node-types/genesis-commit.ts +71 -0
  156. package/src/node-types/genesis-compile-validate.ts +77 -0
  157. package/src/node-types/genesis-diff-fingerprint.ts +67 -0
  158. package/src/node-types/genesis-diff-workflow.ts +71 -0
  159. package/src/node-types/genesis-escrow-grace.ts +62 -0
  160. package/src/node-types/genesis-escrow-migrate.ts +138 -0
  161. package/src/node-types/genesis-escrow-recover.ts +99 -0
  162. package/src/node-types/genesis-escrow-stage.ts +104 -0
  163. package/src/node-types/genesis-escrow-validate.ts +120 -0
  164. package/src/node-types/genesis-load-config.ts +44 -0
  165. package/src/node-types/genesis-observe.ts +119 -0
  166. package/src/node-types/genesis-propose.ts +97 -0
  167. package/src/node-types/genesis-report.ts +95 -0
  168. package/src/node-types/genesis-snapshot.ts +30 -0
  169. package/src/node-types/genesis-try-apply.ts +165 -0
  170. package/src/node-types/genesis-update-history.ts +72 -0
  171. package/src/node-types/genesis-validate-proposal.ts +124 -0
  172. package/src/node-types/git-ops.ts +72 -0
  173. package/src/node-types/index.ts +36 -0
  174. package/src/node-types/load-config.ts +27 -0
  175. package/src/node-types/plan-task.ts +77 -0
  176. package/src/node-types/read-workflow.ts +68 -0
  177. package/src/node-types/receive-task.ts +92 -0
  178. package/src/node-types/report.ts +25 -0
  179. package/src/node-types/resolve-target.ts +64 -0
  180. package/src/node-types/route-task.ts +25 -0
  181. package/src/node-types/send-notify.ts +75 -0
  182. package/src/node-types/validate-result.ts +49 -0
  183. package/src/templates/index.ts +5 -0
  184. package/src/templates/weaver-bot-template.ts +106 -0
  185. package/src/workflows/genesis-task.ts +91 -0
  186. package/src/workflows/index.ts +3 -0
  187. package/src/workflows/weaver-bot-batch.ts +65 -0
  188. package/src/workflows/weaver-bot.ts +79 -0
  189. package/dist/templates/weaver-template.d.ts +0 -11
  190. package/dist/templates/weaver-template.d.ts.map +0 -1
  191. package/dist/templates/weaver-template.js +0 -53
  192. package/dist/templates/weaver-template.js.map +0 -1
  193. package/dist/workflows/weaver.d.ts +0 -24
  194. package/dist/workflows/weaver.d.ts.map +0 -1
  195. package/dist/workflows/weaver.js +0 -28
  196. package/dist/workflows/weaver.js.map +0 -1
@@ -52,7 +52,7 @@
52
52
  * @returns onFailure [order:-1] [hidden] - On Failure
53
53
  * @returns summary [order:0] - Summary text
54
54
  */
55
- export async function weaverBot(execute, taskJson, projectDir, __abortSignal__) {
55
+ export async function weaverBot(execute, params, __abortSignal__) {
56
56
  // @flow-weaver-body-start
57
57
  // (auto-generated by compiler)
58
58
  // @flow-weaver-body-end
@@ -1 +1 @@
1
- {"version":3,"file":"weaver-bot.js","sourceRoot":"","sources":["../../src/workflows/weaver-bot.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,mCAAmC;AAgBnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,OAAgB,EAChB,QAAiB,EACjB,UAAmB,EACnB,eAA6B;IAE7B,0BAA0B;IAC1B,+BAA+B;IAC/B,wBAAwB;IACxB,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC9D,CAAC"}
1
+ {"version":3,"file":"weaver-bot.js","sourceRoot":"","sources":["../../src/workflows/weaver-bot.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,mCAAmC;AAgBnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,OAAgB,EAChB,MAAkD,EAClD,eAA6B;IAE7B,0BAA0B;IAC1B,+BAA+B;IAC/B,wBAAwB;IACxB,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC9D,CAAC"}
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "manifestVersion": 1,
3
3
  "name": "@synergenius/flowweaver-pack-weaver",
4
- "version": "0.6.0",
5
- "description": "Autonomous workflow runner for Flow Weaver. Auto-detect providers, execute workflows, notify results.",
4
+ "version": "0.7.0",
5
+ "description": "AI bot for Flow Weaver. Execute tasks, run workflows, evolve autonomously.",
6
6
  "engineVersion": ">=0.19.4",
7
7
  "categories": [
8
8
  "automation",
@@ -843,7 +843,7 @@
843
843
  "cliCommands": [
844
844
  {
845
845
  "name": "run",
846
- "description": "Run a workflow file",
846
+ "description": "Run a workflow file through the bot",
847
847
  "usage": "<file>"
848
848
  },
849
849
  {
@@ -881,11 +881,12 @@
881
881
  },
882
882
  {
883
883
  "name": "eject",
884
- "description": "Eject managed workflow for customization"
884
+ "description": "Eject bot workflows for customization",
885
+ "usage": "[--workflow <bot|batch|genesis>]"
885
886
  },
886
887
  {
887
888
  "name": "bot",
888
- "description": "Run the autonomous bot with a task",
889
+ "description": "Execute a task from natural language",
889
890
  "usage": "<task>"
890
891
  },
891
892
  {
@@ -904,7 +905,7 @@
904
905
  },
905
906
  {
906
907
  "name": "genesis",
907
- "description": "Run a Genesis self-evolution cycle on a target workflow",
908
+ "description": "Run bot self-evolution cycle on a target workflow",
908
909
  "usage": "[--init] [--watch]"
909
910
  }
910
911
  ],
@@ -912,7 +913,7 @@
912
913
  "mcpTools": [
913
914
  {
914
915
  "name": "fw_weaver_run",
915
- "description": "Execute a workflow with the AI runner"
916
+ "description": "Run a workflow file through the bot"
916
917
  },
917
918
  {
918
919
  "name": "fw_weaver_history",
@@ -928,7 +929,7 @@
928
929
  },
929
930
  {
930
931
  "name": "fw_weaver_bot",
931
- "description": "Run the autonomous bot with a task"
932
+ "description": "Execute a task from natural language"
932
933
  },
933
934
  {
934
935
  "name": "fw_weaver_steer",
@@ -944,7 +945,7 @@
944
945
  },
945
946
  {
946
947
  "name": "fw_weaver_genesis",
947
- "description": "Run a Genesis self-evolution cycle on a target workflow"
948
+ "description": "Run bot self-evolution cycle on a target workflow"
948
949
  }
949
950
  ],
950
951
  "initContributions": {
@@ -954,7 +955,6 @@
954
955
  "description": "Autonomous workflow execution with AI providers and notifications"
955
956
  },
956
957
  "templates": [
957
- "weaver",
958
958
  "weaver-bot"
959
959
  ]
960
960
  },
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@synergenius/flowweaver-pack-weaver",
3
- "version": "0.6.0",
4
- "description": "Autonomous workflow runner for Flow Weaver. Auto-detect providers, execute workflows, notify results.",
3
+ "version": "0.7.0",
4
+ "description": "AI bot for Flow Weaver. Execute tasks, run workflows, evolve autonomously.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@anthropic-ai/sdk": ">=0.30.0",
39
- "@synergenius/flow-weaver": ">=0.20.5",
39
+ "@synergenius/flow-weaver": ">=0.21.0",
40
40
  "zod": ">=3.22.0"
41
41
  },
42
42
  "peerDependenciesMeta": {
@@ -49,6 +49,7 @@
49
49
  },
50
50
  "files": [
51
51
  "dist",
52
+ "src",
52
53
  "flowweaver.manifest.json",
53
54
  "templates.js",
54
55
  "LICENSE"
@@ -0,0 +1,273 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import type { BotProviderConfig, BotConfig, BotAgentProvider, OnUsageCallback, StreamChunk, ToolDefinition, ToolUseResult } from './types.js';
3
+ import { buildSystemPrompt } from './system-prompt.js';
4
+ import { defaultRegistry, loadExternalProvider } from './provider-registry.js';
5
+ import type { ProviderRegistry } from './provider-registry.js';
6
+
7
+ const WHICH_CMD = process.platform === 'win32' ? 'where' : 'which';
8
+
9
+ export type { BotAgentProvider };
10
+
11
+ export function resolveProviderConfig(
12
+ provider: BotConfig['provider'],
13
+ ): BotProviderConfig {
14
+ if (provider === 'auto') return detectProvider();
15
+ if (typeof provider === 'string') return { name: provider };
16
+ return provider;
17
+ }
18
+
19
+ export async function createProvider(
20
+ config: BotProviderConfig,
21
+ registry: ProviderRegistry = defaultRegistry,
22
+ ): Promise<BotAgentProvider> {
23
+ // If config.module is set, load and register it first
24
+ if (config.module) {
25
+ if (!registry.has(config.name)) {
26
+ const { factory, metadata } = await loadExternalProvider(config.module);
27
+ registry.register(config.name, factory, metadata);
28
+ }
29
+ }
30
+
31
+ // Check registry (covers built-ins + loaded externals)
32
+ const entry = registry.resolve(config.name);
33
+ if (entry) {
34
+ return entry.factory({
35
+ model: config.model,
36
+ maxTokens: config.maxTokens,
37
+ options: config.options,
38
+ });
39
+ }
40
+
41
+ // Fallback: try conventional npm package names
42
+ const candidates = [
43
+ `flowweaver-provider-${config.name}`,
44
+ `@synergenius/flowweaver-provider-${config.name}`,
45
+ ];
46
+
47
+ for (const candidate of candidates) {
48
+ try {
49
+ const { factory, metadata } = await loadExternalProvider(candidate);
50
+ registry.register(config.name, factory, metadata);
51
+ return factory({
52
+ model: config.model,
53
+ maxTokens: config.maxTokens,
54
+ options: config.options,
55
+ });
56
+ } catch {
57
+ // Try next candidate
58
+ }
59
+ }
60
+
61
+ throw new Error(
62
+ `Unknown provider: ${config.name}\n` +
63
+ ` Install a provider package: npm install flowweaver-provider-${config.name}\n` +
64
+ ` Or specify a module path: { "provider": { "name": "${config.name}", "module": "./my-provider.js" } }`,
65
+ );
66
+ }
67
+
68
+ export function detectProvider(registry: ProviderRegistry = defaultRegistry): BotProviderConfig {
69
+ // Check registry metadata for env vars and CLI commands
70
+ for (const { name, metadata } of registry.list()) {
71
+ if (metadata.requiredEnvVars) {
72
+ const allPresent = metadata.requiredEnvVars.every((v) => process.env[v]);
73
+ if (allPresent) return { name };
74
+ }
75
+ }
76
+
77
+ for (const { name, metadata } of registry.list()) {
78
+ if (metadata.detectCliCommand) {
79
+ try {
80
+ execFileSync(WHICH_CMD, [metadata.detectCliCommand], { stdio: 'pipe' });
81
+ return { name };
82
+ } catch { /* not installed */ }
83
+ }
84
+ }
85
+
86
+ throw new Error(
87
+ 'No AI provider found. Options:\n' +
88
+ ' 1. Set ANTHROPIC_API_KEY environment variable\n' +
89
+ ' 2. Install Claude CLI: https://docs.anthropic.com/claude-code\n' +
90
+ ' 3. Install GitHub Copilot CLI: https://github.com/features/copilot',
91
+ );
92
+ }
93
+
94
+ export class AnthropicAgentProvider implements BotAgentProvider {
95
+ private model: string;
96
+ private maxTokens: number;
97
+ onUsage?: OnUsageCallback;
98
+
99
+ constructor(config: BotProviderConfig) {
100
+ this.model = config.model ?? 'claude-sonnet-4-6';
101
+ this.maxTokens = config.maxTokens ?? 4096;
102
+ }
103
+
104
+ async decide(request: {
105
+ agentId: string;
106
+ context: Record<string, unknown>;
107
+ prompt: string;
108
+ }): Promise<Record<string, unknown>> {
109
+ if (!process.env.ANTHROPIC_API_KEY) {
110
+ throw new Error(
111
+ 'ANTHROPIC_API_KEY environment variable is required for the Anthropic provider',
112
+ );
113
+ }
114
+
115
+ const Anthropic = await this.loadSdk();
116
+ const client = new Anthropic();
117
+ const systemPrompt = await buildSystemPrompt();
118
+
119
+ const contextStr =
120
+ typeof request.context === 'string'
121
+ ? request.context
122
+ : JSON.stringify(request.context, null, 2);
123
+
124
+ const response = await client.messages.create({
125
+ model: this.model,
126
+ max_tokens: this.maxTokens,
127
+ system: systemPrompt,
128
+ messages: [
129
+ {
130
+ role: 'user',
131
+ content: `Context:\n${contextStr}\n\nInstructions:\n${request.prompt}`,
132
+ },
133
+ ],
134
+ });
135
+
136
+ if (this.onUsage && response.usage) {
137
+ this.onUsage(request.agentId, response.model ?? this.model, {
138
+ inputTokens: response.usage.input_tokens,
139
+ outputTokens: response.usage.output_tokens,
140
+ cacheCreationInputTokens: response.usage.cache_creation_input_tokens,
141
+ cacheReadInputTokens: response.usage.cache_read_input_tokens,
142
+ });
143
+ }
144
+
145
+ const text =
146
+ response.content[0].type === 'text' ? response.content[0].text : '';
147
+ return this.parseJson(text);
148
+ }
149
+
150
+ async *stream(request: {
151
+ agentId: string;
152
+ context: Record<string, unknown>;
153
+ prompt: string;
154
+ }): AsyncIterable<StreamChunk> {
155
+ if (!process.env.ANTHROPIC_API_KEY) {
156
+ throw new Error('ANTHROPIC_API_KEY environment variable is required for the Anthropic provider');
157
+ }
158
+
159
+ const Anthropic = await this.loadSdk();
160
+ const client = new Anthropic();
161
+ const systemPrompt = await buildSystemPrompt();
162
+
163
+ const contextStr = typeof request.context === 'string'
164
+ ? request.context
165
+ : JSON.stringify(request.context, null, 2);
166
+
167
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
168
+ const stream = (client as any).messages.stream({
169
+ model: this.model,
170
+ max_tokens: this.maxTokens,
171
+ system: systemPrompt,
172
+ messages: [{ role: 'user', content: `Context:\n${contextStr}\n\nInstructions:\n${request.prompt}` }],
173
+ });
174
+
175
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
176
+ for await (const event of stream as AsyncIterable<any>) {
177
+ if (event.type === 'content_block_delta' && event.delta?.type === 'text_delta') {
178
+ yield { type: 'text', text: event.delta.text };
179
+ }
180
+ }
181
+
182
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
183
+ const finalMessage = await (stream as any).finalMessage();
184
+ if (finalMessage?.usage) {
185
+ const usage = {
186
+ inputTokens: finalMessage.usage.input_tokens,
187
+ outputTokens: finalMessage.usage.output_tokens,
188
+ cacheCreationInputTokens: finalMessage.usage.cache_creation_input_tokens,
189
+ cacheReadInputTokens: finalMessage.usage.cache_read_input_tokens,
190
+ };
191
+ if (this.onUsage) this.onUsage(request.agentId, finalMessage.model ?? this.model, usage);
192
+ yield { type: 'usage', usage };
193
+ }
194
+ yield { type: 'done' };
195
+ }
196
+
197
+ async decideWithTools(request: {
198
+ agentId: string;
199
+ context: Record<string, unknown>;
200
+ prompt: string;
201
+ tools: ToolDefinition[];
202
+ }): Promise<{ result: Record<string, unknown>; toolCalls?: ToolUseResult[] }> {
203
+ if (!process.env.ANTHROPIC_API_KEY) {
204
+ throw new Error('ANTHROPIC_API_KEY environment variable is required for the Anthropic provider');
205
+ }
206
+
207
+ const Anthropic = await this.loadSdk();
208
+ const client = new Anthropic();
209
+ const systemPrompt = await buildSystemPrompt();
210
+
211
+ const contextStr = typeof request.context === 'string'
212
+ ? request.context
213
+ : JSON.stringify(request.context, null, 2);
214
+
215
+ const response = await client.messages.create({
216
+ model: this.model,
217
+ max_tokens: this.maxTokens,
218
+ system: systemPrompt,
219
+ messages: [{ role: 'user', content: `Context:\n${contextStr}\n\nInstructions:\n${request.prompt}` }],
220
+ tools: request.tools,
221
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
222
+ } as any);
223
+
224
+ if (this.onUsage && response.usage) {
225
+ this.onUsage(request.agentId, response.model ?? this.model, {
226
+ inputTokens: response.usage.input_tokens,
227
+ outputTokens: response.usage.output_tokens,
228
+ cacheCreationInputTokens: response.usage.cache_creation_input_tokens,
229
+ cacheReadInputTokens: response.usage.cache_read_input_tokens,
230
+ });
231
+ }
232
+
233
+ const toolCalls: ToolUseResult[] = [];
234
+ let text = '';
235
+ for (const block of response.content) {
236
+ if (block.type === 'text') text = block.text;
237
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
238
+ else if (block.type === 'tool_use') toolCalls.push({ toolName: (block as any).name, toolInput: (block as any).input });
239
+ }
240
+
241
+ return { result: this.parseJson(text || '{}'), toolCalls: toolCalls.length > 0 ? toolCalls : undefined };
242
+ }
243
+
244
+ private parseJson(text: string): Record<string, unknown> {
245
+ let cleaned = text.trim();
246
+ if (cleaned.startsWith('```')) {
247
+ cleaned = cleaned.replace(/^```(?:json)?\s*\n?/, '').replace(/\n?```\s*$/, '');
248
+ }
249
+
250
+ try {
251
+ return JSON.parse(cleaned);
252
+ } catch {
253
+ const match = cleaned.match(/\{[\s\S]*\}/);
254
+ if (match) {
255
+ return JSON.parse(match[0]);
256
+ }
257
+ throw new Error(`Failed to parse AI response as JSON: ${text.slice(0, 200)}`);
258
+ }
259
+ }
260
+
261
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
262
+ private async loadSdk(): Promise<new () => any> {
263
+ try {
264
+ // @ts-expect-error -- optional peer dep, loaded at runtime
265
+ const mod = await import('@anthropic-ai/sdk');
266
+ return mod.default ?? mod.Anthropic;
267
+ } catch {
268
+ throw new Error(
269
+ 'Bot mode requires @anthropic-ai/sdk. Install it:\n npm install @anthropic-ai/sdk',
270
+ );
271
+ }
272
+ }
273
+ }
@@ -0,0 +1,109 @@
1
+ import { execSync, spawn } from 'node:child_process';
2
+ import { parseStreamLine, extractTextFromChunks } from './cli-stream-parser.js';
3
+ import type { StreamChunk } from './types.js';
4
+
5
+ // Strip CLAUDECODE from child env so nested claude CLI invocations work.
6
+ const childEnv = { ...process.env };
7
+ delete childEnv.CLAUDECODE;
8
+
9
+ export function callCli(provider: string, prompt: string, model?: string): string {
10
+ if (provider === 'claude-cli') {
11
+ const modelFlag = model ? ` --model ${model}` : '';
12
+ return execSync(`claude -p --output-format text${modelFlag}`, {
13
+ input: prompt, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 300_000, env: childEnv,
14
+ }).trim();
15
+ }
16
+ if (provider === 'copilot-cli') {
17
+ return execSync('copilot -p --silent --allow-all-tools', {
18
+ input: prompt, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 300_000, env: childEnv,
19
+ }).trim();
20
+ }
21
+ throw new Error(`Unknown CLI provider: ${provider}`);
22
+ }
23
+
24
+ export async function callCliAsync(provider: string, prompt: string, model?: string): Promise<string> {
25
+ if (provider === 'copilot-cli') {
26
+ return callCli(provider, prompt, model);
27
+ }
28
+ if (provider !== 'claude-cli') {
29
+ throw new Error(`Unknown CLI provider: ${provider}`);
30
+ }
31
+
32
+ const args = ['-p', '--output-format', 'stream-json'];
33
+ if (model) args.push('--model', model);
34
+
35
+ const child = spawn('claude', args, {
36
+ stdio: ['pipe', 'pipe', 'pipe'],
37
+ env: childEnv,
38
+ });
39
+
40
+ child.stdin.write(prompt);
41
+ child.stdin.end();
42
+
43
+ const timeout = setTimeout(() => child.kill('SIGTERM'), 300_000);
44
+
45
+ const chunks: StreamChunk[] = [];
46
+ let buffer = '';
47
+
48
+ try {
49
+ for await (const data of child.stdout) {
50
+ buffer += data.toString();
51
+ const lines = buffer.split('\n');
52
+ buffer = lines.pop()!;
53
+
54
+ for (const line of lines) {
55
+ const chunk = parseStreamLine(line);
56
+ if (chunk) chunks.push(chunk);
57
+ }
58
+ }
59
+
60
+ if (buffer.trim()) {
61
+ const chunk = parseStreamLine(buffer);
62
+ if (chunk) chunks.push(chunk);
63
+ }
64
+ } finally {
65
+ clearTimeout(timeout);
66
+ }
67
+
68
+ await new Promise<void>((resolve, reject) => {
69
+ child.on('close', (code) => {
70
+ if (code && code !== 0) reject(new Error(`claude CLI exited with code ${code}`));
71
+ else resolve();
72
+ });
73
+ child.on('error', reject);
74
+ });
75
+
76
+ return extractTextFromChunks(chunks);
77
+ }
78
+
79
+ export async function callApi(
80
+ apiKey: string, model: string, maxTokens: number,
81
+ systemPrompt: string, userPrompt: string,
82
+ ): Promise<string> {
83
+ const body = JSON.stringify({
84
+ model, max_tokens: maxTokens, system: systemPrompt,
85
+ messages: [{ role: 'user', content: userPrompt }],
86
+ });
87
+ const response = await fetch('https://api.anthropic.com/v1/messages', {
88
+ method: 'POST',
89
+ headers: { 'x-api-key': apiKey, 'anthropic-version': '2023-06-01', 'content-type': 'application/json' },
90
+ body,
91
+ });
92
+ if (!response.ok) {
93
+ const text = await response.text();
94
+ throw new Error(`Anthropic API error ${response.status}: ${text.slice(0, 200)}`);
95
+ }
96
+ const json = await response.json() as { content: Array<{ type: string; text: string }> };
97
+ return json.content[0]?.text ?? '';
98
+ }
99
+
100
+ export function parseJsonResponse(text: string): Record<string, unknown> {
101
+ let cleaned = text.trim();
102
+ if (cleaned.startsWith('```')) {
103
+ cleaned = cleaned.replace(/^```(?:json)?\s*\n?/, '').replace(/\n?```\s*$/, '');
104
+ }
105
+ try { return JSON.parse(cleaned); } catch { /* fallthrough */ }
106
+ const match = cleaned.match(/\{[\s\S]*\}/);
107
+ if (match) return JSON.parse(match[0]);
108
+ throw new Error(`Failed to parse AI response as JSON: ${text.slice(0, 200)}`);
109
+ }