create-windy 0.3.17 → 0.3.19

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 (58) hide show
  1. package/README.md +14 -36
  2. package/dist/cli.js +1534 -3079
  3. package/package.json +1 -1
  4. package/template/.windy-template.json +2 -2
  5. package/template/AGENTS.md +6 -0
  6. package/template/README.md +5 -10
  7. package/template/apps/agent-server/Dockerfile +2 -1
  8. package/template/apps/agent-server/README.md +13 -5
  9. package/template/apps/agent-server/adk_web_agents/canonical_debug/__init__.py +1 -0
  10. package/template/apps/agent-server/adk_web_agents/canonical_debug/agent.py +125 -0
  11. package/template/apps/agent-server/project/adk-web-debug.json +4 -0
  12. package/template/apps/agent-server/src/southwind_agent_server/adk_debug.py +348 -0
  13. package/template/apps/agent-server/tests/test_adk_debug_result_polling.py +139 -0
  14. package/template/apps/agent-server/tests/test_adk_web_canonical_debug.py +235 -0
  15. package/template/apps/server/src/agent/run-debug-authorization.ts +27 -0
  16. package/template/apps/server/src/agent/run-facade-adk-debug.test.ts +56 -0
  17. package/template/apps/server/src/agent/run-facade.test-support.ts +235 -0
  18. package/template/apps/server/src/agent/run-facade.test.ts +8 -244
  19. package/template/apps/server/src/agent/run-facade.ts +23 -48
  20. package/template/apps/server/src/agent/run-operation-registry.ts +51 -0
  21. package/template/apps/server/src/agent/runtime-bootstrap.ts +5 -2
  22. package/template/apps/server/src/agent/tool-audit.ts +3 -0
  23. package/template/apps/server/src/agent/tool-registry.test.ts +29 -0
  24. package/template/apps/server/src/application-services.ts +83 -15
  25. package/template/apps/server/src/guards.ts +16 -0
  26. package/template/apps/server/src/index.ts +23 -20
  27. package/template/apps/server/src/jobs/legacy-adapter.integration.test.ts +0 -1
  28. package/template/apps/server/src/jobs/legacy-adapter.test.ts +6 -0
  29. package/template/apps/server/src/jobs/legacy-service-runtime.ts +18 -0
  30. package/template/apps/server/src/module-host/durable-context-unavailable.test.ts +84 -0
  31. package/template/apps/server/src/module-host/durable-context.test.ts +14 -0
  32. package/template/apps/server/src/module-host/durable-context.ts +17 -15
  33. package/template/apps/server/src/module-host/request-context.test.ts +30 -1
  34. package/template/apps/server/src/module-host/request-context.ts +15 -2
  35. package/template/apps/server/src/module-host/storage-port.ts +1 -1
  36. package/template/apps/server/src/platform-bootstrap.ts +16 -0
  37. package/template/apps/server/src/runtime-adk-debug.test.ts +246 -0
  38. package/template/apps/server/src/runtime-adk-debug.ts +158 -0
  39. package/template/apps/server/src/runtime-request-actor.test.ts +55 -0
  40. package/template/apps/server/src/runtime-request-actor.ts +22 -0
  41. package/template/apps/server/src/runtime.test.ts +3 -0
  42. package/template/apps/server/src/runtime.ts +36 -3
  43. package/template/apps/server/src/scheduler/definitions.test.ts +16 -0
  44. package/template/docker-compose.agent-debug.yml +56 -0
  45. package/template/docker-compose.yml +1 -39
  46. package/template/docs/architecture/ai-runtime.md +14 -5
  47. package/template/docs/architecture/module-manifest-composition.md +14 -0
  48. package/template/docs/development/custom-login-page.md +2 -16
  49. package/template/docs/platform/agent-runtime.md +59 -16
  50. package/template/docs/platform/agent-tool-sandbox.md +4 -3
  51. package/template/docs/platform/platform-authentication.md +9 -1
  52. package/template/package.json +1 -1
  53. package/template/packages/database/drizzle/0043_activate_agent_dependencies.sql +196 -0
  54. package/template/packages/database/drizzle/meta/0043_snapshot.json +8335 -0
  55. package/template/packages/database/drizzle/meta/_journal.json +7 -0
  56. package/template/packages/database/src/schema-notification-delivery.test.ts +15 -6
  57. package/template/packages/database/src/schema-workflow-notification.test.ts +44 -29
  58. package/template/scripts/dev-adk-web.ts +107 -0
