@morlay/dsh-subagent 0.0.9 → 0.0.11-alpha.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.
@@ -4,124 +4,98 @@
4
4
  * @module @deepseek-ai/dsh-subagent/catalog
5
5
  */
6
6
 
7
- import { z } from "zod";
8
- import {
9
- appendChunkedList,
10
- chunkedListSchema,
11
- iterateChunkedList,
12
- } from "@deepseek-ai/dsh-chunked-list";
13
- import type { ChunkedList } from "@deepseek-ai/dsh-chunked-list";
7
+ import { z } from 'zod'
8
+ import { appendChunkedList, chunkedListSchema, iterateChunkedList } from '@deepseek-ai/dsh-chunked-list'
9
+ import type { ChunkedList } from '@deepseek-ai/dsh-chunked-list'
14
10
  import type {
15
11
  Session,
16
12
  SessionEvent,
17
13
  SessionHeader,
18
14
  SessionId,
19
15
  SessionLogOffset,
20
- } from "@deepseek-ai/dsh-session";
21
- import type { ProjectionDefinition } from "@deepseek-ai/dsh-session-projection";
22
- import type { SubagentCatalogEntry } from "./projection-types.ts";
16
+ } from '@deepseek-ai/dsh-session'
17
+ import type { ProjectionDefinition } from '@deepseek-ai/dsh-session-projection'
18
+ import type { SubagentCatalogEntry } from './projection-types.ts'
23
19
 
24
20
  /** Catalog payload version emitted by local child creation. */
25
- export const SUBAGENT_CATALOG_VERSION = 0;
21
+ export const SUBAGENT_CATALOG_VERSION = 0
26
22
 
27
23
  type KnownCatalogMode =
28
- | { readonly mode: "one-shot"; readonly label?: string }
29
- | { readonly mode: "continuable"; readonly label: string };
24
+ | { readonly mode: 'one-shot'; readonly label?: string }
25
+ | { readonly mode: 'continuable'; readonly label: string }
30
26
 
31
27
  /** Parent catalog v0 records local modes, v1 adds unknown children, and v2 records external executions. */
32
- export type SubagentCatalogEvent = {
33
- readonly childId: SessionId;
34
- readonly childCreatedAt: number;
35
- } & (
36
- | ({ readonly version: 0 } & KnownCatalogMode)
37
- | ({ readonly version: 1 } & (
38
- | KnownCatalogMode
39
- | { readonly mode: "unknown"; readonly label?: string }
40
- ))
41
- | { readonly version: 2; readonly mode: "external"; readonly label?: string }
42
- );
28
+ export type SubagentCatalogEvent =
29
+ & {
30
+ readonly childId: SessionId
31
+ readonly childCreatedAt: number
32
+ } & (
33
+ | ({ readonly version: 0 } & KnownCatalogMode)
34
+ | ({ readonly version: 1 } & (KnownCatalogMode | { readonly mode: 'unknown'; readonly label?: string }))
35
+ | { readonly version: 2; readonly mode: 'external'; readonly label?: string }
36
+ )
43
37
 
