create-windy 0.3.17 → 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.
Files changed (57) hide show
  1. package/README.md +14 -36
  2. package/dist/cli.js +1528 -3078
  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 +315 -0
  13. package/template/apps/agent-server/tests/test_adk_web_canonical_debug.py +235 -0
  14. package/template/apps/server/src/agent/run-debug-authorization.ts +27 -0
  15. package/template/apps/server/src/agent/run-facade-adk-debug.test.ts +56 -0
  16. package/template/apps/server/src/agent/run-facade.test-support.ts +235 -0
  17. package/template/apps/server/src/agent/run-facade.test.ts +8 -244
  18. package/template/apps/server/src/agent/run-facade.ts +23 -48
  19. package/template/apps/server/src/agent/run-operation-registry.ts +51 -0
  20. package/template/apps/server/src/agent/runtime-bootstrap.ts +5 -2
  21. package/template/apps/server/src/agent/tool-audit.ts +3 -0
  22. package/template/apps/server/src/agent/tool-registry.test.ts +29 -0
  23. package/template/apps/server/src/application-services.ts +83 -15
  24. package/template/apps/server/src/guards.ts +16 -0
  25. package/template/apps/server/src/index.ts +23 -20
  26. package/template/apps/server/src/jobs/legacy-adapter.integration.test.ts +0 -1
  27. package/template/apps/server/src/jobs/legacy-adapter.test.ts +6 -0
  28. package/template/apps/server/src/jobs/legacy-service-runtime.ts +18 -0
  29. package/template/apps/server/src/module-host/durable-context-unavailable.test.ts +84 -0
  30. package/template/apps/server/src/module-host/durable-context.test.ts +14 -0
  31. package/template/apps/server/src/module-host/durable-context.ts +17 -15
  32. package/template/apps/server/src/module-host/request-context.test.ts +30 -1
  33. package/template/apps/server/src/module-host/request-context.ts +15 -2
  34. package/template/apps/server/src/module-host/storage-port.ts +1 -1
  35. package/template/apps/server/src/platform-bootstrap.ts +16 -0
  36. package/template/apps/server/src/runtime-adk-debug.test.ts +246 -0
  37. package/template/apps/server/src/runtime-adk-debug.ts +158 -0
  38. package/template/apps/server/src/runtime-request-actor.test.ts +55 -0
  39. package/template/apps/server/src/runtime-request-actor.ts +22 -0
  40. package/template/apps/server/src/runtime.test.ts +3 -0
  41. package/template/apps/server/src/runtime.ts +36 -3
  42. package/template/apps/server/src/scheduler/definitions.test.ts +16 -0
  43. package/template/docker-compose.agent-debug.yml +56 -0
  44. package/template/docker-compose.yml +1 -39
  45. package/template/docs/architecture/ai-runtime.md +14 -5
  46. package/template/docs/architecture/module-manifest-composition.md +14 -0
  47. package/template/docs/development/custom-login-page.md +2 -16
  48. package/template/docs/platform/agent-runtime.md +57 -16
  49. package/template/docs/platform/agent-tool-sandbox.md +4 -3
  50. package/template/docs/platform/platform-authentication.md +9 -1
  51. package/template/package.json +1 -1
  52. package/template/packages/database/drizzle/0043_activate_agent_dependencies.sql +196 -0
  53. package/template/packages/database/drizzle/meta/0043_snapshot.json +8335 -0
  54. package/template/packages/database/drizzle/meta/_journal.json +7 -0
  55. package/template/packages/database/src/schema-notification-delivery.test.ts +15 -6
  56. package/template/packages/database/src/schema-workflow-notification.test.ts +44 -29
  57. package/template/scripts/dev-adk-web.ts +107 -0
@@ -1,17 +1,12 @@
1
1
  import { describe, expect, test } from "bun:test";
2
- import type { ModuleManifest } from "@southwind-ai/modules";
3
- import { featureKey } from "@southwind-ai/shared";
4
- import { buildScopeContext } from "../data-access/context.js";
5
- import { createRequestGuardContext } from "../guards.js";
6
- import { initializeModuleHosts } from "../module-host.js";
7
- import { createServerRuntime } from "../runtime.js";
8
- import { createTestRunAuthorizationStore } from "./run-authorization.test-support.js";
9
- import { FakeAgentRuntime } from "./fake-runtime.test-support.js";
10
- import { AgentRunFacade } from "./run-facade.js";
2
+ import {
3
+ createRunFacadeFixture,
4
+ guardContext,
5
+ } from "./run-facade.test-support.js";
11
6
 
