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,68 @@
1
+ /**
2
+ * Zoe Gateway — Type definitions
3
+ *
4
+ * Types for MCP targets, REST targets, audit records, and gateway config.
5
+ * Reuses Zoe's existing ToolModule and ToolDefinition from src/tools/interface.ts.
6
+ */
7
+ export type AuthType = 'none' | 'header' | 'bearer' | 'query' | 'basic';
8
+ export type McpTransportType = 'stdio' | 'sse' | 'http';
9
+ export interface RestTarget {
10
+ kind: 'rest';
11
+ baseUrl: string;
12
+ description: string;
13
+ auth: {
14
+ type: AuthType;
15
+ name?: string;
16
+ credentialRef?: string;
17
+ };
18
+ defaultHeaders: Record<string, string>;
19
+ operations: Array<{
20
+ opId: string;
21
+ method: string;
22
+ path: string;
23
+ summary: string;
24
+ }>;
25
+ tags: string[];
26
+ enabled: boolean;
27
+ }
28
+ export interface McpTarget {
29
+ kind: 'mcp';
30
+ transport: McpTransportType;
31
+ command?: string;
32
+ args?: string[];
33
+ env?: Record<string, string>;
34
+ url?: string;
35
+ auth?: {
36
+ type: AuthType;
37
+ name?: string;
38
+ credentialRef?: string;
39
+ };
40
+ description: string;
41
+ tags: string[];
42
+ enabled: boolean;
43
+ capabilities?: {
44
+ tools?: any[];
45
+ resources?: any[];
46
+ prompts?: any[];
47
+ };
48
+ }
49
+ export type Target = RestTarget | McpTarget;
50
+ export interface AuditRecord {
51
+ timestamp: number;
52
+ agent: string;
53
+ target: string;
54
+ operation: string;
55
+ status: string;
56
+ durationMs: number;
57
+ success: boolean;
58
+ }
59
+ export interface GatewayHooks {
60
+ onAudit?: (record: AuditRecord) => void | Promise<void>;
61
+ onSamplingRequest?: (params: any) => Promise<any>;
62
+ }
63
+ export interface GatewayConfig {
64
+ enabled: boolean;
65
+ semanticTopK: number;
66
+ defaultRateLimitPerMin: number;
67
+ maxAuditLogsInMemory: number;
68
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Zoe Gateway — Type definitions
3
+ *
4
+ * Types for MCP targets, REST targets, audit records, and gateway config.
5
+ * Reuses Zoe's existing ToolModule and ToolDefinition from src/tools/interface.ts.
6
+ */
7
+ export {};
@@ -0,0 +1,46 @@
1
+ const M = (id, name, contextWindow, input, output) => ({
2
+ id, name, contextWindow, pricing: { input, output },
3
+ });
4
+ export const MODEL_CATALOG = {
5
+ 'openai-compatible': [], // No curated list — user provides their own model name
6
+ openai: [
7
+ M('gpt-5.4', 'GPT-5.4', 256000, 2.5, 10),
8
+ M('gpt-5.4-pro', 'GPT-5.4 Pro', 256000, 5, 20),
9
+ M('gpt-5.4-mini', 'GPT-5.4 Mini', 128000, 0.15, 0.6),
10
+ M('gpt-5.4-nano', 'GPT-5.4 Nano', 128000, 0.05, 0.2),
11
+ M('gpt-5.3-instant', 'GPT-5.3 Instant', 128000, 0.5, 2),
12
+ M('gpt-5.3-codex', 'GPT-5.3 Codex', 256000, 2, 8),
13
+ M('o3', 'o3', 200000, 5, 15),
14
+ M('o3-mini', 'o3 Mini', 200000, 1, 4),
15
+ ],
16
+ anthropic: [
17
+ M('claude-sonnet-4-6-20260320', 'Claude Sonnet 4.6', 200000, 3, 15),
18
+ M('claude-opus-4-6-20260320', 'Claude Opus 4.6', 200000, 15, 75),
19
+ M('claude-haiku-4-5-20251001', 'Claude Haiku 4.5', 200000, 0.8, 4),
20
+ ],
21
+ glm: [
22
+ M('haiku', 'GLM-4.5 Air', 128000, 0.5, 1.5),
23
+ M('sonnet', 'GLM-4.7', 128000, 1, 3),
24
+ M('opus', 'GLM-5.1', 128000, 2, 6),
25
+ ],
26
+ };
27
+ export const CUSTOM_MODEL_VALUE = '__custom__';
28
+ /**
29
+ * Default model ID for each provider.
30
+ * Single source of truth — all other files import from here.
31
+ */
32
+ export const DEFAULT_MODELS = {
33
+ openai: 'gpt-5.4',
34
+ anthropic: 'claude-sonnet-4-6-20260320',
35
+ glm: 'opus',
36
+ 'openai-compatible': 'gpt-5.4',
37
+ };
38
+ /** Look up a model's metadata (context window + pricing) by id, across providers. */
39
+ export function getModelMeta(id) {
40
+ for (const list of Object.values(MODEL_CATALOG)) {
41
+ const found = list.find((m) => m.id === id);
42
+ if (found)
43
+ return found;
44
+ }
45
+ return undefined;
46
+ }
@@ -0,0 +1,22 @@
1
+ import { ProviderMessage, ProviderResponse, LLMProvider, ChatOptions, StreamDelta } from './types.js';
2
+ import type { ToolDefinition } from '../tools/interface.js';
3
+ export declare class AnthropicProvider implements LLMProvider {
4
+ private client;
5
+ private model;
6
+ constructor(apiKey: string, model: string, options?: {
7
+ baseURL?: string;
8
+ timeout?: number;
9
+ });
10
+ /**
11
+ * Translate Zoe messages + tools into Anthropic's request shape. Shared by
12
+ * `chat()` and `chatStream()` so the (non-trivial) translation lives once.
13
+ */
14
+ private buildRequest;
15
+ chat(messages: ProviderMessage[], tools: ToolDefinition[], options?: ChatOptions): Promise<ProviderResponse>;
16
+ /**
17
+ * Stream the response via Anthropic's message stream. Text blocks yield
18
+ * `text_delta`; tool_use blocks yield `tool_call_begin` (on block start) then
19
+ * `tool_call_delta` for each `input_json_delta` fragment, keyed by block index.
20
+ */
21
+ chatStream(messages: ProviderMessage[], tools: ToolDefinition[], options?: ChatOptions): AsyncIterable<StreamDelta>;
22
+ }
@@ -0,0 +1,148 @@
1
+ import Anthropic from '@anthropic-ai/sdk';
2
+ export class AnthropicProvider {
3
+ client;
4
+ model;
5
+ constructor(apiKey, model, options) {
6
+ this.client = new Anthropic({
7
+ apiKey,
8
+ baseURL: options?.baseURL,
9
+ timeout: options?.timeout,
10
+ });
11
+ this.model = model;
12
+ }
13
+ /**
14
+ * Translate Zoe messages + tools into Anthropic's request shape. Shared by
15
+ * `chat()` and `chatStream()` so the (non-trivial) translation lives once.
16
+ */
17
+ buildRequest(messages, tools) {
18
+ const systemParts = [];
19
+ const nonSystem = [];
20
+ for (const msg of messages) {
21
+ if (msg.role === 'system') {
22
+ if (msg.content)
23
+ systemParts.push(msg.content);
24
+ }
25
+ else {
26
+ nonSystem.push(msg);
27
+ }
28
+ }
29
+ const anthropicMessages = [];
30
+ for (const msg of nonSystem) {
31
+ if (msg.role === 'assistant' && msg.tool_calls?.length) {
32
+ const content = [];
33
+ if (msg.content)
34
+ content.push({ type: 'text', text: msg.content });
35
+ for (const tc of msg.tool_calls) {
36
+ content.push({
37
+ type: 'tool_use',
38
+ id: tc.id,
39
+ name: tc.name,
40
+ input: JSON.parse(tc.arguments),
41
+ });
42
+ }
43
+ anthropicMessages.push({ role: 'assistant', content });
44
+ }
45
+ else if (msg.role === 'tool') {
46
+ anthropicMessages.push({
47
+ role: 'user',
48
+ content: [{
49
+ type: 'tool_result',
50
+ tool_use_id: msg.tool_call_id,
51
+ content: msg.content ?? '',
52
+ }],
53
+ });
54
+ }
55
+ else {
56
+ anthropicMessages.push({
57
+ role: msg.role,
58
+ content: msg.content ?? '',
59
+ });
60
+ }
61
+ }
62
+ const anthropicTools = tools.map((t) => ({
63
+ name: t.function.name,
64
+ description: t.function.description,
65
+ input_schema: t.function.parameters,
66
+ }));
67
+ return {
68
+ system: systemParts.length ? systemParts.join('\n') : undefined,
69
+ anthropicMessages,
70
+ anthropicTools,
71
+ };
72
+ }
73
+ async chat(messages, tools, options) {
74
+ const { system, anthropicMessages, anthropicTools } = this.buildRequest(messages, tools);
75
+ const response = await this.client.messages.create({
76
+ model: this.model,
77
+ max_tokens: 16384,
78
+ system,
79
+ messages: anthropicMessages,
80
+ tools: anthropicTools,
81
+ }, { signal: options?.signal });
82
+ // Translate response
83
+ let content;
84
+ const toolCalls = [];
85
+ for (const block of response.content) {
86
+ if (block.type === 'text') {
87
+ content = content ? content + block.text : block.text;
88
+ }
89
+ else if (block.type === 'tool_use') {
90
+ toolCalls.push({
91
+ id: block.id,
92
+ name: block.name,
93
+ arguments: JSON.stringify(block.input),
94
+ });
95
+ }
96
+ }
97
+ return {
98
+ content: content || undefined,
99
+ tool_calls: toolCalls.length ? toolCalls : undefined,
100
+ };
101
+ }
102
+ /**
103
+ * Stream the response via Anthropic's message stream. Text blocks yield
104
+ * `text_delta`; tool_use blocks yield `tool_call_begin` (on block start) then
105
+ * `tool_call_delta` for each `input_json_delta` fragment, keyed by block index.
106
+ */
107
+ async *chatStream(messages, tools, options) {
108
+ const { system, anthropicMessages, anthropicTools } = this.buildRequest(messages, tools);
109
+ const stream = this.client.messages.stream({
110
+ model: this.model,
111
+ max_tokens: 16384,
112
+ system,
113
+ messages: anthropicMessages,
114
+ tools: anthropicTools,
115
+ }, { signal: options?.signal });
116
+ for await (const event of stream) {
117
+ if (event.type === 'content_block_start' && event.content_block.type === 'tool_use') {
118
+ yield {
119
+ type: 'tool_call_begin',
120
+ index: event.index,
121
+ id: event.content_block.id,
122
+ name: event.content_block.name,
123
+ };
124
+ }
125
+ else if (event.type === 'content_block_delta') {
126
+ if (event.delta.type === 'text_delta') {
127
+ yield { type: 'text_delta', content: event.delta.text };
128
+ }
129
+ else if (event.delta.type === 'input_json_delta') {
130
+ yield { type: 'tool_call_delta', index: event.index, argumentsDelta: event.delta.partial_json };
131
+ }
132
+ }
133
+ else if (event.type === 'message_delta' && event.usage) {
134
+ const inputTokens = event.usage.input_tokens ?? 0;
135
+ const outputTokens = event.usage.output_tokens ?? 0;
136
+ yield {
137
+ type: 'finish',
138
+ usage: {
139
+ promptTokens: inputTokens,
140
+ completionTokens: outputTokens,
141
+ totalTokens: inputTokens + outputTokens,
142
+ cost: 0,
143
+ },
144
+ };
145
+ }
146
+ }
147
+ }
148
+ }
@@ -0,0 +1,10 @@
1
+ import { ProviderType, LLMProvider } from './types.js';
2
+ export interface ProviderConfig {
3
+ type: ProviderType;
4
+ apiKey: string;
5
+ model: string;
6
+ baseUrl?: string;
7
+ timeout?: number;
8
+ }
9
+ export declare const GLM_MODEL_MAP: Record<string, string>;
10
+ export declare function createProvider(config: ProviderConfig): Promise<LLMProvider>;
@@ -0,0 +1,25 @@
1
+ export const GLM_MODEL_MAP = {
2
+ haiku: 'glm-4.5-air',
3
+ sonnet: 'glm-4.7',
4
+ opus: 'glm-5.1',
5
+ };
6
+ export async function createProvider(config) {
7
+ switch (config.type) {
8
+ case 'openai': {
9
+ const { OpenAIProvider } = await import('./openai.js');
10
+ return new OpenAIProvider(config.apiKey, config.model, 'https://api.openai.com/v1');
11
+ }
12
+ case 'openai-compatible': {
13
+ const { OpenAIProvider } = await import('./openai.js');
14
+ return new OpenAIProvider(config.apiKey, config.model, config.baseUrl);
15
+ }
16
+ case 'anthropic': {
17
+ const { AnthropicProvider } = await import('./anthropic.js');
18
+ return new AnthropicProvider(config.apiKey, config.model);
19
+ }
20
+ case 'glm': {
21
+ const { AnthropicProvider } = await import('./anthropic.js');
22
+ return new AnthropicProvider(config.apiKey, GLM_MODEL_MAP[config.model] || config.model, { baseURL: 'https://api.z.ai/api/anthropic', timeout: 3000000 });
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,15 @@
1
+ import { ProviderMessage, ProviderResponse, LLMProvider, ChatOptions, StreamDelta } from './types.js';
2
+ import type { ToolDefinition } from '../tools/interface.js';
3
+ export declare class OpenAIProvider implements LLMProvider {
4
+ private client;
5
+ private model;
6
+ constructor(apiKey: string, model: string, baseURL?: string);
7
+ chat(messages: ProviderMessage[], tools: ToolDefinition[], options?: ChatOptions): Promise<ProviderResponse>;
8
+ /**
9
+ * Stream the response using the OpenAI SDK's native streaming. Maps chunks to
10
+ * `StreamDelta`s: text deltas, tool-call begin (id+name on the first chunk)
11
+ * and argument fragments (subsequent chunks, keyed by `index`), and a final
12
+ * `finish` with usage (when `stream_options.include_usage` is set).
13
+ */
14
+ chatStream(messages: ProviderMessage[], tools: ToolDefinition[], options?: ChatOptions): AsyncIterable<StreamDelta>;
15
+ }
@@ -0,0 +1,71 @@
1
+ import { OpenAI } from 'openai';
2
+ export class OpenAIProvider {
3
+ client;
4
+ model;
5
+ constructor(apiKey, model, baseURL) {
6
+ this.client = new OpenAI({ apiKey, baseURL });
7
+ this.model = model;
8
+ }
9
+ async chat(messages, tools, options) {
10
+ const response = await this.client.chat.completions.create({
11
+ model: this.model,
12
+ messages: messages,
13
+ tools: tools,
14
+ }, { signal: options?.signal });
15
+ const message = response.choices[0]?.message;
16
+ if (!message)
17
+ return {};
18
+ return {
19
+ content: message.content ?? undefined,
20
+ tool_calls: message.tool_calls
21
+ ?.filter((tc) => tc.type === 'function')
22
+ .map((tc) => ({
23
+ id: tc.id,
24
+ name: tc.function.name,
25
+ arguments: tc.function.arguments,
26
+ })),
27
+ };
28
+ }
29
+ /**
30
+ * Stream the response using the OpenAI SDK's native streaming. Maps chunks to
31
+ * `StreamDelta`s: text deltas, tool-call begin (id+name on the first chunk)
32
+ * and argument fragments (subsequent chunks, keyed by `index`), and a final
33
+ * `finish` with usage (when `stream_options.include_usage` is set).
34
+ */
35
+ async *chatStream(messages, tools, options) {
36
+ const stream = await this.client.chat.completions.create({
37
+ model: this.model,
38
+ messages: messages,
39
+ tools: tools,
40
+ stream: true,
41
+ stream_options: { include_usage: true },
42
+ }, { signal: options?.signal });
43
+ for await (const chunk of stream) {
44
+ const delta = chunk.choices[0]?.delta;
45
+ if (delta?.content) {
46
+ yield { type: 'text_delta', content: delta.content };
47
+ }
48
+ if (delta?.tool_calls) {
49
+ for (const tc of delta.tool_calls) {
50
+ if (tc.function?.name) {
51
+ yield { type: 'tool_call_begin', index: tc.index, id: tc.id ?? '', name: tc.function.name };
52
+ }
53
+ if (tc.function?.arguments) {
54
+ yield { type: 'tool_call_delta', index: tc.index, argumentsDelta: tc.function.arguments };
55
+ }
56
+ }
57
+ }
58
+ if (chunk.usage) {
59
+ yield {
60
+ type: 'finish',
61
+ usage: {
62
+ promptTokens: chunk.usage.prompt_tokens,
63
+ completionTokens: chunk.usage.completion_tokens,
64
+ totalTokens: chunk.usage.total_tokens,
65
+ cost: 0,
66
+ },
67
+ };
68
+ }
69
+ }
70
+ }
71
+ }
@@ -0,0 +1,48 @@
1
+ export type { ProviderType } from "../core/types.js";
2
+ import type { ToolDefinition } from '../tools/interface.js';
3
+ import type { Usage } from '../core/types.js';
4
+ export interface ProviderMessage {
5
+ role: 'system' | 'user' | 'assistant' | 'tool';
6
+ content?: string;
7
+ tool_calls?: ProviderToolCall[];
8
+ tool_call_id?: string;
9
+ }
10
+ export interface ProviderToolCall {
11
+ id: string;
12
+ name: string;
13
+ arguments: string;
14
+ }
15
+ export interface ProviderResponse {
16
+ content?: string;
17
+ tool_calls?: ProviderToolCall[];
18
+ }
19
+ export interface ChatOptions {
20
+ signal?: AbortSignal;
21
+ }
22
+ /**
23
+ * A single chunk from a streaming model response. Providers split a response
24
+ * across many deltas — text arrives token-by-token, and a tool call's JSON
25
+ * arguments usually arrive fragmented. `runAgentLoop` reassembles these via
26
+ * `StreamingResponseAccumulator`.
27
+ */
28
+ export type StreamDelta = {
29
+ type: 'text_delta';
30
+ content: string;
31
+ } | {
32
+ type: 'tool_call_begin';
33
+ index: number;
34
+ id: string;
35
+ name: string;
36
+ } | {
37
+ type: 'tool_call_delta';
38
+ index: number;
39
+ argumentsDelta: string;
40
+ } | {
41
+ type: 'finish';
42
+ usage?: Usage;
43
+ };
44
+ export interface LLMProvider {
45
+ chat(messages: ProviderMessage[], tools: ToolDefinition[], options?: ChatOptions): Promise<ProviderResponse>;
46
+ /** Optional streaming variant. Absent → callers fall back to `chat()`. */
47
+ chatStream?(messages: ProviderMessage[], tools: ToolDefinition[], options?: ChatOptions): AsyncIterable<StreamDelta>;
48
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Dynamic argument parsing and template substitution for skills.
3
+ *
4
+ * Supports:
5
+ * - $1, $2, ... — positional arguments
6
+ * - $ALL — all arguments as a single string
7
+ * - $COUNT — number of arguments
8
+ * - $FIRST — first argument
9
+ * - $LAST — last argument
10
+ */
11
+ export interface ParsedArgs {
12
+ positional: string[];
13
+ raw: string;
14
+ }
15
+ /**
16
+ * Parse a user input string into a skill name and arguments.
17
+ * Handles quoted strings for multi-word arguments.
18
+ *
19
+ * @example
20
+ * parseInvocation('/docker-ops build myapp:1.2.0 --no-cache')
21
+ * // => { skillName: 'docker-ops', args: { positional: ['build', 'myapp:1.2.0', '--no-cache'], raw: 'build myapp:1.2.0 --no-cache' } }
22
+ */
23
+ export declare function parseInvocation(input: string): {
24
+ skillName: string;
25
+ args: ParsedArgs;
26
+ } | null;
27
+ /**
28
+ * Substitute template variables in a skill body with actual arguments.
29
+ *
30
+ * Supported variables:
31
+ * - $1, $2, ..., $N — positional arguments (1-indexed)
32
+ * - $ALL — all arguments joined as a string
33
+ * - $COUNT — number of arguments
34
+ * - $FIRST — first argument (same as $1)
35
+ * - $LAST — last argument
36
+ */
37
+ export declare function substituteArgs(body: string, args: ParsedArgs): string;
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Dynamic argument parsing and template substitution for skills.
3
+ *
4
+ * Supports:
5
+ * - $1, $2, ... — positional arguments
6
+ * - $ALL — all arguments as a single string
7
+ * - $COUNT — number of arguments
8
+ * - $FIRST — first argument
9
+ * - $LAST — last argument
10
+ */
11
+ /**
12
+ * Parse a user input string into a skill name and arguments.
13
+ * Handles quoted strings for multi-word arguments.
14
+ *
15
+ * @example
16
+ * parseInvocation('/docker-ops build myapp:1.2.0 --no-cache')
17
+ * // => { skillName: 'docker-ops', args: { positional: ['build', 'myapp:1.2.0', '--no-cache'], raw: 'build myapp:1.2.0 --no-cache' } }
18
+ */
19
+ export function parseInvocation(input) {
20
+ if (!input.startsWith('/') || input.length < 2)
21
+ return null;
22
+ const body = input.slice(1);
23
+ const firstSpace = body.search(/\s/);
24
+ if (firstSpace === -1) {
25
+ return { skillName: body, args: { positional: [], raw: '' } };
26
+ }
27
+ const skillName = body.slice(0, firstSpace);
28
+ const argsRaw = body.slice(firstSpace + 1).trim();
29
+ return {
30
+ skillName,
31
+ args: {
32
+ positional: splitArgs(argsRaw),
33
+ raw: argsRaw,
34
+ },
35
+ };
36
+ }
37
+ /**
38
+ * Split argument string respecting quoted strings.
39
+ */
40
+ function splitArgs(input) {
41
+ const args = [];
42
+ let current = '';
43
+ let inQuote = false;
44
+ let quoteChar = '';
45
+ for (let i = 0; i < input.length; i++) {
46
+ const ch = input[i];
47
+ if (inQuote) {
48
+ if (ch === quoteChar) {
49
+ inQuote = false;
50
+ }
51
+ else {
52
+ current += ch;
53
+ }
54
+ }
55
+ else if (ch === '"' || ch === "'") {
56
+ inQuote = true;
57
+ quoteChar = ch;
58
+ }
59
+ else if (ch === ' ') {
60
+ if (current) {
61
+ args.push(current);
62
+ current = '';
63
+ }
64
+ }
65
+ else {
66
+ current += ch;
67
+ }
68
+ }
69
+ if (current)
70
+ args.push(current);
71
+ return args;
72
+ }
73
+ /**
74
+ * Substitute template variables in a skill body with actual arguments.
75
+ *
76
+ * Supported variables:
77
+ * - $1, $2, ..., $N — positional arguments (1-indexed)
78
+ * - $ALL — all arguments joined as a string
79
+ * - $COUNT — number of arguments
80
+ * - $FIRST — first argument (same as $1)
81
+ * - $LAST — last argument
82
+ */
83
+ export function substituteArgs(body, args) {
84
+ let result = body;
85
+ // $ALL — all arguments as a single string
86
+ result = result.replace(/\$ALL\b/g, args.raw);
87
+ // $COUNT — number of arguments
88
+ result = result.replace(/\$COUNT\b/g, String(args.positional.length));
89
+ // $FIRST — first argument
90
+ result = result.replace(/\$FIRST\b/g, args.positional[0] || '');
91
+ // $LAST — last argument
92
+ result = result.replace(/\$LAST\b/g, args.positional[args.positional.length - 1] || '');
93
+ // $N — positional arguments (must process AFTER $ALL, $COUNT etc. to avoid conflicts)
94
+ // Replace from highest index down to avoid $10 being matched as $1
95
+ for (let i = args.positional.length; i >= 1; i--) {
96
+ result = result.replace(new RegExp(`\\$${i}\\b`, 'g'), args.positional[i - 1]);
97
+ }
98
+ return result;
99
+ }
@@ -0,0 +1,11 @@
1
+ export type { Skill, SkillFrontmatter, SkillMetadata, SkillRegistry, SkillModelConfig, TruncationResult } from './types.js';
2
+ export { parseSkillFile, parseFrontmatter } from './parser.js';
3
+ export { discoverSkills, getSkillPaths } from './loader.js';
4
+ export { DefaultSkillRegistry } from './registry.js';
5
+ export { parseInvocation, substituteArgs } from './args.js';
6
+ export type { ParsedArgs } from './args.js';
7
+ export { resolveReferences } from './resolver.js';
8
+ export { limitSkillBody, getSkillBodyLimits } from './types.js';
9
+ import { SkillRegistry } from './types.js';
10
+ export declare function initializeSkillRegistry(cwd: string): Promise<SkillRegistry>;
11
+ export declare function getSkillRegistry(): SkillRegistry | null;
@@ -0,0 +1,23 @@
1
+ export { parseSkillFile, parseFrontmatter } from './parser.js';
2
+ export { discoverSkills, getSkillPaths } from './loader.js';
3
+ export { DefaultSkillRegistry } from './registry.js';
4
+ export { parseInvocation, substituteArgs } from './args.js';
5
+ export { resolveReferences } from './resolver.js';
6
+ export { limitSkillBody, getSkillBodyLimits } from './types.js';
7
+ import { discoverSkills } from './loader.js';
8
+ import { DefaultSkillRegistry } from './registry.js';
9
+ let registry = null;
10
+ export async function initializeSkillRegistry(cwd) {
11
+ const skills = await discoverSkills(cwd);
12
+ registry = new DefaultSkillRegistry(skills);
13
+ if (process.env.ZOE_SKILLS_DEBUG) {
14
+ console.log(`[SKILLS] Loaded ${skills.length} skills`);
15
+ for (const s of skills) {
16
+ console.log(`[SKILLS] - ${s.name} from ${s.source}`);
17
+ }
18
+ }
19
+ return registry;
20
+ }
21
+ export function getSkillRegistry() {
22
+ return registry;
23
+ }
@@ -0,0 +1,3 @@
1
+ import { Skill } from './types.js';
2
+ export declare function getSkillPaths(cwd: string): string[];
3
+ export declare function discoverSkills(cwd: string): Promise<Skill[]>;