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.
- package/dist/cli.js +1008 -61
- package/package.json +1 -1
- package/template/.agents/skills/windy-business-module/SKILL.md +58 -8
- package/template/.windy-template.json +2 -2
- package/template/apps/server/src/agent/client-session/attempt-authority.test.ts +162 -0
- package/template/apps/server/src/agent/client-session/attempt-authority.ts +191 -0
- package/template/apps/server/src/agent/client-session/bootstrap.ts +27 -11
- package/template/apps/server/src/agent/client-session/completion.ts +75 -24
- package/template/apps/server/src/agent/client-session/contracts.ts +23 -0
- package/template/apps/server/src/agent/client-session/creation.ts +103 -0
- package/template/apps/server/src/agent/client-session/digest.ts +11 -1
- package/template/apps/server/src/agent/client-session/drizzle-records.ts +150 -0
- package/template/apps/server/src/agent/client-session/drizzle-repository.integration.test.ts +30 -3
- package/template/apps/server/src/agent/client-session/drizzle-repository.ts +23 -132
- package/template/apps/server/src/agent/client-session/finalization.ts +99 -0
- package/template/apps/server/src/agent/client-session/host-auth.ts +22 -10
- package/template/apps/server/src/agent/client-session/host-revocation-composition.test.ts +77 -0
- package/template/apps/server/src/agent/client-session/host-revocation-composition.ts +28 -0
- package/template/apps/server/src/agent/client-session/launch-authority.contract.test.ts +21 -0
- package/template/apps/server/src/agent/client-session/manifest-admission.ts +11 -0
- package/template/apps/server/src/agent/client-session/service.test-support.ts +22 -0
- package/template/apps/server/src/agent/client-session/service.ts +104 -134
- package/template/apps/server/src/agent/client-session/terminal-digest.test.ts +23 -0
- package/template/apps/server/src/agent/client-workflow-artifact/active-blob-references.ts +8 -0
- package/template/apps/server/src/agent/client-workflow-artifact/artifact-builder.ts +60 -0
- package/template/apps/server/src/agent/client-workflow-artifact/authority-current.ts +59 -0
- package/template/apps/server/src/agent/client-workflow-artifact/binding-registry.test.ts +189 -0
- package/template/apps/server/src/agent/client-workflow-artifact/binding-registry.ts +153 -0
- package/template/apps/server/src/agent/client-workflow-artifact/bootstrap.ts +77 -0
- package/template/apps/server/src/agent/client-workflow-artifact/cancellation.ts +47 -0
- package/template/apps/server/src/agent/client-workflow-artifact/completed-recovery.ts +31 -0
- package/template/apps/server/src/agent/client-workflow-artifact/contracts.ts +104 -0
- package/template/apps/server/src/agent/client-workflow-artifact/drizzle-locks.ts +30 -0
- package/template/apps/server/src/agent/client-workflow-artifact/drizzle-mapper.ts +138 -0
- package/template/apps/server/src/agent/client-workflow-artifact/drizzle-repository.ts +346 -0
- package/template/apps/server/src/agent/client-workflow-artifact/error.ts +21 -0
- package/template/apps/server/src/agent/client-workflow-artifact/handler.ts +167 -0
- package/template/apps/server/src/agent/client-workflow-artifact/host-revocation.ts +29 -0
- package/template/apps/server/src/agent/client-workflow-artifact/in-memory-repository.ts +232 -0
- package/template/apps/server/src/agent/client-workflow-artifact/job-port.ts +101 -0
- package/template/apps/server/src/agent/client-workflow-artifact/presentation.ts +41 -0
- package/template/apps/server/src/agent/client-workflow-artifact/recovery.contract.test.ts +253 -0
- package/template/apps/server/src/agent/client-workflow-artifact/release-binding.ts +85 -0
- package/template/apps/server/src/agent/client-workflow-artifact/repository.test.ts +204 -0
- package/template/apps/server/src/agent/client-workflow-artifact/repository.ts +97 -0
- package/template/apps/server/src/agent/client-workflow-artifact/routes-handler.contract.test.ts +201 -0
- package/template/apps/server/src/agent/client-workflow-artifact/routes.ts +161 -0
- package/template/apps/server/src/agent/client-workflow-artifact/runtime-composition.ts +101 -0
- package/template/apps/server/src/agent/client-workflow-artifact/scope-authority.ts +39 -0
- package/template/apps/server/src/agent/client-workflow-artifact/service-authorization.ts +117 -0
- package/template/apps/server/src/agent/client-workflow-artifact/service-support.ts +28 -0
- package/template/apps/server/src/agent/client-workflow-artifact/service.contract.test.ts +345 -0
- package/template/apps/server/src/agent/client-workflow-artifact/service.ts +350 -0
- package/template/apps/server/src/agent/client-workflow-artifact/session-boundary.ts +39 -0
- package/template/apps/server/src/agent/client-workflow-artifact/source-access.contract.test.ts +98 -0
- package/template/apps/server/src/agent/client-workflow-artifact/source-access.ts +80 -0
- package/template/apps/server/src/agent/client-workflow-artifact/takeover.ts +122 -0
- package/template/apps/server/src/agent/client-workflow-artifact/task-authority.contract.test.ts +97 -0
- package/template/apps/server/src/agent/client-workflow-artifact/task-authority.ts +147 -0
- package/template/apps/server/src/agent/client-workflow-artifact/terminal-authority.contract.test.ts +100 -0
- package/template/apps/server/src/agent/client-workflow-artifact/terminal-replay.ts +31 -0
- package/template/apps/server/src/agent/client-workflow-artifact/terminal-seal.ts +211 -0
- package/template/apps/server/src/agent/client-workflow-artifact/workflow-artifact.test-support.ts +173 -0
- package/template/apps/server/src/agent/client-workflow-artifact/workflow-loader.contract.test.ts +254 -0
- package/template/apps/server/src/agent/client-workflow-artifact/workflow-loader.ts +285 -0
- package/template/apps/server/src/agent/run-facade.test-support.ts +17 -4
- package/template/apps/server/src/agent/run-facade.test.ts +16 -0
- package/template/apps/server/src/agent/run-session-authorization.ts +12 -10
- package/template/apps/server/src/agent/runtime-bootstrap-input.ts +5 -1
- package/template/apps/server/src/agent/runtime-bootstrap.ts +33 -33
- package/template/apps/server/src/agent/runtime-public-ports.ts +40 -0
- package/template/apps/server/src/agent/session-invalidation/contracts.ts +25 -26
- package/template/apps/server/src/agent/session-projection-access.ts +31 -19
- package/template/apps/server/src/agent/unavailable-routes.ts +21 -0
- package/template/apps/server/src/agent/workflow-runtime-bootstrap.ts +2 -0
- package/template/apps/server/src/agent-workflow/artifact-source-authorization.ts +12 -6
- package/template/apps/server/src/agent-workflow/command-facade.ts +70 -11
- package/template/apps/server/src/agent-workflow/drizzle-artifact-port.ts +9 -9
- package/template/apps/server/src/agent-workflow/drizzle-delegation-completion.ts +1 -1
- package/template/apps/server/src/agent-workflow/platform-node-adapters.ts +14 -6
- package/template/apps/server/src/agent-workflow/project-launch-authority.contract.test.ts +53 -0
- package/template/apps/server/src/agent-workflow/project-launch-authority.ts +92 -0
- package/template/apps/server/src/agent-workflow/runtime-composition.ts +30 -14
- package/template/apps/server/src/app/agent-runtime-composition.ts +6 -1
- package/template/apps/server/src/app/client-agent-workflow-artifact-binding.ts +14 -0
- package/template/apps/server/src/application-services.ts +6 -0
- package/template/apps/server/src/data-access/scope-containment.test.ts +31 -0
- package/template/apps/server/src/data-access/scope-containment.ts +48 -0
- package/template/apps/server/src/jobs/artifact-publication.test.ts +192 -0
- package/template/apps/server/src/jobs/artifact-publication.ts +56 -0
- package/template/apps/server/src/jobs/artifact-publisher.ts +101 -0
- package/template/apps/server/src/jobs/drizzle-artifact.ts +73 -1
- package/template/apps/server/src/jobs/drizzle-execution-repository.ts +14 -1
- package/template/apps/server/src/jobs/drizzle-execution.integration.test.ts +65 -0
- package/template/apps/server/src/jobs/drizzle-repository.integration.test.ts +1 -0
- package/template/apps/server/src/jobs/execution-repository.ts +28 -0
- package/template/apps/server/src/jobs/execution.test.ts +3 -1
- package/template/apps/server/src/jobs/in-memory-execution.ts +16 -0
- package/template/apps/server/src/jobs/in-memory-lease.ts +45 -1
- package/template/apps/server/src/jobs/legacy-adapter.integration.test.ts +2 -0
- package/template/apps/server/src/jobs/postgres-cleanup-contract.test.ts +58 -0
- package/template/apps/server/src/jobs/worker.ts +8 -14
- package/template/apps/server/src/module-host/background-ai-unavailable.ts +18 -0
- package/template/apps/server/src/module-host/durable-context.ts +19 -22
- package/template/apps/server/src/module-host/implementation-completeness.test.ts +80 -1
- package/template/apps/server/src/module-host/implementation-completeness.ts +28 -1
- package/template/apps/server/src/module-host/request-context.ts +32 -8
- package/template/apps/server/src/module-host/storage-port.ts +3 -0
- package/template/apps/server/src/module-host/workflow-input-artifact-port.test.ts +104 -0
- package/template/apps/server/src/module-host/workflow-input-artifact-port.ts +229 -0
- package/template/apps/server/src/module-host/workflow-input-materialization.test.ts +163 -0
- package/template/apps/server/src/module-host/workflow-input-materialization.ts +161 -0
- package/template/apps/server/src/workflow/drizzle-repository.integration.test.ts +1 -0
- package/template/apps/web/src/pages/system/components/ai-runtime/AiRuntimeFilters.vue +2 -1
- package/template/apps/web/src/pages/system/components/ai-runtime/AiRuntimeFilters.webtest.ts +16 -0
- package/template/docs/architecture/agent-workflow.md +13 -2
- package/template/docs/architecture/durable-jobs.md +7 -0
- package/template/docs/operations/agent-session-memory.md +2 -1
- package/template/docs/operations/agent-session-troubleshooting.md +87 -2
- package/template/docs/operations/agent-workflow-recovery.md +25 -14
- package/template/docs/platform/client-agent-session.md +148 -2
- package/template/packages/ai-client/package.json +2 -1
- package/template/packages/ai-client/src/client-agent/index.ts +1 -0
- package/template/packages/ai-client/src/client-agent/workflow-artifact/contracts.ts +85 -0
- package/template/packages/ai-client/src/client-agent/workflow-artifact/http.test.ts +49 -0
- package/template/packages/ai-client/src/client-agent/workflow-artifact/http.ts +82 -0
- package/template/packages/ai-client/src/client-agent/workflow-artifact/index.ts +3 -0
- package/template/packages/ai-client/src/client-agent/workflow-artifact/validation.test.ts +154 -0
- package/template/packages/ai-client/src/client-agent/workflow-artifact/validation.ts +332 -0
- package/template/packages/database/drizzle/0062_client_agent_workflow_artifact.sql +63 -0
- package/template/packages/database/drizzle/meta/0062_snapshot.json +14839 -0
- package/template/packages/database/drizzle/meta/_journal.json +7 -0
- package/template/packages/database/package.json +1 -1
- package/template/packages/database/src/agent-runtime-schema.test.ts +177 -0
- package/template/packages/database/src/schema/client-agent-workflow-artifact.ts +158 -0
- package/template/packages/database/src/schema/index.ts +1 -0
- package/template/packages/jobs/package.json +1 -1
- package/template/packages/jobs/src/handlers.test.ts +10 -0
- package/template/packages/jobs/src/handlers.ts +28 -11
- package/template/packages/modules/package.json +1 -1
- package/template/packages/modules/src/ai-client-execution-policy.ts +6 -0
- package/template/packages/modules/src/manifest.ts +2 -0
- package/template/packages/modules/src/system-agent-audit-actions.ts +3 -0
- package/template/packages/modules/src/system-ai-api-bindings.ts +15 -0
- package/template/packages/modules/src/system-audit-actions.ts +15 -0
- package/template/packages/server-sdk/index.ts +52 -0
- package/template/packages/server-sdk/package.json +5 -1
- package/template/packages/server-sdk/src/client-agent-session.ts +13 -1
- package/template/packages/server-sdk/src/client-agent-workflow-artifact.contract.test.ts +113 -0
- package/template/packages/server-sdk/src/client-agent-workflow-artifact.ts +183 -0
- package/template/packages/server-sdk/src/durable-handler.ts +7 -0
- package/template/packages/server-sdk/src/request-context.ts +7 -0
- package/template/packages/server-sdk/src/workflow-input-artifact-port.ts +104 -0
- package/template/packages/server-sdk/src/workflow-input-artifact-validation.contract.test.ts +124 -0
- package/template/packages/server-sdk/src/workflow-input-artifact-validation.ts +347 -0
- package/template/packages/server-sdk/src/workflow-input-materialization-handler.ts +43 -0
- package/template/packages/storage/package.json +1 -1
- package/template/packages/storage/src/blob-store-put-once.test.ts +70 -0
- package/template/packages/storage/src/blob-store.ts +9 -0
- package/template/packages/storage/src/local-file-blob-put-once.ts +120 -0
- package/template/packages/storage/src/local-file-blob-store.ts +53 -1
- package/template/packages/storage/src/memory-blob-store.ts +73 -33
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AdvanceClientAgentWorkflowArtifactRequest,
|
|
3
|
+
CancelClientAgentWorkflowArtifactRequest,
|
|
4
|
+
ClaimClientAgentWorkflowArtifactRequest,
|
|
5
|
+
} from "./contracts.js";
|
|
6
|
+
|
|
7
|
+
export const clientAgentWorkflowArtifactHttp = {
|
|
8
|
+
claim: "/api/agent/client-workflow-artifacts/claim",
|
|
9
|
+
advance: "/api/agent/client-workflow-artifacts/advance",
|
|
10
|
+
cancel: "/api/agent/client-workflow-artifacts/cancel",
|
|
11
|
+
} as const;
|
|
12
|
+
|
|
13
|
+
export type ClientAgentWorkflowArtifactHostAuthentication =
|
|
14
|
+
| { readonly mode: "current-session" }
|
|
15
|
+
| {
|
|
16
|
+
readonly mode: "paired-extension";
|
|
17
|
+
readonly accessToken: `bax_${string}`;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function clientAgentWorkflowArtifactClaimRequest(
|
|
21
|
+
body: ClaimClientAgentWorkflowArtifactRequest,
|
|
22
|
+
authentication: ClientAgentWorkflowArtifactHostAuthentication,
|
|
23
|
+
signal?: AbortSignal,
|
|
24
|
+
): { url: string; init: RequestInit } {
|
|
25
|
+
return jsonRequest(
|
|
26
|
+
clientAgentWorkflowArtifactHttp.claim,
|
|
27
|
+
body,
|
|
28
|
+
authentication,
|
|
29
|
+
signal,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function clientAgentWorkflowArtifactAdvanceRequest<Result>(
|
|
34
|
+
body: AdvanceClientAgentWorkflowArtifactRequest<Result>,
|
|
35
|
+
authentication: ClientAgentWorkflowArtifactHostAuthentication,
|
|
36
|
+
signal?: AbortSignal,
|
|
37
|
+
): { url: string; init: RequestInit } {
|
|
38
|
+
return jsonRequest(
|
|
39
|
+
clientAgentWorkflowArtifactHttp.advance,
|
|
40
|
+
body,
|
|
41
|
+
authentication,
|
|
42
|
+
signal,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function clientAgentWorkflowArtifactCancelRequest(
|
|
47
|
+
body: CancelClientAgentWorkflowArtifactRequest,
|
|
48
|
+
authentication: ClientAgentWorkflowArtifactHostAuthentication,
|
|
49
|
+
signal?: AbortSignal,
|
|
50
|
+
): { url: string; init: RequestInit } {
|
|
51
|
+
return jsonRequest(
|
|
52
|
+
clientAgentWorkflowArtifactHttp.cancel,
|
|
53
|
+
body,
|
|
54
|
+
authentication,
|
|
55
|
+
signal,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function jsonRequest(
|
|
60
|
+
url: string,
|
|
61
|
+
body: unknown,
|
|
62
|
+
authentication: ClientAgentWorkflowArtifactHostAuthentication,
|
|
63
|
+
signal?: AbortSignal,
|
|
64
|
+
): { url: string; init: RequestInit } {
|
|
65
|
+
const headers: Record<string, string> = {
|
|
66
|
+
"content-type": "application/json",
|
|
67
|
+
};
|
|
68
|
+
if (authentication.mode === "paired-extension") {
|
|
69
|
+
headers.authorization = `Bearer ${authentication.accessToken}`;
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
url,
|
|
73
|
+
init: {
|
|
74
|
+
method: "POST",
|
|
75
|
+
headers,
|
|
76
|
+
credentials:
|
|
77
|
+
authentication.mode === "current-session" ? "same-origin" : "omit",
|
|
78
|
+
body: JSON.stringify(body),
|
|
79
|
+
...(signal ? { signal } : {}),
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
ClientAgentWorkflowArtifactContractError,
|
|
4
|
+
parseAdvanceClientAgentWorkflowArtifactRequest,
|
|
5
|
+
parseCancelClientAgentWorkflowArtifactRequest,
|
|
6
|
+
parseClientAgentWorkflowArtifactResponse,
|
|
7
|
+
} from "./validation.js";
|
|
8
|
+
|
|
9
|
+
describe("Client Agent Workflow Artifact validation", () => {
|
|
10
|
+
test("接受短期 grant 与最终 Artifact 安全摘要", () => {
|
|
11
|
+
const running = parseClientAgentWorkflowArtifactResponse({
|
|
12
|
+
workId: workId(),
|
|
13
|
+
status: "running",
|
|
14
|
+
claimVersion: 1,
|
|
15
|
+
claimToken: "cawc_12345678",
|
|
16
|
+
sessionGrant: grant(),
|
|
17
|
+
task: task(),
|
|
18
|
+
});
|
|
19
|
+
const completed = parseClientAgentWorkflowArtifactResponse({
|
|
20
|
+
workId: workId(),
|
|
21
|
+
status: "completed",
|
|
22
|
+
claimVersion: 1,
|
|
23
|
+
artifact: {
|
|
24
|
+
artifactId: "artifact_0001",
|
|
25
|
+
kind: "analysis-report",
|
|
26
|
+
contentType: "application/json",
|
|
27
|
+
filename: "analysis.json",
|
|
28
|
+
byteSize: 1024,
|
|
29
|
+
sha256: "d".repeat(64),
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
expect(running.sessionGrant?.sessionId).toBe("cas_1");
|
|
34
|
+
expect(completed.artifact?.filename).toBe("analysis.json");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("拒绝 advance 注入内部 Workflow 或 Provider 坐标", () => {
|
|
38
|
+
expect(() =>
|
|
39
|
+
parseAdvanceClientAgentWorkflowArtifactRequest({
|
|
40
|
+
...advance(),
|
|
41
|
+
workflowRunId: "workflow-run-1",
|
|
42
|
+
}),
|
|
43
|
+
).toThrow("advance.workflowRunId 不允许");
|
|
44
|
+
expect(() =>
|
|
45
|
+
parseAdvanceClientAgentWorkflowArtifactRequest({
|
|
46
|
+
...advance(),
|
|
47
|
+
providerUrl: "https://provider.example",
|
|
48
|
+
}),
|
|
49
|
+
).toThrow(ClientAgentWorkflowArtifactContractError);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("拒绝 claim token/receipt chain 与终态投影漂移", () => {
|
|
53
|
+
expect(() =>
|
|
54
|
+
parseAdvanceClientAgentWorkflowArtifactRequest({
|
|
55
|
+
...advance(),
|
|
56
|
+
claimToken: "workflow-command-1",
|
|
57
|
+
}),
|
|
58
|
+
).toThrow("claimToken 无效");
|
|
59
|
+
expect(() =>
|
|
60
|
+
parseAdvanceClientAgentWorkflowArtifactRequest({
|
|
61
|
+
...advance(),
|
|
62
|
+
receiptIds: ["receipt_0001", "receipt_0001"],
|
|
63
|
+
}),
|
|
64
|
+
).toThrow("receiptIds 不能重复");
|
|
65
|
+
expect(() =>
|
|
66
|
+
parseClientAgentWorkflowArtifactResponse({
|
|
67
|
+
workId: workId(),
|
|
68
|
+
status: "completed",
|
|
69
|
+
claimVersion: 1,
|
|
70
|
+
}),
|
|
71
|
+
).toThrow("completed response 缺少 artifact");
|
|
72
|
+
expect(() =>
|
|
73
|
+
parseClientAgentWorkflowArtifactResponse({
|
|
74
|
+
workId: workId(),
|
|
75
|
+
status: "running",
|
|
76
|
+
claimVersion: 1,
|
|
77
|
+
claimToken: "cawc_12345678",
|
|
78
|
+
sessionGrant: { ...grant(), providerUrl: "https://provider.example" },
|
|
79
|
+
task: task(),
|
|
80
|
+
}),
|
|
81
|
+
).toThrow("sessionGrant.providerUrl 不允许");
|
|
82
|
+
expect(() =>
|
|
83
|
+
parseCancelClientAgentWorkflowArtifactRequest({
|
|
84
|
+
workId: workId(),
|
|
85
|
+
claimToken: "cawc_12345678",
|
|
86
|
+
claimVersion: 0,
|
|
87
|
+
}),
|
|
88
|
+
).toThrow("claimVersion 必须是正整数");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test("canonical task envelope 严格拒绝未知字段与非 JSON 输入", () => {
|
|
92
|
+
expect(() =>
|
|
93
|
+
parseClientAgentWorkflowArtifactResponse({
|
|
94
|
+
workId: workId(),
|
|
95
|
+
status: "running",
|
|
96
|
+
claimVersion: 1,
|
|
97
|
+
claimToken: "cawc_12345678",
|
|
98
|
+
sessionGrant: grant(),
|
|
99
|
+
task: { ...task(), rawArtifact: { secret: true } },
|
|
100
|
+
}),
|
|
101
|
+
).toThrow("task.rawArtifact 不允许");
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("pending 投影使用尚未领取的 generation 0", () => {
|
|
105
|
+
expect(
|
|
106
|
+
parseClientAgentWorkflowArtifactResponse({
|
|
107
|
+
workId: workId(),
|
|
108
|
+
status: "pending",
|
|
109
|
+
claimVersion: 0,
|
|
110
|
+
}).claimVersion,
|
|
111
|
+
).toBe(0);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
function workId() {
|
|
116
|
+
return `cawa_${"w".repeat(32)}`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function advance() {
|
|
120
|
+
return {
|
|
121
|
+
workId: workId(),
|
|
122
|
+
claimToken: `cawc_${"c".repeat(32)}`,
|
|
123
|
+
claimVersion: 1,
|
|
124
|
+
receiptIds: ["receipt_0001"],
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function grant() {
|
|
129
|
+
return {
|
|
130
|
+
clientRunId: "carun_1",
|
|
131
|
+
sessionId: "cas_1",
|
|
132
|
+
trustedBaseUrl: "https://windy.example/api/agent/client-sessions/cas_1/v1/",
|
|
133
|
+
modelAlias: "windy-client-agent-v1",
|
|
134
|
+
limits: {
|
|
135
|
+
maxSteps: 8,
|
|
136
|
+
maxRequestBytes: 65_536,
|
|
137
|
+
maxResponseBytes: 65_536,
|
|
138
|
+
maxDurationSeconds: 60,
|
|
139
|
+
maxConcurrentRequests: 1,
|
|
140
|
+
},
|
|
141
|
+
expiresAt: "2026-08-28T10:00:00.000Z",
|
|
142
|
+
accessToken: `car_${"a".repeat(43)}`,
|
|
143
|
+
capabilities: ["pageAgentClientRun"],
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function task() {
|
|
148
|
+
return {
|
|
149
|
+
schemaVersion: 1,
|
|
150
|
+
taskKey: "sharp.full-case.client-agent",
|
|
151
|
+
input: { artifactLocator: "case/clue.json" },
|
|
152
|
+
inputDigest: `sha256:${"f".repeat(64)}`,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import { parseClientAgentSessionGrant } from "../validation.js";
|
|
2
|
+
import {
|
|
3
|
+
clientAgentWorkflowArtifactSafeCodes,
|
|
4
|
+
clientAgentWorkflowArtifactWorkIdPrefix,
|
|
5
|
+
type AdvanceClientAgentWorkflowArtifactRequest,
|
|
6
|
+
type CancelClientAgentWorkflowArtifactRequest,
|
|
7
|
+
type ClaimClientAgentWorkflowArtifactRequest,
|
|
8
|
+
type ClientAgentWorkflowArtifactResponse,
|
|
9
|
+
type ClientAgentWorkflowArtifactSafeCode,
|
|
10
|
+
type ClientAgentWorkflowArtifactStatus,
|
|
11
|
+
type ClientAgentWorkflowArtifactSummary,
|
|
12
|
+
type ClientAgentWorkflowExecutionTask,
|
|
13
|
+
type ClientAgentWorkflowJsonValue,
|
|
14
|
+
} from "./contracts.js";
|
|
15
|
+
|
|
16
|
+
export class ClientAgentWorkflowArtifactContractError extends TypeError {
|
|
17
|
+
constructor(message: string) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = "ClientAgentWorkflowArtifactContractError";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function parseClaimClientAgentWorkflowArtifactRequest(
|
|
24
|
+
value: unknown,
|
|
25
|
+
): ClaimClientAgentWorkflowArtifactRequest {
|
|
26
|
+
const input = strictObject(value, "claim", [
|
|
27
|
+
"workflowRunId",
|
|
28
|
+
"clientBindingDigest",
|
|
29
|
+
]);
|
|
30
|
+
return {
|
|
31
|
+
workflowRunId: text(input.workflowRunId, "workflowRunId"),
|
|
32
|
+
clientBindingDigest: digest(
|
|
33
|
+
input.clientBindingDigest,
|
|
34
|
+
"clientBindingDigest",
|
|
35
|
+
),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function parseAdvanceClientAgentWorkflowArtifactRequest<
|
|
40
|
+
Result = unknown,
|
|
41
|
+
>(value: unknown): AdvanceClientAgentWorkflowArtifactRequest<Result> {
|
|
42
|
+
const input = strictObject(value, "advance", [
|
|
43
|
+
"workId",
|
|
44
|
+
"claimToken",
|
|
45
|
+
"claimVersion",
|
|
46
|
+
"receiptIds",
|
|
47
|
+
"result",
|
|
48
|
+
]);
|
|
49
|
+
return {
|
|
50
|
+
workId: workId(input.workId),
|
|
51
|
+
claimToken: claimToken(input.claimToken),
|
|
52
|
+
claimVersion: positive(input.claimVersion, "claimVersion"),
|
|
53
|
+
receiptIds: receiptIds(input.receiptIds),
|
|
54
|
+
...(input.result === undefined ? {} : { result: input.result as Result }),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function parseCancelClientAgentWorkflowArtifactRequest(
|
|
59
|
+
value: unknown,
|
|
60
|
+
): CancelClientAgentWorkflowArtifactRequest {
|
|
61
|
+
const input = strictObject(value, "cancel", [
|
|
62
|
+
"workId",
|
|
63
|
+
"claimToken",
|
|
64
|
+
"claimVersion",
|
|
65
|
+
]);
|
|
66
|
+
return {
|
|
67
|
+
workId: workId(input.workId),
|
|
68
|
+
claimToken: claimToken(input.claimToken),
|
|
69
|
+
claimVersion: positive(input.claimVersion, "claimVersion"),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function parseClientAgentWorkflowArtifactResponse(
|
|
74
|
+
value: unknown,
|
|
75
|
+
): ClientAgentWorkflowArtifactResponse {
|
|
76
|
+
const input = strictObject(value, "response", [
|
|
77
|
+
"workId",
|
|
78
|
+
"status",
|
|
79
|
+
"claimVersion",
|
|
80
|
+
"claimToken",
|
|
81
|
+
"sessionGrant",
|
|
82
|
+
"task",
|
|
83
|
+
"artifact",
|
|
84
|
+
"safeCode",
|
|
85
|
+
]);
|
|
86
|
+
const status = workflowStatus(input.status);
|
|
87
|
+
const sessionGrant =
|
|
88
|
+
input.sessionGrant === undefined
|
|
89
|
+
? undefined
|
|
90
|
+
: strictSessionGrant(input.sessionGrant);
|
|
91
|
+
const token =
|
|
92
|
+
input.claimToken === undefined ? undefined : claimToken(input.claimToken);
|
|
93
|
+
const artifact =
|
|
94
|
+
input.artifact === undefined ? undefined : artifactSummary(input.artifact);
|
|
95
|
+
const task = input.task === undefined ? undefined : executionTask(input.task);
|
|
96
|
+
assertProjection(status, token, sessionGrant, task, artifact);
|
|
97
|
+
return {
|
|
98
|
+
workId: workId(input.workId),
|
|
99
|
+
status,
|
|
100
|
+
claimVersion: nonNegative(input.claimVersion, "claimVersion"),
|
|
101
|
+
...(token ? { claimToken: token } : {}),
|
|
102
|
+
...(sessionGrant ? { sessionGrant } : {}),
|
|
103
|
+
...(task ? { task } : {}),
|
|
104
|
+
...(artifact ? { artifact } : {}),
|
|
105
|
+
...(input.safeCode === undefined
|
|
106
|
+
? {}
|
|
107
|
+
: { safeCode: safeCode(input.safeCode) }),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function executionTask(value: unknown): ClientAgentWorkflowExecutionTask {
|
|
112
|
+
const task = strictObject(value, "task", [
|
|
113
|
+
"schemaVersion",
|
|
114
|
+
"taskKey",
|
|
115
|
+
"input",
|
|
116
|
+
"inputDigest",
|
|
117
|
+
]);
|
|
118
|
+
if (task.schemaVersion !== 1) invalid("task.schemaVersion 无效");
|
|
119
|
+
const taskKey = text(task.taskKey, "task.taskKey");
|
|
120
|
+
if (!/^[a-z0-9][a-z0-9._-]*$/u.test(taskKey)) {
|
|
121
|
+
invalid("task.taskKey 无效");
|
|
122
|
+
}
|
|
123
|
+
const input = jsonValue(task.input, "task.input");
|
|
124
|
+
if (new TextEncoder().encode(JSON.stringify(input)).byteLength > 256 * 1024) {
|
|
125
|
+
invalid("task.input 过大");
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
schemaVersion: 1,
|
|
129
|
+
taskKey,
|
|
130
|
+
input,
|
|
131
|
+
inputDigest: digest(task.inputDigest, "task.inputDigest"),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function strictSessionGrant(value: unknown) {
|
|
136
|
+
const grant = strictObject(value, "sessionGrant", [
|
|
137
|
+
"clientRunId",
|
|
138
|
+
"sessionId",
|
|
139
|
+
"trustedBaseUrl",
|
|
140
|
+
"modelAlias",
|
|
141
|
+
"limits",
|
|
142
|
+
"expiresAt",
|
|
143
|
+
"accessToken",
|
|
144
|
+
"capabilities",
|
|
145
|
+
]);
|
|
146
|
+
strictObject(grant.limits, "sessionGrant.limits", [
|
|
147
|
+
"maxSteps",
|
|
148
|
+
"maxRequestBytes",
|
|
149
|
+
"maxResponseBytes",
|
|
150
|
+
"maxDurationSeconds",
|
|
151
|
+
"maxConcurrentRequests",
|
|
152
|
+
]);
|
|
153
|
+
return parseClientAgentSessionGrant(grant);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function artifactSummary(value: unknown): ClientAgentWorkflowArtifactSummary {
|
|
157
|
+
const artifact = strictObject(value, "artifact", [
|
|
158
|
+
"artifactId",
|
|
159
|
+
"kind",
|
|
160
|
+
"contentType",
|
|
161
|
+
"filename",
|
|
162
|
+
"byteSize",
|
|
163
|
+
"sha256",
|
|
164
|
+
]);
|
|
165
|
+
const filename = text(artifact.filename, "artifact.filename");
|
|
166
|
+
if (filename.includes("/") || filename.includes("\\")) {
|
|
167
|
+
invalid("artifact.filename 无效");
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
artifactId: opaque(artifact.artifactId, "artifact.artifactId"),
|
|
171
|
+
kind: text(artifact.kind, "artifact.kind"),
|
|
172
|
+
contentType: text(artifact.contentType, "artifact.contentType"),
|
|
173
|
+
filename,
|
|
174
|
+
byteSize: nonNegative(artifact.byteSize, "artifact.byteSize"),
|
|
175
|
+
sha256: hexDigest(artifact.sha256, "artifact.sha256"),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function assertProjection(
|
|
180
|
+
status: ClientAgentWorkflowArtifactStatus,
|
|
181
|
+
token: unknown,
|
|
182
|
+
sessionGrant: unknown,
|
|
183
|
+
task: unknown,
|
|
184
|
+
artifact: unknown,
|
|
185
|
+
) {
|
|
186
|
+
if (status === "running" && (!token || !sessionGrant || !task)) {
|
|
187
|
+
invalid("running response 缺少 claimToken、sessionGrant 或 task");
|
|
188
|
+
}
|
|
189
|
+
if (status === "completed" && !artifact) {
|
|
190
|
+
invalid("completed response 缺少 artifact");
|
|
191
|
+
}
|
|
192
|
+
if (status !== "running" && (token || sessionGrant || task)) {
|
|
193
|
+
invalid("只有 running response 可以包含 claimToken、sessionGrant 和 task");
|
|
194
|
+
}
|
|
195
|
+
if (status !== "completed" && artifact) {
|
|
196
|
+
invalid("只有 completed response 可以包含 artifact");
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function jsonValue(
|
|
201
|
+
value: unknown,
|
|
202
|
+
label: string,
|
|
203
|
+
depth = 0,
|
|
204
|
+
): ClientAgentWorkflowJsonValue {
|
|
205
|
+
if (depth > 32) invalid(`${label} 嵌套过深`);
|
|
206
|
+
if (
|
|
207
|
+
value === null ||
|
|
208
|
+
typeof value === "string" ||
|
|
209
|
+
typeof value === "boolean" ||
|
|
210
|
+
(typeof value === "number" && Number.isFinite(value))
|
|
211
|
+
) {
|
|
212
|
+
return value;
|
|
213
|
+
}
|
|
214
|
+
if (Array.isArray(value)) {
|
|
215
|
+
return value.map((item) => jsonValue(item, label, depth + 1));
|
|
216
|
+
}
|
|
217
|
+
if (value && typeof value === "object") {
|
|
218
|
+
const record = value as Record<string, unknown>;
|
|
219
|
+
return Object.fromEntries(
|
|
220
|
+
Object.entries(record).map(([key, item]) => [
|
|
221
|
+
key,
|
|
222
|
+
jsonValue(item, `${label}.${key}`, depth + 1),
|
|
223
|
+
]),
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
invalid(`${label} 不是 JSON`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function workflowStatus(value: unknown): ClientAgentWorkflowArtifactStatus {
|
|
230
|
+
if (
|
|
231
|
+
value !== "pending" &&
|
|
232
|
+
value !== "running" &&
|
|
233
|
+
value !== "completed" &&
|
|
234
|
+
value !== "cancelled"
|
|
235
|
+
) {
|
|
236
|
+
invalid("status 无效");
|
|
237
|
+
}
|
|
238
|
+
return value;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function safeCode(value: unknown): ClientAgentWorkflowArtifactSafeCode {
|
|
242
|
+
if (!clientAgentWorkflowArtifactSafeCodes.includes(value as never)) {
|
|
243
|
+
invalid("safeCode 无效");
|
|
244
|
+
}
|
|
245
|
+
return value as ClientAgentWorkflowArtifactSafeCode;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function receiptIds(value: unknown): readonly string[] {
|
|
249
|
+
if (!Array.isArray(value) || value.length === 0 || value.length > 128) {
|
|
250
|
+
invalid("receiptIds 无效");
|
|
251
|
+
}
|
|
252
|
+
const parsed = value.map((item) => opaque(item, "receiptId"));
|
|
253
|
+
if (new Set(parsed).size !== parsed.length) invalid("receiptIds 不能重复");
|
|
254
|
+
return parsed;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function workId(value: unknown): string {
|
|
258
|
+
return prefixedOpaque(
|
|
259
|
+
value,
|
|
260
|
+
"workId",
|
|
261
|
+
clientAgentWorkflowArtifactWorkIdPrefix,
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function claimToken(value: unknown): string {
|
|
266
|
+
return prefixedOpaque(value, "claimToken", "cawc_");
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function prefixedOpaque(value: unknown, label: string, prefix: string): string {
|
|
270
|
+
const parsed = opaque(value, label);
|
|
271
|
+
if (!parsed.startsWith(prefix)) invalid(`${label} 无效`);
|
|
272
|
+
return parsed;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function opaque(value: unknown, label: string): string {
|
|
276
|
+
const parsed = text(value, label);
|
|
277
|
+
if (!/^[A-Za-z0-9_-]{8,512}$/u.test(parsed)) invalid(`${label} 无效`);
|
|
278
|
+
return parsed;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function strictObject(
|
|
282
|
+
value: unknown,
|
|
283
|
+
label: string,
|
|
284
|
+
allowedKeys: readonly string[],
|
|
285
|
+
): Record<string, unknown> {
|
|
286
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
287
|
+
invalid(`${label} 必须是对象`);
|
|
288
|
+
}
|
|
289
|
+
const record = value as Record<string, unknown>;
|
|
290
|
+
const unknownKey = Object.keys(record).find(
|
|
291
|
+
(key) => !allowedKeys.includes(key),
|
|
292
|
+
);
|
|
293
|
+
if (unknownKey) invalid(`${label}.${unknownKey} 不允许`);
|
|
294
|
+
return record;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function text(value: unknown, label: string): string {
|
|
298
|
+
if (typeof value !== "string" || !value.trim() || value.length > 512) {
|
|
299
|
+
invalid(`${label} 无效`);
|
|
300
|
+
}
|
|
301
|
+
return value;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function positive(value: unknown, label: string): number {
|
|
305
|
+
if (!Number.isSafeInteger(value) || Number(value) <= 0) {
|
|
306
|
+
invalid(`${label} 必须是正整数`);
|
|
307
|
+
}
|
|
308
|
+
return Number(value);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function nonNegative(value: unknown, label: string): number {
|
|
312
|
+
if (!Number.isSafeInteger(value) || Number(value) < 0) {
|
|
313
|
+
invalid(`${label} 必须是非负整数`);
|
|
314
|
+
}
|
|
315
|
+
return Number(value);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function digest(value: unknown, label: string): `sha256:${string}` {
|
|
319
|
+
const parsed = text(value, label);
|
|
320
|
+
if (!/^sha256:[a-f0-9]{64}$/u.test(parsed)) invalid(`${label} 无效`);
|
|
321
|
+
return parsed as `sha256:${string}`;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function hexDigest(value: unknown, label: string): string {
|
|
325
|
+
const parsed = text(value, label);
|
|
326
|
+
if (!/^[a-f0-9]{64}$/u.test(parsed)) invalid(`${label} 无效`);
|
|
327
|
+
return parsed;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function invalid(message: string): never {
|
|
331
|
+
throw new ClientAgentWorkflowArtifactContractError(message);
|
|
332
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
CREATE TABLE "client_agent_workflow_artifacts" (
|
|
2
|
+
"work_id" varchar(80) PRIMARY KEY NOT NULL,
|
|
3
|
+
"command_id" varchar(96) NOT NULL,
|
|
4
|
+
"durable_job_id" varchar(64) NOT NULL,
|
|
5
|
+
"run_id" varchar(96) NOT NULL,
|
|
6
|
+
"node_run_id" varchar(96) NOT NULL,
|
|
7
|
+
"effect_kind" varchar(24) NOT NULL,
|
|
8
|
+
"task_key" varchar(160) NOT NULL,
|
|
9
|
+
"operation_key" varchar(200) NOT NULL,
|
|
10
|
+
"binding_digest" varchar(71) NOT NULL,
|
|
11
|
+
"actor_id" varchar(64) NOT NULL,
|
|
12
|
+
"scope_digest" varchar(71) NOT NULL,
|
|
13
|
+
"authorization_snapshot_digest" varchar(71) NOT NULL,
|
|
14
|
+
"run_policy_digest" varchar(71) NOT NULL,
|
|
15
|
+
"request_digest" varchar(71) NOT NULL,
|
|
16
|
+
"input_digest" varchar(71) NOT NULL,
|
|
17
|
+
"effect_generation" integer NOT NULL,
|
|
18
|
+
"effect_fence_token_digest" varchar(71) NOT NULL,
|
|
19
|
+
"status" varchar(32) NOT NULL,
|
|
20
|
+
"claim_generation" integer DEFAULT 0 NOT NULL,
|
|
21
|
+
"client_binding_digest" varchar(71),
|
|
22
|
+
"installation_id" varchar(160),
|
|
23
|
+
"host_session_digest" varchar(71),
|
|
24
|
+
"client_session_id" varchar(80),
|
|
25
|
+
"claim_token_hash" varchar(71),
|
|
26
|
+
"claim_expires_at" double precision,
|
|
27
|
+
"history_sequence" integer DEFAULT 0 NOT NULL,
|
|
28
|
+
"history_head_digest" varchar(71),
|
|
29
|
+
"terminal_receipt_id" varchar(96),
|
|
30
|
+
"terminal_receipt_digest" varchar(71),
|
|
31
|
+
"terminal_request_digest" varchar(71),
|
|
32
|
+
"terminal_result_json" jsonb,
|
|
33
|
+
"artifact_ref" varchar(37),
|
|
34
|
+
"artifact_filename" varchar(240),
|
|
35
|
+
"artifact_content_type" varchar(120),
|
|
36
|
+
"artifact_byte_size" integer,
|
|
37
|
+
"artifact_sha256" varchar(64),
|
|
38
|
+
"cancel_requested_at" double precision,
|
|
39
|
+
"finished_at" double precision,
|
|
40
|
+
"version" integer DEFAULT 1 NOT NULL,
|
|
41
|
+
"created_at" double precision NOT NULL,
|
|
42
|
+
"updated_at" double precision NOT NULL,
|
|
43
|
+
CONSTRAINT "ck_client_agent_workflow_status" CHECK ("client_agent_workflow_artifacts"."status" in ('pending', 'claimed', 'cancellation-requested', 'completed', 'cancelled')),
|
|
44
|
+
CONSTRAINT "ck_client_agent_workflow_generation" CHECK ("client_agent_workflow_artifacts"."effect_generation" > 0 and "client_agent_workflow_artifacts"."claim_generation" >= 0),
|
|
45
|
+
CONSTRAINT "ck_client_agent_workflow_effect_kind" CHECK ("client_agent_workflow_artifacts"."effect_kind" = 'job'),
|
|
46
|
+
CONSTRAINT "ck_client_agent_workflow_claim_binding" CHECK (("client_agent_workflow_artifacts"."claim_generation" = 0 and "client_agent_workflow_artifacts"."status" in ('pending', 'cancellation-requested', 'cancelled') and "client_agent_workflow_artifacts"."client_binding_digest" is null and "client_agent_workflow_artifacts"."installation_id" is null and "client_agent_workflow_artifacts"."host_session_digest" is null and "client_agent_workflow_artifacts"."client_session_id" is null and "client_agent_workflow_artifacts"."claim_token_hash" is null and "client_agent_workflow_artifacts"."claim_expires_at" is null)
|
|
47
|
+
or ("client_agent_workflow_artifacts"."claim_generation" > 0 and "client_agent_workflow_artifacts"."status" <> 'pending' and "client_agent_workflow_artifacts"."client_binding_digest" is not null and "client_agent_workflow_artifacts"."installation_id" is not null and "client_agent_workflow_artifacts"."host_session_digest" is not null)),
|
|
48
|
+
CONSTRAINT "ck_client_agent_workflow_terminal" CHECK (("client_agent_workflow_artifacts"."status" = 'completed' and "client_agent_workflow_artifacts"."terminal_receipt_id" is not null and "client_agent_workflow_artifacts"."terminal_receipt_digest" is not null and "client_agent_workflow_artifacts"."terminal_request_digest" is not null and "client_agent_workflow_artifacts"."terminal_result_json" is not null and "client_agent_workflow_artifacts"."artifact_ref" is not null and "client_agent_workflow_artifacts"."artifact_filename" is not null and "client_agent_workflow_artifacts"."artifact_content_type" is not null and "client_agent_workflow_artifacts"."artifact_byte_size" is not null and "client_agent_workflow_artifacts"."artifact_sha256" is not null and "client_agent_workflow_artifacts"."finished_at" is not null)
|
|
49
|
+
or ("client_agent_workflow_artifacts"."status" = 'cancelled' and "client_agent_workflow_artifacts"."finished_at" is not null and "client_agent_workflow_artifacts"."terminal_receipt_id" is null and "client_agent_workflow_artifacts"."terminal_request_digest" is null and "client_agent_workflow_artifacts"."artifact_ref" is null)
|
|
50
|
+
or ("client_agent_workflow_artifacts"."status" in ('pending', 'claimed', 'cancellation-requested') and "client_agent_workflow_artifacts"."finished_at" is null and "client_agent_workflow_artifacts"."terminal_receipt_id" is null and "client_agent_workflow_artifacts"."terminal_request_digest" is null and "client_agent_workflow_artifacts"."artifact_ref" is null)),
|
|
51
|
+
CONSTRAINT "ck_client_agent_workflow_history" CHECK ("client_agent_workflow_artifacts"."history_sequence" >= 0 and ("client_agent_workflow_artifacts"."history_sequence" = 0 or "client_agent_workflow_artifacts"."history_head_digest" is not null)),
|
|
52
|
+
CONSTRAINT "ck_client_agent_workflow_version" CHECK ("client_agent_workflow_artifacts"."version" > 0 and "client_agent_workflow_artifacts"."created_at" <= "client_agent_workflow_artifacts"."updated_at")
|
|
53
|
+
);
|
|
54
|
+
--> statement-breakpoint
|
|
55
|
+
ALTER TABLE "client_agent_workflow_artifacts" ADD CONSTRAINT "client_agent_workflow_artifacts_durable_job_id_durable_jobs_id_fk" FOREIGN KEY ("durable_job_id") REFERENCES "public"."durable_jobs"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
56
|
+
ALTER TABLE "client_agent_workflow_artifacts" ADD CONSTRAINT "client_agent_workflow_artifacts_client_session_id_client_agent_sessions_session_id_fk" FOREIGN KEY ("client_session_id") REFERENCES "public"."client_agent_sessions"("session_id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
57
|
+
ALTER TABLE "client_agent_workflow_artifacts" ADD CONSTRAINT "fk_client_agent_workflow_effect_fence" FOREIGN KEY ("command_id","run_id","node_run_id","effect_kind","effect_generation","request_digest","effect_fence_token_digest") REFERENCES "public"."agent_workflow_side_effect_commands"("command_id","run_id","node_run_id","effect_kind","generation","request_digest","fence_token_digest") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
58
|
+
CREATE UNIQUE INDEX "uk_client_agent_workflow_command" ON "client_agent_workflow_artifacts" USING btree ("command_id");--> statement-breakpoint
|
|
59
|
+
CREATE UNIQUE INDEX "uk_client_agent_workflow_job" ON "client_agent_workflow_artifacts" USING btree ("durable_job_id");--> statement-breakpoint
|
|
60
|
+
CREATE UNIQUE INDEX "uk_client_agent_workflow_terminal_receipt" ON "client_agent_workflow_artifacts" USING btree ("terminal_receipt_id");--> statement-breakpoint
|
|
61
|
+
CREATE UNIQUE INDEX "uk_client_agent_workflow_client_session" ON "client_agent_workflow_artifacts" USING btree ("client_session_id");--> statement-breakpoint
|
|
62
|
+
CREATE INDEX "idx_client_agent_workflow_claim" ON "client_agent_workflow_artifacts" USING btree ("actor_id","status","updated_at");--> statement-breakpoint
|
|
63
|
+
CREATE INDEX "idx_client_agent_workflow_host" ON "client_agent_workflow_artifacts" USING btree ("host_session_digest","status");
|