@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.
@@ -4,19 +4,19 @@
4
4
  * @module @deepseek-ai/dsh-subagent/continuation-messages
5
5
  */
6
6
 
7
- import type { Agent } from "@deepseek-ai/dsh-agent";
8
- import { boundContextSummary, createUserMessage } from "@deepseek-ai/dsh-llm";
9
- import type { ContentBlock } from "@deepseek-ai/dsh-llm";
10
- import type { SessionId } from "@deepseek-ai/dsh-session";
11
- import type { SubagentResult } from "./types.ts";
7
+ import type { Agent } from '@deepseek-ai/dsh-agent'
8
+ import { boundContextSummary, createUserMessage } from '@deepseek-ai/dsh-llm'
9
+ import type { ContentBlock } from '@deepseek-ai/dsh-llm'
10
+ import type { SessionId } from '@deepseek-ai/dsh-session'
11
+ import type { SubagentResult } from './types.ts'
12
12
 
13
13
  /** Durable attribution for one model-authored message between Agents. */
14
14
  export interface AgentMessageSource {
15
- readonly kind: "agent-message";
15
+ readonly kind: 'agent-message'
16
16
  /** A message another agent addressed to this one (`relay` context form). */
17
- readonly form: "relay";
17
+ readonly form: 'relay'
18
18
  /** Session id of the Agent whose tool call produced the message. */
19
- readonly senderSessionId: SessionId;
19
+ readonly senderSessionId: SessionId
20
20
  }
21
21
 
22
22
  /**
@@ -27,29 +27,29 @@ export interface AgentMessageSource {
27
27
  * transcript that merged them would credit the child with words it never wrote.
28
28
  */
29
29
  export interface SubagentSettledMessageSource {
30
- readonly kind: "subagent-settled";
30
+ readonly kind: 'subagent-settled'
31
31
  /** A runtime account shown without expanding the row (`notice` context form). */
32
- readonly form: "notice";
32
+ readonly form: 'notice'
33
33
  /** One-line account of how the child ended. */
34
- readonly summary: string;
34
+ readonly summary: string
35
35
  /** Session id of the child that settled. */
36
- readonly senderSessionId: SessionId;
36
+ readonly senderSessionId: SessionId
37
37
  }
38
38
 
39
- declare module "@deepseek-ai/dsh-llm" {
39
+ declare module '@deepseek-ai/dsh-llm' {
40
40
  interface MessageSourceMap {
41
- "agent-message": AgentMessageSource;
42
- "subagent-settled": SubagentSettledMessageSource;
41
+ 'agent-message': AgentMessageSource
42
+ 'subagent-settled': SubagentSettledMessageSource
43
43
  }
44
44
  }
45
45
 
46
46
  /** Build durable attribution for one adjacent-Agent message. */
47
47
  function agentMessageSource(sender: Agent): AgentMessageSource {
48
48
  return {
49
- kind: "agent-message",
50
- form: "relay",
49
+ kind: 'agent-message',
50
+ form: 'relay',
51
51
  senderSessionId: sender.id,
52
- };
52
+ }
53
53
  }
54
54
 
55
55
  /**
@@ -63,9 +63,12 @@ export function createAgentMessage(
63
63
  content: ContentBlock[],
64
64
  ): ReturnType<typeof createUserMessage> {
65
65
  return createUserMessage({
66
- content: [{ type: "text" as const, text: `Agent ${sender.id} sent a message: ` }, ...content],
66
+ content: [
67
+ { type: 'text' as const, text: `Agent ${sender.id} sent a message: ` },
68
+ ...content,
69
+ ],
67
70
  source: agentMessageSource(sender),
68
- });
71
+ })
69
72
  }
70
73
 
71
74
  /**
@@ -78,19 +81,18 @@ export function withContinuableReturnGuidance(
78
81
  parentId: SessionId,
79
82
  prompt: ContentBlock[],
80
83
  ): ContentBlock[] {
81
- const encodedParentId = JSON.stringify(parentId);
84
+ const encodedParentId = JSON.stringify(parentId)
82
85
  return [
83
86
  ...prompt,
84
87
  {
85
- type: "text",
86
- text:
87
- `Your parent agent id is ${encodedParentId}. Before you finish, send your result to that agent with ` +
88
- `send_message({ agent_id: ${encodedParentId}, message: "<self-contained result>" }). The parent shares ` +
89
- "your workspace but does not automatically receive your transcript, tool output, or reasoning. Send " +
90
- "earlier messages as well when a finding changes what the parent should do next; sending a message " +
91
- "does not end your turn.",
88
+ type: 'text',
89
+ text: `Your parent agent id is ${encodedParentId}. Before you finish, send your result to that agent with `
90
+ + `send_message({ agent_id: ${encodedParentId}, message: "<self-contained result>" }). The parent shares `
91
+ + 'your workspace but does not automatically receive your transcript, tool output, or reasoning. Send '
92
+ + 'earlier messages as well when a finding changes what the parent should do next; sending a message '
93
+ + 'does not end your turn.',
92
94
  },
93
- ];
95
+ ]
94
96
  }
95
97
 
96
98
  /**
@@ -101,32 +103,28 @@ export function withContinuableReturnGuidance(
101
103
  * @param continuable - whether the child accepts a later message.
102
104
  * @returns the model-facing opening line of the settlement notice.
103
105
  */