12
7
  describe("Guarded Agent Run facade", () => {
13
8
  test("Guard 后由宿主 Handler 生成计划并签发短时 Grant", async () => {
14
- const fixture = await createFixture();
9
+ const fixture = await createRunFacadeFixture();
15
10
  const created = await fixture.facade.start(
16
11
  "business.answer",
17
12
  { question: "你好", internalCaseId: "case-secret" },
@@ -64,7 +59,7 @@ describe("Guarded Agent Run facade", () => {
64
59
  });
65
60
 
66
61
  test("客户端输入不能覆盖 Operation、Tool 或授权", async () => {
67
- const fixture = await createFixture();
62
+ const fixture = await createRunFacadeFixture();
68
63
  await fixture.facade.start(
69
64
  "business.answer",
70
65
  {
@@ -84,7 +79,7 @@ describe("Guarded Agent Run facade", () => {
84
79
  });
85
80
 
86
81
  test("缺少 Operation 权限时不调用 Handler 或 Runtime", async () => {
87
- const fixture = await createFixture([]);
82
+ const fixture = await createRunFacadeFixture([]);
88
83
  await expect(
89
84
  fixture.facade.start(
90
85
  "business.answer",
@@ -98,7 +93,7 @@ describe("Guarded Agent Run facade", () => {
98
93
  });
99
94
 
100
95
  test("恢复时权限已收回会返回不泄露 Run 存在性的 404", async () => {
101
- const fixture = await createFixture();
96
+ const fixture = await createRunFacadeFixture();
102
97
  await fixture.facade.start(
103
98
  "business.answer",
104
99
  { question: "稍后恢复" },
@@ -115,234 +110,3 @@ describe("Guarded Agent Run facade", () => {
115
110
  });
116
111
  });
117
112
  });
118
-
119
- async function createFixture(
120
- permissionKeys: string[] = ["business.ai.execute", "business.records.read"],
121
- ) {
122
- const module = manifest();
123
- const prepared: unknown[] = [];
124
- const hosts = await initializeModuleHosts({
125
- modules: [module],
126
- installations: [
127
- {
128
- manifest: module,
129
- setup(host) {
130
- host.registerAiOperationHandlers([
131
- {
132
- operationKey: "business.answer",
133
- release: {
134
- workflowVersion: "workflow-2",
135
- promptVersion: "prompt-3",
136
- routeVersion: "route-4",
137
- },
138
- prepare(input, context) {
139
- prepared.push({ input, actorId: context.actor.id });
140
- const question =
141
- typeof input === "object" &&
142
- input !== null &&
143
- !Array.isArray(input) &&
144
- typeof input.question === "string"
145
- ? input.question
146
- : "";
147
- return {
148
- instructions: "只回答当前业务问题。",
149
- userPrompt: question,
150
- };
151
- },
152
- },
153
- ]);
154
- },
155
- },
156
- ],
157
- });
158
- const runtime = createServerRuntime(
159
- {},
160
- {
161
- featureCatalog: module.features,
162
- licenseResolver: { resolve: () => ({ status: "valid" }) },
163
- },
164
- );
165
- const context = guardContext(permissionKeys);
166
- const remote = new FakeAgentRuntime();
167
- const facade = new AgentRunFacade(
168
- [module],
169
- hosts,
170
- runtime,
171
- remote,
172
- createTestRunAuthorizationStore(),
173
- );
174
- return { context, facade, prepared, remote, runtime };
175
- }
176
-
177
- function guardContext(permissionKeys: string[]) {
178
- return createRequestGuardContext(
179
- new Request("http://localhost/api/agent/runs"),
180
- {
181
- resolveActor: () => ({
182
- id: "actor-1",
183
- type: "user",
184
- name: "测试用户",
185
- roleCodes: ["user"],
186
- permissionKeys,
187
- scopeContext: buildScopeContext("actor-1", undefined, [
188
- {
189
- id: "role-user",
190
- code: "user",
191
- dataScope: "self",
192
- departmentIds: [],
193
- },
194
- ]),
195
- }),
196
- resolveLicense: () => ({ status: "valid" }),
197
- },
198
- );
199
- }
200
-
201
- function manifest(): ModuleManifest {
202
- return {
203
- name: "business",
204
- version: "0.1.0",
205
- label: "业务",
206
- description: "业务",
207
- menus: [],
208
- adminRoutes: [],
209
- permissions: [
210
- permission("business.ai.execute", "ai", "manage"),
211
- permission("business.records.read", "records", "read"),
212
- ],
213
- apiPermissions: [],
214
- features: [
215
- enabledFeature("business.ai"),
216
- enabledFeature("business.records"),
217
- ],
218
- migrations: [],
219
- schemaExports: [],
220
- jsonSchemas: [
221
- {
222
- key: "business.records.input.v1",
223
- schema: { type: "object" },
224
- },
225
- {
226
- key: "business.records.output.v1",
227
- schema: { type: "object" },
228
- },
229
- {
230
- key: "business.input.v1",
231
- schema: { type: "object" },
232
- },
233
- {
234
- key: "business.output.v1",
235
- schema: { type: "object" },
236
- },
237
- ],
238
- tasks: [],
239
- tools: [
240
- {
241
- key: "business.records.list",
242
- label: "查询记录",
243
- description: "查询当前范围记录。",
244
- inputSchemaKey: "business.records.input.v1",
245
- outputSchemaKey: "business.records.output.v1",
246
- operation: "query",
247
- permissionKey: "business.records.read",
248
- featureKey: "business.records",
249
- auditAction: "business.records.read",
250
- scopeMode: "request",
251
- dataClassification: "internal",
252
- idempotency: "none",
253
- approval: "none",
254
- limits: {
255
- maxDurationSeconds: 10,
256
- maxInputBytes: 4096,
257
- maxOutputBytes: 4096,
258
- },
259
- },
260
- ],
261
- aiOperations: [
262
- {
263
- key: "business.answer",
264
- kind: "agent",
265
- featureKey: "business.ai",
266
- permissionKey: "business.ai.execute",
267
- auditAction: "business.ai.execute",
268
- inputSchemaKey: "business.input.v1",
269
- outputSchemaKey: "business.output.v1",
270
- requiredCapabilities: ["text-generation"],
271
- allowedToolKeys: ["business.records.list"],
272
- dataClassification: "internal",
273
- execution: "streaming",
274
- providerEgress: {
275
- mode: "configured-endpoint",
276
- deploymentKey: "ai.openai-compatible",
277
- },
278
- providerDataPolicy: {
279
- inputFields: [
280
- {
281
- jsonPointer: "/question",
282
- classification: "internal",
283
- dlpAction: "redact",
284
- },
285
- ],
286
- envelopeFields: [
287
- {
288
- field: "instructions",
289
- classification: "internal",
290
- dlpAction: "reject",
291
- },
292
- {
293
- field: "user-prompt",
294
- classification: "internal",
295
- dlpAction: "redact",
296
- },
297
- {
298
- field: "tool-definitions",
299
- classification: "internal",
300
- dlpAction: "reject",
301
- },
302
- {
303
- field: "provider-output",
304
- classification: "internal",
305
- dlpAction: "redact",
306
- },
307
- {
308
- field: "tool-results",
309
- classification: "sensitive",
310
- dlpAction: "redact",
311
- },
312
- ],
313
- },
314
- toolNetworkPolicy: { mode: "forbidden" },
315
- limits: {
316
- maxDurationSeconds: 60,
317
- maxInputBytes: 4096,
318
- maxOutputBytes: 4096,
319
- },
320
- },
321
- ],
322
- providers: [],
323
- auditActions: ["business.ai.execute", "business.records.read"],
324
- };
325
- }
326
-
327
- function permission(key: string, resource: string, action: "read" | "manage") {
328
- return {
329
- key,
330
- label: key,
331
- module: "business",
332
- moduleLabel: "业务",
333
- resource,
334
- resourceLabel: resource,
335
- action,
336
- };
337
- }
338
-
339
- function enabledFeature(key: string) {
340
- return {
341
- key: featureKey(key),
342
- label: key,
343
- module: "business",
344
- visible: "visible" as const,
345
- enabled: true,
346
- stage: "stable" as const,
347
- };
348
- }
@@ -1,8 +1,5 @@
1
1
  import { randomUUIDv7 } from "bun";
2
- import type {
3
- ModuleAiOperationDefinition,
4
- ModuleManifest,
5
- } from "@southwind-ai/modules";
2
+ import type { ModuleManifest } from "@southwind-ai/modules";
6
3
  import {
7
4
  resolveProviderEgress,
8
5
  resolveToolNetworkPolicy,
@@ -10,14 +7,12 @@ import {
10
7
  import type {
11
8
  ModuleAiArtifactRef,
12
9
  ModuleAiJsonValue,
13
- ModuleAiOperationHandlerRegistration,
14
10
  } from "@southwind-ai/server-sdk";
15
11
  import { evaluateAccessGuards } from "../access-guards.js";
16
12
  import { auditActor, type RequestGuardContext } from "../guards.js";
17
13
  import type { InitializedModuleHosts } from "../module-host.js";
18
14
  import { toModuleActor } from "../module-host.js";
19
15
  import type { createServerRuntime } from "../runtime.js";
20
- import { findFeature } from "../route-guards.js";
21
16
  import type { AiArtifactRuntime } from "../ai-artifact/runtime.js";
22
17
  import {
23
18
  AgentRunAuthorizationError,
@@ -26,12 +21,10 @@ import {
26
21
  } from "./run-authorization.js";
27
22
  import type {
28
23
  AgentRuntimePort,
29
- AgentRuntimeOperation,
30
24
  AgentRuntimeStartResponse,
31
25
  AgentRuntimeStatusResponse,
32
26
  } from "./run-contracts.js";
33
27
  import { AgentRuntimeError } from "./run-contracts.js";
34
- import { buildAgentRuntimeRelease } from "./run-release.js";
35
28
  import {
36
29
  governProviderInput,
37
30
  ProviderInputGovernanceError,
@@ -42,10 +35,17 @@ import {
42
35
  digest,
43
36
  publicRunPath,
44
37
  runtimeErrorStatus,
45
- toolDefinitions,
46
38
  } from "./run-definition-support.js";
47
39
  import { AgentRunFacadeError, inaccessibleRun } from "./run-errors.js";
48
40
  import { scopedRuntimeIdempotencyKey } from "./idempotency-key.js";
41
+ import {
42
+ assertSelectedDebugOperation,
43
+ debugActorAuditMetadata,
44
+ } from "./run-debug-authorization.js";
45
+ import {
46
+ buildRegisteredOperations,
47
+ type RegisteredOperation,
48
+ } from "./run-operation-registry.js";
49
49
  export { AgentRunFacadeError } from "./run-errors.js";
50
50
 
51
51
  type ServerRuntime = ReturnType<typeof createServerRuntime>;
@@ -61,36 +61,7 @@ export class AgentRunFacade {
61
61
  private readonly authorizations: AgentRunAuthorizationStore,
62
62
  private readonly artifacts?: AiArtifactRuntime,
63
63
  ) {
64
- const handlers = new Map(
65
- hosts.aiOperationHandlers.map(({ registration, moduleName }) => [
66
- registration.operationKey,
67
- { registration, moduleName },
68
- ]),
69
- );
70
- const features = modules.flatMap(({ features }) => features);
71
- this.#operations = new Map(
72
- modules.flatMap((module) =>
73
- (module.aiOperations ?? []).map((definition) => {
74
- const handler = handlers.get(definition.key);
75
- const tools = toolDefinitions(modules, definition.allowedToolKeys);
76
- return [
77
- definition.key,
78
- {
79
- definition,
80
- ...handler,
81
- feature: findFeature(features, definition.featureKey),
82
- tools,
83
- release: buildAgentRuntimeRelease(
84
- modules,
85
- module,
86
- definition,
87
- handler?.registration,
88
- ),
89
- },
90
- ] as const;
91
- }),
92
- ),
93
- );
64
+ this.#operations = buildRegisteredOperations(modules, hosts);
94
65
  }
95
66
 
96
67
  async start(
@@ -101,6 +72,12 @@ export class AgentRunFacade {
101
72
  artifacts: readonly ModuleAiArtifactRef[] = [],
102
73
  signal: AbortSignal = AbortSignal.timeout(10_000),
103
74
  ): Promise<AgentRuntimeStartResponse> {
75
+ assertSelectedDebugOperation(
76
+ this.runtime,
77
+ context.actor.id,
78
+ operationKey,
79
+ "forbidden",
80
+ );
104
81
  const operation = this.#operations.get(operationKey);
105
82
  if (
106
83
  !operation?.registration?.prepare ||
@@ -237,6 +214,7 @@ export class AgentRunFacade {
237
214
  },
238
215
  requestId: context.requestId,
239
216
  metadata: {
217
+ ...debugActorAuditMetadata(context.actor),
240
218
  artifactCount: rotatedArtifacts.length,
241
219
  artifactBytes: rotatedArtifacts.reduce(
242
220
  (total, artifact) => total + artifact.byteSize,
@@ -278,6 +256,12 @@ export class AgentRunFacade {
278
256
  runId: string,
279
257
  context: RequestGuardContext,
280
258
  ) {
259
+ assertSelectedDebugOperation(
260
+ this.runtime,
261
+ context.actor.id,
262
+ operationKey,
263
+ "hidden",
264
+ );
281
265
  const operation = this.#operations.get(operationKey);
282
266
  if (!operation || operation.definition.kind !== "agent") {
283
267
  throw inaccessibleRun();
@@ -334,12 +318,3 @@ export class AgentRunFacade {
334
318
  };
335
319
  }
336
320
  }
337
-
338
- interface RegisteredOperation {
339
- definition: ModuleAiOperationDefinition;
340
- registration?: ModuleAiOperationHandlerRegistration;
341
- moduleName?: string;
342
- feature: ReturnType<typeof findFeature>;
343
- tools: AgentRuntimeOperation["allowedTools"];
344
- release: AgentRuntimeOperation["release"];
345
- }
@@ -0,0 +1,51 @@
1
+ import type { ModuleManifest } from "@southwind-ai/modules";
2
+ import type { AgentRuntimeOperation } from "./run-contracts.js";
3
+ import type { ModuleAiOperationHandlerRegistration } from "@southwind-ai/server-sdk";
4
+ import type { InitializedModuleHosts } from "../module-host.js";
5
+ import { findFeature } from "../route-guards.js";
6
+ import { toolDefinitions } from "./run-definition-support.js";
7
+ import { buildAgentRuntimeRelease } from "./run-release.js";
8
+
9
+ export interface RegisteredOperation {
10
+ definition: NonNullable<ModuleManifest["aiOperations"]>[number];
11
+ registration?: ModuleAiOperationHandlerRegistration;
12
+ moduleName?: string;
13
+ feature: ReturnType<typeof findFeature>;
14
+ tools: AgentRuntimeOperation["allowedTools"];
15
+ release: AgentRuntimeOperation["release"];
16
+ }
17
+
18
+ export function buildRegisteredOperations(
19
+ modules: readonly ModuleManifest[],
20
+ hosts: InitializedModuleHosts,
21
+ ): Map<string, RegisteredOperation> {
22
+ const handlers = new Map(
23
+ hosts.aiOperationHandlers.map(({ registration, moduleName }) => [
24
+ registration.operationKey,
25
+ { registration, moduleName },
26
+ ]),
27
+ );
28
+ const features = modules.flatMap(({ features }) => features);
29
+ return new Map(
30
+ modules.flatMap((module) =>
31
+ (module.aiOperations ?? []).map((definition) => {
32
+ const handler = handlers.get(definition.key);
33
+ return [
34
+ definition.key,
35
+ {
36
+ definition,
37
+ ...handler,
38
+ feature: findFeature(features, definition.featureKey),
39
+ tools: toolDefinitions(modules, definition.allowedToolKeys),
40
+ release: buildAgentRuntimeRelease(
41
+ modules,
42
+ module,
43
+ definition,
44
+ handler?.registration,
45
+ ),
46
+ },
47
+ ] as const;
48
+ }),
49
+ ),
50
+ );
51
+ }
@@ -60,6 +60,9 @@ export function registerAgentPlatformRuntime(input: {
60
60
  backgroundAi: DeferredAgentBackgroundOperationPortFactory;
61
61
  }) {
62
62
  const features = input.modules.flatMap(({ features }) => features);
63
+ const resolveAgentActor = async (actorId: string) =>
64
+ (await input.runtime.resolveEphemeralActor(actorId)) ??
65
+ (await resolveCurrentSystemActor(input.systemRepositories, actorId));
63
66
  const toolHandlers = new Map([
64
67
  ...createSystemToolHandlers(input.systemRepositories, input.runtime),
65
68
  ...createModuleToolHandlerMap(input.hosts, {
@@ -95,7 +98,7 @@ export function registerAgentPlatformRuntime(input: {
95
98
  input.runtime,
96
99
  features,
97
100
  input.storage,
98
- (actorId) => resolveCurrentSystemActor(input.systemRepositories, actorId),
101
+ resolveAgentActor,
99
102
  );
100
103
  registerAiArtifactRoutes(input.app, aiArtifacts, internalToken);
101
104
  const remote = new RemoteAgentRuntime({
@@ -173,7 +176,7 @@ export function registerAgentPlatformRuntime(input: {
173
176
  input.runtime,
174
177
  runAuthorizations,
175
178
  input.workflow,
176
- (actorId) => resolveCurrentSystemActor(input.systemRepositories, actorId),
179
+ resolveAgentActor,
177
180
  ),
178
181
  internalToken,
179
182
  );
@@ -4,6 +4,7 @@ import type {
4
4
  } from "@southwind-ai/server-sdk";
5
5
  import type { AuditEvent } from "@southwind-ai/shared";
6
6
  import { auditActor, type RequestGuardContext } from "../guards.js";
7
+ import { debugActorAuditMetadata } from "./run-debug-authorization.js";
7
8
  import type { RegisteredTool } from "./tool-registry.js";
8
9
 
9
10
  export function toolJsonBytes(value: ModuleToolInput | ModuleToolResult) {
@@ -26,6 +27,7 @@ export function toolEvent(
26
27
  module: tool.module,
27
28
  requestId: context.requestId,
28
29
  metadata: {
30
+ ...debugActorAuditMetadata(context.actor),
29
31
  inputBytes: toolJsonBytes(input),
30
32
  outputBytes: toolJsonBytes(result),
31
33
  executionMode,
@@ -53,6 +55,7 @@ export function sandboxFailureEvent(
53
55
  module: tool.module,
54
56
  requestId: context.requestId,
55
57
  metadata: {
58
+ ...debugActorAuditMetadata(context.actor),
56
59
  inputBytes: toolJsonBytes(input),
57
60
  executionMode: "sandbox",
58
61
  failureKind: policyDenied ? "policy-denied" : "business-failure",
@@ -1,6 +1,7 @@
1
1
  import { describe, expect, test } from "bun:test";
2
2
  import type { ModuleToolHandlers } from "./tool-registry.js";
3
3
  import { createFoundationSnapshot, loadSystemModules } from "../foundation.js";
4
+ import { bindModuleUserProjection } from "../guards.js";
4
5
  import { createServerRuntime } from "../runtime.js";
5
6
  import { createSystemRepositories } from "../system/seed.js";
6
7
  import { createSystemToolHandlers } from "./routes.js";
@@ -92,6 +93,34 @@ describe("Governed Tool Registry", () => {
92
93
  });
93
94
  expect(JSON.stringify(event)).not.toContain("permissionKeys");
94
95
  });
96
+
97
+ test("调试 Tool 审计保留服务主体并标注真实数据用户", async () => {
98
+ const fixture = await createFixture();
99
+ fixture.context.actor = bindModuleUserProjection(
100
+ {
101
+ ...fixture.context.actor,
102
+ id: "service_adk_debug",
103
+ type: "service",
104
+ name: "ADK 开发调试",
105
+ },
106
+ "user_dev_admin",
107
+ );
108
+
109
+ await fixture.registry.execute(
110
+ "system.features.list",
111
+ { page: 1 },
112
+ fixture.context,
113
+ );
114
+
115
+ const event = fixture.runtime.auditSink.list().at(-1);
116
+ expect(event?.actor).toMatchObject({
117
+ id: "service_adk_debug",
118
+ type: "service",
119
+ });
120
+ expect(event?.metadata).toMatchObject({
121
+ debugDataActorId: "user_dev_admin",
122
+ });
123
+ });
95
124
  });
96
125
 
97
126
  async function createFixture() {