open-agents-ai 0.60.0 → 0.61.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/index.js +444 -39
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -19081,7 +19081,7 @@ var require_extension = __commonJS({
|
|
|
19081
19081
|
var require_websocket = __commonJS({
|
|
19082
19082
|
"node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket.js"(exports, module) {
|
|
19083
19083
|
"use strict";
|
|
19084
|
-
var
|
|
19084
|
+
var EventEmitter4 = __require("events");
|
|
19085
19085
|
var https = __require("https");
|
|
19086
19086
|
var http = __require("http");
|
|
19087
19087
|
var net = __require("net");
|
|
@@ -19113,7 +19113,7 @@ var require_websocket = __commonJS({
|
|
|
19113
19113
|
var protocolVersions = [8, 13];
|
|
19114
19114
|
var readyStates = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"];
|
|
19115
19115
|
var subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/;
|
|
19116
|
-
var WebSocket2 = class _WebSocket extends
|
|
19116
|
+
var WebSocket2 = class _WebSocket extends EventEmitter4 {
|
|
19117
19117
|
/**
|
|
19118
19118
|
* Create a new `WebSocket`.
|
|
19119
19119
|
*
|
|
@@ -20110,7 +20110,7 @@ var require_subprotocol = __commonJS({
|
|
|
20110
20110
|
var require_websocket_server = __commonJS({
|
|
20111
20111
|
"node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket-server.js"(exports, module) {
|
|
20112
20112
|
"use strict";
|
|
20113
|
-
var
|
|
20113
|
+
var EventEmitter4 = __require("events");
|
|
20114
20114
|
var http = __require("http");
|
|
20115
20115
|
var { Duplex } = __require("stream");
|
|
20116
20116
|
var { createHash: createHash2 } = __require("crypto");
|
|
@@ -20123,7 +20123,7 @@ var require_websocket_server = __commonJS({
|
|
|
20123
20123
|
var RUNNING = 0;
|
|
20124
20124
|
var CLOSING = 1;
|
|
20125
20125
|
var CLOSED = 2;
|
|
20126
|
-
var WebSocketServer2 = class extends
|
|
20126
|
+
var WebSocketServer2 = class extends EventEmitter4 {
|
|
20127
20127
|
/**
|
|
20128
20128
|
* Create a `WebSocketServer` instance.
|
|
20129
20129
|
*
|
|
@@ -21604,7 +21604,10 @@ function connect() {
|
|
|
21604
21604
|
ws = null;
|
|
21605
21605
|
}
|
|
21606
21606
|
const proto = location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
21607
|
-
|
|
21607
|
+
const urlParams = new URLSearchParams(location.search);
|
|
21608
|
+
const sessionKey = urlParams.get('key') || '';
|
|
21609
|
+
const keyParam = sessionKey ? '?key=' + encodeURIComponent(sessionKey) : '';
|
|
21610
|
+
ws = new WebSocket(proto + '//' + location.host + '/ws' + keyParam);
|
|
21608
21611
|
ws.binaryType = 'arraybuffer';
|
|
21609
21612
|
|
|
21610
21613
|
ws.onopen = () => {
|
|
@@ -21903,6 +21906,47 @@ var init_voice_session = __esm({
|
|
|
21903
21906
|
}
|
|
21904
21907
|
}
|
|
21905
21908
|
}
|
|
21909
|
+
/**
|
|
21910
|
+
* Send TTS audio to a specific client by clientId.
|
|
21911
|
+
*/
|
|
21912
|
+
sendAudioToClient(clientId, pcmInt16) {
|
|
21913
|
+
const ws = this.wsClients.get(clientId);
|
|
21914
|
+
if (ws) {
|
|
21915
|
+
try {
|
|
21916
|
+
if (ws.readyState === import_websocket.default.OPEN)
|
|
21917
|
+
ws.send(pcmInt16);
|
|
21918
|
+
} catch {
|
|
21919
|
+
}
|
|
21920
|
+
}
|
|
21921
|
+
}
|
|
21922
|
+
/**
|
|
21923
|
+
* Send speaking state change to a specific client.
|
|
21924
|
+
*/
|
|
21925
|
+
sendSpeakingStateToClient(clientId, speaking) {
|
|
21926
|
+
const ws = this.wsClients.get(clientId);
|
|
21927
|
+
if (ws) {
|
|
21928
|
+
const msg = JSON.stringify({ type: speaking ? "speaking_start" : "speaking_end" });
|
|
21929
|
+
try {
|
|
21930
|
+
if (ws.readyState === import_websocket.default.OPEN)
|
|
21931
|
+
ws.send(msg);
|
|
21932
|
+
} catch {
|
|
21933
|
+
}
|
|
21934
|
+
}
|
|
21935
|
+
}
|
|
21936
|
+
/**
|
|
21937
|
+
* Send a transcript message to a specific client.
|
|
21938
|
+
*/
|
|
21939
|
+
sendTranscriptToClient(clientId, speaker, text) {
|
|
21940
|
+
const ws = this.wsClients.get(clientId);
|
|
21941
|
+
if (ws) {
|
|
21942
|
+
const msg = JSON.stringify({ type: "transcript", speaker, text });
|
|
21943
|
+
try {
|
|
21944
|
+
if (ws.readyState === import_websocket.default.OPEN)
|
|
21945
|
+
ws.send(msg);
|
|
21946
|
+
} catch {
|
|
21947
|
+
}
|
|
21948
|
+
}
|
|
21949
|
+
}
|
|
21906
21950
|
/**
|
|
21907
21951
|
* Signal TTS speaking state to clients.
|
|
21908
21952
|
*/
|
|
@@ -21951,9 +21995,11 @@ var init_voice_session = __esm({
|
|
|
21951
21995
|
// ── WebSocket connection handler (using ws package) ──────────────────
|
|
21952
21996
|
handleWSConnection(ws, req) {
|
|
21953
21997
|
const clientId = `ws-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
21998
|
+
const url = new URL(req.url ?? "/", `http://localhost`);
|
|
21999
|
+
const sessionKey = url.searchParams.get("key") ?? null;
|
|
21954
22000
|
this.wsClients.set(clientId, ws);
|
|
21955
22001
|
this.state.connectedUsers.set(clientId, { username: "web-user", connectedAt: Date.now() });
|
|
21956
|
-
this.emit("userConnected", clientId, "web-user");
|
|
22002
|
+
this.emit("userConnected", clientId, "web-user", sessionKey);
|
|
21957
22003
|
this.resetIdleTimer();
|
|
21958
22004
|
const keepaliveInterval = setInterval(() => {
|
|
21959
22005
|
if (ws.readyState !== import_websocket.default.OPEN) {
|
|
@@ -22079,6 +22125,279 @@ var init_voice_session = __esm({
|
|
|
22079
22125
|
}
|
|
22080
22126
|
});
|
|
22081
22127
|
|
|
22128
|
+
// packages/cli/dist/tui/call-agent.js
|
|
22129
|
+
import { EventEmitter as EventEmitter3 } from "node:events";
|
|
22130
|
+
import crypto2 from "node:crypto";
|
|
22131
|
+
function adaptTool(tool) {
|
|
22132
|
+
return {
|
|
22133
|
+
name: tool.name,
|
|
22134
|
+
description: tool.description,
|
|
22135
|
+
parameters: tool.parameters,
|
|
22136
|
+
async execute(args) {
|
|
22137
|
+
const result = await tool.execute(args);
|
|
22138
|
+
return { success: result.success, output: result.output, error: result.error };
|
|
22139
|
+
}
|
|
22140
|
+
};
|
|
22141
|
+
}
|
|
22142
|
+
function getActivityFeed() {
|
|
22143
|
+
if (!_globalFeed)
|
|
22144
|
+
_globalFeed = new ActivityFeed();
|
|
22145
|
+
return _globalFeed;
|
|
22146
|
+
}
|
|
22147
|
+
function generateSessionKey() {
|
|
22148
|
+
return crypto2.randomBytes(16).toString("hex");
|
|
22149
|
+
}
|
|
22150
|
+
var ActivityFeed, _globalFeed, CallSubAgent;
|
|
22151
|
+
var init_call_agent = __esm({
|
|
22152
|
+
"packages/cli/dist/tui/call-agent.js"() {
|
|
22153
|
+
"use strict";
|
|
22154
|
+
init_dist5();
|
|
22155
|
+
init_dist2();
|
|
22156
|
+
ActivityFeed = class {
|
|
22157
|
+
entries = [];
|
|
22158
|
+
maxEntries = 100;
|
|
22159
|
+
push(entry) {
|
|
22160
|
+
this.entries.push(entry);
|
|
22161
|
+
if (this.entries.length > this.maxEntries) {
|
|
22162
|
+
this.entries = this.entries.slice(-this.maxEntries);
|
|
22163
|
+
}
|
|
22164
|
+
}
|
|
22165
|
+
/** Get recent activity as a text summary for sub-agent context */
|
|
22166
|
+
getSummary(maxItems = 20, verbose = false) {
|
|
22167
|
+
const recent = this.entries.slice(-maxItems);
|
|
22168
|
+
if (recent.length === 0)
|
|
22169
|
+
return "No recent activity.";
|
|
22170
|
+
return recent.map((e) => {
|
|
22171
|
+
const src = e.source === "main" ? "Agent" : "Call";
|
|
22172
|
+
const tool = e.toolName ? ` [${e.toolName}]` : "";
|
|
22173
|
+
const status = e.success !== void 0 ? e.success ? " ok" : " fail" : "";
|
|
22174
|
+
if (verbose) {
|
|
22175
|
+
return `[${new Date(e.ts).toLocaleTimeString()}] ${src}${tool}${status}: ${e.summary}`;
|
|
22176
|
+
}
|
|
22177
|
+
return `${src}${tool}${status}: ${e.summary}`;
|
|
22178
|
+
}).join("\n");
|
|
22179
|
+
}
|
|
22180
|
+
/** Get entries since a timestamp */
|
|
22181
|
+
since(ts) {
|
|
22182
|
+
return this.entries.filter((e) => e.ts > ts);
|
|
22183
|
+
}
|
|
22184
|
+
clear() {
|
|
22185
|
+
this.entries.length = 0;
|
|
22186
|
+
}
|
|
22187
|
+
};
|
|
22188
|
+
_globalFeed = null;
|
|
22189
|
+
CallSubAgent = class extends EventEmitter3 {
|
|
22190
|
+
tier;
|
|
22191
|
+
clientId;
|
|
22192
|
+
runner = null;
|
|
22193
|
+
config;
|
|
22194
|
+
repoRoot;
|
|
22195
|
+
opts;
|
|
22196
|
+
processing = false;
|
|
22197
|
+
pendingTranscripts = [];
|
|
22198
|
+
conversationHistory = [];
|
|
22199
|
+
disposed = false;
|
|
22200
|
+
constructor(clientId, opts) {
|
|
22201
|
+
super();
|
|
22202
|
+
this.clientId = clientId;
|
|
22203
|
+
this.tier = opts.tier;
|
|
22204
|
+
this.config = opts.config;
|
|
22205
|
+
this.repoRoot = opts.repoRoot;
|
|
22206
|
+
this.opts = opts;
|
|
22207
|
+
}
|
|
22208
|
+
/** Initialize the runner with appropriate tools for the access tier */
|
|
22209
|
+
async init() {
|
|
22210
|
+
const backend = new OllamaAgenticBackend(this.config.backendUrl, this.config.model, this.config.apiKey);
|
|
22211
|
+
const feed = getActivityFeed();
|
|
22212
|
+
const systemPrompt = this.buildSystemPrompt();
|
|
22213
|
+
const runnerOpts = {
|
|
22214
|
+
maxTurns: this.tier === "admin" ? 15 : 5,
|
|
22215
|
+
maxTokens: 4096,
|
|
22216
|
+
temperature: 0.3,
|
|
22217
|
+
requestTimeoutMs: 3e4,
|
|
22218
|
+
taskTimeoutMs: 12e4,
|
|
22219
|
+
modelTier: this.opts.modelTier ?? "large",
|
|
22220
|
+
contextWindowSize: this.opts.contextWindowSize,
|
|
22221
|
+
personality: this.opts.personality,
|
|
22222
|
+
streamEnabled: false,
|
|
22223
|
+
bruteForce: false,
|
|
22224
|
+
dynamicContext: systemPrompt
|
|
22225
|
+
};
|
|
22226
|
+
this.runner = new AgenticRunner(backend, runnerOpts);
|
|
22227
|
+
this.runner.setWorkingDirectory(this.repoRoot);
|
|
22228
|
+
const tools = this.buildTools();
|
|
22229
|
+
this.runner.registerTools(tools);
|
|
22230
|
+
const clientId = this.clientId;
|
|
22231
|
+
const self = this;
|
|
22232
|
+
this.runner.registerTool({
|
|
22233
|
+
name: "task_complete",
|
|
22234
|
+
description: "Call this when you have fully answered the user's question or completed their request. The summary should be your spoken response to the user.",
|
|
22235
|
+
parameters: {
|
|
22236
|
+
type: "object",
|
|
22237
|
+
properties: {
|
|
22238
|
+
summary: {
|
|
22239
|
+
type: "string",
|
|
22240
|
+
description: "Your spoken response to the user. Keep it concise and conversational \u2014 this will be spoken aloud via TTS."
|
|
22241
|
+
}
|
|
22242
|
+
},
|
|
22243
|
+
required: ["summary"]
|
|
22244
|
+
},
|
|
22245
|
+
execute: async (args) => {
|
|
22246
|
+
const summary = String(args["summary"] ?? "");
|
|
22247
|
+
self.emit("response", summary);
|
|
22248
|
+
feed.push({
|
|
22249
|
+
ts: Date.now(),
|
|
22250
|
+
source: "call",
|
|
22251
|
+
sourceId: clientId,
|
|
22252
|
+
summary: `Responded: ${summary.slice(0, 100)}`
|
|
22253
|
+
});
|
|
22254
|
+
return { success: true, output: summary };
|
|
22255
|
+
}
|
|
22256
|
+
});
|
|
22257
|
+
this.runner.onEvent((event) => {
|
|
22258
|
+
if (event.type === "tool_call") {
|
|
22259
|
+
const toolName = event.toolName ?? "unknown";
|
|
22260
|
+
const args = event.toolArgs ?? {};
|
|
22261
|
+
this.emit("toolCall", toolName, args);
|
|
22262
|
+
feed.push({
|
|
22263
|
+
ts: Date.now(),
|
|
22264
|
+
source: "call",
|
|
22265
|
+
sourceId: this.clientId,
|
|
22266
|
+
summary: `${toolName}(${Object.keys(args).join(", ")})`,
|
|
22267
|
+
toolName
|
|
22268
|
+
});
|
|
22269
|
+
}
|
|
22270
|
+
if (event.type === "tool_result") {
|
|
22271
|
+
const toolName = event.toolName ?? "unknown";
|
|
22272
|
+
const success = event.success ?? false;
|
|
22273
|
+
const content = String(event.content ?? "").slice(0, 100);
|
|
22274
|
+
this.emit("toolResult", toolName, success, content);
|
|
22275
|
+
feed.push({
|
|
22276
|
+
ts: Date.now(),
|
|
22277
|
+
source: "call",
|
|
22278
|
+
sourceId: this.clientId,
|
|
22279
|
+
summary: content,
|
|
22280
|
+
toolName,
|
|
22281
|
+
success
|
|
22282
|
+
});
|
|
22283
|
+
}
|
|
22284
|
+
if (event.type === "model_response" && event.content) {
|
|
22285
|
+
this.emit("response", event.content);
|
|
22286
|
+
}
|
|
22287
|
+
});
|
|
22288
|
+
}
|
|
22289
|
+
/** Process a voice transcript — queues if already processing */
|
|
22290
|
+
handleTranscript(text) {
|
|
22291
|
+
if (this.disposed)
|
|
22292
|
+
return;
|
|
22293
|
+
this.conversationHistory.push({ role: "user", text });
|
|
22294
|
+
if (this.processing) {
|
|
22295
|
+
this.pendingTranscripts.push(text);
|
|
22296
|
+
return;
|
|
22297
|
+
}
|
|
22298
|
+
this.processTranscript(text).catch((err) => {
|
|
22299
|
+
this.emit("error", err instanceof Error ? err : new Error(String(err)));
|
|
22300
|
+
});
|
|
22301
|
+
}
|
|
22302
|
+
/** Dispose and clean up */
|
|
22303
|
+
dispose() {
|
|
22304
|
+
this.disposed = true;
|
|
22305
|
+
this.pendingTranscripts.length = 0;
|
|
22306
|
+
this.runner = null;
|
|
22307
|
+
}
|
|
22308
|
+
// ── Private ──────────────────────────────────────────────────────────
|
|
22309
|
+
async processTranscript(text) {
|
|
22310
|
+
if (!this.runner || this.disposed)
|
|
22311
|
+
return;
|
|
22312
|
+
this.processing = true;
|
|
22313
|
+
try {
|
|
22314
|
+
const historyContext = this.conversationHistory.slice(-10).map((h) => `${h.role === "user" ? "User" : "You"}: ${h.text}`).join("\n");
|
|
22315
|
+
const feed = getActivityFeed();
|
|
22316
|
+
const activitySummary = feed.getSummary(this.tier === "admin" ? 20 : 10, this.tier === "admin");
|
|
22317
|
+
const taskPrompt = [
|
|
22318
|
+
`The user said (via voice): "${text}"`,
|
|
22319
|
+
"",
|
|
22320
|
+
"Recent conversation:",
|
|
22321
|
+
historyContext,
|
|
22322
|
+
"",
|
|
22323
|
+
"Recent agent activity:",
|
|
22324
|
+
activitySummary,
|
|
22325
|
+
"",
|
|
22326
|
+
"Respond conversationally and concisely. Your response will be spoken aloud via TTS.",
|
|
22327
|
+
"Call task_complete with your spoken response as the summary."
|
|
22328
|
+
].join("\n");
|
|
22329
|
+
const result = await this.runner.run(taskPrompt, `Working directory: ${this.repoRoot}`);
|
|
22330
|
+
if (result.summary) {
|
|
22331
|
+
this.conversationHistory.push({ role: "assistant", text: result.summary });
|
|
22332
|
+
}
|
|
22333
|
+
} catch (err) {
|
|
22334
|
+
this.emit("error", err instanceof Error ? err : new Error(String(err)));
|
|
22335
|
+
} finally {
|
|
22336
|
+
this.processing = false;
|
|
22337
|
+
this.emit("done");
|
|
22338
|
+
if (this.pendingTranscripts.length > 0) {
|
|
22339
|
+
const next = this.pendingTranscripts.shift();
|
|
22340
|
+
this.processTranscript(next).catch((err) => {
|
|
22341
|
+
this.emit("error", err instanceof Error ? err : new Error(String(err)));
|
|
22342
|
+
});
|
|
22343
|
+
}
|
|
22344
|
+
}
|
|
22345
|
+
}
|
|
22346
|
+
buildSystemPrompt() {
|
|
22347
|
+
const base = [
|
|
22348
|
+
"You are a voice assistant for an AI coding agent. Users are speaking to you through a live audio call.",
|
|
22349
|
+
"Keep responses SHORT and conversational \u2014 they will be spoken aloud via text-to-speech.",
|
|
22350
|
+
"Avoid code blocks, markdown formatting, or long technical explanations in your spoken responses.",
|
|
22351
|
+
"If the user asks about what the agent is doing, summarize the recent activity concisely."
|
|
22352
|
+
];
|
|
22353
|
+
if (this.opts.emotionContext) {
|
|
22354
|
+
base.push("", "Current emotional context:", this.opts.emotionContext);
|
|
22355
|
+
}
|
|
22356
|
+
if (this.tier === "admin") {
|
|
22357
|
+
base.push("", "This is an ADMIN call \u2014 you have full access to all tools and can execute commands, read/write files, search code, etc.", "You can take actions on behalf of the user just like the main agent.");
|
|
22358
|
+
} else {
|
|
22359
|
+
base.push("", "This is a PUBLIC call \u2014 you have read-only access. You can read files and search code but cannot modify anything.", "You can answer questions about the project and explain what the agent is working on.", "Be helpful and friendly but do not execute any write operations.");
|
|
22360
|
+
}
|
|
22361
|
+
return base.join("\n");
|
|
22362
|
+
}
|
|
22363
|
+
buildTools() {
|
|
22364
|
+
if (this.tier === "admin") {
|
|
22365
|
+
return this.buildAdminTools();
|
|
22366
|
+
}
|
|
22367
|
+
return this.buildPublicTools();
|
|
22368
|
+
}
|
|
22369
|
+
buildAdminTools() {
|
|
22370
|
+
const tools = [
|
|
22371
|
+
new FileReadTool(this.repoRoot),
|
|
22372
|
+
new FileWriteTool(this.repoRoot),
|
|
22373
|
+
new FileEditTool(this.repoRoot),
|
|
22374
|
+
new ShellTool(this.repoRoot),
|
|
22375
|
+
new GrepSearchTool(this.repoRoot),
|
|
22376
|
+
new GlobFindTool(this.repoRoot),
|
|
22377
|
+
new ListDirectoryTool(this.repoRoot),
|
|
22378
|
+
new WebSearchTool(),
|
|
22379
|
+
new WebFetchTool(),
|
|
22380
|
+
new MemoryReadTool(this.repoRoot),
|
|
22381
|
+
new MemoryWriteTool(this.repoRoot),
|
|
22382
|
+
new MemorySearchTool(this.repoRoot)
|
|
22383
|
+
];
|
|
22384
|
+
return tools.map(adaptTool);
|
|
22385
|
+
}
|
|
22386
|
+
buildPublicTools() {
|
|
22387
|
+
const tools = [
|
|
22388
|
+
new FileReadTool(this.repoRoot),
|
|
22389
|
+
new GrepSearchTool(this.repoRoot),
|
|
22390
|
+
new GlobFindTool(this.repoRoot),
|
|
22391
|
+
new ListDirectoryTool(this.repoRoot),
|
|
22392
|
+
new MemoryReadTool(this.repoRoot),
|
|
22393
|
+
new MemorySearchTool(this.repoRoot)
|
|
22394
|
+
];
|
|
22395
|
+
return tools.map(adaptTool);
|
|
22396
|
+
}
|
|
22397
|
+
};
|
|
22398
|
+
}
|
|
22399
|
+
});
|
|
22400
|
+
|
|
22082
22401
|
// packages/cli/dist/tui/model-picker.js
|
|
22083
22402
|
async function fetchOllamaModels(baseUrl) {
|
|
22084
22403
|
const url = `${normalizeBaseUrl(baseUrl)}/api/tags`;
|
|
@@ -28517,7 +28836,7 @@ ${sections.join("\n\n")}`;
|
|
|
28517
28836
|
return "";
|
|
28518
28837
|
}
|
|
28519
28838
|
}
|
|
28520
|
-
function
|
|
28839
|
+
function adaptTool2(tool) {
|
|
28521
28840
|
return {
|
|
28522
28841
|
name: tool.name,
|
|
28523
28842
|
description: tool.description,
|
|
@@ -29219,7 +29538,7 @@ After synthesis, call task_complete with the final prioritized summary.`, toolMo
|
|
|
29219
29538
|
new MemoryReadTool(this.repoRoot),
|
|
29220
29539
|
new MemorySearchTool(this.repoRoot)
|
|
29221
29540
|
];
|
|
29222
|
-
return [...tools.map(
|
|
29541
|
+
return [...tools.map(adaptTool2), taskComplete];
|
|
29223
29542
|
}
|
|
29224
29543
|
case "monitor": {
|
|
29225
29544
|
const tools = [
|
|
@@ -29229,7 +29548,7 @@ After synthesis, call task_complete with the final prioritized summary.`, toolMo
|
|
|
29229
29548
|
new AutoresearchTool(this.repoRoot)
|
|
29230
29549
|
// status-only in prompt
|
|
29231
29550
|
];
|
|
29232
|
-
return [...tools.map(
|
|
29551
|
+
return [...tools.map(adaptTool2), taskComplete];
|
|
29233
29552
|
}
|
|
29234
29553
|
case "evaluator": {
|
|
29235
29554
|
const tools = [
|
|
@@ -29241,7 +29560,7 @@ After synthesis, call task_complete with the final prioritized summary.`, toolMo
|
|
|
29241
29560
|
new MemoryWriteTool(this.repoRoot),
|
|
29242
29561
|
new GrepSearchTool(this.repoRoot)
|
|
29243
29562
|
];
|
|
29244
|
-
return [...tools.map(
|
|
29563
|
+
return [...tools.map(adaptTool2), taskComplete];
|
|
29245
29564
|
}
|
|
29246
29565
|
case "critic": {
|
|
29247
29566
|
const tools = [
|
|
@@ -29250,7 +29569,7 @@ After synthesis, call task_complete with the final prioritized summary.`, toolMo
|
|
|
29250
29569
|
new MemorySearchTool(this.repoRoot),
|
|
29251
29570
|
new GrepSearchTool(this.repoRoot)
|
|
29252
29571
|
];
|
|
29253
|
-
return [...tools.map(
|
|
29572
|
+
return [...tools.map(adaptTool2), taskComplete];
|
|
29254
29573
|
}
|
|
29255
29574
|
case "flow_maintainer": {
|
|
29256
29575
|
const tools = [
|
|
@@ -29258,7 +29577,7 @@ After synthesis, call task_complete with the final prioritized summary.`, toolMo
|
|
|
29258
29577
|
new MemoryWriteTool(this.repoRoot),
|
|
29259
29578
|
new MemorySearchTool(this.repoRoot)
|
|
29260
29579
|
];
|
|
29261
|
-
return [...tools.map(
|
|
29580
|
+
return [...tools.map(adaptTool2), taskComplete];
|
|
29262
29581
|
}
|
|
29263
29582
|
}
|
|
29264
29583
|
}
|
|
@@ -29616,7 +29935,7 @@ ${summaryResult}
|
|
|
29616
29935
|
new WebSearchTool()
|
|
29617
29936
|
];
|
|
29618
29937
|
return [
|
|
29619
|
-
...tools.map(
|
|
29938
|
+
...tools.map(adaptTool2),
|
|
29620
29939
|
this.createTaskCompleteTool()
|
|
29621
29940
|
];
|
|
29622
29941
|
}
|
|
@@ -29635,8 +29954,8 @@ ${summaryResult}
|
|
|
29635
29954
|
new DreamShellTool(this.repoRoot)
|
|
29636
29955
|
];
|
|
29637
29956
|
return [
|
|
29638
|
-
...readTools.map(
|
|
29639
|
-
...dreamWriteTools.map(
|
|
29957
|
+
...readTools.map(adaptTool2),
|
|
29958
|
+
...dreamWriteTools.map(adaptTool2),
|
|
29640
29959
|
this.createTaskCompleteTool()
|
|
29641
29960
|
];
|
|
29642
29961
|
}
|
|
@@ -30044,7 +30363,7 @@ Write consolidation insights and new reflections to memory before selecting a ta
|
|
|
30044
30363
|
The next DMN cycle (and the main agent) will benefit from anything you store now.
|
|
30045
30364
|
`;
|
|
30046
30365
|
}
|
|
30047
|
-
function
|
|
30366
|
+
function adaptTool3(tool) {
|
|
30048
30367
|
return {
|
|
30049
30368
|
name: tool.name,
|
|
30050
30369
|
description: tool.description,
|
|
@@ -30312,7 +30631,7 @@ DMN state directory: ${this.stateDir}`);
|
|
|
30312
30631
|
new WebSearchTool()
|
|
30313
30632
|
];
|
|
30314
30633
|
return [
|
|
30315
|
-
...tools.map(
|
|
30634
|
+
...tools.map(adaptTool3),
|
|
30316
30635
|
this.createTaskCompleteTool()
|
|
30317
30636
|
];
|
|
30318
30637
|
}
|
|
@@ -30587,7 +30906,7 @@ OUTPUT: Call task_complete with JSON:
|
|
|
30587
30906
|
tools.push(new MemoryWriteTool(this.repoRoot));
|
|
30588
30907
|
}
|
|
30589
30908
|
runner.registerTools([
|
|
30590
|
-
...tools.map(
|
|
30909
|
+
...tools.map(adaptTool3),
|
|
30591
30910
|
{
|
|
30592
30911
|
name: "task_complete",
|
|
30593
30912
|
description: `Signal that the ${role} analysis is complete.`,
|
|
@@ -30831,7 +31150,7 @@ function computeSparsity(entries) {
|
|
|
30831
31150
|
const avgOverlap = totalJaccard / totalPairs;
|
|
30832
31151
|
return Math.max(0, Math.min(1, 1 - avgOverlap));
|
|
30833
31152
|
}
|
|
30834
|
-
function
|
|
31153
|
+
function adaptTool4(tool) {
|
|
30835
31154
|
return {
|
|
30836
31155
|
name: tool.name,
|
|
30837
31156
|
description: tool.description,
|
|
@@ -31008,7 +31327,7 @@ Call task_complete with the JSON array when done.`, onEvent)
|
|
|
31008
31327
|
new MemorySearchTool(this.repoRoot)
|
|
31009
31328
|
];
|
|
31010
31329
|
runner.registerTools([
|
|
31011
|
-
...tools.map(
|
|
31330
|
+
...tools.map(adaptTool4),
|
|
31012
31331
|
{
|
|
31013
31332
|
name: "task_complete",
|
|
31014
31333
|
description: "Signal evaluation is complete with your scored results.",
|
|
@@ -31498,7 +31817,7 @@ function formatIntermediateState(event) {
|
|
|
31498
31817
|
}
|
|
31499
31818
|
return null;
|
|
31500
31819
|
}
|
|
31501
|
-
function
|
|
31820
|
+
function adaptTool5(tool) {
|
|
31502
31821
|
return {
|
|
31503
31822
|
name: tool.name,
|
|
31504
31823
|
description: tool.description,
|
|
@@ -32157,7 +32476,7 @@ Telegram admin: @${msg.username}` : `Telegram ${isGroup ? "group" : "public"} ch
|
|
|
32157
32476
|
new TranscribeFileTool(repoRoot),
|
|
32158
32477
|
new TranscribeUrlTool(repoRoot)
|
|
32159
32478
|
];
|
|
32160
|
-
let adaptedTools = allTools.map(
|
|
32479
|
+
let adaptedTools = allTools.map(adaptTool5);
|
|
32161
32480
|
adaptedTools = applyToolPolicy(adaptedTools, context, this.toolPolicyConfig);
|
|
32162
32481
|
if (context !== "telegram-admin-dm") {
|
|
32163
32482
|
const memWriteIdx = adaptedTools.findIndex((t) => t.name === "memory_write");
|
|
@@ -33790,7 +34109,7 @@ function getVersion() {
|
|
|
33790
34109
|
}
|
|
33791
34110
|
return "0.0.0";
|
|
33792
34111
|
}
|
|
33793
|
-
function
|
|
34112
|
+
function adaptTool6(tool) {
|
|
33794
34113
|
return {
|
|
33795
34114
|
name: tool.name,
|
|
33796
34115
|
description: tool.description,
|
|
@@ -33888,7 +34207,7 @@ function buildTools(repoRoot, config, contextWindowSize) {
|
|
|
33888
34207
|
new AgendaTool(repoRoot)
|
|
33889
34208
|
];
|
|
33890
34209
|
return [
|
|
33891
|
-
...executionTools.map(
|
|
34210
|
+
...executionTools.map(adaptTool6),
|
|
33892
34211
|
createSubAgentTool(config, repoRoot, contextWindowSize),
|
|
33893
34212
|
createTaskCompleteTool()
|
|
33894
34213
|
];
|
|
@@ -33940,7 +34259,7 @@ function createSubAgentTool(config, repoRoot, ctxWindowSize) {
|
|
|
33940
34259
|
new MemoryReadTool(repoRoot),
|
|
33941
34260
|
new MemoryWriteTool(repoRoot)
|
|
33942
34261
|
];
|
|
33943
|
-
subRunner.registerTools(subTools.map(
|
|
34262
|
+
subRunner.registerTools(subTools.map(adaptTool6));
|
|
33944
34263
|
subRunner.registerTool(createTaskCompleteTool());
|
|
33945
34264
|
if (background) {
|
|
33946
34265
|
const promise = subRunner.run(task, `Working directory: ${repoRoot}`).then((result2) => {
|
|
@@ -34176,6 +34495,13 @@ ${entry.fullContent}`
|
|
|
34176
34495
|
filesTouched.add(event.toolArgs.path);
|
|
34177
34496
|
}
|
|
34178
34497
|
}
|
|
34498
|
+
getActivityFeed().push({
|
|
34499
|
+
ts: Date.now(),
|
|
34500
|
+
source: "main",
|
|
34501
|
+
sourceId: "main",
|
|
34502
|
+
summary: `${event.toolName ?? "unknown"}(${Object.keys(event.toolArgs ?? {}).join(", ")})`,
|
|
34503
|
+
toolName: event.toolName ?? "unknown"
|
|
34504
|
+
});
|
|
34179
34505
|
lastToolCall = { name: event.toolName ?? "unknown", args: event.toolArgs ?? {} };
|
|
34180
34506
|
statusBar?.recordSpeedToolCall(event.toolName ?? "unknown");
|
|
34181
34507
|
toolCallStartMs = Date.now();
|
|
@@ -34194,6 +34520,14 @@ ${entry.fullContent}`
|
|
|
34194
34520
|
editHistory.logToolCall(lastToolCall.name, lastToolCall.args, event.success ?? false);
|
|
34195
34521
|
lastToolCall = null;
|
|
34196
34522
|
}
|
|
34523
|
+
getActivityFeed().push({
|
|
34524
|
+
ts: Date.now(),
|
|
34525
|
+
source: "main",
|
|
34526
|
+
sourceId: "main",
|
|
34527
|
+
summary: String(event.content ?? "").slice(0, 120),
|
|
34528
|
+
toolName: event.toolName ?? "unknown",
|
|
34529
|
+
success: event.success ?? false
|
|
34530
|
+
});
|
|
34197
34531
|
const resultLen = event.content?.length ?? 0;
|
|
34198
34532
|
if (resultLen > 0) {
|
|
34199
34533
|
statusBar?.recordSpeedToolResult(event.toolName ?? "unknown", resultLen);
|
|
@@ -34571,6 +34905,8 @@ async function startInteractive(config, repoPath) {
|
|
|
34571
34905
|
});
|
|
34572
34906
|
const voiceEngine = new VoiceEngine();
|
|
34573
34907
|
let voiceSession = null;
|
|
34908
|
+
let adminSessionKey = null;
|
|
34909
|
+
const callSubAgents = /* @__PURE__ */ new Map();
|
|
34574
34910
|
const streamRenderer = new StreamRenderer();
|
|
34575
34911
|
if (savedSettings.voice) {
|
|
34576
34912
|
voiceEngine.toggle().catch(() => {
|
|
@@ -35238,34 +35574,83 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
35238
35574
|
return text ? `Stopped. Last transcript: "${text}"` : "Stopped listening.";
|
|
35239
35575
|
},
|
|
35240
35576
|
// Voice call session — standalone cloudflared tunnel for /call
|
|
35241
|
-
//
|
|
35577
|
+
// Each connecting WebSocket client gets a dedicated CallSubAgent.
|
|
35578
|
+
// Admin callers (matching session key) get full tool access; public callers get read-only.
|
|
35242
35579
|
async callStart() {
|
|
35243
35580
|
if (voiceSession?.isActive) {
|
|
35244
35581
|
return voiceSession.tunnelUrl;
|
|
35245
35582
|
}
|
|
35583
|
+
if (!adminSessionKey) {
|
|
35584
|
+
adminSessionKey = generateSessionKey();
|
|
35585
|
+
}
|
|
35246
35586
|
voiceSession = new VoiceSession();
|
|
35247
|
-
const callState = {
|
|
35587
|
+
const callState = {
|
|
35588
|
+
transcribers: /* @__PURE__ */ new Map(),
|
|
35589
|
+
loading: false,
|
|
35590
|
+
sharedTranscriber: null
|
|
35591
|
+
};
|
|
35248
35592
|
const engine = getListenEngine();
|
|
35249
35593
|
voiceSession.onUserAudio = (pcmChunk, userId) => {
|
|
35250
|
-
if (callState.
|
|
35251
|
-
callState.
|
|
35594
|
+
if (callState.sharedTranscriber)
|
|
35595
|
+
callState.sharedTranscriber.write(pcmChunk);
|
|
35252
35596
|
};
|
|
35253
|
-
voiceSession.on("userConnected", (id, username) => {
|
|
35597
|
+
voiceSession.on("userConnected", (id, username, sessionKey) => {
|
|
35254
35598
|
writeContent(() => renderVoiceSessionUser("connected", username));
|
|
35255
|
-
|
|
35599
|
+
const tier = sessionKey && sessionKey === adminSessionKey ? "admin" : "public";
|
|
35600
|
+
writeContent(() => renderInfo(`Call client ${id} connected as ${tier.toUpperCase()}`));
|
|
35601
|
+
const emotionState = emotionEngine?.getState?.();
|
|
35602
|
+
const subAgent = new CallSubAgent(id, {
|
|
35603
|
+
config: currentConfig,
|
|
35604
|
+
repoRoot,
|
|
35605
|
+
tier,
|
|
35606
|
+
emotionContext: emotionState?.label ? `Current mood: ${emotionState.emoji ?? ""} ${emotionState.label}` : void 0,
|
|
35607
|
+
modelTier: getModelTier(currentConfig.model),
|
|
35608
|
+
contextWindowSize: resolvedContextWindowSize > 0 ? resolvedContextWindowSize : void 0
|
|
35609
|
+
});
|
|
35610
|
+
subAgent.on("response", (text) => {
|
|
35611
|
+
writeContent(() => renderVoiceSessionTranscript("agent", text));
|
|
35612
|
+
voiceSession?.sendTranscriptToClient(id, "agent", text);
|
|
35613
|
+
if (voiceEngine.enabled && voiceEngine.ready) {
|
|
35614
|
+
const session = voiceSession;
|
|
35615
|
+
voiceEngine.synthesizeToPCM(text).then((result) => {
|
|
35616
|
+
if (result && session?.isActive) {
|
|
35617
|
+
const { pcm, sampleRate } = result;
|
|
35618
|
+
session.sendSpeakingStateToClient(id, true);
|
|
35619
|
+
session.sendAudioToClient(id, pcm);
|
|
35620
|
+
const durationMs = pcm.length / 2 / sampleRate * 1e3;
|
|
35621
|
+
setTimeout(() => session.sendSpeakingStateToClient(id, false), durationMs);
|
|
35622
|
+
}
|
|
35623
|
+
}).catch(() => {
|
|
35624
|
+
});
|
|
35625
|
+
}
|
|
35626
|
+
});
|
|
35627
|
+
subAgent.on("error", (err) => {
|
|
35628
|
+
writeContent(() => renderWarning(`Call sub-agent error (${id}): ${err.message}`));
|
|
35629
|
+
});
|
|
35630
|
+
subAgent.init().then(() => {
|
|
35631
|
+
callSubAgents.set(id, subAgent);
|
|
35632
|
+
}).catch((err) => {
|
|
35633
|
+
writeContent(() => renderWarning(`Call sub-agent init failed (${id}): ${err instanceof Error ? err.message : String(err)}`));
|
|
35634
|
+
});
|
|
35635
|
+
if (!callState.sharedTranscriber && !callState.loading) {
|
|
35256
35636
|
callState.loading = true;
|
|
35257
35637
|
engine.createCallTranscriber().then((t) => {
|
|
35258
35638
|
if (!t || !voiceSession?.isActive)
|
|
35259
35639
|
return;
|
|
35260
|
-
callState.
|
|
35261
|
-
callState.
|
|
35640
|
+
callState.sharedTranscriber = t;
|
|
35641
|
+
callState.sharedTranscriber.on("transcript", (evt) => {
|
|
35262
35642
|
if (!evt.text?.trim() || !voiceSession?.isActive)
|
|
35263
35643
|
return;
|
|
35264
35644
|
const text = evt.text.trim();
|
|
35265
35645
|
writeContent(() => renderVoiceSessionTranscript("user", text));
|
|
35266
35646
|
voiceSession?.sendTranscript("user", text);
|
|
35267
35647
|
if (evt.isFinal) {
|
|
35268
|
-
|
|
35648
|
+
for (const [clientId, agent] of callSubAgents) {
|
|
35649
|
+
agent.handleTranscript(text);
|
|
35650
|
+
}
|
|
35651
|
+
if (callSubAgents.size === 0) {
|
|
35652
|
+
rl.write(text + "\n");
|
|
35653
|
+
}
|
|
35269
35654
|
}
|
|
35270
35655
|
});
|
|
35271
35656
|
writeContent(() => renderInfo("Call ASR ready \u2014 listening for speech"));
|
|
@@ -35276,6 +35661,11 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
35276
35661
|
});
|
|
35277
35662
|
voiceSession.on("userDisconnected", (id) => {
|
|
35278
35663
|
writeContent(() => renderVoiceSessionUser("disconnected", id));
|
|
35664
|
+
const subAgent = callSubAgents.get(id);
|
|
35665
|
+
if (subAgent) {
|
|
35666
|
+
subAgent.dispose();
|
|
35667
|
+
callSubAgents.delete(id);
|
|
35668
|
+
}
|
|
35279
35669
|
});
|
|
35280
35670
|
voiceSession.on("wsClose", (id, code, reason) => {
|
|
35281
35671
|
if (code > 0)
|
|
@@ -35286,15 +35676,21 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
35286
35676
|
});
|
|
35287
35677
|
voiceSession.on("idle_timeout", () => {
|
|
35288
35678
|
writeContent(() => renderWarning("Call session auto-closed (1 min idle \u2014 no users connected)"));
|
|
35289
|
-
if (callState.
|
|
35290
|
-
callState.
|
|
35291
|
-
callState.
|
|
35679
|
+
if (callState.sharedTranscriber) {
|
|
35680
|
+
callState.sharedTranscriber.stop();
|
|
35681
|
+
callState.sharedTranscriber = null;
|
|
35292
35682
|
}
|
|
35683
|
+
for (const agent of callSubAgents.values())
|
|
35684
|
+
agent.dispose();
|
|
35685
|
+
callSubAgents.clear();
|
|
35293
35686
|
voiceSession = null;
|
|
35294
35687
|
});
|
|
35295
35688
|
try {
|
|
35296
35689
|
const tunnelUrl = await voiceSession.start();
|
|
35690
|
+
const adminUrl = adminSessionKey ? `${tunnelUrl}?key=${adminSessionKey}` : tunnelUrl;
|
|
35297
35691
|
writeContent(() => renderVoiceSessionStart(tunnelUrl));
|
|
35692
|
+
writeContent(() => renderInfo(`Admin call URL (includes key): ${adminUrl}`));
|
|
35693
|
+
writeContent(() => renderInfo(`Public call URL (read-only): ${tunnelUrl}`));
|
|
35298
35694
|
if (voiceEngine.enabled && voiceEngine.ready) {
|
|
35299
35695
|
const session = voiceSession;
|
|
35300
35696
|
voiceEngine.onPCMOutput = (pcm, sampleRate) => {
|
|
@@ -35309,8 +35705,13 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
35309
35705
|
return tunnelUrl;
|
|
35310
35706
|
} catch (err) {
|
|
35311
35707
|
writeContent(() => renderWarning(`Voice session failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
35312
|
-
callState.
|
|
35313
|
-
|
|
35708
|
+
if (callState.sharedTranscriber) {
|
|
35709
|
+
callState.sharedTranscriber.stop();
|
|
35710
|
+
callState.sharedTranscriber = null;
|
|
35711
|
+
}
|
|
35712
|
+
for (const agent of callSubAgents.values())
|
|
35713
|
+
agent.dispose();
|
|
35714
|
+
callSubAgents.clear();
|
|
35314
35715
|
voiceSession = null;
|
|
35315
35716
|
return null;
|
|
35316
35717
|
}
|
|
@@ -35322,6 +35723,9 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
35322
35723
|
writeContent(() => renderVoiceSessionStop(runtime));
|
|
35323
35724
|
voiceSession = null;
|
|
35324
35725
|
voiceEngine.onPCMOutput = null;
|
|
35726
|
+
for (const agent of callSubAgents.values())
|
|
35727
|
+
agent.dispose();
|
|
35728
|
+
callSubAgents.clear();
|
|
35325
35729
|
}
|
|
35326
35730
|
},
|
|
35327
35731
|
isCallActive() {
|
|
@@ -36008,6 +36412,7 @@ var init_interactive = __esm({
|
|
|
36008
36412
|
init_dist();
|
|
36009
36413
|
init_listen();
|
|
36010
36414
|
init_voice_session();
|
|
36415
|
+
init_call_agent();
|
|
36011
36416
|
init_config();
|
|
36012
36417
|
init_updater();
|
|
36013
36418
|
init_commands();
|
package/package.json
CHANGED