104
- function settlementSummary(
105
- childId: SessionId,
106
- stopReason: SubagentResult["stopReason"],
107
- continuable: boolean,
108
- ): string {
109
- const subject = `Background subagent ${childId}`;
106
+ function settlementSummary(childId: SessionId, stopReason: SubagentResult['stopReason'], continuable: boolean): string {
107
+ const subject = `Background subagent ${childId}`
110
108
  switch (stopReason) {
111
- case "completed":
109
+ case 'completed':
112
110
  return continuable
113
111
  ? `${subject} finished and will do no further work unless you send it more.`
114
- : `${subject} finished. It cannot receive follow-up messages.`;
115
- case "aborted":
116
- return `${subject} was stopped before it finished.`;
117
- case "max-tokens":
118
- return `${subject} ran out of room before it finished.`;
112
+ : `${subject} finished. It cannot receive follow-up messages.`
113
+ case 'aborted':
114
+ return `${subject} was stopped before it finished.`
115
+ case 'max-tokens':
116
+ return `${subject} ran out of room before it finished.`
119
117
  // A pre-step rejection — a hook deny, a policy plugin — discarded input
120
118
  // the child had claimed, so the parent must not treat the task as done.
121
- case "refusal":
122
- return `${subject} declined the task.`;
123
- case "error":
124
- return `${subject} failed before it finished.`;
119
+ case 'refusal':
120
+ return `${subject} declined the task.`
121
+ case 'error':
122
+ return `${subject} failed before it finished.`
125
123
  /* v8 ignore next 4 -- `SubagentResult['stopReason']` is merge-extensible, so this arm
126
124
  * needs a backend that adds a variant; an unnameable ending is reported as unfinished
127
125
  * rather than silently as success. */
128
126
  default:
129
- return `${subject} ended abnormally (${String(stopReason)}) before it finished.`;
127
+ return `${subject} ended abnormally (${String(stopReason)}) before it finished.`
130
128
  }
131
129
  }
132
130
 
@@ -135,43 +133,41 @@ function settlementSummary(
135
133
  * @param childId - durable child session id named in the notice.
136
134
  * @param terminal - recorded terminal state for the settled Activation.
137
135
  * @param continuable - whether the child can accept another task.
136
+ * @param omitClosingText - replace the closing text with a note that the child's
137
+ * last message to the parent already carries it.
138
138
  * @returns the durable user-message representation delivered to the parent.
139
139
  */
140
140
  export function createSettlementMessage(
141
141
  childId: SessionId,
142
142
  terminal: SubagentResult,
143
143
  continuable = true,
144
+ omitClosingText = false,
144
145
  ): ReturnType<typeof createUserMessage> {
145
- const summary = settlementSummary(childId, terminal.stopReason, continuable);
146
+ const summary = settlementSummary(childId, terminal.stopReason, continuable)
146
147
  // Parent providers receive this notice as a user message and may reject
147
148
  // nontext assistant blocks. Keep this conversion local so SDK/UI consumers
148
149
  // retain the complete child output.
149
- const closingText = terminal.output.flatMap((block) =>
150
- block.type === "text" && block.text.length > 0 ? [block] : [],
151
- );
150
+ const closingText = terminal.output.flatMap(block =>
151
+ block.type === 'text' && block.text.length > 0 ? [block] : [],
152
+ )
152
153
  return createUserMessage({
153
154
  content: [
154
- { type: "text" as const, text: summary },
155
- ...(closingText.length === 0
156
- ? [{ type: "text" as const, text: "It left no closing message." }]
157
- : [{ type: "text" as const, text: "Its closing message:" }, ...closingText]),
158
- ...(terminal.structured !== undefined
159
- ? [
160
- {
161
- type: "text" as const,
162
- text: `Structured result: ${JSON.stringify(terminal.structured)}`,
163
- },
164
- ]
165
- : []),
166
- ...(terminal.diagnostic !== undefined
167
- ? [{ type: "text" as const, text: terminal.diagnostic }]
168
- : []),
155
+ { type: 'text' as const, text: summary },
156
+ ...omitClosingText
157
+ ? [{ type: 'text' as const, text: 'It sent you a message just before finishing, so its closing message is omitted.' }]
158
+ : closingText.length === 0
159
+ ? [{ type: 'text' as const, text: 'It left no closing message.' }]
160
+ : [{ type: 'text' as const, text: 'Its closing message:' }, ...closingText],
161
+ ...terminal.structured !== undefined
162
+ ? [{ type: 'text' as const, text: `Structured result: ${JSON.stringify(terminal.structured)}` }] : [],
163
+ ...terminal.diagnostic !== undefined
164
+ ? [{ type: 'text' as const, text: terminal.diagnostic }] : [],
169
165
  ],
170
166
  source: {
171
- kind: "subagent-settled" as const,
172
- form: "notice" as const,
167
+ kind: 'subagent-settled' as const,
168
+ form: 'notice' as const,
173
169
  summary: boundContextSummary(summary),
174
170
  senderSessionId: childId,
175
171
  },
176
- });
172
+ })
177
173
  }