44
- declare module "@deepseek-ai/dsh-session/types" {
38
+ declare module '@deepseek-ai/dsh-session/types' {
45
39
  interface SessionEventMap {
46
40
  /**
47
41
  * A direct child's identity and available discovery fields.
48
42
  * @param data - versioned parent-owned catalog entry.
49
43
  */
50
- "subagent/catalog": SubagentCatalogEvent;
44
+ 'subagent/catalog': SubagentCatalogEvent
51
45
  }
52
46
  }
53
47
 
54
48
  /** Host fold state for one parent catalog. */
55
49
  export interface SubagentCatalogState {
56
- readonly inheritedEventCount: SessionLogOffset;
57
- readonly head?: ChunkedList<SubagentCatalogEvent> | undefined;
50
+ readonly inheritedEventCount: SessionLogOffset
51
+ readonly head?: ChunkedList<SubagentCatalogEvent> | undefined
58
52
  }
59
53
 
60
- const sessionIdSchema = z.string() as unknown as z.ZodType<SessionId>;
61
- const oneShotCatalogSchema = z
62
- .object({
63
- version: z.union([z.literal(0), z.literal(1)]),
64
- childId: sessionIdSchema,
65
- childCreatedAt: z.number().int().nonnegative(),
66
- mode: z.literal("one-shot"),
67
- label: z.string().optional(),
68
- })
69
- .strict();
70
- const continuableCatalogSchema = z
71
- .object({
72
- version: z.union([z.literal(0), z.literal(1)]),
73
- childId: sessionIdSchema,
74
- childCreatedAt: z.number().int().nonnegative(),
75
- mode: z.literal("continuable"),
76
- label: z.string(),
77
- })
78
- .strict();
79
- const externalCatalogSchema = oneShotCatalogSchema.extend({
80
- version: z.literal(2),
81
- mode: z.literal("external"),
82
- });
83
- const unknownCatalogSchema = oneShotCatalogSchema.extend({
84
- version: z.literal(1),
85
- mode: z.literal("unknown"),
86
- });
54
+ const sessionIdSchema = z.string() as unknown as z.ZodType<SessionId>
55
+ const oneShotCatalogSchema = z.object({
56
+ version: z.union([z.literal(0), z.literal(1)]),
57
+ childId: sessionIdSchema,
58
+ childCreatedAt: z.number().int().nonnegative(),
59
+ mode: z.literal('one-shot'),
60
+ label: z.string().optional(),
61
+ }).strict()
62
+ const continuableCatalogSchema = z.object({
63
+ version: z.union([z.literal(0), z.literal(1)]),
64
+ childId: sessionIdSchema,
65
+ childCreatedAt: z.number().int().nonnegative(),
66
+ mode: z.literal('continuable'),
67
+ label: z.string(),
68
+ }).strict()
69
+ const externalCatalogSchema = oneShotCatalogSchema.extend({ version: z.literal(2), mode: z.literal('external') })
70
+ const unknownCatalogSchema = oneShotCatalogSchema.extend({ version: z.literal(1), mode: z.literal('unknown') })
87
71
  const eventDataSchema = z.union([
88
72
  oneShotCatalogSchema,
89
73
  externalCatalogSchema,
90
74
  continuableCatalogSchema,
91
75
  unknownCatalogSchema,
92
- ]) as z.ZodType<SubagentCatalogEvent>;
93
- const viewSchema = z.array(
94
- z.union([
95
- oneShotCatalogSchema.omit({ version: true, childId: true, childCreatedAt: true }).extend({
96
- id: sessionIdSchema,
97
- createdAt: oneShotCatalogSchema.shape.childCreatedAt,
98
- }),
99
- externalCatalogSchema.omit({ version: true, childId: true, childCreatedAt: true }).extend({
100
- id: sessionIdSchema,
101
- createdAt: externalCatalogSchema.shape.childCreatedAt,
102
- }),
103
- continuableCatalogSchema.omit({ version: true, childId: true, childCreatedAt: true }).extend({
104
- id: sessionIdSchema,
105
- createdAt: continuableCatalogSchema.shape.childCreatedAt,
106
- }),
107
- unknownCatalogSchema.omit({ version: true, childId: true, childCreatedAt: true }).extend({
108
- id: sessionIdSchema,
109
- createdAt: unknownCatalogSchema.shape.childCreatedAt,
110
- }),
111
- ]),
112
- ) as z.ZodType<SubagentCatalogEntry[]>;
113
- const stateSchema: z.ZodType<SubagentCatalogState> = z
114
- .object({
115
- inheritedEventCount: z.number().int().nonnegative() as unknown as z.ZodType<SessionLogOffset>,
116
- head: chunkedListSchema(eventDataSchema).optional(),
117
- })
118
- .strict();
119
-
120
- declare module "@deepseek-ai/dsh-session-projection/types" {
121
- interface SessionProjectionStateMap {
122
- subagentCatalog: SubagentCatalogState;
123
- }
124
- }
76
+ ]) as z.ZodType<SubagentCatalogEvent>
77
+ const viewSchema = z.array(z.union([
78
+ oneShotCatalogSchema.omit({ version: true, childId: true, childCreatedAt: true }).extend({
79
+ id: sessionIdSchema,
80
+ createdAt: oneShotCatalogSchema.shape.childCreatedAt,
81
+ }),
82
+ externalCatalogSchema.omit({ version: true, childId: true, childCreatedAt: true }).extend({
83
+ id: sessionIdSchema,
84
+ createdAt: externalCatalogSchema.shape.childCreatedAt,
85
+ }),
86
+ continuableCatalogSchema.omit({ version: true, childId: true, childCreatedAt: true }).extend({
87
+ id: sessionIdSchema,
88
+ createdAt: continuableCatalogSchema.shape.childCreatedAt,
89
+ }),
90
+ unknownCatalogSchema.omit({ version: true, childId: true, childCreatedAt: true }).extend({
91
+ id: sessionIdSchema,
92
+ createdAt: unknownCatalogSchema.shape.childCreatedAt,
93
+ }),
94
+ ])) as z.ZodType<SubagentCatalogEntry[]>
95
+ const stateSchema: z.ZodType<SubagentCatalogState> = z.object({
96
+ inheritedEventCount: z.number().int().nonnegative() as unknown as z.ZodType<SessionLogOffset>,
97
+ head: chunkedListSchema(eventDataSchema).optional(),
98
+ }).strict()
125
99
 
