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.
- package/README.md +14 -36
- package/dist/cli.js +1534 -3079
- package/package.json +1 -1
- package/template/.windy-template.json +2 -2
- package/template/AGENTS.md +6 -0
- package/template/README.md +5 -10
- 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 +348 -0
- package/template/apps/agent-server/tests/test_adk_debug_result_polling.py +139 -0
- package/template/apps/agent-server/tests/test_adk_web_canonical_debug.py +235 -0
- 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/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/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 +59 -16
- package/template/docs/platform/agent-tool-sandbox.md +4 -3
- package/template/docs/platform/platform-authentication.md +9 -1
- package/template/package.json +1 -1
- 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
|
@@ -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
|
-
|
|
221
|
-
|
|
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 或受控开发网络。它不是生产
|
|
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,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
|
|
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
|
+
- 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
|
|
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
|
|
|
@@ -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",
|