@@ -5,12 +5,12 @@
5
5
  * @module @deepseek-ai/dsh-subagent/control-types
6
6
  */
7
7
 
8
- import type { PromptContentPart } from "@deepseek-ai/dsh-attachment/types";
9
- import type { Branded } from "@deepseek-ai/dsh-brand";
10
- import type { MessageId } from "@deepseek-ai/dsh-llm/brand";
11
- import type { SessionId } from "@deepseek-ai/dsh-session/types";
8
+ import type { PromptContentPart } from '@deepseek-ai/dsh-attachment/types'
9
+ import type { Branded } from '@deepseek-ai/dsh-brand'
10
+ import type { MessageId } from '@deepseek-ai/dsh-llm/brand'
11
+ import type { SessionId } from '@deepseek-ai/dsh-session/types'
12
12
  // Type-only: the Workspace registry's archive-admission family map this runtime merges `subagent` into.
13
- import type {} from "@deepseek-ai/dsh-workspace/types";
13
+ import type {} from '@deepseek-ai/dsh-workspace/types'
14
14
 
15
15
  /**
16
16
  * Client-minted identity of one browser prompt, persisted on the exact accepted
@@ -19,128 +19,131 @@ import type {} from "@deepseek-ai/dsh-workspace/types";
19
19
  * vocabulary; that package depends on this one, so the brand is spelled here
20
20
  * rather than imported.
21
21
  */
22
- export type SubagentPromptRequestId = Branded<"session-request-id">;
22
+ export type SubagentPromptRequestId = Branded<'session-request-id'>
23
23
 
24
24
  /** Shared child fields for recursive catalog listing. */
