@xenosystem/agent-interface-electron-host 0.1.3 → 0.1.5
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/sdkAgent.d.ts +44 -0
- package/dist/sdkAgent.d.ts.map +1 -1
- package/dist/sdkAgent.js +147 -112
- package/dist/sdkAgent.js.map +1 -1
- package/dist/sdkNativeHeadlessRunner.d.ts +2 -0
- package/dist/sdkNativeHeadlessRunner.d.ts.map +1 -1
- package/dist/sdkNativeHeadlessRunner.js +27 -1
- package/dist/sdkNativeHeadlessRunner.js.map +1 -1
- package/dist/sdkNativeRunner.d.ts +2 -0
- package/dist/sdkNativeRunner.d.ts.map +1 -1
- package/dist/sdkNativeRunner.js +18 -1
- package/dist/sdkNativeRunner.js.map +1 -1
- package/package.json +3 -3
package/dist/sdkAgent.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* built-in tools (Read, Write, Edit, Glob, Grep, Bash).
|
|
10
10
|
*/
|
|
11
11
|
import { type PermissionWaitListener } from '@xenosystem/agent-interface-host';
|
|
12
|
+
import { type CommandExecutionResult } from '@xenosystem/agent-interface-host/node';
|
|
12
13
|
export type { SdkAgentSurface } from './sdkAgentSurface.js';
|
|
13
14
|
import type { SdkAgentSurface } from './sdkAgentSurface.js';
|
|
14
15
|
import { type AgentPermissionProfileName, type AgentSandboxCapabilities, type RuntimeEventEnvelope, type RuntimeEventStore } from '@xenosystem/agent-interface-host/node';
|
|
@@ -41,6 +42,21 @@ export interface SurfaceApprovalRule {
|
|
|
41
42
|
label?: string;
|
|
42
43
|
createdAt?: number;
|
|
43
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Push a pinned node into the loop currently running for a conversation.
|
|
47
|
+
*
|
|
48
|
+
* Returns `undefined` when nothing is running — the caller turns that into a refusal that names
|
|
49
|
+
* the reason, rather than throwing, because "no turn is in flight" is a fact the operator can act
|
|
50
|
+
* on by starting one.
|
|
51
|
+
*/
|
|
52
|
+
export declare function injectContextIntoActiveRun(conversationId: string, input: {
|
|
53
|
+
content: string;
|
|
54
|
+
sourceNodeId?: string;
|
|
55
|
+
label?: string;
|
|
56
|
+
}): Promise<{
|
|
57
|
+
status: 'injected' | 'deferred';
|
|
58
|
+
pendingCount: number;
|
|
59
|
+
} | undefined>;
|
|
44
60
|
export declare function logAgentDebug(message: string, meta?: Record<string, unknown>): void;
|
|
45
61
|
export type { AgentPermissionProfileName, AgentSandboxCapabilities, } from '@xenosystem/agent-interface-host/node';
|
|
46
62
|
export interface SdkAgentRunOptions {
|
|
@@ -56,6 +72,12 @@ export interface SdkAgentRunOptions {
|
|
|
56
72
|
role: string;
|
|
57
73
|
content: string;
|
|
58
74
|
}>;
|
|
75
|
+
/** XENO SPAWN §2.2 pin-forward queued between turns; delivered via `AgentLoop.injectContext()`. */
|
|
76
|
+
injections?: Array<{
|
|
77
|
+
content: string;
|
|
78
|
+
label?: string;
|
|
79
|
+
sourceNodeId?: string;
|
|
80
|
+
}>;
|
|
59
81
|
systemPrompt?: string;
|
|
60
82
|
maxIterations?: number;
|
|
61
83
|
enableThinking?: boolean;
|
|
@@ -97,6 +119,28 @@ export interface SdkAgentRunOptions {
|
|
|
97
119
|
* unlocks `debug-bypass`, so it must never be reached by default.
|
|
98
120
|
*/
|
|
99
121
|
isProduction?: boolean;
|
|
122
|
+
/**
|
|
123
|
+
* Where this turn's Bash/PowerShell commands execute — ADE §5.3.
|
|
124
|
+
*
|
|
125
|
+
* Absent keeps today's local executor. Present is what lets a composition
|
|
126
|
+
* confine the agent without this file knowing about sandboxes.
|
|
127
|
+
*/
|
|
128
|
+
executionEnvironment?: AgentCommandExecutionEnvironment;
|
|
129
|
+
}
|
|
130
|
+
export interface AgentCommandExecutionEnvironment {
|
|
131
|
+
resolutionForConversation(conversationId: string | undefined): {
|
|
132
|
+
executor: {
|
|
133
|
+
execute(request: {
|
|
134
|
+
argv: readonly [string, ...string[]];
|
|
135
|
+
cwd: string;
|
|
136
|
+
timeoutMs: number;
|
|
137
|
+
maxOutputBytes?: number;
|
|
138
|
+
}): Promise<CommandExecutionResult>;
|
|
139
|
+
};
|
|
140
|
+
isolation: {
|
|
141
|
+
isolation: string;
|
|
142
|
+
};
|
|
143
|
+
};
|
|
100
144
|
}
|
|
101
145
|
export declare function runSdkAgent(options: SdkAgentRunOptions): Promise<void>;
|
|
102
146
|
export declare function grantSdkAccess(params: unknown): {
|
package/dist/sdkAgent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdkAgent.d.ts","sourceRoot":"","sources":["../src/sdkAgent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,kCAAkC,CAAA;
|
|
1
|
+
{"version":3,"file":"sdkAgent.d.ts","sourceRoot":"","sources":["../src/sdkAgent.ts"],"names":[],"mappings":"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"}
|
package/dist/sdkAgent.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* built-in tools (Read, Write, Edit, Glob, Grep, Bash).
|
|
10
10
|
*/
|
|
11
11
|
import { createPermissionWaitRegistry, } from '@xenosystem/agent-interface-host';
|
|
12
|
+
import { commandSucceeded, commandShellArgv, LocalCommandExecutor, } from '@xenosystem/agent-interface-host/node';
|
|
12
13
|
import { spawn } from 'child_process';
|
|
13
14
|
import { mkdirSync, readFileSync, existsSync, readdirSync, statSync, writeFileSync } from 'fs';
|
|
14
15
|
import { resolve as pathResolve, dirname, join, basename, extname, relative } from 'path';
|
|
@@ -52,6 +53,7 @@ const activePermissionEngines = new Map();
|
|
|
52
53
|
const hubSessionRuntimes = new Map();
|
|
53
54
|
const pendingSdkCheckpointRestores = new Map();
|
|
54
55
|
const DEFAULT_AGENT_TOOL_TIMEOUT_MS = 120_000;
|
|
56
|
+
const fallbackCommandExecutor = new LocalCommandExecutor();
|
|
55
57
|
const MAX_AGENT_TOOL_TIMEOUT_MS = 300_000;
|
|
56
58
|
const AGENT_VISIBLE_PROGRESS_TIMEOUT_MS = 30_000;
|
|
57
59
|
const AGENT_IDLE_PROGRESS_TIMEOUT_MS = 30_000;
|
|
@@ -73,6 +75,35 @@ const AGENT_CONTEXT_DISCOVERY_TOOL_NAMES = new Set([
|
|
|
73
75
|
]);
|
|
74
76
|
/** Session-granted directories per requestId (conversation turn) */
|
|
75
77
|
const sessionGrantedDirs = new Map();
|
|
78
|
+
/**
|
|
79
|
+
* Loops that are RUNNING RIGHT NOW, so a pinned node can reach one (XENO SPAWN §2.2).
|
|
80
|
+
*
|
|
81
|
+
* 🔴 MID-TURN ONLY, AND THAT IS STRUCTURAL RATHER THAN A SHORTCUT. On this lane the `AgentLoop`
|
|
82
|
+
* is constructed per run and awaited to completion — history is re-sent from the host's record on
|
|
83
|
+
* the next turn — so BETWEEN turns there is no loop in existence to inject into. The ACP lane is
|
|
84
|
+
* the opposite: its agent PROCESS persists across turns, which is why `xeno/context.inject` is
|
|
85
|
+
* natural there and this is not.
|
|
86
|
+
*
|
|
87
|
+
* A pin-forward between turns on this lane therefore belongs in the conversation record that seeds
|
|
88
|
+
* the next turn, not here. That route is NOT built; the capability declaration says so.
|
|
89
|
+
*
|
|
90
|
+
* ⚠️ Keyed by conversation, cleared in the run's `finally`, so an entry can never outlive the loop
|
|
91
|
+
* it points at — a stale handle would accept an injection into a loop that has already returned.
|
|
92
|
+
*/
|
|
93
|
+
const activeAgentLoops = new Map();
|
|
94
|
+
/**
|
|
95
|
+
* Push a pinned node into the loop currently running for a conversation.
|
|
96
|
+
*
|
|
97
|
+
* Returns `undefined` when nothing is running — the caller turns that into a refusal that names
|
|
98
|
+
* the reason, rather than throwing, because "no turn is in flight" is a fact the operator can act
|
|
99
|
+
* on by starting one.
|
|
100
|
+
*/
|
|
101
|
+
export async function injectContextIntoActiveRun(conversationId, input) {
|
|
102
|
+
const loop = activeAgentLoops.get(conversationId);
|
|
103
|
+
if (!loop)
|
|
104
|
+
return undefined;
|
|
105
|
+
return await loop.injectContext(input);
|
|
106
|
+
}
|
|
76
107
|
export function logAgentDebug(message, meta) {
|
|
77
108
|
if (process.env.NODE_ENV === 'production')
|
|
78
109
|
return;
|
|
@@ -398,115 +429,54 @@ function truncateHubToolOutput(output, limit = 12_000) {
|
|
|
398
429
|
const omitted = output.length - limit;
|
|
399
430
|
return `${output.slice(0, headLength)}\n\n[xeno: output truncated; omitted ${omitted} middle characters]\n\n${output.slice(output.length - tailLength)}`;
|
|
400
431
|
}
|
|
401
|
-
|
|
432
|
+
/**
|
|
433
|
+
* The THIRD adopter of `CommandExecutionPort` — ADE §5.3.
|
|
434
|
+
*
|
|
435
|
+
* 🔴 This used to `spawn('powershell.exe')` on the host as the signed-in user.
|
|
436
|
+
* That was the primary agent-reachable path the isolation inventory named, and
|
|
437
|
+
* the one `WorkspaceHostService.runCommand` adopting the port could not cover.
|
|
438
|
+
* Both now go through the same executor the composition binds per run.
|
|
439
|
+
*/
|
|
440
|
+
function executeAgentShellCommand(input, cwd, environment, conversationId) {
|
|
402
441
|
const command = typeof input.command === 'string' ? input.command : '';
|
|
442
|
+
if (!command.trim()) {
|
|
443
|
+
return Promise.resolve({ success: false, output: '', error: 'Missing required parameter: command' });
|
|
444
|
+
}
|
|
403
445
|
const timeoutMs = normalizeToolTimeoutMs(input);
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
windowsHide: true,
|
|
424
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
425
|
-
});
|
|
426
|
-
let stdout = '';
|
|
427
|
-
let stderr = '';
|
|
428
|
-
let settled = false;
|
|
429
|
-
const finish = (result) => {
|
|
430
|
-
if (settled)
|
|
431
|
-
return;
|
|
432
|
-
settled = true;
|
|
433
|
-
clearTimeout(timer);
|
|
434
|
-
resolve(result);
|
|
446
|
+
const resolution = environment?.resolutionForConversation(conversationId);
|
|
447
|
+
const executor = resolution?.executor ?? fallbackCommandExecutor;
|
|
448
|
+
const destination = resolution?.isolation.isolation === 'sandboxed' ? 'sandbox' : 'host';
|
|
449
|
+
return executor.execute({
|
|
450
|
+
argv: commandShellArgv(command, destination),
|
|
451
|
+
cwd,
|
|
452
|
+
timeoutMs,
|
|
453
|
+
}).then((result) => toolResultFromExecution(result));
|
|
454
|
+
}
|
|
455
|
+
function toolResultFromExecution(result) {
|
|
456
|
+
const output = truncateHubToolOutput([result.stdout.trimEnd(), result.stderr.trimEnd()].filter(Boolean).join('\n'));
|
|
457
|
+
if (commandSucceeded(result)) {
|
|
458
|
+
return { success: true, output };
|
|
459
|
+
}
|
|
460
|
+
if (result.timedOut) {
|
|
461
|
+
return {
|
|
462
|
+
success: false,
|
|
463
|
+
output,
|
|
464
|
+
error: result.error || 'The command timed out.',
|
|
435
465
|
};
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
child.kill();
|
|
451
|
-
}
|
|
452
|
-
catch {
|
|
453
|
-
// Ignore best-effort process cleanup errors.
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
finish({
|
|
457
|
-
success: false,
|
|
458
|
-
output: truncateHubToolOutput(stdout),
|
|
459
|
-
error: `Bash timed out after ${timeoutMs}ms. The PowerShell command was stopped.`,
|
|
460
|
-
});
|
|
461
|
-
}, timeoutMs);
|
|
462
|
-
if (typeof timer.unref === 'function')
|
|
463
|
-
timer.unref();
|
|
464
|
-
child.stdout.on('data', (chunk) => {
|
|
465
|
-
stdout += chunk.toString();
|
|
466
|
-
});
|
|
467
|
-
child.stderr.on('data', (chunk) => {
|
|
468
|
-
stderr += chunk.toString();
|
|
469
|
-
});
|
|
470
|
-
child.on('error', (err) => {
|
|
471
|
-
finish({
|
|
472
|
-
success: false,
|
|
473
|
-
output: truncateHubToolOutput(stdout),
|
|
474
|
-
error: err.message || 'PowerShell command failed to start.',
|
|
475
|
-
});
|
|
476
|
-
});
|
|
477
|
-
child.on('exit', (code) => {
|
|
478
|
-
const output = truncateHubToolOutput([stdout.trimEnd(), stderr.trimEnd()].filter(Boolean).join('\n'));
|
|
479
|
-
// 🔴 `code` is null when the process was KILLED BY A SIGNAL rather than
|
|
480
|
-
// exiting. This used to read `code ?? 1`, which reported
|
|
481
|
-
// "Command failed with exit code 1." — inventing a fact.
|
|
482
|
-
//
|
|
483
|
-
// The two are different things to act on: exit 1 means the program ran
|
|
484
|
-
// and failed, so an agent reads the output and fixes the command. A
|
|
485
|
-
// signal means something else stopped it — the OOM killer, an external
|
|
486
|
-
// kill, a race with the timeout path above — and the command may be
|
|
487
|
-
// entirely fine. Telling an agent the first when the second happened
|
|
488
|
-
// sends it to debug code that never got to run.
|
|
489
|
-
//
|
|
490
|
-
// `EngineeringWorkbenchService` already keeps `exitCode: number | null`
|
|
491
|
-
// for exactly this reason, and `xeno-use`'s `sandboxExec` makes its exit
|
|
492
|
-
// code an Option so a signal-killed process cannot report success. When
|
|
493
|
-
// execution routes through that seam this site would otherwise coerce
|
|
494
|
-
// the null straight back out again.
|
|
495
|
-
if (code === null) {
|
|
496
|
-
finish({
|
|
497
|
-
success: false,
|
|
498
|
-
output,
|
|
499
|
-
error: 'The command was terminated by a signal before it exited, so it has no exit code.',
|
|
500
|
-
});
|
|
501
|
-
return;
|
|
502
|
-
}
|
|
503
|
-
finish({
|
|
504
|
-
success: code === 0,
|
|
505
|
-
output,
|
|
506
|
-
...(code === 0 ? {} : { error: `Command failed with exit code ${code}.` }),
|
|
507
|
-
});
|
|
508
|
-
});
|
|
509
|
-
});
|
|
466
|
+
}
|
|
467
|
+
if (result.exitCode === null) {
|
|
468
|
+
return {
|
|
469
|
+
success: false,
|
|
470
|
+
output,
|
|
471
|
+
error: result.error
|
|
472
|
+
|| 'The command was terminated by a signal before it exited, so it has no exit code.',
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
return {
|
|
476
|
+
success: false,
|
|
477
|
+
output,
|
|
478
|
+
error: result.error || `Command failed with exit code ${result.exitCode}.`,
|
|
479
|
+
};
|
|
510
480
|
}
|
|
511
481
|
const FILE_READ_TOOL_NAMES = [
|
|
512
482
|
'Read',
|
|
@@ -3188,7 +3158,7 @@ function wrapRegisteredMultiPathTool(toolRegistry, toolName, pathParams, allowed
|
|
|
3188
3158
|
toolRegistry.register(wrappedTool);
|
|
3189
3159
|
}
|
|
3190
3160
|
export async function runSdkAgent(options) {
|
|
3191
|
-
const { requestId, conversationId, sdkSessionId, subagentRunId, workspaceId, teamId, agentId, model, messages, systemPrompt, maxIterations = 10, enableThinking = false, getAuthToken, getPlatformAuthToken, mainWindow, signal, capabilities, permissionProfile, allowedDirectories, approvalRules: rawApprovalRules, allowTextOnlyFallback = false, toolExecution, onPersistedRuntimeEvent, runtimeEventStore: injectedRuntimeEventStore, coordinationTools, isProduction, } = options;
|
|
3161
|
+
const { requestId, conversationId, sdkSessionId, subagentRunId, workspaceId, teamId, agentId, model, messages, systemPrompt, maxIterations = 10, enableThinking = false, getAuthToken, getPlatformAuthToken, mainWindow, signal, capabilities, permissionProfile, allowedDirectories, approvalRules: rawApprovalRules, allowTextOnlyFallback = false, toolExecution, onPersistedRuntimeEvent, runtimeEventStore: injectedRuntimeEventStore, coordinationTools, isProduction, executionEnvironment, } = options;
|
|
3192
3162
|
const approvalRules = normalizeApprovalRules(rawApprovalRules);
|
|
3193
3163
|
const resolvedPermissionProfile = resolveAgentPermissionProfile({
|
|
3194
3164
|
...(permissionProfile ? { requestedProfile: permissionProfile } : {}),
|
|
@@ -3445,7 +3415,6 @@ export async function runSdkAgent(options) {
|
|
|
3445
3415
|
// directory selection instead of the broken "terminal" pseudo-permission.
|
|
3446
3416
|
const bashTool = toolRegistry.get('Bash');
|
|
3447
3417
|
if (bashTool) {
|
|
3448
|
-
const origExec = bashTool.execute.bind(bashTool);
|
|
3449
3418
|
const wrappedBash = {
|
|
3450
3419
|
definition: bashTool.definition,
|
|
3451
3420
|
execute: async (input) => {
|
|
@@ -3495,10 +3464,7 @@ export async function runSdkAgent(options) {
|
|
|
3495
3464
|
if (typeof input.timeout !== 'number' && typeof input.timeout_ms !== 'number') {
|
|
3496
3465
|
input.timeout = DEFAULT_AGENT_TOOL_TIMEOUT_MS;
|
|
3497
3466
|
}
|
|
3498
|
-
|
|
3499
|
-
return executeWindowsPowerShellTool(input, bashPolicyPath);
|
|
3500
|
-
}
|
|
3501
|
-
return executeToolWithHubTimeout('Bash', input, () => origExec(input));
|
|
3467
|
+
return executeAgentShellCommand(input, bashPolicyPath, executionEnvironment, conversationId);
|
|
3502
3468
|
}
|
|
3503
3469
|
};
|
|
3504
3470
|
toolRegistry.unregister('Bash');
|
|
@@ -3738,6 +3704,35 @@ export async function runSdkAgent(options) {
|
|
|
3738
3704
|
flushRendererTextBatch();
|
|
3739
3705
|
sendRuntimeEventToRenderer(enrichedEvent);
|
|
3740
3706
|
};
|
|
3707
|
+
/**
|
|
3708
|
+
* 🔴 THE SDK'S RUNTIME BUS HAD NO SUBSCRIBER. IT WAS A SEQUENCE COUNTER.
|
|
3709
|
+
*
|
|
3710
|
+
* `runtimeEventBus` is handed to the AgentLoop below, so the SDK emits its whole runtime stream
|
|
3711
|
+
* onto it — and this file used it for `nextSequence()` in 21 places and `subscribe()` in none.
|
|
3712
|
+
* Every event the SDK raised that the host does not separately hand-build was emitted into a bus
|
|
3713
|
+
* nobody listened to.
|
|
3714
|
+
*
|
|
3715
|
+
* That is exactly the `context.*` family, and it is the family XENO SPAWN §15 step 3 is made of:
|
|
3716
|
+
* `context.pressure` (how full the context is, after every model response that reported usage), `context.injected`
|
|
3717
|
+
* (§2.2 pin-forward) and `context.history.compacted` (§2.1's boundary). `RuntimeTimelineProjection`
|
|
3718
|
+
* has handlers for all three; nothing was ever feeding them on this lane.
|
|
3719
|
+
*
|
|
3720
|
+
* ⚠️ FILTERED TO `context.` ON PURPOSE — forwarding the whole bus would DOUBLE-COUNT. The host
|
|
3721
|
+
* already constructs its own envelopes for `turn.*`, `tool.completed`, `model.*.delta`,
|
|
3722
|
+
* `permission.profile.selected` and the `hub.*` family from callbacks, so those would arrive
|
|
3723
|
+
* twice. It builds no `context.*` event at all, which is why this prefix is the exact seam.
|
|
3724
|
+
*
|
|
3725
|
+
* Events from the bus already carry `id`, `sequence` and `timestamp`, so this is a passthrough
|
|
3726
|
+
* into the same sanitize/enrich/publish path every other event here takes.
|
|
3727
|
+
*/
|
|
3728
|
+
runtimeEventBus.subscribe((event) => {
|
|
3729
|
+
if (!event || typeof event !== 'object' || Array.isArray(event))
|
|
3730
|
+
return;
|
|
3731
|
+
const type = event.type;
|
|
3732
|
+
if (typeof type !== 'string' || !type.startsWith('context.'))
|
|
3733
|
+
return;
|
|
3734
|
+
emitRuntimeEvent(event);
|
|
3735
|
+
});
|
|
3741
3736
|
const clearVisibleProgressWatchdog = () => {
|
|
3742
3737
|
if (!visibleProgressWatchdogTimer)
|
|
3743
3738
|
return;
|
|
@@ -4690,6 +4685,41 @@ export async function runSdkAgent(options) {
|
|
|
4690
4685
|
};
|
|
4691
4686
|
signal.addEventListener('abort', onAbort, { once: true });
|
|
4692
4687
|
scheduleVisibleProgressWatchdog();
|
|
4688
|
+
// Registered only for the lifetime of the run below, and only when there is a conversation to
|
|
4689
|
+
// key it by. See `activeAgentLoops` for why this cannot serve a between-turns pin-forward.
|
|
4690
|
+
if (conversationId)
|
|
4691
|
+
activeAgentLoops.set(conversationId, agent);
|
|
4692
|
+
/**
|
|
4693
|
+
* XENO SPAWN §2.2 — nodes pinned while NO turn was running, delivered now.
|
|
4694
|
+
*
|
|
4695
|
+
* 🔴 THE NORMAL CASE FOR PIN-FORWARD, and this lane used to refuse it. §2.2's own framing is an
|
|
4696
|
+
* operator pinning a node so the agent has it for whatever comes next; mid-turn is the exotic
|
|
4697
|
+
* one. The previous answer — "send it as the next prompt instead" — is exactly what §2.2 exists
|
|
4698
|
+
* to prevent, because a prompt makes the agent ANSWER the pinned node and puts a turn on the
|
|
4699
|
+
* timeline nobody asked for.
|
|
4700
|
+
*
|
|
4701
|
+
* ⚠️ Delivered through `AgentLoop.injectContext()` rather than by prepending to `messages`, so
|
|
4702
|
+
* this is the SAME code path as a mid-turn pin: one synthetic-user-message shape, one
|
|
4703
|
+
* `context.injected` emission carrying a real message id, one open-tool-exchange guard. Called
|
|
4704
|
+
* BEFORE `run()`, so nothing is outstanding and each flushes immediately — landing after the
|
|
4705
|
+
* history and before this turn's prompt, which is where recalled context belongs.
|
|
4706
|
+
*
|
|
4707
|
+
* ⚠️ Failures are logged and never thrown. A node that cannot be pinned must not destroy the
|
|
4708
|
+
* turn the user actually asked for — and `injectContext` throws on empty content, which is a
|
|
4709
|
+
* caller bug rather than a reason to lose the run.
|
|
4710
|
+
*/
|
|
4711
|
+
for (const injection of options.injections ?? []) {
|
|
4712
|
+
try {
|
|
4713
|
+
await agent.injectContext(injection);
|
|
4714
|
+
}
|
|
4715
|
+
catch (error) {
|
|
4716
|
+
logAgentDebug('Queued context injection failed', {
|
|
4717
|
+
conversationId,
|
|
4718
|
+
label: injection.label,
|
|
4719
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4720
|
+
});
|
|
4721
|
+
}
|
|
4722
|
+
}
|
|
4693
4723
|
try {
|
|
4694
4724
|
emitModelWaitRuntimeEvent('hub.model.request.started', 'hub-model-request-lifecycle', {
|
|
4695
4725
|
message: 'Agent model run started.',
|
|
@@ -4841,6 +4871,11 @@ export async function runSdkAgent(options) {
|
|
|
4841
4871
|
}
|
|
4842
4872
|
}
|
|
4843
4873
|
finally {
|
|
4874
|
+
// Before anything else: an entry that outlived its loop would accept an injection into a run
|
|
4875
|
+
// that has already returned, and report success for content nobody will ever see.
|
|
4876
|
+
if (conversationId && activeAgentLoops.get(conversationId) === agent) {
|
|
4877
|
+
activeAgentLoops.delete(conversationId);
|
|
4878
|
+
}
|
|
4844
4879
|
flushRendererTextBatch();
|
|
4845
4880
|
flushRendererCompatTextChunk();
|
|
4846
4881
|
clearVisibleProgressWatchdog();
|