agent-tempo 1.7.0 → 2.0.0-beta.2
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/CLAUDE.md +10 -13
- package/README.md +21 -15
- package/dashboard/dist/assets/index-BbR7zIdK.js.map +1 -1
- package/dashboard/package.json +1 -1
- package/dist/activities/hard-terminate.d.ts +2 -2
- package/dist/activities/hard-terminate.js +3 -9
- package/dist/activities/maestro.d.ts +8 -13
- package/dist/activities/maestro.js +3 -10
- package/dist/activities/outbox.js +16 -2
- package/dist/activities/resolve.d.ts +18 -7
- package/dist/activities/resolve.js +58 -46
- package/dist/adapters/base.js +3 -0
- package/dist/adapters/claude-code/adapter.js +7 -0
- package/dist/cli/command-center-command.js +15 -1
- package/dist/cli/commands.d.ts +8 -0
- package/dist/cli/commands.js +79 -11
- package/dist/cli/daemon-command.js +19 -33
- package/dist/cli/help-text.js +9 -7
- package/dist/cli/home-command.d.ts +26 -0
- package/dist/cli/home-command.js +156 -0
- package/dist/cli/removed-verbs.d.ts +0 -4
- package/dist/cli/removed-verbs.js +23 -12
- package/dist/cli/sa-preflight.d.ts +0 -14
- package/dist/cli/sa-preflight.js +1 -17
- package/dist/cli/startup.d.ts +1 -10
- package/dist/cli/startup.js +0 -40
- package/dist/cli.js +34 -80
- package/dist/client/core.js +13 -15
- package/dist/client/index.d.ts +2 -1
- package/dist/client/interface.d.ts +5 -14
- package/dist/client/with-spawn.d.ts +9 -4
- package/dist/client/with-spawn.js +7 -10
- package/dist/config.d.ts +14 -13
- package/dist/config.js +14 -0
- package/dist/constants.d.ts +50 -0
- package/dist/constants.js +60 -1
- package/dist/daemon.js +81 -0
- package/dist/http/auth.d.ts +3 -21
- package/dist/http/auth.js +10 -31
- package/dist/http/event-types.d.ts +38 -4
- package/dist/http/orphans.d.ts +3 -3
- package/dist/http/orphans.js +3 -3
- package/dist/http/server.d.ts +0 -5
- package/dist/http/server.js +79 -29
- package/dist/http/snapshot.js +3 -0
- package/dist/http/writes.d.ts +1 -1
- package/dist/http/writes.js +25 -2
- package/dist/observability/nondeterminism-alarm.d.ts +113 -0
- package/dist/observability/nondeterminism-alarm.js +162 -0
- package/dist/palette/index.d.ts +6 -7
- package/dist/palette/index.js +6 -7
- package/dist/pi/mission-control/actions.d.ts +67 -1
- package/dist/pi/mission-control/actions.js +61 -0
- package/dist/pi/mission-control/extension.d.ts +77 -0
- package/dist/pi/mission-control/extension.js +171 -0
- package/dist/pi/workflow-client.d.ts +14 -16
- package/dist/pi/workflow-client.js +18 -44
- package/dist/server-tools.js +30 -29
- package/dist/server.js +42 -0
- package/dist/tools/action-guard.d.ts +23 -0
- package/dist/tools/action-guard.js +33 -0
- package/dist/tools/coat-check.d.ts +20 -0
- package/dist/tools/coat-check.js +129 -0
- package/dist/tools/gate.d.ts +13 -0
- package/dist/tools/gate.js +88 -0
- package/dist/tools/schedule.d.ts +18 -0
- package/dist/tools/schedule.js +93 -1
- package/dist/tools/stage.d.ts +17 -0
- package/dist/tools/stage.js +85 -1
- package/dist/tools/state.d.ts +14 -0
- package/dist/tools/state.js +95 -0
- package/dist/types.d.ts +54 -7
- package/dist/upgrade/boot-guard.d.ts +95 -0
- package/dist/upgrade/boot-guard.js +88 -0
- package/dist/upgrade/from-upgrade.d.ts +95 -0
- package/dist/upgrade/from-upgrade.js +330 -0
- package/dist/upgrade/phase-engine.js +4 -1
- package/dist/utils/duration.d.ts +3 -6
- package/dist/utils/duration.js +3 -6
- package/dist/utils/format-hosts.d.ts +1 -1
- package/dist/utils/format-hosts.js +0 -2
- package/dist/utils/grpc-shutdown-guard.js +0 -4
- package/dist/utils/hosts.d.ts +4 -10
- package/dist/utils/hosts.js +12 -28
- package/dist/utils/orphan-guard.d.ts +37 -0
- package/dist/utils/orphan-guard.js +26 -0
- package/dist/utils/search-attributes.d.ts +28 -18
- package/dist/utils/search-attributes.js +48 -18
- package/dist/utils/visibility-deadline.d.ts +16 -0
- package/dist/utils/visibility-deadline.js +16 -0
- package/dist/workflows/maestro-signals.d.ts +0 -13
- package/dist/workflows/maestro-signals.js +6 -14
- package/dist/workflows/maestro.js +27 -32
- package/dist/workflows/scheduler.js +7 -1
- package/dist/workflows/session.js +237 -153
- package/dist/workflows/signals.d.ts +9 -1
- package/dist/workflows/signals.js +8 -6
- package/package.json +1 -6
- package/workflow-bundle.js +478 -225
- package/dist/cli/legacy-migration.d.ts +0 -35
- package/dist/cli/legacy-migration.js +0 -341
- package/dist/client/ensure-conductor-spawned.d.ts +0 -35
- package/dist/client/ensure-conductor-spawned.js +0 -48
- package/dist/tui/App.d.ts +0 -85
- package/dist/tui/App.js +0 -1791
- package/dist/tui/bootstrap-types.d.ts +0 -46
- package/dist/tui/bootstrap-types.js +0 -7
- package/dist/tui/commands.d.ts +0 -71
- package/dist/tui/commands.js +0 -1375
- package/dist/tui/components/ChatView.d.ts +0 -35
- package/dist/tui/components/ChatView.js +0 -54
- package/dist/tui/components/CommandPalette.d.ts +0 -21
- package/dist/tui/components/CommandPalette.js +0 -67
- package/dist/tui/components/ConversationStream.d.ts +0 -114
- package/dist/tui/components/ConversationStream.js +0 -307
- package/dist/tui/components/CreateEnsembleWizard.d.ts +0 -19
- package/dist/tui/components/CreateEnsembleWizard.js +0 -223
- package/dist/tui/components/DestroyConfirmModal.d.ts +0 -17
- package/dist/tui/components/DestroyConfirmModal.js +0 -62
- package/dist/tui/components/ErrorView.d.ts +0 -31
- package/dist/tui/components/ErrorView.js +0 -129
- package/dist/tui/components/HomeView.d.ts +0 -54
- package/dist/tui/components/HomeView.js +0 -306
- package/dist/tui/components/LoadLineupModal.d.ts +0 -18
- package/dist/tui/components/LoadLineupModal.js +0 -79
- package/dist/tui/components/MainView.d.ts +0 -21
- package/dist/tui/components/MainView.js +0 -107
- package/dist/tui/components/NewEnsembleModal.d.ts +0 -9
- package/dist/tui/components/NewEnsembleModal.js +0 -73
- package/dist/tui/components/Picker.d.ts +0 -23
- package/dist/tui/components/Picker.js +0 -70
- package/dist/tui/components/PlayerDetailView.d.ts +0 -26
- package/dist/tui/components/PlayerDetailView.js +0 -118
- package/dist/tui/components/PromptArea.d.ts +0 -50
- package/dist/tui/components/PromptArea.js +0 -303
- package/dist/tui/components/RecruitWizard.d.ts +0 -17
- package/dist/tui/components/RecruitWizard.js +0 -221
- package/dist/tui/components/RestoreConfirmModal.d.ts +0 -18
- package/dist/tui/components/RestoreConfirmModal.js +0 -71
- package/dist/tui/components/ScheduleWizard.d.ts +0 -19
- package/dist/tui/components/ScheduleWizard.js +0 -259
- package/dist/tui/components/Splash.d.ts +0 -23
- package/dist/tui/components/Splash.js +0 -221
- package/dist/tui/components/StatusBar.d.ts +0 -48
- package/dist/tui/components/StatusBar.js +0 -128
- package/dist/tui/components/StatusOverlay.d.ts +0 -15
- package/dist/tui/components/StatusOverlay.js +0 -76
- package/dist/tui/components/TitleBar.d.ts +0 -10
- package/dist/tui/components/TitleBar.js +0 -21
- package/dist/tui/index.d.ts +0 -15
- package/dist/tui/index.js +0 -162
- package/dist/tui/ink-context.d.ts +0 -18
- package/dist/tui/ink-context.js +0 -59
- package/dist/tui/ink-loader.d.ts +0 -26
- package/dist/tui/ink-loader.js +0 -42
- package/dist/tui/removed-commands.d.ts +0 -9
- package/dist/tui/removed-commands.js +0 -22
- package/dist/tui/sse-handler.d.ts +0 -52
- package/dist/tui/sse-handler.js +0 -157
- package/dist/tui/store.d.ts +0 -598
- package/dist/tui/store.js +0 -753
- package/dist/tui/utils/format.d.ts +0 -56
- package/dist/tui/utils/format.js +0 -155
- package/dist/tui/utils/fullscreen.d.ts +0 -23
- package/dist/tui/utils/fullscreen.js +0 -71
- package/dist/tui/utils/history.d.ts +0 -10
- package/dist/tui/utils/history.js +0 -85
- package/dist/tui/utils/platform.d.ts +0 -45
- package/dist/tui/utils/platform.js +0 -258
- package/dist/tui/utils/theme.d.ts +0 -21
- package/dist/tui/utils/theme.js +0 -24
|
@@ -34,9 +34,10 @@ export interface SearchAttributeCarrier {
|
|
|
34
34
|
*
|
|
35
35
|
* T0.5 (#747): the read-only metadata fields (`gitRoot`, `playerType`,
|
|
36
36
|
* `isConductor`, plus `part`) migrated from search attributes to the workflow
|
|
37
|
-
* memo. The
|
|
38
|
-
*
|
|
39
|
-
*
|
|
37
|
+
* memo. The memo readers below are now memo-only — #788 pruned the legacy-SA
|
|
38
|
+
* fallback, since the 2.0 clean cutover (guarded by #786) leaves no pre-v1.8
|
|
39
|
+
* SA-only run for a 2.0 worker to read. This file is the single choke point
|
|
40
|
+
* for those reads.
|
|
40
41
|
*/
|
|
41
42
|
export interface WorkflowMetaCarrier extends SearchAttributeCarrier {
|
|
42
43
|
memo?: Record<string, unknown>;
|
|
@@ -44,7 +45,7 @@ export interface WorkflowMetaCarrier extends SearchAttributeCarrier {
|
|
|
44
45
|
/**
|
|
45
46
|
* Canonical memo key names (T0.5, #747) — single registry shared by every
|
|
46
47
|
* write site (session workflow, the five `client.workflow.start({ memo })`
|
|
47
|
-
* seeds) and the
|
|
48
|
+
* seeds) and the memo readers below, so a key can never silently
|
|
48
49
|
* drift between writer and reader. Wire-stable: renaming a key is a
|
|
49
50
|
* breaking change (docs/WIRE-PROTOCOL.md §Workflow memo).
|
|
50
51
|
*
|
|
@@ -59,6 +60,8 @@ export declare const MEMO_KEYS: {
|
|
|
59
60
|
readonly workDir: "AgentTempoWorkDir";
|
|
60
61
|
readonly agentType: "AgentTempoAgentType";
|
|
61
62
|
readonly gitBranch: "AgentTempoGitBranch";
|
|
63
|
+
readonly protocol: "AgentTempoProtocol";
|
|
64
|
+
readonly closeReason: "AgentTempoCloseReason";
|
|
62
65
|
};
|
|
63
66
|
/**
|
|
64
67
|
* Escape a value for use in Temporal visibility query strings — strips
|
|
@@ -93,16 +96,24 @@ export declare function getSearchAttrBool(carrier: SearchAttributeCarrier, name:
|
|
|
93
96
|
export declare function getMemoString(carrier: WorkflowMetaCarrier, name: string): string | undefined;
|
|
94
97
|
/** Read a memo value as a boolean. `undefined` when absent or non-boolean. */
|
|
95
98
|
export declare function getMemoBool(carrier: WorkflowMetaCarrier, name: string): boolean | undefined;
|
|
99
|
+
/** Read a memo value as a number. `undefined` when absent or non-number. */
|
|
100
|
+
export declare function getMemoNumber(carrier: WorkflowMetaCarrier, name: string): number | undefined;
|
|
96
101
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
102
|
+
* #786 — read the 2.0 cutover protocol stamp from a workflow's memo
|
|
103
|
+
* (`AgentTempoProtocol`). Returns `undefined` for an un-stamped (1.x) workflow.
|
|
104
|
+
* The boot guard treats any value other than `PROTOCOL_VERSION` (incl.
|
|
105
|
+
* `undefined`) as un-stamped and refuses to register workers.
|
|
106
|
+
*/
|
|
107
|
+
export declare function getWorkflowProtocol(carrier: WorkflowMetaCarrier): number | undefined;
|
|
108
|
+
/**
|
|
109
|
+
* Read a string metadata field from the workflow memo.
|
|
99
110
|
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
111
|
+
* 2.0 (#788): memo-only. The legacy search-attribute fallback is gone — the
|
|
112
|
+
* A2 clean cutover (guarded by #786) means no pre-v1.8 SA-only run survives
|
|
113
|
+
* for a 2.0 worker to read, so every metadata field now lives in the memo.
|
|
103
114
|
*/
|
|
104
115
|
export declare function getWorkflowMetaString(carrier: WorkflowMetaCarrier, name: string): string | undefined;
|
|
105
|
-
/**
|
|
116
|
+
/** Read a boolean metadata field from the workflow memo (2.0: memo-only — #788). */
|
|
106
117
|
export declare function getWorkflowMetaBool(carrier: WorkflowMetaCarrier, name: string): boolean | undefined;
|
|
107
118
|
/**
|
|
108
119
|
* Read the attachment phase from `AgentTempoAttachmentState`.
|
|
@@ -123,19 +134,18 @@ export declare function getAttachmentPhase(carrier: SearchAttributeCarrier): Att
|
|
|
123
134
|
*/
|
|
124
135
|
export declare function getEnsembleName(carrier: SearchAttributeCarrier): string | undefined;
|
|
125
136
|
/**
|
|
126
|
-
* Read the conductor flag
|
|
127
|
-
*
|
|
137
|
+
* Read the conductor flag from memo `AgentTempoIsConductor` (T0.5; memo-only
|
|
138
|
+
* after the #788 legacy-SA prune).
|
|
128
139
|
*
|
|
129
|
-
* Returns `undefined` when absent
|
|
130
|
-
*
|
|
140
|
+
* Returns `undefined` when absent (e.g. transiently un-indexed after a
|
|
141
|
+
* conductor spawn). Callers wanting the pre-#178 workflow-id-suffix
|
|
131
142
|
* fallback (`endsWith('-conductor')`) should apply it on `undefined`.
|
|
132
143
|
*/
|
|
133
144
|
export declare function getIsConductor(carrier: WorkflowMetaCarrier): boolean | undefined;
|
|
134
145
|
/**
|
|
135
|
-
* Read the player type
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
* `undefined`.
|
|
146
|
+
* Read the player type from memo `AgentTempoPlayerType` (T0.5; memo-only
|
|
147
|
+
* after the #788 legacy-SA prune). Callers keep their existing
|
|
148
|
+
* workflow-id-suffix fallback (`endsWith('-maestro')`) on `undefined`.
|
|
139
149
|
*/
|
|
140
150
|
export declare function getPlayerType(carrier: WorkflowMetaCarrier): string | undefined;
|
|
141
151
|
/**
|
|
@@ -6,6 +6,8 @@ exports.getSearchAttrString = getSearchAttrString;
|
|
|
6
6
|
exports.getSearchAttrBool = getSearchAttrBool;
|
|
7
7
|
exports.getMemoString = getMemoString;
|
|
8
8
|
exports.getMemoBool = getMemoBool;
|
|
9
|
+
exports.getMemoNumber = getMemoNumber;
|
|
10
|
+
exports.getWorkflowProtocol = getWorkflowProtocol;
|
|
9
11
|
exports.getWorkflowMetaString = getWorkflowMetaString;
|
|
10
12
|
exports.getWorkflowMetaBool = getWorkflowMetaBool;
|
|
11
13
|
exports.getAttachmentPhase = getAttachmentPhase;
|
|
@@ -16,7 +18,7 @@ exports.getPart = getPart;
|
|
|
16
18
|
/**
|
|
17
19
|
* Canonical memo key names (T0.5, #747) — single registry shared by every
|
|
18
20
|
* write site (session workflow, the five `client.workflow.start({ memo })`
|
|
19
|
-
* seeds) and the
|
|
21
|
+
* seeds) and the memo readers below, so a key can never silently
|
|
20
22
|
* drift between writer and reader. Wire-stable: renaming a key is a
|
|
21
23
|
* breaking change (docs/WIRE-PROTOCOL.md §Workflow memo).
|
|
22
24
|
*
|
|
@@ -34,6 +36,22 @@ exports.MEMO_KEYS = {
|
|
|
34
36
|
workDir: 'AgentTempoWorkDir',
|
|
35
37
|
agentType: 'AgentTempoAgentType',
|
|
36
38
|
gitBranch: 'AgentTempoGitBranch',
|
|
39
|
+
// #786 — 2.0 cutover protocol stamp. A NUMBER memo (`PROTOCOL_VERSION`) written
|
|
40
|
+
// on every 2.0-created workflow's start input + memo. The daemon boot guard
|
|
41
|
+
// reads it straight off `workflow.list()` results (memo IS returned there) to
|
|
42
|
+
// refuse booting against un-stamped 1.x Running runs — no per-workflow query.
|
|
43
|
+
// Memo, not a search attribute: avoids a 6th Keyword (the #747 SA-diet keeps
|
|
44
|
+
// us at 5/10) and needs no operator registration. See constants.PROTOCOL_VERSION.
|
|
45
|
+
protocol: 'AgentTempoProtocol',
|
|
46
|
+
// #704 — typed terminal close-reason stamped on a workflow's memo when it
|
|
47
|
+
// COMPLETEs via `destroy` (`'destroyed'`) or the booting attach-timeout
|
|
48
|
+
// watchdog (`'boot-timeout'`). Survives completion and is readable via
|
|
49
|
+
// `describe().memo`. The bootstrap orphan-guard (`server.ts`) reads it to
|
|
50
|
+
// self-tombstone a late-launching orphan process whose run was cancelled,
|
|
51
|
+
// discriminated by the running-run × close-reason PAIR. A string memo (not a
|
|
52
|
+
// search attribute): avoids a 6th Keyword (the #747 SA-diet keeps us at 5/10)
|
|
53
|
+
// and needs no operator registration.
|
|
54
|
+
closeReason: 'AgentTempoCloseReason',
|
|
37
55
|
};
|
|
38
56
|
/**
|
|
39
57
|
* Escape a value for use in Temporal visibility query strings — strips
|
|
@@ -86,7 +104,7 @@ function getSearchAttrBool(carrier, name) {
|
|
|
86
104
|
}
|
|
87
105
|
return undefined;
|
|
88
106
|
}
|
|
89
|
-
// ── T0.5 (#747) — memo readers
|
|
107
|
+
// ── T0.5 (#747) — memo readers (memo-only after the #788 legacy-SA prune) ──
|
|
90
108
|
/** Read a memo value as a string. `undefined` when absent or non-string. */
|
|
91
109
|
function getMemoString(carrier, name) {
|
|
92
110
|
const v = carrier.memo?.[name];
|
|
@@ -97,20 +115,33 @@ function getMemoBool(carrier, name) {
|
|
|
97
115
|
const v = carrier.memo?.[name];
|
|
98
116
|
return typeof v === 'boolean' ? v : undefined;
|
|
99
117
|
}
|
|
118
|
+
/** Read a memo value as a number. `undefined` when absent or non-number. */
|
|
119
|
+
function getMemoNumber(carrier, name) {
|
|
120
|
+
const v = carrier.memo?.[name];
|
|
121
|
+
return typeof v === 'number' ? v : undefined;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* #786 — read the 2.0 cutover protocol stamp from a workflow's memo
|
|
125
|
+
* (`AgentTempoProtocol`). Returns `undefined` for an un-stamped (1.x) workflow.
|
|
126
|
+
* The boot guard treats any value other than `PROTOCOL_VERSION` (incl.
|
|
127
|
+
* `undefined`) as un-stamped and refuses to register workers.
|
|
128
|
+
*/
|
|
129
|
+
function getWorkflowProtocol(carrier) {
|
|
130
|
+
return getMemoNumber(carrier, exports.MEMO_KEYS.protocol);
|
|
131
|
+
}
|
|
100
132
|
/**
|
|
101
|
-
*
|
|
102
|
-
* v1.8-sa-diet patch), legacy search attribute as fallback (older runs).
|
|
133
|
+
* Read a string metadata field from the workflow memo.
|
|
103
134
|
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
135
|
+
* 2.0 (#788): memo-only. The legacy search-attribute fallback is gone — the
|
|
136
|
+
* A2 clean cutover (guarded by #786) means no pre-v1.8 SA-only run survives
|
|
137
|
+
* for a 2.0 worker to read, so every metadata field now lives in the memo.
|
|
107
138
|
*/
|
|
108
139
|
function getWorkflowMetaString(carrier, name) {
|
|
109
|
-
return getMemoString(carrier, name)
|
|
140
|
+
return getMemoString(carrier, name);
|
|
110
141
|
}
|
|
111
|
-
/**
|
|
142
|
+
/** Read a boolean metadata field from the workflow memo (2.0: memo-only — #788). */
|
|
112
143
|
function getWorkflowMetaBool(carrier, name) {
|
|
113
|
-
return getMemoBool(carrier, name)
|
|
144
|
+
return getMemoBool(carrier, name);
|
|
114
145
|
}
|
|
115
146
|
// ── Typed wrappers for agent-tempo's custom search attributes ──
|
|
116
147
|
//
|
|
@@ -140,21 +171,20 @@ function getEnsembleName(carrier) {
|
|
|
140
171
|
return getSearchAttrString(carrier, 'AgentTempoEnsemble');
|
|
141
172
|
}
|
|
142
173
|
/**
|
|
143
|
-
* Read the conductor flag
|
|
144
|
-
*
|
|
174
|
+
* Read the conductor flag from memo `AgentTempoIsConductor` (T0.5; memo-only
|
|
175
|
+
* after the #788 legacy-SA prune).
|
|
145
176
|
*
|
|
146
|
-
* Returns `undefined` when absent
|
|
147
|
-
*
|
|
177
|
+
* Returns `undefined` when absent (e.g. transiently un-indexed after a
|
|
178
|
+
* conductor spawn). Callers wanting the pre-#178 workflow-id-suffix
|
|
148
179
|
* fallback (`endsWith('-conductor')`) should apply it on `undefined`.
|
|
149
180
|
*/
|
|
150
181
|
function getIsConductor(carrier) {
|
|
151
182
|
return getWorkflowMetaBool(carrier, exports.MEMO_KEYS.isConductor);
|
|
152
183
|
}
|
|
153
184
|
/**
|
|
154
|
-
* Read the player type
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
* `undefined`.
|
|
185
|
+
* Read the player type from memo `AgentTempoPlayerType` (T0.5; memo-only
|
|
186
|
+
* after the #788 legacy-SA prune). Callers keep their existing
|
|
187
|
+
* workflow-id-suffix fallback (`endsWith('-maestro')`) on `undefined`.
|
|
158
188
|
*/
|
|
159
189
|
function getPlayerType(carrier) {
|
|
160
190
|
return getWorkflowMetaString(carrier, exports.MEMO_KEYS.playerType);
|
|
@@ -100,6 +100,22 @@ export declare const VISIBILITY_DEADLINES_MS: {
|
|
|
100
100
|
* enough to amortize partial scans across many sweeps.
|
|
101
101
|
*/
|
|
102
102
|
readonly orphanQueryCleanup: 30000;
|
|
103
|
+
/**
|
|
104
|
+
* #786 — `checkProtocolGuard` daemon boot scan. Walks every Running
|
|
105
|
+
* agent-tempo workflow (the 4 workflow types) reading only the
|
|
106
|
+
* `AgentTempoProtocol` memo straight off the visibility page — NO
|
|
107
|
+
* per-workflow query, so it's pure page iteration and far cheaper than
|
|
108
|
+
* the orphan scan. 30s is generous headroom for a large-but-healthy
|
|
109
|
+
* namespace (page-streaming even thousands of rows completes in
|
|
110
|
+
* seconds) while still bounding a wedged visibility backend.
|
|
111
|
+
*
|
|
112
|
+
* **Load-bearing: this budget is FAIL-CLOSED.** A timeout here does NOT
|
|
113
|
+
* yield a best-effort partial — the guard treats an unfinished scan as
|
|
114
|
+
* "couldn't prove the cutover is clean" and REFUSES to boot (the #845
|
|
115
|
+
* partial-scan lesson: a 2.0 worker that replays a 1.x history corrupts
|
|
116
|
+
* deterministically, so an unverified scan must never be read as clean).
|
|
117
|
+
*/
|
|
118
|
+
readonly protocolGuardBoot: 30000;
|
|
103
119
|
};
|
|
104
120
|
export type VisibilitySite = keyof typeof VISIBILITY_DEADLINES_MS;
|
|
105
121
|
/**
|
|
@@ -55,6 +55,22 @@ exports.VISIBILITY_DEADLINES_MS = {
|
|
|
55
55
|
* enough to amortize partial scans across many sweeps.
|
|
56
56
|
*/
|
|
57
57
|
orphanQueryCleanup: 30_000,
|
|
58
|
+
/**
|
|
59
|
+
* #786 — `checkProtocolGuard` daemon boot scan. Walks every Running
|
|
60
|
+
* agent-tempo workflow (the 4 workflow types) reading only the
|
|
61
|
+
* `AgentTempoProtocol` memo straight off the visibility page — NO
|
|
62
|
+
* per-workflow query, so it's pure page iteration and far cheaper than
|
|
63
|
+
* the orphan scan. 30s is generous headroom for a large-but-healthy
|
|
64
|
+
* namespace (page-streaming even thousands of rows completes in
|
|
65
|
+
* seconds) while still bounding a wedged visibility backend.
|
|
66
|
+
*
|
|
67
|
+
* **Load-bearing: this budget is FAIL-CLOSED.** A timeout here does NOT
|
|
68
|
+
* yield a best-effort partial — the guard treats an unfinished scan as
|
|
69
|
+
* "couldn't prove the cutover is clean" and REFUSES to boot (the #845
|
|
70
|
+
* partial-scan lesson: a 2.0 worker that replays a 1.x history corrupts
|
|
71
|
+
* deterministically, so an unverified scan must never be read as clean).
|
|
72
|
+
*/
|
|
73
|
+
protocolGuardBoot: 30_000,
|
|
58
74
|
};
|
|
59
75
|
/**
|
|
60
76
|
* Thrown by {@link iterateWithDeadline} when the per-iterator deadline
|
|
@@ -172,19 +172,6 @@ export declare const maestroEnsemblesQuery: import("@temporalio/workflow").Query
|
|
|
172
172
|
export declare const maestroPlayersByEnsembleQuery: import("@temporalio/workflow").QueryDefinition<Record<string, MaestroPlayerInfo[]>, [], string>;
|
|
173
173
|
/** Get recent messages across all ensembles (ring buffer, max 500). */
|
|
174
174
|
export declare const maestroRecentMessagesQuery: import("@temporalio/workflow").QueryDefinition<MaestroRelayMessage[], [], string>;
|
|
175
|
-
/**
|
|
176
|
-
* #274 — the `hostname → HostProfile` map maintained by the global maestro.
|
|
177
|
-
*
|
|
178
|
-
* Returned as a plain `Record<string, HostProfile>` (not a `Map`) so the
|
|
179
|
-
* default Temporal payload converter serializes it without a codec tweak.
|
|
180
|
-
* The `src/utils/hosts.ts` join helper consumes this and reconstructs a
|
|
181
|
-
* `Map`-shaped view at the consumer boundary if callers find it useful.
|
|
182
|
-
*
|
|
183
|
-
* Consumers MUST treat the returned profiles as opaque beyond the
|
|
184
|
-
* `hostname` field — per-field validation happens at the join site, not
|
|
185
|
-
* at query time.
|
|
186
|
-
*/
|
|
187
|
-
export declare const hostProfilesQuery: import("@temporalio/workflow").QueryDefinition<Record<string, HostProfile>, [], string>;
|
|
188
175
|
/**
|
|
189
176
|
* #280 — combined existence + profiles query.
|
|
190
177
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.maestroGlobalSendCommandUpdate = exports.maestroFetchConductorHistoryUpdate = exports.maestroFetchPlayerMessagesUpdate = exports.maestroSendMessageUpdate = exports.hostProfilesWithExistenceQuery = exports.
|
|
3
|
+
exports.maestroGlobalSendCommandUpdate = exports.maestroFetchConductorHistoryUpdate = exports.maestroFetchPlayerMessagesUpdate = exports.maestroSendMessageUpdate = exports.hostProfilesWithExistenceQuery = exports.maestroRecentMessagesQuery = exports.maestroPlayersByEnsembleQuery = exports.maestroEnsemblesQuery = exports.hostProfileSignal = exports.maestroNotifyMessageSignal = exports.maestroGetAnswerQuery = exports.maestroPostAnswerUpdate = exports.coatCheckEvictUpdate = exports.coatCheckListQuery = exports.coatCheckGetUpdate = exports.coatCheckPutUpdate = exports.maestroSendCommandUpdate = exports.getTempoSeriesQuery = exports.getCurrentBpmQuery = exports.getEnsembleStartTimeQuery = exports.getEnsembleDescriptionQuery = exports.maestroEnsembleChatQuery = exports.maestroPendingCommandsQuery = exports.maestroPausedQuery = exports.maestroEventsQuery = exports.maestroPlayersQuery = exports.setEnsembleDescriptionSignal = exports.maestroSetPausedSignal = exports.maestroShutdownSignal = exports.ZERO_CHAT_HIGH_WATER = void 0;
|
|
4
4
|
const workflow_1 = require("@temporalio/workflow");
|
|
5
5
|
var types_1 = require("../types");
|
|
6
6
|
Object.defineProperty(exports, "ZERO_CHAT_HIGH_WATER", { enumerable: true, get: function () { return types_1.ZERO_CHAT_HIGH_WATER; } });
|
|
@@ -127,19 +127,11 @@ exports.maestroEnsemblesQuery = (0, workflow_1.defineQuery)('maestroEnsembles');
|
|
|
127
127
|
exports.maestroPlayersByEnsembleQuery = (0, workflow_1.defineQuery)('maestroPlayersByEnsemble');
|
|
128
128
|
/** Get recent messages across all ensembles (ring buffer, max 500). */
|
|
129
129
|
exports.maestroRecentMessagesQuery = (0, workflow_1.defineQuery)('maestroRecentMessages');
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
* The `src/utils/hosts.ts` join helper consumes this and reconstructs a
|
|
136
|
-
* `Map`-shaped view at the consumer boundary if callers find it useful.
|
|
137
|
-
*
|
|
138
|
-
* Consumers MUST treat the returned profiles as opaque beyond the
|
|
139
|
-
* `hostname` field — per-field validation happens at the join site, not
|
|
140
|
-
* at query time.
|
|
141
|
-
*/
|
|
142
|
-
exports.hostProfilesQuery = (0, workflow_1.defineQuery)('hostProfiles');
|
|
130
|
+
// 2.0 (#788): the legacy `hostProfilesQuery` ('hostProfiles') was removed —
|
|
131
|
+
// superseded by `hostProfilesWithExistenceQuery` below, which folds the
|
|
132
|
+
// running-check + profiles into a single round-trip. Every consumer uses the
|
|
133
|
+
// WithExistence form. Consumers MUST still treat the returned profiles as
|
|
134
|
+
// opaque beyond the `hostname` field (validation happens at the join site).
|
|
143
135
|
/**
|
|
144
136
|
* #280 — combined existence + profiles query.
|
|
145
137
|
*
|
|
@@ -4,6 +4,8 @@ exports.resolveRefreshIntervalMs = resolveRefreshIntervalMs;
|
|
|
4
4
|
exports.agentMaestroWorkflow = agentMaestroWorkflow;
|
|
5
5
|
exports.agentGlobalMaestroWorkflow = agentGlobalMaestroWorkflow;
|
|
6
6
|
const workflow_1 = require("@temporalio/workflow");
|
|
7
|
+
const search_attributes_1 = require("../utils/search-attributes");
|
|
8
|
+
const constants_1 = require("../constants");
|
|
7
9
|
/**
|
|
8
10
|
* Workflow-deterministic clock — mirrors the helper in `src/workflows/session.ts`.
|
|
9
11
|
*
|
|
@@ -30,7 +32,7 @@ const validation_1 = require("../utils/validation");
|
|
|
30
32
|
// ── Activity Proxies ──
|
|
31
33
|
// Only proxy activities actually used in the workflow.
|
|
32
34
|
// fetchConductorHistory is available in the activities but reserved for Phase 2 (TUI).
|
|
33
|
-
const {
|
|
35
|
+
const { refreshEnsembleStateV2, relayCommandToConductor, fetchEnsembleChat } = (0, workflow_1.proxyActivities)({
|
|
34
36
|
startToCloseTimeout: '30 seconds',
|
|
35
37
|
retry: { maximumAttempts: 3 },
|
|
36
38
|
});
|
|
@@ -79,15 +81,16 @@ const TEMPO_BPM_WINDOW_MS = 60_000;
|
|
|
79
81
|
// Per-Ensemble Maestro (existing — unchanged)
|
|
80
82
|
// ══════════════════════════════════════════════════════════════════════════════
|
|
81
83
|
async function agentMaestroWorkflow(input) {
|
|
82
|
-
|
|
84
|
+
// #786 — 2.0 cutover protocol stamp (see constants.PROTOCOL_VERSION). Memo,
|
|
85
|
+
// re-upserted every run incl. CAN successors, so the daemon boot guard sees
|
|
86
|
+
// every Running 2.0 maestro as stamped; a 1.x maestro never runs this → its
|
|
87
|
+
// memo is undefined → guard refuses. Unconditional — #786 is first on the 2.0
|
|
88
|
+
// line, no pre-stamp v2 histories to protect.
|
|
89
|
+
(0, workflow_1.upsertMemo)({ [search_attributes_1.MEMO_KEYS.protocol]: constants_1.PROTOCOL_VERSION });
|
|
83
90
|
// T0.1 (#748) — input-driven, NOT patched-gated: pre-#748 runs have no
|
|
84
91
|
// costProfile field, so they resolve to the legacy 5s default and the V1
|
|
85
92
|
// refresh activity — identical commands on replay.
|
|
86
93
|
const cloudProfile = input.costProfile === 'cloud';
|
|
87
|
-
// T0.6 (#760) — the chat gate NEEDS a marker (unlike T0.1's V2 switch):
|
|
88
|
-
// post-#759 cloud maestros recorded chat-fetch activities on unwatched
|
|
89
|
-
// ticks, so skipping those without a marker would mismatch their replay.
|
|
90
|
-
const chatGateEnabled = (0, workflow_1.patched)('v1.8-t06-chat-gate');
|
|
91
94
|
let refreshIntervalMs = resolveRefreshIntervalMs(input, /* observersPresent */ true);
|
|
92
95
|
let players = input.players ?? [];
|
|
93
96
|
const events = input.events ?? [];
|
|
@@ -461,16 +464,16 @@ async function agentMaestroWorkflow(input) {
|
|
|
461
464
|
// activity: SA/memo-based ensemble-scoped scan + the daemon's SSE
|
|
462
465
|
// observer presence, which drives next tick's cadence (20s watched /
|
|
463
466
|
// 60s unwatched via resolveRefreshIntervalMs).
|
|
464
|
-
|
|
467
|
+
// 2.0 (#788): single refresh activity (V2). It honors the daemon cost
|
|
468
|
+
// profile internally (cloud → SA/memo scan, local → legacy scan) and
|
|
469
|
+
// returns `observersPresent`. Only the cloud profile uses presence to
|
|
470
|
+
// stretch the refresh cadence; local keeps its fixed interval.
|
|
471
|
+
const v2 = await refreshEnsembleStateV2({ ensemble: input.ensemble });
|
|
472
|
+
const newPlayers = v2.players;
|
|
473
|
+
observersPresent = v2.observersPresent;
|
|
465
474
|
if (cloudProfile) {
|
|
466
|
-
const v2 = await refreshEnsembleStateV2({ ensemble: input.ensemble });
|
|
467
|
-
newPlayers = v2.players;
|
|
468
|
-
observersPresent = v2.observersPresent;
|
|
469
475
|
refreshIntervalMs = resolveRefreshIntervalMs(input, observersPresent);
|
|
470
476
|
}
|
|
471
|
-
else {
|
|
472
|
-
newPlayers = await refreshEnsembleState(input.ensemble);
|
|
473
|
-
}
|
|
474
477
|
const nowDate = workflowNow();
|
|
475
478
|
const now = nowDate.toISOString();
|
|
476
479
|
const nowMs = nowDate.getTime();
|
|
@@ -563,14 +566,10 @@ async function agentMaestroWorkflow(input) {
|
|
|
563
566
|
// the maestro's cache — so an unwatched ensemble loses nothing;
|
|
564
567
|
// staleness inherits the accepted T0.1 cadence-stretch contract (the
|
|
565
568
|
// first watched tick re-fetches from the durable high-water marks).
|
|
566
|
-
//
|
|
567
|
-
|
|
568
|
-
// would be a replay command mismatch (input-driven gating only
|
|
569
|
-
// protects pre-#748 runs — verified, contra the initial "no marker
|
|
570
|
-
// expected" estimate).
|
|
571
|
-
if ((0, workflow_1.patched)('v0.19-ensemble-chat')) {
|
|
569
|
+
// (2.0: was patched()-gated for 1.x replay determinism; now unconditional — #787.)
|
|
570
|
+
{
|
|
572
571
|
// Unwatched cloud tick → skip; cache + high-water marks stay untouched.
|
|
573
|
-
const skipChatThisTick =
|
|
572
|
+
const skipChatThisTick = cloudProfile && !observersPresent;
|
|
574
573
|
if (!skipChatThisTick) {
|
|
575
574
|
try {
|
|
576
575
|
const chatResult = await fetchEnsembleChat({
|
|
@@ -710,7 +709,10 @@ const globalActivities = (0, workflow_1.proxyActivities)({
|
|
|
710
709
|
retry: { maximumAttempts: 3 },
|
|
711
710
|
});
|
|
712
711
|
async function agentGlobalMaestroWorkflow(input) {
|
|
713
|
-
|
|
712
|
+
// #786 — 2.0 cutover protocol stamp (the namespace-wide global maestro is
|
|
713
|
+
// stamped too, so the boot guard's scan never sees it as un-stamped). See
|
|
714
|
+
// constants.PROTOCOL_VERSION + agentMaestroWorkflow's stamp note.
|
|
715
|
+
(0, workflow_1.upsertMemo)({ [search_attributes_1.MEMO_KEYS.protocol]: constants_1.PROTOCOL_VERSION });
|
|
714
716
|
// T0.1 (#748) — input-driven (see agentMaestroWorkflow): pre-#748 runs
|
|
715
717
|
// have no costProfile field → legacy 5s + V1 refresh, identical commands.
|
|
716
718
|
const cloudProfile = input.costProfile === 'cloud';
|
|
@@ -774,8 +776,6 @@ async function agentGlobalMaestroWorkflow(input) {
|
|
|
774
776
|
(0, workflow_1.setHandler)(maestro_signals_1.maestroRecentMessagesQuery, () => recentMessages);
|
|
775
777
|
(0, workflow_1.setHandler)(maestro_signals_1.maestroEventsQuery, () => events);
|
|
776
778
|
(0, workflow_1.setHandler)(maestro_signals_1.maestroPendingCommandsQuery, () => pendingCommands);
|
|
777
|
-
// Return a defensive copy so callers can't mutate workflow state.
|
|
778
|
-
(0, workflow_1.setHandler)(maestro_signals_1.hostProfilesQuery, () => ({ ...hostProfiles }));
|
|
779
779
|
// #280 — combined query: reaching this handler proves the workflow is
|
|
780
780
|
// running, so `exists` is always `true` here. Callers infer "missing"
|
|
781
781
|
// by catching transport-level errors (workflow not found, etc.).
|
|
@@ -889,15 +889,10 @@ async function agentGlobalMaestroWorkflow(input) {
|
|
|
889
889
|
let observersPresent = true;
|
|
890
890
|
for (const ensemble of knownEnsembles) {
|
|
891
891
|
try {
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
observersPresent = v2.observersPresent;
|
|
897
|
-
}
|
|
898
|
-
else {
|
|
899
|
-
newPlayers = await globalActivities.refreshEnsembleState(ensemble);
|
|
900
|
-
}
|
|
892
|
+
// 2.0 (#788): single refresh activity (V2) — see the per-ensemble note above.
|
|
893
|
+
const v2 = await globalActivities.refreshEnsembleStateV2({ ensemble });
|
|
894
|
+
const newPlayers = v2.players;
|
|
895
|
+
observersPresent = v2.observersPresent;
|
|
901
896
|
const oldPlayers = playersByEnsemble[ensemble] ?? [];
|
|
902
897
|
const now = new Date().toISOString();
|
|
903
898
|
// Diff snapshots to generate events
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.agentSchedulerWorkflow = agentSchedulerWorkflow;
|
|
4
4
|
const workflow_1 = require("@temporalio/workflow");
|
|
5
|
+
const search_attributes_1 = require("../utils/search-attributes");
|
|
6
|
+
const constants_1 = require("../constants");
|
|
5
7
|
const scheduler_signals_1 = require("./scheduler-signals");
|
|
6
8
|
const { fireSchedule, computeNextCronFire } = (0, workflow_1.proxyActivities)({
|
|
7
9
|
startToCloseTimeout: '30 seconds',
|
|
@@ -10,6 +12,10 @@ const { fireSchedule, computeNextCronFire } = (0, workflow_1.proxyActivities)({
|
|
|
10
12
|
/** Default self-termination grace period — 30 000 ms (see §scheduler "empty self-terminate"). */
|
|
11
13
|
const DEFAULT_GRACE_PERIOD_MS = 30_000;
|
|
12
14
|
async function agentSchedulerWorkflow(input) {
|
|
15
|
+
// #786 — 2.0 cutover protocol stamp (see constants.PROTOCOL_VERSION). Memo,
|
|
16
|
+
// re-upserted every run incl. CAN, so the boot guard sees every Running 2.0
|
|
17
|
+
// scheduler as stamped; a 1.x scheduler never runs this → guard refuses.
|
|
18
|
+
(0, workflow_1.upsertMemo)({ [search_attributes_1.MEMO_KEYS.protocol]: constants_1.PROTOCOL_VERSION });
|
|
13
19
|
let entries = input.entries ?? [];
|
|
14
20
|
let dirty = false; // flag to wake the loop when signals arrive
|
|
15
21
|
let schedulerPaused = input.paused ?? false;
|
|
@@ -126,7 +132,7 @@ async function agentSchedulerWorkflow(input) {
|
|
|
126
132
|
else if (entry.type === 'interval' && entry.interval) {
|
|
127
133
|
entry.nextFireAt = new Date(Date.now() + entry.interval).toISOString();
|
|
128
134
|
}
|
|
129
|
-
else if (
|
|
135
|
+
else if (entry.type === 'cron' && entry.cronExpression) {
|
|
130
136
|
const nextFire = await computeNextCronFire({
|
|
131
137
|
cronExpression: entry.cronExpression,
|
|
132
138
|
timezone: entry.timezone,
|