@myagentroam/node 0.9.115 → 0.9.117

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.
@@ -1,225 +0,0 @@
1
- import { randomUUID } from 'node:crypto';
2
- export function missionUnrestrictedAccess(runner) {
3
- if (runner === 'codex' || runner === 'mar-agent')
4
- return 'full-access';
5
- if (runner === 'claude-code')
6
- return 'bypass';
7
- return 'auto';
8
- }
9
- const START_OPEN = '<mar_mission_start>';
10
- const START_CLOSE = '</mar_mission_start>';
11
- const CONTINUE_OPEN = '<mar_mission_continue>';
12
- const CONTINUE_CLOSE = '</mar_mission_continue>';
13
- function missionPromptTags(text) {
14
- if (text.startsWith(START_OPEN))
15
- return { open: START_OPEN, close: START_CLOSE };
16
- if (text.startsWith(CONTINUE_OPEN))
17
- return { open: CONTINUE_OPEN, close: CONTINUE_CLOSE };
18
- return undefined;
19
- }
20
- export function publicMissionStartText(objective) {
21
- const normalized = objective.trim();
22
- return normalized.length === 0 ? 'Mission Start' : `Mission Start\n${normalized}`;
23
- }
24
- export function stripMissionStartPrompt(text) {
25
- const tags = missionPromptTags(text);
26
- if (tags === undefined)
27
- return text;
28
- const close = text.lastIndexOf(tags.close);
29
- return close === -1 ? '' : text.slice(close + tags.close.length).trimStart();
30
- }
31
- export function publicMissionHistoryText(text) {
32
- const tags = missionPromptTags(text);
33
- if (tags === undefined)
34
- return text;
35
- const stripped = stripMissionStartPrompt(text);
36
- if (stripped.length > 0)
37
- return stripped;
38
- if (tags.open === CONTINUE_OPEN)
39
- return 'Mission Continue';
40
- const close = text.lastIndexOf(tags.close);
41
- const prompt = close === -1 ? text : text.slice(0, close);
42
- const objectiveStart = prompt.indexOf('\nOriginal objective:\n');
43
- const objectiveEnd = prompt.lastIndexOf('\n\nContinue executing this Mission across turns:');
44
- return publicMissionStartText(objectiveStart === -1 || objectiveEnd === -1
45
- ? ''
46
- : prompt.slice(objectiveStart + '\nOriginal objective:\n'.length, objectiveEnd));
47
- }
48
- export class MissionRuntime {
49
- changed;
50
- missions = new Map();
51
- executionFailures = new Map();
52
- constructor(changed) {
53
- this.changed = changed;
54
- }
55
- get(sessionId) {
56
- return this.missions.get(sessionId);
57
- }
58
- migrateSession(previousId, nextId) {
59
- if (previousId === nextId)
60
- return;
61
- const mission = this.missions.get(previousId);
62
- if (mission !== undefined) {
63
- this.missions.delete(previousId);
64
- this.missions.set(nextId, { ...mission, sessionId: nextId });
65
- }
66
- const failures = this.executionFailures.get(previousId);
67
- if (failures !== undefined) {
68
- this.executionFailures.delete(previousId);
69
- this.executionFailures.set(nextId, failures);
70
- }
71
- }
72
- start(sessionId, objective) {
73
- const normalized = objective.trim();
74
- if (normalized.length === 0 || normalized.length > 20_000)
75
- throw new Error('MISSION_OBJECTIVE_INVALID');
76
- const current = this.missions.get(sessionId);
77
- const continuing = current?.status === 'active';
78
- const mission = {
79
- id: continuing ? current.id : randomUUID(),
80
- sessionId,
81
- objective: normalized,
82
- revision: continuing ? current.revision + 1 : 1,
83
- status: 'active',
84
- turns: 0,
85
- retryRequired: false,
86
- retryStartedAtTurn: null,
87
- consecutiveNoProgressTurns: 0,
88
- continuationPaused: false
89
- };
90
- this.missions.set(sessionId, mission);
91
- this.executionFailures.delete(sessionId);
92
- this.changed(mission);
93
- return mission;
94
- }
95
- recordTurn(sessionId) {
96
- const current = this.missions.get(sessionId);
97
- if (current?.status !== 'active')
98
- return current;
99
- const mission = { ...current, turns: current.turns + 1 };
100
- this.missions.set(sessionId, mission);
101
- return mission;
102
- }
103
- recordExecutionResult(sessionId, input) {
104
- const current = this.missions.get(sessionId);
105
- if (current?.status !== 'active')
106
- return 'continue';
107
- if (!input.failed && !input.progressed) {
108
- this.executionFailures.delete(sessionId);
109
- const consecutiveNoProgressTurns = current.consecutiveNoProgressTurns + 1;
110
- const paused = consecutiveNoProgressTurns >= 3;
111
- const mission = {
112
- ...current,
113
- consecutiveNoProgressTurns,
114
- continuationPaused: paused
115
- };
116
- this.missions.set(sessionId, mission);
117
- this.changed(mission);
118
- return paused ? 'paused' : 'continue';
119
- }
120
- if (!input.failed) {
121
- this.executionFailures.delete(sessionId);
122
- if (current.consecutiveNoProgressTurns > 0 || current.continuationPaused) {
123
- const mission = {
124
- ...current,
125
- consecutiveNoProgressTurns: 0,
126
- continuationPaused: false
127
- };
128
- this.missions.set(sessionId, mission);
129
- this.changed(mission);
130
- }
131
- return 'continue';
132
- }
133
- if (current.consecutiveNoProgressTurns > 0 || current.continuationPaused) {
134
- const mission = {
135
- ...current,
136
- consecutiveNoProgressTurns: 0,
137
- continuationPaused: false
138
- };
139
- this.missions.set(sessionId, mission);
140
- }
141
- const failures = (this.executionFailures.get(sessionId) ?? 0) + 1;
142
- this.executionFailures.set(sessionId, failures);
143
- if (failures <= 3)
144
- return 'continue';
145
- const blocked = {
146
- ...(this.missions.get(sessionId) ?? current),
147
- status: 'blocked'
148
- };
149
- this.missions.set(sessionId, blocked);
150
- this.changed(blocked);
151
- return 'blocked';
152
- }
153
- resume(sessionId) {
154
- const current = this.missions.get(sessionId);
155
- if (current?.status !== 'active')
156
- return current;
157
- if (!current.continuationPaused && current.consecutiveNoProgressTurns === 0)
158
- return current;
159
- const mission = {
160
- ...current,
161
- consecutiveNoProgressTurns: 0,
162
- continuationPaused: false
163
- };
164
- this.missions.set(sessionId, mission);
165
- this.changed(mission);
166
- return mission;
167
- }
168
- blockAfterRuntimeFailure(sessionId, missionId, revision) {
169
- const current = this.requireCurrent(sessionId, missionId, revision);
170
- const blocked = { ...current, status: 'blocked' };
171
- this.missions.set(sessionId, blocked);
172
- this.executionFailures.delete(sessionId);
173
- this.changed(blocked);
174
- return blocked;
175
- }
176
- update(sessionId, missionId, revision, status) {
177
- const current = this.requireCurrent(sessionId, missionId, revision);
178
- if (status === 'blocked') {
179
- if (current.turns < 3)
180
- throw new Error('MISSION_BLOCKED_TOO_EARLY');
181
- if (!current.retryRequired) {
182
- const retry = {
183
- ...current,
184
- retryRequired: true,
185
- retryStartedAtTurn: current.turns
186
- };
187
- this.missions.set(sessionId, retry);
188
- this.changed(retry);
189
- return retry;
190
- }
191
- if (current.retryStartedAtTurn === null || current.turns <= current.retryStartedAtTurn)
192
- throw new Error('MISSION_BLOCKED_RETRY_REQUIRED');
193
- }
194
- const mission = { ...current, status };
195
- this.missions.set(sessionId, mission);
196
- this.changed(mission);
197
- return mission;
198
- }
199
- clear(sessionId) {
200
- const removed = this.missions.delete(sessionId);
201
- this.executionFailures.delete(sessionId);
202
- if (removed)
203
- this.changed(undefined);
204
- return removed;
205
- }
206
- prompt(sessionId, kind) {
207
- const mission = this.missions.get(sessionId);
208
- if (mission?.status !== 'active')
209
- throw new Error('MISSION_NOT_ACTIVE');
210
- const heading = kind === 'start' ? 'A Mission has started or changed.' : 'Continue the active Mission.';
211
- const open = kind === 'start' ? START_OPEN : CONTINUE_OPEN;
212
- const close = kind === 'start' ? START_CLOSE : CONTINUE_CLOSE;
213
- return `${open}\n${heading}\n\nOriginal objective:\n${mission.objective}\n\nContinue executing this Mission across turns:\n- Work on the objective now. If it is incomplete, use tools to finish a coherent unit or obtain decisive evidence; do not stop at an acknowledgement, status, plan, or promise.\n- Preserve the original scope. Before completion, review the full objective and verify it with real evidence, then call mar_update_mission with status=completed.\n- Adapt and retry after individual failures. Request blocked only after the same blocker persists for three turns and the required additional retry.\n- Use mar_get_mission only when you need to reread the authoritative objective or status.\n${close}`;
214
- }
215
- requireCurrent(sessionId, missionId, revision) {
216
- const current = this.missions.get(sessionId);
217
- if (current === undefined || current.id !== missionId)
218
- throw new Error('MISSION_NOT_FOUND');
219
- if (current.revision !== revision)
220
- throw new Error('MISSION_REVISION_STALE');
221
- if (current.status !== 'active')
222
- throw new Error('MISSION_NOT_ACTIVE');
223
- return current;
224
- }
225
- }