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.
Files changed (267) hide show
  1. package/CHANGELOG.md +154 -0
  2. package/LICENSE +96 -0
  3. package/README.md +568 -0
  4. package/dist/adapters/cli/agent.d.ts +59 -0
  5. package/dist/adapters/cli/agent.js +232 -0
  6. package/dist/adapters/cli/bootstrap.d.ts +25 -0
  7. package/dist/adapters/cli/bootstrap.js +204 -0
  8. package/dist/adapters/cli/commands/build-registry.d.ts +14 -0
  9. package/dist/adapters/cli/commands/build-registry.js +88 -0
  10. package/dist/adapters/cli/commands/clear.d.ts +7 -0
  11. package/dist/adapters/cli/commands/clear.js +10 -0
  12. package/dist/adapters/cli/commands/compact.d.ts +13 -0
  13. package/dist/adapters/cli/commands/compact.js +96 -0
  14. package/dist/adapters/cli/commands/exit.d.ts +7 -0
  15. package/dist/adapters/cli/commands/exit.js +9 -0
  16. package/dist/adapters/cli/commands/gateway.d.ts +7 -0
  17. package/dist/adapters/cli/commands/gateway.js +152 -0
  18. package/dist/adapters/cli/commands/help.d.ts +9 -0
  19. package/dist/adapters/cli/commands/help.js +12 -0
  20. package/dist/adapters/cli/commands/models.d.ts +10 -0
  21. package/dist/adapters/cli/commands/models.js +32 -0
  22. package/dist/adapters/cli/commands/registry.d.ts +70 -0
  23. package/dist/adapters/cli/commands/registry.js +111 -0
  24. package/dist/adapters/cli/commands/settings-utils.d.ts +38 -0
  25. package/dist/adapters/cli/commands/settings-utils.js +182 -0
  26. package/dist/adapters/cli/commands/settings.d.ts +9 -0
  27. package/dist/adapters/cli/commands/settings.js +395 -0
  28. package/dist/adapters/cli/commands/skills.d.ts +7 -0
  29. package/dist/adapters/cli/commands/skills.js +21 -0
  30. package/dist/adapters/cli/config-loader.d.ts +27 -0
  31. package/dist/adapters/cli/config-loader.js +48 -0
  32. package/dist/adapters/cli/docker-utils.d.ts +37 -0
  33. package/dist/adapters/cli/docker-utils.js +90 -0
  34. package/dist/adapters/cli/index.d.ts +2 -0
  35. package/dist/adapters/cli/index.js +88 -0
  36. package/dist/adapters/cli/repl.d.ts +22 -0
  37. package/dist/adapters/cli/repl.js +256 -0
  38. package/dist/adapters/cli/setup.d.ts +19 -0
  39. package/dist/adapters/cli/setup.js +613 -0
  40. package/dist/adapters/cli/system-prompts.d.ts +56 -0
  41. package/dist/adapters/cli/system-prompts.js +131 -0
  42. package/dist/adapters/cli/tui/app.d.ts +58 -0
  43. package/dist/adapters/cli/tui/app.js +314 -0
  44. package/dist/adapters/cli/tui/components/assistant-message.d.ts +5 -0
  45. package/dist/adapters/cli/tui/components/assistant-message.js +9 -0
  46. package/dist/adapters/cli/tui/components/autocomplete.d.ts +19 -0
  47. package/dist/adapters/cli/tui/components/autocomplete.js +75 -0
  48. package/dist/adapters/cli/tui/components/command-palette.d.ts +15 -0
  49. package/dist/adapters/cli/tui/components/command-palette.js +50 -0
  50. package/dist/adapters/cli/tui/components/diff-viewer.d.ts +5 -0
  51. package/dist/adapters/cli/tui/components/diff-viewer.js +109 -0
  52. package/dist/adapters/cli/tui/components/error-message.d.ts +5 -0
  53. package/dist/adapters/cli/tui/components/error-message.js +8 -0
  54. package/dist/adapters/cli/tui/components/footer.d.ts +20 -0
  55. package/dist/adapters/cli/tui/components/footer.js +19 -0
  56. package/dist/adapters/cli/tui/components/goal-status.d.ts +12 -0
  57. package/dist/adapters/cli/tui/components/goal-status.js +22 -0
  58. package/dist/adapters/cli/tui/components/info-message.d.ts +5 -0
  59. package/dist/adapters/cli/tui/components/info-message.js +8 -0
  60. package/dist/adapters/cli/tui/components/logo-banner.d.ts +7 -0
  61. package/dist/adapters/cli/tui/components/logo-banner.js +33 -0
  62. package/dist/adapters/cli/tui/components/markdown.d.ts +9 -0
  63. package/dist/adapters/cli/tui/components/markdown.js +92 -0
  64. package/dist/adapters/cli/tui/components/message-area.d.ts +19 -0
  65. package/dist/adapters/cli/tui/components/message-area.js +55 -0
  66. package/dist/adapters/cli/tui/components/permission-prompt.d.ts +13 -0
  67. package/dist/adapters/cli/tui/components/permission-prompt.js +32 -0
  68. package/dist/adapters/cli/tui/components/prompt-area.d.ts +22 -0
  69. package/dist/adapters/cli/tui/components/prompt-area.js +68 -0
  70. package/dist/adapters/cli/tui/components/text-input.d.ts +27 -0
  71. package/dist/adapters/cli/tui/components/text-input.js +142 -0
  72. package/dist/adapters/cli/tui/components/tool-call-block.d.ts +11 -0
  73. package/dist/adapters/cli/tui/components/tool-call-block.js +68 -0
  74. package/dist/adapters/cli/tui/components/user-message.d.ts +5 -0
  75. package/dist/adapters/cli/tui/components/user-message.js +8 -0
  76. package/dist/adapters/cli/tui/diff/file-write-meta.d.ts +11 -0
  77. package/dist/adapters/cli/tui/diff/file-write-meta.js +11 -0
  78. package/dist/adapters/cli/tui/diff/line-diff.d.ts +17 -0
  79. package/dist/adapters/cli/tui/diff/line-diff.js +44 -0
  80. package/dist/adapters/cli/tui/feed-serializer.d.ts +29 -0
  81. package/dist/adapters/cli/tui/feed-serializer.js +70 -0
  82. package/dist/adapters/cli/tui/file-index.d.ts +8 -0
  83. package/dist/adapters/cli/tui/file-index.js +41 -0
  84. package/dist/adapters/cli/tui/hooks/use-agent.d.ts +54 -0
  85. package/dist/adapters/cli/tui/hooks/use-agent.js +177 -0
  86. package/dist/adapters/cli/tui/hooks/use-feed.d.ts +16 -0
  87. package/dist/adapters/cli/tui/hooks/use-feed.js +25 -0
  88. package/dist/adapters/cli/tui/hooks/use-file-watcher.d.ts +10 -0
  89. package/dist/adapters/cli/tui/hooks/use-file-watcher.js +43 -0
  90. package/dist/adapters/cli/tui/hooks/use-keybindings.d.ts +16 -0
  91. package/dist/adapters/cli/tui/hooks/use-keybindings.js +25 -0
  92. package/dist/adapters/cli/tui/hooks/use-theme.d.ts +8 -0
  93. package/dist/adapters/cli/tui/hooks/use-theme.js +12 -0
  94. package/dist/adapters/cli/tui/index.d.ts +19 -0
  95. package/dist/adapters/cli/tui/index.js +206 -0
  96. package/dist/adapters/cli/tui/ink-reset.d.ts +29 -0
  97. package/dist/adapters/cli/tui/ink-reset.js +57 -0
  98. package/dist/adapters/cli/tui/layout.d.ts +15 -0
  99. package/dist/adapters/cli/tui/layout.js +15 -0
  100. package/dist/adapters/cli/tui/logo/gradient.d.ts +11 -0
  101. package/dist/adapters/cli/tui/logo/gradient.js +31 -0
  102. package/dist/adapters/cli/tui/overlays/help-dialog.d.ts +4 -0
  103. package/dist/adapters/cli/tui/overlays/help-dialog.js +26 -0
  104. package/dist/adapters/cli/tui/overlays/model-selector.d.ts +14 -0
  105. package/dist/adapters/cli/tui/overlays/model-selector.js +43 -0
  106. package/dist/adapters/cli/tui/overlays/session-selector.d.ts +35 -0
  107. package/dist/adapters/cli/tui/overlays/session-selector.js +162 -0
  108. package/dist/adapters/cli/tui/overlays/settings-overlay.d.ts +24 -0
  109. package/dist/adapters/cli/tui/overlays/settings-overlay.js +126 -0
  110. package/dist/adapters/cli/tui/session-export.d.ts +21 -0
  111. package/dist/adapters/cli/tui/session-export.js +63 -0
  112. package/dist/adapters/cli/tui/theme.d.ts +23 -0
  113. package/dist/adapters/cli/tui/theme.js +22 -0
  114. package/dist/adapters/cli/tui/types.d.ts +52 -0
  115. package/dist/adapters/cli/tui/types.js +12 -0
  116. package/dist/adapters/sdk/agent.d.ts +20 -0
  117. package/dist/adapters/sdk/agent.js +356 -0
  118. package/dist/adapters/sdk/http.d.ts +43 -0
  119. package/dist/adapters/sdk/http.js +61 -0
  120. package/dist/adapters/sdk/index.d.ts +58 -0
  121. package/dist/adapters/sdk/index.js +209 -0
  122. package/dist/adapters/sdk/settings.d.ts +18 -0
  123. package/dist/adapters/sdk/settings.js +57 -0
  124. package/dist/adapters/sdk/tools.d.ts +7 -0
  125. package/dist/adapters/sdk/tools.js +13 -0
  126. package/dist/adapters/server/auth.d.ts +53 -0
  127. package/dist/adapters/server/auth.js +168 -0
  128. package/dist/adapters/server/index.d.ts +40 -0
  129. package/dist/adapters/server/index.js +255 -0
  130. package/dist/adapters/server/rest-gateway.d.ts +13 -0
  131. package/dist/adapters/server/rest-gateway.js +218 -0
  132. package/dist/adapters/server/rest.d.ts +37 -0
  133. package/dist/adapters/server/rest.js +341 -0
  134. package/dist/adapters/server/server-core.d.ts +55 -0
  135. package/dist/adapters/server/server-core.js +121 -0
  136. package/dist/adapters/server/session-store.d.ts +81 -0
  137. package/dist/adapters/server/session-store.js +272 -0
  138. package/dist/adapters/server/settings-handlers.d.ts +24 -0
  139. package/dist/adapters/server/settings-handlers.js +360 -0
  140. package/dist/adapters/server/standalone.d.ts +19 -0
  141. package/dist/adapters/server/standalone.js +113 -0
  142. package/dist/adapters/server/websocket.d.ts +26 -0
  143. package/dist/adapters/server/websocket.js +68 -0
  144. package/dist/adapters/server/ws-handlers.d.ts +32 -0
  145. package/dist/adapters/server/ws-handlers.js +523 -0
  146. package/dist/adapters/server/ws-types.d.ts +304 -0
  147. package/dist/adapters/server/ws-types.js +7 -0
  148. package/dist/core/agent-loop.d.ts +68 -0
  149. package/dist/core/agent-loop.js +423 -0
  150. package/dist/core/config.d.ts +115 -0
  151. package/dist/core/config.js +189 -0
  152. package/dist/core/errors.d.ts +58 -0
  153. package/dist/core/errors.js +88 -0
  154. package/dist/core/hooks.d.ts +35 -0
  155. package/dist/core/hooks.js +49 -0
  156. package/dist/core/index.d.ts +23 -0
  157. package/dist/core/index.js +29 -0
  158. package/dist/core/message-convert.d.ts +41 -0
  159. package/dist/core/message-convert.js +94 -0
  160. package/dist/core/middleware/auth.d.ts +24 -0
  161. package/dist/core/middleware/auth.js +28 -0
  162. package/dist/core/middleware/logging.d.ts +23 -0
  163. package/dist/core/middleware/logging.js +28 -0
  164. package/dist/core/middleware/rate-limit.d.ts +27 -0
  165. package/dist/core/middleware/rate-limit.js +38 -0
  166. package/dist/core/middleware/semantic-tools.d.ts +10 -0
  167. package/dist/core/middleware/semantic-tools.js +43 -0
  168. package/dist/core/middleware.d.ts +48 -0
  169. package/dist/core/middleware.js +38 -0
  170. package/dist/core/permission.d.ts +25 -0
  171. package/dist/core/permission.js +50 -0
  172. package/dist/core/provider-config.d.ts +129 -0
  173. package/dist/core/provider-config.js +273 -0
  174. package/dist/core/provider-env.d.ts +39 -0
  175. package/dist/core/provider-env.js +142 -0
  176. package/dist/core/provider-resolver.d.ts +12 -0
  177. package/dist/core/provider-resolver.js +12 -0
  178. package/dist/core/session-store.d.ts +75 -0
  179. package/dist/core/session-store.js +245 -0
  180. package/dist/core/settings-manager.d.ts +57 -0
  181. package/dist/core/settings-manager.js +359 -0
  182. package/dist/core/settings-schema.d.ts +38 -0
  183. package/dist/core/settings-schema.js +171 -0
  184. package/dist/core/skill-catalog.d.ts +6 -0
  185. package/dist/core/skill-catalog.js +17 -0
  186. package/dist/core/skill-invoker.d.ts +127 -0
  187. package/dist/core/skill-invoker.js +182 -0
  188. package/dist/core/stream-accumulator.d.ts +21 -0
  189. package/dist/core/stream-accumulator.js +51 -0
  190. package/dist/core/stream-manager.d.ts +58 -0
  191. package/dist/core/stream-manager.js +212 -0
  192. package/dist/core/tool-executor.d.ts +84 -0
  193. package/dist/core/tool-executor.js +256 -0
  194. package/dist/core/types.d.ts +259 -0
  195. package/dist/core/types.js +11 -0
  196. package/dist/gateway/gateway.d.ts +52 -0
  197. package/dist/gateway/gateway.js +537 -0
  198. package/dist/gateway/index.d.ts +21 -0
  199. package/dist/gateway/index.js +31 -0
  200. package/dist/gateway/openapi-importer.d.ts +15 -0
  201. package/dist/gateway/openapi-importer.js +66 -0
  202. package/dist/gateway/semantic-scorer.d.ts +7 -0
  203. package/dist/gateway/semantic-scorer.js +24 -0
  204. package/dist/gateway/settings-adapter.d.ts +49 -0
  205. package/dist/gateway/settings-adapter.js +137 -0
  206. package/dist/gateway/tool-factory.d.ts +9 -0
  207. package/dist/gateway/tool-factory.js +414 -0
  208. package/dist/gateway/types.d.ts +68 -0
  209. package/dist/gateway/types.js +7 -0
  210. package/dist/models-catalog.js +46 -0
  211. package/dist/providers/anthropic.d.ts +22 -0
  212. package/dist/providers/anthropic.js +148 -0
  213. package/dist/providers/factory.d.ts +10 -0
  214. package/dist/providers/factory.js +25 -0
  215. package/dist/providers/openai.d.ts +15 -0
  216. package/dist/providers/openai.js +71 -0
  217. package/dist/providers/types.d.ts +48 -0
  218. package/dist/providers/types.js +1 -0
  219. package/dist/skills/args.d.ts +37 -0
  220. package/dist/skills/args.js +99 -0
  221. package/dist/skills/index.d.ts +11 -0
  222. package/dist/skills/index.js +23 -0
  223. package/dist/skills/loader.d.ts +3 -0
  224. package/dist/skills/loader.js +59 -0
  225. package/dist/skills/parser.d.ts +7 -0
  226. package/dist/skills/parser.js +152 -0
  227. package/dist/skills/registry.d.ts +13 -0
  228. package/dist/skills/registry.js +74 -0
  229. package/dist/skills/resolver.d.ts +19 -0
  230. package/dist/skills/resolver.js +116 -0
  231. package/dist/skills/types.d.ts +74 -0
  232. package/dist/skills/types.js +50 -0
  233. package/dist/tools/browser.d.ts +2 -0
  234. package/dist/tools/browser.js +68 -0
  235. package/dist/tools/core.d.ts +20 -0
  236. package/dist/tools/core.js +244 -0
  237. package/dist/tools/email.d.ts +2 -0
  238. package/dist/tools/email.js +61 -0
  239. package/dist/tools/image.d.ts +2 -0
  240. package/dist/tools/image.js +257 -0
  241. package/dist/tools/index.d.ts +2 -0
  242. package/dist/tools/index.js +88 -0
  243. package/dist/tools/interface.d.ts +22 -0
  244. package/dist/tools/interface.js +1 -0
  245. package/dist/tools/notify.d.ts +2 -0
  246. package/dist/tools/notify.js +100 -0
  247. package/dist/tools/prompt-optimizer.d.ts +2 -0
  248. package/dist/tools/prompt-optimizer.js +65 -0
  249. package/dist/tools/screenshot.d.ts +2 -0
  250. package/dist/tools/screenshot.js +184 -0
  251. package/dist/tools/search.d.ts +2 -0
  252. package/dist/tools/search.js +78 -0
  253. package/dist/tools/todos.d.ts +10 -0
  254. package/dist/tools/todos.js +50 -0
  255. package/package.json +119 -0
  256. package/skills/docker-ops/SKILL.md +329 -0
  257. package/skills/k8s-deploy/SKILL.md +397 -0
  258. package/skills/log-analyzer/SKILL.md +331 -0
  259. package/skills/speckit-analyze/SKILL.md +260 -0
  260. package/skills/speckit-checklist/SKILL.md +374 -0
  261. package/skills/speckit-clarify/SKILL.md +286 -0
  262. package/skills/speckit-constitution/SKILL.md +157 -0
  263. package/skills/speckit-implement/SKILL.md +224 -0
  264. package/skills/speckit-plan/SKILL.md +171 -0
  265. package/skills/speckit-specify/SKILL.md +346 -0
  266. package/skills/speckit-tasks/SKILL.md +215 -0
  267. package/skills/speckit-taskstoissues/SKILL.md +107 -0
