agent-tempo 1.3.1 → 1.4.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/CLAUDE.md +39 -5
- package/README.md +6 -2
- package/dashboard/dist/assets/{index-D6Xyje_n.js → index-jmYe6rmS.js} +2 -2
- package/dashboard/dist/assets/index-jmYe6rmS.js.map +1 -0
- package/dashboard/dist/index.html +1 -1
- package/dashboard/package.json +1 -1
- package/dist/activities/outbox.d.ts +30 -1
- package/dist/activities/outbox.js +96 -3
- package/dist/adapters/base.js +5 -0
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.js +7 -0
- package/dist/adapters/pi/adapter.d.ts +2 -0
- package/dist/adapters/pi/adapter.js +43 -0
- package/dist/adapters/pi/index.d.ts +16 -0
- package/dist/adapters/pi/index.js +10 -0
- package/dist/client/core.js +9 -2
- package/dist/client/interface.d.ts +6 -0
- package/dist/config.d.ts +79 -0
- package/dist/config.js +74 -0
- package/dist/daemon.js +32 -1
- package/dist/http/aggregate.d.ts +22 -1
- package/dist/http/aggregate.js +41 -0
- package/dist/http/auth.d.ts +94 -8
- package/dist/http/auth.js +93 -9
- package/dist/http/body.d.ts +4 -1
- package/dist/http/body.js +6 -3
- package/dist/http/event-bus.js +1 -0
- package/dist/http/event-types.d.ts +34 -2
- package/dist/http/event-types.js +1 -0
- package/dist/http/gate-audit.d.ts +12 -0
- package/dist/http/gate-audit.js +95 -0
- package/dist/http/gate-registry.d.ts +167 -0
- package/dist/http/gate-registry.js +163 -0
- package/dist/http/gate-routes.d.ts +48 -0
- package/dist/http/gate-routes.js +102 -0
- package/dist/http/ingest-registry.d.ts +30 -0
- package/dist/http/ingest-registry.js +108 -0
- package/dist/http/inner-loop-routes.d.ts +66 -0
- package/dist/http/inner-loop-routes.js +182 -0
- package/dist/http/inner-loop.d.ts +92 -0
- package/dist/http/inner-loop.js +155 -0
- package/dist/http/server.d.ts +38 -3
- package/dist/http/server.js +211 -6
- package/dist/http/snapshot.d.ts +6 -0
- package/dist/http/snapshot.js +6 -0
- package/dist/pi/cue-pump.d.ts +61 -0
- package/dist/pi/cue-pump.js +95 -0
- package/dist/pi/extension.d.ts +45 -0
- package/dist/pi/extension.js +407 -0
- package/dist/pi/gate-client.d.ts +54 -0
- package/dist/pi/gate-client.js +136 -0
- package/dist/pi/headless.d.ts +85 -0
- package/dist/pi/headless.js +250 -0
- package/dist/pi/index.d.ts +28 -0
- package/dist/pi/index.js +43 -0
- package/dist/pi/inner-loop-client.d.ts +67 -0
- package/dist/pi/inner-loop-client.js +164 -0
- package/dist/pi/inner-loop-publisher.d.ts +187 -0
- package/dist/pi/inner-loop-publisher.js +236 -0
- package/dist/pi/lazy-proxy.d.ts +37 -0
- package/dist/pi/lazy-proxy.js +55 -0
- package/dist/pi/mission-control/actions.d.ts +48 -0
- package/dist/pi/mission-control/actions.js +98 -0
- package/dist/pi/mission-control/board.d.ts +88 -0
- package/dist/pi/mission-control/board.js +141 -0
- package/dist/pi/mission-control/extension.d.ts +51 -0
- package/dist/pi/mission-control/extension.js +330 -0
- package/dist/pi/mission-control/index.d.ts +15 -0
- package/dist/pi/mission-control/index.js +32 -0
- package/dist/pi/mission-control/inner-tail.d.ts +48 -0
- package/dist/pi/mission-control/inner-tail.js +76 -0
- package/dist/pi/mission-control/pi-ui.d.ts +43 -0
- package/dist/pi/mission-control/pi-ui.js +10 -0
- package/dist/pi/mission-control/render.d.ts +6 -0
- package/dist/pi/mission-control/render.js +98 -0
- package/dist/pi/phase-driver.d.ts +74 -0
- package/dist/pi/phase-driver.js +122 -0
- package/dist/pi/pi-types.d.ts +222 -0
- package/dist/pi/pi-types.js +21 -0
- package/dist/pi/probe.d.ts +99 -0
- package/dist/pi/probe.js +179 -0
- package/dist/pi/render-tools.d.ts +17 -0
- package/dist/pi/render-tools.js +56 -0
- package/dist/pi/reset-pump.d.ts +47 -0
- package/dist/pi/reset-pump.js +85 -0
- package/dist/pi/session-seed.d.ts +74 -0
- package/dist/pi/session-seed.js +103 -0
- package/dist/pi/tool-capability.d.ts +60 -0
- package/dist/pi/tool-capability.js +156 -0
- package/dist/pi/workflow-client.d.ts +158 -0
- package/dist/pi/workflow-client.js +289 -0
- package/dist/pi/zod-to-typebox.d.ts +74 -0
- package/dist/pi/zod-to-typebox.js +191 -0
- package/dist/server-tools.d.ts +2 -0
- package/dist/server-tools.js +50 -46
- package/dist/spawn.d.ts +55 -0
- package/dist/spawn.js +72 -0
- package/dist/tools/agent-types.d.ts +2 -2
- package/dist/tools/agent-types.js +22 -17
- package/dist/tools/attachment-info.d.ts +2 -2
- package/dist/tools/attachment-info.js +38 -33
- package/dist/tools/broadcast.d.ts +2 -2
- package/dist/tools/broadcast.js +69 -64
- package/dist/tools/cancel-stage.d.ts +2 -2
- package/dist/tools/cancel-stage.js +20 -15
- package/dist/tools/clear-state.d.ts +2 -2
- package/dist/tools/clear-state.js +25 -20
- package/dist/tools/coat-check-evict.d.ts +2 -2
- package/dist/tools/coat-check-evict.js +29 -24
- package/dist/tools/coat-check-get.d.ts +2 -2
- package/dist/tools/coat-check-get.js +38 -33
- package/dist/tools/coat-check-list.d.ts +2 -2
- package/dist/tools/coat-check-list.js +48 -43
- package/dist/tools/coat-check-put.d.ts +2 -2
- package/dist/tools/coat-check-put.js +38 -33
- package/dist/tools/cue.d.ts +2 -2
- package/dist/tools/cue.js +57 -52
- package/dist/tools/descriptor.d.ts +72 -0
- package/dist/tools/descriptor.js +39 -0
- package/dist/tools/destroy.d.ts +2 -2
- package/dist/tools/destroy.js +153 -148
- package/dist/tools/ensemble.d.ts +2 -2
- package/dist/tools/ensemble.js +71 -66
- package/dist/tools/evaluate-gate.d.ts +2 -2
- package/dist/tools/evaluate-gate.js +33 -27
- package/dist/tools/fetch-state.d.ts +2 -2
- package/dist/tools/fetch-state.js +42 -37
- package/dist/tools/gates.d.ts +2 -2
- package/dist/tools/gates.js +39 -34
- package/dist/tools/hosts.d.ts +2 -2
- package/dist/tools/hosts.js +25 -20
- package/dist/tools/listen.d.ts +2 -2
- package/dist/tools/listen.js +23 -18
- package/dist/tools/load-lineup.d.ts +2 -2
- package/dist/tools/load-lineup.js +324 -319
- package/dist/tools/migrate.d.ts +2 -2
- package/dist/tools/migrate.js +45 -40
- package/dist/tools/pause.d.ts +2 -2
- package/dist/tools/pause.js +34 -29
- package/dist/tools/play.d.ts +2 -2
- package/dist/tools/play.js +53 -48
- package/dist/tools/quality-gate.d.ts +2 -2
- package/dist/tools/quality-gate.js +26 -21
- package/dist/tools/recall.d.ts +2 -2
- package/dist/tools/recall.js +32 -27
- package/dist/tools/recruit.d.ts +2 -2
- package/dist/tools/recruit.js +340 -256
- package/dist/tools/release.d.ts +2 -2
- package/dist/tools/release.js +85 -80
- package/dist/tools/report.d.ts +2 -2
- package/dist/tools/report.js +28 -23
- package/dist/tools/reset.d.ts +3 -0
- package/dist/tools/reset.js +51 -0
- package/dist/tools/restart.d.ts +2 -2
- package/dist/tools/restart.js +51 -46
- package/dist/tools/restore.d.ts +2 -2
- package/dist/tools/restore.js +76 -71
- package/dist/tools/save-lineup.d.ts +2 -2
- package/dist/tools/save-lineup.js +32 -27
- package/dist/tools/save-state.d.ts +2 -2
- package/dist/tools/save-state.js +31 -26
- package/dist/tools/schedule.d.ts +2 -2
- package/dist/tools/schedule.js +133 -128
- package/dist/tools/schedules.d.ts +2 -2
- package/dist/tools/schedules.js +41 -36
- package/dist/tools/set-ensemble-description.d.ts +2 -2
- package/dist/tools/set-ensemble-description.js +26 -21
- package/dist/tools/set-name.d.ts +2 -2
- package/dist/tools/set-name.js +38 -33
- package/dist/tools/set-part.d.ts +2 -2
- package/dist/tools/set-part.js +20 -15
- package/dist/tools/shutdown.d.ts +2 -2
- package/dist/tools/shutdown.js +39 -34
- package/dist/tools/stage.d.ts +2 -2
- package/dist/tools/stage.js +28 -23
- package/dist/tools/stages.d.ts +2 -2
- package/dist/tools/stages.js +36 -31
- package/dist/tools/unschedule.d.ts +2 -2
- package/dist/tools/unschedule.js +30 -25
- package/dist/tools/who-am-i.d.ts +2 -2
- package/dist/tools/who-am-i.js +36 -31
- package/dist/tools/worktree.d.ts +2 -2
- package/dist/tools/worktree.js +134 -129
- package/dist/tui/index.js +6 -6
- package/dist/types.d.ts +47 -2
- package/dist/types.js +1 -1
- package/dist/utils/default-part.js +1 -0
- package/dist/utils/sdk-probe.d.ts +23 -0
- package/dist/utils/sdk-probe.js +46 -7
- package/dist/worker.d.ts +3 -1
- package/dist/worker.js +6 -2
- package/dist/workflows/session.js +70 -2
- package/dist/workflows/signals.d.ts +32 -2
- package/dist/workflows/signals.js +25 -2
- package/package.json +4 -1
- package/workflow-bundle.js +97 -6
- package/dashboard/dist/assets/index-D6Xyje_n.js.map +0 -1
- package/dist/tools/helpers.d.ts +0 -21
- package/dist/tools/helpers.js +0 -25
package/dist/tools/release.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
1
|
import { Client, WorkflowHandle } from '@temporalio/client';
|
|
3
2
|
import { Config } from '../config';
|
|
4
|
-
|
|
3
|
+
import { type TempoToolDescriptor } from './descriptor';
|
|
4
|
+
export declare function buildReleaseTool(client: Client, config: Config, getPlayerId: () => string, handle: WorkflowHandle): TempoToolDescriptor;
|
package/dist/tools/release.js
CHANGED
|
@@ -1,98 +1,103 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.buildReleaseTool = buildReleaseTool;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const resolve_1 = require("../activities/resolve");
|
|
6
6
|
const signals_1 = require("../workflows/signals");
|
|
7
|
-
const
|
|
7
|
+
const descriptor_1 = require("./descriptor");
|
|
8
8
|
const validation_1 = require("../utils/validation");
|
|
9
|
-
function
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
try {
|
|
9
|
+
function buildReleaseTool(client, config, getPlayerId, handle) {
|
|
10
|
+
return {
|
|
11
|
+
name: 'release',
|
|
12
|
+
description: 'Release held player sessions — unlocks their outboxes and delivers deferred task messages. Without a player name, releases all held sessions.',
|
|
13
|
+
params: {
|
|
14
|
+
player: zod_1.z.string().max(validation_1.PLAYER_NAME_MAX).optional()
|
|
15
|
+
.describe('Name of a specific held player to release. Omit to release all held players.'),
|
|
16
|
+
},
|
|
17
|
+
handler: async (args) => {
|
|
18
|
+
const { player } = args;
|
|
21
19
|
if (player) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (!target) {
|
|
26
|
-
return (0, helpers_1.fail)(`No session found with name "${player}".`);
|
|
27
|
-
}
|
|
28
|
-
// Check if the session's outbox is actually locked
|
|
29
|
-
const targetHandle = client.workflow.getHandle(target.workflowId);
|
|
30
|
-
let isLocked = false;
|
|
31
|
-
try {
|
|
32
|
-
isLocked = await targetHandle.query(signals_1.outboxLockedQuery);
|
|
33
|
-
}
|
|
34
|
-
catch {
|
|
35
|
-
// Query may fail for old workflows without the handler — not held
|
|
36
|
-
}
|
|
37
|
-
if (!isLocked) {
|
|
38
|
-
return (0, helpers_1.fail)(`Session "${player}" is not held (outbox not locked). Only held sessions can be released.`);
|
|
39
|
-
}
|
|
40
|
-
const entry = {
|
|
41
|
-
type: 'release',
|
|
42
|
-
targetPlayerId: player,
|
|
43
|
-
};
|
|
44
|
-
const entryId = await handle.executeUpdate(signals_1.submitOutboxUpdate, { args: [entry] });
|
|
45
|
-
return (0, helpers_1.ok)(`Release request submitted for **${player}**. Task assignment will be delivered shortly. (outbox: ${entryId})`);
|
|
20
|
+
const nameError = (0, validation_1.validatePlayerName)(player);
|
|
21
|
+
if (nameError)
|
|
22
|
+
return (0, descriptor_1.fail)(nameError);
|
|
46
23
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
24
|
+
try {
|
|
25
|
+
if (player) {
|
|
26
|
+
// Release a specific player
|
|
27
|
+
const sessions = await (0, resolve_1.scanEnsembleSessions)(client, config.ensemble);
|
|
28
|
+
const target = sessions.find((s) => s.playerId === player);
|
|
29
|
+
if (!target) {
|
|
30
|
+
return (0, descriptor_1.fail)(`No session found with name "${player}".`);
|
|
31
|
+
}
|
|
32
|
+
// Check if the session's outbox is actually locked
|
|
33
|
+
const targetHandle = client.workflow.getHandle(target.workflowId);
|
|
34
|
+
let isLocked = false;
|
|
55
35
|
try {
|
|
56
|
-
|
|
57
|
-
const isLocked = await sessionHandle.query(signals_1.outboxLockedQuery);
|
|
58
|
-
if (isLocked) {
|
|
59
|
-
heldSessions.push(session);
|
|
60
|
-
}
|
|
36
|
+
isLocked = await targetHandle.query(signals_1.outboxLockedQuery);
|
|
61
37
|
}
|
|
62
38
|
catch {
|
|
63
|
-
//
|
|
39
|
+
// Query may fail for old workflows without the handler — not held
|
|
64
40
|
}
|
|
41
|
+
if (!isLocked) {
|
|
42
|
+
return (0, descriptor_1.fail)(`Session "${player}" is not held (outbox not locked). Only held sessions can be released.`);
|
|
43
|
+
}
|
|
44
|
+
const entry = {
|
|
45
|
+
type: 'release',
|
|
46
|
+
targetPlayerId: player,
|
|
47
|
+
};
|
|
48
|
+
const entryId = await handle.executeUpdate(signals_1.submitOutboxUpdate, { args: [entry] });
|
|
49
|
+
return (0, descriptor_1.ok)(`Release request submitted for **${player}**. Task assignment will be delivered shortly. (outbox: ${entryId})`);
|
|
65
50
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
51
|
+
else {
|
|
52
|
+
// Release all held players — scan ensemble and check outboxLocked on each
|
|
53
|
+
const sessions = await (0, resolve_1.scanEnsembleSessions)(client, config.ensemble);
|
|
54
|
+
const heldSessions = [];
|
|
55
|
+
for (const session of sessions) {
|
|
56
|
+
// Skip self and conductors (conductor outbox is never locked)
|
|
57
|
+
if (session.playerId === getPlayerId())
|
|
58
|
+
continue;
|
|
59
|
+
try {
|
|
60
|
+
const sessionHandle = client.workflow.getHandle(session.workflowId);
|
|
61
|
+
const isLocked = await sessionHandle.query(signals_1.outboxLockedQuery);
|
|
62
|
+
if (isLocked) {
|
|
63
|
+
heldSessions.push(session);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Skip sessions where query fails (old workflows, terminated, etc.)
|
|
68
|
+
}
|
|
79
69
|
}
|
|
80
|
-
|
|
81
|
-
|
|
70
|
+
if (heldSessions.length === 0) {
|
|
71
|
+
return (0, descriptor_1.ok)('No held sessions found. Nothing to release.');
|
|
82
72
|
}
|
|
73
|
+
const released = [];
|
|
74
|
+
const errors = [];
|
|
75
|
+
for (const session of heldSessions) {
|
|
76
|
+
try {
|
|
77
|
+
const entry = {
|
|
78
|
+
type: 'release',
|
|
79
|
+
targetPlayerId: session.playerId,
|
|
80
|
+
};
|
|
81
|
+
await handle.executeUpdate(signals_1.submitOutboxUpdate, { args: [entry] });
|
|
82
|
+
released.push(session.playerId);
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
errors.push(`${session.playerId}: ${(0, descriptor_1.formatError)(err)}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const lines = [];
|
|
89
|
+
if (released.length > 0) {
|
|
90
|
+
lines.push(`Released ${released.length} player(s): ${released.join(', ')}`);
|
|
91
|
+
}
|
|
92
|
+
if (errors.length > 0) {
|
|
93
|
+
lines.push(`Errors:\n${errors.map((e) => ` - ${e}`).join('\n')}`);
|
|
94
|
+
}
|
|
95
|
+
return (0, descriptor_1.ok)(lines.join('\n'));
|
|
83
96
|
}
|
|
84
|
-
const lines = [];
|
|
85
|
-
if (released.length > 0) {
|
|
86
|
-
lines.push(`Released ${released.length} player(s): ${released.join(', ')}`);
|
|
87
|
-
}
|
|
88
|
-
if (errors.length > 0) {
|
|
89
|
-
lines.push(`Errors:\n${errors.map((e) => ` - ${e}`).join('\n')}`);
|
|
90
|
-
}
|
|
91
|
-
return (0, helpers_1.ok)(lines.join('\n'));
|
|
92
97
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
return (0, descriptor_1.fail)(`Failed to release: ${(0, descriptor_1.formatError)(err)}`);
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
};
|
|
98
103
|
}
|
package/dist/tools/report.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
1
|
import { WorkflowHandle } from '@temporalio/client';
|
|
3
|
-
|
|
2
|
+
import { type TempoToolDescriptor } from './descriptor';
|
|
3
|
+
export declare function buildReportTool(handle: WorkflowHandle): TempoToolDescriptor;
|
package/dist/tools/report.js
CHANGED
|
@@ -1,29 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.buildReportTool = buildReportTool;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const signals_1 = require("../workflows/signals");
|
|
6
|
-
const
|
|
6
|
+
const descriptor_1 = require("./descriptor");
|
|
7
7
|
const validation_1 = require("../utils/validation");
|
|
8
|
-
function
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
8
|
+
function buildReportTool(handle) {
|
|
9
|
+
return {
|
|
10
|
+
name: 'report',
|
|
11
|
+
description: 'Send an update to the conductor. Use this to report task completion, blockers, or questions. No-op if no conductor is running.',
|
|
12
|
+
params: {
|
|
13
|
+
text: zod_1.z.string().max(validation_1.MESSAGE_MAX).describe('The report content'),
|
|
14
|
+
type: zod_1.z.enum(['result', 'blocker', 'question', 'update']).optional()
|
|
15
|
+
.describe('Type of report: "result" (default, task done), "blocker" (stuck), "question" (need input), "update" (progress update, still working)'),
|
|
16
|
+
},
|
|
17
|
+
handler: async (args) => {
|
|
18
|
+
const text = args.text;
|
|
19
|
+
const type = (args.type ?? 'result');
|
|
20
|
+
try {
|
|
21
|
+
const entry = {
|
|
22
|
+
type: 'report',
|
|
23
|
+
text,
|
|
24
|
+
reportType: type,
|
|
25
|
+
};
|
|
26
|
+
const entryId = await handle.executeUpdate(signals_1.submitOutboxUpdate, { args: [entry] });
|
|
27
|
+
return (0, descriptor_1.ok)(`Report sent to conductor: [${type}] ${text} (outbox: ${entryId})`);
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
return (0, descriptor_1.fail)(`Failed to send report: ${(0, descriptor_1.formatError)(err)}`);
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
};
|
|
29
34
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildResetTool = buildResetTool;
|
|
4
|
+
/**
|
|
5
|
+
* `reset` — clean-wipe a player's conversation context (D14). Enqueues a
|
|
6
|
+
* `ResetOutboxEntry` on the caller's outbox; the dispatch loop runs
|
|
7
|
+
* `deliverReset` on the target, setting a `pendingReset` flag the target's Pi
|
|
8
|
+
* extension polls + acts on (Pi `newSession()` — fresh context, no replay).
|
|
9
|
+
*
|
|
10
|
+
* D14 ruling: reset = CLEAN-WIPE only (always `fresh: true`). For a context
|
|
11
|
+
* wipe that RE-SEEDS from saved state, use `restart` with `loadFromState`
|
|
12
|
+
* instead — that is a different path. Reset is an operator/conductor control op
|
|
13
|
+
* and does NOT route through the MD-G tool gate.
|
|
14
|
+
*/
|
|
15
|
+
const zod_1 = require("zod");
|
|
16
|
+
const signals_1 = require("../workflows/signals");
|
|
17
|
+
const descriptor_1 = require("./descriptor");
|
|
18
|
+
const validation_1 = require("../utils/validation");
|
|
19
|
+
function buildResetTool(handle, getPlayerId) {
|
|
20
|
+
return {
|
|
21
|
+
name: 'reset',
|
|
22
|
+
description: "Clean-wipe a player's conversation context — the target starts a FRESH " +
|
|
23
|
+
"session (no transcript replay). Use this to clear a player that's stuck " +
|
|
24
|
+
'or off-track. For a context wipe that RE-SEEDS from saved state, use ' +
|
|
25
|
+
'`restart` with `loadFromState` instead.',
|
|
26
|
+
params: {
|
|
27
|
+
playerId: zod_1.z.string().max(validation_1.PLAYER_NAME_MAX).describe('The player whose context to clean-wipe'),
|
|
28
|
+
reason: zod_1.z.string().max(500).optional().describe('Optional reason — surfaced to the wiped session and recorded for audit'),
|
|
29
|
+
},
|
|
30
|
+
handler: async (args) => {
|
|
31
|
+
const { playerId, reason } = args;
|
|
32
|
+
const nameError = (0, validation_1.validatePlayerName)(playerId);
|
|
33
|
+
if (nameError)
|
|
34
|
+
return (0, descriptor_1.fail)(nameError);
|
|
35
|
+
try {
|
|
36
|
+
const entry = {
|
|
37
|
+
type: 'reset',
|
|
38
|
+
targetPlayerId: playerId,
|
|
39
|
+
invokerPlayerId: getPlayerId(),
|
|
40
|
+
fresh: true, // D14: reset = clean-wipe only.
|
|
41
|
+
...(reason !== undefined ? { reason } : {}),
|
|
42
|
+
};
|
|
43
|
+
const entryId = await handle.executeUpdate(signals_1.submitOutboxUpdate, { args: [entry] });
|
|
44
|
+
return (0, descriptor_1.ok)(`Reset (clean-wipe) queued for **${playerId}**. (outbox: ${entryId})`);
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
return (0, descriptor_1.fail)(`Failed to reset: ${(0, descriptor_1.formatError)(err)}`);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
package/dist/tools/restart.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
1
|
import { Client, WorkflowHandle } from '@temporalio/client';
|
|
3
2
|
import { Config } from '../config';
|
|
3
|
+
import { type TempoToolDescriptor } from './descriptor';
|
|
4
4
|
export interface RestartToolArgs {
|
|
5
5
|
playerId: string;
|
|
6
6
|
host?: string;
|
|
@@ -32,4 +32,4 @@ export declare function enforceYesStealGuard(client: Client, ensemble: string, p
|
|
|
32
32
|
force?: boolean;
|
|
33
33
|
confirmStealFromHost?: string;
|
|
34
34
|
}, localHostname?: string): Promise<string | null>;
|
|
35
|
-
export declare function
|
|
35
|
+
export declare function buildRestartTool(client: Client, config: Config, getPlayerId: () => string, handle: WorkflowHandle): TempoToolDescriptor;
|
package/dist/tools/restart.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.enforceYesStealGuard = enforceYesStealGuard;
|
|
4
|
-
exports.
|
|
4
|
+
exports.buildRestartTool = buildRestartTool;
|
|
5
5
|
/**
|
|
6
6
|
* `restart` — reap the current attachment, claim a fresh one, spawn a new adapter.
|
|
7
7
|
*
|
|
@@ -35,7 +35,7 @@ const zod_1 = require("zod");
|
|
|
35
35
|
const os_1 = require("os");
|
|
36
36
|
const signals_1 = require("../workflows/signals");
|
|
37
37
|
const resolve_1 = require("./resolve");
|
|
38
|
-
const
|
|
38
|
+
const descriptor_1 = require("./descriptor");
|
|
39
39
|
const validation_1 = require("../utils/validation");
|
|
40
40
|
const DEFAULT_CONTEXT_MESSAGES = 10;
|
|
41
41
|
/**
|
|
@@ -84,48 +84,53 @@ async function enforceYesStealGuard(client, ensemble, playerId, args, localHostn
|
|
|
84
84
|
}
|
|
85
85
|
return null;
|
|
86
86
|
}
|
|
87
|
-
function
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
zod_1.z.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
87
|
+
function buildRestartTool(client, config, getPlayerId, handle) {
|
|
88
|
+
return {
|
|
89
|
+
name: 'restart',
|
|
90
|
+
description: 'Restart a session — reap the current attachment (gracefully, or with force=true), claim a fresh attachment, spawn a new adapter, and optionally replay recent context. Replaces `encore`, `recruit --force`, and `stop`-then-`recruit`. Pass `host` to restart on a different machine; when `force=true` AND the target is currently on a different host, pass `confirmStealFromHost` matching that hostname (design §16.5). Pass `loadFromState` to seed the restarted session from a saved-state slot (#334) instead of (or alongside) transcript replay.',
|
|
91
|
+
params: {
|
|
92
|
+
playerId: zod_1.z.string().max(validation_1.PLAYER_NAME_MAX).describe('The player name to restart'),
|
|
93
|
+
host: zod_1.z.string().optional().describe('Target host for the new attachment (defaults to the session\'s preferredHost or last-known hostname). When set, the spawn is routed to the per-host task queue `agent-tempo-{host}`.'),
|
|
94
|
+
fresh: zod_1.z.boolean().optional().describe('Skip context replay — spawn a clean slate (default false)'),
|
|
95
|
+
force: zod_1.z.boolean().optional().describe('Steal a live attachment via forceDetach (default false; graceful detach is tried first regardless)'),
|
|
96
|
+
contextMessages: zod_1.z.number().min(0).max(validation_1.RESTART_CONTEXT_MESSAGES_MAX).optional().describe(`Number of recent messages to include in context (default ${DEFAULT_CONTEXT_MESSAGES}, max ${validation_1.RESTART_CONTEXT_MESSAGES_MAX})`),
|
|
97
|
+
confirmStealFromHost: zod_1.z.string().optional().describe('Required when `force=true` and the target\'s current attachment is on a different host. Must match the hostname currently holding the attachment (design §16.5 Option B).'),
|
|
98
|
+
// #334 PR-2 — saved-state seed integration.
|
|
99
|
+
loadFromState: zod_1.z.union([
|
|
100
|
+
zod_1.z.boolean(),
|
|
101
|
+
zod_1.z.string().regex(validation_1.PLAYER_STATE_KEY_REGEX).max(validation_1.PLAYER_STATE_KEY_MAX),
|
|
102
|
+
]).optional().describe(`Seed the restarted session with a saved-state slot. \`true\` resolves to the default key "${validation_1.PLAYER_STATE_DEFAULT_KEY}"; a string names a specific slot. By default, transcript replay is suppressed when this is set — pass \`transcript: 'replay'\` to stack both. Falls back to transcript replay if the slot is empty.`),
|
|
103
|
+
transcript: zod_1.z.enum(['suppress', 'replay']).optional().describe('When `loadFromState` is set, controls transcript-replay interaction: `suppress` (default) seeds only the saved state; `replay` seeds the saved state and then replays the recent transcript on top of it. Ignored when `loadFromState` is absent.'),
|
|
104
|
+
},
|
|
105
|
+
handler: async (args) => {
|
|
106
|
+
const input = args;
|
|
107
|
+
const nameError = (0, validation_1.validatePlayerName)(input.playerId);
|
|
108
|
+
if (nameError)
|
|
109
|
+
return (0, descriptor_1.fail)(nameError);
|
|
110
|
+
// Client-side --yes-steal guard (§16.5). Cross-host force-restart
|
|
111
|
+
// requires an explicit confirmStealFromHost matching the current holder.
|
|
112
|
+
const guardError = await enforceYesStealGuard(client, config.ensemble, input.playerId, input);
|
|
113
|
+
if (guardError)
|
|
114
|
+
return (0, descriptor_1.fail)(guardError);
|
|
115
|
+
try {
|
|
116
|
+
const entry = {
|
|
117
|
+
type: 'restart',
|
|
118
|
+
targetPlayerId: input.playerId,
|
|
119
|
+
invokerPlayerId: getPlayerId(),
|
|
120
|
+
...(input.host !== undefined ? { host: input.host } : {}),
|
|
121
|
+
...(input.fresh !== undefined ? { fresh: input.fresh } : {}),
|
|
122
|
+
...(input.force !== undefined ? { force: input.force } : {}),
|
|
123
|
+
...(input.contextMessages !== undefined ? { contextMessages: input.contextMessages } : {}),
|
|
124
|
+
...(input.loadFromState !== undefined ? { loadFromState: input.loadFromState } : {}),
|
|
125
|
+
...(input.transcript !== undefined ? { transcript: input.transcript } : {}),
|
|
126
|
+
};
|
|
127
|
+
const entryId = await handle.executeUpdate(signals_1.submitOutboxUpdate, { args: [entry] });
|
|
128
|
+
return (0, descriptor_1.ok)(`Restart queued for **${input.playerId}**${input.host ? ` on ${input.host}` : ''}` +
|
|
129
|
+
`${input.fresh ? ' (fresh)' : ''}${input.force ? ' (force)' : ''}. (outbox: ${entryId})`);
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
return (0, descriptor_1.fail)(`Failed to restart: ${(0, descriptor_1.formatError)(err)}`);
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
};
|
|
131
136
|
}
|
package/dist/tools/restore.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
1
|
import { Client } from '@temporalio/client';
|
|
3
2
|
import { Config } from '../config';
|
|
4
|
-
|
|
3
|
+
import { type TempoToolDescriptor } from './descriptor';
|
|
4
|
+
export declare function buildRestoreTool(client: Client, config: Config, getPlayerId: () => string): TempoToolDescriptor;
|