@synergenius/flowweaver-pack-weaver 0.6.1 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bot/ai-client.d.ts +1 -0
- package/dist/bot/ai-client.d.ts.map +1 -1
- package/dist/bot/ai-client.js +52 -1
- package/dist/bot/ai-client.js.map +1 -1
- package/dist/bot/audit-logger.d.ts +5 -0
- package/dist/bot/audit-logger.d.ts.map +1 -0
- package/dist/bot/audit-logger.js +42 -0
- package/dist/bot/audit-logger.js.map +1 -0
- package/dist/bot/audit-store.d.ts +13 -0
- package/dist/bot/audit-store.d.ts.map +1 -0
- package/dist/bot/audit-store.js +59 -0
- package/dist/bot/audit-store.js.map +1 -0
- package/dist/bot/cli-provider.d.ts +1 -0
- package/dist/bot/cli-provider.d.ts.map +1 -1
- package/dist/bot/cli-provider.js +86 -22
- package/dist/bot/cli-provider.js.map +1 -1
- package/dist/bot/cli-stream-parser.d.ts +11 -0
- package/dist/bot/cli-stream-parser.d.ts.map +1 -0
- package/dist/bot/cli-stream-parser.js +53 -0
- package/dist/bot/cli-stream-parser.js.map +1 -0
- package/dist/bot/file-validator.d.ts +1 -1
- package/dist/bot/file-validator.d.ts.map +1 -1
- package/dist/bot/file-validator.js +13 -27
- package/dist/bot/file-validator.js.map +1 -1
- package/dist/bot/fw-api.d.ts +8 -0
- package/dist/bot/fw-api.d.ts.map +1 -0
- package/dist/bot/fw-api.js +12 -0
- package/dist/bot/fw-api.js.map +1 -0
- package/dist/bot/runner.d.ts +2 -1
- package/dist/bot/runner.d.ts.map +1 -1
- package/dist/bot/runner.js +8 -0
- package/dist/bot/runner.js.map +1 -1
- package/dist/bot/step-executor.d.ts +3 -2
- package/dist/bot/step-executor.d.ts.map +1 -1
- package/dist/bot/step-executor.js +9 -30
- package/dist/bot/step-executor.js.map +1 -1
- package/dist/bot/system-prompt.d.ts +13 -1
- package/dist/bot/system-prompt.d.ts.map +1 -1
- package/dist/bot/system-prompt.js +28 -22
- package/dist/bot/system-prompt.js.map +1 -1
- package/dist/bot/types.d.ts +9 -1
- package/dist/bot/types.d.ts.map +1 -1
- package/dist/cli-bridge.d.ts.map +1 -1
- package/dist/cli-bridge.js +2 -1
- package/dist/cli-bridge.js.map +1 -1
- package/dist/cli-handlers.d.ts +2 -1
- package/dist/cli-handlers.d.ts.map +1 -1
- package/dist/cli-handlers.js +69 -0
- package/dist/cli-handlers.js.map +1 -1
- package/dist/node-types/approval-gate.d.ts.map +1 -1
- package/dist/node-types/approval-gate.js +24 -0
- package/dist/node-types/approval-gate.js.map +1 -1
- package/dist/node-types/exec-validate-retry.d.ts.map +1 -1
- package/dist/node-types/exec-validate-retry.js +10 -4
- package/dist/node-types/exec-validate-retry.js.map +1 -1
- package/dist/node-types/execute-plan.js +1 -1
- package/dist/node-types/execute-plan.js.map +1 -1
- package/dist/node-types/git-ops.d.ts.map +1 -1
- package/dist/node-types/git-ops.js +2 -0
- package/dist/node-types/git-ops.js.map +1 -1
- package/dist/node-types/plan-task.d.ts.map +1 -1
- package/dist/node-types/plan-task.js +9 -1
- package/dist/node-types/plan-task.js.map +1 -1
- package/dist/node-types/send-notify.d.ts.map +1 -1
- package/dist/node-types/send-notify.js +4 -1
- package/dist/node-types/send-notify.js.map +1 -1
- package/dist/node-types/validate-result.d.ts +2 -2
- package/dist/node-types/validate-result.d.ts.map +1 -1
- package/dist/node-types/validate-result.js +2 -2
- package/dist/node-types/validate-result.js.map +1 -1
- package/dist/templates/weaver-bot-template.js +1 -1
- package/dist/templates/weaver-bot-template.js.map +1 -1
- package/dist/workflows/weaver-bot-batch.d.ts +4 -1
- package/dist/workflows/weaver-bot-batch.d.ts.map +1 -1
- package/dist/workflows/weaver-bot-batch.js +1 -1
- package/dist/workflows/weaver-bot-batch.js.map +1 -1
- package/dist/workflows/weaver-bot.d.ts +4 -1
- package/dist/workflows/weaver-bot.d.ts.map +1 -1
- package/dist/workflows/weaver-bot.js +1 -1
- package/dist/workflows/weaver-bot.js.map +1 -1
- package/flowweaver.manifest.json +23 -1
- package/package.json +3 -2
- package/src/bot/agent-provider.ts +273 -0
- package/src/bot/ai-client.ts +109 -0
- package/src/bot/approvals.ts +273 -0
- package/src/bot/audit-logger.ts +45 -0
- package/src/bot/audit-store.ts +69 -0
- package/src/bot/bot-agent-channel.ts +99 -0
- package/src/bot/cli-provider.ts +169 -0
- package/src/bot/cli-stream-parser.ts +59 -0
- package/src/bot/cost-store.ts +92 -0
- package/src/bot/cost-tracker.ts +72 -0
- package/src/bot/cron-parser.ts +153 -0
- package/src/bot/cron-scheduler.ts +48 -0
- package/src/bot/dashboard.ts +658 -0
- package/src/bot/design-checker.ts +327 -0
- package/src/bot/file-lock.ts +73 -0
- package/src/bot/file-validator.ts +41 -0
- package/src/bot/file-watcher.ts +103 -0
- package/src/bot/fw-api.ts +18 -0
- package/src/bot/genesis-prompt-context.ts +135 -0
- package/src/bot/genesis-store.ts +180 -0
- package/src/bot/index.ts +127 -0
- package/src/bot/notifications.ts +263 -0
- package/src/bot/pipeline-runner.ts +324 -0
- package/src/bot/provider-registry.ts +236 -0
- package/src/bot/run-store.ts +169 -0
- package/src/bot/runner.ts +311 -0
- package/src/bot/session-state.ts +73 -0
- package/src/bot/steering.ts +44 -0
- package/src/bot/step-executor.ts +34 -0
- package/src/bot/system-prompt.ts +280 -0
- package/src/bot/task-queue.ts +111 -0
- package/src/bot/types.ts +571 -0
- package/src/bot/utils.ts +17 -0
- package/src/bot/watch-daemon.ts +203 -0
- package/src/bot/web-approval.ts +240 -0
- package/src/cli-bridge.ts +41 -0
- package/src/cli-handlers.ts +1271 -0
- package/src/docs/weaver-config.md +135 -0
- package/src/index.ts +173 -0
- package/src/mcp-tools.ts +274 -0
- package/src/node-types/abort-task.ts +31 -0
- package/src/node-types/approval-gate.ts +95 -0
- package/src/node-types/bot-report.ts +82 -0
- package/src/node-types/build-context.ts +65 -0
- package/src/node-types/detect-provider.ts +75 -0
- package/src/node-types/exec-validate-retry.ts +175 -0
- package/src/node-types/execute-plan.ts +130 -0
- package/src/node-types/execute-target.ts +267 -0
- package/src/node-types/fix-errors.ts +68 -0
- package/src/node-types/genesis-apply-retry.ts +138 -0
- package/src/node-types/genesis-apply.ts +96 -0
- package/src/node-types/genesis-approve.ts +73 -0
- package/src/node-types/genesis-check-stabilize.ts +37 -0
- package/src/node-types/genesis-check-threshold.ts +34 -0
- package/src/node-types/genesis-commit.ts +71 -0
- package/src/node-types/genesis-compile-validate.ts +77 -0
- package/src/node-types/genesis-diff-fingerprint.ts +67 -0
- package/src/node-types/genesis-diff-workflow.ts +71 -0
- package/src/node-types/genesis-escrow-grace.ts +62 -0
- package/src/node-types/genesis-escrow-migrate.ts +138 -0
- package/src/node-types/genesis-escrow-recover.ts +99 -0
- package/src/node-types/genesis-escrow-stage.ts +104 -0
- package/src/node-types/genesis-escrow-validate.ts +120 -0
- package/src/node-types/genesis-load-config.ts +44 -0
- package/src/node-types/genesis-observe.ts +119 -0
- package/src/node-types/genesis-propose.ts +97 -0
- package/src/node-types/genesis-report.ts +95 -0
- package/src/node-types/genesis-snapshot.ts +30 -0
- package/src/node-types/genesis-try-apply.ts +165 -0
- package/src/node-types/genesis-update-history.ts +72 -0
- package/src/node-types/genesis-validate-proposal.ts +124 -0
- package/src/node-types/git-ops.ts +72 -0
- package/src/node-types/index.ts +36 -0
- package/src/node-types/load-config.ts +27 -0
- package/src/node-types/plan-task.ts +77 -0
- package/src/node-types/read-workflow.ts +68 -0
- package/src/node-types/receive-task.ts +92 -0
- package/src/node-types/report.ts +25 -0
- package/src/node-types/resolve-target.ts +64 -0
- package/src/node-types/route-task.ts +25 -0
- package/src/node-types/send-notify.ts +75 -0
- package/src/node-types/validate-result.ts +49 -0
- package/src/templates/index.ts +5 -0
- package/src/templates/weaver-bot-template.ts +106 -0
- package/src/workflows/genesis-task.ts +91 -0
- package/src/workflows/index.ts +3 -0
- package/src/workflows/weaver-bot-batch.ts +65 -0
- package/src/workflows/weaver-bot.ts +79 -0
|
@@ -38,7 +38,10 @@
|
|
|
38
38
|
* @returns onFailure [order:-1] [hidden] - On Failure
|
|
39
39
|
* @returns summary [order:0] - Summary text
|
|
40
40
|
*/
|
|
41
|
-
export declare function weaverBotBatch(execute: boolean,
|
|
41
|
+
export declare function weaverBotBatch(execute: boolean, params: {
|
|
42
|
+
taskJson?: string;
|
|
43
|
+
projectDir?: string;
|
|
44
|
+
}, __abortSignal__?: AbortSignal): Promise<{
|
|
42
45
|
onSuccess: boolean;
|
|
43
46
|
onFailure: boolean;
|
|
44
47
|
summary: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"weaver-bot-batch.d.ts","sourceRoot":"","sources":["../../src/workflows/weaver-bot-batch.ts"],"names":[],"mappings":"AAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,OAAO,EAChB,QAAQ,CAAC,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"weaver-bot-batch.d.ts","sourceRoot":"","sources":["../../src/workflows/weaver-bot-batch.ts"],"names":[],"mappings":"AAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAClD,eAAe,CAAC,EAAE,WAAW,GAC5B,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAK7E"}
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
* @returns onFailure [order:-1] [hidden] - On Failure
|
|
41
41
|
* @returns summary [order:0] - Summary text
|
|
42
42
|
*/
|
|
43
|
-
export async function weaverBotBatch(execute,
|
|
43
|
+
export async function weaverBotBatch(execute, params, __abortSignal__) {
|
|
44
44
|
// @flow-weaver-body-start
|
|
45
45
|
// (auto-generated by compiler)
|
|
46
46
|
// @flow-weaver-body-end
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"weaver-bot-batch.js","sourceRoot":"","sources":["../../src/workflows/weaver-bot-batch.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,mCAAmC;AAcnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAgB,EAChB,
|
|
1
|
+
{"version":3,"file":"weaver-bot-batch.js","sourceRoot":"","sources":["../../src/workflows/weaver-bot-batch.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,mCAAmC;AAcnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,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"}
|
|
@@ -50,7 +50,10 @@
|
|
|
50
50
|
* @returns onFailure [order:-1] [hidden] - On Failure
|
|
51
51
|
* @returns summary [order:0] - Summary text
|
|
52
52
|
*/
|
|
53
|
-
export declare function weaverBot(execute: boolean,
|
|
53
|
+
export declare function weaverBot(execute: boolean, params: {
|
|
54
|
+
taskJson?: string;
|
|
55
|
+
projectDir?: string;
|
|
56
|
+
}, __abortSignal__?: AbortSignal): Promise<{
|
|
54
57
|
onSuccess: boolean;
|
|
55
58
|
onFailure: boolean;
|
|
56
59
|
summary: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"weaver-bot.d.ts","sourceRoot":"","sources":["../../src/workflows/weaver-bot.ts"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,OAAO,EAChB,QAAQ,CAAC,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"weaver-bot.d.ts","sourceRoot":"","sources":["../../src/workflows/weaver-bot.ts"],"names":[],"mappings":"AAiBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAClD,eAAe,CAAC,EAAE,WAAW,GAC5B,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAK7E"}
|
|
@@ -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,
|
|
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,
|
|
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"}
|
package/flowweaver.manifest.json
CHANGED
|
@@ -1,13 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifestVersion": 1,
|
|
3
3
|
"name": "@synergenius/flowweaver-pack-weaver",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.7.1",
|
|
5
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",
|
|
9
9
|
"ai"
|
|
10
10
|
],
|
|
11
|
+
"botRegistrations": [
|
|
12
|
+
{
|
|
13
|
+
"id": "weaver-bot",
|
|
14
|
+
"name": "Weaver Bot",
|
|
15
|
+
"description": "AI-powered autonomous workflow creator",
|
|
16
|
+
"icon": "psychology",
|
|
17
|
+
"color": "#6366f1",
|
|
18
|
+
"workflowExport": "weaverBot",
|
|
19
|
+
"paramName": "taskJson",
|
|
20
|
+
"sourceTemplateId": "weaver-bot"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"id": "weaver-genesis",
|
|
24
|
+
"name": "Weaver Genesis",
|
|
25
|
+
"description": "Self-evolution cycle for a target workflow",
|
|
26
|
+
"icon": "autoAwesome",
|
|
27
|
+
"color": "#9f5fe3",
|
|
28
|
+
"workflowExport": "genesisTask",
|
|
29
|
+
"paramName": "config",
|
|
30
|
+
"sourceTemplateId": "genesis-task"
|
|
31
|
+
}
|
|
32
|
+
],
|
|
11
33
|
"nodeTypes": [
|
|
12
34
|
{
|
|
13
35
|
"name": "weaverLoadConfig",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synergenius/flowweaver-pack-weaver",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "AI bot for Flow Weaver. Execute tasks, run workflows, evolve autonomously.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"@anthropic-ai/sdk": ">=0.30.0",
|
|
39
|
-
"@synergenius/flow-weaver": ">=0.
|
|
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
|
+
}
|