@@ -0,0 +1,52 @@
1
+ /**
2
+ * TUI feed types — the discriminated union of feed entries.
3
+ *
4
+ * `use-feed` holds an array of `FeedEntry`; each `kind` maps to a render
5
+ * component. Entries are immutable once complete (so Ink's `<Static>` can
6
+ * render history efficiently); only the currently-streaming entry mutates.
7
+ *
8
+ * The shapes derive from Core's `StepResult` (text / tool_call) plus the
9
+ * adapter-level concerns the readline REPL handles inline: user input,
10
+ * permission approval, and errors.
11
+ */
12
+ export interface UserMessageEntry {
13
+ id: string;
14
+ kind: 'user';
15
+ content: string;
16
+ }
17
+ export interface AssistantMessageEntry {
18
+ id: string;
19
+ kind: 'assistant';
20
+ content: string;
21
+ }
22
+ export interface ToolCallEntry {
23
+ id: string;
24
+ kind: 'tool';
25
+ name: string;
26
+ args: Record<string, unknown>;
27
+ status: 'running' | 'ok' | 'fail';
28
+ output?: string;
29
+ durationMs?: number;
30
+ /** Tool-specific structured payload (e.g. write_file's FileWriteMetadata)
31
+ * for richer rendering. Opaque here; parsed at the component boundary. */
32
+ metadata?: unknown;
33
+ }
34
+ export interface ErrorEntry {
35
+ id: string;
36
+ kind: 'error';
37
+ message: string;
38
+ }
39
+ export interface InfoEntry {
40
+ id: string;
41
+ kind: 'info';
42
+ content: string;
43
+ }
44
+ export interface LogoEntry {
45
+ id: string;
46
+ kind: 'logo';
47
+ }
48
+ export type FeedEntry = UserMessageEntry | AssistantMessageEntry | ToolCallEntry | ErrorEntry | InfoEntry | LogoEntry;
49
+ type DistributiveOmit<T, K extends keyof any> = T extends unknown ? Omit<T, K> : never;
50
+ /** A feed entry without its generated id — the input shape for `appendEntry`. */
51
+ export type FeedEntryInput = DistributiveOmit<FeedEntry, 'id'>;
52
+ export {};
@@ -0,0 +1,12 @@
1
+ /**
2
+ * TUI feed types — the discriminated union of feed entries.
3
+ *
4
+ * `use-feed` holds an array of `FeedEntry`; each `kind` maps to a render
5
+ * component. Entries are immutable once complete (so Ink's `<Static>` can
6
+ * render history efficiently); only the currently-streaming entry mutates.
7
+ *
8
+ * The shapes derive from Core's `StepResult` (text / tool_call) plus the
9
+ * adapter-level concerns the readline REPL handles inline: user input,
10
+ * permission approval, and errors.
11
+ */
12
+ export {};
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Zoe SDK — createAgent()
3
+ *
4
+ * A persistent agent with session memory, provider switching, and abort support.
5
+ * Wraps the LLMProvider directly (not the CLI-oriented Agent class) so results
6
+ * are structured rather than printed to the console.
7
+ */
8
+ import type { AgentCreateOptions, SdkAgent } from "../../core/types.js";
9
+ /**
10
+ * Create a persistent agent with session memory, provider switching,
11
+ * and abort support.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * const agent = await createAgent({ model: "gpt-4o" });
16
+ * const result = await agent.chat("Hello!");
17
+ * console.log(result.text);
18
+ * ```
19
+ */
20
+ export declare function createAgent(options?: AgentCreateOptions): Promise<SdkAgent>;
@@ -0,0 +1,356 @@
1
+ /**
2
+ * Zoe SDK — createAgent()
3
+ *
4
+ * A persistent agent with session memory, provider switching, and abort support.
5
+ * Wraps the LLMProvider directly (not the CLI-oriented Agent class) so results
6
+ * are structured rather than printed to the console.
7
+ */
8
+ import { getProvider } from "../../core/provider-resolver.js";
9
+ import { createHookExecutor } from "../../core/hooks.js";
10
+ import { StreamManager } from "../../core/stream-manager.js";
11
+ import { resolveTools, getAllToolDefinitions } from "./tools.js";
12
+ import { createPersistenceBackend, persistSession } from "../../core/session-store.js";
13
+ import { runAgentLoop } from "../../core/agent-loop.js";
14
+ import { generateId, now, toZoeError, } from "../../core/message-convert.js";
15
+ // ── Session persistence helpers ──────────────────────────────────────────
16
+ /**
17
+ * Adapt a legacy `SessionStore` (save/load takes messages) to the
18
+ * `PersistenceBackend` interface (save/load takes full SessionData).
19
+ * If the object already has the `PersistenceBackend` signature, it passes through.
20
+ */
21
+ function wrapAsPersistenceBackend(store) {
22
+ if ("__persistenceBackend" in store && store.__persistenceBackend === true) {
23
+ return store;
24
+ }
25
+ const s = store;
26
+ return {
27
+ __persistenceBackend: true,
28
+ save: async (id, data) => {
29
+ await s.save(id, data.messages);
30
+ },
31
+ load: async (id) => {
32
+ const messages = await s.load(id);
33
+ if (!messages)
34
+ return null;
35
+ return { id, messages, createdAt: Date.now(), updatedAt: Date.now() };
36
+ },
37
+ delete: s.delete.bind(s),
38
+ list: s.list.bind(s),
39
+ };
40
+ }
41
+ // ── createAgent ──────────────────────────────────────────────────────────
42
+ /**
43
+ * Create a persistent agent with session memory, provider switching,
44
+ * and abort support.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * const agent = await createAgent({ model: "gpt-4o" });
49
+ * const result = await agent.chat("Hello!");
50
+ * console.log(result.text);
51
+ * ```
52
+ */
53
+ export async function createAgent(options) {
54
+ const opts = options ?? {};
55
+ // Resolve provider
56
+ let { provider: llmProvider, model } = await getProvider(opts.provider, opts.model);
57
+ // System prompt
58
+ let systemPrompt = opts.systemPrompt ?? "You are a helpful assistant.";
59
+ // Tools
60
+ let toolDefs = opts.tools ? resolveTools(opts.tools) : getAllToolDefinitions();
61
+ // Hooks
62
+ const hookExecutor = createHookExecutor(opts.hooks);
63
+ // State
64
+ const messages = [];
65
+ const sessionId = generateId();
66
+ let activeAbortController = new AbortController();
67
+ // Concurrency guard — only one chat/chatStream at a time
68
+ let lock = Promise.resolve();
69
+ let releaseLock = null;
70
+ function acquire() {
71
+ const prev = lock;
72
+ lock = new Promise((r) => { releaseLock = r; });
73
+ return prev;
74
+ }
75
+ function release() {
76
+ releaseLock?.();
77
+ releaseLock = null;
78
+ }
79
+ // Cumulative usage
80
+ const cumulativeUsage = {
81
+ totalPromptTokens: 0,
82
+ totalCompletionTokens: 0,
83
+ totalCost: 0,
84
+ requestCount: 0,
85
+ };
86
+ // Session store
87
+ let backend = null;
88
+ if (opts.persist) {
89
+ if (typeof opts.persist === "string") {
90
+ // Legacy: string path → file backend
91
+ backend = createPersistenceBackend({ type: "file", path: opts.persist });
92
+ }
93
+ else if ("type" in opts.persist && typeof opts.persist.type === "string") {
94
+ // PersistenceConfig object
95
+ backend = createPersistenceBackend(opts.persist);
96
+ }
97
+ else if ("save" in opts.persist && "load" in opts.persist) {
98
+ // Already a PersistenceBackend or legacy SessionStore — use directly
99
+ backend = wrapAsPersistenceBackend(opts.persist);
100
+ }
101
+ // Try loading existing session
102
+ if (backend) {
103
+ const existing = await backend.load(sessionId);
104
+ if (existing) {
105
+ messages.push(...existing.messages);
106
+ }
107
+ }
108
+ }
109
+ // Add initial system prompt if no messages exist
110
+ if (messages.length === 0 && systemPrompt) {
111
+ messages.push({
112
+ id: generateId(),
113
+ role: "system",
114
+ content: systemPrompt,
115
+ timestamp: now(),
116
+ });
117
+ }
118
+ // ── Helper: persist messages ────────────────────────────────────────────
119
+ async function persistMessages() {
120
+ if (backend) {
121
+ await persistSession(backend, sessionId, messages);
122
+ }
123
+ }
124
+ // ── chat() ──────────────────────────────────────────────────────────────
125
+ async function chat(userMessage) {
126
+ await acquire();
127
+ try {
128
+ // Reset abort controller for this call
129
+ activeAbortController = new AbortController();
130
+ // Add user message
131
+ messages.push({
132
+ id: generateId(),
133
+ role: "user",
134
+ content: userMessage,
135
+ timestamp: now(),
136
+ });
137
+ const maxSteps = opts.maxSteps ?? 10;
138
+ const result = await runAgentLoop({
139
+ provider: llmProvider,
140
+ model: model,
141
+ messages,
142
+ toolDefs,
143
+ systemPrompt: systemPrompt,
144
+ maxSteps,
145
+ hooks: hookExecutor,
146
+ signal: activeAbortController.signal,
147
+ config: opts.config,
148
+ metadata: opts.metadata,
149
+ middleware: opts.middleware,
150
+ approveTool: opts.approveTool,
151
+ permissionLevel: opts.permissionLevel,
152
+ });
153
+ // Update cumulative usage from result
154
+ cumulativeUsage.totalPromptTokens += result.usage.promptTokens;
155
+ cumulativeUsage.totalCompletionTokens += result.usage.completionTokens;
156
+ cumulativeUsage.totalCost += result.usage.cost;
157
+ cumulativeUsage.requestCount += 1;
158
+ // Persist
159
+ await persistMessages();
160
+ // Get the final text
161
+ const lastAssistant = [...messages]
162
+ .reverse()
163
+ .find((m) => m.role === "assistant" && m.content);
164
+ const text = lastAssistant?.content ?? "";
165
+ return {
166
+ text,
167
+ toolCalls: result.toolCalls,
168
+ usage: result.usage,
169
+ };
170
+ }
171
+ finally {
172
+ release();
173
+ }
174
+ }
175
+ // ── chatStream() ────────────────────────────────────────────────────────
176
+ async function chatStream(message, streamOptions) {
177
+ await acquire();
178
+ try {
179
+ const streamAbort = new AbortController();
180
+ activeAbortController = streamAbort;
181
+ const mergedHooks = {
182
+ ...opts.hooks,
183
+ ...streamOptions,
184
+ };
185
+ const streamHookExecutor = createHookExecutor(mergedHooks);
186
+ // Add user message
187
+ messages.push({
188
+ id: generateId(),
189
+ role: "user",
190
+ content: message,
191
+ timestamp: now(),
192
+ });
193
+ const maxSteps = streamOptions?.maxSteps ?? opts.maxSteps ?? 10;
194
+ // Stream manager handles queues, async iterables, and SSE
195
+ const stream = new StreamManager();
196
+ // Run the loop in the background — lock released in finally when done
197
+ (async () => {
198
+ try {
199
+ const result = await runAgentLoop({
200
+ provider: llmProvider,
201
+ model: model,
202
+ messages,
203
+ toolDefs,
204
+ systemPrompt: systemPrompt,
205
+ maxSteps,
206
+ hooks: streamHookExecutor,
207
+ signal: streamAbort.signal,
208
+ config: opts.config,
209
+ metadata: opts.metadata,
210
+ middleware: opts.middleware,
211
+ approveTool: opts.approveTool,
212
+ permissionLevel: opts.permissionLevel,
213
+ stream: true,
214
+ onStep: (step) => {
215
+ if (streamOptions?.onStep)
216
+ streamOptions.onStep(step);
217
+ // Streaming emits text_delta; non-streaming emits one complete
218
+ // 'text'. Both flow to consumers as text deltas via enqueueText.
219
+ if ((step.type === "text" || step.type === "text_delta") && step.content) {
220
+ if (streamOptions?.onText)
221
+ streamOptions.onText(step.content);
222
+ stream.enqueueText(step.content);
223
+ }
224
+ if (step.type === "tool_call" && step.toolCall) {
225
+ if (streamOptions?.onToolCall) {
226
+ streamOptions.onToolCall({
227
+ name: step.toolCall.name,
228
+ args: step.toolCall.args,
229
+ callId: step.toolCall.id,
230
+ });
231
+ }
232
+ if (streamOptions?.onToolResult) {
233
+ streamOptions.onToolResult({
234
+ callId: step.toolCall.id,
235
+ output: step.toolCall.result,
236
+ success: true,
237
+ });
238
+ }
239
+ }
240
+ stream.enqueueStep(step);
241
+ },
242
+ });
243
+ // Update cumulative usage from result
244
+ cumulativeUsage.totalPromptTokens += result.usage.promptTokens;
245
+ cumulativeUsage.totalCompletionTokens += result.usage.completionTokens;
246
+ cumulativeUsage.totalCost += result.usage.cost;
247
+ cumulativeUsage.requestCount += 1;
248
+ // Derive final text from the message history (robust to streaming,
249
+ // where steps contain text_delta, not a complete 'text' step).
250
+ const lastAssistant = [...messages]
251
+ .reverse()
252
+ .find((m) => m.role === "assistant" && m.content);
253
+ const finalText = lastAssistant?.content ?? "";
254
+ stream.resolveText(finalText);
255
+ stream.resolveUsage(result.usage);
256
+ stream.resolveFinish(result.finishReason);
257
+ }
258
+ catch (err) {
259
+ const zoeErr = toZoeError(err, "PROVIDER_ERROR");
260
+ if (streamOptions?.onError)
261
+ streamOptions.onError(zoeErr);
262
+ stream.resolveText("");
263
+ stream.resolveUsage({ promptTokens: 0, completionTokens: 0, totalTokens: 0, cost: 0 });
264
+ stream.resolveFinish("error");
265
+ }
266
+ finally {
267
+ stream.complete();
268
+ await persistMessages();
269
+ release();
270
+ }
271
+ })();
272
+ return {
273
+ textStream: stream.textStream,
274
+ steps: stream.stepsStream,
275
+ fullText: stream.fullText,
276
+ usage: stream.usage,
277
+ finishReason: stream.finishReason,
278
+ abort: () => streamAbort.abort(),
279
+ toResponse: () => stream.toResponse(),
280
+ toSSEStream: () => stream.toSSEStream(),
281
+ };
282
+ }
283
+ catch (_err) {
284
+ release();
285
+ throw _err;
286
+ }
287
+ }
288
+ // ── switchProvider() ────────────────────────────────────────────────────
289
+ async function switchProvider(providerType, newModel) {
290
+ const result = await getProvider(providerType, newModel);
291
+ llmProvider = result.provider;
292
+ model = result.model;
293
+ }
294
+ // ── setSystemPrompt() ───────────────────────────────────────────────────
295
+ function setSystemPrompt(prompt) {
296
+ systemPrompt = prompt;
297
+ // Replace existing system message or add new one
298
+ const sysIdx = messages.findIndex((m) => m.role === "system");
299
+ if (sysIdx >= 0) {
300
+ messages[sysIdx] = {
301
+ id: messages[sysIdx].id,
302
+ role: "system",
303
+ content: prompt,
304
+ timestamp: now(),
305
+ };
306
+ }
307
+ else {
308
+ messages.unshift({
309
+ id: generateId(),
310
+ role: "system",
311
+ content: prompt,
312
+ timestamp: now(),
313
+ });
314
+ }
315
+ }
316
+ // ── setTools() ──────────────────────────────────────────────────────────
317
+ function setTools(tools) {
318
+ toolDefs = resolveTools(tools);
319
+ }
320
+ // ── abort() ─────────────────────────────────────────────────────────────
321
+ function abort() {
322
+ activeAbortController.abort();
323
+ }
324
+ // ── clear() ─────────────────────────────────────────────────────────────
325
+ function clear() {
326
+ messages.length = 0;
327
+ if (systemPrompt) {
328
+ messages.push({
329
+ id: generateId(),
330
+ role: "system",
331
+ content: systemPrompt,
332
+ timestamp: now(),
333
+ });
334
+ }
335
+ }
336
+ // ── getHistory() ────────────────────────────────────────────────────────
337
+ function getHistory() {
338
+ return [...messages];
339
+ }
340
+ // ── getUsage() ──────────────────────────────────────────────────────────
341
+ function getUsage() {
342
+ return { ...cumulativeUsage };
343
+ }
344
+ // ── Return the SdkAgent interface ───────────────────────────────────────
345
+ return {
346
+ chat,
347
+ chatStream,
348
+ switchProvider,
349
+ setSystemPrompt,
350
+ setTools,
351
+ abort,
352
+ clear,
353
+ getHistory,
354
+ getUsage,
355
+ };
356
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Zoe SDK — HTTP response helpers
3
+ *
4
+ * Converts StreamTextResult into HTTP-friendly SSE responses
5
+ * using the Web API Response and ReadableStream interfaces.
6
+ *
7
+ * Delegates to StreamManager for SSE generation.
8
+ */
9
+ import type { StreamTextResult } from "../../core/types.js";
10
+ export interface SSEOptions {
11
+ headers?: Record<string, string>;
12
+ }
13
+ /**
14
+ * Formats a single Server-Sent Events message.
15
+ *
16
+ * @param event The SSE event name
17
+ * @param data The payload (will be JSON-serialised)
18
+ * @returns A string in SSE wire format: `event: ...\ndata: ...\n\n`
19
+ */
20
+ export declare function createSSEMessage(event: string, data: unknown): string;
21
+ /**
22
+ * Converts a StreamTextResult into a SSE-formatted ReadableStream.
23
+ *
24
+ * Delegates to the StreamManager's toSSEStream() for actual event generation.
25
+ * The result's toSSEStream() emits events in the correct order:
26
+ * - `text` — incremental text deltas
27
+ * - `tool_call` — tool invocations
28
+ * - `tool_result` — tool execution results
29
+ * - `done` — final usage and finish reason
30
+ */
31
+ export declare function toSSEStream(result: StreamTextResult, _options?: SSEOptions): ReadableStream;
32
+ /**
33
+ * Converts a StreamTextResult into a Web API `Response` with an SSE body.
34
+ *
35
+ * Delegates to the StreamManager's toResponse() which sets standard SSE headers:
36
+ * - `Content-Type: text/event-stream`
37
+ * - `Cache-Control: no-cache`
38
+ * - `Connection: keep-alive`
39
+ *
40
+ * @param result The streaming result to convert
41
+ * @param options Optional extra headers to merge into the response
42
+ */
43
+ export declare function toResponse(result: StreamTextResult, options?: SSEOptions): Response;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Zoe SDK — HTTP response helpers
3
+ *
4
+ * Converts StreamTextResult into HTTP-friendly SSE responses
5
+ * using the Web API Response and ReadableStream interfaces.
6
+ *
7
+ * Delegates to StreamManager for SSE generation.
8
+ */
9
+ // ── SSE helpers ─────────────────────────────────────────────────────────
10
+ /**
11
+ * Formats a single Server-Sent Events message.
12
+ *
13
+ * @param event The SSE event name
14
+ * @param data The payload (will be JSON-serialised)
15
+ * @returns A string in SSE wire format: `event: ...\ndata: ...\n\n`
16
+ */
17
+ export function createSSEMessage(event, data) {
18
+ return `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
19
+ }
20
+ // ── toSSEStream ─────────────────────────────────────────────────────────
21
+ /**
22
+ * Converts a StreamTextResult into a SSE-formatted ReadableStream.
23
+ *
24
+ * Delegates to the StreamManager's toSSEStream() for actual event generation.
25
+ * The result's toSSEStream() emits events in the correct order:
26
+ * - `text` — incremental text deltas
27
+ * - `tool_call` — tool invocations
28
+ * - `tool_result` — tool execution results
29
+ * - `done` — final usage and finish reason
30
+ */
31
+ export function toSSEStream(result, _options) {
32
+ return result.toSSEStream();
33
+ }
34
+ // ── toResponse ──────────────────────────────────────────────────────────
35
+ /**
36
+ * Converts a StreamTextResult into a Web API `Response` with an SSE body.
37
+ *
38
+ * Delegates to the StreamManager's toResponse() which sets standard SSE headers:
39
+ * - `Content-Type: text/event-stream`
40
+ * - `Cache-Control: no-cache`
41
+ * - `Connection: keep-alive`
42
+ *
43
+ * @param result The streaming result to convert
44
+ * @param options Optional extra headers to merge into the response
45
+ */
46
+ export function toResponse(result, options) {
47
+ if (options?.headers) {
48
+ // If custom headers are requested, create a new Response wrapping
49
+ // the StreamManager's SSE stream with merged headers.
50
+ const body = result.toSSEStream();
51
+ return new Response(body, {
52
+ headers: {
53
+ "Content-Type": "text/event-stream",
54
+ "Cache-Control": "no-cache",
55
+ Connection: "keep-alive",
56
+ ...options.headers,
57
+ },
58
+ });
59
+ }
60
+ return result.toResponse();
61
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Zoe SDK — Public entry point
3
+ *
4
+ * Exports `generateText`, `streamText`, `createAgent`, and all public types,
5
+ * tool factories, provider helpers, and skill utilities.
6
+ */
7
+ import type { GenerateTextOptions, GenerateTextResult, StreamTextOptions, StreamTextResult } from "../../core/types.js";
8
+ export { createAgent } from "./agent.js";
9
+ export { tool, CORE_TOOLS, COMM_TOOLS, ADVANCED_TOOLS, ALL_TOOLS } from "./tools.js";
10
+ export { settings, SettingsError } from "./settings.js";
11
+ export { configureProviders, loadProviderConfig, provider } from "../../core/provider-resolver.js";
12
+ export { createSkillProviderSwitcher } from "../../core/skill-invoker.js";
13
+ export type { SSEOptions } from "./http.js";
14
+ export { compose, type PipelineContext, type Middleware, loggingMiddleware, rateLimitMiddleware, authMiddleware, } from "../../core/index.js";
15
+ import type { GatewayConfig } from "../../gateway/types.js";
16
+ import type { GatewaySettingsAdapter } from "../../gateway/settings-adapter.js";
17
+ export declare const gateway: {
18
+ createGateway(config: GatewayConfig, settingsAdapter?: GatewaySettingsAdapter): Promise<import("../../gateway/gateway.js").MCPGateway | null>;
19
+ };
20
+ export type { ProviderType, MultiProviderConfig, Message, ToolCall, StepResult, Usage, CumulativeUsage, UserToolDefinition, ToolContext, ToolResult, Hooks, GenerateTextOptions, GenerateTextResult, StreamTextOptions, StreamTextResult, AgentCreateOptions, SdkAgent, AgentResponse, SessionStore, SessionData, PersistenceBackend, PersistenceConfig, SkillMetadata, ZoeError, PermissionLevel, ToolRiskCategory, } from "../../core/types.js";
21
+ export { createPersistenceBackend, registerBackend, createSessionStore, createMemoryStore, } from "../../core/session-store.js";
22
+ export type { SkillProviderSwitcher, ProviderSwitcherConfig, } from "../../core/skill-invoker.js";
23
+ /**
24
+ * Run a one-shot agent loop and return the structured result.
25
+ *
26
+ * Creates fresh state for each call (stateless). Handles tool calls
27
+ * automatically until the provider returns no more tool calls or
28
+ * `maxSteps` is reached.
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * const result = await generateText("What is the weather in SF?", {
33
+ * tools: ["web_search"],
34
+ * maxSteps: 5,
35
+ * });
36
+ * console.log(result.text);
37
+ * ```
38
+ */
39
+ export declare function generateText(prompt: string, options?: GenerateTextOptions): Promise<GenerateTextResult>;
40
+ /**
41
+ * Run a one-shot agent loop with streaming callbacks.
42
+ *
43
+ * Returns AsyncIterables for text and steps, plus `toResponse()` and
44
+ * `toSSEStream()` for HTTP server integration.
45
+ *
46
+ * Note: The current provider.chat() API returns full responses (not deltas),
47
+ * so onText receives the complete text at once. Future versions will integrate
48
+ * with provider-level streaming.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * const stream = await streamText("Explain quantum computing", {
53
+ * onText: (delta) => process.stdout.write(delta),
54
+ * });
55
+ * const finalText = await stream.fullText;
56
+ * ```
57
+ */
58
+ export declare function streamText(prompt: string, options?: StreamTextOptions): Promise<StreamTextResult>;