126
100
  /**
127
101
  * Materialize complete and unknown-mode child identities from parent catalog events.
@@ -129,28 +103,26 @@ declare module "@deepseek-ai/dsh-session-projection/types" {
129
103
  * @returns current direct-child rows in parent catalog event order.
130
104
  */
131
105
  function subagentCatalogEntries(state: SubagentCatalogState): SubagentCatalogEntry[] {
132
- const entries: SubagentCatalogEntry[] = [];
106
+ const entries: SubagentCatalogEntry[] = []
133
107
  for (const data of iterateChunkedList(state.head)) {
134
- const { version: _version, childId, childCreatedAt, ...descriptor } = data;
135
- entries.push({ id: childId, createdAt: childCreatedAt, ...descriptor });
108
+ const { version: _version, childId, childCreatedAt, ...descriptor } = data
109
+ entries.push({ id: childId, createdAt: childCreatedAt, ...descriptor })
136
110
  }
137
- return entries;
111
+ return entries
138
112
  }
139
113
 
140
114
  /** Parent-owned direct-child catalog projection; invalid own facts reject restoration. */
141
115
  export const subagentCatalogProjectionDefinition = {
142
- key: "subagentCatalog",
116
+ key: 'subagentCatalog',
143
117
  stateSchema,
144
- init: (_header: SessionHeader, inheritedEventCount: SessionLogOffset) => ({
145
- inheritedEventCount,
146
- }),
118
+ init: (_header: SessionHeader, inheritedEventCount: SessionLogOffset) => ({ inheritedEventCount }),
147
119
  apply: (state, event: SessionEvent) => {
148
- if (event.type !== "subagent/catalog" || event.seq < state.inheritedEventCount) return state;
149
- return { ...state, head: appendChunkedList(state.head, eventDataSchema.parse(event.data)) };
120
+ if (event.type !== 'subagent/catalog' || event.seq < state.inheritedEventCount) return state
121
+ return { ...state, head: appendChunkedList(state.head, eventDataSchema.parse(event.data)) }
150
122
  },
151
123
  stateVersion: 6,
152
124
  wire: { viewSchema, view: subagentCatalogEntries },
153
- } satisfies ProjectionDefinition<"subagentCatalog", SubagentCatalogState>;
125
+ } satisfies ProjectionDefinition<'subagentCatalog', SubagentCatalogState>
154
126
 
