agent-relay-server 0.22.0 → 0.23.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/package.json +1 -1
- package/public/index.html +489 -332
- package/runner/src/adapter.ts +3 -0
package/package.json
CHANGED
package/public/index.html
CHANGED
|
@@ -10510,6 +10510,40 @@ function prepareForSpeech(markdown) {
|
|
|
10510
10510
|
}
|
|
10511
10511
|
//#endregion
|
|
10512
10512
|
//#region src/lib/voice.ts
|
|
10513
|
+
var KOKORO_VOICES = [
|
|
10514
|
+
{
|
|
10515
|
+
id: "am_michael",
|
|
10516
|
+
label: "Michael (US ♂)"
|
|
10517
|
+
},
|
|
10518
|
+
{
|
|
10519
|
+
id: "am_adam",
|
|
10520
|
+
label: "Adam (US ♂)"
|
|
10521
|
+
},
|
|
10522
|
+
{
|
|
10523
|
+
id: "af_heart",
|
|
10524
|
+
label: "Heart (US ♀)"
|
|
10525
|
+
},
|
|
10526
|
+
{
|
|
10527
|
+
id: "af_bella",
|
|
10528
|
+
label: "Bella (US ♀)"
|
|
10529
|
+
},
|
|
10530
|
+
{
|
|
10531
|
+
id: "af_nicole",
|
|
10532
|
+
label: "Nicole (US ♀)"
|
|
10533
|
+
},
|
|
10534
|
+
{
|
|
10535
|
+
id: "af_sarah",
|
|
10536
|
+
label: "Sarah (US ♀)"
|
|
10537
|
+
},
|
|
10538
|
+
{
|
|
10539
|
+
id: "bm_george",
|
|
10540
|
+
label: "George (UK ♂)"
|
|
10541
|
+
},
|
|
10542
|
+
{
|
|
10543
|
+
id: "bf_emma",
|
|
10544
|
+
label: "Emma (UK ♀)"
|
|
10545
|
+
}
|
|
10546
|
+
];
|
|
10513
10547
|
var MAX_CHUNK = 220;
|
|
10514
10548
|
/** Split into utterance-sized chunks (sentence boundaries; hard-split very long runs). */
|
|
10515
10549
|
function chunkForSpeech(text) {
|
|
@@ -10537,6 +10571,7 @@ var VoiceTts = class {
|
|
|
10537
10571
|
lang = "en-US";
|
|
10538
10572
|
mode = "kokoro";
|
|
10539
10573
|
kokoroVoice = "am_michael";
|
|
10574
|
+
browserVoice = "";
|
|
10540
10575
|
active = null;
|
|
10541
10576
|
queue = [];
|
|
10542
10577
|
currentChat = null;
|
|
@@ -10586,6 +10621,10 @@ var VoiceTts = class {
|
|
|
10586
10621
|
setKokoroVoice(voice) {
|
|
10587
10622
|
this.kokoroVoice = voice;
|
|
10588
10623
|
}
|
|
10624
|
+
/** Set the browser engine's voice by voiceURI. Empty = default for the language. */
|
|
10625
|
+
setBrowserVoice(uri) {
|
|
10626
|
+
this.browserVoice = uri;
|
|
10627
|
+
}
|
|
10589
10628
|
setActiveChat(chatId) {
|
|
10590
10629
|
if (chatId === this.active) return;
|
|
10591
10630
|
this.active = chatId;
|
|
@@ -10683,7 +10722,11 @@ var VoiceTts = class {
|
|
|
10683
10722
|
if (gen !== this.gen) return;
|
|
10684
10723
|
if (!synthAvailable || i >= chunks.length) return done();
|
|
10685
10724
|
const u = new SpeechSynthesisUtterance(chunks[i]);
|
|
10686
|
-
|
|
10725
|
+
const picked = this.browserVoice ? window.speechSynthesis.getVoices().find((v) => v.voiceURI === this.browserVoice) : void 0;
|
|
10726
|
+
if (picked) {
|
|
10727
|
+
u.voice = picked;
|
|
10728
|
+
u.lang = picked.lang;
|
|
10729
|
+
} else u.lang = this.lang || navigator.language || "en-US";
|
|
10687
10730
|
u.onend = () => this.speakBrowser(chunks, i + 1, gen, done);
|
|
10688
10731
|
u.onerror = () => this.speakBrowser(chunks, i + 1, gen, done);
|
|
10689
10732
|
window.speechSynthesis.speak(u);
|
|
@@ -10732,12 +10775,16 @@ var VoiceTts = class {
|
|
|
10732
10775
|
}
|
|
10733
10776
|
};
|
|
10734
10777
|
var voiceTts = new VoiceTts();
|
|
10735
|
-
/**
|
|
10736
|
-
* until the engine
|
|
10737
|
-
function
|
|
10778
|
+
/** The browser's individual speech voices ({uri, label, lang}), sorted by language
|
|
10779
|
+
* then name. May be empty until the engine loads (listen for `voiceschanged`). */
|
|
10780
|
+
function availableSpeechVoices() {
|
|
10738
10781
|
if (!synthAvailable) return [];
|
|
10739
10782
|
try {
|
|
10740
|
-
return
|
|
10783
|
+
return window.speechSynthesis.getVoices().map((v) => ({
|
|
10784
|
+
uri: v.voiceURI,
|
|
10785
|
+
label: `${v.name} (${v.lang})`,
|
|
10786
|
+
lang: v.lang
|
|
10787
|
+
})).sort((a, b) => a.lang.localeCompare(b.lang) || a.label.localeCompare(b.label));
|
|
10741
10788
|
} catch {
|
|
10742
10789
|
return [];
|
|
10743
10790
|
}
|
|
@@ -12176,6 +12223,7 @@ var useRelayStore = create$1()(persist((set, get) => ({
|
|
|
12176
12223
|
voiceTtsLang: "en-US",
|
|
12177
12224
|
voiceTtsMode: "kokoro",
|
|
12178
12225
|
voiceTtsKokoroVoice: "am_michael",
|
|
12226
|
+
voiceTtsBrowserVoice: "",
|
|
12179
12227
|
voiceInputMode: "compose",
|
|
12180
12228
|
agentSort: "status",
|
|
12181
12229
|
agentSortDir: "asc",
|
|
@@ -12220,6 +12268,8 @@ var useRelayStore = create$1()(persist((set, get) => ({
|
|
|
12220
12268
|
chatAgentHostFilter: "",
|
|
12221
12269
|
chatAgentSort: "status",
|
|
12222
12270
|
chatAgentSortDir: "asc",
|
|
12271
|
+
chatAgentGroupBy: "",
|
|
12272
|
+
chatAgentFiltersCollapsed: true,
|
|
12223
12273
|
chatStatusEvents: {},
|
|
12224
12274
|
chatStickToBottom: true,
|
|
12225
12275
|
chatHasNewItems: false,
|
|
@@ -12382,6 +12432,10 @@ var useRelayStore = create$1()(persist((set, get) => ({
|
|
|
12382
12432
|
voiceTts.setKokoroVoice(voice);
|
|
12383
12433
|
set({ voiceTtsKokoroVoice: voice });
|
|
12384
12434
|
},
|
|
12435
|
+
setVoiceTtsBrowserVoice(uri) {
|
|
12436
|
+
voiceTts.setBrowserVoice(uri);
|
|
12437
|
+
set({ voiceTtsBrowserVoice: uri });
|
|
12438
|
+
},
|
|
12385
12439
|
setVoiceInputMode(mode) {
|
|
12386
12440
|
set({ voiceInputMode: mode });
|
|
12387
12441
|
},
|
|
@@ -12398,6 +12452,7 @@ var useRelayStore = create$1()(persist((set, get) => ({
|
|
|
12398
12452
|
voiceTts.setLang(get().voiceTtsLang);
|
|
12399
12453
|
voiceTts.setMode(get().voiceTtsMode);
|
|
12400
12454
|
voiceTts.setKokoroVoice(get().voiceTtsKokoroVoice);
|
|
12455
|
+
voiceTts.setBrowserVoice(get().voiceTtsBrowserVoice);
|
|
12401
12456
|
syncVoiceActiveChat(get());
|
|
12402
12457
|
setUnauthorizedHandler(() => {
|
|
12403
12458
|
if (!get().authNeeded) set({
|
|
@@ -14520,6 +14575,7 @@ var useRelayStore = create$1()(persist((set, get) => ({
|
|
|
14520
14575
|
voiceTtsLang: state.voiceTtsLang,
|
|
14521
14576
|
voiceTtsMode: state.voiceTtsMode,
|
|
14522
14577
|
voiceTtsKokoroVoice: state.voiceTtsKokoroVoice,
|
|
14578
|
+
voiceTtsBrowserVoice: state.voiceTtsBrowserVoice,
|
|
14523
14579
|
voiceInputMode: state.voiceInputMode,
|
|
14524
14580
|
agentSort: state.agentSort,
|
|
14525
14581
|
agentSortDir: state.agentSortDir,
|
|
@@ -14538,6 +14594,8 @@ var useRelayStore = create$1()(persist((set, get) => ({
|
|
|
14538
14594
|
chatAgentHostFilter: state.chatAgentHostFilter,
|
|
14539
14595
|
chatAgentSort: state.chatAgentSort,
|
|
14540
14596
|
chatAgentSortDir: state.chatAgentSortDir,
|
|
14597
|
+
chatAgentGroupBy: state.chatAgentGroupBy,
|
|
14598
|
+
chatAgentFiltersCollapsed: state.chatAgentFiltersCollapsed,
|
|
14541
14599
|
activityFilter: state.activityFilter,
|
|
14542
14600
|
analyticsPeriod: state.analyticsPeriod,
|
|
14543
14601
|
memoryFilters: state.memoryFilters,
|
|
@@ -108818,7 +108876,7 @@ function ContextMeter({ agent }) {
|
|
|
108818
108876
|
function runtimeChips(agent) {
|
|
108819
108877
|
const spawned = isRelaySpawned(agent);
|
|
108820
108878
|
const approval = approvalMode(agent);
|
|
108821
|
-
const workspace =
|
|
108879
|
+
const workspace = agentWorkspaceMeta(agent);
|
|
108822
108880
|
return [
|
|
108823
108881
|
{
|
|
108824
108882
|
key: "origin",
|
|
@@ -108858,7 +108916,7 @@ function approvalMode(agent) {
|
|
|
108858
108916
|
className: "border-amber-500/30 bg-amber-500/10 text-amber-300"
|
|
108859
108917
|
};
|
|
108860
108918
|
}
|
|
108861
|
-
function
|
|
108919
|
+
function agentWorkspaceMeta(agent) {
|
|
108862
108920
|
const workspace = recordValue(agent.meta?.workspace);
|
|
108863
108921
|
const requested = stringValue(workspace.requestedMode) || stringValue(agent.meta?.workspaceMode);
|
|
108864
108922
|
const effective = stringValue(workspace.mode);
|
|
@@ -108868,6 +108926,7 @@ function workspaceMode(agent) {
|
|
|
108868
108926
|
label: "Isolated",
|
|
108869
108927
|
title: "Workspace: isolated worktree",
|
|
108870
108928
|
Icon: GitBranch,
|
|
108929
|
+
iconColor: "text-violet-300",
|
|
108871
108930
|
className: "border-violet-500/30 bg-violet-500/10 text-violet-300"
|
|
108872
108931
|
};
|
|
108873
108932
|
if (mode === "shared") return {
|
|
@@ -108875,6 +108934,7 @@ function workspaceMode(agent) {
|
|
|
108875
108934
|
label: "Shared",
|
|
108876
108935
|
title: "Workspace: shared repo checkout",
|
|
108877
108936
|
Icon: Share2,
|
|
108937
|
+
iconColor: "text-cyan-300",
|
|
108878
108938
|
className: "border-cyan-500/30 bg-cyan-500/10 text-cyan-300"
|
|
108879
108939
|
};
|
|
108880
108940
|
return {
|
|
@@ -108882,12 +108942,18 @@ function workspaceMode(agent) {
|
|
|
108882
108942
|
label: "Default",
|
|
108883
108943
|
title: effective ? `Workspace: default/inherit, resolved to ${effective}` : "Workspace: default/inherit",
|
|
108884
108944
|
Icon: Layers,
|
|
108945
|
+
iconColor: "text-zinc-400",
|
|
108885
108946
|
className: "border-zinc-500/30 bg-zinc-500/10 text-zinc-300"
|
|
108886
108947
|
};
|
|
108887
108948
|
}
|
|
108888
108949
|
function recordValue(value) {
|
|
108889
108950
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
108890
108951
|
}
|
|
108952
|
+
function agentProjectName(agent) {
|
|
108953
|
+
const workspace = recordValue(agent.meta?.workspace);
|
|
108954
|
+
const root = stringValue(workspace.repoRoot) || stringValue(workspace.sourceCwd) || stringValue(agent.meta?.cwd);
|
|
108955
|
+
return root ? shortPath$1(root, 2) : "";
|
|
108956
|
+
}
|
|
108891
108957
|
function runtimeBadges(agent) {
|
|
108892
108958
|
const caps = agent.providerCapabilities;
|
|
108893
108959
|
const context = agent.context;
|
|
@@ -108903,40 +108969,47 @@ function runtimeBadges(agent) {
|
|
|
108903
108969
|
if (context) badges.push(`${Math.round(context.utilization * 100)}% ctx`);
|
|
108904
108970
|
return badges;
|
|
108905
108971
|
}
|
|
108906
|
-
function ContextRing({ utilization, className }) {
|
|
108972
|
+
function ContextRing({ utilization, size = 26, className }) {
|
|
108907
108973
|
const pct = Math.round(Math.min(1, Math.max(0, utilization)) * 100);
|
|
108908
|
-
const
|
|
108974
|
+
const stroke = size >= 24 ? 3 : 2.5;
|
|
108975
|
+
const c = size / 2;
|
|
108976
|
+
const r = c - stroke;
|
|
108909
108977
|
const circumference = 2 * Math.PI * r;
|
|
108910
108978
|
const offset = circumference * (1 - Math.min(1, Math.max(0, utilization)));
|
|
108911
108979
|
const color = utilization > .8 ? "text-red-400" : utilization > .5 ? "text-yellow-400" : "text-emerald-400";
|
|
108912
108980
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
108913
108981
|
className: `relative shrink-0 ${className ?? ""}`,
|
|
108982
|
+
style: {
|
|
108983
|
+
width: size,
|
|
108984
|
+
height: size
|
|
108985
|
+
},
|
|
108914
108986
|
title: `Context: ${pct}%`,
|
|
108915
108987
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
|
|
108916
|
-
width:
|
|
108917
|
-
height:
|
|
108918
|
-
viewBox:
|
|
108988
|
+
width: size,
|
|
108989
|
+
height: size,
|
|
108990
|
+
viewBox: `0 0 ${size} ${size}`,
|
|
108919
108991
|
className: "rotate-[-90deg]",
|
|
108920
108992
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
|
|
108921
|
-
cx:
|
|
108922
|
-
cy:
|
|
108993
|
+
cx: c,
|
|
108994
|
+
cy: c,
|
|
108923
108995
|
r,
|
|
108924
108996
|
fill: "none",
|
|
108925
|
-
strokeWidth:
|
|
108997
|
+
strokeWidth: stroke,
|
|
108926
108998
|
className: "stroke-muted-foreground/20"
|
|
108927
108999
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
|
|
108928
|
-
cx:
|
|
108929
|
-
cy:
|
|
109000
|
+
cx: c,
|
|
109001
|
+
cy: c,
|
|
108930
109002
|
r,
|
|
108931
109003
|
fill: "none",
|
|
108932
|
-
strokeWidth:
|
|
109004
|
+
strokeWidth: stroke,
|
|
108933
109005
|
strokeDasharray: circumference,
|
|
108934
109006
|
strokeDashoffset: offset,
|
|
108935
109007
|
strokeLinecap: "round",
|
|
108936
109008
|
className: `${color} stroke-current transition-all duration-500`
|
|
108937
109009
|
})]
|
|
108938
109010
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
108939
|
-
className: `absolute inset-0 flex items-center justify-center
|
|
109011
|
+
className: `absolute inset-0 flex items-center justify-center font-semibold leading-none ${color}`,
|
|
109012
|
+
style: { fontSize: size >= 24 ? 8 : 7 },
|
|
108940
109013
|
children: pct
|
|
108941
109014
|
})]
|
|
108942
109015
|
});
|
|
@@ -125643,6 +125716,8 @@ function AgentListPanel({ threads, onSelectAgent }) {
|
|
|
125643
125716
|
const chatAgentTagFilter = useRelayStore((s) => s.chatAgentTagFilter);
|
|
125644
125717
|
const chatAgentCapFilter = useRelayStore((s) => s.chatAgentCapFilter);
|
|
125645
125718
|
const chatAgentHostFilter = useRelayStore((s) => s.chatAgentHostFilter);
|
|
125719
|
+
const chatAgentGroupBy = useRelayStore((s) => s.chatAgentGroupBy);
|
|
125720
|
+
const chatAgentFiltersCollapsed = useRelayStore((s) => s.chatAgentFiltersCollapsed);
|
|
125646
125721
|
const now = useNow();
|
|
125647
125722
|
const chatAgents = useChatAgents();
|
|
125648
125723
|
const threadByPeer = (0, import_react.useMemo)(() => {
|
|
@@ -125666,161 +125741,287 @@ function AgentListPanel({ threads, onSelectAgent }) {
|
|
|
125666
125741
|
const uniqueTags = (0, import_react.useMemo)(() => [...new Set(chatAgents.flatMap((a) => a.tags || []))], [chatAgents]);
|
|
125667
125742
|
const uniqueCaps = (0, import_react.useMemo)(() => [...new Set(chatAgents.flatMap((a) => userFacingCapabilities(a.capabilities || [])))], [chatAgents]);
|
|
125668
125743
|
const uniqueHosts = useUniqueHosts();
|
|
125744
|
+
const groupedAgents = (0, import_react.useMemo)(() => {
|
|
125745
|
+
if (chatAgentGroupBy !== "project") return null;
|
|
125746
|
+
const groups = /* @__PURE__ */ new Map();
|
|
125747
|
+
for (const a of sortedAgents) {
|
|
125748
|
+
const key = agentProjectName(a) || "No project";
|
|
125749
|
+
const bucket = groups.get(key);
|
|
125750
|
+
if (bucket) bucket.push(a);
|
|
125751
|
+
else groups.set(key, [a]);
|
|
125752
|
+
}
|
|
125753
|
+
return [...groups.entries()].sort((a, b) => a[0].localeCompare(b[0]));
|
|
125754
|
+
}, [sortedAgents, chatAgentGroupBy]);
|
|
125755
|
+
const activeFilterCount = [
|
|
125756
|
+
chatAgentProviderFilter,
|
|
125757
|
+
chatAgentStatusFilter,
|
|
125758
|
+
chatAgentTagFilter,
|
|
125759
|
+
chatAgentCapFilter,
|
|
125760
|
+
chatAgentHostFilter
|
|
125761
|
+
].filter(Boolean).length;
|
|
125669
125762
|
function handleSelect(id) {
|
|
125670
125763
|
openInboxThread(id, threadByPeer.get(id)?.messages);
|
|
125671
125764
|
onSelectAgent?.(id);
|
|
125672
125765
|
}
|
|
125673
|
-
|
|
125674
|
-
|
|
125675
|
-
|
|
125676
|
-
|
|
125677
|
-
|
|
125678
|
-
|
|
125679
|
-
|
|
125680
|
-
|
|
125681
|
-
|
|
125682
|
-
|
|
125683
|
-
|
|
125684
|
-
|
|
125685
|
-
|
|
125686
|
-
|
|
125687
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
125688
|
-
|
|
125689
|
-
|
|
125690
|
-
|
|
125691
|
-
|
|
125692
|
-
|
|
125766
|
+
function renderAgentRow(agent) {
|
|
125767
|
+
const thread = threadByPeer.get(agent.id);
|
|
125768
|
+
const unread = thread?.attention.unread || 0;
|
|
125769
|
+
const lastMsg = thread?.previewMessage;
|
|
125770
|
+
const lastActivityAt = threadActivityTimestamp(thread);
|
|
125771
|
+
const isSelected = selectedInboxThread === agent.id;
|
|
125772
|
+
const ws = agentWorkspaceMeta(agent);
|
|
125773
|
+
const project = agentProjectName(agent);
|
|
125774
|
+
const WsIcon = ws.Icon;
|
|
125775
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
|
|
125776
|
+
className: cn$2("w-full text-left px-3 py-2.5 flex items-start gap-2.5 hover:bg-muted/50 transition-colors border-b border-border/50", isSelected && "bg-muted/60"),
|
|
125777
|
+
onClick: () => handleSelect(agent.id),
|
|
125778
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
125779
|
+
className: "relative shrink-0 mt-0.5",
|
|
125780
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AgentTypeIcon, { agent }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusDot, {
|
|
125781
|
+
agent,
|
|
125782
|
+
now,
|
|
125783
|
+
className: "absolute -bottom-0.5 -right-0.5 w-2 h-2"
|
|
125784
|
+
})]
|
|
125785
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
125786
|
+
className: "flex-1 min-w-0",
|
|
125787
|
+
children: [
|
|
125788
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
125789
|
+
className: "flex items-center justify-between gap-1 mb-0.5",
|
|
125790
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
125791
|
+
className: "text-xs font-medium truncate",
|
|
125792
|
+
children: displayName(agent)
|
|
125793
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
125794
|
+
className: "flex items-center gap-1 shrink-0",
|
|
125795
|
+
children: [lastActivityAt > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
125796
|
+
className: "text-[10px] text-muted-foreground",
|
|
125797
|
+
title: fmtTime$1(lastActivityAt),
|
|
125798
|
+
children: timeAgo(now, lastActivityAt)
|
|
125799
|
+
}), unread > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge$1, {
|
|
125800
|
+
className: "bg-red-500 text-white text-xs min-w-[18px] h-[18px] flex items-center justify-center shrink-0 px-1",
|
|
125801
|
+
children: unread
|
|
125802
|
+
})]
|
|
125803
|
+
})]
|
|
125804
|
+
}),
|
|
125805
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
125806
|
+
className: "flex items-center gap-1.5 mb-0.5 text-[10px] text-muted-foreground",
|
|
125693
125807
|
children: [
|
|
125694
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("
|
|
125695
|
-
|
|
125696
|
-
|
|
125697
|
-
|
|
125698
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125699
|
-
value: "name",
|
|
125700
|
-
children: "By name"
|
|
125808
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
125809
|
+
title: ws.title,
|
|
125810
|
+
className: "inline-flex shrink-0",
|
|
125811
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WsIcon, { className: cn$2("h-3 w-3", ws.iconColor) })
|
|
125701
125812
|
}),
|
|
125702
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("
|
|
125703
|
-
|
|
125704
|
-
children:
|
|
125813
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
125814
|
+
className: "truncate",
|
|
125815
|
+
children: project || ws.label
|
|
125705
125816
|
}),
|
|
125706
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("
|
|
125707
|
-
|
|
125708
|
-
children:
|
|
125817
|
+
agent.context && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
125818
|
+
className: "ml-auto shrink-0",
|
|
125819
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextRing, {
|
|
125820
|
+
utilization: agent.context.utilization,
|
|
125821
|
+
size: 18
|
|
125822
|
+
})
|
|
125709
125823
|
})
|
|
125710
125824
|
]
|
|
125711
|
-
}),
|
|
125712
|
-
|
|
125713
|
-
|
|
125714
|
-
|
|
125715
|
-
|
|
125716
|
-
|
|
125717
|
-
|
|
125718
|
-
|
|
125719
|
-
|
|
125720
|
-
|
|
125721
|
-
|
|
125722
|
-
|
|
125723
|
-
|
|
125724
|
-
|
|
125825
|
+
}),
|
|
125826
|
+
lastMsg && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
|
|
125827
|
+
className: "text-xs text-muted-foreground truncate leading-tight",
|
|
125828
|
+
children: [lastMsg.from === "user" ? "You: " : "", messagePreview(lastMsg)]
|
|
125829
|
+
}),
|
|
125830
|
+
agent.status !== "offline" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
125831
|
+
className: "mt-1",
|
|
125832
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
125833
|
+
className: cn$2("text-xs", agent.status === "busy" ? "text-yellow-400" : "text-emerald-400"),
|
|
125834
|
+
children: agent.status
|
|
125835
|
+
})
|
|
125836
|
+
})
|
|
125837
|
+
]
|
|
125838
|
+
})]
|
|
125839
|
+
}) }, agent.id);
|
|
125840
|
+
}
|
|
125841
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
125842
|
+
className: "flex flex-col h-full border-r border-border min-w-0",
|
|
125843
|
+
children: [
|
|
125844
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
125845
|
+
className: "p-3 border-b border-border space-y-2",
|
|
125846
|
+
children: [
|
|
125847
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
125848
|
+
className: "relative",
|
|
125849
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Search, { className: "absolute left-2.5 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-muted-foreground pointer-events-none" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Input, {
|
|
125850
|
+
placeholder: "Search agents...",
|
|
125851
|
+
value: chatAgentSearch,
|
|
125852
|
+
onChange: (e) => set({ chatAgentSearch: e.target.value }),
|
|
125853
|
+
className: "pl-8 h-7 text-xs"
|
|
125854
|
+
})]
|
|
125855
|
+
}),
|
|
125856
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
|
|
125857
|
+
type: "button",
|
|
125858
|
+
onClick: () => set({ chatAgentFiltersCollapsed: !chatAgentFiltersCollapsed }),
|
|
125859
|
+
className: "sm:hidden flex w-full items-center justify-between h-6 px-1.5 text-xs rounded-md border border-border bg-background text-muted-foreground",
|
|
125860
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
125861
|
+
className: "inline-flex items-center gap-1.5",
|
|
125725
125862
|
children: [
|
|
125726
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("
|
|
125727
|
-
|
|
125728
|
-
|
|
125729
|
-
|
|
125730
|
-
|
|
125731
|
-
value: "claude",
|
|
125732
|
-
children: "Claude"
|
|
125733
|
-
}),
|
|
125734
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125735
|
-
value: "codex",
|
|
125736
|
-
children: "Codex"
|
|
125737
|
-
}),
|
|
125738
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125739
|
-
value: "agent",
|
|
125740
|
-
children: "Agent"
|
|
125741
|
-
}),
|
|
125742
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125743
|
-
value: "user",
|
|
125744
|
-
children: "User"
|
|
125863
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SlidersHorizontal, { className: "w-3.5 h-3.5" }),
|
|
125864
|
+
"Filters & sort",
|
|
125865
|
+
activeFilterCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge$1, {
|
|
125866
|
+
className: "bg-primary/20 text-primary text-[10px] h-4 min-w-4 px-1 flex items-center justify-center",
|
|
125867
|
+
children: activeFilterCount
|
|
125745
125868
|
})
|
|
125746
125869
|
]
|
|
125747
|
-
}),
|
|
125748
|
-
|
|
125749
|
-
|
|
125750
|
-
|
|
125751
|
-
|
|
125752
|
-
|
|
125753
|
-
|
|
125870
|
+
}), chatAgentFiltersCollapsed ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronDown, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronUp, { className: "w-3.5 h-3.5" })]
|
|
125871
|
+
}),
|
|
125872
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
125873
|
+
className: cn$2("space-y-2", chatAgentFiltersCollapsed ? "hidden" : "block", "sm:block"),
|
|
125874
|
+
children: [
|
|
125875
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
125876
|
+
className: "flex items-center gap-1.5",
|
|
125877
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
|
|
125878
|
+
value: chatAgentSort,
|
|
125879
|
+
onChange: (e) => set({ chatAgentSort: e.target.value }),
|
|
125880
|
+
className: "flex-1 h-6 text-xs rounded-md border border-border bg-background px-1.5 text-foreground",
|
|
125881
|
+
children: [
|
|
125882
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125883
|
+
value: "status",
|
|
125884
|
+
children: "By status"
|
|
125885
|
+
}),
|
|
125886
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125887
|
+
value: "name",
|
|
125888
|
+
children: "By name"
|
|
125889
|
+
}),
|
|
125890
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125891
|
+
value: "lastSeen",
|
|
125892
|
+
children: "By last seen"
|
|
125893
|
+
}),
|
|
125894
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125895
|
+
value: "lastMessage",
|
|
125896
|
+
children: "By last activity"
|
|
125897
|
+
})
|
|
125898
|
+
]
|
|
125899
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
125900
|
+
variant: "ghost",
|
|
125901
|
+
size: "icon-xs",
|
|
125902
|
+
onClick: () => set({ chatAgentSortDir: chatAgentSortDir === "asc" ? "desc" : "asc" }),
|
|
125903
|
+
children: chatAgentSortDir === "asc" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowUpNarrowWide, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowDownWideNarrow, { className: "w-3.5 h-3.5" })
|
|
125904
|
+
})]
|
|
125905
|
+
}),
|
|
125906
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
|
|
125907
|
+
value: chatAgentGroupBy,
|
|
125908
|
+
onChange: (e) => set({ chatAgentGroupBy: e.target.value }),
|
|
125909
|
+
className: "w-full h-6 text-xs rounded-md border border-border bg-background px-1.5 text-foreground",
|
|
125910
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125754
125911
|
value: "",
|
|
125755
|
-
children: "
|
|
125756
|
-
}),
|
|
125757
|
-
|
|
125758
|
-
|
|
125759
|
-
|
|
125760
|
-
|
|
125761
|
-
|
|
125762
|
-
|
|
125763
|
-
|
|
125764
|
-
|
|
125765
|
-
|
|
125766
|
-
|
|
125767
|
-
|
|
125768
|
-
|
|
125769
|
-
|
|
125770
|
-
|
|
125771
|
-
|
|
125772
|
-
|
|
125773
|
-
|
|
125774
|
-
|
|
125775
|
-
|
|
125776
|
-
|
|
125777
|
-
|
|
125778
|
-
|
|
125779
|
-
|
|
125780
|
-
|
|
125781
|
-
|
|
125782
|
-
|
|
125783
|
-
|
|
125784
|
-
|
|
125785
|
-
|
|
125786
|
-
|
|
125787
|
-
|
|
125788
|
-
|
|
125789
|
-
|
|
125790
|
-
|
|
125791
|
-
|
|
125792
|
-
|
|
125793
|
-
|
|
125794
|
-
|
|
125795
|
-
|
|
125796
|
-
|
|
125797
|
-
|
|
125798
|
-
|
|
125799
|
-
|
|
125800
|
-
|
|
125801
|
-
|
|
125802
|
-
|
|
125803
|
-
|
|
125804
|
-
|
|
125805
|
-
|
|
125806
|
-
|
|
125807
|
-
|
|
125808
|
-
|
|
125809
|
-
|
|
125810
|
-
|
|
125811
|
-
|
|
125812
|
-
|
|
125813
|
-
|
|
125814
|
-
|
|
125815
|
-
|
|
125816
|
-
|
|
125817
|
-
|
|
125818
|
-
|
|
125912
|
+
children: "No grouping"
|
|
125913
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125914
|
+
value: "project",
|
|
125915
|
+
children: "Group by project"
|
|
125916
|
+
})]
|
|
125917
|
+
}),
|
|
125918
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
125919
|
+
className: "flex gap-1",
|
|
125920
|
+
children: [
|
|
125921
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
|
|
125922
|
+
value: chatAgentProviderFilter,
|
|
125923
|
+
onChange: (e) => set({ chatAgentProviderFilter: e.target.value }),
|
|
125924
|
+
className: "flex-1 h-6 text-xs rounded-md border border-border bg-background px-1.5 text-foreground",
|
|
125925
|
+
children: [
|
|
125926
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125927
|
+
value: "",
|
|
125928
|
+
children: "All types"
|
|
125929
|
+
}),
|
|
125930
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125931
|
+
value: "claude",
|
|
125932
|
+
children: "Claude"
|
|
125933
|
+
}),
|
|
125934
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125935
|
+
value: "codex",
|
|
125936
|
+
children: "Codex"
|
|
125937
|
+
}),
|
|
125938
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125939
|
+
value: "agent",
|
|
125940
|
+
children: "Agent"
|
|
125941
|
+
}),
|
|
125942
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125943
|
+
value: "user",
|
|
125944
|
+
children: "User"
|
|
125945
|
+
})
|
|
125946
|
+
]
|
|
125947
|
+
}),
|
|
125948
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
|
|
125949
|
+
value: chatAgentStatusFilter,
|
|
125950
|
+
onChange: (e) => set({ chatAgentStatusFilter: e.target.value }),
|
|
125951
|
+
className: "flex-1 h-6 text-xs rounded-md border border-border bg-background px-1.5 text-foreground",
|
|
125952
|
+
children: [
|
|
125953
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125954
|
+
value: "",
|
|
125955
|
+
children: "All status"
|
|
125956
|
+
}),
|
|
125957
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125958
|
+
value: "online",
|
|
125959
|
+
children: "Online"
|
|
125960
|
+
}),
|
|
125961
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125962
|
+
value: "idle",
|
|
125963
|
+
children: "Idle"
|
|
125964
|
+
}),
|
|
125965
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125966
|
+
value: "busy",
|
|
125967
|
+
children: "Busy"
|
|
125968
|
+
}),
|
|
125969
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125970
|
+
value: "offline",
|
|
125971
|
+
children: "Offline"
|
|
125972
|
+
})
|
|
125973
|
+
]
|
|
125974
|
+
}),
|
|
125975
|
+
uniqueHosts.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
|
|
125976
|
+
value: chatAgentHostFilter,
|
|
125977
|
+
onChange: (e) => set({ chatAgentHostFilter: e.target.value }),
|
|
125978
|
+
className: "flex-1 h-6 text-xs rounded-md border border-border bg-background px-1.5 text-foreground",
|
|
125979
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125980
|
+
value: "",
|
|
125981
|
+
children: "All hosts"
|
|
125982
|
+
}), uniqueHosts.map((h) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125983
|
+
value: h,
|
|
125984
|
+
children: h
|
|
125985
|
+
}, h))]
|
|
125986
|
+
})
|
|
125987
|
+
]
|
|
125988
|
+
}),
|
|
125989
|
+
(uniqueTags.length > 0 || uniqueCaps.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
125990
|
+
className: "flex gap-1",
|
|
125991
|
+
children: [uniqueTags.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
|
|
125992
|
+
value: chatAgentTagFilter,
|
|
125993
|
+
onChange: (e) => set({ chatAgentTagFilter: e.target.value }),
|
|
125994
|
+
className: "flex-1 h-6 text-xs rounded-md border border-border bg-background px-1.5 text-foreground",
|
|
125995
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
125996
|
+
value: "",
|
|
125997
|
+
children: "All tags"
|
|
125998
|
+
}), uniqueTags.map((t) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("option", {
|
|
125999
|
+
value: t,
|
|
126000
|
+
children: ["#", t]
|
|
126001
|
+
}, t))]
|
|
126002
|
+
}), uniqueCaps.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
|
|
126003
|
+
value: chatAgentCapFilter,
|
|
126004
|
+
onChange: (e) => set({ chatAgentCapFilter: e.target.value }),
|
|
126005
|
+
className: "flex-1 h-6 text-xs rounded-md border border-border bg-background px-1.5 text-foreground",
|
|
126006
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
126007
|
+
value: "",
|
|
126008
|
+
children: "All caps"
|
|
126009
|
+
}), uniqueCaps.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
126010
|
+
value: c,
|
|
126011
|
+
children: c
|
|
126012
|
+
}, c))]
|
|
126013
|
+
})]
|
|
126014
|
+
})
|
|
126015
|
+
]
|
|
126016
|
+
})
|
|
126017
|
+
]
|
|
126018
|
+
}),
|
|
126019
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
|
|
125819
126020
|
type: "button",
|
|
125820
|
-
className: "flex w-full items-
|
|
126021
|
+
className: "flex w-full shrink-0 items-center gap-2.5 border-b border-border px-3 py-2 text-left transition-colors hover:bg-muted/50",
|
|
125821
126022
|
onClick: openAgentSpawn,
|
|
125822
126023
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
125823
|
-
className: "
|
|
126024
|
+
className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full border border-dashed border-primary/50 bg-primary/10 text-primary",
|
|
125824
126025
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Plus, { className: "h-3.5 w-3.5" })
|
|
125825
126026
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
125826
126027
|
className: "min-w-0 flex-1",
|
|
@@ -125828,71 +126029,31 @@ function AgentListPanel({ threads, onSelectAgent }) {
|
|
|
125828
126029
|
className: "text-xs font-medium",
|
|
125829
126030
|
children: "New Agent"
|
|
125830
126031
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
125831
|
-
className: "
|
|
126032
|
+
className: "truncate text-[10px] text-muted-foreground",
|
|
125832
126033
|
children: "Spawn a fresh chat agent"
|
|
125833
126034
|
})]
|
|
125834
126035
|
})]
|
|
125835
|
-
}),
|
|
125836
|
-
|
|
125837
|
-
|
|
125838
|
-
|
|
125839
|
-
|
|
125840
|
-
|
|
125841
|
-
|
|
125842
|
-
|
|
125843
|
-
const unread = thread?.attention.unread || 0;
|
|
125844
|
-
const lastMsg = thread?.previewMessage;
|
|
125845
|
-
const lastActivityAt = threadActivityTimestamp(thread);
|
|
125846
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
|
|
125847
|
-
className: cn$2("w-full text-left px-3 py-2.5 flex items-start gap-2.5 hover:bg-muted/50 transition-colors border-b border-border/50", selectedInboxThread === agent.id && "bg-muted/60"),
|
|
125848
|
-
onClick: () => handleSelect(agent.id),
|
|
125849
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
125850
|
-
className: "relative shrink-0 mt-0.5",
|
|
125851
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AgentTypeIcon, { agent }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusDot, {
|
|
125852
|
-
agent,
|
|
125853
|
-
now,
|
|
125854
|
-
className: "absolute -bottom-0.5 -right-0.5 w-2 h-2"
|
|
125855
|
-
})]
|
|
125856
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
125857
|
-
className: "flex-1 min-w-0",
|
|
125858
|
-
children: [
|
|
125859
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
125860
|
-
className: "flex items-center justify-between gap-1 mb-0.5",
|
|
125861
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
125862
|
-
className: "text-xs font-medium truncate",
|
|
125863
|
-
children: displayName(agent)
|
|
125864
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
125865
|
-
className: "flex items-center gap-1 shrink-0",
|
|
125866
|
-
children: [lastActivityAt > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
125867
|
-
className: "text-[10px] text-muted-foreground",
|
|
125868
|
-
title: fmtTime$1(lastActivityAt),
|
|
125869
|
-
children: timeAgo(now, lastActivityAt)
|
|
125870
|
-
}), unread > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge$1, {
|
|
125871
|
-
className: "bg-red-500 text-white text-xs min-w-[18px] h-[18px] flex items-center justify-center shrink-0 px-1",
|
|
125872
|
-
children: unread
|
|
125873
|
-
})]
|
|
125874
|
-
})]
|
|
125875
|
-
}),
|
|
125876
|
-
typeof agent.meta?.cwd === "string" && agent.meta.cwd && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
125877
|
-
className: "font-mono text-[10px] text-muted-foreground/60 truncate",
|
|
125878
|
-
children: shortPath$1(agent.meta.cwd)
|
|
125879
|
-
}),
|
|
125880
|
-
lastMsg && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", {
|
|
125881
|
-
className: "text-xs text-muted-foreground truncate leading-tight",
|
|
125882
|
-
children: [lastMsg.from === "user" ? "You: " : "", messagePreview(lastMsg)]
|
|
125883
|
-
}),
|
|
125884
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
125885
|
-
className: "flex flex-wrap gap-1 mt-1",
|
|
125886
|
-
children: agent.status !== "offline" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
125887
|
-
className: cn$2("text-xs", agent.status === "busy" ? "text-yellow-400" : agent.status === "idle" ? "text-emerald-400" : "text-emerald-400"),
|
|
125888
|
-
children: agent.status
|
|
125889
|
-
})
|
|
125890
|
-
})
|
|
125891
|
-
]
|
|
126036
|
+
}),
|
|
126037
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
126038
|
+
className: "flex-1 overflow-y-auto",
|
|
126039
|
+
children: sortedAgents.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
126040
|
+
className: "flex flex-col items-center justify-center py-10 text-center px-4",
|
|
126041
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Bot, { className: "w-8 h-8 text-zinc-600 mb-2" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
126042
|
+
className: "text-xs text-muted-foreground",
|
|
126043
|
+
children: "No agents match filters"
|
|
125892
126044
|
})]
|
|
125893
|
-
})
|
|
125894
|
-
|
|
125895
|
-
|
|
126045
|
+
}) : groupedAgents ? groupedAgents.map(([project, agents]) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
126046
|
+
className: "sticky top-0 z-10 flex items-center gap-1.5 border-b border-border/50 bg-background/95 px-3 py-1 text-[10px] font-medium uppercase tracking-wide text-muted-foreground backdrop-blur",
|
|
126047
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
126048
|
+
className: "truncate",
|
|
126049
|
+
children: project
|
|
126050
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
126051
|
+
className: "text-muted-foreground/50",
|
|
126052
|
+
children: agents.length
|
|
126053
|
+
})]
|
|
126054
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { children: agents.map(renderAgentRow) })] }, project)) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { children: sortedAgents.map(renderAgentRow) })
|
|
126055
|
+
})
|
|
126056
|
+
]
|
|
125896
126057
|
});
|
|
125897
126058
|
}
|
|
125898
126059
|
function chatTimestamp(iso) {
|
|
@@ -125952,40 +126113,6 @@ var TIMELINE_STATUS_LABELS = {
|
|
|
125952
126113
|
var TIMELINE_STATUSES = new Set(Object.keys(TIMELINE_STATUS_LABELS));
|
|
125953
126114
|
var STATUS_DEDUPE_WINDOW_MS = 3e3;
|
|
125954
126115
|
var CHAT_BOTTOM_THRESHOLD_PX = 96;
|
|
125955
|
-
var KOKORO_VOICES = [
|
|
125956
|
-
{
|
|
125957
|
-
id: "am_michael",
|
|
125958
|
-
label: "Michael (US ♂)"
|
|
125959
|
-
},
|
|
125960
|
-
{
|
|
125961
|
-
id: "am_adam",
|
|
125962
|
-
label: "Adam (US ♂)"
|
|
125963
|
-
},
|
|
125964
|
-
{
|
|
125965
|
-
id: "af_heart",
|
|
125966
|
-
label: "Heart (US ♀)"
|
|
125967
|
-
},
|
|
125968
|
-
{
|
|
125969
|
-
id: "af_bella",
|
|
125970
|
-
label: "Bella (US ♀)"
|
|
125971
|
-
},
|
|
125972
|
-
{
|
|
125973
|
-
id: "af_nicole",
|
|
125974
|
-
label: "Nicole (US ♀)"
|
|
125975
|
-
},
|
|
125976
|
-
{
|
|
125977
|
-
id: "af_sarah",
|
|
125978
|
-
label: "Sarah (US ♀)"
|
|
125979
|
-
},
|
|
125980
|
-
{
|
|
125981
|
-
id: "bm_george",
|
|
125982
|
-
label: "George (UK ♂)"
|
|
125983
|
-
},
|
|
125984
|
-
{
|
|
125985
|
-
id: "bf_emma",
|
|
125986
|
-
label: "Emma (UK ♀)"
|
|
125987
|
-
}
|
|
125988
|
-
];
|
|
125989
126116
|
function StatusMarker({ event }) {
|
|
125990
126117
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
125991
126118
|
className: "flex items-center justify-center gap-2 py-2 my-1",
|
|
@@ -127145,21 +127272,7 @@ function ChatPanel({ threads, onBack, showBackButton }) {
|
|
|
127145
127272
|
const fetchOrchestrators = useRelayStore((s) => s.fetchOrchestrators);
|
|
127146
127273
|
const voiceTtsEnabled = useRelayStore((s) => s.voiceTtsEnabled);
|
|
127147
127274
|
const setVoiceTtsEnabled = useRelayStore((s) => s.setVoiceTtsEnabled);
|
|
127148
|
-
const voiceTtsLang = useRelayStore((s) => s.voiceTtsLang);
|
|
127149
|
-
const setVoiceTtsLang = useRelayStore((s) => s.setVoiceTtsLang);
|
|
127150
|
-
const voiceTtsMode = useRelayStore((s) => s.voiceTtsMode);
|
|
127151
|
-
const setVoiceTtsMode = useRelayStore((s) => s.setVoiceTtsMode);
|
|
127152
|
-
const voiceTtsKokoroVoice = useRelayStore((s) => s.voiceTtsKokoroVoice);
|
|
127153
|
-
const setVoiceTtsKokoroVoice = useRelayStore((s) => s.setVoiceTtsKokoroVoice);
|
|
127154
127275
|
const voiceInputMode = useRelayStore((s) => s.voiceInputMode);
|
|
127155
|
-
const [speechLangs, setSpeechLangs] = (0, import_react.useState)(() => availableSpeechLangs());
|
|
127156
|
-
(0, import_react.useEffect)(() => {
|
|
127157
|
-
if (!voiceTts.available) return;
|
|
127158
|
-
const refresh = () => setSpeechLangs(availableSpeechLangs());
|
|
127159
|
-
refresh();
|
|
127160
|
-
window.speechSynthesis.addEventListener?.("voiceschanged", refresh);
|
|
127161
|
-
return () => window.speechSynthesis.removeEventListener?.("voiceschanged", refresh);
|
|
127162
|
-
}, []);
|
|
127163
127276
|
const fileInputRef = (0, import_react.useRef)(null);
|
|
127164
127277
|
const pttRecorderRef = (0, import_react.useRef)(null);
|
|
127165
127278
|
const [micState, setMicState] = (0, import_react.useState)("idle");
|
|
@@ -127583,52 +127696,11 @@ function ChatPanel({ threads, onBack, showBackButton }) {
|
|
|
127583
127696
|
voiceTts.available && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
127584
127697
|
variant: "ghost",
|
|
127585
127698
|
size: "icon-sm",
|
|
127586
|
-
title: voiceTtsEnabled ? "Speaking agent responses aloud — click to mute" : "Speak agent responses aloud (active chat)",
|
|
127699
|
+
title: voiceTtsEnabled ? "Speaking agent responses aloud — click to mute (engine & voice in Settings)" : "Speak agent responses aloud (active chat) — engine & voice in Settings",
|
|
127587
127700
|
className: voiceTtsEnabled ? "text-primary" : "",
|
|
127588
127701
|
onClick: () => setVoiceTtsEnabled(!voiceTtsEnabled),
|
|
127589
127702
|
children: voiceTtsEnabled ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Volume2, { className: "w-3.5 h-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(VolumeX, { className: "w-3.5 h-3.5" })
|
|
127590
127703
|
}),
|
|
127591
|
-
voiceTts.available && voiceTtsEnabled && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
|
|
127592
|
-
value: voiceTtsMode,
|
|
127593
|
-
onChange: (e) => setVoiceTtsMode(e.target.value),
|
|
127594
|
-
title: "Voice engine — Kokoro (server, natural) falls back to browser automatically",
|
|
127595
|
-
className: "h-7 rounded border border-border bg-background px-1 text-xs",
|
|
127596
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
127597
|
-
value: "kokoro",
|
|
127598
|
-
children: "Kokoro"
|
|
127599
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
127600
|
-
value: "browser",
|
|
127601
|
-
children: "Browser"
|
|
127602
|
-
})]
|
|
127603
|
-
}), voiceTtsMode === "kokoro" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("select", {
|
|
127604
|
-
value: voiceTtsKokoroVoice,
|
|
127605
|
-
onChange: (e) => setVoiceTtsKokoroVoice(e.target.value),
|
|
127606
|
-
title: "Kokoro voice",
|
|
127607
|
-
className: "h-7 rounded border border-border bg-background px-1 text-xs",
|
|
127608
|
-
children: [...KOKORO_VOICES, ...KOKORO_VOICES.some((v) => v.id === voiceTtsKokoroVoice) ? [] : [{
|
|
127609
|
-
id: voiceTtsKokoroVoice,
|
|
127610
|
-
label: voiceTtsKokoroVoice
|
|
127611
|
-
}]].map((v) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
127612
|
-
value: v.id,
|
|
127613
|
-
children: v.label
|
|
127614
|
-
}, v.id))
|
|
127615
|
-
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("select", {
|
|
127616
|
-
value: voiceTtsLang,
|
|
127617
|
-
onChange: (e) => setVoiceTtsLang(e.target.value),
|
|
127618
|
-
title: "Voice language",
|
|
127619
|
-
className: "h-7 rounded border border-border bg-background px-1 text-xs",
|
|
127620
|
-
children: [[...new Set([
|
|
127621
|
-
"en-US",
|
|
127622
|
-
...speechLangs,
|
|
127623
|
-
...voiceTtsLang ? [voiceTtsLang] : []
|
|
127624
|
-
])].sort().map((l) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
127625
|
-
value: l,
|
|
127626
|
-
children: l
|
|
127627
|
-
}, l)), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", {
|
|
127628
|
-
value: "",
|
|
127629
|
-
children: "Browser default"
|
|
127630
|
-
})]
|
|
127631
|
-
})] }),
|
|
127632
127704
|
canOpenTerminal && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
127633
127705
|
variant: "ghost",
|
|
127634
127706
|
size: "icon-sm",
|
|
@@ -154222,30 +154294,101 @@ function WorkspaceSettings() {
|
|
|
154222
154294
|
});
|
|
154223
154295
|
}
|
|
154224
154296
|
function VoiceSettings() {
|
|
154297
|
+
const voiceTtsEnabled = useRelayStore((s) => s.voiceTtsEnabled);
|
|
154298
|
+
const setVoiceTtsEnabled = useRelayStore((s) => s.setVoiceTtsEnabled);
|
|
154299
|
+
const voiceTtsMode = useRelayStore((s) => s.voiceTtsMode);
|
|
154300
|
+
const setVoiceTtsMode = useRelayStore((s) => s.setVoiceTtsMode);
|
|
154301
|
+
const voiceTtsKokoroVoice = useRelayStore((s) => s.voiceTtsKokoroVoice);
|
|
154302
|
+
const setVoiceTtsKokoroVoice = useRelayStore((s) => s.setVoiceTtsKokoroVoice);
|
|
154303
|
+
const voiceTtsBrowserVoice = useRelayStore((s) => s.voiceTtsBrowserVoice);
|
|
154304
|
+
const setVoiceTtsBrowserVoice = useRelayStore((s) => s.setVoiceTtsBrowserVoice);
|
|
154225
154305
|
const voiceInputMode = useRelayStore((s) => s.voiceInputMode);
|
|
154226
154306
|
const setVoiceInputMode = useRelayStore((s) => s.setVoiceInputMode);
|
|
154307
|
+
const [browserVoices, setBrowserVoices] = (0, import_react.useState)(() => availableSpeechVoices());
|
|
154308
|
+
(0, import_react.useEffect)(() => {
|
|
154309
|
+
if (typeof window === "undefined" || !("speechSynthesis" in window)) return;
|
|
154310
|
+
const refresh = () => setBrowserVoices(availableSpeechVoices());
|
|
154311
|
+
refresh();
|
|
154312
|
+
window.speechSynthesis.addEventListener?.("voiceschanged", refresh);
|
|
154313
|
+
return () => window.speechSynthesis.removeEventListener?.("voiceschanged", refresh);
|
|
154314
|
+
}, []);
|
|
154315
|
+
const kokoroOptions = KOKORO_VOICES.some((v) => v.id === voiceTtsKokoroVoice) ? KOKORO_VOICES : [...KOKORO_VOICES, {
|
|
154316
|
+
id: voiceTtsKokoroVoice,
|
|
154317
|
+
label: voiceTtsKokoroVoice
|
|
154318
|
+
}];
|
|
154227
154319
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
|
|
154228
154320
|
className: "space-y-3 rounded-lg border p-4",
|
|
154229
|
-
children: [
|
|
154230
|
-
|
|
154231
|
-
|
|
154232
|
-
|
|
154233
|
-
|
|
154234
|
-
|
|
154235
|
-
|
|
154236
|
-
|
|
154237
|
-
|
|
154238
|
-
|
|
154239
|
-
|
|
154240
|
-
|
|
154241
|
-
|
|
154242
|
-
|
|
154243
|
-
|
|
154244
|
-
|
|
154245
|
-
|
|
154246
|
-
|
|
154321
|
+
children: [
|
|
154322
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
154323
|
+
className: "flex items-center justify-between gap-2",
|
|
154324
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
154325
|
+
className: "flex items-center gap-2",
|
|
154326
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Volume2, { className: "w-4 h-4" }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", {
|
|
154327
|
+
className: "text-sm font-semibold",
|
|
154328
|
+
children: "Voice"
|
|
154329
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
154330
|
+
className: "text-xs text-muted-foreground",
|
|
154331
|
+
children: "Speak agent responses aloud in the active chat, and how push-to-talk behaves."
|
|
154332
|
+
})] })]
|
|
154333
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Switch, {
|
|
154334
|
+
checked: voiceTtsEnabled,
|
|
154335
|
+
onCheckedChange: setVoiceTtsEnabled
|
|
154336
|
+
})]
|
|
154337
|
+
}),
|
|
154338
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, {
|
|
154339
|
+
label: "Speech engine",
|
|
154340
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Select$1, {
|
|
154341
|
+
value: voiceTtsMode,
|
|
154342
|
+
onValueChange: (v) => setVoiceTtsMode(v),
|
|
154343
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectValue, {}) }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SelectContent, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
|
|
154344
|
+
value: "kokoro",
|
|
154345
|
+
children: "Kokoro (server, natural — falls back to browser)"
|
|
154346
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
|
|
154347
|
+
value: "browser",
|
|
154348
|
+
children: "Browser (Web Speech API)"
|
|
154349
|
+
})] })]
|
|
154350
|
+
})
|
|
154351
|
+
}),
|
|
154352
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, {
|
|
154353
|
+
label: "Kokoro voice",
|
|
154354
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Select$1, {
|
|
154355
|
+
value: voiceTtsKokoroVoice,
|
|
154356
|
+
onValueChange: setVoiceTtsKokoroVoice,
|
|
154357
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectValue, {}) }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectContent, { children: kokoroOptions.map((v) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
|
|
154358
|
+
value: v.id,
|
|
154359
|
+
children: v.label
|
|
154360
|
+
}, v.id)) })]
|
|
154361
|
+
})
|
|
154362
|
+
}),
|
|
154363
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, {
|
|
154364
|
+
label: "Browser voice",
|
|
154365
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Select$1, {
|
|
154366
|
+
value: voiceTtsBrowserVoice || "__default__",
|
|
154367
|
+
onValueChange: (v) => setVoiceTtsBrowserVoice(v === "__default__" ? "" : v),
|
|
154368
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectValue, {}) }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SelectContent, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
|
|
154369
|
+
value: "__default__",
|
|
154370
|
+
children: "System default"
|
|
154371
|
+
}), browserVoices.map((v) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
|
|
154372
|
+
value: v.uri,
|
|
154373
|
+
children: v.label
|
|
154374
|
+
}, v.uri))] })]
|
|
154375
|
+
})
|
|
154376
|
+
}),
|
|
154377
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, {
|
|
154378
|
+
label: "Push-to-talk input",
|
|
154379
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Select$1, {
|
|
154380
|
+
value: voiceInputMode,
|
|
154381
|
+
onValueChange: (v) => setVoiceInputMode(v),
|
|
154382
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectValue, {}) }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SelectContent, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
|
|
154383
|
+
value: "compose",
|
|
154384
|
+
children: "Fill the message box (review, then Enter)"
|
|
154385
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SelectItem, {
|
|
154386
|
+
value: "autosend",
|
|
154387
|
+
children: "Send immediately (speak-and-send)"
|
|
154388
|
+
})] })]
|
|
154389
|
+
})
|
|
154247
154390
|
})
|
|
154248
|
-
|
|
154391
|
+
]
|
|
154249
154392
|
});
|
|
154250
154393
|
}
|
|
154251
154394
|
var EFFORTS = [
|
|
@@ -159927,6 +160070,10 @@ if ("serviceWorker" in navigator) {
|
|
|
159927
160070
|
min-width: calc(var(--spacing) * 0);
|
|
159928
160071
|
}
|
|
159929
160072
|
|
|
160073
|
+
.min-w-4 {
|
|
160074
|
+
min-width: calc(var(--spacing) * 4);
|
|
160075
|
+
}
|
|
160076
|
+
|
|
159930
160077
|
.min-w-5 {
|
|
159931
160078
|
min-width: calc(var(--spacing) * 5);
|
|
159932
160079
|
}
|
|
@@ -160981,6 +161128,16 @@ if ("serviceWorker" in navigator) {
|
|
|
160981
161128
|
}
|
|
160982
161129
|
}
|
|
160983
161130
|
|
|
161131
|
+
.bg-background\/95 {
|
|
161132
|
+
background-color: var(--background);
|
|
161133
|
+
}
|
|
161134
|
+
|
|
161135
|
+
@supports (color: color-mix(in lab, red, red)) {
|
|
161136
|
+
.bg-background\/95 {
|
|
161137
|
+
background-color: color-mix(in oklab, var(--background) 95%, transparent);
|
|
161138
|
+
}
|
|
161139
|
+
}
|
|
161140
|
+
|
|
160984
161141
|
.bg-black\/0 {
|
|
160985
161142
|
background-color: #0000;
|
|
160986
161143
|
}
|
|
@@ -161851,10 +162008,6 @@ if ("serviceWorker" in navigator) {
|
|
|
161851
162008
|
font-size: .8rem;
|
|
161852
162009
|
}
|
|
161853
162010
|
|
|
161854
|
-
.text-\[8px\] {
|
|
161855
|
-
font-size: 8px;
|
|
161856
|
-
}
|
|
161857
|
-
|
|
161858
162011
|
.text-\[9px\] {
|
|
161859
162012
|
font-size: 9px;
|
|
161860
162013
|
}
|
|
@@ -163469,6 +163622,10 @@ if ("serviceWorker" in navigator) {
|
|
|
163469
163622
|
}
|
|
163470
163623
|
|
|
163471
163624
|
@media (min-width: 40rem) {
|
|
163625
|
+
.sm\:block {
|
|
163626
|
+
display: block;
|
|
163627
|
+
}
|
|
163628
|
+
|
|
163472
163629
|
.sm\:flex {
|
|
163473
163630
|
display: flex;
|
|
163474
163631
|
}
|
package/runner/src/adapter.ts
CHANGED
|
@@ -84,6 +84,9 @@ export interface RunnerSpawnConfig {
|
|
|
84
84
|
providerConfig: ProviderConfig;
|
|
85
85
|
env: Record<string, string>;
|
|
86
86
|
controlPort: number;
|
|
87
|
+
// Stage 2 (#215): the MCP endpoint the agent connects to — the runner-local proxy URL when the
|
|
88
|
+
// proxy is active. Undefined → the adapter targets the relay's MCP endpoint directly (Stage 1).
|
|
89
|
+
relayMcpEndpoint?: string;
|
|
87
90
|
monitor?: {
|
|
88
91
|
deliver(messages: Message[]): Promise<number[]>;
|
|
89
92
|
};
|