@myagentroam/node 0.9.135 → 0.9.137
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/codex-app-server.js +14 -0
- package/dist/connector.js +4 -2
- package/dist/node-execution-environment.js +8 -0
- package/dist/runner/abstract-runner.js +35 -4
- package/dist/runner/claude/managed-run-controller.js +8 -1
- package/dist/runner/codex/conversation-parser.js +194 -13
- package/dist/runner/codex/managed-run-controller.js +2 -1
- package/dist/runner/codex/tool-normalizer.js +3 -73
- package/dist/runner/codex-runner.js +113 -10
- package/dist/runner/mar-agent/computer-use.js +1 -0
- package/dist/runner/mar-agent/conversation-normalizer.js +18 -11
- package/dist/runner/mar-agent/hosted-conversation-runtime.js +3 -2
- package/dist/runner/mar-agent/managed-run-controller.js +46 -8
- package/dist/runner/mar-agent/mcp-client-pool.js +253 -29
- package/dist/runner/mar-agent/runtime-model-factory.js +1 -1
- package/dist/runner/mar-agent-runner.js +3 -0
- package/dist/runner/opencode/managed-run-controller.js +2 -1
- package/dist/service/continuous-run-coordinator.js +3 -1
- package/dist/service/conversation-history-service.js +29 -40
- package/dist/service/hosted-conversation-node-service.js +1 -1
- package/dist/service/native-session-watch-service.js +13 -4
- package/dist/service/run-event-service.js +15 -0
- package/dist/service/session-catalog-service.js +3 -4
- package/dist/service/session-message-service.js +4 -2
- package/dist/util/node-operation-parsers.js +1 -3
- package/package.json +6 -5
|
@@ -5,7 +5,7 @@ import { homedir } from 'node:os';
|
|
|
5
5
|
import { resolve } from 'node:path';
|
|
6
6
|
import { discoverAllNativeSessions } from '../native-session-history.js';
|
|
7
7
|
import { readCodexNativeContextUsage } from '../native-session-history.js';
|
|
8
|
-
import { codexThreadCwd, deduplicateDirectSessions, extractCodexThreads, isWithinWorkspace, latestNativeActivity } from './codex/conversation-parser.js';
|
|
8
|
+
import { codexThreadCwd, codexThreadHistoryModes, codexPaginatedThread, codexPaginatedCursor, codexPaginatedConversationPage, deduplicateDirectSessions, extractCodexThreads, isWithinWorkspace, latestNativeActivity } from './codex/conversation-parser.js';
|
|
9
9
|
import { codexSessionControl } from '../codex-app-server.js';
|
|
10
10
|
import { extractId } from '../util/runner-native-session-parsers.js';
|
|
11
11
|
import { nodeLog } from '../operational.js';
|
|
@@ -19,6 +19,8 @@ export class CodexRunner extends AbstractRunner {
|
|
|
19
19
|
discoveryScope = 'ALL_WORKSPACES';
|
|
20
20
|
execution = new CodexExecutionState();
|
|
21
21
|
fastEnabled = false;
|
|
22
|
+
threadHistoryModes = new Map();
|
|
23
|
+
threadHistoryModeReads = new Map();
|
|
22
24
|
runClients = new Map();
|
|
23
25
|
notificationListeners = new Set();
|
|
24
26
|
clientNotificationDisposers = new Map();
|
|
@@ -265,9 +267,36 @@ export class CodexRunner extends AbstractRunner {
|
|
|
265
267
|
return input.title;
|
|
266
268
|
}
|
|
267
269
|
async readConversationHistory(readers) {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
270
|
+
const page = await readers.official();
|
|
271
|
+
return page === undefined ? undefined : { ...page, source: 'official' };
|
|
272
|
+
}
|
|
273
|
+
async readOfficialConversation(session, input, managedTurn, registerImages) {
|
|
274
|
+
if (session.externalSessionId === null)
|
|
275
|
+
return undefined;
|
|
276
|
+
const threadId = session.externalSessionId;
|
|
277
|
+
const cursor = codexPaginatedCursor(session.id, input.cursor);
|
|
278
|
+
const limit = Math.min(Math.max(input.limit ?? 30, 1), 100);
|
|
279
|
+
await this.start();
|
|
280
|
+
await this.readThreadHistoryMode(threadId);
|
|
281
|
+
const page = await this.client.listThreadTurns(threadId, {
|
|
282
|
+
...(cursor === undefined ? {} : { cursor }),
|
|
283
|
+
limit
|
|
284
|
+
});
|
|
285
|
+
const nextCursor = typeof page === 'object' && page !== null && 'nextCursor' in page
|
|
286
|
+
? page.nextCursor
|
|
287
|
+
: undefined;
|
|
288
|
+
let earlierTurnId = null;
|
|
289
|
+
if (typeof nextCursor === 'string') {
|
|
290
|
+
const earlier = await this.client.listThreadTurns(threadId, { cursor: nextCursor, limit: 1 });
|
|
291
|
+
if (typeof earlier !== 'object' ||
|
|
292
|
+
earlier === null ||
|
|
293
|
+
!('data' in earlier) ||
|
|
294
|
+
!Array.isArray(earlier.data) ||
|
|
295
|
+
typeof earlier.data[0]?.id !== 'string')
|
|
296
|
+
throw new Error('NATIVE_TRANSCRIPT_UNAVAILABLE');
|
|
297
|
+
earlierTurnId = earlier.data[0].id;
|
|
298
|
+
}
|
|
299
|
+
return codexPaginatedConversationPage(session, page, earlierTurnId, managedTurn, registerImages);
|
|
271
300
|
}
|
|
272
301
|
acceptsTruncatedNativeHistory() {
|
|
273
302
|
return true;
|
|
@@ -340,7 +369,8 @@ export class CodexRunner extends AbstractRunner {
|
|
|
340
369
|
let threads = [];
|
|
341
370
|
try {
|
|
342
371
|
await this.start();
|
|
343
|
-
|
|
372
|
+
const result = await this.listThreads();
|
|
373
|
+
threads = extractCodexThreads(result);
|
|
344
374
|
}
|
|
345
375
|
catch {
|
|
346
376
|
// Native transcripts remain a valid read-only discovery source.
|
|
@@ -427,7 +457,8 @@ export class CodexRunner extends AbstractRunner {
|
|
|
427
457
|
'session.rename',
|
|
428
458
|
'session.remove',
|
|
429
459
|
'session.pin',
|
|
430
|
-
...(session.externalSessionId === null ? [] : ['session.rewind'])
|
|
460
|
+
...(session.externalSessionId === null ? [] : ['session.rewind']),
|
|
461
|
+
...(this.supportsRollback(session) ? ['session.rollback'] : [])
|
|
431
462
|
],
|
|
432
463
|
reasonCode: null
|
|
433
464
|
}
|
|
@@ -498,6 +529,8 @@ export class CodexRunner extends AbstractRunner {
|
|
|
498
529
|
client.clearEnvironment();
|
|
499
530
|
}
|
|
500
531
|
this.runClients.clear();
|
|
532
|
+
this.threadHistoryModes.clear();
|
|
533
|
+
this.threadHistoryModeReads.clear();
|
|
501
534
|
this.client.stop();
|
|
502
535
|
if (this.profileCacheTimer !== undefined)
|
|
503
536
|
clearTimeout(this.profileCacheTimer);
|
|
@@ -539,11 +572,52 @@ export class CodexRunner extends AbstractRunner {
|
|
|
539
572
|
respond(requestId, result, runId) {
|
|
540
573
|
this.clientFor(runId).respond(requestId, result);
|
|
541
574
|
}
|
|
542
|
-
listThreads() {
|
|
543
|
-
|
|
575
|
+
async listThreads() {
|
|
576
|
+
const result = await this.client.listThreads();
|
|
577
|
+
this.observeThreadHistoryModes(result);
|
|
578
|
+
return result;
|
|
579
|
+
}
|
|
580
|
+
observeThreadHistoryModes(result, expectedThreadId) {
|
|
581
|
+
for (const descriptor of codexThreadHistoryModes(result))
|
|
582
|
+
if (expectedThreadId === undefined || descriptor.id === expectedThreadId)
|
|
583
|
+
this.threadHistoryModes.set(descriptor.id, descriptor.paginated);
|
|
584
|
+
}
|
|
585
|
+
readThreadHistoryMode(threadId) {
|
|
586
|
+
if (this.threadHistoryModes.has(threadId))
|
|
587
|
+
return Promise.resolve();
|
|
588
|
+
const existing = this.threadHistoryModeReads.get(threadId);
|
|
589
|
+
if (existing !== undefined)
|
|
590
|
+
return existing;
|
|
591
|
+
const read = this.client
|
|
592
|
+
.readThread(threadId)
|
|
593
|
+
.then((result) => {
|
|
594
|
+
if (this.threadHistoryModeReads.get(threadId) !== read)
|
|
595
|
+
return;
|
|
596
|
+
if (!this.threadHistoryModes.has(threadId))
|
|
597
|
+
this.observeThreadHistoryModes(result, threadId);
|
|
598
|
+
if (!this.threadHistoryModes.has(threadId))
|
|
599
|
+
this.threadHistoryModes.set(threadId, false);
|
|
600
|
+
})
|
|
601
|
+
.catch(() => {
|
|
602
|
+
// A capability probe must not make otherwise readable history unavailable.
|
|
603
|
+
if (this.threadHistoryModeReads.get(threadId) === read &&
|
|
604
|
+
!this.threadHistoryModes.has(threadId))
|
|
605
|
+
this.threadHistoryModes.set(threadId, false);
|
|
606
|
+
})
|
|
607
|
+
.finally(() => {
|
|
608
|
+
if (this.threadHistoryModeReads.get(threadId) === read)
|
|
609
|
+
this.threadHistoryModeReads.delete(threadId);
|
|
610
|
+
});
|
|
611
|
+
this.threadHistoryModeReads.set(threadId, read);
|
|
612
|
+
return read;
|
|
544
613
|
}
|
|
545
614
|
startThread(cwd, configuration, runId) {
|
|
546
|
-
return this.clientFor(runId)
|
|
615
|
+
return this.clientFor(runId)
|
|
616
|
+
.startThread(cwd, configuration)
|
|
617
|
+
.then((result) => {
|
|
618
|
+
this.observeThreadHistoryModes(result);
|
|
619
|
+
return result;
|
|
620
|
+
});
|
|
547
621
|
}
|
|
548
622
|
forkThread(threadId, cwd, lastTurnId, configuration) {
|
|
549
623
|
return this.client.forkThread(threadId, cwd, lastTurnId, configuration);
|
|
@@ -558,12 +632,41 @@ export class CodexRunner extends AbstractRunner {
|
|
|
558
632
|
? await client.startThread(session.cwd, configuration)
|
|
559
633
|
: await client.forkThread(threadId, session.cwd, boundary, configuration);
|
|
560
634
|
const forkedThreadId = extractId(result, 'thread');
|
|
635
|
+
this.observeThreadHistoryModes(result);
|
|
561
636
|
await client.setThreadName(forkedThreadId, title);
|
|
562
637
|
return forkedThreadId;
|
|
563
638
|
});
|
|
564
639
|
}
|
|
640
|
+
supportsRollback(session) {
|
|
641
|
+
return (session.externalSessionId !== null &&
|
|
642
|
+
this.threadHistoryModes.get(session.externalSessionId) === true);
|
|
643
|
+
}
|
|
644
|
+
async rollbackNative(session, boundary, targetTurnBoundary) {
|
|
645
|
+
void boundary;
|
|
646
|
+
if (!this.supportsRollback(session) || targetTurnBoundary === undefined)
|
|
647
|
+
throw new Error('SESSION_ROLLBACK_UNAVAILABLE');
|
|
648
|
+
const threadId = session.externalSessionId;
|
|
649
|
+
return this.withTemporaryClient(async (client) => {
|
|
650
|
+
const resumed = await client.resumeThread(threadId, session.cwd, {
|
|
651
|
+
model: session.model,
|
|
652
|
+
effort: session.effort,
|
|
653
|
+
access: session.access
|
|
654
|
+
});
|
|
655
|
+
if (!codexPaginatedThread(resumed)) {
|
|
656
|
+
this.threadHistoryModes.set(threadId, false);
|
|
657
|
+
throw new Error('SESSION_ROLLBACK_UNAVAILABLE');
|
|
658
|
+
}
|
|
659
|
+
await client.revertThread(threadId, targetTurnBoundary);
|
|
660
|
+
return Date.now();
|
|
661
|
+
});
|
|
662
|
+
}
|
|
565
663
|
resumeThread(threadId, cwd, configuration, runId) {
|
|
566
|
-
return this.clientFor(runId)
|
|
664
|
+
return this.clientFor(runId)
|
|
665
|
+
.resumeThread(threadId, cwd, configuration)
|
|
666
|
+
.then((result) => {
|
|
667
|
+
this.observeThreadHistoryModes(result, threadId);
|
|
668
|
+
return result;
|
|
669
|
+
});
|
|
567
670
|
}
|
|
568
671
|
startTurn(threadId, text, cwd, configuration, attachments, runId) {
|
|
569
672
|
return this.clientFor(runId).startTurn(threadId, text, cwd, configuration, attachments);
|
|
@@ -30,16 +30,18 @@ export class MarAgentConversationNormalizer {
|
|
|
30
30
|
}
|
|
31
31
|
if (event.type === 'message.completed') {
|
|
32
32
|
const modelName = record(event)?.modelName;
|
|
33
|
+
const itemId = this.messageItemId(event.itemId);
|
|
34
|
+
const payload = {
|
|
35
|
+
text: event.text,
|
|
36
|
+
format: 'markdown',
|
|
37
|
+
model: typeof modelName === 'string' ? modelName : null
|
|
38
|
+
};
|
|
33
39
|
return [
|
|
34
40
|
{
|
|
35
|
-
itemId
|
|
41
|
+
itemId,
|
|
36
42
|
kind: 'assistant_message',
|
|
37
43
|
status: 'COMPLETED',
|
|
38
|
-
payload
|
|
39
|
-
text: event.text,
|
|
40
|
-
format: 'markdown',
|
|
41
|
-
model: typeof modelName === 'string' ? modelName : null
|
|
42
|
-
}
|
|
44
|
+
payload
|
|
43
45
|
}
|
|
44
46
|
];
|
|
45
47
|
}
|
|
@@ -61,12 +63,17 @@ export class MarAgentConversationNormalizer {
|
|
|
61
63
|
payload: { sections: [{ index: 0, text: compactRunnerText(event.text, 10_000) }] }
|
|
62
64
|
}
|
|
63
65
|
];
|
|
64
|
-
if (event.type === 'tool.started'
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
if (event.type === 'tool.started' ||
|
|
67
|
+
event.type === 'tool.completed' ||
|
|
68
|
+
event.type === 'tool.failed') {
|
|
69
|
+
if (event.parentCallId !== undefined)
|
|
70
|
+
return [];
|
|
71
|
+
if (event.type === 'tool.started')
|
|
72
|
+
return this.#toolStarted(event);
|
|
73
|
+
if (event.type === 'tool.completed')
|
|
74
|
+
return this.#toolCompleted(event);
|
|
69
75
|
return this.#toolFailed(event);
|
|
76
|
+
}
|
|
70
77
|
if (event.type === 'hosted_tool.updated') {
|
|
71
78
|
const sourceSummary = event.summary.sources
|
|
72
79
|
?.slice(0, 20)
|
|
@@ -228,6 +228,7 @@ export class MarAgentHostedConversationRuntime {
|
|
|
228
228
|
: undefined;
|
|
229
229
|
const mcp = 'mcpServers' in input && input.mcpServers.length > 0
|
|
230
230
|
? await MarAgentMcpClientPool.connect(input.mcpServers, input.workspaceDirectory, {
|
|
231
|
+
authorizationScope: JSON.stringify([input.homeDirectory, input.sessionId]),
|
|
231
232
|
processExecutor: input.processExecutor,
|
|
232
233
|
owner: {
|
|
233
234
|
sessionId: input.sessionId,
|
|
@@ -270,8 +271,8 @@ export class MarAgentHostedConversationRuntime {
|
|
|
270
271
|
...(mcp === undefined
|
|
271
272
|
? {}
|
|
272
273
|
: {
|
|
273
|
-
|
|
274
|
-
callMcp: (call) => mcp.call(call.name, call.arguments)
|
|
274
|
+
mcpCatalog: () => mcp.catalog(),
|
|
275
|
+
callMcp: (call, signal, context) => mcp.call(call.name, call.arguments, signal, context?.expectedTool)
|
|
275
276
|
}),
|
|
276
277
|
allowUntrustedTls: false
|
|
277
278
|
});
|
|
@@ -163,7 +163,8 @@ export class MarAgentManagedRunController {
|
|
|
163
163
|
const mcpSecretEnvironment = parseSecretEnvironment(payload.mcpSecretEnvironment);
|
|
164
164
|
mcpServers = this.runner.mcpConfiguration(payload.mcpInstallations, {
|
|
165
165
|
...secretEnvironment,
|
|
166
|
-
...mcpSecretEnvironment
|
|
166
|
+
...mcpSecretEnvironment,
|
|
167
|
+
MAR_USERNAME: secretEnvironment['MAR_USERNAME'] ?? ''
|
|
167
168
|
});
|
|
168
169
|
if (mcpServers.some((server) => server.name === 'computer'))
|
|
169
170
|
throw new Error('MAR_AGENT_MCP_RESERVED_NAMESPACE');
|
|
@@ -271,6 +272,7 @@ export class MarAgentManagedRunController {
|
|
|
271
272
|
if (runtime.activeRunId !== undefined)
|
|
272
273
|
throw new Error('MAR_AGENT_SESSION_RUNTIME_ACTIVE');
|
|
273
274
|
runtime.activeRunId = input.runId;
|
|
275
|
+
await runtime.mcpLease.pool.refreshForExecution();
|
|
274
276
|
const executionMcpServers = input.mcpServers.filter((server) => server.lifecycle === 'EXECUTION');
|
|
275
277
|
computerUseBinding = await this.#computerUse?.bind({
|
|
276
278
|
runId: input.runId,
|
|
@@ -290,7 +292,8 @@ export class MarAgentManagedRunController {
|
|
|
290
292
|
}
|
|
291
293
|
if (executionMcpServers.length > 0) {
|
|
292
294
|
executionMcpLease = await this.#mcpClients.acquire(executionMcpServers, input.cwd, {
|
|
293
|
-
reusable: false
|
|
295
|
+
reusable: false,
|
|
296
|
+
authorizationScope: runtime.session.id
|
|
294
297
|
});
|
|
295
298
|
}
|
|
296
299
|
const userTools = executionMcpLease?.pool.definitions() ?? [];
|
|
@@ -311,11 +314,37 @@ export class MarAgentManagedRunController {
|
|
|
311
314
|
skills: [...(imageExtensions.skills ?? []), computerUseHostSkill]
|
|
312
315
|
}, {
|
|
313
316
|
tools: [...nodeTools, ...userTools],
|
|
314
|
-
|
|
317
|
+
catalog: () => {
|
|
318
|
+
const external = executionMcpLease?.pool.catalog() ?? {
|
|
319
|
+
revision: '',
|
|
320
|
+
servers: [],
|
|
321
|
+
tools: []
|
|
322
|
+
};
|
|
323
|
+
const computer = nodeTools.map((definition) => ({
|
|
324
|
+
definition,
|
|
325
|
+
serverId: 'computer',
|
|
326
|
+
rawName: definition.name,
|
|
327
|
+
sourceIdentity: `node:${input.runId}:computer`,
|
|
328
|
+
definitionRevision: createHash('sha256')
|
|
329
|
+
.update(JSON.stringify(definition))
|
|
330
|
+
.digest('hex'),
|
|
331
|
+
lifetime: 'execution',
|
|
332
|
+
exposure: 'direct'
|
|
333
|
+
}));
|
|
334
|
+
return {
|
|
335
|
+
revision: `${external.revision}:${input.runId}`,
|
|
336
|
+
servers: [
|
|
337
|
+
...external.servers,
|
|
338
|
+
...(computer.length ? [{ id: 'computer', name: 'Computer' }] : [])
|
|
339
|
+
],
|
|
340
|
+
tools: [...external.tools, ...computer]
|
|
341
|
+
};
|
|
342
|
+
},
|
|
343
|
+
call: async (call, signal, context) => {
|
|
315
344
|
if (computerUseBinding?.tools.some((tool) => tool.name === call.name))
|
|
316
345
|
return computerUseBinding.call(call, signal);
|
|
317
346
|
if (executionMcpLease?.pool.definitions().some((tool) => tool.name === call.name))
|
|
318
|
-
return executionMcpLease.pool.call(call.name, call.arguments);
|
|
347
|
+
return executionMcpLease.pool.call(call.name, call.arguments, signal, context?.expectedTool);
|
|
319
348
|
throw new Error('MAR_AGENT_MCP_TOOL_NOT_FOUND');
|
|
320
349
|
}
|
|
321
350
|
});
|
|
@@ -472,7 +501,11 @@ export class MarAgentManagedRunController {
|
|
|
472
501
|
const dynamicCredentials = input.models.some((model) => model.credential?.type === 'RUNTIME_TICKET' ||
|
|
473
502
|
model.imageGeneration?.credential?.type === 'RUNTIME_TICKET');
|
|
474
503
|
const sharedMcpServers = input.mcpServers.filter((server) => server.lifecycle !== 'EXECUTION');
|
|
475
|
-
const mcpLease = await this.#mcpClients.acquire(sharedMcpServers, input.cwd
|
|
504
|
+
const mcpLease = await this.#mcpClients.acquire(sharedMcpServers, input.cwd, {
|
|
505
|
+
// Native Session IDs are assigned after the first lease; do not let that promotion
|
|
506
|
+
// change a confirmed actor's discovery identity when its warm runtime is recreated.
|
|
507
|
+
authorizationScope: input.secretEnvironment?.['MAR_USERNAME'] ? input.cwd : sessionKey
|
|
508
|
+
});
|
|
476
509
|
let agent;
|
|
477
510
|
let runtime;
|
|
478
511
|
let models = [];
|
|
@@ -488,8 +521,8 @@ export class MarAgentManagedRunController {
|
|
|
488
521
|
const runId = runtime?.activeRunId;
|
|
489
522
|
return runId === undefined ? {} : this.requestQuestion(runId, request, signal);
|
|
490
523
|
},
|
|
491
|
-
|
|
492
|
-
callMcp: async (call) => mcp.call(call.name, call.arguments),
|
|
524
|
+
mcpCatalog: () => mcp.catalog(),
|
|
525
|
+
callMcp: async (call, signal, context) => mcp.call(call.name, call.arguments, signal, context?.expectedTool),
|
|
493
526
|
webSearch: (request, signal) => this.host.webSearch(request, signal),
|
|
494
527
|
allowUntrustedTls: allowsUntrustedWebFetchTls(hostConfiguration.environment),
|
|
495
528
|
resourceIdleTtlMs: this.#resourceIdleTtlMs
|
|
@@ -635,7 +668,12 @@ export class MarAgentManagedRunController {
|
|
|
635
668
|
project(runId, event) {
|
|
636
669
|
if (contextUsageChanged(event))
|
|
637
670
|
this.host.refreshContext?.(runId);
|
|
638
|
-
if (event.type === '
|
|
671
|
+
if (event.type === 'model.performance')
|
|
672
|
+
this.host.emit(runId, 'run.performance', {
|
|
673
|
+
latencyMs: event.latencyMs,
|
|
674
|
+
...(event.tokensPerSecond === undefined ? {} : { tokensPerSecond: event.tokensPerSecond })
|
|
675
|
+
});
|
|
676
|
+
else if (event.type === 'message.delta')
|
|
639
677
|
this.host.emit(runId, 'text.delta', {
|
|
640
678
|
text: event.delta,
|
|
641
679
|
phase: event.phase,
|