@zmzai/agent-framework 0.1.0 → 0.2.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 (145) hide show
  1. package/README.md +37 -0
  2. package/dist/adapters/openai-provider.d.ts +31 -2
  3. package/dist/adapters/openai-provider.d.ts.map +1 -1
  4. package/dist/adapters/openai-provider.js +118 -74
  5. package/dist/adapters/openai-provider.js.map +1 -1
  6. package/dist/adapters/subprocess-sandbox.d.ts +4 -5
  7. package/dist/adapters/subprocess-sandbox.d.ts.map +1 -1
  8. package/dist/adapters/subprocess-sandbox.js +106 -18
  9. package/dist/adapters/subprocess-sandbox.js.map +1 -1
  10. package/dist/adapters/terminal-backend.d.ts +5 -0
  11. package/dist/adapters/terminal-backend.d.ts.map +1 -0
  12. package/dist/adapters/terminal-backend.js +153 -0
  13. package/dist/adapters/terminal-backend.js.map +1 -0
  14. package/dist/cli.js +0 -0
  15. package/dist/core/agent/registry.d.ts +3 -0
  16. package/dist/core/agent/registry.d.ts.map +1 -1
  17. package/dist/core/agent/registry.js +9 -2
  18. package/dist/core/agent/registry.js.map +1 -1
  19. package/dist/core/events/manifest.d.ts +29 -4
  20. package/dist/core/events/manifest.d.ts.map +1 -1
  21. package/dist/core/events/manifest.js +21 -0
  22. package/dist/core/events/manifest.js.map +1 -1
  23. package/dist/core/mcp/client.d.ts +46 -0
  24. package/dist/core/mcp/client.d.ts.map +1 -0
  25. package/dist/core/mcp/client.js +286 -0
  26. package/dist/core/mcp/client.js.map +1 -0
  27. package/dist/core/mcp/http-client.d.ts +54 -0
  28. package/dist/core/mcp/http-client.d.ts.map +1 -0
  29. package/dist/core/mcp/http-client.js +385 -0
  30. package/dist/core/mcp/http-client.js.map +1 -0
  31. package/dist/core/mcp/servers.d.ts +30 -0
  32. package/dist/core/mcp/servers.d.ts.map +1 -0
  33. package/dist/core/mcp/servers.js +104 -0
  34. package/dist/core/mcp/servers.js.map +1 -0
  35. package/dist/core/permission/ruleset.d.ts +1 -1
  36. package/dist/core/permission/ruleset.d.ts.map +1 -1
  37. package/dist/core/permission/ruleset.js +4 -0
  38. package/dist/core/permission/ruleset.js.map +1 -1
  39. package/dist/core/permission/write-path.d.ts +27 -0
  40. package/dist/core/permission/write-path.d.ts.map +1 -0
  41. package/dist/core/permission/write-path.js +52 -0
  42. package/dist/core/permission/write-path.js.map +1 -0
  43. package/dist/core/repomap/cache.d.ts +24 -0
  44. package/dist/core/repomap/cache.d.ts.map +1 -0
  45. package/dist/core/repomap/cache.js +59 -0
  46. package/dist/core/repomap/cache.js.map +1 -0
  47. package/dist/core/repomap/graph.d.ts +14 -0
  48. package/dist/core/repomap/graph.d.ts.map +1 -0
  49. package/dist/core/repomap/graph.js +89 -0
  50. package/dist/core/repomap/graph.js.map +1 -0
  51. package/dist/core/repomap/render.d.ts +10 -0
  52. package/dist/core/repomap/render.d.ts.map +1 -0
  53. package/dist/core/repomap/render.js +33 -0
  54. package/dist/core/repomap/render.js.map +1 -0
  55. package/dist/core/repomap/repomap.d.ts +38 -0
  56. package/dist/core/repomap/repomap.d.ts.map +1 -0
  57. package/dist/core/repomap/repomap.js +116 -0
  58. package/dist/core/repomap/repomap.js.map +1 -0
  59. package/dist/core/repomap/tags.d.ts +26 -0
  60. package/dist/core/repomap/tags.d.ts.map +1 -0
  61. package/dist/core/repomap/tags.js +191 -0
  62. package/dist/core/repomap/tags.js.map +1 -0
  63. package/dist/core/runtime/compaction.d.ts +26 -14
  64. package/dist/core/runtime/compaction.d.ts.map +1 -1
  65. package/dist/core/runtime/compaction.js +46 -34
  66. package/dist/core/runtime/compaction.js.map +1 -1
  67. package/dist/core/runtime/lifecycle.d.ts +79 -0
  68. package/dist/core/runtime/lifecycle.d.ts.map +1 -0
  69. package/dist/core/runtime/lifecycle.js +71 -0
  70. package/dist/core/runtime/lifecycle.js.map +1 -0
  71. package/dist/core/runtime/pi-bridge.d.ts +4 -1
  72. package/dist/core/runtime/pi-bridge.d.ts.map +1 -1
  73. package/dist/core/runtime/pi-bridge.js +15 -1
  74. package/dist/core/runtime/pi-bridge.js.map +1 -1
  75. package/dist/core/runtime/run-transcript.d.ts +14 -0
  76. package/dist/core/runtime/run-transcript.d.ts.map +1 -0
  77. package/dist/core/runtime/run-transcript.js +35 -0
  78. package/dist/core/runtime/run-transcript.js.map +1 -0
  79. package/dist/core/runtime/runner.d.ts +38 -9
  80. package/dist/core/runtime/runner.d.ts.map +1 -1
  81. package/dist/core/runtime/runner.js +140 -20
  82. package/dist/core/runtime/runner.js.map +1 -1
  83. package/dist/core/session/sqlite-store.d.ts +18 -0
  84. package/dist/core/session/sqlite-store.d.ts.map +1 -0
  85. package/dist/core/session/sqlite-store.js +159 -0
  86. package/dist/core/session/sqlite-store.js.map +1 -0
  87. package/dist/core/session/types.d.ts +12 -0
  88. package/dist/core/session/types.d.ts.map +1 -1
  89. package/dist/core/tools/adapter.d.ts +11 -4
  90. package/dist/core/tools/adapter.d.ts.map +1 -1
  91. package/dist/core/tools/adapter.js +167 -8
  92. package/dist/core/tools/adapter.js.map +1 -1
  93. package/dist/core/tools/builtins.d.ts.map +1 -1
  94. package/dist/core/tools/builtins.js +5 -2
  95. package/dist/core/tools/builtins.js.map +1 -1
  96. package/dist/core/tools/context.d.ts +2 -0
  97. package/dist/core/tools/context.d.ts.map +1 -1
  98. package/dist/core/tools/def.d.ts +25 -0
  99. package/dist/core/tools/def.d.ts.map +1 -1
  100. package/dist/core/tools/def.js +3 -1
  101. package/dist/core/tools/def.js.map +1 -1
  102. package/dist/core/tools/git.d.ts +12 -0
  103. package/dist/core/tools/git.d.ts.map +1 -0
  104. package/dist/core/tools/git.js +189 -0
  105. package/dist/core/tools/git.js.map +1 -0
  106. package/dist/core/tools/patch.d.ts +45 -0
  107. package/dist/core/tools/patch.d.ts.map +1 -0
  108. package/dist/core/tools/patch.js +224 -0
  109. package/dist/core/tools/patch.js.map +1 -0
  110. package/dist/core/tools/qa-check.d.ts.map +1 -1
  111. package/dist/core/tools/qa-check.js +9 -2
  112. package/dist/core/tools/qa-check.js.map +1 -1
  113. package/dist/core/tools/repomap.d.ts +8 -0
  114. package/dist/core/tools/repomap.d.ts.map +1 -0
  115. package/dist/core/tools/repomap.js +34 -0
  116. package/dist/core/tools/repomap.js.map +1 -0
  117. package/dist/core/tools/terminal.d.ts +80 -0
  118. package/dist/core/tools/terminal.d.ts.map +1 -0
  119. package/dist/core/tools/terminal.js +265 -0
  120. package/dist/core/tools/terminal.js.map +1 -0
  121. package/dist/core/tools/trim.d.ts +31 -0
  122. package/dist/core/tools/trim.d.ts.map +1 -0
  123. package/dist/core/tools/trim.js +98 -0
  124. package/dist/core/tools/trim.js.map +1 -0
  125. package/dist/core/tools/webfetch.d.ts +10 -0
  126. package/dist/core/tools/webfetch.d.ts.map +1 -0
  127. package/dist/core/tools/webfetch.js +104 -0
  128. package/dist/core/tools/webfetch.js.map +1 -0
  129. package/dist/core/tools/websearch.d.ts +19 -0
  130. package/dist/core/tools/websearch.d.ts.map +1 -0
  131. package/dist/core/tools/websearch.js +132 -0
  132. package/dist/core/tools/websearch.js.map +1 -0
  133. package/dist/index.d.ts +30 -5
  134. package/dist/index.d.ts.map +1 -1
  135. package/dist/index.js +19 -1
  136. package/dist/index.js.map +1 -1
  137. package/dist/server/create-agent-runtime.d.ts +68 -0
  138. package/dist/server/create-agent-runtime.d.ts.map +1 -0
  139. package/dist/server/create-agent-runtime.js +67 -0
  140. package/dist/server/create-agent-runtime.js.map +1 -0
  141. package/dist/server/create-server.d.ts +5 -0
  142. package/dist/server/create-server.d.ts.map +1 -1
  143. package/dist/server/create-server.js +2 -0
  144. package/dist/server/create-server.js.map +1 -1
  145. package/package.json +23 -9
