zoe-agent 0.3.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/CHANGELOG.md +154 -0
- package/LICENSE +96 -0
- package/README.md +568 -0
- package/dist/adapters/cli/agent.d.ts +59 -0
- package/dist/adapters/cli/agent.js +232 -0
- package/dist/adapters/cli/bootstrap.d.ts +25 -0
- package/dist/adapters/cli/bootstrap.js +204 -0
- package/dist/adapters/cli/commands/build-registry.d.ts +14 -0
- package/dist/adapters/cli/commands/build-registry.js +88 -0
- package/dist/adapters/cli/commands/clear.d.ts +7 -0
- package/dist/adapters/cli/commands/clear.js +10 -0
- package/dist/adapters/cli/commands/compact.d.ts +13 -0
- package/dist/adapters/cli/commands/compact.js +96 -0
- package/dist/adapters/cli/commands/exit.d.ts +7 -0
- package/dist/adapters/cli/commands/exit.js +9 -0
- package/dist/adapters/cli/commands/gateway.d.ts +7 -0
- package/dist/adapters/cli/commands/gateway.js +152 -0
- package/dist/adapters/cli/commands/help.d.ts +9 -0
- package/dist/adapters/cli/commands/help.js +12 -0
- package/dist/adapters/cli/commands/models.d.ts +10 -0
- package/dist/adapters/cli/commands/models.js +32 -0
- package/dist/adapters/cli/commands/registry.d.ts +70 -0
- package/dist/adapters/cli/commands/registry.js +111 -0
- package/dist/adapters/cli/commands/settings-utils.d.ts +38 -0
- package/dist/adapters/cli/commands/settings-utils.js +182 -0
- package/dist/adapters/cli/commands/settings.d.ts +9 -0
- package/dist/adapters/cli/commands/settings.js +395 -0
- package/dist/adapters/cli/commands/skills.d.ts +7 -0
- package/dist/adapters/cli/commands/skills.js +21 -0
- package/dist/adapters/cli/config-loader.d.ts +27 -0
- package/dist/adapters/cli/config-loader.js +48 -0
- package/dist/adapters/cli/docker-utils.d.ts +37 -0
- package/dist/adapters/cli/docker-utils.js +90 -0
- package/dist/adapters/cli/index.d.ts +2 -0
- package/dist/adapters/cli/index.js +88 -0
- package/dist/adapters/cli/repl.d.ts +22 -0
- package/dist/adapters/cli/repl.js +256 -0
- package/dist/adapters/cli/setup.d.ts +19 -0
- package/dist/adapters/cli/setup.js +613 -0
- package/dist/adapters/cli/system-prompts.d.ts +56 -0
- package/dist/adapters/cli/system-prompts.js +131 -0
- package/dist/adapters/cli/tui/app.d.ts +58 -0
- package/dist/adapters/cli/tui/app.js +314 -0
- package/dist/adapters/cli/tui/components/assistant-message.d.ts +5 -0
- package/dist/adapters/cli/tui/components/assistant-message.js +9 -0
- package/dist/adapters/cli/tui/components/autocomplete.d.ts +19 -0
- package/dist/adapters/cli/tui/components/autocomplete.js +75 -0
- package/dist/adapters/cli/tui/components/command-palette.d.ts +15 -0
- package/dist/adapters/cli/tui/components/command-palette.js +50 -0
- package/dist/adapters/cli/tui/components/diff-viewer.d.ts +5 -0
- package/dist/adapters/cli/tui/components/diff-viewer.js +109 -0
- package/dist/adapters/cli/tui/components/error-message.d.ts +5 -0
- package/dist/adapters/cli/tui/components/error-message.js +8 -0
- package/dist/adapters/cli/tui/components/footer.d.ts +20 -0
- package/dist/adapters/cli/tui/components/footer.js +19 -0
- package/dist/adapters/cli/tui/components/goal-status.d.ts +12 -0
- package/dist/adapters/cli/tui/components/goal-status.js +22 -0
- package/dist/adapters/cli/tui/components/info-message.d.ts +5 -0
- package/dist/adapters/cli/tui/components/info-message.js +8 -0
- package/dist/adapters/cli/tui/components/logo-banner.d.ts +7 -0
- package/dist/adapters/cli/tui/components/logo-banner.js +33 -0
- package/dist/adapters/cli/tui/components/markdown.d.ts +9 -0
- package/dist/adapters/cli/tui/components/markdown.js +92 -0
- package/dist/adapters/cli/tui/components/message-area.d.ts +19 -0
- package/dist/adapters/cli/tui/components/message-area.js +55 -0
- package/dist/adapters/cli/tui/components/permission-prompt.d.ts +13 -0
- package/dist/adapters/cli/tui/components/permission-prompt.js +32 -0
- package/dist/adapters/cli/tui/components/prompt-area.d.ts +22 -0
- package/dist/adapters/cli/tui/components/prompt-area.js +68 -0
- package/dist/adapters/cli/tui/components/text-input.d.ts +27 -0
- package/dist/adapters/cli/tui/components/text-input.js +142 -0
- package/dist/adapters/cli/tui/components/tool-call-block.d.ts +11 -0
- package/dist/adapters/cli/tui/components/tool-call-block.js +68 -0
- package/dist/adapters/cli/tui/components/user-message.d.ts +5 -0
- package/dist/adapters/cli/tui/components/user-message.js +8 -0
- package/dist/adapters/cli/tui/diff/file-write-meta.d.ts +11 -0
- package/dist/adapters/cli/tui/diff/file-write-meta.js +11 -0
- package/dist/adapters/cli/tui/diff/line-diff.d.ts +17 -0
- package/dist/adapters/cli/tui/diff/line-diff.js +44 -0
- package/dist/adapters/cli/tui/feed-serializer.d.ts +29 -0
- package/dist/adapters/cli/tui/feed-serializer.js +70 -0
- package/dist/adapters/cli/tui/file-index.d.ts +8 -0
- package/dist/adapters/cli/tui/file-index.js +41 -0
- package/dist/adapters/cli/tui/hooks/use-agent.d.ts +54 -0
- package/dist/adapters/cli/tui/hooks/use-agent.js +177 -0
- package/dist/adapters/cli/tui/hooks/use-feed.d.ts +16 -0
- package/dist/adapters/cli/tui/hooks/use-feed.js +25 -0
- package/dist/adapters/cli/tui/hooks/use-file-watcher.d.ts +10 -0
- package/dist/adapters/cli/tui/hooks/use-file-watcher.js +43 -0
- package/dist/adapters/cli/tui/hooks/use-keybindings.d.ts +16 -0
- package/dist/adapters/cli/tui/hooks/use-keybindings.js +25 -0
- package/dist/adapters/cli/tui/hooks/use-theme.d.ts +8 -0
- package/dist/adapters/cli/tui/hooks/use-theme.js +12 -0
- package/dist/adapters/cli/tui/index.d.ts +19 -0
- package/dist/adapters/cli/tui/index.js +206 -0
- package/dist/adapters/cli/tui/ink-reset.d.ts +29 -0
- package/dist/adapters/cli/tui/ink-reset.js +57 -0
- package/dist/adapters/cli/tui/layout.d.ts +15 -0
- package/dist/adapters/cli/tui/layout.js +15 -0
- package/dist/adapters/cli/tui/logo/gradient.d.ts +11 -0
- package/dist/adapters/cli/tui/logo/gradient.js +31 -0
- package/dist/adapters/cli/tui/overlays/help-dialog.d.ts +4 -0
- package/dist/adapters/cli/tui/overlays/help-dialog.js +26 -0
- package/dist/adapters/cli/tui/overlays/model-selector.d.ts +14 -0
- package/dist/adapters/cli/tui/overlays/model-selector.js +43 -0
- package/dist/adapters/cli/tui/overlays/session-selector.d.ts +35 -0
- package/dist/adapters/cli/tui/overlays/session-selector.js +162 -0
- package/dist/adapters/cli/tui/overlays/settings-overlay.d.ts +24 -0
- package/dist/adapters/cli/tui/overlays/settings-overlay.js +126 -0
- package/dist/adapters/cli/tui/session-export.d.ts +21 -0
- package/dist/adapters/cli/tui/session-export.js +63 -0
- package/dist/adapters/cli/tui/theme.d.ts +23 -0
- package/dist/adapters/cli/tui/theme.js +22 -0
- package/dist/adapters/cli/tui/types.d.ts +52 -0
- package/dist/adapters/cli/tui/types.js +12 -0
- package/dist/adapters/sdk/agent.d.ts +20 -0
- package/dist/adapters/sdk/agent.js +356 -0
- package/dist/adapters/sdk/http.d.ts +43 -0
- package/dist/adapters/sdk/http.js +61 -0
- package/dist/adapters/sdk/index.d.ts +58 -0
- package/dist/adapters/sdk/index.js +209 -0
- package/dist/adapters/sdk/settings.d.ts +18 -0
- package/dist/adapters/sdk/settings.js +57 -0
- package/dist/adapters/sdk/tools.d.ts +7 -0
- package/dist/adapters/sdk/tools.js +13 -0
- package/dist/adapters/server/auth.d.ts +53 -0
- package/dist/adapters/server/auth.js +168 -0
- package/dist/adapters/server/index.d.ts +40 -0
- package/dist/adapters/server/index.js +255 -0
- package/dist/adapters/server/rest-gateway.d.ts +13 -0
- package/dist/adapters/server/rest-gateway.js +218 -0
- package/dist/adapters/server/rest.d.ts +37 -0
- package/dist/adapters/server/rest.js +341 -0
- package/dist/adapters/server/server-core.d.ts +55 -0
- package/dist/adapters/server/server-core.js +121 -0
- package/dist/adapters/server/session-store.d.ts +81 -0
- package/dist/adapters/server/session-store.js +272 -0
- package/dist/adapters/server/settings-handlers.d.ts +24 -0
- package/dist/adapters/server/settings-handlers.js +360 -0
- package/dist/adapters/server/standalone.d.ts +19 -0
- package/dist/adapters/server/standalone.js +113 -0
- package/dist/adapters/server/websocket.d.ts +26 -0
- package/dist/adapters/server/websocket.js +68 -0
- package/dist/adapters/server/ws-handlers.d.ts +32 -0
- package/dist/adapters/server/ws-handlers.js +523 -0
- package/dist/adapters/server/ws-types.d.ts +304 -0
- package/dist/adapters/server/ws-types.js +7 -0
- package/dist/core/agent-loop.d.ts +68 -0
- package/dist/core/agent-loop.js +423 -0
- package/dist/core/config.d.ts +115 -0
- package/dist/core/config.js +189 -0
- package/dist/core/errors.d.ts +58 -0
- package/dist/core/errors.js +88 -0
- package/dist/core/hooks.d.ts +35 -0
- package/dist/core/hooks.js +49 -0
- package/dist/core/index.d.ts +23 -0
- package/dist/core/index.js +29 -0
- package/dist/core/message-convert.d.ts +41 -0
- package/dist/core/message-convert.js +94 -0
- package/dist/core/middleware/auth.d.ts +24 -0
- package/dist/core/middleware/auth.js +28 -0
- package/dist/core/middleware/logging.d.ts +23 -0
- package/dist/core/middleware/logging.js +28 -0
- package/dist/core/middleware/rate-limit.d.ts +27 -0
- package/dist/core/middleware/rate-limit.js +38 -0
- package/dist/core/middleware/semantic-tools.d.ts +10 -0
- package/dist/core/middleware/semantic-tools.js +43 -0
- package/dist/core/middleware.d.ts +48 -0
- package/dist/core/middleware.js +38 -0
- package/dist/core/permission.d.ts +25 -0
- package/dist/core/permission.js +50 -0
- package/dist/core/provider-config.d.ts +129 -0
- package/dist/core/provider-config.js +273 -0
- package/dist/core/provider-env.d.ts +39 -0
- package/dist/core/provider-env.js +142 -0
- package/dist/core/provider-resolver.d.ts +12 -0
- package/dist/core/provider-resolver.js +12 -0
- package/dist/core/session-store.d.ts +75 -0
- package/dist/core/session-store.js +245 -0
- package/dist/core/settings-manager.d.ts +57 -0
- package/dist/core/settings-manager.js +359 -0
- package/dist/core/settings-schema.d.ts +38 -0
- package/dist/core/settings-schema.js +171 -0
- package/dist/core/skill-catalog.d.ts +6 -0
- package/dist/core/skill-catalog.js +17 -0
- package/dist/core/skill-invoker.d.ts +127 -0
- package/dist/core/skill-invoker.js +182 -0
- package/dist/core/stream-accumulator.d.ts +21 -0
- package/dist/core/stream-accumulator.js +51 -0
- package/dist/core/stream-manager.d.ts +58 -0
- package/dist/core/stream-manager.js +212 -0
- package/dist/core/tool-executor.d.ts +84 -0
- package/dist/core/tool-executor.js +256 -0
- package/dist/core/types.d.ts +259 -0
- package/dist/core/types.js +11 -0
- package/dist/gateway/gateway.d.ts +52 -0
- package/dist/gateway/gateway.js +537 -0
- package/dist/gateway/index.d.ts +21 -0
- package/dist/gateway/index.js +31 -0
- package/dist/gateway/openapi-importer.d.ts +15 -0
- package/dist/gateway/openapi-importer.js +66 -0
- package/dist/gateway/semantic-scorer.d.ts +7 -0
- package/dist/gateway/semantic-scorer.js +24 -0
- package/dist/gateway/settings-adapter.d.ts +49 -0
- package/dist/gateway/settings-adapter.js +137 -0
- package/dist/gateway/tool-factory.d.ts +9 -0
- package/dist/gateway/tool-factory.js +414 -0
- package/dist/gateway/types.d.ts +68 -0
- package/dist/gateway/types.js +7 -0
- package/dist/models-catalog.js +46 -0
- package/dist/providers/anthropic.d.ts +22 -0
- package/dist/providers/anthropic.js +148 -0
- package/dist/providers/factory.d.ts +10 -0
- package/dist/providers/factory.js +25 -0
- package/dist/providers/openai.d.ts +15 -0
- package/dist/providers/openai.js +71 -0
- package/dist/providers/types.d.ts +48 -0
- package/dist/providers/types.js +1 -0
- package/dist/skills/args.d.ts +37 -0
- package/dist/skills/args.js +99 -0
- package/dist/skills/index.d.ts +11 -0
- package/dist/skills/index.js +23 -0
- package/dist/skills/loader.d.ts +3 -0
- package/dist/skills/loader.js +59 -0
- package/dist/skills/parser.d.ts +7 -0
- package/dist/skills/parser.js +152 -0
- package/dist/skills/registry.d.ts +13 -0
- package/dist/skills/registry.js +74 -0
- package/dist/skills/resolver.d.ts +19 -0
- package/dist/skills/resolver.js +116 -0
- package/dist/skills/types.d.ts +74 -0
- package/dist/skills/types.js +50 -0
- package/dist/tools/browser.d.ts +2 -0
- package/dist/tools/browser.js +68 -0
- package/dist/tools/core.d.ts +20 -0
- package/dist/tools/core.js +244 -0
- package/dist/tools/email.d.ts +2 -0
- package/dist/tools/email.js +61 -0
- package/dist/tools/image.d.ts +2 -0
- package/dist/tools/image.js +257 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +88 -0
- package/dist/tools/interface.d.ts +22 -0
- package/dist/tools/interface.js +1 -0
- package/dist/tools/notify.d.ts +2 -0
- package/dist/tools/notify.js +100 -0
- package/dist/tools/prompt-optimizer.d.ts +2 -0
- package/dist/tools/prompt-optimizer.js +65 -0
- package/dist/tools/screenshot.d.ts +2 -0
- package/dist/tools/screenshot.js +184 -0
- package/dist/tools/search.d.ts +2 -0
- package/dist/tools/search.js +78 -0
- package/dist/tools/todos.d.ts +10 -0
- package/dist/tools/todos.js +50 -0
- package/package.json +119 -0
- package/skills/docker-ops/SKILL.md +329 -0
- package/skills/k8s-deploy/SKILL.md +397 -0
- package/skills/log-analyzer/SKILL.md +331 -0
- package/skills/speckit-analyze/SKILL.md +260 -0
- package/skills/speckit-checklist/SKILL.md +374 -0
- package/skills/speckit-clarify/SKILL.md +286 -0
- package/skills/speckit-constitution/SKILL.md +157 -0
- package/skills/speckit-implement/SKILL.md +224 -0
- package/skills/speckit-plan/SKILL.md +171 -0
- package/skills/speckit-specify/SKILL.md +346 -0
- package/skills/speckit-tasks/SKILL.md +215 -0
- package/skills/speckit-taskstoissues/SKILL.md +107 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zoe Core — StreamManager
|
|
3
|
+
*
|
|
4
|
+
* Shared streaming queue management for text deltas, step results,
|
|
5
|
+
* and SSE conversion. Eliminates duplication between SDK's streamText()
|
|
6
|
+
* and agent's chatStream().
|
|
7
|
+
*
|
|
8
|
+
* Pattern: push-based queues with resolver-based backpressure.
|
|
9
|
+
* Producers call enqueueText/enqueueStep; consumers iterate via
|
|
10
|
+
* textStream/stepsStream async iterables.
|
|
11
|
+
*/
|
|
12
|
+
import type { StepResult, Usage } from "./types.js";
|
|
13
|
+
export declare class StreamManager {
|
|
14
|
+
private textQueue;
|
|
15
|
+
private stepQueue;
|
|
16
|
+
private eventQueue;
|
|
17
|
+
private textDone;
|
|
18
|
+
private stepsDone;
|
|
19
|
+
private eventsDone;
|
|
20
|
+
private textResolver;
|
|
21
|
+
private stepResolver;
|
|
22
|
+
private eventResolver;
|
|
23
|
+
private textResolve;
|
|
24
|
+
private usageResolve;
|
|
25
|
+
private finishResolve;
|
|
26
|
+
readonly fullText: Promise<string>;
|
|
27
|
+
readonly usage: Promise<Usage>;
|
|
28
|
+
readonly finishReason: Promise<string>;
|
|
29
|
+
constructor();
|
|
30
|
+
/** Enqueue a text delta and wake any waiting consumer. */
|
|
31
|
+
enqueueText(delta: string): void;
|
|
32
|
+
/** Enqueue a step result and wake any waiting consumer. */
|
|
33
|
+
enqueueStep(step: StepResult): void;
|
|
34
|
+
/** Resolve the fullText promise. */
|
|
35
|
+
resolveText(text: string): void;
|
|
36
|
+
/** Resolve the usage promise. */
|
|
37
|
+
resolveUsage(usage: Usage): void;
|
|
38
|
+
/** Resolve the finishReason promise. */
|
|
39
|
+
resolveFinish(reason: string): void;
|
|
40
|
+
/** Signal completion: set done flags and wake any waiting consumers. */
|
|
41
|
+
complete(): void;
|
|
42
|
+
/** Async iterable of text deltas. */
|
|
43
|
+
get textStream(): AsyncIterable<string>;
|
|
44
|
+
/** Async iterable of step results. */
|
|
45
|
+
get stepsStream(): AsyncIterable<StepResult>;
|
|
46
|
+
/**
|
|
47
|
+
* Returns a ReadableStream that pipes text deltas and tool events as SSE.
|
|
48
|
+
*
|
|
49
|
+
* Events emitted:
|
|
50
|
+
* - `text` — { delta: string }
|
|
51
|
+
* - `tool_call` — { callId, name, args }
|
|
52
|
+
* - `tool_result` — { callId, output, success }
|
|
53
|
+
* - `done` — { usage: { totalTokens, cost }, finishReason }
|
|
54
|
+
*/
|
|
55
|
+
toSSEStream(): ReadableStream;
|
|
56
|
+
/** Returns a Web API Response wrapping the SSE stream. */
|
|
57
|
+
toResponse(): Response;
|
|
58
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zoe Core — StreamManager
|
|
3
|
+
*
|
|
4
|
+
* Shared streaming queue management for text deltas, step results,
|
|
5
|
+
* and SSE conversion. Eliminates duplication between SDK's streamText()
|
|
6
|
+
* and agent's chatStream().
|
|
7
|
+
*
|
|
8
|
+
* Pattern: push-based queues with resolver-based backpressure.
|
|
9
|
+
* Producers call enqueueText/enqueueStep; consumers iterate via
|
|
10
|
+
* textStream/stepsStream async iterables.
|
|
11
|
+
*/
|
|
12
|
+
// ── SSE helper ────────────────────────────────────────────────────────────
|
|
13
|
+
function sseLine(event, data) {
|
|
14
|
+
return `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
|
|
15
|
+
}
|
|
16
|
+
// ── StreamManager ─────────────────────────────────────────────────────────
|
|
17
|
+
export class StreamManager {
|
|
18
|
+
// Queues for individual consumers
|
|
19
|
+
textQueue = [];
|
|
20
|
+
stepQueue = [];
|
|
21
|
+
// Unified event queue preserving interleaved insertion order for SSE
|
|
22
|
+
eventQueue = [];
|
|
23
|
+
// Done flags
|
|
24
|
+
textDone = false;
|
|
25
|
+
stepsDone = false;
|
|
26
|
+
eventsDone = false;
|
|
27
|
+
// Resolvers for backpressure
|
|
28
|
+
textResolver = null;
|
|
29
|
+
stepResolver = null;
|
|
30
|
+
eventResolver = null;
|
|
31
|
+
// Result promises
|
|
32
|
+
textResolve;
|
|
33
|
+
usageResolve;
|
|
34
|
+
finishResolve;
|
|
35
|
+
fullText;
|
|
36
|
+
usage;
|
|
37
|
+
finishReason;
|
|
38
|
+
constructor() {
|
|
39
|
+
this.fullText = new Promise((r) => { this.textResolve = r; });
|
|
40
|
+
this.usage = new Promise((r) => { this.usageResolve = r; });
|
|
41
|
+
this.finishReason = new Promise((r) => { this.finishResolve = r; });
|
|
42
|
+
}
|
|
43
|
+
// ── Producer API ──────────────────────────────────────────────────────
|
|
44
|
+
/** Enqueue a text delta and wake any waiting consumer. */
|
|
45
|
+
enqueueText(delta) {
|
|
46
|
+
this.textQueue.push(delta);
|
|
47
|
+
this.eventQueue.push({ type: "text", delta });
|
|
48
|
+
if (this.textResolver) {
|
|
49
|
+
this.textResolver();
|
|
50
|
+
this.textResolver = null;
|
|
51
|
+
}
|
|
52
|
+
if (this.eventResolver) {
|
|
53
|
+
this.eventResolver();
|
|
54
|
+
this.eventResolver = null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** Enqueue a step result and wake any waiting consumer. */
|
|
58
|
+
enqueueStep(step) {
|
|
59
|
+
this.stepQueue.push(step);
|
|
60
|
+
this.eventQueue.push({ type: "step", step });
|
|
61
|
+
if (this.stepResolver) {
|
|
62
|
+
this.stepResolver();
|
|
63
|
+
this.stepResolver = null;
|
|
64
|
+
}
|
|
65
|
+
if (this.eventResolver) {
|
|
66
|
+
this.eventResolver();
|
|
67
|
+
this.eventResolver = null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/** Resolve the fullText promise. */
|
|
71
|
+
resolveText(text) {
|
|
72
|
+
this.textResolve(text);
|
|
73
|
+
}
|
|
74
|
+
/** Resolve the usage promise. */
|
|
75
|
+
resolveUsage(usage) {
|
|
76
|
+
this.usageResolve(usage);
|
|
77
|
+
}
|
|
78
|
+
/** Resolve the finishReason promise. */
|
|
79
|
+
resolveFinish(reason) {
|
|
80
|
+
this.finishResolve(reason);
|
|
81
|
+
}
|
|
82
|
+
/** Signal completion: set done flags and wake any waiting consumers. */
|
|
83
|
+
complete() {
|
|
84
|
+
this.textDone = true;
|
|
85
|
+
this.stepsDone = true;
|
|
86
|
+
this.eventsDone = true;
|
|
87
|
+
if (this.textResolver) {
|
|
88
|
+
this.textResolver();
|
|
89
|
+
this.textResolver = null;
|
|
90
|
+
}
|
|
91
|
+
if (this.stepResolver) {
|
|
92
|
+
this.stepResolver();
|
|
93
|
+
this.stepResolver = null;
|
|
94
|
+
}
|
|
95
|
+
if (this.eventResolver) {
|
|
96
|
+
this.eventResolver();
|
|
97
|
+
this.eventResolver = null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// ── Consumer API ──────────────────────────────────────────────────────
|
|
101
|
+
/** Async iterable of text deltas. */
|
|
102
|
+
get textStream() {
|
|
103
|
+
const self = this;
|
|
104
|
+
return {
|
|
105
|
+
[Symbol.asyncIterator]() {
|
|
106
|
+
return {
|
|
107
|
+
async next() {
|
|
108
|
+
while (self.textQueue.length === 0 && !self.textDone) {
|
|
109
|
+
await new Promise((r) => { self.textResolver = r; });
|
|
110
|
+
}
|
|
111
|
+
if (self.textQueue.length > 0) {
|
|
112
|
+
return { value: self.textQueue.shift(), done: false };
|
|
113
|
+
}
|
|
114
|
+
return { value: undefined, done: true };
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/** Async iterable of step results. */
|
|
121
|
+
get stepsStream() {
|
|
122
|
+
const self = this;
|
|
123
|
+
return {
|
|
124
|
+
[Symbol.asyncIterator]() {
|
|
125
|
+
return {
|
|
126
|
+
async next() {
|
|
127
|
+
while (self.stepQueue.length === 0 && !self.stepsDone) {
|
|
128
|
+
await new Promise((r) => { self.stepResolver = r; });
|
|
129
|
+
}
|
|
130
|
+
if (self.stepQueue.length > 0) {
|
|
131
|
+
return { value: self.stepQueue.shift(), done: false };
|
|
132
|
+
}
|
|
133
|
+
return { value: undefined, done: true };
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Returns a ReadableStream that pipes text deltas and tool events as SSE.
|
|
141
|
+
*
|
|
142
|
+
* Events emitted:
|
|
143
|
+
* - `text` — { delta: string }
|
|
144
|
+
* - `tool_call` — { callId, name, args }
|
|
145
|
+
* - `tool_result` — { callId, output, success }
|
|
146
|
+
* - `done` — { usage: { totalTokens, cost }, finishReason }
|
|
147
|
+
*/
|
|
148
|
+
toSSEStream() {
|
|
149
|
+
const encoder = new TextEncoder();
|
|
150
|
+
const self = this;
|
|
151
|
+
return new ReadableStream({
|
|
152
|
+
async start(controller) {
|
|
153
|
+
try {
|
|
154
|
+
// Drain unified event queue preserving interleaved order
|
|
155
|
+
while (true) {
|
|
156
|
+
while (self.eventQueue.length === 0 && !self.eventsDone) {
|
|
157
|
+
await new Promise((r) => { self.eventResolver = r; });
|
|
158
|
+
}
|
|
159
|
+
if (self.eventQueue.length === 0)
|
|
160
|
+
break;
|
|
161
|
+
const event = self.eventQueue.shift();
|
|
162
|
+
if (event.type === "text") {
|
|
163
|
+
controller.enqueue(encoder.encode(sseLine("text", { delta: event.delta })));
|
|
164
|
+
}
|
|
165
|
+
else if (event.type === "step" && event.step.type === "tool_call" && event.step.toolCall) {
|
|
166
|
+
controller.enqueue(encoder.encode(sseLine("tool_call", {
|
|
167
|
+
callId: event.step.toolCall.id,
|
|
168
|
+
name: event.step.toolCall.name,
|
|
169
|
+
args: event.step.toolCall.args,
|
|
170
|
+
})));
|
|
171
|
+
controller.enqueue(encoder.encode(sseLine("tool_result", {
|
|
172
|
+
callId: event.step.toolCall.id,
|
|
173
|
+
output: event.step.toolCall.result,
|
|
174
|
+
success: true,
|
|
175
|
+
})));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// Done event
|
|
179
|
+
const [usage, finishReason] = await Promise.all([
|
|
180
|
+
self.usage,
|
|
181
|
+
self.finishReason,
|
|
182
|
+
]);
|
|
183
|
+
controller.enqueue(encoder.encode(sseLine("done", {
|
|
184
|
+
usage: {
|
|
185
|
+
totalTokens: usage.totalTokens,
|
|
186
|
+
cost: usage.cost,
|
|
187
|
+
},
|
|
188
|
+
finishReason,
|
|
189
|
+
})));
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
if (err instanceof Error && err.name !== "AbortError") {
|
|
193
|
+
console.warn("[StreamManager] SSE stream error:", err);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
finally {
|
|
197
|
+
controller.close();
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
/** Returns a Web API Response wrapping the SSE stream. */
|
|
203
|
+
toResponse() {
|
|
204
|
+
return new Response(this.toSSEStream(), {
|
|
205
|
+
headers: {
|
|
206
|
+
"Content-Type": "text/event-stream",
|
|
207
|
+
"Cache-Control": "no-cache",
|
|
208
|
+
Connection: "keep-alive",
|
|
209
|
+
},
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zoe Core — Tool executor
|
|
3
|
+
*
|
|
4
|
+
* Tool registry, resolution, factory, and execution logic.
|
|
5
|
+
* Transport-agnostic: no chalk, no HTTP, no CLI concerns.
|
|
6
|
+
*/
|
|
7
|
+
import { ToolModule, ToolDefinition, ToolExecExtra } from "../tools/interface.js";
|
|
8
|
+
import { UserToolDefinition, ToolResult } from "./types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Return the tool definitions for all registered tools (built-in + custom).
|
|
11
|
+
*/
|
|
12
|
+
export declare function getAllToolDefinitions(): ToolDefinition[];
|
|
13
|
+
/**
|
|
14
|
+
* Return all registered tool modules (built-in + custom).
|
|
15
|
+
*/
|
|
16
|
+
export declare function getAllToolModules(): ToolModule[];
|
|
17
|
+
export declare const CORE_TOOLS: string[];
|
|
18
|
+
export declare const COMM_TOOLS: string[];
|
|
19
|
+
export declare const ADVANCED_TOOLS: string[];
|
|
20
|
+
export declare const ALL_TOOLS: string[];
|
|
21
|
+
/**
|
|
22
|
+
* Create a custom tool module from a Zod-like schema definition.
|
|
23
|
+
*
|
|
24
|
+
* Returns a `ToolModule` compatible with the built-in tool registry,
|
|
25
|
+
* so custom tools can be mixed freely with built-in ones.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const myTool = tool({
|
|
30
|
+
* description: "Greets a person",
|
|
31
|
+
* parameters: z.object({ name: z.string() }),
|
|
32
|
+
* execute: async ({ name }) => `Hello, ${name}!`,
|
|
33
|
+
* });
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function tool(definition: UserToolDefinition): ToolModule;
|
|
37
|
+
/**
|
|
38
|
+
* Register a tool module in the global tool registry.
|
|
39
|
+
*
|
|
40
|
+
* @param module A `ToolModule` to add to the registry
|
|
41
|
+
*/
|
|
42
|
+
export declare function registerTool(module: ToolModule): void;
|
|
43
|
+
/**
|
|
44
|
+
* Coerce a tool handler's `string | ToolResult` return into a `ToolResult`.
|
|
45
|
+
* Plain strings (the common case) become `{ output, success: true }` with no
|
|
46
|
+
* metadata. Structured ToolResults pass through with `metadata` preserved.
|
|
47
|
+
*/
|
|
48
|
+
export declare function normalizeToolResult(raw: string | ToolResult): ToolResult;
|
|
49
|
+
/**
|
|
50
|
+
* Execute a tool by name with the given arguments and optional config.
|
|
51
|
+
*
|
|
52
|
+
* @param name Tool function name (e.g. "execute_shell_command")
|
|
53
|
+
* @param args Arguments object for the tool
|
|
54
|
+
* @param config Optional runtime config passed to the tool handler
|
|
55
|
+
* @returns ToolResult — `output` (what the LLM sees) + optional `metadata`
|
|
56
|
+
* for adapters (e.g. write_file's FileWriteMetadata for the diff)
|
|
57
|
+
* @throws Error if the tool name is not found in the registry
|
|
58
|
+
*/
|
|
59
|
+
export declare function executeTool(name: string, args: Record<string, unknown>, config?: Record<string, unknown>, extra?: ToolExecExtra): Promise<ToolResult>;
|
|
60
|
+
/**
|
|
61
|
+
* Return the built-in tool definitions belonging to a named group.
|
|
62
|
+
*
|
|
63
|
+
* @param group One of "core", "comm", "advanced", or "all"
|
|
64
|
+
* @returns Array of OpenAI function definitions for the matching tools
|
|
65
|
+
* @throws Error if the group name is not recognised
|
|
66
|
+
*/
|
|
67
|
+
export declare function getToolGroup(group: "core" | "comm" | "advanced" | "all"): ToolDefinition[];
|
|
68
|
+
type ToolInput = string | UserToolDefinition;
|
|
69
|
+
/**
|
|
70
|
+
* Resolve a mixed array of tool references into concrete OpenAI function
|
|
71
|
+
* definitions ready to send to the LLM.
|
|
72
|
+
*
|
|
73
|
+
* Accepted input shapes:
|
|
74
|
+
* - `"all"` — expands to all built-in tools
|
|
75
|
+
* - `"core"` / `"comm"` / `"advanced"` — expands to the named group
|
|
76
|
+
* - A built-in tool name string — looked up from the internal registry
|
|
77
|
+
* - A `UserToolDefinition` object — converted via `tool()` factory
|
|
78
|
+
*
|
|
79
|
+
* @param tools Array of tool references (defaults to all built-in tools)
|
|
80
|
+
* @returns Deduplicated array of OpenAI function definitions
|
|
81
|
+
* @throws Error if a string name is not found in the built-in registry
|
|
82
|
+
*/
|
|
83
|
+
export declare function resolveTools(tools?: ToolInput[]): ToolDefinition[];
|
|
84
|
+
export {};
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zoe Core — Tool executor
|
|
3
|
+
*
|
|
4
|
+
* Tool registry, resolution, factory, and execution logic.
|
|
5
|
+
* Transport-agnostic: no chalk, no HTTP, no CLI concerns.
|
|
6
|
+
*/
|
|
7
|
+
import { builtInTools } from "../tools/index.js";
|
|
8
|
+
// ── Internal registry ───────────────────────────────────────────────
|
|
9
|
+
const registry = [...builtInTools];
|
|
10
|
+
/**
|
|
11
|
+
* Return the tool definitions for all registered tools (built-in + custom).
|
|
12
|
+
*/
|
|
13
|
+
export function getAllToolDefinitions() {
|
|
14
|
+
return registry.map((t) => t.definition);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Return all registered tool modules (built-in + custom).
|
|
18
|
+
*/
|
|
19
|
+
export function getAllToolModules() {
|
|
20
|
+
return registry;
|
|
21
|
+
}
|
|
22
|
+
// ── Tool groups ──────────────────────────────────────────────────────
|
|
23
|
+
export const CORE_TOOLS = [
|
|
24
|
+
"execute_shell_command",
|
|
25
|
+
"read_file",
|
|
26
|
+
"write_file",
|
|
27
|
+
"get_current_datetime",
|
|
28
|
+
];
|
|
29
|
+
export const COMM_TOOLS = [
|
|
30
|
+
"send_email",
|
|
31
|
+
"web_search",
|
|
32
|
+
"send_notification",
|
|
33
|
+
];
|
|
34
|
+
export const ADVANCED_TOOLS = [
|
|
35
|
+
"read_website",
|
|
36
|
+
"take_screenshot",
|
|
37
|
+
"generate_image",
|
|
38
|
+
"optimize_prompt",
|
|
39
|
+
"use_skill",
|
|
40
|
+
];
|
|
41
|
+
export const ALL_TOOLS = [...CORE_TOOLS, ...COMM_TOOLS, ...ADVANCED_TOOLS];
|
|
42
|
+
// ── Helpers ──────────────────────────────────────────────────────────
|
|
43
|
+
let customToolCounter = 0;
|
|
44
|
+
/**
|
|
45
|
+
* Convert a parameter definition into JSON Schema.
|
|
46
|
+
*
|
|
47
|
+
* Accepts plain `{ type: "object", properties: {...}, required: [...] }` objects.
|
|
48
|
+
* Anything else is wrapped in a generic object schema.
|
|
49
|
+
*/
|
|
50
|
+
function parametersToJsonSchema(parameters) {
|
|
51
|
+
if (parameters == null || typeof parameters !== "object") {
|
|
52
|
+
return { type: "object", properties: {} };
|
|
53
|
+
}
|
|
54
|
+
const rec = parameters;
|
|
55
|
+
// Already a valid JSON Schema object — validate basic shape
|
|
56
|
+
if ("type" in rec && "properties" in rec
|
|
57
|
+
&& typeof rec.type === "string"
|
|
58
|
+
&& typeof rec.properties === "object" && rec.properties !== null) {
|
|
59
|
+
return rec;
|
|
60
|
+
}
|
|
61
|
+
// Unknown shape — wrap generically
|
|
62
|
+
return { type: "object", properties: {} };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Generate a unique tool name when the user doesn't supply one.
|
|
66
|
+
*/
|
|
67
|
+
function generateToolName() {
|
|
68
|
+
customToolCounter += 1;
|
|
69
|
+
return `custom_tool_${customToolCounter}`;
|
|
70
|
+
}
|
|
71
|
+
// ── tool() factory ───────────────────────────────────────────────────
|
|
72
|
+
/**
|
|
73
|
+
* Create a custom tool module from a Zod-like schema definition.
|
|
74
|
+
*
|
|
75
|
+
* Returns a `ToolModule` compatible with the built-in tool registry,
|
|
76
|
+
* so custom tools can be mixed freely with built-in ones.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* const myTool = tool({
|
|
81
|
+
* description: "Greets a person",
|
|
82
|
+
* parameters: z.object({ name: z.string() }),
|
|
83
|
+
* execute: async ({ name }) => `Hello, ${name}!`,
|
|
84
|
+
* });
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export function tool(definition) {
|
|
88
|
+
const functionName = definition.name ?? generateToolName();
|
|
89
|
+
const jsonSchema = parametersToJsonSchema(definition.parameters);
|
|
90
|
+
const openaiDefinition = {
|
|
91
|
+
type: "function",
|
|
92
|
+
function: {
|
|
93
|
+
name: functionName,
|
|
94
|
+
description: definition.description,
|
|
95
|
+
parameters: {
|
|
96
|
+
type: jsonSchema.type ?? "object",
|
|
97
|
+
properties: jsonSchema.properties ?? {},
|
|
98
|
+
required: jsonSchema.required ?? [],
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
const handler = async (args, config, extra) => {
|
|
103
|
+
const context = {
|
|
104
|
+
config: config ?? {},
|
|
105
|
+
onUpdate: extra?.onUpdate,
|
|
106
|
+
signal: extra?.signal,
|
|
107
|
+
};
|
|
108
|
+
// Passthrough — normalization (string | ToolResult → ToolResult) happens once
|
|
109
|
+
// at the executeTool boundary. Direct handler callers get back exactly what
|
|
110
|
+
// `execute` returned (a string in the common case → backward compatible).
|
|
111
|
+
return definition.execute(args, context);
|
|
112
|
+
};
|
|
113
|
+
return {
|
|
114
|
+
name: functionName,
|
|
115
|
+
definition: openaiDefinition,
|
|
116
|
+
handler,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
// ── registerTool ──────────────────────────────────────────────────────
|
|
120
|
+
/**
|
|
121
|
+
* Register a tool module in the global tool registry.
|
|
122
|
+
*
|
|
123
|
+
* @param module A `ToolModule` to add to the registry
|
|
124
|
+
*/
|
|
125
|
+
export function registerTool(module) {
|
|
126
|
+
if (registry.some(t => t.definition.function.name === module.definition.function.name)) {
|
|
127
|
+
console.warn(`[tool-executor] Duplicate tool registration ignored: ${module.definition.function.name}`);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
registry.push(module);
|
|
131
|
+
}
|
|
132
|
+
// ── executeTool ───────────────────────────────────────────────────────
|
|
133
|
+
/**
|
|
134
|
+
* Coerce a tool handler's `string | ToolResult` return into a `ToolResult`.
|
|
135
|
+
* Plain strings (the common case) become `{ output, success: true }` with no
|
|
136
|
+
* metadata. Structured ToolResults pass through with `metadata` preserved.
|
|
137
|
+
*/
|
|
138
|
+
export function normalizeToolResult(raw) {
|
|
139
|
+
if (typeof raw === "string")
|
|
140
|
+
return { output: raw, success: true };
|
|
141
|
+
if (raw && typeof raw === "object" && "output" in raw)
|
|
142
|
+
return raw;
|
|
143
|
+
return { output: String(raw), success: true };
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Execute a tool by name with the given arguments and optional config.
|
|
147
|
+
*
|
|
148
|
+
* @param name Tool function name (e.g. "execute_shell_command")
|
|
149
|
+
* @param args Arguments object for the tool
|
|
150
|
+
* @param config Optional runtime config passed to the tool handler
|
|
151
|
+
* @returns ToolResult — `output` (what the LLM sees) + optional `metadata`
|
|
152
|
+
* for adapters (e.g. write_file's FileWriteMetadata for the diff)
|
|
153
|
+
* @throws Error if the tool name is not found in the registry
|
|
154
|
+
*/
|
|
155
|
+
export async function executeTool(name, args, config, extra) {
|
|
156
|
+
const found = registry.find((t) => t.definition.function.name === name);
|
|
157
|
+
if (!found) {
|
|
158
|
+
throw new Error(`Unknown tool "${name}". Available: ${registry
|
|
159
|
+
.map((t) => t.definition.function.name)
|
|
160
|
+
.join(", ")}`);
|
|
161
|
+
}
|
|
162
|
+
const raw = await found.handler(args, config, extra);
|
|
163
|
+
return normalizeToolResult(raw);
|
|
164
|
+
}
|
|
165
|
+
// ── getToolGroup ─────────────────────────────────────────────────────
|
|
166
|
+
/**
|
|
167
|
+
* Return the built-in tool definitions belonging to a named group.
|
|
168
|
+
*
|
|
169
|
+
* @param group One of "core", "comm", "advanced", or "all"
|
|
170
|
+
* @returns Array of OpenAI function definitions for the matching tools
|
|
171
|
+
* @throws Error if the group name is not recognised
|
|
172
|
+
*/
|
|
173
|
+
export function getToolGroup(group) {
|
|
174
|
+
let names;
|
|
175
|
+
switch (group) {
|
|
176
|
+
case "core":
|
|
177
|
+
names = CORE_TOOLS;
|
|
178
|
+
break;
|
|
179
|
+
case "comm":
|
|
180
|
+
names = COMM_TOOLS;
|
|
181
|
+
break;
|
|
182
|
+
case "advanced":
|
|
183
|
+
names = ADVANCED_TOOLS;
|
|
184
|
+
break;
|
|
185
|
+
case "all":
|
|
186
|
+
names = ALL_TOOLS;
|
|
187
|
+
break;
|
|
188
|
+
default:
|
|
189
|
+
throw new Error(`Unknown tool group "${group}". Valid groups: core, comm, advanced, all`);
|
|
190
|
+
}
|
|
191
|
+
const defs = [];
|
|
192
|
+
for (const name of names) {
|
|
193
|
+
const found = registry.find((t) => t.definition.function.name === name);
|
|
194
|
+
if (found) {
|
|
195
|
+
defs.push(found.definition);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return defs;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Resolve a mixed array of tool references into concrete OpenAI function
|
|
202
|
+
* definitions ready to send to the LLM.
|
|
203
|
+
*
|
|
204
|
+
* Accepted input shapes:
|
|
205
|
+
* - `"all"` — expands to all built-in tools
|
|
206
|
+
* - `"core"` / `"comm"` / `"advanced"` — expands to the named group
|
|
207
|
+
* - A built-in tool name string — looked up from the internal registry
|
|
208
|
+
* - A `UserToolDefinition` object — converted via `tool()` factory
|
|
209
|
+
*
|
|
210
|
+
* @param tools Array of tool references (defaults to all built-in tools)
|
|
211
|
+
* @returns Deduplicated array of OpenAI function definitions
|
|
212
|
+
* @throws Error if a string name is not found in the built-in registry
|
|
213
|
+
*/
|
|
214
|
+
export function resolveTools(tools) {
|
|
215
|
+
const inputs = tools ?? ["all"];
|
|
216
|
+
const seen = new Set();
|
|
217
|
+
const result = [];
|
|
218
|
+
for (const input of inputs) {
|
|
219
|
+
// String reference — group name or built-in tool name
|
|
220
|
+
if (typeof input === "string") {
|
|
221
|
+
// Group expansion
|
|
222
|
+
if (input === "all" || input === "core" || input === "comm" || input === "advanced") {
|
|
223
|
+
const groupDefs = getToolGroup(input);
|
|
224
|
+
for (const def of groupDefs) {
|
|
225
|
+
const name = def.function.name;
|
|
226
|
+
if (!seen.has(name)) {
|
|
227
|
+
seen.add(name);
|
|
228
|
+
result.push(def);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
// Individual built-in tool lookup
|
|
234
|
+
const found = registry.find((t) => t.definition.function.name === input);
|
|
235
|
+
if (!found) {
|
|
236
|
+
throw new Error(`Unknown tool "${input}". Available: ${registry
|
|
237
|
+
.map((t) => t.definition.function.name)
|
|
238
|
+
.join(", ")}`);
|
|
239
|
+
}
|
|
240
|
+
const name = found.definition.function.name;
|
|
241
|
+
if (!seen.has(name)) {
|
|
242
|
+
seen.add(name);
|
|
243
|
+
result.push(found.definition);
|
|
244
|
+
}
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
// ToolDefinition object — convert via factory
|
|
248
|
+
const module = tool(input);
|
|
249
|
+
const name = module.definition.function.name;
|
|
250
|
+
if (!seen.has(name)) {
|
|
251
|
+
seen.add(name);
|
|
252
|
+
result.push(module.definition);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return result;
|
|
256
|
+
}
|