@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/cli/index.js
CHANGED
|
@@ -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" },
|
|
@@ -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()}`,
|
|
@@ -43773,7 +43807,7 @@ var NULL_EVENT_LOG = {
|
|
|
43773
43807
|
function graphNodeToTask(node, workflowInput) {
|
|
43774
43808
|
return {
|
|
43775
43809
|
id: node.id,
|
|
43776
|
-
role: node.agentRole ?? "coder",
|
|
43810
|
+
role: node.agentRole ?? mapLegacyAgentRole(node.id, "coder"),
|
|
43777
43811
|
objective: node.description,
|
|
43778
43812
|
context: {
|
|
43779
43813
|
workflowInput,
|
|
@@ -43920,6 +43954,20 @@ function readPath(input, path65) {
|
|
|
43920
43954
|
return void 0;
|
|
43921
43955
|
}, input);
|
|
43922
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
|
+
}
|
|
43923
43971
|
function cloneUnknown(value) {
|
|
43924
43972
|
if (value === void 0 || value === null) return value;
|
|
43925
43973
|
try {
|
|
@@ -43946,6 +43994,22 @@ function cloneArtifact(artifact) {
|
|
|
43946
43994
|
}
|
|
43947
43995
|
|
|
43948
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
|
+
};
|
|
43949
44013
|
function createRuntimeRequestContext(input = {}) {
|
|
43950
44014
|
return {
|
|
43951
44015
|
surface: input.surface ?? "api",
|
|
@@ -43988,6 +44052,27 @@ function runtimeContextToMetadata(context) {
|
|
|
43988
44052
|
dataClassification: context.policy?.dataBoundary?.classification
|
|
43989
44053
|
};
|
|
43990
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
|
+
}
|
|
43991
44076
|
function evaluateRuntimeToolPolicy(policy, input) {
|
|
43992
44077
|
if (policy?.allowedTools && !policy.allowedTools.includes(input.toolName)) {
|
|
43993
44078
|
return {
|
|
@@ -43996,7 +44081,7 @@ function evaluateRuntimeToolPolicy(policy, input) {
|
|
|
43996
44081
|
risk: input.risk
|
|
43997
44082
|
};
|
|
43998
44083
|
}
|
|
43999
|
-
if (policy?.maxToolRisk &&
|
|
44084
|
+
if (policy?.maxToolRisk && riskRank2(input.risk) > riskRank2(policy.maxToolRisk)) {
|
|
44000
44085
|
return {
|
|
44001
44086
|
allowed: false,
|
|
44002
44087
|
reason: `Runtime policy allows tools up to ${policy.maxToolRisk} risk; ${input.toolName} is ${input.risk}.`,
|
|
@@ -44014,7 +44099,7 @@ function evaluateRuntimeToolPolicy(policy, input) {
|
|
|
44014
44099
|
return { allowed: true, risk: input.risk };
|
|
44015
44100
|
}
|
|
44016
44101
|
function evaluateRuntimeRiskPolicy(policy, input) {
|
|
44017
|
-
if (policy?.maxToolRisk &&
|
|
44102
|
+
if (policy?.maxToolRisk && riskRank2(input.risk) > riskRank2(policy.maxToolRisk)) {
|
|
44018
44103
|
return {
|
|
44019
44104
|
allowed: false,
|
|
44020
44105
|
reason: `Runtime policy allows work up to ${policy.maxToolRisk} risk; ${input.subject} is ${input.risk}.`,
|
|
@@ -44031,24 +44116,66 @@ function evaluateRuntimeRiskPolicy(policy, input) {
|
|
|
44031
44116
|
}
|
|
44032
44117
|
return { allowed: true, risk: input.risk };
|
|
44033
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
|
+
}
|
|
44034
44131
|
function assertRuntimeUsageWithinPolicy(policy, usage) {
|
|
44035
44132
|
const budget = policy?.costBudget;
|
|
44133
|
+
const subject = usage.subject ?? "runtime usage";
|
|
44036
44134
|
if (!budget) return;
|
|
44037
44135
|
if (budget.maxInputTokens !== void 0 && (usage.inputTokens ?? 0) > budget.maxInputTokens) {
|
|
44038
|
-
throw new
|
|
44039
|
-
|
|
44040
|
-
|
|
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
|
+
});
|
|
44041
44143
|
}
|
|
44042
44144
|
if (budget.maxOutputTokens !== void 0 && (usage.outputTokens ?? 0) > budget.maxOutputTokens) {
|
|
44043
|
-
throw new
|
|
44044
|
-
|
|
44045
|
-
|
|
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
|
+
});
|
|
44046
44161
|
}
|
|
44047
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
|
+
}
|
|
44048
44171
|
function cloneRuntimePolicy(policy) {
|
|
44049
44172
|
return mergeRuntimePolicy(void 0, policy) ?? {};
|
|
44050
44173
|
}
|
|
44051
|
-
function
|
|
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) {
|
|
44052
44179
|
switch (risk) {
|
|
44053
44180
|
case "read-only":
|
|
44054
44181
|
return 0;
|
|
@@ -58697,6 +58824,7 @@ init_providers();
|
|
|
58697
58824
|
|
|
58698
58825
|
// src/runtime/agent-runtime.ts
|
|
58699
58826
|
init_env();
|
|
58827
|
+
init_pricing();
|
|
58700
58828
|
init_registry4();
|
|
58701
58829
|
|
|
58702
58830
|
// src/runtime/default-turn-runner.ts
|
|
@@ -58815,6 +58943,206 @@ function createRuntimeSessionStore() {
|
|
|
58815
58943
|
return new InMemoryRuntimeSessionStore();
|
|
58816
58944
|
}
|
|
58817
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
|
+
|
|
58818
59146
|
// src/runtime/workflow-registry.ts
|
|
58819
59147
|
function cloneWorkflow(workflow) {
|
|
58820
59148
|
return {
|
|
@@ -59144,14 +59472,22 @@ var WorkflowEngine = class {
|
|
|
59144
59472
|
this.catalog = catalog;
|
|
59145
59473
|
this.eventLog = eventLog;
|
|
59146
59474
|
this.sharedState = options.sharedState ?? new InMemorySharedWorkspaceStore();
|
|
59147
|
-
this.nodeExecutor = options.nodeExecutor;
|
|
59148
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);
|
|
59149
59483
|
}
|
|
59150
59484
|
catalog;
|
|
59151
59485
|
eventLog;
|
|
59152
59486
|
handlers = /* @__PURE__ */ new Map();
|
|
59153
59487
|
sharedState;
|
|
59154
59488
|
runtimePolicy;
|
|
59489
|
+
runtimeContext;
|
|
59490
|
+
runtimeHostMode;
|
|
59155
59491
|
nodeExecutor;
|
|
59156
59492
|
registerHandler(workflowId, handler) {
|
|
59157
59493
|
if (!this.catalog.get(workflowId)) {
|
|
@@ -59166,6 +59502,7 @@ var WorkflowEngine = class {
|
|
|
59166
59502
|
return this.catalog.createPlan(workflowId, input, this.eventLog);
|
|
59167
59503
|
}
|
|
59168
59504
|
async run(request) {
|
|
59505
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "workflow.run");
|
|
59169
59506
|
const workflow = this.catalog.get(request.workflowId);
|
|
59170
59507
|
if (!workflow) {
|
|
59171
59508
|
throw new Error(`Unknown workflow: ${request.workflowId}`);
|
|
@@ -59285,7 +59622,14 @@ var AgentRuntime = class {
|
|
|
59285
59622
|
this.model = options.model ?? options.providerConfig?.model ?? getDefaultModel(options.providerType);
|
|
59286
59623
|
this.runtimeContext = options.runtimeContext ? createRuntimeRequestContext(options.runtimeContext) : void 0;
|
|
59287
59624
|
this.runtimePolicy = mergeRuntimePolicy(this.runtimeContext?.policy, options.runtimePolicy);
|
|
59288
|
-
this.
|
|
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
|
+
});
|
|
59289
59633
|
}
|
|
59290
59634
|
options;
|
|
59291
59635
|
providerRegistry;
|
|
@@ -59301,6 +59645,9 @@ var AgentRuntime = class {
|
|
|
59301
59645
|
provider;
|
|
59302
59646
|
runtimeContext;
|
|
59303
59647
|
runtimePolicy;
|
|
59648
|
+
runtimeHostMode;
|
|
59649
|
+
requestTimestampsBySubject = /* @__PURE__ */ new Map();
|
|
59650
|
+
activeRuns = 0;
|
|
59304
59651
|
async initialize() {
|
|
59305
59652
|
const providerInjected = Boolean(this.options.provider);
|
|
59306
59653
|
const provider = this.options.provider ?? await this.providerRegistry.createProvider(this.providerType, {
|
|
@@ -59349,10 +59696,12 @@ var AgentRuntime = class {
|
|
|
59349
59696
|
},
|
|
59350
59697
|
modes: listAgentModes(),
|
|
59351
59698
|
context: this.runtimeContext,
|
|
59352
|
-
policy: this.runtimePolicy
|
|
59699
|
+
policy: this.runtimePolicy,
|
|
59700
|
+
hostMode: this.runtimeHostMode
|
|
59353
59701
|
};
|
|
59354
59702
|
}
|
|
59355
59703
|
createSession(options = {}) {
|
|
59704
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "session.create");
|
|
59356
59705
|
const session = this.runtimeSessionStore.create({
|
|
59357
59706
|
...options,
|
|
59358
59707
|
metadata: {
|
|
@@ -59376,6 +59725,27 @@ var AgentRuntime = class {
|
|
|
59376
59725
|
listSessions() {
|
|
59377
59726
|
return this.runtimeSessionStore.list();
|
|
59378
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
|
+
}
|
|
59379
59749
|
async runTurn(input) {
|
|
59380
59750
|
const provider = this.provider;
|
|
59381
59751
|
if (!provider) {
|
|
@@ -59386,6 +59756,12 @@ var AgentRuntime = class {
|
|
|
59386
59756
|
throw new Error(`Runtime session not found: ${input.sessionId}`);
|
|
59387
59757
|
}
|
|
59388
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");
|
|
59389
59765
|
this.eventLog.record("turn.started", {
|
|
59390
59766
|
sessionId: effectiveSession.id,
|
|
59391
59767
|
provider: this.providerType,
|
|
@@ -59402,7 +59778,13 @@ var AgentRuntime = class {
|
|
|
59402
59778
|
permissionPolicy: this.permissionPolicy,
|
|
59403
59779
|
eventLog: this.eventLog
|
|
59404
59780
|
});
|
|
59405
|
-
|
|
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
|
+
});
|
|
59406
59788
|
const updatedSession = this.runtimeSessionStore.update({
|
|
59407
59789
|
...effectiveSession,
|
|
59408
59790
|
messages: [
|
|
@@ -59419,6 +59801,7 @@ var AgentRuntime = class {
|
|
|
59419
59801
|
sessionId: updatedSession.id,
|
|
59420
59802
|
inputTokens: result.usage.inputTokens,
|
|
59421
59803
|
outputTokens: result.usage.outputTokens,
|
|
59804
|
+
estimatedCostUsd,
|
|
59422
59805
|
model: result.model,
|
|
59423
59806
|
runtimeApi: true
|
|
59424
59807
|
});
|
|
@@ -59430,6 +59813,8 @@ var AgentRuntime = class {
|
|
|
59430
59813
|
runtimeApi: true
|
|
59431
59814
|
});
|
|
59432
59815
|
throw error;
|
|
59816
|
+
} finally {
|
|
59817
|
+
releaseRuntimeRequest();
|
|
59433
59818
|
}
|
|
59434
59819
|
}
|
|
59435
59820
|
async *streamTurn(input) {
|
|
@@ -59442,6 +59827,12 @@ var AgentRuntime = class {
|
|
|
59442
59827
|
throw new Error(`Runtime session not found: ${input.sessionId}`);
|
|
59443
59828
|
}
|
|
59444
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");
|
|
59445
59836
|
const messages = [
|
|
59446
59837
|
...effectiveSession.messages,
|
|
59447
59838
|
{
|
|
@@ -59491,7 +59882,13 @@ var AgentRuntime = class {
|
|
|
59491
59882
|
model: input.options?.model ?? this.getModel(),
|
|
59492
59883
|
mode: effectiveSession.mode
|
|
59493
59884
|
};
|
|
59494
|
-
|
|
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
|
+
});
|
|
59495
59892
|
const updatedSession = this.runtimeSessionStore.update({
|
|
59496
59893
|
...effectiveSession,
|
|
59497
59894
|
messages: [
|
|
@@ -59510,6 +59907,7 @@ var AgentRuntime = class {
|
|
|
59510
59907
|
sessionId: updatedSession.id,
|
|
59511
59908
|
inputTokens: result.usage.inputTokens,
|
|
59512
59909
|
outputTokens: result.usage.outputTokens,
|
|
59910
|
+
estimatedCostUsd,
|
|
59513
59911
|
model: result.model,
|
|
59514
59912
|
streaming: true,
|
|
59515
59913
|
runtimeApi: true
|
|
@@ -59539,9 +59937,11 @@ var AgentRuntime = class {
|
|
|
59539
59937
|
runtimeApi: true
|
|
59540
59938
|
});
|
|
59541
59939
|
}
|
|
59940
|
+
releaseRuntimeRequest();
|
|
59542
59941
|
}
|
|
59543
59942
|
}
|
|
59544
59943
|
async executeTool(input) {
|
|
59944
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "tool.execute");
|
|
59545
59945
|
const startedAt = performance.now();
|
|
59546
59946
|
const session = input.sessionId ? this.getSession(input.sessionId) : void 0;
|
|
59547
59947
|
if (input.sessionId && !session) {
|
|
@@ -59652,6 +60052,7 @@ var AgentRuntime = class {
|
|
|
59652
60052
|
};
|
|
59653
60053
|
}
|
|
59654
60054
|
assertToolAllowed(mode, toolName, input) {
|
|
60055
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "tool.assertAllowed");
|
|
59655
60056
|
const tool = this.toolRegistry.get(toolName);
|
|
59656
60057
|
if (!tool) {
|
|
59657
60058
|
this.eventLog.record("tool.blocked", {
|
|
@@ -59681,7 +60082,65 @@ var AgentRuntime = class {
|
|
|
59681
60082
|
});
|
|
59682
60083
|
return allowed;
|
|
59683
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;
|
|
60139
|
+
}
|
|
59684
60140
|
};
|
|
60141
|
+
function countUserTurns(session) {
|
|
60142
|
+
return session.messages.filter((message) => message.role === "user").length;
|
|
60143
|
+
}
|
|
59685
60144
|
async function createAgentRuntime(options) {
|
|
59686
60145
|
const runtime = new AgentRuntime(options);
|
|
59687
60146
|
await runtime.initialize();
|