25
- export type SubagentCatalogRow = {
26
- /** The durable child session id, stable across Activations. */
27
- readonly id: SessionId;
28
- /**
29
- * Whether recursive catalog listing observed a resident Session. This
30
- * does not encode a durable outcome or guarantee continuation delivery.
31
- */
32
- readonly activity: "running" | "inactive";
33
- } & (
34
- | {
25
+ export type SubagentCatalogRow =
26
+ & {
27
+ /** The durable child session id, stable across Activations. */
28
+ readonly id: SessionId
29
+ /**
30
+ * Whether recursive catalog listing observed a resident Session. This
31
+ * does not encode a durable outcome or guarantee continuation delivery.
32
+ */
33
+ readonly activity: 'running' | 'inactive'
34
+ } & (
35
+ | {
35
36
  /** A terminal one-shot child. */
36
- readonly mode: "one-shot";
37
+ readonly mode: 'one-shot'
37
38
  /** Optional durable creation label from the parent catalog. */
38
- readonly label?: string;
39
+ readonly label?: string
39
40
  }
40
- | {
41
+ | {
41
42
  /** An external execution without a local child Session. */
42
- readonly mode: "external";
43
+ readonly mode: 'external'
43
44
  /** Optional durable creation label from the parent catalog. */
44
- readonly label?: string;
45
+ readonly label?: string
45
46
  }
46
- | {
47
+ | {
47
48
  /** A resumable conversation. */
48
- readonly mode: "continuable";
49
+ readonly mode: 'continuable'
49
50
  /** Durable creation label from the parent catalog. */
50
- readonly label: string;
51
+ readonly label: string
51
52
  }
52
- );
53
+ )
53
54
 
54
55
  /**
55
56
  * One recursive catalog row. Traversal may also return diagnostics for
56
57
  * unknown catalog modes or unreadable child catalogs.
57
58
  */
58
59
  export type SubagentListEntry =
59
- | (SubagentCatalogRow & {
60
- readonly kind: "child";
61
- /** Whether the child catalog contains a direct child. */
62
- readonly hasChildren: boolean;
63
- })
60
+ | SubagentCatalogRow & {
61
+ readonly kind: 'child'
62
+ /** Whether the child catalog contains a direct child. */
63
+ readonly hasChildren: boolean
64
+ }
64
65
  | {
65
- readonly kind: "diagnostic";
66
- /** The candidate's session id. */
67
- readonly id: SessionId;
68
- /**
69
- * `corrupt` means the child catalog read found invalid or conflicting
70
- * Session data; `unavailable` means it could not be read. Either failure
71
- * stops that branch. `unsupported` means the parent catalog records an
72
- * unknown child mode; its readable catalog is still traversed.
73
- */
74
- readonly reason: "corrupt" | "unsupported" | "unavailable";
75
- };
66
+ readonly kind: 'diagnostic'
67
+ /** The candidate's session id. */
68
+ readonly id: SessionId
69
+ /**
70
+ * `corrupt` means the child catalog read found invalid or conflicting
71
+ * Session data; `unavailable` means it could not be read. Either failure
72
+ * stops that branch. `unsupported` means the parent catalog records an
73
+ * unknown child mode; its readable catalog is still traversed.
74
+ */
75
+ readonly reason: 'corrupt' | 'unsupported' | 'unavailable'
76
+ }
76
77
 
77
78
  /** Durable parent/child browsing address; unknown mode is resolved when child history is read. */
78
- export type SubagentAddress = {
79
- readonly parentSessionId: SessionId;
80
- readonly childSessionId: SessionId;
81
- } & (
82
- | { readonly mode: "one-shot" }
83
- | { readonly mode: "continuable" }
84
- | { readonly mode: "unknown" }
85
- );
79
+ export type SubagentAddress =
80
+ & {
81
+ readonly parentSessionId: SessionId
82
+ readonly childSessionId: SessionId
83
+ }
84
+ & (
85
+ | { readonly mode: 'one-shot' }
86
+ | { readonly mode: 'continuable' }
87
+ | { readonly mode: 'unknown' }
88
+ )
86
89
 
87
90
  /** One Agent inbox destination, as the prompt request selects it. */
88
- export type SubagentDelivery = SubagentPromptRequest["delivery"];
91
+ export type SubagentDelivery = SubagentPromptRequest['delivery']
89
92
 
90
93
  /** One human message addressed to a continuable direct child. */
91
94
  export interface SubagentPromptRequest {
92
95
  /** Identity persisted on the accepted message, minted before the call. */
93
- readonly requestId: SubagentPromptRequestId;
94
- readonly parentSessionId: SessionId;
95
- readonly childSessionId: SessionId;
96
+ readonly requestId: SubagentPromptRequestId
97
+ readonly parentSessionId: SessionId
98
+ readonly childSessionId: SessionId
96
99
  /** Required discriminator retained from the browser control address. */
97
- readonly mode: "continuable";
100
+ readonly mode: 'continuable'
98
101
  /** Whether this message queues a later turn or targets the nearest step. */
99
- readonly delivery: "queue" | "steer";
102
+ readonly delivery: 'queue' | 'steer'
100
103
  /**
101
104
  * Browser prompt parts delivered as the child's user message. The Host
102
105
  * admits and persists image parts before delivery, so the wire never
103
106
  * carries a durable attachment reference the caller could fabricate.
104
107
  */
105
- readonly content: readonly PromptContentPart[];
108
+ readonly content: readonly PromptContentPart[]
106
109
  /** Optional browser zone sampled for this exact human prompt. */
107
- readonly clientTimeZone?: string;
110
+ readonly clientTimeZone?: string
108
111
  }
109
112
 
110
113
  /** Inbox identity returned once the continuation accepts one human message. */
111
114
  export interface SubagentPromptReceipt {
112
- readonly messageId: MessageId;
115
+ readonly messageId: MessageId
113
116
  }
114
117
 
115
118
  /** Uniform acknowledgement that one interrupt request was admitted. */
116
119
  export interface SubagentInterruptReceipt {
117
- readonly accepted: true;
120
+ readonly accepted: true
118
121
  }
119
122
 
120
123
  /**
121
124
  * Failure details the control surface answers with. Prompts and interrupts
122
125
  * share these failures with the Client Remote result.
123
126
  */
124
- declare module "@deepseek-ai/dsh-workspace/types" {
127
+ declare module '@deepseek-ai/dsh-workspace/types' {
125
128
  interface SessionActivityKindMap {
126
129
  /** A subagent session delegated from this session (at any depth) is inside a turn. */
127
- subagent: true;
130
+ subagent: true
128
131
  }
129
132
  }
130
133
 
131
- declare module "@deepseek-ai/dsh-typert-protocol" {
134
+ declare module '@deepseek-ai/dsh-typert-protocol' {
132
135
  interface RemoteErrorDetailsMap {
133
136
  /** A browser-supplied zone is neither UTC nor a canonical IANA name. */
134
- "subagent/invalid-time-zone": { readonly value: string };
137
+ 'subagent/invalid-time-zone': { readonly value: string }
135
138
  /** No live Agent carries the addressed parent session. */
136
- "subagent/parent-unavailable": { readonly parentSessionId: SessionId };
139
+ 'subagent/parent-unavailable': { readonly parentSessionId: SessionId }
137
140
  /** The addressed child cannot take a continuation. */
138
- "subagent/not-resumable": { readonly childSessionId: SessionId };
141
+ 'subagent/not-resumable': { readonly childSessionId: SessionId }
139
142
  /** The claimed parent does not own the addressed child. */
140
- "subagent/unauthorized": { readonly childSessionId: SessionId };
143
+ 'subagent/unauthorized': { readonly childSessionId: SessionId }
141
144
  /** Image admission or model image-capability refusal. */
142
- "subagent/attachment-invalid": { readonly reason: string };
145
+ 'subagent/attachment-invalid': { readonly reason: string }
143
146
  /** The child exists but its inbox cannot admit the message now. */
144
- "subagent/delivery-unavailable": { readonly childSessionId: SessionId };
147
+ 'subagent/delivery-unavailable': { readonly childSessionId: SessionId }
145
148
  }
146
149
  }
@@ -5,26 +5,26 @@
5
5
  * @module @deepseek-ai/dsh-subagent
6
6
  */
7
7
 
8
- import { AttachmentError } from "@deepseek-ai/dsh-attachment";
9
- import type { SessionId } from "@deepseek-ai/dsh-session";
10
- import { RemoteError } from "@deepseek-ai/dsh-typert-protocol";
11
- import { z } from "zod";
12
- import { SubagentError } from "./error.ts";
8
+ import { AttachmentError } from '@deepseek-ai/dsh-attachment'
9
+ import type { SessionId } from '@deepseek-ai/dsh-session'
10
+ import { RemoteError } from '@deepseek-ai/dsh-typert-protocol'
11
+ import { z } from 'zod'
12
+ import { SubagentError } from './error.ts'
13
13
 
14
- const SESSION_ID_SCHEMA = z.string().min(1);
14
+ const SESSION_ID_SCHEMA = z.string().min(1)
15
15
  const CONTROL_ID_SCHEMAS = {
16
- "subagent.prompt": z.object({
16
+ 'subagent.prompt': z.object({
17
17
  parentSessionId: SESSION_ID_SCHEMA,
18
18
  childSessionId: SESSION_ID_SCHEMA,
19
- mode: z.literal("continuable"),
20
- delivery: z.enum(["queue", "steer"]),
19
+ mode: z.literal('continuable'),
20
+ delivery: z.enum(['queue', 'steer']),
21
21
  }),
22
- "subagent.interrupt": z.object({
22
+ 'subagent.interrupt': z.object({
23
23
  parentSessionId: SESSION_ID_SCHEMA,
24
24
  childSessionId: SESSION_ID_SCHEMA,
25
- mode: z.literal("continuable"),
25
+ mode: z.literal('continuable'),
26
26
  }),
27
- } as const;
27
+ } as const
28
28
 
29
29
  /**
30
30
  * Apply the subagent payload checks that are stricter than generated
@@ -37,11 +37,9 @@ export function validateControlRequest(
37
37
  method: keyof typeof CONTROL_ID_SCHEMAS,
38
38
  payload: unknown,
39
39
  ): void {
40
- const parsed = CONTROL_ID_SCHEMAS[method].safeParse(payload);
40
+ const parsed = CONTROL_ID_SCHEMAS[method].safeParse(payload)
41
41
  if (!parsed.success) {
42
- throw new RemoteError("gateway/bad-request", `invalid payload for ${method}`, {
43
- issues: parsed.error.issues,
44
- });
42
+ throw new RemoteError('gateway/bad-request', `invalid payload for ${method}`, { issues: parsed.error.issues })
45
43
  }
46
44
  }
47
45
 
@@ -55,69 +53,55 @@ export function validateControlRequest(
55
53
  * @returns Never — the refusal is thrown.
56
54
  * @throws {RemoteError} always.
57
55
  */
58
- export function rejectPrompt(
59
- error: unknown,
60
- childSessionId: SessionId,
61
- signal: AbortSignal,
62
- ): never {
56
+ export function rejectPrompt(error: unknown, childSessionId: SessionId, signal: AbortSignal): never {
63
57
  if (isCancellation(error, signal)) {
64
- throw new RemoteError(
65
- "gateway/cancelled",
66
- "subagent prompt was cancelled",
67
- {},
68
- { cause: error },
69
- );
58
+ throw new RemoteError('gateway/cancelled', 'subagent prompt was cancelled', {}, { cause: error })
70
59
  }
71
60
  if (error instanceof AttachmentError) {
72
- throw new RemoteError(
73
- "subagent/attachment-invalid",
74
- error.message,
75
- { reason: error.code },
76
- { cause: error },
77
- );
61
+ throw new RemoteError('subagent/attachment-invalid', error.message, { reason: error.code }, { cause: error })
78
62
  }
79
63
  if (error instanceof SubagentError) {
80
64
  switch (error.code) {
81
- case "MODEL_DOES_NOT_SUPPORT_IMAGES":
65
+ case 'MODEL_DOES_NOT_SUPPORT_IMAGES':
82
66
  throw new RemoteError(
83
- "subagent/attachment-invalid",
67
+ 'subagent/attachment-invalid',
84
68
  error.message,
85
69
  { reason: error.code },
86
70
  { cause: error },
87
- );
88
- case "NOT_RESUMABLE":
71
+ )
72
+ case 'NOT_RESUMABLE':
89
73
  throw new RemoteError(
90
- "subagent/not-resumable",
91
- "subagent cannot be resumed",
74
+ 'subagent/not-resumable',
75
+ 'subagent cannot be resumed',
92
76
  { childSessionId },
93
77
  { cause: error },
94
- );
95
- case "UNAUTHORIZED":
78
+ )
79
+ case 'UNAUTHORIZED':
96
80
  throw new RemoteError(
97
- "subagent/unauthorized",
98
- "subagent does not belong to this parent",
81
+ 'subagent/unauthorized',
82
+ 'subagent does not belong to this parent',
99
83
  { childSessionId },
100
84
  { cause: error },
101
- );
102
- case "DRAINING":
103
- case "ACTIVATION_CLOSING":
104
- case "ACTIVATION_LIMIT_REACHED":
105
- case "CONTINUATION_UNAVAILABLE":
106
- case "PERSISTENCE_UNAVAILABLE":
85
+ )
86
+ case 'DRAINING':
87
+ case 'ACTIVATION_CLOSING':
88
+ case 'ACTIVATION_LIMIT_REACHED':
89
+ case 'CONTINUATION_UNAVAILABLE':
90
+ case 'PERSISTENCE_UNAVAILABLE':
107
91
  throw new RemoteError(
108
- "subagent/delivery-unavailable",
109
- "subagent follow-up is temporarily unavailable",
92
+ 'subagent/delivery-unavailable',
93
+ 'subagent follow-up is temporarily unavailable',
110
94
  { childSessionId },
111
95
  { cause: error },
112
- );
96
+ )
113
97
  // A code outside the admission vocabulary is not the caller's move to make.
114
98
  default:
115
- break;
99
+ break
116
100
  }
117
101
  }
118
- throw new RemoteError("gateway/internal", "subagent prompt failed", {}, { cause: error });
102
+ throw new RemoteError('gateway/internal', 'subagent prompt failed', {}, { cause: error })
119
103
  }
120
104
 
121
105
  function isCancellation(error: unknown, signal: AbortSignal): boolean {
122
- return signal.aborted || (error instanceof SubagentError && error.code === "CANCELLED");
106
+ return signal.aborted || (error instanceof SubagentError && error.code === 'CANCELLED')
123
107
  }
@@ -6,12 +6,12 @@
6
6
  * @module @deepseek-ai/dsh-subagent/depth
7
7
  */
8
8
 
9
- import type { Agent } from "@deepseek-ai/dsh-agent";
9
+ import type { Agent } from '@deepseek-ai/dsh-agent'
10
10
 
11
- declare module "@deepseek-ai/dsh-agent" {
11
+ declare module '@deepseek-ai/dsh-agent' {
12
12
  interface AgentOptions {
13
13
  /** Delegation depth: zero for a top-level agent and parent depth + 1 for a child. */
14
- subagentDepth?: number;
14
+ subagentDepth?: number
15
15
  }
16
16
  }
17
17
 
@@ -26,16 +26,13 @@ declare module "@deepseek-ai/dsh-agent" {
26
26
  * @throws if the runtime `AgentOptions.subagentDepth` is not a non-negative safe integer.
27
27
  */
28
28
  export function delegationDepthOf(agent: Agent): number {
29
- const runtime = agent.options.subagentDepth;
30
- if (
31
- runtime !== undefined &&
32
- (!Number.isSafeInteger(runtime) || runtime < 0 || Object.is(runtime, -0))
33
- ) {
34
- throw new TypeError("agent subagentDepth must be a non-negative safe integer");
29
+ const runtime = agent.options.subagentDepth
30
+ if (runtime !== undefined && (!Number.isSafeInteger(runtime) || runtime < 0 || Object.is(runtime, -0))) {
31
+ throw new TypeError('agent subagentDepth must be a non-negative safe integer')
35
32
  }
36
33
  // The header value was validated at the session boundary (creation and
37
34
  // persistence load both construct through the store).
38
- return Math.max(agent.session.header.delegationDepth ?? 0, runtime ?? 0);
35
+ return Math.max(agent.session.header.delegationDepth ?? 0, runtime ?? 0)
39
36
  }
40
37
 
41
38
  /**
@@ -43,13 +40,12 @@ export function delegationDepthOf(agent: Agent): number {
43
40
  * @param maxDepth - the optional runtime value to validate.
44
41
  */
45
42
  export function assertSubagentMaxDepth(maxDepth: unknown): void {
46
- if (
47
- maxDepth !== undefined &&
48
- (typeof maxDepth !== "number" ||
49
- !Number.isSafeInteger(maxDepth) ||
50
- maxDepth < 0 ||
51
- Object.is(maxDepth, -0))
52
- ) {
53
- throw new TypeError("subagent maxDepth must be a non-negative safe integer");
43
+ if (maxDepth !== undefined && (
44
+ typeof maxDepth !== 'number'
45
+ || !Number.isSafeInteger(maxDepth)
46
+ || maxDepth < 0
47
+ || Object.is(maxDepth, -0)
48
+ )) {
49
+ throw new TypeError('subagent maxDepth must be a non-negative safe integer')
54
50
  }
55
51
  }