create-windy 0.6.14 → 0.6.16

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 (162) hide show
  1. package/dist/cli.js +1008 -61
  2. package/package.json +1 -1
  3. package/template/.agents/skills/windy-business-module/SKILL.md +58 -8
  4. package/template/.windy-template.json +2 -2
  5. package/template/apps/server/src/agent/client-session/attempt-authority.test.ts +162 -0
  6. package/template/apps/server/src/agent/client-session/attempt-authority.ts +191 -0
  7. package/template/apps/server/src/agent/client-session/bootstrap.ts +27 -11
  8. package/template/apps/server/src/agent/client-session/completion.ts +75 -24
  9. package/template/apps/server/src/agent/client-session/contracts.ts +23 -0
  10. package/template/apps/server/src/agent/client-session/creation.ts +103 -0
  11. package/template/apps/server/src/agent/client-session/digest.ts +11 -1
  12. package/template/apps/server/src/agent/client-session/drizzle-records.ts +150 -0
  13. package/template/apps/server/src/agent/client-session/drizzle-repository.integration.test.ts +30 -3
  14. package/template/apps/server/src/agent/client-session/drizzle-repository.ts +23 -132
  15. package/template/apps/server/src/agent/client-session/finalization.ts +99 -0
  16. package/template/apps/server/src/agent/client-session/host-auth.ts +22 -10
  17. package/template/apps/server/src/agent/client-session/host-revocation-composition.test.ts +77 -0
  18. package/template/apps/server/src/agent/client-session/host-revocation-composition.ts +28 -0
  19. package/template/apps/server/src/agent/client-session/launch-authority.contract.test.ts +21 -0
  20. package/template/apps/server/src/agent/client-session/manifest-admission.ts +11 -0
  21. package/template/apps/server/src/agent/client-session/service.test-support.ts +22 -0
  22. package/template/apps/server/src/agent/client-session/service.ts +104 -134
  23. package/template/apps/server/src/agent/client-session/terminal-digest.test.ts +23 -0
  24. package/template/apps/server/src/agent/client-workflow-artifact/active-blob-references.ts +8 -0
  25. package/template/apps/server/src/agent/client-workflow-artifact/artifact-builder.ts +60 -0
  26. package/template/apps/server/src/agent/client-workflow-artifact/authority-current.ts +59 -0
  27. package/template/apps/server/src/agent/client-workflow-artifact/binding-registry.test.ts +189 -0
  28. package/template/apps/server/src/agent/client-workflow-artifact/binding-registry.ts +153 -0
  29. package/template/apps/server/src/agent/client-workflow-artifact/bootstrap.ts +77 -0
  30. package/template/apps/server/src/agent/client-workflow-artifact/cancellation.ts +47 -0
  31. package/template/apps/server/src/agent/client-workflow-artifact/completed-recovery.ts +31 -0
  32. package/template/apps/server/src/agent/client-workflow-artifact/contracts.ts +104 -0
  33. package/template/apps/server/src/agent/client-workflow-artifact/drizzle-locks.ts +30 -0
  34. package/template/apps/server/src/agent/client-workflow-artifact/drizzle-mapper.ts +138 -0
  35. package/template/apps/server/src/agent/client-workflow-artifact/drizzle-repository.ts +346 -0
  36. package/template/apps/server/src/agent/client-workflow-artifact/error.ts +21 -0
  37. package/template/apps/server/src/agent/client-workflow-artifact/handler.ts +167 -0
  38. package/template/apps/server/src/agent/client-workflow-artifact/host-revocation.ts +29 -0
  39. package/template/apps/server/src/agent/client-workflow-artifact/in-memory-repository.ts +232 -0
  40. package/template/apps/server/src/agent/client-workflow-artifact/job-port.ts +101 -0
  41. package/template/apps/server/src/agent/client-workflow-artifact/presentation.ts +41 -0
  42. package/template/apps/server/src/agent/client-workflow-artifact/recovery.contract.test.ts +253 -0
  43. package/template/apps/server/src/agent/client-workflow-artifact/release-binding.ts +85 -0
  44. package/template/apps/server/src/agent/client-workflow-artifact/repository.test.ts +204 -0
  45. package/template/apps/server/src/agent/client-workflow-artifact/repository.ts +97 -0
  46. package/template/apps/server/src/agent/client-workflow-artifact/routes-handler.contract.test.ts +201 -0
  47. package/template/apps/server/src/agent/client-workflow-artifact/routes.ts +161 -0
  48. package/template/apps/server/src/agent/client-workflow-artifact/runtime-composition.ts +101 -0
  49. package/template/apps/server/src/agent/client-workflow-artifact/scope-authority.ts +39 -0
  50. package/template/apps/server/src/agent/client-workflow-artifact/service-authorization.ts +117 -0
  51. package/template/apps/server/src/agent/client-workflow-artifact/service-support.ts +28 -0
  52. package/template/apps/server/src/agent/client-workflow-artifact/service.contract.test.ts +345 -0
  53. package/template/apps/server/src/agent/client-workflow-artifact/service.ts +350 -0
  54. package/template/apps/server/src/agent/client-workflow-artifact/session-boundary.ts +39 -0
  55. package/template/apps/server/src/agent/client-workflow-artifact/source-access.contract.test.ts +98 -0
  56. package/template/apps/server/src/agent/client-workflow-artifact/source-access.ts +80 -0
  57. package/template/apps/server/src/agent/client-workflow-artifact/takeover.ts +122 -0
  58. package/template/apps/server/src/agent/client-workflow-artifact/task-authority.contract.test.ts +97 -0
  59. package/template/apps/server/src/agent/client-workflow-artifact/task-authority.ts +147 -0
  60. package/template/apps/server/src/agent/client-workflow-artifact/terminal-authority.contract.test.ts +100 -0
  61. package/template/apps/server/src/agent/client-workflow-artifact/terminal-replay.ts +31 -0
  62. package/template/apps/server/src/agent/client-workflow-artifact/terminal-seal.ts +211 -0
  63. package/template/apps/server/src/agent/client-workflow-artifact/workflow-artifact.test-support.ts +173 -0
  64. package/template/apps/server/src/agent/client-workflow-artifact/workflow-loader.contract.test.ts +254 -0
  65. package/template/apps/server/src/agent/client-workflow-artifact/workflow-loader.ts +285 -0
  66. package/template/apps/server/src/agent/run-facade.test-support.ts +17 -4
  67. package/template/apps/server/src/agent/run-facade.test.ts +16 -0
  68. package/template/apps/server/src/agent/run-session-authorization.ts +12 -10
  69. package/template/apps/server/src/agent/runtime-bootstrap-input.ts +5 -1
  70. package/template/apps/server/src/agent/runtime-bootstrap.ts +33 -33
  71. package/template/apps/server/src/agent/runtime-public-ports.ts +40 -0
  72. package/template/apps/server/src/agent/session-invalidation/contracts.ts +25 -26
  73. package/template/apps/server/src/agent/session-projection-access.ts +31 -19
  74. package/template/apps/server/src/agent/unavailable-routes.ts +21 -0
  75. package/template/apps/server/src/agent/workflow-runtime-bootstrap.ts +2 -0
  76. package/template/apps/server/src/agent-workflow/artifact-source-authorization.ts +12 -6
  77. package/template/apps/server/src/agent-workflow/command-facade.ts +70 -11
  78. package/template/apps/server/src/agent-workflow/drizzle-artifact-port.ts +9 -9
  79. package/template/apps/server/src/agent-workflow/drizzle-delegation-completion.ts +1 -1
  80. package/template/apps/server/src/agent-workflow/platform-node-adapters.ts +14 -6
  81. package/template/apps/server/src/agent-workflow/project-launch-authority.contract.test.ts +53 -0
  82. package/template/apps/server/src/agent-workflow/project-launch-authority.ts +92 -0
  83. package/template/apps/server/src/agent-workflow/runtime-composition.ts +30 -14
  84. package/template/apps/server/src/app/agent-runtime-composition.ts +6 -1
  85. package/template/apps/server/src/app/client-agent-workflow-artifact-binding.ts +14 -0
  86. package/template/apps/server/src/application-services.ts +6 -0
  87. package/template/apps/server/src/data-access/scope-containment.test.ts +31 -0
  88. package/template/apps/server/src/data-access/scope-containment.ts +48 -0
  89. package/template/apps/server/src/jobs/artifact-publication.test.ts +192 -0
  90. package/template/apps/server/src/jobs/artifact-publication.ts +56 -0
  91. package/template/apps/server/src/jobs/artifact-publisher.ts +101 -0
  92. package/template/apps/server/src/jobs/drizzle-artifact.ts +73 -1
  93. package/template/apps/server/src/jobs/drizzle-execution-repository.ts +14 -1
  94. package/template/apps/server/src/jobs/drizzle-execution.integration.test.ts +65 -0
  95. package/template/apps/server/src/jobs/drizzle-repository.integration.test.ts +1 -0
  96. package/template/apps/server/src/jobs/execution-repository.ts +28 -0
  97. package/template/apps/server/src/jobs/execution.test.ts +3 -1
  98. package/template/apps/server/src/jobs/in-memory-execution.ts +16 -0
  99. package/template/apps/server/src/jobs/in-memory-lease.ts +45 -1
  100. package/template/apps/server/src/jobs/legacy-adapter.integration.test.ts +2 -0
  101. package/template/apps/server/src/jobs/postgres-cleanup-contract.test.ts +58 -0
  102. package/template/apps/server/src/jobs/worker.ts +8 -14
  103. package/template/apps/server/src/module-host/background-ai-unavailable.ts +18 -0
  104. package/template/apps/server/src/module-host/durable-context.ts +19 -22
  105. package/template/apps/server/src/module-host/implementation-completeness.test.ts +80 -1
  106. package/template/apps/server/src/module-host/implementation-completeness.ts +28 -1
  107. package/template/apps/server/src/module-host/request-context.ts +32 -8
  108. package/template/apps/server/src/module-host/storage-port.ts +3 -0
  109. package/template/apps/server/src/module-host/workflow-input-artifact-port.test.ts +104 -0
  110. package/template/apps/server/src/module-host/workflow-input-artifact-port.ts +229 -0
  111. package/template/apps/server/src/module-host/workflow-input-materialization.test.ts +163 -0
  112. package/template/apps/server/src/module-host/workflow-input-materialization.ts +161 -0
  113. package/template/apps/server/src/workflow/drizzle-repository.integration.test.ts +1 -0
  114. package/template/apps/web/src/pages/system/components/ai-runtime/AiRuntimeFilters.vue +2 -1
  115. package/template/apps/web/src/pages/system/components/ai-runtime/AiRuntimeFilters.webtest.ts +16 -0
  116. package/template/docs/architecture/agent-workflow.md +13 -2
  117. package/template/docs/architecture/durable-jobs.md +7 -0
  118. package/template/docs/operations/agent-session-memory.md +2 -1
  119. package/template/docs/operations/agent-session-troubleshooting.md +87 -2
  120. package/template/docs/operations/agent-workflow-recovery.md +25 -14
  121. package/template/docs/platform/client-agent-session.md +148 -2
  122. package/template/packages/ai-client/package.json +2 -1
  123. package/template/packages/ai-client/src/client-agent/index.ts +1 -0
  124. package/template/packages/ai-client/src/client-agent/workflow-artifact/contracts.ts +85 -0
  125. package/template/packages/ai-client/src/client-agent/workflow-artifact/http.test.ts +49 -0
  126. package/template/packages/ai-client/src/client-agent/workflow-artifact/http.ts +82 -0
  127. package/template/packages/ai-client/src/client-agent/workflow-artifact/index.ts +3 -0
  128. package/template/packages/ai-client/src/client-agent/workflow-artifact/validation.test.ts +154 -0
  129. package/template/packages/ai-client/src/client-agent/workflow-artifact/validation.ts +332 -0
  130. package/template/packages/database/drizzle/0062_client_agent_workflow_artifact.sql +63 -0
  131. package/template/packages/database/drizzle/meta/0062_snapshot.json +14839 -0
  132. package/template/packages/database/drizzle/meta/_journal.json +7 -0
  133. package/template/packages/database/package.json +1 -1
  134. package/template/packages/database/src/agent-runtime-schema.test.ts +177 -0
  135. package/template/packages/database/src/schema/client-agent-workflow-artifact.ts +158 -0
  136. package/template/packages/database/src/schema/index.ts +1 -0
  137. package/template/packages/jobs/package.json +1 -1
  138. package/template/packages/jobs/src/handlers.test.ts +10 -0
  139. package/template/packages/jobs/src/handlers.ts +28 -11
  140. package/template/packages/modules/package.json +1 -1
  141. package/template/packages/modules/src/ai-client-execution-policy.ts +6 -0
  142. package/template/packages/modules/src/manifest.ts +2 -0
  143. package/template/packages/modules/src/system-agent-audit-actions.ts +3 -0
  144. package/template/packages/modules/src/system-ai-api-bindings.ts +15 -0
  145. package/template/packages/modules/src/system-audit-actions.ts +15 -0
  146. package/template/packages/server-sdk/index.ts +52 -0
  147. package/template/packages/server-sdk/package.json +5 -1
  148. package/template/packages/server-sdk/src/client-agent-session.ts +13 -1
  149. package/template/packages/server-sdk/src/client-agent-workflow-artifact.contract.test.ts +113 -0
  150. package/template/packages/server-sdk/src/client-agent-workflow-artifact.ts +183 -0
  151. package/template/packages/server-sdk/src/durable-handler.ts +7 -0
  152. package/template/packages/server-sdk/src/request-context.ts +7 -0
  153. package/template/packages/server-sdk/src/workflow-input-artifact-port.ts +104 -0
  154. package/template/packages/server-sdk/src/workflow-input-artifact-validation.contract.test.ts +124 -0
  155. package/template/packages/server-sdk/src/workflow-input-artifact-validation.ts +347 -0
  156. package/template/packages/server-sdk/src/workflow-input-materialization-handler.ts +43 -0
  157. package/template/packages/storage/package.json +1 -1
  158. package/template/packages/storage/src/blob-store-put-once.test.ts +70 -0
  159. package/template/packages/storage/src/blob-store.ts +9 -0
  160. package/template/packages/storage/src/local-file-blob-put-once.ts +120 -0
  161. package/template/packages/storage/src/local-file-blob-store.ts +53 -1
  162. package/template/packages/storage/src/memory-blob-store.ts +73 -33
