@huanlin/dsh-plugin-yet-another-subagent 0.1.3 → 0.1.5
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/lib/client.js +3086 -1578
- package/lib/index.js +5487 -5487
- 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/dictionaries.d.ts +17 -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,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SettingsPage — the `ya-subagent` settings section: profile list CRUD.
|
|
3
|
+
*
|
|
4
|
+
* Visual language: matches ModelsSection / GeneralSection — outlined rowCard
|
|
5
|
+
* per profile (border-l2, r12, p12/14), filled editor surface
|
|
6
|
+
* (bg-module-platform, r12, p14/16), capsule controls (h36 r18 primary,
|
|
7
|
+
* h28 r14 secondary), 32px fields with border-l2 / bg-layer-1, 12/18 caption
|
|
8
|
+
* labels. Every color resolves through --dsw-alias-* tokens.
|
|
9
|
+
*
|
|
10
|
+
* Each profile card is collapsible (chevron in the row head); the editor
|
|
11
|
+
* surface is hidden when collapsed. Builtin profiles (cordis.yml seed) carry
|
|
12
|
+
* a `builtin`/`内置` badge next to the title. The "+ Add subagent" button at
|
|
13
|
+
* the bottom reveals an inline draft card with all fields editable (including
|
|
14
|
+
* id) and Create / Cancel actions.
|
|
15
|
+
*
|
|
16
|
+
* The persona field is a radio (inherit deployment persona vs custom text);
|
|
17
|
+
* the textarea is shown only when custom. The tool filter is a select
|
|
18
|
+
* (none / allow / deny); a multi-select dropdown is shown only when allow or
|
|
19
|
+
* deny is picked, populated from `tools.list` (the host's current
|
|
20
|
+
* `ctx.tools.schemas()`).
|
|
21
|
+
*
|
|
22
|
+
* Pulls the profile list once on mount via `connection.rpc.call('/ya-subagent',
|
|
23
|
+
* 'profiles.list')`, dispatches add/update/remove through the
|
|
24
|
+
* same RPC. The toolview slot is keyed by `subagent` and registered once at
|
|
25
|
+
* plugin load, so profile mutations do not need to re-register slots.
|
|
26
|
+
*
|
|
27
|
+
* @module @huanlin/dsh-plugin-yet-another-subagent/client/SettingsPage
|
|
28
|
+
*/
|
|
29
|
+
import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
30
|
+
import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
|
|
31
|
+
import type { ClientConnectionRpc } from '@deepseek-ai/dsh-client-connection/client';
|
|
32
|
+
import type { SubagentProfile } from '../types.ts';
|
|
33
|
+
/** Inject face: RPC handle + locale translate. */
|
|
34
|
+
export interface YaSubagentSettingsInjected {
|
|
35
|
+
readonly rpc: ClientConnectionRpc;
|
|
36
|
+
/** Refetch the profile list from the host. */
|
|
37
|
+
readonly fetchProfiles: () => Promise<readonly SubagentProfile[]>;
|
|
38
|
+
/** Bound locale translator for the ya-subagent namespace. */
|
|
39
|
+
readonly t: (key: string) => string;
|
|
40
|
+
}
|
|
41
|
+
/** Full props: settings.section runtime share + locale seat + inject. */
|
|
42
|
+
type SettingsPageProps = PropsRuntime<'settings.section'> & PropsLocale<'ya-subagent'> & YaSubagentSettingsInjected;
|
|
43
|
+
/**
|
|
44
|
+
* Render the subagent profiles settings page.
|
|
45
|
+
* @param props - settings.section runtime share + locale + inject.
|
|
46
|
+
* @returns the page element.
|
|
47
|
+
*/
|
|
48
|
+
export declare function SettingsPage({ rpc, fetchProfiles, t }: SettingsPageProps): import("react").JSX.Element;
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SubagentCard — the model-facing toolcall card for the `subagent` tool.
|
|
3
|
+
*
|
|
4
|
+
* Three display branches:
|
|
5
|
+
* 1. **Running** (block is `RunningToolCall`): the tool call is in flight.
|
|
6
|
+
* Show "running" with a spinner dot; no child session to subscribe to.
|
|
7
|
+
* 2. **Continuable settled** (result text matches `started <label>
|
|
8
|
+
* subagent <id>`): subscribe to the child's `yaSubagentProgress`
|
|
9
|
+
* projection for live toolcall/token counts; clickable to open.
|
|
10
|
+
* 3. **Foreground settled** (result text is the child's output): the
|
|
11
|
+
* one-shot child has completed; show "completed" with an output
|
|
12
|
+
* preview. No child session survives.
|
|
13
|
+
*
|
|
14
|
+
* @module @huanlin/dsh-plugin-yet-another-subagent/client/SubagentCard
|
|
15
|
+
*/
|
|
16
|
+
import type { ToolCallViewProps } from '@deepseek-ai/dsh-client-ui-tool/client';
|
|
17
|
+
import type { InjectFace, PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
|
|
18
|
+
/** Sessions service shape consumed by this card (narrow face of ISessions). */
|
|
19
|
+
export interface SubagentCardSessions {
|
|
20
|
+
binding(id: string): {
|
|
21
|
+
session: {
|
|
22
|
+
projections: {
|
|
23
|
+
faceOf(key: string): {
|
|
24
|
+
getSnapshot(): unknown;
|
|
25
|
+
subscribe(fn: () => void): () => void;
|
|
26
|
+
} | undefined;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
} | undefined;
|
|
30
|
+
openSubagent(address: {
|
|
31
|
+
parentSessionId: string;
|
|
32
|
+
childSessionId: string;
|
|
33
|
+
mode: 'continuable' | 'one-shot';
|
|
34
|
+
}): void;
|
|
35
|
+
subagentAddress(id: string): {
|
|
36
|
+
parentSessionId: string;
|
|
37
|
+
childSessionId: string;
|
|
38
|
+
mode: 'continuable' | 'one-shot';
|
|
39
|
+
} | undefined;
|
|
40
|
+
refreshSubagents(parentSessionId: string): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
/** Inject face: the sessions service handle + profile label lookup. */
|
|
43
|
+
export type SubagentCardInjected = {
|
|
44
|
+
sessions: SubagentCardSessions;
|
|
45
|
+
/** Resolve a profile id to its display label; undefined if unknown. */
|
|
46
|
+
profileLabelOf: (id: string) => string | undefined;
|
|
47
|
+
};
|
|
48
|
+
/** Full props: toolview runtime share + this package's locale seat + inject. */
|
|
49
|
+
type SubagentCardProps = ToolCallViewProps & PropsLocale<'ya-subagent'> & InjectFace<SubagentCardInjected>;
|
|
50
|
+
/**
|
|
51
|
+
* Render one `subagent` tool call as a compact live card.
|
|
52
|
+
* @param props - keyed toolview payload + locale seat + sessions inject.
|
|
53
|
+
* @returns the dedicated subagent card.
|
|
54
|
+
*/
|
|
55
|
+
export declare function SubagentCard({ block, callId, toolName, sessionId, sessions, profileLabelOf, t }: SubagentCardProps): import("react").JSX.Element;
|
|
56
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SubagentTreeView — a `conversation.view` entry showing the root session's
|
|
3
|
+
* full subagent tree (all depths) with live progress.
|
|
4
|
+
*
|
|
5
|
+
* Uses `sessions.subagentsByParent` (the catalog) as the primary tree
|
|
6
|
+
* structure source — this works for ALL depths without needing per-session
|
|
7
|
+
* bindings. `setSubagentCatalogOpen` keeps catalogs auto-refreshing.
|
|
8
|
+
* Projections (`yaSubagentProgress`) are used additionally when a session
|
|
9
|
+
* binding is available (current session + opened children) for richer data.
|
|
10
|
+
*
|
|
11
|
+
* @module @huanlin/dsh-plugin-yet-another-subagent/client/SubagentTreeView
|
|
12
|
+
*/
|
|
13
|
+
import type { ConvViewProps } from '@deepseek-ai/dsh-client-ui-conversation/client';
|
|
14
|
+
import type { InjectFace, PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
|
|
15
|
+
/** Catalog entry shape (narrow face of SubagentListEntry). */
|
|
16
|
+
interface CatalogEntry {
|
|
17
|
+
readonly kind: string;
|
|
18
|
+
readonly id: string;
|
|
19
|
+
readonly mode?: string;
|
|
20
|
+
readonly activity?: string;
|
|
21
|
+
readonly hasChildren?: boolean;
|
|
22
|
+
readonly label?: string;
|
|
23
|
+
}
|
|
24
|
+
/** Sessions service shape consumed by this view. */
|
|
25
|
+
interface TreeSessions {
|
|
26
|
+
binding(id: string): {
|
|
27
|
+
session: {
|
|
28
|
+
projections: {
|
|
29
|
+
faceOf(key: string): {
|
|
30
|
+
getSnapshot(): unknown;
|
|
31
|
+
subscribe(fn: () => void): () => void;
|
|
32
|
+
} | undefined;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
} | undefined;
|
|
36
|
+
openSubagent(address: {
|
|
37
|
+
parentSessionId: string;
|
|
38
|
+
childSessionId: string;
|
|
39
|
+
mode: 'continuable' | 'one-shot';
|
|
40
|
+
}): void;
|
|
41
|
+
subagentAddress(id: string): {
|
|
42
|
+
parentSessionId: string;
|
|
43
|
+
childSessionId: string;
|
|
44
|
+
mode: 'continuable' | 'one-shot';
|
|
45
|
+
} | undefined;
|
|
46
|
+
refreshSubagents(parentSessionId: string): Promise<void>;
|
|
47
|
+
setSubagentCatalogOpen(parentSessionId: string, open: boolean): void;
|
|
48
|
+
subagentsByParent: Readonly<Record<string, {
|
|
49
|
+
entries: readonly CatalogEntry[];
|
|
50
|
+
parentAvailable: boolean;
|
|
51
|
+
}>>;
|
|
52
|
+
}
|
|
53
|
+
export type SubagentTreeViewInjected = {
|
|
54
|
+
sessions: TreeSessions;
|
|
55
|
+
profileLabelOf: (id: string) => string | undefined;
|
|
56
|
+
};
|
|
57
|
+
type SubagentTreeViewProps = ConvViewProps & PropsLocale<'ya-subagent'> & InjectFace<SubagentTreeViewInjected>;
|
|
58
|
+
/**
|
|
59
|
+
* Render the subagent tree view. Always shows the ROOT session's full tree;
|
|
60
|
+
* highlights the current session if it is a subagent.
|
|
61
|
+
*/
|
|
62
|
+
export declare function SubagentTreeView({ sessionId, sessions, profileLabelOf, t }: SubagentTreeViewProps): import("react").JSX.Element;
|
|
63
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dictionaries.ts — the 19 better-locale override languages for the
|
|
3
|
+
* yet-another-subagent copy, keyed by language id. Each dictionary carries
|
|
4
|
+
* the same key set as `en`/`zh` in `./locales.ts` (enforced by the
|
|
5
|
+
* `Record<YaSubagentKey, string>` annotation); values keep `{placeholder}`
|
|
6
|
+
* interpolation, matching the better-locale store's `LocaleDict` contract.
|
|
7
|
+
*
|
|
8
|
+
* The apply function registers these into `ctx.betterLocale` (the override
|
|
9
|
+
* store) under `NS`, so when the user selects an override language through
|
|
10
|
+
* dsh-plugin-better-locale (and DSH is on 'en', whose slot the override
|
|
11
|
+
* borrows), the plugin UI renders in the override language.
|
|
12
|
+
*
|
|
13
|
+
* @module @huanlin/dsh-plugin-yet-another-subagent/client/dictionaries
|
|
14
|
+
*/
|
|
15
|
+
import type { YaSubagentKey } from './locales.ts';
|
|
16
|
+
/** All override-language dictionaries for the `ya-subagent` namespace. */
|
|
17
|
+
export declare const dicts: Record<string, Record<YaSubagentKey, string>>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yet-another-subagent — browser half.
|
|
3
|
+
*
|
|
4
|
+
* Single bundle, dual entry: this is the client half (exports `./client`).
|
|
5
|
+
* Host half ships via `.` (see `src/index.ts`).
|
|
6
|
+
*
|
|
7
|
+
* Two registrations:
|
|
8
|
+
* 1. `settings.section` slot — the profile editor page (SettingsPage).
|
|
9
|
+
* 2. `tool.call.toolview` keyed slot, key `subagent` — the live toolcall
|
|
10
|
+
* card (SubagentCard). A single key covers all profiles because the
|
|
11
|
+
* tool name is always `subagent`; the profile is a call parameter.
|
|
12
|
+
*
|
|
13
|
+
* @module @huanlin/dsh-plugin-yet-another-subagent/client
|
|
14
|
+
*/
|
|
15
|
+
import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
|
|
16
|
+
import { type YaSubagentKey } from './locales.ts';
|
|
17
|
+
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
18
|
+
interface LocaleNamespaceMap {
|
|
19
|
+
/** The subagent settings page + tool card copy. */
|
|
20
|
+
'ya-subagent': YaSubagentKey;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/** Required services: settings/tool slots, locale, sessions, connection. */
|
|
24
|
+
export declare const inject: string[];
|
|
25
|
+
/**
|
|
26
|
+
* Client plugin body: register settings page + single `subagent` toolview slot.
|
|
27
|
+
* @param ctx - client root context.
|
|
28
|
+
*/
|
|
29
|
+
export declare function apply(ctx: ClientContext): void;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Locale dictionaries for yet-another-subagent.
|
|
3
|
+
*
|
|
4
|
+
* @module @huanlin/dsh-plugin-yet-another-subagent/client/locales
|
|
5
|
+
*/
|
|
6
|
+
/** All copy keys for the ya-subagent namespace. */
|
|
7
|
+
export type YaSubagentKey = 'nav' | 'page.title' | 'page.empty' | 'page.add' | 'page.add.placeholder.id' | 'page.add.placeholder.label' | 'page.add.submit' | 'page.add.error' | 'page.add.cancel' | 'row.label' | 'row.id' | 'row.model.kind.auto' | 'row.model.kind.manual' | 'row.model.provider' | 'row.model.model' | 'row.model.provider.placeholder' | 'row.model.model.placeholder' | 'row.model.noModels' | 'row.persona' | 'row.persona.kind.inherit' | 'row.persona.kind.custom' | 'row.persona.text' | 'row.toolFilter' | 'row.toolFilter.kind.none' | 'row.toolFilter.kind.allow' | 'row.toolFilter.kind.deny' | 'row.toolFilter.tools' | 'row.toolFilter.tools.search' | 'row.toolFilter.tools.empty' | 'row.toolFilter.tools.selected' | 'row.toolFilter.tools.selectAll' | 'row.toolFilter.tools.clear' | 'row.maxDepth' | 'row.delete' | 'row.delete.confirm' | 'row.save' | 'row.saved' | 'row.error' | 'row.expand' | 'row.collapse' | 'badge.builtin' | 'card.starting' | 'card.waiting' | 'card.idle' | 'card.running' | 'card.completed' | 'card.child-running' | 'card.child-idle' | 'card.toolcalls' | 'card.tokens' | 'card.calling' | 'card.open' | 'card.unavailable' | 'tree.tab' | 'tree.empty' | 'tree.rootHint' | 'tree.toolcalls' | 'tree.tokens' | 'tree.calling' | 'tree.state.running' | 'tree.state.idle' | 'tree.state.settled' | 'repair.button' | 'repair.confirm.title' | 'repair.confirm.body' | 'repair.confirm.warning' | 'repair.confirm.cancel' | 'repair.confirm.proceed' | 'repair.running' | 'repair.result.title' | 'repair.result.scanned' | 'repair.result.repaired' | 'repair.result.skipped' | 'repair.result.errors' | 'repair.result.errorEntry' | 'repair.result.close' | 'repair.error';
|
|
8
|
+
/** Locale namespace id. */
|
|
9
|
+
export declare const NS = "ya-subagent";
|
|
10
|
+
/** English dictionary. */
|
|
11
|
+
export declare const en: Record<YaSubagentKey, string>;
|
|
12
|
+
/** Chinese dictionary. */
|
|
13
|
+
export declare const zh: Record<YaSubagentKey, string>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yet-another-subagent — host plugin entry.
|
|
3
|
+
*
|
|
4
|
+
* Single bundle, dual entry: this is the host half (exports `.`). The browser
|
|
5
|
+
* half ships via `./client` (see `src/client/index.ts`).
|
|
6
|
+
*
|
|
7
|
+
* Architecture (design doc §1):
|
|
8
|
+
* - A single `subagent` tool is exposed to the model. The desired profile
|
|
9
|
+
* is selected via the `profile` parameter (enum of profile ids). Profile
|
|
10
|
+
* add/remove updates the enum without changing the tool name set.
|
|
11
|
+
* - The tool reuses the official `spawn` provider via `ctx.subagents.startContinuable`.
|
|
12
|
+
* - Profiles live in an in-memory `ProfileStore` mutated through RPC.
|
|
13
|
+
* - Two projections (`subagentProfile` on parent, `yaSubagentProgress` on
|
|
14
|
+
* child) bridge the single-stage client runtime so SubagentCard can
|
|
15
|
+
* subscribe to live child progress.
|
|
16
|
+
*
|
|
17
|
+
* @module @huanlin/dsh-plugin-yet-another-subagent
|
|
18
|
+
*/
|
|
19
|
+
import type { Context } from 'cordis';
|
|
20
|
+
import z from 'schemastery';
|
|
21
|
+
import type { YaSubagentConfig } from './types.ts';
|
|
22
|
+
export declare const name = "yet-another-subagent";
|
|
23
|
+
export declare const inject: string[];
|
|
24
|
+
export type { SubagentProfile, YaSubagentConfig } from './types.ts';
|
|
25
|
+
/** Settings namespace under which profile state persists (`$DSH_HOME/settings.yaml`). */
|
|
26
|
+
export declare const SETTINGS_NAMESPACE: import("@deepseek-ai/dsh-settings").SettingsNamespace;
|
|
27
|
+
export interface Config extends YaSubagentConfig {
|
|
28
|
+
}
|
|
29
|
+
export declare const Config: z<Config>;
|
|
30
|
+
/**
|
|
31
|
+
* Plugin body: register profile tools, RPC, and projections.
|
|
32
|
+
*
|
|
33
|
+
* Persistence: when a settings service is mounted, the profile list lives
|
|
34
|
+
* under the `ya-subagent` namespace in `$DSH_HOME/settings.yaml`. The
|
|
35
|
+
* cordis.yml `profiles` field is the composition `base` (first-boot seed);
|
|
36
|
+
* runtime mutations persist through `scope.replace()`. Headless assemblies
|
|
37
|
+
* without a settings provider fall back to in-memory state (cordis.yml seed
|
|
38
|
+
* only, no persistence).
|
|
39
|
+
* @param ctx - host context carrying `tools`, `subagents`, `sessionProjections`.
|
|
40
|
+
* @param config - resolved config (seed profiles + generalFixed).
|
|
41
|
+
*/
|
|
42
|
+
export declare function apply(ctx: Context, config: Config): void;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion for `@huanlin/dsh-plugin-yet-another-subagent`.
|
|
3
|
+
*
|
|
4
|
+
* @module @huanlin/dsh-plugin-yet-another-subagent/invariant
|
|
5
|
+
*/
|
|
6
|
+
import type { Context } from 'cordis';
|
|
7
|
+
/** Cordis companion plugin name. */
|
|
8
|
+
export declare const name = "yet-another-subagent-invariant";
|
|
9
|
+
/** Service required before the companion can reserve package ownership. */
|
|
10
|
+
export declare const inject: string[];
|
|
11
|
+
/**
|
|
12
|
+
* Register this package's invariant companion.
|
|
13
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
14
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
15
|
+
*/
|
|
16
|
+
export declare const apply: (ctx: Context) => Promise<() => void>;
|
|
@@ -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 };
|