@aparte/plugin-subagents 1.6.0 → 1.8.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/dist/aparte-subagent-view.d.ts +21 -0
- package/dist/aparte-subagent-view.d.ts.map +1 -1
- package/dist/{setup-CaTzFtu8.js → connect-BF7Y9tBE.js} +376 -71
- package/dist/connect-BF7Y9tBE.js.map +1 -0
- package/dist/connect.d.ts +44 -0
- package/dist/connect.d.ts.map +1 -0
- package/dist/custom-elements.json +620 -1
- package/dist/drawing.d.ts +9 -1
- package/dist/drawing.d.ts.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.node.d.ts +3 -1
- package/dist/index.node.d.ts.map +1 -1
- package/dist/index.node.js +3 -2
- package/dist/lanes.d.ts +2 -0
- package/dist/lanes.d.ts.map +1 -1
- package/dist/line.d.ts +2 -1
- package/dist/line.d.ts.map +1 -1
- package/dist/open.d.ts +34 -0
- package/dist/open.d.ts.map +1 -0
- package/dist/steps.d.ts +22 -0
- package/dist/steps.d.ts.map +1 -0
- package/dist/types.d.ts +28 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/words.d.ts +26 -0
- package/dist/words.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/setup-CaTzFtu8.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createSegmentList, createStreamAdapter, runWithConfig, getSegmentRenderer, installDefaultRenderersOnce, deferHydrationOf, subscribeConfigChange, resolveConfig, contextConfig,
|
|
1
|
+
import { createSegmentList, createStreamAdapter, runWithConfig, getSegmentRenderer, installDefaultRenderersOnce, pluralize, deferHydrationOf, onRenderersChange, subscribeConfigChange, resolveConfig, contextConfig, formatDuration, segmentTiming, aparteGlobalConfig, registerSegmentRenderer, unregisterSegmentRenderer } from "@aparte/core";
|
|
2
2
|
const SUBAGENT_SEGMENT_TYPE = "subagent";
|
|
3
3
|
const STATUSES = /* @__PURE__ */ new Set(["running", "waiting", "done", "failed", "stopped"]);
|
|
4
4
|
function subagentOf(segment) {
|
|
@@ -55,11 +55,41 @@ function callStatusOf(status) {
|
|
|
55
55
|
return "aborted";
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
+
const open = /* @__PURE__ */ new Map();
|
|
59
|
+
const keyOf$1 = (messageId, agentId) => `${messageId}\0${agentId}`;
|
|
60
|
+
function stepStarted(messageId, agentId, name) {
|
|
61
|
+
const key = keyOf$1(messageId, agentId);
|
|
62
|
+
open.set(key, [...open.get(key) ?? [], name]);
|
|
63
|
+
}
|
|
64
|
+
function stepEnded(messageId, agentId, name) {
|
|
65
|
+
const key = keyOf$1(messageId, agentId);
|
|
66
|
+
const steps = open.get(key);
|
|
67
|
+
if (!steps) return;
|
|
68
|
+
const at = steps.lastIndexOf(name);
|
|
69
|
+
if (at < 0) return;
|
|
70
|
+
const rest = steps.filter((_, i) => i !== at);
|
|
71
|
+
if (rest.length > 0) open.set(key, rest);
|
|
72
|
+
else open.delete(key);
|
|
73
|
+
}
|
|
74
|
+
function stepsEnded(messageId, agentId) {
|
|
75
|
+
open.delete(keyOf$1(messageId, agentId));
|
|
76
|
+
}
|
|
77
|
+
function currentStep(messageId, agentId) {
|
|
78
|
+
if (messageId !== void 0) return open.get(keyOf$1(messageId, agentId))?.at(-1);
|
|
79
|
+
const suffix = `\0${agentId}`;
|
|
80
|
+
for (const [key, steps] of open) if (key.endsWith(suffix)) return steps.at(-1);
|
|
81
|
+
return void 0;
|
|
82
|
+
}
|
|
58
83
|
const MAX_RUNS = 64;
|
|
59
84
|
const MAX_LANES = 512;
|
|
60
85
|
const MAX_EARLY = 2e3;
|
|
61
86
|
const COALESCED = /* @__PURE__ */ new Set(["text-delta", "thinking-delta", "sources", "text-flush", "turn-start"]);
|
|
62
87
|
const isOpen = (status) => (status ?? "pending") === "pending" || status === "awaiting-approval";
|
|
88
|
+
const lastWrites = /* @__PURE__ */ new Map();
|
|
89
|
+
const writeKey = (messageId, agentId) => `${messageId}\0${agentId}`;
|
|
90
|
+
function lastLaneWrite(messageId, agentId) {
|
|
91
|
+
return lastWrites.get(writeKey(messageId, agentId));
|
|
92
|
+
}
|
|
63
93
|
const laneWatchers = /* @__PURE__ */ new Set();
|
|
64
94
|
function watchLaneWrites(fn) {
|
|
65
95
|
laneWatchers.add(fn);
|
|
@@ -160,7 +190,7 @@ function createLanes() {
|
|
|
160
190
|
}
|
|
161
191
|
}
|
|
162
192
|
write(run, lane.host, lane.anchorId, updates);
|
|
163
|
-
if (
|
|
193
|
+
if (run.closed) return;
|
|
164
194
|
const anchor = anchorOf(run, lane) ?? {
|
|
165
195
|
id: lane.anchorId,
|
|
166
196
|
type: SUBAGENT_SEGMENT_TYPE,
|
|
@@ -174,6 +204,7 @@ function createLanes() {
|
|
|
174
204
|
agentId: lane.id,
|
|
175
205
|
anchor
|
|
176
206
|
};
|
|
207
|
+
lastWrites.set(writeKey(run.messageId, lane.id), note);
|
|
177
208
|
for (const fn of [...laneWatchers]) {
|
|
178
209
|
try {
|
|
179
210
|
fn(note);
|
|
@@ -224,6 +255,7 @@ function createLanes() {
|
|
|
224
255
|
if (run.closed) return;
|
|
225
256
|
for (const lane of run.lanes.values()) {
|
|
226
257
|
const working = lane.status === "running" || lane.status === "waiting";
|
|
258
|
+
stepsEnded(run.messageId, lane.id);
|
|
227
259
|
settleLane(lane, true);
|
|
228
260
|
lane.streaming = false;
|
|
229
261
|
run.dirty.add(lane);
|
|
@@ -233,6 +265,10 @@ function createLanes() {
|
|
|
233
265
|
forget(run);
|
|
234
266
|
};
|
|
235
267
|
const forget = (run) => {
|
|
268
|
+
for (const lane of run.lanes.values()) {
|
|
269
|
+
stepsEnded(run.messageId, lane.id);
|
|
270
|
+
lastWrites.delete(writeKey(run.messageId, lane.id));
|
|
271
|
+
}
|
|
236
272
|
run.closed = true;
|
|
237
273
|
stopFrame(run);
|
|
238
274
|
run.unlisten();
|
|
@@ -325,6 +361,7 @@ function createLanes() {
|
|
|
325
361
|
};
|
|
326
362
|
const retire = (run, lane) => {
|
|
327
363
|
run.lanes.delete(lane.id);
|
|
364
|
+
stepsEnded(run.messageId, lane.id);
|
|
328
365
|
if (lane.status === "running" || lane.status === "waiting") {
|
|
329
366
|
lane.status = "stopped";
|
|
330
367
|
settleLane(lane, true);
|
|
@@ -423,6 +460,7 @@ function createLanes() {
|
|
|
423
460
|
if (e.result !== void 0) lane.result = e.result;
|
|
424
461
|
if (e.error !== void 0) lane.error = e.error;
|
|
425
462
|
if (e.status !== "waiting") {
|
|
463
|
+
stepsEnded(run.messageId, lane.id);
|
|
426
464
|
settleLane(lane, false);
|
|
427
465
|
lane.streaming = false;
|
|
428
466
|
}
|
|
@@ -435,6 +473,8 @@ function createLanes() {
|
|
|
435
473
|
if (event.type === "tool-awaiting-approval") lane.asking.add(event.toolCallId);
|
|
436
474
|
else if (event.type !== "tool-start") lane.asking.delete(event.toolCallId);
|
|
437
475
|
}
|
|
476
|
+
if (event.type === "step-start") stepStarted(run.messageId, lane.id, event.name);
|
|
477
|
+
else if (event.type === "step-end") stepEnded(run.messageId, lane.id, event.name);
|
|
438
478
|
const before = lane.list.segments.length;
|
|
439
479
|
lane.emit(event);
|
|
440
480
|
if (event.type === "tool-start") callStarted(run, lane, event.toolCallId);
|
|
@@ -493,6 +533,58 @@ function createLanes() {
|
|
|
493
533
|
}
|
|
494
534
|
};
|
|
495
535
|
}
|
|
536
|
+
const shown = /* @__PURE__ */ new Map();
|
|
537
|
+
const keyOf = (messageId, agentId) => `${messageId}\0${agentId}`;
|
|
538
|
+
function isShown(messageId, agentId) {
|
|
539
|
+
if (!messageId || shown.size === 0) return false;
|
|
540
|
+
const key = keyOf(messageId, agentId);
|
|
541
|
+
for (const value of shown.values()) if (value === key) return true;
|
|
542
|
+
return false;
|
|
543
|
+
}
|
|
544
|
+
function setShown(owner, at) {
|
|
545
|
+
if (at) shown.set(owner, keyOf(at.messageId, at.agentId));
|
|
546
|
+
else shown.delete(owner);
|
|
547
|
+
}
|
|
548
|
+
const openButtonOf = (row) => row.querySelector(":scope > :is(.aparte-tool-line, .aparte-tool-open-slot) > .aparte-tool-open");
|
|
549
|
+
function markRow(row, on) {
|
|
550
|
+
const button = openButtonOf(row);
|
|
551
|
+
if (!button) return;
|
|
552
|
+
row.toggleAttribute("data-current", on);
|
|
553
|
+
if (on) button.setAttribute("aria-current", "true");
|
|
554
|
+
else button.removeAttribute("aria-current");
|
|
555
|
+
}
|
|
556
|
+
function unmarkAll(root) {
|
|
557
|
+
for (const row of root.querySelectorAll(".aparte-segment-tool-call[data-current]")) markRow(row, false);
|
|
558
|
+
}
|
|
559
|
+
function targetIdOf(row) {
|
|
560
|
+
const chat = row.closest("aparte-chat");
|
|
561
|
+
if (chat) return chat.id || void 0;
|
|
562
|
+
const view = row.closest("aparte-subagent-view:not([data-inline])");
|
|
563
|
+
if (!view) return void 0;
|
|
564
|
+
const id = view.getAttribute("for") || (typeof view.chat?.id === "string" ? view.chat.id : "");
|
|
565
|
+
return id || void 0;
|
|
566
|
+
}
|
|
567
|
+
function dispatchOpen(row, segment, sub, standIn) {
|
|
568
|
+
const messageId = segment.messageId || row.closest("[message-id]")?.getAttribute("message-id") || "";
|
|
569
|
+
if (!messageId) return;
|
|
570
|
+
const targetId = targetIdOf(row);
|
|
571
|
+
const name = sub.name?.trim();
|
|
572
|
+
const toolCallId = standIn ? void 0 : segment.toolCall?.id;
|
|
573
|
+
const detail = {
|
|
574
|
+
...targetId ? { targetId } : {},
|
|
575
|
+
messageId,
|
|
576
|
+
agentId: sub.id,
|
|
577
|
+
...name ? { name } : {},
|
|
578
|
+
...toolCallId ? { toolCallId } : {}
|
|
579
|
+
};
|
|
580
|
+
row.dispatchEvent(new CustomEvent("aparte-subagent-open", { bubbles: true, composed: true, detail }));
|
|
581
|
+
}
|
|
582
|
+
function innerRendererFor(segment, config) {
|
|
583
|
+
if (segment.type === "activity") return config.getActivityRenderer(segment.activityType) ?? null;
|
|
584
|
+
if (segment.type !== "tool_call") return null;
|
|
585
|
+
const name = segment.toolCall?.name;
|
|
586
|
+
return name && !config.isToolHidden(name) ? config.getToolRenderer(name) ?? null : null;
|
|
587
|
+
}
|
|
496
588
|
function rendererFor(type, config) {
|
|
497
589
|
const renderer = getSegmentRenderer(type, config);
|
|
498
590
|
if (renderer) return renderer;
|
|
@@ -546,7 +638,7 @@ class LaneDrawing {
|
|
|
546
638
|
seen.add(segment.id);
|
|
547
639
|
const renderer = rendererFor(segment.type, config);
|
|
548
640
|
let row = this.rows.get(segment.id);
|
|
549
|
-
if (row && row.renderer !== renderer) {
|
|
641
|
+
if (row && (row.renderer !== renderer || row.inner !== innerRendererFor(segment, config))) {
|
|
550
642
|
this.release(segment.id, config);
|
|
551
643
|
row.el.remove();
|
|
552
644
|
row = void 0;
|
|
@@ -582,7 +674,7 @@ class LaneDrawing {
|
|
|
582
674
|
draw(segment, renderer, config, live) {
|
|
583
675
|
const el = renderer ? toElement(runWithConfig(config, () => renderer.render(segment)), segment) : fallbackOf(segment);
|
|
584
676
|
if (!el) return void 0;
|
|
585
|
-
const row = { el, renderer, segment };
|
|
677
|
+
const row = { el, renderer, inner: innerRendererFor(segment, config), segment };
|
|
586
678
|
this.rows.set(segment.id, row);
|
|
587
679
|
if (renderer?.setup) {
|
|
588
680
|
const as = drawnAs(segment, live);
|
|
@@ -603,9 +695,10 @@ class LaneDrawing {
|
|
|
603
695
|
}
|
|
604
696
|
if (renderer.update) {
|
|
605
697
|
const before = row.el;
|
|
698
|
+
const next2 = before.nextSibling;
|
|
606
699
|
runWithConfig(config, () => renderer.update(before, segment));
|
|
607
700
|
if (before.parentNode !== this.container) {
|
|
608
|
-
const now = this.childOf(segment.id);
|
|
701
|
+
const now = this.childOf(segment.id) ?? this.inPlaceOf(next2, segment.id);
|
|
609
702
|
if (now) row.el = now;
|
|
610
703
|
}
|
|
611
704
|
return;
|
|
@@ -624,6 +717,18 @@ class LaneDrawing {
|
|
|
624
717
|
}
|
|
625
718
|
return null;
|
|
626
719
|
}
|
|
720
|
+
/**
|
|
721
|
+
* The element standing where a row stood (before `next`) when it is no row's: what a
|
|
722
|
+
* renderer put in place of its own without the id (`outerHTML`, `replaceWith`), stamped so
|
|
723
|
+
* the loop finds it. A renderer that took its element away left another row there, or
|
|
724
|
+
* nothing: the row keeps its element, and the loop puts it back.
|
|
725
|
+
*/
|
|
726
|
+
inPlaceOf(next, id) {
|
|
727
|
+
const there = next ? next.previousSibling : this.container.lastChild;
|
|
728
|
+
if (there?.nodeType !== Node.ELEMENT_NODE || there.hasAttribute("data-segment-id")) return null;
|
|
729
|
+
there.setAttribute("data-segment-id", id);
|
|
730
|
+
return there;
|
|
731
|
+
}
|
|
627
732
|
release(id, config) {
|
|
628
733
|
const row = this.rows.get(id);
|
|
629
734
|
if (!row) return;
|
|
@@ -640,7 +745,7 @@ class LaneDrawing {
|
|
|
640
745
|
}
|
|
641
746
|
}
|
|
642
747
|
}
|
|
643
|
-
const styles = "/*\n * @aparte/plugin-subagents — a sub-agent's conversation.\n *\n * Only what is the plugin's own. The rows inside are core's (text, reasoning, tool rows,\n * a nested sub-agent's line) and wear core's sheets; under a line, the transcript sits in\n * core's tool detail, which already draws the rule and the indent a disclosure has. So\n * this sheet draws the task line, the spacing of the rows, and — for the standalone view\n * only — the same quiet rule down the leading edge, since nothing of core's is around it.\n *\n * Logical properties throughout, so a right-to-left locale puts the rule on its own\n * leading edge. No colour of its own: core's tokens. Nothing moves, so there is no motion\n * to reduce.\n */\naparte-subagent-view {\n display: block;\n min-inline-size: 0;\n}\n\n/* Standalone (a canvas, a pane, a dialog): outside any message, so the conversation's\n type is set here, as core's segment container sets it in a reply. */\naparte-subagent-view:not([data-inline]) {\n font-size: var(--aparte-content-font-size);\n line-height: var(--aparte-content-line-height);\n color: var(--aparte-content-color);\n font-family: var(--aparte-font-family);\n}\n\n/* Nothing to show (an unknown sub-agent, or one not started yet): nothing drawn. */\naparte-subagent-view[data-empty] {\n display: none;\n}\n\n.aparte-subagent-task {\n margin: 0 0 var(--aparte-space-3);\n color: var(--aparte-text-muted);\n font-size: var(--aparte-font-size-sm);\n}\n\n.aparte-subagent-transcript {\n display: flex;\n flex-direction: column;\n gap: var(--aparte-space-4);\n min-inline-size: 0;\n}\n\n.aparte-subagent-transcript:empty {\n display: none;\n}\n\naparte-subagent-view:not([data-inline]) > .aparte-subagent-transcript {\n padding-inline-start: var(--aparte-subagent-indent, var(--aparte-space-6));\n border-inline-start: var(--aparte-border-width) solid var(--aparte-border);\n}\n";
|
|
748
|
+
const styles = "/*\n * @aparte/plugin-subagents — a sub-agent's conversation.\n *\n * Only what is the plugin's own. The rows inside are core's (text, reasoning, tool rows,\n * a nested sub-agent's line) and wear core's sheets; under a line, the transcript sits in\n * core's tool detail, which already draws the rule and the indent a disclosure has. So\n * this sheet draws the task line, the spacing of the rows, and — for the standalone view\n * only — the same quiet rule down the leading edge, since nothing of core's is around it.\n *\n * Logical properties throughout, so a right-to-left locale puts the rule on its own\n * leading edge. No colour of its own: core's tokens. Nothing moves, so there is no motion\n * to reduce.\n */\naparte-subagent-view {\n display: block;\n min-inline-size: 0;\n}\n\n/* Standalone (a canvas, a pane, a dialog): outside any message, so the conversation's\n type is set here, as core's segment container sets it in a reply. */\naparte-subagent-view:not([data-inline]) {\n font-size: var(--aparte-content-font-size);\n line-height: var(--aparte-content-line-height);\n color: var(--aparte-content-color);\n font-family: var(--aparte-font-family);\n}\n\n/* Nothing to show (an unknown sub-agent, or one not started yet): nothing drawn. */\naparte-subagent-view[data-empty] {\n display: none;\n}\n\n/* A closable view (a pane of its own): the sub-agent's name, and Close at the far end. The\n name takes the focus when the pane opens, so it shows a ring only to the keyboard. */\n.aparte-subagent-head {\n display: flex;\n align-items: center;\n gap: var(--aparte-space-3);\n margin-block-end: var(--aparte-space-3);\n}\n\n.aparte-subagent-head[hidden] {\n display: none;\n}\n\n.aparte-subagent-name {\n flex: 1 1 auto;\n min-inline-size: 0;\n margin: 0;\n overflow: hidden;\n font-size: var(--aparte-font-size-md);\n font-weight: var(--aparte-font-weight-semibold);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.aparte-subagent-name:focus {\n outline: none;\n}\n\n.aparte-subagent-name:focus-visible {\n outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);\n}\n\n.aparte-subagent-close {\n flex: none;\n}\n\n.aparte-subagent-task {\n margin: 0 0 var(--aparte-space-3);\n color: var(--aparte-text-muted);\n font-size: var(--aparte-font-size-sm);\n}\n\n.aparte-subagent-transcript {\n display: flex;\n flex-direction: column;\n gap: var(--aparte-space-4);\n min-inline-size: 0;\n}\n\n.aparte-subagent-transcript:empty {\n display: none;\n}\n\naparte-subagent-view:not([data-inline]) > .aparte-subagent-transcript {\n padding-inline-start: var(--aparte-subagent-indent, var(--aparte-space-6));\n border-inline-start: var(--aparte-border-width) solid var(--aparte-border);\n}\n";
|
|
644
749
|
const STYLE_ID = "aparte-subagent-styles";
|
|
645
750
|
const MARK = ".aparte-subagent-transcript";
|
|
646
751
|
let holder = null;
|
|
@@ -660,6 +765,86 @@ function ensureStyles() {
|
|
|
660
765
|
document.head.appendChild(style);
|
|
661
766
|
holder = style;
|
|
662
767
|
}
|
|
768
|
+
const WORDS = {
|
|
769
|
+
/** How many tool calls a sub-agent made, on its line: "3 tools". */
|
|
770
|
+
subagentsTools: {
|
|
771
|
+
en: "one:{n} tool|other:{n} tools",
|
|
772
|
+
fr: "one:{n} outil|other:{n} outils",
|
|
773
|
+
de: "one:{n} Tool|other:{n} Tools",
|
|
774
|
+
es: "one:{n} herramienta|other:{n} herramientas",
|
|
775
|
+
it: "one:{n} strumento|other:{n} strumenti",
|
|
776
|
+
ja: "other:{n} 個のツール",
|
|
777
|
+
ko: "other:도구 {n}개",
|
|
778
|
+
pt: "one:{n} ferramenta|other:{n} ferramentas",
|
|
779
|
+
ru: "one:{n} инструмент|few:{n} инструмента|many:{n} инструментов|other:{n} инструмента",
|
|
780
|
+
zh: "other:{n} 个工具"
|
|
781
|
+
},
|
|
782
|
+
/** What a sub-agent's second line says before its first call. */
|
|
783
|
+
subagentsStarting: {
|
|
784
|
+
en: "Starting…",
|
|
785
|
+
fr: "Démarrage…",
|
|
786
|
+
de: "Wird gestartet…",
|
|
787
|
+
es: "Iniciando…",
|
|
788
|
+
it: "Avvio…",
|
|
789
|
+
ja: "開始しています…",
|
|
790
|
+
ko: "시작하는 중…",
|
|
791
|
+
pt: "Iniciando…",
|
|
792
|
+
ru: "Запуск…",
|
|
793
|
+
zh: "正在启动…"
|
|
794
|
+
},
|
|
795
|
+
/** The name of a sub-agent that was given none, when no call names its line either. */
|
|
796
|
+
subagentsUnnamed: {
|
|
797
|
+
en: "Sub-agent",
|
|
798
|
+
fr: "Sous-agent",
|
|
799
|
+
de: "Subagent",
|
|
800
|
+
es: "Subagente",
|
|
801
|
+
it: "Sottoagente",
|
|
802
|
+
ja: "サブエージェント",
|
|
803
|
+
ko: "하위 에이전트",
|
|
804
|
+
pt: "Subagente",
|
|
805
|
+
ru: "Субагент",
|
|
806
|
+
zh: "子智能体"
|
|
807
|
+
},
|
|
808
|
+
/** The Open button on a sub-agent's line (`setupSubagents({ open: 'event' })`): its name and tooltip. */
|
|
809
|
+
subagentsOpen: {
|
|
810
|
+
en: "Open {name}",
|
|
811
|
+
fr: "Ouvrir {name}",
|
|
812
|
+
de: "{name} öffnen",
|
|
813
|
+
es: "Abrir {name}",
|
|
814
|
+
it: "Apri {name}",
|
|
815
|
+
ja: "{name} を開く",
|
|
816
|
+
ko: "{name} 열기",
|
|
817
|
+
pt: "Abrir {name}",
|
|
818
|
+
ru: "Открыть: {name}",
|
|
819
|
+
zh: "打开 {name}"
|
|
820
|
+
},
|
|
821
|
+
/** The Close button of a `<aparte-subagent-view closable>`. */
|
|
822
|
+
subagentsClose: {
|
|
823
|
+
en: "Close",
|
|
824
|
+
fr: "Fermer",
|
|
825
|
+
de: "Schließen",
|
|
826
|
+
es: "Cerrar",
|
|
827
|
+
it: "Chiudi",
|
|
828
|
+
ja: "閉じる",
|
|
829
|
+
ko: "닫기",
|
|
830
|
+
pt: "Fechar",
|
|
831
|
+
ru: "Закрыть",
|
|
832
|
+
zh: "关闭"
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
function languageOf(config) {
|
|
836
|
+
const tag = config.getLocale().tag;
|
|
837
|
+
return typeof tag === "string" && tag ? tag.split("-")[0].toLowerCase() : "en";
|
|
838
|
+
}
|
|
839
|
+
function word(config, key) {
|
|
840
|
+
const fromApp = config.getLocale()[key];
|
|
841
|
+
const table = WORDS[key];
|
|
842
|
+
return typeof fromApp === "string" && fromApp || table[languageOf(config)] || table.en;
|
|
843
|
+
}
|
|
844
|
+
function toolCount(config, n) {
|
|
845
|
+
const tag = config.getLocale().tag;
|
|
846
|
+
return pluralize(word(config, "subagentsTools"), n, typeof tag === "string" && tag ? tag : void 0);
|
|
847
|
+
}
|
|
663
848
|
const CONVERSATION_EVENTS = [
|
|
664
849
|
"aparte-subagent-start",
|
|
665
850
|
"aparte-subagent-end",
|
|
@@ -702,10 +887,14 @@ const ElementBase = typeof HTMLElement === "undefined" ? class {
|
|
|
702
887
|
} : HTMLElement;
|
|
703
888
|
class AparteSubagentView extends ElementBase {
|
|
704
889
|
static get observedAttributes() {
|
|
705
|
-
return ["for", "message-id", "agent-id"];
|
|
890
|
+
return ["for", "message-id", "agent-id", "closable"];
|
|
706
891
|
}
|
|
707
892
|
_chat = null;
|
|
708
893
|
_task = null;
|
|
894
|
+
/** A closable view's head: the sub-agent's name and Close. */
|
|
895
|
+
_head = null;
|
|
896
|
+
_name = null;
|
|
897
|
+
_close = null;
|
|
709
898
|
_drawing = null;
|
|
710
899
|
/** The config the rows were drawn with, and the segment they were drawn from. */
|
|
711
900
|
_config = null;
|
|
@@ -713,10 +902,20 @@ class AparteSubagentView extends ElementBase {
|
|
|
713
902
|
_listening = null;
|
|
714
903
|
_stopConfig = null;
|
|
715
904
|
_stopWatching = null;
|
|
905
|
+
_stopRenderers = null;
|
|
716
906
|
_queued = false;
|
|
717
907
|
_releaseQueued = false;
|
|
718
908
|
_warned = "";
|
|
719
909
|
_onConversation = () => this._schedule();
|
|
910
|
+
_onKeydown = (event) => {
|
|
911
|
+
if (event.key !== "Escape" || event.defaultPrevented || !this._closable()) return;
|
|
912
|
+
event.preventDefault();
|
|
913
|
+
this._emitClose();
|
|
914
|
+
};
|
|
915
|
+
/** A renderer registered or taken off on the config the rows were drawn with: the rows it changes are drawn again. */
|
|
916
|
+
_onRenderers = (config) => {
|
|
917
|
+
if (config === this._config) this.refresh();
|
|
918
|
+
};
|
|
720
919
|
_onWrite = (write) => {
|
|
721
920
|
if (fed.has(this) || !this.isConnected) return;
|
|
722
921
|
if (write.messageId !== this.getAttribute("message-id") || write.agentId !== this.getAttribute("agent-id")) return;
|
|
@@ -734,6 +933,10 @@ class AparteSubagentView extends ElementBase {
|
|
|
734
933
|
this._listen();
|
|
735
934
|
this.refresh();
|
|
736
935
|
}
|
|
936
|
+
/** Put the focus on the sub-agent's name, in a `closable` view: where a pane that just opened starts. */
|
|
937
|
+
focusTitle() {
|
|
938
|
+
if (this._name && !this._head?.hidden) this._name.focus();
|
|
939
|
+
}
|
|
737
940
|
/** Read the sub-agent again and draw it: what the element does on every change it hears. */
|
|
738
941
|
refresh() {
|
|
739
942
|
const feed = fed.get(this);
|
|
@@ -745,6 +948,8 @@ class AparteSubagentView extends ElementBase {
|
|
|
745
948
|
connectedCallback() {
|
|
746
949
|
ensureStyles();
|
|
747
950
|
this._build();
|
|
951
|
+
this.addEventListener("keydown", this._onKeydown);
|
|
952
|
+
this._stopRenderers ??= onRenderersChange(this._onRenderers);
|
|
748
953
|
if (!fed.has(this)) {
|
|
749
954
|
this._listen();
|
|
750
955
|
this._stopWatching ??= watchLaneWrites(this._onWrite);
|
|
@@ -755,11 +960,14 @@ class AparteSubagentView extends ElementBase {
|
|
|
755
960
|
this.refresh();
|
|
756
961
|
}
|
|
757
962
|
disconnectedCallback() {
|
|
963
|
+
this.removeEventListener("keydown", this._onKeydown);
|
|
758
964
|
this._unlisten();
|
|
759
965
|
this._stopWatching?.();
|
|
760
966
|
this._stopWatching = null;
|
|
761
967
|
this._stopConfig?.();
|
|
762
968
|
this._stopConfig = null;
|
|
969
|
+
this._stopRenderers?.();
|
|
970
|
+
this._stopRenderers = null;
|
|
763
971
|
if (this._releaseQueued) return;
|
|
764
972
|
this._releaseQueued = true;
|
|
765
973
|
queueMicrotask(() => {
|
|
@@ -772,6 +980,7 @@ class AparteSubagentView extends ElementBase {
|
|
|
772
980
|
if (previous === value || !this.isConnected || fed.has(this)) return;
|
|
773
981
|
if (_name === "for") this._listen();
|
|
774
982
|
this.refresh();
|
|
983
|
+
if (_name === "closable" && this._config) this._relabelHead(this._config);
|
|
775
984
|
}
|
|
776
985
|
// ── Reading the conversation ───────────────────────────────────────────
|
|
777
986
|
_source() {
|
|
@@ -809,7 +1018,8 @@ class AparteSubagentView extends ElementBase {
|
|
|
809
1018
|
} catch {
|
|
810
1019
|
return null;
|
|
811
1020
|
}
|
|
812
|
-
const
|
|
1021
|
+
const live = lastLaneWrite(messageId, agentId);
|
|
1022
|
+
const anchor = (message ? findSubagent(message.segments ?? [], agentId) : void 0) ?? (live && this._matches(live) ? live.anchor : void 0);
|
|
813
1023
|
const key = `${messageId}\0${agentId}`;
|
|
814
1024
|
if (message && !anchor && !message.isStreaming && message.status !== "pending" && message.status !== "streaming" && this._warned !== key) {
|
|
815
1025
|
this._warned = key;
|
|
@@ -844,21 +1054,64 @@ class AparteSubagentView extends ElementBase {
|
|
|
844
1054
|
}
|
|
845
1055
|
_onConfigChange() {
|
|
846
1056
|
this.refresh();
|
|
847
|
-
if (this._config)
|
|
1057
|
+
if (this._config) {
|
|
1058
|
+
this._drawing?.relabel(this._config);
|
|
1059
|
+
this._relabelHead(this._config);
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
/** A pane of its own, never a line's detail. */
|
|
1063
|
+
_closable() {
|
|
1064
|
+
return this.hasAttribute("closable") && !fed.has(this);
|
|
1065
|
+
}
|
|
1066
|
+
_emitClose() {
|
|
1067
|
+
this.dispatchEvent(new CustomEvent("aparte-subagent-view-close", { bubbles: true, composed: true }));
|
|
1068
|
+
}
|
|
1069
|
+
/** The head's words, in the chat's language: the name, and Close. */
|
|
1070
|
+
_relabelHead(config) {
|
|
1071
|
+
if (!this._head) return;
|
|
1072
|
+
const closable = this._closable();
|
|
1073
|
+
this._head.hidden = !closable;
|
|
1074
|
+
if (!closable) {
|
|
1075
|
+
this._name.textContent = "";
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1078
|
+
const name = (this._anchor ? subagentOf(this._anchor)?.name?.trim() : "") || word(config, "subagentsUnnamed");
|
|
1079
|
+
if (this._name.textContent !== name) this._name.textContent = name;
|
|
1080
|
+
const close = word(config, "subagentsClose");
|
|
1081
|
+
if (this._close.getAttribute("aria-label") !== close) {
|
|
1082
|
+
this._close.setAttribute("aria-label", close);
|
|
1083
|
+
this._close.title = close;
|
|
1084
|
+
this._close.innerHTML = config.getIcon("close");
|
|
1085
|
+
}
|
|
848
1086
|
}
|
|
849
1087
|
// ── Drawing ────────────────────────────────────────────────────────────
|
|
850
1088
|
_build() {
|
|
851
1089
|
if (this._drawing) {
|
|
852
1090
|
if (this._task.parentNode !== this) this.prepend(this._task);
|
|
1091
|
+
if (this._head.parentNode !== this) this.prepend(this._head);
|
|
853
1092
|
if (this._drawing.container.parentNode !== this) this.append(this._drawing.container);
|
|
854
1093
|
return;
|
|
855
1094
|
}
|
|
1095
|
+
const head = this.ownerDocument.createElement("div");
|
|
1096
|
+
head.className = "aparte-subagent-head";
|
|
1097
|
+
head.hidden = true;
|
|
1098
|
+
const name = this.ownerDocument.createElement("h2");
|
|
1099
|
+
name.className = "aparte-subagent-name";
|
|
1100
|
+
name.tabIndex = -1;
|
|
1101
|
+
const close = this.ownerDocument.createElement("button");
|
|
1102
|
+
close.type = "button";
|
|
1103
|
+
close.className = "aparte-btn aparte-btn--icon aparte-btn--sm aparte-subagent-close";
|
|
1104
|
+
close.addEventListener("click", () => this._emitClose());
|
|
1105
|
+
head.append(name, close);
|
|
1106
|
+
this._head = head;
|
|
1107
|
+
this._name = name;
|
|
1108
|
+
this._close = close;
|
|
856
1109
|
const task = this.ownerDocument.createElement("p");
|
|
857
1110
|
task.className = "aparte-subagent-task";
|
|
858
1111
|
task.hidden = true;
|
|
859
1112
|
const list = this.ownerDocument.createElement("div");
|
|
860
1113
|
list.className = "aparte-subagent-transcript";
|
|
861
|
-
this.append(task, list);
|
|
1114
|
+
this.append(head, task, list);
|
|
862
1115
|
this._task = task;
|
|
863
1116
|
this._drawing = new LaneDrawing(list);
|
|
864
1117
|
}
|
|
@@ -874,6 +1127,7 @@ class AparteSubagentView extends ElementBase {
|
|
|
874
1127
|
const task = (anchor ? subagentOf(anchor)?.description?.trim() : "") ?? "";
|
|
875
1128
|
if (this._task.textContent !== task) this._task.textContent = task;
|
|
876
1129
|
this._task.hidden = !task;
|
|
1130
|
+
this._relabelHead(config);
|
|
877
1131
|
const lane = anchor ? laneOf(anchor) : { segments: [], live: false };
|
|
878
1132
|
runWithConfig(config, () => drawing.sync(lane.segments, config, lane.live));
|
|
879
1133
|
}
|
|
@@ -927,66 +1181,12 @@ const subagentTranscript = (segment) => {
|
|
|
927
1181
|
feedView(view, segment, config);
|
|
928
1182
|
return view;
|
|
929
1183
|
};
|
|
930
|
-
const WORDS = {
|
|
931
|
-
/** How many tool calls a sub-agent made, on its line: "3 tools". */
|
|
932
|
-
subagentsTools: {
|
|
933
|
-
en: "one:{n} tool|other:{n} tools",
|
|
934
|
-
fr: "one:{n} outil|other:{n} outils",
|
|
935
|
-
de: "one:{n} Tool|other:{n} Tools",
|
|
936
|
-
es: "one:{n} herramienta|other:{n} herramientas",
|
|
937
|
-
it: "one:{n} strumento|other:{n} strumenti",
|
|
938
|
-
ja: "other:{n} 個のツール",
|
|
939
|
-
ko: "other:도구 {n}개",
|
|
940
|
-
pt: "one:{n} ferramenta|other:{n} ferramentas",
|
|
941
|
-
ru: "one:{n} инструмент|few:{n} инструмента|many:{n} инструментов|other:{n} инструмента",
|
|
942
|
-
zh: "other:{n} 个工具"
|
|
943
|
-
},
|
|
944
|
-
/** What a sub-agent's second line says before its first call. */
|
|
945
|
-
subagentsStarting: {
|
|
946
|
-
en: "Starting…",
|
|
947
|
-
fr: "Démarrage…",
|
|
948
|
-
de: "Wird gestartet…",
|
|
949
|
-
es: "Iniciando…",
|
|
950
|
-
it: "Avvio…",
|
|
951
|
-
ja: "開始しています…",
|
|
952
|
-
ko: "시작하는 중…",
|
|
953
|
-
pt: "Iniciando…",
|
|
954
|
-
ru: "Запуск…",
|
|
955
|
-
zh: "正在启动…"
|
|
956
|
-
},
|
|
957
|
-
/** The name of a sub-agent that was given none, when no call names its line either. */
|
|
958
|
-
subagentsUnnamed: {
|
|
959
|
-
en: "Sub-agent",
|
|
960
|
-
fr: "Sous-agent",
|
|
961
|
-
de: "Subagent",
|
|
962
|
-
es: "Subagente",
|
|
963
|
-
it: "Sottoagente",
|
|
964
|
-
ja: "サブエージェント",
|
|
965
|
-
ko: "하위 에이전트",
|
|
966
|
-
pt: "Subagente",
|
|
967
|
-
ru: "Субагент",
|
|
968
|
-
zh: "子智能体"
|
|
969
|
-
}
|
|
970
|
-
};
|
|
971
|
-
function languageOf(config) {
|
|
972
|
-
const tag = config.getLocale().tag;
|
|
973
|
-
return typeof tag === "string" && tag ? tag.split("-")[0].toLowerCase() : "en";
|
|
974
|
-
}
|
|
975
|
-
function word(config, key) {
|
|
976
|
-
const fromApp = config.getLocale()[key];
|
|
977
|
-
const table = WORDS[key];
|
|
978
|
-
return typeof fromApp === "string" && fromApp || table[languageOf(config)] || table.en;
|
|
979
|
-
}
|
|
980
|
-
function toolCount(config, n) {
|
|
981
|
-
const tag = config.getLocale().tag;
|
|
982
|
-
return pluralize(word(config, "subagentsTools"), n, typeof tag === "string" && tag ? tag : void 0);
|
|
983
|
-
}
|
|
984
1184
|
const standIns = /* @__PURE__ */ new WeakSet();
|
|
985
1185
|
function markStandIn(segment) {
|
|
986
1186
|
standIns.add(segment);
|
|
987
1187
|
return segment;
|
|
988
1188
|
}
|
|
989
|
-
const isOpenCall = (segment) => segment.type === "tool_call" && ["pending", "awaiting-approval"].includes(segment.status ?? "pending");
|
|
1189
|
+
const isOpenCall = (segment) => segment.type === "tool_call" && ["pending", "awaiting-approval"].includes(segment.status ?? "pending") && !segment.queued && segment.deferred?.reason !== "queued";
|
|
990
1190
|
const textOf = (read) => {
|
|
991
1191
|
try {
|
|
992
1192
|
const value = read();
|
|
@@ -999,12 +1199,12 @@ function callLine(call, config) {
|
|
|
999
1199
|
const name = call.toolCall?.name ?? "";
|
|
1000
1200
|
const nested = subagentOf(call);
|
|
1001
1201
|
const label = config.getToolDisplay(name)?.label;
|
|
1002
|
-
const
|
|
1202
|
+
const shown2 = (label !== void 0 ? textOf(() => typeof label === "function" ? label(call) : label) : "") || nested?.name?.trim() || name;
|
|
1003
1203
|
const summary = config.getToolSummary(name);
|
|
1004
1204
|
const target = (summary ? textOf(() => summary(call)) : "") || nested?.description?.trim() || "";
|
|
1005
|
-
return [
|
|
1205
|
+
return [shown2, target].filter(Boolean).join(" ");
|
|
1006
1206
|
}
|
|
1007
|
-
function activityOf(sub, config) {
|
|
1207
|
+
function activityOf(sub, config, step) {
|
|
1008
1208
|
let latest;
|
|
1009
1209
|
for (let i = sub.segments.length - 1; i >= 0; i -= 1) {
|
|
1010
1210
|
const segment = sub.segments[i];
|
|
@@ -1012,6 +1212,7 @@ function activityOf(sub, config) {
|
|
|
1012
1212
|
if (isOpenCall(segment)) return callLine(segment, config);
|
|
1013
1213
|
latest ??= segment;
|
|
1014
1214
|
}
|
|
1215
|
+
if (step) return step;
|
|
1015
1216
|
return latest ? callLine(latest, config) : "";
|
|
1016
1217
|
}
|
|
1017
1218
|
function durationOf(anchor, sub) {
|
|
@@ -1069,7 +1270,7 @@ function createLineProvider(options = {}) {
|
|
|
1069
1270
|
const note = [];
|
|
1070
1271
|
if (!standIn && statusOfCall(segment.status) !== status) note.push(stateWord(config, status));
|
|
1071
1272
|
if (options.activity !== false) {
|
|
1072
|
-
line.activity = live ? activityOf(sub, config) || word(config, "subagentsStarting") : summary() || stateWord(config, status);
|
|
1273
|
+
line.activity = live ? activityOf(sub, config, currentStep(segment.messageId, sub.id)) || word(config, "subagentsStarting") : summary() || stateWord(config, status);
|
|
1073
1274
|
} else if (!live) {
|
|
1074
1275
|
const done = summary();
|
|
1075
1276
|
if (done) note.push(done);
|
|
@@ -1077,6 +1278,14 @@ function createLineProvider(options = {}) {
|
|
|
1077
1278
|
if (note.length > 0) line.note = note.join(" · ");
|
|
1078
1279
|
const details = options.details;
|
|
1079
1280
|
line.details = typeof details === "function" ? details : details === "transcript" ? subagentTranscript : false;
|
|
1281
|
+
if (options.open === "event") {
|
|
1282
|
+
const shownName = name || word(config, "subagentsUnnamed");
|
|
1283
|
+
line.open = {
|
|
1284
|
+
label: word(config, "subagentsOpen").replace("{name}", () => shownName),
|
|
1285
|
+
current: isShown(segment.messageId, sub.id),
|
|
1286
|
+
onOpen: (row) => dispatchOpen(row, segment, sub, standIn)
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1080
1289
|
return line;
|
|
1081
1290
|
};
|
|
1082
1291
|
}
|
|
@@ -1153,12 +1362,108 @@ function setupSubagents(options = {}, config = aparteGlobalConfig) {
|
|
|
1153
1362
|
installed.set(config, dispose);
|
|
1154
1363
|
return dispose;
|
|
1155
1364
|
}
|
|
1365
|
+
function connectSubagentView(options) {
|
|
1366
|
+
const { chat, view, split } = options;
|
|
1367
|
+
const viewPane = options.pane ?? "end";
|
|
1368
|
+
const chatPane = viewPane === "end" ? "start" : "end";
|
|
1369
|
+
const owner = {};
|
|
1370
|
+
if (!view.chat && !view.getAttribute("for")) view.chat = chat;
|
|
1371
|
+
const wasClosable = view.hasAttribute("closable");
|
|
1372
|
+
view.setAttribute("closable", "");
|
|
1373
|
+
let opener = null;
|
|
1374
|
+
let opened = null;
|
|
1375
|
+
let isOpen2 = false;
|
|
1376
|
+
const roots = () => chat.contains(view) ? [chat] : [chat, view];
|
|
1377
|
+
const mark = (row) => {
|
|
1378
|
+
for (const root of roots()) unmarkAll(root);
|
|
1379
|
+
if (row) markRow(row, true);
|
|
1380
|
+
};
|
|
1381
|
+
const fold = () => {
|
|
1382
|
+
if (split) {
|
|
1383
|
+
split.pane = chatPane;
|
|
1384
|
+
split.single = true;
|
|
1385
|
+
}
|
|
1386
|
+
isOpen2 = false;
|
|
1387
|
+
options.onClose?.();
|
|
1388
|
+
};
|
|
1389
|
+
const onOpen = (event) => {
|
|
1390
|
+
const detail = event.detail;
|
|
1391
|
+
if (!detail?.messageId || !detail.agentId) return;
|
|
1392
|
+
const row = event.target instanceof HTMLElement ? event.target : null;
|
|
1393
|
+
opener = row;
|
|
1394
|
+
opened = detail;
|
|
1395
|
+
setShown(owner, { messageId: detail.messageId, agentId: detail.agentId });
|
|
1396
|
+
mark(row);
|
|
1397
|
+
view.setAttribute("message-id", detail.messageId);
|
|
1398
|
+
view.setAttribute("agent-id", detail.agentId);
|
|
1399
|
+
if (split) {
|
|
1400
|
+
split.single = false;
|
|
1401
|
+
split.pane = viewPane;
|
|
1402
|
+
}
|
|
1403
|
+
isOpen2 = true;
|
|
1404
|
+
options.onOpen?.(detail);
|
|
1405
|
+
view.focusTitle();
|
|
1406
|
+
};
|
|
1407
|
+
const close = (giveFocusBack) => {
|
|
1408
|
+
const active = view.ownerDocument.activeElement;
|
|
1409
|
+
const adrift = !active || active === view.ownerDocument.body || view.contains(active);
|
|
1410
|
+
setShown(owner, null);
|
|
1411
|
+
mark(null);
|
|
1412
|
+
fold();
|
|
1413
|
+
if (giveFocusBack) {
|
|
1414
|
+
const line = opener?.isConnected ? opener : lineOf(opened);
|
|
1415
|
+
const button = line ? openButtonOf(line) : null;
|
|
1416
|
+
if (button) button.focus();
|
|
1417
|
+
else if (adrift) focusComposer(chat);
|
|
1418
|
+
}
|
|
1419
|
+
opener = null;
|
|
1420
|
+
opened = null;
|
|
1421
|
+
};
|
|
1422
|
+
const lineOf = (detail) => {
|
|
1423
|
+
if (!detail) return null;
|
|
1424
|
+
const id = detail.toolCallId ?? detail.agentId;
|
|
1425
|
+
for (const root of roots()) {
|
|
1426
|
+
for (const row of root.querySelectorAll(".aparte-segment-tool-call[data-tool-call-id]")) {
|
|
1427
|
+
if (row.getAttribute("data-tool-call-id") === id && openButtonOf(row)) return row;
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
return null;
|
|
1431
|
+
};
|
|
1432
|
+
const onClose = () => close(true);
|
|
1433
|
+
const onLoaded = () => {
|
|
1434
|
+
if (isOpen2 || opened) close(false);
|
|
1435
|
+
view.removeAttribute("message-id");
|
|
1436
|
+
view.removeAttribute("agent-id");
|
|
1437
|
+
};
|
|
1438
|
+
chat.addEventListener("aparte-subagent-open", onOpen);
|
|
1439
|
+
const viewListens = !chat.contains(view);
|
|
1440
|
+
if (viewListens) view.addEventListener("aparte-subagent-open", onOpen);
|
|
1441
|
+
view.addEventListener("aparte-subagent-view-close", onClose);
|
|
1442
|
+
for (const name of ["aparte-conversation-loaded", "aparte-reset-done"]) chat.addEventListener(name, onLoaded);
|
|
1443
|
+
if (split && !view.getAttribute("agent-id")) {
|
|
1444
|
+
split.pane = chatPane;
|
|
1445
|
+
split.single = true;
|
|
1446
|
+
}
|
|
1447
|
+
return () => {
|
|
1448
|
+
chat.removeEventListener("aparte-subagent-open", onOpen);
|
|
1449
|
+
if (viewListens) view.removeEventListener("aparte-subagent-open", onOpen);
|
|
1450
|
+
view.removeEventListener("aparte-subagent-view-close", onClose);
|
|
1451
|
+
for (const name of ["aparte-conversation-loaded", "aparte-reset-done"]) chat.removeEventListener(name, onLoaded);
|
|
1452
|
+
setShown(owner, null);
|
|
1453
|
+
mark(null);
|
|
1454
|
+
if (!wasClosable) view.removeAttribute("closable");
|
|
1455
|
+
};
|
|
1456
|
+
}
|
|
1457
|
+
function focusComposer(chat) {
|
|
1458
|
+
chat.querySelector("aparte-composer-input")?.focusEnd?.();
|
|
1459
|
+
}
|
|
1156
1460
|
export {
|
|
1157
1461
|
AparteSubagentView as A,
|
|
1158
1462
|
SUBAGENT_SEGMENT_TYPE as S,
|
|
1159
1463
|
subagentOf as a,
|
|
1160
1464
|
subagentStatus as b,
|
|
1161
|
-
|
|
1465
|
+
connectSubagentView as c,
|
|
1466
|
+
subagentTranscript as d,
|
|
1162
1467
|
setupSubagents as s
|
|
1163
1468
|
};
|
|
1164
|
-
//# sourceMappingURL=
|
|
1469
|
+
//# sourceMappingURL=connect-BF7Y9tBE.js.map
|