botmux 2.33.0 → 2.33.1
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 +211 -4
- 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,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkerSpawnFn factories for workflow subagent dispatch.
|
|
3
|
+
*
|
|
4
|
+
* Two layers:
|
|
5
|
+
*
|
|
6
|
+
* 1. **Output protocol** — agent-facing convention for delivering the
|
|
7
|
+
* structured output a workflow step needs. The agent emits a
|
|
8
|
+
* well-known marker block in its final assistant message; the
|
|
9
|
+
* workflow runtime parses the marker and extracts JSON.
|
|
10
|
+
*
|
|
11
|
+
* 2. **Factories** —
|
|
12
|
+
* - `createStubSpawnFn(handler)`: dev / test seam. Wraps a
|
|
13
|
+
* user-supplied `(input) => Promise<output>` so tests can
|
|
14
|
+
* drive the orchestrator/loop end-to-end without spinning up
|
|
15
|
+
* a real worker.
|
|
16
|
+
* - `createDaemonSpawnFn(deps)`: real daemon-backed spawn.
|
|
17
|
+
* v0 ships the signature + a TODO body; the daemon wiring
|
|
18
|
+
* (worker-pool fork, transcript capture, kill on timeout)
|
|
19
|
+
* lands as a Slice D follow-up. The interface is stable so
|
|
20
|
+
* the orchestrator and loop don't have to change when the
|
|
21
|
+
* live spawner lands.
|
|
22
|
+
*
|
|
23
|
+
* Why a marker block instead of "last JSON message wins": the agent
|
|
24
|
+
* naturally produces conversational prose plus tool calls plus a final
|
|
25
|
+
* answer; a marker is the only thing that survives prose around it
|
|
26
|
+
* cleanly. The marker matches what the planned `botmux-workflow` skill
|
|
27
|
+
* (UI doc §9) will inject as a tool wrapper.
|
|
28
|
+
*/
|
|
29
|
+
import type { BotSnapshot } from './events/payloads.js';
|
|
30
|
+
import type { WorkerSpawnFn, WorkerSpawnInput, WorkerSessionInfo } from './runtime.js';
|
|
31
|
+
export declare const WORKFLOW_OUTPUT_BEGIN = "<WORKFLOW_OUTPUT>";
|
|
32
|
+
export declare const WORKFLOW_OUTPUT_END = "</WORKFLOW_OUTPUT>";
|
|
33
|
+
/**
|
|
34
|
+
* Augment a step's prompt with the output-protocol footer. Callers
|
|
35
|
+
* should prepend / replace the agent prompt with this so the agent
|
|
36
|
+
* knows how to deliver structured output. Idempotent: re-applying
|
|
37
|
+
* doesn't double-stack the footer.
|
|
38
|
+
*/
|
|
39
|
+
export declare function withWorkflowOutputProtocol(prompt: string): string;
|
|
40
|
+
export type ParseWorkflowOutputResult = {
|
|
41
|
+
ok: true;
|
|
42
|
+
value: unknown;
|
|
43
|
+
raw: string;
|
|
44
|
+
} | {
|
|
45
|
+
ok: false;
|
|
46
|
+
reason: 'no-marker' | 'unclosed-marker' | 'invalid-json';
|
|
47
|
+
detail?: string;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Extract structured JSON from an agent's final transcript.
|
|
51
|
+
*
|
|
52
|
+
* Strategy — anchored from the **last** `</WORKFLOW_OUTPUT>` (END)
|
|
53
|
+
* marker:
|
|
54
|
+
* - find the most recent END
|
|
55
|
+
* - find the latest BEGIN that precedes that END
|
|
56
|
+
* - everything between is the "final" block
|
|
57
|
+
* - parse as JSON
|
|
58
|
+
*
|
|
59
|
+
* Why anchor from the end: real LLM transcripts often include earlier
|
|
60
|
+
* draft markers (the agent revises mid-stream). A naive
|
|
61
|
+
* "first BEGIN → next END" scan can splice across a malformed early
|
|
62
|
+
* block. Anchoring from the END gives us the last *complete* block.
|
|
63
|
+
*
|
|
64
|
+
* Failure modes:
|
|
65
|
+
* - no BEGIN anywhere → `no-marker`
|
|
66
|
+
* - BEGIN(s) but no END → `unclosed-marker`
|
|
67
|
+
* - block exists but content isn't JSON → `invalid-json` + parser msg
|
|
68
|
+
*/
|
|
69
|
+
export declare function parseWorkflowOutput(text: string): ParseWorkflowOutputResult;
|
|
70
|
+
export type StubSpawnHandler = (input: WorkerSpawnInput) => Promise<unknown> | unknown;
|
|
71
|
+
/**
|
|
72
|
+
* Wrap a plain handler so it satisfies `WorkerSpawnFn`. Always
|
|
73
|
+
* returns success; the handler's return value is treated as the
|
|
74
|
+
* structured output. Use for tests / dev where you just need a
|
|
75
|
+
* deterministic answer.
|
|
76
|
+
*
|
|
77
|
+
* NB: this factory is a structured-output shortcut. It does NOT
|
|
78
|
+
* simulate the agent-side marker protocol — the handler receives the
|
|
79
|
+
* raw `WorkerSpawnInput` (not the prompt-with-protocol-footer) and
|
|
80
|
+
* returns the output value directly. Tests that want to exercise
|
|
81
|
+
* `parseWorkflowOutput` should call `createDaemonSpawnFn` with a
|
|
82
|
+
* `runOneShot` that fakes the transcript.
|
|
83
|
+
*/
|
|
84
|
+
export declare function createStubSpawnFn(handler: StubSpawnHandler): WorkerSpawnFn;
|
|
85
|
+
/**
|
|
86
|
+
* Input the daemon's one-shot worker invocation needs from the
|
|
87
|
+
* workflow runtime. Carries the FULL frozen-identity + execution-
|
|
88
|
+
* policy contract through — `botSnapshot` is what `runCreated`
|
|
89
|
+
* froze, not whatever bot-registry currently says. Per UI doc §3.4,
|
|
90
|
+
* mutating bots.json after a run starts must not change execution.
|
|
91
|
+
*/
|
|
92
|
+
export type DaemonRunOneShotInput = {
|
|
93
|
+
botName: string;
|
|
94
|
+
botSnapshot?: BotSnapshot;
|
|
95
|
+
prompt: string;
|
|
96
|
+
workingDir?: string;
|
|
97
|
+
modelOverrides?: {
|
|
98
|
+
model?: string;
|
|
99
|
+
reasoningEffort?: string;
|
|
100
|
+
};
|
|
101
|
+
toolPolicy?: {
|
|
102
|
+
allow?: string[];
|
|
103
|
+
deny?: string[];
|
|
104
|
+
};
|
|
105
|
+
timeoutMs?: number;
|
|
106
|
+
/** Run/node/activity context — daemon may use to mint a worker id or
|
|
107
|
+
* tag sidecar artifacts. Required so the daemon never has to
|
|
108
|
+
* back-resolve identity from globals. */
|
|
109
|
+
runId: string;
|
|
110
|
+
nodeId: string;
|
|
111
|
+
activityId: string;
|
|
112
|
+
attemptId: string;
|
|
113
|
+
/** Conventional per-attempt execution log path. */
|
|
114
|
+
attemptLogPath?: string;
|
|
115
|
+
/**
|
|
116
|
+
* Cooperative cancel handle (v0.1.4-a slice 2). When `aborted` fires,
|
|
117
|
+
* the daemon-backed runOneShot sends the worker a close message + SIGINT
|
|
118
|
+
* for a graceful shutdown, then escalates to SIGKILL after `cancelGraceMs`.
|
|
119
|
+
* Resolves the outer Promise via `WorkflowSpawnCancelledError` so
|
|
120
|
+
* `createDaemonSpawnFn` can map it to `{ kind: 'cancelled', cancelOriginEventId }`.
|
|
121
|
+
*/
|
|
122
|
+
cancelSignal?: AbortSignal;
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* Sentinel error class used by `runOneShot` to signal cancel — caught by
|
|
126
|
+
* `createDaemonSpawnFn` and translated into a `WorkerSpawnResult` of
|
|
127
|
+
* `kind: 'cancelled'`. Keeping it a distinct class (instead of e.g. a
|
|
128
|
+
* `result.cancelled?` field) lets test stubs reject with it without
|
|
129
|
+
* needing to know the `DaemonRunOneShotResult` shape.
|
|
130
|
+
*/
|
|
131
|
+
export declare class WorkflowSpawnCancelledError extends Error {
|
|
132
|
+
readonly cancelOriginEventId: string;
|
|
133
|
+
readonly session?: WorkerSessionInfo;
|
|
134
|
+
constructor(cancelOriginEventId: string, session?: WorkerSessionInfo);
|
|
135
|
+
}
|
|
136
|
+
export type DaemonRunOneShotResult = {
|
|
137
|
+
finalTranscript: string;
|
|
138
|
+
session: WorkerSessionInfo;
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Hooks the workflow runtime needs from the daemon to spawn real
|
|
142
|
+
* workers. Caller (daemon startup) builds an instance of this shape
|
|
143
|
+
* and passes it to `createDaemonSpawnFn`.
|
|
144
|
+
*
|
|
145
|
+
* v0 ships only the type; the runtime can keep going with stub spawns
|
|
146
|
+
* while the daemon wiring lands. The split lets us land workflow
|
|
147
|
+
* runtime + cards + loop without blocking on worker.ts integration.
|
|
148
|
+
*/
|
|
149
|
+
export type DaemonSpawnDeps = {
|
|
150
|
+
/**
|
|
151
|
+
* Fork a worker bound to the named bot, hand it the prompt, and
|
|
152
|
+
* resolve with the worker's final transcript text (or reject on
|
|
153
|
+
* crash / timeout). Implementation reuses
|
|
154
|
+
* `src/core/worker-pool.ts forkWorker` + a transient root id.
|
|
155
|
+
*/
|
|
156
|
+
runOneShot(input: DaemonRunOneShotInput): Promise<DaemonRunOneShotResult>;
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* Compose a `WorkerSpawnFn` that uses real daemon hooks. The hooks
|
|
160
|
+
* are injected so the workflows package doesn't pull in daemon
|
|
161
|
+
* internals. v0 placeholder is documented; the daemon integration
|
|
162
|
+
* lands as a follow-up.
|
|
163
|
+
*/
|
|
164
|
+
export declare function createDaemonSpawnFn(deps: DaemonSpawnDeps): WorkerSpawnFn;
|
|
165
|
+
//# sourceMappingURL=spawn-bot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn-bot.d.ts","sourceRoot":"","sources":["../../src/workflows/spawn-bot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EACV,aAAa,EACb,gBAAgB,EAEhB,iBAAiB,EAClB,MAAM,cAAc,CAAC;AAItB,eAAO,MAAM,qBAAqB,sBAAsB,CAAC;AACzD,eAAO,MAAM,mBAAmB,uBAAuB,CAAC;AAExD;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGjE;AAED,MAAM,MAAM,yBAAyB,GACjC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,WAAW,GAAG,iBAAiB,GAAG,cAAc,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7F;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,yBAAyB,CAsB3E;AAiBD,MAAM,MAAM,gBAAgB,GAAG,CAC7B,KAAK,EAAE,gBAAgB,KACpB,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;AAEhC;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,GAAG,aAAa,CAc1E;AAID;;;;;;GAMG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9D,UAAU,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;8CAE0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,WAAW,CAAC;CAC5B,CAAC;AAEF;;;;;;GAMG;AACH,qBAAa,2BAA4B,SAAQ,KAAK;IACpD,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,iBAAiB,CAAC;gBACzB,mBAAmB,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB;CAMrE;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,iBAAiB,CAAC;CAC5B,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;;OAKG;IACH,UAAU,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;CAC3E,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,eAAe,GAAG,aAAa,CAmDxE"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkerSpawnFn factories for workflow subagent dispatch.
|
|
3
|
+
*
|
|
4
|
+
* Two layers:
|
|
5
|
+
*
|
|
6
|
+
* 1. **Output protocol** — agent-facing convention for delivering the
|
|
7
|
+
* structured output a workflow step needs. The agent emits a
|
|
8
|
+
* well-known marker block in its final assistant message; the
|
|
9
|
+
* workflow runtime parses the marker and extracts JSON.
|
|
10
|
+
*
|
|
11
|
+
* 2. **Factories** —
|
|
12
|
+
* - `createStubSpawnFn(handler)`: dev / test seam. Wraps a
|
|
13
|
+
* user-supplied `(input) => Promise<output>` so tests can
|
|
14
|
+
* drive the orchestrator/loop end-to-end without spinning up
|
|
15
|
+
* a real worker.
|
|
16
|
+
* - `createDaemonSpawnFn(deps)`: real daemon-backed spawn.
|
|
17
|
+
* v0 ships the signature + a TODO body; the daemon wiring
|
|
18
|
+
* (worker-pool fork, transcript capture, kill on timeout)
|
|
19
|
+
* lands as a Slice D follow-up. The interface is stable so
|
|
20
|
+
* the orchestrator and loop don't have to change when the
|
|
21
|
+
* live spawner lands.
|
|
22
|
+
*
|
|
23
|
+
* Why a marker block instead of "last JSON message wins": the agent
|
|
24
|
+
* naturally produces conversational prose plus tool calls plus a final
|
|
25
|
+
* answer; a marker is the only thing that survives prose around it
|
|
26
|
+
* cleanly. The marker matches what the planned `botmux-workflow` skill
|
|
27
|
+
* (UI doc §9) will inject as a tool wrapper.
|
|
28
|
+
*/
|
|
29
|
+
// ─── Output protocol ──────────────────────────────────────────────────────
|
|
30
|
+
export const WORKFLOW_OUTPUT_BEGIN = '<WORKFLOW_OUTPUT>';
|
|
31
|
+
export const WORKFLOW_OUTPUT_END = '</WORKFLOW_OUTPUT>';
|
|
32
|
+
/**
|
|
33
|
+
* Augment a step's prompt with the output-protocol footer. Callers
|
|
34
|
+
* should prepend / replace the agent prompt with this so the agent
|
|
35
|
+
* knows how to deliver structured output. Idempotent: re-applying
|
|
36
|
+
* doesn't double-stack the footer.
|
|
37
|
+
*/
|
|
38
|
+
export function withWorkflowOutputProtocol(prompt) {
|
|
39
|
+
if (prompt.includes(WORKFLOW_OUTPUT_BEGIN))
|
|
40
|
+
return prompt;
|
|
41
|
+
return `${prompt}\n\n---\nWhen you finish, emit your final structured output between the markers below as a single valid JSON value. Do not include anything else inside the markers.\n\n${WORKFLOW_OUTPUT_BEGIN}\n{"...your JSON output..."}\n${WORKFLOW_OUTPUT_END}\n`;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Extract structured JSON from an agent's final transcript.
|
|
45
|
+
*
|
|
46
|
+
* Strategy — anchored from the **last** `</WORKFLOW_OUTPUT>` (END)
|
|
47
|
+
* marker:
|
|
48
|
+
* - find the most recent END
|
|
49
|
+
* - find the latest BEGIN that precedes that END
|
|
50
|
+
* - everything between is the "final" block
|
|
51
|
+
* - parse as JSON
|
|
52
|
+
*
|
|
53
|
+
* Why anchor from the end: real LLM transcripts often include earlier
|
|
54
|
+
* draft markers (the agent revises mid-stream). A naive
|
|
55
|
+
* "first BEGIN → next END" scan can splice across a malformed early
|
|
56
|
+
* block. Anchoring from the END gives us the last *complete* block.
|
|
57
|
+
*
|
|
58
|
+
* Failure modes:
|
|
59
|
+
* - no BEGIN anywhere → `no-marker`
|
|
60
|
+
* - BEGIN(s) but no END → `unclosed-marker`
|
|
61
|
+
* - block exists but content isn't JSON → `invalid-json` + parser msg
|
|
62
|
+
*/
|
|
63
|
+
export function parseWorkflowOutput(text) {
|
|
64
|
+
const lastEnd = text.lastIndexOf(WORKFLOW_OUTPUT_END);
|
|
65
|
+
if (lastEnd < 0) {
|
|
66
|
+
return text.includes(WORKFLOW_OUTPUT_BEGIN)
|
|
67
|
+
? { ok: false, reason: 'unclosed-marker' }
|
|
68
|
+
: { ok: false, reason: 'no-marker' };
|
|
69
|
+
}
|
|
70
|
+
const beginBeforeEnd = text.lastIndexOf(WORKFLOW_OUTPUT_BEGIN, lastEnd);
|
|
71
|
+
if (beginBeforeEnd < 0) {
|
|
72
|
+
return { ok: false, reason: 'no-marker' };
|
|
73
|
+
}
|
|
74
|
+
const rawBlock = text.slice(beginBeforeEnd + WORKFLOW_OUTPUT_BEGIN.length, lastEnd).trim();
|
|
75
|
+
const block = sanitizeWorkflowOutputBlock(rawBlock);
|
|
76
|
+
try {
|
|
77
|
+
return { ok: true, value: JSON.parse(block), raw: block };
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
return {
|
|
81
|
+
ok: false,
|
|
82
|
+
reason: 'invalid-json',
|
|
83
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function sanitizeWorkflowOutputBlock(block) {
|
|
88
|
+
// PTY fallback transcripts can include terminal control sequences and
|
|
89
|
+
// hard-wrapped CR/LF bytes inside an otherwise valid one-line JSON block.
|
|
90
|
+
// Agent transcript files remain preferred when available; this keeps the
|
|
91
|
+
// fallback from rejecting clean model output just because the terminal view
|
|
92
|
+
// polluted it.
|
|
93
|
+
return block
|
|
94
|
+
.replace(/\x1b\][\s\S]*?(?:\x07|\x1b\\)/g, '')
|
|
95
|
+
.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, '')
|
|
96
|
+
.replace(/[\u0000-\u001f\u007f]/g, '')
|
|
97
|
+
.trim();
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Wrap a plain handler so it satisfies `WorkerSpawnFn`. Always
|
|
101
|
+
* returns success; the handler's return value is treated as the
|
|
102
|
+
* structured output. Use for tests / dev where you just need a
|
|
103
|
+
* deterministic answer.
|
|
104
|
+
*
|
|
105
|
+
* NB: this factory is a structured-output shortcut. It does NOT
|
|
106
|
+
* simulate the agent-side marker protocol — the handler receives the
|
|
107
|
+
* raw `WorkerSpawnInput` (not the prompt-with-protocol-footer) and
|
|
108
|
+
* returns the output value directly. Tests that want to exercise
|
|
109
|
+
* `parseWorkflowOutput` should call `createDaemonSpawnFn` with a
|
|
110
|
+
* `runOneShot` that fakes the transcript.
|
|
111
|
+
*/
|
|
112
|
+
export function createStubSpawnFn(handler) {
|
|
113
|
+
return async (input) => {
|
|
114
|
+
const startedAt = Date.now();
|
|
115
|
+
const output = await Promise.resolve(handler(input));
|
|
116
|
+
const session = {
|
|
117
|
+
sessionId: `stub-${input.activityId}-${input.attemptId}`,
|
|
118
|
+
botName: input.botName,
|
|
119
|
+
cliId: input.botSnapshot?.cliId,
|
|
120
|
+
workingDir: input.workingDir,
|
|
121
|
+
startedAt,
|
|
122
|
+
endedAt: Date.now(),
|
|
123
|
+
};
|
|
124
|
+
return { kind: 'success', output, session };
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Sentinel error class used by `runOneShot` to signal cancel — caught by
|
|
129
|
+
* `createDaemonSpawnFn` and translated into a `WorkerSpawnResult` of
|
|
130
|
+
* `kind: 'cancelled'`. Keeping it a distinct class (instead of e.g. a
|
|
131
|
+
* `result.cancelled?` field) lets test stubs reject with it without
|
|
132
|
+
* needing to know the `DaemonRunOneShotResult` shape.
|
|
133
|
+
*/
|
|
134
|
+
export class WorkflowSpawnCancelledError extends Error {
|
|
135
|
+
cancelOriginEventId;
|
|
136
|
+
session;
|
|
137
|
+
constructor(cancelOriginEventId, session) {
|
|
138
|
+
super('workflow spawn cancelled');
|
|
139
|
+
this.name = 'WorkflowSpawnCancelledError';
|
|
140
|
+
this.cancelOriginEventId = cancelOriginEventId;
|
|
141
|
+
this.session = session;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Compose a `WorkerSpawnFn` that uses real daemon hooks. The hooks
|
|
146
|
+
* are injected so the workflows package doesn't pull in daemon
|
|
147
|
+
* internals. v0 placeholder is documented; the daemon integration
|
|
148
|
+
* lands as a follow-up.
|
|
149
|
+
*/
|
|
150
|
+
export function createDaemonSpawnFn(deps) {
|
|
151
|
+
return async (input) => {
|
|
152
|
+
const prompt = withWorkflowOutputProtocol(input.prompt);
|
|
153
|
+
let oneShot;
|
|
154
|
+
try {
|
|
155
|
+
oneShot = await deps.runOneShot({
|
|
156
|
+
botName: input.botName,
|
|
157
|
+
botSnapshot: input.botSnapshot,
|
|
158
|
+
prompt,
|
|
159
|
+
workingDir: input.workingDir,
|
|
160
|
+
modelOverrides: input.modelOverrides,
|
|
161
|
+
toolPolicy: input.toolPolicy,
|
|
162
|
+
runId: input.runId,
|
|
163
|
+
nodeId: input.nodeId,
|
|
164
|
+
activityId: input.activityId,
|
|
165
|
+
attemptId: input.attemptId,
|
|
166
|
+
attemptLogPath: input.attemptLogPath,
|
|
167
|
+
cancelSignal: input.cancelSignal,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
// Translate the sentinel cancel error into a cancelled spawn result.
|
|
172
|
+
if (err instanceof WorkflowSpawnCancelledError) {
|
|
173
|
+
return {
|
|
174
|
+
kind: 'cancelled',
|
|
175
|
+
cancelOriginEventId: err.cancelOriginEventId,
|
|
176
|
+
session: err.session,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
kind: 'failure',
|
|
181
|
+
errorCode: 'WorkerCrashed',
|
|
182
|
+
errorClass: 'retryable',
|
|
183
|
+
errorMessage: err instanceof Error ? err.message : String(err),
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
const parsed = parseWorkflowOutput(oneShot.finalTranscript);
|
|
187
|
+
if (!parsed.ok) {
|
|
188
|
+
return {
|
|
189
|
+
kind: 'failure',
|
|
190
|
+
errorCode: 'OutputSchemaViolation',
|
|
191
|
+
errorClass: 'manual',
|
|
192
|
+
errorMessage: formatParseFailure(parsed, oneShot.finalTranscript),
|
|
193
|
+
session: oneShot.session,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
kind: 'success',
|
|
198
|
+
output: parsed.value,
|
|
199
|
+
session: oneShot.session,
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function formatParseFailure(parsed, transcript) {
|
|
204
|
+
// Truncate so log lines don't blow up — full transcript still lives
|
|
205
|
+
// in the worker's terminal log / session sidecar for debugging.
|
|
206
|
+
const SNIPPET_MAX = 240;
|
|
207
|
+
const snippet = transcript.length > SNIPPET_MAX
|
|
208
|
+
? transcript.slice(0, SNIPPET_MAX) + '…(truncated)'
|
|
209
|
+
: transcript;
|
|
210
|
+
const detail = parsed.detail ? `: ${parsed.detail}` : '';
|
|
211
|
+
return (`Worker output did not contain a parseable ` +
|
|
212
|
+
`${WORKFLOW_OUTPUT_BEGIN}…${WORKFLOW_OUTPUT_END} block ` +
|
|
213
|
+
`(${parsed.reason}${detail}). Transcript: ${JSON.stringify(snippet)}`);
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=spawn-bot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spawn-bot.js","sourceRoot":"","sources":["../../src/workflows/spawn-bot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System / recovery boundary host API (events doc v0.1.2 §2.6, Step 10
|
|
3
|
+
* of 10).
|
|
4
|
+
*
|
|
5
|
+
* Step 10 deliverables (paired with Step 7 resume + Step 9 cancel):
|
|
6
|
+
* - `reportWorkerLost` — write `workerLost { workerId, lostActivityIds }`.
|
|
7
|
+
* Resume already handles the consequence (Step 7):
|
|
8
|
+
* * for each lost activity with dangling effectAttempted → run
|
|
9
|
+
* the reconcile decision tree;
|
|
10
|
+
* * for each lost activity without effectAttempted → write
|
|
11
|
+
* activityFailed { WorkerCrashed, retryable };
|
|
12
|
+
* * dangling waits stay alone (worker death is not a wait
|
|
13
|
+
* resolution).
|
|
14
|
+
* So this module only adds the host-side writer; the recovery
|
|
15
|
+
* loop is already in place.
|
|
16
|
+
*
|
|
17
|
+
* Note on the cancel fan-out (also Step 10): the fan-out lives in
|
|
18
|
+
* replay (not here) — it's a deterministic projection of node/run
|
|
19
|
+
* cancel onto in-flight activities, not a new event-writing path.
|
|
20
|
+
*/
|
|
21
|
+
import type { EventLog } from './events/append.js';
|
|
22
|
+
import type { WorkerLostEvent } from './events/types.js';
|
|
23
|
+
export type ReportWorkerLostInput = {
|
|
24
|
+
/** Identifier of the worker that timed out / disconnected. */
|
|
25
|
+
workerId: string;
|
|
26
|
+
/**
|
|
27
|
+
* Activities the runtime registry believes the worker held leases
|
|
28
|
+
* for at the moment of detection. Resume walks these alongside the
|
|
29
|
+
* generic dangling-set fallback — supplying them here lets the
|
|
30
|
+
* runtime tag the event with audit-grade evidence even if the
|
|
31
|
+
* dangling set picks up additional activities later.
|
|
32
|
+
*/
|
|
33
|
+
lostActivityIds: string[];
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Record a worker timeout / heartbeat loss. Spec §2.6 v0.1.1: this is
|
|
37
|
+
* the system-fault path; explicitly NOT cancel. Resume's recovery
|
|
38
|
+
* loop (Step 7) reads dangling state, not this event — workerLost is
|
|
39
|
+
* primarily an audit trail. Writing it before resume runs is the
|
|
40
|
+
* recommended ordering so the audit reflects why recovery fired.
|
|
41
|
+
*
|
|
42
|
+
* Returns the appended event (with eventId etc).
|
|
43
|
+
*
|
|
44
|
+
* Throws if `lostActivityIds` is empty (spec mandates min 1; an empty
|
|
45
|
+
* list means "worker lost but had no work" which is a no-op the
|
|
46
|
+
* runtime should detect before writing this event).
|
|
47
|
+
*/
|
|
48
|
+
export declare function reportWorkerLost(log: EventLog, input: ReportWorkerLostInput): Promise<WorkerLostEvent>;
|
|
49
|
+
//# sourceMappingURL=system.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../src/workflows/system.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,MAAM,MAAM,qBAAqB,GAAG;IAClC,8DAA8D;IAC9D,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,QAAQ,EACb,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,eAAe,CAAC,CAe1B"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System / recovery boundary host API (events doc v0.1.2 §2.6, Step 10
|
|
3
|
+
* of 10).
|
|
4
|
+
*
|
|
5
|
+
* Step 10 deliverables (paired with Step 7 resume + Step 9 cancel):
|
|
6
|
+
* - `reportWorkerLost` — write `workerLost { workerId, lostActivityIds }`.
|
|
7
|
+
* Resume already handles the consequence (Step 7):
|
|
8
|
+
* * for each lost activity with dangling effectAttempted → run
|
|
9
|
+
* the reconcile decision tree;
|
|
10
|
+
* * for each lost activity without effectAttempted → write
|
|
11
|
+
* activityFailed { WorkerCrashed, retryable };
|
|
12
|
+
* * dangling waits stay alone (worker death is not a wait
|
|
13
|
+
* resolution).
|
|
14
|
+
* So this module only adds the host-side writer; the recovery
|
|
15
|
+
* loop is already in place.
|
|
16
|
+
*
|
|
17
|
+
* Note on the cancel fan-out (also Step 10): the fan-out lives in
|
|
18
|
+
* replay (not here) — it's a deterministic projection of node/run
|
|
19
|
+
* cancel onto in-flight activities, not a new event-writing path.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Record a worker timeout / heartbeat loss. Spec §2.6 v0.1.1: this is
|
|
23
|
+
* the system-fault path; explicitly NOT cancel. Resume's recovery
|
|
24
|
+
* loop (Step 7) reads dangling state, not this event — workerLost is
|
|
25
|
+
* primarily an audit trail. Writing it before resume runs is the
|
|
26
|
+
* recommended ordering so the audit reflects why recovery fired.
|
|
27
|
+
*
|
|
28
|
+
* Returns the appended event (with eventId etc).
|
|
29
|
+
*
|
|
30
|
+
* Throws if `lostActivityIds` is empty (spec mandates min 1; an empty
|
|
31
|
+
* list means "worker lost but had no work" which is a no-op the
|
|
32
|
+
* runtime should detect before writing this event).
|
|
33
|
+
*/
|
|
34
|
+
export async function reportWorkerLost(log, input) {
|
|
35
|
+
if (input.lostActivityIds.length === 0) {
|
|
36
|
+
throw new Error(`reportWorkerLost(${input.workerId}): lostActivityIds is empty — the runtime should skip writing workerLost when the worker held no leases.`);
|
|
37
|
+
}
|
|
38
|
+
return (await log.append({
|
|
39
|
+
runId: log.runId,
|
|
40
|
+
type: 'workerLost',
|
|
41
|
+
actor: 'system',
|
|
42
|
+
payload: {
|
|
43
|
+
workerId: input.workerId,
|
|
44
|
+
lostActivityIds: input.lostActivityIds,
|
|
45
|
+
},
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=system.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system.js","sourceRoot":"","sources":["../../src/workflows/system.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAkBH;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAa,EACb,KAA4B;IAE5B,IAAI,KAAK,CAAC,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CACb,oBAAoB,KAAK,CAAC,QAAQ,0GAA0G,CAC7I,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC;QACvB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,QAAQ;QACf,OAAO,EAAE;YACP,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,eAAe,EAAE,KAAK,CAAC,eAAe;SACvC;KACF,CAAC,CAAoB,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared workflow trigger — used by the dashboard catalog `POST .../run`
|
|
3
|
+
* route on the daemon side. Wraps the load/coerce/createRun/drive sequence
|
|
4
|
+
* with injectable deps so the orchestration can be unit-tested without the
|
|
5
|
+
* full daemon process.
|
|
6
|
+
*
|
|
7
|
+
* IM `/workflow run` still goes through `executeWorkflowCommand`; this helper
|
|
8
|
+
* is the dashboard-trigger path that consumes pre-decoded JSON params and
|
|
9
|
+
* fires the workflow loop in the background.
|
|
10
|
+
*/
|
|
11
|
+
import { type RawParamInput } from './params.js';
|
|
12
|
+
import { EventLog } from './events/append.js';
|
|
13
|
+
import { type BotResolver } from './run-init.js';
|
|
14
|
+
import type { WorkflowDefinition } from './definition.js';
|
|
15
|
+
import type { WorkflowRuntimeContext, WorkerSpawnFn } from './runtime.js';
|
|
16
|
+
export type TriggerInput = {
|
|
17
|
+
workflowId: string;
|
|
18
|
+
rawParams: Record<string, RawParamInput>;
|
|
19
|
+
chatBinding: {
|
|
20
|
+
chatId: string;
|
|
21
|
+
larkAppId: string;
|
|
22
|
+
};
|
|
23
|
+
initiator: string;
|
|
24
|
+
};
|
|
25
|
+
export type TriggerDeps = {
|
|
26
|
+
spawnSubagent: WorkerSpawnFn;
|
|
27
|
+
botResolver: BotResolver;
|
|
28
|
+
/** Build the ctx scaffolding (hostExecutors, reconcilers, loadEffectInput). */
|
|
29
|
+
makeRuntimeContext: (log: EventLog, def: WorkflowDefinition, spawnSubagent: WorkerSpawnFn) => WorkflowRuntimeContext;
|
|
30
|
+
/** Daemon side registers the ctx so future cancel/approve can find it. */
|
|
31
|
+
attachRuntime: (runId: string, ctx: WorkflowRuntimeContext) => {
|
|
32
|
+
ready?: Promise<unknown>;
|
|
33
|
+
};
|
|
34
|
+
/** Fire-and-forget loop drive — daemon owns the actual scheduling. */
|
|
35
|
+
driveRun: (runId: string) => void;
|
|
36
|
+
/** Test seam: override the file lookup. */
|
|
37
|
+
loadWorkflowDefinition?: (workflowId: string) => Promise<WorkflowDefinition>;
|
|
38
|
+
/** Test seam: deterministic run id. */
|
|
39
|
+
makeRunId?: (def: WorkflowDefinition) => string;
|
|
40
|
+
/** Test seam: explicit runs dir override. */
|
|
41
|
+
makeEventLog?: (runId: string) => EventLog;
|
|
42
|
+
};
|
|
43
|
+
export type TriggerSuccess = {
|
|
44
|
+
ok: true;
|
|
45
|
+
runId: string;
|
|
46
|
+
workflowId: string;
|
|
47
|
+
status: string;
|
|
48
|
+
lastSeq: number;
|
|
49
|
+
};
|
|
50
|
+
export type TriggerFailure = {
|
|
51
|
+
ok: false;
|
|
52
|
+
error: 'unknown_workflow';
|
|
53
|
+
message: string;
|
|
54
|
+
} | {
|
|
55
|
+
ok: false;
|
|
56
|
+
error: 'invalid_params';
|
|
57
|
+
message: string;
|
|
58
|
+
issues: Array<{
|
|
59
|
+
path: string[];
|
|
60
|
+
code: string;
|
|
61
|
+
message: string;
|
|
62
|
+
}>;
|
|
63
|
+
} | {
|
|
64
|
+
ok: false;
|
|
65
|
+
error: 'load_definition_failed' | 'internal_error';
|
|
66
|
+
message: string;
|
|
67
|
+
};
|
|
68
|
+
export type TriggerResult = TriggerSuccess | TriggerFailure;
|
|
69
|
+
export declare function triggerWorkflowRun(input: TriggerInput, deps: TriggerDeps): Promise<TriggerResult>;
|
|
70
|
+
//# sourceMappingURL=trigger-run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trigger-run.d.ts","sourceRoot":"","sources":["../../src/workflows/trigger-run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAA4C,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAC3F,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,OAAO,EAAa,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,KAAK,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE1E,MAAM,MAAM,YAAY,GAAG;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACzC,WAAW,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,aAAa,EAAE,aAAa,CAAC;IAC7B,WAAW,EAAE,WAAW,CAAC;IACzB,+EAA+E;IAC/E,kBAAkB,EAAE,CAClB,GAAG,EAAE,QAAQ,EACb,GAAG,EAAE,kBAAkB,EACvB,aAAa,EAAE,aAAa,KACzB,sBAAsB,CAAC;IAC5B,0EAA0E;IAC1E,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,sBAAsB,KAAK;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,CAAC;IAC5F,sEAAsE;IACtE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,2CAA2C;IAC3C,sBAAsB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC7E,uCAAuC;IACvC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,kBAAkB,KAAK,MAAM,CAAC;IAChD,6CAA6C;IAC7C,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,QAAQ,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,IAAI,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,cAAc,GACtB;IACE,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,kBAAkB,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB,GACD;IACE,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,gBAAgB,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClE,GACD;IACE,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,wBAAwB,GAAG,gBAAgB,CAAC;IACnD,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEN,MAAM,MAAM,aAAa,GAAG,cAAc,GAAG,cAAc,CAAC;AAE5D,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,aAAa,CAAC,CAmExB"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared workflow trigger — used by the dashboard catalog `POST .../run`
|
|
3
|
+
* route on the daemon side. Wraps the load/coerce/createRun/drive sequence
|
|
4
|
+
* with injectable deps so the orchestration can be unit-tested without the
|
|
5
|
+
* full daemon process.
|
|
6
|
+
*
|
|
7
|
+
* IM `/workflow run` still goes through `executeWorkflowCommand`; this helper
|
|
8
|
+
* is the dashboard-trigger path that consumes pre-decoded JSON params and
|
|
9
|
+
* fires the workflow loop in the background.
|
|
10
|
+
*/
|
|
11
|
+
import { coerceWorkflowParams, ParamCoerceFailure } from './params.js';
|
|
12
|
+
import { EventLog } from './events/append.js';
|
|
13
|
+
import { loadWorkflowDefinition as defaultLoadWorkflowDefinition } from './loader.js';
|
|
14
|
+
import { mintWorkflowRunId } from './run-id.js';
|
|
15
|
+
import { createRun } from './run-init.js';
|
|
16
|
+
import { replay } from './events/replay.js';
|
|
17
|
+
import { getRunsDir } from './runs-dir.js';
|
|
18
|
+
export async function triggerWorkflowRun(input, deps) {
|
|
19
|
+
const loadDef = deps.loadWorkflowDefinition ?? defaultLoadWorkflowDefinition;
|
|
20
|
+
let def;
|
|
21
|
+
try {
|
|
22
|
+
def = await loadDef(input.workflowId);
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
26
|
+
if (message.startsWith(`Workflow '${input.workflowId}' not found`)) {
|
|
27
|
+
return { ok: false, error: 'unknown_workflow', message };
|
|
28
|
+
}
|
|
29
|
+
return { ok: false, error: 'load_definition_failed', message };
|
|
30
|
+
}
|
|
31
|
+
let coerced;
|
|
32
|
+
try {
|
|
33
|
+
coerced = coerceWorkflowParams(def, input.rawParams);
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
if (err instanceof ParamCoerceFailure) {
|
|
37
|
+
return {
|
|
38
|
+
ok: false,
|
|
39
|
+
error: 'invalid_params',
|
|
40
|
+
message: err.message,
|
|
41
|
+
issues: err.issues.map((i) => ({
|
|
42
|
+
path: i.name ? [i.name] : [],
|
|
43
|
+
code: i.code,
|
|
44
|
+
message: i.message,
|
|
45
|
+
})),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
49
|
+
return { ok: false, error: 'internal_error', message };
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const runId = (deps.makeRunId ?? ((d) => mintWorkflowRunId(d.workflowId, Date.now())))(def);
|
|
53
|
+
const log = deps.makeEventLog ? deps.makeEventLog(runId) : new EventLog(runId, getRunsDir());
|
|
54
|
+
const ctx = deps.makeRuntimeContext(log, def, deps.spawnSubagent);
|
|
55
|
+
await createRun(log, {
|
|
56
|
+
def,
|
|
57
|
+
params: coerced,
|
|
58
|
+
initiator: input.initiator,
|
|
59
|
+
botResolver: deps.botResolver,
|
|
60
|
+
chatBinding: input.chatBinding,
|
|
61
|
+
});
|
|
62
|
+
const watcher = deps.attachRuntime(runId, ctx);
|
|
63
|
+
if (watcher.ready) {
|
|
64
|
+
try {
|
|
65
|
+
await watcher.ready;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// watcher start failures are logged by the daemon; the run is still
|
|
69
|
+
// valid and will keep producing events the watcher can re-pick on
|
|
70
|
+
// restart, so don't abort the trigger here.
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
deps.driveRun(runId);
|
|
74
|
+
const snapshot = replay(await log.readAll());
|
|
75
|
+
return {
|
|
76
|
+
ok: true,
|
|
77
|
+
runId,
|
|
78
|
+
workflowId: def.workflowId,
|
|
79
|
+
status: snapshot.run.status,
|
|
80
|
+
lastSeq: snapshot.lastSeq,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
85
|
+
return { ok: false, error: 'internal_error', message };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=trigger-run.js.map
|