155
127
  /**
156
128
  * Append a complete direct-child discovery fact to its parent Session.
@@ -161,19 +133,19 @@ export const subagentCatalogProjectionDefinition = {
161
133
  export function establishCatalogChild(
162
134
  parent: Session,
163
135
  child: SessionHeader,
164
- descriptor: { readonly mode: "continuable"; readonly label: string },
136
+ descriptor: { readonly mode: 'continuable'; readonly label: string },
165
137
  ): void {
166
- parent.append("subagent/catalog", {
138
+ parent.append('subagent/catalog', {
167
139
  version: SUBAGENT_CATALOG_VERSION,
168
140
  childId: child.id,
169
141
  childCreatedAt: child.createdAt,
170
142
  mode: descriptor.mode,
171
143
  label: descriptor.label,
172
- });
144
+ })
173
145
  }
174
146
 
175
147
  /** Catalog payload version emitted by external execution creation. */
176
- const EXTERNAL_SUBAGENT_CATALOG_VERSION = 2;
148
+ const EXTERNAL_SUBAGENT_CATALOG_VERSION = 2
177
149
 
178
150
  /**
179
151
  * Record an external execution without a local child Session.
@@ -181,16 +153,12 @@ const EXTERNAL_SUBAGENT_CATALOG_VERSION = 2;
181
153
  * @param childId - identity returned by the external provider.
182
154
  * @param label - display label assigned by the caller.
183
155
  */
