botmux 2.33.0 → 2.34.0
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.en.md +12 -1
- package/README.md +45 -1
- package/dist/adapters/cli/claude-code.d.ts.map +1 -1
- package/dist/adapters/cli/claude-code.js +11 -0
- package/dist/adapters/cli/claude-code.js.map +1 -1
- package/dist/cli/bots-list-output.d.ts +21 -0
- package/dist/cli/bots-list-output.d.ts.map +1 -0
- package/dist/cli/bots-list-output.js +23 -0
- package/dist/cli/bots-list-output.js.map +1 -0
- package/dist/cli/workflow.d.ts +13 -0
- package/dist/cli/workflow.d.ts.map +1 -0
- package/dist/cli/workflow.js +781 -0
- package/dist/cli/workflow.js.map +1 -0
- package/dist/cli.js +69 -14
- package/dist/cli.js.map +1 -1
- package/dist/core/command-handler.d.ts.map +1 -1
- package/dist/core/command-handler.js +219 -6
- package/dist/core/command-handler.js.map +1 -1
- package/dist/core/session-manager.d.ts +6 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +22 -12
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/worker-pool.d.ts +13 -0
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +100 -6
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.d.ts +3 -0
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +884 -3
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/auth.d.ts +36 -0
- package/dist/dashboard/auth.d.ts.map +1 -1
- package/dist/dashboard/auth.js +22 -0
- package/dist/dashboard/auth.js.map +1 -1
- package/dist/dashboard/web/app.js +20 -1
- package/dist/dashboard/web/app.js.map +1 -1
- package/dist/dashboard/web/i18n.d.ts.map +1 -1
- package/dist/dashboard/web/i18n.js +356 -0
- package/dist/dashboard/web/i18n.js.map +1 -1
- package/dist/dashboard/web/workflow-catalog.d.ts +2 -0
- package/dist/dashboard/web/workflow-catalog.d.ts.map +1 -0
- package/dist/dashboard/web/workflow-catalog.js +323 -0
- package/dist/dashboard/web/workflow-catalog.js.map +1 -0
- package/dist/dashboard/web/workflows.d.ts +2 -0
- package/dist/dashboard/web/workflows.d.ts.map +1 -0
- package/dist/dashboard/web/workflows.js +1618 -0
- package/dist/dashboard/web/workflows.js.map +1 -0
- package/dist/dashboard/workflow-api.d.ts +23 -0
- package/dist/dashboard/workflow-api.d.ts.map +1 -0
- package/dist/dashboard/workflow-api.js +463 -0
- package/dist/dashboard/workflow-api.js.map +1 -0
- package/dist/dashboard-web/app.js +494 -199
- package/dist/dashboard-web/index.html +1 -0
- package/dist/dashboard-web/style.css +160 -6
- package/dist/dashboard-web/terminal-replay.html +227 -0
- package/dist/dashboard.js +29 -12
- package/dist/dashboard.js.map +1 -1
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +12 -0
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/zh.d.ts.map +1 -1
- package/dist/i18n/zh.js +12 -0
- package/dist/i18n/zh.js.map +1 -1
- package/dist/im/lark/card-handler.d.ts +3 -0
- package/dist/im/lark/card-handler.d.ts.map +1 -1
- package/dist/im/lark/card-handler.js +27 -1
- package/dist/im/lark/card-handler.js.map +1 -1
- package/dist/im/lark/client.d.ts +19 -2
- package/dist/im/lark/client.d.ts.map +1 -1
- package/dist/im/lark/client.js +21 -2
- package/dist/im/lark/client.js.map +1 -1
- package/dist/im/lark/workflow-card-handler.d.ts +50 -0
- package/dist/im/lark/workflow-card-handler.d.ts.map +1 -0
- package/dist/im/lark/workflow-card-handler.js +152 -0
- package/dist/im/lark/workflow-card-handler.js.map +1 -0
- package/dist/im/lark/workflow-cards.d.ts +46 -0
- package/dist/im/lark/workflow-cards.d.ts.map +1 -0
- package/dist/im/lark/workflow-cards.js +226 -0
- package/dist/im/lark/workflow-cards.js.map +1 -0
- package/dist/im/lark/workflow-progress-card.d.ts +76 -0
- package/dist/im/lark/workflow-progress-card.d.ts.map +1 -0
- package/dist/im/lark/workflow-progress-card.js +279 -0
- package/dist/im/lark/workflow-progress-card.js.map +1 -0
- package/dist/im/lark/workflow-slash-command.d.ts +92 -0
- package/dist/im/lark/workflow-slash-command.d.ts.map +1 -0
- package/dist/im/lark/workflow-slash-command.js +185 -0
- package/dist/im/lark/workflow-slash-command.js.map +1 -0
- package/dist/services/group-creator.d.ts.map +1 -1
- package/dist/services/group-creator.js +17 -4
- package/dist/services/group-creator.js.map +1 -1
- package/dist/services/groups-store.d.ts +11 -0
- package/dist/services/groups-store.d.ts.map +1 -1
- package/dist/services/groups-store.js +26 -0
- package/dist/services/groups-store.js.map +1 -1
- package/dist/services/jsonl-cursor.d.ts +12 -0
- package/dist/services/jsonl-cursor.d.ts.map +1 -0
- package/dist/services/jsonl-cursor.js +45 -0
- package/dist/services/jsonl-cursor.js.map +1 -0
- package/dist/services/schedule-store.d.ts +35 -0
- package/dist/services/schedule-store.d.ts.map +1 -1
- package/dist/services/schedule-store.js +108 -1
- package/dist/services/schedule-store.js.map +1 -1
- package/dist/skills/definitions.d.ts.map +1 -1
- package/dist/skills/definitions.js +399 -0
- package/dist/skills/definitions.js.map +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/cli-usage-limit.d.ts.map +1 -1
- package/dist/utils/cli-usage-limit.js +4 -0
- package/dist/utils/cli-usage-limit.js.map +1 -1
- package/dist/worker.js +118 -14
- package/dist/worker.js.map +1 -1
- package/dist/workflows/attempt-resume.d.ts +114 -0
- package/dist/workflows/attempt-resume.d.ts.map +1 -0
- package/dist/workflows/attempt-resume.js +385 -0
- package/dist/workflows/attempt-resume.js.map +1 -0
- package/dist/workflows/attempt-terminal.d.ts +21 -0
- package/dist/workflows/attempt-terminal.d.ts.map +1 -0
- package/dist/workflows/attempt-terminal.js +7 -0
- package/dist/workflows/attempt-terminal.js.map +1 -0
- package/dist/workflows/blob.d.ts +27 -0
- package/dist/workflows/blob.d.ts.map +1 -0
- package/dist/workflows/blob.js +39 -0
- package/dist/workflows/blob.js.map +1 -0
- package/dist/workflows/cancel-run.d.ts +45 -0
- package/dist/workflows/cancel-run.d.ts.map +1 -0
- package/dist/workflows/cancel-run.js +99 -0
- package/dist/workflows/cancel-run.js.map +1 -0
- package/dist/workflows/cancel.d.ts +111 -0
- package/dist/workflows/cancel.d.ts.map +1 -0
- package/dist/workflows/cancel.js +120 -0
- package/dist/workflows/cancel.js.map +1 -0
- package/dist/workflows/catalog.d.ts +60 -0
- package/dist/workflows/catalog.d.ts.map +1 -0
- package/dist/workflows/catalog.js +119 -0
- package/dist/workflows/catalog.js.map +1 -0
- package/dist/workflows/cold-attach.d.ts +30 -0
- package/dist/workflows/cold-attach.d.ts.map +1 -0
- package/dist/workflows/cold-attach.js +40 -0
- package/dist/workflows/cold-attach.js.map +1 -0
- package/dist/workflows/cold-scan.d.ts +21 -0
- package/dist/workflows/cold-scan.d.ts.map +1 -0
- package/dist/workflows/cold-scan.js +70 -0
- package/dist/workflows/cold-scan.js.map +1 -0
- package/dist/workflows/daemon-spawn.d.ts +117 -0
- package/dist/workflows/daemon-spawn.d.ts.map +1 -0
- package/dist/workflows/daemon-spawn.js +551 -0
- package/dist/workflows/daemon-spawn.js.map +1 -0
- package/dist/workflows/definition.d.ts +1309 -0
- package/dist/workflows/definition.d.ts.map +1 -0
- package/dist/workflows/definition.js +334 -0
- package/dist/workflows/definition.js.map +1 -0
- package/dist/workflows/effect-input.d.ts +4 -0
- package/dist/workflows/effect-input.d.ts.map +1 -0
- package/dist/workflows/effect-input.js +18 -0
- package/dist/workflows/effect-input.js.map +1 -0
- package/dist/workflows/events/append.d.ts +77 -0
- package/dist/workflows/events/append.d.ts.map +1 -0
- package/dist/workflows/events/append.js +214 -0
- package/dist/workflows/events/append.js.map +1 -0
- package/dist/workflows/events/idempotency.d.ts +77 -0
- package/dist/workflows/events/idempotency.d.ts.map +1 -0
- package/dist/workflows/events/idempotency.js +116 -0
- package/dist/workflows/events/idempotency.js.map +1 -0
- package/dist/workflows/events/index.d.ts +7 -0
- package/dist/workflows/events/index.d.ts.map +1 -0
- package/dist/workflows/events/index.js +7 -0
- package/dist/workflows/events/index.js.map +1 -0
- package/dist/workflows/events/payloads.d.ts +917 -0
- package/dist/workflows/events/payloads.d.ts.map +1 -0
- package/dist/workflows/events/payloads.js +337 -0
- package/dist/workflows/events/payloads.js.map +1 -0
- package/dist/workflows/events/replay.d.ts +238 -0
- package/dist/workflows/events/replay.d.ts.map +1 -0
- package/dist/workflows/events/replay.js +608 -0
- package/dist/workflows/events/replay.js.map +1 -0
- package/dist/workflows/events/schema.d.ts +5242 -0
- package/dist/workflows/events/schema.d.ts.map +1 -0
- package/dist/workflows/events/schema.js +295 -0
- package/dist/workflows/events/schema.js.map +1 -0
- package/dist/workflows/events/types.d.ts +34 -0
- package/dist/workflows/events/types.d.ts.map +1 -0
- package/dist/workflows/events/types.js +2 -0
- package/dist/workflows/events/types.js.map +1 -0
- package/dist/workflows/fanout.d.ts +36 -0
- package/dist/workflows/fanout.d.ts.map +1 -0
- package/dist/workflows/fanout.js +114 -0
- package/dist/workflows/fanout.js.map +1 -0
- package/dist/workflows/hostExecutors/botmux-schedule.d.ts +41 -0
- package/dist/workflows/hostExecutors/botmux-schedule.d.ts.map +1 -0
- package/dist/workflows/hostExecutors/botmux-schedule.js +121 -0
- package/dist/workflows/hostExecutors/botmux-schedule.js.map +1 -0
- package/dist/workflows/hostExecutors/feishu-im.d.ts +12 -0
- package/dist/workflows/hostExecutors/feishu-im.d.ts.map +1 -0
- package/dist/workflows/hostExecutors/feishu-im.js +49 -0
- package/dist/workflows/hostExecutors/feishu-im.js.map +1 -0
- package/dist/workflows/hostExecutors/feishu-reply.d.ts +24 -0
- package/dist/workflows/hostExecutors/feishu-reply.d.ts.map +1 -0
- package/dist/workflows/hostExecutors/feishu-reply.js +88 -0
- package/dist/workflows/hostExecutors/feishu-reply.js.map +1 -0
- package/dist/workflows/hostExecutors/feishu-send.d.ts +23 -0
- package/dist/workflows/hostExecutors/feishu-send.d.ts.map +1 -0
- package/dist/workflows/hostExecutors/feishu-send.js +124 -0
- package/dist/workflows/hostExecutors/feishu-send.js.map +1 -0
- package/dist/workflows/hostExecutors/index.d.ts +8 -0
- package/dist/workflows/hostExecutors/index.d.ts.map +1 -0
- package/dist/workflows/hostExecutors/index.js +8 -0
- package/dist/workflows/hostExecutors/index.js.map +1 -0
- package/dist/workflows/hostExecutors/protocol.d.ts +42 -0
- package/dist/workflows/hostExecutors/protocol.d.ts.map +1 -0
- package/dist/workflows/hostExecutors/protocol.js +181 -0
- package/dist/workflows/hostExecutors/protocol.js.map +1 -0
- package/dist/workflows/hostExecutors/registry.d.ts +10 -0
- package/dist/workflows/hostExecutors/registry.d.ts.map +1 -0
- package/dist/workflows/hostExecutors/registry.js +36 -0
- package/dist/workflows/hostExecutors/registry.js.map +1 -0
- package/dist/workflows/hostExecutors/types.d.ts +78 -0
- package/dist/workflows/hostExecutors/types.d.ts.map +1 -0
- package/dist/workflows/hostExecutors/types.js +2 -0
- package/dist/workflows/hostExecutors/types.js.map +1 -0
- package/dist/workflows/loader.d.ts +16 -0
- package/dist/workflows/loader.d.ts.map +1 -0
- package/dist/workflows/loader.js +56 -0
- package/dist/workflows/loader.js.map +1 -0
- package/dist/workflows/loop.d.ts +50 -0
- package/dist/workflows/loop.d.ts.map +1 -0
- package/dist/workflows/loop.js +350 -0
- package/dist/workflows/loop.js.map +1 -0
- package/dist/workflows/ops-projection.d.ts +168 -0
- package/dist/workflows/ops-projection.d.ts.map +1 -0
- package/dist/workflows/ops-projection.js +707 -0
- package/dist/workflows/ops-projection.js.map +1 -0
- package/dist/workflows/orchestrator.d.ts +107 -0
- package/dist/workflows/orchestrator.d.ts.map +1 -0
- package/dist/workflows/orchestrator.js +197 -0
- package/dist/workflows/orchestrator.js.map +1 -0
- package/dist/workflows/output-binding.d.ts +70 -0
- package/dist/workflows/output-binding.d.ts.map +1 -0
- package/dist/workflows/output-binding.js +265 -0
- package/dist/workflows/output-binding.js.map +1 -0
- package/dist/workflows/params.d.ts +61 -0
- package/dist/workflows/params.d.ts.map +1 -0
- package/dist/workflows/params.js +195 -0
- package/dist/workflows/params.js.map +1 -0
- package/dist/workflows/resume.d.ts +263 -0
- package/dist/workflows/resume.d.ts.map +1 -0
- package/dist/workflows/resume.js +808 -0
- package/dist/workflows/resume.js.map +1 -0
- package/dist/workflows/run-id.d.ts +2 -0
- package/dist/workflows/run-id.d.ts.map +1 -0
- package/dist/workflows/run-id.js +7 -0
- package/dist/workflows/run-id.js.map +1 -0
- package/dist/workflows/run-init.d.ts +48 -0
- package/dist/workflows/run-init.d.ts.map +1 -0
- package/dist/workflows/run-init.js +99 -0
- package/dist/workflows/run-init.js.map +1 -0
- package/dist/workflows/runs-dir.d.ts +4 -0
- package/dist/workflows/runs-dir.d.ts.map +1 -0
- package/dist/workflows/runs-dir.js +15 -0
- package/dist/workflows/runs-dir.js.map +1 -0
- package/dist/workflows/runtime.d.ts +211 -0
- package/dist/workflows/runtime.d.ts.map +1 -0
- package/dist/workflows/runtime.js +594 -0
- package/dist/workflows/runtime.js.map +1 -0
- package/dist/workflows/spawn-bot.d.ts +165 -0
- package/dist/workflows/spawn-bot.d.ts.map +1 -0
- package/dist/workflows/spawn-bot.js +215 -0
- package/dist/workflows/spawn-bot.js.map +1 -0
- package/dist/workflows/system.d.ts +49 -0
- package/dist/workflows/system.d.ts.map +1 -0
- package/dist/workflows/system.js +48 -0
- package/dist/workflows/system.js.map +1 -0
- package/dist/workflows/trigger-run.d.ts +70 -0
- package/dist/workflows/trigger-run.d.ts.map +1 -0
- package/dist/workflows/trigger-run.js +88 -0
- package/dist/workflows/trigger-run.js.map +1 -0
- package/dist/workflows/wait.d.ts +120 -0
- package/dist/workflows/wait.d.ts.map +1 -0
- package/dist/workflows/wait.js +181 -0
- package/dist/workflows/wait.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { writeJsonBlob } from '../blob.js';
|
|
2
|
+
import { computeInputHash, deriveIdempotencyKey } from '../events/idempotency.js';
|
|
3
|
+
// ─── Public API ─────────────────────────────────────────────────────────────
|
|
4
|
+
/**
|
|
5
|
+
* Drive the side-effecting protocol for one attempt (events doc v0.1.2
|
|
6
|
+
* §2.3, §4.3). Writes three events in order:
|
|
7
|
+
*
|
|
8
|
+
* 1. `effectAttempted` — written **before** invoking the provider so a
|
|
9
|
+
* crash mid-call leaves a dangling intent that resume can reconcile.
|
|
10
|
+
* 2. provider invocation (via `executor.invoke`).
|
|
11
|
+
* 3. `activitySucceeded` OR `activityFailed` — terminal event for this
|
|
12
|
+
* attempt; carries `externalRefs` on success or classified error on
|
|
13
|
+
* failure.
|
|
14
|
+
*
|
|
15
|
+
* The protocol does NOT write `attemptCreated/leaseSigned/activityRunning`
|
|
16
|
+
* — those are the scheduler/worker layer's responsibility. This function
|
|
17
|
+
* assumes the caller has already advanced the activity to `running`.
|
|
18
|
+
*
|
|
19
|
+
* The protocol does NOT do retry/backoff — that's the scheduler's job
|
|
20
|
+
* (Step 7+). A failed invocation is reported via `ok: false` and the
|
|
21
|
+
* caller decides whether to spawn a new `attemptCreated`.
|
|
22
|
+
*
|
|
23
|
+
* Idempotency contract:
|
|
24
|
+
* - `idempotencyKey` is deterministic per attempt (5-tuple hash), so
|
|
25
|
+
* re-running the same attempt with the same input produces the same
|
|
26
|
+
* uuid → Feishu/schedule provider returns the original ref.
|
|
27
|
+
* - `inputHash` is recorded for the resume path to detect attempt
|
|
28
|
+
* mutability violations (Step 7). This function doesn't enforce
|
|
29
|
+
* immutability across calls — Step 7 reads recorded inputHash and
|
|
30
|
+
* fails if a future attempt re-derives a different one.
|
|
31
|
+
*/
|
|
32
|
+
export async function executeSideEffect(ctx, input, executor) {
|
|
33
|
+
const idempotencyKey = deriveIdempotencyKey({
|
|
34
|
+
workflowId: ctx.workflowId,
|
|
35
|
+
revisionId: ctx.revisionId,
|
|
36
|
+
runId: ctx.runId,
|
|
37
|
+
nodeId: ctx.nodeId,
|
|
38
|
+
attemptId: ctx.attemptId,
|
|
39
|
+
});
|
|
40
|
+
const inputHash = computeInputHash(executor.canonicalInput(input));
|
|
41
|
+
// 1. effectAttempted — written BEFORE invoking the provider so a crash
|
|
42
|
+
// mid-call leaves a dangling effectAttempted for resume to reconcile.
|
|
43
|
+
await ctx.log.append({
|
|
44
|
+
runId: ctx.runId,
|
|
45
|
+
type: 'effectAttempted',
|
|
46
|
+
actor: 'hostExecutor',
|
|
47
|
+
payload: {
|
|
48
|
+
activityId: ctx.activityId,
|
|
49
|
+
attemptId: ctx.attemptId,
|
|
50
|
+
idempotencyKey,
|
|
51
|
+
inputHash,
|
|
52
|
+
idempotencyTtlMs: executor.idempotencyTtlMs,
|
|
53
|
+
provider: executor.provider,
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
// 2. provider invocation
|
|
57
|
+
try {
|
|
58
|
+
const { output, externalRefs } = await executor.invoke(input, idempotencyKey);
|
|
59
|
+
// 3a. activitySucceeded. outputRef points at a real JSON blob
|
|
60
|
+
// `{ output, externalRefs }` so dashboard / CLI show / reconcile
|
|
61
|
+
// evidence can inspect the full provider response without
|
|
62
|
+
// replaying events. We keep `externalRefs` on the event payload
|
|
63
|
+
// too — replay/reconciler reads it without touching disk.
|
|
64
|
+
//
|
|
65
|
+
// Non-plain-JSON outputs (Date, Map, Set, Buffer, BigInt,
|
|
66
|
+
// function) are rejected here so they fall through the same
|
|
67
|
+
// classifier path as a provider crash. Executors must return
|
|
68
|
+
// plain JSON-serializable values; silently coercing a Date to
|
|
69
|
+
// `{}` would corrupt the audit trail.
|
|
70
|
+
assertJsonPlain(output, 'output');
|
|
71
|
+
assertJsonPlain(externalRefs, 'externalRefs');
|
|
72
|
+
const outputRef = await writeJsonBlob(ctx.log, { output, externalRefs });
|
|
73
|
+
const successEvent = (await ctx.log.append({
|
|
74
|
+
runId: ctx.runId,
|
|
75
|
+
type: 'activitySucceeded',
|
|
76
|
+
actor: 'hostExecutor',
|
|
77
|
+
payload: {
|
|
78
|
+
activityId: ctx.activityId,
|
|
79
|
+
attemptId: ctx.attemptId,
|
|
80
|
+
outputRef,
|
|
81
|
+
externalRefs,
|
|
82
|
+
},
|
|
83
|
+
}));
|
|
84
|
+
return { ok: true, event: successEvent, output, externalRefs };
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
// 3b. activityFailed. Map via the executor's classifier when
|
|
88
|
+
// present; default to UnknownProviderError/manual (codex round 2
|
|
89
|
+
// — TTL/unknown failures need human resolution, not silent retry).
|
|
90
|
+
const classification = executor.classifyError?.(err) ?? defaultClassification(err);
|
|
91
|
+
// Truncate uniformly — protects against custom classifiers that
|
|
92
|
+
// return long messages (e.g. dumping a full provider response).
|
|
93
|
+
const safeMessage = truncateMessage(classification.errorMessage);
|
|
94
|
+
const failedEvent = (await ctx.log.append({
|
|
95
|
+
runId: ctx.runId,
|
|
96
|
+
type: 'activityFailed',
|
|
97
|
+
actor: 'hostExecutor',
|
|
98
|
+
payload: {
|
|
99
|
+
activityId: ctx.activityId,
|
|
100
|
+
attemptId: ctx.attemptId,
|
|
101
|
+
error: {
|
|
102
|
+
errorCode: classification.errorCode,
|
|
103
|
+
errorClass: classification.errorClass,
|
|
104
|
+
errorMessage: safeMessage,
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
}));
|
|
108
|
+
return {
|
|
109
|
+
ok: false,
|
|
110
|
+
event: failedEvent,
|
|
111
|
+
error: { ...classification, errorMessage: safeMessage },
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
116
|
+
/**
|
|
117
|
+
* Error-message truncation budget. The schema bound is 4096 (events doc
|
|
118
|
+
* §3.3), but the envelope payload also has to fit `INLINE_PAYLOAD_MAX_BYTES`
|
|
119
|
+
* (4096) total — so a 4096-char message alone would overflow the event
|
|
120
|
+
* envelope cap after JSON encoding + other fields. Truncate to leave
|
|
121
|
+
* headroom; large error bodies should be written to a stackRef blob.
|
|
122
|
+
*/
|
|
123
|
+
const ERROR_MESSAGE_MAX_CHARS = 2048;
|
|
124
|
+
function truncateMessage(msg) {
|
|
125
|
+
return msg.length > ERROR_MESSAGE_MAX_CHARS
|
|
126
|
+
? msg.slice(0, ERROR_MESSAGE_MAX_CHARS - 3) + '...'
|
|
127
|
+
: msg;
|
|
128
|
+
}
|
|
129
|
+
function defaultClassification(err) {
|
|
130
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
131
|
+
return {
|
|
132
|
+
errorCode: 'UnknownProviderError',
|
|
133
|
+
errorClass: 'manual',
|
|
134
|
+
errorMessage: truncateMessage(msg),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Reject non-plain-JSON values before they reach `writeJsonBlob`, where
|
|
139
|
+
* `canonicalJsonStringify` would silently coerce a Date / Map / Set into
|
|
140
|
+
* `{}`. Path-prefixed error messages so the classifier can surface
|
|
141
|
+
* which field tripped it.
|
|
142
|
+
*/
|
|
143
|
+
function assertJsonPlain(value, path) {
|
|
144
|
+
if (value === null)
|
|
145
|
+
return;
|
|
146
|
+
const t = typeof value;
|
|
147
|
+
if (t === 'string' || t === 'number' || t === 'boolean' || t === 'undefined') {
|
|
148
|
+
// `undefined` is JSON-omitted, not a serialization failure — only
|
|
149
|
+
// reject the explicitly hostile types below.
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (t === 'bigint') {
|
|
153
|
+
throw new Error(`hostExecutor output not JSON-serializable at ${path}: BigInt`);
|
|
154
|
+
}
|
|
155
|
+
if (t === 'function' || t === 'symbol') {
|
|
156
|
+
throw new Error(`hostExecutor output not JSON-serializable at ${path}: ${t}`);
|
|
157
|
+
}
|
|
158
|
+
if (value instanceof Date) {
|
|
159
|
+
throw new Error(`hostExecutor output not JSON-serializable at ${path}: Date (use .toISOString() string)`);
|
|
160
|
+
}
|
|
161
|
+
if (value instanceof Map || value instanceof Set) {
|
|
162
|
+
throw new Error(`hostExecutor output not JSON-serializable at ${path}: ${value.constructor.name}`);
|
|
163
|
+
}
|
|
164
|
+
if (Buffer.isBuffer(value) || ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
|
|
165
|
+
throw new Error(`hostExecutor output not JSON-serializable at ${path}: binary buffer`);
|
|
166
|
+
}
|
|
167
|
+
if (Array.isArray(value)) {
|
|
168
|
+
value.forEach((v, i) => assertJsonPlain(v, `${path}[${i}]`));
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const obj = value;
|
|
172
|
+
const proto = Object.getPrototypeOf(obj);
|
|
173
|
+
if (proto !== Object.prototype && proto !== null) {
|
|
174
|
+
const ctorName = obj.constructor?.name ?? 'unknown';
|
|
175
|
+
throw new Error(`hostExecutor output not JSON-serializable at ${path}: non-plain object (${ctorName})`);
|
|
176
|
+
}
|
|
177
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
178
|
+
assertJsonPlain(v, `${path}.${k}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../src/workflows/hostExecutors/protocol.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ProviderReconciler } from '../resume.js';
|
|
2
|
+
import type { SideEffectingExecutor } from './types.js';
|
|
3
|
+
export type RegisteredHostExecutor<Input = unknown, Output = unknown> = {
|
|
4
|
+
executor: SideEffectingExecutor<Input, Output>;
|
|
5
|
+
parseInput(input: unknown): Input;
|
|
6
|
+
};
|
|
7
|
+
export type HostExecutorRegistry = Map<string, RegisteredHostExecutor>;
|
|
8
|
+
export declare function createDefaultHostExecutorRegistry(): HostExecutorRegistry;
|
|
9
|
+
export declare function createDefaultProviderReconcilers(): Map<string, ProviderReconciler>;
|
|
10
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/workflows/hostExecutors/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAevD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAExD,MAAM,MAAM,sBAAsB,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,OAAO,IAAI;IACtE,QAAQ,EAAE,qBAAqB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC/C,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,GAAG,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;AAEvE,wBAAgB,iCAAiC,IAAI,oBAAoB,CAwBxE;AAED,wBAAgB,gCAAgC,IAAI,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAKlF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { botmuxScheduleExecutor, botmuxScheduleReconciler, parseScheduleInput, } from './botmux-schedule.js';
|
|
2
|
+
import { feishuSendExecutor, parseFeishuSendInput, } from './feishu-send.js';
|
|
3
|
+
import { feishuReplyExecutor, parseFeishuReplyInput, } from './feishu-reply.js';
|
|
4
|
+
import { feishuImReconciler } from './feishu-im.js';
|
|
5
|
+
export function createDefaultHostExecutorRegistry() {
|
|
6
|
+
return new Map([
|
|
7
|
+
[
|
|
8
|
+
'botmux-schedule',
|
|
9
|
+
{
|
|
10
|
+
executor: botmuxScheduleExecutor,
|
|
11
|
+
parseInput: parseScheduleInput,
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
[
|
|
15
|
+
'feishu-send',
|
|
16
|
+
{
|
|
17
|
+
executor: feishuSendExecutor,
|
|
18
|
+
parseInput: parseFeishuSendInput,
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
[
|
|
22
|
+
'feishu-reply',
|
|
23
|
+
{
|
|
24
|
+
executor: feishuReplyExecutor,
|
|
25
|
+
parseInput: parseFeishuReplyInput,
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
]);
|
|
29
|
+
}
|
|
30
|
+
export function createDefaultProviderReconcilers() {
|
|
31
|
+
return new Map([
|
|
32
|
+
[botmuxScheduleReconciler.provider, botmuxScheduleReconciler],
|
|
33
|
+
[feishuImReconciler.provider, feishuImReconciler],
|
|
34
|
+
]);
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/workflows/hostExecutors/registry.ts"],"names":[],"mappings":"AACA,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAUpD,MAAM,UAAU,iCAAiC;IAC/C,OAAO,IAAI,GAAG,CAAC;QACb;YACE,iBAAiB;YACjB;gBACE,QAAQ,EAAE,sBAAsB;gBAChC,UAAU,EAAE,kBAAkB;aACE;SACnC;QACD;YACE,aAAa;YACb;gBACE,QAAQ,EAAE,kBAAkB;gBAC5B,UAAU,EAAE,oBAAoB;aACA;SACnC;QACD;YACE,cAAc;YACd;gBACE,QAAQ,EAAE,mBAAmB;gBAC7B,UAAU,EAAE,qBAAqB;aACD;SACnC;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,gCAAgC;IAC9C,OAAO,IAAI,GAAG,CAAC;QACb,CAAC,wBAAwB,CAAC,QAAQ,EAAE,wBAAwB,CAAC;QAC7D,CAAC,kBAAkB,CAAC,QAAQ,EAAE,kBAAkB,CAAC;KAClD,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { EventLog } from '../events/append.js';
|
|
2
|
+
import type { ErrorClass, ErrorCode } from '../events/payloads.js';
|
|
3
|
+
/**
|
|
4
|
+
* Runtime context handed to every hostExecutor invocation. The caller
|
|
5
|
+
* (workflow scheduler/worker) is responsible for already having written:
|
|
6
|
+
* - `attemptCreated` (with this `nodeId/activityId/attemptId`)
|
|
7
|
+
* - `leaseSigned`
|
|
8
|
+
* - `activityRunning`
|
|
9
|
+
* before invoking the side-effect protocol. This context only needs the
|
|
10
|
+
* tuple required to derive `idempotencyKey` plus the event log handle so
|
|
11
|
+
* the protocol can record its 3 events (`effectAttempted`,
|
|
12
|
+
* `activitySucceeded`/`activityFailed`).
|
|
13
|
+
*/
|
|
14
|
+
export type HostExecutorContext = {
|
|
15
|
+
log: EventLog;
|
|
16
|
+
runId: string;
|
|
17
|
+
workflowId: string;
|
|
18
|
+
revisionId: string;
|
|
19
|
+
nodeId: string;
|
|
20
|
+
activityId: string;
|
|
21
|
+
attemptId: string;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Classified executor error. Executors that can give precise error codes
|
|
25
|
+
* (Feishu 230011 etc.) return a typed result; everything else falls back
|
|
26
|
+
* to `UnknownProviderError` / `manual` (events doc v0.1.2 §3.3).
|
|
27
|
+
*/
|
|
28
|
+
export type ExecutorErrorClassification = {
|
|
29
|
+
errorCode: ErrorCode;
|
|
30
|
+
errorClass: ErrorClass;
|
|
31
|
+
/** Human-readable detail; truncated to 4KB upstream. */
|
|
32
|
+
errorMessage: string;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* A side-effecting hostExecutor (send / reply / schedule in v0). Pure
|
|
36
|
+
* executors (transform / bots / history / quoted / sub-agent) have a
|
|
37
|
+
* separate interface in `pure.ts` because they skip `effectAttempted`.
|
|
38
|
+
*/
|
|
39
|
+
export interface SideEffectingExecutor<Input, Output> {
|
|
40
|
+
/** Identifier embedded in `effectAttempted.provider`. */
|
|
41
|
+
readonly provider: string;
|
|
42
|
+
/**
|
|
43
|
+
* Provider TTL. Feeds `effectAttempted.idempotencyTtlMs` and the
|
|
44
|
+
* resume reconciler's TTL-vs-manual decision (events doc §4.3.1).
|
|
45
|
+
*/
|
|
46
|
+
readonly idempotencyTtlMs: number;
|
|
47
|
+
/**
|
|
48
|
+
* Convert the typed `Input` into the canonical shape that's hashed
|
|
49
|
+
* into `effectAttempted.inputHash`. Codex round 2 / 4 invariant: this
|
|
50
|
+
* MUST include every field that participates in the external effect
|
|
51
|
+
* (e.g. for Feishu reply: `receive_id`, `root_message_id`, `msg_type`,
|
|
52
|
+
* `content`) so that retries can detect input drift.
|
|
53
|
+
*/
|
|
54
|
+
canonicalInput(input: Input): unknown;
|
|
55
|
+
/**
|
|
56
|
+
* Invoke the provider. `idempotencyKey` is the runtime-derived
|
|
57
|
+
* dedupe token (≤ 50 chars) that callers should forward to the
|
|
58
|
+
* provider's idempotency knob (Feishu uuid / schedule task id).
|
|
59
|
+
*/
|
|
60
|
+
invoke(input: Input, idempotencyKey: string): Promise<{
|
|
61
|
+
output: Output;
|
|
62
|
+
/**
|
|
63
|
+
* Provider-returned identifiers stored in
|
|
64
|
+
* `activitySucceeded.externalRefs`. Type-specific (send/reply →
|
|
65
|
+
* `{ messageId }`, schedule → `{ taskId }`).
|
|
66
|
+
*/
|
|
67
|
+
externalRefs: Record<string, unknown>;
|
|
68
|
+
}>;
|
|
69
|
+
/**
|
|
70
|
+
* Map an `invoke` error to an event-typed error. Returning `null`
|
|
71
|
+
* (or omitting the method) falls back to the protocol default:
|
|
72
|
+
* `{ UnknownProviderError, manual }`.
|
|
73
|
+
* Codex round 2: TTL-class errors are `manual` (need human resolution),
|
|
74
|
+
* lease/worker/network errors stay `retryable`.
|
|
75
|
+
*/
|
|
76
|
+
classifyError?(err: unknown): ExecutorErrorClassification | null;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/workflows/hostExecutors/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEnE;;;;;;;;;;GAUG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,GAAG,EAAE,QAAQ,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;IACvB,wDAAwD;IACxD,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;;GAIG;AACH,MAAM,WAAW,qBAAqB,CAAC,KAAK,EAAE,MAAM;IAClD,yDAAyD;IACzD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAElC;;;;;;OAMG;IACH,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC;IAEtC;;;;OAIG;IACH,MAAM,CACJ,KAAK,EAAE,KAAK,EACZ,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC;QACT,MAAM,EAAE,MAAM,CAAC;QACf;;;;WAIG;QACH,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACvC,CAAC,CAAC;IAEH;;;;;;OAMG;IACH,aAAa,CAAC,CAAC,GAAG,EAAE,OAAO,GAAG,2BAA2B,GAAG,IAAI,CAAC;CAClE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/workflows/hostExecutors/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type WorkflowDefinition } from './definition.js';
|
|
2
|
+
export type RunChatBinding = {
|
|
3
|
+
chatId: string;
|
|
4
|
+
larkAppId: string;
|
|
5
|
+
};
|
|
6
|
+
type RunFileOptions = {
|
|
7
|
+
runDir?: string;
|
|
8
|
+
runsDir?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function workflowDefinitionSearchPaths(workflowId: string): string[];
|
|
11
|
+
export declare function loadWorkflowDefinition(workflowId: string): Promise<WorkflowDefinition>;
|
|
12
|
+
export declare function snapshotWorkflowDefinition(runId: string, def: WorkflowDefinition, opts?: RunFileOptions): Promise<string>;
|
|
13
|
+
export declare function writeRunChatBinding(runId: string, binding: RunChatBinding, opts?: RunFileOptions): Promise<string>;
|
|
14
|
+
export declare function readRunChatBinding(runId: string, opts?: RunFileOptions): Promise<RunChatBinding>;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/workflows/loader.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,iBAAiB,CAAC;AAGzB,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAM1E;AAED,wBAAsB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAkB5F;AAED,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,kBAAkB,EACvB,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,MAAM,CAAC,CAKjB;AAED,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,cAAc,EACvB,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,MAAM,CAAC,CAKjB;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,cAAc,CAAC,CASzB"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { canonicalJsonStringify, parseWorkflowDefinition, } from './definition.js';
|
|
4
|
+
import { ensureRunDir } from './runs-dir.js';
|
|
5
|
+
export function workflowDefinitionSearchPaths(workflowId) {
|
|
6
|
+
const home = process.env.HOME;
|
|
7
|
+
return [
|
|
8
|
+
join(process.cwd(), 'workflows', `${workflowId}.workflow.json`),
|
|
9
|
+
join(home ?? '', '.botmux', 'workflows', `${workflowId}.workflow.json`),
|
|
10
|
+
];
|
|
11
|
+
}
|
|
12
|
+
export async function loadWorkflowDefinition(workflowId) {
|
|
13
|
+
const paths = workflowDefinitionSearchPaths(workflowId);
|
|
14
|
+
for (const path of paths) {
|
|
15
|
+
try {
|
|
16
|
+
const raw = await fs.readFile(path, 'utf-8');
|
|
17
|
+
return parseWorkflowDefinition(JSON.parse(raw));
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
if (err.code === 'ENOENT')
|
|
21
|
+
continue;
|
|
22
|
+
throw new Error(`Failed to load workflow '${workflowId}' from ${path}: ${err instanceof Error ? err.message : String(err)}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
throw new Error(`Workflow '${workflowId}' not found. Looked in:\n${paths.map((p) => `- ${p}`).join('\n')}`);
|
|
26
|
+
}
|
|
27
|
+
export async function snapshotWorkflowDefinition(runId, def, opts = {}) {
|
|
28
|
+
const dir = await getOrEnsureRunDir(runId, opts);
|
|
29
|
+
const path = join(dir, 'workflow.json');
|
|
30
|
+
await fs.writeFile(path, canonicalJsonStringify(def), 'utf-8');
|
|
31
|
+
return path;
|
|
32
|
+
}
|
|
33
|
+
export async function writeRunChatBinding(runId, binding, opts = {}) {
|
|
34
|
+
const dir = await getOrEnsureRunDir(runId, opts);
|
|
35
|
+
const path = join(dir, 'chat-binding.json');
|
|
36
|
+
await fs.writeFile(path, JSON.stringify(binding, null, 2), 'utf-8');
|
|
37
|
+
return path;
|
|
38
|
+
}
|
|
39
|
+
export async function readRunChatBinding(runId, opts = {}) {
|
|
40
|
+
const dir = await getOrEnsureRunDir(runId, opts);
|
|
41
|
+
const path = join(dir, 'chat-binding.json');
|
|
42
|
+
const raw = await fs.readFile(path, 'utf-8');
|
|
43
|
+
const parsed = JSON.parse(raw);
|
|
44
|
+
if (!parsed.chatId || !parsed.larkAppId) {
|
|
45
|
+
throw new Error(`Invalid workflow chat binding at ${path}`);
|
|
46
|
+
}
|
|
47
|
+
return { chatId: parsed.chatId, larkAppId: parsed.larkAppId };
|
|
48
|
+
}
|
|
49
|
+
async function getOrEnsureRunDir(runId, opts) {
|
|
50
|
+
if (opts.runDir) {
|
|
51
|
+
await fs.mkdir(opts.runDir, { recursive: true });
|
|
52
|
+
return opts.runDir;
|
|
53
|
+
}
|
|
54
|
+
return ensureRunDir(runId, opts.runsDir);
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/workflows/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Orchestrator loop runner.
|
|
3
|
+
*
|
|
4
|
+
* Drives `decideNextActions → dispatch* → replay → repeat` until either
|
|
5
|
+
* the run reaches a terminal status or the orchestrator returns no
|
|
6
|
+
* actions (which on a non-terminal run means we're paused on an open
|
|
7
|
+
* `waitCreated`).
|
|
8
|
+
*
|
|
9
|
+
* Per-tick dispatch model (v0.1.3+):
|
|
10
|
+
* 1. Split ready actions into `dispatch*` (gate / work) and `complete*`
|
|
11
|
+
* (settle node / run). The two phases have different concurrency
|
|
12
|
+
* semantics — dispatch can race, settles must not.
|
|
13
|
+
* 2. Within the dispatch phase: cap concurrency by `defaults.maxConcurrency`
|
|
14
|
+
* (default 4) and enforce per-bot serialization (one in-flight subagent
|
|
15
|
+
* per bot within a tick). Deferred dispatches just stay in the next
|
|
16
|
+
* tick's ready set; no separate scheduling state needed.
|
|
17
|
+
* 3. Run dispatches via `Promise.allSettled` so a sibling throwing doesn't
|
|
18
|
+
* starve the rest. After settle, replay fresh and patch any non-terminal
|
|
19
|
+
* activity with an `activityFailed` (errorClass=fatal, errorCode=
|
|
20
|
+
* WorkerCrashed; closest fit in the existing enum — see payloads.ts) —
|
|
21
|
+
* but NEVER write a second terminal if the dispatch already wrote one
|
|
22
|
+
* before throwing. If a dispatch throws BEFORE writing `attemptCreated`,
|
|
23
|
+
* we have no attempt to attach the failure to; the tick returns
|
|
24
|
+
* `no-progress` rather than re-dispatching the same action forever.
|
|
25
|
+
* 4. Settle actions (`completeNode*` / `completeRun*`) run sequentially so
|
|
26
|
+
* event log order stays readable and `completeRun*` is never racy.
|
|
27
|
+
*
|
|
28
|
+
* Re-entry: external events (e.g. `waitResolved` written by the lark
|
|
29
|
+
* card handler) don't drive this loop — the caller is responsible for
|
|
30
|
+
* invoking `runLoop` again when it knows new events have landed. See
|
|
31
|
+
* `src/workflows/fanout.ts` (Slice D-4) for the daemon-side trigger.
|
|
32
|
+
*/
|
|
33
|
+
import { type Snapshot } from './events/replay.js';
|
|
34
|
+
import { type WorkflowRuntimeContext } from './runtime.js';
|
|
35
|
+
export type RunLoopStopReason = 'terminal' | 'awaiting-wait' | 'no-progress' | 'max-ticks';
|
|
36
|
+
export type RunLoopResult = {
|
|
37
|
+
reason: RunLoopStopReason;
|
|
38
|
+
ticks: number;
|
|
39
|
+
lastSnapshot: Snapshot;
|
|
40
|
+
};
|
|
41
|
+
export type RunLoopOptions = {
|
|
42
|
+
/**
|
|
43
|
+
* Defensive cap on tick count. A correctly modeled workflow with N
|
|
44
|
+
* nodes terminates in O(N) ticks; the cap exists to keep buggy
|
|
45
|
+
* orchestrator output from spinning forever. Default 1000.
|
|
46
|
+
*/
|
|
47
|
+
maxTicks?: number;
|
|
48
|
+
};
|
|
49
|
+
export declare function runLoop(ctx: WorkflowRuntimeContext, options?: RunLoopOptions): Promise<RunLoopResult>;
|
|
50
|
+
//# sourceMappingURL=loop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/workflows/loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAQH,OAAO,EAAU,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE3D,OAAO,EAQL,KAAK,sBAAsB,EAC5B,MAAM,cAAc,CAAC;AAStB,MAAM,MAAM,iBAAiB,GACzB,UAAU,GACV,eAAe,GACf,aAAa,GACb,WAAW,CAAC;AAEhB,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,iBAAiB,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,QAAQ,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,wBAAsB,OAAO,CAC3B,GAAG,EAAE,sBAAsB,EAC3B,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,aAAa,CAAC,CA4KxB"}
|