@corbat-tech/coco 2.36.0 → 2.38.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 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, rm } from 'fs/promises';
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: access14 } = await import('fs/promises');
10611
- const { join: join20 } = await import('path');
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 access14(join20(this.projectPath, "pom.xml"));
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 access14(join20(this.projectPath, f));
10620
+ await access13(join19(this.projectPath, f));
10620
10621
  isJava = true;
10621
10622
  break;
10622
10623
  } catch {
@@ -19437,6 +19438,199 @@ z.string().regex(
19437
19438
  // src/cli/repl/agents/manager.ts
19438
19439
  init_logger();
19439
19440
 
19441
+ // src/runtime/multi-agent.ts
19442
+ var SharedWorkspaceState = class {
19443
+ facts = /* @__PURE__ */ new Map();
19444
+ decisions = /* @__PURE__ */ new Map();
19445
+ risks = /* @__PURE__ */ new Map();
19446
+ files = /* @__PURE__ */ new Map();
19447
+ testResults = /* @__PURE__ */ new Map();
19448
+ artifacts = [];
19449
+ writeFact(key, value) {
19450
+ this.facts.set(key, value);
19451
+ }
19452
+ recordDecision(key, value) {
19453
+ this.decisions.set(key, value);
19454
+ }
19455
+ recordRisk(key, value) {
19456
+ this.risks.set(key, value);
19457
+ }
19458
+ recordFile(path44, value) {
19459
+ this.files.set(path44, value);
19460
+ }
19461
+ recordTestResult(key, value) {
19462
+ this.testResults.set(key, value);
19463
+ }
19464
+ addArtifact(artifact) {
19465
+ this.artifacts.push(cloneArtifact(artifact));
19466
+ }
19467
+ readForRole(role) {
19468
+ const includeSensitive = role === "security" || role === "integrator" || role === "pm";
19469
+ return {
19470
+ facts: Object.fromEntries(this.facts),
19471
+ decisions: Object.fromEntries(this.decisions),
19472
+ risks: includeSensitive ? Object.fromEntries(this.risks) : {},
19473
+ files: Object.fromEntries(this.files),
19474
+ testResults: Object.fromEntries(this.testResults),
19475
+ artifacts: this.artifacts.filter((artifact) => includeSensitive || artifact.kind !== "riskReport").map(cloneArtifact)
19476
+ };
19477
+ }
19478
+ snapshot() {
19479
+ return {
19480
+ facts: Object.fromEntries(this.facts),
19481
+ decisions: Object.fromEntries(this.decisions),
19482
+ risks: Object.fromEntries(this.risks),
19483
+ files: Object.fromEntries(this.files),
19484
+ testResults: Object.fromEntries(this.testResults),
19485
+ artifacts: this.artifacts.map(cloneArtifact)
19486
+ };
19487
+ }
19488
+ };
19489
+ function createAgentArtifact(input) {
19490
+ return {
19491
+ ...input,
19492
+ id: input.id ?? `artifact-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
19493
+ createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
19494
+ };
19495
+ }
19496
+ function createSummaryArtifact(output, metadata = {}) {
19497
+ return createAgentArtifact({
19498
+ kind: "summary",
19499
+ content: output,
19500
+ title: metadata.title ?? "Agent summary",
19501
+ agentRunId: metadata.agentRunId,
19502
+ taskId: metadata.taskId
19503
+ });
19504
+ }
19505
+ function normalizeAgentRunResult(input) {
19506
+ const completedAt = input.completedAt ?? (/* @__PURE__ */ new Date()).toISOString();
19507
+ const startedAt = input.startedAt ?? completedAt;
19508
+ const status = input.status ?? (input.success ? "completed" : "failed");
19509
+ const artifacts = input.artifacts && input.artifacts.length > 0 ? input.artifacts.map(cloneArtifact) : [createSummaryArtifact(input.output, { agentRunId: input.id, taskId: input.taskId })];
19510
+ return {
19511
+ id: input.id,
19512
+ taskId: input.taskId,
19513
+ role: input.role,
19514
+ status,
19515
+ success: input.success,
19516
+ output: input.output,
19517
+ artifacts,
19518
+ toolsUsed: [...input.toolsUsed ?? []],
19519
+ turns: input.turns ?? 0,
19520
+ durationMs: input.durationMs ?? 0,
19521
+ usage: input.usage,
19522
+ error: input.error,
19523
+ startedAt,
19524
+ completedAt,
19525
+ metadata: input.metadata
19526
+ };
19527
+ }
19528
+ function validateAgentCapabilities(capability, requiredTools = []) {
19529
+ const allowed = new Set(capability.allowedTools);
19530
+ return requiredTools.filter((tool) => !allowed.has(tool)).map((tool) => ({
19531
+ code: "missing-dependency",
19532
+ message: `Tool '${tool}' is not allowed for agent role '${capability.role}'.`
19533
+ }));
19534
+ }
19535
+ function validateAgentGraph(graph) {
19536
+ const issues = [];
19537
+ const nodeIds = /* @__PURE__ */ new Set();
19538
+ const gateIds = new Set((graph.gates ?? []).map((gate) => gate.id));
19539
+ if (graph.parallelism !== void 0 && graph.parallelism < 1) {
19540
+ issues.push({
19541
+ code: "invalid-parallelism",
19542
+ message: "Graph parallelism must be greater than zero."
19543
+ });
19544
+ }
19545
+ for (const node of graph.nodes) {
19546
+ if (nodeIds.has(node.id)) {
19547
+ issues.push({
19548
+ code: "duplicate-node",
19549
+ message: `Duplicate graph node '${node.id}'.`,
19550
+ nodeId: node.id
19551
+ });
19552
+ }
19553
+ nodeIds.add(node.id);
19554
+ if (node.retryPolicy && node.retryPolicy.maxAttempts < 1) {
19555
+ issues.push({
19556
+ code: "invalid-retry-policy",
19557
+ message: `Node '${node.id}' retry policy must allow at least one attempt.`,
19558
+ nodeId: node.id
19559
+ });
19560
+ }
19561
+ for (const dep of node.dependsOn ?? []) {
19562
+ if (!nodeIds.has(dep) && !graph.nodes.some((candidate) => candidate.id === dep)) {
19563
+ issues.push({
19564
+ code: "missing-dependency",
19565
+ message: `Node '${node.id}' depends on missing node '${dep}'.`,
19566
+ nodeId: node.id
19567
+ });
19568
+ }
19569
+ }
19570
+ for (const gate of node.gates ?? []) {
19571
+ if (!gateIds.has(gate)) {
19572
+ issues.push({
19573
+ code: "missing-gate",
19574
+ message: `Node '${node.id}' references missing gate '${gate}'.`,
19575
+ nodeId: node.id,
19576
+ gateId: gate
19577
+ });
19578
+ }
19579
+ }
19580
+ }
19581
+ for (const edge of graph.edges ?? []) {
19582
+ if (!nodeIds.has(edge.from)) {
19583
+ issues.push({
19584
+ code: "missing-edge-node",
19585
+ message: `Graph edge references missing source node '${edge.from}'.`,
19586
+ nodeId: edge.from
19587
+ });
19588
+ }
19589
+ if (!nodeIds.has(edge.to)) {
19590
+ issues.push({
19591
+ code: "missing-edge-node",
19592
+ message: `Graph edge references missing target node '${edge.to}'.`,
19593
+ nodeId: edge.to
19594
+ });
19595
+ }
19596
+ }
19597
+ const levels = buildExecutionLevels(graph, issues);
19598
+ return { valid: issues.length === 0, issues, levels };
19599
+ }
19600
+ function buildExecutionLevels(graph, issues) {
19601
+ const dependencies = /* @__PURE__ */ new Map();
19602
+ for (const node of graph.nodes) {
19603
+ dependencies.set(node.id, new Set(node.dependsOn ?? []));
19604
+ }
19605
+ for (const edge of graph.edges ?? []) {
19606
+ if (dependencies.has(edge.to)) {
19607
+ dependencies.get(edge.to).add(edge.from);
19608
+ }
19609
+ }
19610
+ const completed = /* @__PURE__ */ new Set();
19611
+ const levels = [];
19612
+ while (completed.size < dependencies.size) {
19613
+ const level = [...dependencies.entries()].filter(([id, deps]) => !completed.has(id) && [...deps].every((dep) => completed.has(dep))).map(([id]) => id);
19614
+ if (level.length === 0) {
19615
+ const remaining = [...dependencies.keys()].filter((id) => !completed.has(id));
19616
+ issues.push({
19617
+ code: "cycle",
19618
+ message: `Graph contains a cycle involving: ${remaining.join(", ")}.`
19619
+ });
19620
+ return levels;
19621
+ }
19622
+ for (const id of level) completed.add(id);
19623
+ levels.push(level);
19624
+ }
19625
+ return levels;
19626
+ }
19627
+ function cloneArtifact(artifact) {
19628
+ return {
19629
+ ...artifact,
19630
+ metadata: artifact.metadata ? { ...artifact.metadata } : void 0
19631
+ };
19632
+ }
19633
+
19440
19634
  // src/cli/repl/agents/prompts.ts
19441
19635
  var EXPLORE_PROMPT = `You are an exploration agent for Corbat-Coco.
19442
19636
  Your purpose is to search the codebase to answer questions and gather information.
@@ -20017,11 +20211,15 @@ var AgentManager = class extends EventEmitter {
20017
20211
  failedAgent.status = "failed";
20018
20212
  failedAgent.error = error;
20019
20213
  failedAgent.completedAt = /* @__PURE__ */ new Date();
20020
- return {
20214
+ return this.buildResult({
20021
20215
  agent: failedAgent,
20022
20216
  success: false,
20023
- output: error
20024
- };
20217
+ output: error,
20218
+ turns: 0,
20219
+ toolsUsed: [],
20220
+ startedAt: failedAgent.createdAt.toISOString(),
20221
+ usage: { inputTokens: 0, outputTokens: 0 }
20222
+ });
20025
20223
  }
20026
20224
  const agent = this.createAgent(type, task);
20027
20225
  this.activeAgents.set(agent.id, agent);
@@ -20073,11 +20271,15 @@ var AgentManager = class extends EventEmitter {
20073
20271
  options.onStatusChange?.(agent);
20074
20272
  this.logger.error(`Agent ${agent.id} failed unexpectedly`, { error: errorMessage });
20075
20273
  this.emitEvent("fail", agent);
20076
- return {
20274
+ return this.buildResult({
20077
20275
  agent,
20078
20276
  success: false,
20079
- output: errorMessage
20080
- };
20277
+ output: errorMessage,
20278
+ turns: 0,
20279
+ toolsUsed: [],
20280
+ startedAt: agent.createdAt.toISOString(),
20281
+ usage: { inputTokens: 0, outputTokens: 0 }
20282
+ });
20081
20283
  }
20082
20284
  }
20083
20285
  /**
@@ -20198,6 +20400,8 @@ var AgentManager = class extends EventEmitter {
20198
20400
  let finalOutput = "";
20199
20401
  let iteration = 0;
20200
20402
  const maxTurns = config.maxTurns ?? 10;
20403
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
20404
+ const toolsUsed = /* @__PURE__ */ new Set();
20201
20405
  while (iteration < maxTurns) {
20202
20406
  iteration++;
20203
20407
  if (options.signal?.aborted) {
@@ -20206,12 +20410,15 @@ var AgentManager = class extends EventEmitter {
20206
20410
  agent.completedAt = /* @__PURE__ */ new Date();
20207
20411
  this.moveToCompleted(agent.id);
20208
20412
  options.onStatusChange?.(agent);
20209
- return {
20413
+ return this.buildResult({
20210
20414
  agent,
20211
20415
  success: false,
20212
20416
  output: "Agent execution was aborted",
20417
+ turns: iteration,
20418
+ toolsUsed: Array.from(toolsUsed),
20419
+ startedAt,
20213
20420
  usage: { inputTokens: totalInputTokens, outputTokens: totalOutputTokens }
20214
- };
20421
+ });
20215
20422
  }
20216
20423
  const response = await this.provider.chatWithTools(messages, {
20217
20424
  system: config.systemPrompt,
@@ -20228,7 +20435,7 @@ var AgentManager = class extends EventEmitter {
20228
20435
  messages.push({ role: "assistant", content: response.content });
20229
20436
  break;
20230
20437
  }
20231
- const toolResults = await this.executeToolCalls(response.toolCalls, config);
20438
+ const toolResults = await this.executeToolCalls(response.toolCalls, config, toolsUsed);
20232
20439
  const toolUses = response.toolCalls.map((tc) => ({
20233
20440
  type: "tool_use",
20234
20441
  id: tc.id,
@@ -20252,12 +20459,15 @@ var AgentManager = class extends EventEmitter {
20252
20459
  iterations: iteration,
20253
20460
  outputLength: finalOutput.length
20254
20461
  });
20255
- return {
20462
+ return this.buildResult({
20256
20463
  agent,
20257
20464
  success: true,
20258
20465
  output: finalOutput,
20466
+ turns: iteration,
20467
+ toolsUsed: Array.from(toolsUsed),
20468
+ startedAt,
20259
20469
  usage: { inputTokens: totalInputTokens, outputTokens: totalOutputTokens }
20260
- };
20470
+ });
20261
20471
  }
20262
20472
  /**
20263
20473
  * Get tool definitions filtered for the agent's allowed tools
@@ -20270,10 +20480,11 @@ var AgentManager = class extends EventEmitter {
20270
20480
  /**
20271
20481
  * Execute tool calls and return results
20272
20482
  */
20273
- async executeToolCalls(toolCalls, config) {
20483
+ async executeToolCalls(toolCalls, config, toolsUsed) {
20274
20484
  const results = [];
20275
20485
  const allowedTools = new Set(config.tools);
20276
20486
  for (const toolCall of toolCalls) {
20487
+ toolsUsed.add(toolCall.name);
20277
20488
  if (!allowedTools.has(toolCall.name)) {
20278
20489
  results.push({
20279
20490
  type: "tool_result",
@@ -20314,6 +20525,33 @@ var AgentManager = class extends EventEmitter {
20314
20525
  this.abortControllers.delete(agentId);
20315
20526
  }
20316
20527
  }
20528
+ buildResult(input) {
20529
+ const structuredResult = normalizeAgentRunResult({
20530
+ id: `${input.agent.id}-run`,
20531
+ taskId: input.agent.id,
20532
+ role: agentTypeToRuntimeRole(input.agent.type),
20533
+ success: input.success,
20534
+ output: input.output,
20535
+ turns: input.turns,
20536
+ toolsUsed: input.toolsUsed,
20537
+ usage: input.usage,
20538
+ startedAt: input.startedAt,
20539
+ durationMs: input.agent.completedAt ? input.agent.completedAt.getTime() - input.agent.createdAt.getTime() : 0,
20540
+ status: input.success ? "completed" : "failed",
20541
+ error: input.success ? void 0 : input.agent.error,
20542
+ metadata: { agentType: input.agent.type }
20543
+ });
20544
+ return {
20545
+ agent: input.agent,
20546
+ success: input.success,
20547
+ output: input.output,
20548
+ artifacts: structuredResult.artifacts,
20549
+ structuredResult,
20550
+ toolsUsed: input.toolsUsed,
20551
+ turns: input.turns,
20552
+ usage: input.usage
20553
+ };
20554
+ }
20317
20555
  /**
20318
20556
  * Emit an agent event
20319
20557
  */
@@ -20323,6 +20561,31 @@ var AgentManager = class extends EventEmitter {
20323
20561
  this.emit("agent", event);
20324
20562
  }
20325
20563
  };
20564
+ function agentTypeToRuntimeRole(type) {
20565
+ switch (type) {
20566
+ case "explore":
20567
+ return "researcher";
20568
+ case "plan":
20569
+ return "planner";
20570
+ case "test":
20571
+ case "e2e":
20572
+ case "tdd":
20573
+ return "tester";
20574
+ case "debug":
20575
+ case "refactor":
20576
+ return "coder";
20577
+ case "review":
20578
+ return "reviewer";
20579
+ case "architect":
20580
+ return "architect";
20581
+ case "security":
20582
+ return "security";
20583
+ case "docs":
20584
+ return "docs";
20585
+ case "database":
20586
+ return "database";
20587
+ }
20588
+ }
20326
20589
 
20327
20590
  // src/agents/provider-bridge.ts
20328
20591
  var agentProvider = null;
@@ -20352,302 +20615,142 @@ function getAgentManager() {
20352
20615
  return agentManagerInstance;
20353
20616
  }
20354
20617
 
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];
20618
+ // src/runtime/agent-runtime.ts
20619
+ init_env();
20620
+ var PUBLIC_WEB_TOOLS = /* @__PURE__ */ new Set(["search_public_docs", "list_public_services"]);
20621
+ var CUSTOMER_SUPPORT_TOOLS = /* @__PURE__ */ new Set([
20622
+ "search_public_docs",
20623
+ "knowledge_search",
20624
+ "create_support_draft",
20625
+ "request_human_escalation"
20626
+ ]);
20627
+ function createNoToolRegistry() {
20628
+ return new ToolRegistry();
20408
20629
  }
20409
- function listAgentModes() {
20410
- return Object.values(AGENT_MODES);
20630
+ function createCodingToolRegistry() {
20631
+ return createFullToolRegistry();
20411
20632
  }
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;
20633
+ function createPublicWebToolRegistry(source) {
20634
+ return copyAllowedTools(PUBLIC_WEB_TOOLS, source);
20635
+ }
20636
+ function createCustomerSupportToolRegistry(source) {
20637
+ return copyAllowedTools(CUSTOMER_SUPPORT_TOOLS, source);
20638
+ }
20639
+ function createSupportRagToolRegistry(options = {}) {
20640
+ const registry = createRagToolRegistry(options.retriever);
20641
+ if (options.supportDraft) {
20642
+ registry.register(
20643
+ defineTool({
20644
+ name: "create_support_draft",
20645
+ description: "Create a support response draft from the customer message and approved retrieved sources.",
20646
+ category: "document",
20647
+ parameters: z.object({
20648
+ conversationId: z.string(),
20649
+ customerMessage: z.string(),
20650
+ retrievedSources: z.array(
20651
+ z.object({
20652
+ id: z.string(),
20653
+ title: z.string(),
20654
+ content: z.string(),
20655
+ url: z.string().optional(),
20656
+ score: z.number(),
20657
+ metadata: z.record(z.string(), z.unknown()).optional()
20658
+ })
20659
+ ).optional()
20660
+ }),
20661
+ execute: options.supportDraft
20662
+ })
20663
+ );
20551
20664
  }
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");
20665
+ if (options.humanEscalation) {
20666
+ registry.register(
20667
+ defineTool({
20668
+ name: "request_human_escalation",
20669
+ description: "Prepare a human escalation request. Runtime consumers must confirmation-gate this external action.",
20670
+ category: "config",
20671
+ parameters: z.object({
20672
+ conversationId: z.string(),
20673
+ summary: z.string(),
20674
+ priority: z.enum(["low", "normal", "high", "urgent"]),
20675
+ reason: z.string()
20676
+ }),
20677
+ execute: options.humanEscalation
20678
+ })
20679
+ );
20580
20680
  }
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;
20681
+ return registry;
20682
+ }
20683
+ function createSalesIntakeToolRegistry(options = {}) {
20684
+ const registry = new ToolRegistry();
20685
+ if (options.leadSummary) {
20686
+ registry.register(
20687
+ defineTool({
20688
+ name: "create_sales_lead_summary",
20689
+ description: "Create a structured lead intake summary and recommended commercial next step.",
20690
+ category: "document",
20691
+ parameters: z.object({
20692
+ conversationId: z.string(),
20693
+ company: z.string().optional(),
20694
+ contact: z.string().optional(),
20695
+ problem: z.string(),
20696
+ desiredOutcome: z.string().optional(),
20697
+ urgency: z.enum(["low", "normal", "high"]).optional(),
20698
+ budgetRange: z.string().optional(),
20699
+ currentStack: z.string().optional()
20700
+ }),
20701
+ execute: options.leadSummary
20702
+ })
20703
+ );
20610
20704
  }
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 };
20705
+ return registry;
20706
+ }
20707
+ function createInternalOpsToolRegistry(options = {}) {
20708
+ const registry = new ToolRegistry();
20709
+ if (options.opsDraft) {
20710
+ registry.register(
20711
+ defineTool({
20712
+ name: "create_internal_ops_draft",
20713
+ description: "Prepare an internal operations action draft. This does not execute the operation.",
20714
+ category: "document",
20715
+ parameters: z.object({
20716
+ requestId: z.string(),
20717
+ requester: z.string().optional(),
20718
+ workflow: z.string(),
20719
+ requestedAction: z.string(),
20720
+ context: z.string().optional()
20721
+ }),
20722
+ execute: options.opsDraft
20723
+ })
20724
+ );
20631
20725
  }
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";
20726
+ return registry;
20727
+ }
20728
+ function createRagToolRegistry(retriever) {
20729
+ const registry = new ToolRegistry();
20730
+ if (!retriever) return registry;
20731
+ registry.register(
20732
+ defineTool({
20733
+ name: "knowledge_search",
20734
+ description: "Search the configured knowledge base and return ranked sources.",
20735
+ category: "search",
20736
+ parameters: z.object({
20737
+ query: z.string(),
20738
+ limit: z.number().optional()
20739
+ }),
20740
+ execute: async ({ query, limit }) => retriever.search(query, { limit })
20741
+ })
20742
+ );
20743
+ return registry;
20744
+ }
20745
+ function copyAllowedTools(allowed, source) {
20746
+ const registry = new ToolRegistry();
20747
+ if (!source) return registry;
20748
+ for (const name of allowed) {
20749
+ const tool = source.get(name);
20750
+ if (tool) registry.register(tool);
20643
20751
  }
20644
- };
20645
- function createSessionStore(config) {
20646
- return new SessionStore(config);
20752
+ return registry;
20647
20753
  }
20648
-
20649
- // src/runtime/agent-runtime.ts
20650
- init_env();
20651
20754
  init_errors();
20652
20755
  init_allowed_paths();
20653
20756
  function levenshtein(a, b) {
@@ -31415,7 +31518,7 @@ var HTTPTransport = class {
31415
31518
 
31416
31519
  // src/mcp/transport/sse.ts
31417
31520
  init_errors2();
31418
- var DEFAULT_CONFIG3 = {
31521
+ var DEFAULT_CONFIG2 = {
31419
31522
  initialReconnectDelay: 1e3,
31420
31523
  maxReconnectDelay: 3e4,
31421
31524
  maxReconnectAttempts: 10
@@ -31431,7 +31534,7 @@ var SSETransport = class {
31431
31534
  errorHandler = null;
31432
31535
  closeHandler = null;
31433
31536
  constructor(config) {
31434
- this.config = { ...DEFAULT_CONFIG3, ...config };
31537
+ this.config = { ...DEFAULT_CONFIG2, ...config };
31435
31538
  }
31436
31539
  /**
31437
31540
  * Connect to the SSE endpoint
@@ -32397,6 +32500,100 @@ function createFullToolRegistry() {
32397
32500
  registerAllTools(registry);
32398
32501
  return registry;
32399
32502
  }
32503
+
32504
+ // src/runtime/agent-modes.ts
32505
+ var AGENT_MODES = {
32506
+ ask: {
32507
+ id: "ask",
32508
+ label: "Ask",
32509
+ description: "Answer questions and explain code without modifying files.",
32510
+ readOnly: true,
32511
+ preferredTools: ["read_file", "grep", "glob", "codebase_map", "lsp_definition"],
32512
+ requiresVerification: false
32513
+ },
32514
+ plan: {
32515
+ id: "plan",
32516
+ label: "Plan",
32517
+ description: "Explore and produce an implementation plan with read-only tools.",
32518
+ readOnly: true,
32519
+ preferredTools: ["read_file", "grep", "glob", "codebase_map", "lsp_workspace_symbols"],
32520
+ requiresVerification: false
32521
+ },
32522
+ build: {
32523
+ id: "build",
32524
+ label: "Build",
32525
+ description: "Implement code changes and verify them.",
32526
+ readOnly: false,
32527
+ preferredTools: ["read_file", "edit_file", "write_file", "bash_exec", "run_tests"],
32528
+ requiresVerification: true
32529
+ },
32530
+ debug: {
32531
+ id: "debug",
32532
+ label: "Debug",
32533
+ description: "Reproduce failures, trace root cause, patch, and verify.",
32534
+ readOnly: false,
32535
+ preferredTools: ["bash_exec", "read_file", "grep", "lsp_references", "edit_file"],
32536
+ requiresVerification: true
32537
+ },
32538
+ review: {
32539
+ id: "review",
32540
+ label: "Review",
32541
+ description: "Inspect code quality, security, behavior changes, and test gaps.",
32542
+ readOnly: true,
32543
+ preferredTools: ["git_diff", "read_file", "grep", "review_code", "calculate_quality"],
32544
+ requiresVerification: false
32545
+ },
32546
+ architect: {
32547
+ id: "architect",
32548
+ label: "Architect",
32549
+ description: "Design architecture and split work for architect/editor execution.",
32550
+ readOnly: true,
32551
+ preferredTools: ["codebase_map", "lsp_workspace_symbols", "grep", "create_agent_plan"],
32552
+ requiresVerification: false
32553
+ }
32554
+ };
32555
+ function getAgentMode(mode) {
32556
+ return AGENT_MODES[mode];
32557
+ }
32558
+ function listAgentModes() {
32559
+ return Object.values(AGENT_MODES);
32560
+ }
32561
+ function isAgentMode(value) {
32562
+ return value in AGENT_MODES;
32563
+ }
32564
+
32565
+ // src/runtime/default-turn-runner.ts
32566
+ var DefaultRuntimeTurnRunner = class {
32567
+ async run(input, context) {
32568
+ const messages = [
32569
+ ...context.session.messages,
32570
+ {
32571
+ role: "user",
32572
+ content: input.content
32573
+ }
32574
+ ];
32575
+ const response = await context.provider.chat(messages, {
32576
+ model: input.options?.model,
32577
+ maxTokens: input.options?.maxTokens,
32578
+ temperature: input.options?.temperature,
32579
+ stopSequences: input.options?.stopSequences,
32580
+ system: context.session.instructions ?? input.options?.system,
32581
+ timeout: input.options?.timeout,
32582
+ signal: input.options?.signal,
32583
+ thinking: input.options?.thinking
32584
+ });
32585
+ return {
32586
+ sessionId: context.session.id,
32587
+ content: response.content,
32588
+ usage: response.usage,
32589
+ model: response.model,
32590
+ mode: context.session.mode
32591
+ };
32592
+ }
32593
+ };
32594
+ function createDefaultRuntimeTurnRunner() {
32595
+ return new DefaultRuntimeTurnRunner();
32596
+ }
32400
32597
  var InMemoryEventLog = class {
32401
32598
  events = [];
32402
32599
  record(type, data = {}) {
@@ -32515,7 +32712,8 @@ var DESTRUCTIVE_TOOL_NAMES = /* @__PURE__ */ new Set([
32515
32712
  "delete_file",
32516
32713
  "restore_checkpoint",
32517
32714
  "git_commit",
32518
- "git_push"
32715
+ "git_push",
32716
+ "request_human_escalation"
32519
32717
  ]);
32520
32718
  function riskForTool(tool) {
32521
32719
  if (READ_ONLY_TOOL_NAMES.has(tool.name)) return "read-only";
@@ -32548,6 +32746,22 @@ var DefaultPermissionPolicy = class {
32548
32746
  }
32549
32747
  return { allowed: true, risk };
32550
32748
  }
32749
+ canExecuteToolInput(mode, tool, input) {
32750
+ if (tool.name !== "run_linter") {
32751
+ return this.canExecuteTool(mode, tool);
32752
+ }
32753
+ const definition = getAgentMode(mode);
32754
+ const fixEnabled = input["fix"] === true;
32755
+ const decision = fixEnabled ? { allowed: true, risk: "write" } : { allowed: true, risk: "read-only" };
32756
+ if (definition.readOnly && fixEnabled) {
32757
+ return {
32758
+ allowed: false,
32759
+ reason: `${definition.label} mode is read-only; run_linter with fix=true can modify files.`,
32760
+ risk: "write"
32761
+ };
32762
+ }
32763
+ return decision;
32764
+ }
32551
32765
  };
32552
32766
  function createPermissionPolicy() {
32553
32767
  return new DefaultPermissionPolicy();
@@ -32587,108 +32801,135 @@ var ProviderRegistry = class {
32587
32801
  function createProviderRegistry() {
32588
32802
  return new ProviderRegistry();
32589
32803
  }
32590
-
32591
- // src/runtime/agent-runtime.ts
32592
- var AgentRuntime = class {
32593
- constructor(options) {
32594
- this.options = options;
32595
- this.providerRegistry = createProviderRegistry();
32596
- this.toolRegistry = options.toolRegistry ?? createFullToolRegistry();
32597
- this.sessionStore = options.sessionStore ?? createSessionStore({});
32598
- this.permissionPolicy = options.permissionPolicy ?? createPermissionPolicy();
32599
- this.eventLog = options.eventLog ?? (options.eventLogPath ? createFileEventLog(options.eventLogPath) : createEventLog());
32600
- this.providerType = options.providerType;
32601
- this.model = options.model ?? options.providerConfig?.model ?? getDefaultModel(options.providerType);
32804
+ function createSessionId() {
32805
+ return `rt_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
32806
+ }
32807
+ function cloneSession(session) {
32808
+ return structuredClone(session);
32809
+ }
32810
+ var InMemoryRuntimeSessionStore = class {
32811
+ sessions = /* @__PURE__ */ new Map();
32812
+ create(options = {}) {
32813
+ const now = (/* @__PURE__ */ new Date()).toISOString();
32814
+ const session = {
32815
+ id: options.id ?? createSessionId(),
32816
+ createdAt: now,
32817
+ updatedAt: now,
32818
+ mode: options.mode ?? "ask",
32819
+ messages: options.messages ? options.messages.map((message) => ({ ...message })) : [],
32820
+ instructions: options.instructions,
32821
+ metadata: { ...options.metadata }
32822
+ };
32823
+ this.sessions.set(session.id, cloneSession(session));
32824
+ return cloneSession(session);
32602
32825
  }
32603
- options;
32604
- providerRegistry;
32605
- toolRegistry;
32606
- sessionStore;
32607
- permissionPolicy;
32608
- eventLog;
32609
- providerType;
32610
- model;
32611
- async initialize() {
32612
- const providerInjected = Boolean(this.options.provider);
32613
- const provider = this.options.provider ?? await this.providerRegistry.createProvider(this.providerType, {
32614
- ...this.options.providerConfig,
32615
- model: this.getModel()
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() });
32826
+ get(id) {
32827
+ const session = this.sessions.get(id);
32828
+ return session ? cloneSession(session) : void 0;
32829
+ }
32830
+ update(session) {
32831
+ const updated = {
32832
+ ...session,
32833
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
32834
+ messages: session.messages.map((message) => ({ ...message })),
32835
+ metadata: { ...session.metadata }
32836
+ };
32837
+ this.sessions.set(updated.id, cloneSession(updated));
32838
+ return cloneSession(updated);
32624
32839
  }
32625
- getModel() {
32626
- return this.model;
32840
+ list() {
32841
+ return [...this.sessions.values()].map(cloneSession);
32627
32842
  }
32628
- updateProvider(providerType, model2, provider) {
32629
- this.providerType = providerType;
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
- });
32843
+ delete(id) {
32844
+ return this.sessions.delete(id);
32636
32845
  }
32637
- publishToGlobalBridge(provider) {
32638
- if (this.options.publishToGlobalBridge !== true) return;
32639
- setAgentProvider(provider);
32640
- setAgentToolRegistry(this.toolRegistry);
32846
+ };
32847
+ var FileRuntimeSessionStore = class {
32848
+ constructor(filePath) {
32849
+ this.filePath = filePath;
32850
+ mkdirSync(dirname(filePath), { recursive: true });
32851
+ this.sessions = this.readSessionsFromDisk();
32641
32852
  }
32642
- snapshot() {
32643
- const capability = this.providerRegistry.getCapability(this.providerType, this.getModel());
32644
- const toolNames = this.toolRegistry.getAll().map((tool) => tool.name).sort();
32645
- return {
32646
- provider: {
32647
- type: this.providerType,
32648
- model: this.getModel(),
32649
- capability
32650
- },
32651
- tools: {
32652
- count: toolNames.length,
32653
- names: toolNames
32654
- },
32655
- modes: listAgentModes()
32853
+ filePath;
32854
+ sessions = /* @__PURE__ */ new Map();
32855
+ create(options = {}) {
32856
+ const now = (/* @__PURE__ */ new Date()).toISOString();
32857
+ const session = {
32858
+ id: options.id ?? createSessionId(),
32859
+ createdAt: now,
32860
+ updatedAt: now,
32861
+ mode: options.mode ?? "ask",
32862
+ messages: options.messages ? options.messages.map((message) => ({ ...message })) : [],
32863
+ instructions: options.instructions,
32864
+ metadata: { ...options.metadata }
32656
32865
  };
32866
+ const sessions = this.readSessionsFromDisk();
32867
+ sessions.set(session.id, cloneSession(session));
32868
+ this.sessions = sessions;
32869
+ this.persist(sessions);
32870
+ return cloneSession(session);
32657
32871
  }
32658
- assertToolAllowed(mode, toolName) {
32659
- const tool = this.toolRegistry.get(toolName);
32660
- if (!tool) {
32661
- this.eventLog.record("tool.blocked", {
32662
- mode,
32663
- tool: toolName,
32664
- reason: "Tool not registered."
32665
- });
32666
- return false;
32872
+ get(id) {
32873
+ this.sessions = this.readSessionsFromDisk();
32874
+ const session = this.sessions.get(id);
32875
+ return session ? cloneSession(session) : void 0;
32876
+ }
32877
+ update(session) {
32878
+ const updated = {
32879
+ ...session,
32880
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
32881
+ messages: session.messages.map((message) => ({ ...message })),
32882
+ metadata: { ...session.metadata }
32883
+ };
32884
+ const sessions = this.readSessionsFromDisk();
32885
+ sessions.set(updated.id, cloneSession(updated));
32886
+ this.sessions = sessions;
32887
+ this.persist(sessions);
32888
+ return cloneSession(updated);
32889
+ }
32890
+ list() {
32891
+ this.sessions = this.readSessionsFromDisk();
32892
+ return [...this.sessions.values()].map(cloneSession);
32893
+ }
32894
+ delete(id) {
32895
+ const sessions = this.readSessionsFromDisk();
32896
+ const deleted = sessions.delete(id);
32897
+ this.sessions = sessions;
32898
+ if (deleted) this.persist(sessions);
32899
+ return deleted;
32900
+ }
32901
+ readSessionsFromDisk() {
32902
+ let raw;
32903
+ try {
32904
+ raw = readFileSync(this.filePath, "utf-8");
32905
+ } catch (error) {
32906
+ if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
32907
+ return /* @__PURE__ */ new Map();
32908
+ }
32909
+ throw error;
32667
32910
  }
32668
- const decision = this.permissionPolicy.canExecuteTool(mode, tool);
32669
- this.eventLog.record(decision.allowed ? "tool.allowed" : "tool.blocked", {
32670
- mode,
32671
- tool: toolName,
32672
- ...decision
32673
- });
32674
- return decision.allowed;
32911
+ if (!raw.trim()) return /* @__PURE__ */ new Map();
32912
+ const parsed = JSON.parse(raw);
32913
+ if (parsed.version !== 1 || !Array.isArray(parsed.sessions)) {
32914
+ throw new Error(`Unsupported runtime session store format: ${this.filePath}`);
32915
+ }
32916
+ return new Map(parsed.sessions.map((session) => [session.id, cloneSession(session)]));
32917
+ }
32918
+ persist(sessions) {
32919
+ const payload = {
32920
+ version: 1,
32921
+ sessions: [...sessions.values()].map(cloneSession)
32922
+ };
32923
+ const tempPath = `${this.filePath}.${randomUUID()}.tmp`;
32924
+ writeFileSync(tempPath, JSON.stringify(payload, null, 2) + "\n", "utf-8");
32925
+ renameSync(tempPath, this.filePath);
32675
32926
  }
32676
32927
  };
32677
- async function createAgentRuntime(options) {
32678
- const runtime = new AgentRuntime(options);
32679
- await runtime.initialize();
32680
- return runtime;
32928
+ function createRuntimeSessionStore() {
32929
+ return new InMemoryRuntimeSessionStore();
32681
32930
  }
32682
-
32683
- // src/runtime/extension-manifests.ts
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
- };
32931
+ function createFileRuntimeSessionStore(filePath) {
32932
+ return new FileRuntimeSessionStore(filePath);
32692
32933
  }
32693
32934
 
32694
32935
  // src/runtime/workflow-registry.ts
@@ -32699,7 +32940,32 @@ function cloneWorkflow(workflow) {
32699
32940
  steps: workflow.steps.map((step) => ({
32700
32941
  ...step,
32701
32942
  requiredTools: [...step.requiredTools]
32702
- }))
32943
+ })),
32944
+ nodes: workflow.nodes?.map((node) => ({
32945
+ ...node,
32946
+ dependsOn: node.dependsOn ? [...node.dependsOn] : void 0,
32947
+ requiredTools: node.requiredTools ? [...node.requiredTools] : void 0,
32948
+ gates: node.gates ? [...node.gates] : void 0,
32949
+ retryPolicy: node.retryPolicy ? { ...node.retryPolicy } : void 0
32950
+ })),
32951
+ edges: workflow.edges?.map((edge) => ({ ...edge })),
32952
+ gates: workflow.gates?.map((gate) => ({ ...gate })),
32953
+ retryPolicy: workflow.retryPolicy ? { ...workflow.retryPolicy } : void 0
32954
+ };
32955
+ }
32956
+ function workflowToAgentGraph(workflow) {
32957
+ const nodes = workflow.nodes ?? workflow.steps.map((step, index) => ({
32958
+ id: step.id,
32959
+ description: step.description,
32960
+ requiredTools: [...step.requiredTools],
32961
+ risk: step.risk,
32962
+ dependsOn: index > 0 ? [workflow.steps[index - 1].id] : []
32963
+ }));
32964
+ return {
32965
+ nodes,
32966
+ edges: workflow.edges,
32967
+ gates: workflow.gates,
32968
+ parallelism: workflow.parallelism
32703
32969
  };
32704
32970
  }
32705
32971
  var WorkflowCatalog = class {
@@ -32710,6 +32976,12 @@ var WorkflowCatalog = class {
32710
32976
  }
32711
32977
  }
32712
32978
  register(workflow) {
32979
+ const validation = validateAgentGraph(workflowToAgentGraph(workflow));
32980
+ if (!validation.valid) {
32981
+ throw new Error(
32982
+ `Invalid workflow graph for '${workflow.id}': ${validation.issues.map((issue) => issue.message).join("; ")}`
32983
+ );
32984
+ }
32713
32985
  this.workflows.set(workflow.id, cloneWorkflow(workflow));
32714
32986
  }
32715
32987
  get(id) {
@@ -32735,7 +33007,8 @@ var WorkflowCatalog = class {
32735
33007
  workflowId,
32736
33008
  planId: plan.id,
32737
33009
  replayable: workflow.replayable,
32738
- checks: workflow.checks
33010
+ checks: workflow.checks,
33011
+ graphLevels: validateAgentGraph(workflowToAgentGraph(workflow)).levels
32739
33012
  });
32740
33013
  return plan;
32741
33014
  }
@@ -32883,11 +33156,1213 @@ function createWorkflowRegistry(workflows) {
32883
33156
  return createWorkflowCatalog(workflows);
32884
33157
  }
32885
33158
 
33159
+ // src/runtime/workflow-engine.ts
33160
+ var WorkflowEngine = class {
33161
+ constructor(catalog = createWorkflowCatalog(), eventLog = createEventLog()) {
33162
+ this.catalog = catalog;
33163
+ this.eventLog = eventLog;
33164
+ }
33165
+ catalog;
33166
+ eventLog;
33167
+ handlers = /* @__PURE__ */ new Map();
33168
+ registerHandler(workflowId, handler) {
33169
+ if (!this.catalog.get(workflowId)) {
33170
+ throw new Error(`Unknown workflow: ${workflowId}`);
33171
+ }
33172
+ this.handlers.set(workflowId, handler);
33173
+ }
33174
+ createPlan(workflowId, input) {
33175
+ return this.catalog.createPlan(workflowId, input, this.eventLog);
33176
+ }
33177
+ async run(request) {
33178
+ const workflow = this.catalog.get(request.workflowId);
33179
+ if (!workflow) {
33180
+ throw new Error(`Unknown workflow: ${request.workflowId}`);
33181
+ }
33182
+ const handler = this.handlers.get(request.workflowId);
33183
+ if (!handler) {
33184
+ throw new Error(`No handler registered for workflow: ${request.workflowId}`);
33185
+ }
33186
+ const plan = request.plan ?? this.createPlan(request.workflowId, request.input);
33187
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
33188
+ const runId = `${request.workflowId}-run-${Date.now().toString(36)}`;
33189
+ this.eventLog.record("workflow.started", {
33190
+ workflowId: request.workflowId,
33191
+ planId: plan.id,
33192
+ runId
33193
+ });
33194
+ try {
33195
+ const output = await handler(request.input, {
33196
+ workflow,
33197
+ plan,
33198
+ eventLog: this.eventLog
33199
+ });
33200
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
33201
+ const result = {
33202
+ id: runId,
33203
+ workflowId: request.workflowId,
33204
+ status: "completed",
33205
+ output,
33206
+ startedAt,
33207
+ completedAt
33208
+ };
33209
+ this.eventLog.record("workflow.completed", {
33210
+ workflowId: request.workflowId,
33211
+ planId: plan.id,
33212
+ runId
33213
+ });
33214
+ return result;
33215
+ } catch (error) {
33216
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
33217
+ const message = error instanceof Error ? error.message : String(error);
33218
+ this.eventLog.record("workflow.failed", {
33219
+ workflowId: request.workflowId,
33220
+ planId: plan.id,
33221
+ runId,
33222
+ error: message
33223
+ });
33224
+ return {
33225
+ id: runId,
33226
+ workflowId: request.workflowId,
33227
+ status: "failed",
33228
+ output: null,
33229
+ startedAt,
33230
+ completedAt,
33231
+ error: message
33232
+ };
33233
+ }
33234
+ }
33235
+ };
33236
+ function createWorkflowEngine(catalog, eventLog) {
33237
+ return new WorkflowEngine(catalog, eventLog);
33238
+ }
33239
+
33240
+ // src/runtime/agent-runtime.ts
33241
+ var AgentRuntime = class {
33242
+ constructor(options) {
33243
+ this.options = options;
33244
+ this.providerRegistry = createProviderRegistry();
33245
+ this.toolRegistry = options.toolRegistry ?? createFullToolRegistry();
33246
+ this.sessionStore = options.sessionStore;
33247
+ this.runtimeSessionStore = options.runtimeSessionStore ?? createRuntimeSessionStore();
33248
+ this.eventLog = options.eventLog ?? (options.eventLogPath ? createFileEventLog(options.eventLogPath) : createEventLog());
33249
+ this.workflowEngine = options.workflowEngine ?? createWorkflowEngine(void 0, this.eventLog);
33250
+ this.permissionPolicy = options.permissionPolicy ?? createPermissionPolicy();
33251
+ this.turnRunner = options.turnRunner ?? createDefaultRuntimeTurnRunner();
33252
+ this.providerType = options.providerType;
33253
+ this.model = options.model ?? options.providerConfig?.model ?? getDefaultModel(options.providerType);
33254
+ }
33255
+ options;
33256
+ providerRegistry;
33257
+ toolRegistry;
33258
+ sessionStore;
33259
+ runtimeSessionStore;
33260
+ workflowEngine;
33261
+ permissionPolicy;
33262
+ eventLog;
33263
+ turnRunner;
33264
+ providerType;
33265
+ model;
33266
+ provider;
33267
+ async initialize() {
33268
+ const providerInjected = Boolean(this.options.provider);
33269
+ const provider = this.options.provider ?? await this.providerRegistry.createProvider(this.providerType, {
33270
+ ...this.options.providerConfig,
33271
+ model: this.getModel()
33272
+ });
33273
+ this.provider = provider;
33274
+ this.publishToGlobalBridge(provider);
33275
+ this.eventLog.record(providerInjected ? "provider.attached" : "provider.created", {
33276
+ provider: this.providerType,
33277
+ model: this.getModel(),
33278
+ createdByRuntime: !providerInjected
33279
+ });
33280
+ this.eventLog.record("runtime.initialized", { snapshot: this.snapshot() });
33281
+ }
33282
+ getModel() {
33283
+ return this.model;
33284
+ }
33285
+ updateProvider(providerType, model2, provider) {
33286
+ this.providerType = providerType;
33287
+ this.model = model2 ?? getDefaultModel(providerType);
33288
+ this.provider = provider;
33289
+ this.publishToGlobalBridge(provider);
33290
+ this.eventLog.record("provider.updated", {
33291
+ provider: this.providerType,
33292
+ model: this.model
33293
+ });
33294
+ }
33295
+ publishToGlobalBridge(provider) {
33296
+ if (this.options.publishToGlobalBridge !== true) return;
33297
+ setAgentProvider(provider);
33298
+ setAgentToolRegistry(this.toolRegistry);
33299
+ }
33300
+ snapshot() {
33301
+ const capability = this.providerRegistry.getCapability(this.providerType, this.getModel());
33302
+ const toolNames = this.toolRegistry.getAll().map((tool) => tool.name).sort();
33303
+ return {
33304
+ provider: {
33305
+ type: this.providerType,
33306
+ model: this.getModel(),
33307
+ capability
33308
+ },
33309
+ tools: {
33310
+ count: toolNames.length,
33311
+ names: toolNames
33312
+ },
33313
+ modes: listAgentModes()
33314
+ };
33315
+ }
33316
+ createSession(options = {}) {
33317
+ const session = this.runtimeSessionStore.create(options);
33318
+ this.eventLog.record("session.created", {
33319
+ sessionId: session.id,
33320
+ mode: session.mode,
33321
+ metadataKeys: Object.keys(session.metadata).sort()
33322
+ });
33323
+ return session;
33324
+ }
33325
+ getSession(sessionId) {
33326
+ return this.runtimeSessionStore.get(sessionId);
33327
+ }
33328
+ listSessions() {
33329
+ return this.runtimeSessionStore.list();
33330
+ }
33331
+ async runTurn(input) {
33332
+ const provider = this.provider;
33333
+ if (!provider) {
33334
+ throw new Error("Runtime provider is not initialized.");
33335
+ }
33336
+ const session = input.sessionId ? this.runtimeSessionStore.get(input.sessionId) : this.createSession({ mode: input.mode, metadata: input.metadata });
33337
+ if (!session) {
33338
+ throw new Error(`Runtime session not found: ${input.sessionId}`);
33339
+ }
33340
+ const effectiveSession = input.mode && input.mode !== session.mode ? { ...session, mode: input.mode } : session;
33341
+ this.eventLog.record("turn.started", {
33342
+ sessionId: effectiveSession.id,
33343
+ provider: this.providerType,
33344
+ model: this.getModel(),
33345
+ mode: effectiveSession.mode,
33346
+ runtimeApi: true
33347
+ });
33348
+ try {
33349
+ const result = await this.turnRunner.run(input, {
33350
+ runtime: this,
33351
+ session: effectiveSession,
33352
+ provider,
33353
+ toolRegistry: this.toolRegistry,
33354
+ permissionPolicy: this.permissionPolicy,
33355
+ eventLog: this.eventLog
33356
+ });
33357
+ const updatedSession = this.runtimeSessionStore.update({
33358
+ ...effectiveSession,
33359
+ messages: [
33360
+ ...effectiveSession.messages,
33361
+ { role: "user", content: input.content },
33362
+ { role: "assistant", content: result.content }
33363
+ ]
33364
+ });
33365
+ this.eventLog.record("session.updated", {
33366
+ sessionId: updatedSession.id,
33367
+ messages: updatedSession.messages.length
33368
+ });
33369
+ this.eventLog.record("turn.completed", {
33370
+ sessionId: updatedSession.id,
33371
+ inputTokens: result.usage.inputTokens,
33372
+ outputTokens: result.usage.outputTokens,
33373
+ model: result.model,
33374
+ runtimeApi: true
33375
+ });
33376
+ return { ...result, sessionId: updatedSession.id, mode: updatedSession.mode };
33377
+ } catch (error) {
33378
+ this.eventLog.record("turn.failed", {
33379
+ sessionId: effectiveSession.id,
33380
+ error: error instanceof Error ? error.message : String(error),
33381
+ runtimeApi: true
33382
+ });
33383
+ throw error;
33384
+ }
33385
+ }
33386
+ async *streamTurn(input) {
33387
+ const provider = this.provider;
33388
+ if (!provider) {
33389
+ throw new Error("Runtime provider is not initialized.");
33390
+ }
33391
+ const session = input.sessionId ? this.runtimeSessionStore.get(input.sessionId) : this.createSession({ mode: input.mode, metadata: input.metadata });
33392
+ if (!session) {
33393
+ throw new Error(`Runtime session not found: ${input.sessionId}`);
33394
+ }
33395
+ const effectiveSession = input.mode && input.mode !== session.mode ? { ...session, mode: input.mode } : session;
33396
+ const messages = [
33397
+ ...effectiveSession.messages,
33398
+ {
33399
+ role: "user",
33400
+ content: input.content
33401
+ }
33402
+ ];
33403
+ this.eventLog.record("turn.started", {
33404
+ sessionId: effectiveSession.id,
33405
+ provider: this.providerType,
33406
+ model: this.getModel(),
33407
+ mode: effectiveSession.mode,
33408
+ streaming: true,
33409
+ runtimeApi: true
33410
+ });
33411
+ let content = "";
33412
+ let completed = false;
33413
+ let failed = false;
33414
+ try {
33415
+ for await (const chunk of provider.stream(messages, {
33416
+ model: input.options?.model,
33417
+ maxTokens: input.options?.maxTokens,
33418
+ temperature: input.options?.temperature,
33419
+ stopSequences: input.options?.stopSequences,
33420
+ system: effectiveSession.instructions ?? input.options?.system,
33421
+ timeout: input.options?.timeout,
33422
+ signal: input.options?.signal,
33423
+ thinking: input.options?.thinking
33424
+ })) {
33425
+ if (chunk.type === "text" && chunk.text) {
33426
+ content += chunk.text;
33427
+ yield {
33428
+ type: "text",
33429
+ sessionId: effectiveSession.id,
33430
+ text: chunk.text
33431
+ };
33432
+ }
33433
+ }
33434
+ const updatedSession = this.runtimeSessionStore.update({
33435
+ ...effectiveSession,
33436
+ messages: [
33437
+ ...effectiveSession.messages,
33438
+ { role: "user", content: input.content },
33439
+ { role: "assistant", content }
33440
+ ]
33441
+ });
33442
+ const result = {
33443
+ sessionId: updatedSession.id,
33444
+ content,
33445
+ usage: {
33446
+ inputTokens: provider.countTokens(input.content),
33447
+ outputTokens: provider.countTokens(content),
33448
+ estimated: true
33449
+ },
33450
+ model: input.options?.model ?? this.getModel(),
33451
+ mode: updatedSession.mode
33452
+ };
33453
+ this.eventLog.record("session.updated", {
33454
+ sessionId: updatedSession.id,
33455
+ messages: updatedSession.messages.length
33456
+ });
33457
+ this.eventLog.record("turn.completed", {
33458
+ sessionId: updatedSession.id,
33459
+ inputTokens: result.usage.inputTokens,
33460
+ outputTokens: result.usage.outputTokens,
33461
+ model: result.model,
33462
+ streaming: true,
33463
+ runtimeApi: true
33464
+ });
33465
+ completed = true;
33466
+ yield { type: "done", sessionId: updatedSession.id, result };
33467
+ } catch (error) {
33468
+ failed = true;
33469
+ const message = error instanceof Error ? error.message : String(error);
33470
+ this.eventLog.record("turn.failed", {
33471
+ sessionId: effectiveSession.id,
33472
+ error: message,
33473
+ streaming: true,
33474
+ runtimeApi: true
33475
+ });
33476
+ yield {
33477
+ type: "error",
33478
+ sessionId: effectiveSession.id,
33479
+ error: message
33480
+ };
33481
+ } finally {
33482
+ if (!completed && !failed) {
33483
+ this.eventLog.record("turn.cancelled", {
33484
+ sessionId: effectiveSession.id,
33485
+ outputTokens: provider.countTokens(content),
33486
+ streaming: true,
33487
+ runtimeApi: true
33488
+ });
33489
+ }
33490
+ }
33491
+ }
33492
+ async executeTool(input) {
33493
+ const startedAt = performance.now();
33494
+ const session = input.sessionId ? this.getSession(input.sessionId) : void 0;
33495
+ if (input.sessionId && !session) {
33496
+ const decision2 = {
33497
+ allowed: false,
33498
+ reason: `Runtime session not found: ${input.sessionId}`,
33499
+ risk: "read-only"
33500
+ };
33501
+ this.eventLog.record("tool.blocked", {
33502
+ sessionId: input.sessionId,
33503
+ mode: input.mode ?? "ask",
33504
+ tool: input.toolName,
33505
+ reason: decision2.reason,
33506
+ runtimeApi: true
33507
+ });
33508
+ return {
33509
+ toolName: input.toolName,
33510
+ success: false,
33511
+ error: decision2.reason,
33512
+ duration: performance.now() - startedAt,
33513
+ decision: decision2
33514
+ };
33515
+ }
33516
+ const mode = input.mode ?? session?.mode ?? "ask";
33517
+ const tool = this.toolRegistry.get(input.toolName);
33518
+ if (!tool) {
33519
+ const decision2 = {
33520
+ allowed: false,
33521
+ reason: "Tool not registered.",
33522
+ risk: "read-only"
33523
+ };
33524
+ this.eventLog.record("tool.blocked", {
33525
+ sessionId: input.sessionId,
33526
+ mode,
33527
+ tool: input.toolName,
33528
+ reason: decision2.reason,
33529
+ runtimeApi: true
33530
+ });
33531
+ return {
33532
+ toolName: input.toolName,
33533
+ success: false,
33534
+ error: decision2.reason,
33535
+ duration: performance.now() - startedAt,
33536
+ decision: decision2
33537
+ };
33538
+ }
33539
+ const decision = this.permissionPolicy.canExecuteToolInput ? this.permissionPolicy.canExecuteToolInput(mode, tool, input.input) : this.permissionPolicy.canExecuteTool(mode, tool);
33540
+ if (!decision.allowed || decision.requiresConfirmation && input.confirmed !== true) {
33541
+ const reason = decision.reason ?? (decision.requiresConfirmation ? "Tool requires explicit runtime confirmation." : "Tool is not allowed.");
33542
+ this.eventLog.record("tool.blocked", {
33543
+ sessionId: input.sessionId,
33544
+ mode,
33545
+ tool: input.toolName,
33546
+ reason,
33547
+ risk: decision.risk,
33548
+ requiresConfirmation: decision.requiresConfirmation,
33549
+ runtimeApi: true
33550
+ });
33551
+ return {
33552
+ toolName: input.toolName,
33553
+ success: false,
33554
+ error: reason,
33555
+ duration: performance.now() - startedAt,
33556
+ decision
33557
+ };
33558
+ }
33559
+ this.eventLog.record("tool.started", {
33560
+ sessionId: input.sessionId,
33561
+ mode,
33562
+ tool: input.toolName,
33563
+ risk: decision.risk,
33564
+ runtimeApi: true,
33565
+ metadataKeys: Object.keys(input.metadata ?? {}).sort()
33566
+ });
33567
+ const result = await this.toolRegistry.execute(input.toolName, input.input);
33568
+ this.eventLog.record("tool.completed", {
33569
+ sessionId: input.sessionId,
33570
+ mode,
33571
+ tool: input.toolName,
33572
+ success: result.success,
33573
+ duration: result.duration,
33574
+ runtimeApi: true
33575
+ });
33576
+ return {
33577
+ toolName: input.toolName,
33578
+ success: result.success,
33579
+ output: result.data,
33580
+ error: result.error,
33581
+ duration: result.duration,
33582
+ decision
33583
+ };
33584
+ }
33585
+ assertToolAllowed(mode, toolName, input) {
33586
+ const tool = this.toolRegistry.get(toolName);
33587
+ if (!tool) {
33588
+ this.eventLog.record("tool.blocked", {
33589
+ mode,
33590
+ tool: toolName,
33591
+ reason: "Tool not registered."
33592
+ });
33593
+ return false;
33594
+ }
33595
+ const decision = input && this.permissionPolicy.canExecuteToolInput ? this.permissionPolicy.canExecuteToolInput(mode, tool, input) : this.permissionPolicy.canExecuteTool(mode, tool);
33596
+ this.eventLog.record(decision.allowed ? "tool.allowed" : "tool.blocked", {
33597
+ mode,
33598
+ tool: toolName,
33599
+ ...decision
33600
+ });
33601
+ return decision.allowed;
33602
+ }
33603
+ };
33604
+ async function createAgentRuntime(options) {
33605
+ const runtime = new AgentRuntime(options);
33606
+ await runtime.initialize();
33607
+ return runtime;
33608
+ }
33609
+
33610
+ // src/runtime/tool-calling-turn-runner.ts
33611
+ function runtimeWithTools(runtime) {
33612
+ if (runtime && typeof runtime === "object" && "executeTool" in runtime && typeof runtime.executeTool === "function") {
33613
+ return runtime;
33614
+ }
33615
+ throw new Error("ToolCallingRuntimeTurnRunner requires a runtime with executeTool().");
33616
+ }
33617
+ function toolResultToContent(result) {
33618
+ if (!result.success) {
33619
+ return `Error: ${result.error ?? "Tool failed."}`;
33620
+ }
33621
+ if (typeof result.output === "string") return result.output;
33622
+ return JSON.stringify(result.output ?? null);
33623
+ }
33624
+ var ToolCallingRuntimeTurnRunner = class {
33625
+ maxToolIterations;
33626
+ constructor(options = {}) {
33627
+ this.maxToolIterations = options.maxToolIterations ?? 10;
33628
+ }
33629
+ async run(input, context) {
33630
+ const runtime = runtimeWithTools(context.runtime);
33631
+ const messages = [
33632
+ ...context.session.messages,
33633
+ {
33634
+ role: "user",
33635
+ content: input.content
33636
+ }
33637
+ ];
33638
+ const tools = context.toolRegistry.getToolDefinitionsForLLM();
33639
+ const confirmedTools = new Set(input.confirmedTools ?? []);
33640
+ let inputTokens = 0;
33641
+ let outputTokens = 0;
33642
+ let lastModel = input.options?.model ?? context.provider.id;
33643
+ for (let iteration = 0; iteration < this.maxToolIterations; iteration++) {
33644
+ const response = await context.provider.chatWithTools(messages, {
33645
+ tools,
33646
+ model: input.options?.model,
33647
+ maxTokens: input.options?.maxTokens,
33648
+ temperature: input.options?.temperature,
33649
+ stopSequences: input.options?.stopSequences,
33650
+ system: context.session.instructions ?? input.options?.system,
33651
+ timeout: input.options?.timeout,
33652
+ signal: input.options?.signal,
33653
+ thinking: input.options?.thinking
33654
+ });
33655
+ inputTokens += response.usage.inputTokens;
33656
+ outputTokens += response.usage.outputTokens;
33657
+ lastModel = response.model;
33658
+ if (response.stopReason !== "tool_use" || response.toolCalls.length === 0) {
33659
+ return {
33660
+ sessionId: context.session.id,
33661
+ content: response.content,
33662
+ usage: { inputTokens, outputTokens },
33663
+ model: response.model,
33664
+ mode: context.session.mode
33665
+ };
33666
+ }
33667
+ const assistantContent = [];
33668
+ if (response.content.trim().length > 0) {
33669
+ assistantContent.push({ type: "text", text: response.content });
33670
+ }
33671
+ for (const toolCall of response.toolCalls) {
33672
+ assistantContent.push({
33673
+ type: "tool_use",
33674
+ id: toolCall.id,
33675
+ name: toolCall.name,
33676
+ input: toolCall.input,
33677
+ geminiThoughtSignature: toolCall.geminiThoughtSignature
33678
+ });
33679
+ }
33680
+ messages.push({
33681
+ role: "assistant",
33682
+ content: assistantContent
33683
+ });
33684
+ const toolResults = [];
33685
+ for (const toolCall of response.toolCalls) {
33686
+ const result = await runtime.executeTool({
33687
+ sessionId: context.session.id,
33688
+ mode: context.session.mode,
33689
+ toolName: toolCall.name,
33690
+ input: toolCall.input,
33691
+ confirmed: confirmedTools.has(toolCall.name),
33692
+ metadata: input.metadata
33693
+ });
33694
+ toolResults.push({
33695
+ type: "tool_result",
33696
+ tool_use_id: toolCall.id,
33697
+ content: toolResultToContent(result),
33698
+ is_error: !result.success
33699
+ });
33700
+ }
33701
+ messages.push({
33702
+ role: "user",
33703
+ content: toolResults
33704
+ });
33705
+ }
33706
+ return {
33707
+ sessionId: context.session.id,
33708
+ content: "The tool-calling runtime reached its maximum tool iteration budget.",
33709
+ usage: { inputTokens, outputTokens },
33710
+ model: lastModel,
33711
+ mode: context.session.mode
33712
+ };
33713
+ }
33714
+ };
33715
+ function createToolCallingRuntimeTurnRunner(options) {
33716
+ return new ToolCallingRuntimeTurnRunner(options);
33717
+ }
33718
+ var HttpRequestError = class extends Error {
33719
+ constructor(message, status) {
33720
+ super(message);
33721
+ this.status = status;
33722
+ }
33723
+ status;
33724
+ };
33725
+ async function readJsonBody(request, maxBodyBytes) {
33726
+ const chunks = [];
33727
+ let size = 0;
33728
+ for await (const chunk of request) {
33729
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
33730
+ size += buffer.length;
33731
+ if (size > maxBodyBytes) {
33732
+ throw new HttpRequestError(`Request body exceeds ${maxBodyBytes} bytes.`, 413);
33733
+ }
33734
+ chunks.push(buffer);
33735
+ }
33736
+ const raw = Buffer.concat(chunks).toString("utf-8").trim();
33737
+ try {
33738
+ return raw ? JSON.parse(raw) : {};
33739
+ } catch {
33740
+ throw new HttpRequestError("Invalid JSON request body.", 400);
33741
+ }
33742
+ }
33743
+ function sendJson(response, status, body) {
33744
+ response.statusCode = status;
33745
+ response.setHeader("content-type", "application/json; charset=utf-8");
33746
+ response.end(JSON.stringify(body, null, 2));
33747
+ }
33748
+ function notFound(response) {
33749
+ sendJson(response, 404, { error: "Not found" });
33750
+ }
33751
+ function assertValidMode(mode) {
33752
+ if (mode === void 0) return void 0;
33753
+ if (typeof mode === "string" && isAgentMode(mode)) return mode;
33754
+ throw new HttpRequestError("Invalid runtime mode.", 400);
33755
+ }
33756
+ function createRuntimeHttpServer(runtime, options = {}) {
33757
+ const maxBodyBytes = options.maxBodyBytes ?? 1024 * 1024;
33758
+ return createServer(async (request, response) => {
33759
+ try {
33760
+ const url = new URL(request.url ?? "/", "http://localhost");
33761
+ const parts = url.pathname.split("/").filter(Boolean);
33762
+ if (request.method === "POST" && url.pathname === "/sessions") {
33763
+ const body = await readJsonBody(request, maxBodyBytes);
33764
+ const session = runtime.createSession({
33765
+ mode: assertValidMode(body.mode),
33766
+ instructions: body.instructions,
33767
+ metadata: body.metadata
33768
+ });
33769
+ sendJson(response, 201, session);
33770
+ return;
33771
+ }
33772
+ if (request.method === "GET" && parts[0] === "sessions" && parts[1] && parts.length === 2) {
33773
+ const session = runtime.getSession(parts[1]);
33774
+ if (!session) {
33775
+ notFound(response);
33776
+ return;
33777
+ }
33778
+ sendJson(response, 200, session);
33779
+ return;
33780
+ }
33781
+ if (request.method === "POST" && parts[0] === "sessions" && parts[1] && parts[2] === "messages") {
33782
+ const body = await readJsonBody(request, maxBodyBytes);
33783
+ if (!body.content || typeof body.content !== "string") {
33784
+ sendJson(response, 400, { error: "content is required" });
33785
+ return;
33786
+ }
33787
+ if (!runtime.getSession(parts[1])) {
33788
+ notFound(response);
33789
+ return;
33790
+ }
33791
+ const result = await runtime.runTurn({
33792
+ ...body,
33793
+ mode: assertValidMode(body.mode),
33794
+ sessionId: parts[1]
33795
+ });
33796
+ sendJson(response, 200, result);
33797
+ return;
33798
+ }
33799
+ if (request.method === "GET" && parts[0] === "sessions" && parts[1] && parts[2] === "events") {
33800
+ const events = runtime.eventLog.list().filter((event) => event.data["sessionId"] === parts[1]);
33801
+ sendJson(response, 200, { events });
33802
+ return;
33803
+ }
33804
+ if (request.method === "GET" && url.pathname === "/state") {
33805
+ sendJson(response, 200, runtime.snapshot());
33806
+ return;
33807
+ }
33808
+ notFound(response);
33809
+ } catch (error) {
33810
+ const status = error instanceof HttpRequestError ? error.status : 500;
33811
+ sendJson(response, status, {
33812
+ error: error instanceof Error ? error.message : String(error)
33813
+ });
33814
+ }
33815
+ });
33816
+ }
33817
+
33818
+ // src/runtime/extension-manifests.ts
33819
+ function createMcpToolPolicy(server, tool, risk, allowedModes = ["ask", "plan", "build", "debug", "review", "architect"]) {
33820
+ return {
33821
+ server,
33822
+ tool,
33823
+ risk,
33824
+ requiresConfirmation: risk === "destructive" || risk === "secrets-sensitive",
33825
+ allowedModes
33826
+ };
33827
+ }
33828
+
33829
+ // src/runtime/guardrails.ts
33830
+ var DEFAULT_REDACTION = "[REDACTED]";
33831
+ var SECRET_PATTERNS = [
33832
+ { id: "openai-api-key", pattern: /\bsk-[A-Za-z0-9_-]{20,}\b/g },
33833
+ { id: "anthropic-api-key", pattern: /\bsk-ant-[A-Za-z0-9_-]{20,}\b/g },
33834
+ { id: "github-token", pattern: /\bgh[pousr]_[A-Za-z0-9_]{20,}\b/g },
33835
+ { id: "generic-bearer-token", pattern: /\bBearer\s+[A-Za-z0-9._~+/=-]{20,}\b/gi },
33836
+ {
33837
+ id: "private-key",
33838
+ pattern: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g
33839
+ }
33840
+ ];
33841
+ var PROMPT_INJECTION_PATTERNS = [
33842
+ {
33843
+ id: "ignore-instructions",
33844
+ pattern: /\b(ignore|forget|override)\b.{0,40}\b(instructions|system|developer)\b/i
33845
+ },
33846
+ {
33847
+ id: "reveal-prompt",
33848
+ pattern: /\b(reveal|print|show|dump)\b.{0,40}\b(system prompt|instructions|developer message)\b/i
33849
+ },
33850
+ {
33851
+ id: "tool-exfiltration",
33852
+ pattern: /\b(use|call|run)\b.{0,40}\b(tool|shell|filesystem|git)\b.{0,40}\b(secret|token|key)\b/i
33853
+ }
33854
+ ];
33855
+ var defaultPublicGuardrails = {
33856
+ maxInputChars: 4e3,
33857
+ maxOutputChars: 6e3,
33858
+ secretRedaction: { enabled: true },
33859
+ promptInjectionDetection: true
33860
+ };
33861
+ function redactSecrets(content, config = { enabled: true }) {
33862
+ if (!config.enabled) return { content, findings: [] };
33863
+ let redacted = content;
33864
+ const findings = [];
33865
+ const replacement = config.replacement ?? DEFAULT_REDACTION;
33866
+ for (const { id, pattern } of SECRET_PATTERNS) {
33867
+ const before = redacted;
33868
+ redacted = redacted.replace(pattern, replacement);
33869
+ if (before !== redacted) {
33870
+ findings.push({
33871
+ id,
33872
+ stage: "input",
33873
+ severity: "warning",
33874
+ message: `Potential secret redacted: ${id}`,
33875
+ redacted: true
33876
+ });
33877
+ }
33878
+ }
33879
+ return { content: redacted, findings };
33880
+ }
33881
+ function runGuardrails(stage, content, config = {}) {
33882
+ const findings = [];
33883
+ const maxChars = stage === "input" ? config.maxInputChars : config.maxOutputChars;
33884
+ let checked = content;
33885
+ if (typeof maxChars === "number" && checked.length > maxChars) {
33886
+ findings.push({
33887
+ id: `${stage}-too-long`,
33888
+ stage,
33889
+ severity: "blocked",
33890
+ message: `${stage} exceeds ${maxChars} characters.`
33891
+ });
33892
+ }
33893
+ const redaction = redactSecrets(checked, config.secretRedaction);
33894
+ checked = redaction.content;
33895
+ findings.push(...redaction.findings.map((finding) => ({ ...finding, stage })));
33896
+ if (config.promptInjectionDetection) {
33897
+ for (const { id, pattern } of PROMPT_INJECTION_PATTERNS) {
33898
+ if (pattern.test(checked)) {
33899
+ findings.push({
33900
+ id,
33901
+ stage,
33902
+ severity: "warning",
33903
+ message: `Potential prompt-injection pattern detected: ${id}`
33904
+ });
33905
+ }
33906
+ }
33907
+ }
33908
+ const blockedTopics = config.topicBoundary?.blockedTopics ?? [];
33909
+ for (const topic of blockedTopics) {
33910
+ if (topic && checked.toLowerCase().includes(topic.toLowerCase())) {
33911
+ findings.push({
33912
+ id: "blocked-topic",
33913
+ stage,
33914
+ severity: "blocked",
33915
+ message: `Content mentions blocked topic: ${topic}`
33916
+ });
33917
+ }
33918
+ }
33919
+ return {
33920
+ allowed: !findings.some((finding) => finding.severity === "blocked"),
33921
+ content: checked,
33922
+ findings
33923
+ };
33924
+ }
33925
+ function validateStructuredOutput(output, schema) {
33926
+ if (!schema) return [];
33927
+ const result = schema.safeParse(output);
33928
+ if (result.success) return [];
33929
+ return [
33930
+ {
33931
+ id: "invalid-structured-output",
33932
+ stage: "output",
33933
+ severity: "blocked",
33934
+ message: result.error.issues.map((issue) => issue.message).join("; ")
33935
+ }
33936
+ ];
33937
+ }
33938
+
33939
+ // src/runtime/blueprints.ts
33940
+ function mapActionModeToRuntimeMode(mode) {
33941
+ if (mode === "act") return "build";
33942
+ if (mode === "review") return "review";
33943
+ return "ask";
33944
+ }
33945
+ function createSafeToolRegistry(allowedTools, source) {
33946
+ const safe = new ToolRegistry();
33947
+ if (!source) return safe;
33948
+ for (const toolName of allowedTools) {
33949
+ const tool = source.get(toolName);
33950
+ if (tool) safe.register(tool);
33951
+ }
33952
+ return safe;
33953
+ }
33954
+ async function createAgentFromBlueprint(blueprint, options) {
33955
+ const runtime = await createAgentRuntime({
33956
+ providerType: options.providerType,
33957
+ model: options.model,
33958
+ providerConfig: options.providerConfig,
33959
+ provider: options.provider,
33960
+ eventLog: options.eventLog,
33961
+ turnRunner: options.turnRunner,
33962
+ toolRegistry: options.toolRegistry ?? createSafeToolRegistry(blueprint.allowedTools.length > 0 ? blueprint.allowedTools : []),
33963
+ publishToGlobalBridge: false
33964
+ });
33965
+ return {
33966
+ blueprint,
33967
+ runtime,
33968
+ createSession(metadata = {}) {
33969
+ return runtime.createSession({
33970
+ mode: mapActionModeToRuntimeMode(blueprint.defaultMode),
33971
+ instructions: blueprint.instructions,
33972
+ metadata: {
33973
+ blueprintId: blueprint.id,
33974
+ surface: blueprint.surface,
33975
+ ...metadata
33976
+ }
33977
+ });
33978
+ },
33979
+ async runTurn(input) {
33980
+ const guardrails = { ...defaultPublicGuardrails, ...blueprint.guardrails };
33981
+ const checkedInput = runGuardrails("input", input.content, guardrails);
33982
+ runtime.eventLog.record("guardrail.input", {
33983
+ blueprintId: blueprint.id,
33984
+ allowed: checkedInput.allowed,
33985
+ findings: checkedInput.findings
33986
+ });
33987
+ if (!checkedInput.allowed) {
33988
+ throw new Error(formatGuardrailBlock(checkedInput.findings));
33989
+ }
33990
+ const result = await runtime.runTurn({
33991
+ ...input,
33992
+ content: checkedInput.content,
33993
+ mode: input.mode ?? mapActionModeToRuntimeMode(blueprint.defaultMode)
33994
+ });
33995
+ const checkedOutput = runGuardrails("output", result.content, guardrails);
33996
+ runtime.eventLog.record("guardrail.output", {
33997
+ blueprintId: blueprint.id,
33998
+ allowed: checkedOutput.allowed,
33999
+ findings: checkedOutput.findings
34000
+ });
34001
+ if (!checkedOutput.allowed) {
34002
+ throw new Error(formatGuardrailBlock(checkedOutput.findings));
34003
+ }
34004
+ return { ...result, content: checkedOutput.content };
34005
+ }
34006
+ };
34007
+ }
34008
+ function formatGuardrailBlock(findings) {
34009
+ const messages = findings.filter((finding) => finding.severity === "blocked").map((finding) => finding.message);
34010
+ return messages.length > 0 ? messages.join("; ") : "Guardrail blocked the request.";
34011
+ }
34012
+ function createBaseBlueprint(input) {
34013
+ return {
34014
+ ...input,
34015
+ guardrails: input.guardrails ?? defaultPublicGuardrails,
34016
+ memory: input.memory ?? { enabled: true, retention: "session" },
34017
+ approval: input.approval ?? { requireHumanForExternalActions: true },
34018
+ observability: input.observability ?? { logEvents: true, redactSensitiveData: true }
34019
+ };
34020
+ }
34021
+
34022
+ // src/runtime/rag.ts
34023
+ var InMemoryKnowledgeRetriever = class {
34024
+ constructor(documents) {
34025
+ this.documents = documents;
34026
+ }
34027
+ documents;
34028
+ async search(query, options = {}) {
34029
+ const terms = tokenize(query);
34030
+ const limit = options.limit ?? 5;
34031
+ const minScore = options.minScore ?? 0;
34032
+ return this.documents.map((document) => ({
34033
+ ...document,
34034
+ score: scoreDocument(document, terms)
34035
+ })).filter((source) => source.score >= minScore && source.score > 0).sort((a, b) => b.score - a.score).slice(0, limit);
34036
+ }
34037
+ };
34038
+ function createInMemoryKnowledgeRetriever(documents) {
34039
+ return new InMemoryKnowledgeRetriever(documents);
34040
+ }
34041
+ function formatRetrievedSourcesForPrompt(sources) {
34042
+ if (sources.length === 0) return "No retrieved sources.";
34043
+ return sources.map((source, index) => {
34044
+ const url = source.url ? `
34045
+ URL: ${source.url}` : "";
34046
+ return `[${index + 1}] ${source.title}${url}
34047
+ ${source.content}`;
34048
+ }).join("\n\n");
34049
+ }
34050
+ function tokenize(text2) {
34051
+ return text2.toLowerCase().split(/[^a-z0-9áéíóúüñ]+/i).map((term) => term.trim()).filter((term) => term.length > 2);
34052
+ }
34053
+ function scoreDocument(document, terms) {
34054
+ const haystack = `${document.title}
34055
+ ${document.content}`.toLowerCase();
34056
+ if (terms.length === 0) return 0;
34057
+ const matches = terms.filter((term) => haystack.includes(term)).length;
34058
+ return matches / terms.length;
34059
+ }
34060
+
34061
+ // src/presets/index.ts
34062
+ var publicWebsiteAssistantPreset = {
34063
+ id: "public-website-assistant",
34064
+ name: "Public Website Assistant",
34065
+ createBlueprint(config) {
34066
+ return createBaseBlueprint({
34067
+ id: "public-website-assistant",
34068
+ name: "Public Website Assistant",
34069
+ description: "Safe public assistant for landing pages, FAQs, service explanation, and lead intake.",
34070
+ surface: "web",
34071
+ defaultMode: "ask",
34072
+ maturity: "experimental",
34073
+ instructions: [
34074
+ `You are the public website assistant for ${config.brand}.`,
34075
+ "Help visitors understand services, ask concise qualification questions, and suggest a safe next step.",
34076
+ "Do not claim that you sent messages, changed systems, booked meetings, or created records unless a registered tool result proves it.",
34077
+ "If you are unsure, say so and offer to route the visitor to a human.",
34078
+ config.audience ? `Primary audience: ${config.audience}.` : "",
34079
+ config.extraInstructions ?? ""
34080
+ ].filter(Boolean).join("\n"),
34081
+ allowedTools: []
34082
+ });
34083
+ },
34084
+ async createRuntime(config) {
34085
+ return createPresetRuntime(config, publicWebsiteAssistantPreset.createBlueprint(config));
34086
+ }
34087
+ };
34088
+ var ragKnowledgeAssistantPreset = {
34089
+ id: "rag-knowledge-assistant",
34090
+ name: "RAG Knowledge Assistant",
34091
+ createBlueprint(config) {
34092
+ return createBaseBlueprint({
34093
+ id: "rag-knowledge-assistant",
34094
+ name: "RAG Knowledge Assistant",
34095
+ description: "Assistant that answers from a configured knowledge base and cites retrieved sources.",
34096
+ surface: "web",
34097
+ defaultMode: "ask",
34098
+ maturity: "experimental",
34099
+ instructions: [
34100
+ `You are a knowledge assistant for ${config.brand}.`,
34101
+ "Answer only from retrieved or approved knowledge.",
34102
+ "Cite source titles when using retrieved content.",
34103
+ "If the answer is not in the available knowledge, say you do not know and suggest escalation.",
34104
+ config.extraInstructions ?? ""
34105
+ ].filter(Boolean).join("\n"),
34106
+ allowedTools: config.retriever ? ["knowledge_search"] : []
34107
+ });
34108
+ },
34109
+ async createRuntime(config) {
34110
+ const blueprint = ragKnowledgeAssistantPreset.createBlueprint(config);
34111
+ return createPresetRuntime(config, blueprint, createRagToolRegistry(config.retriever));
34112
+ }
34113
+ };
34114
+ var supportRagAssistantPreset = {
34115
+ id: "support-rag-assistant",
34116
+ name: "Support RAG Assistant",
34117
+ createBlueprint(config) {
34118
+ const allowedTools = [];
34119
+ if (config.retriever) allowedTools.push("knowledge_search");
34120
+ if (config.supportDraft) allowedTools.push("create_support_draft");
34121
+ if (config.humanEscalation) allowedTools.push("request_human_escalation");
34122
+ return createBaseBlueprint({
34123
+ id: "support-rag-assistant",
34124
+ name: "Support RAG Assistant",
34125
+ description: "Support assistant that answers from approved knowledge, drafts responses, and escalates uncertain cases.",
34126
+ surface: "web",
34127
+ defaultMode: "draft",
34128
+ maturity: "experimental",
34129
+ instructions: [
34130
+ `You are a support assistant for ${config.brand}.`,
34131
+ "Answer only from approved retrieved knowledge.",
34132
+ "Cite source titles when using retrieved content.",
34133
+ "If retrieval is weak or the case is sensitive, say you are unsure and prepare an escalation.",
34134
+ "Never claim a ticket was created, closed, or escalated unless a registered tool result proves it.",
34135
+ config.extraInstructions ?? ""
34136
+ ].filter(Boolean).join("\n"),
34137
+ allowedTools,
34138
+ approval: { requireHumanForExternalActions: true, requireHumanForSensitiveData: true }
34139
+ });
34140
+ },
34141
+ async createRuntime(config) {
34142
+ const blueprint = supportRagAssistantPreset.createBlueprint(config);
34143
+ return createPresetRuntime(
34144
+ config,
34145
+ blueprint,
34146
+ createSupportRagToolRegistry({
34147
+ retriever: config.retriever,
34148
+ supportDraft: config.supportDraft,
34149
+ humanEscalation: config.humanEscalation
34150
+ }),
34151
+ createToolCallingRuntimeTurnRunner()
34152
+ );
34153
+ }
34154
+ };
34155
+ var salesIntakeAssistantPreset = {
34156
+ id: "sales-intake-assistant",
34157
+ name: "Sales Intake Assistant",
34158
+ createBlueprint(config) {
34159
+ return createBaseBlueprint({
34160
+ id: "sales-intake-assistant",
34161
+ name: "Sales Intake Assistant",
34162
+ description: "Assistant for lead qualification, project context, urgency, budget, and next step capture.",
34163
+ surface: "web",
34164
+ defaultMode: "ask",
34165
+ maturity: "experimental",
34166
+ instructions: [
34167
+ `You are the sales intake assistant for ${config.brand}.`,
34168
+ "Collect problem, desired outcome, urgency, approximate budget, current stack, decision process, and contact preference.",
34169
+ "Keep the conversation concise and useful. Produce a clear summary and recommended next step when enough context is available.",
34170
+ "Do not promise pricing, timelines, or delivery commitments.",
34171
+ "Use create_sales_lead_summary only to prepare an internal summary; do not claim a CRM record was created.",
34172
+ config.extraInstructions ?? ""
34173
+ ].filter(Boolean).join("\n"),
34174
+ allowedTools: config.leadSummary ? ["create_sales_lead_summary"] : []
34175
+ });
34176
+ },
34177
+ async createRuntime(config) {
34178
+ return createPresetRuntime(
34179
+ config,
34180
+ salesIntakeAssistantPreset.createBlueprint(config),
34181
+ createSalesIntakeToolRegistry({ leadSummary: config.leadSummary }),
34182
+ createToolCallingRuntimeTurnRunner()
34183
+ );
34184
+ }
34185
+ };
34186
+ var customerSupportAssistantPreset = {
34187
+ id: "customer-support-assistant",
34188
+ name: "Customer Support Assistant",
34189
+ createBlueprint(config) {
34190
+ return createBaseBlueprint({
34191
+ id: "customer-support-assistant",
34192
+ name: "Customer Support Assistant",
34193
+ description: "Assistant for support triage, answer drafts, and escalation recommendations.",
34194
+ surface: "web",
34195
+ defaultMode: "draft",
34196
+ maturity: "experimental",
34197
+ instructions: [
34198
+ `You are the customer support assistant for ${config.brand}.`,
34199
+ "Classify the issue, suggest a helpful answer, and escalate sensitive or uncertain cases to a human.",
34200
+ "Do not close tickets or make account changes without explicit approval and a registered tool result.",
34201
+ config.extraInstructions ?? ""
34202
+ ].filter(Boolean).join("\n"),
34203
+ allowedTools: []
34204
+ });
34205
+ },
34206
+ async createRuntime(config) {
34207
+ return createPresetRuntime(
34208
+ config,
34209
+ customerSupportAssistantPreset.createBlueprint(config),
34210
+ createCustomerSupportToolRegistry(config.toolRegistry)
34211
+ );
34212
+ }
34213
+ };
34214
+ var appointmentBookingAssistantPreset = {
34215
+ id: "appointment-booking-assistant",
34216
+ name: "Appointment Booking Assistant",
34217
+ createBlueprint(config) {
34218
+ return createBaseBlueprint({
34219
+ id: "appointment-booking-assistant",
34220
+ name: "Appointment Booking Assistant",
34221
+ description: "Assistant for appointment intake, availability discussion, and confirmation-gated booking.",
34222
+ surface: "web",
34223
+ defaultMode: "draft",
34224
+ maturity: "experimental",
34225
+ instructions: [
34226
+ `You are the appointment assistant for ${config.brand}.`,
34227
+ config.businessHours ? `Business hours: ${config.businessHours}.` : "",
34228
+ "Collect preferred time, timezone, purpose, and contact details.",
34229
+ "Never book, cancel, or move an appointment without explicit user confirmation and an approved tool call.",
34230
+ config.extraInstructions ?? ""
34231
+ ].filter(Boolean).join("\n"),
34232
+ allowedTools: []
34233
+ });
34234
+ },
34235
+ async createRuntime(config) {
34236
+ return createPresetRuntime(config, appointmentBookingAssistantPreset.createBlueprint(config));
34237
+ }
34238
+ };
34239
+ var internalOpsAssistantPreset = {
34240
+ id: "internal-ops-assistant",
34241
+ name: "Internal Ops Assistant",
34242
+ createBlueprint(config) {
34243
+ return createBaseBlueprint({
34244
+ id: "internal-ops-assistant",
34245
+ name: "Internal Ops Assistant",
34246
+ description: "Internal automation assistant for controlled operations workflows.",
34247
+ surface: "internal",
34248
+ defaultMode: "draft",
34249
+ maturity: "experimental",
34250
+ instructions: [
34251
+ `You are an internal operations assistant for ${config.brand}.`,
34252
+ "Prefer drafts and summaries before actions. Ask for confirmation before external side effects.",
34253
+ "Use create_internal_ops_draft for controlled planning only. Do not execute ERP, CRM, billing, or account changes unless a separate allowlisted tool exists.",
34254
+ "Follow the configured tool policy and record decisions for audit.",
34255
+ config.extraInstructions ?? ""
34256
+ ].filter(Boolean).join("\n"),
34257
+ allowedTools: config.opsDraft ? ["create_internal_ops_draft"] : [],
34258
+ approval: { requireHumanForExternalActions: true, requireHumanForSensitiveData: true }
34259
+ });
34260
+ },
34261
+ async createRuntime(config) {
34262
+ return createPresetRuntime(
34263
+ config,
34264
+ internalOpsAssistantPreset.createBlueprint(config),
34265
+ createInternalOpsToolRegistry({ opsDraft: config.opsDraft }),
34266
+ createToolCallingRuntimeTurnRunner()
34267
+ );
34268
+ }
34269
+ };
34270
+ var codingAgentPreset = {
34271
+ id: "coding-agent",
34272
+ name: "Coco Coding Agent",
34273
+ createBlueprint(config) {
34274
+ return createBaseBlueprint({
34275
+ id: "coding-agent",
34276
+ name: "Coco Coding Agent",
34277
+ description: "Coco's full coding-agent surface for trusted developer environments.",
34278
+ surface: "cli",
34279
+ defaultMode: "act",
34280
+ maturity: "beta",
34281
+ instructions: config.extraInstructions ?? "You are Coco, a coding agent for trusted repositories.",
34282
+ allowedTools: [],
34283
+ guardrails: { secretRedaction: { enabled: true }, promptInjectionDetection: true },
34284
+ approval: { requireHumanForExternalActions: true, requireHumanForSensitiveData: true }
34285
+ });
34286
+ },
34287
+ async createRuntime(config) {
34288
+ return createPresetRuntime(
34289
+ config,
34290
+ codingAgentPreset.createBlueprint(config),
34291
+ createCodingToolRegistry()
34292
+ );
34293
+ }
34294
+ };
34295
+ async function createPresetRuntime(config, blueprint, fallbackToolRegistry = createNoToolRegistry(), fallbackTurnRunner = config.turnRunner) {
34296
+ return createAgentRuntime({
34297
+ providerType: config.providerType,
34298
+ model: config.model,
34299
+ providerConfig: config.providerConfig,
34300
+ provider: config.provider,
34301
+ eventLog: config.eventLog,
34302
+ turnRunner: config.turnRunner ?? fallbackTurnRunner,
34303
+ toolRegistry: blueprint.id === "coding-agent" ? config.toolRegistry ?? fallbackToolRegistry : config.toolRegistry ? createSafeToolRegistry(blueprint.allowedTools, config.toolRegistry) : fallbackToolRegistry,
34304
+ publishToGlobalBridge: false
34305
+ });
34306
+ }
34307
+ var AGENT_PRESETS = [
34308
+ publicWebsiteAssistantPreset,
34309
+ ragKnowledgeAssistantPreset,
34310
+ supportRagAssistantPreset,
34311
+ salesIntakeAssistantPreset,
34312
+ customerSupportAssistantPreset,
34313
+ appointmentBookingAssistantPreset,
34314
+ internalOpsAssistantPreset,
34315
+ codingAgentPreset
34316
+ ];
34317
+
34318
+ // src/adapters/index.ts
34319
+ function createHttpAssistantAdapter(runtime) {
34320
+ return {
34321
+ createSession(metadata = {}) {
34322
+ const session = runtime.createSession({ mode: "ask", metadata });
34323
+ return { sessionId: session.id };
34324
+ },
34325
+ async handleMessage(input) {
34326
+ const sessionId = input.sessionId ?? runtime.createSession({ mode: "ask", metadata: input.metadata }).id;
34327
+ const result = await runtime.runTurn({
34328
+ sessionId,
34329
+ content: input.content,
34330
+ metadata: input.metadata
34331
+ });
34332
+ return { sessionId, content: result.content, metadata: { model: result.model } };
34333
+ }
34334
+ };
34335
+ }
34336
+ function createStreamingHttpAssistantAdapter(runtime) {
34337
+ const base = createHttpAssistantAdapter(runtime);
34338
+ return {
34339
+ ...base,
34340
+ async *streamMessage(input) {
34341
+ const sessionId = input.sessionId ?? runtime.createSession({ mode: "ask", metadata: input.metadata }).id;
34342
+ yield* runtime.streamTurn({
34343
+ sessionId,
34344
+ content: input.content,
34345
+ metadata: input.metadata
34346
+ });
34347
+ }
34348
+ };
34349
+ }
34350
+ function createWebhookAssistantAdapter(runtime, options = {}) {
34351
+ return {
34352
+ id: options.id ?? "webhook-assistant",
34353
+ surface: options.surface ?? "api",
34354
+ async handle(input) {
34355
+ const adapter = createHttpAssistantAdapter(runtime);
34356
+ return adapter.handleMessage(input);
34357
+ }
34358
+ };
34359
+ }
34360
+
32886
34361
  // src/index.ts
32887
34362
  init_errors();
32888
34363
  init_logger();
32889
34364
  init_proxy();
32890
34365
 
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 };
34366
+ export { ADRGenerator, AGENT_MODES, AGENT_PRESETS, AgentRuntime, AnthropicProvider, ArchitectureGenerator, BacklogGenerator, CICDGenerator, CocoError, CodeGenerator, CodeReviewer, CompleteExecutor, ConfigError, ConvergeExecutor, DEFAULT_WORKFLOWS, DefaultPermissionPolicy, DefaultRuntimeTurnRunner, DiscoveryEngine, DockerGenerator, DocsGenerator, FileEventLog, FileRuntimeSessionStore, InMemoryEventLog, InMemoryKnowledgeRetriever, InMemoryRuntimeSessionStore, OrchestrateExecutor, OutputExecutor, PhaseError, ProviderRegistry, SessionManager, SharedWorkspaceState, SpecificationGenerator, TaskError, TaskIterator, ToolCallingRuntimeTurnRunner, ToolRegistry, VERSION, WorkflowCatalog, WorkflowEngine, WorkflowRegistry, appointmentBookingAssistantPreset, codingAgentPreset, configExists, createADRGenerator, createAgentArtifact, createAgentFromBlueprint, createAgentRuntime, createAnthropicProvider, createArchitectureGenerator, createBacklogGenerator, createBaseBlueprint, createCICDGenerator, createCodeGenerator, createCodeReviewer, createCodingToolRegistry, createCompleteExecutor, createConvergeExecutor, createCustomerSupportToolRegistry, createDefaultConfig, createDefaultRuntimeTurnRunner, createDiscoveryEngine, createDockerGenerator, createDocsGenerator, createEventLog, createFileEventLog, createFileRuntimeSessionStore, createFullToolRegistry, createHttpAssistantAdapter, createInMemoryKnowledgeRetriever, createLogger, createMcpToolPolicy, createNoToolRegistry, createOrchestrateExecutor, createOrchestrator, createOutputExecutor, createPermissionPolicy, createProvider, createProviderRegistry, createPublicWebToolRegistry, createRagToolRegistry, createRuntimeHttpServer, createRuntimeSessionStore, createSafeToolRegistry, createSessionManager, createSpecificationGenerator, createStreamingHttpAssistantAdapter, createSummaryArtifact, createSupportRagToolRegistry, createTaskIterator, createToolCallingRuntimeTurnRunner, createToolRegistry, createWebhookAssistantAdapter, createWorkflowCatalog, createWorkflowEngine, createWorkflowRegistry, customerSupportAssistantPreset, defaultPublicGuardrails, formatRetrievedSourcesForPrompt, getAgentMode, installProxyDispatcher, internalOpsAssistantPreset, isAgentMode, listAgentModes, loadConfig, mapActionModeToRuntimeMode, normalizeAgentRunResult, publicWebsiteAssistantPreset, ragKnowledgeAssistantPreset, redactSecrets, registerAllTools, runGuardrails, salesIntakeAssistantPreset, saveConfig, supportRagAssistantPreset, validateAgentCapabilities, validateAgentGraph, validateStructuredOutput, workflowToAgentGraph };
32892
34367
  //# sourceMappingURL=index.js.map
32893
34368
  //# sourceMappingURL=index.js.map