|
@@ -31,6 +31,7 @@
|
|
|
|
|
|
|
|
import { Context } from '@deepseek-ai/cordis'
|
|
import { Context } from '@deepseek-ai/cordis'
|
|
|
import z from '@deepseek-ai/schemastery'
|
|
import z from '@deepseek-ai/schemastery'
|
|
|
|
|
+import type {} from '@deepseek-ai/dsh-settings'
|
|
|
import type {} from '@deepseek-ai/dsh-attachment'
|
|
import type {} from '@deepseek-ai/dsh-attachment'
|
|
|
import { scopeTarget } from '@deepseek-ai/dsh-scope'
|
|
import { scopeTarget } from '@deepseek-ai/dsh-scope'
|
|
|
import type { Scoped } from '@deepseek-ai/dsh-scope'
|
|
import type { Scoped } from '@deepseek-ai/dsh-scope'
|
|
@@ -189,13 +190,17 @@ interface BrowserPromptSource {
|
|
|
export interface Config {
|
|
export interface Config {
|
|
|
/** Maximum live continuable children across one root's tree, excluding the root; defaults to 8. */
|
|
/** Maximum live continuable children across one root's tree, excluding the root; defaults to 8. */
|
|
|
maxActiveSubagents?: number
|
|
maxActiveSubagents?: number
|
|
|
|
|
+ /** Default delegation depth for tools without an explicit limit; defaults to 3. */
|
|
|
|
|
+ maxDepth?: number
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/** Named provider registry with one-shot runs, durable discovery, and continuable-child operations. */
|
|
/** Named provider registry with one-shot runs, durable discovery, and continuable-child operations. */
|
|
|
export class SubagentRuntime extends TypertRemoteService {
|
|
export class SubagentRuntime extends TypertRemoteService {
|
|
|
static Config: z<Config> = z.object({
|
|
static Config: z<Config> = z.object({
|
|
|
|
|
+ maxDepth: z.number().step(1).min(0).max(Number.MAX_SAFE_INTEGER).default(3),
|
|
|
maxActiveSubagents: z.number().step(1).min(1).max(Number.MAX_SAFE_INTEGER).default(8),
|
|
maxActiveSubagents: z.number().step(1).min(1).max(Number.MAX_SAFE_INTEGER).default(8),
|
|
|
})
|
|
})
|
|
|
|
|
+ private settingsSource: () => Config
|
|
|
private providers = new Map<string, SubagentProvider>()
|
|
private providers = new Map<string, SubagentProvider>()
|
|
|
private continuations: SubagentContinuationManager | undefined
|
|
private continuations: SubagentContinuationManager | undefined
|
|
|
/**
|
|
/**
|
|
@@ -207,12 +212,21 @@ export class SubagentRuntime extends TypertRemoteService {
|
|
|
|
|
|
|
|
constructor(ctx: Context, config: Config) {
|
|
constructor(ctx: Context, config: Config) {
|
|
|
super(ctx, 'subagents')
|
|
super(ctx, 'subagents')
|
|
|
|
|
+ assertSubagentMaxDepth(config.maxDepth)
|
|
|
|
|
+ this.settingsSource = () => config
|
|
|
|
|
+ ctx.inject(['settings'], (settingsCtx) => {
|
|
|
|
|
+ settingsCtx.settings.installSection(ctx, 'subagent', SubagentRuntime.Config, config, {
|
|
|
|
|
+ validate: (value) => { assertSubagentMaxDepth(value.maxDepth) },
|
|
|
|
|
+ setSource: (source) => { this.settingsSource = source },
|
|
|
|
|
+ onChange: () => {},
|
|
|
|
|
+ })
|
|
|
|
|
+ })
|
|
|
this.emitLifecycle = createLifecycleEmitter(this.ctx, parent => scopeTarget(this, parent))
|
|
this.emitLifecycle = createLifecycleEmitter(this.ctx, parent => scopeTarget(this, parent))
|
|
|
ctx.inject(['agents'], (childCtx: Context) => {
|
|
ctx.inject(['agents'], (childCtx: Context) => {
|
|
|
const manager = new SubagentContinuationManager(childCtx, {
|
|
const manager = new SubagentContinuationManager(childCtx, {
|
|
|
prepareContinuable: (name, request) => this.prepareContinuable(name, request),
|
|
prepareContinuable: (name, request) => this.prepareContinuable(name, request),
|
|
|
observeActivation: (provider, childId, parent) => this.observeActivation(provider, childId, parent),
|
|
observeActivation: (provider, childId, parent) => this.observeActivation(provider, childId, parent),
|
|
|
- }, (config as Required<Config>).maxActiveSubagents)
|
|
|
|
|
|
|
+ }, () => (this.settingsSource() as Required<Config>).maxActiveSubagents)
|
|
|
this.continuations = manager
|
|
this.continuations = manager
|
|
|
childCtx.effect(() => () => {
|
|
childCtx.effect(() => () => {
|
|
|
/* v8 ignore else -- one injected binding owns the slot until its fiber disposes. */
|
|
/* v8 ignore else -- one injected binding owns the slot until its fiber disposes. */
|
|
@@ -226,6 +240,16 @@ export class SubagentRuntime extends TypertRemoteService {
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Resolve a delegation tool's depth policy against the current user setting.
|
|
|
|
|
+ * @param configured - Explicit tool limit, or provider-managed for external delegation.
|
|
|
|
|
+ * @returns The numeric limit, or undefined when the provider owns depth enforcement.
|
|
|
|
|
+ */
|
|
|
|
|
+ resolveMaxDepth(configured?: number | 'provider-managed'): number | undefined {
|
|
|
|
|
+ if (configured === 'provider-managed') return undefined
|
|
|
|
|
+ return configured ?? (this.settingsSource() as Required<Config>).maxDepth
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* Establish one durable continuable child and deliver its initial prompt.
|
|
* Establish one durable continuable child and deliver its initial prompt.
|
|
|
* Resolves when the child's inbox accepts that prompt, without waiting for the
|
|
* Resolves when the child's inbox accepts that prompt, without waiting for the
|