package/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # @zmzai/agent-framework
2
+
3
+ zmzai 生态的 coding agent 内核库——sessions、permissions、tools、runner、events(OpenCode 风格事件溯源)。
4
+
5
+ 自 `zmzai-agent/packages/agent-framework` 经 `git subtree split` 抽出为独立仓库,git 历史完整保留。
6
+
7
+ ## 消费方
8
+
9
+ - **zmzai-agent**(平台应用):Mongo workspace / skills / memory recall 装配
10
+ - **zmzai-harness**(本地工作台):fs workspace / 多项目 / terminal / checkpoints 装配
11
+
12
+ 两端均以 `link:../zmzai-framework` 消费;开发 framework 时跑 `npx tsc -p tsconfig.build.json --watch`(或 `pnpm run build:watch`,如已配置),两端 dev server 重载即生效。
13
+
14
+ ## 开发
15
+
16
+ ```bash
17
+ pnpm install
18
+ pnpm run typecheck # tsc --noEmit
19
+ pnpm test # vitest run
20
+ pnpm run build # tsc -p tsconfig.build.json → dist/
21
+ ```
22
+
23
+ ## 能力地图
24
+
25
+ | 模块 | 位置 | 说明 |
26
+ |---|---|---|
27
+ | 会话与消息 | `src/core/session/` | jsonl / SQLite(node:sqlite)双存储 |
28
+ | 事件流 | `src/core/events/` | 事件溯源 + seq 重放(manifest 定义 schema) |
29
+ | 工具集 | `src/core/tools/` | read/glob/grep/write/edit/bash/terminal/git/todo/apply_patch/web… |
30
+ | 权限引擎 | `src/core/permissions/` | ruleset LAST-match + approvalMode 档位 |
31
+ | 压缩 | `src/core/runtime/compaction.ts` | 投影式 compaction(不改历史) |
32
+ | 沙箱 | `src/adapters/subprocess-sandbox.ts` | 快照 + 产物回写(本机单用户形态) |
33
+ | 模型接入 | `src/adapters/openai-provider.ts` | relay/OpenAI 兼容 + failover + reasoningEffort |
34
+
35
+ ## 版本策略
36
+
37
+ [changesets](./.changeset/README.md) 管理:feature → minor,fix → patch。合入 main 前跑 `pnpm changeset` 提交变更集;Release workflow 自动汇总版本、开 "Version Packages" PR,合并后自动 build + `npm publish` + 打 tag。
@@ -1,4 +1,24 @@
1
1
  import type { ModelProvider } from "./index.js";
