@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.
- package/dist/index.d.mts +86 -129
- package/dist/index.mjs +43 -49
- package/dist/rows.d.mts +1 -3
- package/dist/rows.mjs +1 -2
- package/package.json +28 -28
- package/src/continuation-messages.ts +73 -59
- package/src/index.ts +263 -189
- package/src/manager.ts +900 -716
- package/src/vendor/dsh-subagent/activation.ts +81 -89
- package/src/vendor/dsh-subagent/archive-admission.ts +38 -45
- package/src/vendor/dsh-subagent/assistant-output.ts +17 -19
- package/src/vendor/dsh-subagent/catalog.ts +79 -111
- package/src/vendor/dsh-subagent/child-agent.ts +83 -92
- package/src/vendor/dsh-subagent/continuation-messages.ts +64 -68
- package/src/vendor/dsh-subagent/control-types.ts +71 -68
- package/src/vendor/dsh-subagent/control.ts +39 -55
- package/src/vendor/dsh-subagent/depth.ts +14 -18
- package/src/vendor/dsh-subagent/descriptor.ts +107 -113
- package/src/vendor/dsh-subagent/error.ts +3 -3
- package/src/vendor/dsh-subagent/index.ts +193 -254
- package/src/vendor/dsh-subagent/internal.ts +17 -21
- package/src/vendor/dsh-subagent/lifecycle.ts +48 -51
- package/src/vendor/dsh-subagent/list-children.ts +57 -65
- package/src/vendor/dsh-subagent/manager.ts +726 -862
- package/src/vendor/dsh-subagent/out-of-process.ts +59 -61
- package/src/vendor/dsh-subagent/projection-types.ts +40 -38
- package/src/vendor/dsh-subagent/projection.ts +85 -107
- package/src/vendor/dsh-subagent/structured.ts +48 -57
- package/src/vendor/dsh-subagent/types.ts +68 -68
|
@@ -21,12 +21,12 @@
|
|
|
21
21
|
* @module @deepseek-ai/dsh-subagent/descriptor
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
import { snapshotJsonValue } from
|
|
25
|
-
import type { SessionEvent } from
|
|
26
|
-
import type { ReasoningEffortId } from
|
|
27
|
-
import type { ToolRestriction } from
|
|
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
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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,
|
|
94
|
+
export type ContinuableSubagentDescriptorInput = Omit<ContinuableSubagentDescriptorData, 'version'>
|
|
95
95
|
|
|
96
|
-
const DESCRIPTOR_BASE_KEYS = [
|
|
97
|
-
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
])
|
|
106
|
-
const TOOL_FILTER_KEYS = new Set([
|
|
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 ===
|
|
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
|
|
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 !==
|
|
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(
|
|
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(
|
|
153
|
+
throw new Error('persisted subagent descriptor toolFilter must be an object')
|
|
153
154
|
}
|
|
154
|
-
assertKnownKeys(value, TOOL_FILTER_KEYS,
|
|
155
|
-
const allow = optionalStringArray(value,
|
|
156
|
-
const deny = optionalStringArray(value,
|
|
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(
|
|
159
|
+
throw new Error('persisted subagent descriptor toolFilter must declare allow and/or deny')
|
|
159
160
|
}
|
|
160
161
|
return {
|
|
161
|
-
...
|
|
162
|
-
...
|
|
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(
|
|
170
|
+
throw new Error('persisted subagent descriptor payload must be an object')
|
|
170
171
|
}
|
|
171
|
-
const version = value[
|
|
172
|
-
if (typeof version !==
|
|
173
|
-
throw new Error(
|
|
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[
|
|
178
|
-
if (mode !==
|
|
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 ===
|
|
184
|
-
|
|
185
|
-
)
|
|
186
|
-
const provider = value[
|
|
187
|
-
if (typeof provider !==
|
|
188
|
-
throw new Error(
|
|
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 ===
|
|
191
|
-
const label = optionalString(value,
|
|
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
|
-
...
|
|
197
|
-
}
|
|
197
|
+
...label !== undefined ? { label } : {},
|
|
198
|
+
}
|
|
198
199
|
}
|
|
199
|
-
const label = value[
|
|
200
|
-
if (typeof label !==
|
|
201
|
-
throw new Error(
|
|
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,
|
|
204
|
-
const agentModel = optionalString(value,
|
|
205
|
-
const agentReasoningEffort = optionalString(value,
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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
|
-
...
|
|
218
|
-
...
|
|
219
|
-
...
|
|
220
|
-
...
|
|
221
|
-
...
|
|
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
|
-
...
|
|
240
|
-
...
|
|
241
|
-
...
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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(
|
|
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<
|
|
271
|
-
|
|
272
|
-
)
|
|
273
|
-
|
|
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
|
|
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 =
|
|
12
|
+
super(message, code, options)
|
|
13
|
+
this.name = 'SubagentError'
|
|
14
14
|
}
|
|
15
15
|
}
|