184
- export function establishExternalCatalogChild(
185
- parent: Session,
186
- childId: SessionId,
187
- label: string,
188
- ): void {
189
- parent.append("subagent/catalog", {
156
+ export function establishExternalCatalogChild(parent: Session, childId: SessionId, label: string): void {
157
+ parent.append('subagent/catalog', {
190
158
  version: EXTERNAL_SUBAGENT_CATALOG_VERSION,
191
159
  childId,
192
160
  childCreatedAt: Date.now(),
193
- mode: "external",
161
+ mode: 'external',
194
162
  label,
195
- });
163
+ })
196
164
  }
@@ -6,36 +6,33 @@
6
6
  * @module @deepseek-ai/dsh-subagent/child-agent
7
7
  */
8
8
 
9
- import type { Context } from "@deepseek-ai/cordis";
10
- import type { Agent, AgentOptions, CreateAgentOptions } from "@deepseek-ai/dsh-agent";
11
- import type { SandboxMode } from "@deepseek-ai/dsh-sandbox";
12
- import type { Session, SessionId } from "@deepseek-ai/dsh-session";
13
- import type {} from "@deepseek-ai/dsh-system-prompt";
14
- import type { ToolRestriction } from "@deepseek-ai/dsh-tools";
9
+ import type { Context } from '@deepseek-ai/cordis'
10
+ import type { Agent, AgentOptions, CreateAgentOptions } from '@deepseek-ai/dsh-agent'
11
+ import type { SandboxMode } from '@deepseek-ai/dsh-sandbox'
12
+ import type { Session, SessionId } from '@deepseek-ai/dsh-session'
13
+ import type {} from '@deepseek-ai/dsh-system-prompt'
14
+ import type { ToolRestriction } from '@deepseek-ai/dsh-tools'
15
15
  // Type-only: make `ctx.get('sandboxPolicy')`, `ctx.get('approval')`, and
16
16
  // `ctx.get('permissionPresets')` resolve to their services when composed — delegation consumes them
17
17
  // opportunistically (the documented `ctx.get` pattern), never as a hard dep —
18
18
  // and merge the inherited permission session-event payloads.
19
- import type {} from "@deepseek-ai/dsh-sandbox-policy";
20
- import type {} from "@deepseek-ai/dsh-user-approval";
21
- import type {} from "@deepseek-ai/dsh-permission-presets";
19
+ import type {} from '@deepseek-ai/dsh-sandbox-policy'
20
+ import type {} from '@deepseek-ai/dsh-user-approval'
21
+ import type {} from '@deepseek-ai/dsh-permission-presets'
22
22
  // Type-only: make `ctx.get('agentPresets')` resolve to the preset roster when
23
23
  // composed — a child inherits its parent's composition opportunistically (the
24
24
  // documented `ctx.get` pattern), never as a hard dep. A rosterless deployment
25
25
  // keeps its model-facing rows on the host plane, where the child already sees
26
26
  // them through the tool registry's global layer.
27
- import type {} from "@deepseek-ai/dsh-agent-preset-registry";
28
- import { delegationDepthOf } from "./depth.ts";
29
- import { SubagentError } from "./error.ts";
27
+ import type {} from '@deepseek-ai/dsh-agent-preset-registry'
28
+ import { delegationDepthOf } from './depth.ts'
29
+ import { SubagentError } from './error.ts'
30
30
 
31
31
  /** Thrown when starting a child would exceed the requested depth cap. */
32
32
  export class SubagentDepthError extends Error {
33
- constructor(
34
- public readonly attemptedDepth: number,
35
- public readonly maxDepth: number,
36
- ) {
37
- super(`subagent depth ${attemptedDepth} exceeds maxDepth ${maxDepth}`);
38
- this.name = "SubagentDepthError";
33
+ constructor(public readonly attemptedDepth: number, public readonly maxDepth: number) {
34
+ super(`subagent depth ${attemptedDepth} exceeds maxDepth ${maxDepth}`)
35
+ this.name = 'SubagentDepthError'
39
36
  }
40
37
  }
41
38
 
@@ -50,14 +47,14 @@ export class SubagentDepthError extends Error {
50
47
  * @throws {RangeError} when the resolved depth leaves the safe-integer range.
51
48
  */
52
49
  export function resolveChildDepth(parent: Agent, maxDepth: number | undefined): number {
53
- const childDepth = delegationDepthOf(parent) + 1;
50
+ const childDepth = delegationDepthOf(parent) + 1
54
51
  if (!Number.isSafeInteger(childDepth)) {
55
- throw new RangeError("subagent child depth exceeds the safe-integer range");
52
+ throw new RangeError('subagent child depth exceeds the safe-integer range')
56
53
  }
57
54
  if (maxDepth !== undefined && childDepth > maxDepth) {
58
- throw new SubagentDepthError(childDepth, maxDepth);
55
+ throw new SubagentDepthError(childDepth, maxDepth)
59
56
  }
60
- return childDepth;
57
+ return childDepth
61
58
  }
62
59
 
63
60
  /**
@@ -69,22 +66,22 @@ export function resolveChildDepth(parent: Agent, maxDepth: number | undefined):
69
66
  * @returns detached Agent options for child-option merging.
70
67
  */
71
68
  export function parentAgentOptionsForDelegation(parent: Agent): AgentOptions {
72
- const requestConfig = parent.session.requestHeader()?.config;
73
- if (requestConfig === undefined) return { ...parent.options };
69
+ const requestConfig = parent.session.requestHeader()?.config
70
+ if (requestConfig === undefined) return { ...parent.options }
74
71
  const {
75
72
  provider: _createdProvider,
76
73
  model: _createdModel,
77
74
  reasoningEffort: _createdReasoningEffort,
78
75
  ...createdOptions
79
- } = parent.options;
76
+ } = parent.options
80
77
  return {
81
78
  ...createdOptions,
82
79
  provider: requestConfig.provider,
83
80
  model: requestConfig.model,
84
- ...(requestConfig.reasoningEffort === undefined
81
+ ...requestConfig.reasoningEffort === undefined
85
82
  ? {}
86
- : { reasoningEffort: requestConfig.reasoningEffort }),
87
- };
83
+ : { reasoningEffort: requestConfig.reasoningEffort },
84
+ }
88
85
  }
89
86
 
90
87
  /**
@@ -103,22 +100,22 @@ export function resolveChildAgentOptions(
103
100
  requested: AgentOptions | undefined,
104
101
  childDepth: number,
105
102
  ): AgentOptions {
106
- const parentOptions = parentAgentOptionsForDelegation(parent);
107
- const parentProvider = parentOptions.provider;
108
- const parentModel = parentOptions.model;
109
- const parentReasoningEffort = parentOptions.reasoningEffort;
110
- const parentMaxTokens = parentOptions.maxTokens;
103
+ const parentOptions = parentAgentOptionsForDelegation(parent)
104
+ const parentProvider = parentOptions.provider
105
+ const parentModel = parentOptions.model
106
+ const parentReasoningEffort = parentOptions.reasoningEffort
107
+ const parentMaxTokens = parentOptions.maxTokens
111
108
  const resolved: AgentOptions = {
112
- ...(parentProvider !== undefined ? { provider: parentProvider } : {}),
113
- ...(parentModel !== undefined ? { model: parentModel } : {}),
114
- ...(parentReasoningEffort !== undefined ? { reasoningEffort: parentReasoningEffort } : {}),
115
- ...(parentMaxTokens !== undefined ? { maxTokens: parentMaxTokens } : {}),
109
+ ...parentProvider !== undefined ? { provider: parentProvider } : {},
110
+ ...parentModel !== undefined ? { model: parentModel } : {},
111
+ ...parentReasoningEffort !== undefined ? { reasoningEffort: parentReasoningEffort } : {},
112
+ ...parentMaxTokens !== undefined ? { maxTokens: parentMaxTokens } : {},
116
113
  ...requested,
117
114
  subagentDepth: childDepth,
118
- };
119
- const routeChanged = resolved.provider !== parentProvider || resolved.model !== parentModel;
120
- if (routeChanged && requested?.reasoningEffort === undefined) delete resolved.reasoningEffort;
121
- return resolved;
115
+ }
116
+ const routeChanged = resolved.provider !== parentProvider || resolved.model !== parentModel
117
+ if (routeChanged && requested?.reasoningEffort === undefined) delete resolved.reasoningEffort
118
+ return resolved
122
119
  }
123
120
 
124
121
  /**
@@ -140,30 +137,30 @@ export function childSessionMeta(
140
137
  childDepth: number,
141
138
  isSeeded: boolean,
142
139
  selectedPreset?: string,
143
- ): NonNullable<CreateAgentOptions["meta"]> {
144
- const parentHeader = parent.session.header;
145
- const agentPreset = selectedPreset ?? parent.ctx.get("agentPresets")?.composedPreset(parent.ctx);
140
+ ): NonNullable<CreateAgentOptions['meta']> {
141
+ const parentHeader = parent.session.header
142
+ const agentPreset = selectedPreset ?? parent.ctx.get('agentPresets')?.composedPreset(parent.ctx)
146
143
  return {
147
- ...(parentHeader.cwd !== undefined ? { cwd: parentHeader.cwd } : {}),
148
- ...(agentPreset === undefined ? {} : { agentPreset }),
144
+ ...parentHeader.cwd !== undefined ? { cwd: parentHeader.cwd } : {},
145
+ ...agentPreset === undefined ? {} : { agentPreset },
149
146
  parentSession: parentHeader.id,
150
147
  isSeeded,
151
148
  // Navigation classification only; the descriptor remains the authority
152
149
  // for mode and continuation capability.
153
- origin: "subagent",
150
+ origin: 'subagent',
154
151
  // Durable: the recursion budget must survive persistence and resume.
155
152
  delegationDepth: childDepth,
156
- };
153
+ }
157
154
  }
158
155
 
159
156
  /** The scoped composition a child agent's creation window applies. */
160
157
  export interface ChildComposition {
161
158
  /** Independently mounted preset; omission shares the parent's standing generation. */
162
- readonly agentPreset?: string | undefined;
159
+ readonly agentPreset?: string | undefined
163
160
  /** Historical descriptor persona reapplied only during cold resume. */
164
- readonly persona?: string | undefined;
161
+ readonly persona?: string | undefined
165
162
  /** Historical descriptor tool restriction reapplied only during cold resume. */
166
- readonly toolFilter?: ToolRestriction | undefined;
163
+ readonly toolFilter?: ToolRestriction | undefined
167
164
  }
168
165
 
169
166
  /**
@@ -171,11 +168,11 @@ export interface ChildComposition {
171
168
  * runtime-context contribution rather than a system-prompt section, so the
172
169
  * deployment's system prompt stays uniform across parents and children.
173
170
  */
174
- export const SUBAGENT_DELEGATION_CONTEXT =
175
- "You are a delegated subagent: your permission scope was fixed when you were started and cannot be " +
176
- "widened from inside this session — operations that require approval are rejected automatically. " +
177
- "When the task needs access beyond that scope, do not retry the denied operation; state the " +
178
- "limitation in your reply so the delegating agent can handle it.";
171
+ export const SUBAGENT_DELEGATION_CONTEXT
172
+ = 'You are a delegated subagent: your permission scope was fixed when you were started and cannot be '
173
+ + 'widened from inside this session — operations that require approval are rejected automatically. '
174
+ + 'When the task needs access beyond that scope, do not retry the denied operation; state the '
175
+ + 'limitation in your reply so the delegating agent can handle it.'
179
176
 
180
177
  /**
181
178
  * Compose a child before publication and restore historical descriptor overrides.
@@ -192,35 +189,32 @@ export function applyChildComposition(
192
189
  composition: ChildComposition,
193
190
  ): void | Promise<void> {
194
191
  if (composition.agentPreset !== undefined) {
195
- const presets = childCtx.get("agentPresets");
192
+ const presets = childCtx.get('agentPresets')
196
193
  if (presets === undefined) {
197
- throw new SubagentError(
198
- "selecting a child agent preset requires the agent-presets service",
199
- "PRESET_UNAVAILABLE",
200
- );
194
+ throw new SubagentError('selecting a child agent preset requires the agent-presets service', 'PRESET_UNAVAILABLE')
201
195
  }
202
196
  return presets.mount(childCtx, composition.agentPreset).then(() => {
203
- applyChildOverrides(childCtx, composition);
204
- });
197
+ applyChildOverrides(childCtx, composition)
198
+ })
205
199
  }
206
- childCtx.get("agentPresets")?.composeFrom(childCtx, parent.ctx);
207
- applyChildOverrides(childCtx, composition);
200
+ childCtx.get('agentPresets')?.composeFrom(childCtx, parent.ctx)
201
+ applyChildOverrides(childCtx, composition)
208
202
  }
209
203
 
210
204
  function applyChildOverrides(childCtx: Context, composition: ChildComposition): void {
211
205
  childCtx.systemPrompt.context({
212
- name: "subagent:delegation",
213
- order: childCtx.systemPrompt.getContextOrder("SUBAGENT_DELEGATION"),
206
+ name: 'subagent:delegation',
207
+ order: childCtx.systemPrompt.getContextOrder('SUBAGENT_DELEGATION'),
214
208
  text: SUBAGENT_DELEGATION_CONTEXT,
215
- });
209
+ })
216
210
  if (composition.persona !== undefined) {
217
211
  childCtx.systemPrompt.section({
218
- name: "deployment:persona-prefix",
219
- order: childCtx.systemPrompt.getSectionOrder("DEPLOYMENT_PERSONA_PREFIX"),
212
+ name: 'deployment:persona-prefix',
213
+ order: childCtx.systemPrompt.getSectionOrder('DEPLOYMENT_PERSONA_PREFIX'),
220
214
  text: composition.persona,
221
- });
215
+ })
222
216
  }
223
- if (composition.toolFilter !== undefined) childCtx.tools.restrict(composition.toolFilter);
217
+ if (composition.toolFilter !== undefined) childCtx.tools.restrict(composition.toolFilter)
224
218
  }
225
219
 
226
220
  /** Policy seeded onto a child session's log at the delegation boundary. */
@@ -229,15 +223,15 @@ export interface DelegatedPolicyOverrides {
229
223
  * The parent's current preset identity when it runs in Auto or Full access;
230
224
  * the child keeps it under the pinned `never` approval policy.
231
225
  */
232
- readonly permissionPreset: "auto" | "danger-full-access" | undefined;
226
+ readonly permissionPreset: 'auto' | 'danger-full-access' | undefined
233
227
  /** The parent session's explicit sandbox-mode override, or `undefined` without one. */
234
- readonly sandboxMode: SandboxMode | undefined;
228
+ readonly sandboxMode: SandboxMode | undefined
235
229
  /**
236
230
  * `'never'` whenever the approval capability is composed, `undefined`
237
231
  * otherwise: a delegated child acts only within the sandbox scope fixed at
238
232
  * delegation, so its asks are rejected deterministically.
239
233
  */
240
- readonly approvalPolicy: "never" | undefined;
234
+ readonly approvalPolicy: 'never' | undefined
241
235
  }
242
236
 
243
237
  /**
@@ -252,21 +246,21 @@ export interface DelegatedPolicyOverrides {
252
246
  * @returns the sandbox override (or `undefined` without one) and the approval pin.
253
247
  */
254
248
  export function captureDelegatedPolicyOverrides(parent: Agent): DelegatedPolicyOverrides {
255
- const preset = parent.ctx.get("permissionPresets")?.current(parent.session);
249
+ const preset = parent.ctx.get('permissionPresets')?.current(parent.session)
256
250
  return {
257
- permissionPreset: preset === "auto" || preset === "danger-full-access" ? preset : undefined,
258
- sandboxMode: parent.ctx.get("sandboxPolicy")?.overrideOf(parent.session),
259
- approvalPolicy: parent.ctx.get("approval") === undefined ? undefined : "never",
260
- };
251
+ permissionPreset: preset === 'auto' || preset === 'danger-full-access' ? preset : undefined,
252
+ sandboxMode: parent.ctx.get('sandboxPolicy')?.overrideOf(parent.session),
253
+ approvalPolicy: parent.ctx.get('approval') === undefined ? undefined : 'never',
254
+ }
261
255
  }