2
+ /** 动态额外请求头(如登录态 cookie)。函数形式每次请求前求值,支持异步。 */
3
+ export type ProviderHeaders = Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
4
+ /** 故障转移端点:主端点在首个流事件即报错时依次尝试(abort 不切)。 */
5
+ export type FailoverEndpoint = {
6
+ baseUrl: string;
7
+ apiKey?: string;
8
+ /** 备用端点上的模型 id(缺省沿用主模型 id)。 */
9
+ modelId?: string;
10
+ };
11
+ /** 降级事件(P0 可观测):每次实际发生端点切换时回调一次。 */
12
+ export type FailoverEvent = {
13
+ /** 被放弃的端点(undefined = 主端点)。 */
14
+ from?: string;
15
+ /** 切换到的端点。 */
16
+ to: string;
17
+ /** 触发降级的首事件错误文本。 */
18
+ error: string;
19
+ /** 第几次尝试(1 起)。 */
20
+ attempt: number;
21
+ };
2
22
  /** OpenAI-compatible ModelProvider (M5 CLI reference): drives the framework
3
23
  * against any OpenAI-compatible chat-completions endpoint via env vars:
4
24
  *
@@ -8,10 +28,19 @@ import type { ModelProvider } from "./index.js";
8
28
  *
9
29
  * The same provider serves relay-compatible backends (m.zmzai.cloud uses the
10
30
  * OpenAI wire format), so the framework runs standalone with zero product
11
- * coupling. */
31
+ * coupling. headers 选项用于注入登录态 cookie 等动态鉴权头;baseUrl 支持
32
+ * 函数形式(每次请求求值,宿主可在运行时切换端点,如设置页改 relay 地址)。
33
+ *
34
+ * 路由降级(N2a):failoverEndpoints 配置备用 OpenAI 兼容端点。主端点在
35
+ * 首个流事件即返回 error(reason=error,网络断/5xx/429/配置失效)时依次
36
+ * 切换;首个事件已正常(连接 + 上游可用)则后续错误不再降级。 */
12
37
  export declare function createOpenAiModelProvider(input?: {
13
- baseUrl?: string;
38
+ baseUrl?: string | (() => string);
14
39
  apiKey?: string;
15
40
  defaultModel?: string;
41
+ headers?: ProviderHeaders;
42
+ failoverEndpoints?: FailoverEndpoint[];
43
+ /** 降级发生时回调(宿主用于日志/UI 提示)。 */
44
+ onFailover?: (event: FailoverEvent) => void;
16
45
  }): ModelProvider;
