@corbat-tech/coco 2.39.0 → 2.41.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/adapters/index.d.ts +93 -3
- package/dist/adapters/index.js +199 -1
- package/dist/adapters/index.js.map +1 -1
- package/dist/agent-runtime-BJeNjVuk.d.ts +71 -0
- package/dist/{blueprints-DYgm3K65.d.ts → blueprints-Dw5-uWU9.d.ts} +30 -4
- package/dist/cli/index.js +1436 -345
- package/dist/cli/index.js.map +1 -1
- package/dist/{agent-runtime-DJY9FzL_.d.ts → context-BLPsKYxc.d.ts} +500 -248
- package/dist/{index-Dp1o8c9g.d.ts → index-DhUKtM2p.d.ts} +2 -2
- package/dist/index.d.ts +10 -10
- package/dist/index.js +14887 -14117
- package/dist/index.js.map +1 -1
- package/dist/presets/index.d.ts +5 -5
- package/dist/presets/index.js +22778 -22952
- package/dist/presets/index.js.map +1 -1
- package/dist/{profiles-BcyL-gQ9.d.ts → profiles-GRoVNorK.d.ts} +7 -4
- package/dist/rag-B2oGudNb.d.ts +178 -0
- package/dist/runtime/index.d.ts +278 -8
- package/dist/runtime/index.js +7530 -24074
- package/dist/runtime/index.js.map +1 -1
- package/dist/tools/index.d.ts +4 -4
- package/dist/tools/index.js +10 -3
- package/dist/tools/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/extension-manifests-CAQQILhE.d.ts +0 -147
- package/dist/rag-BakFRE-u.d.ts +0 -31
- package/dist/registry-CEpl9Jq0.d.ts +0 -115
package/dist/cli/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { execFileSync,
|
|
2
|
+
import { execFileSync, execSync, spawn, execFile, exec } from 'child_process';
|
|
3
3
|
import { setGlobalDispatcher, EnvHttpProxyAgent } from 'undici';
|
|
4
4
|
import * as fs5 from 'fs';
|
|
5
5
|
import fs5__default, { accessSync, mkdirSync, appendFileSync, readFileSync, writeFileSync, constants as constants$1 } from 'fs';
|
|
@@ -23,7 +23,7 @@ import Anthropic from '@anthropic-ai/sdk';
|
|
|
23
23
|
import { jsonrepair } from 'jsonrepair';
|
|
24
24
|
import OpenAI from 'openai';
|
|
25
25
|
import { GoogleGenAI, FunctionCallingConfigMode } from '@google/genai';
|
|
26
|
-
import { parse } from 'yaml';
|
|
26
|
+
import { parse as parse$1 } from 'yaml';
|
|
27
27
|
import { minimatch } from 'minimatch';
|
|
28
28
|
import hljs from 'highlight.js/lib/core';
|
|
29
29
|
import bash from 'highlight.js/lib/languages/bash';
|
|
@@ -42,7 +42,7 @@ import yaml from 'highlight.js/lib/languages/yaml';
|
|
|
42
42
|
import { diffLines, diffWords } from 'diff';
|
|
43
43
|
import { glob } from 'glob';
|
|
44
44
|
import { execa } from 'execa';
|
|
45
|
-
import { parse
|
|
45
|
+
import { parse } from '@typescript-eslint/typescript-estree';
|
|
46
46
|
import { simpleGit } from 'simple-git';
|
|
47
47
|
import { Marked } from 'marked';
|
|
48
48
|
import { markedTerminal } from 'marked-terminal';
|
|
@@ -10061,7 +10061,7 @@ function parseSkillMarkdown(raw) {
|
|
|
10061
10061
|
const frontmatter = normalized.slice(3, closeIndex).trim();
|
|
10062
10062
|
const afterMarkerStart = closeIndex + closeMarker.length;
|
|
10063
10063
|
const contentStart = normalized[afterMarkerStart] === "\n" ? afterMarkerStart + 1 : afterMarkerStart;
|
|
10064
|
-
const parsed = frontmatter.length > 0 ? parse(frontmatter) : {};
|
|
10064
|
+
const parsed = frontmatter.length > 0 ? parse$1(frontmatter) : {};
|
|
10065
10065
|
return {
|
|
10066
10066
|
data: parsed && typeof parsed === "object" ? parsed : {},
|
|
10067
10067
|
content: normalized.slice(contentStart)
|
|
@@ -15465,7 +15465,7 @@ var init_complexity = __esm({
|
|
|
15465
15465
|
* Analyze single file
|
|
15466
15466
|
*/
|
|
15467
15467
|
async analyzeFile(file, content) {
|
|
15468
|
-
const ast = parse
|
|
15468
|
+
const ast = parse(content, {
|
|
15469
15469
|
loc: true,
|
|
15470
15470
|
range: true,
|
|
15471
15471
|
comment: false,
|
|
@@ -16062,7 +16062,7 @@ var init_completeness = __esm({
|
|
|
16062
16062
|
for (const file of files) {
|
|
16063
16063
|
try {
|
|
16064
16064
|
const content = await readFile(file, "utf-8");
|
|
16065
|
-
const ast = parse
|
|
16065
|
+
const ast = parse(content, {
|
|
16066
16066
|
loc: true,
|
|
16067
16067
|
range: true,
|
|
16068
16068
|
jsx: file.endsWith(".tsx") || file.endsWith(".jsx")
|
|
@@ -16275,7 +16275,7 @@ var init_robustness = __esm({
|
|
|
16275
16275
|
for (const file of targetFiles) {
|
|
16276
16276
|
try {
|
|
16277
16277
|
const content = await readFile(file, "utf-8");
|
|
16278
|
-
const ast = parse
|
|
16278
|
+
const ast = parse(content, {
|
|
16279
16279
|
loc: true,
|
|
16280
16280
|
range: true,
|
|
16281
16281
|
jsx: file.endsWith(".tsx") || file.endsWith(".jsx")
|
|
@@ -16568,7 +16568,7 @@ var init_documentation = __esm({
|
|
|
16568
16568
|
for (const file of targetFiles) {
|
|
16569
16569
|
try {
|
|
16570
16570
|
const content = await readFile(file, "utf-8");
|
|
16571
|
-
const ast = parse
|
|
16571
|
+
const ast = parse(content, {
|
|
16572
16572
|
loc: true,
|
|
16573
16573
|
range: true,
|
|
16574
16574
|
comment: true,
|
|
@@ -16946,7 +16946,7 @@ var init_readability = __esm({
|
|
|
16946
16946
|
for (const file of targetFiles) {
|
|
16947
16947
|
try {
|
|
16948
16948
|
const content = await readFile(file, "utf-8");
|
|
16949
|
-
const ast = parse
|
|
16949
|
+
const ast = parse(content, {
|
|
16950
16950
|
loc: true,
|
|
16951
16951
|
range: true,
|
|
16952
16952
|
jsx: file.endsWith(".tsx") || file.endsWith(".jsx")
|
|
@@ -17104,7 +17104,7 @@ var init_maintainability = __esm({
|
|
|
17104
17104
|
try {
|
|
17105
17105
|
const content = await readFile(file, "utf-8");
|
|
17106
17106
|
const lineCount = countLines(content);
|
|
17107
|
-
const ast = parse
|
|
17107
|
+
const ast = parse(content, {
|
|
17108
17108
|
loc: true,
|
|
17109
17109
|
range: true,
|
|
17110
17110
|
jsx: file.endsWith(".tsx") || file.endsWith(".jsx")
|
|
@@ -43237,6 +43237,7 @@ var LEGACY_ROLE_MAPPINGS = [
|
|
|
43237
43237
|
{ legacy: "coder", role: "coder", reason: "legacy executor role" },
|
|
43238
43238
|
{ legacy: "test", role: "tester", reason: "test authoring/execution" },
|
|
43239
43239
|
{ legacy: "tester", role: "tester", reason: "legacy executor role" },
|
|
43240
|
+
{ legacy: "verifier", role: "tester", reason: "verification maps to tester capability" },
|
|
43240
43241
|
{ legacy: "tdd", role: "tester", reason: "test-first implementation" },
|
|
43241
43242
|
{ legacy: "e2e", role: "tester", reason: "end-to-end testing" },
|
|
43242
43243
|
{ legacy: "review", role: "reviewer", reason: "code review" },
|
|
@@ -43310,7 +43311,7 @@ var InMemorySharedWorkspaceStore = class {
|
|
|
43310
43311
|
write(input) {
|
|
43311
43312
|
assertProvenance(input.provenance);
|
|
43312
43313
|
const record = {
|
|
43313
|
-
id: `state-${randomUUID()}`,
|
|
43314
|
+
id: input.id ?? `state-${randomUUID()}`,
|
|
43314
43315
|
kind: input.kind,
|
|
43315
43316
|
key: input.key,
|
|
43316
43317
|
value: cloneUnknown(input.value),
|
|
@@ -43333,6 +43334,39 @@ var InMemorySharedWorkspaceStore = class {
|
|
|
43333
43334
|
this.records = [];
|
|
43334
43335
|
}
|
|
43335
43336
|
};
|
|
43337
|
+
function evaluateAgentToolPolicy(input) {
|
|
43338
|
+
const manifestEntry = input.manifest?.[input.toolName];
|
|
43339
|
+
const risk = manifestEntry?.risk ?? input.capability.risk;
|
|
43340
|
+
if (!input.capability.allowedTools.includes(input.toolName)) {
|
|
43341
|
+
return {
|
|
43342
|
+
allowed: false,
|
|
43343
|
+
risk,
|
|
43344
|
+
reason: `Tool '${input.toolName}' is not allowed for agent role '${input.capability.role}'.`
|
|
43345
|
+
};
|
|
43346
|
+
}
|
|
43347
|
+
if (manifestEntry?.requiredCapability) {
|
|
43348
|
+
const allowedRoles = Array.isArray(manifestEntry.requiredCapability) ? manifestEntry.requiredCapability : [manifestEntry.requiredCapability];
|
|
43349
|
+
if (!allowedRoles.includes(input.capability.role)) {
|
|
43350
|
+
return {
|
|
43351
|
+
allowed: false,
|
|
43352
|
+
risk,
|
|
43353
|
+
reason: `Tool '${input.toolName}' requires role ${allowedRoles.join(", ")}.`
|
|
43354
|
+
};
|
|
43355
|
+
}
|
|
43356
|
+
}
|
|
43357
|
+
if (riskRank(risk) > riskRank(input.capability.risk)) {
|
|
43358
|
+
return {
|
|
43359
|
+
allowed: false,
|
|
43360
|
+
risk,
|
|
43361
|
+
reason: `Tool '${input.toolName}' risk '${risk}' exceeds agent capability risk '${input.capability.risk}'.`
|
|
43362
|
+
};
|
|
43363
|
+
}
|
|
43364
|
+
return {
|
|
43365
|
+
allowed: true,
|
|
43366
|
+
risk,
|
|
43367
|
+
requiresConsent: manifestEntry?.requiresConsent ?? (risk === "destructive" || risk === "secrets-sensitive")
|
|
43368
|
+
};
|
|
43369
|
+
}
|
|
43336
43370
|
function createAgentTraceContext(input = {}) {
|
|
43337
43371
|
return {
|
|
43338
43372
|
traceId: input.traceId ?? `trace-${randomUUID()}`,
|
|
@@ -43353,7 +43387,7 @@ var AgentGraphEngine = class {
|
|
|
43353
43387
|
constructor(options = {}) {
|
|
43354
43388
|
this.eventLog = options.eventLog;
|
|
43355
43389
|
this.sharedState = options.sharedState ?? new InMemorySharedWorkspaceStore();
|
|
43356
|
-
this.nodeExecutor = options.nodeExecutor ??
|
|
43390
|
+
this.nodeExecutor = options.nodeExecutor ?? (options.allowSimulated ? dryRunAgentGraphNodeExecutor : missingAgentGraphNodeExecutor);
|
|
43357
43391
|
this.gateEvaluator = options.gateEvaluator ?? defaultAgentGateEvaluator;
|
|
43358
43392
|
this.trace = options.trace ?? createAgentTraceContext();
|
|
43359
43393
|
}
|
|
@@ -43437,6 +43471,39 @@ var AgentGraphEngine = class {
|
|
|
43437
43471
|
}
|
|
43438
43472
|
}
|
|
43439
43473
|
async executeNode(input) {
|
|
43474
|
+
const skipReason = shouldSkipNode(input.node, input.graph, input.input, input.nodeResults);
|
|
43475
|
+
if (skipReason) {
|
|
43476
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
43477
|
+
const task = graphNodeToTask(input.node, input.input);
|
|
43478
|
+
const skipped = normalizeAgentRunResult({
|
|
43479
|
+
id: `${input.workflowRunId}-${input.node.id}-skipped`,
|
|
43480
|
+
taskId: task.id,
|
|
43481
|
+
role: task.role,
|
|
43482
|
+
success: true,
|
|
43483
|
+
status: "cancelled",
|
|
43484
|
+
output: `Skipped node '${input.node.id}': ${skipReason}`,
|
|
43485
|
+
startedAt: completedAt,
|
|
43486
|
+
completedAt,
|
|
43487
|
+
durationMs: 0,
|
|
43488
|
+
metadata: {
|
|
43489
|
+
workflowRunId: input.workflowRunId,
|
|
43490
|
+
nodeId: input.node.id,
|
|
43491
|
+
skipped: true,
|
|
43492
|
+
skipReason
|
|
43493
|
+
}
|
|
43494
|
+
});
|
|
43495
|
+
this.eventLog?.record("agent.completed", {
|
|
43496
|
+
workflowRunId: input.workflowRunId,
|
|
43497
|
+
nodeId: input.node.id,
|
|
43498
|
+
agentRunId: skipped.id,
|
|
43499
|
+
taskId: task.id,
|
|
43500
|
+
role: skipped.role,
|
|
43501
|
+
skipped: true,
|
|
43502
|
+
reason: skipReason,
|
|
43503
|
+
trace: input.graphTrace
|
|
43504
|
+
});
|
|
43505
|
+
return skipped;
|
|
43506
|
+
}
|
|
43440
43507
|
const attempts = input.node.retryPolicy?.maxAttempts ?? 1;
|
|
43441
43508
|
let lastResult;
|
|
43442
43509
|
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
@@ -43455,19 +43522,40 @@ var AgentGraphEngine = class {
|
|
|
43455
43522
|
attempt,
|
|
43456
43523
|
trace
|
|
43457
43524
|
});
|
|
43458
|
-
const result = await
|
|
43459
|
-
|
|
43460
|
-
|
|
43461
|
-
|
|
43462
|
-
|
|
43463
|
-
|
|
43464
|
-
|
|
43465
|
-
|
|
43466
|
-
|
|
43467
|
-
|
|
43525
|
+
const result = await runWithOptionalTimeout(
|
|
43526
|
+
this.nodeExecutor({
|
|
43527
|
+
node: input.node,
|
|
43528
|
+
task,
|
|
43529
|
+
attempt,
|
|
43530
|
+
workflowRunId: input.workflowRunId,
|
|
43531
|
+
trace,
|
|
43532
|
+
dependencyResults: input.nodeResults,
|
|
43533
|
+
sharedState: this.sharedState,
|
|
43534
|
+
eventLog: this.eventLog ?? NULL_EVENT_LOG
|
|
43535
|
+
}),
|
|
43536
|
+
input.node.timeoutMs,
|
|
43537
|
+
() => normalizeAgentRunResult({
|
|
43538
|
+
id: `${input.workflowRunId}-${input.node.id}-attempt-${attempt}-timeout`,
|
|
43539
|
+
taskId: task.id,
|
|
43540
|
+
role: task.role,
|
|
43541
|
+
success: false,
|
|
43542
|
+
status: "timeout",
|
|
43543
|
+
output: "",
|
|
43544
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
43545
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
43546
|
+
durationMs: input.node.timeoutMs ?? 0,
|
|
43547
|
+
error: `Node '${input.node.id}' timed out after ${input.node.timeoutMs}ms.`,
|
|
43548
|
+
metadata: {
|
|
43549
|
+
workflowRunId: input.workflowRunId,
|
|
43550
|
+
nodeId: input.node.id,
|
|
43551
|
+
trace,
|
|
43552
|
+
timeoutMs: input.node.timeoutMs
|
|
43553
|
+
}
|
|
43554
|
+
})
|
|
43555
|
+
);
|
|
43468
43556
|
lastResult = result;
|
|
43469
43557
|
for (const artifact of result.artifacts) {
|
|
43470
|
-
this.sharedState.write({
|
|
43558
|
+
const record = this.sharedState.write({
|
|
43471
43559
|
kind: "artifact",
|
|
43472
43560
|
key: artifact.id,
|
|
43473
43561
|
value: artifact,
|
|
@@ -43479,6 +43567,15 @@ var AgentGraphEngine = class {
|
|
|
43479
43567
|
risk: input.node.risk
|
|
43480
43568
|
}
|
|
43481
43569
|
});
|
|
43570
|
+
this.eventLog?.record("shared_state.updated", {
|
|
43571
|
+
workflowRunId: input.workflowRunId,
|
|
43572
|
+
nodeId: input.node.id,
|
|
43573
|
+
agentRunId: result.id,
|
|
43574
|
+
recordId: record.id,
|
|
43575
|
+
kind: record.kind,
|
|
43576
|
+
key: record.key,
|
|
43577
|
+
trace
|
|
43578
|
+
});
|
|
43482
43579
|
this.eventLog?.record("agent.artifact.created", {
|
|
43483
43580
|
workflowRunId: input.workflowRunId,
|
|
43484
43581
|
nodeId: input.node.id,
|
|
@@ -43499,6 +43596,14 @@ var AgentGraphEngine = class {
|
|
|
43499
43596
|
attempt,
|
|
43500
43597
|
trace
|
|
43501
43598
|
});
|
|
43599
|
+
this.eventLog?.record("checkpoint.created", {
|
|
43600
|
+
workflowRunId: input.workflowRunId,
|
|
43601
|
+
nodeId: input.node.id,
|
|
43602
|
+
agentRunId: result.id,
|
|
43603
|
+
taskId: task.id,
|
|
43604
|
+
attempt,
|
|
43605
|
+
trace
|
|
43606
|
+
});
|
|
43502
43607
|
return result;
|
|
43503
43608
|
}
|
|
43504
43609
|
this.eventLog?.record("agent.failed", {
|
|
@@ -43702,7 +43807,7 @@ var NULL_EVENT_LOG = {
|
|
|
43702
43807
|
function graphNodeToTask(node, workflowInput) {
|
|
43703
43808
|
return {
|
|
43704
43809
|
id: node.id,
|
|
43705
|
-
role: node.agentRole ?? "coder",
|
|
43810
|
+
role: node.agentRole ?? mapLegacyAgentRole(node.id, "coder"),
|
|
43706
43811
|
objective: node.description,
|
|
43707
43812
|
context: {
|
|
43708
43813
|
workflowInput,
|
|
@@ -43712,7 +43817,7 @@ function graphNodeToTask(node, workflowInput) {
|
|
|
43712
43817
|
constraints: node.requiredTools?.map((tool) => `Requires tool: ${tool}`)
|
|
43713
43818
|
};
|
|
43714
43819
|
}
|
|
43715
|
-
async function
|
|
43820
|
+
async function dryRunAgentGraphNodeExecutor(execution) {
|
|
43716
43821
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
43717
43822
|
const dependencyOutputs = Object.fromEntries(
|
|
43718
43823
|
[...execution.dependencyResults.entries()].map(([id, result]) => [
|
|
@@ -43744,10 +43849,36 @@ async function defaultAgentGraphNodeExecutor(execution) {
|
|
|
43744
43849
|
}
|
|
43745
43850
|
});
|
|
43746
43851
|
}
|
|
43852
|
+
async function missingAgentGraphNodeExecutor(execution) {
|
|
43853
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
43854
|
+
return normalizeAgentRunResult({
|
|
43855
|
+
id: `${execution.workflowRunId}-${execution.node.id}-missing-executor`,
|
|
43856
|
+
taskId: execution.task.id,
|
|
43857
|
+
role: execution.task.role,
|
|
43858
|
+
success: false,
|
|
43859
|
+
output: "",
|
|
43860
|
+
startedAt: completedAt,
|
|
43861
|
+
completedAt,
|
|
43862
|
+
durationMs: 0,
|
|
43863
|
+
error: "AgentGraphEngine requires a nodeExecutor. Pass a real executor or set allowSimulated: true for dry-run/demo workflows.",
|
|
43864
|
+
metadata: {
|
|
43865
|
+
workflowRunId: execution.workflowRunId,
|
|
43866
|
+
nodeId: execution.node.id,
|
|
43867
|
+
trace: execution.trace,
|
|
43868
|
+
missingExecutor: true
|
|
43869
|
+
}
|
|
43870
|
+
});
|
|
43871
|
+
}
|
|
43747
43872
|
async function defaultAgentGateEvaluator(input) {
|
|
43748
43873
|
if (!input.result.success) {
|
|
43749
43874
|
return { passed: false, reason: "Agent result was not successful." };
|
|
43750
43875
|
}
|
|
43876
|
+
if (input.gate.kind === "tests" || input.gate.kind === "coverage" || input.gate.kind === "security" || input.gate.kind === "quality-score" || input.gate.kind === "human-approval") {
|
|
43877
|
+
return {
|
|
43878
|
+
passed: false,
|
|
43879
|
+
reason: `Gate '${input.gate.kind}' requires an explicit evaluator.`
|
|
43880
|
+
};
|
|
43881
|
+
}
|
|
43751
43882
|
return { passed: true };
|
|
43752
43883
|
}
|
|
43753
43884
|
function chunk(items, size) {
|
|
@@ -43758,6 +43889,85 @@ function chunk(items, size) {
|
|
|
43758
43889
|
}
|
|
43759
43890
|
return result;
|
|
43760
43891
|
}
|
|
43892
|
+
async function runWithOptionalTimeout(promise, timeoutMs, onTimeout) {
|
|
43893
|
+
if (!timeoutMs || timeoutMs <= 0) return promise;
|
|
43894
|
+
return Promise.race([
|
|
43895
|
+
promise,
|
|
43896
|
+
new Promise((resolve4) => {
|
|
43897
|
+
setTimeout(() => resolve4(onTimeout()), timeoutMs);
|
|
43898
|
+
})
|
|
43899
|
+
]);
|
|
43900
|
+
}
|
|
43901
|
+
function shouldSkipNode(node, graph, workflowInput, dependencyResults) {
|
|
43902
|
+
const nodeCondition = evaluateGraphCondition(node.condition, workflowInput, dependencyResults);
|
|
43903
|
+
if (!nodeCondition.passed) return nodeCondition.reason;
|
|
43904
|
+
for (const edge of graph.edges ?? []) {
|
|
43905
|
+
if (edge.to !== node.id || !edge.condition) continue;
|
|
43906
|
+
const edgeCondition = evaluateGraphCondition(edge.condition, workflowInput, dependencyResults);
|
|
43907
|
+
if (!edgeCondition.passed) {
|
|
43908
|
+
return `edge '${edge.from}' -> '${edge.to}' condition '${edge.condition}' was false`;
|
|
43909
|
+
}
|
|
43910
|
+
}
|
|
43911
|
+
return void 0;
|
|
43912
|
+
}
|
|
43913
|
+
function evaluateGraphCondition(condition, workflowInput, dependencyResults) {
|
|
43914
|
+
if (!condition || condition === "always") return { passed: true };
|
|
43915
|
+
if (condition === "never") return { passed: false, reason: "condition 'never' was false" };
|
|
43916
|
+
if (condition.startsWith("!input.")) {
|
|
43917
|
+
const path65 = condition.slice("!input.".length);
|
|
43918
|
+
return {
|
|
43919
|
+
passed: !readPath(workflowInput, path65),
|
|
43920
|
+
reason: `condition '${condition}' was false`
|
|
43921
|
+
};
|
|
43922
|
+
}
|
|
43923
|
+
if (condition.startsWith("input.")) {
|
|
43924
|
+
const path65 = condition.slice("input.".length);
|
|
43925
|
+
return {
|
|
43926
|
+
passed: Boolean(readPath(workflowInput, path65)),
|
|
43927
|
+
reason: `condition '${condition}' was false`
|
|
43928
|
+
};
|
|
43929
|
+
}
|
|
43930
|
+
if (condition.startsWith("dependency.") && condition.endsWith(".success")) {
|
|
43931
|
+
const id = condition.slice("dependency.".length, -".success".length);
|
|
43932
|
+
return {
|
|
43933
|
+
passed: dependencyResults.get(id)?.success === true,
|
|
43934
|
+
reason: `condition '${condition}' was false`
|
|
43935
|
+
};
|
|
43936
|
+
}
|
|
43937
|
+
if (condition.startsWith("dependency.") && condition.endsWith(".failed")) {
|
|
43938
|
+
const id = condition.slice("dependency.".length, -".failed".length);
|
|
43939
|
+
return {
|
|
43940
|
+
passed: dependencyResults.get(id)?.success === false,
|
|
43941
|
+
reason: `condition '${condition}' was false`
|
|
43942
|
+
};
|
|
43943
|
+
}
|
|
43944
|
+
return {
|
|
43945
|
+
passed: false,
|
|
43946
|
+
reason: `Unsupported graph condition '${condition}'.`
|
|
43947
|
+
};
|
|
43948
|
+
}
|
|
43949
|
+
function readPath(input, path65) {
|
|
43950
|
+
return path65.split(".").reduce((current, segment) => {
|
|
43951
|
+
if (current && typeof current === "object" && segment in current) {
|
|
43952
|
+
return current[segment];
|
|
43953
|
+
}
|
|
43954
|
+
return void 0;
|
|
43955
|
+
}, input);
|
|
43956
|
+
}
|
|
43957
|
+
function riskRank(risk) {
|
|
43958
|
+
switch (risk) {
|
|
43959
|
+
case "read-only":
|
|
43960
|
+
return 0;
|
|
43961
|
+
case "network":
|
|
43962
|
+
return 1;
|
|
43963
|
+
case "write":
|
|
43964
|
+
return 2;
|
|
43965
|
+
case "destructive":
|
|
43966
|
+
return 3;
|
|
43967
|
+
case "secrets-sensitive":
|
|
43968
|
+
return 4;
|
|
43969
|
+
}
|
|
43970
|
+
}
|
|
43761
43971
|
function cloneUnknown(value) {
|
|
43762
43972
|
if (value === void 0 || value === null) return value;
|
|
43763
43973
|
try {
|
|
@@ -43783,14 +43993,603 @@ function cloneArtifact(artifact) {
|
|
|
43783
43993
|
};
|
|
43784
43994
|
}
|
|
43785
43995
|
|
|
43996
|
+
// src/runtime/context.ts
|
|
43997
|
+
var RuntimePolicyViolation = class extends Error {
|
|
43998
|
+
code;
|
|
43999
|
+
subject;
|
|
44000
|
+
tenantId;
|
|
44001
|
+
policyPath;
|
|
44002
|
+
severity;
|
|
44003
|
+
constructor(input) {
|
|
44004
|
+
super(input.message);
|
|
44005
|
+
this.name = "RuntimePolicyViolation";
|
|
44006
|
+
this.code = input.code;
|
|
44007
|
+
this.subject = input.subject;
|
|
44008
|
+
this.tenantId = input.tenantId;
|
|
44009
|
+
this.policyPath = input.policyPath;
|
|
44010
|
+
this.severity = input.severity ?? "blocked";
|
|
44011
|
+
}
|
|
44012
|
+
};
|
|
44013
|
+
function createRuntimeRequestContext(input = {}) {
|
|
44014
|
+
return {
|
|
44015
|
+
surface: input.surface ?? "api",
|
|
44016
|
+
tenant: input.tenant ? { ...input.tenant, metadata: { ...input.tenant.metadata } } : void 0,
|
|
44017
|
+
user: input.user ? {
|
|
44018
|
+
...input.user,
|
|
44019
|
+
roles: [...input.user.roles ?? []],
|
|
44020
|
+
groups: [...input.user.groups ?? []],
|
|
44021
|
+
metadata: { ...input.user.metadata }
|
|
44022
|
+
} : void 0,
|
|
44023
|
+
channel: input.channel,
|
|
44024
|
+
correlationId: input.correlationId,
|
|
44025
|
+
policy: input.policy ? cloneRuntimePolicy(input.policy) : void 0,
|
|
44026
|
+
metadata: { ...input.metadata }
|
|
44027
|
+
};
|
|
44028
|
+
}
|
|
44029
|
+
function mergeRuntimePolicy(base, override) {
|
|
44030
|
+
if (!base && !override) return void 0;
|
|
44031
|
+
return {
|
|
44032
|
+
...base,
|
|
44033
|
+
...override,
|
|
44034
|
+
allowedTools: override?.allowedTools ? [...override.allowedTools] : base?.allowedTools ? [...base.allowedTools] : void 0,
|
|
44035
|
+
requireHumanApprovalFor: override?.requireHumanApprovalFor ? [...override.requireHumanApprovalFor] : base?.requireHumanApprovalFor ? [...base.requireHumanApprovalFor] : void 0,
|
|
44036
|
+
dataBoundary: { ...base?.dataBoundary, ...override?.dataBoundary },
|
|
44037
|
+
costBudget: { ...base?.costBudget, ...override?.costBudget },
|
|
44038
|
+
retention: { ...base?.retention, ...override?.retention },
|
|
44039
|
+
rateLimit: { ...base?.rateLimit, ...override?.rateLimit }
|
|
44040
|
+
};
|
|
44041
|
+
}
|
|
44042
|
+
function runtimeContextToMetadata(context) {
|
|
44043
|
+
if (!context) return {};
|
|
44044
|
+
return {
|
|
44045
|
+
surface: context.surface,
|
|
44046
|
+
channel: context.channel,
|
|
44047
|
+
correlationId: context.correlationId,
|
|
44048
|
+
tenantId: context.tenant?.id,
|
|
44049
|
+
tenantName: context.tenant?.name,
|
|
44050
|
+
userId: context.user?.id,
|
|
44051
|
+
userRoles: context.user?.roles,
|
|
44052
|
+
dataClassification: context.policy?.dataBoundary?.classification
|
|
44053
|
+
};
|
|
44054
|
+
}
|
|
44055
|
+
function createRuntimeTenantBoundary(context, hostMode = "local") {
|
|
44056
|
+
return {
|
|
44057
|
+
hostMode,
|
|
44058
|
+
surface: context?.surface ?? "api",
|
|
44059
|
+
tenantId: context?.tenant?.id,
|
|
44060
|
+
required: hostMode === "hosted" && context?.surface !== "cli"
|
|
44061
|
+
};
|
|
44062
|
+
}
|
|
44063
|
+
function assertRuntimeTenantBoundary(context, hostMode = "local", subject = "runtime operation") {
|
|
44064
|
+
const boundary = createRuntimeTenantBoundary(context, hostMode);
|
|
44065
|
+
if (boundary.required && !boundary.tenantId) {
|
|
44066
|
+
throw new RuntimePolicyViolation({
|
|
44067
|
+
code: "tenant_required",
|
|
44068
|
+
subject,
|
|
44069
|
+
tenantId: boundary.tenantId,
|
|
44070
|
+
policyPath: "runtimeContext.tenant.id",
|
|
44071
|
+
message: `Runtime tenant is required for hosted ${boundary.surface} operations.`
|
|
44072
|
+
});
|
|
44073
|
+
}
|
|
44074
|
+
return boundary;
|
|
44075
|
+
}
|
|
44076
|
+
function evaluateRuntimeToolPolicy(policy, input) {
|
|
44077
|
+
if (policy?.allowedTools && !policy.allowedTools.includes(input.toolName)) {
|
|
44078
|
+
return {
|
|
44079
|
+
allowed: false,
|
|
44080
|
+
reason: `Runtime policy does not allow tool: ${input.toolName}`,
|
|
44081
|
+
risk: input.risk
|
|
44082
|
+
};
|
|
44083
|
+
}
|
|
44084
|
+
if (policy?.maxToolRisk && riskRank2(input.risk) > riskRank2(policy.maxToolRisk)) {
|
|
44085
|
+
return {
|
|
44086
|
+
allowed: false,
|
|
44087
|
+
reason: `Runtime policy allows tools up to ${policy.maxToolRisk} risk; ${input.toolName} is ${input.risk}.`,
|
|
44088
|
+
risk: input.risk
|
|
44089
|
+
};
|
|
44090
|
+
}
|
|
44091
|
+
if (policy?.requireHumanApprovalFor?.includes(input.risk) && input.confirmed !== true) {
|
|
44092
|
+
return {
|
|
44093
|
+
allowed: false,
|
|
44094
|
+
requiresConfirmation: true,
|
|
44095
|
+
reason: `Runtime policy requires human approval for ${input.risk} tools.`,
|
|
44096
|
+
risk: input.risk
|
|
44097
|
+
};
|
|
44098
|
+
}
|
|
44099
|
+
return { allowed: true, risk: input.risk };
|
|
44100
|
+
}
|
|
44101
|
+
function evaluateRuntimeRiskPolicy(policy, input) {
|
|
44102
|
+
if (policy?.maxToolRisk && riskRank2(input.risk) > riskRank2(policy.maxToolRisk)) {
|
|
44103
|
+
return {
|
|
44104
|
+
allowed: false,
|
|
44105
|
+
reason: `Runtime policy allows work up to ${policy.maxToolRisk} risk; ${input.subject} is ${input.risk}.`,
|
|
44106
|
+
risk: input.risk
|
|
44107
|
+
};
|
|
44108
|
+
}
|
|
44109
|
+
if (policy?.requireHumanApprovalFor?.includes(input.risk) && input.confirmed !== true) {
|
|
44110
|
+
return {
|
|
44111
|
+
allowed: false,
|
|
44112
|
+
requiresConfirmation: true,
|
|
44113
|
+
reason: `Runtime policy requires human approval for ${input.risk} work.`,
|
|
44114
|
+
risk: input.risk
|
|
44115
|
+
};
|
|
44116
|
+
}
|
|
44117
|
+
return { allowed: true, risk: input.risk };
|
|
44118
|
+
}
|
|
44119
|
+
function assertRuntimeTurnWithinPolicy(policy, input) {
|
|
44120
|
+
const maxTurns = policy?.costBudget?.maxTurns;
|
|
44121
|
+
if (maxTurns !== void 0 && input.currentTurns >= maxTurns) {
|
|
44122
|
+
throw new RuntimePolicyViolation({
|
|
44123
|
+
code: "max_turns_exceeded",
|
|
44124
|
+
subject: input.subject,
|
|
44125
|
+
tenantId: input.tenantId,
|
|
44126
|
+
policyPath: "runtimePolicy.costBudget.maxTurns",
|
|
44127
|
+
message: `Runtime policy turn budget exceeded: ${input.currentTurns}/${maxTurns}`
|
|
44128
|
+
});
|
|
44129
|
+
}
|
|
44130
|
+
}
|
|
44131
|
+
function assertRuntimeUsageWithinPolicy(policy, usage) {
|
|
44132
|
+
const budget = policy?.costBudget;
|
|
44133
|
+
const subject = usage.subject ?? "runtime usage";
|
|
44134
|
+
if (!budget) return;
|
|
44135
|
+
if (budget.maxInputTokens !== void 0 && (usage.inputTokens ?? 0) > budget.maxInputTokens) {
|
|
44136
|
+
throw new RuntimePolicyViolation({
|
|
44137
|
+
code: "input_tokens_exceeded",
|
|
44138
|
+
subject,
|
|
44139
|
+
tenantId: usage.tenantId,
|
|
44140
|
+
policyPath: "runtimePolicy.costBudget.maxInputTokens",
|
|
44141
|
+
message: `Runtime policy input token budget exceeded: ${usage.inputTokens ?? 0}/${budget.maxInputTokens}`
|
|
44142
|
+
});
|
|
44143
|
+
}
|
|
44144
|
+
if (budget.maxOutputTokens !== void 0 && (usage.outputTokens ?? 0) > budget.maxOutputTokens) {
|
|
44145
|
+
throw new RuntimePolicyViolation({
|
|
44146
|
+
code: "output_tokens_exceeded",
|
|
44147
|
+
subject,
|
|
44148
|
+
tenantId: usage.tenantId,
|
|
44149
|
+
policyPath: "runtimePolicy.costBudget.maxOutputTokens",
|
|
44150
|
+
message: `Runtime policy output token budget exceeded: ${usage.outputTokens ?? 0}/${budget.maxOutputTokens}`
|
|
44151
|
+
});
|
|
44152
|
+
}
|
|
44153
|
+
if (budget.maxEstimatedCostUsd !== void 0 && (usage.estimatedCostUsd ?? 0) > budget.maxEstimatedCostUsd) {
|
|
44154
|
+
throw new RuntimePolicyViolation({
|
|
44155
|
+
code: "estimated_cost_exceeded",
|
|
44156
|
+
subject,
|
|
44157
|
+
tenantId: usage.tenantId,
|
|
44158
|
+
policyPath: "runtimePolicy.costBudget.maxEstimatedCostUsd",
|
|
44159
|
+
message: `Runtime policy estimated cost budget exceeded: ${usage.estimatedCostUsd ?? 0}/${budget.maxEstimatedCostUsd}`
|
|
44160
|
+
});
|
|
44161
|
+
}
|
|
44162
|
+
}
|
|
44163
|
+
function createRetentionCutoffs(policy, now = /* @__PURE__ */ new Date()) {
|
|
44164
|
+
const retention = policy?.retention;
|
|
44165
|
+
return {
|
|
44166
|
+
conversationBefore: cutoffIso(now, retention?.conversationDays),
|
|
44167
|
+
eventBefore: cutoffIso(now, retention?.eventDays),
|
|
44168
|
+
artifactBefore: cutoffIso(now, retention?.artifactDays)
|
|
44169
|
+
};
|
|
44170
|
+
}
|
|
44171
|
+
function cloneRuntimePolicy(policy) {
|
|
44172
|
+
return mergeRuntimePolicy(void 0, policy) ?? {};
|
|
44173
|
+
}
|
|
44174
|
+
function cutoffIso(now, days) {
|
|
44175
|
+
if (days === void 0) return void 0;
|
|
44176
|
+
return new Date(now.getTime() - days * 24 * 60 * 60 * 1e3).toISOString();
|
|
44177
|
+
}
|
|
44178
|
+
function riskRank2(risk) {
|
|
44179
|
+
switch (risk) {
|
|
44180
|
+
case "read-only":
|
|
44181
|
+
return 0;
|
|
44182
|
+
case "network":
|
|
44183
|
+
return 1;
|
|
44184
|
+
case "write":
|
|
44185
|
+
return 2;
|
|
44186
|
+
case "destructive":
|
|
44187
|
+
return 3;
|
|
44188
|
+
case "secrets-sensitive":
|
|
44189
|
+
return 4;
|
|
44190
|
+
}
|
|
44191
|
+
}
|
|
44192
|
+
var InMemoryEventLog = class {
|
|
44193
|
+
events = [];
|
|
44194
|
+
record(type, data = {}) {
|
|
44195
|
+
const event = {
|
|
44196
|
+
id: randomUUID(),
|
|
44197
|
+
type,
|
|
44198
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
44199
|
+
data
|
|
44200
|
+
};
|
|
44201
|
+
this.events.push(event);
|
|
44202
|
+
return event;
|
|
44203
|
+
}
|
|
44204
|
+
list() {
|
|
44205
|
+
return [...this.events];
|
|
44206
|
+
}
|
|
44207
|
+
count() {
|
|
44208
|
+
return this.events.length;
|
|
44209
|
+
}
|
|
44210
|
+
clear() {
|
|
44211
|
+
this.events = [];
|
|
44212
|
+
}
|
|
44213
|
+
};
|
|
44214
|
+
var FileEventLog = class {
|
|
44215
|
+
constructor(filePath) {
|
|
44216
|
+
this.filePath = filePath;
|
|
44217
|
+
try {
|
|
44218
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
44219
|
+
} catch {
|
|
44220
|
+
this.writable = false;
|
|
44221
|
+
}
|
|
44222
|
+
}
|
|
44223
|
+
filePath;
|
|
44224
|
+
memory = new InMemoryEventLog();
|
|
44225
|
+
writable = true;
|
|
44226
|
+
record(type, data = {}) {
|
|
44227
|
+
const event = this.memory.record(type, data);
|
|
44228
|
+
if (this.writable) {
|
|
44229
|
+
try {
|
|
44230
|
+
appendFileSync(this.filePath, JSON.stringify(event) + "\n", "utf-8");
|
|
44231
|
+
} catch {
|
|
44232
|
+
this.writable = false;
|
|
44233
|
+
}
|
|
44234
|
+
}
|
|
44235
|
+
return event;
|
|
44236
|
+
}
|
|
44237
|
+
list() {
|
|
44238
|
+
if (!this.writable) return this.memory.list();
|
|
44239
|
+
try {
|
|
44240
|
+
const raw = readFileSync(this.filePath, "utf-8");
|
|
44241
|
+
return raw.split("\n").filter(Boolean).flatMap((line) => {
|
|
44242
|
+
try {
|
|
44243
|
+
return [JSON.parse(line)];
|
|
44244
|
+
} catch {
|
|
44245
|
+
return [];
|
|
44246
|
+
}
|
|
44247
|
+
});
|
|
44248
|
+
} catch {
|
|
44249
|
+
return this.memory.list();
|
|
44250
|
+
}
|
|
44251
|
+
}
|
|
44252
|
+
count() {
|
|
44253
|
+
return this.list().length;
|
|
44254
|
+
}
|
|
44255
|
+
clear() {
|
|
44256
|
+
this.memory.clear();
|
|
44257
|
+
if (this.writable) {
|
|
44258
|
+
try {
|
|
44259
|
+
writeFileSync(this.filePath, "", "utf-8");
|
|
44260
|
+
} catch {
|
|
44261
|
+
this.writable = false;
|
|
44262
|
+
}
|
|
44263
|
+
}
|
|
44264
|
+
}
|
|
44265
|
+
};
|
|
44266
|
+
function createEventLog() {
|
|
44267
|
+
return new InMemoryEventLog();
|
|
44268
|
+
}
|
|
44269
|
+
function createFileEventLog(filePath) {
|
|
44270
|
+
return new FileEventLog(filePath);
|
|
44271
|
+
}
|
|
44272
|
+
|
|
44273
|
+
// src/runtime/agent-modes.ts
|
|
44274
|
+
var AGENT_MODES = {
|
|
44275
|
+
ask: {
|
|
44276
|
+
id: "ask",
|
|
44277
|
+
label: "Ask",
|
|
44278
|
+
description: "Answer questions and explain code without modifying files.",
|
|
44279
|
+
readOnly: true,
|
|
44280
|
+
preferredTools: ["read_file", "grep", "glob", "codebase_map", "lsp_definition"],
|
|
44281
|
+
requiresVerification: false
|
|
44282
|
+
},
|
|
44283
|
+
plan: {
|
|
44284
|
+
id: "plan",
|
|
44285
|
+
label: "Plan",
|
|
44286
|
+
description: "Explore and produce an implementation plan with read-only tools.",
|
|
44287
|
+
readOnly: true,
|
|
44288
|
+
preferredTools: ["read_file", "grep", "glob", "codebase_map", "lsp_workspace_symbols"],
|
|
44289
|
+
requiresVerification: false
|
|
44290
|
+
},
|
|
44291
|
+
build: {
|
|
44292
|
+
id: "build",
|
|
44293
|
+
label: "Build",
|
|
44294
|
+
description: "Implement code changes and verify them.",
|
|
44295
|
+
readOnly: false,
|
|
44296
|
+
preferredTools: ["read_file", "edit_file", "write_file", "bash_exec", "run_tests"],
|
|
44297
|
+
requiresVerification: true
|
|
44298
|
+
},
|
|
44299
|
+
debug: {
|
|
44300
|
+
id: "debug",
|
|
44301
|
+
label: "Debug",
|
|
44302
|
+
description: "Reproduce failures, trace root cause, patch, and verify.",
|
|
44303
|
+
readOnly: false,
|
|
44304
|
+
preferredTools: ["bash_exec", "read_file", "grep", "lsp_references", "edit_file"],
|
|
44305
|
+
requiresVerification: true
|
|
44306
|
+
},
|
|
44307
|
+
review: {
|
|
44308
|
+
id: "review",
|
|
44309
|
+
label: "Review",
|
|
44310
|
+
description: "Inspect code quality, security, behavior changes, and test gaps.",
|
|
44311
|
+
readOnly: true,
|
|
44312
|
+
preferredTools: ["git_diff", "read_file", "grep", "review_code", "calculate_quality"],
|
|
44313
|
+
requiresVerification: false
|
|
44314
|
+
},
|
|
44315
|
+
architect: {
|
|
44316
|
+
id: "architect",
|
|
44317
|
+
label: "Architect",
|
|
44318
|
+
description: "Design architecture and split work for architect/editor execution.",
|
|
44319
|
+
readOnly: true,
|
|
44320
|
+
preferredTools: ["codebase_map", "lsp_workspace_symbols", "grep", "create_agent_plan"],
|
|
44321
|
+
requiresVerification: false
|
|
44322
|
+
}
|
|
44323
|
+
};
|
|
44324
|
+
function getAgentMode(mode) {
|
|
44325
|
+
return AGENT_MODES[mode];
|
|
44326
|
+
}
|
|
44327
|
+
function listAgentModes() {
|
|
44328
|
+
return Object.values(AGENT_MODES);
|
|
44329
|
+
}
|
|
44330
|
+
function isAgentMode(value) {
|
|
44331
|
+
return value in AGENT_MODES;
|
|
44332
|
+
}
|
|
44333
|
+
|
|
44334
|
+
// src/runtime/permission-policy.ts
|
|
44335
|
+
var READ_ONLY_CATEGORIES = /* @__PURE__ */ new Set(["search", "web", "document"]);
|
|
44336
|
+
var WRITE_CATEGORIES = /* @__PURE__ */ new Set(["file", "git", "test", "build", "memory"]);
|
|
44337
|
+
var READ_ONLY_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
44338
|
+
"glob",
|
|
44339
|
+
"read_file",
|
|
44340
|
+
"list_dir",
|
|
44341
|
+
"tree",
|
|
44342
|
+
"grep",
|
|
44343
|
+
"find_in_file",
|
|
44344
|
+
"semantic_search",
|
|
44345
|
+
"codebase_map",
|
|
44346
|
+
"repo_context",
|
|
44347
|
+
"lsp_status",
|
|
44348
|
+
"lsp_document_symbols",
|
|
44349
|
+
"lsp_workspace_symbols",
|
|
44350
|
+
"lsp_definition",
|
|
44351
|
+
"lsp_references",
|
|
44352
|
+
"git_status",
|
|
44353
|
+
"git_log",
|
|
44354
|
+
"git_diff",
|
|
44355
|
+
"git_show",
|
|
44356
|
+
"git_branch",
|
|
44357
|
+
"recall_memory",
|
|
44358
|
+
"list_memories",
|
|
44359
|
+
"list_checkpoints",
|
|
44360
|
+
"checkAgentCapability"
|
|
44361
|
+
]);
|
|
44362
|
+
var WRITE_CAPABLE_TOOL_NAMES = /* @__PURE__ */ new Set(["run_linter"]);
|
|
44363
|
+
var DESTRUCTIVE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
44364
|
+
"bash_exec",
|
|
44365
|
+
"write_file",
|
|
44366
|
+
"edit_file",
|
|
44367
|
+
"delete_file",
|
|
44368
|
+
"restore_checkpoint",
|
|
44369
|
+
"git_commit",
|
|
44370
|
+
"git_push",
|
|
44371
|
+
"request_human_escalation"
|
|
44372
|
+
]);
|
|
44373
|
+
function riskForTool(tool) {
|
|
44374
|
+
if (READ_ONLY_TOOL_NAMES.has(tool.name)) return "read-only";
|
|
44375
|
+
if (DESTRUCTIVE_TOOL_NAMES.has(tool.name)) return "destructive";
|
|
44376
|
+
if (WRITE_CAPABLE_TOOL_NAMES.has(tool.name)) return "write";
|
|
44377
|
+
if (tool.category === "web") return "network";
|
|
44378
|
+
if (WRITE_CATEGORIES.has(tool.category)) return "write";
|
|
44379
|
+
if (tool.category === "quality") return "write";
|
|
44380
|
+
return "read-only";
|
|
44381
|
+
}
|
|
44382
|
+
var DefaultPermissionPolicy = class {
|
|
44383
|
+
canExecuteTool(mode, tool) {
|
|
44384
|
+
const definition = getAgentMode(mode);
|
|
44385
|
+
const risk = riskForTool(tool);
|
|
44386
|
+
const readOnlyTool = READ_ONLY_TOOL_NAMES.has(tool.name) || READ_ONLY_CATEGORIES.has(tool.category);
|
|
44387
|
+
if (definition.readOnly && !readOnlyTool) {
|
|
44388
|
+
return {
|
|
44389
|
+
allowed: false,
|
|
44390
|
+
reason: `${definition.label} mode is read-only; ${tool.name} is a ${tool.category} tool.`,
|
|
44391
|
+
risk
|
|
44392
|
+
};
|
|
44393
|
+
}
|
|
44394
|
+
if (risk === "destructive") {
|
|
44395
|
+
return {
|
|
44396
|
+
allowed: true,
|
|
44397
|
+
requiresConfirmation: true,
|
|
44398
|
+
reason: `${tool.name} can change repository state and should be confirmed.`,
|
|
44399
|
+
risk
|
|
44400
|
+
};
|
|
44401
|
+
}
|
|
44402
|
+
return { allowed: true, risk };
|
|
44403
|
+
}
|
|
44404
|
+
canExecuteToolInput(mode, tool, input) {
|
|
44405
|
+
if (tool.name === "spawnSimpleAgent") {
|
|
44406
|
+
const risk = riskForSpawnedAgent(input);
|
|
44407
|
+
const definition2 = getAgentMode(mode);
|
|
44408
|
+
if (definition2.readOnly && risk !== "read-only" && risk !== "network") {
|
|
44409
|
+
return {
|
|
44410
|
+
allowed: false,
|
|
44411
|
+
reason: `${definition2.label} mode is read-only; spawnSimpleAgent with this role can perform ${risk} work.`,
|
|
44412
|
+
risk
|
|
44413
|
+
};
|
|
44414
|
+
}
|
|
44415
|
+
return {
|
|
44416
|
+
allowed: true,
|
|
44417
|
+
requiresConfirmation: risk === "destructive" || risk === "secrets-sensitive",
|
|
44418
|
+
risk
|
|
44419
|
+
};
|
|
44420
|
+
}
|
|
44421
|
+
if (tool.name !== "run_linter") {
|
|
44422
|
+
return this.canExecuteTool(mode, tool);
|
|
44423
|
+
}
|
|
44424
|
+
const definition = getAgentMode(mode);
|
|
44425
|
+
const fixEnabled = input["fix"] === true;
|
|
44426
|
+
const decision = fixEnabled ? { allowed: true, risk: "write" } : { allowed: true, risk: "read-only" };
|
|
44427
|
+
if (definition.readOnly && fixEnabled) {
|
|
44428
|
+
return {
|
|
44429
|
+
allowed: false,
|
|
44430
|
+
reason: `${definition.label} mode is read-only; run_linter with fix=true can modify files.`,
|
|
44431
|
+
risk: "write"
|
|
44432
|
+
};
|
|
44433
|
+
}
|
|
44434
|
+
return decision;
|
|
44435
|
+
}
|
|
44436
|
+
};
|
|
44437
|
+
function createPermissionPolicy() {
|
|
44438
|
+
return new DefaultPermissionPolicy();
|
|
44439
|
+
}
|
|
44440
|
+
function riskForSpawnedAgent(input) {
|
|
44441
|
+
const type = typeof input["type"] === "string" ? input["type"] : void 0;
|
|
44442
|
+
const role = typeof input["role"] === "string" ? input["role"] : void 0;
|
|
44443
|
+
const resolved = type ?? role;
|
|
44444
|
+
switch (resolved) {
|
|
44445
|
+
case "explore":
|
|
44446
|
+
case "plan":
|
|
44447
|
+
case "review":
|
|
44448
|
+
case "architect":
|
|
44449
|
+
case "security":
|
|
44450
|
+
case "docs":
|
|
44451
|
+
case "researcher":
|
|
44452
|
+
case "reviewer":
|
|
44453
|
+
case "planner":
|
|
44454
|
+
return "read-only";
|
|
44455
|
+
case "database":
|
|
44456
|
+
return "secrets-sensitive";
|
|
44457
|
+
case "test":
|
|
44458
|
+
case "tdd":
|
|
44459
|
+
case "e2e":
|
|
44460
|
+
case "tester":
|
|
44461
|
+
return "destructive";
|
|
44462
|
+
case "debug":
|
|
44463
|
+
case "refactor":
|
|
44464
|
+
case "coder":
|
|
44465
|
+
case "optimizer":
|
|
44466
|
+
return "write";
|
|
44467
|
+
default:
|
|
44468
|
+
return "read-only";
|
|
44469
|
+
}
|
|
44470
|
+
}
|
|
44471
|
+
|
|
44472
|
+
// src/runtime/runtime-tool-executor.ts
|
|
44473
|
+
var RuntimeToolExecutor = class {
|
|
44474
|
+
toolRegistry;
|
|
44475
|
+
eventLog;
|
|
44476
|
+
permissionPolicy;
|
|
44477
|
+
defaultMode;
|
|
44478
|
+
runtimePolicy;
|
|
44479
|
+
constructor(options) {
|
|
44480
|
+
this.toolRegistry = options.toolRegistry;
|
|
44481
|
+
this.eventLog = options.eventLog ?? createEventLog();
|
|
44482
|
+
this.permissionPolicy = options.permissionPolicy ?? createPermissionPolicy();
|
|
44483
|
+
this.defaultMode = options.mode ?? "ask";
|
|
44484
|
+
this.runtimePolicy = options.runtimePolicy;
|
|
44485
|
+
}
|
|
44486
|
+
async execute(input) {
|
|
44487
|
+
const startedAt = performance.now();
|
|
44488
|
+
const mode = input.mode ?? this.defaultMode;
|
|
44489
|
+
const allowedTools = input.allowedTools ? new Set(input.allowedTools) : void 0;
|
|
44490
|
+
if (allowedTools && !allowedTools.has(input.toolName)) {
|
|
44491
|
+
const decision2 = {
|
|
44492
|
+
allowed: false,
|
|
44493
|
+
reason: `Tool '${input.toolName}' is not available to this agent.`,
|
|
44494
|
+
risk: "read-only"
|
|
44495
|
+
};
|
|
44496
|
+
return this.block(input, mode, decision2, startedAt);
|
|
44497
|
+
}
|
|
44498
|
+
const tool = this.toolRegistry.get(input.toolName);
|
|
44499
|
+
if (!tool) {
|
|
44500
|
+
const decision2 = {
|
|
44501
|
+
allowed: false,
|
|
44502
|
+
reason: "Tool not registered.",
|
|
44503
|
+
risk: "read-only"
|
|
44504
|
+
};
|
|
44505
|
+
return this.block(input, mode, decision2, startedAt);
|
|
44506
|
+
}
|
|
44507
|
+
const decision = this.permissionPolicy.canExecuteToolInput ? this.permissionPolicy.canExecuteToolInput(mode, tool, input.input) : this.permissionPolicy.canExecuteTool(mode, tool);
|
|
44508
|
+
const runtimeDecision = decision.allowed ? evaluateRuntimeToolPolicy(this.runtimePolicy, {
|
|
44509
|
+
toolName: input.toolName,
|
|
44510
|
+
risk: decision.risk,
|
|
44511
|
+
confirmed: input.confirmed
|
|
44512
|
+
}) : void 0;
|
|
44513
|
+
if (!decision.allowed || runtimeDecision?.allowed === false || decision.requiresConfirmation && input.confirmed !== true) {
|
|
44514
|
+
const reason = runtimeDecision?.reason ?? decision.reason ?? (decision.requiresConfirmation ? "Tool requires explicit runtime confirmation." : "Tool is not allowed.");
|
|
44515
|
+
return this.block(
|
|
44516
|
+
input,
|
|
44517
|
+
mode,
|
|
44518
|
+
{
|
|
44519
|
+
...decision,
|
|
44520
|
+
allowed: false,
|
|
44521
|
+
reason,
|
|
44522
|
+
requiresConfirmation: runtimeDecision?.requiresConfirmation ?? decision.requiresConfirmation,
|
|
44523
|
+
risk: runtimeDecision?.risk ?? decision.risk
|
|
44524
|
+
},
|
|
44525
|
+
startedAt,
|
|
44526
|
+
{ runtimePolicyBlocked: runtimeDecision ? !runtimeDecision.allowed : false }
|
|
44527
|
+
);
|
|
44528
|
+
}
|
|
44529
|
+
this.eventLog.record("agent.tool.called", {
|
|
44530
|
+
mode,
|
|
44531
|
+
tool: input.toolName,
|
|
44532
|
+
risk: decision.risk,
|
|
44533
|
+
metadata: input.metadata
|
|
44534
|
+
});
|
|
44535
|
+
this.eventLog.record("tool.started", {
|
|
44536
|
+
mode,
|
|
44537
|
+
tool: input.toolName,
|
|
44538
|
+
risk: decision.risk,
|
|
44539
|
+
runtimeApi: true,
|
|
44540
|
+
metadataKeys: Object.keys(input.metadata ?? {}).sort()
|
|
44541
|
+
});
|
|
44542
|
+
const result = await this.toolRegistry.execute(input.toolName, input.input);
|
|
44543
|
+
this.eventLog.record("tool.completed", {
|
|
44544
|
+
mode,
|
|
44545
|
+
tool: input.toolName,
|
|
44546
|
+
success: result.success,
|
|
44547
|
+
duration: result.duration,
|
|
44548
|
+
runtimeApi: true
|
|
44549
|
+
});
|
|
44550
|
+
return {
|
|
44551
|
+
toolName: input.toolName,
|
|
44552
|
+
success: result.success,
|
|
44553
|
+
output: result.data,
|
|
44554
|
+
error: result.error,
|
|
44555
|
+
duration: result.duration,
|
|
44556
|
+
decision
|
|
44557
|
+
};
|
|
44558
|
+
}
|
|
44559
|
+
block(input, mode, decision, startedAt, extraData = {}) {
|
|
44560
|
+
this.eventLog.record("tool.blocked", {
|
|
44561
|
+
mode,
|
|
44562
|
+
tool: input.toolName,
|
|
44563
|
+
reason: decision.reason,
|
|
44564
|
+
risk: decision.risk,
|
|
44565
|
+
requiresConfirmation: decision.requiresConfirmation,
|
|
44566
|
+
runtimeApi: true,
|
|
44567
|
+
metadata: input.metadata,
|
|
44568
|
+
...extraData
|
|
44569
|
+
});
|
|
44570
|
+
return {
|
|
44571
|
+
toolName: input.toolName,
|
|
44572
|
+
success: false,
|
|
44573
|
+
error: decision.reason ?? "Tool is not allowed.",
|
|
44574
|
+
duration: performance.now() - startedAt,
|
|
44575
|
+
decision
|
|
44576
|
+
};
|
|
44577
|
+
}
|
|
44578
|
+
};
|
|
44579
|
+
function createRuntimeToolExecutor(options) {
|
|
44580
|
+
return new RuntimeToolExecutor(options);
|
|
44581
|
+
}
|
|
44582
|
+
|
|
43786
44583
|
// src/agents/executor.ts
|
|
43787
44584
|
var AgentExecutor = class {
|
|
43788
|
-
constructor(provider, toolRegistry) {
|
|
44585
|
+
constructor(provider, toolRegistry, runtimeToolExecutor) {
|
|
43789
44586
|
this.provider = provider;
|
|
43790
44587
|
this.toolRegistry = toolRegistry;
|
|
44588
|
+
this.runtimeToolExecutor = runtimeToolExecutor ?? createRuntimeToolExecutor({ toolRegistry, mode: "ask" });
|
|
43791
44589
|
}
|
|
43792
44590
|
provider;
|
|
43793
44591
|
toolRegistry;
|
|
44592
|
+
runtimeToolExecutor;
|
|
43794
44593
|
/**
|
|
43795
44594
|
* Execute an agent on a task with multi-turn tool use
|
|
43796
44595
|
*/
|
|
@@ -43858,11 +44657,21 @@ var AgentExecutor = class {
|
|
|
43858
44657
|
for (const toolCall of response.toolCalls) {
|
|
43859
44658
|
toolsUsed.add(toolCall.name);
|
|
43860
44659
|
try {
|
|
43861
|
-
const result = await this.
|
|
44660
|
+
const result = await this.runtimeToolExecutor.execute({
|
|
44661
|
+
toolName: toolCall.name,
|
|
44662
|
+
input: toolCall.input,
|
|
44663
|
+
allowedTools: agent.allowedTools.length > 0 ? agent.allowedTools : void 0,
|
|
44664
|
+
mode: runtimeModeForAgent(agent.role),
|
|
44665
|
+
metadata: {
|
|
44666
|
+
agentRole: agent.role,
|
|
44667
|
+
taskId: task.id,
|
|
44668
|
+
toolCallId: toolCall.id
|
|
44669
|
+
}
|
|
44670
|
+
});
|
|
43862
44671
|
toolResults.push({
|
|
43863
44672
|
type: "tool_result",
|
|
43864
44673
|
tool_use_id: toolCall.id,
|
|
43865
|
-
content: result.success ? JSON.stringify(result.
|
|
44674
|
+
content: result.success ? JSON.stringify(result.output) : `Error: ${result.error}`,
|
|
43866
44675
|
is_error: !result.success
|
|
43867
44676
|
});
|
|
43868
44677
|
} catch (error) {
|
|
@@ -44073,6 +44882,22 @@ Use tools to analyze requirements and explore the codebase.`,
|
|
|
44073
44882
|
allowedTools: ["read_file", "grep", "glob", "codebase_map"]
|
|
44074
44883
|
}
|
|
44075
44884
|
};
|
|
44885
|
+
function runtimeModeForAgent(role) {
|
|
44886
|
+
switch (role) {
|
|
44887
|
+
case "researcher":
|
|
44888
|
+
case "planner":
|
|
44889
|
+
return "plan";
|
|
44890
|
+
case "architect":
|
|
44891
|
+
return "architect";
|
|
44892
|
+
case "reviewer":
|
|
44893
|
+
return "review";
|
|
44894
|
+
case "tester":
|
|
44895
|
+
case "editor":
|
|
44896
|
+
case "coder":
|
|
44897
|
+
case "optimizer":
|
|
44898
|
+
return "build";
|
|
44899
|
+
}
|
|
44900
|
+
}
|
|
44076
44901
|
var DEFAULTS = {
|
|
44077
44902
|
maxConcurrency: os4__default.cpus().length,
|
|
44078
44903
|
minConcurrency: 1,
|
|
@@ -46392,16 +47217,18 @@ var AgentManager = class extends EventEmitter {
|
|
|
46392
47217
|
abortControllers = /* @__PURE__ */ new Map();
|
|
46393
47218
|
provider;
|
|
46394
47219
|
toolRegistry;
|
|
47220
|
+
runtimeToolExecutor;
|
|
46395
47221
|
logger = getLogger();
|
|
46396
47222
|
/**
|
|
46397
47223
|
* Create a new AgentManager
|
|
46398
47224
|
* @param provider - LLM provider for agent execution
|
|
46399
47225
|
* @param toolRegistry - Tool registry for agent tool access
|
|
46400
47226
|
*/
|
|
46401
|
-
constructor(provider, toolRegistry) {
|
|
47227
|
+
constructor(provider, toolRegistry, runtimeToolExecutor) {
|
|
46402
47228
|
super();
|
|
46403
47229
|
this.provider = provider;
|
|
46404
47230
|
this.toolRegistry = toolRegistry;
|
|
47231
|
+
this.runtimeToolExecutor = runtimeToolExecutor ?? createRuntimeToolExecutor({ toolRegistry, mode: "ask" });
|
|
46405
47232
|
}
|
|
46406
47233
|
/**
|
|
46407
47234
|
* Spawn a new subagent for a specific task
|
|
@@ -46716,11 +47543,20 @@ var AgentManager = class extends EventEmitter {
|
|
|
46716
47543
|
continue;
|
|
46717
47544
|
}
|
|
46718
47545
|
try {
|
|
46719
|
-
const result = await this.
|
|
47546
|
+
const result = await this.runtimeToolExecutor.execute({
|
|
47547
|
+
toolName: toolCall.name,
|
|
47548
|
+
input: toolCall.input,
|
|
47549
|
+
allowedTools: config.tools,
|
|
47550
|
+
mode: runtimeModeForAgentType(config.type),
|
|
47551
|
+
metadata: {
|
|
47552
|
+
agentType: config.type,
|
|
47553
|
+
toolCallId: toolCall.id
|
|
47554
|
+
}
|
|
47555
|
+
});
|
|
46720
47556
|
results.push({
|
|
46721
47557
|
type: "tool_result",
|
|
46722
47558
|
tool_use_id: toolCall.id,
|
|
46723
|
-
content: result.success ? String(result.
|
|
47559
|
+
content: result.success ? String(result.output ?? "Success") : `Error: ${result.error}`,
|
|
46724
47560
|
is_error: !result.success
|
|
46725
47561
|
});
|
|
46726
47562
|
} catch (error) {
|
|
@@ -46785,6 +47621,27 @@ var AgentManager = class extends EventEmitter {
|
|
|
46785
47621
|
function agentTypeToRuntimeRole(type) {
|
|
46786
47622
|
return mapLegacyAgentRole(type);
|
|
46787
47623
|
}
|
|
47624
|
+
function runtimeModeForAgentType(type) {
|
|
47625
|
+
switch (type) {
|
|
47626
|
+
case "explore":
|
|
47627
|
+
case "plan":
|
|
47628
|
+
case "docs":
|
|
47629
|
+
return "plan";
|
|
47630
|
+
case "review":
|
|
47631
|
+
case "security":
|
|
47632
|
+
return "review";
|
|
47633
|
+
case "architect":
|
|
47634
|
+
return "architect";
|
|
47635
|
+
case "debug":
|
|
47636
|
+
return "debug";
|
|
47637
|
+
case "test":
|
|
47638
|
+
case "tdd":
|
|
47639
|
+
case "e2e":
|
|
47640
|
+
case "refactor":
|
|
47641
|
+
case "database":
|
|
47642
|
+
return "build";
|
|
47643
|
+
}
|
|
47644
|
+
}
|
|
46788
47645
|
|
|
46789
47646
|
// src/agents/provider-bridge.ts
|
|
46790
47647
|
var agentProvider = null;
|
|
@@ -50656,7 +51513,7 @@ async function validateCode(code, filePath, _language) {
|
|
|
50656
51513
|
const errors = [];
|
|
50657
51514
|
const warnings = [];
|
|
50658
51515
|
try {
|
|
50659
|
-
const ast = parse
|
|
51516
|
+
const ast = parse(code, {
|
|
50660
51517
|
loc: true,
|
|
50661
51518
|
range: true,
|
|
50662
51519
|
comment: true,
|
|
@@ -50783,7 +51640,7 @@ async function analyzeFile(filePath, includeAst = false) {
|
|
|
50783
51640
|
const exports$1 = [];
|
|
50784
51641
|
let ast;
|
|
50785
51642
|
try {
|
|
50786
|
-
ast = parse
|
|
51643
|
+
ast = parse(content, {
|
|
50787
51644
|
loc: true,
|
|
50788
51645
|
range: true,
|
|
50789
51646
|
comment: true,
|
|
@@ -53261,69 +54118,6 @@ var repoMapCommand = {
|
|
|
53261
54118
|
return false;
|
|
53262
54119
|
}
|
|
53263
54120
|
};
|
|
53264
|
-
|
|
53265
|
-
// src/runtime/agent-modes.ts
|
|
53266
|
-
var AGENT_MODES = {
|
|
53267
|
-
ask: {
|
|
53268
|
-
id: "ask",
|
|
53269
|
-
label: "Ask",
|
|
53270
|
-
description: "Answer questions and explain code without modifying files.",
|
|
53271
|
-
readOnly: true,
|
|
53272
|
-
preferredTools: ["read_file", "grep", "glob", "codebase_map", "lsp_definition"],
|
|
53273
|
-
requiresVerification: false
|
|
53274
|
-
},
|
|
53275
|
-
plan: {
|
|
53276
|
-
id: "plan",
|
|
53277
|
-
label: "Plan",
|
|
53278
|
-
description: "Explore and produce an implementation plan with read-only tools.",
|
|
53279
|
-
readOnly: true,
|
|
53280
|
-
preferredTools: ["read_file", "grep", "glob", "codebase_map", "lsp_workspace_symbols"],
|
|
53281
|
-
requiresVerification: false
|
|
53282
|
-
},
|
|
53283
|
-
build: {
|
|
53284
|
-
id: "build",
|
|
53285
|
-
label: "Build",
|
|
53286
|
-
description: "Implement code changes and verify them.",
|
|
53287
|
-
readOnly: false,
|
|
53288
|
-
preferredTools: ["read_file", "edit_file", "write_file", "bash_exec", "run_tests"],
|
|
53289
|
-
requiresVerification: true
|
|
53290
|
-
},
|
|
53291
|
-
debug: {
|
|
53292
|
-
id: "debug",
|
|
53293
|
-
label: "Debug",
|
|
53294
|
-
description: "Reproduce failures, trace root cause, patch, and verify.",
|
|
53295
|
-
readOnly: false,
|
|
53296
|
-
preferredTools: ["bash_exec", "read_file", "grep", "lsp_references", "edit_file"],
|
|
53297
|
-
requiresVerification: true
|
|
53298
|
-
},
|
|
53299
|
-
review: {
|
|
53300
|
-
id: "review",
|
|
53301
|
-
label: "Review",
|
|
53302
|
-
description: "Inspect code quality, security, behavior changes, and test gaps.",
|
|
53303
|
-
readOnly: true,
|
|
53304
|
-
preferredTools: ["git_diff", "read_file", "grep", "review_code", "calculate_quality"],
|
|
53305
|
-
requiresVerification: false
|
|
53306
|
-
},
|
|
53307
|
-
architect: {
|
|
53308
|
-
id: "architect",
|
|
53309
|
-
label: "Architect",
|
|
53310
|
-
description: "Design architecture and split work for architect/editor execution.",
|
|
53311
|
-
readOnly: true,
|
|
53312
|
-
preferredTools: ["codebase_map", "lsp_workspace_symbols", "grep", "create_agent_plan"],
|
|
53313
|
-
requiresVerification: false
|
|
53314
|
-
}
|
|
53315
|
-
};
|
|
53316
|
-
function getAgentMode(mode) {
|
|
53317
|
-
return AGENT_MODES[mode];
|
|
53318
|
-
}
|
|
53319
|
-
function listAgentModes() {
|
|
53320
|
-
return Object.values(AGENT_MODES);
|
|
53321
|
-
}
|
|
53322
|
-
function isAgentMode(value) {
|
|
53323
|
-
return value in AGENT_MODES;
|
|
53324
|
-
}
|
|
53325
|
-
|
|
53326
|
-
// src/cli/repl/commands/mode.ts
|
|
53327
54121
|
function currentMode(session) {
|
|
53328
54122
|
return session.agentMode ?? (session.planMode ? "plan" : "build");
|
|
53329
54123
|
}
|
|
@@ -58030,6 +58824,8 @@ init_providers();
|
|
|
58030
58824
|
|
|
58031
58825
|
// src/runtime/agent-runtime.ts
|
|
58032
58826
|
init_env();
|
|
58827
|
+
init_pricing();
|
|
58828
|
+
init_registry4();
|
|
58033
58829
|
|
|
58034
58830
|
// src/runtime/default-turn-runner.ts
|
|
58035
58831
|
var DefaultRuntimeTurnRunner = class {
|
|
@@ -58063,224 +58859,6 @@ var DefaultRuntimeTurnRunner = class {
|
|
|
58063
58859
|
function createDefaultRuntimeTurnRunner() {
|
|
58064
58860
|
return new DefaultRuntimeTurnRunner();
|
|
58065
58861
|
}
|
|
58066
|
-
var InMemoryEventLog = class {
|
|
58067
|
-
events = [];
|
|
58068
|
-
record(type, data = {}) {
|
|
58069
|
-
const event = {
|
|
58070
|
-
id: randomUUID(),
|
|
58071
|
-
type,
|
|
58072
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
58073
|
-
data
|
|
58074
|
-
};
|
|
58075
|
-
this.events.push(event);
|
|
58076
|
-
return event;
|
|
58077
|
-
}
|
|
58078
|
-
list() {
|
|
58079
|
-
return [...this.events];
|
|
58080
|
-
}
|
|
58081
|
-
count() {
|
|
58082
|
-
return this.events.length;
|
|
58083
|
-
}
|
|
58084
|
-
clear() {
|
|
58085
|
-
this.events = [];
|
|
58086
|
-
}
|
|
58087
|
-
};
|
|
58088
|
-
var FileEventLog = class {
|
|
58089
|
-
constructor(filePath) {
|
|
58090
|
-
this.filePath = filePath;
|
|
58091
|
-
try {
|
|
58092
|
-
mkdirSync(dirname(filePath), { recursive: true });
|
|
58093
|
-
} catch {
|
|
58094
|
-
this.writable = false;
|
|
58095
|
-
}
|
|
58096
|
-
}
|
|
58097
|
-
filePath;
|
|
58098
|
-
memory = new InMemoryEventLog();
|
|
58099
|
-
writable = true;
|
|
58100
|
-
record(type, data = {}) {
|
|
58101
|
-
const event = this.memory.record(type, data);
|
|
58102
|
-
if (this.writable) {
|
|
58103
|
-
try {
|
|
58104
|
-
appendFileSync(this.filePath, JSON.stringify(event) + "\n", "utf-8");
|
|
58105
|
-
} catch {
|
|
58106
|
-
this.writable = false;
|
|
58107
|
-
}
|
|
58108
|
-
}
|
|
58109
|
-
return event;
|
|
58110
|
-
}
|
|
58111
|
-
list() {
|
|
58112
|
-
if (!this.writable) return this.memory.list();
|
|
58113
|
-
try {
|
|
58114
|
-
const raw = readFileSync(this.filePath, "utf-8");
|
|
58115
|
-
return raw.split("\n").filter(Boolean).flatMap((line) => {
|
|
58116
|
-
try {
|
|
58117
|
-
return [JSON.parse(line)];
|
|
58118
|
-
} catch {
|
|
58119
|
-
return [];
|
|
58120
|
-
}
|
|
58121
|
-
});
|
|
58122
|
-
} catch {
|
|
58123
|
-
return this.memory.list();
|
|
58124
|
-
}
|
|
58125
|
-
}
|
|
58126
|
-
count() {
|
|
58127
|
-
return this.list().length;
|
|
58128
|
-
}
|
|
58129
|
-
clear() {
|
|
58130
|
-
this.memory.clear();
|
|
58131
|
-
if (this.writable) {
|
|
58132
|
-
try {
|
|
58133
|
-
writeFileSync(this.filePath, "", "utf-8");
|
|
58134
|
-
} catch {
|
|
58135
|
-
this.writable = false;
|
|
58136
|
-
}
|
|
58137
|
-
}
|
|
58138
|
-
}
|
|
58139
|
-
};
|
|
58140
|
-
function createEventLog() {
|
|
58141
|
-
return new InMemoryEventLog();
|
|
58142
|
-
}
|
|
58143
|
-
function createFileEventLog(filePath) {
|
|
58144
|
-
return new FileEventLog(filePath);
|
|
58145
|
-
}
|
|
58146
|
-
|
|
58147
|
-
// src/runtime/permission-policy.ts
|
|
58148
|
-
var READ_ONLY_CATEGORIES = /* @__PURE__ */ new Set(["search", "web", "document"]);
|
|
58149
|
-
var WRITE_CATEGORIES = /* @__PURE__ */ new Set(["file", "git", "test", "build", "memory"]);
|
|
58150
|
-
var READ_ONLY_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
58151
|
-
"glob",
|
|
58152
|
-
"read_file",
|
|
58153
|
-
"list_dir",
|
|
58154
|
-
"tree",
|
|
58155
|
-
"grep",
|
|
58156
|
-
"find_in_file",
|
|
58157
|
-
"semantic_search",
|
|
58158
|
-
"codebase_map",
|
|
58159
|
-
"repo_context",
|
|
58160
|
-
"lsp_status",
|
|
58161
|
-
"lsp_document_symbols",
|
|
58162
|
-
"lsp_workspace_symbols",
|
|
58163
|
-
"lsp_definition",
|
|
58164
|
-
"lsp_references",
|
|
58165
|
-
"git_status",
|
|
58166
|
-
"git_log",
|
|
58167
|
-
"git_diff",
|
|
58168
|
-
"git_show",
|
|
58169
|
-
"git_branch",
|
|
58170
|
-
"recall_memory",
|
|
58171
|
-
"list_memories",
|
|
58172
|
-
"list_checkpoints",
|
|
58173
|
-
"checkAgentCapability"
|
|
58174
|
-
]);
|
|
58175
|
-
var WRITE_CAPABLE_TOOL_NAMES = /* @__PURE__ */ new Set(["run_linter"]);
|
|
58176
|
-
var DESTRUCTIVE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
58177
|
-
"bash_exec",
|
|
58178
|
-
"write_file",
|
|
58179
|
-
"edit_file",
|
|
58180
|
-
"delete_file",
|
|
58181
|
-
"restore_checkpoint",
|
|
58182
|
-
"git_commit",
|
|
58183
|
-
"git_push",
|
|
58184
|
-
"request_human_escalation"
|
|
58185
|
-
]);
|
|
58186
|
-
function riskForTool(tool) {
|
|
58187
|
-
if (READ_ONLY_TOOL_NAMES.has(tool.name)) return "read-only";
|
|
58188
|
-
if (DESTRUCTIVE_TOOL_NAMES.has(tool.name)) return "destructive";
|
|
58189
|
-
if (WRITE_CAPABLE_TOOL_NAMES.has(tool.name)) return "write";
|
|
58190
|
-
if (tool.category === "web") return "network";
|
|
58191
|
-
if (WRITE_CATEGORIES.has(tool.category)) return "write";
|
|
58192
|
-
if (tool.category === "quality") return "write";
|
|
58193
|
-
return "read-only";
|
|
58194
|
-
}
|
|
58195
|
-
var DefaultPermissionPolicy = class {
|
|
58196
|
-
canExecuteTool(mode, tool) {
|
|
58197
|
-
const definition = getAgentMode(mode);
|
|
58198
|
-
const risk = riskForTool(tool);
|
|
58199
|
-
const readOnlyTool = READ_ONLY_TOOL_NAMES.has(tool.name) || READ_ONLY_CATEGORIES.has(tool.category);
|
|
58200
|
-
if (definition.readOnly && !readOnlyTool) {
|
|
58201
|
-
return {
|
|
58202
|
-
allowed: false,
|
|
58203
|
-
reason: `${definition.label} mode is read-only; ${tool.name} is a ${tool.category} tool.`,
|
|
58204
|
-
risk
|
|
58205
|
-
};
|
|
58206
|
-
}
|
|
58207
|
-
if (risk === "destructive") {
|
|
58208
|
-
return {
|
|
58209
|
-
allowed: true,
|
|
58210
|
-
requiresConfirmation: true,
|
|
58211
|
-
reason: `${tool.name} can change repository state and should be confirmed.`,
|
|
58212
|
-
risk
|
|
58213
|
-
};
|
|
58214
|
-
}
|
|
58215
|
-
return { allowed: true, risk };
|
|
58216
|
-
}
|
|
58217
|
-
canExecuteToolInput(mode, tool, input) {
|
|
58218
|
-
if (tool.name === "spawnSimpleAgent") {
|
|
58219
|
-
const risk = riskForSpawnedAgent(input);
|
|
58220
|
-
const definition2 = getAgentMode(mode);
|
|
58221
|
-
if (definition2.readOnly && risk !== "read-only" && risk !== "network") {
|
|
58222
|
-
return {
|
|
58223
|
-
allowed: false,
|
|
58224
|
-
reason: `${definition2.label} mode is read-only; spawnSimpleAgent with this role can perform ${risk} work.`,
|
|
58225
|
-
risk
|
|
58226
|
-
};
|
|
58227
|
-
}
|
|
58228
|
-
return {
|
|
58229
|
-
allowed: true,
|
|
58230
|
-
requiresConfirmation: risk === "destructive" || risk === "secrets-sensitive",
|
|
58231
|
-
risk
|
|
58232
|
-
};
|
|
58233
|
-
}
|
|
58234
|
-
if (tool.name !== "run_linter") {
|
|
58235
|
-
return this.canExecuteTool(mode, tool);
|
|
58236
|
-
}
|
|
58237
|
-
const definition = getAgentMode(mode);
|
|
58238
|
-
const fixEnabled = input["fix"] === true;
|
|
58239
|
-
const decision = fixEnabled ? { allowed: true, risk: "write" } : { allowed: true, risk: "read-only" };
|
|
58240
|
-
if (definition.readOnly && fixEnabled) {
|
|
58241
|
-
return {
|
|
58242
|
-
allowed: false,
|
|
58243
|
-
reason: `${definition.label} mode is read-only; run_linter with fix=true can modify files.`,
|
|
58244
|
-
risk: "write"
|
|
58245
|
-
};
|
|
58246
|
-
}
|
|
58247
|
-
return decision;
|
|
58248
|
-
}
|
|
58249
|
-
};
|
|
58250
|
-
function createPermissionPolicy() {
|
|
58251
|
-
return new DefaultPermissionPolicy();
|
|
58252
|
-
}
|
|
58253
|
-
function riskForSpawnedAgent(input) {
|
|
58254
|
-
const type = typeof input["type"] === "string" ? input["type"] : void 0;
|
|
58255
|
-
const role = typeof input["role"] === "string" ? input["role"] : void 0;
|
|
58256
|
-
const resolved = type ?? role;
|
|
58257
|
-
switch (resolved) {
|
|
58258
|
-
case "explore":
|
|
58259
|
-
case "plan":
|
|
58260
|
-
case "review":
|
|
58261
|
-
case "architect":
|
|
58262
|
-
case "security":
|
|
58263
|
-
case "docs":
|
|
58264
|
-
case "researcher":
|
|
58265
|
-
case "reviewer":
|
|
58266
|
-
case "planner":
|
|
58267
|
-
return "read-only";
|
|
58268
|
-
case "database":
|
|
58269
|
-
return "secrets-sensitive";
|
|
58270
|
-
case "test":
|
|
58271
|
-
case "tdd":
|
|
58272
|
-
case "e2e":
|
|
58273
|
-
case "tester":
|
|
58274
|
-
return "destructive";
|
|
58275
|
-
case "debug":
|
|
58276
|
-
case "refactor":
|
|
58277
|
-
case "coder":
|
|
58278
|
-
case "optimizer":
|
|
58279
|
-
return "write";
|
|
58280
|
-
default:
|
|
58281
|
-
return "read-only";
|
|
58282
|
-
}
|
|
58283
|
-
}
|
|
58284
58862
|
|
|
58285
58863
|
// src/runtime/provider-registry.ts
|
|
58286
58864
|
init_providers();
|
|
@@ -58365,6 +58943,206 @@ function createRuntimeSessionStore() {
|
|
|
58365
58943
|
return new InMemoryRuntimeSessionStore();
|
|
58366
58944
|
}
|
|
58367
58945
|
|
|
58946
|
+
// src/runtime/agent-runner.ts
|
|
58947
|
+
var AgentRunner = class {
|
|
58948
|
+
constructor(options = {}) {
|
|
58949
|
+
this.options = options;
|
|
58950
|
+
}
|
|
58951
|
+
options;
|
|
58952
|
+
async run(input) {
|
|
58953
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
58954
|
+
const trace = input.trace ?? createAgentTraceContext({ taskId: input.task.id });
|
|
58955
|
+
this.options.eventLog?.record("agent.started", {
|
|
58956
|
+
taskId: input.task.id,
|
|
58957
|
+
role: input.task.role,
|
|
58958
|
+
trace
|
|
58959
|
+
});
|
|
58960
|
+
try {
|
|
58961
|
+
const raw = await (this.options.executor ?? defaultExecutor)({
|
|
58962
|
+
task: input.task,
|
|
58963
|
+
capability: input.capability,
|
|
58964
|
+
trace,
|
|
58965
|
+
assertToolAllowed: (toolName) => {
|
|
58966
|
+
const decision = evaluateAgentToolPolicy({
|
|
58967
|
+
capability: input.capability,
|
|
58968
|
+
toolName,
|
|
58969
|
+
manifest: input.toolRiskManifest
|
|
58970
|
+
});
|
|
58971
|
+
this.options.eventLog?.record("agent.tool.called", {
|
|
58972
|
+
taskId: input.task.id,
|
|
58973
|
+
role: input.task.role,
|
|
58974
|
+
toolName,
|
|
58975
|
+
decision,
|
|
58976
|
+
trace
|
|
58977
|
+
});
|
|
58978
|
+
if (!decision.allowed) {
|
|
58979
|
+
throw new Error(decision.reason ?? `Tool '${toolName}' is not allowed.`);
|
|
58980
|
+
}
|
|
58981
|
+
}
|
|
58982
|
+
});
|
|
58983
|
+
const result = normalizeAgentRunResult({
|
|
58984
|
+
id: `${input.task.id}-run-${Date.now().toString(36)}`,
|
|
58985
|
+
taskId: input.task.id,
|
|
58986
|
+
role: input.task.role,
|
|
58987
|
+
success: raw.success ?? true,
|
|
58988
|
+
output: raw.output,
|
|
58989
|
+
turns: raw.turns,
|
|
58990
|
+
toolsUsed: raw.toolsUsed,
|
|
58991
|
+
usage: {
|
|
58992
|
+
inputTokens: raw.inputTokens ?? 0,
|
|
58993
|
+
outputTokens: raw.outputTokens ?? 0,
|
|
58994
|
+
estimated: raw.inputTokens === void 0 || raw.outputTokens === void 0
|
|
58995
|
+
},
|
|
58996
|
+
startedAt,
|
|
58997
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
58998
|
+
durationMs: Date.now() - Date.parse(startedAt),
|
|
58999
|
+
error: raw.error,
|
|
59000
|
+
metadata: { ...raw.metadata, trace }
|
|
59001
|
+
});
|
|
59002
|
+
this.options.eventLog?.record(result.success ? "agent.completed" : "agent.failed", {
|
|
59003
|
+
taskId: input.task.id,
|
|
59004
|
+
role: input.task.role,
|
|
59005
|
+
agentRunId: result.id,
|
|
59006
|
+
trace,
|
|
59007
|
+
error: result.error
|
|
59008
|
+
});
|
|
59009
|
+
return result;
|
|
59010
|
+
} catch (error) {
|
|
59011
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
59012
|
+
const result = normalizeAgentRunResult({
|
|
59013
|
+
id: `${input.task.id}-run-${Date.now().toString(36)}`,
|
|
59014
|
+
taskId: input.task.id,
|
|
59015
|
+
role: input.task.role,
|
|
59016
|
+
success: false,
|
|
59017
|
+
output: message,
|
|
59018
|
+
startedAt,
|
|
59019
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
59020
|
+
durationMs: Date.now() - Date.parse(startedAt),
|
|
59021
|
+
error: message,
|
|
59022
|
+
metadata: { trace }
|
|
59023
|
+
});
|
|
59024
|
+
this.options.eventLog?.record("agent.failed", {
|
|
59025
|
+
taskId: input.task.id,
|
|
59026
|
+
role: input.task.role,
|
|
59027
|
+
agentRunId: result.id,
|
|
59028
|
+
trace,
|
|
59029
|
+
error: message
|
|
59030
|
+
});
|
|
59031
|
+
return result;
|
|
59032
|
+
}
|
|
59033
|
+
}
|
|
59034
|
+
};
|
|
59035
|
+
async function defaultExecutor(context) {
|
|
59036
|
+
return {
|
|
59037
|
+
output: `Agent ${context.capability.role} accepted task '${context.task.objective}'.`
|
|
59038
|
+
};
|
|
59039
|
+
}
|
|
59040
|
+
|
|
59041
|
+
// src/runtime/runtime-agent-node-executor.ts
|
|
59042
|
+
var RuntimeAgentNodeExecutor = class {
|
|
59043
|
+
constructor(options) {
|
|
59044
|
+
this.options = options;
|
|
59045
|
+
this.runner = options.runner ?? new AgentRunner(options.runnerOptions);
|
|
59046
|
+
}
|
|
59047
|
+
options;
|
|
59048
|
+
runner;
|
|
59049
|
+
execute = async (execution) => {
|
|
59050
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
59051
|
+
const definition = this.options.registry.getByRole(execution.task.role);
|
|
59052
|
+
if (!definition) {
|
|
59053
|
+
return normalizeAgentRunResult({
|
|
59054
|
+
id: `${execution.workflowRunId}-${execution.node.id}-missing-definition`,
|
|
59055
|
+
taskId: execution.task.id,
|
|
59056
|
+
role: execution.task.role,
|
|
59057
|
+
success: false,
|
|
59058
|
+
output: "",
|
|
59059
|
+
startedAt,
|
|
59060
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
59061
|
+
error: `No agent definition registered for role '${execution.task.role}'.`,
|
|
59062
|
+
metadata: {
|
|
59063
|
+
workflowRunId: execution.workflowRunId,
|
|
59064
|
+
nodeId: execution.node.id,
|
|
59065
|
+
trace: execution.trace
|
|
59066
|
+
}
|
|
59067
|
+
});
|
|
59068
|
+
}
|
|
59069
|
+
const blockedTool = this.findBlockedTool(definition, execution);
|
|
59070
|
+
if (blockedTool) {
|
|
59071
|
+
return normalizeAgentRunResult({
|
|
59072
|
+
id: `${execution.workflowRunId}-${execution.node.id}-policy-blocked`,
|
|
59073
|
+
taskId: execution.task.id,
|
|
59074
|
+
role: execution.task.role,
|
|
59075
|
+
success: false,
|
|
59076
|
+
output: "",
|
|
59077
|
+
startedAt,
|
|
59078
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
59079
|
+
error: blockedTool,
|
|
59080
|
+
metadata: {
|
|
59081
|
+
workflowRunId: execution.workflowRunId,
|
|
59082
|
+
nodeId: execution.node.id,
|
|
59083
|
+
agentDefinitionId: definition.id,
|
|
59084
|
+
trace: execution.trace
|
|
59085
|
+
}
|
|
59086
|
+
});
|
|
59087
|
+
}
|
|
59088
|
+
const input = {
|
|
59089
|
+
task: {
|
|
59090
|
+
...execution.task,
|
|
59091
|
+
context: {
|
|
59092
|
+
...execution.task.context,
|
|
59093
|
+
instructions: definition.instructions,
|
|
59094
|
+
sharedState: execution.sharedState.readForRole(definition.role)
|
|
59095
|
+
}
|
|
59096
|
+
},
|
|
59097
|
+
capability: definition.capability,
|
|
59098
|
+
trace: execution.trace,
|
|
59099
|
+
toolRiskManifest: this.options.toolRiskManifest
|
|
59100
|
+
};
|
|
59101
|
+
const result = await this.runner.run(input);
|
|
59102
|
+
return normalizeAgentRunResult({
|
|
59103
|
+
...result,
|
|
59104
|
+
metadata: {
|
|
59105
|
+
...result.metadata,
|
|
59106
|
+
workflowRunId: execution.workflowRunId,
|
|
59107
|
+
nodeId: execution.node.id,
|
|
59108
|
+
agentDefinitionId: definition.id
|
|
59109
|
+
}
|
|
59110
|
+
});
|
|
59111
|
+
};
|
|
59112
|
+
findBlockedTool(definition, execution) {
|
|
59113
|
+
for (const toolName of execution.node.requiredTools ?? []) {
|
|
59114
|
+
const agentDecision = evaluateAgentToolPolicy({
|
|
59115
|
+
capability: definition.capability,
|
|
59116
|
+
toolName,
|
|
59117
|
+
manifest: this.options.toolRiskManifest
|
|
59118
|
+
});
|
|
59119
|
+
execution.eventLog.record("agent.tool.called", {
|
|
59120
|
+
workflowRunId: execution.workflowRunId,
|
|
59121
|
+
nodeId: execution.node.id,
|
|
59122
|
+
taskId: execution.task.id,
|
|
59123
|
+
role: execution.task.role,
|
|
59124
|
+
toolName,
|
|
59125
|
+
decision: agentDecision,
|
|
59126
|
+
trace: execution.trace
|
|
59127
|
+
});
|
|
59128
|
+
if (!agentDecision.allowed) {
|
|
59129
|
+
return agentDecision.reason ?? `Tool '${toolName}' is not allowed for agent.`;
|
|
59130
|
+
}
|
|
59131
|
+
const runtimeDecision = evaluateRuntimeToolPolicy(this.options.runtimePolicy, {
|
|
59132
|
+
toolName,
|
|
59133
|
+
risk: agentDecision.risk
|
|
59134
|
+
});
|
|
59135
|
+
if (!runtimeDecision.allowed) {
|
|
59136
|
+
return runtimeDecision.reason ?? `Tool '${toolName}' is blocked by runtime policy.`;
|
|
59137
|
+
}
|
|
59138
|
+
}
|
|
59139
|
+
return void 0;
|
|
59140
|
+
}
|
|
59141
|
+
};
|
|
59142
|
+
function createRuntimeAgentNodeExecutor(options) {
|
|
59143
|
+
return new RuntimeAgentNodeExecutor(options).execute;
|
|
59144
|
+
}
|
|
59145
|
+
|
|
58368
59146
|
// src/runtime/workflow-registry.ts
|
|
58369
59147
|
function cloneWorkflow(workflow) {
|
|
58370
59148
|
return {
|
|
@@ -58447,6 +59225,109 @@ var WorkflowCatalog = class {
|
|
|
58447
59225
|
}
|
|
58448
59226
|
};
|
|
58449
59227
|
var DEFAULT_WORKFLOWS = [
|
|
59228
|
+
{
|
|
59229
|
+
id: "enterprise-rag-answer",
|
|
59230
|
+
name: "Enterprise RAG Answer",
|
|
59231
|
+
description: "Retrieve tenant-scoped knowledge, draft a cited answer, and review for policy compliance.",
|
|
59232
|
+
inputSchema: "question: string; tenantId: string; userId?: string",
|
|
59233
|
+
outputKind: "json",
|
|
59234
|
+
replayable: true,
|
|
59235
|
+
checks: ["retrieval citations", "policy review", "answer quality"],
|
|
59236
|
+
steps: [],
|
|
59237
|
+
parallelism: 2,
|
|
59238
|
+
gates: [
|
|
59239
|
+
{
|
|
59240
|
+
id: "quality",
|
|
59241
|
+
kind: "quality-score",
|
|
59242
|
+
description: "Answer meets tenant quality and citation requirements.",
|
|
59243
|
+
required: true
|
|
59244
|
+
}
|
|
59245
|
+
],
|
|
59246
|
+
nodes: [
|
|
59247
|
+
{
|
|
59248
|
+
id: "retrieve",
|
|
59249
|
+
agentRole: "researcher",
|
|
59250
|
+
description: "Retrieve tenant-scoped sources and produce citations.",
|
|
59251
|
+
requiredTools: ["knowledge_search"],
|
|
59252
|
+
risk: "read-only",
|
|
59253
|
+
timeoutMs: 3e4
|
|
59254
|
+
},
|
|
59255
|
+
{
|
|
59256
|
+
id: "draft-answer",
|
|
59257
|
+
agentRole: "docs",
|
|
59258
|
+
description: "Draft a concise answer grounded only in retrieved sources.",
|
|
59259
|
+
dependsOn: ["retrieve"],
|
|
59260
|
+
risk: "read-only",
|
|
59261
|
+
timeoutMs: 3e4
|
|
59262
|
+
},
|
|
59263
|
+
{
|
|
59264
|
+
id: "policy-review",
|
|
59265
|
+
agentRole: "reviewer",
|
|
59266
|
+
description: "Review citations, data boundary, and unsupported claims.",
|
|
59267
|
+
dependsOn: ["draft-answer"],
|
|
59268
|
+
gates: ["quality"],
|
|
59269
|
+
risk: "read-only",
|
|
59270
|
+
timeoutMs: 3e4
|
|
59271
|
+
}
|
|
59272
|
+
]
|
|
59273
|
+
},
|
|
59274
|
+
{
|
|
59275
|
+
id: "whatsapp-support-assistant",
|
|
59276
|
+
name: "WhatsApp Support Assistant",
|
|
59277
|
+
description: "Handle a WhatsApp customer message with retrieval, support draft, and optional escalation.",
|
|
59278
|
+
inputSchema: "message: string; phoneNumber: string; tenantId: string",
|
|
59279
|
+
outputKind: "json",
|
|
59280
|
+
replayable: true,
|
|
59281
|
+
checks: ["retrieval citations", "support policy", "human escalation when needed"],
|
|
59282
|
+
steps: [],
|
|
59283
|
+
parallelism: 2,
|
|
59284
|
+
gates: [
|
|
59285
|
+
{
|
|
59286
|
+
id: "human-escalation",
|
|
59287
|
+
kind: "human-approval",
|
|
59288
|
+
description: "Human review is required before sensitive or external follow-up.",
|
|
59289
|
+
required: false
|
|
59290
|
+
}
|
|
59291
|
+
],
|
|
59292
|
+
nodes: [
|
|
59293
|
+
{
|
|
59294
|
+
id: "classify-message",
|
|
59295
|
+
agentRole: "planner",
|
|
59296
|
+
description: "Classify intent, urgency, and required data boundary.",
|
|
59297
|
+
risk: "read-only",
|
|
59298
|
+
timeoutMs: 15e3
|
|
59299
|
+
},
|
|
59300
|
+
{
|
|
59301
|
+
id: "retrieve-context",
|
|
59302
|
+
agentRole: "researcher",
|
|
59303
|
+
description: "Retrieve tenant support knowledge relevant to the customer message.",
|
|
59304
|
+
dependsOn: ["classify-message"],
|
|
59305
|
+
requiredTools: ["knowledge_search"],
|
|
59306
|
+
risk: "read-only",
|
|
59307
|
+
timeoutMs: 3e4
|
|
59308
|
+
},
|
|
59309
|
+
{
|
|
59310
|
+
id: "draft-response",
|
|
59311
|
+
agentRole: "docs",
|
|
59312
|
+
description: "Draft a WhatsApp-safe response with concise citations for audit.",
|
|
59313
|
+
dependsOn: ["retrieve-context"],
|
|
59314
|
+
requiredTools: ["create_support_draft"],
|
|
59315
|
+
risk: "read-only",
|
|
59316
|
+
timeoutMs: 3e4
|
|
59317
|
+
},
|
|
59318
|
+
{
|
|
59319
|
+
id: "escalate-if-needed",
|
|
59320
|
+
agentRole: "integrator",
|
|
59321
|
+
description: "Create a human escalation request when classification requires it.",
|
|
59322
|
+
dependsOn: ["draft-response"],
|
|
59323
|
+
requiredTools: ["request_human_escalation"],
|
|
59324
|
+
gates: ["human-escalation"],
|
|
59325
|
+
condition: "input.requiresEscalation",
|
|
59326
|
+
risk: "network",
|
|
59327
|
+
timeoutMs: 3e4
|
|
59328
|
+
}
|
|
59329
|
+
]
|
|
59330
|
+
},
|
|
58450
59331
|
{
|
|
58451
59332
|
id: "architect-editor-verifier",
|
|
58452
59333
|
name: "Architect / Editor / Verifier",
|
|
@@ -58591,12 +59472,22 @@ var WorkflowEngine = class {
|
|
|
58591
59472
|
this.catalog = catalog;
|
|
58592
59473
|
this.eventLog = eventLog;
|
|
58593
59474
|
this.sharedState = options.sharedState ?? new InMemorySharedWorkspaceStore();
|
|
58594
|
-
this.
|
|
59475
|
+
this.runtimePolicy = options.runtimePolicy;
|
|
59476
|
+
this.runtimeContext = options.runtimeContext;
|
|
59477
|
+
this.runtimeHostMode = options.runtimeHostMode ?? "local";
|
|
59478
|
+
this.nodeExecutor = options.nodeExecutor ?? (options.agentDefinitionRegistry ? createRuntimeAgentNodeExecutor({
|
|
59479
|
+
...options.agentNodeExecutorOptions,
|
|
59480
|
+
registry: options.agentDefinitionRegistry,
|
|
59481
|
+
runtimePolicy: options.runtimePolicy
|
|
59482
|
+
}) : void 0);
|
|
58595
59483
|
}
|
|
58596
59484
|
catalog;
|
|
58597
59485
|
eventLog;
|
|
58598
59486
|
handlers = /* @__PURE__ */ new Map();
|
|
58599
59487
|
sharedState;
|
|
59488
|
+
runtimePolicy;
|
|
59489
|
+
runtimeContext;
|
|
59490
|
+
runtimeHostMode;
|
|
58600
59491
|
nodeExecutor;
|
|
58601
59492
|
registerHandler(workflowId, handler) {
|
|
58602
59493
|
if (!this.catalog.get(workflowId)) {
|
|
@@ -58611,6 +59502,7 @@ var WorkflowEngine = class {
|
|
|
58611
59502
|
return this.catalog.createPlan(workflowId, input, this.eventLog);
|
|
58612
59503
|
}
|
|
58613
59504
|
async run(request) {
|
|
59505
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "workflow.run");
|
|
58614
59506
|
const workflow = this.catalog.get(request.workflowId);
|
|
58615
59507
|
if (!workflow) {
|
|
58616
59508
|
throw new Error(`Unknown workflow: ${request.workflowId}`);
|
|
@@ -58627,6 +59519,8 @@ var WorkflowEngine = class {
|
|
|
58627
59519
|
trace
|
|
58628
59520
|
});
|
|
58629
59521
|
try {
|
|
59522
|
+
const graph = workflowToAgentGraph(workflow);
|
|
59523
|
+
assertWorkflowAllowedByRuntimePolicy(graph, this.runtimePolicy);
|
|
58630
59524
|
const graphResult = handler ? void 0 : await new AgentGraphEngine({
|
|
58631
59525
|
eventLog: this.eventLog,
|
|
58632
59526
|
sharedState: this.sharedState,
|
|
@@ -58634,7 +59528,7 @@ var WorkflowEngine = class {
|
|
|
58634
59528
|
trace
|
|
58635
59529
|
}).run({
|
|
58636
59530
|
workflowRunId: runId,
|
|
58637
|
-
graph
|
|
59531
|
+
graph,
|
|
58638
59532
|
input: request.input
|
|
58639
59533
|
});
|
|
58640
59534
|
const output = graphResult ?? await handler(request.input, {
|
|
@@ -58686,6 +59580,29 @@ var WorkflowEngine = class {
|
|
|
58686
59580
|
}
|
|
58687
59581
|
}
|
|
58688
59582
|
};
|
|
59583
|
+
function assertWorkflowAllowedByRuntimePolicy(graph, policy) {
|
|
59584
|
+
if (!policy) return;
|
|
59585
|
+
for (const node of graph.nodes) {
|
|
59586
|
+
const risk = node.risk ?? "read-only";
|
|
59587
|
+
const riskDecision = evaluateRuntimeRiskPolicy(policy, {
|
|
59588
|
+
subject: `workflow node ${node.id}`,
|
|
59589
|
+
risk
|
|
59590
|
+
});
|
|
59591
|
+
if (!riskDecision.allowed) {
|
|
59592
|
+
throw new Error(
|
|
59593
|
+
`Workflow node ${node.id} is blocked by runtime policy: ${riskDecision.reason}`
|
|
59594
|
+
);
|
|
59595
|
+
}
|
|
59596
|
+
for (const toolName of node.requiredTools ?? []) {
|
|
59597
|
+
const decision = evaluateRuntimeToolPolicy(policy, { toolName, risk });
|
|
59598
|
+
if (!decision.allowed) {
|
|
59599
|
+
throw new Error(
|
|
59600
|
+
`Workflow node ${node.id} is blocked by runtime policy: ${decision.reason}`
|
|
59601
|
+
);
|
|
59602
|
+
}
|
|
59603
|
+
}
|
|
59604
|
+
}
|
|
59605
|
+
}
|
|
58689
59606
|
function createWorkflowEngine(catalog, eventLog, options) {
|
|
58690
59607
|
return new WorkflowEngine(catalog, eventLog, options);
|
|
58691
59608
|
}
|
|
@@ -58695,15 +59612,24 @@ var AgentRuntime = class {
|
|
|
58695
59612
|
constructor(options) {
|
|
58696
59613
|
this.options = options;
|
|
58697
59614
|
this.providerRegistry = createProviderRegistry();
|
|
58698
|
-
this.toolRegistry = options.toolRegistry ??
|
|
59615
|
+
this.toolRegistry = options.toolRegistry ?? new ToolRegistry();
|
|
58699
59616
|
this.sessionStore = options.sessionStore;
|
|
58700
59617
|
this.runtimeSessionStore = options.runtimeSessionStore ?? createRuntimeSessionStore();
|
|
58701
59618
|
this.eventLog = options.eventLog ?? (options.eventLogPath ? createFileEventLog(options.eventLogPath) : createEventLog());
|
|
58702
|
-
this.workflowEngine = options.workflowEngine ?? createWorkflowEngine(void 0, this.eventLog);
|
|
58703
59619
|
this.permissionPolicy = options.permissionPolicy ?? createPermissionPolicy();
|
|
58704
59620
|
this.turnRunner = options.turnRunner ?? createDefaultRuntimeTurnRunner();
|
|
58705
59621
|
this.providerType = options.providerType;
|
|
58706
59622
|
this.model = options.model ?? options.providerConfig?.model ?? getDefaultModel(options.providerType);
|
|
59623
|
+
this.runtimeContext = options.runtimeContext ? createRuntimeRequestContext(options.runtimeContext) : void 0;
|
|
59624
|
+
this.runtimePolicy = mergeRuntimePolicy(this.runtimeContext?.policy, options.runtimePolicy);
|
|
59625
|
+
this.runtimeHostMode = options.runtimeHostMode ?? "local";
|
|
59626
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "runtime.initialize");
|
|
59627
|
+
this.workflowEngine = options.workflowEngine ?? createWorkflowEngine(void 0, this.eventLog, {
|
|
59628
|
+
runtimePolicy: this.runtimePolicy,
|
|
59629
|
+
runtimeContext: this.runtimeContext,
|
|
59630
|
+
runtimeHostMode: this.runtimeHostMode,
|
|
59631
|
+
agentDefinitionRegistry: options.agentDefinitionRegistry
|
|
59632
|
+
});
|
|
58707
59633
|
}
|
|
58708
59634
|
options;
|
|
58709
59635
|
providerRegistry;
|
|
@@ -58717,6 +59643,11 @@ var AgentRuntime = class {
|
|
|
58717
59643
|
providerType;
|
|
58718
59644
|
model;
|
|
58719
59645
|
provider;
|
|
59646
|
+
runtimeContext;
|
|
59647
|
+
runtimePolicy;
|
|
59648
|
+
runtimeHostMode;
|
|
59649
|
+
requestTimestampsBySubject = /* @__PURE__ */ new Map();
|
|
59650
|
+
activeRuns = 0;
|
|
58720
59651
|
async initialize() {
|
|
58721
59652
|
const providerInjected = Boolean(this.options.provider);
|
|
58722
59653
|
const provider = this.options.provider ?? await this.providerRegistry.createProvider(this.providerType, {
|
|
@@ -58747,8 +59678,8 @@ var AgentRuntime = class {
|
|
|
58747
59678
|
}
|
|
58748
59679
|
publishToGlobalBridge(provider) {
|
|
58749
59680
|
if (this.options.publishToGlobalBridge !== true) return;
|
|
58750
|
-
setAgentProvider(provider);
|
|
58751
|
-
setAgentToolRegistry(this.toolRegistry);
|
|
59681
|
+
this.options.legacyAgentBridge?.setAgentProvider(provider);
|
|
59682
|
+
this.options.legacyAgentBridge?.setAgentToolRegistry(this.toolRegistry);
|
|
58752
59683
|
}
|
|
58753
59684
|
snapshot() {
|
|
58754
59685
|
const capability = this.providerRegistry.getCapability(this.providerType, this.getModel());
|
|
@@ -58763,14 +59694,27 @@ var AgentRuntime = class {
|
|
|
58763
59694
|
count: toolNames.length,
|
|
58764
59695
|
names: toolNames
|
|
58765
59696
|
},
|
|
58766
|
-
modes: listAgentModes()
|
|
59697
|
+
modes: listAgentModes(),
|
|
59698
|
+
context: this.runtimeContext,
|
|
59699
|
+
policy: this.runtimePolicy,
|
|
59700
|
+
hostMode: this.runtimeHostMode
|
|
58767
59701
|
};
|
|
58768
59702
|
}
|
|
58769
59703
|
createSession(options = {}) {
|
|
58770
|
-
|
|
59704
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "session.create");
|
|
59705
|
+
const session = this.runtimeSessionStore.create({
|
|
59706
|
+
...options,
|
|
59707
|
+
metadata: {
|
|
59708
|
+
...runtimeContextToMetadata(this.runtimeContext),
|
|
59709
|
+
...options.metadata
|
|
59710
|
+
}
|
|
59711
|
+
});
|
|
58771
59712
|
this.eventLog.record("session.created", {
|
|
58772
59713
|
sessionId: session.id,
|
|
58773
59714
|
mode: session.mode,
|
|
59715
|
+
...session.metadata["tenantId"] ? { tenantId: session.metadata["tenantId"] } : {},
|
|
59716
|
+
...session.metadata["surface"] ? { surface: session.metadata["surface"] } : {},
|
|
59717
|
+
...session.metadata["correlationId"] ? { correlationId: session.metadata["correlationId"] } : {},
|
|
58774
59718
|
metadataKeys: Object.keys(session.metadata).sort()
|
|
58775
59719
|
});
|
|
58776
59720
|
return session;
|
|
@@ -58781,6 +59725,27 @@ var AgentRuntime = class {
|
|
|
58781
59725
|
listSessions() {
|
|
58782
59726
|
return this.runtimeSessionStore.list();
|
|
58783
59727
|
}
|
|
59728
|
+
cleanupRetention(options = {}) {
|
|
59729
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "retention.cleanup");
|
|
59730
|
+
const dryRun = options.dryRun ?? true;
|
|
59731
|
+
const cutoffs = createRetentionCutoffs(this.runtimePolicy, options.now);
|
|
59732
|
+
const expiredSessionIds = cutoffs.conversationBefore ? this.runtimeSessionStore.list().filter((session) => session.updatedAt < cutoffs.conversationBefore).map((session) => session.id) : [];
|
|
59733
|
+
const deletedSessionIds = dryRun ? [] : expiredSessionIds.filter((id) => this.runtimeSessionStore.delete(id));
|
|
59734
|
+
this.eventLog.record("retention.cleanup", {
|
|
59735
|
+
dryRun,
|
|
59736
|
+
cutoffs,
|
|
59737
|
+
expiredSessionIds,
|
|
59738
|
+
deletedSessionIds,
|
|
59739
|
+
tenantId: this.runtimeContext?.tenant?.id,
|
|
59740
|
+
runtimeApi: true
|
|
59741
|
+
});
|
|
59742
|
+
return {
|
|
59743
|
+
dryRun,
|
|
59744
|
+
cutoffs,
|
|
59745
|
+
expiredSessionIds,
|
|
59746
|
+
deletedSessionIds
|
|
59747
|
+
};
|
|
59748
|
+
}
|
|
58784
59749
|
async runTurn(input) {
|
|
58785
59750
|
const provider = this.provider;
|
|
58786
59751
|
if (!provider) {
|
|
@@ -58791,6 +59756,12 @@ var AgentRuntime = class {
|
|
|
58791
59756
|
throw new Error(`Runtime session not found: ${input.sessionId}`);
|
|
58792
59757
|
}
|
|
58793
59758
|
const effectiveSession = input.mode && input.mode !== session.mode ? { ...session, mode: input.mode } : session;
|
|
59759
|
+
assertRuntimeTurnWithinPolicy(this.runtimePolicy, {
|
|
59760
|
+
subject: "turn.run",
|
|
59761
|
+
currentTurns: countUserTurns(effectiveSession),
|
|
59762
|
+
tenantId: this.runtimeContext?.tenant?.id
|
|
59763
|
+
});
|
|
59764
|
+
const releaseRuntimeRequest = this.beginRuntimeRequest("turn.run");
|
|
58794
59765
|
this.eventLog.record("turn.started", {
|
|
58795
59766
|
sessionId: effectiveSession.id,
|
|
58796
59767
|
provider: this.providerType,
|
|
@@ -58807,6 +59778,13 @@ var AgentRuntime = class {
|
|
|
58807
59778
|
permissionPolicy: this.permissionPolicy,
|
|
58808
59779
|
eventLog: this.eventLog
|
|
58809
59780
|
});
|
|
59781
|
+
const estimatedCostUsd = this.estimateTurnCost(result);
|
|
59782
|
+
assertRuntimeUsageWithinPolicy(this.runtimePolicy, {
|
|
59783
|
+
...result.usage,
|
|
59784
|
+
estimatedCostUsd,
|
|
59785
|
+
tenantId: this.runtimeContext?.tenant?.id,
|
|
59786
|
+
subject: "turn.run"
|
|
59787
|
+
});
|
|
58810
59788
|
const updatedSession = this.runtimeSessionStore.update({
|
|
58811
59789
|
...effectiveSession,
|
|
58812
59790
|
messages: [
|
|
@@ -58823,6 +59801,7 @@ var AgentRuntime = class {
|
|
|
58823
59801
|
sessionId: updatedSession.id,
|
|
58824
59802
|
inputTokens: result.usage.inputTokens,
|
|
58825
59803
|
outputTokens: result.usage.outputTokens,
|
|
59804
|
+
estimatedCostUsd,
|
|
58826
59805
|
model: result.model,
|
|
58827
59806
|
runtimeApi: true
|
|
58828
59807
|
});
|
|
@@ -58834,6 +59813,8 @@ var AgentRuntime = class {
|
|
|
58834
59813
|
runtimeApi: true
|
|
58835
59814
|
});
|
|
58836
59815
|
throw error;
|
|
59816
|
+
} finally {
|
|
59817
|
+
releaseRuntimeRequest();
|
|
58837
59818
|
}
|
|
58838
59819
|
}
|
|
58839
59820
|
async *streamTurn(input) {
|
|
@@ -58846,6 +59827,12 @@ var AgentRuntime = class {
|
|
|
58846
59827
|
throw new Error(`Runtime session not found: ${input.sessionId}`);
|
|
58847
59828
|
}
|
|
58848
59829
|
const effectiveSession = input.mode && input.mode !== session.mode ? { ...session, mode: input.mode } : session;
|
|
59830
|
+
assertRuntimeTurnWithinPolicy(this.runtimePolicy, {
|
|
59831
|
+
subject: "turn.stream",
|
|
59832
|
+
currentTurns: countUserTurns(effectiveSession),
|
|
59833
|
+
tenantId: this.runtimeContext?.tenant?.id
|
|
59834
|
+
});
|
|
59835
|
+
const releaseRuntimeRequest = this.beginRuntimeRequest("turn.stream");
|
|
58849
59836
|
const messages = [
|
|
58850
59837
|
...effectiveSession.messages,
|
|
58851
59838
|
{
|
|
@@ -58884,16 +59871,8 @@ var AgentRuntime = class {
|
|
|
58884
59871
|
};
|
|
58885
59872
|
}
|
|
58886
59873
|
}
|
|
58887
|
-
const updatedSession = this.runtimeSessionStore.update({
|
|
58888
|
-
...effectiveSession,
|
|
58889
|
-
messages: [
|
|
58890
|
-
...effectiveSession.messages,
|
|
58891
|
-
{ role: "user", content: input.content },
|
|
58892
|
-
{ role: "assistant", content }
|
|
58893
|
-
]
|
|
58894
|
-
});
|
|
58895
59874
|
const result = {
|
|
58896
|
-
sessionId:
|
|
59875
|
+
sessionId: effectiveSession.id,
|
|
58897
59876
|
content,
|
|
58898
59877
|
usage: {
|
|
58899
59878
|
inputTokens: provider.countTokens(input.content),
|
|
@@ -58901,8 +59880,25 @@ var AgentRuntime = class {
|
|
|
58901
59880
|
estimated: true
|
|
58902
59881
|
},
|
|
58903
59882
|
model: input.options?.model ?? this.getModel(),
|
|
58904
|
-
mode:
|
|
59883
|
+
mode: effectiveSession.mode
|
|
58905
59884
|
};
|
|
59885
|
+
const estimatedCostUsd = this.estimateTurnCost(result);
|
|
59886
|
+
assertRuntimeUsageWithinPolicy(this.runtimePolicy, {
|
|
59887
|
+
...result.usage,
|
|
59888
|
+
estimatedCostUsd,
|
|
59889
|
+
tenantId: this.runtimeContext?.tenant?.id,
|
|
59890
|
+
subject: "turn.stream"
|
|
59891
|
+
});
|
|
59892
|
+
const updatedSession = this.runtimeSessionStore.update({
|
|
59893
|
+
...effectiveSession,
|
|
59894
|
+
messages: [
|
|
59895
|
+
...effectiveSession.messages,
|
|
59896
|
+
{ role: "user", content: input.content },
|
|
59897
|
+
{ role: "assistant", content }
|
|
59898
|
+
]
|
|
59899
|
+
});
|
|
59900
|
+
result.sessionId = updatedSession.id;
|
|
59901
|
+
result.mode = updatedSession.mode;
|
|
58906
59902
|
this.eventLog.record("session.updated", {
|
|
58907
59903
|
sessionId: updatedSession.id,
|
|
58908
59904
|
messages: updatedSession.messages.length
|
|
@@ -58911,6 +59907,7 @@ var AgentRuntime = class {
|
|
|
58911
59907
|
sessionId: updatedSession.id,
|
|
58912
59908
|
inputTokens: result.usage.inputTokens,
|
|
58913
59909
|
outputTokens: result.usage.outputTokens,
|
|
59910
|
+
estimatedCostUsd,
|
|
58914
59911
|
model: result.model,
|
|
58915
59912
|
streaming: true,
|
|
58916
59913
|
runtimeApi: true
|
|
@@ -58940,9 +59937,11 @@ var AgentRuntime = class {
|
|
|
58940
59937
|
runtimeApi: true
|
|
58941
59938
|
});
|
|
58942
59939
|
}
|
|
59940
|
+
releaseRuntimeRequest();
|
|
58943
59941
|
}
|
|
58944
59942
|
}
|
|
58945
59943
|
async executeTool(input) {
|
|
59944
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "tool.execute");
|
|
58946
59945
|
const startedAt = performance.now();
|
|
58947
59946
|
const session = input.sessionId ? this.getSession(input.sessionId) : void 0;
|
|
58948
59947
|
if (input.sessionId && !session) {
|
|
@@ -58990,15 +59989,22 @@ var AgentRuntime = class {
|
|
|
58990
59989
|
};
|
|
58991
59990
|
}
|
|
58992
59991
|
const decision = this.permissionPolicy.canExecuteToolInput ? this.permissionPolicy.canExecuteToolInput(mode, tool, input.input) : this.permissionPolicy.canExecuteTool(mode, tool);
|
|
58993
|
-
|
|
58994
|
-
|
|
59992
|
+
const runtimeDecision = decision.allowed ? evaluateRuntimeToolPolicy(this.runtimePolicy, {
|
|
59993
|
+
toolName: input.toolName,
|
|
59994
|
+
risk: decision.risk,
|
|
59995
|
+
confirmed: input.confirmed
|
|
59996
|
+
}) : void 0;
|
|
59997
|
+
const effectiveDecision = runtimeDecision ?? decision;
|
|
59998
|
+
if (!decision.allowed || !effectiveDecision.allowed || decision.requiresConfirmation && input.confirmed !== true) {
|
|
59999
|
+
const reason = effectiveDecision.reason ?? decision.reason ?? (decision.requiresConfirmation ? "Tool requires explicit runtime confirmation." : "Tool is not allowed.");
|
|
58995
60000
|
this.eventLog.record("tool.blocked", {
|
|
58996
60001
|
sessionId: input.sessionId,
|
|
58997
60002
|
mode,
|
|
58998
60003
|
tool: input.toolName,
|
|
58999
60004
|
reason,
|
|
59000
|
-
risk:
|
|
59001
|
-
requiresConfirmation: decision.requiresConfirmation,
|
|
60005
|
+
risk: effectiveDecision.risk,
|
|
60006
|
+
requiresConfirmation: effectiveDecision.requiresConfirmation ?? decision.requiresConfirmation,
|
|
60007
|
+
runtimePolicyBlocked: runtimeDecision ? !runtimeDecision.allowed : false,
|
|
59002
60008
|
runtimeApi: true
|
|
59003
60009
|
});
|
|
59004
60010
|
return {
|
|
@@ -59006,14 +60012,20 @@ var AgentRuntime = class {
|
|
|
59006
60012
|
success: false,
|
|
59007
60013
|
error: reason,
|
|
59008
60014
|
duration: performance.now() - startedAt,
|
|
59009
|
-
decision
|
|
60015
|
+
decision: {
|
|
60016
|
+
...decision,
|
|
60017
|
+
allowed: false,
|
|
60018
|
+
reason,
|
|
60019
|
+
requiresConfirmation: effectiveDecision.requiresConfirmation ?? decision.requiresConfirmation,
|
|
60020
|
+
risk: effectiveDecision.risk
|
|
60021
|
+
}
|
|
59010
60022
|
};
|
|
59011
60023
|
}
|
|
59012
60024
|
this.eventLog.record("tool.started", {
|
|
59013
60025
|
sessionId: input.sessionId,
|
|
59014
60026
|
mode,
|
|
59015
60027
|
tool: input.toolName,
|
|
59016
|
-
risk:
|
|
60028
|
+
risk: effectiveDecision.risk,
|
|
59017
60029
|
runtimeApi: true,
|
|
59018
60030
|
metadataKeys: Object.keys(input.metadata ?? {}).sort()
|
|
59019
60031
|
});
|
|
@@ -59032,10 +60044,15 @@ var AgentRuntime = class {
|
|
|
59032
60044
|
output: result.data,
|
|
59033
60045
|
error: result.error,
|
|
59034
60046
|
duration: result.duration,
|
|
59035
|
-
decision
|
|
60047
|
+
decision: {
|
|
60048
|
+
...decision,
|
|
60049
|
+
risk: effectiveDecision.risk,
|
|
60050
|
+
requiresConfirmation: decision.requiresConfirmation
|
|
60051
|
+
}
|
|
59036
60052
|
};
|
|
59037
60053
|
}
|
|
59038
60054
|
assertToolAllowed(mode, toolName, input) {
|
|
60055
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "tool.assertAllowed");
|
|
59039
60056
|
const tool = this.toolRegistry.get(toolName);
|
|
59040
60057
|
if (!tool) {
|
|
59041
60058
|
this.eventLog.record("tool.blocked", {
|
|
@@ -59046,14 +60063,84 @@ var AgentRuntime = class {
|
|
|
59046
60063
|
return false;
|
|
59047
60064
|
}
|
|
59048
60065
|
const decision = input && this.permissionPolicy.canExecuteToolInput ? this.permissionPolicy.canExecuteToolInput(mode, tool, input) : this.permissionPolicy.canExecuteTool(mode, tool);
|
|
59049
|
-
|
|
60066
|
+
const runtimeDecision = decision.allowed ? evaluateRuntimeToolPolicy(this.runtimePolicy, {
|
|
60067
|
+
toolName,
|
|
60068
|
+
risk: decision.risk,
|
|
60069
|
+
confirmed: false
|
|
60070
|
+
}) : void 0;
|
|
60071
|
+
const allowed = decision.allowed && runtimeDecision?.allowed !== false;
|
|
60072
|
+
this.eventLog.record(allowed ? "tool.allowed" : "tool.blocked", {
|
|
59050
60073
|
mode,
|
|
59051
60074
|
tool: toolName,
|
|
59052
|
-
...decision
|
|
59053
|
-
|
|
59054
|
-
|
|
60075
|
+
...decision,
|
|
60076
|
+
...runtimeDecision && !runtimeDecision.allowed ? {
|
|
60077
|
+
allowed: false,
|
|
60078
|
+
reason: runtimeDecision.reason,
|
|
60079
|
+
requiresConfirmation: runtimeDecision.requiresConfirmation,
|
|
60080
|
+
runtimePolicyBlocked: true
|
|
60081
|
+
} : {}
|
|
60082
|
+
});
|
|
60083
|
+
return allowed;
|
|
60084
|
+
}
|
|
60085
|
+
beginRuntimeRequest(subject) {
|
|
60086
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, subject);
|
|
60087
|
+
this.assertWithinRateLimit(subject);
|
|
60088
|
+
this.assertWithinConcurrencyLimit(subject);
|
|
60089
|
+
this.activeRuns += 1;
|
|
60090
|
+
let released = false;
|
|
60091
|
+
return () => {
|
|
60092
|
+
if (released) return;
|
|
60093
|
+
released = true;
|
|
60094
|
+
this.activeRuns = Math.max(0, this.activeRuns - 1);
|
|
60095
|
+
};
|
|
60096
|
+
}
|
|
60097
|
+
assertWithinRateLimit(subject) {
|
|
60098
|
+
const maxRequestsPerMinute = this.runtimePolicy?.rateLimit?.maxRequestsPerMinute;
|
|
60099
|
+
if (maxRequestsPerMinute === void 0) return;
|
|
60100
|
+
const now = Date.now();
|
|
60101
|
+
const windowStart = now - 6e4;
|
|
60102
|
+
const key = `${this.runtimeContext?.tenant?.id ?? "global"}:${subject}`;
|
|
60103
|
+
const recent = (this.requestTimestampsBySubject.get(key) ?? []).filter(
|
|
60104
|
+
(timestamp) => timestamp > windowStart
|
|
60105
|
+
);
|
|
60106
|
+
if (recent.length >= maxRequestsPerMinute) {
|
|
60107
|
+
this.requestTimestampsBySubject.set(key, recent);
|
|
60108
|
+
throw new RuntimePolicyViolation({
|
|
60109
|
+
code: "rate_limit_exceeded",
|
|
60110
|
+
subject,
|
|
60111
|
+
tenantId: this.runtimeContext?.tenant?.id,
|
|
60112
|
+
policyPath: "runtimePolicy.rateLimit.maxRequestsPerMinute",
|
|
60113
|
+
message: `Runtime policy rate limit exceeded: ${recent.length}/${maxRequestsPerMinute} requests per minute.`
|
|
60114
|
+
});
|
|
60115
|
+
}
|
|
60116
|
+
recent.push(now);
|
|
60117
|
+
this.requestTimestampsBySubject.set(key, recent);
|
|
60118
|
+
}
|
|
60119
|
+
assertWithinConcurrencyLimit(subject) {
|
|
60120
|
+
const maxConcurrentRuns = this.runtimePolicy?.rateLimit?.maxConcurrentRuns;
|
|
60121
|
+
if (maxConcurrentRuns === void 0) return;
|
|
60122
|
+
if (this.activeRuns >= maxConcurrentRuns) {
|
|
60123
|
+
throw new RuntimePolicyViolation({
|
|
60124
|
+
code: "concurrency_limit_exceeded",
|
|
60125
|
+
subject,
|
|
60126
|
+
tenantId: this.runtimeContext?.tenant?.id,
|
|
60127
|
+
policyPath: "runtimePolicy.rateLimit.maxConcurrentRuns",
|
|
60128
|
+
message: `Runtime policy concurrency limit exceeded: ${this.activeRuns}/${maxConcurrentRuns} active runs.`
|
|
60129
|
+
});
|
|
60130
|
+
}
|
|
60131
|
+
}
|
|
60132
|
+
estimateTurnCost(result) {
|
|
60133
|
+
return estimateCost(
|
|
60134
|
+
result.model,
|
|
60135
|
+
result.usage.inputTokens,
|
|
60136
|
+
result.usage.outputTokens,
|
|
60137
|
+
this.providerType
|
|
60138
|
+
).totalCost;
|
|
59055
60139
|
}
|
|
59056
60140
|
};
|
|
60141
|
+
function countUserTurns(session) {
|
|
60142
|
+
return session.messages.filter((message) => message.role === "user").length;
|
|
60143
|
+
}
|
|
59057
60144
|
async function createAgentRuntime(options) {
|
|
59058
60145
|
const runtime = new AgentRuntime(options);
|
|
59059
60146
|
await runtime.initialize();
|
|
@@ -59729,8 +60816,10 @@ async function startRepl(options = {}) {
|
|
|
59729
60816
|
providerType: internalProviderId,
|
|
59730
60817
|
model: session.config.provider.model || void 0,
|
|
59731
60818
|
provider,
|
|
60819
|
+
toolRegistry: createFullToolRegistry(),
|
|
59732
60820
|
eventLogPath: path39__default.join(projectPath, ".coco", "events", `${session.id}.jsonl`),
|
|
59733
|
-
publishToGlobalBridge: true
|
|
60821
|
+
publishToGlobalBridge: true,
|
|
60822
|
+
legacyAgentBridge: { setAgentProvider, setAgentToolRegistry }
|
|
59734
60823
|
});
|
|
59735
60824
|
session.runtime = runtime;
|
|
59736
60825
|
const toolRegistry = runtime.toolRegistry;
|
|
@@ -61005,9 +62094,11 @@ ${stdinContent}
|
|
|
61005
62094
|
providerType,
|
|
61006
62095
|
model: session.config.provider.model || void 0,
|
|
61007
62096
|
provider,
|
|
62097
|
+
toolRegistry: createFullToolRegistry(),
|
|
61008
62098
|
eventLogPath: path39__default.join(options.projectPath, ".coco", "events", `${session.id}.jsonl`),
|
|
61009
62099
|
turnRunner: options.useRuntimeRunner ? createToolCallingRuntimeTurnRunner() : void 0,
|
|
61010
|
-
publishToGlobalBridge: true
|
|
62100
|
+
publishToGlobalBridge: true,
|
|
62101
|
+
legacyAgentBridge: { setAgentProvider, setAgentToolRegistry }
|
|
61011
62102
|
});
|
|
61012
62103
|
session.runtime = runtime;
|
|
61013
62104
|
const toolRegistry = runtime.toolRegistry;
|