@morlay/dsh-subagent 0.0.10 → 0.0.11-alpha.1

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.
@@ -21,12 +21,12 @@
21
21
  * @module @deepseek-ai/dsh-subagent/descriptor
22
22
  */
23
23
 
24
- import { snapshotJsonValue } from "@deepseek-ai/dsh-util-values";
25
- import type { SessionEvent } from "@deepseek-ai/dsh-session";
26
- import type { ReasoningEffortId } from "@deepseek-ai/dsh-llm";
27
- import type { ToolRestriction } from "@deepseek-ai/dsh-tools";
24
+ import { snapshotJsonValue } from '@deepseek-ai/dsh-util-values'
25
+ import type { SessionEvent } from '@deepseek-ai/dsh-session'
26
+ import type { ReasoningEffortId } from '@deepseek-ai/dsh-llm'
27
+ import type { ToolRestriction } from '@deepseek-ai/dsh-tools'
28
28
 
29
- declare module "@deepseek-ai/dsh-session/types" {
29
+ declare module '@deepseek-ai/dsh-session/types' {
30
30
  interface SessionEventMap {
31
31
  /**
32
32
  * Durable identity and lifecycle mode of a session-backed subagent child,
@@ -35,7 +35,7 @@ declare module "@deepseek-ai/dsh-session/types" {
35
35
  * resumable composition. Log-only: it carries no `surfaceOp`, never enters
36
36
  * model history, and survives compaction.
37
37
  */
38
- "subagent/descriptor": SubagentDescriptorData;
38
+ 'subagent/descriptor': SubagentDescriptorData
39
39
  }
40
40
  }
41
41
 
@@ -45,181 +45,180 @@ declare module "@deepseek-ai/dsh-session/types" {
45
45
  * Supporting another composition input is a deliberate version change, never
46
46
  * an implicit extra field.
47
47
  */
48
- export const SUBAGENT_DESCRIPTOR_VERSION = 3;
48
+ export const SUBAGENT_DESCRIPTOR_VERSION = 3
49
49
 
50
50
  /** Fields shared by every supported `subagent/descriptor` payload. */
51
51
  interface SubagentDescriptorBase {
52
52
  /** Descriptor format version ({@link SUBAGENT_DESCRIPTOR_VERSION}). */
53
- readonly version: number;
53
+ readonly version: number
54
54
  /** Whether the child is a terminal one-shot run or a resumable conversation. */
55
- readonly mode: "one-shot" | "continuable";
55
+ readonly mode: 'one-shot' | 'continuable'
56
56
  /** The `ctx.subagents` provider name that established the child. */
57
- readonly provider: string;
57
+ readonly provider: string
58
58
  }
59
59
 
60
60
  /** A session-backed subagent that cannot be cold-resumed after its run. */
61
61
  export interface OneShotSubagentDescriptorData extends SubagentDescriptorBase {
62
- readonly mode: "one-shot";
62
+ readonly mode: 'one-shot'
63
63
  /**
64
64
  * The initial delegation's short `description`, kept as the child's durable
65
65
  * creation label so enumeration can identify the conversation without
66
66
  * replaying parent tool results or exposing the child prompt.
67
67
  */
68
- readonly label?: string;
68
+ readonly label?: string
69
69
  }
70
70
 
71
71
  /** A session-backed subagent whose declared composition supports cold resume. */
72
72
  export interface ContinuableSubagentDescriptorData extends SubagentDescriptorBase {
73
- readonly mode: "continuable";
73
+ readonly mode: 'continuable'
74
74
  /** The initial delegation's short `description`, used for durable enumeration. */
75
- readonly label: string;
75
+ readonly label: string
76
76
  /** Resolved child `agentOptions.provider`, when one was declared. */
77
- readonly agentProvider?: string;
77
+ readonly agentProvider?: string
78
78
  /** Resolved child `agentOptions.model`, when one was declared. */
79
- readonly agentModel?: string;
79
+ readonly agentModel?: string
80
80
  /** Resolved child `agentOptions.reasoningEffort`, when one was declared. */
81
- readonly agentReasoningEffort?: ReasoningEffortId;
81
+ readonly agentReasoningEffort?: ReasoningEffortId
82
82
  /** Per-child persona that shadows the deployment persona on resume. */
83
- readonly persona?: string;
83
+ readonly persona?: string
84
84
  /** Child tool scoping reapplied on resume. */
85
- readonly toolFilter?: ToolRestriction;
85
+ readonly toolFilter?: ToolRestriction
86
86
  }
87
87
 
88
88
  /** The supported durable subagent identity and optional continuation composition. */
89
89
  export type SubagentDescriptorData =
90
90
  | OneShotSubagentDescriptorData
91
- | ContinuableSubagentDescriptorData;
91
+ | ContinuableSubagentDescriptorData
92
92
 
93
93
  /** Continuable composition fields before the snapshot stamps their format version. */
94
- export type ContinuableSubagentDescriptorInput = Omit<ContinuableSubagentDescriptorData, "version">;
94
+ export type ContinuableSubagentDescriptorInput = Omit<ContinuableSubagentDescriptorData, 'version'>
95
95
 
96
- const DESCRIPTOR_BASE_KEYS = ["version", "mode", "provider", "label"] as const;
97
- const ONE_SHOT_DESCRIPTOR_KEYS = new Set(DESCRIPTOR_BASE_KEYS);
96
+ const DESCRIPTOR_BASE_KEYS = [
97
+ 'version',
98
+ 'mode',
99
+ 'provider',
100
+ 'label',
101
+ ] as const
102
+ const ONE_SHOT_DESCRIPTOR_KEYS = new Set(DESCRIPTOR_BASE_KEYS)
98
103
  const CONTINUABLE_DESCRIPTOR_KEYS = new Set([
99
104
  ...DESCRIPTOR_BASE_KEYS,
100
- "agentProvider",
101
- "agentModel",
102
- "agentReasoningEffort",
103
- "persona",
104
- "toolFilter",
105
- ]);
106
- const TOOL_FILTER_KEYS = new Set(["allow", "deny"]);
105
+ 'agentProvider',
106
+ 'agentModel',
107
+ 'agentReasoningEffort',
108
+ 'persona',
109
+ 'toolFilter',
110
+ ])
111
+ const TOOL_FILTER_KEYS = new Set(['allow', 'deny'])
107
112
 
