groove-dev 0.27.171 → 0.27.174
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/node_modules/@groove-dev/cli/package.json +1 -1
- package/node_modules/@groove-dev/daemon/package.json +1 -1
- package/node_modules/@groove-dev/daemon/src/api.js +2 -0
- package/node_modules/@groove-dev/daemon/src/index.js +2 -0
- package/node_modules/@groove-dev/daemon/src/innerchat.js +100 -0
- package/node_modules/@groove-dev/daemon/src/process.js +5 -0
- package/node_modules/@groove-dev/daemon/src/providers/claude-code.js +2 -1
- package/node_modules/@groove-dev/daemon/src/routes/innerchat.js +34 -0
- package/node_modules/@groove-dev/daemon/src/validate.js +2 -2
- package/node_modules/@groove-dev/daemon/test/innerchat.test.js +203 -0
- package/node_modules/@groove-dev/gui/dist/assets/index-BvJwMNAX.css +1 -0
- package/node_modules/@groove-dev/gui/dist/assets/{index-BsCp-oqa.js → index-DZY-EWPs.js} +217 -217
- package/node_modules/@groove-dev/gui/dist/index.html +2 -2
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/node_modules/@groove-dev/gui/src/components/agents/agent-config.jsx +1 -0
- package/node_modules/@groove-dev/gui/src/components/agents/recommended-team-card.jsx +1 -1
- package/node_modules/@groove-dev/gui/src/components/chat/chat-messages.jsx +25 -1
- package/node_modules/@groove-dev/gui/src/stores/groove.js +51 -0
- package/node_modules/@groove-dev/gui/src/stores/slices/agents-slice.js +14 -0
- package/node_modules/@groove-dev/gui/src/stores/slices/ui-slice.js +9 -0
- package/node_modules/@groove-dev/gui/src/views/agents.jsx +1 -1
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/daemon/package.json +1 -1
- package/packages/daemon/src/api.js +2 -0
- package/packages/daemon/src/index.js +2 -0
- package/packages/daemon/src/innerchat.js +100 -0
- package/packages/daemon/src/process.js +5 -0
- package/packages/daemon/src/providers/claude-code.js +2 -1
- package/packages/daemon/src/routes/innerchat.js +34 -0
- package/packages/daemon/src/validate.js +2 -2
- package/packages/gui/dist/assets/index-BvJwMNAX.css +1 -0
- package/packages/gui/dist/assets/{index-BsCp-oqa.js → index-DZY-EWPs.js} +217 -217
- package/packages/gui/dist/index.html +2 -2
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/components/agents/agent-config.jsx +1 -0
- package/packages/gui/src/components/agents/recommended-team-card.jsx +1 -1
- package/packages/gui/src/components/chat/chat-messages.jsx +25 -1
- package/packages/gui/src/stores/groove.js +51 -0
- package/packages/gui/src/stores/slices/agents-slice.js +14 -0
- package/packages/gui/src/stores/slices/ui-slice.js +9 -0
- package/packages/gui/src/views/agents.jsx +1 -1
- package/node_modules/@groove-dev/gui/dist/assets/index-BrMU-6gi.css +0 -1
- package/packages/gui/dist/assets/index-BrMU-6gi.css +0 -1
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<link rel="icon" type="image/png" href="/favicon.png" />
|
|
8
8
|
<title>Groove GUI</title>
|
|
9
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
+
<script type="module" crossorigin src="/assets/index-DZY-EWPs.js"></script>
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/vendor-26L3JoZv.js">
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/assets/reactflow-DoBZjiHE.js">
|
|
12
12
|
<link rel="modulepreload" crossorigin href="/assets/codemirror-BYKpdS2W.js">
|
|
13
13
|
<link rel="modulepreload" crossorigin href="/assets/xterm--7_ns2zW.js">
|
|
14
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
14
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BvJwMNAX.css">
|
|
15
15
|
</head>
|
|
16
16
|
<body>
|
|
17
17
|
<div id="root"></div>
|
|
@@ -251,7 +251,7 @@ export function RecommendedTeamCard() {
|
|
|
251
251
|
<div className="space-y-1">
|
|
252
252
|
<label className="flex items-center gap-1 text-2xs text-text-3 font-sans"><Gauge size={10} />Effort Level</label>
|
|
253
253
|
<div className="flex bg-surface-3 rounded-md p-0.5 border border-border-subtle">
|
|
254
|
-
{[{ value: 'min', label: 'Min' }, { value: 'low', label: 'Low' }, { value: 'default', label: 'Default' }, { value: 'high', label: 'High' }, { value: 'max', label: 'Max' }].map((opt) => (
|
|
254
|
+
{[{ value: 'min', label: 'Min' }, { value: 'low', label: 'Low' }, { value: 'default', label: 'Default' }, { value: 'high', label: 'High' }, { value: 'max', label: 'Max' }, { value: 'ultra', label: 'Ultra' }].map((opt) => (
|
|
255
255
|
<button
|
|
256
256
|
key={opt.value}
|
|
257
257
|
onClick={() => handleAgentField(i, 'effort', opt.value)}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// FSL-1.1-Apache-2.0 — see LICENSE
|
|
2
2
|
import { useRef, useEffect, useState, useCallback } from 'react';
|
|
3
|
-
import { Copy, Check, ArrowRight, Download, Maximize2, X, Image as ImageIcon, RefreshCw, Loader2 } from 'lucide-react';
|
|
3
|
+
import { Copy, Check, ArrowRight, Download, Maximize2, X, Image as ImageIcon, RefreshCw, Loader2, MessageSquare } from 'lucide-react';
|
|
4
4
|
import { cn } from '../../lib/cn';
|
|
5
5
|
import { timeAgo } from '../../lib/format';
|
|
6
6
|
import { ThinkingIndicator } from '../ui/thinking-indicator';
|
|
@@ -391,6 +391,29 @@ function SystemMessage({ msg }) {
|
|
|
391
391
|
);
|
|
392
392
|
}
|
|
393
393
|
|
|
394
|
+
function InnerChatMessage({ msg }) {
|
|
395
|
+
const senderName = msg.innerchat?.fromAgent?.name || 'Agent';
|
|
396
|
+
const senderRole = msg.innerchat?.fromAgent?.role;
|
|
397
|
+
const cleanText = stripEmojis(msg.text);
|
|
398
|
+
return (
|
|
399
|
+
<div className="max-w-[85%]">
|
|
400
|
+
<div className="flex items-center gap-1.5 mb-1">
|
|
401
|
+
<MessageSquare size={11} className="text-warning" />
|
|
402
|
+
<span className="text-2xs font-sans font-medium text-warning">InnerChat</span>
|
|
403
|
+
<span className="text-2xs font-sans text-text-3">from</span>
|
|
404
|
+
<span className="text-2xs font-sans font-medium text-text-1">{senderName}</span>
|
|
405
|
+
{senderRole && <span className="text-2xs font-sans text-text-3">{senderRole}</span>}
|
|
406
|
+
</div>
|
|
407
|
+
<div className="border-l-2 border-warning/40 pl-3.5 py-1">
|
|
408
|
+
<div className="text-sm text-text-1 font-sans whitespace-pre-wrap break-words leading-relaxed">
|
|
409
|
+
<RenderedMarkdown text={cleanText} />
|
|
410
|
+
</div>
|
|
411
|
+
</div>
|
|
412
|
+
<div className="text-2xs text-text-4 font-sans mt-1">{timeAgo(msg.timestamp)}</div>
|
|
413
|
+
</div>
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
|
|
394
417
|
function StreamingCursor() {
|
|
395
418
|
return (
|
|
396
419
|
<span className="inline-block w-2 h-4 bg-accent/60 ml-0.5 animate-pulse rounded-sm" />
|
|
@@ -484,6 +507,7 @@ export function ChatMessages({ messages, isStreaming, model, mode, onImageReply,
|
|
|
484
507
|
{messages.map((msg, i) => {
|
|
485
508
|
if (msg.type === 'image-loading') return <ImageLoadingMessage key={i} msg={msg} />;
|
|
486
509
|
if (msg.type === 'image') return <ImageMessage key={i} msg={msg} onReply={onImageReply} />;
|
|
510
|
+
if (msg.from === 'innerchat') return <InnerChatMessage key={i} msg={msg} />;
|
|
487
511
|
if (msg.from === 'user') return <UserMessage key={i} msg={msg} />;
|
|
488
512
|
if (msg.from === 'system') return <SystemMessage key={i} msg={msg} />;
|
|
489
513
|
return <AssistantMessage key={i} msg={msg} model={model} role={role} />;
|
|
@@ -367,6 +367,57 @@ export const useGrooveStore = create((set, get) => ({
|
|
|
367
367
|
break;
|
|
368
368
|
}
|
|
369
369
|
|
|
370
|
+
case 'innerchat:sent': {
|
|
371
|
+
const ic = msg.data;
|
|
372
|
+
get().addChatMessage(ic.to.id, 'innerchat', ic.message, false);
|
|
373
|
+
set((s) => {
|
|
374
|
+
const icMsgs = { ...s.innerchatMessages };
|
|
375
|
+
icMsgs[ic.id] = ic;
|
|
376
|
+
persistJSON('groove:innerchatMessages', icMsgs);
|
|
377
|
+
return { innerchatMessages: icMsgs };
|
|
378
|
+
});
|
|
379
|
+
// Tag the chat message with innerchat metadata
|
|
380
|
+
set((s) => {
|
|
381
|
+
const history = { ...s.chatHistory };
|
|
382
|
+
const arr = history[ic.to.id] || [];
|
|
383
|
+
if (arr.length > 0) {
|
|
384
|
+
const last = arr[arr.length - 1];
|
|
385
|
+
if (last.from === 'innerchat' && last.text === ic.message) {
|
|
386
|
+
arr[arr.length - 1] = { ...last, innerchat: { messageId: ic.id, fromAgent: ic.from } };
|
|
387
|
+
history[ic.to.id] = arr;
|
|
388
|
+
persistJSON('groove:chatHistory', history);
|
|
389
|
+
return { chatHistory: history };
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return {};
|
|
393
|
+
});
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
case 'innerchat:response': {
|
|
398
|
+
const ic = msg.data;
|
|
399
|
+
get().addChatMessage(ic.from.id, 'innerchat', ic.response, false);
|
|
400
|
+
set((s) => {
|
|
401
|
+
const icMsgs = { ...s.innerchatMessages };
|
|
402
|
+
icMsgs[ic.id] = ic;
|
|
403
|
+
persistJSON('groove:innerchatMessages', icMsgs);
|
|
404
|
+
// Tag the response chat message with innerchat metadata
|
|
405
|
+
const history = { ...s.chatHistory };
|
|
406
|
+
const arr = history[ic.from.id] || [];
|
|
407
|
+
if (arr.length > 0) {
|
|
408
|
+
const last = arr[arr.length - 1];
|
|
409
|
+
if (last.from === 'innerchat' && last.text === ic.response) {
|
|
410
|
+
arr[arr.length - 1] = { ...last, innerchat: { messageId: ic.id, fromAgent: ic.to } };
|
|
411
|
+
history[ic.from.id] = arr;
|
|
412
|
+
persistJSON('groove:chatHistory', history);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return { innerchatMessages: icMsgs, chatHistory: history };
|
|
416
|
+
});
|
|
417
|
+
get().addToast('info', `${ic.to.name} replied to ${ic.from.name}`, 'InnerChat response received');
|
|
418
|
+
break;
|
|
419
|
+
}
|
|
420
|
+
|
|
370
421
|
case 'recommended-team:ready':
|
|
371
422
|
if (!get().recommendedTeam) get().checkRecommendedTeam();
|
|
372
423
|
break;
|
|
@@ -102,6 +102,20 @@ export const createAgentsSlice = (set, get) => ({
|
|
|
102
102
|
}
|
|
103
103
|
},
|
|
104
104
|
|
|
105
|
+
// ── InnerChat ─────────────────────────────────────────────
|
|
106
|
+
|
|
107
|
+
innerchatMessages: loadJSON('groove:innerchatMessages') || {},
|
|
108
|
+
|
|
109
|
+
async sendInnerChat(fromId, toId, message) {
|
|
110
|
+
try {
|
|
111
|
+
const msg = await api.post('/innerchat/send', { from: fromId, to: toId, message });
|
|
112
|
+
return msg;
|
|
113
|
+
} catch (err) {
|
|
114
|
+
get().addToast('error', 'InnerChat failed', err.message);
|
|
115
|
+
throw err;
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
|
|
105
119
|
// ── Chat ──────────────────────────────────────────────────
|
|
106
120
|
|
|
107
121
|
addChatMessage(agentId, from, text, isQuery = false, attachments = undefined) {
|
|
@@ -120,6 +120,15 @@ export const createUiSlice = (set, get) => ({
|
|
|
120
120
|
if (pane === 1 && agentId === null) {
|
|
121
121
|
updates.fleetSplitMode = false;
|
|
122
122
|
}
|
|
123
|
+
const primaryId = agentId || selected[0];
|
|
124
|
+
if (primaryId) {
|
|
125
|
+
const tid = get().activeTeamId;
|
|
126
|
+
const panel = { type: 'agent', agentId: primaryId };
|
|
127
|
+
updates.detailPanel = panel;
|
|
128
|
+
updates.teamDetailPanels = { ...get().teamDetailPanels, [tid]: panel };
|
|
129
|
+
} else {
|
|
130
|
+
updates.detailPanel = null;
|
|
131
|
+
}
|
|
123
132
|
set(updates);
|
|
124
133
|
},
|
|
125
134
|
fleetToggleSplit() {
|
|
@@ -1470,7 +1470,7 @@ function _RecommendedTeamCard_removed() { return null; /* extracted to component
|
|
|
1470
1470
|
<div className="space-y-1">
|
|
1471
1471
|
<label className="flex items-center gap-1 text-2xs text-text-3 font-sans"><Gauge size={10} />Effort Level</label>
|
|
1472
1472
|
<div className="flex bg-surface-3 rounded-md p-0.5 border border-border-subtle">
|
|
1473
|
-
{[{ value: 'min', label: 'Min' }, { value: 'low', label: 'Low' }, { value: 'default', label: 'Default' }, { value: 'high', label: 'High' }, { value: 'max', label: 'Max' }].map((opt) => (
|
|
1473
|
+
{[{ value: 'min', label: 'Min' }, { value: 'low', label: 'Low' }, { value: 'default', label: 'Default' }, { value: 'high', label: 'High' }, { value: 'max', label: 'Max' }, { value: 'ultra', label: 'Ultra' }].map((opt) => (
|
|
1474
1474
|
<button
|
|
1475
1475
|
key={opt.value}
|
|
1476
1476
|
onClick={() => handleAgentField(i, 'effort', opt.value)}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "groove-dev",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.174",
|
|
4
4
|
"description": "Open-source agent orchestration layer — the AI company OS. Local model agent engine (GGUF/Ollama/llama-server), HuggingFace model browser, MCP integrations (Slack, Gmail, Stripe, 15+), agent scheduling (cron), business roles (CMO, CFO, EA). GUI dashboard, multi-agent coordination, zero cold-start, infinite sessions. Works with Claude Code, Codex, Gemini CLI, Ollama, any local model.",
|
|
5
5
|
"license": "FSL-1.1-Apache-2.0",
|
|
6
6
|
"author": "Groove Dev <hello@groovedev.ai> (https://groovedev.ai)",
|
|
@@ -27,6 +27,7 @@ import { registerIntegrationRoutes } from './routes/integrations.js';
|
|
|
27
27
|
import { registerFileRoutes, resetEditorRoot } from './routes/files.js';
|
|
28
28
|
import { registerNetworkRoutes } from './routes/network.js';
|
|
29
29
|
import { registerScheduleRoutes } from './routes/schedules.js';
|
|
30
|
+
import { registerInnerChatRoutes } from './routes/innerchat.js';
|
|
30
31
|
|
|
31
32
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
32
33
|
const pkgVersion = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
|
|
@@ -175,6 +176,7 @@ export function createApi(app, daemon) {
|
|
|
175
176
|
registerFileRoutes(app, daemon);
|
|
176
177
|
registerNetworkRoutes(app, daemon);
|
|
177
178
|
registerScheduleRoutes(app, daemon);
|
|
179
|
+
registerInnerChatRoutes(app, daemon);
|
|
178
180
|
|
|
179
181
|
|
|
180
182
|
// Token usage
|
|
@@ -46,6 +46,7 @@ import { MLXServerManager } from './mlx-server.js';
|
|
|
46
46
|
import { RepoImporter } from './repo-import.js';
|
|
47
47
|
import { ConversationManager } from './conversations.js';
|
|
48
48
|
import { Toys } from './toys.js';
|
|
49
|
+
import { InnerChat } from './innerchat.js';
|
|
49
50
|
import { TrajectoryCapture, ConsentManager } from '../../../moe-training/client/index.js';
|
|
50
51
|
import { isFirstRun, runFirstTimeSetup, loadConfig, saveConfig, printWelcome } from './firstrun.js';
|
|
51
52
|
import { bindDaemon as bindGrooveNetworkDaemon } from './providers/groove-network.js';
|
|
@@ -158,6 +159,7 @@ export class Daemon {
|
|
|
158
159
|
this.repoImporter = new RepoImporter(this);
|
|
159
160
|
this.modelLab = new ModelLab(this);
|
|
160
161
|
this.toys = new Toys(this);
|
|
162
|
+
this.innerchat = new InnerChat(this);
|
|
161
163
|
this.trajectoryCapture = null;
|
|
162
164
|
|
|
163
165
|
// Hook teams.delete to clean up agent-loop session files
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// FSL-1.1-Apache-2.0 — see LICENSE
|
|
2
|
+
|
|
3
|
+
import { randomUUID } from 'crypto';
|
|
4
|
+
|
|
5
|
+
export class InnerChat {
|
|
6
|
+
constructor(daemon) {
|
|
7
|
+
this.daemon = daemon;
|
|
8
|
+
this.messages = new Map();
|
|
9
|
+
this.pendingResponses = new Map();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async send(fromAgentId, toAgentId, message) {
|
|
13
|
+
const fromAgent = this.daemon.registry.get(fromAgentId);
|
|
14
|
+
const toAgent = this.daemon.registry.get(toAgentId);
|
|
15
|
+
if (!fromAgent) throw new Error(`Sender agent ${fromAgentId} not found`);
|
|
16
|
+
if (!toAgent) throw new Error(`Target agent ${toAgentId} not found`);
|
|
17
|
+
|
|
18
|
+
const id = randomUUID().slice(0, 12);
|
|
19
|
+
const msg = {
|
|
20
|
+
id,
|
|
21
|
+
from: { id: fromAgent.id, name: fromAgent.name, role: fromAgent.role },
|
|
22
|
+
to: { id: toAgent.id, name: toAgent.name, role: toAgent.role },
|
|
23
|
+
message,
|
|
24
|
+
response: null,
|
|
25
|
+
status: 'sent',
|
|
26
|
+
timestamp: Date.now(),
|
|
27
|
+
respondedAt: null,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
this.messages.set(id, msg);
|
|
31
|
+
this.pendingResponses.set(toAgentId, id);
|
|
32
|
+
|
|
33
|
+
const wrapped = `[InnerChat from ${fromAgent.name} (${fromAgent.role})]\n\n${message}\n\nReply normally — your response will be relayed back to ${fromAgent.name}.`;
|
|
34
|
+
|
|
35
|
+
let deliveryStatus = 'sent';
|
|
36
|
+
if (this.daemon.processes.hasAgentLoop(toAgentId)) {
|
|
37
|
+
const sent = await this.daemon.processes.sendMessage(toAgentId, wrapped, 'agent');
|
|
38
|
+
deliveryStatus = sent ? 'delivered' : 'queued';
|
|
39
|
+
} else if (this.daemon.processes.isRunning(toAgentId)) {
|
|
40
|
+
this.daemon.processes.queueMessage(toAgentId, wrapped);
|
|
41
|
+
deliveryStatus = 'queued';
|
|
42
|
+
} else {
|
|
43
|
+
throw new Error(`Target agent ${toAgent.name} is not running`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
msg.status = deliveryStatus;
|
|
47
|
+
this.daemon.broadcast({ type: 'innerchat:sent', data: msg });
|
|
48
|
+
this.daemon.audit.log('innerchat.send', { id, from: fromAgentId, to: toAgentId });
|
|
49
|
+
|
|
50
|
+
return msg;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
onAgentOutput(agentId, output) {
|
|
54
|
+
const messageId = this.pendingResponses.get(agentId);
|
|
55
|
+
if (!messageId) return;
|
|
56
|
+
if (output.type !== 'result') return;
|
|
57
|
+
|
|
58
|
+
const msg = this.messages.get(messageId);
|
|
59
|
+
if (!msg) return;
|
|
60
|
+
|
|
61
|
+
let responseText = '';
|
|
62
|
+
if (typeof output.data === 'string') {
|
|
63
|
+
responseText = output.data;
|
|
64
|
+
} else if (Array.isArray(output.data)) {
|
|
65
|
+
responseText = output.data.filter(b => b.type === 'text').map(b => b.text).join('\n');
|
|
66
|
+
}
|
|
67
|
+
if (!responseText.trim()) return;
|
|
68
|
+
|
|
69
|
+
msg.response = responseText.trim();
|
|
70
|
+
msg.status = 'responded';
|
|
71
|
+
msg.respondedAt = Date.now();
|
|
72
|
+
this.pendingResponses.delete(agentId);
|
|
73
|
+
|
|
74
|
+
const relay = `[InnerChat reply from ${msg.to.name} (${msg.to.role})]\n\n${msg.response}`;
|
|
75
|
+
const senderId = msg.from.id;
|
|
76
|
+
if (this.daemon.processes.hasAgentLoop(senderId)) {
|
|
77
|
+
this.daemon.processes.sendMessage(senderId, relay, 'agent').catch(() => {});
|
|
78
|
+
} else if (this.daemon.processes.isRunning(senderId)) {
|
|
79
|
+
this.daemon.processes.queueMessage(senderId, relay);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this.daemon.broadcast({ type: 'innerchat:response', data: msg });
|
|
83
|
+
this.daemon.audit.log('innerchat.response', { id: messageId, from: msg.from.id, to: msg.to.id });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
getMessages(agentId = null) {
|
|
87
|
+
const all = Array.from(this.messages.values());
|
|
88
|
+
if (!agentId) return all;
|
|
89
|
+
return all.filter(m => m.from.id === agentId || m.to.id === agentId);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
getMessage(id) {
|
|
93
|
+
return this.messages.get(id) || null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
getPending(agentId) {
|
|
97
|
+
const messageId = this.pendingResponses.get(agentId);
|
|
98
|
+
return messageId ? this.messages.get(messageId) : null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -1582,6 +1582,11 @@ For normal file edits within your scope, proceed without review.
|
|
|
1582
1582
|
|
|
1583
1583
|
registry.update(agentId, updates);
|
|
1584
1584
|
|
|
1585
|
+
// Notify innerchat for response capture
|
|
1586
|
+
if (this.daemon.innerchat) {
|
|
1587
|
+
this.daemon.innerchat.onAgentOutput(agentId, output);
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1585
1590
|
// Throttle streaming broadcasts to 4/sec per agent
|
|
1586
1591
|
const isStreaming = output.type !== 'result';
|
|
1587
1592
|
if (isStreaming) {
|
|
@@ -39,6 +39,7 @@ export class ClaudeCodeProvider extends Provider {
|
|
|
39
39
|
static authType = 'subscription';
|
|
40
40
|
static managesOwnContext = true; // Claude Code compacts context internally (~25-37% → 2-8%)
|
|
41
41
|
static models = [
|
|
42
|
+
{ id: 'claude-fable-5', name: 'Claude Fable 5', tier: 'heavy', contextWindow: 1_000_000 },
|
|
42
43
|
{ id: 'claude-opus-4-8', name: 'Claude Opus 4.8', tier: 'heavy', contextWindow: 1_000_000 },
|
|
43
44
|
{ id: 'claude-opus-4-6', name: 'Claude Opus 4.6', tier: 'heavy', contextWindow: 1_000_000 },
|
|
44
45
|
{ id: 'claude-sonnet-4-6', name: 'Claude Sonnet 4.6', tier: 'medium', contextWindow: 200_000 },
|
|
@@ -74,7 +75,7 @@ export class ClaudeCodeProvider extends Provider {
|
|
|
74
75
|
normalizeConfig(config) {
|
|
75
76
|
if (typeof config.reasoningEffort === 'number') {
|
|
76
77
|
const e = config.reasoningEffort;
|
|
77
|
-
config.effort = e <=
|
|
78
|
+
config.effort = e <= 15 ? 'none' : e <= 30 ? 'low' : e <= 50 ? 'medium' : e <= 70 ? 'high' : e <= 85 ? 'xhigh' : 'ultra';
|
|
78
79
|
}
|
|
79
80
|
return config;
|
|
80
81
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// FSL-1.1-Apache-2.0 — see LICENSE
|
|
2
|
+
|
|
3
|
+
export function registerInnerChatRoutes(app, daemon) {
|
|
4
|
+
app.post('/api/innerchat/send', async (req, res) => {
|
|
5
|
+
try {
|
|
6
|
+
const { from, to, message } = req.body;
|
|
7
|
+
if (!from || typeof from !== 'string') return res.status(400).json({ error: 'from (agent ID) is required' });
|
|
8
|
+
if (!to || typeof to !== 'string') return res.status(400).json({ error: 'to (agent ID) is required' });
|
|
9
|
+
if (!message || typeof message !== 'string' || !message.trim()) return res.status(400).json({ error: 'message is required' });
|
|
10
|
+
if (from === to) return res.status(400).json({ error: 'cannot send a message to yourself' });
|
|
11
|
+
|
|
12
|
+
const msg = await daemon.innerchat.send(from, to, message.trim());
|
|
13
|
+
res.json(msg);
|
|
14
|
+
} catch (err) {
|
|
15
|
+
res.status(400).json({ error: err.message });
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
app.get('/api/innerchat/messages', (req, res) => {
|
|
20
|
+
const { agentId } = req.query;
|
|
21
|
+
res.json({ messages: daemon.innerchat.getMessages(agentId || null) });
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
app.get('/api/innerchat/messages/:id', (req, res) => {
|
|
25
|
+
const msg = daemon.innerchat.getMessage(req.params.id);
|
|
26
|
+
if (!msg) return res.status(404).json({ error: 'Message not found' });
|
|
27
|
+
res.json(msg);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
app.get('/api/innerchat/pending/:agentId', (req, res) => {
|
|
31
|
+
const pending = daemon.innerchat.getPending(req.params.agentId);
|
|
32
|
+
res.json({ pending: pending || null });
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -112,7 +112,7 @@ export function validateAgentConfig(config) {
|
|
|
112
112
|
if (!isNaN(v) && v >= 0 && v <= 100) verbosity = Math.round(v);
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
const validEffort = ['min', 'low', 'default', 'high', 'max'];
|
|
115
|
+
const validEffort = ['min', 'low', 'default', 'high', 'max', 'ultra'];
|
|
116
116
|
const effort = validEffort.includes(config.effort) ? config.effort : undefined;
|
|
117
117
|
|
|
118
118
|
const validRouting = ['fixed', 'auto', 'auto-floor'];
|
|
@@ -227,7 +227,7 @@ export function validateGatewayConfig(config) {
|
|
|
227
227
|
};
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
-
const VALID_REASONING_EFFORTS = ['none', 'low', 'medium', 'high', 'xhigh'];
|
|
230
|
+
const VALID_REASONING_EFFORTS = ['none', 'low', 'medium', 'high', 'xhigh', 'ultra'];
|
|
231
231
|
const VALID_VERBOSITIES = ['low', 'medium'];
|
|
232
232
|
|
|
233
233
|
export function validateReasoningEffort(value) {
|