@corbat-tech/coco 2.40.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 +81 -3
- package/dist/adapters/index.js +179 -1
- package/dist/adapters/index.js.map +1 -1
- package/dist/{agent-runtime-Cd6pB640.d.ts → agent-runtime-BJeNjVuk.d.ts} +20 -2
- package/dist/{blueprints-Dmdaw6_I.d.ts → blueprints-Dw5-uWU9.d.ts} +28 -4
- package/dist/cli/index.js +474 -15
- package/dist/cli/index.js.map +1 -1
- package/dist/{workflow-engine-DleSoUhy.d.ts → context-BLPsKYxc.d.ts} +247 -129
- package/dist/{index-BD5_a3Q8.d.ts → index-DhUKtM2p.d.ts} +2 -2
- package/dist/index.d.ts +10 -10
- package/dist/index.js +1324 -128
- package/dist/index.js.map +1 -1
- package/dist/presets/index.d.ts +5 -5
- package/dist/presets/index.js +521 -17
- package/dist/presets/index.js.map +1 -1
- package/dist/{profiles-BA9dvyaF.d.ts → profiles-GRoVNorK.d.ts} +3 -3
- package/dist/{rag-D-Zo1oyo.d.ts → rag-B2oGudNb.d.ts} +68 -2
- package/dist/runtime/index.d.ts +278 -8
- package/dist/runtime/index.js +1113 -122
- package/dist/runtime/index.js.map +1 -1
- package/dist/tools/index.d.ts +4 -4
- package/dist/tools/index.js +1 -0
- package/dist/tools/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/runtime-tool-executor-L5i8QWzn.d.ts +0 -174
package/dist/presets/index.js
CHANGED
|
@@ -3363,6 +3363,53 @@ function defineTool(definition) {
|
|
|
3363
3363
|
// src/runtime/agent-runtime.ts
|
|
3364
3364
|
init_env();
|
|
3365
3365
|
|
|
3366
|
+
// src/providers/pricing.ts
|
|
3367
|
+
init_catalog();
|
|
3368
|
+
var MODEL_PRICING = getCatalogModelPricingMap();
|
|
3369
|
+
var DEFAULT_PRICING = {
|
|
3370
|
+
anthropic: { inputPerMillion: 3, outputPerMillion: 15, contextWindow: 2e5 },
|
|
3371
|
+
openai: { inputPerMillion: 2.5, outputPerMillion: 10, contextWindow: 128e3 },
|
|
3372
|
+
codex: { inputPerMillion: 0, outputPerMillion: 0, contextWindow: 128e3 },
|
|
3373
|
+
// ChatGPT Plus/Pro subscription
|
|
3374
|
+
gemini: { inputPerMillion: 0.1, outputPerMillion: 0.4, contextWindow: 1e6 },
|
|
3375
|
+
vertex: { inputPerMillion: 0.1, outputPerMillion: 0.4, contextWindow: 1048576 },
|
|
3376
|
+
kimi: { inputPerMillion: 1.2, outputPerMillion: 1.2, contextWindow: 8192 },
|
|
3377
|
+
"kimi-code": { inputPerMillion: 0, outputPerMillion: 0, contextWindow: 131072 },
|
|
3378
|
+
// Included in subscription
|
|
3379
|
+
copilot: { inputPerMillion: 0, outputPerMillion: 0, contextWindow: 2e5 },
|
|
3380
|
+
// Included in subscription
|
|
3381
|
+
lmstudio: { inputPerMillion: 0, outputPerMillion: 0, contextWindow: 32768 },
|
|
3382
|
+
// Free - local models
|
|
3383
|
+
ollama: { inputPerMillion: 0, outputPerMillion: 0, contextWindow: 128e3 },
|
|
3384
|
+
// Free - local models
|
|
3385
|
+
groq: { inputPerMillion: 0.05, outputPerMillion: 0.08, contextWindow: 128e3 },
|
|
3386
|
+
// Free tier available
|
|
3387
|
+
openrouter: { inputPerMillion: 2, outputPerMillion: 8, contextWindow: 2e5 },
|
|
3388
|
+
// Varies by model
|
|
3389
|
+
mistral: { inputPerMillion: 0.25, outputPerMillion: 0.75, contextWindow: 32768 },
|
|
3390
|
+
deepseek: { inputPerMillion: 0.14, outputPerMillion: 0.28, contextWindow: 128e3 },
|
|
3391
|
+
// Very cheap
|
|
3392
|
+
together: { inputPerMillion: 0.2, outputPerMillion: 0.2, contextWindow: 32768 },
|
|
3393
|
+
huggingface: { inputPerMillion: 0, outputPerMillion: 0, contextWindow: 32768 },
|
|
3394
|
+
// Free tier
|
|
3395
|
+
qwen: { inputPerMillion: 0.3, outputPerMillion: 1.2, contextWindow: 131072 }
|
|
3396
|
+
// qwen-coder-plus pricing
|
|
3397
|
+
};
|
|
3398
|
+
function estimateCost(model2, inputTokens, outputTokens, provider) {
|
|
3399
|
+
const pricing = MODEL_PRICING[model2] ?? (provider ? DEFAULT_PRICING[provider] : DEFAULT_PRICING.anthropic);
|
|
3400
|
+
const inputCost = inputTokens / 1e6 * pricing.inputPerMillion;
|
|
3401
|
+
const outputCost = outputTokens / 1e6 * pricing.outputPerMillion;
|
|
3402
|
+
return {
|
|
3403
|
+
inputCost,
|
|
3404
|
+
outputCost,
|
|
3405
|
+
totalCost: inputCost + outputCost,
|
|
3406
|
+
inputTokens,
|
|
3407
|
+
outputTokens,
|
|
3408
|
+
model: model2,
|
|
3409
|
+
currency: "USD"
|
|
3410
|
+
};
|
|
3411
|
+
}
|
|
3412
|
+
|
|
3366
3413
|
// src/runtime/agent-modes.ts
|
|
3367
3414
|
var AGENT_MODES = {
|
|
3368
3415
|
ask: {
|
|
@@ -3422,6 +3469,22 @@ function listAgentModes() {
|
|
|
3422
3469
|
}
|
|
3423
3470
|
|
|
3424
3471
|
// src/runtime/context.ts
|
|
3472
|
+
var RuntimePolicyViolation = class extends Error {
|
|
3473
|
+
code;
|
|
3474
|
+
subject;
|
|
3475
|
+
tenantId;
|
|
3476
|
+
policyPath;
|
|
3477
|
+
severity;
|
|
3478
|
+
constructor(input) {
|
|
3479
|
+
super(input.message);
|
|
3480
|
+
this.name = "RuntimePolicyViolation";
|
|
3481
|
+
this.code = input.code;
|
|
3482
|
+
this.subject = input.subject;
|
|
3483
|
+
this.tenantId = input.tenantId;
|
|
3484
|
+
this.policyPath = input.policyPath;
|
|
3485
|
+
this.severity = input.severity ?? "blocked";
|
|
3486
|
+
}
|
|
3487
|
+
};
|
|
3425
3488
|
function createRuntimeRequestContext(input = {}) {
|
|
3426
3489
|
return {
|
|
3427
3490
|
surface: input.surface ?? "api",
|
|
@@ -3464,6 +3527,27 @@ function runtimeContextToMetadata(context) {
|
|
|
3464
3527
|
dataClassification: context.policy?.dataBoundary?.classification
|
|
3465
3528
|
};
|
|
3466
3529
|
}
|
|
3530
|
+
function createRuntimeTenantBoundary(context, hostMode = "local") {
|
|
3531
|
+
return {
|
|
3532
|
+
hostMode,
|
|
3533
|
+
surface: context?.surface ?? "api",
|
|
3534
|
+
tenantId: context?.tenant?.id,
|
|
3535
|
+
required: hostMode === "hosted" && context?.surface !== "cli"
|
|
3536
|
+
};
|
|
3537
|
+
}
|
|
3538
|
+
function assertRuntimeTenantBoundary(context, hostMode = "local", subject = "runtime operation") {
|
|
3539
|
+
const boundary = createRuntimeTenantBoundary(context, hostMode);
|
|
3540
|
+
if (boundary.required && !boundary.tenantId) {
|
|
3541
|
+
throw new RuntimePolicyViolation({
|
|
3542
|
+
code: "tenant_required",
|
|
3543
|
+
subject,
|
|
3544
|
+
tenantId: boundary.tenantId,
|
|
3545
|
+
policyPath: "runtimeContext.tenant.id",
|
|
3546
|
+
message: `Runtime tenant is required for hosted ${boundary.surface} operations.`
|
|
3547
|
+
});
|
|
3548
|
+
}
|
|
3549
|
+
return boundary;
|
|
3550
|
+
}
|
|
3467
3551
|
function evaluateRuntimeToolPolicy(policy, input) {
|
|
3468
3552
|
if (policy?.allowedTools && !policy.allowedTools.includes(input.toolName)) {
|
|
3469
3553
|
return {
|
|
@@ -3507,23 +3591,65 @@ function evaluateRuntimeRiskPolicy(policy, input) {
|
|
|
3507
3591
|
}
|
|
3508
3592
|
return { allowed: true, risk: input.risk };
|
|
3509
3593
|
}
|
|
3594
|
+
function assertRuntimeTurnWithinPolicy(policy, input) {
|
|
3595
|
+
const maxTurns = policy?.costBudget?.maxTurns;
|
|
3596
|
+
if (maxTurns !== void 0 && input.currentTurns >= maxTurns) {
|
|
3597
|
+
throw new RuntimePolicyViolation({
|
|
3598
|
+
code: "max_turns_exceeded",
|
|
3599
|
+
subject: input.subject,
|
|
3600
|
+
tenantId: input.tenantId,
|
|
3601
|
+
policyPath: "runtimePolicy.costBudget.maxTurns",
|
|
3602
|
+
message: `Runtime policy turn budget exceeded: ${input.currentTurns}/${maxTurns}`
|
|
3603
|
+
});
|
|
3604
|
+
}
|
|
3605
|
+
}
|
|
3510
3606
|
function assertRuntimeUsageWithinPolicy(policy, usage) {
|
|
3511
3607
|
const budget = policy?.costBudget;
|
|
3608
|
+
const subject = usage.subject ?? "runtime usage";
|
|
3512
3609
|
if (!budget) return;
|
|
3513
3610
|
if (budget.maxInputTokens !== void 0 && (usage.inputTokens ?? 0) > budget.maxInputTokens) {
|
|
3514
|
-
throw new
|
|
3515
|
-
|
|
3516
|
-
|
|
3611
|
+
throw new RuntimePolicyViolation({
|
|
3612
|
+
code: "input_tokens_exceeded",
|
|
3613
|
+
subject,
|
|
3614
|
+
tenantId: usage.tenantId,
|
|
3615
|
+
policyPath: "runtimePolicy.costBudget.maxInputTokens",
|
|
3616
|
+
message: `Runtime policy input token budget exceeded: ${usage.inputTokens ?? 0}/${budget.maxInputTokens}`
|
|
3617
|
+
});
|
|
3517
3618
|
}
|
|
3518
3619
|
if (budget.maxOutputTokens !== void 0 && (usage.outputTokens ?? 0) > budget.maxOutputTokens) {
|
|
3519
|
-
throw new
|
|
3520
|
-
|
|
3521
|
-
|
|
3620
|
+
throw new RuntimePolicyViolation({
|
|
3621
|
+
code: "output_tokens_exceeded",
|
|
3622
|
+
subject,
|
|
3623
|
+
tenantId: usage.tenantId,
|
|
3624
|
+
policyPath: "runtimePolicy.costBudget.maxOutputTokens",
|
|
3625
|
+
message: `Runtime policy output token budget exceeded: ${usage.outputTokens ?? 0}/${budget.maxOutputTokens}`
|
|
3626
|
+
});
|
|
3627
|
+
}
|
|
3628
|
+
if (budget.maxEstimatedCostUsd !== void 0 && (usage.estimatedCostUsd ?? 0) > budget.maxEstimatedCostUsd) {
|
|
3629
|
+
throw new RuntimePolicyViolation({
|
|
3630
|
+
code: "estimated_cost_exceeded",
|
|
3631
|
+
subject,
|
|
3632
|
+
tenantId: usage.tenantId,
|
|
3633
|
+
policyPath: "runtimePolicy.costBudget.maxEstimatedCostUsd",
|
|
3634
|
+
message: `Runtime policy estimated cost budget exceeded: ${usage.estimatedCostUsd ?? 0}/${budget.maxEstimatedCostUsd}`
|
|
3635
|
+
});
|
|
3522
3636
|
}
|
|
3523
3637
|
}
|
|
3638
|
+
function createRetentionCutoffs(policy, now = /* @__PURE__ */ new Date()) {
|
|
3639
|
+
const retention = policy?.retention;
|
|
3640
|
+
return {
|
|
3641
|
+
conversationBefore: cutoffIso(now, retention?.conversationDays),
|
|
3642
|
+
eventBefore: cutoffIso(now, retention?.eventDays),
|
|
3643
|
+
artifactBefore: cutoffIso(now, retention?.artifactDays)
|
|
3644
|
+
};
|
|
3645
|
+
}
|
|
3524
3646
|
function cloneRuntimePolicy(policy) {
|
|
3525
3647
|
return mergeRuntimePolicy(void 0, policy) ?? {};
|
|
3526
3648
|
}
|
|
3649
|
+
function cutoffIso(now, days) {
|
|
3650
|
+
if (days === void 0) return void 0;
|
|
3651
|
+
return new Date(now.getTime() - days * 24 * 60 * 60 * 1e3).toISOString();
|
|
3652
|
+
}
|
|
3527
3653
|
function riskRank(risk) {
|
|
3528
3654
|
switch (risk) {
|
|
3529
3655
|
case "read-only":
|
|
@@ -7855,10 +7981,6 @@ var VertexProvider = class {
|
|
|
7855
7981
|
}
|
|
7856
7982
|
};
|
|
7857
7983
|
|
|
7858
|
-
// src/providers/pricing.ts
|
|
7859
|
-
init_catalog();
|
|
7860
|
-
getCatalogModelPricingMap();
|
|
7861
|
-
|
|
7862
7984
|
// src/providers/circuit-breaker.ts
|
|
7863
7985
|
init_errors();
|
|
7864
7986
|
var DEFAULT_CIRCUIT_BREAKER_CONFIG = {
|
|
@@ -8431,6 +8553,7 @@ var LEGACY_ROLE_MAPPINGS = [
|
|
|
8431
8553
|
{ legacy: "coder", role: "coder", reason: "legacy executor role" },
|
|
8432
8554
|
{ legacy: "test", role: "tester", reason: "test authoring/execution" },
|
|
8433
8555
|
{ legacy: "tester", role: "tester", reason: "legacy executor role" },
|
|
8556
|
+
{ legacy: "verifier", role: "tester", reason: "verification maps to tester capability" },
|
|
8434
8557
|
{ legacy: "tdd", role: "tester", reason: "test-first implementation" },
|
|
8435
8558
|
{ legacy: "e2e", role: "tester", reason: "end-to-end testing" },
|
|
8436
8559
|
{ legacy: "review", role: "reviewer", reason: "code review" },
|
|
@@ -8444,7 +8567,10 @@ var LEGACY_ROLE_MAPPINGS = [
|
|
|
8444
8567
|
{ legacy: "docs", role: "docs", reason: "documentation" },
|
|
8445
8568
|
{ legacy: "database", role: "database", reason: "database work" }
|
|
8446
8569
|
];
|
|
8447
|
-
new Map(LEGACY_ROLE_MAPPINGS.map((mapping) => [mapping.legacy, mapping]));
|
|
8570
|
+
var LEGACY_ROLE_MAP = new Map(LEGACY_ROLE_MAPPINGS.map((mapping) => [mapping.legacy, mapping]));
|
|
8571
|
+
function mapLegacyAgentRole(legacyRole, fallback = "coder") {
|
|
8572
|
+
return LEGACY_ROLE_MAP.get(legacyRole)?.role ?? fallback;
|
|
8573
|
+
}
|
|
8448
8574
|
function assertProvenance(provenance) {
|
|
8449
8575
|
if (!provenance.workflowRunId) {
|
|
8450
8576
|
throw new Error("Shared workspace writes require workflowRunId provenance.");
|
|
@@ -8524,6 +8650,39 @@ var InMemorySharedWorkspaceStore = class {
|
|
|
8524
8650
|
this.records = [];
|
|
8525
8651
|
}
|
|
8526
8652
|
};
|
|
8653
|
+
function evaluateAgentToolPolicy(input) {
|
|
8654
|
+
const manifestEntry = input.manifest?.[input.toolName];
|
|
8655
|
+
const risk = manifestEntry?.risk ?? input.capability.risk;
|
|
8656
|
+
if (!input.capability.allowedTools.includes(input.toolName)) {
|
|
8657
|
+
return {
|
|
8658
|
+
allowed: false,
|
|
8659
|
+
risk,
|
|
8660
|
+
reason: `Tool '${input.toolName}' is not allowed for agent role '${input.capability.role}'.`
|
|
8661
|
+
};
|
|
8662
|
+
}
|
|
8663
|
+
if (manifestEntry?.requiredCapability) {
|
|
8664
|
+
const allowedRoles = Array.isArray(manifestEntry.requiredCapability) ? manifestEntry.requiredCapability : [manifestEntry.requiredCapability];
|
|
8665
|
+
if (!allowedRoles.includes(input.capability.role)) {
|
|
8666
|
+
return {
|
|
8667
|
+
allowed: false,
|
|
8668
|
+
risk,
|
|
8669
|
+
reason: `Tool '${input.toolName}' requires role ${allowedRoles.join(", ")}.`
|
|
8670
|
+
};
|
|
8671
|
+
}
|
|
8672
|
+
}
|
|
8673
|
+
if (riskRank2(risk) > riskRank2(input.capability.risk)) {
|
|
8674
|
+
return {
|
|
8675
|
+
allowed: false,
|
|
8676
|
+
risk,
|
|
8677
|
+
reason: `Tool '${input.toolName}' risk '${risk}' exceeds agent capability risk '${input.capability.risk}'.`
|
|
8678
|
+
};
|
|
8679
|
+
}
|
|
8680
|
+
return {
|
|
8681
|
+
allowed: true,
|
|
8682
|
+
risk,
|
|
8683
|
+
requiresConsent: manifestEntry?.requiresConsent ?? (risk === "destructive" || risk === "secrets-sensitive")
|
|
8684
|
+
};
|
|
8685
|
+
}
|
|
8527
8686
|
function createAgentTraceContext(input = {}) {
|
|
8528
8687
|
return {
|
|
8529
8688
|
traceId: input.traceId ?? `trace-${randomUUID()}`,
|
|
@@ -8964,7 +9123,7 @@ var NULL_EVENT_LOG = {
|
|
|
8964
9123
|
function graphNodeToTask(node, workflowInput) {
|
|
8965
9124
|
return {
|
|
8966
9125
|
id: node.id,
|
|
8967
|
-
role: node.agentRole ?? "coder",
|
|
9126
|
+
role: node.agentRole ?? mapLegacyAgentRole(node.id, "coder"),
|
|
8968
9127
|
objective: node.description,
|
|
8969
9128
|
context: {
|
|
8970
9129
|
workflowInput,
|
|
@@ -9111,6 +9270,20 @@ function readPath(input, path38) {
|
|
|
9111
9270
|
return void 0;
|
|
9112
9271
|
}, input);
|
|
9113
9272
|
}
|
|
9273
|
+
function riskRank2(risk) {
|
|
9274
|
+
switch (risk) {
|
|
9275
|
+
case "read-only":
|
|
9276
|
+
return 0;
|
|
9277
|
+
case "network":
|
|
9278
|
+
return 1;
|
|
9279
|
+
case "write":
|
|
9280
|
+
return 2;
|
|
9281
|
+
case "destructive":
|
|
9282
|
+
return 3;
|
|
9283
|
+
case "secrets-sensitive":
|
|
9284
|
+
return 4;
|
|
9285
|
+
}
|
|
9286
|
+
}
|
|
9114
9287
|
function cloneUnknown(value) {
|
|
9115
9288
|
if (value === void 0 || value === null) return value;
|
|
9116
9289
|
try {
|
|
@@ -9136,6 +9309,206 @@ function cloneArtifact(artifact) {
|
|
|
9136
9309
|
};
|
|
9137
9310
|
}
|
|
9138
9311
|
|
|
9312
|
+
// src/runtime/agent-runner.ts
|
|
9313
|
+
var AgentRunner = class {
|
|
9314
|
+
constructor(options = {}) {
|
|
9315
|
+
this.options = options;
|
|
9316
|
+
}
|
|
9317
|
+
options;
|
|
9318
|
+
async run(input) {
|
|
9319
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9320
|
+
const trace = input.trace ?? createAgentTraceContext({ taskId: input.task.id });
|
|
9321
|
+
this.options.eventLog?.record("agent.started", {
|
|
9322
|
+
taskId: input.task.id,
|
|
9323
|
+
role: input.task.role,
|
|
9324
|
+
trace
|
|
9325
|
+
});
|
|
9326
|
+
try {
|
|
9327
|
+
const raw = await (this.options.executor ?? defaultExecutor)({
|
|
9328
|
+
task: input.task,
|
|
9329
|
+
capability: input.capability,
|
|
9330
|
+
trace,
|
|
9331
|
+
assertToolAllowed: (toolName) => {
|
|
9332
|
+
const decision = evaluateAgentToolPolicy({
|
|
9333
|
+
capability: input.capability,
|
|
9334
|
+
toolName,
|
|
9335
|
+
manifest: input.toolRiskManifest
|
|
9336
|
+
});
|
|
9337
|
+
this.options.eventLog?.record("agent.tool.called", {
|
|
9338
|
+
taskId: input.task.id,
|
|
9339
|
+
role: input.task.role,
|
|
9340
|
+
toolName,
|
|
9341
|
+
decision,
|
|
9342
|
+
trace
|
|
9343
|
+
});
|
|
9344
|
+
if (!decision.allowed) {
|
|
9345
|
+
throw new Error(decision.reason ?? `Tool '${toolName}' is not allowed.`);
|
|
9346
|
+
}
|
|
9347
|
+
}
|
|
9348
|
+
});
|
|
9349
|
+
const result = normalizeAgentRunResult({
|
|
9350
|
+
id: `${input.task.id}-run-${Date.now().toString(36)}`,
|
|
9351
|
+
taskId: input.task.id,
|
|
9352
|
+
role: input.task.role,
|
|
9353
|
+
success: raw.success ?? true,
|
|
9354
|
+
output: raw.output,
|
|
9355
|
+
turns: raw.turns,
|
|
9356
|
+
toolsUsed: raw.toolsUsed,
|
|
9357
|
+
usage: {
|
|
9358
|
+
inputTokens: raw.inputTokens ?? 0,
|
|
9359
|
+
outputTokens: raw.outputTokens ?? 0,
|
|
9360
|
+
estimated: raw.inputTokens === void 0 || raw.outputTokens === void 0
|
|
9361
|
+
},
|
|
9362
|
+
startedAt,
|
|
9363
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9364
|
+
durationMs: Date.now() - Date.parse(startedAt),
|
|
9365
|
+
error: raw.error,
|
|
9366
|
+
metadata: { ...raw.metadata, trace }
|
|
9367
|
+
});
|
|
9368
|
+
this.options.eventLog?.record(result.success ? "agent.completed" : "agent.failed", {
|
|
9369
|
+
taskId: input.task.id,
|
|
9370
|
+
role: input.task.role,
|
|
9371
|
+
agentRunId: result.id,
|
|
9372
|
+
trace,
|
|
9373
|
+
error: result.error
|
|
9374
|
+
});
|
|
9375
|
+
return result;
|
|
9376
|
+
} catch (error) {
|
|
9377
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
9378
|
+
const result = normalizeAgentRunResult({
|
|
9379
|
+
id: `${input.task.id}-run-${Date.now().toString(36)}`,
|
|
9380
|
+
taskId: input.task.id,
|
|
9381
|
+
role: input.task.role,
|
|
9382
|
+
success: false,
|
|
9383
|
+
output: message,
|
|
9384
|
+
startedAt,
|
|
9385
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9386
|
+
durationMs: Date.now() - Date.parse(startedAt),
|
|
9387
|
+
error: message,
|
|
9388
|
+
metadata: { trace }
|
|
9389
|
+
});
|
|
9390
|
+
this.options.eventLog?.record("agent.failed", {
|
|
9391
|
+
taskId: input.task.id,
|
|
9392
|
+
role: input.task.role,
|
|
9393
|
+
agentRunId: result.id,
|
|
9394
|
+
trace,
|
|
9395
|
+
error: message
|
|
9396
|
+
});
|
|
9397
|
+
return result;
|
|
9398
|
+
}
|
|
9399
|
+
}
|
|
9400
|
+
};
|
|
9401
|
+
async function defaultExecutor(context) {
|
|
9402
|
+
return {
|
|
9403
|
+
output: `Agent ${context.capability.role} accepted task '${context.task.objective}'.`
|
|
9404
|
+
};
|
|
9405
|
+
}
|
|
9406
|
+
|
|
9407
|
+
// src/runtime/runtime-agent-node-executor.ts
|
|
9408
|
+
var RuntimeAgentNodeExecutor = class {
|
|
9409
|
+
constructor(options) {
|
|
9410
|
+
this.options = options;
|
|
9411
|
+
this.runner = options.runner ?? new AgentRunner(options.runnerOptions);
|
|
9412
|
+
}
|
|
9413
|
+
options;
|
|
9414
|
+
runner;
|
|
9415
|
+
execute = async (execution) => {
|
|
9416
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9417
|
+
const definition = this.options.registry.getByRole(execution.task.role);
|
|
9418
|
+
if (!definition) {
|
|
9419
|
+
return normalizeAgentRunResult({
|
|
9420
|
+
id: `${execution.workflowRunId}-${execution.node.id}-missing-definition`,
|
|
9421
|
+
taskId: execution.task.id,
|
|
9422
|
+
role: execution.task.role,
|
|
9423
|
+
success: false,
|
|
9424
|
+
output: "",
|
|
9425
|
+
startedAt,
|
|
9426
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9427
|
+
error: `No agent definition registered for role '${execution.task.role}'.`,
|
|
9428
|
+
metadata: {
|
|
9429
|
+
workflowRunId: execution.workflowRunId,
|
|
9430
|
+
nodeId: execution.node.id,
|
|
9431
|
+
trace: execution.trace
|
|
9432
|
+
}
|
|
9433
|
+
});
|
|
9434
|
+
}
|
|
9435
|
+
const blockedTool = this.findBlockedTool(definition, execution);
|
|
9436
|
+
if (blockedTool) {
|
|
9437
|
+
return normalizeAgentRunResult({
|
|
9438
|
+
id: `${execution.workflowRunId}-${execution.node.id}-policy-blocked`,
|
|
9439
|
+
taskId: execution.task.id,
|
|
9440
|
+
role: execution.task.role,
|
|
9441
|
+
success: false,
|
|
9442
|
+
output: "",
|
|
9443
|
+
startedAt,
|
|
9444
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9445
|
+
error: blockedTool,
|
|
9446
|
+
metadata: {
|
|
9447
|
+
workflowRunId: execution.workflowRunId,
|
|
9448
|
+
nodeId: execution.node.id,
|
|
9449
|
+
agentDefinitionId: definition.id,
|
|
9450
|
+
trace: execution.trace
|
|
9451
|
+
}
|
|
9452
|
+
});
|
|
9453
|
+
}
|
|
9454
|
+
const input = {
|
|
9455
|
+
task: {
|
|
9456
|
+
...execution.task,
|
|
9457
|
+
context: {
|
|
9458
|
+
...execution.task.context,
|
|
9459
|
+
instructions: definition.instructions,
|
|
9460
|
+
sharedState: execution.sharedState.readForRole(definition.role)
|
|
9461
|
+
}
|
|
9462
|
+
},
|
|
9463
|
+
capability: definition.capability,
|
|
9464
|
+
trace: execution.trace,
|
|
9465
|
+
toolRiskManifest: this.options.toolRiskManifest
|
|
9466
|
+
};
|
|
9467
|
+
const result = await this.runner.run(input);
|
|
9468
|
+
return normalizeAgentRunResult({
|
|
9469
|
+
...result,
|
|
9470
|
+
metadata: {
|
|
9471
|
+
...result.metadata,
|
|
9472
|
+
workflowRunId: execution.workflowRunId,
|
|
9473
|
+
nodeId: execution.node.id,
|
|
9474
|
+
agentDefinitionId: definition.id
|
|
9475
|
+
}
|
|
9476
|
+
});
|
|
9477
|
+
};
|
|
9478
|
+
findBlockedTool(definition, execution) {
|
|
9479
|
+
for (const toolName of execution.node.requiredTools ?? []) {
|
|
9480
|
+
const agentDecision = evaluateAgentToolPolicy({
|
|
9481
|
+
capability: definition.capability,
|
|
9482
|
+
toolName,
|
|
9483
|
+
manifest: this.options.toolRiskManifest
|
|
9484
|
+
});
|
|
9485
|
+
execution.eventLog.record("agent.tool.called", {
|
|
9486
|
+
workflowRunId: execution.workflowRunId,
|
|
9487
|
+
nodeId: execution.node.id,
|
|
9488
|
+
taskId: execution.task.id,
|
|
9489
|
+
role: execution.task.role,
|
|
9490
|
+
toolName,
|
|
9491
|
+
decision: agentDecision,
|
|
9492
|
+
trace: execution.trace
|
|
9493
|
+
});
|
|
9494
|
+
if (!agentDecision.allowed) {
|
|
9495
|
+
return agentDecision.reason ?? `Tool '${toolName}' is not allowed for agent.`;
|
|
9496
|
+
}
|
|
9497
|
+
const runtimeDecision = evaluateRuntimeToolPolicy(this.options.runtimePolicy, {
|
|
9498
|
+
toolName,
|
|
9499
|
+
risk: agentDecision.risk
|
|
9500
|
+
});
|
|
9501
|
+
if (!runtimeDecision.allowed) {
|
|
9502
|
+
return runtimeDecision.reason ?? `Tool '${toolName}' is blocked by runtime policy.`;
|
|
9503
|
+
}
|
|
9504
|
+
}
|
|
9505
|
+
return void 0;
|
|
9506
|
+
}
|
|
9507
|
+
};
|
|
9508
|
+
function createRuntimeAgentNodeExecutor(options) {
|
|
9509
|
+
return new RuntimeAgentNodeExecutor(options).execute;
|
|
9510
|
+
}
|
|
9511
|
+
|
|
9139
9512
|
// src/runtime/workflow-registry.ts
|
|
9140
9513
|
function cloneWorkflow(workflow) {
|
|
9141
9514
|
return {
|
|
@@ -9465,14 +9838,22 @@ var WorkflowEngine = class {
|
|
|
9465
9838
|
this.catalog = catalog;
|
|
9466
9839
|
this.eventLog = eventLog;
|
|
9467
9840
|
this.sharedState = options.sharedState ?? new InMemorySharedWorkspaceStore();
|
|
9468
|
-
this.nodeExecutor = options.nodeExecutor;
|
|
9469
9841
|
this.runtimePolicy = options.runtimePolicy;
|
|
9842
|
+
this.runtimeContext = options.runtimeContext;
|
|
9843
|
+
this.runtimeHostMode = options.runtimeHostMode ?? "local";
|
|
9844
|
+
this.nodeExecutor = options.nodeExecutor ?? (options.agentDefinitionRegistry ? createRuntimeAgentNodeExecutor({
|
|
9845
|
+
...options.agentNodeExecutorOptions,
|
|
9846
|
+
registry: options.agentDefinitionRegistry,
|
|
9847
|
+
runtimePolicy: options.runtimePolicy
|
|
9848
|
+
}) : void 0);
|
|
9470
9849
|
}
|
|
9471
9850
|
catalog;
|
|
9472
9851
|
eventLog;
|
|
9473
9852
|
handlers = /* @__PURE__ */ new Map();
|
|
9474
9853
|
sharedState;
|
|
9475
9854
|
runtimePolicy;
|
|
9855
|
+
runtimeContext;
|
|
9856
|
+
runtimeHostMode;
|
|
9476
9857
|
nodeExecutor;
|
|
9477
9858
|
registerHandler(workflowId, handler) {
|
|
9478
9859
|
if (!this.catalog.get(workflowId)) {
|
|
@@ -9487,6 +9868,7 @@ var WorkflowEngine = class {
|
|
|
9487
9868
|
return this.catalog.createPlan(workflowId, input, this.eventLog);
|
|
9488
9869
|
}
|
|
9489
9870
|
async run(request) {
|
|
9871
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "workflow.run");
|
|
9490
9872
|
const workflow = this.catalog.get(request.workflowId);
|
|
9491
9873
|
if (!workflow) {
|
|
9492
9874
|
throw new Error(`Unknown workflow: ${request.workflowId}`);
|
|
@@ -9606,7 +9988,14 @@ var AgentRuntime = class {
|
|
|
9606
9988
|
this.model = options.model ?? options.providerConfig?.model ?? getDefaultModel(options.providerType);
|
|
9607
9989
|
this.runtimeContext = options.runtimeContext ? createRuntimeRequestContext(options.runtimeContext) : void 0;
|
|
9608
9990
|
this.runtimePolicy = mergeRuntimePolicy(this.runtimeContext?.policy, options.runtimePolicy);
|
|
9609
|
-
this.
|
|
9991
|
+
this.runtimeHostMode = options.runtimeHostMode ?? "local";
|
|
9992
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "runtime.initialize");
|
|
9993
|
+
this.workflowEngine = options.workflowEngine ?? createWorkflowEngine(void 0, this.eventLog, {
|
|
9994
|
+
runtimePolicy: this.runtimePolicy,
|
|
9995
|
+
runtimeContext: this.runtimeContext,
|
|
9996
|
+
runtimeHostMode: this.runtimeHostMode,
|
|
9997
|
+
agentDefinitionRegistry: options.agentDefinitionRegistry
|
|
9998
|
+
});
|
|
9610
9999
|
}
|
|
9611
10000
|
options;
|
|
9612
10001
|
providerRegistry;
|
|
@@ -9622,6 +10011,9 @@ var AgentRuntime = class {
|
|
|
9622
10011
|
provider;
|
|
9623
10012
|
runtimeContext;
|
|
9624
10013
|
runtimePolicy;
|
|
10014
|
+
runtimeHostMode;
|
|
10015
|
+
requestTimestampsBySubject = /* @__PURE__ */ new Map();
|
|
10016
|
+
activeRuns = 0;
|
|
9625
10017
|
async initialize() {
|
|
9626
10018
|
const providerInjected = Boolean(this.options.provider);
|
|
9627
10019
|
const provider = this.options.provider ?? await this.providerRegistry.createProvider(this.providerType, {
|
|
@@ -9670,10 +10062,12 @@ var AgentRuntime = class {
|
|
|
9670
10062
|
},
|
|
9671
10063
|
modes: listAgentModes(),
|
|
9672
10064
|
context: this.runtimeContext,
|
|
9673
|
-
policy: this.runtimePolicy
|
|
10065
|
+
policy: this.runtimePolicy,
|
|
10066
|
+
hostMode: this.runtimeHostMode
|
|
9674
10067
|
};
|
|
9675
10068
|
}
|
|
9676
10069
|
createSession(options = {}) {
|
|
10070
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "session.create");
|
|
9677
10071
|
const session = this.runtimeSessionStore.create({
|
|
9678
10072
|
...options,
|
|
9679
10073
|
metadata: {
|
|
@@ -9697,6 +10091,27 @@ var AgentRuntime = class {
|
|
|
9697
10091
|
listSessions() {
|
|
9698
10092
|
return this.runtimeSessionStore.list();
|
|
9699
10093
|
}
|
|
10094
|
+
cleanupRetention(options = {}) {
|
|
10095
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "retention.cleanup");
|
|
10096
|
+
const dryRun = options.dryRun ?? true;
|
|
10097
|
+
const cutoffs = createRetentionCutoffs(this.runtimePolicy, options.now);
|
|
10098
|
+
const expiredSessionIds = cutoffs.conversationBefore ? this.runtimeSessionStore.list().filter((session) => session.updatedAt < cutoffs.conversationBefore).map((session) => session.id) : [];
|
|
10099
|
+
const deletedSessionIds = dryRun ? [] : expiredSessionIds.filter((id) => this.runtimeSessionStore.delete(id));
|
|
10100
|
+
this.eventLog.record("retention.cleanup", {
|
|
10101
|
+
dryRun,
|
|
10102
|
+
cutoffs,
|
|
10103
|
+
expiredSessionIds,
|
|
10104
|
+
deletedSessionIds,
|
|
10105
|
+
tenantId: this.runtimeContext?.tenant?.id,
|
|
10106
|
+
runtimeApi: true
|
|
10107
|
+
});
|
|
10108
|
+
return {
|
|
10109
|
+
dryRun,
|
|
10110
|
+
cutoffs,
|
|
10111
|
+
expiredSessionIds,
|
|
10112
|
+
deletedSessionIds
|
|
10113
|
+
};
|
|
10114
|
+
}
|
|
9700
10115
|
async runTurn(input) {
|
|
9701
10116
|
const provider = this.provider;
|
|
9702
10117
|
if (!provider) {
|
|
@@ -9707,6 +10122,12 @@ var AgentRuntime = class {
|
|
|
9707
10122
|
throw new Error(`Runtime session not found: ${input.sessionId}`);
|
|
9708
10123
|
}
|
|
9709
10124
|
const effectiveSession = input.mode && input.mode !== session.mode ? { ...session, mode: input.mode } : session;
|
|
10125
|
+
assertRuntimeTurnWithinPolicy(this.runtimePolicy, {
|
|
10126
|
+
subject: "turn.run",
|
|
10127
|
+
currentTurns: countUserTurns(effectiveSession),
|
|
10128
|
+
tenantId: this.runtimeContext?.tenant?.id
|
|
10129
|
+
});
|
|
10130
|
+
const releaseRuntimeRequest = this.beginRuntimeRequest("turn.run");
|
|
9710
10131
|
this.eventLog.record("turn.started", {
|
|
9711
10132
|
sessionId: effectiveSession.id,
|
|
9712
10133
|
provider: this.providerType,
|
|
@@ -9723,7 +10144,13 @@ var AgentRuntime = class {
|
|
|
9723
10144
|
permissionPolicy: this.permissionPolicy,
|
|
9724
10145
|
eventLog: this.eventLog
|
|
9725
10146
|
});
|
|
9726
|
-
|
|
10147
|
+
const estimatedCostUsd = this.estimateTurnCost(result);
|
|
10148
|
+
assertRuntimeUsageWithinPolicy(this.runtimePolicy, {
|
|
10149
|
+
...result.usage,
|
|
10150
|
+
estimatedCostUsd,
|
|
10151
|
+
tenantId: this.runtimeContext?.tenant?.id,
|
|
10152
|
+
subject: "turn.run"
|
|
10153
|
+
});
|
|
9727
10154
|
const updatedSession = this.runtimeSessionStore.update({
|
|
9728
10155
|
...effectiveSession,
|
|
9729
10156
|
messages: [
|
|
@@ -9740,6 +10167,7 @@ var AgentRuntime = class {
|
|
|
9740
10167
|
sessionId: updatedSession.id,
|
|
9741
10168
|
inputTokens: result.usage.inputTokens,
|
|
9742
10169
|
outputTokens: result.usage.outputTokens,
|
|
10170
|
+
estimatedCostUsd,
|
|
9743
10171
|
model: result.model,
|
|
9744
10172
|
runtimeApi: true
|
|
9745
10173
|
});
|
|
@@ -9751,6 +10179,8 @@ var AgentRuntime = class {
|
|
|
9751
10179
|
runtimeApi: true
|
|
9752
10180
|
});
|
|
9753
10181
|
throw error;
|
|
10182
|
+
} finally {
|
|
10183
|
+
releaseRuntimeRequest();
|
|
9754
10184
|
}
|
|
9755
10185
|
}
|
|
9756
10186
|
async *streamTurn(input) {
|
|
@@ -9763,6 +10193,12 @@ var AgentRuntime = class {
|
|
|
9763
10193
|
throw new Error(`Runtime session not found: ${input.sessionId}`);
|
|
9764
10194
|
}
|
|
9765
10195
|
const effectiveSession = input.mode && input.mode !== session.mode ? { ...session, mode: input.mode } : session;
|
|
10196
|
+
assertRuntimeTurnWithinPolicy(this.runtimePolicy, {
|
|
10197
|
+
subject: "turn.stream",
|
|
10198
|
+
currentTurns: countUserTurns(effectiveSession),
|
|
10199
|
+
tenantId: this.runtimeContext?.tenant?.id
|
|
10200
|
+
});
|
|
10201
|
+
const releaseRuntimeRequest = this.beginRuntimeRequest("turn.stream");
|
|
9766
10202
|
const messages = [
|
|
9767
10203
|
...effectiveSession.messages,
|
|
9768
10204
|
{
|
|
@@ -9812,7 +10248,13 @@ var AgentRuntime = class {
|
|
|
9812
10248
|
model: input.options?.model ?? this.getModel(),
|
|
9813
10249
|
mode: effectiveSession.mode
|
|
9814
10250
|
};
|
|
9815
|
-
|
|
10251
|
+
const estimatedCostUsd = this.estimateTurnCost(result);
|
|
10252
|
+
assertRuntimeUsageWithinPolicy(this.runtimePolicy, {
|
|
10253
|
+
...result.usage,
|
|
10254
|
+
estimatedCostUsd,
|
|
10255
|
+
tenantId: this.runtimeContext?.tenant?.id,
|
|
10256
|
+
subject: "turn.stream"
|
|
10257
|
+
});
|
|
9816
10258
|
const updatedSession = this.runtimeSessionStore.update({
|
|
9817
10259
|
...effectiveSession,
|
|
9818
10260
|
messages: [
|
|
@@ -9831,6 +10273,7 @@ var AgentRuntime = class {
|
|
|
9831
10273
|
sessionId: updatedSession.id,
|
|
9832
10274
|
inputTokens: result.usage.inputTokens,
|
|
9833
10275
|
outputTokens: result.usage.outputTokens,
|
|
10276
|
+
estimatedCostUsd,
|
|
9834
10277
|
model: result.model,
|
|
9835
10278
|
streaming: true,
|
|
9836
10279
|
runtimeApi: true
|
|
@@ -9860,9 +10303,11 @@ var AgentRuntime = class {
|
|
|
9860
10303
|
runtimeApi: true
|
|
9861
10304
|
});
|
|
9862
10305
|
}
|
|
10306
|
+
releaseRuntimeRequest();
|
|
9863
10307
|
}
|
|
9864
10308
|
}
|
|
9865
10309
|
async executeTool(input) {
|
|
10310
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "tool.execute");
|
|
9866
10311
|
const startedAt = performance.now();
|
|
9867
10312
|
const session = input.sessionId ? this.getSession(input.sessionId) : void 0;
|
|
9868
10313
|
if (input.sessionId && !session) {
|
|
@@ -9973,6 +10418,7 @@ var AgentRuntime = class {
|
|
|
9973
10418
|
};
|
|
9974
10419
|
}
|
|
9975
10420
|
assertToolAllowed(mode, toolName, input) {
|
|
10421
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "tool.assertAllowed");
|
|
9976
10422
|
const tool = this.toolRegistry.get(toolName);
|
|
9977
10423
|
if (!tool) {
|
|
9978
10424
|
this.eventLog.record("tool.blocked", {
|
|
@@ -10002,7 +10448,65 @@ var AgentRuntime = class {
|
|
|
10002
10448
|
});
|
|
10003
10449
|
return allowed;
|
|
10004
10450
|
}
|
|
10451
|
+
beginRuntimeRequest(subject) {
|
|
10452
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, subject);
|
|
10453
|
+
this.assertWithinRateLimit(subject);
|
|
10454
|
+
this.assertWithinConcurrencyLimit(subject);
|
|
10455
|
+
this.activeRuns += 1;
|
|
10456
|
+
let released = false;
|
|
10457
|
+
return () => {
|
|
10458
|
+
if (released) return;
|
|
10459
|
+
released = true;
|
|
10460
|
+
this.activeRuns = Math.max(0, this.activeRuns - 1);
|
|
10461
|
+
};
|
|
10462
|
+
}
|
|
10463
|
+
assertWithinRateLimit(subject) {
|
|
10464
|
+
const maxRequestsPerMinute = this.runtimePolicy?.rateLimit?.maxRequestsPerMinute;
|
|
10465
|
+
if (maxRequestsPerMinute === void 0) return;
|
|
10466
|
+
const now = Date.now();
|
|
10467
|
+
const windowStart = now - 6e4;
|
|
10468
|
+
const key = `${this.runtimeContext?.tenant?.id ?? "global"}:${subject}`;
|
|
10469
|
+
const recent = (this.requestTimestampsBySubject.get(key) ?? []).filter(
|
|
10470
|
+
(timestamp) => timestamp > windowStart
|
|
10471
|
+
);
|
|
10472
|
+
if (recent.length >= maxRequestsPerMinute) {
|
|
10473
|
+
this.requestTimestampsBySubject.set(key, recent);
|
|
10474
|
+
throw new RuntimePolicyViolation({
|
|
10475
|
+
code: "rate_limit_exceeded",
|
|
10476
|
+
subject,
|
|
10477
|
+
tenantId: this.runtimeContext?.tenant?.id,
|
|
10478
|
+
policyPath: "runtimePolicy.rateLimit.maxRequestsPerMinute",
|
|
10479
|
+
message: `Runtime policy rate limit exceeded: ${recent.length}/${maxRequestsPerMinute} requests per minute.`
|
|
10480
|
+
});
|
|
10481
|
+
}
|
|
10482
|
+
recent.push(now);
|
|
10483
|
+
this.requestTimestampsBySubject.set(key, recent);
|
|
10484
|
+
}
|
|
10485
|
+
assertWithinConcurrencyLimit(subject) {
|
|
10486
|
+
const maxConcurrentRuns = this.runtimePolicy?.rateLimit?.maxConcurrentRuns;
|
|
10487
|
+
if (maxConcurrentRuns === void 0) return;
|
|
10488
|
+
if (this.activeRuns >= maxConcurrentRuns) {
|
|
10489
|
+
throw new RuntimePolicyViolation({
|
|
10490
|
+
code: "concurrency_limit_exceeded",
|
|
10491
|
+
subject,
|
|
10492
|
+
tenantId: this.runtimeContext?.tenant?.id,
|
|
10493
|
+
policyPath: "runtimePolicy.rateLimit.maxConcurrentRuns",
|
|
10494
|
+
message: `Runtime policy concurrency limit exceeded: ${this.activeRuns}/${maxConcurrentRuns} active runs.`
|
|
10495
|
+
});
|
|
10496
|
+
}
|
|
10497
|
+
}
|
|
10498
|
+
estimateTurnCost(result) {
|
|
10499
|
+
return estimateCost(
|
|
10500
|
+
result.model,
|
|
10501
|
+
result.usage.inputTokens,
|
|
10502
|
+
result.usage.outputTokens,
|
|
10503
|
+
this.providerType
|
|
10504
|
+
).totalCost;
|
|
10505
|
+
}
|
|
10005
10506
|
};
|
|
10507
|
+
function countUserTurns(session) {
|
|
10508
|
+
return session.messages.filter((message) => message.role === "user").length;
|
|
10509
|
+
}
|
|
10006
10510
|
async function createAgentRuntime(options) {
|
|
10007
10511
|
const runtime = new AgentRuntime(options);
|
|
10008
10512
|
await runtime.initialize();
|