@@ -0,0 +1,55 @@
1
+ import { expect, test } from "bun:test";
2
+ import type { RequestActor } from "./guards.js";
3
+ import { resolveRequestActor } from "./runtime-request-actor.js";
4
+
5
+ const debugActor: RequestActor = {
6
+ id: "service_adk_debug",
7
+ type: "service",
8
+ name: "ADK 开发调试",
9
+ roleCodes: ["adk-debug"],
10
+ permissionKeys: ["analysis.copilot.execute"],
11
+ };
12
+
13
+ test("保留凭据命中后不回退普通认证", async () => {
14
+ let standardCalls = 0;
15
+ const request = new Request("http://localhost/api/foundation");
16
+ const actor = await resolveRequestActor(
17
+ request,
18
+ () => {
19
+ standardCalls += 1;
20
+ return {
21
+ id: "user_regular",
22
+ type: "user",
23
+ name: "普通用户",
24
+ roleCodes: ["user"],
25
+ permissionKeys: [],
26
+ };
27
+ },
28
+ {
29
+ claimsRequest: () => true,
30
+ resolveRequest: () => undefined,
31
+ },
32
+ );
33
+
34
+ expect(actor).toBeUndefined();
35
+ expect(standardCalls).toBe(0);
36
+ });
37
+
38
+ test("保留凭据在 canonical 路径始终解析为专用主体", async () => {
39
+ const actor = await resolveRequestActor(
40
+ new Request("http://localhost/api/agent/runs", { method: "POST" }),
41
+ () => ({
42
+ id: "user_regular",
43
+ type: "user",
44
+ name: "普通用户",
45
+ roleCodes: ["user"],
46
+ permissionKeys: ["analysis.copilot.execute"],
47
+ }),
48
+ {
49
+ claimsRequest: () => true,
50
+ resolveRequest: () => debugActor,
51
+ },
52
+ );
53
+
54
+ expect(actor).toBe(debugActor);
55
+ });
@@ -0,0 +1,22 @@
1
+ import type { RequestActor } from "./guards.js";
2
+
3
+ export interface ReservedRequestActorResolver {
4
+ claimsRequest(request: Request): boolean;
5
+ resolveRequest(
6
+ request: Request,
7
+ ): Promise<RequestActor | undefined> | RequestActor | undefined;
8
+ }
9
+
10
+ export async function resolveRequestActor(
11
+ request: Request,
12
+ resolveStandard: () =>
13
+ | Promise<RequestActor | undefined>
14
+ | RequestActor
15
+ | undefined,
16
+ reserved?: ReservedRequestActorResolver,
17
+ ): Promise<RequestActor | undefined> {
18
+ if (reserved?.claimsRequest(request)) {
19
+ return reserved.resolveRequest(request);
20
+ }
21
+ return resolveStandard();
22
+ }
@@ -22,6 +22,9 @@ describe("server runtime", () => {
22
22
 
23
23
  expect(context.actor.id).toBe("user_dev_admin");
24
24
  expect(context.actor.permissionKeys).toContain("system.menu.read");
25
+ // @windy-module work-order begin
26
+ expect(context.actor.permissionKeys).toContain("work-order.ticket.read");
27
+ // @windy-module work-order end
25
28
  });
26
29
 
