@huanlin/dsh-plugin-yet-another-subagent 0.1.2 → 0.1.4
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/README.md +136 -130
- package/lib/client.js +145 -3
- package/lib/index.js +289 -27
- package/lib/types/client/SettingsPage.d.ts +49 -0
- package/lib/types/client/SubagentCard.d.ts +56 -0
- package/lib/types/client/SubagentTreeView.d.ts +63 -0
- package/lib/types/client/index.d.ts +29 -0
- package/lib/types/client/locales.d.ts +13 -0
- package/lib/types/index.d.ts +42 -0
- package/lib/types/invariant.d.ts +16 -0
- package/lib/types/profile-store.d.ts +59 -0
- package/lib/types/projection.d.ts +103 -0
- package/lib/types/repair.d.ts +49 -0
- package/lib/types/rpc.d.ts +59 -0
- package/lib/types/tool-factory.d.ts +45 -0
- package/lib/types/types.d.ts +116 -0
- package/package.json +159 -158
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory profile store with CRUD. Backed by `ctx.settings` when a settings
|
|
3
|
+
* service is mounted (persists to `$DSH_HOME/settings.yaml` under the
|
|
4
|
+
* `ya-subagent` namespace); falls back to a plain Map in headless assemblies
|
|
5
|
+
* where no settings provider is available (cordis.yml seed only, no
|
|
6
|
+
* persistence).
|
|
7
|
+
*
|
|
8
|
+
* @module @huanlin/dsh-plugin-yet-another-subagent/profile-store
|
|
9
|
+
*/
|
|
10
|
+
import type { SettingsScope } from '@deepseek-ai/dsh-settings';
|
|
11
|
+
import type { SubagentProfile, YaSubagentConfig } from './types.ts';
|
|
12
|
+
/** CRUD result for RPC: the success branch carries the latest list. */
|
|
13
|
+
export type ProfileMutationResult = {
|
|
14
|
+
readonly ok: true;
|
|
15
|
+
readonly profiles: readonly SubagentProfile[];
|
|
16
|
+
} | {
|
|
17
|
+
readonly ok: false;
|
|
18
|
+
readonly error: string;
|
|
19
|
+
};
|
|
20
|
+
/** Shape stored under the `ya-subagent` settings namespace. */
|
|
21
|
+
export interface YaSubagentSettings {
|
|
22
|
+
readonly profiles: readonly SubagentProfile[];
|
|
23
|
+
readonly generalFixed: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Mutable profile store. Owns the canonical list; tool registration and RPC
|
|
27
|
+
* handlers share one instance per plugin fiber. When `scope` is set, every
|
|
28
|
+
* mutation persists through `scope.update`; otherwise the store is in-memory
|
|
29
|
+
* only (cordis.yml seed, lost on unload).
|
|
30
|
+
*/
|
|
31
|
+
export declare class ProfileStore {
|
|
32
|
+
private readonly profiles;
|
|
33
|
+
/** Whether `general` is locked (cannot be removed). */
|
|
34
|
+
readonly generalFixed: boolean;
|
|
35
|
+
/** Optional settings scope for persistence; absent in headless mode. */
|
|
36
|
+
private scope;
|
|
37
|
+
constructor(seed: YaSubagentConfig);
|
|
38
|
+
/**
|
|
39
|
+
* Attach a settings scope. Subsequent mutations persist through it; the
|
|
40
|
+
* initial in-memory state is replaced with the scope's resolved value
|
|
41
|
+
* (which layers schema defaults, the composition `base`, and the user
|
|
42
|
+
* document).
|
|
43
|
+
*/
|
|
44
|
+
attachScope(scope: SettingsScope<YaSubagentSettings>): void;
|
|
45
|
+
/** Reload the in-memory map from the settings scope's current resolved value. */
|
|
46
|
+
reloadFromScope(): void;
|
|
47
|
+
/** Snapshot of all profiles, in insertion order. */
|
|
48
|
+
list(): readonly SubagentProfile[];
|
|
49
|
+
/** Look up one profile by id. */
|
|
50
|
+
get(id: string): SubagentProfile | undefined;
|
|
51
|
+
/** Add a new profile. Returns failure for duplicate id or invalid shape. */
|
|
52
|
+
add(profile: SubagentProfile): ProfileMutationResult;
|
|
53
|
+
/** Update an existing profile. Returns failure if the id is unknown. */
|
|
54
|
+
update(profile: SubagentProfile): ProfileMutationResult;
|
|
55
|
+
/** Remove a profile. Returns failure for unknown id or protected `general`. */
|
|
56
|
+
remove(id: string): ProfileMutationResult;
|
|
57
|
+
/** Persist the current list through the attached settings scope (fire-and-forget; errors logged). */
|
|
58
|
+
private persist;
|
|
59
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Two session projections (design doc §3.6):
|
|
3
|
+
*
|
|
4
|
+
* - `subagentProfile` (parent session): fold `tool/call` (name `subagent`,
|
|
5
|
+
* profile in `arguments.profile`) + the matching `tool/result.subagentId`,
|
|
6
|
+
* building a `childId → profileId` map. Used as a cross-check / fallback
|
|
7
|
+
* for SubagentCard (which usually reads `profileLabel` straight from the
|
|
8
|
+
* result content).
|
|
9
|
+
*
|
|
10
|
+
* - `yaSubagentProgress` (child session): toolcall count, token usage,
|
|
11
|
+
* and lifecycle state. Pushed over the projection frame so the parent's
|
|
12
|
+
* SubagentCard can subscribe even though client runtime drops non-current
|
|
13
|
+
* `session/event` frames (single-stage model).
|
|
14
|
+
*
|
|
15
|
+
* Both units are pure synchronous folds; the framework drives them and the
|
|
16
|
+
* host wire layer ships the validated views.
|
|
17
|
+
*
|
|
18
|
+
* @module @huanlin/dsh-plugin-yet-another-subagent/projection
|
|
19
|
+
*/
|
|
20
|
+
import type { ProjectionDefinition } from '@deepseek-ai/dsh-session-projection';
|
|
21
|
+
import type { SessionEvent } from '@deepseek-ai/dsh-session';
|
|
22
|
+
/** `subagentProfile` wire shape: childId → profileId, plus callId → childId. */
|
|
23
|
+
export interface SubagentProfileProjection {
|
|
24
|
+
/** childId → profileId (durable). */
|
|
25
|
+
readonly children: Record<string, string>;
|
|
26
|
+
/** callId → childId (for foreground calls where the result text has no embedded id). */
|
|
27
|
+
readonly calls: Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
/** Internal fold state for `subagentProfile`. */
|
|
30
|
+
interface ProfileState {
|
|
31
|
+
/** callId → profileId, awaiting the matching `tool/result`. */
|
|
32
|
+
readonly pending: Map<string, string>;
|
|
33
|
+
/** childId → profileId (the durable mapping). */
|
|
34
|
+
readonly mapping: Record<string, string>;
|
|
35
|
+
/** callId → childId (survives after the pending entry is consumed). */
|
|
36
|
+
readonly callToChild: Record<string, string>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Fold the parent session's `tool/call` + `tool/result` for tool name
|
|
40
|
+
* `subagent`. The profile id is carried in `tool/call.arguments.profile`
|
|
41
|
+
* (JSON-encoded). The result content embeds `subagentId` (continuable branch)
|
|
42
|
+
* or `runId` (foreground branch); the continuable branch is the durable
|
|
43
|
+
* child identity that survives across activations.
|
|
44
|
+
*/
|
|
45
|
+
export declare const subagentProfileProjection: ProjectionDefinition<'subagentProfile', ProfileState>;
|
|
46
|
+
/** `yaSubagentProgress` wire shape: live child progress for the parent's card. */
|
|
47
|
+
export interface YaSubagentProgressProjection {
|
|
48
|
+
/** Number of `tool/call` events folded so far. */
|
|
49
|
+
readonly toolCallCount: number;
|
|
50
|
+
/** Cumulative token usage folded from `assistant/message.usage`. */
|
|
51
|
+
readonly tokens: {
|
|
52
|
+
readonly input: number;
|
|
53
|
+
readonly output: number;
|
|
54
|
+
readonly cacheRead: number;
|
|
55
|
+
readonly cacheWrite: number;
|
|
56
|
+
readonly reasoning: number;
|
|
57
|
+
};
|
|
58
|
+
/** Lifecycle state derived from turn boundaries. */
|
|
59
|
+
readonly state: 'running' | 'idle' | 'settled';
|
|
60
|
+
/** Latest activity: streaming text, tool call, or finalized message text. */
|
|
61
|
+
readonly activity?: Activity;
|
|
62
|
+
}
|
|
63
|
+
/** Discriminated activity union: text or tool call. */
|
|
64
|
+
export type Activity = {
|
|
65
|
+
readonly kind: 'text';
|
|
66
|
+
readonly text: string;
|
|
67
|
+
} | {
|
|
68
|
+
readonly kind: 'tool';
|
|
69
|
+
readonly name: string;
|
|
70
|
+
readonly args?: string;
|
|
71
|
+
};
|
|
72
|
+
interface ProgressState {
|
|
73
|
+
readonly toolCallCount: number;
|
|
74
|
+
readonly tokens: {
|
|
75
|
+
readonly input: number;
|
|
76
|
+
readonly output: number;
|
|
77
|
+
readonly cacheRead: number;
|
|
78
|
+
readonly cacheWrite: number;
|
|
79
|
+
readonly reasoning: number;
|
|
80
|
+
};
|
|
81
|
+
readonly state: 'running' | 'idle' | 'settled';
|
|
82
|
+
/** Accumulator for the current text block's streaming deltas. */
|
|
83
|
+
readonly streamingText: string;
|
|
84
|
+
readonly activity?: Activity;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Fold the child session's own events into a compact progress view. Token
|
|
88
|
+
* usage accumulates from `assistant/message.usage` (cache fields are
|
|
89
|
+
* optional); tool calls are counted; lifecycle follows turn boundaries.
|
|
90
|
+
*/
|
|
91
|
+
export declare const yaSubagentProgressProjection: ProjectionDefinition<'yaSubagentProgress', ProgressState>;
|
|
92
|
+
/** Convenience: the projection keys registered by this plugin. */
|
|
93
|
+
export declare const PROJECTION_KEYS: readonly ["subagentProfile", "yaSubagentProgress"];
|
|
94
|
+
/** Type-side declaration merge so consumers can read these keys via the projection registry. */
|
|
95
|
+
declare module '@deepseek-ai/dsh-session-projection/types' {
|
|
96
|
+
interface SessionProjectionMap {
|
|
97
|
+
/** Parent-session map of childId → profileId. Empty object when no children yet. */
|
|
98
|
+
subagentProfile: SubagentProfileProjection;
|
|
99
|
+
/** Child-session live progress (toolcall count + token usage + state). */
|
|
100
|
+
yaSubagentProgress: YaSubagentProgressProjection;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
export type { SessionEvent };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-shot session-log repair: stamp `"ignorable": true` onto legacy
|
|
3
|
+
* `ya-subagent/started` events so the harness persistence read path
|
|
4
|
+
* (`assertEventsSupported`) will skip them instead of refusing the whole log.
|
|
5
|
+
*
|
|
6
|
+
* Background: older plugin versions wrote `ya-subagent/started` via
|
|
7
|
+
* `session.append(...)`, but `session.append` cannot set the `ignorable`
|
|
8
|
+
* envelope flag, and `KNOWN_SESSION_EVENT_TYPES` is code-generated with no
|
|
9
|
+
* plugin registration surface. The read path therefore refuses any log
|
|
10
|
+
* containing the type unless each occurrence carries `ignorable: true`.
|
|
11
|
+
* This module rewrites on-disk artifacts in place (after a `.bak` backup) to
|
|
12
|
+
* add that flag to every `ya-subagent/started` row missing it.
|
|
13
|
+
*
|
|
14
|
+
* Two physical encodings (mirrors `session-persistence-jsonl`):
|
|
15
|
+
* - `.jsonl` — plaintext, one JSON record per line.
|
|
16
|
+
* - `.jsonl.zstd` — concatenated independent Zstandard frames: the first
|
|
17
|
+
* frame holds the session header line, subsequent
|
|
18
|
+
* frames each hold one append batch of event lines.
|
|
19
|
+
* Each frame is independently decodable + checksummed.
|
|
20
|
+
* Only frames whose decoded plaintext contains a target
|
|
21
|
+
* row are recompressed; untouched frames are copied
|
|
22
|
+
* verbatim so byte-identity is preserved where possible.
|
|
23
|
+
*
|
|
24
|
+
* Idempotent: rows already carrying `ignorable: true` are skipped; files with
|
|
25
|
+
* no target rows are left untouched (no backup, no rewrite).
|
|
26
|
+
*
|
|
27
|
+
* @module @huanlin/dsh-plugin-yet-another-subagent/repair
|
|
28
|
+
*/
|
|
29
|
+
/** Aggregate result of one repair run. */
|
|
30
|
+
export interface RepairStats {
|
|
31
|
+
/** Session log files examined (`.jsonl` + `.jsonl.zstd`). */
|
|
32
|
+
readonly scanned: number;
|
|
33
|
+
/** Files rewritten because at least one target row was patched. */
|
|
34
|
+
readonly repaired: number;
|
|
35
|
+
/** Files with no patchable rows (already clean or no target events). */
|
|
36
|
+
readonly skipped: number;
|
|
37
|
+
/** Per-file errors (path + message); empty on a clean run. */
|
|
38
|
+
readonly errors: readonly {
|
|
39
|
+
readonly path: string;
|
|
40
|
+
readonly message: string;
|
|
41
|
+
}[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Recursively repair every session log under `sessionsRoot`.
|
|
45
|
+
*
|
|
46
|
+
* @param sessionsRoot - absolute path to `$DSH_HOME/sessions`.
|
|
47
|
+
* @returns aggregate stats. Never throws — per-file failures land in `errors`.
|
|
48
|
+
*/
|
|
49
|
+
export declare function repairSessions(sessionsRoot: string): Promise<RepairStats>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RPC handler: profile list CRUD + tool list on a dedicated `/ya-subagent`
|
|
3
|
+
* channel registered via `ctx.connection.rpc.handle('/ya-subagent', ...)`.
|
|
4
|
+
*
|
|
5
|
+
* A dedicated channel avoids the single-interceptor limit on the shared `/api`
|
|
6
|
+
* channel (the Typert gateway owns that slot; staking it here would shadow
|
|
7
|
+
* `commands/execute` and every other `/api` endpoint).
|
|
8
|
+
*
|
|
9
|
+
* Endpoints (all POST, payload shape noted):
|
|
10
|
+
* - `profiles.list` payload: {} → { profiles: SubagentProfile[] }
|
|
11
|
+
* - `profiles.add` payload: { profile: SubagentProfile } → { profiles: ... } | error
|
|
12
|
+
* - `profiles.update` payload: { profile: SubagentProfile } → { profiles: ... } | error
|
|
13
|
+
* - `profiles.remove` payload: { id: string } → { profiles: ... } | error
|
|
14
|
+
* - `tools.list` payload: {} → { tools: { name, description }[] }
|
|
15
|
+
*
|
|
16
|
+
* Returns the existing RpcResult shape; business errors use the `internal`
|
|
17
|
+
* code with a descriptive message (the RpcError code union is closed; we do
|
|
18
|
+
* not extend it for plugin-specific failures — see design doc §3.5).
|
|
19
|
+
*
|
|
20
|
+
* @module @huanlin/dsh-plugin-yet-another-subagent/rpc
|
|
21
|
+
*/
|
|
22
|
+
import type { Context } from 'cordis';
|
|
23
|
+
import type { SubagentProfile } from './types.ts';
|
|
24
|
+
import type { ProfileStore } from './profile-store.ts';
|
|
25
|
+
import { type RepairStats } from './repair.ts';
|
|
26
|
+
/** Wire shape for `profiles.list` responses. */
|
|
27
|
+
export interface ProfileListResponse {
|
|
28
|
+
readonly profiles: readonly SubagentProfile[];
|
|
29
|
+
}
|
|
30
|
+
/** Wire shape for `tools.list` responses. */
|
|
31
|
+
export interface ToolListResponse {
|
|
32
|
+
readonly tools: readonly {
|
|
33
|
+
readonly name: string;
|
|
34
|
+
readonly description: string;
|
|
35
|
+
}[];
|
|
36
|
+
}
|
|
37
|
+
/** Wire shape for `profiles.add` request payload. */
|
|
38
|
+
export interface ProfileAddPayload {
|
|
39
|
+
readonly profile: SubagentProfile;
|
|
40
|
+
}
|
|
41
|
+
/** Wire shape for `profiles.update` request payload. */
|
|
42
|
+
export interface ProfileUpdatePayload {
|
|
43
|
+
readonly profile: SubagentProfile;
|
|
44
|
+
}
|
|
45
|
+
/** Wire shape for `profiles.remove` request payload. */
|
|
46
|
+
export interface ProfileRemovePayload {
|
|
47
|
+
readonly id: string;
|
|
48
|
+
}
|
|
49
|
+
/** All ya-subagent RPC endpoint result values. */
|
|
50
|
+
export type YaSubagentValue = ProfileListResponse | ToolListResponse | RepairStats;
|
|
51
|
+
/**
|
|
52
|
+
* Register the ya-subagent RPC channel on the host's connection service.
|
|
53
|
+
* `connection` is in the plugin's inject list, so `ctx.connection` is
|
|
54
|
+
* directly available; the channel route rolls back on fiber disposal
|
|
55
|
+
* (the inner `owner.effect` owns cleanup).
|
|
56
|
+
* @param ctx - host context.
|
|
57
|
+
* @param store - profile store.
|
|
58
|
+
*/
|
|
59
|
+
export declare function registerRpc(ctx: Context, store: ProfileStore): void;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool factory: compile the profile list into a single `defineTool` definition.
|
|
3
|
+
*
|
|
4
|
+
* One `subagent` tool is exposed to the model regardless of how many profiles
|
|
5
|
+
* are configured. The desired profile is selected via the `profile` parameter
|
|
6
|
+
* (an enum of available profile ids). This keeps the tool surface flat — the
|
|
7
|
+
* model learns one tool, not N — and profile add/remove does not change the
|
|
8
|
+
* tool name set the model was trained against.
|
|
9
|
+
*
|
|
10
|
+
* Two profile-specific extensions are preserved from the per-profile design:
|
|
11
|
+
* 1. The continuable result content embeds `profileLabel` so SubagentCard
|
|
12
|
+
* can render with zero RPC (SkillRow paradigm, design doc §4.4).
|
|
13
|
+
* 2. The `profile` parameter enum lists the live profile ids.
|
|
14
|
+
*
|
|
15
|
+
* Foreground (one-shot) path is kept for `run_in_background: false`; the
|
|
16
|
+
* default is continuable background.
|
|
17
|
+
*
|
|
18
|
+
* @module @huanlin/dsh-plugin-yet-another-subagent/tool-factory
|
|
19
|
+
*/
|
|
20
|
+
import type { Context } from 'cordis';
|
|
21
|
+
import type { SubagentProvider, SubagentResult, SubagentRun } from '@deepseek-ai/dsh-subagent';
|
|
22
|
+
import type { JobOutcome } from '@deepseek-ai/dsh-jobs';
|
|
23
|
+
import type { SubagentProfile } from './types.ts';
|
|
24
|
+
/** Merge-extensible session event: child started for a tool call. */
|
|
25
|
+
declare module '@deepseek-ai/dsh-session' {
|
|
26
|
+
interface SessionEventMap {
|
|
27
|
+
'ya-subagent/started': {
|
|
28
|
+
callId: string;
|
|
29
|
+
childId: string;
|
|
30
|
+
profileId: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** Settle pending startup without rejecting the task producer contract. */
|
|
35
|
+
declare function settleStart(start: Promise<SubagentRun>, signal: AbortSignal): Promise<JobOutcome>;
|
|
36
|
+
/**
|
|
37
|
+
* Build the single model-facing `subagent` tool definition.
|
|
38
|
+
*
|
|
39
|
+
* @param profiles - the live profile list (drives the `profile` enum).
|
|
40
|
+
* @param ctx - host context carrying `subagents` (and `jobs` for one-shot background).
|
|
41
|
+
* @returns a `defineTool` definition ready for `ctx.tools.register`.
|
|
42
|
+
*/
|
|
43
|
+
export declare function buildTool(profiles: readonly SubagentProfile[], ctx: Context): import("@deepseek-ai/dsh-tools").ToolDefinition;
|
|
44
|
+
export { settleStart };
|
|
45
|
+
export type { SubagentProvider, SubagentResult, SubagentRun, JobOutcome };
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile data model for yet-another-subagent.
|
|
3
|
+
*
|
|
4
|
+
* @module @huanlin/dsh-plugin-yet-another-subagent/types
|
|
5
|
+
*/
|
|
6
|
+
import type { AgentOptions } from '@deepseek-ai/dsh-agent';
|
|
7
|
+
/** A model-facing tool name is `subagent_<id>`. */
|
|
8
|
+
export interface SubagentProfile {
|
|
9
|
+
/** Unique id; lowercase letters, digits, hyphens; 1–32 chars. Used as `subagent_<id>`. */
|
|
10
|
+
readonly id: string;
|
|
11
|
+
/** Display name (nav label / card title). */
|
|
12
|
+
readonly label: string;
|
|
13
|
+
/**
|
|
14
|
+
* Model selection. `kind: 'auto'` inherits the parent model (provider/model
|
|
15
|
+
* are ignored); `kind: 'manual'` pins a specific provider/model.
|
|
16
|
+
*/
|
|
17
|
+
readonly model: {
|
|
18
|
+
readonly kind: 'auto' | 'manual';
|
|
19
|
+
readonly provider: string;
|
|
20
|
+
readonly model: string;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Persona selection. `kind: 'inherit'` omits the per-child persona so the
|
|
24
|
+
* child uses the deployment `system-prompt` persona (same as the official
|
|
25
|
+
* `tool-subagent` default when no `persona` is configured). `kind: 'custom'`
|
|
26
|
+
* shadows the deployment persona with the provided text.
|
|
27
|
+
*/
|
|
28
|
+
readonly persona: {
|
|
29
|
+
readonly kind: 'inherit';
|
|
30
|
+
} | {
|
|
31
|
+
readonly kind: 'custom';
|
|
32
|
+
readonly text: string;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Tool filter selection. `kind: 'none'` applies no filter (child sees every
|
|
36
|
+
* visible global tool). `kind: 'allow'` keeps only the named tools;
|
|
37
|
+
* `kind: 'deny'` removes the named tools. The chosen tools are only sent to
|
|
38
|
+
* the provider when `kind` is not `'none'`.
|
|
39
|
+
*/
|
|
40
|
+
readonly toolFilter: {
|
|
41
|
+
readonly kind: 'none';
|
|
42
|
+
} | {
|
|
43
|
+
readonly kind: 'allow';
|
|
44
|
+
readonly tools: readonly string[];
|
|
45
|
+
} | {
|
|
46
|
+
readonly kind: 'deny';
|
|
47
|
+
readonly tools: readonly string[];
|
|
48
|
+
};
|
|
49
|
+
/** Maximum delegation depth (non-negative safe integer); default 3. */
|
|
50
|
+
readonly maxDepth: number;
|
|
51
|
+
/**
|
|
52
|
+
* Background policy when `run_in_background: true` is set. `'continuable'`
|
|
53
|
+
* (default, matches the base bundle) starts a background subagent that keeps
|
|
54
|
+
* its conversation — the caller receives only its subagent id and sends more
|
|
55
|
+
* work via `send_message`. `'one-shot'` starts a background task that returns
|
|
56
|
+
* a job id — the caller collects the result with `job_output` and stops it
|
|
57
|
+
* with `job_kill`.
|
|
58
|
+
*/
|
|
59
|
+
readonly backgroundMode: 'continuable' | 'one-shot';
|
|
60
|
+
/**
|
|
61
|
+
* Whether this profile is part of the bundle seed (cordis.patch.yml) and
|
|
62
|
+
* therefore labelled `builtin` in the UI. User-added profiles are `false`.
|
|
63
|
+
* Builtin profiles can still be edited or removed (unless `generalFixed`
|
|
64
|
+
* protects them); the flag is purely a presentation hint.
|
|
65
|
+
*/
|
|
66
|
+
readonly builtin: boolean;
|
|
67
|
+
}
|
|
68
|
+
/** Top-level config. */
|
|
69
|
+
export interface YaSubagentConfig {
|
|
70
|
+
/** Initial profile list (cordis.yml layer). Runtime mutations live in memory only. */
|
|
71
|
+
readonly profiles: readonly SubagentProfile[];
|
|
72
|
+
/** When true, the `general` profile cannot be removed. */
|
|
73
|
+
readonly generalFixed: boolean;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Coerce a possibly-stale profile shape (from an older `settings.yaml` or a
|
|
77
|
+
* caller that still uses the legacy `persona?: string` / `toolFilter?: { allow?, deny? }`
|
|
78
|
+
* form) into the current {@link SubagentProfile} shape. Idempotent on already-
|
|
79
|
+
* current shapes.
|
|
80
|
+
*
|
|
81
|
+
* Rules:
|
|
82
|
+
* - `persona: undefined | '' | null` → `{ kind: 'inherit' }`
|
|
83
|
+
* - `persona: string` (non-empty) → `{ kind: 'custom', text }`
|
|
84
|
+
* - `persona: { kind: 'inherit' }` → as-is
|
|
85
|
+
* - `persona: { kind: 'custom', text }` → as-is (text trimmed; empty → inherit)
|
|
86
|
+
* - `toolFilter: undefined | null` → `{ kind: 'none' }`
|
|
87
|
+
* - `toolFilter: { allow: [...], deny: [...] }` → allow wins if non-empty, else deny, else none
|
|
88
|
+
* - `toolFilter: { kind: 'none' | 'allow' | 'deny', tools? }` → as-is (tools defaulted to [])
|
|
89
|
+
* - `builtin: undefined | null` → `false`
|
|
90
|
+
*/
|
|
91
|
+
export declare function migrateProfile(input: unknown): SubagentProfile;
|
|
92
|
+
/** Derive agentOptions from a profile's model selection. */
|
|
93
|
+
export declare function agentOptionsFor(profile: SubagentProfile): {
|
|
94
|
+
readonly agentOptions?: AgentOptions;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Project the persona field onto the request shape: `undefined` for `inherit`
|
|
98
|
+
* (omit the field so the child uses the deployment persona) and the text for
|
|
99
|
+
* `custom`.
|
|
100
|
+
*/
|
|
101
|
+
export declare function personaForRequest(profile: SubagentProfile): {
|
|
102
|
+
readonly persona?: string;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Project the toolFilter field onto the request shape: `undefined` for `none`
|
|
106
|
+
* (omit the field so the child sees every visible tool) and the allow/deny
|
|
107
|
+
* pair for `allow`/`deny`.
|
|
108
|
+
*/
|
|
109
|
+
export declare function toolFilterForRequest(profile: SubagentProfile): {
|
|
110
|
+
readonly toolFilter?: {
|
|
111
|
+
readonly allow?: readonly string[];
|
|
112
|
+
readonly deny?: readonly string[];
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
/** Validate a profile id: lowercase letters, digits, hyphens; 1–32 chars. */
|
|
116
|
+
export declare function isValidProfileId(id: string): boolean;
|