262
256
 
263
257
  /**
264
258
  * Append the captured delegation policy onto the child's own log as
265
- * `source: 'delegation'` events inside the unpublished creation window, so the
259
+ * `source: 'delegation'` events after Session announcement and before Agent registration, so the
266
260
  * child's effective policy is reconstructable from its log alone. Appends land
267
261
  * after any fork seed, so fresh policy wins stale seed state; later child
268
262
  * switches still win over these events.
269
- * @param childSession - the unpublished child's session.
263
+ * @param childSession - the child's announced, writable Session.
270
264
  * @param overrides - the policy captured at delegation.
271
265
  */
272
266
  export function appendDelegatedPolicyOverrides(
@@ -274,27 +268,24 @@ export function appendDelegatedPolicyOverrides(
274
268
  overrides: DelegatedPolicyOverrides,
275
269
  ): void {
276
270
  if (overrides.sandboxMode !== undefined) {
277
- childSession.append("sandbox/mode", { mode: overrides.sandboxMode, source: "delegation" });
271
+ childSession.append('sandbox/mode', { mode: overrides.sandboxMode, source: 'delegation' })
278
272
  }
279
273
  if (overrides.approvalPolicy !== undefined) {
280
- childSession.append("approval/policy", {
281
- policy: overrides.approvalPolicy,
282
- source: "delegation",
283
- });
274
+ childSession.append('approval/policy', { policy: overrides.approvalPolicy, source: 'delegation' })
284
275
  }
285
276
  if (overrides.permissionPreset !== undefined) {
286
- childSession.append("permission/preset", { preset: overrides.permissionPreset });
277
+ childSession.append('permission/preset', { preset: overrides.permissionPreset })
287
278
  }
288
279
  }
289
280
 
290
281
  /** Identity and lineage inputs shared by every in-process child creation. */
291
282
  export interface ChildCreateInputs {
292
283
  /** The child's reserved session id. */
293
- readonly sessionId: SessionId;
284
+ readonly sessionId: SessionId
294
285
  /** The delegating parent agent. */
295
- readonly parent: Agent;
286
+ readonly parent: Agent
296
287
  /** The resolved delegation depth. */
297
- readonly childDepth: number;
288
+ readonly childDepth: number
298
289
  /** How many leading seed events came from the parent's log. */
299
- readonly lineageSeedLength: number;
290
+ readonly lineageSeedLength: number
300
291
  }