@corbat-tech/coco 2.36.0 → 2.37.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/cli/index.js +648 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +226 -1043
- package/dist/index.js +799 -394
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Logger } from 'tslog';
|
|
2
2
|
import * as fs4 from 'fs';
|
|
3
|
-
import fs4__default, { readFileSync, mkdirSync, appendFileSync, writeFileSync, constants } from 'fs';
|
|
3
|
+
import fs4__default, { readFileSync, mkdirSync, appendFileSync, writeFileSync, renameSync, constants } from 'fs';
|
|
4
4
|
import * as path17 from 'path';
|
|
5
5
|
import path17__default, { dirname, join, basename, resolve } from 'path';
|
|
6
6
|
import * as fs16 from 'fs/promises';
|
|
7
|
-
import fs16__default, { access, readFile, readdir, writeFile, mkdir
|
|
7
|
+
import fs16__default, { access, readFile, readdir, writeFile, mkdir } from 'fs/promises';
|
|
8
8
|
import { randomUUID, randomBytes, createHash } from 'crypto';
|
|
9
9
|
import * as http from 'http';
|
|
10
|
+
import { createServer } from 'http';
|
|
10
11
|
import { fileURLToPath, URL as URL$1 } from 'url';
|
|
11
12
|
import { exec, execFile, execSync, execFileSync, spawn } from 'child_process';
|
|
12
13
|
import { setGlobalDispatcher, EnvHttpProxyAgent } from 'undici';
|
|
@@ -10607,16 +10608,16 @@ var QualityEvaluator = class {
|
|
|
10607
10608
|
* Find source files in project, adapting to the detected language stack.
|
|
10608
10609
|
*/
|
|
10609
10610
|
async findSourceFiles() {
|
|
10610
|
-
const { access:
|
|
10611
|
-
const { join:
|
|
10611
|
+
const { access: access13 } = await import('fs/promises');
|
|
10612
|
+
const { join: join19 } = await import('path');
|
|
10612
10613
|
let isJava = false;
|
|
10613
10614
|
try {
|
|
10614
|
-
await
|
|
10615
|
+
await access13(join19(this.projectPath, "pom.xml"));
|
|
10615
10616
|
isJava = true;
|
|
10616
10617
|
} catch {
|
|
10617
10618
|
for (const f of ["build.gradle", "build.gradle.kts"]) {
|
|
10618
10619
|
try {
|
|
10619
|
-
await
|
|
10620
|
+
await access13(join19(this.projectPath, f));
|
|
10620
10621
|
isJava = true;
|
|
10621
10622
|
break;
|
|
10622
10623
|
} catch {
|
|
@@ -20352,300 +20353,6 @@ function getAgentManager() {
|
|
|
20352
20353
|
return agentManagerInstance;
|
|
20353
20354
|
}
|
|
20354
20355
|
|
|
20355
|
-
// src/cli/repl/modes.ts
|
|
20356
|
-
var AGENT_MODES = {
|
|
20357
|
-
ask: {
|
|
20358
|
-
id: "ask",
|
|
20359
|
-
label: "Ask",
|
|
20360
|
-
description: "Answer questions and explain code without modifying files.",
|
|
20361
|
-
readOnly: true,
|
|
20362
|
-
preferredTools: ["read_file", "grep", "glob", "codebase_map", "lsp_definition"],
|
|
20363
|
-
requiresVerification: false
|
|
20364
|
-
},
|
|
20365
|
-
plan: {
|
|
20366
|
-
id: "plan",
|
|
20367
|
-
label: "Plan",
|
|
20368
|
-
description: "Explore and produce an implementation plan with read-only tools.",
|
|
20369
|
-
readOnly: true,
|
|
20370
|
-
preferredTools: ["read_file", "grep", "glob", "codebase_map", "lsp_workspace_symbols"],
|
|
20371
|
-
requiresVerification: false
|
|
20372
|
-
},
|
|
20373
|
-
build: {
|
|
20374
|
-
id: "build",
|
|
20375
|
-
label: "Build",
|
|
20376
|
-
description: "Implement code changes and verify them.",
|
|
20377
|
-
readOnly: false,
|
|
20378
|
-
preferredTools: ["read_file", "edit_file", "write_file", "bash_exec", "run_tests"],
|
|
20379
|
-
requiresVerification: true
|
|
20380
|
-
},
|
|
20381
|
-
debug: {
|
|
20382
|
-
id: "debug",
|
|
20383
|
-
label: "Debug",
|
|
20384
|
-
description: "Reproduce failures, trace root cause, patch, and verify.",
|
|
20385
|
-
readOnly: false,
|
|
20386
|
-
preferredTools: ["bash_exec", "read_file", "grep", "lsp_references", "edit_file"],
|
|
20387
|
-
requiresVerification: true
|
|
20388
|
-
},
|
|
20389
|
-
review: {
|
|
20390
|
-
id: "review",
|
|
20391
|
-
label: "Review",
|
|
20392
|
-
description: "Inspect code quality, security, behavior changes, and test gaps.",
|
|
20393
|
-
readOnly: true,
|
|
20394
|
-
preferredTools: ["git_diff", "read_file", "grep", "review_code", "calculate_quality"],
|
|
20395
|
-
requiresVerification: false
|
|
20396
|
-
},
|
|
20397
|
-
architect: {
|
|
20398
|
-
id: "architect",
|
|
20399
|
-
label: "Architect",
|
|
20400
|
-
description: "Design architecture and split work for architect/editor execution.",
|
|
20401
|
-
readOnly: true,
|
|
20402
|
-
preferredTools: ["codebase_map", "lsp_workspace_symbols", "grep", "create_agent_plan"],
|
|
20403
|
-
requiresVerification: false
|
|
20404
|
-
}
|
|
20405
|
-
};
|
|
20406
|
-
function getAgentMode(mode) {
|
|
20407
|
-
return AGENT_MODES[mode];
|
|
20408
|
-
}
|
|
20409
|
-
function listAgentModes() {
|
|
20410
|
-
return Object.values(AGENT_MODES);
|
|
20411
|
-
}
|
|
20412
|
-
|
|
20413
|
-
// src/cli/repl/sessions/storage.ts
|
|
20414
|
-
init_paths();
|
|
20415
|
-
var DEFAULT_CONFIG2 = {
|
|
20416
|
-
storageDir: CONFIG_PATHS.sessions,
|
|
20417
|
-
autoSaveInterval: 3e4,
|
|
20418
|
-
maxSessionsPerProject: 20,
|
|
20419
|
-
compressOldSessions: false
|
|
20420
|
-
};
|
|
20421
|
-
var SessionStore = class {
|
|
20422
|
-
config;
|
|
20423
|
-
initialized = false;
|
|
20424
|
-
constructor(config = {}) {
|
|
20425
|
-
this.config = { ...DEFAULT_CONFIG2, ...config };
|
|
20426
|
-
}
|
|
20427
|
-
async ensureInitialized() {
|
|
20428
|
-
if (this.initialized) return;
|
|
20429
|
-
await mkdir(this.config.storageDir, { recursive: true });
|
|
20430
|
-
this.initialized = true;
|
|
20431
|
-
}
|
|
20432
|
-
getSessionFiles(sessionId) {
|
|
20433
|
-
const sessionDir = this.getSessionDir(sessionId);
|
|
20434
|
-
return {
|
|
20435
|
-
metadata: join(sessionDir, "metadata.json"),
|
|
20436
|
-
conversation: join(sessionDir, "conversation.jsonl"),
|
|
20437
|
-
context: join(sessionDir, "context.json")
|
|
20438
|
-
};
|
|
20439
|
-
}
|
|
20440
|
-
getSessionDir(sessionId) {
|
|
20441
|
-
return join(this.config.storageDir, sessionId);
|
|
20442
|
-
}
|
|
20443
|
-
async exists(sessionId) {
|
|
20444
|
-
try {
|
|
20445
|
-
const files = this.getSessionFiles(sessionId);
|
|
20446
|
-
await access(files.metadata);
|
|
20447
|
-
return true;
|
|
20448
|
-
} catch {
|
|
20449
|
-
return false;
|
|
20450
|
-
}
|
|
20451
|
-
}
|
|
20452
|
-
async save(session) {
|
|
20453
|
-
await this.ensureInitialized();
|
|
20454
|
-
const files = this.getSessionFiles(session.id);
|
|
20455
|
-
const sessionDir = this.getSessionDir(session.id);
|
|
20456
|
-
await mkdir(sessionDir, { recursive: true });
|
|
20457
|
-
const metadata = {
|
|
20458
|
-
id: session.id,
|
|
20459
|
-
projectPath: session.projectPath,
|
|
20460
|
-
startedAt: session.startedAt,
|
|
20461
|
-
lastSavedAt: /* @__PURE__ */ new Date(),
|
|
20462
|
-
config: session.config,
|
|
20463
|
-
messageCount: session.messages.length,
|
|
20464
|
-
totalTokens: this.calculateTokens(session),
|
|
20465
|
-
title: this.generateTitle(session),
|
|
20466
|
-
status: "active"
|
|
20467
|
-
};
|
|
20468
|
-
await writeFile(files.metadata, JSON.stringify(metadata, null, 2), "utf-8");
|
|
20469
|
-
const conversationLines = session.messages.map((msg) => {
|
|
20470
|
-
const serialized = {
|
|
20471
|
-
role: msg.role,
|
|
20472
|
-
content: msg.content,
|
|
20473
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
20474
|
-
};
|
|
20475
|
-
return JSON.stringify(serialized);
|
|
20476
|
-
});
|
|
20477
|
-
await writeFile(files.conversation, conversationLines.join("\n"), "utf-8");
|
|
20478
|
-
const context = {
|
|
20479
|
-
tokenUsage: this.calculateTokens(session)
|
|
20480
|
-
};
|
|
20481
|
-
await writeFile(files.context, JSON.stringify(context, null, 2), "utf-8");
|
|
20482
|
-
}
|
|
20483
|
-
async load(sessionId) {
|
|
20484
|
-
await this.ensureInitialized();
|
|
20485
|
-
const files = this.getSessionFiles(sessionId);
|
|
20486
|
-
try {
|
|
20487
|
-
const metadataContent = await readFile(files.metadata, "utf-8");
|
|
20488
|
-
const metadata = JSON.parse(metadataContent);
|
|
20489
|
-
const conversationContent = await readFile(files.conversation, "utf-8");
|
|
20490
|
-
const messages = conversationContent.split("\n").filter((line) => line.trim()).map((line) => {
|
|
20491
|
-
const parsed = JSON.parse(line);
|
|
20492
|
-
return {
|
|
20493
|
-
role: parsed.role,
|
|
20494
|
-
content: parsed.content
|
|
20495
|
-
};
|
|
20496
|
-
});
|
|
20497
|
-
const session = {
|
|
20498
|
-
id: metadata.id,
|
|
20499
|
-
startedAt: new Date(metadata.startedAt),
|
|
20500
|
-
messages,
|
|
20501
|
-
projectPath: metadata.projectPath,
|
|
20502
|
-
config: metadata.config,
|
|
20503
|
-
trustedTools: /* @__PURE__ */ new Set()
|
|
20504
|
-
};
|
|
20505
|
-
return session;
|
|
20506
|
-
} catch {
|
|
20507
|
-
return null;
|
|
20508
|
-
}
|
|
20509
|
-
}
|
|
20510
|
-
async listSessions(projectPath) {
|
|
20511
|
-
await this.ensureInitialized();
|
|
20512
|
-
const sessions = [];
|
|
20513
|
-
try {
|
|
20514
|
-
const entries = await readdir(this.config.storageDir, {
|
|
20515
|
-
withFileTypes: true
|
|
20516
|
-
});
|
|
20517
|
-
for (const entry of entries) {
|
|
20518
|
-
if (!entry.isDirectory()) continue;
|
|
20519
|
-
const metadataPath = join(this.config.storageDir, entry.name, "metadata.json");
|
|
20520
|
-
try {
|
|
20521
|
-
const content = await readFile(metadataPath, "utf-8");
|
|
20522
|
-
const metadata = JSON.parse(content);
|
|
20523
|
-
metadata.startedAt = new Date(metadata.startedAt);
|
|
20524
|
-
metadata.lastSavedAt = new Date(metadata.lastSavedAt);
|
|
20525
|
-
if (!projectPath || metadata.projectPath === projectPath) {
|
|
20526
|
-
sessions.push(metadata);
|
|
20527
|
-
}
|
|
20528
|
-
} catch {
|
|
20529
|
-
continue;
|
|
20530
|
-
}
|
|
20531
|
-
}
|
|
20532
|
-
} catch {
|
|
20533
|
-
return [];
|
|
20534
|
-
}
|
|
20535
|
-
sessions.sort((a, b) => new Date(b.lastSavedAt).getTime() - new Date(a.lastSavedAt).getTime());
|
|
20536
|
-
return sessions;
|
|
20537
|
-
}
|
|
20538
|
-
async delete(sessionId) {
|
|
20539
|
-
await this.ensureInitialized();
|
|
20540
|
-
const sessionDir = this.getSessionDir(sessionId);
|
|
20541
|
-
try {
|
|
20542
|
-
await rm(sessionDir, { recursive: true, force: true });
|
|
20543
|
-
return true;
|
|
20544
|
-
} catch {
|
|
20545
|
-
return false;
|
|
20546
|
-
}
|
|
20547
|
-
}
|
|
20548
|
-
async getMostRecent(projectPath) {
|
|
20549
|
-
const sessions = await this.listSessions(projectPath);
|
|
20550
|
-
return sessions[0] ?? null;
|
|
20551
|
-
}
|
|
20552
|
-
/**
|
|
20553
|
-
* Append messages to an existing session's conversation file
|
|
20554
|
-
* Creates the file if it doesn't exist
|
|
20555
|
-
* @param sessionId - The session ID
|
|
20556
|
-
* @param messages - Messages to append
|
|
20557
|
-
*/
|
|
20558
|
-
async appendMessages(sessionId, messages) {
|
|
20559
|
-
await this.ensureInitialized();
|
|
20560
|
-
const files = this.getSessionFiles(sessionId);
|
|
20561
|
-
const sessionDir = this.getSessionDir(sessionId);
|
|
20562
|
-
await mkdir(sessionDir, { recursive: true });
|
|
20563
|
-
const newLines = messages.map((msg) => {
|
|
20564
|
-
const serialized = {
|
|
20565
|
-
role: msg.role,
|
|
20566
|
-
content: msg.content,
|
|
20567
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
20568
|
-
};
|
|
20569
|
-
return JSON.stringify(serialized);
|
|
20570
|
-
});
|
|
20571
|
-
let existingContent = "";
|
|
20572
|
-
try {
|
|
20573
|
-
existingContent = await readFile(files.conversation, "utf-8");
|
|
20574
|
-
if (existingContent && !existingContent.endsWith("\n")) {
|
|
20575
|
-
existingContent += "\n";
|
|
20576
|
-
}
|
|
20577
|
-
} catch {
|
|
20578
|
-
}
|
|
20579
|
-
await writeFile(files.conversation, existingContent + newLines.join("\n"), "utf-8");
|
|
20580
|
-
}
|
|
20581
|
-
/**
|
|
20582
|
-
* Prune old sessions to keep storage manageable
|
|
20583
|
-
* Keeps the most recent maxSessionsPerProject sessions per project
|
|
20584
|
-
* @param projectPath - Optional project path to prune (prunes all if not specified)
|
|
20585
|
-
* @returns Number of sessions deleted
|
|
20586
|
-
*/
|
|
20587
|
-
async pruneOldSessions(projectPath) {
|
|
20588
|
-
await this.ensureInitialized();
|
|
20589
|
-
const allSessions = await this.listSessions();
|
|
20590
|
-
const sessionsByProject = /* @__PURE__ */ new Map();
|
|
20591
|
-
for (const session of allSessions) {
|
|
20592
|
-
if (projectPath && session.projectPath !== projectPath) {
|
|
20593
|
-
continue;
|
|
20594
|
-
}
|
|
20595
|
-
const existing = sessionsByProject.get(session.projectPath) ?? [];
|
|
20596
|
-
existing.push(session);
|
|
20597
|
-
sessionsByProject.set(session.projectPath, existing);
|
|
20598
|
-
}
|
|
20599
|
-
let deletedCount = 0;
|
|
20600
|
-
for (const [, sessions] of sessionsByProject) {
|
|
20601
|
-
const sessionsToDelete = sessions.slice(this.config.maxSessionsPerProject);
|
|
20602
|
-
for (const session of sessionsToDelete) {
|
|
20603
|
-
const deleted = await this.delete(session.id);
|
|
20604
|
-
if (deleted) {
|
|
20605
|
-
deletedCount++;
|
|
20606
|
-
}
|
|
20607
|
-
}
|
|
20608
|
-
}
|
|
20609
|
-
return deletedCount;
|
|
20610
|
-
}
|
|
20611
|
-
calculateTokens(session) {
|
|
20612
|
-
if (session.contextManager) {
|
|
20613
|
-
const stats = session.contextManager.getUsageStats();
|
|
20614
|
-
return {
|
|
20615
|
-
input: stats.used,
|
|
20616
|
-
output: 0
|
|
20617
|
-
};
|
|
20618
|
-
}
|
|
20619
|
-
let input = 0;
|
|
20620
|
-
let output = 0;
|
|
20621
|
-
for (const msg of session.messages) {
|
|
20622
|
-
const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
|
|
20623
|
-
const tokens = Math.ceil(content.length / 4);
|
|
20624
|
-
if (msg.role === "user") {
|
|
20625
|
-
input += tokens;
|
|
20626
|
-
} else {
|
|
20627
|
-
output += tokens;
|
|
20628
|
-
}
|
|
20629
|
-
}
|
|
20630
|
-
return { input, output };
|
|
20631
|
-
}
|
|
20632
|
-
generateTitle(session) {
|
|
20633
|
-
for (const msg of session.messages) {
|
|
20634
|
-
if (msg.role === "user" && typeof msg.content === "string") {
|
|
20635
|
-
const content = msg.content.trim();
|
|
20636
|
-
if (content.length > 10) {
|
|
20637
|
-
const firstLine = content.split("\n")[0] ?? content;
|
|
20638
|
-
return firstLine.length > 50 ? firstLine.slice(0, 47) + "..." : firstLine;
|
|
20639
|
-
}
|
|
20640
|
-
}
|
|
20641
|
-
}
|
|
20642
|
-
return "Untitled session";
|
|
20643
|
-
}
|
|
20644
|
-
};
|
|
20645
|
-
function createSessionStore(config) {
|
|
20646
|
-
return new SessionStore(config);
|
|
20647
|
-
}
|
|
20648
|
-
|
|
20649
20356
|
// src/runtime/agent-runtime.ts
|
|
20650
20357
|
init_env();
|
|
20651
20358
|
init_errors();
|
|
@@ -31415,7 +31122,7 @@ var HTTPTransport = class {
|
|
|
31415
31122
|
|
|
31416
31123
|
// src/mcp/transport/sse.ts
|
|
31417
31124
|
init_errors2();
|
|
31418
|
-
var
|
|
31125
|
+
var DEFAULT_CONFIG2 = {
|
|
31419
31126
|
initialReconnectDelay: 1e3,
|
|
31420
31127
|
maxReconnectDelay: 3e4,
|
|
31421
31128
|
maxReconnectAttempts: 10
|
|
@@ -31431,7 +31138,7 @@ var SSETransport = class {
|
|
|
31431
31138
|
errorHandler = null;
|
|
31432
31139
|
closeHandler = null;
|
|
31433
31140
|
constructor(config) {
|
|
31434
|
-
this.config = { ...
|
|
31141
|
+
this.config = { ...DEFAULT_CONFIG2, ...config };
|
|
31435
31142
|
}
|
|
31436
31143
|
/**
|
|
31437
31144
|
* Connect to the SSE endpoint
|
|
@@ -32397,6 +32104,100 @@ function createFullToolRegistry() {
|
|
|
32397
32104
|
registerAllTools(registry);
|
|
32398
32105
|
return registry;
|
|
32399
32106
|
}
|
|
32107
|
+
|
|
32108
|
+
// src/runtime/agent-modes.ts
|
|
32109
|
+
var AGENT_MODES = {
|
|
32110
|
+
ask: {
|
|
32111
|
+
id: "ask",
|
|
32112
|
+
label: "Ask",
|
|
32113
|
+
description: "Answer questions and explain code without modifying files.",
|
|
32114
|
+
readOnly: true,
|
|
32115
|
+
preferredTools: ["read_file", "grep", "glob", "codebase_map", "lsp_definition"],
|
|
32116
|
+
requiresVerification: false
|
|
32117
|
+
},
|
|
32118
|
+
plan: {
|
|
32119
|
+
id: "plan",
|
|
32120
|
+
label: "Plan",
|
|
32121
|
+
description: "Explore and produce an implementation plan with read-only tools.",
|
|
32122
|
+
readOnly: true,
|
|
32123
|
+
preferredTools: ["read_file", "grep", "glob", "codebase_map", "lsp_workspace_symbols"],
|
|
32124
|
+
requiresVerification: false
|
|
32125
|
+
},
|
|
32126
|
+
build: {
|
|
32127
|
+
id: "build",
|
|
32128
|
+
label: "Build",
|
|
32129
|
+
description: "Implement code changes and verify them.",
|
|
32130
|
+
readOnly: false,
|
|
32131
|
+
preferredTools: ["read_file", "edit_file", "write_file", "bash_exec", "run_tests"],
|
|
32132
|
+
requiresVerification: true
|
|
32133
|
+
},
|
|
32134
|
+
debug: {
|
|
32135
|
+
id: "debug",
|
|
32136
|
+
label: "Debug",
|
|
32137
|
+
description: "Reproduce failures, trace root cause, patch, and verify.",
|
|
32138
|
+
readOnly: false,
|
|
32139
|
+
preferredTools: ["bash_exec", "read_file", "grep", "lsp_references", "edit_file"],
|
|
32140
|
+
requiresVerification: true
|
|
32141
|
+
},
|
|
32142
|
+
review: {
|
|
32143
|
+
id: "review",
|
|
32144
|
+
label: "Review",
|
|
32145
|
+
description: "Inspect code quality, security, behavior changes, and test gaps.",
|
|
32146
|
+
readOnly: true,
|
|
32147
|
+
preferredTools: ["git_diff", "read_file", "grep", "review_code", "calculate_quality"],
|
|
32148
|
+
requiresVerification: false
|
|
32149
|
+
},
|
|
32150
|
+
architect: {
|
|
32151
|
+
id: "architect",
|
|
32152
|
+
label: "Architect",
|
|
32153
|
+
description: "Design architecture and split work for architect/editor execution.",
|
|
32154
|
+
readOnly: true,
|
|
32155
|
+
preferredTools: ["codebase_map", "lsp_workspace_symbols", "grep", "create_agent_plan"],
|
|
32156
|
+
requiresVerification: false
|
|
32157
|
+
}
|
|
32158
|
+
};
|
|
32159
|
+
function getAgentMode(mode) {
|
|
32160
|
+
return AGENT_MODES[mode];
|
|
32161
|
+
}
|
|
32162
|
+
function listAgentModes() {
|
|
32163
|
+
return Object.values(AGENT_MODES);
|
|
32164
|
+
}
|
|
32165
|
+
function isAgentMode(value) {
|
|
32166
|
+
return value in AGENT_MODES;
|
|
32167
|
+
}
|
|
32168
|
+
|
|
32169
|
+
// src/runtime/default-turn-runner.ts
|
|
32170
|
+
var DefaultRuntimeTurnRunner = class {
|
|
32171
|
+
async run(input, context) {
|
|
32172
|
+
const messages = [
|
|
32173
|
+
...context.session.messages,
|
|
32174
|
+
{
|
|
32175
|
+
role: "user",
|
|
32176
|
+
content: input.content
|
|
32177
|
+
}
|
|
32178
|
+
];
|
|
32179
|
+
const response = await context.provider.chat(messages, {
|
|
32180
|
+
model: input.options?.model,
|
|
32181
|
+
maxTokens: input.options?.maxTokens,
|
|
32182
|
+
temperature: input.options?.temperature,
|
|
32183
|
+
stopSequences: input.options?.stopSequences,
|
|
32184
|
+
system: context.session.instructions ?? input.options?.system,
|
|
32185
|
+
timeout: input.options?.timeout,
|
|
32186
|
+
signal: input.options?.signal,
|
|
32187
|
+
thinking: input.options?.thinking
|
|
32188
|
+
});
|
|
32189
|
+
return {
|
|
32190
|
+
sessionId: context.session.id,
|
|
32191
|
+
content: response.content,
|
|
32192
|
+
usage: response.usage,
|
|
32193
|
+
model: response.model,
|
|
32194
|
+
mode: context.session.mode
|
|
32195
|
+
};
|
|
32196
|
+
}
|
|
32197
|
+
};
|
|
32198
|
+
function createDefaultRuntimeTurnRunner() {
|
|
32199
|
+
return new DefaultRuntimeTurnRunner();
|
|
32200
|
+
}
|
|
32400
32201
|
var InMemoryEventLog = class {
|
|
32401
32202
|
events = [];
|
|
32402
32203
|
record(type, data = {}) {
|
|
@@ -32548,6 +32349,22 @@ var DefaultPermissionPolicy = class {
|
|
|
32548
32349
|
}
|
|
32549
32350
|
return { allowed: true, risk };
|
|
32550
32351
|
}
|
|
32352
|
+
canExecuteToolInput(mode, tool, input) {
|
|
32353
|
+
if (tool.name !== "run_linter") {
|
|
32354
|
+
return this.canExecuteTool(mode, tool);
|
|
32355
|
+
}
|
|
32356
|
+
const definition = getAgentMode(mode);
|
|
32357
|
+
const fixEnabled = input["fix"] === true;
|
|
32358
|
+
const decision = fixEnabled ? { allowed: true, risk: "write" } : { allowed: true, risk: "read-only" };
|
|
32359
|
+
if (definition.readOnly && fixEnabled) {
|
|
32360
|
+
return {
|
|
32361
|
+
allowed: false,
|
|
32362
|
+
reason: `${definition.label} mode is read-only; run_linter with fix=true can modify files.`,
|
|
32363
|
+
risk: "write"
|
|
32364
|
+
};
|
|
32365
|
+
}
|
|
32366
|
+
return decision;
|
|
32367
|
+
}
|
|
32551
32368
|
};
|
|
32552
32369
|
function createPermissionPolicy() {
|
|
32553
32370
|
return new DefaultPermissionPolicy();
|
|
@@ -32587,108 +32404,135 @@ var ProviderRegistry = class {
|
|
|
32587
32404
|
function createProviderRegistry() {
|
|
32588
32405
|
return new ProviderRegistry();
|
|
32589
32406
|
}
|
|
32590
|
-
|
|
32591
|
-
|
|
32592
|
-
|
|
32593
|
-
|
|
32594
|
-
|
|
32595
|
-
|
|
32596
|
-
|
|
32597
|
-
|
|
32598
|
-
|
|
32599
|
-
|
|
32600
|
-
|
|
32601
|
-
|
|
32407
|
+
function createSessionId() {
|
|
32408
|
+
return `rt_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
32409
|
+
}
|
|
32410
|
+
function cloneSession(session) {
|
|
32411
|
+
return structuredClone(session);
|
|
32412
|
+
}
|
|
32413
|
+
var InMemoryRuntimeSessionStore = class {
|
|
32414
|
+
sessions = /* @__PURE__ */ new Map();
|
|
32415
|
+
create(options = {}) {
|
|
32416
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
32417
|
+
const session = {
|
|
32418
|
+
id: options.id ?? createSessionId(),
|
|
32419
|
+
createdAt: now,
|
|
32420
|
+
updatedAt: now,
|
|
32421
|
+
mode: options.mode ?? "ask",
|
|
32422
|
+
messages: options.messages ? options.messages.map((message) => ({ ...message })) : [],
|
|
32423
|
+
instructions: options.instructions,
|
|
32424
|
+
metadata: { ...options.metadata }
|
|
32425
|
+
};
|
|
32426
|
+
this.sessions.set(session.id, cloneSession(session));
|
|
32427
|
+
return cloneSession(session);
|
|
32602
32428
|
}
|
|
32603
|
-
|
|
32604
|
-
|
|
32605
|
-
|
|
32606
|
-
|
|
32607
|
-
|
|
32608
|
-
|
|
32609
|
-
|
|
32610
|
-
|
|
32611
|
-
|
|
32612
|
-
|
|
32613
|
-
|
|
32614
|
-
|
|
32615
|
-
|
|
32616
|
-
});
|
|
32617
|
-
this.publishToGlobalBridge(provider);
|
|
32618
|
-
this.eventLog.record(providerInjected ? "provider.attached" : "provider.created", {
|
|
32619
|
-
provider: this.providerType,
|
|
32620
|
-
model: this.getModel(),
|
|
32621
|
-
createdByRuntime: !providerInjected
|
|
32622
|
-
});
|
|
32623
|
-
this.eventLog.record("runtime.initialized", { snapshot: this.snapshot() });
|
|
32429
|
+
get(id) {
|
|
32430
|
+
const session = this.sessions.get(id);
|
|
32431
|
+
return session ? cloneSession(session) : void 0;
|
|
32432
|
+
}
|
|
32433
|
+
update(session) {
|
|
32434
|
+
const updated = {
|
|
32435
|
+
...session,
|
|
32436
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
32437
|
+
messages: session.messages.map((message) => ({ ...message })),
|
|
32438
|
+
metadata: { ...session.metadata }
|
|
32439
|
+
};
|
|
32440
|
+
this.sessions.set(updated.id, cloneSession(updated));
|
|
32441
|
+
return cloneSession(updated);
|
|
32624
32442
|
}
|
|
32625
|
-
|
|
32626
|
-
return this.
|
|
32443
|
+
list() {
|
|
32444
|
+
return [...this.sessions.values()].map(cloneSession);
|
|
32627
32445
|
}
|
|
32628
|
-
|
|
32629
|
-
this.
|
|
32630
|
-
this.model = model2 ?? getDefaultModel(providerType);
|
|
32631
|
-
this.publishToGlobalBridge(provider);
|
|
32632
|
-
this.eventLog.record("provider.updated", {
|
|
32633
|
-
provider: this.providerType,
|
|
32634
|
-
model: this.model
|
|
32635
|
-
});
|
|
32446
|
+
delete(id) {
|
|
32447
|
+
return this.sessions.delete(id);
|
|
32636
32448
|
}
|
|
32637
|
-
|
|
32638
|
-
|
|
32639
|
-
|
|
32640
|
-
|
|
32449
|
+
};
|
|
32450
|
+
var FileRuntimeSessionStore = class {
|
|
32451
|
+
constructor(filePath) {
|
|
32452
|
+
this.filePath = filePath;
|
|
32453
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
32454
|
+
this.sessions = this.readSessionsFromDisk();
|
|
32641
32455
|
}
|
|
32642
|
-
|
|
32643
|
-
|
|
32644
|
-
|
|
32645
|
-
|
|
32646
|
-
|
|
32647
|
-
|
|
32648
|
-
|
|
32649
|
-
|
|
32650
|
-
|
|
32651
|
-
|
|
32652
|
-
|
|
32653
|
-
|
|
32654
|
-
},
|
|
32655
|
-
modes: listAgentModes()
|
|
32456
|
+
filePath;
|
|
32457
|
+
sessions = /* @__PURE__ */ new Map();
|
|
32458
|
+
create(options = {}) {
|
|
32459
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
32460
|
+
const session = {
|
|
32461
|
+
id: options.id ?? createSessionId(),
|
|
32462
|
+
createdAt: now,
|
|
32463
|
+
updatedAt: now,
|
|
32464
|
+
mode: options.mode ?? "ask",
|
|
32465
|
+
messages: options.messages ? options.messages.map((message) => ({ ...message })) : [],
|
|
32466
|
+
instructions: options.instructions,
|
|
32467
|
+
metadata: { ...options.metadata }
|
|
32656
32468
|
};
|
|
32469
|
+
const sessions = this.readSessionsFromDisk();
|
|
32470
|
+
sessions.set(session.id, cloneSession(session));
|
|
32471
|
+
this.sessions = sessions;
|
|
32472
|
+
this.persist(sessions);
|
|
32473
|
+
return cloneSession(session);
|
|
32657
32474
|
}
|
|
32658
|
-
|
|
32659
|
-
|
|
32660
|
-
|
|
32661
|
-
|
|
32662
|
-
|
|
32663
|
-
|
|
32664
|
-
|
|
32665
|
-
|
|
32666
|
-
|
|
32475
|
+
get(id) {
|
|
32476
|
+
this.sessions = this.readSessionsFromDisk();
|
|
32477
|
+
const session = this.sessions.get(id);
|
|
32478
|
+
return session ? cloneSession(session) : void 0;
|
|
32479
|
+
}
|
|
32480
|
+
update(session) {
|
|
32481
|
+
const updated = {
|
|
32482
|
+
...session,
|
|
32483
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
32484
|
+
messages: session.messages.map((message) => ({ ...message })),
|
|
32485
|
+
metadata: { ...session.metadata }
|
|
32486
|
+
};
|
|
32487
|
+
const sessions = this.readSessionsFromDisk();
|
|
32488
|
+
sessions.set(updated.id, cloneSession(updated));
|
|
32489
|
+
this.sessions = sessions;
|
|
32490
|
+
this.persist(sessions);
|
|
32491
|
+
return cloneSession(updated);
|
|
32492
|
+
}
|
|
32493
|
+
list() {
|
|
32494
|
+
this.sessions = this.readSessionsFromDisk();
|
|
32495
|
+
return [...this.sessions.values()].map(cloneSession);
|
|
32496
|
+
}
|
|
32497
|
+
delete(id) {
|
|
32498
|
+
const sessions = this.readSessionsFromDisk();
|
|
32499
|
+
const deleted = sessions.delete(id);
|
|
32500
|
+
this.sessions = sessions;
|
|
32501
|
+
if (deleted) this.persist(sessions);
|
|
32502
|
+
return deleted;
|
|
32503
|
+
}
|
|
32504
|
+
readSessionsFromDisk() {
|
|
32505
|
+
let raw;
|
|
32506
|
+
try {
|
|
32507
|
+
raw = readFileSync(this.filePath, "utf-8");
|
|
32508
|
+
} catch (error) {
|
|
32509
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
32510
|
+
return /* @__PURE__ */ new Map();
|
|
32511
|
+
}
|
|
32512
|
+
throw error;
|
|
32667
32513
|
}
|
|
32668
|
-
|
|
32669
|
-
|
|
32670
|
-
|
|
32671
|
-
|
|
32672
|
-
|
|
32673
|
-
|
|
32674
|
-
|
|
32514
|
+
if (!raw.trim()) return /* @__PURE__ */ new Map();
|
|
32515
|
+
const parsed = JSON.parse(raw);
|
|
32516
|
+
if (parsed.version !== 1 || !Array.isArray(parsed.sessions)) {
|
|
32517
|
+
throw new Error(`Unsupported runtime session store format: ${this.filePath}`);
|
|
32518
|
+
}
|
|
32519
|
+
return new Map(parsed.sessions.map((session) => [session.id, cloneSession(session)]));
|
|
32520
|
+
}
|
|
32521
|
+
persist(sessions) {
|
|
32522
|
+
const payload = {
|
|
32523
|
+
version: 1,
|
|
32524
|
+
sessions: [...sessions.values()].map(cloneSession)
|
|
32525
|
+
};
|
|
32526
|
+
const tempPath = `${this.filePath}.${randomUUID()}.tmp`;
|
|
32527
|
+
writeFileSync(tempPath, JSON.stringify(payload, null, 2) + "\n", "utf-8");
|
|
32528
|
+
renameSync(tempPath, this.filePath);
|
|
32675
32529
|
}
|
|
32676
32530
|
};
|
|
32677
|
-
|
|
32678
|
-
|
|
32679
|
-
await runtime.initialize();
|
|
32680
|
-
return runtime;
|
|
32531
|
+
function createRuntimeSessionStore() {
|
|
32532
|
+
return new InMemoryRuntimeSessionStore();
|
|
32681
32533
|
}
|
|
32682
|
-
|
|
32683
|
-
|
|
32684
|
-
function createMcpToolPolicy(server, tool, risk, allowedModes = ["ask", "plan", "build", "debug", "review", "architect"]) {
|
|
32685
|
-
return {
|
|
32686
|
-
server,
|
|
32687
|
-
tool,
|
|
32688
|
-
risk,
|
|
32689
|
-
requiresConfirmation: risk === "destructive" || risk === "secrets-sensitive",
|
|
32690
|
-
allowedModes
|
|
32691
|
-
};
|
|
32534
|
+
function createFileRuntimeSessionStore(filePath) {
|
|
32535
|
+
return new FileRuntimeSessionStore(filePath);
|
|
32692
32536
|
}
|
|
32693
32537
|
|
|
32694
32538
|
// src/runtime/workflow-registry.ts
|
|
@@ -32883,11 +32727,572 @@ function createWorkflowRegistry(workflows) {
|
|
|
32883
32727
|
return createWorkflowCatalog(workflows);
|
|
32884
32728
|
}
|
|
32885
32729
|
|
|
32730
|
+
// src/runtime/workflow-engine.ts
|
|
32731
|
+
var WorkflowEngine = class {
|
|
32732
|
+
constructor(catalog = createWorkflowCatalog(), eventLog = createEventLog()) {
|
|
32733
|
+
this.catalog = catalog;
|
|
32734
|
+
this.eventLog = eventLog;
|
|
32735
|
+
}
|
|
32736
|
+
catalog;
|
|
32737
|
+
eventLog;
|
|
32738
|
+
handlers = /* @__PURE__ */ new Map();
|
|
32739
|
+
registerHandler(workflowId, handler) {
|
|
32740
|
+
if (!this.catalog.get(workflowId)) {
|
|
32741
|
+
throw new Error(`Unknown workflow: ${workflowId}`);
|
|
32742
|
+
}
|
|
32743
|
+
this.handlers.set(workflowId, handler);
|
|
32744
|
+
}
|
|
32745
|
+
createPlan(workflowId, input) {
|
|
32746
|
+
return this.catalog.createPlan(workflowId, input, this.eventLog);
|
|
32747
|
+
}
|
|
32748
|
+
async run(request) {
|
|
32749
|
+
const workflow = this.catalog.get(request.workflowId);
|
|
32750
|
+
if (!workflow) {
|
|
32751
|
+
throw new Error(`Unknown workflow: ${request.workflowId}`);
|
|
32752
|
+
}
|
|
32753
|
+
const handler = this.handlers.get(request.workflowId);
|
|
32754
|
+
if (!handler) {
|
|
32755
|
+
throw new Error(`No handler registered for workflow: ${request.workflowId}`);
|
|
32756
|
+
}
|
|
32757
|
+
const plan = request.plan ?? this.createPlan(request.workflowId, request.input);
|
|
32758
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
32759
|
+
const runId = `${request.workflowId}-run-${Date.now().toString(36)}`;
|
|
32760
|
+
this.eventLog.record("workflow.started", {
|
|
32761
|
+
workflowId: request.workflowId,
|
|
32762
|
+
planId: plan.id,
|
|
32763
|
+
runId
|
|
32764
|
+
});
|
|
32765
|
+
try {
|
|
32766
|
+
const output = await handler(request.input, {
|
|
32767
|
+
workflow,
|
|
32768
|
+
plan,
|
|
32769
|
+
eventLog: this.eventLog
|
|
32770
|
+
});
|
|
32771
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
32772
|
+
const result = {
|
|
32773
|
+
id: runId,
|
|
32774
|
+
workflowId: request.workflowId,
|
|
32775
|
+
status: "completed",
|
|
32776
|
+
output,
|
|
32777
|
+
startedAt,
|
|
32778
|
+
completedAt
|
|
32779
|
+
};
|
|
32780
|
+
this.eventLog.record("workflow.completed", {
|
|
32781
|
+
workflowId: request.workflowId,
|
|
32782
|
+
planId: plan.id,
|
|
32783
|
+
runId
|
|
32784
|
+
});
|
|
32785
|
+
return result;
|
|
32786
|
+
} catch (error) {
|
|
32787
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
32788
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
32789
|
+
this.eventLog.record("workflow.failed", {
|
|
32790
|
+
workflowId: request.workflowId,
|
|
32791
|
+
planId: plan.id,
|
|
32792
|
+
runId,
|
|
32793
|
+
error: message
|
|
32794
|
+
});
|
|
32795
|
+
return {
|
|
32796
|
+
id: runId,
|
|
32797
|
+
workflowId: request.workflowId,
|
|
32798
|
+
status: "failed",
|
|
32799
|
+
output: null,
|
|
32800
|
+
startedAt,
|
|
32801
|
+
completedAt,
|
|
32802
|
+
error: message
|
|
32803
|
+
};
|
|
32804
|
+
}
|
|
32805
|
+
}
|
|
32806
|
+
};
|
|
32807
|
+
function createWorkflowEngine(catalog, eventLog) {
|
|
32808
|
+
return new WorkflowEngine(catalog, eventLog);
|
|
32809
|
+
}
|
|
32810
|
+
|
|
32811
|
+
// src/runtime/agent-runtime.ts
|
|
32812
|
+
var AgentRuntime = class {
|
|
32813
|
+
constructor(options) {
|
|
32814
|
+
this.options = options;
|
|
32815
|
+
this.providerRegistry = createProviderRegistry();
|
|
32816
|
+
this.toolRegistry = options.toolRegistry ?? createFullToolRegistry();
|
|
32817
|
+
this.sessionStore = options.sessionStore;
|
|
32818
|
+
this.runtimeSessionStore = options.runtimeSessionStore ?? createRuntimeSessionStore();
|
|
32819
|
+
this.eventLog = options.eventLog ?? (options.eventLogPath ? createFileEventLog(options.eventLogPath) : createEventLog());
|
|
32820
|
+
this.workflowEngine = options.workflowEngine ?? createWorkflowEngine(void 0, this.eventLog);
|
|
32821
|
+
this.permissionPolicy = options.permissionPolicy ?? createPermissionPolicy();
|
|
32822
|
+
this.turnRunner = options.turnRunner ?? createDefaultRuntimeTurnRunner();
|
|
32823
|
+
this.providerType = options.providerType;
|
|
32824
|
+
this.model = options.model ?? options.providerConfig?.model ?? getDefaultModel(options.providerType);
|
|
32825
|
+
}
|
|
32826
|
+
options;
|
|
32827
|
+
providerRegistry;
|
|
32828
|
+
toolRegistry;
|
|
32829
|
+
sessionStore;
|
|
32830
|
+
runtimeSessionStore;
|
|
32831
|
+
workflowEngine;
|
|
32832
|
+
permissionPolicy;
|
|
32833
|
+
eventLog;
|
|
32834
|
+
turnRunner;
|
|
32835
|
+
providerType;
|
|
32836
|
+
model;
|
|
32837
|
+
provider;
|
|
32838
|
+
async initialize() {
|
|
32839
|
+
const providerInjected = Boolean(this.options.provider);
|
|
32840
|
+
const provider = this.options.provider ?? await this.providerRegistry.createProvider(this.providerType, {
|
|
32841
|
+
...this.options.providerConfig,
|
|
32842
|
+
model: this.getModel()
|
|
32843
|
+
});
|
|
32844
|
+
this.provider = provider;
|
|
32845
|
+
this.publishToGlobalBridge(provider);
|
|
32846
|
+
this.eventLog.record(providerInjected ? "provider.attached" : "provider.created", {
|
|
32847
|
+
provider: this.providerType,
|
|
32848
|
+
model: this.getModel(),
|
|
32849
|
+
createdByRuntime: !providerInjected
|
|
32850
|
+
});
|
|
32851
|
+
this.eventLog.record("runtime.initialized", { snapshot: this.snapshot() });
|
|
32852
|
+
}
|
|
32853
|
+
getModel() {
|
|
32854
|
+
return this.model;
|
|
32855
|
+
}
|
|
32856
|
+
updateProvider(providerType, model2, provider) {
|
|
32857
|
+
this.providerType = providerType;
|
|
32858
|
+
this.model = model2 ?? getDefaultModel(providerType);
|
|
32859
|
+
this.provider = provider;
|
|
32860
|
+
this.publishToGlobalBridge(provider);
|
|
32861
|
+
this.eventLog.record("provider.updated", {
|
|
32862
|
+
provider: this.providerType,
|
|
32863
|
+
model: this.model
|
|
32864
|
+
});
|
|
32865
|
+
}
|
|
32866
|
+
publishToGlobalBridge(provider) {
|
|
32867
|
+
if (this.options.publishToGlobalBridge !== true) return;
|
|
32868
|
+
setAgentProvider(provider);
|
|
32869
|
+
setAgentToolRegistry(this.toolRegistry);
|
|
32870
|
+
}
|
|
32871
|
+
snapshot() {
|
|
32872
|
+
const capability = this.providerRegistry.getCapability(this.providerType, this.getModel());
|
|
32873
|
+
const toolNames = this.toolRegistry.getAll().map((tool) => tool.name).sort();
|
|
32874
|
+
return {
|
|
32875
|
+
provider: {
|
|
32876
|
+
type: this.providerType,
|
|
32877
|
+
model: this.getModel(),
|
|
32878
|
+
capability
|
|
32879
|
+
},
|
|
32880
|
+
tools: {
|
|
32881
|
+
count: toolNames.length,
|
|
32882
|
+
names: toolNames
|
|
32883
|
+
},
|
|
32884
|
+
modes: listAgentModes()
|
|
32885
|
+
};
|
|
32886
|
+
}
|
|
32887
|
+
createSession(options = {}) {
|
|
32888
|
+
const session = this.runtimeSessionStore.create(options);
|
|
32889
|
+
this.eventLog.record("session.created", {
|
|
32890
|
+
sessionId: session.id,
|
|
32891
|
+
mode: session.mode,
|
|
32892
|
+
metadataKeys: Object.keys(session.metadata).sort()
|
|
32893
|
+
});
|
|
32894
|
+
return session;
|
|
32895
|
+
}
|
|
32896
|
+
getSession(sessionId) {
|
|
32897
|
+
return this.runtimeSessionStore.get(sessionId);
|
|
32898
|
+
}
|
|
32899
|
+
listSessions() {
|
|
32900
|
+
return this.runtimeSessionStore.list();
|
|
32901
|
+
}
|
|
32902
|
+
async runTurn(input) {
|
|
32903
|
+
const provider = this.provider;
|
|
32904
|
+
if (!provider) {
|
|
32905
|
+
throw new Error("Runtime provider is not initialized.");
|
|
32906
|
+
}
|
|
32907
|
+
const session = input.sessionId ? this.runtimeSessionStore.get(input.sessionId) : this.createSession({ mode: input.mode, metadata: input.metadata });
|
|
32908
|
+
if (!session) {
|
|
32909
|
+
throw new Error(`Runtime session not found: ${input.sessionId}`);
|
|
32910
|
+
}
|
|
32911
|
+
const effectiveSession = input.mode && input.mode !== session.mode ? { ...session, mode: input.mode } : session;
|
|
32912
|
+
this.eventLog.record("turn.started", {
|
|
32913
|
+
sessionId: effectiveSession.id,
|
|
32914
|
+
provider: this.providerType,
|
|
32915
|
+
model: this.getModel(),
|
|
32916
|
+
mode: effectiveSession.mode,
|
|
32917
|
+
runtimeApi: true
|
|
32918
|
+
});
|
|
32919
|
+
try {
|
|
32920
|
+
const result = await this.turnRunner.run(input, {
|
|
32921
|
+
runtime: this,
|
|
32922
|
+
session: effectiveSession,
|
|
32923
|
+
provider,
|
|
32924
|
+
toolRegistry: this.toolRegistry,
|
|
32925
|
+
permissionPolicy: this.permissionPolicy,
|
|
32926
|
+
eventLog: this.eventLog
|
|
32927
|
+
});
|
|
32928
|
+
const updatedSession = this.runtimeSessionStore.update({
|
|
32929
|
+
...effectiveSession,
|
|
32930
|
+
messages: [
|
|
32931
|
+
...effectiveSession.messages,
|
|
32932
|
+
{ role: "user", content: input.content },
|
|
32933
|
+
{ role: "assistant", content: result.content }
|
|
32934
|
+
]
|
|
32935
|
+
});
|
|
32936
|
+
this.eventLog.record("session.updated", {
|
|
32937
|
+
sessionId: updatedSession.id,
|
|
32938
|
+
messages: updatedSession.messages.length
|
|
32939
|
+
});
|
|
32940
|
+
this.eventLog.record("turn.completed", {
|
|
32941
|
+
sessionId: updatedSession.id,
|
|
32942
|
+
inputTokens: result.usage.inputTokens,
|
|
32943
|
+
outputTokens: result.usage.outputTokens,
|
|
32944
|
+
model: result.model,
|
|
32945
|
+
runtimeApi: true
|
|
32946
|
+
});
|
|
32947
|
+
return { ...result, sessionId: updatedSession.id, mode: updatedSession.mode };
|
|
32948
|
+
} catch (error) {
|
|
32949
|
+
this.eventLog.record("turn.failed", {
|
|
32950
|
+
sessionId: effectiveSession.id,
|
|
32951
|
+
error: error instanceof Error ? error.message : String(error),
|
|
32952
|
+
runtimeApi: true
|
|
32953
|
+
});
|
|
32954
|
+
throw error;
|
|
32955
|
+
}
|
|
32956
|
+
}
|
|
32957
|
+
async *streamTurn(input) {
|
|
32958
|
+
const provider = this.provider;
|
|
32959
|
+
if (!provider) {
|
|
32960
|
+
throw new Error("Runtime provider is not initialized.");
|
|
32961
|
+
}
|
|
32962
|
+
const session = input.sessionId ? this.runtimeSessionStore.get(input.sessionId) : this.createSession({ mode: input.mode, metadata: input.metadata });
|
|
32963
|
+
if (!session) {
|
|
32964
|
+
throw new Error(`Runtime session not found: ${input.sessionId}`);
|
|
32965
|
+
}
|
|
32966
|
+
const effectiveSession = input.mode && input.mode !== session.mode ? { ...session, mode: input.mode } : session;
|
|
32967
|
+
const messages = [
|
|
32968
|
+
...effectiveSession.messages,
|
|
32969
|
+
{
|
|
32970
|
+
role: "user",
|
|
32971
|
+
content: input.content
|
|
32972
|
+
}
|
|
32973
|
+
];
|
|
32974
|
+
this.eventLog.record("turn.started", {
|
|
32975
|
+
sessionId: effectiveSession.id,
|
|
32976
|
+
provider: this.providerType,
|
|
32977
|
+
model: this.getModel(),
|
|
32978
|
+
mode: effectiveSession.mode,
|
|
32979
|
+
streaming: true,
|
|
32980
|
+
runtimeApi: true
|
|
32981
|
+
});
|
|
32982
|
+
let content = "";
|
|
32983
|
+
let completed = false;
|
|
32984
|
+
let failed = false;
|
|
32985
|
+
try {
|
|
32986
|
+
for await (const chunk of provider.stream(messages, {
|
|
32987
|
+
model: input.options?.model,
|
|
32988
|
+
maxTokens: input.options?.maxTokens,
|
|
32989
|
+
temperature: input.options?.temperature,
|
|
32990
|
+
stopSequences: input.options?.stopSequences,
|
|
32991
|
+
system: effectiveSession.instructions ?? input.options?.system,
|
|
32992
|
+
timeout: input.options?.timeout,
|
|
32993
|
+
signal: input.options?.signal,
|
|
32994
|
+
thinking: input.options?.thinking
|
|
32995
|
+
})) {
|
|
32996
|
+
if (chunk.type === "text" && chunk.text) {
|
|
32997
|
+
content += chunk.text;
|
|
32998
|
+
yield {
|
|
32999
|
+
type: "text",
|
|
33000
|
+
sessionId: effectiveSession.id,
|
|
33001
|
+
text: chunk.text
|
|
33002
|
+
};
|
|
33003
|
+
}
|
|
33004
|
+
}
|
|
33005
|
+
const updatedSession = this.runtimeSessionStore.update({
|
|
33006
|
+
...effectiveSession,
|
|
33007
|
+
messages: [
|
|
33008
|
+
...effectiveSession.messages,
|
|
33009
|
+
{ role: "user", content: input.content },
|
|
33010
|
+
{ role: "assistant", content }
|
|
33011
|
+
]
|
|
33012
|
+
});
|
|
33013
|
+
const result = {
|
|
33014
|
+
sessionId: updatedSession.id,
|
|
33015
|
+
content,
|
|
33016
|
+
usage: {
|
|
33017
|
+
inputTokens: provider.countTokens(input.content),
|
|
33018
|
+
outputTokens: provider.countTokens(content),
|
|
33019
|
+
estimated: true
|
|
33020
|
+
},
|
|
33021
|
+
model: input.options?.model ?? this.getModel(),
|
|
33022
|
+
mode: updatedSession.mode
|
|
33023
|
+
};
|
|
33024
|
+
this.eventLog.record("session.updated", {
|
|
33025
|
+
sessionId: updatedSession.id,
|
|
33026
|
+
messages: updatedSession.messages.length
|
|
33027
|
+
});
|
|
33028
|
+
this.eventLog.record("turn.completed", {
|
|
33029
|
+
sessionId: updatedSession.id,
|
|
33030
|
+
inputTokens: result.usage.inputTokens,
|
|
33031
|
+
outputTokens: result.usage.outputTokens,
|
|
33032
|
+
model: result.model,
|
|
33033
|
+
streaming: true,
|
|
33034
|
+
runtimeApi: true
|
|
33035
|
+
});
|
|
33036
|
+
completed = true;
|
|
33037
|
+
yield { type: "done", sessionId: updatedSession.id, result };
|
|
33038
|
+
} catch (error) {
|
|
33039
|
+
failed = true;
|
|
33040
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
33041
|
+
this.eventLog.record("turn.failed", {
|
|
33042
|
+
sessionId: effectiveSession.id,
|
|
33043
|
+
error: message,
|
|
33044
|
+
streaming: true,
|
|
33045
|
+
runtimeApi: true
|
|
33046
|
+
});
|
|
33047
|
+
yield {
|
|
33048
|
+
type: "error",
|
|
33049
|
+
sessionId: effectiveSession.id,
|
|
33050
|
+
error: message
|
|
33051
|
+
};
|
|
33052
|
+
} finally {
|
|
33053
|
+
if (!completed && !failed) {
|
|
33054
|
+
this.eventLog.record("turn.cancelled", {
|
|
33055
|
+
sessionId: effectiveSession.id,
|
|
33056
|
+
outputTokens: provider.countTokens(content),
|
|
33057
|
+
streaming: true,
|
|
33058
|
+
runtimeApi: true
|
|
33059
|
+
});
|
|
33060
|
+
}
|
|
33061
|
+
}
|
|
33062
|
+
}
|
|
33063
|
+
async executeTool(input) {
|
|
33064
|
+
const startedAt = performance.now();
|
|
33065
|
+
const session = input.sessionId ? this.getSession(input.sessionId) : void 0;
|
|
33066
|
+
if (input.sessionId && !session) {
|
|
33067
|
+
const decision2 = {
|
|
33068
|
+
allowed: false,
|
|
33069
|
+
reason: `Runtime session not found: ${input.sessionId}`,
|
|
33070
|
+
risk: "read-only"
|
|
33071
|
+
};
|
|
33072
|
+
this.eventLog.record("tool.blocked", {
|
|
33073
|
+
sessionId: input.sessionId,
|
|
33074
|
+
mode: input.mode ?? "ask",
|
|
33075
|
+
tool: input.toolName,
|
|
33076
|
+
reason: decision2.reason,
|
|
33077
|
+
runtimeApi: true
|
|
33078
|
+
});
|
|
33079
|
+
return {
|
|
33080
|
+
toolName: input.toolName,
|
|
33081
|
+
success: false,
|
|
33082
|
+
error: decision2.reason,
|
|
33083
|
+
duration: performance.now() - startedAt,
|
|
33084
|
+
decision: decision2
|
|
33085
|
+
};
|
|
33086
|
+
}
|
|
33087
|
+
const mode = input.mode ?? session?.mode ?? "ask";
|
|
33088
|
+
const tool = this.toolRegistry.get(input.toolName);
|
|
33089
|
+
if (!tool) {
|
|
33090
|
+
const decision2 = {
|
|
33091
|
+
allowed: false,
|
|
33092
|
+
reason: "Tool not registered.",
|
|
33093
|
+
risk: "read-only"
|
|
33094
|
+
};
|
|
33095
|
+
this.eventLog.record("tool.blocked", {
|
|
33096
|
+
sessionId: input.sessionId,
|
|
33097
|
+
mode,
|
|
33098
|
+
tool: input.toolName,
|
|
33099
|
+
reason: decision2.reason,
|
|
33100
|
+
runtimeApi: true
|
|
33101
|
+
});
|
|
33102
|
+
return {
|
|
33103
|
+
toolName: input.toolName,
|
|
33104
|
+
success: false,
|
|
33105
|
+
error: decision2.reason,
|
|
33106
|
+
duration: performance.now() - startedAt,
|
|
33107
|
+
decision: decision2
|
|
33108
|
+
};
|
|
33109
|
+
}
|
|
33110
|
+
const decision = this.permissionPolicy.canExecuteToolInput ? this.permissionPolicy.canExecuteToolInput(mode, tool, input.input) : this.permissionPolicy.canExecuteTool(mode, tool);
|
|
33111
|
+
if (!decision.allowed || decision.requiresConfirmation && input.confirmed !== true) {
|
|
33112
|
+
const reason = decision.reason ?? (decision.requiresConfirmation ? "Tool requires explicit runtime confirmation." : "Tool is not allowed.");
|
|
33113
|
+
this.eventLog.record("tool.blocked", {
|
|
33114
|
+
sessionId: input.sessionId,
|
|
33115
|
+
mode,
|
|
33116
|
+
tool: input.toolName,
|
|
33117
|
+
reason,
|
|
33118
|
+
risk: decision.risk,
|
|
33119
|
+
requiresConfirmation: decision.requiresConfirmation,
|
|
33120
|
+
runtimeApi: true
|
|
33121
|
+
});
|
|
33122
|
+
return {
|
|
33123
|
+
toolName: input.toolName,
|
|
33124
|
+
success: false,
|
|
33125
|
+
error: reason,
|
|
33126
|
+
duration: performance.now() - startedAt,
|
|
33127
|
+
decision
|
|
33128
|
+
};
|
|
33129
|
+
}
|
|
33130
|
+
this.eventLog.record("tool.started", {
|
|
33131
|
+
sessionId: input.sessionId,
|
|
33132
|
+
mode,
|
|
33133
|
+
tool: input.toolName,
|
|
33134
|
+
risk: decision.risk,
|
|
33135
|
+
runtimeApi: true,
|
|
33136
|
+
metadataKeys: Object.keys(input.metadata ?? {}).sort()
|
|
33137
|
+
});
|
|
33138
|
+
const result = await this.toolRegistry.execute(input.toolName, input.input);
|
|
33139
|
+
this.eventLog.record("tool.completed", {
|
|
33140
|
+
sessionId: input.sessionId,
|
|
33141
|
+
mode,
|
|
33142
|
+
tool: input.toolName,
|
|
33143
|
+
success: result.success,
|
|
33144
|
+
duration: result.duration,
|
|
33145
|
+
runtimeApi: true
|
|
33146
|
+
});
|
|
33147
|
+
return {
|
|
33148
|
+
toolName: input.toolName,
|
|
33149
|
+
success: result.success,
|
|
33150
|
+
output: result.data,
|
|
33151
|
+
error: result.error,
|
|
33152
|
+
duration: result.duration,
|
|
33153
|
+
decision
|
|
33154
|
+
};
|
|
33155
|
+
}
|
|
33156
|
+
assertToolAllowed(mode, toolName, input) {
|
|
33157
|
+
const tool = this.toolRegistry.get(toolName);
|
|
33158
|
+
if (!tool) {
|
|
33159
|
+
this.eventLog.record("tool.blocked", {
|
|
33160
|
+
mode,
|
|
33161
|
+
tool: toolName,
|
|
33162
|
+
reason: "Tool not registered."
|
|
33163
|
+
});
|
|
33164
|
+
return false;
|
|
33165
|
+
}
|
|
33166
|
+
const decision = input && this.permissionPolicy.canExecuteToolInput ? this.permissionPolicy.canExecuteToolInput(mode, tool, input) : this.permissionPolicy.canExecuteTool(mode, tool);
|
|
33167
|
+
this.eventLog.record(decision.allowed ? "tool.allowed" : "tool.blocked", {
|
|
33168
|
+
mode,
|
|
33169
|
+
tool: toolName,
|
|
33170
|
+
...decision
|
|
33171
|
+
});
|
|
33172
|
+
return decision.allowed;
|
|
33173
|
+
}
|
|
33174
|
+
};
|
|
33175
|
+
async function createAgentRuntime(options) {
|
|
33176
|
+
const runtime = new AgentRuntime(options);
|
|
33177
|
+
await runtime.initialize();
|
|
33178
|
+
return runtime;
|
|
33179
|
+
}
|
|
33180
|
+
var HttpRequestError = class extends Error {
|
|
33181
|
+
constructor(message, status) {
|
|
33182
|
+
super(message);
|
|
33183
|
+
this.status = status;
|
|
33184
|
+
}
|
|
33185
|
+
status;
|
|
33186
|
+
};
|
|
33187
|
+
async function readJsonBody(request, maxBodyBytes) {
|
|
33188
|
+
const chunks = [];
|
|
33189
|
+
let size = 0;
|
|
33190
|
+
for await (const chunk of request) {
|
|
33191
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
33192
|
+
size += buffer.length;
|
|
33193
|
+
if (size > maxBodyBytes) {
|
|
33194
|
+
throw new HttpRequestError(`Request body exceeds ${maxBodyBytes} bytes.`, 413);
|
|
33195
|
+
}
|
|
33196
|
+
chunks.push(buffer);
|
|
33197
|
+
}
|
|
33198
|
+
const raw = Buffer.concat(chunks).toString("utf-8").trim();
|
|
33199
|
+
try {
|
|
33200
|
+
return raw ? JSON.parse(raw) : {};
|
|
33201
|
+
} catch {
|
|
33202
|
+
throw new HttpRequestError("Invalid JSON request body.", 400);
|
|
33203
|
+
}
|
|
33204
|
+
}
|
|
33205
|
+
function sendJson(response, status, body) {
|
|
33206
|
+
response.statusCode = status;
|
|
33207
|
+
response.setHeader("content-type", "application/json; charset=utf-8");
|
|
33208
|
+
response.end(JSON.stringify(body, null, 2));
|
|
33209
|
+
}
|
|
33210
|
+
function notFound(response) {
|
|
33211
|
+
sendJson(response, 404, { error: "Not found" });
|
|
33212
|
+
}
|
|
33213
|
+
function assertValidMode(mode) {
|
|
33214
|
+
if (mode === void 0) return void 0;
|
|
33215
|
+
if (typeof mode === "string" && isAgentMode(mode)) return mode;
|
|
33216
|
+
throw new HttpRequestError("Invalid runtime mode.", 400);
|
|
33217
|
+
}
|
|
33218
|
+
function createRuntimeHttpServer(runtime, options = {}) {
|
|
33219
|
+
const maxBodyBytes = options.maxBodyBytes ?? 1024 * 1024;
|
|
33220
|
+
return createServer(async (request, response) => {
|
|
33221
|
+
try {
|
|
33222
|
+
const url = new URL(request.url ?? "/", "http://localhost");
|
|
33223
|
+
const parts = url.pathname.split("/").filter(Boolean);
|
|
33224
|
+
if (request.method === "POST" && url.pathname === "/sessions") {
|
|
33225
|
+
const body = await readJsonBody(request, maxBodyBytes);
|
|
33226
|
+
const session = runtime.createSession({
|
|
33227
|
+
mode: assertValidMode(body.mode),
|
|
33228
|
+
instructions: body.instructions,
|
|
33229
|
+
metadata: body.metadata
|
|
33230
|
+
});
|
|
33231
|
+
sendJson(response, 201, session);
|
|
33232
|
+
return;
|
|
33233
|
+
}
|
|
33234
|
+
if (request.method === "GET" && parts[0] === "sessions" && parts[1] && parts.length === 2) {
|
|
33235
|
+
const session = runtime.getSession(parts[1]);
|
|
33236
|
+
if (!session) {
|
|
33237
|
+
notFound(response);
|
|
33238
|
+
return;
|
|
33239
|
+
}
|
|
33240
|
+
sendJson(response, 200, session);
|
|
33241
|
+
return;
|
|
33242
|
+
}
|
|
33243
|
+
if (request.method === "POST" && parts[0] === "sessions" && parts[1] && parts[2] === "messages") {
|
|
33244
|
+
const body = await readJsonBody(request, maxBodyBytes);
|
|
33245
|
+
if (!body.content || typeof body.content !== "string") {
|
|
33246
|
+
sendJson(response, 400, { error: "content is required" });
|
|
33247
|
+
return;
|
|
33248
|
+
}
|
|
33249
|
+
if (!runtime.getSession(parts[1])) {
|
|
33250
|
+
notFound(response);
|
|
33251
|
+
return;
|
|
33252
|
+
}
|
|
33253
|
+
const result = await runtime.runTurn({
|
|
33254
|
+
...body,
|
|
33255
|
+
mode: assertValidMode(body.mode),
|
|
33256
|
+
sessionId: parts[1]
|
|
33257
|
+
});
|
|
33258
|
+
sendJson(response, 200, result);
|
|
33259
|
+
return;
|
|
33260
|
+
}
|
|
33261
|
+
if (request.method === "GET" && parts[0] === "sessions" && parts[1] && parts[2] === "events") {
|
|
33262
|
+
const events = runtime.eventLog.list().filter((event) => event.data["sessionId"] === parts[1]);
|
|
33263
|
+
sendJson(response, 200, { events });
|
|
33264
|
+
return;
|
|
33265
|
+
}
|
|
33266
|
+
if (request.method === "GET" && url.pathname === "/state") {
|
|
33267
|
+
sendJson(response, 200, runtime.snapshot());
|
|
33268
|
+
return;
|
|
33269
|
+
}
|
|
33270
|
+
notFound(response);
|
|
33271
|
+
} catch (error) {
|
|
33272
|
+
const status = error instanceof HttpRequestError ? error.status : 500;
|
|
33273
|
+
sendJson(response, status, {
|
|
33274
|
+
error: error instanceof Error ? error.message : String(error)
|
|
33275
|
+
});
|
|
33276
|
+
}
|
|
33277
|
+
});
|
|
33278
|
+
}
|
|
33279
|
+
|
|
33280
|
+
// src/runtime/extension-manifests.ts
|
|
33281
|
+
function createMcpToolPolicy(server, tool, risk, allowedModes = ["ask", "plan", "build", "debug", "review", "architect"]) {
|
|
33282
|
+
return {
|
|
33283
|
+
server,
|
|
33284
|
+
tool,
|
|
33285
|
+
risk,
|
|
33286
|
+
requiresConfirmation: risk === "destructive" || risk === "secrets-sensitive",
|
|
33287
|
+
allowedModes
|
|
33288
|
+
};
|
|
33289
|
+
}
|
|
33290
|
+
|
|
32886
33291
|
// src/index.ts
|
|
32887
33292
|
init_errors();
|
|
32888
33293
|
init_logger();
|
|
32889
33294
|
init_proxy();
|
|
32890
33295
|
|
|
32891
|
-
export { ADRGenerator, AgentRuntime, AnthropicProvider, ArchitectureGenerator, BacklogGenerator, CICDGenerator, CocoError, CodeGenerator, CodeReviewer, CompleteExecutor, ConfigError, ConvergeExecutor, DEFAULT_WORKFLOWS, DefaultPermissionPolicy, DiscoveryEngine, DockerGenerator, DocsGenerator, FileEventLog, InMemoryEventLog, OrchestrateExecutor, OutputExecutor, PhaseError, ProviderRegistry, SessionManager, SpecificationGenerator, TaskError, TaskIterator, ToolRegistry, VERSION, WorkflowCatalog, WorkflowRegistry, configExists, createADRGenerator, createAgentRuntime, createAnthropicProvider, createArchitectureGenerator, createBacklogGenerator, createCICDGenerator, createCodeGenerator, createCodeReviewer, createCompleteExecutor, createConvergeExecutor, createDefaultConfig, createDiscoveryEngine, createDockerGenerator, createDocsGenerator, createEventLog, createFileEventLog, createFullToolRegistry, createLogger, createMcpToolPolicy, createOrchestrateExecutor, createOrchestrator, createOutputExecutor, createPermissionPolicy, createProvider, createProviderRegistry, createSessionManager, createSpecificationGenerator, createTaskIterator, createToolRegistry, createWorkflowCatalog, createWorkflowRegistry, installProxyDispatcher, loadConfig, registerAllTools, saveConfig };
|
|
33296
|
+
export { ADRGenerator, AGENT_MODES, AgentRuntime, AnthropicProvider, ArchitectureGenerator, BacklogGenerator, CICDGenerator, CocoError, CodeGenerator, CodeReviewer, CompleteExecutor, ConfigError, ConvergeExecutor, DEFAULT_WORKFLOWS, DefaultPermissionPolicy, DefaultRuntimeTurnRunner, DiscoveryEngine, DockerGenerator, DocsGenerator, FileEventLog, FileRuntimeSessionStore, InMemoryEventLog, InMemoryRuntimeSessionStore, OrchestrateExecutor, OutputExecutor, PhaseError, ProviderRegistry, SessionManager, SpecificationGenerator, TaskError, TaskIterator, ToolRegistry, VERSION, WorkflowCatalog, WorkflowEngine, WorkflowRegistry, configExists, createADRGenerator, createAgentRuntime, createAnthropicProvider, createArchitectureGenerator, createBacklogGenerator, createCICDGenerator, createCodeGenerator, createCodeReviewer, createCompleteExecutor, createConvergeExecutor, createDefaultConfig, createDefaultRuntimeTurnRunner, createDiscoveryEngine, createDockerGenerator, createDocsGenerator, createEventLog, createFileEventLog, createFileRuntimeSessionStore, createFullToolRegistry, createLogger, createMcpToolPolicy, createOrchestrateExecutor, createOrchestrator, createOutputExecutor, createPermissionPolicy, createProvider, createProviderRegistry, createRuntimeHttpServer, createRuntimeSessionStore, createSessionManager, createSpecificationGenerator, createTaskIterator, createToolRegistry, createWorkflowCatalog, createWorkflowEngine, createWorkflowRegistry, getAgentMode, installProxyDispatcher, isAgentMode, listAgentModes, loadConfig, registerAllTools, saveConfig };
|
|
32892
33297
|
//# sourceMappingURL=index.js.map
|
|
32893
33298
|
//# sourceMappingURL=index.js.map
|