create-windy 0.3.16 → 0.3.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -36
- package/dist/cli.js +1831 -3178
- package/package.json +1 -1
- package/template/.windy-template.json +2 -2
- package/template/AGENTS.md +7 -1
- package/template/README.md +8 -11
- package/template/apps/agent-server/Dockerfile +2 -1
- package/template/apps/agent-server/README.md +13 -5
- package/template/apps/agent-server/adk_web_agents/canonical_debug/__init__.py +1 -0
- package/template/apps/agent-server/adk_web_agents/canonical_debug/agent.py +125 -0
- package/template/apps/agent-server/project/adk-web-debug.json +4 -0
- package/template/apps/agent-server/src/southwind_agent_server/adk_debug.py +315 -0
- package/template/apps/agent-server/tests/test_adk_web_canonical_debug.py +235 -0
- package/template/apps/server/Dockerfile +1 -1
- package/template/apps/server/src/agent/run-debug-authorization.ts +27 -0
- package/template/apps/server/src/agent/run-facade-adk-debug.test.ts +56 -0
- package/template/apps/server/src/agent/run-facade.test-support.ts +235 -0
- package/template/apps/server/src/agent/run-facade.test.ts +8 -244
- package/template/apps/server/src/agent/run-facade.ts +23 -48
- package/template/apps/server/src/agent/run-operation-registry.ts +51 -0
- package/template/apps/server/src/agent/runtime-bootstrap.ts +5 -2
- package/template/apps/server/src/agent/tool-audit.ts +3 -0
- package/template/apps/server/src/agent/tool-registry.test.ts +29 -0
- package/template/apps/server/src/application-services.ts +83 -15
- package/template/apps/server/src/audit/contracts.ts +8 -0
- package/template/apps/server/src/audit/recovery-queue.test.ts +48 -1
- package/template/apps/server/src/audit/recovery-queue.ts +73 -4
- package/template/apps/server/src/audit/reliable-writer.test.ts +120 -2
- package/template/apps/server/src/audit/reliable-writer.ts +98 -34
- package/template/apps/server/src/guards.ts +16 -0
- package/template/apps/server/src/index.ts +23 -20
- package/template/apps/server/src/jobs/legacy-adapter.integration.test.ts +0 -1
- package/template/apps/server/src/jobs/legacy-adapter.test.ts +6 -0
- package/template/apps/server/src/jobs/legacy-service-runtime.ts +18 -0
- package/template/apps/server/src/module-host/durable-context-unavailable.test.ts +84 -0
- package/template/apps/server/src/module-host/durable-context.test.ts +14 -0
- package/template/apps/server/src/module-host/durable-context.ts +17 -15
- package/template/apps/server/src/module-host/request-context.test.ts +30 -1
- package/template/apps/server/src/module-host/request-context.ts +15 -2
- package/template/apps/server/src/module-host/storage-port.ts +1 -1
- package/template/apps/server/src/platform-bootstrap.ts +16 -0
- package/template/apps/server/src/runtime-adk-debug.test.ts +246 -0
- package/template/apps/server/src/runtime-adk-debug.ts +158 -0
- package/template/apps/server/src/runtime-request-actor.test.ts +55 -0
- package/template/apps/server/src/runtime-request-actor.ts +22 -0
- package/template/apps/server/src/runtime.test.ts +3 -0
- package/template/apps/server/src/runtime.ts +36 -3
- package/template/apps/server/src/scheduler/definitions.test.ts +16 -0
- package/template/apps/web/Dockerfile +1 -1
- package/template/docker-compose.agent-debug.yml +56 -0
- package/template/docker-compose.yml +1 -39
- package/template/docs/architecture/ai-runtime.md +14 -5
- package/template/docs/architecture/module-manifest-composition.md +14 -0
- package/template/docs/development/custom-login-page.md +2 -16
- package/template/docs/platform/agent-runtime.md +57 -16
- package/template/docs/platform/agent-tool-sandbox.md +4 -3
- package/template/docs/platform/audit-reliability.md +33 -5
- package/template/docs/platform/platform-authentication.md +9 -1
- package/template/package.json +4 -3
- package/template/packages/database/drizzle/0043_activate_agent_dependencies.sql +196 -0
- package/template/packages/database/drizzle/meta/0043_snapshot.json +8335 -0
- package/template/packages/database/drizzle/meta/_journal.json +7 -0
- package/template/packages/database/src/schema-notification-delivery.test.ts +15 -6
- package/template/packages/database/src/schema-workflow-notification.test.ts +44 -29
- package/template/scripts/dev-adk-web.ts +107 -0
|
@@ -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
|
});
|
|
@@ -22,7 +22,7 @@ COPY packages/server-sdk/package.json packages/server-sdk/package.json
|
|
|
22
22
|
COPY packages/shared/package.json packages/shared/package.json
|
|
23
23
|
COPY packages/storage/package.json packages/storage/package.json
|
|
24
24
|
# windy-copy:deps end
|
|
25
|
-
RUN bun install
|
|
25
|
+
RUN --mount=type=cache,id=windy-bun-1.3.14,target=/root/.bun/install/cache,sharing=shared bun -e 'const child=Bun.spawn(["bun","install","--frozen-lockfile","--no-progress"],{stdin:"inherit",stdout:"inherit",stderr:"inherit"});const heartbeat=setInterval(()=>console.log("[windy] Bun 依赖安装仍在进行"),15000);const exitCode=await child.exited;clearInterval(heartbeat);process.exit(exitCode)'
|
|
26
26
|
|
|
27
27
|
FROM deps AS build
|
|
28
28
|
# windy-copy:build begin
|
|
@@ -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 或受控开发网络。它不是生产
|
|
657
|
+
ADK Web 只在 developer profile 启动,绑定 localhost 或受控开发网络。它不是生产
|
|
658
|
+
Prompt 管理或生产 Debug 控制面。
|
|
658
659
|
|
|
659
660
|
当前 Compose 使用独立 `agent-debug` profile,宿主机只发布
|
|
660
|
-
`127.0.0.1:8000
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
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
|
-
|
|
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`
|
|
149
|
-
|
|
150
|
-
|
|
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,60 @@ 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
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
-
|
|
205
|
-
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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
|
+
- 事件摘要最多 64 条,单个 SSE frame 最大 64 KiB;流式 `output.delta` 只显示计数,
|
|
244
|
+
客户端边读边压缩,不先把完整事件流保存在内存。
|
|
245
|
+
|
|
246
|
+
`safe_debug` 仍保留为不接业务的纯 ADK UI smoke。`canonical_debug` 能验证真实数据、
|
|
247
|
+
模型与 Tool 链,但 ADK Web 显示的是“dispatcher → canonical Run”,不是另一进程内部
|
|
248
|
+
完整的 Prompt/Agent/Workflow 节点图。完整 workflow replay 需要另行定义版本化调试
|
|
249
|
+
协议,不能从当前事件摘要推断。
|
|
209
250
|
|
|
210
251
|
## 客户端协议
|
|
211
252
|
|
|
@@ -41,9 +41,10 @@ Worker 重启会轮换密钥。Client 在连接中断或密钥轮换竞态时用
|
|
|
41
41
|
读取宿主路径或依赖导入时初始化的外部连接。
|
|
42
42
|
|
|
43
43
|
命名 Volume 初始由 root 持有。一次性的 `tool-sandbox-init` 仅挂载该 IPC Volume,
|
|
44
|
-
使用 `CHOWN` capability
|
|
45
|
-
|
|
46
|
-
`
|
|
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
|
|
|
@@ -79,9 +79,19 @@ License 上传仍只记录候选摘要、可识别的 License ID、公钥 ID 和
|
|
|
79
79
|
2. Server 启动、以及后续任一审计写入恢复成功时,会顺序重放队列。
|
|
80
80
|
3. PostgreSQL 以事件 ID 幂等插入,连接超时后即使数据库实际已提交,重放也不会生成重复事件。
|
|
81
81
|
4. 只有成功持久化的前缀会从队列移除;首次失败事件及其后续事件继续保留。
|
|
82
|
+
5. 启动读取队列遇到权限、JSON 格式或其它文件 I/O 错误时,Server 仍以审计
|
|
83
|
+
`degraded` 状态启动并告警,不让审计恢复文件阻断全部无关业务。
|
|
84
|
+
未知 `formatVersion`、缺失或非数组 `events`、损坏的事件结构都属于格式错误;
|
|
85
|
+
平台不会把它们静默解释为空队列。
|
|
86
|
+
6. 恢复故障只有在队列重新成功读取、且非空队列成功原子改写后才清除;单次普通审计
|
|
87
|
+
成功写入 PostgreSQL 不能把仍不可读的恢复队列误报为健康。
|
|
82
88
|
|
|
83
89
|
恢复文件所在目录必须挂载到持久卷,并只允许 Server 运行账号访问。不要把它放到容器临时层、共享静态目录或备份公开目录。
|
|
84
90
|
|
|
91
|
+
启动降级不改变两类写入策略:普通请求继续按 best-effort 审计语义执行;关键动作优先
|
|
92
|
+
写 PostgreSQL,主库持续失败时再写恢复队列。只有主库与恢复队列同时不可用时,关键
|
|
93
|
+
动作仍然 fail closed,不会因为 Server 已监听端口而降级放行。
|
|
94
|
+
|
|
85
95
|
## 可观测状态
|
|
86
96
|
|
|
87
97
|
`GET /api/health` 的 `audit` 字段返回非敏感运行状态:
|
|
@@ -97,7 +107,9 @@ License 上传仍只记录候选摘要、可识别的 License ID、公钥 ID 和
|
|
|
97
107
|
"dropped": 1,
|
|
98
108
|
"lastFailureAt": "2026-07-10T08:00:00.000Z",
|
|
99
109
|
"lastSuccessAt": "2026-07-10T07:59:00.000Z",
|
|
100
|
-
"
|
|
110
|
+
"recoveryFailure": "permission-denied",
|
|
111
|
+
"lastRecoveryFailureAt": "2026-07-10T08:00:01.000Z",
|
|
112
|
+
"alert": "关键审计恢复队列不可用:文件权限不足"
|
|
101
113
|
}
|
|
102
114
|
```
|
|
103
115
|
|
|
@@ -105,6 +117,10 @@ License 上传仍只记录候选摘要、可识别的 License ID、公钥 ID 和
|
|
|
105
117
|
- `retries` 是已经执行的重试次数。
|
|
106
118
|
- `queued` 是当前仍待恢复的关键事件数。
|
|
107
119
|
- `dropped` 是 PostgreSQL 持续失败后未进入持久队列的普通事件数。
|
|
120
|
+
- `recoveryFailure` 是不包含路径或事件正文的稳定故障分类:
|
|
121
|
+
`permission-denied`、`invalid-format`、`io-error` 或 `unknown`。
|
|
122
|
+
- `lastRecoveryFailureAt` 是最近一次恢复队列操作失败的时间;队列不可读时
|
|
123
|
+
`queued=0` 只代表没有已知计数,不能解释为文件内没有待恢复事件。
|
|
108
124
|
- `state=degraded` 或 `queued/dropped > 0` 应触发运维告警。
|
|
109
125
|
|
|
110
126
|
进入降级状态时 Server 同时写入结构化 error 日志,日志只包含上述状态,不包含事件正文。
|
|
@@ -130,10 +146,22 @@ License 上传仍只记录候选摘要、可识别的 License ID、公钥 ID 和
|
|
|
130
146
|
|
|
131
147
|
1. 检查 `/api/health` 的 `audit` 状态和 Server 的“审计持久化进入降级状态”日志。
|
|
132
148
|
2. 检查 PostgreSQL 连接、连接池容量、`audit_logs` 表和磁盘容量。
|
|
133
|
-
3.
|
|
134
|
-
|
|
135
|
-
|
|
149
|
+
3. 对恢复文件或持久卷先做只读备份或卷快照,再进行权限和内容处置。平台不会自动
|
|
150
|
+
丢弃、清空或覆盖不可读、格式损坏的队列,因为其中可能包含尚未落库的关键事件。
|
|
151
|
+
4. `permission-denied` 时把目录和文件所有权恢复为 Server 运行账号,保持文件
|
|
152
|
+
`0600`、目录不对其它账号开放;不要用全局可写权限绕过问题。
|
|
153
|
+
5. `invalid-format` 时保留原始备份,把损坏文件人工隔离到 Server 不会继续写入的位置,
|
|
154
|
+
离线核对可恢复事件后再修复或重建有效队列。未经审阅不要直接截断文件或创建空文件
|
|
155
|
+
覆盖原内容。
|
|
156
|
+
6. `io-error` 时检查挂载、只读文件系统、磁盘容量和底层存储健康;修复后执行一个普通
|
|
157
|
+
的已审计请求触发恢复,也可以重启 Server 在启动阶段恢复。
|
|
158
|
+
7. 只有 `recoveryFailure` 已清除、`queued=0` 且状态恢复为 `healthy` 后才解除告警。
|
|
159
|
+
`dropped` 是累计计数,不会自动归零,应结合故障窗口内的进程内事件和业务日志进行
|
|
160
|
+
人工补查。
|
|
136
161
|
|
|
137
162
|
## 验证覆盖
|
|
138
163
|
|
|
139
|
-
|
|
164
|
+
自动测试覆盖瞬时故障后成功、退避上限、普通事件持续失败、关键事件入队、数据库恢复
|
|
165
|
+
重放、启动读取权限错误和损坏 JSON 后降级、普通写入不得误清恢复故障、数据库与队列
|
|
166
|
+
同时失败、队列内容深层脱敏、License 损坏文件恢复上传入队,以及 PostgreSQL 事件 ID
|
|
167
|
+
幂等重放。真实 PostgreSQL 集成测试使用 `AUDIT_TEST_DATABASE_URL` 显式启用。
|
|
@@ -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。
|
|
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
|
|
package/template/package.json
CHANGED
|
@@ -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": "
|
|
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",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"ops:db": "bun run scripts/production-database.ts",
|
|
51
51
|
"ops:release": "bun run scripts/production-release.ts",
|
|
52
52
|
"test:merge": "bun run scripts/merge-gate.ts",
|
|
53
|
-
"release:verify": "bun run scripts/release-verify.ts",
|
|
53
|
+
"release:verify": "bun run scripts/release-verify.ts --full",
|
|
54
54
|
"release:candidate": "bun run scripts/release-candidate.ts",
|
|
55
55
|
"release:verify:full": "bun run scripts/release-verify.ts --full",
|
|
56
56
|
"test:packages:pack": "bun run scripts/platform-package-release.ts",
|
|
@@ -70,7 +70,8 @@
|
|
|
70
70
|
"test": "bun test --path-ignore-patterns='packages/create-windy/template/**' && bun run --cwd apps/web test"
|
|
71
71
|
},
|
|
72
72
|
"lint-staged": {
|
|
73
|
-
"*.{
|
|
73
|
+
"*.{css,html,json,jsonc,less,md,mdx,scss,yaml,yml}": "oxfmt --write",
|
|
74
|
+
"*.{cjs,cts,js,jsx,mjs,mts,ts,tsx,vue}": [
|
|
74
75
|
"oxfmt --write",
|
|
75
76
|
"oxlint"
|
|
76
77
|
]
|