@aparte/plugin-subagents 0.0.0-stage → 1.6.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 aparté
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,90 @@
1
- # Temporary Holding Version
1
+ # @aparte/plugin-subagents
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Sub-agents for [aparté](https://github.com/apartejs/aparte): one line per sub-agent — its name and its task,
4
+ and under them what it is doing now, then what it did ("3 tools · 12 s") — with its conversation kept out of
5
+ the reply and out of what the model reads.
6
+
7
+ ```bash
8
+ npm install @aparte/plugin-subagents @aparte/core
9
+ ```
10
+
11
+ ```ts
12
+ import { aparteGlobalConfig } from '@aparte/core';
13
+ import { setupSubagents } from '@aparte/plugin-subagents';
14
+
15
+ setupSubagents(); // the line alone, on the global config
16
+
17
+ // Or tuned (the config last, like every setup*; the global one by default):
18
+ const stop = setupSubagents({ activity: true, counts: false }, aparteGlobalConfig);
19
+ stop(); // takes it off again
20
+ ```
21
+
22
+ **Where the line comes from.** A sub-agent opened by a tool call takes that call's row: everything you
23
+ declare for the tool with `registerToolDisplay` (`label`, `icon`, `quiet`, `hidden`, `details`) still
24
+ applies, and wins over what the plugin says. A sub-agent no call opened — or a second one opened by the
25
+ same call — gets a `subagent` segment (`SUBAGENT_SEGMENT_TYPE`, typed `AparteSubagentSegment`) drawn as the
26
+ same row, named by the agent: `registerToolDisplay('<agent name>', …)` reaches it.
27
+
28
+ **Options** (`SubagentsOptions`): `activity` gives the line a second line from the sub-agent's start to its
29
+ end — *Starting…*, its latest tool call, then what it did — so the row keeps its height (default `true`);
30
+ `counts` says what it did, its tool calls and how long it worked, once it is over (default `true`); `details` is what is behind
31
+ the line — `false` by default (no disclosure), `'transcript'` for the sub-agent's conversation, or a
32
+ function that returns what to show under it.
33
+
34
+ **Its conversation under the line.** With `details: 'transcript'`, each line opens on what the sub-agent
35
+ said and did — the task it was given, its text, its reasoning, its own tool rows, and its own sub-agents
36
+ as lines — drawn by the same renderers as the reply and kept up to date while it works. The line stays
37
+ closed until the reader opens it:
38
+
39
+ ```ts
40
+ setupSubagents({ details: 'transcript' });
41
+ ```
42
+
43
+ `subagentTranscript` is that detail as a function, so you can put it under one tool's line only, or open
44
+ it by default:
45
+
46
+ ```ts
47
+ import { aparteGlobalConfig } from '@aparte/core';
48
+ import { setupSubagents, subagentTranscript } from '@aparte/plugin-subagents';
49
+
50
+ setupSubagents();
51
+ aparteGlobalConfig.registerToolDisplay('task', { details: subagentTranscript, open: true });
52
+ ```
53
+
54
+ **Its conversation anywhere else.** `<aparte-subagent-view>` (`AparteSubagentView`) shows the same
55
+ conversation where you place it — a pane of `<aparte-split>`, a canvas, a dialog. Name the chat with `for`
56
+ (or set the `chat` property, typed `SubagentViewSource`), the reply with `message-id`, the sub-agent with
57
+ `agent-id`. It follows the sub-agent live, shows the saved conversation after a reload, and draws nothing
58
+ (`data-empty`) until there is something to show. `aparte-subagent-start` gives the three ids:
59
+
60
+ ```html
61
+ <aparte-split primary="start" position="55" single>
62
+ <aparte-chat id="chat">…</aparte-chat>
63
+ <aparte-subagent-view for="chat"></aparte-subagent-view>
64
+ </aparte-split>
65
+ <script type="module">
66
+ import { setupSubagents } from '@aparte/plugin-subagents';
67
+
68
+ setupSubagents();
69
+ const view = document.querySelector('aparte-subagent-view');
70
+ document.getElementById('chat').addEventListener('aparte-subagent-start', (e) => {
71
+ view.setAttribute('message-id', e.detail.messageId);
72
+ view.setAttribute('agent-id', e.detail.agentId);
73
+ });
74
+ </script>
75
+ ```
76
+
77
+ **Reading it back.** The sub-agent (`AparteSubagent`: `id`, `name`, `description`, `status`, `result`,
78
+ `error`, `parentId`, `segments`) is saved on the segment that stands for it. `subagentOf(segment)` returns
79
+ it; `subagentStatus(segment)` returns its state (`AparteSubagentStatus`: `running`, `waiting`, `done`,
80
+ `failed`, `stopped`), and reads `stopped` for a sub-agent a reload or a Stop left unfinished.
81
+
82
+ **Events.** The chat element hears `aparte-subagent-start` (`AparteSubagentStartEventDetail`: `messageId`,
83
+ `agentId`, `name`, `description`, `toolCallId`, `parentId`) and `aparte-subagent-end`
84
+ (`AparteSubagentEndEventDetail`: `messageId`, `agentId`, `status`), so an app can list the sub-agents of a
85
+ reply wherever it likes.
86
+
87
+ Without the plugin, a sub-agent's text and tool calls are still kept out of the reply: the call that opened
88
+ it shows as an ordinary tool row. `@aparte/core` is the only **peer dependency**.
89
+
90
+ > ESM-only. Part of the aparté monorepo.
@@ -0,0 +1,129 @@
1
+ /**
2
+ * `<aparte-subagent-view>` — a sub-agent's conversation, wherever the app puts it.
3
+ *
4
+ * The line in the reply says what a sub-agent is doing; this element shows what it said and
5
+ * did — its text, its reasoning, its tool rows, its own sub-agents as lines — drawn by the
6
+ * same renderers as the reply. It is also what `subagentTranscript` puts under the line, so
7
+ * there is one drawing of a conversation, not two.
8
+ *
9
+ * Standalone, it reads the sub-agent from the chat: live, from each write of the plugin's
10
+ * lane (once a frame while it streams); saved, from the segment that stands for it in the
11
+ * reply, searched through the lanes of its parents too. A saved conversation is adopted
12
+ * before it is drawn (`createSegmentList`), so nothing in it reads as still arriving.
13
+ *
14
+ * Light DOM, like core. It writes its own two parts as children and decides nothing about
15
+ * the layout.
16
+ */
17
+ import { type AparteConfig, type AparteMessage, type AparteSegment } from '@aparte/core';
18
+ /** Where the view reads the conversation: a chat element, its viewport, or anything with `getMessages()`. */
19
+ export type SubagentViewSource = (Element | object) & {
20
+ getMessages?: () => AparteMessage[];
21
+ getMessage?: (id: string) => AparteMessage | undefined;
22
+ };
23
+ /**
24
+ * The conversation of the sub-agent `anchor` stands for, as it is drawn: as it is while the
25
+ * sub-agent works, adopted once it is over (a reload, a Stop, its end) — every text settled,
26
+ * every call still open read as stopped.
27
+ */
28
+ export declare function laneOf(anchor: AparteSegment): {
29
+ segments: readonly AparteSegment[];
30
+ live: boolean;
31
+ };
32
+ /** The segment that stands for `agentId` among `segments`, or in the lanes of the sub-agents there. */
33
+ export declare function findSubagent(segments: readonly AparteSegment[], agentId: string, depth?: number): AparteSegment | undefined;
34
+ /** Importable where there is no DOM: the class then extends nothing and is never defined. */
35
+ declare const ElementBase: typeof HTMLElement;
36
+ /**
37
+ * A sub-agent's conversation — its text, its reasoning, its tool rows, its own sub-agents as
38
+ * lines — where the app places it: a canvas, a pane of `<aparte-split>`, a dialog. It follows
39
+ * the sub-agent live while it works and shows the saved conversation after a reload. Name the
40
+ * chat with `for` (or the `chat` property), the reply with `message-id`, the sub-agent with
41
+ * `agent-id`: `aparte-subagent-start` gives all three as its sub-agents start.
42
+ *
43
+ * It is the same element `subagentTranscript` puts under a sub-agent's line.
44
+ *
45
+ * @element aparte-subagent-view
46
+ *
47
+ * @attr {string} for - The `id` of the chat: `<aparte-chat>`, its viewport, or any element with `getMessages()`. Or set the `chat` property.
48
+ * @attr {string} message-id - The reply the sub-agent worked for (`aparte-subagent-start`'s `messageId`).
49
+ * @attr {string} agent-id - Which sub-agent (`aparte-subagent-start`'s `agentId`).
50
+ * @attr {boolean} data-empty - Written BY the element while there is nothing to show (an unknown sub-agent, or one not started yet): it then draws nothing. Read-only; style or fold your layout against it.
51
+ * @attr {boolean} data-inline - Written BY the element when it is a line's detail rather than a view of its own. Read-only.
52
+ *
53
+ * @cssprop [--aparte-subagent-indent=var(--aparte-space-6)] - The space between the rule down the leading edge and the conversation, in a standalone view.
54
+ *
55
+ * @example The chat in one pane, a sub-agent's conversation in the other
56
+ * ```html
57
+ * <aparte-split primary="start" position="55" single>
58
+ * <aparte-chat id="chat">…</aparte-chat>
59
+ * <aparte-subagent-view for="chat"></aparte-subagent-view>
60
+ * </aparte-split>
61
+ * <script type="module">
62
+ * import { setupSubagents } from '@aparte/plugin-subagents';
63
+ *
64
+ * setupSubagents();
65
+ * const view = document.querySelector('aparte-subagent-view');
66
+ * // Show the latest sub-agent to start, as it works.
67
+ * document.getElementById('chat').addEventListener('aparte-subagent-start', (e) => {
68
+ * view.setAttribute('message-id', e.detail.messageId);
69
+ * view.setAttribute('agent-id', e.detail.agentId);
70
+ * });
71
+ * </script>
72
+ * ```
73
+ */
74
+ export declare class AparteSubagentView extends ElementBase {
75
+ static get observedAttributes(): string[];
76
+ private _chat;
77
+ private _task;
78
+ private _drawing;
79
+ /** The config the rows were drawn with, and the segment they were drawn from. */
80
+ private _config;
81
+ private _anchor;
82
+ private _listening;
83
+ private _stopConfig;
84
+ private _stopWatching;
85
+ private _queued;
86
+ private _releaseQueued;
87
+ private _warned;
88
+ private readonly _onConversation;
89
+ private readonly _onWrite;
90
+ /** The chat, when it has no `id` for the `for` attribute: an element, or anything with `getMessages()`. */
91
+ get chat(): SubagentViewSource | null;
92
+ set chat(value: SubagentViewSource | null);
93
+ /** Read the sub-agent again and draw it: what the element does on every change it hears. */
94
+ refresh(): void;
95
+ connectedCallback(): void;
96
+ disconnectedCallback(): void;
97
+ attributeChangedCallback(_name: string, previous: string | null, value: string | null): void;
98
+ private _source;
99
+ private _sourceConfig;
100
+ /** A write from this view's chat: the run's target is the chat, inside it, or named by its id. */
101
+ private _matches;
102
+ /**
103
+ * The segment that stands for the sub-agent in the chat's reply; `undefined` when there is
104
+ * none, `null` when the chat cannot be read at all.
105
+ */
106
+ private _find;
107
+ private _listen;
108
+ private _unlisten;
109
+ /** Folds a burst of events (a whole run's end) into one read. */
110
+ private _schedule;
111
+ private _onConfigChange;
112
+ private _build;
113
+ /** Draw `anchor`'s conversation with `config`. */
114
+ private _draw;
115
+ /** Out of the page for good: every row's renderer cleans up, and the drawing goes. */
116
+ private _release;
117
+ }
118
+ /**
119
+ * Draw `anchor` in `view`, as a line's detail: the view then reads nothing of its own and
120
+ * shows what each call hands it. `onRelease` runs when the view leaves the page for good.
121
+ */
122
+ export declare function feedView(view: AparteSubagentView, anchor: AparteSegment, config: AparteConfig, onRelease?: () => void): void;
123
+ declare global {
124
+ interface HTMLElementTagNameMap {
125
+ 'aparte-subagent-view': AparteSubagentView;
126
+ }
127
+ }
128
+ export {};
129
+ //# sourceMappingURL=aparte-subagent-view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aparte-subagent-view.d.ts","sourceRoot":"","sources":["../src/aparte-subagent-view.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAMH,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,aAAa,EACrB,MAAM,cAAc,CAAC;AAMtB,6GAA6G;AAC7G,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,GAAG;IAClD,WAAW,CAAC,EAAE,MAAM,aAAa,EAAE,CAAC;IACpC,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,aAAa,GAAG,SAAS,CAAC;CAC1D,CAAC;AAeF;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG;IAAE,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAWnG;AAED,uGAAuG;AACvG,wBAAgB,YAAY,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,aAAa,GAAG,SAAS,CAUtH;AAUD,6FAA6F;AAC7F,QAAA,MAAM,WAAW,EAAoE,OAAO,WAAW,CAAC;AAExG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,qBAAa,kBAAmB,SAAQ,WAAW;IAC/C,MAAM,KAAK,kBAAkB,IAAI,MAAM,EAAE,CAA8C;IAEvF,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,QAAQ,CAA4B;IAC5C,iFAAiF;IACjF,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,OAAO,CAAM;IAErB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgC;IAChE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAKvB;IAIF,2GAA2G;IAC3G,IAAI,IAAI,IAAI,kBAAkB,GAAG,IAAI,CAAuB;IAC5D,IAAI,IAAI,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,EAKxC;IAED,4FAA4F;IAC5F,OAAO,IAAI,IAAI;IAUf,iBAAiB,IAAI,IAAI;IAazB,oBAAoB,IAAI,IAAI;IAiB5B,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAQ5F,OAAO,CAAC,OAAO;IAMf,OAAO,CAAC,aAAa;IAKrB,kGAAkG;IAClG,OAAO,CAAC,QAAQ;IAShB;;;OAGG;IACH,OAAO,CAAC,KAAK;IA4Bb,OAAO,CAAC,OAAO;IAef,OAAO,CAAC,SAAS;IAKjB,iEAAiE;IACjE,OAAO,CAAC,SAAS;IASjB,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,MAAM;IAiBd,kDAAkD;IAClD,OAAO,CAAC,KAAK;IAgBb,sFAAsF;IACtF,OAAO,CAAC,QAAQ;CAQnB;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,CAAC,EAAE,MAAM,IAAI,GAAG,IAAI,CAI5H;AASD,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,sBAAsB,EAAE,kBAAkB,CAAC;KAC9C;CACJ"}