@yielded/agent-workflow 0.1.0-beta.172 → 0.1.0-beta.174
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/AgentWorkflow.mjs +1 -1
- package/dist/{WorkflowAgentHost-DTcWCdU2.mjs → WorkflowAgentHost-Dkq5IC6U.mjs} +25 -25
- package/dist/WorkflowAgentHost-Dkq5IC6U.mjs.map +1 -0
- package/dist/WorkflowAgentHost.mjs +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/src/WorkflowAgentHost.ts +31 -33
- package/dist/WorkflowAgentHost-DTcWCdU2.mjs.map +0 -1
package/dist/AgentWorkflow.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import { WorkflowDispatchError } from "./WorkflowDispatch.mjs";
|
|
3
|
-
import { n as WorkflowAgentHost, t as WorkflowAdmissionClosed } from "./WorkflowAgentHost-
|
|
3
|
+
import { n as WorkflowAgentHost, t as WorkflowAdmissionClosed } from "./WorkflowAgentHost-Dkq5IC6U.mjs";
|
|
4
4
|
import { WorkflowExecutionFailure } from "./WorkflowExecution.mjs";
|
|
5
5
|
import { AgentInputError, AgentOutputError } from "@yielded/agent/agent-error";
|
|
6
6
|
import { BindingUnavailable } from "@yielded/agent/agent-registration";
|
|
@@ -39,7 +39,7 @@ const WorkflowHostConfig = Schema.Struct({
|
|
|
39
39
|
});
|
|
40
40
|
var WorkflowHostConfigError = class extends Schema.TaggedError()("WorkflowHostConfigError", { message: Schema.String }) {};
|
|
41
41
|
var WorkflowAdmissionClosed = class extends Schema.TaggedError()("WorkflowAdmissionClosed", { message: Schema.String }) {};
|
|
42
|
-
const nativeOperation = (operation, effect) => effect.pipe(Effect.catchDefect((cause) => Effect.fail(
|
|
42
|
+
const nativeOperation = (operation, effect) => effect.pipe(Effect.catchDefect((cause) => Effect.fail(WorkflowDispatchError.make({
|
|
43
43
|
operation,
|
|
44
44
|
message: "Workflow engine operation failed",
|
|
45
45
|
cause
|
|
@@ -52,7 +52,7 @@ const makeHost = Effect.fnUntraced(function* (options) {
|
|
|
52
52
|
executionConcurrency: options.executionConcurrency ?? 1,
|
|
53
53
|
repairBatchSize: options.repairBatchSize ?? 32,
|
|
54
54
|
dispatchTimeoutMillis: options.dispatchTimeoutMillis ?? 1e4
|
|
55
|
-
}).pipe(Effect.mapError((error) =>
|
|
55
|
+
}).pipe(Effect.mapError((error) => WorkflowHostConfigError.make({ message: error.message })));
|
|
56
56
|
const runtime = yield* DurableAgentRuntime;
|
|
57
57
|
const crypto = yield* Crypto.Crypto;
|
|
58
58
|
const runtimeConfig = yield* DurableRuntimeConfig;
|
|
@@ -61,7 +61,7 @@ const makeHost = Effect.fnUntraced(function* (options) {
|
|
|
61
61
|
const dispatch = yield* WorkflowDispatchStore;
|
|
62
62
|
const trigger = yield* WorkflowRepairTrigger;
|
|
63
63
|
const failpoint = yield* WorkflowDispatchFailpoint;
|
|
64
|
-
if (runtimeConfig.deploymentId !== config.deploymentId) return yield*
|
|
64
|
+
if (runtimeConfig.deploymentId !== config.deploymentId) return yield* WorkflowHostConfigError.make({ message: "Workflow and durable runtime deploymentId must match" });
|
|
65
65
|
const permits = yield* Semaphore.make(config.executionConcurrency);
|
|
66
66
|
const lanes = yield* RcMap.make({ lookup: (_threadId) => Semaphore.make(1) });
|
|
67
67
|
const repairPermit = yield* Semaphore.make(1);
|
|
@@ -93,7 +93,7 @@ const makeHost = Effect.fnUntraced(function* (options) {
|
|
|
93
93
|
if (executionId !== (yield* workflow.executionId(payload))) return yield* Effect.die("Workflow execution identity does not match its Submission");
|
|
94
94
|
yield* validateReceipt(payload.receipt).pipe(Effect.orDie);
|
|
95
95
|
const initial = yield* runtime.inspectSubmissionStatus(payload.receipt).pipe(Effect.orDie);
|
|
96
|
-
if (initial._tag === "settled") return
|
|
96
|
+
if (initial._tag === "settled") return WorkflowSettlementReference.make({
|
|
97
97
|
version: 1,
|
|
98
98
|
submissionId: initial.settlement.submissionId,
|
|
99
99
|
threadId: payload.receipt.threadId,
|
|
@@ -108,7 +108,7 @@ const makeHost = Effect.fnUntraced(function* (options) {
|
|
|
108
108
|
return yield* runtime.inspectSubmissionStatus(payload.receipt);
|
|
109
109
|
}))));
|
|
110
110
|
})).pipe(Effect.orDie);
|
|
111
|
-
if (status._tag === "settled") return
|
|
111
|
+
if (status._tag === "settled") return WorkflowSettlementReference.make({
|
|
112
112
|
version: 1,
|
|
113
113
|
submissionId: status.settlement.submissionId,
|
|
114
114
|
threadId: payload.receipt.threadId,
|
|
@@ -118,13 +118,13 @@ const makeHost = Effect.fnUntraced(function* (options) {
|
|
|
118
118
|
return yield* Workflow.suspend(instance);
|
|
119
119
|
}));
|
|
120
120
|
const intentFor = Effect.fnUntraced(function* (receipt) {
|
|
121
|
-
const payload =
|
|
121
|
+
const payload = WorkflowSubmission.make({
|
|
122
122
|
version: 1,
|
|
123
123
|
deploymentId: config.deploymentId,
|
|
124
124
|
receipt
|
|
125
125
|
});
|
|
126
126
|
const executionId = yield* workflow.executionId(payload);
|
|
127
|
-
return
|
|
127
|
+
return WorkflowDispatchIntent.make({
|
|
128
128
|
...payload,
|
|
129
129
|
workflowName: nativeName,
|
|
130
130
|
executionId
|
|
@@ -133,7 +133,7 @@ const makeHost = Effect.fnUntraced(function* (options) {
|
|
|
133
133
|
const dispatchIntent = Effect.fnUntraced(function* (requested) {
|
|
134
134
|
let intent = requested;
|
|
135
135
|
const expected = yield* intentFor(intent.receipt);
|
|
136
|
-
if (intent.executionId !== expected.executionId || intent.deploymentId !== expected.deploymentId || intent.workflowName !== expected.workflowName) return yield*
|
|
136
|
+
if (intent.executionId !== expected.executionId || intent.deploymentId !== expected.deploymentId || intent.workflowName !== expected.workflowName) return yield* WorkflowDispatchError.make({
|
|
137
137
|
operation: "dispatch",
|
|
138
138
|
message: "Dispatch identity does not match the configured Workflow"
|
|
139
139
|
});
|
|
@@ -144,7 +144,7 @@ const makeHost = Effect.fnUntraced(function* (options) {
|
|
|
144
144
|
yield* failpoint.hit("launch:before", intent);
|
|
145
145
|
yield* nativeOperation("execute", engine.execute(workflow, {
|
|
146
146
|
executionId: intent.executionId,
|
|
147
|
-
payload:
|
|
147
|
+
payload: WorkflowSubmission.make(intent),
|
|
148
148
|
discard: true
|
|
149
149
|
}).pipe(Effect.updateContext((context) => Context.omit(WorkflowEngine.WorkflowInstance)(context))));
|
|
150
150
|
yield* failpoint.hit("launch:after", intent);
|
|
@@ -153,14 +153,14 @@ const makeHost = Effect.fnUntraced(function* (options) {
|
|
|
153
153
|
const result = yield* nativeOperation("poll", engine.poll(workflow, intent.executionId));
|
|
154
154
|
yield* failpoint.hit("completion:after-observe", intent);
|
|
155
155
|
if (Option.isNone(result) || result.value._tag !== "Complete") return false;
|
|
156
|
-
if (Exit.isFailure(result.value.exit)) return yield*
|
|
156
|
+
if (Exit.isFailure(result.value.exit)) return yield* WorkflowDispatchError.make({
|
|
157
157
|
operation: "completion",
|
|
158
158
|
message: "Native Workflow completed without a Settlement reference; intent retained",
|
|
159
159
|
cause: result.value.exit.cause
|
|
160
160
|
});
|
|
161
161
|
const status = yield* runtime.inspectSubmissionStatus(intent.receipt);
|
|
162
162
|
const reference = result.value.exit.value;
|
|
163
|
-
if (status._tag !== "settled" || reference.version !== 1 || reference.submissionId !== intent.receipt.submissionId || reference.threadId !== intent.receipt.threadId || reference.settlementId !== status.settlement.settlementId) return yield*
|
|
163
|
+
if (status._tag !== "settled" || reference.version !== 1 || reference.submissionId !== intent.receipt.submissionId || reference.threadId !== intent.receipt.threadId || reference.settlementId !== status.settlement.settlementId) return yield* WorkflowDispatchError.make({
|
|
164
164
|
operation: "completion",
|
|
165
165
|
message: "Native completion disagrees with canonical Settlement; intent retained"
|
|
166
166
|
});
|
|
@@ -183,8 +183,8 @@ const makeHost = Effect.fnUntraced(function* (options) {
|
|
|
183
183
|
const discovery = yield* bounded("scanSubmissions", ledger.scanNonterminal.pipe(Stream.filter((row) => row.deploymentId === config.deploymentId), Stream.drop(submissionOffset), Stream.take(config.repairBatchSize), Stream.runCollect)).pipe(Effect.result);
|
|
184
184
|
const submissions = Result.isSuccess(discovery) ? discovery.success : [];
|
|
185
185
|
if (Result.isSuccess(discovery)) submissionOffset = submissions.length < config.repairBatchSize ? 0 : submissionOffset + submissions.length;
|
|
186
|
-
const discovered = yield* Effect.forEach(submissions, (row) => Effect.flatMap(intentFor(
|
|
187
|
-
const outstanding = yield* bounded("scanIntents", dispatch.scan(
|
|
186
|
+
const discovered = yield* Effect.forEach(submissions, (row) => Effect.flatMap(intentFor(Receipt.make(row)), dispatchIntent).pipe(Effect.result));
|
|
187
|
+
const outstanding = yield* bounded("scanIntents", dispatch.scan(WorkflowDispatchScan.make({
|
|
188
188
|
deploymentId: config.deploymentId,
|
|
189
189
|
workflowName: nativeName,
|
|
190
190
|
...intentCursor === void 0 ? {} : { after: intentCursor },
|
|
@@ -198,7 +198,7 @@ const makeHost = Effect.fnUntraced(function* (options) {
|
|
|
198
198
|
if (Result.isFailure(outstanding)) return yield* outstanding.failure;
|
|
199
199
|
const failure = results.find(Result.isFailure);
|
|
200
200
|
if (failure !== void 0) return yield* Effect.fail(failure.failure);
|
|
201
|
-
return
|
|
201
|
+
return WorkflowRepairReport.make({
|
|
202
202
|
discovered: submissions.length,
|
|
203
203
|
inspected: intents.length,
|
|
204
204
|
completed: results.filter((result) => Result.isSuccess(result) && result.success).length
|
|
@@ -207,17 +207,17 @@ const makeHost = Effect.fnUntraced(function* (options) {
|
|
|
207
207
|
yield* trigger.register(repair.pipe(Effect.asVoid, Effect.catchCause((cause) => Cause.hasInterruptsOnly(cause) ? Effect.interrupt : Effect.logError("Workflow dispatch repair failed; durable obligations remain", cause))));
|
|
208
208
|
yield* Effect.addFinalizer(() => Ref.set(admission, false));
|
|
209
209
|
const submit = Effect.fnUntraced(function* (agent, input, options) {
|
|
210
|
-
if (!(yield* Ref.get(admission))) return yield*
|
|
210
|
+
if (!(yield* Ref.get(admission))) return yield* WorkflowAdmissionClosed.make({ message: "The Workflow host is shutting down" });
|
|
211
211
|
const receipt = yield* runtime.submit(agent, input, options);
|
|
212
212
|
yield* dispatchIntent(yield* intentFor(receipt));
|
|
213
213
|
return receipt;
|
|
214
214
|
});
|
|
215
215
|
const execute = Effect.fnUntraced(function* (agent, input, options) {
|
|
216
|
-
if ((yield* WorkflowEngine.WorkflowEngine) !== engine) return yield*
|
|
216
|
+
if ((yield* WorkflowEngine.WorkflowEngine) !== engine) return yield* WorkflowExecutionFailure.make({
|
|
217
217
|
reason: "engine-mismatch",
|
|
218
218
|
message: "Agent host and parent workflow must share one WorkflowEngine Layer"
|
|
219
219
|
});
|
|
220
|
-
const name = yield* Schema.decodeEffect(Schema.NonEmptyString)(options.name).pipe(Effect.mapError(() =>
|
|
220
|
+
const name = yield* Schema.decodeEffect(Schema.NonEmptyString)(options.name).pipe(Effect.mapError(() => WorkflowExecutionFailure.make({
|
|
221
221
|
reason: "invalid-name",
|
|
222
222
|
message: "Workflow agent steps need a nonempty stable name"
|
|
223
223
|
})));
|
|
@@ -228,7 +228,7 @@ const makeHost = Effect.fnUntraced(function* (options) {
|
|
|
228
228
|
config.principal,
|
|
229
229
|
completionToken
|
|
230
230
|
]).pipe(Effect.provideService(Crypto.Crypto, crypto));
|
|
231
|
-
if (!(yield* Ref.get(admission))) return yield*
|
|
231
|
+
if (!(yield* Ref.get(admission))) return yield* WorkflowAdmissionClosed.make({ message: "The Workflow host is shutting down" });
|
|
232
232
|
const receipt = yield* runtime.submitRegistered({ definition: agent }, input, {
|
|
233
233
|
threadId: ThreadId.make(`workflow/${identity}`),
|
|
234
234
|
idempotencyKey: IdempotencyKey.make(identity),
|
|
@@ -239,33 +239,33 @@ const makeHost = Effect.fnUntraced(function* (options) {
|
|
|
239
239
|
"agent.workflow.step": name
|
|
240
240
|
});
|
|
241
241
|
yield* runtime.submissionStatus(receipt);
|
|
242
|
-
yield* dispatchIntent(
|
|
242
|
+
yield* dispatchIntent(WorkflowDispatchIntent.make({
|
|
243
243
|
...yield* intentFor(receipt),
|
|
244
244
|
completionToken
|
|
245
245
|
}));
|
|
246
246
|
const reference = yield* DurableDeferred.await(completion);
|
|
247
247
|
const record = yield* runtime.settlementRecord(receipt);
|
|
248
|
-
if (reference.submissionId !== receipt.submissionId || reference.threadId !== receipt.threadId || reference.settlementId !== record.settlementId) return yield*
|
|
248
|
+
if (reference.submissionId !== receipt.submissionId || reference.threadId !== receipt.threadId || reference.settlementId !== record.settlementId) return yield* WorkflowDispatchError.make({
|
|
249
249
|
operation: "result",
|
|
250
250
|
message: "Workflow completion disagrees with canonical Settlement"
|
|
251
251
|
});
|
|
252
|
-
if (record.outcome === "failed") return yield*
|
|
252
|
+
if (record.outcome === "failed") return yield* WorkflowExecutionFailure.make({
|
|
253
253
|
reason: "failed",
|
|
254
254
|
message: "Agent submission failed",
|
|
255
255
|
receipt,
|
|
256
256
|
failure: record.result
|
|
257
257
|
});
|
|
258
|
-
if (record.outcome === "aborted") return yield*
|
|
258
|
+
if (record.outcome === "aborted") return yield* WorkflowExecutionFailure.make({
|
|
259
259
|
reason: "aborted",
|
|
260
260
|
message: "Agent submission was aborted",
|
|
261
261
|
receipt
|
|
262
262
|
});
|
|
263
|
-
if (record.result === void 0) return yield*
|
|
263
|
+
if (record.result === void 0) return yield* WorkflowExecutionFailure.make({
|
|
264
264
|
reason: "missing-output",
|
|
265
265
|
message: "Completed submission has no independent output",
|
|
266
266
|
receipt
|
|
267
267
|
});
|
|
268
|
-
return yield* Schema.decodeEffect(agent.output)(record.result).pipe(Effect.mapError((cause) =>
|
|
268
|
+
return yield* Schema.decodeEffect(agent.output)(record.result).pipe(Effect.mapError((cause) => AgentOutputError.make({ message: `Cannot decode canonical agent output: ${cause.message}` })));
|
|
269
269
|
});
|
|
270
270
|
return WorkflowAgentHost.of({
|
|
271
271
|
execute,
|
|
@@ -295,4 +295,4 @@ var WorkflowAgentHost = class WorkflowAgentHost extends Context.Service()("@effe
|
|
|
295
295
|
//#endregion
|
|
296
296
|
export { WorkflowHostConfigError as i, WorkflowAgentHost as n, WorkflowAgentHost_exports as r, WorkflowAdmissionClosed as t };
|
|
297
297
|
|
|
298
|
-
//# sourceMappingURL=WorkflowAgentHost-
|
|
298
|
+
//# sourceMappingURL=WorkflowAgentHost-Dkq5IC6U.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WorkflowAgentHost-Dkq5IC6U.mjs","names":[],"sources":["../src/internal/completion.ts","../src/WorkflowAgentHost.ts"],"sourcesContent":["import { DurableDeferred } from \"effect/workflow\";\n\nimport { WorkflowSettlementReference } from \"../WorkflowDispatch.ts\";\n\n/** Native deferred results contain only canonical identities, never a second agent result. */\nexport const workflowCompletion = (name: string) =>\n DurableDeferred.make(name, { success: WorkflowSettlementReference });\n","import { AgentOutputError } from \"@yielded/agent/agent-error\";\nimport { type BindingUnavailable } from \"@yielded/agent/agent-registration\";\nimport { digestJson } from \"@yielded/agent/digest\";\nimport {\n DurableAgentRuntime,\n DurableRuntimeConfig,\n Receipt,\n type DurableAwaitFailure,\n type DurableSubmitAgent,\n type DurableSubmitFailure,\n type DurableSubmitOptions,\n} from \"@yielded/agent/durable-agent-runtime\";\nimport { ThreadId } from \"@yielded/agent/identifiers\";\nimport { DeploymentId } from \"@yielded/agent/records\";\nimport {\n IdempotencyKey,\n Principal,\n SubmissionLedger,\n SubmissionLookupById,\n} from \"@yielded/agent/submission-ledger\";\nimport {\n Cause,\n Context,\n Crypto,\n Effect,\n Exit,\n Layer,\n Option,\n RcMap,\n Ref,\n Result,\n Schema,\n Semaphore,\n Stream,\n} from \"effect\";\nimport { DurableDeferred, Workflow, WorkflowEngine } from \"effect/workflow\";\n\nimport { workflowCompletion } from \"./internal/completion.ts\";\nimport {\n WorkflowDispatchError,\n WorkflowDispatchFailpoint,\n WorkflowDispatchIntent,\n WorkflowDispatchScan,\n WorkflowDispatchStore,\n WorkflowRepairReport,\n WorkflowRepairTrigger,\n WorkflowSettlementReference,\n WorkflowSubmission,\n} from \"./WorkflowDispatch.ts\";\nimport {\n WorkflowExecutionFailure,\n type WorkflowAgent,\n type WorkflowExecuteOptions,\n} from \"./WorkflowExecution.ts\";\n\nconst WorkflowHostConfig = Schema.Struct({\n deploymentId: DeploymentId,\n principal: Principal,\n workflowName: Schema.NonEmptyString,\n executionConcurrency: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 64 })),\n repairBatchSize: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 1000 })),\n dispatchTimeoutMillis: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 300_000 })),\n});\n\nexport class WorkflowHostConfigError extends Schema.TaggedError<WorkflowHostConfigError>()(\n \"WorkflowHostConfigError\",\n { message: Schema.String },\n) {}\n\nexport class WorkflowAdmissionClosed extends Schema.TaggedError<WorkflowAdmissionClosed>()(\n \"WorkflowAdmissionClosed\",\n { message: Schema.String },\n) {}\n\nexport interface WorkflowAgentHostOptions {\n readonly deploymentId: string;\n /** Application-owned identity for submissions from AgentWorkflow.execute. */\n readonly principal: string;\n /** Stable versioned name prefix. The native name also includes deploymentId. */\n readonly workflowName?: string;\n /** Concurrent Attempts within this host Layer instance, not a fleet-wide limit. Default 1. */\n readonly executionConcurrency?: number;\n /** Maximum entries per scan per repair invocation. Default 32. */\n readonly repairBatchSize?: number;\n /** Bound each dispatch or scan, including a retrying native engine. Default 10000 ms. */\n readonly dispatchTimeoutMillis?: number;\n}\n\nexport type WorkflowRepairFailure = WorkflowDispatchError | DurableAwaitFailure;\n\nconst nativeOperation = <A, E, R>(operation: string, effect: Effect.Effect<A, E, R>) =>\n effect.pipe(\n Effect.catchDefect((cause) =>\n Effect.fail(\n WorkflowDispatchError.make({\n operation,\n message: \"Workflow engine operation failed\",\n cause,\n }),\n ),\n ),\n );\n\nconst makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions) {\n const config = yield* Schema.decodeEffect(WorkflowHostConfig)({\n deploymentId: options.deploymentId,\n principal: options.principal,\n workflowName: options.workflowName ?? \"effect-agent/Submission/v1\",\n executionConcurrency: options.executionConcurrency ?? 1,\n repairBatchSize: options.repairBatchSize ?? 32,\n dispatchTimeoutMillis: options.dispatchTimeoutMillis ?? 10_000,\n }).pipe(Effect.mapError((error) => WorkflowHostConfigError.make({ message: error.message })));\n\n const runtime = yield* DurableAgentRuntime;\n const crypto = yield* Crypto.Crypto;\n const runtimeConfig = yield* DurableRuntimeConfig;\n const ledger = yield* SubmissionLedger;\n const engine = yield* WorkflowEngine.WorkflowEngine;\n const dispatch = yield* WorkflowDispatchStore;\n const trigger = yield* WorkflowRepairTrigger;\n const failpoint = yield* WorkflowDispatchFailpoint;\n\n if (runtimeConfig.deploymentId !== config.deploymentId) {\n return yield* WorkflowHostConfigError.make({\n message: \"Workflow and durable runtime deploymentId must match\",\n });\n }\n const permits = yield* Semaphore.make(config.executionConcurrency);\n const lanes = yield* RcMap.make({ lookup: (_threadId: ThreadId) => Semaphore.make(1) });\n const repairPermit = yield* Semaphore.make(1);\n const admission = yield* Ref.make(true);\n const nativeName = `${config.workflowName}/deployment/${config.deploymentId.length}:${config.deploymentId}`;\n\n const workflow = Workflow.make(nativeName, {\n payload: WorkflowSubmission,\n success: WorkflowSettlementReference,\n idempotencyKey: ({ deploymentId, receipt }) =>\n `v1/${deploymentId.length}:${deploymentId}/${receipt.submissionId}`,\n }).annotate(Workflow.SuspendOnFailure, true);\n\n const bounded = <A, E, R>(operation: string, effect: Effect.Effect<A, E, R>) =>\n nativeOperation(operation, effect).pipe(\n Effect.timeout(config.dispatchTimeoutMillis),\n Effect.catchTag(\"TimeoutError\", () =>\n Effect.fail(\n WorkflowDispatchError.make({\n operation,\n message: \"Workflow dispatch operation timed out; accepted work remains recoverable\",\n }),\n ),\n ),\n );\n\n const validateReceipt = Effect.fnUntraced(function* (receipt: Receipt) {\n const found = yield* ledger.lookup(\n SubmissionLookupById.make({ submissionId: receipt.submissionId }),\n );\n\n if (\n Option.isNone(found) ||\n found.value.deploymentId !== config.deploymentId ||\n found.value.threadId !== receipt.threadId ||\n found.value.receiptId !== receipt.receiptId ||\n found.value.queueSequence !== receipt.queueSequence\n ) {\n return yield* WorkflowDispatchError.make({\n operation: \"identity\",\n message: \"Workflow Receipt does not match its authoritative deployment and Submission\",\n });\n }\n });\n\n // No Activities: rerun journal recovery directly on every native resume. The upstream\n // failure annotation suspends infrastructure failures and defects instead of settling them.\n yield* engine.register(\n workflow,\n Effect.fnUntraced(function* (payload, executionId) {\n yield* Effect.annotateCurrentSpan({\n \"workflow.execution.id\": executionId,\n \"agent.submission.id\": payload.receipt.submissionId,\n \"agent.thread.id\": payload.receipt.threadId,\n });\n if (payload.deploymentId !== config.deploymentId) {\n return yield* Effect.die(\"Workflow payload belongs to another deployment\");\n }\n if (executionId !== (yield* workflow.executionId(payload))) {\n return yield* Effect.die(\"Workflow execution identity does not match its Submission\");\n }\n yield* validateReceipt(payload.receipt).pipe(Effect.orDie);\n const initial = yield* runtime.inspectSubmissionStatus(payload.receipt).pipe(Effect.orDie);\n\n if (initial._tag === \"settled\") {\n return WorkflowSettlementReference.make({\n version: 1,\n submissionId: initial.settlement.submissionId,\n threadId: payload.receipt.threadId,\n settlementId: initial.settlement.settlementId,\n });\n }\n\n const status = yield* Effect.scoped(\n Effect.gen(function* () {\n // Serialize recovery and processing for one Thread even when a ledger allows\n // same-producer takeover. Followers wait without consuming a global permit.\n const lane = yield* RcMap.get(lanes, payload.receipt.threadId);\n\n return yield* lane.withPermit(\n permits.withPermit(\n Effect.scoped(\n Effect.gen(function* () {\n yield* runtime.recoverSubmission(payload.receipt.submissionId);\n const recovered = yield* runtime.inspectSubmissionStatus(payload.receipt);\n\n if (recovered._tag === \"settled\") return recovered;\n yield* runtime.processThreadHead(payload.receipt.threadId);\n\n return yield* runtime.inspectSubmissionStatus(payload.receipt);\n }),\n ),\n ),\n );\n }),\n ).pipe(Effect.orDie);\n\n if (status._tag === \"settled\") {\n return WorkflowSettlementReference.make({\n version: 1,\n submissionId: status.settlement.submissionId,\n threadId: payload.receipt.threadId,\n settlementId: status.settlement.settlementId,\n });\n }\n // Release the permit and Attempt Scope before native suspension, whose lifetime may\n // outlast this process. Completion is never inferred from an empty processing result.\n const instance = yield* WorkflowEngine.WorkflowInstance;\n\n return yield* Workflow.suspend(instance);\n }),\n );\n\n const intentFor = Effect.fnUntraced(function* (receipt: Receipt) {\n const payload = WorkflowSubmission.make({\n version: 1,\n deploymentId: config.deploymentId,\n receipt,\n });\n\n const executionId = yield* workflow.executionId(payload);\n\n return WorkflowDispatchIntent.make({\n ...payload,\n workflowName: nativeName,\n executionId,\n });\n });\n\n const dispatchIntent = Effect.fnUntraced(\n function* (\n requested: WorkflowDispatchIntent,\n ): Effect.fn.Return<boolean, WorkflowRepairFailure> {\n let intent = requested;\n const expected = yield* intentFor(intent.receipt);\n\n if (\n intent.executionId !== expected.executionId ||\n intent.deploymentId !== expected.deploymentId ||\n intent.workflowName !== expected.workflowName\n ) {\n return yield* WorkflowDispatchError.make({\n operation: \"dispatch\",\n message: \"Dispatch identity does not match the configured Workflow\",\n });\n }\n yield* validateReceipt(intent.receipt);\n yield* failpoint.hit(\"intent:before-persist\", intent);\n intent = yield* dispatch.put(intent);\n yield* failpoint.hit(\"intent:after-persist\", intent);\n yield* failpoint.hit(\"launch:before\", intent);\n // Submission lifetime belongs to the durable host. Strip the optional parent\n // instance so upstream child interruption cannot cancel this recovery workflow.\n yield* nativeOperation(\n \"execute\",\n engine\n .execute(workflow, {\n executionId: intent.executionId,\n payload: WorkflowSubmission.make(intent),\n discard: true,\n })\n .pipe(\n Effect.updateContext((context: Context.Context<never>) =>\n Context.omit(WorkflowEngine.WorkflowInstance)(context),\n ),\n ),\n );\n yield* failpoint.hit(\"launch:after\", intent);\n // Resume before suspension may be a no-op. Keep the intent and retry on a later trigger.\n yield* nativeOperation(\"resume\", engine.resume(workflow, intent.executionId));\n yield* failpoint.hit(\"completion:before-observe\", intent);\n const result = yield* nativeOperation(\"poll\", engine.poll(workflow, intent.executionId));\n\n yield* failpoint.hit(\"completion:after-observe\", intent);\n if (Option.isNone(result) || result.value._tag !== \"Complete\") return false;\n if (Exit.isFailure(result.value.exit)) {\n return yield* WorkflowDispatchError.make({\n operation: \"completion\",\n message: \"Native Workflow completed without a Settlement reference; intent retained\",\n cause: result.value.exit.cause,\n });\n }\n const status = yield* runtime.inspectSubmissionStatus(intent.receipt);\n const reference = result.value.exit.value;\n\n if (\n status._tag !== \"settled\" ||\n reference.version !== 1 ||\n reference.submissionId !== intent.receipt.submissionId ||\n reference.threadId !== intent.receipt.threadId ||\n reference.settlementId !== status.settlement.settlementId\n ) {\n return yield* WorkflowDispatchError.make({\n operation: \"completion\",\n message: \"Native completion disagrees with canonical Settlement; intent retained\",\n });\n }\n if (intent.completionToken !== undefined) {\n yield* failpoint.hit(\"completion:before-notify\", intent);\n yield* nativeOperation(\n \"notify\",\n DurableDeferred.succeed(workflowCompletion(\"settlement\"), {\n token: intent.completionToken,\n value: reference,\n }).pipe(Effect.provideService(WorkflowEngine.WorkflowEngine, engine)),\n );\n yield* failpoint.hit(\"completion:after-notify\", intent);\n }\n yield* failpoint.hit(\"cleanup:before\", intent);\n yield* dispatch.remove(intent);\n yield* failpoint.hit(\"cleanup:after\", intent);\n\n return true;\n },\n (effect) => bounded(\"dispatch\", effect),\n );\n\n let submissionOffset = 0;\n let intentCursor: string | undefined;\n\n const repair = repairPermit.withPermit(\n Effect.gen(function* () {\n // Respect adapter ordering, which may differ from JavaScript string comparison.\n // Deletions may defer a row until the next wrap; restarts repeat idempotent work.\n const discovery = yield* bounded(\n \"scanSubmissions\",\n ledger.scanNonterminal.pipe(\n Stream.filter((row) => row.deploymentId === config.deploymentId),\n Stream.drop(submissionOffset),\n Stream.take(config.repairBatchSize),\n Stream.runCollect,\n ),\n ).pipe(Effect.result);\n\n const submissions = Result.isSuccess(discovery) ? discovery.success : [];\n\n if (Result.isSuccess(discovery)) {\n submissionOffset =\n submissions.length < config.repairBatchSize ? 0 : submissionOffset + submissions.length;\n }\n\n const discovered = yield* Effect.forEach(submissions, (row) =>\n Effect.flatMap(intentFor(Receipt.make(row)), dispatchIntent).pipe(Effect.result),\n );\n\n const outstanding = yield* bounded(\n \"scanIntents\",\n dispatch.scan(\n WorkflowDispatchScan.make({\n deploymentId: config.deploymentId,\n workflowName: nativeName,\n ...(intentCursor === undefined ? {} : { after: intentCursor }),\n limit: config.repairBatchSize,\n }),\n ),\n ).pipe(Effect.result);\n\n const intents = Result.isSuccess(outstanding) ? outstanding.success : [];\n\n if (Result.isSuccess(outstanding))\n intentCursor =\n intents.length < config.repairBatchSize\n ? undefined\n : intents[intents.length - 1]?.executionId;\n\n const inspected = yield* Effect.forEach(intents, (intent) =>\n dispatchIntent(intent).pipe(Effect.result),\n );\n\n const results = [...discovered, ...inspected];\n\n if (Result.isFailure(discovery)) return yield* discovery.failure;\n if (Result.isFailure(outstanding)) return yield* outstanding.failure;\n const failure = results.find(Result.isFailure);\n\n if (failure !== undefined) return yield* Effect.fail(failure.failure);\n\n return WorkflowRepairReport.make({\n discovered: submissions.length,\n inspected: intents.length,\n completed: results.filter((result) => Result.isSuccess(result) && result.success).length,\n });\n }),\n );\n\n yield* trigger.register(\n repair.pipe(\n Effect.asVoid,\n Effect.catchCause((cause) =>\n Cause.hasInterruptsOnly(cause)\n ? Effect.interrupt\n : Effect.logError(\"Workflow dispatch repair failed; durable obligations remain\", cause),\n ),\n ),\n );\n yield* Effect.addFinalizer(() => Ref.set(admission, false));\n\n const submit = Effect.fnUntraced(function* <InputSchema extends Schema.Top>(\n agent: DurableSubmitAgent<InputSchema>,\n input: InputSchema[\"Type\"],\n options: DurableSubmitOptions,\n ): Effect.fn.Return<\n Receipt,\n DurableSubmitFailure | WorkflowRepairFailure | WorkflowAdmissionClosed,\n InputSchema[\"EncodingServices\"]\n > {\n if (!(yield* Ref.get(admission))) {\n return yield* WorkflowAdmissionClosed.make({ message: \"The Workflow host is shutting down\" });\n }\n const receipt = yield* runtime.submit(agent, input, options);\n\n yield* dispatchIntent(yield* intentFor(receipt));\n\n return receipt;\n });\n\n const execute = Effect.fnUntraced(function* <Input extends Schema.Top, Output extends Schema.Top>(\n agent: WorkflowAgent<Input, Output>,\n input: Input[\"Type\"],\n options: WorkflowExecuteOptions,\n ) {\n const parentEngine = yield* WorkflowEngine.WorkflowEngine;\n\n if (parentEngine !== engine) {\n return yield* WorkflowExecutionFailure.make({\n reason: \"engine-mismatch\",\n message: \"Agent host and parent workflow must share one WorkflowEngine Layer\",\n });\n }\n\n const name = yield* Schema.decodeEffect(Schema.NonEmptyString)(options.name).pipe(\n Effect.mapError(() =>\n WorkflowExecutionFailure.make({\n reason: \"invalid-name\",\n message: \"Workflow agent steps need a nonempty stable name\",\n }),\n ),\n );\n\n const completion = workflowCompletion(`effect-agent/${name}`);\n const completionToken = yield* DurableDeferred.token(completion);\n\n // Agent identity and input deliberately do not participate: changing either on replay\n // must conflict with the original admission rather than launch new external work.\n const identity = yield* digestJson([\n config.deploymentId,\n config.principal,\n completionToken,\n ]).pipe(Effect.provideService(Crypto.Crypto, crypto));\n\n if (!(yield* Ref.get(admission))) {\n return yield* WorkflowAdmissionClosed.make({ message: \"The Workflow host is shutting down\" });\n }\n\n const receipt = yield* runtime.submitRegistered({ definition: agent }, input, {\n threadId: ThreadId.make(`workflow/${identity}`),\n idempotencyKey: IdempotencyKey.make(identity),\n principal: config.principal,\n });\n\n yield* Effect.annotateCurrentSpan({\n \"agent.submission.id\": receipt.submissionId,\n \"agent.workflow.step\": name,\n });\n yield* runtime.submissionStatus(receipt);\n yield* dispatchIntent(\n WorkflowDispatchIntent.make({ ...(yield* intentFor(receipt)), completionToken }),\n );\n\n // The deferred stores only a reference. Always reauthorize and read canonical data,\n // including on replay after the workflow engine has cached the notification.\n const reference = yield* DurableDeferred.await(completion);\n\n const record = yield* runtime.settlementRecord(receipt);\n\n if (\n reference.submissionId !== receipt.submissionId ||\n reference.threadId !== receipt.threadId ||\n reference.settlementId !== record.settlementId\n ) {\n return yield* WorkflowDispatchError.make({\n operation: \"result\",\n message: \"Workflow completion disagrees with canonical Settlement\",\n });\n }\n if (record.outcome === \"failed\") {\n return yield* WorkflowExecutionFailure.make({\n reason: \"failed\",\n message: \"Agent submission failed\",\n receipt,\n failure: record.result,\n });\n }\n if (record.outcome === \"aborted\") {\n return yield* WorkflowExecutionFailure.make({\n reason: \"aborted\",\n message: \"Agent submission was aborted\",\n receipt,\n });\n }\n if (record.result === undefined) {\n return yield* WorkflowExecutionFailure.make({\n reason: \"missing-output\",\n message: \"Completed submission has no independent output\",\n receipt,\n });\n }\n\n return yield* Schema.decodeEffect(agent.output)(record.result).pipe(\n Effect.mapError((cause) =>\n AgentOutputError.make({\n message: `Cannot decode canonical agent output: ${cause.message}`,\n }),\n ),\n );\n });\n\n return WorkflowAgentHost.of({\n execute,\n submit,\n awaitSettlement: runtime.awaitSettlement,\n observe: runtime.observe,\n abort: runtime.abort,\n resolveApproval: runtime.resolveApproval,\n resolveUnknown: runtime.resolveUnknown,\n submissionStatus: runtime.submissionStatus,\n repair,\n executionId: (receipt: Receipt) =>\n intentFor(receipt).pipe(Effect.map((intent) => intent.executionId)),\n });\n});\n\n/**\n * Optional engine-independent host. Supply the upstream WorkflowEngine, the existing\n * durable runtime and ledger, durable dispatch storage, and a host-owned repair trigger.\n * Do not also start the ordinary Node worker loop. Waiter interruption only detaches;\n * abort and resolutions retain the runtime's authorization and durable intent protocol.\n */\nexport class WorkflowAgentHost extends Context.Service<\n WorkflowAgentHost,\n {\n readonly execute: <Input extends Schema.Top, Output extends Schema.Top>(\n agent: WorkflowAgent<Input, Output>,\n input: Input[\"Type\"],\n options: WorkflowExecuteOptions,\n ) => Effect.Effect<\n Output[\"Type\"],\n | DurableSubmitFailure\n | BindingUnavailable\n | DurableAwaitFailure\n | WorkflowDispatchError\n | WorkflowAdmissionClosed\n | WorkflowExecutionFailure\n | AgentOutputError,\n | Input[\"EncodingServices\"]\n | Output[\"DecodingServices\"]\n | WorkflowEngine.WorkflowInstance\n | WorkflowEngine.WorkflowEngine\n >;\n readonly submit: <InputSchema extends Schema.Top>(\n agent: DurableSubmitAgent<InputSchema>,\n input: InputSchema[\"Type\"],\n options: DurableSubmitOptions,\n ) => Effect.Effect<\n Receipt,\n DurableSubmitFailure | WorkflowRepairFailure | WorkflowAdmissionClosed,\n InputSchema[\"EncodingServices\"]\n >;\n readonly awaitSettlement: DurableAgentRuntime[\"Service\"][\"awaitSettlement\"];\n readonly observe: DurableAgentRuntime[\"Service\"][\"observe\"];\n readonly abort: DurableAgentRuntime[\"Service\"][\"abort\"];\n readonly resolveApproval: DurableAgentRuntime[\"Service\"][\"resolveApproval\"];\n readonly resolveUnknown: DurableAgentRuntime[\"Service\"][\"resolveUnknown\"];\n readonly submissionStatus: DurableAgentRuntime[\"Service\"][\"submissionStatus\"];\n readonly repair: Effect.Effect<WorkflowRepairReport, WorkflowRepairFailure>;\n readonly executionId: (receipt: Receipt) => Effect.Effect<string>;\n }\n>()(\"@effect-agent/workflow/WorkflowAgentHost\") {\n /** Drive the injected runtime, whose Layer owns executable registrations and their services. */\n static layer(options: WorkflowAgentHostOptions) {\n return Layer.effect(WorkflowAgentHost)(makeHost(options));\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import "./WorkflowDispatch.mjs";
|
|
2
|
-
import { i as WorkflowHostConfigError, n as WorkflowAgentHost, t as WorkflowAdmissionClosed } from "./WorkflowAgentHost-
|
|
2
|
+
import { i as WorkflowHostConfigError, n as WorkflowAgentHost, t as WorkflowAdmissionClosed } from "./WorkflowAgentHost-Dkq5IC6U.mjs";
|
|
3
3
|
import "./WorkflowExecution.mjs";
|
|
4
4
|
export { WorkflowAdmissionClosed, WorkflowAgentHost, WorkflowHostConfigError };
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as WorkflowDispatch_exports } from "./WorkflowDispatch.mjs";
|
|
2
|
-
import { r as WorkflowAgentHost_exports } from "./WorkflowAgentHost-
|
|
2
|
+
import { r as WorkflowAgentHost_exports } from "./WorkflowAgentHost-Dkq5IC6U.mjs";
|
|
3
3
|
import { t as WorkflowExecution_exports } from "./WorkflowExecution.mjs";
|
|
4
4
|
import { t as AgentWorkflow_exports } from "./AgentWorkflow.mjs";
|
|
5
5
|
export { AgentWorkflow_exports as AgentWorkflow, WorkflowAgentHost_exports as WorkflowAgentHost, WorkflowDispatch_exports as WorkflowDispatch, WorkflowExecution_exports as WorkflowExecution };
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@yielded/agent-workflow","version":"0.1.0-beta.
|
|
1
|
+
{"name":"@yielded/agent-workflow","version":"0.1.0-beta.174","dependencies":{"@yielded/agent":"0.1.0-beta.174"},"devDependencies":{"@effect/platform-node":"4.0.3","@effect/vitest":"4.0.3","@yielded/agent-storage-memory":"0.1.0-beta.174","effect":"4.0.3","typescript":"7.0.2","vite":"npm:@voidzero-dev/vite-plus-core@1.1.0","vite-plus":"1.1.0","vitest":"5.0.3"},"peerDependencies":{"effect":"^4.0.0"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./agent-workflow":{"types":"./dist/AgentWorkflow.d.mts","default":"./dist/AgentWorkflow.mjs"},"./workflow-agent-host":{"types":"./dist/WorkflowAgentHost.d.mts","default":"./dist/WorkflowAgentHost.mjs"},"./workflow-dispatch":{"types":"./dist/WorkflowDispatch.d.mts","default":"./dist/WorkflowDispatch.mjs"},"./workflow-execution":{"types":"./dist/WorkflowExecution.d.mts","default":"./dist/WorkflowExecution.mjs"}},"description":"Effect Workflow execution for the existing durable Agent runtime.","license":"MIT","repository":{"type":"git","url":"git+https://github.com/yielded-dev/agent.git","directory":"packages/workflow"},"files":["dist","src"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json","test":"vp test --passWithNoTests"}}
|
package/src/WorkflowAgentHost.ts
CHANGED
|
@@ -92,7 +92,7 @@ const nativeOperation = <A, E, R>(operation: string, effect: Effect.Effect<A, E,
|
|
|
92
92
|
effect.pipe(
|
|
93
93
|
Effect.catchDefect((cause) =>
|
|
94
94
|
Effect.fail(
|
|
95
|
-
|
|
95
|
+
WorkflowDispatchError.make({
|
|
96
96
|
operation,
|
|
97
97
|
message: "Workflow engine operation failed",
|
|
98
98
|
cause,
|
|
@@ -109,7 +109,7 @@ const makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions)
|
|
|
109
109
|
executionConcurrency: options.executionConcurrency ?? 1,
|
|
110
110
|
repairBatchSize: options.repairBatchSize ?? 32,
|
|
111
111
|
dispatchTimeoutMillis: options.dispatchTimeoutMillis ?? 10_000,
|
|
112
|
-
}).pipe(Effect.mapError((error) =>
|
|
112
|
+
}).pipe(Effect.mapError((error) => WorkflowHostConfigError.make({ message: error.message })));
|
|
113
113
|
|
|
114
114
|
const runtime = yield* DurableAgentRuntime;
|
|
115
115
|
const crypto = yield* Crypto.Crypto;
|
|
@@ -121,7 +121,7 @@ const makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions)
|
|
|
121
121
|
const failpoint = yield* WorkflowDispatchFailpoint;
|
|
122
122
|
|
|
123
123
|
if (runtimeConfig.deploymentId !== config.deploymentId) {
|
|
124
|
-
return yield*
|
|
124
|
+
return yield* WorkflowHostConfigError.make({
|
|
125
125
|
message: "Workflow and durable runtime deploymentId must match",
|
|
126
126
|
});
|
|
127
127
|
}
|
|
@@ -190,7 +190,7 @@ const makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions)
|
|
|
190
190
|
const initial = yield* runtime.inspectSubmissionStatus(payload.receipt).pipe(Effect.orDie);
|
|
191
191
|
|
|
192
192
|
if (initial._tag === "settled") {
|
|
193
|
-
return
|
|
193
|
+
return WorkflowSettlementReference.make({
|
|
194
194
|
version: 1,
|
|
195
195
|
submissionId: initial.settlement.submissionId,
|
|
196
196
|
threadId: payload.receipt.threadId,
|
|
@@ -223,7 +223,7 @@ const makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions)
|
|
|
223
223
|
).pipe(Effect.orDie);
|
|
224
224
|
|
|
225
225
|
if (status._tag === "settled") {
|
|
226
|
-
return
|
|
226
|
+
return WorkflowSettlementReference.make({
|
|
227
227
|
version: 1,
|
|
228
228
|
submissionId: status.settlement.submissionId,
|
|
229
229
|
threadId: payload.receipt.threadId,
|
|
@@ -239,7 +239,7 @@ const makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions)
|
|
|
239
239
|
);
|
|
240
240
|
|
|
241
241
|
const intentFor = Effect.fnUntraced(function* (receipt: Receipt) {
|
|
242
|
-
const payload =
|
|
242
|
+
const payload = WorkflowSubmission.make({
|
|
243
243
|
version: 1,
|
|
244
244
|
deploymentId: config.deploymentId,
|
|
245
245
|
receipt,
|
|
@@ -247,7 +247,7 @@ const makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions)
|
|
|
247
247
|
|
|
248
248
|
const executionId = yield* workflow.executionId(payload);
|
|
249
249
|
|
|
250
|
-
return
|
|
250
|
+
return WorkflowDispatchIntent.make({
|
|
251
251
|
...payload,
|
|
252
252
|
workflowName: nativeName,
|
|
253
253
|
executionId,
|
|
@@ -266,7 +266,7 @@ const makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions)
|
|
|
266
266
|
intent.deploymentId !== expected.deploymentId ||
|
|
267
267
|
intent.workflowName !== expected.workflowName
|
|
268
268
|
) {
|
|
269
|
-
return yield*
|
|
269
|
+
return yield* WorkflowDispatchError.make({
|
|
270
270
|
operation: "dispatch",
|
|
271
271
|
message: "Dispatch identity does not match the configured Workflow",
|
|
272
272
|
});
|
|
@@ -283,7 +283,7 @@ const makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions)
|
|
|
283
283
|
engine
|
|
284
284
|
.execute(workflow, {
|
|
285
285
|
executionId: intent.executionId,
|
|
286
|
-
payload:
|
|
286
|
+
payload: WorkflowSubmission.make(intent),
|
|
287
287
|
discard: true,
|
|
288
288
|
})
|
|
289
289
|
.pipe(
|
|
@@ -301,7 +301,7 @@ const makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions)
|
|
|
301
301
|
yield* failpoint.hit("completion:after-observe", intent);
|
|
302
302
|
if (Option.isNone(result) || result.value._tag !== "Complete") return false;
|
|
303
303
|
if (Exit.isFailure(result.value.exit)) {
|
|
304
|
-
return yield*
|
|
304
|
+
return yield* WorkflowDispatchError.make({
|
|
305
305
|
operation: "completion",
|
|
306
306
|
message: "Native Workflow completed without a Settlement reference; intent retained",
|
|
307
307
|
cause: result.value.exit.cause,
|
|
@@ -317,7 +317,7 @@ const makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions)
|
|
|
317
317
|
reference.threadId !== intent.receipt.threadId ||
|
|
318
318
|
reference.settlementId !== status.settlement.settlementId
|
|
319
319
|
) {
|
|
320
|
-
return yield*
|
|
320
|
+
return yield* WorkflowDispatchError.make({
|
|
321
321
|
operation: "completion",
|
|
322
322
|
message: "Native completion disagrees with canonical Settlement; intent retained",
|
|
323
323
|
});
|
|
@@ -367,13 +367,13 @@ const makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions)
|
|
|
367
367
|
}
|
|
368
368
|
|
|
369
369
|
const discovered = yield* Effect.forEach(submissions, (row) =>
|
|
370
|
-
Effect.flatMap(intentFor(
|
|
370
|
+
Effect.flatMap(intentFor(Receipt.make(row)), dispatchIntent).pipe(Effect.result),
|
|
371
371
|
);
|
|
372
372
|
|
|
373
373
|
const outstanding = yield* bounded(
|
|
374
374
|
"scanIntents",
|
|
375
375
|
dispatch.scan(
|
|
376
|
-
|
|
376
|
+
WorkflowDispatchScan.make({
|
|
377
377
|
deploymentId: config.deploymentId,
|
|
378
378
|
workflowName: nativeName,
|
|
379
379
|
...(intentCursor === undefined ? {} : { after: intentCursor }),
|
|
@@ -402,7 +402,7 @@ const makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions)
|
|
|
402
402
|
|
|
403
403
|
if (failure !== undefined) return yield* Effect.fail(failure.failure);
|
|
404
404
|
|
|
405
|
-
return
|
|
405
|
+
return WorkflowRepairReport.make({
|
|
406
406
|
discovered: submissions.length,
|
|
407
407
|
inspected: intents.length,
|
|
408
408
|
completed: results.filter((result) => Result.isSuccess(result) && result.success).length,
|
|
@@ -432,7 +432,7 @@ const makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions)
|
|
|
432
432
|
InputSchema["EncodingServices"]
|
|
433
433
|
> {
|
|
434
434
|
if (!(yield* Ref.get(admission))) {
|
|
435
|
-
return yield*
|
|
435
|
+
return yield* WorkflowAdmissionClosed.make({ message: "The Workflow host is shutting down" });
|
|
436
436
|
}
|
|
437
437
|
const receipt = yield* runtime.submit(agent, input, options);
|
|
438
438
|
|
|
@@ -449,19 +449,18 @@ const makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions)
|
|
|
449
449
|
const parentEngine = yield* WorkflowEngine.WorkflowEngine;
|
|
450
450
|
|
|
451
451
|
if (parentEngine !== engine) {
|
|
452
|
-
return yield*
|
|
452
|
+
return yield* WorkflowExecutionFailure.make({
|
|
453
453
|
reason: "engine-mismatch",
|
|
454
454
|
message: "Agent host and parent workflow must share one WorkflowEngine Layer",
|
|
455
455
|
});
|
|
456
456
|
}
|
|
457
457
|
|
|
458
458
|
const name = yield* Schema.decodeEffect(Schema.NonEmptyString)(options.name).pipe(
|
|
459
|
-
Effect.mapError(
|
|
460
|
-
(
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
}),
|
|
459
|
+
Effect.mapError(() =>
|
|
460
|
+
WorkflowExecutionFailure.make({
|
|
461
|
+
reason: "invalid-name",
|
|
462
|
+
message: "Workflow agent steps need a nonempty stable name",
|
|
463
|
+
}),
|
|
465
464
|
),
|
|
466
465
|
);
|
|
467
466
|
|
|
@@ -477,7 +476,7 @@ const makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions)
|
|
|
477
476
|
]).pipe(Effect.provideService(Crypto.Crypto, crypto));
|
|
478
477
|
|
|
479
478
|
if (!(yield* Ref.get(admission))) {
|
|
480
|
-
return yield*
|
|
479
|
+
return yield* WorkflowAdmissionClosed.make({ message: "The Workflow host is shutting down" });
|
|
481
480
|
}
|
|
482
481
|
|
|
483
482
|
const receipt = yield* runtime.submitRegistered({ definition: agent }, input, {
|
|
@@ -492,7 +491,7 @@ const makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions)
|
|
|
492
491
|
});
|
|
493
492
|
yield* runtime.submissionStatus(receipt);
|
|
494
493
|
yield* dispatchIntent(
|
|
495
|
-
|
|
494
|
+
WorkflowDispatchIntent.make({ ...(yield* intentFor(receipt)), completionToken }),
|
|
496
495
|
);
|
|
497
496
|
|
|
498
497
|
// The deferred stores only a reference. Always reauthorize and read canonical data,
|
|
@@ -506,13 +505,13 @@ const makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions)
|
|
|
506
505
|
reference.threadId !== receipt.threadId ||
|
|
507
506
|
reference.settlementId !== record.settlementId
|
|
508
507
|
) {
|
|
509
|
-
return yield*
|
|
508
|
+
return yield* WorkflowDispatchError.make({
|
|
510
509
|
operation: "result",
|
|
511
510
|
message: "Workflow completion disagrees with canonical Settlement",
|
|
512
511
|
});
|
|
513
512
|
}
|
|
514
513
|
if (record.outcome === "failed") {
|
|
515
|
-
return yield*
|
|
514
|
+
return yield* WorkflowExecutionFailure.make({
|
|
516
515
|
reason: "failed",
|
|
517
516
|
message: "Agent submission failed",
|
|
518
517
|
receipt,
|
|
@@ -520,14 +519,14 @@ const makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions)
|
|
|
520
519
|
});
|
|
521
520
|
}
|
|
522
521
|
if (record.outcome === "aborted") {
|
|
523
|
-
return yield*
|
|
522
|
+
return yield* WorkflowExecutionFailure.make({
|
|
524
523
|
reason: "aborted",
|
|
525
524
|
message: "Agent submission was aborted",
|
|
526
525
|
receipt,
|
|
527
526
|
});
|
|
528
527
|
}
|
|
529
528
|
if (record.result === undefined) {
|
|
530
|
-
return yield*
|
|
529
|
+
return yield* WorkflowExecutionFailure.make({
|
|
531
530
|
reason: "missing-output",
|
|
532
531
|
message: "Completed submission has no independent output",
|
|
533
532
|
receipt,
|
|
@@ -535,11 +534,10 @@ const makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions)
|
|
|
535
534
|
}
|
|
536
535
|
|
|
537
536
|
return yield* Schema.decodeEffect(agent.output)(record.result).pipe(
|
|
538
|
-
Effect.mapError(
|
|
539
|
-
(
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
}),
|
|
537
|
+
Effect.mapError((cause) =>
|
|
538
|
+
AgentOutputError.make({
|
|
539
|
+
message: `Cannot decode canonical agent output: ${cause.message}`,
|
|
540
|
+
}),
|
|
543
541
|
),
|
|
544
542
|
);
|
|
545
543
|
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"WorkflowAgentHost-DTcWCdU2.mjs","names":[],"sources":["../src/internal/completion.ts","../src/WorkflowAgentHost.ts"],"sourcesContent":["import { DurableDeferred } from \"effect/workflow\";\n\nimport { WorkflowSettlementReference } from \"../WorkflowDispatch.ts\";\n\n/** Native deferred results contain only canonical identities, never a second agent result. */\nexport const workflowCompletion = (name: string) =>\n DurableDeferred.make(name, { success: WorkflowSettlementReference });\n","import { AgentOutputError } from \"@yielded/agent/agent-error\";\nimport { type BindingUnavailable } from \"@yielded/agent/agent-registration\";\nimport { digestJson } from \"@yielded/agent/digest\";\nimport {\n DurableAgentRuntime,\n DurableRuntimeConfig,\n Receipt,\n type DurableAwaitFailure,\n type DurableSubmitAgent,\n type DurableSubmitFailure,\n type DurableSubmitOptions,\n} from \"@yielded/agent/durable-agent-runtime\";\nimport { ThreadId } from \"@yielded/agent/identifiers\";\nimport { DeploymentId } from \"@yielded/agent/records\";\nimport {\n IdempotencyKey,\n Principal,\n SubmissionLedger,\n SubmissionLookupById,\n} from \"@yielded/agent/submission-ledger\";\nimport {\n Cause,\n Context,\n Crypto,\n Effect,\n Exit,\n Layer,\n Option,\n RcMap,\n Ref,\n Result,\n Schema,\n Semaphore,\n Stream,\n} from \"effect\";\nimport { DurableDeferred, Workflow, WorkflowEngine } from \"effect/workflow\";\n\nimport { workflowCompletion } from \"./internal/completion.ts\";\nimport {\n WorkflowDispatchError,\n WorkflowDispatchFailpoint,\n WorkflowDispatchIntent,\n WorkflowDispatchScan,\n WorkflowDispatchStore,\n WorkflowRepairReport,\n WorkflowRepairTrigger,\n WorkflowSettlementReference,\n WorkflowSubmission,\n} from \"./WorkflowDispatch.ts\";\nimport {\n WorkflowExecutionFailure,\n type WorkflowAgent,\n type WorkflowExecuteOptions,\n} from \"./WorkflowExecution.ts\";\n\nconst WorkflowHostConfig = Schema.Struct({\n deploymentId: DeploymentId,\n principal: Principal,\n workflowName: Schema.NonEmptyString,\n executionConcurrency: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 64 })),\n repairBatchSize: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 1000 })),\n dispatchTimeoutMillis: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 300_000 })),\n});\n\nexport class WorkflowHostConfigError extends Schema.TaggedError<WorkflowHostConfigError>()(\n \"WorkflowHostConfigError\",\n { message: Schema.String },\n) {}\n\nexport class WorkflowAdmissionClosed extends Schema.TaggedError<WorkflowAdmissionClosed>()(\n \"WorkflowAdmissionClosed\",\n { message: Schema.String },\n) {}\n\nexport interface WorkflowAgentHostOptions {\n readonly deploymentId: string;\n /** Application-owned identity for submissions from AgentWorkflow.execute. */\n readonly principal: string;\n /** Stable versioned name prefix. The native name also includes deploymentId. */\n readonly workflowName?: string;\n /** Concurrent Attempts within this host Layer instance, not a fleet-wide limit. Default 1. */\n readonly executionConcurrency?: number;\n /** Maximum entries per scan per repair invocation. Default 32. */\n readonly repairBatchSize?: number;\n /** Bound each dispatch or scan, including a retrying native engine. Default 10000 ms. */\n readonly dispatchTimeoutMillis?: number;\n}\n\nexport type WorkflowRepairFailure = WorkflowDispatchError | DurableAwaitFailure;\n\nconst nativeOperation = <A, E, R>(operation: string, effect: Effect.Effect<A, E, R>) =>\n effect.pipe(\n Effect.catchDefect((cause) =>\n Effect.fail(\n new WorkflowDispatchError({\n operation,\n message: \"Workflow engine operation failed\",\n cause,\n }),\n ),\n ),\n );\n\nconst makeHost = Effect.fnUntraced(function* (options: WorkflowAgentHostOptions) {\n const config = yield* Schema.decodeEffect(WorkflowHostConfig)({\n deploymentId: options.deploymentId,\n principal: options.principal,\n workflowName: options.workflowName ?? \"effect-agent/Submission/v1\",\n executionConcurrency: options.executionConcurrency ?? 1,\n repairBatchSize: options.repairBatchSize ?? 32,\n dispatchTimeoutMillis: options.dispatchTimeoutMillis ?? 10_000,\n }).pipe(Effect.mapError((error) => new WorkflowHostConfigError({ message: error.message })));\n\n const runtime = yield* DurableAgentRuntime;\n const crypto = yield* Crypto.Crypto;\n const runtimeConfig = yield* DurableRuntimeConfig;\n const ledger = yield* SubmissionLedger;\n const engine = yield* WorkflowEngine.WorkflowEngine;\n const dispatch = yield* WorkflowDispatchStore;\n const trigger = yield* WorkflowRepairTrigger;\n const failpoint = yield* WorkflowDispatchFailpoint;\n\n if (runtimeConfig.deploymentId !== config.deploymentId) {\n return yield* new WorkflowHostConfigError({\n message: \"Workflow and durable runtime deploymentId must match\",\n });\n }\n const permits = yield* Semaphore.make(config.executionConcurrency);\n const lanes = yield* RcMap.make({ lookup: (_threadId: ThreadId) => Semaphore.make(1) });\n const repairPermit = yield* Semaphore.make(1);\n const admission = yield* Ref.make(true);\n const nativeName = `${config.workflowName}/deployment/${config.deploymentId.length}:${config.deploymentId}`;\n\n const workflow = Workflow.make(nativeName, {\n payload: WorkflowSubmission,\n success: WorkflowSettlementReference,\n idempotencyKey: ({ deploymentId, receipt }) =>\n `v1/${deploymentId.length}:${deploymentId}/${receipt.submissionId}`,\n }).annotate(Workflow.SuspendOnFailure, true);\n\n const bounded = <A, E, R>(operation: string, effect: Effect.Effect<A, E, R>) =>\n nativeOperation(operation, effect).pipe(\n Effect.timeout(config.dispatchTimeoutMillis),\n Effect.catchTag(\"TimeoutError\", () =>\n Effect.fail(\n WorkflowDispatchError.make({\n operation,\n message: \"Workflow dispatch operation timed out; accepted work remains recoverable\",\n }),\n ),\n ),\n );\n\n const validateReceipt = Effect.fnUntraced(function* (receipt: Receipt) {\n const found = yield* ledger.lookup(\n SubmissionLookupById.make({ submissionId: receipt.submissionId }),\n );\n\n if (\n Option.isNone(found) ||\n found.value.deploymentId !== config.deploymentId ||\n found.value.threadId !== receipt.threadId ||\n found.value.receiptId !== receipt.receiptId ||\n found.value.queueSequence !== receipt.queueSequence\n ) {\n return yield* WorkflowDispatchError.make({\n operation: \"identity\",\n message: \"Workflow Receipt does not match its authoritative deployment and Submission\",\n });\n }\n });\n\n // No Activities: rerun journal recovery directly on every native resume. The upstream\n // failure annotation suspends infrastructure failures and defects instead of settling them.\n yield* engine.register(\n workflow,\n Effect.fnUntraced(function* (payload, executionId) {\n yield* Effect.annotateCurrentSpan({\n \"workflow.execution.id\": executionId,\n \"agent.submission.id\": payload.receipt.submissionId,\n \"agent.thread.id\": payload.receipt.threadId,\n });\n if (payload.deploymentId !== config.deploymentId) {\n return yield* Effect.die(\"Workflow payload belongs to another deployment\");\n }\n if (executionId !== (yield* workflow.executionId(payload))) {\n return yield* Effect.die(\"Workflow execution identity does not match its Submission\");\n }\n yield* validateReceipt(payload.receipt).pipe(Effect.orDie);\n const initial = yield* runtime.inspectSubmissionStatus(payload.receipt).pipe(Effect.orDie);\n\n if (initial._tag === \"settled\") {\n return new WorkflowSettlementReference({\n version: 1,\n submissionId: initial.settlement.submissionId,\n threadId: payload.receipt.threadId,\n settlementId: initial.settlement.settlementId,\n });\n }\n\n const status = yield* Effect.scoped(\n Effect.gen(function* () {\n // Serialize recovery and processing for one Thread even when a ledger allows\n // same-producer takeover. Followers wait without consuming a global permit.\n const lane = yield* RcMap.get(lanes, payload.receipt.threadId);\n\n return yield* lane.withPermit(\n permits.withPermit(\n Effect.scoped(\n Effect.gen(function* () {\n yield* runtime.recoverSubmission(payload.receipt.submissionId);\n const recovered = yield* runtime.inspectSubmissionStatus(payload.receipt);\n\n if (recovered._tag === \"settled\") return recovered;\n yield* runtime.processThreadHead(payload.receipt.threadId);\n\n return yield* runtime.inspectSubmissionStatus(payload.receipt);\n }),\n ),\n ),\n );\n }),\n ).pipe(Effect.orDie);\n\n if (status._tag === \"settled\") {\n return new WorkflowSettlementReference({\n version: 1,\n submissionId: status.settlement.submissionId,\n threadId: payload.receipt.threadId,\n settlementId: status.settlement.settlementId,\n });\n }\n // Release the permit and Attempt Scope before native suspension, whose lifetime may\n // outlast this process. Completion is never inferred from an empty processing result.\n const instance = yield* WorkflowEngine.WorkflowInstance;\n\n return yield* Workflow.suspend(instance);\n }),\n );\n\n const intentFor = Effect.fnUntraced(function* (receipt: Receipt) {\n const payload = new WorkflowSubmission({\n version: 1,\n deploymentId: config.deploymentId,\n receipt,\n });\n\n const executionId = yield* workflow.executionId(payload);\n\n return new WorkflowDispatchIntent({\n ...payload,\n workflowName: nativeName,\n executionId,\n });\n });\n\n const dispatchIntent = Effect.fnUntraced(\n function* (\n requested: WorkflowDispatchIntent,\n ): Effect.fn.Return<boolean, WorkflowRepairFailure> {\n let intent = requested;\n const expected = yield* intentFor(intent.receipt);\n\n if (\n intent.executionId !== expected.executionId ||\n intent.deploymentId !== expected.deploymentId ||\n intent.workflowName !== expected.workflowName\n ) {\n return yield* new WorkflowDispatchError({\n operation: \"dispatch\",\n message: \"Dispatch identity does not match the configured Workflow\",\n });\n }\n yield* validateReceipt(intent.receipt);\n yield* failpoint.hit(\"intent:before-persist\", intent);\n intent = yield* dispatch.put(intent);\n yield* failpoint.hit(\"intent:after-persist\", intent);\n yield* failpoint.hit(\"launch:before\", intent);\n // Submission lifetime belongs to the durable host. Strip the optional parent\n // instance so upstream child interruption cannot cancel this recovery workflow.\n yield* nativeOperation(\n \"execute\",\n engine\n .execute(workflow, {\n executionId: intent.executionId,\n payload: new WorkflowSubmission(intent),\n discard: true,\n })\n .pipe(\n Effect.updateContext((context: Context.Context<never>) =>\n Context.omit(WorkflowEngine.WorkflowInstance)(context),\n ),\n ),\n );\n yield* failpoint.hit(\"launch:after\", intent);\n // Resume before suspension may be a no-op. Keep the intent and retry on a later trigger.\n yield* nativeOperation(\"resume\", engine.resume(workflow, intent.executionId));\n yield* failpoint.hit(\"completion:before-observe\", intent);\n const result = yield* nativeOperation(\"poll\", engine.poll(workflow, intent.executionId));\n\n yield* failpoint.hit(\"completion:after-observe\", intent);\n if (Option.isNone(result) || result.value._tag !== \"Complete\") return false;\n if (Exit.isFailure(result.value.exit)) {\n return yield* new WorkflowDispatchError({\n operation: \"completion\",\n message: \"Native Workflow completed without a Settlement reference; intent retained\",\n cause: result.value.exit.cause,\n });\n }\n const status = yield* runtime.inspectSubmissionStatus(intent.receipt);\n const reference = result.value.exit.value;\n\n if (\n status._tag !== \"settled\" ||\n reference.version !== 1 ||\n reference.submissionId !== intent.receipt.submissionId ||\n reference.threadId !== intent.receipt.threadId ||\n reference.settlementId !== status.settlement.settlementId\n ) {\n return yield* new WorkflowDispatchError({\n operation: \"completion\",\n message: \"Native completion disagrees with canonical Settlement; intent retained\",\n });\n }\n if (intent.completionToken !== undefined) {\n yield* failpoint.hit(\"completion:before-notify\", intent);\n yield* nativeOperation(\n \"notify\",\n DurableDeferred.succeed(workflowCompletion(\"settlement\"), {\n token: intent.completionToken,\n value: reference,\n }).pipe(Effect.provideService(WorkflowEngine.WorkflowEngine, engine)),\n );\n yield* failpoint.hit(\"completion:after-notify\", intent);\n }\n yield* failpoint.hit(\"cleanup:before\", intent);\n yield* dispatch.remove(intent);\n yield* failpoint.hit(\"cleanup:after\", intent);\n\n return true;\n },\n (effect) => bounded(\"dispatch\", effect),\n );\n\n let submissionOffset = 0;\n let intentCursor: string | undefined;\n\n const repair = repairPermit.withPermit(\n Effect.gen(function* () {\n // Respect adapter ordering, which may differ from JavaScript string comparison.\n // Deletions may defer a row until the next wrap; restarts repeat idempotent work.\n const discovery = yield* bounded(\n \"scanSubmissions\",\n ledger.scanNonterminal.pipe(\n Stream.filter((row) => row.deploymentId === config.deploymentId),\n Stream.drop(submissionOffset),\n Stream.take(config.repairBatchSize),\n Stream.runCollect,\n ),\n ).pipe(Effect.result);\n\n const submissions = Result.isSuccess(discovery) ? discovery.success : [];\n\n if (Result.isSuccess(discovery)) {\n submissionOffset =\n submissions.length < config.repairBatchSize ? 0 : submissionOffset + submissions.length;\n }\n\n const discovered = yield* Effect.forEach(submissions, (row) =>\n Effect.flatMap(intentFor(new Receipt(row)), dispatchIntent).pipe(Effect.result),\n );\n\n const outstanding = yield* bounded(\n \"scanIntents\",\n dispatch.scan(\n new WorkflowDispatchScan({\n deploymentId: config.deploymentId,\n workflowName: nativeName,\n ...(intentCursor === undefined ? {} : { after: intentCursor }),\n limit: config.repairBatchSize,\n }),\n ),\n ).pipe(Effect.result);\n\n const intents = Result.isSuccess(outstanding) ? outstanding.success : [];\n\n if (Result.isSuccess(outstanding))\n intentCursor =\n intents.length < config.repairBatchSize\n ? undefined\n : intents[intents.length - 1]?.executionId;\n\n const inspected = yield* Effect.forEach(intents, (intent) =>\n dispatchIntent(intent).pipe(Effect.result),\n );\n\n const results = [...discovered, ...inspected];\n\n if (Result.isFailure(discovery)) return yield* discovery.failure;\n if (Result.isFailure(outstanding)) return yield* outstanding.failure;\n const failure = results.find(Result.isFailure);\n\n if (failure !== undefined) return yield* Effect.fail(failure.failure);\n\n return new WorkflowRepairReport({\n discovered: submissions.length,\n inspected: intents.length,\n completed: results.filter((result) => Result.isSuccess(result) && result.success).length,\n });\n }),\n );\n\n yield* trigger.register(\n repair.pipe(\n Effect.asVoid,\n Effect.catchCause((cause) =>\n Cause.hasInterruptsOnly(cause)\n ? Effect.interrupt\n : Effect.logError(\"Workflow dispatch repair failed; durable obligations remain\", cause),\n ),\n ),\n );\n yield* Effect.addFinalizer(() => Ref.set(admission, false));\n\n const submit = Effect.fnUntraced(function* <InputSchema extends Schema.Top>(\n agent: DurableSubmitAgent<InputSchema>,\n input: InputSchema[\"Type\"],\n options: DurableSubmitOptions,\n ): Effect.fn.Return<\n Receipt,\n DurableSubmitFailure | WorkflowRepairFailure | WorkflowAdmissionClosed,\n InputSchema[\"EncodingServices\"]\n > {\n if (!(yield* Ref.get(admission))) {\n return yield* new WorkflowAdmissionClosed({ message: \"The Workflow host is shutting down\" });\n }\n const receipt = yield* runtime.submit(agent, input, options);\n\n yield* dispatchIntent(yield* intentFor(receipt));\n\n return receipt;\n });\n\n const execute = Effect.fnUntraced(function* <Input extends Schema.Top, Output extends Schema.Top>(\n agent: WorkflowAgent<Input, Output>,\n input: Input[\"Type\"],\n options: WorkflowExecuteOptions,\n ) {\n const parentEngine = yield* WorkflowEngine.WorkflowEngine;\n\n if (parentEngine !== engine) {\n return yield* new WorkflowExecutionFailure({\n reason: \"engine-mismatch\",\n message: \"Agent host and parent workflow must share one WorkflowEngine Layer\",\n });\n }\n\n const name = yield* Schema.decodeEffect(Schema.NonEmptyString)(options.name).pipe(\n Effect.mapError(\n () =>\n new WorkflowExecutionFailure({\n reason: \"invalid-name\",\n message: \"Workflow agent steps need a nonempty stable name\",\n }),\n ),\n );\n\n const completion = workflowCompletion(`effect-agent/${name}`);\n const completionToken = yield* DurableDeferred.token(completion);\n\n // Agent identity and input deliberately do not participate: changing either on replay\n // must conflict with the original admission rather than launch new external work.\n const identity = yield* digestJson([\n config.deploymentId,\n config.principal,\n completionToken,\n ]).pipe(Effect.provideService(Crypto.Crypto, crypto));\n\n if (!(yield* Ref.get(admission))) {\n return yield* new WorkflowAdmissionClosed({ message: \"The Workflow host is shutting down\" });\n }\n\n const receipt = yield* runtime.submitRegistered({ definition: agent }, input, {\n threadId: ThreadId.make(`workflow/${identity}`),\n idempotencyKey: IdempotencyKey.make(identity),\n principal: config.principal,\n });\n\n yield* Effect.annotateCurrentSpan({\n \"agent.submission.id\": receipt.submissionId,\n \"agent.workflow.step\": name,\n });\n yield* runtime.submissionStatus(receipt);\n yield* dispatchIntent(\n new WorkflowDispatchIntent({ ...(yield* intentFor(receipt)), completionToken }),\n );\n\n // The deferred stores only a reference. Always reauthorize and read canonical data,\n // including on replay after the workflow engine has cached the notification.\n const reference = yield* DurableDeferred.await(completion);\n\n const record = yield* runtime.settlementRecord(receipt);\n\n if (\n reference.submissionId !== receipt.submissionId ||\n reference.threadId !== receipt.threadId ||\n reference.settlementId !== record.settlementId\n ) {\n return yield* new WorkflowDispatchError({\n operation: \"result\",\n message: \"Workflow completion disagrees with canonical Settlement\",\n });\n }\n if (record.outcome === \"failed\") {\n return yield* new WorkflowExecutionFailure({\n reason: \"failed\",\n message: \"Agent submission failed\",\n receipt,\n failure: record.result,\n });\n }\n if (record.outcome === \"aborted\") {\n return yield* new WorkflowExecutionFailure({\n reason: \"aborted\",\n message: \"Agent submission was aborted\",\n receipt,\n });\n }\n if (record.result === undefined) {\n return yield* new WorkflowExecutionFailure({\n reason: \"missing-output\",\n message: \"Completed submission has no independent output\",\n receipt,\n });\n }\n\n return yield* Schema.decodeEffect(agent.output)(record.result).pipe(\n Effect.mapError(\n (cause) =>\n new AgentOutputError({\n message: `Cannot decode canonical agent output: ${cause.message}`,\n }),\n ),\n );\n });\n\n return WorkflowAgentHost.of({\n execute,\n submit,\n awaitSettlement: runtime.awaitSettlement,\n observe: runtime.observe,\n abort: runtime.abort,\n resolveApproval: runtime.resolveApproval,\n resolveUnknown: runtime.resolveUnknown,\n submissionStatus: runtime.submissionStatus,\n repair,\n executionId: (receipt: Receipt) =>\n intentFor(receipt).pipe(Effect.map((intent) => intent.executionId)),\n });\n});\n\n/**\n * Optional engine-independent host. Supply the upstream WorkflowEngine, the existing\n * durable runtime and ledger, durable dispatch storage, and a host-owned repair trigger.\n * Do not also start the ordinary Node worker loop. Waiter interruption only detaches;\n * abort and resolutions retain the runtime's authorization and durable intent protocol.\n */\nexport class WorkflowAgentHost extends Context.Service<\n WorkflowAgentHost,\n {\n readonly execute: <Input extends Schema.Top, Output extends Schema.Top>(\n agent: WorkflowAgent<Input, Output>,\n input: Input[\"Type\"],\n options: WorkflowExecuteOptions,\n ) => Effect.Effect<\n Output[\"Type\"],\n | DurableSubmitFailure\n | BindingUnavailable\n | DurableAwaitFailure\n | WorkflowDispatchError\n | WorkflowAdmissionClosed\n | WorkflowExecutionFailure\n | AgentOutputError,\n | Input[\"EncodingServices\"]\n | Output[\"DecodingServices\"]\n | WorkflowEngine.WorkflowInstance\n | WorkflowEngine.WorkflowEngine\n >;\n readonly submit: <InputSchema extends Schema.Top>(\n agent: DurableSubmitAgent<InputSchema>,\n input: InputSchema[\"Type\"],\n options: DurableSubmitOptions,\n ) => Effect.Effect<\n Receipt,\n DurableSubmitFailure | WorkflowRepairFailure | WorkflowAdmissionClosed,\n InputSchema[\"EncodingServices\"]\n >;\n readonly awaitSettlement: DurableAgentRuntime[\"Service\"][\"awaitSettlement\"];\n readonly observe: DurableAgentRuntime[\"Service\"][\"observe\"];\n readonly abort: DurableAgentRuntime[\"Service\"][\"abort\"];\n readonly resolveApproval: DurableAgentRuntime[\"Service\"][\"resolveApproval\"];\n readonly resolveUnknown: DurableAgentRuntime[\"Service\"][\"resolveUnknown\"];\n readonly submissionStatus: DurableAgentRuntime[\"Service\"][\"submissionStatus\"];\n readonly repair: Effect.Effect<WorkflowRepairReport, WorkflowRepairFailure>;\n readonly executionId: (receipt: Receipt) => Effect.Effect<string>;\n }\n>()(\"@effect-agent/workflow/WorkflowAgentHost\") {\n /** Drive the injected runtime, whose Layer owns executable registrations and their services. */\n static layer(options: WorkflowAgentHostOptions) {\n return Layer.effect(WorkflowAgentHost)(makeHost(options));\n }\n}\n"],"mappings":"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"}
|