@contractspec/integration.workflow-devkit 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/dist/agent-adapter.js +1 -79
- package/dist/browser/agent-adapter.js +1 -79
- package/dist/browser/chat-routes.js +1 -100
- package/dist/browser/compiler.js +17 -141
- package/dist/browser/helpers.js +1 -80
- package/dist/browser/index.js +17 -443
- package/dist/browser/next.js +1 -8
- package/dist/browser/runtime.js +1 -180
- package/dist/chat-routes.js +1 -100
- package/dist/compiler.d.ts +1 -1
- package/dist/compiler.js +17 -141
- package/dist/helpers.d.ts +1 -1
- package/dist/helpers.js +1 -80
- package/dist/index.js +17 -443
- package/dist/next.js +1 -8
- package/dist/node/agent-adapter.js +1 -79
- package/dist/node/chat-routes.js +1 -100
- package/dist/node/compiler.js +17 -141
- package/dist/node/helpers.js +1 -80
- package/dist/node/index.js +17 -443
- package/dist/node/next.js +1 -8
- package/dist/node/runtime.js +1 -180
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +1 -180
- package/dist/types.d.ts +2 -1
- package/package.json +10 -10
package/dist/index.js
CHANGED
|
@@ -1,286 +1,8 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
|
|
3
|
-
class InMemoryWorkflowDevkitCheckpointStore {
|
|
4
|
-
envelopes = new Map;
|
|
5
|
-
async delete(sessionId) {
|
|
6
|
-
this.envelopes.delete(sessionId);
|
|
7
|
-
}
|
|
8
|
-
async load(sessionId) {
|
|
9
|
-
return this.envelopes.get(sessionId) ?? null;
|
|
10
|
-
}
|
|
11
|
-
async save(envelope) {
|
|
12
|
-
this.envelopes.set(envelope.sessionId, envelope);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
class InMemoryWorkflowDevkitSuspensionStore {
|
|
17
|
-
states = new Map;
|
|
18
|
-
async clear(sessionId) {
|
|
19
|
-
this.states.delete(sessionId);
|
|
20
|
-
}
|
|
21
|
-
async get(sessionId) {
|
|
22
|
-
return this.states.get(sessionId) ?? null;
|
|
23
|
-
}
|
|
24
|
-
async set(sessionId, state) {
|
|
25
|
-
this.states.set(sessionId, state);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
function createWorkflowDevkitAgentRuntimeAdapterBundle(options = {}) {
|
|
29
|
-
const checkpointStore = options.checkpointStore ?? new InMemoryWorkflowDevkitCheckpointStore;
|
|
30
|
-
const suspensionStore = options.suspensionStore ?? new InMemoryWorkflowDevkitSuspensionStore;
|
|
31
|
-
const resolveSessionToken = options.resolveSessionToken ?? defaultWorkflowDevkitAgentToken;
|
|
32
|
-
return {
|
|
33
|
-
key: "workflow-devkit",
|
|
34
|
-
checkpoint: {
|
|
35
|
-
delete(sessionId) {
|
|
36
|
-
return checkpointStore.delete(sessionId);
|
|
37
|
-
},
|
|
38
|
-
load(sessionId) {
|
|
39
|
-
return checkpointStore.load(sessionId);
|
|
40
|
-
},
|
|
41
|
-
save(envelope) {
|
|
42
|
-
return checkpointStore.save(envelope);
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
suspendResume: {
|
|
46
|
-
async resume(params) {
|
|
47
|
-
await suspensionStore.set(params.sessionId, {
|
|
48
|
-
input: params.input,
|
|
49
|
-
metadata: params.metadata,
|
|
50
|
-
reason: "resumed",
|
|
51
|
-
resumedAt: new Date,
|
|
52
|
-
suspendedAt: new Date
|
|
53
|
-
});
|
|
54
|
-
if (options.workflowApi) {
|
|
55
|
-
await options.workflowApi.resumeHook(resolveSessionToken(params.sessionId), {
|
|
56
|
-
input: params.input,
|
|
57
|
-
metadata: params.metadata,
|
|
58
|
-
sessionId: params.sessionId
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
async suspend(params) {
|
|
63
|
-
await suspensionStore.set(params.sessionId, {
|
|
64
|
-
metadata: params.metadata,
|
|
65
|
-
reason: params.reason,
|
|
66
|
-
suspendedAt: new Date
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
function defaultWorkflowDevkitAgentToken(sessionId) {
|
|
73
|
-
return `agent-session:${sessionId}`;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// src/chat-routes.ts
|
|
77
|
-
import { createUIMessageStreamResponse } from "ai";
|
|
78
|
-
import { getRun, resumeHook, start } from "workflow/api";
|
|
79
|
-
var WORKFLOW_RUN_ID_HEADER = "x-workflow-run-id";
|
|
80
|
-
var WORKFLOW_STREAM_TAIL_INDEX_HEADER = "x-workflow-stream-tail-index";
|
|
81
|
-
function createWorkflowDevkitStartRoute(options) {
|
|
82
|
-
const workflowApi = options.workflowApi ?? { start };
|
|
83
|
-
return async (request) => {
|
|
84
|
-
const body = await request.json();
|
|
85
|
-
const args = await options.buildArgs(body, request);
|
|
86
|
-
const run = await workflowApi.start(options.workflow, args);
|
|
87
|
-
if (options.createResponse) {
|
|
88
|
-
return options.createResponse({ body, run });
|
|
89
|
-
}
|
|
90
|
-
if (!run.readable) {
|
|
91
|
-
return new Response(JSON.stringify({ runId: run.runId }), {
|
|
92
|
-
headers: {
|
|
93
|
-
"Content-Type": "application/json",
|
|
94
|
-
[WORKFLOW_RUN_ID_HEADER]: run.runId
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
return createUIMessageStreamResponse({
|
|
99
|
-
headers: {
|
|
100
|
-
[WORKFLOW_RUN_ID_HEADER]: run.runId
|
|
101
|
-
},
|
|
102
|
-
stream: run.readable
|
|
103
|
-
});
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
function createWorkflowDevkitFollowUpRoute(options) {
|
|
107
|
-
const workflowApi = options.workflowApi ?? { resumeHook };
|
|
108
|
-
return async (request, context) => {
|
|
109
|
-
const runId = context.params.runId ?? context.params.id;
|
|
110
|
-
if (!runId) {
|
|
111
|
-
return new Response(JSON.stringify({ error: "Missing run id" }), {
|
|
112
|
-
status: 400
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
const body = await request.json();
|
|
116
|
-
const token = options.resolveToken({ body, request, runId });
|
|
117
|
-
const payload = options.buildPayload ? await options.buildPayload(body, request) : body;
|
|
118
|
-
await workflowApi.resumeHook(token, payload);
|
|
119
|
-
return new Response(JSON.stringify({ ok: true }), {
|
|
120
|
-
headers: {
|
|
121
|
-
"Content-Type": "application/json",
|
|
122
|
-
[WORKFLOW_RUN_ID_HEADER]: runId
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
function createWorkflowDevkitStreamRoute(options = {}) {
|
|
128
|
-
const workflowApi = options.workflowApi ?? { getRun };
|
|
129
|
-
return async (request, context) => {
|
|
130
|
-
const runId = context.params.runId ?? context.params.id;
|
|
131
|
-
if (!runId) {
|
|
132
|
-
return new Response(JSON.stringify({ error: "Missing run id" }), {
|
|
133
|
-
status: 400
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
const run = workflowApi.getRun(runId);
|
|
137
|
-
if (!run) {
|
|
138
|
-
return new Response(JSON.stringify({ error: "Workflow run not found" }), {
|
|
139
|
-
status: 404
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
const startIndex = readStartIndex(request.url);
|
|
143
|
-
const readable = run.getReadable ? run.getReadable({ startIndex }) : run.readable;
|
|
144
|
-
if (!readable) {
|
|
145
|
-
return new Response(JSON.stringify({ error: "Run has no readable stream" }), {
|
|
146
|
-
status: 404
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
const tailIndex = await readable.getTailIndex?.();
|
|
150
|
-
return createUIMessageStreamResponse({
|
|
151
|
-
headers: {
|
|
152
|
-
...tailIndex !== undefined ? {
|
|
153
|
-
[WORKFLOW_STREAM_TAIL_INDEX_HEADER]: String(tailIndex)
|
|
154
|
-
} : {}
|
|
155
|
-
},
|
|
156
|
-
stream: readable
|
|
157
|
-
});
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
function readStartIndex(url) {
|
|
161
|
-
const parsed = new URL(url);
|
|
162
|
-
const rawStartIndex = parsed.searchParams.get("startIndex");
|
|
163
|
-
if (!rawStartIndex) {
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
const parsedStartIndex = Number(rawStartIndex);
|
|
167
|
-
return Number.isFinite(parsedStartIndex) ? parsedStartIndex : undefined;
|
|
168
|
-
}
|
|
2
|
+
class Y{envelopes=new Map;async delete(C){this.envelopes.delete(C)}async load(C){return this.envelopes.get(C)??null}async save(C){this.envelopes.set(C.sessionId,C)}}class Z{states=new Map;async clear(C){this.states.delete(C)}async get(C){return this.states.get(C)??null}async set(C,_){this.states.set(C,_)}}function F(C={}){let _=C.checkpointStore??new Y,H=C.suspensionStore??new Z,A=C.resolveSessionToken??M;return{key:"workflow-devkit",checkpoint:{delete(O){return _.delete(O)},load(O){return _.load(O)},save(O){return _.save(O)}},suspendResume:{async resume(O){if(await H.set(O.sessionId,{input:O.input,metadata:O.metadata,reason:"resumed",resumedAt:new Date,suspendedAt:new Date}),C.workflowApi)await C.workflowApi.resumeHook(A(O.sessionId),{input:O.input,metadata:O.metadata,sessionId:O.sessionId})},async suspend(O){await H.set(O.sessionId,{metadata:O.metadata,reason:O.reason,suspendedAt:new Date})}}}}function M(C){return`agent-session:${C}`}import{createUIMessageStreamResponse as P}from"ai";import{getRun as f,resumeHook as h,start as N}from"workflow/api";var Q="x-workflow-run-id",B="x-workflow-stream-tail-index";function g(C){let _=C.workflowApi??{start:N};return async(H)=>{let A=await H.json(),O=await C.buildArgs(A,H),K=await _.start(C.workflow,O);if(C.createResponse)return C.createResponse({body:A,run:K});if(!K.readable)return new Response(JSON.stringify({runId:K.runId}),{headers:{"Content-Type":"application/json",[Q]:K.runId}});return P({headers:{[Q]:K.runId},stream:K.readable})}}function S(C){let _=C.workflowApi??{resumeHook:h};return async(H,A)=>{let O=A.params.runId??A.params.id;if(!O)return new Response(JSON.stringify({error:"Missing run id"}),{status:400});let K=await H.json(),L=C.resolveToken({body:K,request:H,runId:O}),W=C.buildPayload?await C.buildPayload(K,H):K;return await _.resumeHook(L,W),new Response(JSON.stringify({ok:!0}),{headers:{"Content-Type":"application/json",[Q]:O}})}}function y(C={}){let _=C.workflowApi??{getRun:f};return async(H,A)=>{let O=A.params.runId??A.params.id;if(!O)return new Response(JSON.stringify({error:"Missing run id"}),{status:400});let K=_.getRun(O);if(!K)return new Response(JSON.stringify({error:"Workflow run not found"}),{status:404});let L=w(H.url),W=K.getReadable?K.getReadable({startIndex:L}):K.readable;if(!W)return new Response(JSON.stringify({error:"Run has no readable stream"}),{status:404});let j=await W.getTailIndex?.();return P({headers:{...j!==void 0?{[B]:String(j)}:{}},stream:W})}}function w(C){let H=new URL(C).searchParams.get("startIndex");if(!H)return;let A=Number(H);return Number.isFinite(A)?A:void 0}import{evaluateExpression as b}from"@contractspec/lib.contracts-spec/workflow/expression";function R(C){return C.runtime?.workflowDevkit?.behavior??C.type}function U(C){let _=C.definition.entryStepId??C.definition.steps[0]?.id;if(!_)throw Error(`Workflow ${C.meta.key}.v${C.meta.version} does not define an entry step.`);return _}function v(C,_){if(_)return _;let H=C.runtime?.workflowDevkit?.runIdentity?.strategy??"meta-key-version",A=C.runtime?.workflowDevkit?.runIdentity?.prefix,O=H==="meta-key-version"?`${C.meta.key}.v${C.meta.version}`:`${C.meta.key}.v${C.meta.version}`;return A?`${A}:${O}`:O}function V(C,_,H){let A=_.runtime?.workflowDevkit;if(!A)return;let O=A.hookWait?.token??A.webhookWait?.token??A.approvalWait?.token??A.streamSession?.followUpToken;if(O)return O;let K=C.runtime?.workflowDevkit?.hookTokens?.strategy??"deterministic",L=C.runtime?.workflowDevkit?.hookTokens?.prefix??C.meta.key,W=D(_.id);if(K==="session-scoped"){let j=D(v(C,H));return`${L}:${j}:${W}`}if(K==="step-scoped")return`${L}:v${C.meta.version}:${W}`;return`${L}:${W}`}function E(C,_,H,A,O){let K=C.definition.transitions.filter((L)=>L.from===_.id);for(let L of K)if(b(L.condition,{data:H,input:A,output:O}))return L.to;return null}function z(C,_,H){let A={...C};if(T(_))Object.assign(A,_);if(T(H))Object.assign(A,H);return A}function D(C){return C.replace(/[^a-zA-Z0-9_-]+/g,"-")}function T(C){return C!=null&&typeof C==="object"&&!Array.isArray(C)}function q(C){return{entryStepId:U(C),hostTarget:C.runtime?.workflowDevkit?.hostTarget??"generic",hookTokenStrategy:C.runtime?.workflowDevkit?.hookTokens?.strategy??"deterministic",integrationMode:C.runtime?.workflowDevkit?.integrationMode??"manual",runIdentityStrategy:C.runtime?.workflowDevkit?.runIdentity?.strategy??"meta-key-version",specKey:C.meta.key,specVersion:C.meta.version,steps:C.definition.steps.map((_)=>({behavior:R(_),id:_.id,label:_.label,operationRef:_.action?.operation?`${_.action.operation.key}.v${_.action.operation.version}`:void 0,runtime:_.runtime?.workflowDevkit,transitions:C.definition.transitions.filter((H)=>H.from===_.id).map((H)=>({condition:H.condition,to:H.to})),type:_.type,waitToken:V(C,_)}))}}function k(C,_){let H=q(C),A=_.workflowFunctionName??`${D(_.exportName)}WorkflowDevkit`;return{genericBootstrap:l(_.exportName,A),manifest:JSON.stringify(H,null,2),nextFollowUpRoute:m(A),nextStartRoute:I(A),nextStreamRoute:x(),workflowModule:d(_.exportName,_.specImportPath,A)}}function l(C,_){return`import { ${_} } from "./${D(C)}.workflow-devkit";
|
|
169
3
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
function inferWorkflowDevkitBehavior(step) {
|
|
173
|
-
return step.runtime?.workflowDevkit?.behavior ?? step.type;
|
|
174
|
-
}
|
|
175
|
-
function resolveWorkflowDevkitEntryStepId(spec) {
|
|
176
|
-
const entryStepId = spec.definition.entryStepId ?? spec.definition.steps[0]?.id;
|
|
177
|
-
if (!entryStepId) {
|
|
178
|
-
throw new Error(`Workflow ${spec.meta.key}.v${spec.meta.version} does not define an entry step.`);
|
|
179
|
-
}
|
|
180
|
-
return entryStepId;
|
|
181
|
-
}
|
|
182
|
-
function resolveWorkflowDevkitRunIdentity(spec, runIdentity) {
|
|
183
|
-
if (runIdentity) {
|
|
184
|
-
return runIdentity;
|
|
185
|
-
}
|
|
186
|
-
const strategy = spec.runtime?.workflowDevkit?.runIdentity?.strategy ?? "meta-key-version";
|
|
187
|
-
const prefix = spec.runtime?.workflowDevkit?.runIdentity?.prefix;
|
|
188
|
-
const baseIdentity = strategy === "meta-key-version" ? `${spec.meta.key}.v${spec.meta.version}` : `${spec.meta.key}.v${spec.meta.version}`;
|
|
189
|
-
return prefix ? `${prefix}:${baseIdentity}` : baseIdentity;
|
|
190
|
-
}
|
|
191
|
-
function resolveWorkflowDevkitWaitToken(spec, step, runIdentity) {
|
|
192
|
-
const runtime = step.runtime?.workflowDevkit;
|
|
193
|
-
if (!runtime) {
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
const explicitToken = runtime.hookWait?.token ?? runtime.webhookWait?.token ?? runtime.approvalWait?.token ?? runtime.streamSession?.followUpToken;
|
|
197
|
-
if (explicitToken) {
|
|
198
|
-
return explicitToken;
|
|
199
|
-
}
|
|
200
|
-
const tokenStrategy = spec.runtime?.workflowDevkit?.hookTokens?.strategy ?? "deterministic";
|
|
201
|
-
const prefix = spec.runtime?.workflowDevkit?.hookTokens?.prefix ?? spec.meta.key;
|
|
202
|
-
const stableStepId = sanitizeIdentifier(step.id);
|
|
203
|
-
if (tokenStrategy === "session-scoped") {
|
|
204
|
-
const resolvedRunIdentity = sanitizeIdentifier(resolveWorkflowDevkitRunIdentity(spec, runIdentity));
|
|
205
|
-
return `${prefix}:${resolvedRunIdentity}:${stableStepId}`;
|
|
206
|
-
}
|
|
207
|
-
if (tokenStrategy === "step-scoped") {
|
|
208
|
-
return `${prefix}:v${spec.meta.version}:${stableStepId}`;
|
|
209
|
-
}
|
|
210
|
-
return `${prefix}:${stableStepId}`;
|
|
211
|
-
}
|
|
212
|
-
function resolveWorkflowDevkitNextStepId(spec, step, data, input, output) {
|
|
213
|
-
const transitions = spec.definition.transitions.filter((transition) => transition.from === step.id);
|
|
214
|
-
for (const transition of transitions) {
|
|
215
|
-
if (evaluateExpression(transition.condition, {
|
|
216
|
-
data,
|
|
217
|
-
input,
|
|
218
|
-
output
|
|
219
|
-
})) {
|
|
220
|
-
return transition.to;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
return null;
|
|
224
|
-
}
|
|
225
|
-
function mergeWorkflowDevkitData(current, input, output) {
|
|
226
|
-
const next = { ...current };
|
|
227
|
-
if (isRecord(input)) {
|
|
228
|
-
Object.assign(next, input);
|
|
229
|
-
}
|
|
230
|
-
if (isRecord(output)) {
|
|
231
|
-
Object.assign(next, output);
|
|
232
|
-
}
|
|
233
|
-
return next;
|
|
234
|
-
}
|
|
235
|
-
function sanitizeIdentifier(value) {
|
|
236
|
-
return value.replace(/[^a-zA-Z0-9_-]+/g, "-");
|
|
237
|
-
}
|
|
238
|
-
function isRecord(value) {
|
|
239
|
-
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// src/compiler.ts
|
|
243
|
-
function compileWorkflowSpecToWorkflowDevkit(spec) {
|
|
244
|
-
return {
|
|
245
|
-
entryStepId: resolveWorkflowDevkitEntryStepId(spec),
|
|
246
|
-
hostTarget: spec.runtime?.workflowDevkit?.hostTarget ?? "generic",
|
|
247
|
-
hookTokenStrategy: spec.runtime?.workflowDevkit?.hookTokens?.strategy ?? "deterministic",
|
|
248
|
-
integrationMode: spec.runtime?.workflowDevkit?.integrationMode ?? "manual",
|
|
249
|
-
runIdentityStrategy: spec.runtime?.workflowDevkit?.runIdentity?.strategy ?? "meta-key-version",
|
|
250
|
-
specKey: spec.meta.key,
|
|
251
|
-
specVersion: spec.meta.version,
|
|
252
|
-
steps: spec.definition.steps.map((step) => ({
|
|
253
|
-
behavior: inferWorkflowDevkitBehavior(step),
|
|
254
|
-
id: step.id,
|
|
255
|
-
label: step.label,
|
|
256
|
-
operationRef: step.action?.operation ? `${step.action.operation.key}.v${step.action.operation.version}` : undefined,
|
|
257
|
-
runtime: step.runtime?.workflowDevkit,
|
|
258
|
-
transitions: spec.definition.transitions.filter((transition) => transition.from === step.id).map((transition) => ({
|
|
259
|
-
condition: transition.condition,
|
|
260
|
-
to: transition.to
|
|
261
|
-
})),
|
|
262
|
-
type: step.type,
|
|
263
|
-
waitToken: resolveWorkflowDevkitWaitToken(spec, step)
|
|
264
|
-
}))
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
function generateWorkflowDevkitArtifacts(spec, options) {
|
|
268
|
-
const compilation = compileWorkflowSpecToWorkflowDevkit(spec);
|
|
269
|
-
const workflowFunctionName = options.workflowFunctionName ?? `${sanitizeIdentifier(options.exportName)}WorkflowDevkit`;
|
|
270
|
-
return {
|
|
271
|
-
genericBootstrap: createGenericBootstrapTemplate(options.exportName, workflowFunctionName),
|
|
272
|
-
manifest: JSON.stringify(compilation, null, 2),
|
|
273
|
-
nextFollowUpRoute: createFollowUpRouteTemplate(workflowFunctionName),
|
|
274
|
-
nextStartRoute: createStartRouteTemplate(workflowFunctionName),
|
|
275
|
-
nextStreamRoute: createStreamRouteTemplate(),
|
|
276
|
-
workflowModule: createWorkflowModuleTemplate(options.exportName, options.specImportPath, workflowFunctionName)
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
function createGenericBootstrapTemplate(exportName, workflowFunctionName) {
|
|
280
|
-
return `import { ${workflowFunctionName} } from "./${sanitizeIdentifier(exportName)}.workflow-devkit";
|
|
281
|
-
|
|
282
|
-
export const ${sanitizeIdentifier(exportName)}WorkflowDevkitBootstrap = {
|
|
283
|
-
workflow: ${workflowFunctionName},
|
|
4
|
+
export const ${D(C)}WorkflowDevkitBootstrap = {
|
|
5
|
+
workflow: ${_},
|
|
284
6
|
createBridge() {
|
|
285
7
|
return {
|
|
286
8
|
executeAutomationStep: async () => {
|
|
@@ -289,46 +11,37 @@ export const ${sanitizeIdentifier(exportName)}WorkflowDevkitBootstrap = {
|
|
|
289
11
|
};
|
|
290
12
|
},
|
|
291
13
|
};
|
|
292
|
-
|
|
293
|
-
}
|
|
294
|
-
function createStartRouteTemplate(workflowFunctionName) {
|
|
295
|
-
return `import { createWorkflowDevkitStartRoute } from "@contractspec/integration.workflow-devkit";
|
|
296
|
-
import { ${workflowFunctionName} } from "./workflow";
|
|
14
|
+
`}function I(C){return`import { createWorkflowDevkitStartRoute } from "@contractspec/integration.workflow-devkit";
|
|
15
|
+
import { ${C} } from "./workflow";
|
|
297
16
|
|
|
298
17
|
export const POST = createWorkflowDevkitStartRoute({
|
|
299
|
-
workflow: ${
|
|
18
|
+
workflow: ${C},
|
|
300
19
|
async buildArgs(body) {
|
|
301
20
|
return [body];
|
|
302
21
|
},
|
|
303
22
|
});
|
|
304
|
-
|
|
305
|
-
}
|
|
306
|
-
function createFollowUpRouteTemplate(workflowFunctionName) {
|
|
307
|
-
return `import { createWorkflowDevkitFollowUpRoute } from "@contractspec/integration.workflow-devkit";
|
|
23
|
+
`}function m(C){return`import { createWorkflowDevkitFollowUpRoute } from "@contractspec/integration.workflow-devkit";
|
|
308
24
|
|
|
309
25
|
export const POST = createWorkflowDevkitFollowUpRoute({
|
|
310
26
|
resolveToken({ runId }) {
|
|
311
|
-
return \`${
|
|
27
|
+
return \`${C}:\${runId}\`;
|
|
312
28
|
},
|
|
313
29
|
});
|
|
314
|
-
|
|
315
|
-
}
|
|
316
|
-
function createStreamRouteTemplate() {
|
|
317
|
-
return `import { createWorkflowDevkitStreamRoute } from "@contractspec/integration.workflow-devkit";
|
|
30
|
+
`}function x(){return`import { createWorkflowDevkitStreamRoute } from "@contractspec/integration.workflow-devkit";
|
|
318
31
|
|
|
319
32
|
export const GET = createWorkflowDevkitStreamRoute();
|
|
320
|
-
|
|
321
|
-
}
|
|
322
|
-
function createWorkflowModuleTemplate(exportName, specImportPath, workflowFunctionName) {
|
|
323
|
-
return `import { createHook, createWebhook, sleep } from "workflow";
|
|
33
|
+
`}function d(C,_,H){return`import { createHook, createWebhook, sleep } from "workflow";
|
|
324
34
|
import { runWorkflowSpecWithWorkflowDevkit } from "@contractspec/integration.workflow-devkit";
|
|
325
|
-
import { ${
|
|
35
|
+
import { ${C} } from "${_}";
|
|
326
36
|
|
|
327
|
-
export async function ${
|
|
37
|
+
export async function ${H}(input = {}, bridge = {}) {
|
|
328
38
|
"use workflow";
|
|
329
39
|
|
|
40
|
+
// Keep the workflow function deterministic.
|
|
41
|
+
// Any Node.js or side-effectful logic should live in "use step" helpers that
|
|
42
|
+
// your bridge calls, not in this orchestrator itself.
|
|
330
43
|
return runWorkflowSpecWithWorkflowDevkit({
|
|
331
|
-
spec: ${
|
|
44
|
+
spec: ${C},
|
|
332
45
|
initialData: input,
|
|
333
46
|
bridge,
|
|
334
47
|
primitives: {
|
|
@@ -338,143 +51,4 @@ export async function ${workflowFunctionName}(input = {}, bridge = {}) {
|
|
|
338
51
|
},
|
|
339
52
|
});
|
|
340
53
|
}
|
|
341
|
-
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// src/next.ts
|
|
345
|
-
import { withWorkflow } from "workflow/next";
|
|
346
|
-
function withContractSpecWorkflow(nextConfig) {
|
|
347
|
-
return withWorkflow(nextConfig);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// src/runtime.ts
|
|
351
|
-
async function runWorkflowSpecWithWorkflowDevkit(options) {
|
|
352
|
-
const history = [];
|
|
353
|
-
let currentStepId = resolveWorkflowDevkitEntryStepId(options.spec);
|
|
354
|
-
let data = { ...options.initialData ?? {} };
|
|
355
|
-
let input = options.initialData;
|
|
356
|
-
while (currentStepId) {
|
|
357
|
-
const step = lookupStep(options.spec, currentStepId);
|
|
358
|
-
const runtime = step.runtime?.workflowDevkit;
|
|
359
|
-
const context = {
|
|
360
|
-
data,
|
|
361
|
-
input,
|
|
362
|
-
runIdentity: options.runIdentity,
|
|
363
|
-
runtime,
|
|
364
|
-
spec: options.spec,
|
|
365
|
-
step
|
|
366
|
-
};
|
|
367
|
-
const behavior = inferWorkflowDevkitBehavior(step);
|
|
368
|
-
const token = resolveWorkflowDevkitWaitToken(options.spec, step, options.runIdentity);
|
|
369
|
-
const output = await executeWorkflowDevkitBehavior(behavior, context, token, options.bridge, options.primitives);
|
|
370
|
-
history.push({
|
|
371
|
-
behavior,
|
|
372
|
-
input,
|
|
373
|
-
output,
|
|
374
|
-
stepId: step.id,
|
|
375
|
-
token
|
|
376
|
-
});
|
|
377
|
-
data = mergeWorkflowDevkitData(data, input, output);
|
|
378
|
-
const nextStepId = resolveWorkflowDevkitNextStepId(options.spec, step, data, input, output);
|
|
379
|
-
if (!nextStepId) {
|
|
380
|
-
return {
|
|
381
|
-
currentStep: null,
|
|
382
|
-
data,
|
|
383
|
-
history,
|
|
384
|
-
status: "completed"
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
|
-
currentStepId = nextStepId;
|
|
388
|
-
input = output;
|
|
389
|
-
}
|
|
390
|
-
return {
|
|
391
|
-
currentStep: null,
|
|
392
|
-
data,
|
|
393
|
-
history,
|
|
394
|
-
status: "completed"
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
async function executeWorkflowDevkitBehavior(behavior, context, token, bridge, primitives) {
|
|
398
|
-
switch (behavior) {
|
|
399
|
-
case "sleep":
|
|
400
|
-
if (!context.runtime?.sleep?.duration) {
|
|
401
|
-
throw new Error(`Step "${context.step.id}" is missing sleep.duration.`);
|
|
402
|
-
}
|
|
403
|
-
await primitives.sleep(context.runtime.sleep.duration);
|
|
404
|
-
return { sleptFor: context.runtime.sleep.duration };
|
|
405
|
-
case "hookWait":
|
|
406
|
-
return awaitExternalWait(context, token, bridge?.onExternalWait, primitives.createHook);
|
|
407
|
-
case "webhookWait":
|
|
408
|
-
return awaitExternalWait(context, token, bridge?.onExternalWait, primitives.createWebhook ?? primitives.createHook, context.runtime?.webhookWait?.path, context.runtime?.webhookWait?.method);
|
|
409
|
-
case "approvalWait":
|
|
410
|
-
return awaitExternalWait(context, token, bridge?.onApprovalRequested, primitives.createHook);
|
|
411
|
-
case "streamSession":
|
|
412
|
-
return awaitExternalWait(context, token, bridge?.onStreamSession, primitives.createHook);
|
|
413
|
-
case "automation":
|
|
414
|
-
if (!bridge?.executeAutomationStep) {
|
|
415
|
-
throw new Error("Workflow DevKit bridge requires executeAutomationStep for automation steps.");
|
|
416
|
-
}
|
|
417
|
-
return bridge.executeAutomationStep(context);
|
|
418
|
-
case "human":
|
|
419
|
-
if (!bridge?.awaitHumanInput) {
|
|
420
|
-
throw new Error("Workflow DevKit bridge requires awaitHumanInput for human steps without explicit wait behavior.");
|
|
421
|
-
}
|
|
422
|
-
return bridge.awaitHumanInput(context);
|
|
423
|
-
case "decision":
|
|
424
|
-
return bridge?.executeDecisionStep ? bridge.executeDecisionStep(context) : context.input;
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
async function awaitExternalWait(context, token, notifier, factory, path, method) {
|
|
428
|
-
if (!token) {
|
|
429
|
-
throw new Error(`Step "${context.step.id}" requires a Workflow DevKit wait token.`);
|
|
430
|
-
}
|
|
431
|
-
const behavior = context.runtime?.behavior;
|
|
432
|
-
if (behavior !== "approvalWait" && behavior !== "hookWait" && behavior !== "streamSession" && behavior !== "webhookWait") {
|
|
433
|
-
throw new Error(`Step "${context.step.id}" is not configured with an external wait behavior.`);
|
|
434
|
-
}
|
|
435
|
-
const waitContext = {
|
|
436
|
-
...context,
|
|
437
|
-
behavior,
|
|
438
|
-
token
|
|
439
|
-
};
|
|
440
|
-
await notifier?.(waitContext);
|
|
441
|
-
const hook = factory({ method, path, token });
|
|
442
|
-
try {
|
|
443
|
-
return await hook;
|
|
444
|
-
} finally {
|
|
445
|
-
await hook.dispose?.();
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
function lookupStep(spec, stepId) {
|
|
449
|
-
const step = spec.definition.steps.find((candidate) => candidate.id === stepId);
|
|
450
|
-
if (!step) {
|
|
451
|
-
throw new Error(`Step "${stepId}" not found in workflow ${spec.meta.key}.v${spec.meta.version}.`);
|
|
452
|
-
}
|
|
453
|
-
return step;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// src/index.ts
|
|
457
|
-
import { WorkflowChatTransport } from "@workflow/ai";
|
|
458
|
-
export {
|
|
459
|
-
withContractSpecWorkflow,
|
|
460
|
-
sanitizeIdentifier,
|
|
461
|
-
runWorkflowSpecWithWorkflowDevkit,
|
|
462
|
-
resolveWorkflowDevkitWaitToken,
|
|
463
|
-
resolveWorkflowDevkitRunIdentity,
|
|
464
|
-
resolveWorkflowDevkitNextStepId,
|
|
465
|
-
resolveWorkflowDevkitEntryStepId,
|
|
466
|
-
mergeWorkflowDevkitData,
|
|
467
|
-
inferWorkflowDevkitBehavior,
|
|
468
|
-
generateWorkflowDevkitArtifacts,
|
|
469
|
-
defaultWorkflowDevkitAgentToken,
|
|
470
|
-
createWorkflowDevkitStreamRoute,
|
|
471
|
-
createWorkflowDevkitStartRoute,
|
|
472
|
-
createWorkflowDevkitFollowUpRoute,
|
|
473
|
-
createWorkflowDevkitAgentRuntimeAdapterBundle,
|
|
474
|
-
compileWorkflowSpecToWorkflowDevkit,
|
|
475
|
-
WorkflowChatTransport,
|
|
476
|
-
WORKFLOW_STREAM_TAIL_INDEX_HEADER,
|
|
477
|
-
WORKFLOW_RUN_ID_HEADER,
|
|
478
|
-
InMemoryWorkflowDevkitSuspensionStore,
|
|
479
|
-
InMemoryWorkflowDevkitCheckpointStore
|
|
480
|
-
};
|
|
54
|
+
`}import{withWorkflow as u}from"workflow/next";function c(C){return u(C)}async function a(C){let _=[],H=U(C.spec),A={...C.initialData??{}},O=C.initialData;while(H){let K=p(C.spec,H),L=K.runtime?.workflowDevkit,W={data:A,input:O,runIdentity:C.runIdentity,runtime:L,spec:C.spec,step:K},j=R(K),$=V(C.spec,K,C.runIdentity),J=await r(j,W,$,C.bridge,C.primitives);_.push({behavior:j,input:O,output:J,stepId:K.id,token:$}),A=z(A,O,J);let G=E(C.spec,K,A,O,J);if(!G)return{currentStep:null,data:A,history:_,status:"completed"};H=G,O=J}return{currentStep:null,data:A,history:_,status:"completed"}}async function r(C,_,H,A,O){switch(C){case"sleep":if(!_.runtime?.sleep?.duration)throw Error(`Step "${_.step.id}" is missing sleep.duration.`);return await O.sleep(_.runtime.sleep.duration),{sleptFor:_.runtime.sleep.duration};case"hookWait":return X(_,H,A?.onExternalWait,O.createHook);case"webhookWait":return X(_,H,A?.onExternalWait,O.createWebhook??O.createHook,_.runtime?.webhookWait?.path,_.runtime?.webhookWait?.method);case"approvalWait":return X(_,H,A?.onApprovalRequested,O.createHook);case"streamSession":return X(_,H,A?.onStreamSession,O.createHook);case"automation":if(!A?.executeAutomationStep)throw Error("Workflow DevKit bridge requires executeAutomationStep for automation steps.");return A.executeAutomationStep(_);case"human":if(!A?.awaitHumanInput)throw Error("Workflow DevKit bridge requires awaitHumanInput for human steps without explicit wait behavior.");return A.awaitHumanInput(_);case"decision":return A?.executeDecisionStep?A.executeDecisionStep(_):_.input}}async function X(C,_,H,A,O,K){if(!_)throw Error(`Step "${C.step.id}" requires a Workflow DevKit wait token.`);let L=C.runtime?.behavior;if(L!=="approvalWait"&&L!=="hookWait"&&L!=="streamSession"&&L!=="webhookWait")throw Error(`Step "${C.step.id}" is not configured with an external wait behavior.`);let W={...C,behavior:L,token:_};await H?.(W);let j=A({method:K,path:O,token:_});try{return await j}finally{await j.dispose?.()}}function p(C,_){let H=C.definition.steps.find((A)=>A.id===_);if(!H)throw Error(`Step "${_}" not found in workflow ${C.meta.key}.v${C.meta.version}.`);return H}import{WorkflowChatTransport as jC}from"@workflow/ai";export{c as withContractSpecWorkflow,D as sanitizeIdentifier,a as runWorkflowSpecWithWorkflowDevkit,V as resolveWorkflowDevkitWaitToken,v as resolveWorkflowDevkitRunIdentity,E as resolveWorkflowDevkitNextStepId,U as resolveWorkflowDevkitEntryStepId,z as mergeWorkflowDevkitData,R as inferWorkflowDevkitBehavior,k as generateWorkflowDevkitArtifacts,M as defaultWorkflowDevkitAgentToken,y as createWorkflowDevkitStreamRoute,g as createWorkflowDevkitStartRoute,S as createWorkflowDevkitFollowUpRoute,F as createWorkflowDevkitAgentRuntimeAdapterBundle,q as compileWorkflowSpecToWorkflowDevkit,jC as WorkflowChatTransport,B as WORKFLOW_STREAM_TAIL_INDEX_HEADER,Q as WORKFLOW_RUN_ID_HEADER,Z as InMemoryWorkflowDevkitSuspensionStore,Y as InMemoryWorkflowDevkitCheckpointStore};
|
package/dist/next.js
CHANGED
|
@@ -1,9 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
|
|
3
|
-
import { withWorkflow } from "workflow/next";
|
|
4
|
-
function withContractSpecWorkflow(nextConfig) {
|
|
5
|
-
return withWorkflow(nextConfig);
|
|
6
|
-
}
|
|
7
|
-
export {
|
|
8
|
-
withContractSpecWorkflow
|
|
9
|
-
};
|
|
2
|
+
import{withWorkflow as t}from"workflow/next";function e(o){return t(o)}export{e as withContractSpecWorkflow};
|
|
@@ -1,79 +1 @@
|
|
|
1
|
-
|
|
2
|
-
class InMemoryWorkflowDevkitCheckpointStore {
|
|
3
|
-
envelopes = new Map;
|
|
4
|
-
async delete(sessionId) {
|
|
5
|
-
this.envelopes.delete(sessionId);
|
|
6
|
-
}
|
|
7
|
-
async load(sessionId) {
|
|
8
|
-
return this.envelopes.get(sessionId) ?? null;
|
|
9
|
-
}
|
|
10
|
-
async save(envelope) {
|
|
11
|
-
this.envelopes.set(envelope.sessionId, envelope);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
class InMemoryWorkflowDevkitSuspensionStore {
|
|
16
|
-
states = new Map;
|
|
17
|
-
async clear(sessionId) {
|
|
18
|
-
this.states.delete(sessionId);
|
|
19
|
-
}
|
|
20
|
-
async get(sessionId) {
|
|
21
|
-
return this.states.get(sessionId) ?? null;
|
|
22
|
-
}
|
|
23
|
-
async set(sessionId, state) {
|
|
24
|
-
this.states.set(sessionId, state);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
function createWorkflowDevkitAgentRuntimeAdapterBundle(options = {}) {
|
|
28
|
-
const checkpointStore = options.checkpointStore ?? new InMemoryWorkflowDevkitCheckpointStore;
|
|
29
|
-
const suspensionStore = options.suspensionStore ?? new InMemoryWorkflowDevkitSuspensionStore;
|
|
30
|
-
const resolveSessionToken = options.resolveSessionToken ?? defaultWorkflowDevkitAgentToken;
|
|
31
|
-
return {
|
|
32
|
-
key: "workflow-devkit",
|
|
33
|
-
checkpoint: {
|
|
34
|
-
delete(sessionId) {
|
|
35
|
-
return checkpointStore.delete(sessionId);
|
|
36
|
-
},
|
|
37
|
-
load(sessionId) {
|
|
38
|
-
return checkpointStore.load(sessionId);
|
|
39
|
-
},
|
|
40
|
-
save(envelope) {
|
|
41
|
-
return checkpointStore.save(envelope);
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
suspendResume: {
|
|
45
|
-
async resume(params) {
|
|
46
|
-
await suspensionStore.set(params.sessionId, {
|
|
47
|
-
input: params.input,
|
|
48
|
-
metadata: params.metadata,
|
|
49
|
-
reason: "resumed",
|
|
50
|
-
resumedAt: new Date,
|
|
51
|
-
suspendedAt: new Date
|
|
52
|
-
});
|
|
53
|
-
if (options.workflowApi) {
|
|
54
|
-
await options.workflowApi.resumeHook(resolveSessionToken(params.sessionId), {
|
|
55
|
-
input: params.input,
|
|
56
|
-
metadata: params.metadata,
|
|
57
|
-
sessionId: params.sessionId
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
async suspend(params) {
|
|
62
|
-
await suspensionStore.set(params.sessionId, {
|
|
63
|
-
metadata: params.metadata,
|
|
64
|
-
reason: params.reason,
|
|
65
|
-
suspendedAt: new Date
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
function defaultWorkflowDevkitAgentToken(sessionId) {
|
|
72
|
-
return `agent-session:${sessionId}`;
|
|
73
|
-
}
|
|
74
|
-
export {
|
|
75
|
-
defaultWorkflowDevkitAgentToken,
|
|
76
|
-
createWorkflowDevkitAgentRuntimeAdapterBundle,
|
|
77
|
-
InMemoryWorkflowDevkitSuspensionStore,
|
|
78
|
-
InMemoryWorkflowDevkitCheckpointStore
|
|
79
|
-
};
|
|
1
|
+
class x{envelopes=new Map;async delete(b){this.envelopes.delete(b)}async load(b){return this.envelopes.get(b)??null}async save(b){this.envelopes.set(b.sessionId,b)}}class z{states=new Map;async clear(b){this.states.delete(b)}async get(b){return this.states.get(b)??null}async set(b,j){this.states.set(b,j)}}function C(b={}){let j=b.checkpointStore??new x,q=b.suspensionStore??new z,A=b.resolveSessionToken??B;return{key:"workflow-devkit",checkpoint:{delete(g){return j.delete(g)},load(g){return j.load(g)},save(g){return j.save(g)}},suspendResume:{async resume(g){if(await q.set(g.sessionId,{input:g.input,metadata:g.metadata,reason:"resumed",resumedAt:new Date,suspendedAt:new Date}),b.workflowApi)await b.workflowApi.resumeHook(A(g.sessionId),{input:g.input,metadata:g.metadata,sessionId:g.sessionId})},async suspend(g){await q.set(g.sessionId,{metadata:g.metadata,reason:g.reason,suspendedAt:new Date})}}}}function B(b){return`agent-session:${b}`}export{B as defaultWorkflowDevkitAgentToken,C as createWorkflowDevkitAgentRuntimeAdapterBundle,z as InMemoryWorkflowDevkitSuspensionStore,x as InMemoryWorkflowDevkitCheckpointStore};
|