@demicodes/agent 0.19.0 → 0.19.2
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/client-entry.d.mts +2 -2
- package/dist/index.d.mts +41 -5
- package/dist/index.mjs +172 -51
- package/dist/stdio-transport.d.mts +1 -1
- package/dist/{transport-BRqZoaeo.d.mts → transport-CHrPzcrU.d.mts} +2 -0
- package/dist/{websocket-transport-C6Y5CeLG.d.mts → websocket-transport-NZ5Btmb4.d.mts} +1 -1
- package/package.json +5 -5
package/dist/client-entry.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { f as TranscriptPatch, l as ServerFrame, n as AgentServerTransport, o as ClientFrame, r as AgentTransport, s as ClientSessionEvent, t as AgentClientTransport, u as ShellCommandStatusLike, x as AgentMetadata } from "./transport-
|
|
2
|
-
import { a as AgentClient, i as AgentActionOptions, n as createWebSocketClientTransport, o as AgentClientListener, r as createWebSocketServerTransport, t as JsonWebSocket } from "./websocket-transport-
|
|
1
|
+
import { f as TranscriptPatch, l as ServerFrame, n as AgentServerTransport, o as ClientFrame, r as AgentTransport, s as ClientSessionEvent, t as AgentClientTransport, u as ShellCommandStatusLike, x as AgentMetadata } from "./transport-CHrPzcrU.mjs";
|
|
2
|
+
import { a as AgentClient, i as AgentActionOptions, n as createWebSocketClientTransport, o as AgentClientListener, r as createWebSocketServerTransport, t as JsonWebSocket } from "./websocket-transport-NZ5Btmb4.mjs";
|
|
3
3
|
import { ProviderSelection } from "@demicodes/provider";
|
|
4
4
|
export { type AgentActionOptions, AgentClient, type AgentClientListener, type AgentClientTransport, type AgentMetadata, type AgentServerTransport, type AgentTransport, type ClientFrame, type ClientSessionEvent, type JsonWebSocket, type ProviderSelection, type ServerFrame, type ShellCommandStatusLike, type TranscriptPatch, createWebSocketClientTransport, createWebSocketServerTransport };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { A as AgentSystemPromptContext, B as CompactionWindow, C as AgentReferenceResolveContext, D as AgentSessionParams, E as AgentSessionOptions, F as ExternalMutationReservation, G as DEFAULT_TURN_RETRY_POLICY, H as TranscriptLog, I as ModelSwitchApply, J as resolveRetryPolicy, K as TurnRetryPolicy, L as SessionEvent, M as AgentToolContext, N as AgentToolInvokeContext, O as AgentSessionRestoreParams, P as AgentToolInvokeResult, R as SessionEventListener, S as AgentPromptContext, T as AgentSessionCloneParams, U as TranscriptOptions, V as DrainedTranscriptPatches, W as estimateTranscriptBlockTokens, Y as retryDelayMs, _ as AgentHarnessContext, a as createInProcessTransportPair, b as AgentLifecycleEvent, c as ConversationSummary, d as SubagentJob, f as TranscriptPatch, g as AgentHarness, h as AgentDisposeContext, i as InProcessTransportPair, j as AgentTool, k as AgentSessionStore, l as ServerFrame, m as AbortTarget, n as AgentServerTransport, o as ClientFrame, p as AbortResult, q as isRetryableCode, r as AgentTransport, s as ClientSessionEvent, t as AgentClientTransport, u as ShellCommandStatusLike, v as AgentHarnessRuntime, w as AgentSessionCheckpoint, x as AgentMetadata, y as AgentHostContext, z as SubagentProfile } from "./transport-
|
|
2
|
-
import { a as AgentClient, i as AgentActionOptions, n as createWebSocketClientTransport, o as AgentClientListener, r as createWebSocketServerTransport, t as JsonWebSocket } from "./websocket-transport-
|
|
3
|
-
import { BashAuditEvent, BashEnvironment, BashEnvironmentOptions, Command, CommandMetadataRecord, Host, ShellCommandStatus, ShellOutputChunk } from "@demicodes/shell";
|
|
1
|
+
import { A as AgentSystemPromptContext, B as CompactionWindow, C as AgentReferenceResolveContext, D as AgentSessionParams, E as AgentSessionOptions, F as ExternalMutationReservation, G as DEFAULT_TURN_RETRY_POLICY, H as TranscriptLog, I as ModelSwitchApply, J as resolveRetryPolicy, K as TurnRetryPolicy, L as SessionEvent, M as AgentToolContext, N as AgentToolInvokeContext, O as AgentSessionRestoreParams, P as AgentToolInvokeResult, R as SessionEventListener, S as AgentPromptContext, T as AgentSessionCloneParams, U as TranscriptOptions, V as DrainedTranscriptPatches, W as estimateTranscriptBlockTokens, Y as retryDelayMs, _ as AgentHarnessContext, a as createInProcessTransportPair, b as AgentLifecycleEvent, c as ConversationSummary, d as SubagentJob, f as TranscriptPatch, g as AgentHarness, h as AgentDisposeContext, i as InProcessTransportPair, j as AgentTool, k as AgentSessionStore, l as ServerFrame, m as AbortTarget, n as AgentServerTransport, o as ClientFrame, p as AbortResult, q as isRetryableCode, r as AgentTransport, s as ClientSessionEvent, t as AgentClientTransport, u as ShellCommandStatusLike, v as AgentHarnessRuntime, w as AgentSessionCheckpoint, x as AgentMetadata, y as AgentHostContext, z as SubagentProfile } from "./transport-CHrPzcrU.mjs";
|
|
2
|
+
import { a as AgentClient, i as AgentActionOptions, n as createWebSocketClientTransport, o as AgentClientListener, r as createWebSocketServerTransport, t as JsonWebSocket } from "./websocket-transport-NZ5Btmb4.mjs";
|
|
3
|
+
import { BashAuditEvent, BashEnvironment, BashEnvironmentOptions, Command, CommandMetadataRecord, Host, HostStore, ShellCommandStatus, ShellOutputChunk } from "@demicodes/shell";
|
|
4
4
|
import { AgentProvider, Provider } from "@demicodes/provider";
|
|
5
5
|
import { Block, Model, ModelMediaKind, ModelSelection, ProviderErrorDiagnostics, QueuedMessage, SessionPhase, UserContentBlock } from "@demicodes/core";
|
|
6
6
|
//#region src/recovery.d.ts
|
|
@@ -271,6 +271,14 @@ interface AgentServerOptions {
|
|
|
271
271
|
providers: Provider[];
|
|
272
272
|
shell?: Omit<BashEnvironmentOptions, 'host' | 'commands'>;
|
|
273
273
|
session?: AgentServerSessionOptions;
|
|
274
|
+
subagents?: {
|
|
275
|
+
/**
|
|
276
|
+
* When false, a child closing never wakes an idle parent with an automatic
|
|
277
|
+
* user send; the host app observes the `subagent closed` frame and drives
|
|
278
|
+
* the parent itself. Defaults to true.
|
|
279
|
+
*/
|
|
280
|
+
notifyParentOnIdle?: boolean;
|
|
281
|
+
};
|
|
274
282
|
/**
|
|
275
283
|
* Optional host-side shell prep (env, PATH, etc.). Implementation-agnostic —
|
|
276
284
|
* command bridge wiring lives in `@demicodes/host-local`, not here.
|
|
@@ -314,6 +322,7 @@ declare class AgentServer {
|
|
|
314
322
|
private readonly shellOptions;
|
|
315
323
|
private readonly sessionOptions;
|
|
316
324
|
private readonly prepareShell;
|
|
325
|
+
private readonly notifyParentOnIdle;
|
|
317
326
|
private readonly bindings;
|
|
318
327
|
private readonly sessionOwnership;
|
|
319
328
|
constructor(options: AgentServerOptions);
|
|
@@ -342,14 +351,20 @@ interface ChildSupervisorOptions<State> {
|
|
|
342
351
|
shellOptions: Omit<BashEnvironmentOptions, 'host' | 'commands'>;
|
|
343
352
|
prepareShell: PrepareShell | null;
|
|
344
353
|
sessionOptions: AgentServerSessionOptions;
|
|
354
|
+
/** When false, a child closing never wakes an idle parent; the host app orchestrates the wakeup from the `subagent closed` frame. */
|
|
355
|
+
notifyParentOnIdle: boolean;
|
|
356
|
+
/** Backing store for child checkpoints and job metadata, keyed under the parent's session directory. */
|
|
357
|
+
store: HostStore;
|
|
345
358
|
emit(frame: ServerFrame): void;
|
|
346
359
|
}
|
|
347
360
|
/**
|
|
348
361
|
* Per-parent subagent supervisor. Owns every child `AgentSession` this parent
|
|
349
362
|
* spawns: lifecycle (spawn / steer / abort / natural end), the `demi agent`
|
|
350
363
|
* command tree, child shell environments, and the `subagent*` protocol frames
|
|
351
|
-
* on the parent connection. Children
|
|
352
|
-
* checkpoint
|
|
364
|
+
* on the parent connection. Children persist exactly like the parent: each
|
|
365
|
+
* live child keeps a checkpoint and job record under the parent's session
|
|
366
|
+
* directory, and reopening the parent restores and resumes them (`restore`).
|
|
367
|
+
* A closed child leaves nothing behind.
|
|
353
368
|
*/
|
|
354
369
|
declare class ChildSupervisor<State = unknown> {
|
|
355
370
|
private readonly options;
|
|
@@ -369,9 +384,29 @@ declare class ChildSupervisor<State = unknown> {
|
|
|
369
384
|
} | null;
|
|
370
385
|
/** Re-emits `subagent started` + transcript reset for every running child (transcript resync). */
|
|
371
386
|
replay(): void;
|
|
387
|
+
/**
|
|
388
|
+
* Detaches every live child on connection teardown: aborts in-flight turns,
|
|
389
|
+
* flushes checkpoints, and keeps the persisted job so the next open of this
|
|
390
|
+
* parent restores it — the same dispose semantics as the parent session.
|
|
391
|
+
* No `closed` frame is emitted: the children are not done, just paused.
|
|
392
|
+
*/
|
|
372
393
|
dispose(): Promise<void>;
|
|
394
|
+
/**
|
|
395
|
+
* Rebuilds every persisted live child of this parent and finishes what it was
|
|
396
|
+
* doing: an interrupted turn resumes from its resume point; an already
|
|
397
|
+
* quiescent child closes with its result. Children share the parent's
|
|
398
|
+
* persistence lifecycle — a parent restore is a child restore.
|
|
399
|
+
*/
|
|
400
|
+
restore(): Promise<void>;
|
|
401
|
+
private restoreJob;
|
|
373
402
|
abortSubtree(id: string): Promise<void>;
|
|
374
403
|
private spawn;
|
|
404
|
+
/** Everything spawn and restore share: the command tree, the harness runtime, and the job record (session attached separately). */
|
|
405
|
+
private assembleJob;
|
|
406
|
+
private attachSession;
|
|
407
|
+
private childStoreKey;
|
|
408
|
+
private childSessionStore;
|
|
409
|
+
private deletePersistedJob;
|
|
375
410
|
/** Delivers one steer to a child: mid-turn as a steer, idle as a new user turn. */
|
|
376
411
|
private steerChild;
|
|
377
412
|
private pumpStdinSteers;
|
|
@@ -381,6 +416,7 @@ declare class ChildSupervisor<State = unknown> {
|
|
|
381
416
|
/** Resolves when the child is idle with no pending yield wakeups (or the job closed). */
|
|
382
417
|
private waitForQuiescence;
|
|
383
418
|
private closeJob;
|
|
419
|
+
private disposeJobShells;
|
|
384
420
|
/** Wakes an idle parent with a user send; a parent blocked in the spawn gets the tool result instead. */
|
|
385
421
|
private notifyIdleParent;
|
|
386
422
|
private createChildAgentNode;
|
package/dist/index.mjs
CHANGED
|
@@ -2660,8 +2660,10 @@ const SPAWN_PROMPT_DESCRIPTION = "The child's first user message and only task b
|
|
|
2660
2660
|
* Per-parent subagent supervisor. Owns every child `AgentSession` this parent
|
|
2661
2661
|
* spawns: lifecycle (spawn / steer / abort / natural end), the `demi agent`
|
|
2662
2662
|
* command tree, child shell environments, and the `subagent*` protocol frames
|
|
2663
|
-
* on the parent connection. Children
|
|
2664
|
-
* checkpoint
|
|
2663
|
+
* on the parent connection. Children persist exactly like the parent: each
|
|
2664
|
+
* live child keeps a checkpoint and job record under the parent's session
|
|
2665
|
+
* directory, and reopening the parent restores and resumes them (`restore`).
|
|
2666
|
+
* A closed child leaves nothing behind.
|
|
2665
2667
|
*/
|
|
2666
2668
|
var ChildSupervisor = class {
|
|
2667
2669
|
options;
|
|
@@ -2860,9 +2862,70 @@ var ChildSupervisor = class {
|
|
|
2860
2862
|
});
|
|
2861
2863
|
}
|
|
2862
2864
|
}
|
|
2865
|
+
/**
|
|
2866
|
+
* Detaches every live child on connection teardown: aborts in-flight turns,
|
|
2867
|
+
* flushes checkpoints, and keeps the persisted job so the next open of this
|
|
2868
|
+
* parent restores it — the same dispose semantics as the parent session.
|
|
2869
|
+
* No `closed` frame is emitted: the children are not done, just paused.
|
|
2870
|
+
*/
|
|
2863
2871
|
async dispose() {
|
|
2864
2872
|
this.isDisposed = true;
|
|
2865
|
-
for (const job of [...this.jobs.values()])
|
|
2873
|
+
for (const job of [...this.jobs.values()]) {
|
|
2874
|
+
job.isClosing = true;
|
|
2875
|
+
job.unsubscribe();
|
|
2876
|
+
this.jobs.delete(job.id);
|
|
2877
|
+
await job.session.dispose().catch(noop);
|
|
2878
|
+
await this.disposeJobShells(job);
|
|
2879
|
+
job.settleClosed({ phase: "aborted" });
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
/**
|
|
2883
|
+
* Rebuilds every persisted live child of this parent and finishes what it was
|
|
2884
|
+
* doing: an interrupted turn resumes from its resume point; an already
|
|
2885
|
+
* quiescent child closes with its result. Children share the parent's
|
|
2886
|
+
* persistence lifecycle — a parent restore is a child restore.
|
|
2887
|
+
*/
|
|
2888
|
+
async restore() {
|
|
2889
|
+
const parent = this.parentSession;
|
|
2890
|
+
if (!parent || this.isDisposed) return;
|
|
2891
|
+
const prefix = `agent-sessions/${parent.id()}/subagents/`;
|
|
2892
|
+
const keys = await this.options.store.list(prefix).catch(() => []);
|
|
2893
|
+
const ids = [...new Set(keys.map((key) => key.slice(prefix.length).split("/")[0] ?? "").filter(Boolean))];
|
|
2894
|
+
for (const id of ids) {
|
|
2895
|
+
if (this.jobs.has(id)) continue;
|
|
2896
|
+
try {
|
|
2897
|
+
await this.restoreJob(id);
|
|
2898
|
+
} catch {
|
|
2899
|
+
await this.deletePersistedJob(id);
|
|
2900
|
+
}
|
|
2901
|
+
}
|
|
2902
|
+
}
|
|
2903
|
+
async restoreJob(id) {
|
|
2904
|
+
const parent = this.parentSession;
|
|
2905
|
+
if (!parent) return;
|
|
2906
|
+
const meta = await this.options.store.readJson(this.childStoreKey(id, "job.json"));
|
|
2907
|
+
const checkpoint = await this.childSessionStore(id).loadCheckpoint();
|
|
2908
|
+
if (!meta || !checkpoint) throw new Error("incomplete persisted subagent");
|
|
2909
|
+
const profile = this.resolveProfile(meta.profileName ?? void 0);
|
|
2910
|
+
const { job, runtime } = this.assembleJob({
|
|
2911
|
+
id,
|
|
2912
|
+
description: meta.description,
|
|
2913
|
+
profileName: meta.profileName,
|
|
2914
|
+
profile,
|
|
2915
|
+
metadata: meta.metadata,
|
|
2916
|
+
spawnedAt: meta.spawnedAt
|
|
2917
|
+
});
|
|
2918
|
+
const session = AgentSession.fromCheckpoint({
|
|
2919
|
+
provider: parent.cloneProviderRuntime(),
|
|
2920
|
+
runtime,
|
|
2921
|
+
checkpoint
|
|
2922
|
+
}, {
|
|
2923
|
+
agentSessionId: id,
|
|
2924
|
+
store: this.childSessionStore(id),
|
|
2925
|
+
...this.options.sessionOptions
|
|
2926
|
+
});
|
|
2927
|
+
this.attachSession(job, session);
|
|
2928
|
+
this.watchTurn(job, session.resume(meta.metadata ? { metadata: meta.metadata } : {}));
|
|
2866
2929
|
}
|
|
2867
2930
|
async abortSubtree(id) {
|
|
2868
2931
|
const job = this.jobs.get(id);
|
|
@@ -2877,6 +2940,40 @@ var ChildSupervisor = class {
|
|
|
2877
2940
|
const profile = this.resolveProfile(input.profileName);
|
|
2878
2941
|
const id = createId();
|
|
2879
2942
|
const metadata = parent.actionMetadata();
|
|
2943
|
+
const profileName = input.profileName ?? (this.options.profiles ? profile.name : null);
|
|
2944
|
+
const spawnedAt = Date.now();
|
|
2945
|
+
const { job, runtime } = this.assembleJob({
|
|
2946
|
+
id,
|
|
2947
|
+
description: input.description,
|
|
2948
|
+
profileName,
|
|
2949
|
+
profile,
|
|
2950
|
+
metadata,
|
|
2951
|
+
spawnedAt
|
|
2952
|
+
});
|
|
2953
|
+
await this.options.store.writeJson(this.childStoreKey(id, "job.json"), {
|
|
2954
|
+
description: input.description,
|
|
2955
|
+
profileName,
|
|
2956
|
+
metadata,
|
|
2957
|
+
spawnedAt
|
|
2958
|
+
});
|
|
2959
|
+
const session = new AgentSession({
|
|
2960
|
+
provider: parent.cloneProviderRuntime(),
|
|
2961
|
+
model: profile.model ?? structuredClone(parent.modelSelection),
|
|
2962
|
+
cwd: this.options.cwd,
|
|
2963
|
+
runtime,
|
|
2964
|
+
state: this.options.agent.initialState()
|
|
2965
|
+
}, {
|
|
2966
|
+
agentSessionId: id,
|
|
2967
|
+
store: this.childSessionStore(id),
|
|
2968
|
+
...this.options.sessionOptions
|
|
2969
|
+
});
|
|
2970
|
+
this.attachSession(job, session);
|
|
2971
|
+
this.watchChild(job, input.prompt);
|
|
2972
|
+
return job;
|
|
2973
|
+
}
|
|
2974
|
+
/** Everything spawn and restore share: the command tree, the harness runtime, and the job record (session attached separately). */
|
|
2975
|
+
assembleJob(input) {
|
|
2976
|
+
const { id, profile } = input;
|
|
2880
2977
|
const agentNode = this.createChildAgentNode(id, input.description);
|
|
2881
2978
|
const commands = injectSubagentCommand(profile.commands ? profile.commands([...this.options.parentCommands]) : [...this.options.parentCommands], agentNode);
|
|
2882
2979
|
const commandRegistry = new CommandRegistry();
|
|
@@ -2891,15 +2988,15 @@ var ChildSupervisor = class {
|
|
|
2891
2988
|
id,
|
|
2892
2989
|
description: input.description,
|
|
2893
2990
|
profile,
|
|
2894
|
-
profileName: input.profileName
|
|
2895
|
-
metadata,
|
|
2991
|
+
profileName: input.profileName,
|
|
2992
|
+
metadata: input.metadata,
|
|
2896
2993
|
session: null,
|
|
2897
2994
|
commandRegistry,
|
|
2898
2995
|
commandNames,
|
|
2899
2996
|
environments: /* @__PURE__ */ new Map(),
|
|
2900
2997
|
pendingEnvironments: /* @__PURE__ */ new Map(),
|
|
2901
2998
|
readonlyHosts: /* @__PURE__ */ new WeakMap(),
|
|
2902
|
-
spawnedAt:
|
|
2999
|
+
spawnedAt: input.spawnedAt,
|
|
2903
3000
|
lastEventAt: Date.now(),
|
|
2904
3001
|
tools: [],
|
|
2905
3002
|
lastAssistantTextAt: null,
|
|
@@ -2912,56 +3009,64 @@ var ChildSupervisor = class {
|
|
|
2912
3009
|
};
|
|
2913
3010
|
const agent = this.options.agent;
|
|
2914
3011
|
const preamble = this.subagentPreamble(id);
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
3012
|
+
return {
|
|
3013
|
+
job,
|
|
3014
|
+
runtime: {
|
|
3015
|
+
harnessName: agent.name,
|
|
3016
|
+
initialState: () => agent.initialState(),
|
|
3017
|
+
systemPrompt: (ctx) => (profile.systemPrompt ?? agent.systemPrompt).call(agent, {
|
|
3018
|
+
...ctx,
|
|
3019
|
+
commandsPrompt
|
|
3020
|
+
}),
|
|
3021
|
+
preamble: async (ctx) => {
|
|
3022
|
+
const inheritedPreamble = profile.systemPrompt ? null : await agent.preamble?.(ctx) ?? null;
|
|
3023
|
+
return inheritedPreamble ? `${inheritedPreamble}\n\n${preamble}` : preamble;
|
|
3024
|
+
},
|
|
3025
|
+
tools: () => createStandardAgentTools({
|
|
3026
|
+
environment: (ctx) => this.childEnvironment(job, ctx),
|
|
3027
|
+
scheduleYield: (ctx, durationMs) => job.session.scheduleYieldWakeup(durationMs, ctx.metadata)
|
|
3028
|
+
})
|
|
3029
|
+
}
|
|
2930
3030
|
};
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
runtime,
|
|
2936
|
-
state: agent.initialState()
|
|
2937
|
-
}, {
|
|
2938
|
-
agentSessionId: id,
|
|
2939
|
-
...this.options.sessionOptions
|
|
2940
|
-
});
|
|
2941
|
-
job.unsubscribe = job.session.subscribe((event) => {
|
|
3031
|
+
}
|
|
3032
|
+
attachSession(job, session) {
|
|
3033
|
+
job.session = session;
|
|
3034
|
+
job.unsubscribe = session.subscribe((event) => {
|
|
2942
3035
|
if (event.type !== "transcript_changed") return;
|
|
2943
3036
|
this.recordTelemetry(job, event.patches);
|
|
2944
3037
|
this.options.emit({
|
|
2945
3038
|
type: "subagent_transcript_patch",
|
|
2946
|
-
subagentId: id,
|
|
3039
|
+
subagentId: job.id,
|
|
2947
3040
|
patches: event.patches,
|
|
2948
3041
|
revision: event.revision
|
|
2949
3042
|
});
|
|
2950
3043
|
});
|
|
2951
|
-
this.jobs.set(id, job);
|
|
3044
|
+
this.jobs.set(job.id, job);
|
|
2952
3045
|
this.options.emit({
|
|
2953
3046
|
type: "subagent",
|
|
2954
3047
|
event: "started",
|
|
2955
3048
|
job: this.wireJob(job)
|
|
2956
3049
|
});
|
|
3050
|
+
const transcript = session.transcript();
|
|
2957
3051
|
this.options.emit({
|
|
2958
3052
|
type: "subagent_transcript_reset",
|
|
2959
|
-
subagentId: id,
|
|
2960
|
-
blocks:
|
|
2961
|
-
revision:
|
|
3053
|
+
subagentId: job.id,
|
|
3054
|
+
blocks: structuredClone(transcript.blocks),
|
|
3055
|
+
revision: transcript.revision
|
|
2962
3056
|
});
|
|
2963
|
-
|
|
2964
|
-
|
|
3057
|
+
}
|
|
3058
|
+
childStoreKey(childId, file) {
|
|
3059
|
+
return `agent-sessions/${this.parentSession?.id() ?? ""}/subagents/${childId}/${file}`;
|
|
3060
|
+
}
|
|
3061
|
+
childSessionStore(childId) {
|
|
3062
|
+
return {
|
|
3063
|
+
saveCheckpoint: (checkpoint) => this.options.store.writeJson(this.childStoreKey(childId, "checkpoint.json"), checkpoint),
|
|
3064
|
+
loadCheckpoint: () => this.options.store.readJson(this.childStoreKey(childId, "checkpoint.json"))
|
|
3065
|
+
};
|
|
3066
|
+
}
|
|
3067
|
+
async deletePersistedJob(id) {
|
|
3068
|
+
await this.options.store.delete(this.childStoreKey(id, "checkpoint.json")).catch(noop);
|
|
3069
|
+
await this.options.store.delete(this.childStoreKey(id, "job.json")).catch(noop);
|
|
2965
3070
|
}
|
|
2966
3071
|
/** Delivers one steer to a child: mid-turn as a steer, idle as a new user turn. */
|
|
2967
3072
|
async steerChild(job, message) {
|
|
@@ -3028,12 +3133,8 @@ var ChildSupervisor = class {
|
|
|
3028
3133
|
this.jobs.delete(job.id);
|
|
3029
3134
|
const result = phase === "completed" ? boundedResultText(lastAssistantText(job.session.transcript().blocks)) : void 0;
|
|
3030
3135
|
await job.session.dispose().catch(noop);
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
const environment = await pending.catch(() => null);
|
|
3034
|
-
if (environment) environments.add(environment);
|
|
3035
|
-
}
|
|
3036
|
-
for (const environment of environments) await environment.disposeAllShells().catch(noop);
|
|
3136
|
+
await this.disposeJobShells(job);
|
|
3137
|
+
await this.deletePersistedJob(job.id);
|
|
3037
3138
|
const close = {
|
|
3038
3139
|
phase,
|
|
3039
3140
|
...result !== void 0 ? { result } : {},
|
|
@@ -3047,9 +3148,17 @@ var ChildSupervisor = class {
|
|
|
3047
3148
|
job.settleClosed(close);
|
|
3048
3149
|
this.notifyIdleParent(job, close);
|
|
3049
3150
|
}
|
|
3151
|
+
async disposeJobShells(job) {
|
|
3152
|
+
const environments = /* @__PURE__ */ new Set([...job.environments.values()]);
|
|
3153
|
+
for (const pending of job.pendingEnvironments.values()) {
|
|
3154
|
+
const environment = await pending.catch(() => null);
|
|
3155
|
+
if (environment) environments.add(environment);
|
|
3156
|
+
}
|
|
3157
|
+
for (const environment of environments) await environment.disposeAllShells().catch(noop);
|
|
3158
|
+
}
|
|
3050
3159
|
/** Wakes an idle parent with a user send; a parent blocked in the spawn gets the tool result instead. */
|
|
3051
3160
|
notifyIdleParent(job, close) {
|
|
3052
|
-
if (this.isDisposed) return;
|
|
3161
|
+
if (this.isDisposed || !this.options.notifyParentOnIdle) return;
|
|
3053
3162
|
const parent = this.parentSession;
|
|
3054
3163
|
if (!parent || parent.phase() !== "idle") return;
|
|
3055
3164
|
const label = `subagent ${job.id}${job.description ? ` — ${job.description}` : ""}`;
|
|
@@ -3057,7 +3166,7 @@ var ChildSupervisor = class {
|
|
|
3057
3166
|
parent.send([{
|
|
3058
3167
|
type: "text",
|
|
3059
3168
|
text: body
|
|
3060
|
-
}]).catch(noop);
|
|
3169
|
+
}], job.metadata ? { metadata: job.metadata } : {}).catch(noop);
|
|
3061
3170
|
}
|
|
3062
3171
|
createChildAgentNode(childId, description) {
|
|
3063
3172
|
return {
|
|
@@ -3090,13 +3199,15 @@ var ChildSupervisor = class {
|
|
|
3090
3199
|
type: "text",
|
|
3091
3200
|
text: `[subagent ${childId}${description ? ` — ${description}` : ""}] ${message}`
|
|
3092
3201
|
}];
|
|
3202
|
+
const metadata = this.jobs.get(childId)?.metadata ?? null;
|
|
3203
|
+
const sendOptions = metadata ? { metadata } : {};
|
|
3093
3204
|
if (parent.phase() !== "idle") {
|
|
3094
3205
|
parent.steer(content).catch(() => {
|
|
3095
|
-
parent.send(content).catch(noop);
|
|
3206
|
+
parent.send(content, sendOptions).catch(noop);
|
|
3096
3207
|
});
|
|
3097
3208
|
return;
|
|
3098
3209
|
}
|
|
3099
|
-
parent.send(content).catch(noop);
|
|
3210
|
+
parent.send(content, sendOptions).catch(noop);
|
|
3100
3211
|
}
|
|
3101
3212
|
async childEnvironment(job, ctx) {
|
|
3102
3213
|
const resolved = await this.options.agent.host({
|
|
@@ -3306,6 +3417,7 @@ var ChildSupervisor = class {
|
|
|
3306
3417
|
description: job.description,
|
|
3307
3418
|
profile: job.profileName,
|
|
3308
3419
|
phase: job.phase,
|
|
3420
|
+
metadata: job.metadata,
|
|
3309
3421
|
...result !== void 0 ? { result } : {}
|
|
3310
3422
|
};
|
|
3311
3423
|
}
|
|
@@ -3445,6 +3557,7 @@ var AgentServer = class {
|
|
|
3445
3557
|
shellOptions;
|
|
3446
3558
|
sessionOptions;
|
|
3447
3559
|
prepareShell;
|
|
3560
|
+
notifyParentOnIdle;
|
|
3448
3561
|
bindings = /* @__PURE__ */ new Set();
|
|
3449
3562
|
sessionOwnership = new SessionOwnershipRegistry();
|
|
3450
3563
|
constructor(options) {
|
|
@@ -3453,6 +3566,7 @@ var AgentServer = class {
|
|
|
3453
3566
|
this.shellOptions = options.shell ?? {};
|
|
3454
3567
|
this.sessionOptions = options.session ?? {};
|
|
3455
3568
|
this.prepareShell = options.prepareShell ?? null;
|
|
3569
|
+
this.notifyParentOnIdle = options.subagents?.notifyParentOnIdle ?? true;
|
|
3456
3570
|
}
|
|
3457
3571
|
client() {
|
|
3458
3572
|
const transports = createInProcessTransportPair();
|
|
@@ -3467,6 +3581,7 @@ var AgentServer = class {
|
|
|
3467
3581
|
shell: this.shellOptions,
|
|
3468
3582
|
session: this.sessionOptions,
|
|
3469
3583
|
prepareShell: this.prepareShell,
|
|
3584
|
+
notifyParentOnIdle: this.notifyParentOnIdle,
|
|
3470
3585
|
sessions: this.sessionOwnership
|
|
3471
3586
|
});
|
|
3472
3587
|
this.bindings.add(binding);
|
|
@@ -3516,6 +3631,7 @@ var AgentTransportBindingImpl = class {
|
|
|
3516
3631
|
shellOptions;
|
|
3517
3632
|
sessionOptions;
|
|
3518
3633
|
prepareShell;
|
|
3634
|
+
notifyParentOnIdle;
|
|
3519
3635
|
sessions;
|
|
3520
3636
|
session = null;
|
|
3521
3637
|
currentAgent = null;
|
|
@@ -3537,6 +3653,7 @@ var AgentTransportBindingImpl = class {
|
|
|
3537
3653
|
this.shellOptions = options.shell ?? {};
|
|
3538
3654
|
this.sessionOptions = options.session ?? {};
|
|
3539
3655
|
this.prepareShell = options.prepareShell;
|
|
3656
|
+
this.notifyParentOnIdle = options.notifyParentOnIdle;
|
|
3540
3657
|
this.sessions = options.sessions;
|
|
3541
3658
|
this.unsubscribeTransport = this.transport.onFrame((frame) => {
|
|
3542
3659
|
this.handleFrame(frame);
|
|
@@ -3731,10 +3848,11 @@ var AgentTransportBindingImpl = class {
|
|
|
3731
3848
|
await this.sessions.claim(agentSessionId, this);
|
|
3732
3849
|
this.currentSessionId = agentSessionId;
|
|
3733
3850
|
const initialState = agent.initialState();
|
|
3734
|
-
const
|
|
3851
|
+
const provisionalHost = await agent.host({
|
|
3735
3852
|
state: initialState,
|
|
3736
3853
|
cwd: frame.cwd
|
|
3737
|
-
})
|
|
3854
|
+
});
|
|
3855
|
+
const store = new HostAgentSessionStore(provisionalHost.store, agentSessionId);
|
|
3738
3856
|
const checkpoint = await store.loadCheckpoint();
|
|
3739
3857
|
const restoring = checkpoint !== null && checkpoint.harnessName === agent.name;
|
|
3740
3858
|
const state = restoring ? structuredClone(checkpoint.state) : initialState;
|
|
@@ -3752,6 +3870,8 @@ var AgentTransportBindingImpl = class {
|
|
|
3752
3870
|
shellOptions: this.shellOptions,
|
|
3753
3871
|
prepareShell: this.prepareShell,
|
|
3754
3872
|
sessionOptions: this.sessionOptions,
|
|
3873
|
+
notifyParentOnIdle: this.notifyParentOnIdle,
|
|
3874
|
+
store: provisionalHost.store,
|
|
3755
3875
|
emit: (subagentFrame) => this.send(subagentFrame)
|
|
3756
3876
|
});
|
|
3757
3877
|
const commands = injectSubagentCommand(harnessCommands, supervisor.rootCommandNode());
|
|
@@ -3822,6 +3942,7 @@ var AgentTransportBindingImpl = class {
|
|
|
3822
3942
|
type: "queue",
|
|
3823
3943
|
queue: this.session.queuedMessages()
|
|
3824
3944
|
});
|
|
3945
|
+
if (restoring) await supervisor.restore();
|
|
3825
3946
|
}
|
|
3826
3947
|
sendTranscriptReset(session) {
|
|
3827
3948
|
const transcript = session.transcript();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as AgentServerTransport, t as AgentClientTransport } from "./transport-
|
|
1
|
+
import { n as AgentServerTransport, t as AgentClientTransport } from "./transport-CHrPzcrU.mjs";
|
|
2
2
|
import { Readable, Writable } from "node:stream";
|
|
3
3
|
//#region src/stdio-transport.d.ts
|
|
4
4
|
declare function createStdioClientTransport(readable: Readable, writable: Writable): AgentClientTransport;
|
|
@@ -398,6 +398,8 @@ interface SubagentJob {
|
|
|
398
398
|
description: string;
|
|
399
399
|
profile: string | null;
|
|
400
400
|
phase: 'running' | 'completed' | 'aborted' | 'error';
|
|
401
|
+
/** Action metadata of the round that spawned the child. */
|
|
402
|
+
metadata: AgentMetadata | null;
|
|
401
403
|
/** Present on `closed`: the child's last assistant text, at most 32 KiB. */
|
|
402
404
|
result?: string;
|
|
403
405
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { I as ModelSwitchApply, c as ConversationSummary, n as AgentServerTransport, p as AbortResult, s as ClientSessionEvent, t as AgentClientTransport, x as AgentMetadata } from "./transport-
|
|
1
|
+
import { I as ModelSwitchApply, c as ConversationSummary, n as AgentServerTransport, p as AbortResult, s as ClientSessionEvent, t as AgentClientTransport, x as AgentMetadata } from "./transport-CHrPzcrU.mjs";
|
|
2
2
|
import { ProviderSelection } from "@demicodes/provider";
|
|
3
3
|
import { Block, UserContentBlock } from "@demicodes/core";
|
|
4
4
|
//#region src/client.d.ts
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@demicodes/agent",
|
|
3
3
|
"description": "Session runtime and transport-neutral client and server protocol for Demi.",
|
|
4
|
-
"version": "0.19.
|
|
4
|
+
"version": "0.19.2",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@demicodes/core": "^0.19.
|
|
23
|
-
"@demicodes/provider": "^0.19.
|
|
24
|
-
"@demicodes/shell": "^0.19.
|
|
25
|
-
"@demicodes/utils": "^0.19.
|
|
22
|
+
"@demicodes/core": "^0.19.2",
|
|
23
|
+
"@demicodes/provider": "^0.19.2",
|
|
24
|
+
"@demicodes/shell": "^0.19.2",
|
|
25
|
+
"@demicodes/utils": "^0.19.2",
|
|
26
26
|
"zod": "^4.0.0"
|
|
27
27
|
},
|
|
28
28
|
"license": "Apache-2.0",
|