108
113
  /** Whether a persisted JSON value is an object record. */
109
114
  function isRecord(value: unknown): value is Record<string, unknown> {
110
- return typeof value === "object" && value !== null && !Array.isArray(value);
115
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
111
116
  }
112
117
 
113
118
  /** Reject fields outside one versioned record's declared schema. */
114
- function assertKnownKeys(
115
- value: Record<string, unknown>,
116
- keys: ReadonlySet<string>,
117
- path: string,
118
- ): void {
119
- const unknown = Object.keys(value).find((key) => !keys.has(key));
119
+ function assertKnownKeys(value: Record<string, unknown>, keys: ReadonlySet<string>, path: string): void {
120
+ const unknown = Object.keys(value).find(key => !keys.has(key))
120
121
  if (unknown !== undefined) {
121
- throw new Error(`persisted subagent descriptor ${path} has unknown field "${unknown}"`);
122
+ throw new Error(`persisted subagent descriptor ${path} has unknown field "${unknown}"`)
122
123
  }
123
124
  }
124
125
 
125
126
  /** Read one optional string field from a persisted descriptor record. */
126
127
  function optionalString(value: Record<string, unknown>, key: string): string | undefined {
127
- if (!Object.hasOwn(value, key)) return undefined;
128
- const field = value[key];
129
- if (typeof field !== "string") {
130
- throw new Error(`persisted subagent descriptor ${key} must be a string`);
128
+ if (!Object.hasOwn(value, key)) return undefined
129
+ const field = value[key]
130
+ if (typeof field !== 'string') {
131
+ throw new Error(`persisted subagent descriptor ${key} must be a string`)
131
132
  }
132
- return field;
133
+ return field
133
134
  }
134
135
 
135
136
  /** Read one optional string-array field from a persisted tool restriction. */
136
137
  function optionalStringArray(value: Record<string, unknown>, key: string): string[] | undefined {
137
- if (!Object.hasOwn(value, key)) return undefined;
138
- const field = value[key];
138
+ if (!Object.hasOwn(value, key)) return undefined
139
+ const field = value[key]
139
140
  if (!Array.isArray(field)) {
140
- throw new Error(`persisted subagent descriptor toolFilter.${key} must be an array of strings`);
141
+ throw new Error(`persisted subagent descriptor toolFilter.${key} must be an array of strings`)
141
142
  }
142
- const items: unknown[] = field;
143
- if (items.some((item) => typeof item !== "string")) {
144
- throw new Error(`persisted subagent descriptor toolFilter.${key} must be an array of strings`);
143
+ const items: unknown[] = field
144
+ if (items.some(item => typeof item !== 'string')) {
145
+ throw new Error(`persisted subagent descriptor toolFilter.${key} must be an array of strings`)
145
146
  }
146
- return items as string[];
147
+ return items as string[]
147
148
  }
148
149
 
149
150
  /** Validate and reconstruct a persisted tool restriction. */
150
151
  function parseToolFilter(value: unknown): ToolRestriction {
151
152
  if (!isRecord(value)) {
152
- throw new Error("persisted subagent descriptor toolFilter must be an object");
153
+ throw new Error('persisted subagent descriptor toolFilter must be an object')
153
154
  }
154
- assertKnownKeys(value, TOOL_FILTER_KEYS, "toolFilter");
155
- const allow = optionalStringArray(value, "allow");
156
- const deny = optionalStringArray(value, "deny");
155
+ assertKnownKeys(value, TOOL_FILTER_KEYS, 'toolFilter')
156
+ const allow = optionalStringArray(value, 'allow')
157
+ const deny = optionalStringArray(value, 'deny')
157
158
  if (allow === undefined && deny === undefined) {
158
- throw new Error("persisted subagent descriptor toolFilter must declare allow and/or deny");
159
+ throw new Error('persisted subagent descriptor toolFilter must declare allow and/or deny')
159
160
  }
160
161
  return {
161
- ...(allow !== undefined ? { allow } : {}),
162
- ...(deny !== undefined ? { deny } : {}),
163
- };
162
+ ...allow !== undefined ? { allow } : {},
163
+ ...deny !== undefined ? { deny } : {},
164
+ }
164
165
  }
165
166
 
166
167
  /** Validate one persisted descriptor payload for the current runtime. */
167
168
  function parseSubagentDescriptor(value: unknown): SubagentDescriptorData | undefined {
168
169
  if (!isRecord(value)) {
169
- throw new Error("persisted subagent descriptor payload must be an object");
170
+ throw new Error('persisted subagent descriptor payload must be an object')
170
171
  }
171
- const version = value["version"];
172
- if (typeof version !== "number") {
173
- throw new Error("persisted subagent descriptor version must be a number");
172
+ const version = value['version']
173
+ if (typeof version !== 'number') {
174
+ throw new Error('persisted subagent descriptor version must be a number')
174
175
  }
175
- if (version !== SUBAGENT_DESCRIPTOR_VERSION) return undefined;
176
+ if (version !== SUBAGENT_DESCRIPTOR_VERSION) return undefined
176
177
 
177
- const mode = value["mode"];
178
- if (mode !== "one-shot" && mode !== "continuable") {
179
- throw new Error('persisted subagent descriptor mode must be "one-shot" or "continuable"');
178
+ const mode = value['mode']
179
+ if (mode !== 'one-shot' && mode !== 'continuable') {
180
+ throw new Error('persisted subagent descriptor mode must be "one-shot" or "continuable"')
180
181
  }
181
182
  assertKnownKeys(
182
183
  value,
183
- mode === "one-shot" ? ONE_SHOT_DESCRIPTOR_KEYS : CONTINUABLE_DESCRIPTOR_KEYS,
184
- "payload",
185
- );
186
- const provider = value["provider"];
187
- if (typeof provider !== "string") {
188
- throw new Error("persisted subagent descriptor provider must be a string");
184
+ mode === 'one-shot' ? ONE_SHOT_DESCRIPTOR_KEYS : CONTINUABLE_DESCRIPTOR_KEYS,
185
+ 'payload',
186
+ )
187
+ const provider = value['provider']
188
+ if (typeof provider !== 'string') {
189
+ throw new Error('persisted subagent descriptor provider must be a string')
189
190
  }
190
- if (mode === "one-shot") {
191
- const label = optionalString(value, "label");
191
+ if (mode === 'one-shot') {
192
+ const label = optionalString(value, 'label')
192
193
  return {
193
194
  version: SUBAGENT_DESCRIPTOR_VERSION,
194
195
  mode,
195
196
  provider,
196
- ...(label !== undefined ? { label } : {}),
197
- };
197
+ ...label !== undefined ? { label } : {},
198
+ }
198
199
  }
199
- const label = value["label"];
200
- if (typeof label !== "string") {
201
- throw new Error("persisted subagent descriptor label must be a string");
200
+ const label = value['label']
201
+ if (typeof label !== 'string') {
202
+ throw new Error('persisted subagent descriptor label must be a string')
202
203
  }
203
- const agentProvider = optionalString(value, "agentProvider");
204
- const agentModel = optionalString(value, "agentModel");
205
- const agentReasoningEffort = optionalString(value, "agentReasoningEffort") as
206
- | ReasoningEffortId
207
- | undefined;
208
- const persona = optionalString(value, "persona");
209
- const toolFilter = Object.hasOwn(value, "toolFilter")
210
- ? parseToolFilter(value["toolFilter"])
211
- : undefined;
204
+ const agentProvider = optionalString(value, 'agentProvider')
205
+ const agentModel = optionalString(value, 'agentModel')
206
+ const agentReasoningEffort = optionalString(value, 'agentReasoningEffort') as ReasoningEffortId | undefined
207
+ const persona = optionalString(value, 'persona')
208
+ const toolFilter = Object.hasOwn(value, 'toolFilter')
209
+ ? parseToolFilter(value['toolFilter'])
210
+ : undefined
212
211
  return {
213
212
  version: SUBAGENT_DESCRIPTOR_VERSION,
214
213
  mode,
215
214
  provider,
216
215
  label,
217
- ...(agentProvider !== undefined ? { agentProvider } : {}),
218
- ...(agentModel !== undefined ? { agentModel } : {}),
219
- ...(agentReasoningEffort !== undefined ? { agentReasoningEffort } : {}),
220
- ...(persona !== undefined ? { persona } : {}),
221
- ...(toolFilter !== undefined ? { toolFilter } : {}),
222
- };
216
+ ...agentProvider !== undefined ? { agentProvider } : {},
217
+ ...agentModel !== undefined ? { agentModel } : {},
218
+ ...agentReasoningEffort !== undefined ? { agentReasoningEffort } : {},
219
+ ...persona !== undefined ? { persona } : {},
220
+ ...toolFilter !== undefined ? { toolFilter } : {},
221
+ }
223
222
  }
224
223
 
225
224
  /**
@@ -236,19 +235,17 @@ export function snapshotSubagentDescriptor(
236
235
  mode: input.mode,
237
236
  provider: input.provider,
238
237
  label: input.label,
239
- ...(input.agentProvider !== undefined ? { agentProvider: input.agentProvider } : {}),
240
- ...(input.agentModel !== undefined ? { agentModel: input.agentModel } : {}),
241
- ...(input.agentReasoningEffort !== undefined
242
- ? { agentReasoningEffort: input.agentReasoningEffort }
243
- : {}),
244
- ...(input.persona !== undefined ? { persona: input.persona } : {}),
245
- ...(input.toolFilter !== undefined ? { toolFilter: input.toolFilter } : {}),
246
- };
247
- const snapshot = snapshotJsonValue(candidate);
238
+ ...input.agentProvider !== undefined ? { agentProvider: input.agentProvider } : {},
239
+ ...input.agentModel !== undefined ? { agentModel: input.agentModel } : {},
240
+ ...input.agentReasoningEffort !== undefined ? { agentReasoningEffort: input.agentReasoningEffort } : {},
241
+ ...input.persona !== undefined ? { persona: input.persona } : {},
242
+ ...input.toolFilter !== undefined ? { toolFilter: input.toolFilter } : {},
243
+ }
244
+ const snapshot = snapshotJsonValue(candidate)
248
245
  if (snapshot === undefined) {
249
- throw new Error("subagent descriptor is not losslessly JSON-serializable");
246
+ throw new Error('subagent descriptor is not losslessly JSON-serializable')
250
247
  }
251
- return snapshot;
248
+ return snapshot
252
249
  }
253
250
 
254
251
  /**
@@ -263,13 +260,10 @@ export function snapshotSubagentDescriptor(
263
260
  * @throws when a current-version persisted payload does not match its complete
264
261
  * declared schema.
265
262
  */
266
- export function foldSubagentDescriptor(
267
- events: readonly SessionEvent[],
268
- ): SubagentDescriptorData | undefined {
263
+ export function foldSubagentDescriptor(events: readonly SessionEvent[]): SubagentDescriptorData | undefined {
269
264
  const event = events.find(
270
- (candidate): candidate is SessionEvent<"subagent/descriptor"> =>
271
- candidate.type === "subagent/descriptor",
272
- );
273
- if (event === undefined) return undefined;
274
- return parseSubagentDescriptor(event.data);
265
+ (candidate): candidate is SessionEvent<'subagent/descriptor'> => candidate.type === 'subagent/descriptor',
266
+ )
267
+ if (event === undefined) return undefined
268
+ return parseSubagentDescriptor(event.data)
275
269
  }
@@ -4,12 +4,12 @@
4
4
  * @module @deepseek-ai/dsh-subagent
5
5
  */
6
6
 
7
- import { HarnessError } from "@deepseek-ai/dsh-llm";
7
+ import { HarnessError } from '@deepseek-ai/dsh-llm'
8
8
 
9
9
  /** Typed failure for the subagent seam. */
10
10
  export class SubagentError extends HarnessError {
11
11
  constructor(message: string, code: string, options?: ErrorOptions) {
12
- super(message, code, options);
13
- this.name = "SubagentError";
12
+ super(message, code, options)
13
+ this.name = 'SubagentError'
14
14
  }
15
15
  }