27
30
  test("生产环境强制关闭开发管理员 token", async () => {
@@ -31,6 +31,13 @@ import {
31
31
  requestSourcePolicyFromEnv,
32
32
  resolveRequestSource,
33
33
  } from "./http/request-source.js";
34
+ import { resolveRequestActor } from "./runtime-request-actor.js";
35
+ // @windy-module system.agent begin
36
+ import {
37
+ createAdkDebugRuntime,
38
+ type AdkDebugActorResolver,
39
+ } from "./runtime-adk-debug.js";
40
+ // @windy-module system.agent end
34
41
 
35
42
  export type {
36
43
  FeatureFlagRuntimeResolver,
@@ -78,6 +85,9 @@ export interface ServerRuntimeOptions {
78
85
  featureCatalog?: readonly FeatureFlagDefinition[];
79
86
  auditWriter?: AuditEventWriter;
80
87
  auditReader?: AuditEventReader;
88
+ // @windy-module system.agent begin
89
+ adkDebugActorResolver?: AdkDebugActorResolver;
90
+ // @windy-module system.agent end
81
91
  }
82
92
 
83
93
  export class InMemorySessionStore {
@@ -186,6 +196,19 @@ export function createServerRuntime(
186
196
  options: ServerRuntimeOptions = {},
187
197
  ) {
188
198
  const developmentAuth = readDevelopmentAuthBypass(env);
199
+ // @windy-module system.agent begin
200
+ const adkDebug = createAdkDebugRuntime(
201
+ env,
202
+ undefined,
203
+ options.adkDebugActorResolver,
204
+ );
205
+ if (adkDebug.usesToken(developmentAuth.token)) {
206
+ throw new Error("ADK Web 调试 Token 不能复用开发管理员 Token");
207
+ }
208
+ if (adkDebug.usesToken(env.AGENT_SERVER_INTERNAL_TOKEN?.trim())) {
209
+ throw new Error("ADK Web 调试 Token 不能复用 Agent 内部服务 Token");
210
+ }
211
+ // @windy-module system.agent end
189
212
  const sessionStore = new InMemorySessionStore(
190
213
  developmentAuth.token
191
214
  ? [{ token: developmentAuth.token, actor: developmentAdminActor() }]
@@ -216,9 +239,15 @@ export function createServerRuntime(
216
239
  metadata.clientIp,
217
240
  requestSourcePolicy,
218
241
  );
219
- const actor =
220
- (await options.actorResolver?.resolve(request)) ||
221
- sessionStore.resolve(request);
242
+ const actor = await resolveRequestActor(
243
+ request,
244
+ async () =>
245
+ (await options.actorResolver?.resolve(request)) ||
246
+ sessionStore.resolve(request),
247
+ // @windy-module system.agent begin
248
+ adkDebug,
249
+ // @windy-module system.agent end
250
+ );
222
251
  const license =
223
252
  (await options.licenseResolver?.resolve()) || licenseStore.resolve();
224
253
  return createRequestGuardContext(request, {
@@ -227,6 +256,10 @@ export function createServerRuntime(
227
256
  resolveLicense: () => license,
228
257
  });
229
258
  },
259
+ // @windy-module system.agent begin
260
+ resolveEphemeralActor: adkDebug.resolveActor,
261
+ agentDebugOperationForActor: adkDebug.operationForActor,
262
+ // @windy-module system.agent end
230
263
  async createGuardContextForActor(
231
264
  request: Request,
232
265
  actor: RequestActor,
@@ -8,12 +8,22 @@ describe("平台任务 Manifest Adapter", () => {
8
8
  const definitions = createPlatformTaskDefinitions(
9
9
  createFoundationSnapshot().features,
10
10
  {
11
+ // @windy-module system.bulk-data begin
11
12
  bulkDataDispatch: () => ({ claimed: false }),
12
13
  bulkDataCleanup: () => ({ deleted: 0 }),
14
+ // @windy-module system.bulk-data end
15
+ // @windy-module system.storage begin
13
16
  storageCleanup: () => ({ deleted: 0 }),
17
+ // @windy-module system.storage end
18
+ // @windy-module system.workflow begin
14
19
  workflowTimeoutDispatch: () => ({ claimed: false }),
20
+ // @windy-module system.workflow end
21
+ // @windy-module system.data-governance begin
15
22
  governedExportDispatch: () => ({ claimed: false }),
23
+ // @windy-module system.data-governance end
24
+ // @windy-module system.notification begin
16
25
  notificationDispatch: () => ({ claimed: false }),
26
+ // @windy-module system.notification end
17
27
  },
18
28
  );
19
29
 
@@ -22,20 +32,26 @@ describe("平台任务 Manifest Adapter", () => {
22
32
  .tasks.map(({ key }) => key)
23
33
  .sort(),
24
34
  );
35
+ // @windy-module system.bulk-data begin
25
36
  expect(
26
37
  definitions
27
38
  .find(({ key }) => key === "system.bulk-data.dispatch")
28
39
  ?.isIdleResult?.({ claimed: false }),
29
40
  ).toBe(true);
41
+ // @windy-module system.bulk-data end
42
+ // @windy-module system.data-governance begin
30
43
  expect(
31
44
  definitions
32
45
  .find(({ key }) => key === "system.governed-export.dispatch")
33
46
  ?.isIdleResult?.({ claimed: false }),
34
47
  ).toBe(true);
48
+ // @windy-module system.data-governance end
49
+ // @windy-module system.notification begin
35
50
  expect(
36
51
  definitions
37
52
  .find(({ key }) => key === "system.notification.dispatch")
38
53
  ?.isIdleResult?.({ claimed: false }),
39
54
  ).toBe(true);
55
+ // @windy-module system.notification end
40
56
  });
41
57
  });
@@ -0,0 +1,56 @@
1
+ services:
2
+ server:
3
+ environment:
4
+ PLATFORM_ENABLE_AI: "true"
5
+ WINDY_ADK_DEBUG_TOKEN: ${ADK_DEBUG_PLATFORM_TOKEN:?请先由 create-windy doctor 修复本地调试 Token}
6
+ WINDY_ADK_DEBUG_OPERATION_KEY: ${WINDY_ADK_DEBUG_OPERATION_KEY:?项目尚未选择 ADK Web 调试 Operation}
7
+ WINDY_ADK_DEBUG_DATA_ACTOR_ID: ${WINDY_ADK_DEBUG_DATA_ACTOR_ID:?项目尚未选择 ADK Web 真实开发数据用户}
8
+
9
+ adk-web-debug:
10
+ profiles: ["agent-debug"]
11
+ build:
12
+ context: .
13
+ dockerfile: apps/agent-server/Dockerfile
14
+ environment:
15
+ ADK_DEBUG_PLATFORM_URL: http://server:9747
16
+ ADK_DEBUG_PLATFORM_TOKEN: ${ADK_DEBUG_PLATFORM_TOKEN:?请先由 create-windy doctor 修复本地调试 Token}
17
+ ADK_DEBUG_OPERATION_KEY: ${WINDY_ADK_DEBUG_OPERATION_KEY:?项目尚未选择 ADK Web 调试 Operation}
18
+ command:
19
+ [
20
+ "adk",
21
+ "web",
22
+ "--host",
23
+ "0.0.0.0",
24
+ "--port",
25
+ "8000",
26
+ "--no-reload",
27
+ "--session_service_uri",
28
+ "memory://",
29
+ "--artifact_service_uri",
30
+ "memory://",
31
+ "--logo-text",
32
+ "Windy ADK 真实 Run 调试",
33
+ "--logo-image-url",
34
+ "data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%2F%3E",
35
+ "/app/apps/agent-server/adk_web_agents",
36
+ ]
37
+ ports:
38
+ - "127.0.0.1:8000:8000"
39
+ healthcheck:
40
+ test:
41
+ [
42
+ "CMD",
43
+ "python",
44
+ "-c",
45
+ "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/', timeout=3)",
46
+ ]
47
+ interval: 10s
48
+ timeout: 5s
49
+ retries: 5
50
+ depends_on:
51
+ server:
52
+ condition: service_started
53
+ agent-server:
54
+ condition: service_healthy
55
+ tool-sandbox:
56
+ condition: service_started
@@ -100,7 +100,7 @@ services:
100
100
  [
101
101
  "sh",
102
102
  "-c",
103
- "chmod 0700 /run/windy-tool-sandbox && chown 1000:1000 /run/windy-tool-sandbox",
103
+ "chown 0:0 /run/windy-tool-sandbox && chmod 0700 /run/windy-tool-sandbox && chown 1000:1000 /run/windy-tool-sandbox",
104
104
  ]
105
105
  network_mode: none
106
106
  read_only: true
@@ -230,44 +230,6 @@ services:
230
230
  server:
231
231
  condition: service_started
232
232
 
233
- adk-web-debug:
234
- profiles: ["agent-debug"]
235
- build:
236
- context: .
237
- dockerfile: apps/agent-server/Dockerfile
238
- command:
239
- [
240
- "adk",
241
- "web",
242
- "--host",
243
- "0.0.0.0",
244
- "--port",
245
- "8000",
246
- "--no-reload",
247
- "--session_service_uri",
248
- "memory://",
249
- "--artifact_service_uri",
250
- "memory://",
251
- "--logo-text",
252
- "Windy ADK 开发调试(无业务工具)",
253
- "--logo-image-url",
254
- "data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%2F%3E",
255
- "/app/apps/agent-server/adk_web_agents",
256
- ]
257
- ports:
258
- - "127.0.0.1:8000:8000"
259
- healthcheck:
260
- test:
261
- [
262
- "CMD",
263
- "python",
264
- "-c",
265
- "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/', timeout=3)",
266
- ]
267
- interval: 10s
268
- timeout: 5s
269
- retries: 5
270
-
271
233
  web:
272
234
  build:
273
235
  context: .
@@ -654,13 +654,22 @@ type DictationEvent =
654
654
 
655
655
  ## Prompt、Debug 与 Trace
656
656
 
657
- ADK Web 只在 developer profile 启动,绑定 localhost 或受控开发网络。它不是生产 Prompt 管理或生产 Debug 控制面。
657
+ ADK Web 只在 developer profile 启动,绑定 localhost 或受控开发网络。它不是生产
658
+ Prompt 管理或生产 Debug 控制面。
658
659
 
659
660
  当前 Compose 使用独立 `agent-debug` profile,宿主机只发布
660
- `127.0.0.1:8000`。由于原生 ADK Web 没有 Southwind AI Server 签发的 Actor 与
661
- Execution Grant,它只加载一个无 Provider、无业务 Tool 的确定性调试 Agent。真实业务
662
- Operation 只能走 canonical HTTP/SSE → ADK Adapter → 受治理 Provider/Tool Host 链路;
663
- 不得把 ADK Web 的调试会话解释为生产授权或业务执行证据。
661
+ `127.0.0.1:8000`。Windy 的 `canonical_debug` 是确定性 Adapter:它把用户文本交给
662
+ project-owned 配置选择的真实文本 Operation,并通过 canonical HTTP/SSE 读取 Run、
663
+ Tool 和终态摘要。业务 Permission、Scope、Execution Grant、Provider 与 Tool Host
664
+ 继续由正式 Server/Agent Server 管理,ADK Web 不获得 Repository、Provider Key 或内部
665
+ Token。项目配置只包含 Operation Key 与当前启用的真实开发数据用户 ID,不能重复或扩大
666
+ Manifest 的权限、Scope 与 Tool 列表。数据用户用于复用其成员关系和当前 Scope。开发 Wrapper
667
+ 创建的核心主体仍是 `service_adk_debug`,权限只取该用户已有权限与 Operation/allowed
668
+ Tools 闭包的精确交集,并且只能调用 canonical Run API;审计不会把它记录成普通用户会话。
669
+
670
+ 该 Adapter 证明真实业务执行链,不等于把另一进程内的完整 ADK Agent/Workflow 图装入
671
+ 原生 ADK Web。内部节点、Prompt 版本和 replay 若要可视化,必须通过另一个版本化协议
672
+ 显式暴露。不得把开发调试会话解释为生产授权或业务执行证据。
664
673
 
665
674
  Prompt 和 Workflow 使用:
666
675
 
@@ -28,6 +28,20 @@ Manifest 当前覆盖:
28
28
 
29
29
  同一个稳定能力基础 Key 仍可分别出现在 Feature、Permission 前缀、菜单和页面入口中;“重复”按能力类别判断,避免破坏项目既定 Key 语义。
30
30
 
31
+ ## 功能注册门禁
32
+
33
+ 所有面向用户、业务或系统开放的能力必须有 Manifest 功能注册;这是一项可执行门禁,
34
+ 不是只靠文档约定的建议。每个能力注册一个 Feature 基础 Key,并声明所需动作;Feature
35
+ 用于功能目录、开关与 License,动作派生或声明同一基础 Key 下的 RBAC Permission。
36
+ 例如 `personnel.profile` 对应 `personnel.profile.read`、`personnel.profile.create`、
37
+ `personnel.profile.update` 与 `personnel.profile.delete`。
38
+
39
+ 菜单、Admin 路由、按钮、Server API、Agent Tool、后台任务、Provider、审计动作和
40
+ License 配置必须引用同一 Manifest 中已注册的 Feature/Permission。未知引用、重复 Key、
41
+ 缺少 Feature、缺少动作权限或未声明实现均在三处以同一规则 fail closed:模块安装前、
42
+ 项目构建时和服务监听前。这样权限目录与 License/Feature 目录不会依赖第二份手写 Key
43
+ 列表,也不会出现只注册页面或 API 的“幽灵功能”。
44
+
31
45
  ## 模块与 Adapter
32
46
 
33
47
  - `@southwind-ai/modules` 是深 Module:拥有声明类型、依赖排序、引用规则和组合验证,不依赖 Elysia 或 Vue。
@@ -74,19 +74,5 @@ const developmentAuth = developmentAuthStatus();
74
74
  布局和内容,但不应绕过 Router 的 `guestOnly` Guard、首次改密跳转或平台认证
75
75
  composable。
76
76
 
77
- ## 从 0.2.32 升级
78
-
79
- 可直接在现有业务改动上执行:更新不会检查无关工作区改动;若平台变更与同一共享文件
80
- 重叠,计划会报告三方合并冲突:
81
-
82
- ```bash
83
- bunx --bun create-windy@latest update --check --cwd .
84
- bunx --bun create-windy@latest update --dry-run --cwd .
85
- bunx --bun create-windy@latest update --cwd .
86
- bun install
87
- ```
88
-
89
- 计划中应看到 selector 以 `project-owned` 新增,Router 通过三方合并接入 selector。
90
- 若旧业务登录页曾放在 `apps/web/src/pages/auth/LoginPage.vue` 或直接改 Router,应将
91
- 业务 SFC 移到 `apps/web/src/app/auth/`,改 selector 指向它,再恢复受管文件。后续升级
92
- 会保留 selector 和业务 SFC。
77
+ 该 selector 与业务 SFC 属于 project-owned seam。后续 Starter 更新必须保留它们,
78
+ Router 只通过稳定 selector 组合,不把业务登录页重新纳入受管文件。
@@ -124,6 +124,8 @@ Manifest 的 Operation limits 同时包含输入、执行时间和输出上限
124
124
  ```dotenv
125
125
  PLATFORM_ENABLE_AI=true
126
126
  AGENT_SERVER_INTERNAL_TOKEN=<至少 32 字符的随机值>
127
+ ADK_DEBUG_PLATFORM_TOKEN=<create-windy 自动生成的独立随机值>
128
+ AGENT_RUN_ENCRYPTION_SECRET=<至少 32 字符的独立随机值>
127
129
  AI_ARTIFACT_ENCRYPTION_SECRET=<至少 32 字符的随机值>
128
130
  QWEN_API_URL=https://dashscope-intl.aliyuncs.com/compatible-mode/v1
129
131
  QWEN_API_KEY=<服务端密钥>
@@ -145,9 +147,13 @@ AI_PROVIDER_AUDIT_RETENTION_DAYS=90
145
147
  bun run dev:agent
146
148
  ```
147
149
 
148
- `create-windy` 会为新的本地项目同时生成内部 Token 与 Artifact 加密 Secret。已有项目
149
- 升级后必须补齐 `AI_ARTIFACT_ENCRYPTION_SECRET`;它只用于平台签发短时 opaque
150
- ArtifactRef,不得复用 Provider Key。Vision Deployment 需把能力与输入模态显式扩展为
150
+ `create-windy` 会为新的本地项目分别生成内部 Token、ADK 调试 Token、Run Store 加密
151
+ Secret 与 Artifact 加密 Secret,四者不得互相复用。已有项目升级时 updater 只会为
152
+ 普通 `.env` 原子补齐缺失或空的受管 Secret,不覆盖任何非空值;符号链接、重复定义或
153
+ 缺失的 `.env` 会停止自动修复并由 `windy doctor` 报告,避免覆盖外部 Secret Store 或
154
+ 已有部署配置。
155
+ `AI_ARTIFACT_ENCRYPTION_SECRET` 只用于平台签发短时 opaque ArtifactRef,不得复用
156
+ Provider Key。Vision Deployment 需把能力与输入模态显式扩展为
151
157
  `text-generation,vision` 和 `text,image`,详见
152
158
  [Vision AI Runtime](./vision-ai-runtime.md)。Document profile 的配置与调用链见
153
159
  [Document AI Runtime](./document-ai-runtime.md)。
@@ -187,25 +193,62 @@ Agent profile 还必须挂载 `AI_PROVIDER_AUDIT_STORE_PATH`。create-windy Star
187
193
 
188
194
  ## Developer-only ADK Web
189
195
 
190
- ADK Web 使用独立 profile 启动:
196
+ ADK Web 使用独立 profile 调试真实 canonical Run。项目先在 project-owned 的
197
+ `apps/agent-server/project/adk-web-debug.json` 选择一个文本 Operation:
198
+
199
+ ```json
200
+ {
201
+ "schemaVersion": 1,
202
+ "textOperation": {
203
+ "key": "your-module.copilot.global",
204
+ "dataActorId": "user_dev_admin"
205
+ }
206
+ }
207
+ ```
208
+
209
+ 该 v1 接缝只承诺 `{ "question": string } -> { "text": string }`。Operation、Permission、
210
+ Feature、Tool、Scope、Provider Policy 和输入输出 Schema 仍由业务 Module Manifest
211
+ 声明;`dataActorId` 必须是项目当前存在且启用的开发用户,用于复用真实案件成员关系与
212
+ 当前 Scope。Windy 不接受第二份权限、Scope 或 Tool 列表。用户不存在、权限闭包不足、
213
+ Operation 未知或不符合文本契约时明确拒绝,不回退成伪造回答。
214
+
215
+ 一条命令会同时启动 Server、Tool Sandbox、Agent Server 与 ADK Web:
191
216
 
192
217
  ```bash
193
218
  bun run dev:adk-web
194
219
  ```
195
220
 
196
221
  访问地址为 `http://127.0.0.1:8000`。Compose 服务在容器内监听 `0.0.0.0:8000`,
197
- 但端口只发布到宿主机 `127.0.0.1`。普通 `dev`、`agent` profile 和生产 Compose 均不
198
- 包含该服务。
199
-
200
- 该界面明确显示“Windy ADK 开发调试(无业务工具)”,并只加载一个确定性 Agent:
201
-
202
- - 不读取 `QWEN_*`、Provider URL/Secret 或 `AGENT_SERVER_INTERNAL_TOKEN`;
203
- - 不注册业务 Tool,不连接 Tool Host 或业务 Repository;
204
- - 不接收 Actor、Scope 或 Execution Grant;
205
- - 只用于观察 ADK Web、Session 和 Event,不代表真实业务 Operation。
206
-
207
- 真实业务调试必须继续从 canonical Run API 发起并提供 Southwind AI Server 签发的
208
- Execution Grant;不能通过 ADK Web 补造或绕过这条授权链。
222
+ 但端口只发布到宿主机 `127.0.0.1`。启动脚本读取 project-owned JSON,将唯一
223
+ Operation Key 与真实开发数据用户注入 Windy-owned `docker-compose.agent-debug.yml`;
224
+ 普通 `dev`、`agent` profile 和生产 Compose 均不包含该服务或调试身份。
225
+
226
+ 选择 `canonical_debug` 应用后,每条问题由确定性 dispatcher 交给正式
227
+ `POST /api/agent/runs`,再读取 SSE 与最终结果:
228
+
229
+ - `create-windy` 自动生成独立随机 `ADK_DEBUG_PLATFORM_TOKEN`,无需复制登录 Token;
230
+ - Server 只在 `NODE_ENV=development` 且加载调试 Compose Wrapper 时创建专用
231
+ `service_adk_debug` 身份;该 Token 只在 canonical Run 路径生效,不能访问 Foundation、
232
+ Admin 或其它 Server API;即使与普通会话 Token 误碰撞也被视为保留调试凭据,不会
233
+ 回退普通认证;
234
+ - Server 每次从用户目录解析 `dataActorId`,复用该用户当前 Scope 和业务成员 ID;只在
235
+ 用户本身拥有完整权限闭包时,向 Module 投影该真实用户。核心 Run、Token 和审计主体仍
236
+ 是 `service_adk_debug`,不会冒充普通用户会话;
237
+ - 专用身份的权限精确收窄到所选 Operation Permission 与其 `allowedToolKeys` 的
238
+ Permission 闭包,并在 Tool Host 重新解析用户和复核 Scope;不能切换到其它 Operation;
239
+ - ADK Web 容器不读取 `QWEN_*`、Provider Secret、`AGENT_SERVER_INTERNAL_TOKEN`,
240
+ 不连接业务 Repository 或 Tool Host;
241
+ - 正式 Server 仍签发 Actor、Scope 和短时 Execution Grant,Agent Server 仍按
242
+ `allowedToolKeys` 执行并审计;
243
+ - SSE 先于结果持久化结束时,Adapter 最多再等待 60 秒并每 500ms 读取同一个 Run
244
+ 的结果;只重试明确标记为可重试的 `RUN_CONFLICT`,不会重新创建 Run;
245
+ - 事件摘要最多 64 条,单个 SSE frame 最大 64 KiB;流式 `output.delta` 只显示计数,
246
+ 客户端边读边压缩,不先把完整事件流保存在内存。
247
+
248
+ `safe_debug` 仍保留为不接业务的纯 ADK UI smoke。`canonical_debug` 能验证真实数据、
249
+ 模型与 Tool 链,但 ADK Web 显示的是“dispatcher → canonical Run”,不是另一进程内部
250
+ 完整的 Prompt/Agent/Workflow 节点图。完整 workflow replay 需要另行定义版本化调试
251
+ 协议,不能从当前事件摘要推断。
209
252
 
210
253
  ## 客户端协议
211
254
 
@@ -41,9 +41,10 @@ Worker 重启会轮换密钥。Client 在连接中断或密钥轮换竞态时用
41
41
  读取宿主路径或依赖导入时初始化的外部连接。
42
42
 
43
43
  命名 Volume 初始由 root 持有。一次性的 `tool-sandbox-init` 仅挂载该 IPC Volume,
44
- 使用 `CHOWN` capability 将目录交给镜像内固定的 `bun` 用户后退出;它同样无网络、
45
- 无 Secret、只读 RootFS。常驻 Worker 与 Server 随后以相同非 root UID 访问权限为
46
- `0700` 的目录,HMAC 密钥文件权限为 `0600`。
44
+ 使用 `CHOWN` capability 先临时取回目录所有权,收紧为 `0700`,再交给镜像内固定的
45
+ `bun` 用户后退出;这个顺序对首次创建和已由 `bun` 持有的残留 Volume 都是幂等的,
46
+ 无需扩大为 `FOWNER` capability。它同样无网络、无 Secret、只读 RootFS。常驻 Worker
47
+ 与 Server 随后以相同非 root UID 访问该目录,HMAC 密钥文件权限为 `0600`。
47
48
 
48
49
  ## 失败与审计
49
50
 
@@ -97,7 +97,15 @@ Server 会幂等创建默认开发管理员和 `developer` 角色;仅当默认
97
97
  - `WINDY_DB_USER_TOKEN_PREFIX` 只能修改开发直通前缀。
98
98
  - `NODE_ENV=production` 时,上述 Token 与 `user:` 直通无条件关闭,即使环境变量误配置也不会生效。
99
99
 
100
- Web 不提供默认开发 Token。只有 Vite 开发模式同时设置 `VITE_DEV_AUTH_BYPASS=1` 和非空 `VITE_DEV_ADMIN_TOKEN` 时,前端才会携带显式 Bearer Token,并在登录页和应用壳持续显示警告;生产构建无条件忽略这两个变量。完成一次真实密码登录后,当前页面生命周期内会停用开发 Token,后续请求只使用 Cookie。Docker Compose 不再注入默认 `dev-admin-token`。
100
+ Web 不提供默认开发 Token。只有 Vite 开发模式同时设置 `VITE_DEV_AUTH_BYPASS=1` 和非空 `VITE_DEV_ADMIN_TOKEN` 时,前端才会携带显式 Bearer Token,并在登录页和应用壳持续显示警告;生产构建无条件忽略这两个变量。完成一次真实密码登录后,当前页面生命周期内会停用开发 Token,后续请求只使用 Cookie。
101
+
102
+ 选择 Agent 模块的新项目会在本机 `.env` 自动生成独立随机
103
+ `ADK_DEBUG_PLATFORM_TOKEN`。只有 `bun run dev:adk-web` 加载的开发 Compose Wrapper
104
+ 会把它作为 `WINDY_ADK_DEBUG_TOKEN` 注入 Server,并注入 localhost-only ADK Web;它
105
+ 不会复用 `WINDY_DEV_ADMIN_TOKEN`,也不会启用固定 `dev-admin-token` 或 `user:` 直通。
106
+ Server 仅在 canonical Agent Run 路径把它解析成 `service_adk_debug`,权限收敛为项目
107
+ 选择的 Operation 与 allowed Tools 权限闭包。该 Token 不进入 Web、Agent Server、
108
+ Provider 或生产 Compose;非 development Server 即使误配也会拒绝。
101
109
 
102
110
  未配置 `DATABASE_URL` 时不会注册真实登录 API;只允许显式的非生产开发直通,不存在内存生产账号或默认生产密码。
103
111
 
@@ -19,7 +19,7 @@
19
19
  "dev:document": "PLATFORM_ENABLE_AI=true DOCUMENT_SERVER_URL=http://document-server:8090 docker compose --profile agent --profile document up --build",
20
20
  "dev:speech": "PLATFORM_ENABLE_AI=true SPEECH_SERVER_URL=http://speech-server:8091 docker compose --profile agent --profile speech up --build",
21
21
  "dev:embedding": "PLATFORM_ENABLE_AI=true EMBEDDING_SERVER_URL=http://embedding-server:8092 docker compose --profile agent --profile embedding up --build",
22
- "dev:adk-web": "docker compose --profile agent-debug up --build adk-web-debug",
22
+ "dev:adk-web": "bun run scripts/dev-adk-web.ts",
23
23
  "dev:search": "OPENSEARCH_URL=http://opensearch:9200 docker compose --profile search up --build",
24
24
  "dev:license": "bun run --cwd apps/license dev",
25
25
  "dev:license:docker": "docker compose --profile license up license",