@myagentroam/node 0.10.32 → 0.10.33
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/dist/database.js +10 -1
- package/dist/migrations/v018.js +9 -0
- package/dist/runner/mar-agent/marctl-skill.js +7 -6
- package/dist/runtime-state.js +3 -0
- package/dist/service/continuous-run-coordinator.js +3 -3
- package/dist/service/external-session-resume-service.js +2 -1
- package/dist/service/native-session-projection-service.js +4 -1
- package/dist/service/session-catalog-service.js +1 -0
- package/dist/service/session-lifecycle-service.js +23 -9
- package/dist/service/session-presentation-service.js +7 -2
- package/dist/util/personal-instructions.js +11 -0
- package/package.json +5 -5
package/dist/database.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { NODE_SCHEMA_MIGRATION_V17 } from './migrations/v017.js';
|
|
2
|
+
import { NODE_SCHEMA_MIGRATION_V18 } from './migrations/v018.js';
|
|
3
|
+
import { normalizeSessionPrompt } from './util/personal-instructions.js';
|
|
2
4
|
import { randomUUID } from 'node:crypto';
|
|
3
5
|
import { closeSync, existsSync, mkdirSync, openSync, rmSync } from 'node:fs';
|
|
4
6
|
import { dirname } from 'node:path';
|
|
@@ -16,7 +18,8 @@ export const NODE_SCHEMA_MIGRATIONS = [
|
|
|
16
18
|
NODE_SCHEMA_MIGRATION_V14,
|
|
17
19
|
NODE_SCHEMA_MIGRATION_V15,
|
|
18
20
|
NODE_SCHEMA_MIGRATION_V16,
|
|
19
|
-
NODE_SCHEMA_MIGRATION_V17
|
|
21
|
+
NODE_SCHEMA_MIGRATION_V17,
|
|
22
|
+
NODE_SCHEMA_MIGRATION_V18
|
|
20
23
|
];
|
|
21
24
|
const LEGACY_NODE_SCHEMA_V12 = NODE_SCHEMA_VERSION_V13 - 1;
|
|
22
25
|
const OBSOLETE_NODE_SCHEMA_V16 = 16;
|
|
@@ -266,6 +269,9 @@ export class NodeDatabase {
|
|
|
266
269
|
const runnerTitle = input.runnerTitle === undefined
|
|
267
270
|
? (current?.runnerTitle ?? null)
|
|
268
271
|
: input.runnerTitle?.trim() || null;
|
|
272
|
+
const sessionPrompt = input.sessionPrompt === undefined
|
|
273
|
+
? (current?.sessionPrompt ?? null)
|
|
274
|
+
: normalizeSessionPrompt(input.sessionPrompt);
|
|
269
275
|
const runnerTitlePending = input.runnerTitlePending === undefined
|
|
270
276
|
? (current?.runnerTitlePending ?? false)
|
|
271
277
|
: input.runnerTitlePending;
|
|
@@ -285,6 +291,7 @@ export class NodeDatabase {
|
|
|
285
291
|
const metadata = JSON.stringify({
|
|
286
292
|
version: 1,
|
|
287
293
|
customTitle,
|
|
294
|
+
sessionPrompt,
|
|
288
295
|
runnerTitle,
|
|
289
296
|
runnerTitlePending,
|
|
290
297
|
model,
|
|
@@ -321,6 +328,7 @@ export class NodeDatabase {
|
|
|
321
328
|
}
|
|
322
329
|
return {
|
|
323
330
|
customTitle,
|
|
331
|
+
sessionPrompt,
|
|
324
332
|
runnerTitle,
|
|
325
333
|
runnerTitlePending,
|
|
326
334
|
pinnedAt: pinOrder === null ? null : 1,
|
|
@@ -564,6 +572,7 @@ function sessionMetadata(row) {
|
|
|
564
572
|
const value = (key) => typeof raw[key] === 'string' ? raw[key] : null;
|
|
565
573
|
return {
|
|
566
574
|
customTitle: value('customTitle'),
|
|
575
|
+
sessionPrompt: value('sessionPrompt'),
|
|
567
576
|
runnerTitle: value('runnerTitle'),
|
|
568
577
|
runnerTitlePending: raw['runnerTitlePending'] === true,
|
|
569
578
|
model: value('model'),
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NODE_SCHEMA_MIGRATION_V17 } from './v017.js';
|
|
2
|
+
export const NODE_SCHEMA_MIGRATION_V18 = {
|
|
3
|
+
version: 18,
|
|
4
|
+
sql: `UPDATE agent_sessions
|
|
5
|
+
SET metadata = json_set(metadata, '$.sessionPrompt', NULL)
|
|
6
|
+
WHERE json_type(metadata, '$.sessionPrompt') IS NULL;`,
|
|
7
|
+
preflight: (database) => NODE_SCHEMA_MIGRATION_V17.assert(database),
|
|
8
|
+
assert: (database) => NODE_SCHEMA_MIGRATION_V17.assert(database)
|
|
9
|
+
};
|
|
@@ -17,15 +17,16 @@ export function marctlHostSkill(environment = {}) {
|
|
|
17
17
|
}
|
|
18
18
|
const marctlInstructions = [
|
|
19
19
|
'## MAR Workspace CLI',
|
|
20
|
-
'Use exec to run marctl.
|
|
20
|
+
'Use exec to run marctl. Reuse loaded guidance while it remains in context. Consult local marctl help sessions for unclear options and marctl --version when version matters; neither needs a network request. Capabilities and permissions still apply.',
|
|
21
|
+
'Use sessions current --json only when the current identity or scope is unknown. For a known target ID, use sessions show <session-id> --json only when fresh state is needed, without current/list first. Use sessions list --limit 10 --json to discover an unknown target; list has no name-search option. Stop once found and follow nextCursor only if needed. Do not scan the Workspace to prove capacity: check assigned work, recorded worker IDs and overlapping write scopes.',
|
|
21
22
|
'MAR binds sessions to the current Node and Workspace. No --node or --workspace override exists. Use returned native Session IDs, not titles, for later operations. A Workspace terminal may have no current Session. Missing scope, an old Node, expired authorization or an unavailable Runner is an explicit error, not permission to bypass the API.',
|
|
22
23
|
'## Create and coordinate independent Sessions',
|
|
23
|
-
'
|
|
24
|
+
'Prefer -m / --message for short text; use --message-file for longer UTF-8 text or an existing file (- reads stdin). These options are mutually exclusive. Example: marctl sessions start --runner codex --title "fixer#42 Handle empty totals" -m "Implement issue #42 and report test evidence" --json. Other Runner names are mar-agent, claude-code and opencode. An omitted model uses the target Runner configuration, not the Coordinator model.',
|
|
24
25
|
'For start/send, repeat --image <local-path> to attach PNG, JPEG, GIF or WebP images, with or without text. Images are read on this CLI host, not by remote path. Limits: 5 images, 5 MiB each, 10 MiB total. Actual Runner/model image capabilities apply; goal set accepts text only.',
|
|
25
|
-
'Create workers only as tasks need them
|
|
26
|
-
'
|
|
27
|
-
'Send with sessions send <session-id>
|
|
28
|
-
'Wait with sessions wait <session-id> --run <run-id> --timeout
|
|
26
|
+
'Create workers only as tasks need them, named fixer#<task-id> <description> or reviewer#<task-or-change-id> <description>. These are conventions, not product roles or a fixed pool. Put role, scope, acceptance criteria and delivery requirements in the first message. Session Prompt is edited in the Web UI only; marctl has no editing command, and sends to existing Sessions use normal prompt injection.',
|
|
27
|
+
'Reuse recorded Session/Run IDs and receipts. Refresh volatile Run, queue and Goal state with sessions show only when the next action depends on it. For results use sessions history <session-id> --limit 10 --json; follow nextCursor only for missing evidence. Select needed JSON fields and relevant assistant results instead of dumping full Session lists or tool transcripts. Hidden reasoning, credentials and raw model requests are not collaboration artifacts.',
|
|
28
|
+
'Send with sessions send <session-id> -m "Review the updated patch" --json. Default send does not interrupt and can resume a paused queue; --delivery queue preserves a paused queue. Otherwise eligible queued input can start when idle. --delivery replace-current cancels the current Run and prioritizes the new input after release; it is not live steering. There are no queue-item edit/delete/reorder commands; show includes queue state. start/send return clientMessageId and the accepted/queued result. A queued result may refer to the currently active Run: associate queueItemId/clientMessageId with history before deciding that input finished.',
|
|
29
|
+
'Wait with sessions wait <session-id> --run <run-id> --timeout 5m --json through the existing Watch. Prefer --timeout 5m when blocked on task completion; use 30s for a short deadline. Continue useful independent work before waiting. If exec returns a running process or cell, reuse its process/cell handle rather than starting another wait or polling show/list. Timeout or cancelled waiting does not stop the task. Use sessions stop <session-id> --run <run-id> --json only to stop that active Run; ownership rules still apply.',
|
|
29
30
|
'Goal get/set/clear use the existing Session Goal semantics; see marctl help sessions. A Coordinator can work from ordinary messages or its existing schedule without a Goal. Worker completion never automatically wakes it. Actively wait/read results, or finish and reconcile on the next user message or scheduled input.',
|
|
30
31
|
'## Verify, recover and respect authorization',
|
|
31
32
|
'An accepted message or SUCCEEDED Run is not proof of business completion. Inspect artifacts and test evidence. If review finds a defect, send a focused correction to the recorded Fixer Session, then request another review with the recorded Reviewer ID.',
|
package/dist/runtime-state.js
CHANGED
|
@@ -78,6 +78,7 @@ export class NodeRuntimeState {
|
|
|
78
78
|
effort: input.effort ?? null,
|
|
79
79
|
access: input.access ?? null,
|
|
80
80
|
customTitle,
|
|
81
|
+
sessionPrompt: input.sessionPrompt ?? null,
|
|
81
82
|
runnerTitle: input.title?.trim().slice(0, 160) || null,
|
|
82
83
|
pinnedAt: null,
|
|
83
84
|
// A first user prompt is only a process-local temporary title. A
|
|
@@ -112,6 +113,7 @@ export class NodeRuntimeState {
|
|
|
112
113
|
effort: null,
|
|
113
114
|
access: null,
|
|
114
115
|
customTitle: null,
|
|
116
|
+
sessionPrompt: null,
|
|
115
117
|
runnerTitle: null,
|
|
116
118
|
pinnedAt: null,
|
|
117
119
|
titleSource: 'AUTO',
|
|
@@ -275,6 +277,7 @@ export class NodeRuntimeState {
|
|
|
275
277
|
throw new Error('SESSION_TITLE_INVALID');
|
|
276
278
|
return this.replaceSession(current.id, {
|
|
277
279
|
customTitle: title,
|
|
280
|
+
sessionPrompt: input.sessionPrompt === undefined ? (current.sessionPrompt ?? null) : input.sessionPrompt,
|
|
278
281
|
pinnedAt: input.pinned === undefined ? current.pinnedAt : input.pinned ? this.now() : null,
|
|
279
282
|
titleSource: title === null ? 'AUTO' : 'CUSTOM'
|
|
280
283
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { withNonImageAttachmentPrompt } from '../util/node-operation-parsers.js';
|
|
2
2
|
import { safeErrorCode } from '../util/safe-error.js';
|
|
3
|
+
import { withSessionPrompt } from '../util/personal-instructions.js';
|
|
3
4
|
import { prepareComposerResourceInput } from './composer-message-input.js';
|
|
4
5
|
export class ContinuousRunCoordinator {
|
|
5
6
|
options;
|
|
@@ -327,6 +328,7 @@ export class ContinuousRunCoordinator {
|
|
|
327
328
|
this.rejectStaleGoal(executionId);
|
|
328
329
|
return;
|
|
329
330
|
}
|
|
331
|
+
const personalInstructions = withSessionPrompt(pending.personalInstructions, this.options.runtime.getAgentSession(pending.sessionId)?.sessionPrompt);
|
|
330
332
|
this.options.control('run.start', {
|
|
331
333
|
...(pending.usageGrant === undefined ? {} : { usageGrant: pending.usageGrant }),
|
|
332
334
|
runId: executionId,
|
|
@@ -364,9 +366,7 @@ export class ContinuousRunCoordinator {
|
|
|
364
366
|
...mailMcp?.secrets
|
|
365
367
|
}
|
|
366
368
|
}),
|
|
367
|
-
...(
|
|
368
|
-
? {}
|
|
369
|
-
: { personalInstructions: pending.personalInstructions }),
|
|
369
|
+
...(personalInstructions === undefined ? {} : { personalInstructions }),
|
|
370
370
|
...(pending.marAgentModel === undefined ? {} : { marAgentModel: pending.marAgentModel }),
|
|
371
371
|
...(pending.marAgentModels === undefined ? {} : { marAgentModels: pending.marAgentModels }),
|
|
372
372
|
...(pending.marAgentCompact === undefined
|
|
@@ -69,7 +69,8 @@ export class ExternalSessionResumeService {
|
|
|
69
69
|
effort: configuration.effort,
|
|
70
70
|
access: configuration.access,
|
|
71
71
|
...(session.runnerTitle === null ? {} : { title: session.runnerTitle }),
|
|
72
|
-
...(session.customTitle === null ? {} : { customTitle: session.customTitle })
|
|
72
|
+
...(session.customTitle === null ? {} : { customTitle: session.customTitle }),
|
|
73
|
+
sessionPrompt: session.sessionPrompt ?? null
|
|
73
74
|
});
|
|
74
75
|
},
|
|
75
76
|
workspacePath: this.options.workspacePath,
|
|
@@ -80,6 +80,7 @@ export class NativeSessionProjectionService {
|
|
|
80
80
|
effort: record.metadata.effort,
|
|
81
81
|
access: record.metadata.access,
|
|
82
82
|
customTitle: record.metadata.customTitle,
|
|
83
|
+
sessionPrompt: record.metadata.sessionPrompt ?? null,
|
|
83
84
|
runnerTitle: record.metadata.runnerTitle,
|
|
84
85
|
pinnedAt: record.pinOrder === null ? null : 1,
|
|
85
86
|
pinOrder: record.pinOrder,
|
|
@@ -112,7 +113,8 @@ export class NativeSessionProjectionService {
|
|
|
112
113
|
...(direct.effort === null ? {} : { effort: direct.effort }),
|
|
113
114
|
...(direct.access === null ? {} : { access: direct.access }),
|
|
114
115
|
...(direct.runnerTitle === null ? {} : { title: direct.runnerTitle }),
|
|
115
|
-
...(direct.customTitle === null ? {} : { customTitle: direct.customTitle })
|
|
116
|
+
...(direct.customTitle === null ? {} : { customTitle: direct.customTitle }),
|
|
117
|
+
sessionPrompt: direct.sessionPrompt ?? null
|
|
116
118
|
});
|
|
117
119
|
}
|
|
118
120
|
resumedConfiguration(session) {
|
|
@@ -183,6 +185,7 @@ export class NativeSessionProjectionService {
|
|
|
183
185
|
effort: metadata?.effort ?? null,
|
|
184
186
|
access: metadata?.access ?? null,
|
|
185
187
|
customTitle: metadata?.customTitle ?? null,
|
|
188
|
+
sessionPrompt: metadata?.sessionPrompt ?? null,
|
|
186
189
|
runnerTitle,
|
|
187
190
|
pinnedAt: metadata?.pinnedAt ?? null,
|
|
188
191
|
pinOrder: metadata?.pinOrder ?? null,
|
|
@@ -94,6 +94,7 @@ export class SessionCatalogService {
|
|
|
94
94
|
effort: persisted.metadata.effort,
|
|
95
95
|
access: persisted.metadata.access,
|
|
96
96
|
customTitle: persisted.metadata.customTitle,
|
|
97
|
+
sessionPrompt: persisted.metadata.sessionPrompt ?? null,
|
|
97
98
|
runnerTitle: persisted.metadata.runnerTitle,
|
|
98
99
|
pinnedAt: persisted.pinOrder === null ? null : 1,
|
|
99
100
|
pinOrder: persisted.pinOrder,
|
|
@@ -2,6 +2,7 @@ import { parseMessageAttachments, validSessionEffort, validSessionOption, validS
|
|
|
2
2
|
import { isPlainRecord } from '../util/node-operation-parsers.js';
|
|
3
3
|
import { parseSecretEnvironment } from '../util/secret-environment.js';
|
|
4
4
|
import { ScheduledSessionStore } from './scheduled-session-store.js';
|
|
5
|
+
import { normalizeSessionPrompt } from '../util/personal-instructions.js';
|
|
5
6
|
export class SessionLifecycleService {
|
|
6
7
|
options;
|
|
7
8
|
starts = new Map();
|
|
@@ -21,6 +22,7 @@ export class SessionLifecycleService {
|
|
|
21
22
|
this.starts.clear();
|
|
22
23
|
}
|
|
23
24
|
async updateMetadata(input) {
|
|
25
|
+
const sessionPrompt = input.sessionPrompt === undefined ? undefined : normalizeSessionPrompt(input.sessionPrompt);
|
|
24
26
|
if (typeof input.sessionId !== 'string' ||
|
|
25
27
|
(input.customTitle !== undefined &&
|
|
26
28
|
input.customTitle !== null &&
|
|
@@ -35,6 +37,8 @@ export class SessionLifecycleService {
|
|
|
35
37
|
(await this.options.projection.createMetadataProjection(input.sessionId));
|
|
36
38
|
if (current === undefined)
|
|
37
39
|
throw new Error('SESSION_NOT_FOUND');
|
|
40
|
+
if (sessionPrompt !== undefined && current.externalSessionId === null)
|
|
41
|
+
throw new Error('SESSION_ACTIVATION_REQUIRED');
|
|
38
42
|
if (input.pinned === false) {
|
|
39
43
|
const task = new ScheduledSessionStore(this.options.database().raw).get(current.externalSessionId ?? current.id);
|
|
40
44
|
if (task?.enabled === true)
|
|
@@ -43,21 +47,31 @@ export class SessionLifecycleService {
|
|
|
43
47
|
const nativeCodexRename = this.options.runners.require(current.runner).usesRunnerTitleForRename() &&
|
|
44
48
|
current.externalSessionId !== null &&
|
|
45
49
|
input.customTitle !== undefined;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
if (input.customTitle !== undefined || input.pinned !== undefined)
|
|
51
|
+
await this.options.projection.rename(current, {
|
|
52
|
+
...(input.customTitle === undefined ? {} : { title: input.customTitle }),
|
|
53
|
+
...(input.pinned === undefined ? {} : { pinned: input.pinned })
|
|
54
|
+
});
|
|
55
|
+
if (sessionPrompt !== undefined && current.externalSessionId !== null)
|
|
56
|
+
this.options.database().saveNativeSessionMetadata({
|
|
57
|
+
runner: current.runner,
|
|
58
|
+
externalSessionId: current.externalSessionId,
|
|
59
|
+
workspaceId: current.workspaceId,
|
|
60
|
+
sessionPrompt
|
|
61
|
+
});
|
|
50
62
|
const metadataTitle = nativeCodexRename ? null : input.customTitle;
|
|
51
63
|
const updated = this.options.runtime.updateSessionMetadata({
|
|
52
64
|
sessionId: current.id,
|
|
65
|
+
...(sessionPrompt === undefined ? {} : { sessionPrompt }),
|
|
53
66
|
...(metadataTitle === undefined ? {} : { customTitle: metadataTitle }),
|
|
54
67
|
...(input.pinned === undefined ? {} : { pinned: input.pinned })
|
|
55
68
|
});
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
69
|
+
const next = nativeCodexRename
|
|
70
|
+
? this.options.runtime.setRunnerTitleFromNative(updated.id, input.customTitle ?? '')
|
|
71
|
+
: updated;
|
|
72
|
+
if (sessionPrompt !== undefined)
|
|
73
|
+
this.options.emitSession(next);
|
|
74
|
+
return { session: this.options.present(next) };
|
|
61
75
|
}
|
|
62
76
|
movePin(input) {
|
|
63
77
|
if (typeof input.sessionId !== 'string' ||
|
|
@@ -9,7 +9,12 @@ export class SessionPresentationService {
|
|
|
9
9
|
if (session.externalSessionId !== null && database !== undefined) {
|
|
10
10
|
const metadata = database.getNativeSessionMetadata(session.runner, session.externalSessionId, session.workspaceId);
|
|
11
11
|
if (metadata !== undefined)
|
|
12
|
-
session = {
|
|
12
|
+
session = {
|
|
13
|
+
...session,
|
|
14
|
+
sessionPrompt: metadata.sessionPrompt ?? null,
|
|
15
|
+
pinnedAt: metadata.pinnedAt,
|
|
16
|
+
pinOrder: metadata.pinOrder
|
|
17
|
+
};
|
|
13
18
|
}
|
|
14
19
|
const presentation = this.options.runners
|
|
15
20
|
.require(session.runner)
|
|
@@ -23,7 +28,7 @@ export class SessionPresentationService {
|
|
|
23
28
|
runtime: {
|
|
24
29
|
...presentation.runtime,
|
|
25
30
|
capabilities: session.externalSessionId !== null && database !== undefined
|
|
26
|
-
? [...presentation.runtime.capabilities, 'session.schedule']
|
|
31
|
+
? [...presentation.runtime.capabilities, 'session.schedule', 'session.prompt']
|
|
27
32
|
: presentation.runtime.capabilities
|
|
28
33
|
},
|
|
29
34
|
schedule: database === undefined
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
const MAX_CONTENT_LENGTH = 20_000;
|
|
2
|
+
export function normalizeSessionPrompt(value) {
|
|
3
|
+
if (value === null)
|
|
4
|
+
return null;
|
|
5
|
+
if (typeof value !== 'string' || value.trim().length > MAX_CONTENT_LENGTH)
|
|
6
|
+
throw new Error('SESSION_PROMPT_INVALID');
|
|
7
|
+
return value.trim() || null;
|
|
8
|
+
}
|
|
9
|
+
export function withSessionPrompt(personalInstructions, sessionPrompt) {
|
|
10
|
+
const merged = [personalInstructions, sessionPrompt].filter(Boolean).join('\n\n');
|
|
11
|
+
return merged.length === 0 ? undefined : merged;
|
|
12
|
+
}
|
|
2
13
|
export function personalInstructionsForRunner(value, runner) {
|
|
3
14
|
if (value === undefined)
|
|
4
15
|
return undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@myagentroam/node",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.33",
|
|
4
4
|
"description": "MyAgentRoam Node runtime CLI.",
|
|
5
5
|
"license": "Apache-2.0 AND GPL-2.0-or-later",
|
|
6
6
|
"type": "module",
|
|
@@ -37,10 +37,10 @@
|
|
|
37
37
|
"playwright": "1.62.1",
|
|
38
38
|
"ws": "^8.21.3",
|
|
39
39
|
"zod": "4.4.3",
|
|
40
|
-
"@myagentroam/agent": "0.10.
|
|
41
|
-
"@myagentroam/
|
|
42
|
-
"@myagentroam/marctl": "0.10.
|
|
43
|
-
"@myagentroam/
|
|
40
|
+
"@myagentroam/agent": "0.10.33",
|
|
41
|
+
"@myagentroam/protocol": "0.10.33",
|
|
42
|
+
"@myagentroam/marctl": "0.10.5",
|
|
43
|
+
"@myagentroam/code-navigation": "0.10.1"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/ws": "^8.18.1"
|