@myagentroam/node 0.11.73 → 0.12.0
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/runner/mar-agent/hosted-conversation-runtime.js +3 -2
- package/dist/runner/mar-agent/runtime-extensions.js +33 -0
- package/dist/runner/mar-agent/session-runtime.js +5 -4
- package/dist/runner/mar-agent-runner.js +33 -45
- package/dist/session/native-session-projection-service.js +1 -2
- package/dist/session/session-catalog-service.js +71 -25
- package/package.json +4 -4
|
@@ -9,7 +9,8 @@ import { MarAgentRuntimeModelFactory, sdkModelConfigurations, closeImageCredenti
|
|
|
9
9
|
import { createImageGenerationExtensions } from './image-generation-extensions.js';
|
|
10
10
|
import { createWebToolsExtensions } from './web-tools-extensions.js';
|
|
11
11
|
import { combineExecutionExtensions } from './execution-extensions.js';
|
|
12
|
-
import { compactRuntimeConfigurations,
|
|
12
|
+
import { compactRuntimeConfigurations, updateMarAgentCompactState } from './compact-extensions.js';
|
|
13
|
+
import { marAgentRuntimeExtensionSource } from './runtime-extensions.js';
|
|
13
14
|
import { webSessionScope } from '../../service/web-fetch-contracts.js';
|
|
14
15
|
/**
|
|
15
16
|
* Opens one short-lived MAR Agent Host per hosted Run so template mounts cannot leak across Run
|
|
@@ -391,7 +392,7 @@ export class MarAgentHostedConversationRuntime {
|
|
|
391
392
|
mode: 'node',
|
|
392
393
|
host,
|
|
393
394
|
models: sdkModelConfigurations(models.filter((model) => input.models.some((candidate) => candidate.id === model.id))),
|
|
394
|
-
extensions:
|
|
395
|
+
extensions: marAgentRuntimeExtensionSource(compactState),
|
|
395
396
|
defaultModelId: 'defaultModelId' in input ? input.defaultModelId : input.modelId,
|
|
396
397
|
workspaceMapping: {
|
|
397
398
|
logicalPath: '/workspace',
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { marAgentCompactExtensionSource } from './compact-extensions.js';
|
|
2
|
+
export function marAgentRuntimeExtensionSource(state) {
|
|
3
|
+
const compactSource = marAgentCompactExtensionSource(state);
|
|
4
|
+
return {
|
|
5
|
+
async resolve(request) {
|
|
6
|
+
const snapshot = await compactSource.resolve(request);
|
|
7
|
+
return {
|
|
8
|
+
...snapshot,
|
|
9
|
+
extensions: [
|
|
10
|
+
...snapshot.extensions,
|
|
11
|
+
{
|
|
12
|
+
id: 'mar.node.file-links',
|
|
13
|
+
apiVersion: '1.0',
|
|
14
|
+
attachSession(context) {
|
|
15
|
+
context.hooks.intercept('prompt.sections', (input, _call, next) => next({
|
|
16
|
+
...input,
|
|
17
|
+
sections: [
|
|
18
|
+
...input.sections,
|
|
19
|
+
{
|
|
20
|
+
id: 'mar.node.file-links',
|
|
21
|
+
text: input.facts?.mode === 'compact'
|
|
22
|
+
? null
|
|
23
|
+
: 'When mentioning key files changed in this task, prefer Markdown links to their absolute paths for easy preview.'
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -9,7 +9,8 @@ import { nodeExecutionEnvironment } from '../../node-execution-environment.js';
|
|
|
9
9
|
import { nodeLog } from '../../operational.js';
|
|
10
10
|
import { BUNDLED_RIPGREP_VERSION, bundledRipgrepPath, prependBundledRipgrepToPath } from '../../ripgrep-binary.js';
|
|
11
11
|
import { canonicalJson } from '../../util/canonical-json.js';
|
|
12
|
-
import { compactRuntimeConfigurations,
|
|
12
|
+
import { compactRuntimeConfigurations, updateMarAgentCompactState } from './compact-extensions.js';
|
|
13
|
+
import { marAgentRuntimeExtensionSource } from './runtime-extensions.js';
|
|
13
14
|
import { MarAgentConversationNormalizer } from './conversation-normalizer.js';
|
|
14
15
|
import { sdkModelConfigurations } from './runtime-model-factory.js';
|
|
15
16
|
export const HOST_CONFIGURATION_CATEGORIES = [
|
|
@@ -72,7 +73,7 @@ export async function createSessionRuntime(input, sessionKey, fingerprint, hostC
|
|
|
72
73
|
});
|
|
73
74
|
const compactState = { revision: 0 };
|
|
74
75
|
updateMarAgentCompactState(compactState, input.compact, models, input.models.map((model) => model.id));
|
|
75
|
-
const
|
|
76
|
+
const runtimeSource = marAgentRuntimeExtensionSource(compactState);
|
|
76
77
|
const networkProvider = networkContext;
|
|
77
78
|
agent = await dependencies.createAgent({
|
|
78
79
|
mode: 'node',
|
|
@@ -80,10 +81,10 @@ export async function createSessionRuntime(input, sessionKey, fingerprint, hostC
|
|
|
80
81
|
models: sdkModelConfigurations(models.filter((model) => input.models.some((candidate) => candidate.id === model.id))),
|
|
81
82
|
defaultModelId: input.model.id,
|
|
82
83
|
extensions: networkProvider === undefined
|
|
83
|
-
?
|
|
84
|
+
? runtimeSource
|
|
84
85
|
: {
|
|
85
86
|
async resolve(request) {
|
|
86
|
-
const snapshot = await
|
|
87
|
+
const snapshot = await runtimeSource.resolve(request);
|
|
87
88
|
return {
|
|
88
89
|
...snapshot,
|
|
89
90
|
extensions: [
|
|
@@ -310,45 +310,32 @@ export class MarAgentRunner extends AbstractRunner {
|
|
|
310
310
|
try {
|
|
311
311
|
catalog = await openAgentSessionCatalog({ homeDirectory: this.homeDirectory });
|
|
312
312
|
const activeCatalog = catalog;
|
|
313
|
-
const listed = await activeCatalog.list({ limit: 200 });
|
|
314
|
-
if (context.cleanup) {
|
|
315
|
-
const sessions = [...listed.sessions];
|
|
316
|
-
let cursor = listed.nextCursor;
|
|
317
|
-
while (cursor !== undefined) {
|
|
318
|
-
const next = await activeCatalog.list({ limit: 200, cursor });
|
|
319
|
-
sessions.push(...next.sessions);
|
|
320
|
-
cursor = next.nextCursor;
|
|
321
|
-
}
|
|
322
|
-
const workspaces = workspace ? [workspace] : context.workspaces;
|
|
323
|
-
return sessions.flatMap((session) => {
|
|
324
|
-
const target = workspaces.find((candidate) => resolve(candidate.path) === resolve(session.workspace));
|
|
325
|
-
return target
|
|
326
|
-
? [
|
|
327
|
-
context.createProjection({
|
|
328
|
-
workspace: target,
|
|
329
|
-
runner: this.name,
|
|
330
|
-
externalSessionId: session.id,
|
|
331
|
-
cwd: session.workspace,
|
|
332
|
-
...(session.source?.parentSessionId === undefined
|
|
333
|
-
? {}
|
|
334
|
-
: { parentSessionId: session.source.parentSessionId }),
|
|
335
|
-
lastActivityAt: Date.parse(session.lastActivityAt)
|
|
336
|
-
})
|
|
337
|
-
]
|
|
338
|
-
: [];
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
313
|
const workspaces = workspace ? [workspace] : context.workspaces;
|
|
342
|
-
|
|
314
|
+
const sessions = (await activeCatalog.listSnapshot()).flatMap((session) => {
|
|
343
315
|
const target = workspaces.find((candidate) => resolve(candidate.path) === resolve(session.workspace));
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
:
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
316
|
+
return target ? [{ session, target }] : [];
|
|
317
|
+
});
|
|
318
|
+
if (context.cleanup) {
|
|
319
|
+
return sessions.map(({ session, target }) => context.createProjection({
|
|
320
|
+
workspace: target,
|
|
321
|
+
runner: this.name,
|
|
322
|
+
externalSessionId: session.id,
|
|
323
|
+
cwd: session.workspace,
|
|
324
|
+
...(session.source?.parentSessionId === undefined
|
|
325
|
+
? {}
|
|
326
|
+
: { parentSessionId: session.source.parentSessionId }),
|
|
327
|
+
lastActivityAt: Date.parse(session.lastActivityAt)
|
|
328
|
+
}));
|
|
329
|
+
}
|
|
330
|
+
const discovered = [];
|
|
331
|
+
const batchSize = 8;
|
|
332
|
+
for (let offset = 0; offset < sessions.length; offset += batchSize) {
|
|
333
|
+
const batch = await Promise.allSettled(sessions.slice(offset, offset + batchSize).map(async ({ session, target }) => {
|
|
334
|
+
const executionConfiguration = session.modelId === undefined
|
|
335
|
+
? await activeCatalog.executionConfiguration(session.id)
|
|
336
|
+
: session;
|
|
337
|
+
const title = await marAgentSessionTitle(session, activeCatalog);
|
|
338
|
+
return {
|
|
352
339
|
...context.createProjection({
|
|
353
340
|
workspace: target,
|
|
354
341
|
runner: this.name,
|
|
@@ -366,14 +353,15 @@ export class MarAgentRunner extends AbstractRunner {
|
|
|
366
353
|
...(executionConfiguration?.reasoningEffort === undefined
|
|
367
354
|
? {}
|
|
368
355
|
: { effort: executionConfiguration.reasoningEffort })
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
356
|
+
};
|
|
357
|
+
}));
|
|
358
|
+
for (const entry of batch) {
|
|
359
|
+
if (entry.status === 'rejected')
|
|
360
|
+
throw entry.reason;
|
|
361
|
+
discovered.push(entry.value);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return discovered;
|
|
377
365
|
}
|
|
378
366
|
finally {
|
|
379
367
|
await catalog?.close().catch(() => undefined);
|
|
@@ -361,8 +361,7 @@ export class NativeSessionProjectionService {
|
|
|
361
361
|
projectionForNative(native) {
|
|
362
362
|
return this.resolveNativeProjection(native, this.options.runtime, false);
|
|
363
363
|
}
|
|
364
|
-
projectionsForNative(native) {
|
|
365
|
-
const lookup = this.options.runtime.createSessionLookup();
|
|
364
|
+
projectionsForNative(native, lookup = this.options.runtime.createSessionLookup()) {
|
|
366
365
|
return new Map(native.map((session) => [session, this.resolveNativeProjection(session, lookup, false)]));
|
|
367
366
|
}
|
|
368
367
|
managedForNative(native) {
|
|
@@ -76,7 +76,7 @@ export class SessionCatalogService {
|
|
|
76
76
|
ancestors.add(parent.id);
|
|
77
77
|
root = parent;
|
|
78
78
|
}
|
|
79
|
-
const project = this.navigationProjector(input.workspaceId);
|
|
79
|
+
const { project } = this.navigationProjector(input.workspaceId, (id) => sessionActivityStatus(this.options.runtime, id));
|
|
80
80
|
const queue = [root];
|
|
81
81
|
const visited = new Set([root.id]);
|
|
82
82
|
const nodes = [];
|
|
@@ -97,10 +97,26 @@ export class SessionCatalogService {
|
|
|
97
97
|
}
|
|
98
98
|
navigation(query) {
|
|
99
99
|
const database = this.options.database();
|
|
100
|
-
const
|
|
100
|
+
const statuses = new Map();
|
|
101
|
+
const status = (id) => {
|
|
102
|
+
const cached = statuses.get(id);
|
|
103
|
+
if (cached !== undefined)
|
|
104
|
+
return cached;
|
|
105
|
+
const value = sessionActivityStatus(this.options.runtime, id);
|
|
106
|
+
statuses.set(id, value);
|
|
107
|
+
return value;
|
|
108
|
+
};
|
|
109
|
+
let projection;
|
|
110
|
+
const projector = () => (projection ??= this.navigationProjector(query.workspaceId, status));
|
|
111
|
+
const project = (record) => projector().project(record);
|
|
112
|
+
const registered = new Map();
|
|
101
113
|
const get = (id) => {
|
|
114
|
+
if (registered.has(id))
|
|
115
|
+
return registered.get(id);
|
|
102
116
|
const record = database.getSessionRecord(id);
|
|
103
|
-
|
|
117
|
+
const scoped = record?.workspaceId === query.workspaceId ? record : undefined;
|
|
118
|
+
registered.set(id, scoped);
|
|
119
|
+
return scoped;
|
|
104
120
|
};
|
|
105
121
|
const requestedIds = new Set([
|
|
106
122
|
...query.sessionIds,
|
|
@@ -113,19 +129,13 @@ export class SessionCatalogService {
|
|
|
113
129
|
return record === undefined ? [] : [project(record)];
|
|
114
130
|
});
|
|
115
131
|
const descendantsByAnchor = new Map();
|
|
116
|
-
const statuses = new Map();
|
|
117
|
-
const status = (id) => {
|
|
118
|
-
const cached = statuses.get(id);
|
|
119
|
-
if (cached !== undefined)
|
|
120
|
-
return cached;
|
|
121
|
-
const value = sessionActivityStatus(this.options.runtime, id);
|
|
122
|
-
statuses.set(id, value);
|
|
123
|
-
return value;
|
|
124
|
-
};
|
|
125
132
|
const descendants = (anchor) => {
|
|
126
133
|
let records = descendantsByAnchor.get(anchor);
|
|
127
134
|
if (records === undefined) {
|
|
128
|
-
|
|
135
|
+
const tree = database.sessionTreeRecords(query.workspaceId, anchor);
|
|
136
|
+
for (const record of tree)
|
|
137
|
+
registered.set(record.id, record);
|
|
138
|
+
records = tree.slice(1);
|
|
129
139
|
descendantsByAnchor.set(anchor, records);
|
|
130
140
|
}
|
|
131
141
|
return records;
|
|
@@ -166,12 +176,32 @@ export class SessionCatalogService {
|
|
|
166
176
|
activePaths.add(record.metadata.parentSessionId);
|
|
167
177
|
}
|
|
168
178
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
];
|
|
179
|
+
const activity = new Map(records.map((record) => [record.id, projector().lastActivityAt(record)]));
|
|
180
|
+
const compare = (left, right) => Number(activePaths.has(right.id)) - Number(activePaths.has(left.id)) ||
|
|
181
|
+
activity.get(right.id) - activity.get(left.id) ||
|
|
182
|
+
(left.id < right.id ? -1 : left.id > right.id ? 1 : 0);
|
|
183
|
+
const prioritized = [...records].sort(compare);
|
|
184
|
+
const byId = new Map(records.map((record) => [record.id, record]));
|
|
185
|
+
const selected = new Map();
|
|
186
|
+
const fill = (candidates) => {
|
|
187
|
+
for (const record of candidates) {
|
|
188
|
+
if (selected.size >= query.limit)
|
|
189
|
+
break;
|
|
190
|
+
const path = [];
|
|
191
|
+
let current = record;
|
|
192
|
+
while (current !== undefined && !selected.has(current.id)) {
|
|
193
|
+
path.push(current);
|
|
194
|
+
current = byId.get(current.metadata.parentSessionId ?? '');
|
|
195
|
+
}
|
|
196
|
+
if (path.length > query.limit - selected.size)
|
|
197
|
+
continue;
|
|
198
|
+
for (const ancestor of path.reverse())
|
|
199
|
+
selected.set(ancestor.id, ancestor);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
// An unfit path must not consume slots before another active session that can fit.
|
|
203
|
+
fill(prioritized.filter((record) => status(record.id) !== 'IDLE'));
|
|
204
|
+
fill(prioritized);
|
|
175
205
|
const parent = anchor?.metadata.parentSessionId
|
|
176
206
|
? get(anchor.metadata.parentSessionId)
|
|
177
207
|
: undefined;
|
|
@@ -180,23 +210,28 @@ export class SessionCatalogService {
|
|
|
180
210
|
: {
|
|
181
211
|
anchorSessionId: anchor.id,
|
|
182
212
|
parent: parent === undefined ? null : project(parent),
|
|
183
|
-
nodes:
|
|
213
|
+
nodes: [...selected.values()].sort(compare).map(project),
|
|
184
214
|
truncated: records.length > query.limit
|
|
185
215
|
};
|
|
186
216
|
return { sessions, summaries, tree, missingSessionIds };
|
|
187
217
|
}
|
|
188
|
-
navigationProjector(workspaceId) {
|
|
218
|
+
navigationProjector(workspaceId, status) {
|
|
219
|
+
const lookup = this.options.runtime.createSessionLookup();
|
|
189
220
|
const native = this.options
|
|
190
221
|
.cachedNative()
|
|
191
222
|
.filter((session) => session.workspaceId === workspaceId);
|
|
192
|
-
const projections = this.options.projection.projectionsForNative(native);
|
|
223
|
+
const projections = this.options.projection.projectionsForNative(native, lookup);
|
|
193
224
|
const activityById = new Map();
|
|
194
225
|
for (const source of native) {
|
|
195
226
|
const id = projections.get(source)?.id ?? source.id;
|
|
196
227
|
activityById.set(id, latestSessionActivityAt(activityById.get(id) ?? 0, source.lastActivityAt));
|
|
197
228
|
}
|
|
198
|
-
|
|
199
|
-
|
|
229
|
+
const current = (session) => lookup.getAgentSessionById(session.id) ??
|
|
230
|
+
lookup.findAgentSessionByExternalSession(session.runner, session.id, workspaceId);
|
|
231
|
+
const lastActivityAt = (session) => latestSessionActivityAt(current(session)?.lastActivityAt ?? 0, activityById.get(session.id) ?? 0);
|
|
232
|
+
const projected = new Map();
|
|
233
|
+
const project = (session) => {
|
|
234
|
+
const active = current(session);
|
|
200
235
|
const live = active === undefined ? undefined : this.options.present(active);
|
|
201
236
|
return {
|
|
202
237
|
id: session.id,
|
|
@@ -208,10 +243,21 @@ export class SessionCatalogService {
|
|
|
208
243
|
'Untitled session',
|
|
209
244
|
runner: session.runner,
|
|
210
245
|
activity: live && 'activity' in live ? live.activity : 'IDLE',
|
|
211
|
-
status:
|
|
246
|
+
status: status(session.id),
|
|
212
247
|
lastActivityAt: latestSessionActivityAt(live?.lastActivityAt ?? 0, activityById.get(session.id) ?? 0)
|
|
213
248
|
};
|
|
214
249
|
};
|
|
250
|
+
return {
|
|
251
|
+
lastActivityAt,
|
|
252
|
+
project: (session) => {
|
|
253
|
+
let value = projected.get(session.id);
|
|
254
|
+
if (value === undefined) {
|
|
255
|
+
value = project(session);
|
|
256
|
+
projected.set(session.id, value);
|
|
257
|
+
}
|
|
258
|
+
return value;
|
|
259
|
+
}
|
|
260
|
+
};
|
|
215
261
|
}
|
|
216
262
|
async collect(input) {
|
|
217
263
|
const workspaceId = typeof input.workspaceId === 'string' ? input.workspaceId : undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@myagentroam/node",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "MyAgentRoam Node runtime CLI.",
|
|
5
5
|
"license": "Apache-2.0 AND GPL-2.0-or-later",
|
|
6
6
|
"type": "module",
|
|
@@ -40,10 +40,10 @@
|
|
|
40
40
|
"turndown-plugin-gfm": "^1.0.2",
|
|
41
41
|
"ws": "^8.21.3",
|
|
42
42
|
"zod": "4.4.3",
|
|
43
|
-
"@myagentroam/agent": "0.
|
|
43
|
+
"@myagentroam/agent": "0.12.0",
|
|
44
|
+
"@myagentroam/marctl": "0.12.0",
|
|
44
45
|
"@myagentroam/code-navigation": "0.11.1",
|
|
45
|
-
"@myagentroam/protocol": "0.
|
|
46
|
-
"@myagentroam/marctl": "0.11.12"
|
|
46
|
+
"@myagentroam/protocol": "0.12.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@types/turndown": "^5.0.6",
|