@@ -435,6 +435,13 @@
435
435
  "when": 1787795894000,
436
436
  "tag": "0061_agent_workflow",
437
437
  "breakpoints": true
438
+ },
439
+ {
440
+ "idx": 62,
441
+ "version": "7",
442
+ "when": 1787904000000,
443
+ "tag": "0062_client_agent_workflow_artifact",
444
+ "breakpoints": true
438
445
  }
439
446
  ]
440
447
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@southwind-ai/database",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "engines": {
@@ -11,6 +11,7 @@ import {
11
11
  agentRuntimeRuns,
12
12
  clientAgentReceipts,
13
13
  clientAgentSessions,
14
+ clientAgentWorkflowArtifacts,
14
15
  } from "./schema/index.js";
15
16
 
16
17
  test("Agent Run 固定不可变 Release 并持久化恢复租约", async () => {
@@ -65,6 +66,76 @@ test("Agent Run 固定不可变 Release 并持久化恢复租约", async () => {
65
66
  expect(getTableConfig(clientAgentReceipts).name).toBe(
66
67
  "client_agent_receipts",
67
68
  );
69
+ expect(getTableConfig(clientAgentWorkflowArtifacts).name).toBe(
70
+ "client_agent_workflow_artifacts",
71
+ );
72
+ expect(clientAgentWorkflowArtifacts.bindingDigest.notNull).toBe(true);
73
+ expect(clientAgentWorkflowArtifacts.effectKind.notNull).toBe(true);
74
+ expect(clientAgentWorkflowArtifacts.effectFenceTokenDigest.notNull).toBe(
75
+ true,
76
+ );
77
+ expect(clientAgentWorkflowArtifacts.terminalRequestDigest.notNull).toBe(
78
+ false,
79
+ );
80
+ const workflowArtifactConfig = getTableConfig(clientAgentWorkflowArtifacts);
81
+ expect(
82
+ workflowArtifactConfig.foreignKeys
83
+ .map((foreignKey) => foreignKey.getName())
84
+ .sort(),
85
+ ).toEqual([
86
+ "client_agent_workflow_artifacts_client_session_id_client_agent_sessions_session_id_fk",
87
+ "client_agent_workflow_artifacts_durable_job_id_durable_jobs_id_fk",
88
+ "fk_client_agent_workflow_effect_fence",
89
+ ]);
90
+ const effectFenceForeignKey = workflowArtifactConfig.foreignKeys.find(
91
+ (foreignKey) =>
92
+ foreignKey.getName() === "fk_client_agent_workflow_effect_fence",
93
+ );
94
+ expect(
95
+ effectFenceForeignKey?.reference().columns.map(({ name }) => name),
96
+ ).toEqual([
97
+ "command_id",
98
+ "run_id",
99
+ "node_run_id",
100
+ "effect_kind",
101
+ "effect_generation",
102
+ "request_digest",
103
+ "effect_fence_token_digest",
104
+ ]);
105
+ expect(
106
+ effectFenceForeignKey?.reference().foreignColumns.map(({ name }) => name),
107
+ ).toEqual([
108
+ "command_id",
109
+ "run_id",
110
+ "node_run_id",
111
+ "effect_kind",
112
+ "generation",
113
+ "request_digest",
114
+ "fence_token_digest",
115
+ ]);
116
+ expect(
117
+ workflowArtifactConfig.indexes
118
+ .map(
119
+ ({ config }) => `${config.unique ? "unique:" : "index:"}${config.name}`,
120
+ )
121
+ .sort(),
122
+ ).toEqual([
123
+ "index:idx_client_agent_workflow_claim",
124
+ "index:idx_client_agent_workflow_host",
125
+ "unique:uk_client_agent_workflow_client_session",
126
+ "unique:uk_client_agent_workflow_command",
127
+ "unique:uk_client_agent_workflow_job",
128
+ "unique:uk_client_agent_workflow_terminal_receipt",
129
+ ]);
130
+ expect(workflowArtifactConfig.checks.map(({ name }) => name).sort()).toEqual([
131
+ "ck_client_agent_workflow_claim_binding",
132
+ "ck_client_agent_workflow_effect_kind",
133
+ "ck_client_agent_workflow_generation",
134
+ "ck_client_agent_workflow_history",
135
+ "ck_client_agent_workflow_status",
136
+ "ck_client_agent_workflow_terminal",
137
+ "ck_client_agent_workflow_version",
138
+ ]);
68
139
 
69
140
  const migration = await Bun.file(
70
141
  new URL("../drizzle/0040_colossal_baron_strucker.sql", import.meta.url),
@@ -143,6 +214,112 @@ test("Agent Run 固定不可变 Release 并持久化恢复租约", async () => {
143
214
  ).text();
144
215
  expect(hostBindingMigration).toContain("host_session_digest");
145
216
  expect(hostBindingMigration).not.toContain("provider_key");
217
+ const workflowArtifactMigration = await Bun.file(
218
+ new URL(
219
+ "../drizzle/0062_client_agent_workflow_artifact.sql",
220
+ import.meta.url,
221
+ ),
222
+ ).text();
223
+ expect(workflowArtifactMigration).toContain(
224
+ 'CREATE TABLE "client_agent_workflow_artifacts"',
225
+ );
226
+ expect(workflowArtifactMigration).toContain(
227
+ '"terminal_request_digest" varchar(71)',
228
+ );
229
+ expect(workflowArtifactMigration).toContain(
230
+ 'CONSTRAINT "fk_client_agent_workflow_effect_fence"',
231
+ );
232
+ expect(workflowArtifactMigration).toContain(
233
+ 'CREATE UNIQUE INDEX "uk_client_agent_workflow_client_session"',
234
+ );
235
+ expect(workflowArtifactMigration).not.toContain(
236
+ 'CONSTRAINT "client_agent_workflow_artifacts_command_id_agent_workflow_side_effect_commands_command_id_fk"',
237
+ );
238
+ const workflowArtifactSnapshot = (await Bun.file(
239
+ new URL("../drizzle/meta/0062_snapshot.json", import.meta.url),
240
+ ).json()) as {
241
+ prevId: string;
242
+ tables: Record<
243
+ string,
244
+ {
245
+ columns: Record<
246
+ string,
247
+ {
248
+ name: string;
249
+ type: string;
250
+ primaryKey: boolean;
251
+ notNull: boolean;
252
+ }
253
+ >;
254
+ indexes: Record<string, unknown>;
255
+ foreignKeys: Record<string, unknown>;
256
+ checkConstraints: Record<string, unknown>;
257
+ }
258
+ >;
259
+ };
260
+ const previousWorkflowArtifactSnapshot = (await Bun.file(
261
+ new URL("../drizzle/meta/0061_snapshot.json", import.meta.url),
262
+ ).json()) as { id: string };
263
+ expect(workflowArtifactSnapshot.prevId).toBe(
264
+ previousWorkflowArtifactSnapshot.id,
265
+ );
266
+ expect(
267
+ workflowArtifactSnapshot.tables["public.client_agent_workflow_artifacts"]
268
+ ?.columns.terminal_request_digest,
269
+ ).toEqual({
270
+ name: "terminal_request_digest",
271
+ type: "varchar(71)",
272
+ primaryKey: false,
273
+ notNull: false,
274
+ });
275
+ const workflowArtifactSnapshotTable =
276
+ workflowArtifactSnapshot.tables["public.client_agent_workflow_artifacts"];
277
+ expect(
278
+ Object.keys(workflowArtifactSnapshotTable?.indexes ?? {}).sort(),
279
+ ).toEqual([
280
+ "idx_client_agent_workflow_claim",
281
+ "idx_client_agent_workflow_host",
282
+ "uk_client_agent_workflow_client_session",
283
+ "uk_client_agent_workflow_command",
284
+ "uk_client_agent_workflow_job",
285
+ "uk_client_agent_workflow_terminal_receipt",
286
+ ]);
287
+ expect(
288
+ Object.keys(workflowArtifactSnapshotTable?.foreignKeys ?? {}).sort(),
289
+ ).toEqual([
290
+ "client_agent_workflow_artifacts_client_session_id_client_agent_sessions_session_id_fk",
291
+ "client_agent_workflow_artifacts_durable_job_id_durable_jobs_id_fk",
292
+ "fk_client_agent_workflow_effect_fence",
293
+ ]);
294
+ expect(
295
+ Object.keys(workflowArtifactSnapshotTable?.checkConstraints ?? {}).sort(),
296
+ ).toEqual([
297
+ "ck_client_agent_workflow_claim_binding",
298
+ "ck_client_agent_workflow_effect_kind",
299
+ "ck_client_agent_workflow_generation",
300
+ "ck_client_agent_workflow_history",
301
+ "ck_client_agent_workflow_status",
302
+ "ck_client_agent_workflow_terminal",
303
+ "ck_client_agent_workflow_version",
304
+ ]);
305
+ const migrationJournal = (await Bun.file(
306
+ new URL("../drizzle/meta/_journal.json", import.meta.url),
307
+ ).json()) as {
308
+ entries: readonly {
309
+ idx: number;
310
+ version: string;
311
+ tag: string;
312
+ breakpoints: boolean;
313
+ }[];
314
+ };
315
+ expect(migrationJournal.entries.at(-1)).toMatchObject({
316
+ idx: 62,
317
+ version: "7",
318
+ tag: "0062_client_agent_workflow_artifact",
319
+ breakpoints: true,
320
+ });
321
+ expect(workflowArtifactMigration).not.toContain("provider_key");
322
+ expect(workflowArtifactMigration).not.toContain("message_json");
146
323
  expect(screenshotMigration).toContain(
147
324
  'CREATE UNIQUE INDEX "uk_agent_screenshot_intakes_run"',
148
325
  );
@@ -0,0 +1,158 @@
1
+ import { sql } from "drizzle-orm";
2
+ import {
3
+ check,
4
+ doublePrecision,
5
+ foreignKey,
6
+ index,
7
+ integer,
8
+ jsonb,
9
+ pgTable,
10
+ uniqueIndex,
11
+ varchar,
12
+ } from "drizzle-orm/pg-core";
13
+ import { durableJobs } from "./durable-jobs.js";
14
+ import { clientAgentSessions } from "./client-agent.js";
15
+ import { agentWorkflowSideEffectCommands } from "./agent-workflow-effects.js";
16
+
17
+ export type ClientAgentWorkflowArtifactStatus =
18
+ | "pending"
19
+ | "claimed"
20
+ | "cancellation-requested"
21
+ | "completed"
22
+ | "cancelled";
23
+
24
+ /**
25
+ * Workflow effect 与浏览器 Client Agent Session 之间的唯一桥接事实。
26
+ * 原始对话和 Provider 配置不在这里持久化;逐次执行历史继续由
27
+ * client_agent_receipts 承载。
28
+ */
29
+ export const clientAgentWorkflowArtifacts = pgTable(
30
+ "client_agent_workflow_artifacts",
31
+ {
32
+ workId: varchar("work_id", { length: 80 }).primaryKey(),
33
+ commandId: varchar("command_id", { length: 96 }).notNull(),
34
+ durableJobId: varchar("durable_job_id", { length: 64 })
35
+ .notNull()
36
+ .references(() => durableJobs.id, { onDelete: "restrict" }),
37
+ runId: varchar("run_id", { length: 96 }).notNull(),
38
+ nodeRunId: varchar("node_run_id", { length: 96 }).notNull(),
39
+ effectKind: varchar("effect_kind", { length: 24 }).$type<"job">().notNull(),
40
+ taskKey: varchar("task_key", { length: 160 }).notNull(),
41
+ operationKey: varchar("operation_key", { length: 200 }).notNull(),
42
+ bindingDigest: varchar("binding_digest", { length: 71 }).notNull(),
43
+ actorId: varchar("actor_id", { length: 64 }).notNull(),
44
+ scopeDigest: varchar("scope_digest", { length: 71 }).notNull(),
45
+ authorizationSnapshotDigest: varchar("authorization_snapshot_digest", {
46
+ length: 71,
47
+ }).notNull(),
48
+ runPolicyDigest: varchar("run_policy_digest", { length: 71 }).notNull(),
49
+ requestDigest: varchar("request_digest", { length: 71 }).notNull(),
50
+ inputDigest: varchar("input_digest", { length: 71 }).notNull(),
51
+ effectGeneration: integer("effect_generation").notNull(),
52
+ effectFenceTokenDigest: varchar("effect_fence_token_digest", {
53
+ length: 71,
54
+ }).notNull(),
55
+ status: varchar("status", { length: 32 })
56
+ .$type<ClientAgentWorkflowArtifactStatus>()
57
+ .notNull(),
58
+ claimGeneration: integer("claim_generation").notNull().default(0),
59
+ clientBindingDigest: varchar("client_binding_digest", { length: 71 }),
60
+ installationId: varchar("installation_id", { length: 160 }),
61
+ hostSessionDigest: varchar("host_session_digest", { length: 71 }),
62
+ clientSessionId: varchar("client_session_id", { length: 80 }).references(
63
+ () => clientAgentSessions.sessionId,
64
+ { onDelete: "restrict" },
65
+ ),
66
+ claimTokenHash: varchar("claim_token_hash", { length: 71 }),
67
+ claimExpiresAt: doublePrecision("claim_expires_at"),
68
+ historySequence: integer("history_sequence").notNull().default(0),
69
+ historyHeadDigest: varchar("history_head_digest", { length: 71 }),
70
+ terminalReceiptId: varchar("terminal_receipt_id", { length: 96 }),
71
+ terminalReceiptDigest: varchar("terminal_receipt_digest", { length: 71 }),
72
+ terminalRequestDigest: varchar("terminal_request_digest", { length: 71 }),
73
+ terminalResultJson: jsonb("terminal_result_json").$type<
74
+ Record<string, unknown>
75
+ >(),
76
+ artifactRef: varchar("artifact_ref", { length: 37 }),
77
+ artifactFilename: varchar("artifact_filename", { length: 240 }),
78
+ artifactContentType: varchar("artifact_content_type", { length: 120 }),
79
+ artifactByteSize: integer("artifact_byte_size"),
80
+ artifactSha256: varchar("artifact_sha256", { length: 64 }),
81
+ cancelRequestedAt: doublePrecision("cancel_requested_at"),
82
+ finishedAt: doublePrecision("finished_at"),
83
+ version: integer("version").notNull().default(1),
84
+ createdAt: doublePrecision("created_at").notNull(),
85
+ updatedAt: doublePrecision("updated_at").notNull(),
86
+ },
87
+ (table) => [
88
+ uniqueIndex("uk_client_agent_workflow_command").on(table.commandId),
89
+ uniqueIndex("uk_client_agent_workflow_job").on(table.durableJobId),
90
+ uniqueIndex("uk_client_agent_workflow_terminal_receipt").on(
91
+ table.terminalReceiptId,
92
+ ),
93
+ uniqueIndex("uk_client_agent_workflow_client_session").on(
94
+ table.clientSessionId,
95
+ ),
96
+ index("idx_client_agent_workflow_claim").on(
97
+ table.actorId,
98
+ table.status,
99
+ table.updatedAt,
100
+ ),
101
+ index("idx_client_agent_workflow_host").on(
102
+ table.hostSessionDigest,
103
+ table.status,
104
+ ),
105
+ foreignKey({
106
+ columns: [
107
+ table.commandId,
108
+ table.runId,
109
+ table.nodeRunId,
110
+ table.effectKind,
111
+ table.effectGeneration,
112
+ table.requestDigest,
113
+ table.effectFenceTokenDigest,
114
+ ],
115
+ foreignColumns: [
116
+ agentWorkflowSideEffectCommands.commandId,
117
+ agentWorkflowSideEffectCommands.runId,
118
+ agentWorkflowSideEffectCommands.nodeRunId,
119
+ agentWorkflowSideEffectCommands.effectKind,
120
+ agentWorkflowSideEffectCommands.generation,
121
+ agentWorkflowSideEffectCommands.requestDigest,
122
+ agentWorkflowSideEffectCommands.fenceTokenDigest,
123
+ ],
124
+ name: "fk_client_agent_workflow_effect_fence",
125
+ }).onDelete("restrict"),
126
+ check(
127
+ "ck_client_agent_workflow_status",
128
+ sql`${table.status} in ('pending', 'claimed', 'cancellation-requested', 'completed', 'cancelled')`,
129
+ ),
130
+ check(
131
+ "ck_client_agent_workflow_generation",
132
+ sql`${table.effectGeneration} > 0 and ${table.claimGeneration} >= 0`,
133
+ ),
134
+ check(
135
+ "ck_client_agent_workflow_effect_kind",
136
+ sql`${table.effectKind} = 'job'`,
137
+ ),
138
+ check(
139
+ "ck_client_agent_workflow_claim_binding",
140
+ sql`(${table.claimGeneration} = 0 and ${table.status} in ('pending', 'cancellation-requested', 'cancelled') and ${table.clientBindingDigest} is null and ${table.installationId} is null and ${table.hostSessionDigest} is null and ${table.clientSessionId} is null and ${table.claimTokenHash} is null and ${table.claimExpiresAt} is null)
141
+ or (${table.claimGeneration} > 0 and ${table.status} <> 'pending' and ${table.clientBindingDigest} is not null and ${table.installationId} is not null and ${table.hostSessionDigest} is not null)`,
142
+ ),
143
+ check(
144
+ "ck_client_agent_workflow_terminal",
145
+ sql`(${table.status} = 'completed' and ${table.terminalReceiptId} is not null and ${table.terminalReceiptDigest} is not null and ${table.terminalRequestDigest} is not null and ${table.terminalResultJson} is not null and ${table.artifactRef} is not null and ${table.artifactFilename} is not null and ${table.artifactContentType} is not null and ${table.artifactByteSize} is not null and ${table.artifactSha256} is not null and ${table.finishedAt} is not null)
146
+ or (${table.status} = 'cancelled' and ${table.finishedAt} is not null and ${table.terminalReceiptId} is null and ${table.terminalRequestDigest} is null and ${table.artifactRef} is null)
147
+ or (${table.status} in ('pending', 'claimed', 'cancellation-requested') and ${table.finishedAt} is null and ${table.terminalReceiptId} is null and ${table.terminalRequestDigest} is null and ${table.artifactRef} is null)`,
148
+ ),
149
+ check(
150
+ "ck_client_agent_workflow_history",
151
+ sql`${table.historySequence} >= 0 and (${table.historySequence} = 0 or ${table.historyHeadDigest} is not null)`,
152
+ ),
153
+ check(
154
+ "ck_client_agent_workflow_version",
155
+ sql`${table.version} > 0 and ${table.createdAt} <= ${table.updatedAt}`,
156
+ ),
157
+ ],
158
+ );
@@ -39,6 +39,7 @@ export * from "./agent-context-message.js";
39
39
  export * from "./agent-session-receipt.js";
40
40
  export * from "./agent-session.js";
41
41
  export * from "./client-agent.js";
42
+ export * from "./client-agent-workflow-artifact.js";
42
43
  export * from "./embedding-runtime.js";
43
44
  export * from "./ai-output-artifacts.js";
44
45
  // @windy-module system.agent end
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@southwind-ai/jobs",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "engines": {
@@ -81,5 +81,15 @@ function createContext(): DurableHandlerContext {
81
81
  heartbeat: async () => undefined,
82
82
  progress: async () => undefined,
83
83
  publishArtifact: async () => undefined,
84
+ publishArtifactOnce: async (publicationKey, artifact) => ({
85
+ schemaVersion: 1,
86
+ publicationKey,
87
+ artifactId: "dap_stable",
88
+ jobId: "job-1",
89
+ stageKey: "main",
90
+ kind: artifact.kind,
91
+ artifactRef: artifact.artifactRef,
92
+ sha256: artifact.sha256,
93
+ }),
84
94
  };
85
95
  }
@@ -1,5 +1,28 @@
1
1
  import type { ArtifactRef } from "@southwind-ai/storage";
2
2
 
3
+ export interface DurableHandlerArtifactInput {
4
+ kind: string;
5
+ artifactRef: ArtifactRef;
6
+ filename: string;
7
+ contentType: string;
8
+ byteSize: number;
9
+ sha256: string;
10
+ ownerId: string;
11
+ expiresAt?: string;
12
+ metadata?: Record<string, unknown>;
13
+ }
14
+
15
+ export interface DurableArtifactPublicationReceipt {
16
+ readonly schemaVersion: 1;
17
+ readonly publicationKey: string;
18
+ readonly artifactId: string;
19
+ readonly jobId: string;
20
+ readonly stageKey: string;
21
+ readonly kind: string;
22
+ readonly artifactRef: ArtifactRef;
23
+ readonly sha256: string;
24
+ }
25
+
3
26
  export interface PayloadParser<T> {
4
27
  parse(input: unknown): T;
5
28
  }
@@ -16,17 +39,11 @@ export interface DurableHandlerContext {
16
39
  message?: string;
17
40
  metadata?: Record<string, unknown>;
18
41
  }): Promise<void>;
19
- publishArtifact(input: {
20
- kind: string;
21
- artifactRef: ArtifactRef;
22
- filename: string;
23
- contentType: string;
24
- byteSize: number;
25
- sha256: string;
26
- ownerId: string;
27
- expiresAt?: string;
28
- metadata?: Record<string, unknown>;
29
- }): Promise<void>;
42
+ publishArtifact(input: DurableHandlerArtifactInput): Promise<void>;
43
+ publishArtifactOnce?(
44
+ publicationKey: string,
45
+ artifact: DurableHandlerArtifactInput,
46
+ ): Promise<DurableArtifactPublicationReceipt>;
30
47
  }
31
48
 
32
49
  export interface DurableHandlerDefinition<T> {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@southwind-ai/modules",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "engines": {
@@ -16,6 +16,12 @@ export function validateClientExecution(
16
16
  if (policy.mode !== "governed-session") {
17
17
  throw new Error(`${operation.key} Client Agent Session 模式无效`);
18
18
  }
19
+ if (
20
+ policy.launchAuthority !== undefined &&
21
+ !["direct", "workflow-artifact"].includes(policy.launchAuthority)
22
+ ) {
23
+ throw new Error(`${operation.key} Client Agent launch authority 无效`);
24
+ }
19
25
  const limits = [
20
26
  policy.maxSteps,
21
27
  policy.maxRequestBytes,
@@ -174,6 +174,8 @@ export interface AiOperationLimits {
174
174
  */
175
175
  export interface AiClientExecutionPolicy {
176
176
  readonly mode: "governed-session";
177
+ /** 缺省为 direct;workflow-artifact 只能由固定 Workflow Artifact Host seam 启动。 */
178
+ readonly launchAuthority?: "direct" | "workflow-artifact";
177
179
  readonly maxSteps: number;
178
180
  readonly maxRequestBytes: number;
179
181
  readonly maxResponseBytes: number;
@@ -23,4 +23,7 @@ export const agentAuditActionKeys: ReadonlySet<string> = new Set([
23
23
  "agent.workflow.run.signal",
24
24
  "agent.workflow.evaluation.record",
25
25
  "agent.workflow.artifact.resolve",
26
+ "agent.workflow.client-artifact.claim",
27
+ "agent.workflow.client-artifact.advance",
28
+ "agent.workflow.client-artifact.cancel",
26
29
  ]);
@@ -149,6 +149,21 @@ function workflowBindings(): ApiPermissionBinding[] {
149
149
  "system.agent-workflow",
150
150
  "agent.workflow.evaluation.record",
151
151
  ),
152
+ ...(
153
+ [
154
+ ["/api/agent/client-workflow-artifacts/claim", "claim"],
155
+ ["/api/agent/client-workflow-artifacts/advance", "advance"],
156
+ ["/api/agent/client-workflow-artifacts/cancel", "cancel"],
157
+ ] as const
158
+ ).map(([path, action]) =>
159
+ binding(
160
+ "POST",
161
+ path,
162
+ "system.agent-workflow.manage",
163
+ "system.agent-workflow",
164
+ `agent.workflow.client-artifact.${action}`,
165
+ ),
166
+ ),
152
167
  ];
153
168
  }
154
169
 
@@ -209,6 +209,21 @@ export const systemAuditActions: ModuleManifest["auditActions"] = [
209
209
  label: "解析 Agent Workflow 产物",
210
210
  description: "在对象授权与数据范围内解析 Workflow 产物引用。",
211
211
  },
212
+ {
213
+ key: "agent.workflow.client-artifact.claim",
214
+ label: "领取 Client Agent Workflow 任务",
215
+ description: "按当前宿主身份领取已持久化且受 fence 约束的浏览器任务。",
216
+ },
217
+ {
218
+ key: "agent.workflow.client-artifact.advance",
219
+ label: "推进 Client Agent Workflow 任务",
220
+ description: "校验完整 Provider receipt 链并封存 Durable Artifact。",
221
+ },
222
+ {
223
+ key: "agent.workflow.client-artifact.cancel",
224
+ label: "取消 Client Agent Workflow 任务",
225
+ description: "取消当前领取代次并拒绝迟到结果写入。",
226
+ },
212
227
  // @windy-module system.agent end
213
228
  "security.denied",
214
229
  "system.error",
@@ -2,6 +2,7 @@ export type { ModuleActor } from "./src/actor.js";
2
2
  export { pageAgentClientRunCapability } from "./src/client-agent-session.js";
3
3
  export type {
4
4
  ModuleClientAgentHostAuthAdapter,
5
+ ModuleClientAgentHostAuthPurpose,
5
6
  ModuleClientAgentHostPrincipal,
6
7
  ModuleClientAgentSessionCreateInput,
7
8
  ModuleClientAgentSessionGrant,
@@ -10,6 +11,30 @@ export type {
10
11
  ModuleClientAgentSessionStatus,
11
12
  ModuleClientAgentSessionView,
12
13
  } from "./src/client-agent-session.js";
14
+ // @windy-module system.agent begin
15
+ export {
16
+ CLIENT_AGENT_WORKFLOW_ARTIFACT_BINDING_LIMITS,
17
+ CLIENT_AGENT_WORKFLOW_ARTIFACT_TASK_KEY,
18
+ CLIENT_AGENT_WORKFLOW_ARTIFACT_WORK_ID_PREFIX,
19
+ CLIENT_AGENT_WORKFLOW_SCOPE_CONTAINMENT_CONTRACT_VERSION,
20
+ } from "./src/client-agent-workflow-artifact.js";
21
+ export type {
22
+ ModuleClientAgentWorkflowArtifactBeginSpec,
23
+ ModuleClientAgentWorkflowArtifactCommand,
24
+ ModuleClientAgentWorkflowArtifactPolicy,
25
+ ModuleClientAgentWorkflowArtifactPort,
26
+ ModuleClientAgentWorkflowArtifactProjectBinding,
27
+ ModuleClientAgentWorkflowArtifactSafeCode,
28
+ ModuleClientAgentWorkflowArtifactStatus,
29
+ ModuleClientAgentWorkflowArtifactSummary,
30
+ ModuleClientAgentWorkflowArtifactTerminalResultAuthority,
31
+ ModuleClientAgentWorkflowClientTaskAuthority,
32
+ ModuleClientAgentWorkflowExecutionTask,
33
+ ModuleClientAgentWorkflowTaskInputArtifact,
34
+ ModuleClientAgentWorkflowProjectLaunchAuthority,
35
+ ModuleClientAgentWorkflowArtifactView,
36
+ } from "./src/client-agent-workflow-artifact.js";
37
+ // @windy-module system.agent end
13
38
  export type {
14
39
  ModuleAiArtifactPort,
15
40
  ModuleAiArtifactRef,
@@ -150,6 +175,33 @@ export type {
150
175
  ModuleDurableHandlerDefinition,
151
176
  ModuleDurableStoragePort,
152
177
  } from "./src/durable-handler.js";
178
+ // @windy-module system.agent begin
179
+ export {
180
+ ModuleWorkflowInputArtifactUnavailableError,
181
+ ModuleWorkflowInputMaterializationError,
182
+ requireModuleWorkflowInputArtifactPublicationPortV1,
183
+ type ModuleWorkflowInputArtifactPublicationPortV1,
184
+ type ModuleWorkflowInputArtifactPublicationV1,
185
+ type ModuleWorkflowInputArtifactSourceV1,
186
+ type ModuleWorkflowInputJsonArtifactV1,
187
+ type ModuleWorkflowInputResourceArtifactV1,
188
+ type ModuleWorkflowInputMaterializationHandleV1,
189
+ type ModuleWorkflowInputMaterializationPortV1,
190
+ type ModuleWorkflowInputMaterializationSourceV1,
191
+ type ModuleWorkflowInputMaterializationViewV1,
192
+ moduleWorkflowInputMaterializationHandlerKey,
193
+ } from "./src/workflow-input-artifact-port.js";
194
+ export {
195
+ MODULE_WORKFLOW_INPUT_MATERIALIZATION_LIMITS_V1,
196
+ parseModuleWorkflowInputJsonArtifactV1,
197
+ parseModuleWorkflowInputJsonValueV1,
198
+ parseModuleWorkflowInputMaterializationBeginV1,
199
+ parseModuleWorkflowInputMaterializationPayloadV1,
200
+ parseModuleWorkflowInputMaterializationSourceV1,
201
+ parseModuleWorkflowInputResourceArtifactV1,
202
+ } from "./src/workflow-input-artifact-validation.js";
203
+ export { defineModuleWorkflowInputMaterializationHandlerV1 } from "./src/workflow-input-materialization-handler.js";
204
+ // @windy-module system.agent end
153
205
  export type {
154
206
  GovernedExportRenderedArtifact,
155
207
  GovernedExportWatermarkContext,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@southwind-ai/server-sdk",
3
- "version": "0.4.4",
3
+ "version": "0.4.5",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "engines": {
@@ -32,6 +32,7 @@
32
32
  "src/audit-port.ts",
33
33
  "src/background-ai-port.ts",
34
34
  "src/client-agent-session.ts",
35
+ "src/client-agent-workflow-artifact.ts",
35
36
  "src/data-governance-registration.ts",
36
37
  "src/debug-session-provider.ts",
37
38
  "src/durable-handler.ts",
@@ -52,6 +53,9 @@
52
53
  "src/task-registration.ts",
53
54
  "src/tool-registration.ts",
54
55
  "src/tool-host-port.ts",
56
+ "src/workflow-input-artifact-port.ts",
57
+ "src/workflow-input-artifact-validation.ts",
58
+ "src/workflow-input-materialization-handler.ts",
55
59
  "src/user-directory-port.ts",
56
60
  "contracts/**/*.json"
57
61
  ],
@@ -8,11 +8,23 @@ export interface ModuleClientAgentHostPrincipal {
8
8
  readonly sessionId: string;
9
9
  }
10
10
 
11
+ export type ModuleClientAgentHostAuthPurpose = "control" | "completion";
12
+
11
13
  export interface ModuleClientAgentHostAuthAdapter {
12
14
  ready(signal?: AbortSignal): Promise<boolean>;
13
15
  authenticate(input: {
14
16
  readonly token: string;
15
- readonly purpose: "control" | "completion";
17
+ readonly purpose: ModuleClientAgentHostAuthPurpose;
18
+ readonly signal?: AbortSignal;
19
+ }): Promise<ModuleClientAgentHostPrincipal | undefined>;
20
+ /**
21
+ * Web Cookie 等当前登录会话可选入口。Host 已解析 canonical Actor,Adapter 只确认
22
+ * installation/session 绑定;返回 principal 仍不得携带权限、Scope 或业务坐标。
23
+ */
24
+ authenticateCurrentSession?(input: {
25
+ readonly request: Request;
26
+ readonly actorId: string;
27
+ readonly purpose: ModuleClientAgentHostAuthPurpose;
16
28
  readonly signal?: AbortSignal;
17
29
  }): Promise<ModuleClientAgentHostPrincipal | undefined>;
18
30
  bindRevocations(