17
46
  //# sourceMappingURL=openai-provider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"openai-provider.d.ts","sourceRoot":"","sources":["../../src/adapters/openai-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAIhD;;;;;;;;;gBASgB;AAChB,wBAAgB,yBAAyB,CAAC,KAAK,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,aAAa,CAoG7H"}
1
+ {"version":3,"file":"openai-provider.d.ts","sourceRoot":"","sources":["../../src/adapters/openai-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAIhD,6CAA6C;AAC7C,MAAM,MAAM,eAAe,GACvB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtB,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;AAErE,0CAA0C;AAC1C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,oCAAoC;AACpC,MAAM,MAAM,aAAa,GAAG;IAC1B,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc;IACd,EAAE,EAAE,MAAM,CAAC;IACX,oBAAoB;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;;;;;;;;;;sCAcsC;AACtC,wBAAgB,yBAAyB,CAAC,KAAK,CAAC,EAAE;IAChD,OAAO,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACvC,6BAA6B;IAC7B,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CAC7C,GAAG,aAAa,CA+IhB"}
@@ -7,11 +7,26 @@
7
7
  *
8
8
  * The same provider serves relay-compatible backends (m.zmzai.cloud uses the
9
9
  * OpenAI wire format), so the framework runs standalone with zero product
10
- * coupling. */
10
+ * coupling. headers 选项用于注入登录态 cookie 等动态鉴权头;baseUrl 支持
11
+ * 函数形式(每次请求求值,宿主可在运行时切换端点,如设置页改 relay 地址)。
12
+ *
13
+ * 路由降级(N2a):failoverEndpoints 配置备用 OpenAI 兼容端点。主端点在
14
+ * 首个流事件即返回 error(reason=error,网络断/5xx/429/配置失效)时依次
15
+ * 切换;首个事件已正常(连接 + 上游可用)则后续错误不再降级。 */
11
16
  export function createOpenAiModelProvider(input) {
12
- const baseUrl = (input?.baseUrl ?? process.env.OPENAI_BASE_URL ?? "https://api.openai.com/v1").replace(/\/$/, "");
17
+ // baseUrl 动态求值:函数形式每次请求重新解析(设置页改 relay 端点即时生效)
18
+ const baseUrlInput = input?.baseUrl;
19
+ const resolveBase = () => ((typeof baseUrlInput === "function" ? baseUrlInput() : baseUrlInput) ?? process.env.OPENAI_BASE_URL ?? "https://api.openai.com/v1").replace(/\/$/, "");
13
20
  const apiKey = input?.apiKey ?? process.env.OPENAI_API_KEY ?? "";
14
21
  const defaultModel = input?.defaultModel ?? process.env.OPENAI_MODEL ?? "gpt-4o";
22
+ const failovers = input?.failoverEndpoints ?? [];
23
+ const onFailover = input?.onFailover;
24
+ const resolveHeaders = async () => {
25
+ const h = input?.headers;
26
+ if (!h)
27
+ return {};
28
+ return typeof h === "function" ? await h() : h;
29
+ };
15
30
  return {
16
31
  getModel(ref) {
17
32
  return {
@@ -19,96 +34,125 @@ export function createOpenAiModelProvider(input) {
19
34
  name: ref.modelId || defaultModel,
20
35
  api: "openai-completions",
21
36
  provider: "zmzai-openai",
22
- baseUrl,
37
+ baseUrl: resolveBase(),
23
38
  reasoning: false,
24
- input: ["text"],
39
+ input: ["text", "image"],
25
40
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
26
41
  contextWindow: 128_000,
27
42
  maxTokens: 16_384,
43
+ // 兼容开关收紧到经典 OpenAI 字段:部分上游(含 relay 的通道)对
44
+ // strict / stream_options 等新字段会 400,这里显式禁用。
45
+ // supportsReasoningEffort:relay 已按模型白名单接受 reasoning_effort
46
+ // (不支持的模型 relay 返回 400 REASONING_EFFORT_NOT_ALLOWED,UI 层
47
+ // 只在模型允许的档位上展示选择器)。
48
+ compat: {
49
+ supportsStrictMode: false,
50
+ maxTokensField: "max_tokens",
51
+ supportsUsageInStreaming: false,
52
+ supportsReasoningEffort: true,
53
+ supportsFinishReason: true,
54
+ },
28
55
  };
29
56
  },
30
57
  streamFor(session) {
31
58
  void session;
32
- // streamFn built per call; auth header injected by the provider wrapper.
59
+ // streamFn built per call; auth cookie injected by the custom fetch below.
33
60
  return (async (model, context, options) => {
61
+ const { streamSimple } = await import("@earendil-works/pi-ai/api/openai-completions");
34
62
  const { createAssistantMessageEventStream } = await import("@earendil-works/pi-ai");
35
- const stream = createAssistantMessageEventStream();
36
- void (async () => {
63
+ const dynamicHeaders = await resolveHeaders();
64
+ // 每次调 streamFn 重新求值 headers(登录态/个人 key 可动态变化)
65
+ const attempt = async (ep) => {
66
+ const target = ep
67
+ ? { ...model, baseUrl: ep.baseUrl.replace(/\/$/, ""), ...(ep.modelId ? { id: ep.modelId, name: ep.modelId } : {}) }
68
+ // 主端点同样每请求重算 baseUrl(summaryModel 等缓存的 model 对象也生效)
69
+ : { ...model, baseUrl: resolveBase() };
70
+ return streamSimple(target, context, {
71
+ ...(options ?? {}),
72
+ // 占位 key:pi-ai 要求非空 apiKey(否则 throw)。relay 不校验
73
+ // Bearer,真实鉴权靠下方自定义 fetch 注入的登录 cookie。
74
+ // 注意用 ||:apiKey 可能为空串(未配 key 且无 env),?? 不会回退。
75
+ apiKey: ep?.apiKey || apiKey || "cookie-auth",
76
+ maxTokens: options?.maxTokens ?? 16_384,
77
+ // 自定义 fetch:剥掉 SDK 自动生成的 Authorization(relay 对无效
78
+ // Bearer 直接 401,不会回退到 cookie 登录态),再注入动态头。
79
+ fetch: async (url, init) => {
80
+ const headers = new Headers(init?.headers);
81
+ headers.delete("authorization");
82
+ for (const [name, value] of Object.entries(dynamicHeaders))
83
+ headers.set(name, value);
84
+ return fetch(url, { ...(init ?? {}), headers });
85
+ },
86
+ });
87
+ };
88
+ // 无备用端点:直连主端点(零额外开销)
89
+ if (failovers.length === 0)
90
+ return attempt();
91
+ // 有备用端点:peek 首事件判定健康度,error(reason=error) 时降级重试
92
+ const endpoints = [undefined, ...failovers];
93
+ let lastStream = null;
94
+ let lastFirst = null;
95
+ let lastIterator = null;
96
+ for (let i = 0; i < endpoints.length; i++) {
97
+ let stream;
37
98
  try {
38
- const messages = (context.messages ?? []).map((message) => {
39
- if (message.role === "user" || message.role === "assistant") {
40
- const content = message.content;
41
- if (typeof content === "string")
42
- return { role: message.role, content };
43
- if (Array.isArray(content)) {
44
- return { role: message.role, content: content.filter((b) => b.type === "text").map((b) => ({ type: "text", text: b.text ?? "" })) };
45
- }
46
- }
47
- if (message.role === "toolResult") {
48
- const text = Array.isArray(message.content)
49
- ? message.content.filter((b) => b.type === "text").map((b) => b.text ?? "").join("\n")
50
- : String(message.content ?? "");
51
- return { role: "tool", content: text, tool_call_id: message.toolCallId ?? "" };
52
- }
53
- return null;
54
- }).filter(Boolean);
55
- const response = await fetch(`${baseUrl}/chat/completions`, {
56
- method: "POST",
57
- headers: { "content-type": "application/json", ...(apiKey ? { authorization: `Bearer ${apiKey}` } : {}) },
58
- body: JSON.stringify({
59
- model: model.id,
60
- messages,
61
- stream: true,
62
- ...(options?.maxTokens ? { max_tokens: options.maxTokens } : {}),
63
- }),
64
- });
65
- if (!response.ok || !response.body) {
66
- const error = { type: "error", reason: "error", error: await response.text().catch(() => "HTTP error") };
67
- stream.push(error);
68
- stream.end(error);
69
- return;
99
+ stream = await attempt(endpoints[i]);
100
+ }
101
+ catch (error) {
102
+ if (i + 1 < endpoints.length)
103
+ continue;
104
+ throw error;
105
+ }
106
+ const iterator = stream[Symbol.asyncIterator]();
107
+ const first = await iterator.next();
108
+ const event = first.value;
109
+ const retryable = !first.done && event?.type === "error" && event.reason === "error";
110
+ if (retryable && i + 1 < endpoints.length) {
111
+ // error 事件的 payload 是 AssistantMessage(含 errorMessage)
112
+ const errPayload = event.error;
113
+ const detail = errPayload?.errorMessage ?? JSON.stringify(errPayload ?? {}) ?? "上游不可用";
114
+ try {
115
+ onFailover?.({
116
+ from: endpoints[i] ? endpoints[i].baseUrl : undefined,
117
+ to: endpoints[i + 1].baseUrl,
118
+ error: String(detail).slice(0, 300),
119
+ attempt: i + 1,
120
+ });
121
+ }
122
+ catch {
123
+ // 观测回调永不影响主链路
70
124
  }
71
- const reader = response.body.getReader();
72
- const decoder = new TextDecoder();
73
- let buffer = "";
74
- const partial = { role: "assistant", content: [{ type: "text", text: "" }] };
125
+ continue;
126
+ }
127
+ lastStream = stream;
128
+ lastFirst = first;
129
+ lastIterator = iterator;
130
+ break;
131
+ }
132
+ if (!lastStream || !lastIterator) {
133
+ // 理论不可达(endpoints 至少一项);防御性抛错
134
+ throw new Error("模型请求失败:所有端点均不可用");
135
+ }
136
+ // 健康流桥接:peek 到的事件重放进 wrapper,后台继续透传剩余事件
137
+ const wrapper = createAssistantMessageEventStream();
138
+ void (async () => {
139
+ try {
140
+ if (!lastFirst.done && lastFirst.value)
141
+ wrapper.push(lastFirst.value);
75
142
  while (true) {
76
- const { done, value } = await reader.read();
77
- if (done)
78
- break;
79
- buffer += decoder.decode(value, { stream: true });
80
- const lines = buffer.split("\n");
81
- buffer = lines.pop() ?? "";
82
- for (const line of lines) {
83
- const trimmed = line.trim();
84
- if (!trimmed.startsWith("data:"))
85
- continue;
86
- const data = trimmed.slice(5).trim();
87
- if (data === "[DONE]")
88
- continue;
89
- try {
90
- const chunk = JSON.parse(data);
91
- const delta = chunk.choices?.[0]?.delta?.content;
92
- if (delta) {
93
- partial.content[0].text += delta;
94
- stream.push({ type: "text_delta", contentIndex: 0, delta, partial });
95
- }
96
- }
97
- catch {
98
- // partial JSON — ignore
99
- }
143
+ const next = await lastIterator.next();
144
+ if (next.done) {
145
+ wrapper.end();
146
+ return;
100
147
  }
148
+ wrapper.push(next.value);
101
149
  }
102
- stream.push({ type: "done", reason: "stop", message: partial });
103
- stream.end(partial);
104
150
  }
105
- catch (error) {
106
- const err = error instanceof Error ? error.message : String(error);
107
- stream.push({ type: "error", reason: "error", error: err });
108
- stream.end({ role: "assistant", content: [{ type: "text", text: "" }], stopReason: "error", errorMessage: err });
151
+ catch {
152
+ wrapper.end();
109
153
  }
110
154
  })();
111
- return stream;
155
+ return wrapper;
112
156
  });
113
157
  },
114
158
  };
@@ -1 +1 @@
1
- {"version":3,"file":"openai-provider.js","sourceRoot":"","sources":["../../src/adapters/openai-provider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"openai-provider.js","sourceRoot":"","sources":["../../src/adapters/openai-provider.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,6 @@
1
1
  import type { SandboxExecutor } from "../adapters/index.js";
2
- /** Subprocess SandboxExecutor (M5 §5 CLI reference implementation): writes the
3
- * snapshot to a temp dir and runs the command as a plain child process — NO
4
- * isolation. Good enough to demo the framework standalone; production uses
5
- * OpenSandbox. */
6
- export declare function createSubprocessSandbox(): SandboxExecutor;
2
+ export declare function createSubprocessSandbox(input?: {
3
+ /** 提供后:快照从真实工作区采集、新产物回写工作区(函数形式随项目切换)。 */
4
+ workspaceRoot?: string | (() => string | null | undefined);
5
+ }): SandboxExecutor;
7
6
  //# sourceMappingURL=subprocess-sandbox.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"subprocess-sandbox.d.ts","sourceRoot":"","sources":["../../src/adapters/subprocess-sandbox.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG5D;;;mBAGmB;AACnB,wBAAgB,uBAAuB,IAAI,eAAe,CAoEzD"}
1
+ {"version":3,"file":"subprocess-sandbox.d.ts","sourceRoot":"","sources":["../../src/adapters/subprocess-sandbox.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AA2B5D,wBAAgB,uBAAuB,CAAC,KAAK,CAAC,EAAE;IAC9C,0CAA0C;IAC1C,aAAa,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;CAC5D,GAAG,eAAe,CAiIlB"}
@@ -1,25 +1,82 @@
1
1
  import { spawn } from "node:child_process";
2
- import { mkdtemp, writeFile, rm, readdir, readFile } from "node:fs/promises";
2
+ import { copyFile, mkdir, mkdtemp, readdir, readFile, rm, stat, writeFile } from "node:fs/promises";
3
3
  import { tmpdir } from "node:os";
4
4
  import path from "node:path";
5
- /** Subprocess SandboxExecutor (M5 §5 CLI reference implementation): writes the
6
- * snapshot to a temp dir and runs the command as a plain child process — NO
7
- * isolation. Good enough to demo the framework standalone; production uses
8
- * OpenSandbox. */
9
- export function createSubprocessSandbox() {
5
+ /** Subprocess SandboxExecutor (M5 §5): 快照到 temp 目录跑普通子进程——无隔离,
6
+ * 面向本机单用户宿主(生产隔离由 OpenSandbox 等真沙箱承担)。
7
+ *
8
+ * 快照/回写语义(E2E 实测修复):
9
+ * - 提供 workspaceRoot 时,buildSnapshot 从真实工作区采集文本文件(跳过
10
+ * node_modules/.git 等重目录,限量防爆),bash 命令能看到并改动工作区文件;
11
+ * - 命令结束后,快照外的新文件(npm install 的 node_modules、构建产物等)
12
+ * 直接 fs 回写工作区——不逐文件版本化,产物面板事件只收小文本样本,
13
+ * 避免 node_modules 数千条 artifact.created 刷屏。 */
14
+ const SNAPSHOT_MAX_FILES = 5000;
15
+ const SNAPSHOT_MAX_BYTES = 32 * 1024 * 1024;
16
+ const SNAPSHOT_MAX_FILE_BYTES = 512 * 1024;
17
+ /** 快照采集跳过的重目录(依赖/构建缓存不入快照,npm install 会重新生成)。 */
18
+ const SNAPSHOT_SKIP_DIRS = new Set([
19
+ "node_modules", ".git", ".next", ".nuxt", "dist", "build", "out",
20
+ ".cache", ".venv", "venv", "__pycache__", ".turbo", ".harness-data",
21
+ ]);
22
+ /** 产物面板/回写事件排除(批量落盘照常,只是不进事件流)。 */
23
+ const ARTIFACT_SKIP_DIRS = new Set(["node_modules", ".git", "__pycache__", ".cache"]);
24
+ const ARTIFACT_MAX_PATHS = 100;
25
+ const WORKSPACE_CONTENT_MAX_FILES = 30;
26
+ const WORKSPACE_CONTENT_MAX_BYTES = 256 * 1024;
27
+ export function createSubprocessSandbox(input) {
28
+ const wsRoot = () => (typeof input?.workspaceRoot === "function" ? input.workspaceRoot() : input?.workspaceRoot) ?? null;
10
29
  return {
11
- async buildSnapshot(input) {
12
- void input;
13
- return { revisionId: null, files: [] };
30
+ async buildSnapshot() {
31
+ const ws = wsRoot();
32
+ if (!ws)
33
+ return { revisionId: null, files: [] };
34
+ const files = [];
35
+ let total = 0;
36
+ const walk = async (dir) => {
37
+ if (files.length >= SNAPSHOT_MAX_FILES || total >= SNAPSHOT_MAX_BYTES)
38
+ return;
39
+ const entries = await readdir(dir, { withFileTypes: true });
40
+ for (const entry of entries) {
41
+ if (files.length >= SNAPSHOT_MAX_FILES || total >= SNAPSHOT_MAX_BYTES)
42
+ return;
43
+ const full = path.join(dir, entry.name);
44
+ if (entry.isDirectory()) {
45
+ if (SNAPSHOT_SKIP_DIRS.has(entry.name))
46
+ continue;
47
+ await walk(full);
48
+ }
49
+ else if (entry.isFile()) {
50
+ const info = await stat(full);
51
+ if (info.size > SNAPSHOT_MAX_FILE_BYTES)
52
+ continue;
53
+ const content = await readFile(full, "utf8");
54
+ if (content.includes("\uFFFD"))
55
+ continue; // 二进制不入快照
56
+ total += info.size;
57
+ files.push({ path: path.relative(ws, full), content });
58
+ }
59
+ }
60
+ };
61
+ try {
62
+ await walk(ws);
63
+ }
64
+ catch {
65
+ /* 工作区读取失败按空快照跑 */
66
+ }
67
+ return { revisionId: null, files };
14
68
  },
15
69
  async run(input) {
16
70
  const dir = await mkdtemp(path.join(tmpdir(), "fw-sandbox-"));
17
71
  try {
18
72
  for (const file of input.snapshot.files) {
19
73
  const full = path.join(dir, file.path);
74
+ await mkdir(path.dirname(full), { recursive: true });
20
75
  await writeFile(full, file.content, "utf8");
21
76
  }
22
77
  const cwd = input.command.cwd ? path.join(dir, input.command.cwd) : dir;
78
+ // cwd 可能指向快照里没有文件的子目录(如刚 mkdir 的空项目):先建出来
79
+ await mkdir(cwd, { recursive: true });
23
80
  const result = await new Promise((resolve, reject) => {
24
81
  const child = spawn(input.command.program, input.command.args ?? [], {
25
82
  cwd,
@@ -37,38 +94,69 @@ export function createSubprocessSandbox() {
37
94
  child.on("error", reject);
38
95
  child.on("close", (code) => resolve({ code, output }));
39
96
  });
40
- // Collect files written during the run as deliverables.
97
+ // 收集快照外的新文件:批量 fs 回写工作区 + 产物元数据(限流)
98
+ const snapshotPaths = new Set(input.snapshot.files.map((f) => f.path));
99
+ const ws = wsRoot();
41
100
  const artifacts = [];
101
+ let contentSamples = 0;
102
+ let truncated = false;
42
103
  const walk = async (dirPath) => {
104
+ if (truncated)
105
+ return;
43
106
  const entries = await readdir(dirPath, { withFileTypes: true });
44
107
  for (const entry of entries) {
108
+ if (truncated)
109
+ return;
45
110
  const full = path.join(dirPath, entry.name);
46
111
  if (entry.isDirectory()) {
47
112
  await walk(full);
48
113
  }
49
- else if (entry.name !== ".fw-sandbox") {
114
+ else if (entry.isFile() && entry.name !== ".fw-sandbox") {
50
115
  const rel = path.relative(dir, full);
51
- const content = await readFile(full);
116
+ if (snapshotPaths.has(rel))
117
+ continue;
118
+ const info = await stat(full);
119
+ // 批量回写:新文件原样落回工作区(node_modules 也落,install 才有意义)
120
+ if (ws) {
121
+ const parent = path.relative(dir, path.dirname(full));
122
+ const destDir = parent ? path.join(ws, parent) : ws;
123
+ await mkdir(destDir, { recursive: true });
124
+ await copyFile(full, path.join(ws, rel));
125
+ }
126
+ if (ARTIFACT_SKIP_DIRS.has(rel.split(path.sep)[0] ?? ""))
127
+ continue;
128
+ if (artifacts.length >= ARTIFACT_MAX_PATHS) {
129
+ truncated = true;
130
+ continue;
131
+ }
132
+ // 事件样本:仅小文本给 workspaceContent(走版本化写入 + diff 卡片)
133
+ let workspaceContent;
134
+ if (info.size <= WORKSPACE_CONTENT_MAX_BYTES && contentSamples < WORKSPACE_CONTENT_MAX_FILES) {
135
+ const text = await readFile(full, "utf8");
136
+ if (!text.includes("\uFFFD")) {
137
+ workspaceContent = text;
138
+ contentSamples++;
139
+ }
140
+ }
52
141
  artifacts.push({
53
142
  path: rel,
54
- bytes: content.length,
143
+ bytes: info.size,
55
144
  contentType: guessContentType(rel),
56
- downloadUrl: `file://${full}`,
145
+ // 回写后的文件指向工作区真实路径(temp 目录在 finally 里会删)
146
+ downloadUrl: ws ? `file://${path.join(ws, rel)}` : `file://${full}`,
147
+ ...(workspaceContent !== undefined ? { workspaceContent } : {}),
57
148
  });
58
149
  }
59
150
  }
60
151
  };
61
152
  await walk(dir);
62
- // Only files NOT in the original snapshot count as deliverables.
63
- const snapshotPaths = new Set(input.snapshot.files.map((f) => f.path));
64
- const deliverables = artifacts.filter((a) => !snapshotPaths.has(a.path));
65
153
  return {
66
154
  ok: result.code === 0,
67
155
  outcome: result.code === 0 ? "succeeded" : "failed",
68
156
  exitCode: result.code,
69
157
  outputText: result.output,
70
158
  durationMs: 0,
71
- artifacts: deliverables,
159
+ artifacts,
72
160
  };
73
161
  }
74
162
  finally {
@@ -1 +1 @@
1
- {"version":3,"file":"subprocess-sandbox.js","sourceRoot":"","sources":["../../src/adapters/subprocess-sandbox.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"subprocess-sandbox.js","sourceRoot":"","sources":["../../src/adapters/subprocess-sandbox.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { TerminalBackend } from "../core/tools/terminal.js";
2
+ /** 宿主终端后端单例:优先真 PTY,node-pty 不可用或 spawn 探测失败时降级管道模式。
3
+ * 首次调用即锁定后端种类(同步),session 标签从此不存在竞态。 */
4
+ export declare function createHostTerminalBackend(): TerminalBackend;
5
+ //# sourceMappingURL=terminal-backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-backend.d.ts","sourceRoot":"","sources":["../../src/adapters/terminal-backend.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAqDjE;yCACyC;AACzC,wBAAgB,yBAAyB,IAAI,eAAe,CAQ3D"}