@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/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import * as path17 from 'path';
|
|
|
5
5
|
import path17__default, { dirname, join, basename, resolve } from 'path';
|
|
6
6
|
import * as fs16 from 'fs/promises';
|
|
7
7
|
import fs16__default, { access, readFile, readdir, writeFile, mkdir } from 'fs/promises';
|
|
8
|
-
import { randomUUID, randomBytes, createHash } from 'crypto';
|
|
8
|
+
import { randomUUID, createHmac, timingSafeEqual, randomBytes, createHash } from 'crypto';
|
|
9
9
|
import * as http from 'http';
|
|
10
10
|
import { createServer } from 'http';
|
|
11
11
|
import { fileURLToPath, URL as URL$1 } from 'url';
|
|
@@ -3411,8 +3411,8 @@ function fillPrompt(template, variables) {
|
|
|
3411
3411
|
let result = template;
|
|
3412
3412
|
for (const [key, value] of Object.entries(variables)) {
|
|
3413
3413
|
const placeholder = `{{${key}}}`;
|
|
3414
|
-
const
|
|
3415
|
-
result = result.replaceAll(placeholder,
|
|
3414
|
+
const stringValue2 = typeof value === "string" ? value : typeof value === "number" ? String(value) : JSON.stringify(value, null, 2);
|
|
3415
|
+
result = result.replaceAll(placeholder, stringValue2);
|
|
3416
3416
|
}
|
|
3417
3417
|
return result;
|
|
3418
3418
|
}
|
|
@@ -5341,8 +5341,8 @@ function fillPrompt2(template, variables) {
|
|
|
5341
5341
|
let result = template;
|
|
5342
5342
|
for (const [key, value] of Object.entries(variables)) {
|
|
5343
5343
|
const placeholder = `{{${key}}}`;
|
|
5344
|
-
const
|
|
5345
|
-
result = result.replaceAll(placeholder,
|
|
5344
|
+
const stringValue2 = typeof value === "string" ? value : typeof value === "number" ? String(value) : JSON.stringify(value, null, 2);
|
|
5345
|
+
result = result.replaceAll(placeholder, stringValue2);
|
|
5346
5346
|
}
|
|
5347
5347
|
return result;
|
|
5348
5348
|
}
|
|
@@ -10888,8 +10888,8 @@ function fillPrompt3(template, variables) {
|
|
|
10888
10888
|
let result = template;
|
|
10889
10889
|
for (const [key, value] of Object.entries(variables)) {
|
|
10890
10890
|
const placeholder = `{{${key}}}`;
|
|
10891
|
-
const
|
|
10892
|
-
result = result.replaceAll(placeholder,
|
|
10891
|
+
const stringValue2 = typeof value === "string" ? value : typeof value === "number" ? String(value) : JSON.stringify(value, null, 2);
|
|
10892
|
+
result = result.replaceAll(placeholder, stringValue2);
|
|
10893
10893
|
}
|
|
10894
10894
|
return result;
|
|
10895
10895
|
}
|
|
@@ -18456,7 +18456,50 @@ var VertexProvider = class {
|
|
|
18456
18456
|
|
|
18457
18457
|
// src/providers/pricing.ts
|
|
18458
18458
|
init_catalog();
|
|
18459
|
-
getCatalogModelPricingMap();
|
|
18459
|
+
var MODEL_PRICING = getCatalogModelPricingMap();
|
|
18460
|
+
var DEFAULT_PRICING = {
|
|
18461
|
+
anthropic: { inputPerMillion: 3, outputPerMillion: 15, contextWindow: 2e5 },
|
|
18462
|
+
openai: { inputPerMillion: 2.5, outputPerMillion: 10, contextWindow: 128e3 },
|
|
18463
|
+
codex: { inputPerMillion: 0, outputPerMillion: 0, contextWindow: 128e3 },
|
|
18464
|
+
// ChatGPT Plus/Pro subscription
|
|
18465
|
+
gemini: { inputPerMillion: 0.1, outputPerMillion: 0.4, contextWindow: 1e6 },
|
|
18466
|
+
vertex: { inputPerMillion: 0.1, outputPerMillion: 0.4, contextWindow: 1048576 },
|
|
18467
|
+
kimi: { inputPerMillion: 1.2, outputPerMillion: 1.2, contextWindow: 8192 },
|
|
18468
|
+
"kimi-code": { inputPerMillion: 0, outputPerMillion: 0, contextWindow: 131072 },
|
|
18469
|
+
// Included in subscription
|
|
18470
|
+
copilot: { inputPerMillion: 0, outputPerMillion: 0, contextWindow: 2e5 },
|
|
18471
|
+
// Included in subscription
|
|
18472
|
+
lmstudio: { inputPerMillion: 0, outputPerMillion: 0, contextWindow: 32768 },
|
|
18473
|
+
// Free - local models
|
|
18474
|
+
ollama: { inputPerMillion: 0, outputPerMillion: 0, contextWindow: 128e3 },
|
|
18475
|
+
// Free - local models
|
|
18476
|
+
groq: { inputPerMillion: 0.05, outputPerMillion: 0.08, contextWindow: 128e3 },
|
|
18477
|
+
// Free tier available
|
|
18478
|
+
openrouter: { inputPerMillion: 2, outputPerMillion: 8, contextWindow: 2e5 },
|
|
18479
|
+
// Varies by model
|
|
18480
|
+
mistral: { inputPerMillion: 0.25, outputPerMillion: 0.75, contextWindow: 32768 },
|
|
18481
|
+
deepseek: { inputPerMillion: 0.14, outputPerMillion: 0.28, contextWindow: 128e3 },
|
|
18482
|
+
// Very cheap
|
|
18483
|
+
together: { inputPerMillion: 0.2, outputPerMillion: 0.2, contextWindow: 32768 },
|
|
18484
|
+
huggingface: { inputPerMillion: 0, outputPerMillion: 0, contextWindow: 32768 },
|
|
18485
|
+
// Free tier
|
|
18486
|
+
qwen: { inputPerMillion: 0.3, outputPerMillion: 1.2, contextWindow: 131072 }
|
|
18487
|
+
// qwen-coder-plus pricing
|
|
18488
|
+
};
|
|
18489
|
+
function estimateCost(model2, inputTokens, outputTokens, provider) {
|
|
18490
|
+
const pricing = MODEL_PRICING[model2] ?? (provider ? DEFAULT_PRICING[provider] : DEFAULT_PRICING.anthropic);
|
|
18491
|
+
const inputCost = inputTokens / 1e6 * pricing.inputPerMillion;
|
|
18492
|
+
const outputCost = outputTokens / 1e6 * pricing.outputPerMillion;
|
|
18493
|
+
return {
|
|
18494
|
+
inputCost,
|
|
18495
|
+
outputCost,
|
|
18496
|
+
totalCost: inputCost + outputCost,
|
|
18497
|
+
inputTokens,
|
|
18498
|
+
outputTokens,
|
|
18499
|
+
model: model2,
|
|
18500
|
+
currency: "USD"
|
|
18501
|
+
};
|
|
18502
|
+
}
|
|
18460
18503
|
|
|
18461
18504
|
// src/providers/circuit-breaker.ts
|
|
18462
18505
|
init_errors();
|
|
@@ -19500,6 +19543,22 @@ function isAgentMode(value) {
|
|
|
19500
19543
|
}
|
|
19501
19544
|
|
|
19502
19545
|
// src/runtime/context.ts
|
|
19546
|
+
var RuntimePolicyViolation = class extends Error {
|
|
19547
|
+
code;
|
|
19548
|
+
subject;
|
|
19549
|
+
tenantId;
|
|
19550
|
+
policyPath;
|
|
19551
|
+
severity;
|
|
19552
|
+
constructor(input) {
|
|
19553
|
+
super(input.message);
|
|
19554
|
+
this.name = "RuntimePolicyViolation";
|
|
19555
|
+
this.code = input.code;
|
|
19556
|
+
this.subject = input.subject;
|
|
19557
|
+
this.tenantId = input.tenantId;
|
|
19558
|
+
this.policyPath = input.policyPath;
|
|
19559
|
+
this.severity = input.severity ?? "blocked";
|
|
19560
|
+
}
|
|
19561
|
+
};
|
|
19503
19562
|
function createRuntimeRequestContext(input = {}) {
|
|
19504
19563
|
return {
|
|
19505
19564
|
surface: input.surface ?? "api",
|
|
@@ -19542,6 +19601,27 @@ function runtimeContextToMetadata(context) {
|
|
|
19542
19601
|
dataClassification: context.policy?.dataBoundary?.classification
|
|
19543
19602
|
};
|
|
19544
19603
|
}
|
|
19604
|
+
function createRuntimeTenantBoundary(context, hostMode = "local") {
|
|
19605
|
+
return {
|
|
19606
|
+
hostMode,
|
|
19607
|
+
surface: context?.surface ?? "api",
|
|
19608
|
+
tenantId: context?.tenant?.id,
|
|
19609
|
+
required: hostMode === "hosted" && context?.surface !== "cli"
|
|
19610
|
+
};
|
|
19611
|
+
}
|
|
19612
|
+
function assertRuntimeTenantBoundary(context, hostMode = "local", subject = "runtime operation") {
|
|
19613
|
+
const boundary = createRuntimeTenantBoundary(context, hostMode);
|
|
19614
|
+
if (boundary.required && !boundary.tenantId) {
|
|
19615
|
+
throw new RuntimePolicyViolation({
|
|
19616
|
+
code: "tenant_required",
|
|
19617
|
+
subject,
|
|
19618
|
+
tenantId: boundary.tenantId,
|
|
19619
|
+
policyPath: "runtimeContext.tenant.id",
|
|
19620
|
+
message: `Runtime tenant is required for hosted ${boundary.surface} operations.`
|
|
19621
|
+
});
|
|
19622
|
+
}
|
|
19623
|
+
return boundary;
|
|
19624
|
+
}
|
|
19545
19625
|
function evaluateRuntimeToolPolicy(policy, input) {
|
|
19546
19626
|
if (policy?.allowedTools && !policy.allowedTools.includes(input.toolName)) {
|
|
19547
19627
|
return {
|
|
@@ -19585,23 +19665,65 @@ function evaluateRuntimeRiskPolicy(policy, input) {
|
|
|
19585
19665
|
}
|
|
19586
19666
|
return { allowed: true, risk: input.risk };
|
|
19587
19667
|
}
|
|
19668
|
+
function assertRuntimeTurnWithinPolicy(policy, input) {
|
|
19669
|
+
const maxTurns = policy?.costBudget?.maxTurns;
|
|
19670
|
+
if (maxTurns !== void 0 && input.currentTurns >= maxTurns) {
|
|
19671
|
+
throw new RuntimePolicyViolation({
|
|
19672
|
+
code: "max_turns_exceeded",
|
|
19673
|
+
subject: input.subject,
|
|
19674
|
+
tenantId: input.tenantId,
|
|
19675
|
+
policyPath: "runtimePolicy.costBudget.maxTurns",
|
|
19676
|
+
message: `Runtime policy turn budget exceeded: ${input.currentTurns}/${maxTurns}`
|
|
19677
|
+
});
|
|
19678
|
+
}
|
|
19679
|
+
}
|
|
19588
19680
|
function assertRuntimeUsageWithinPolicy(policy, usage) {
|
|
19589
19681
|
const budget = policy?.costBudget;
|
|
19682
|
+
const subject = usage.subject ?? "runtime usage";
|
|
19590
19683
|
if (!budget) return;
|
|
19591
19684
|
if (budget.maxInputTokens !== void 0 && (usage.inputTokens ?? 0) > budget.maxInputTokens) {
|
|
19592
|
-
throw new
|
|
19593
|
-
|
|
19594
|
-
|
|
19685
|
+
throw new RuntimePolicyViolation({
|
|
19686
|
+
code: "input_tokens_exceeded",
|
|
19687
|
+
subject,
|
|
19688
|
+
tenantId: usage.tenantId,
|
|
19689
|
+
policyPath: "runtimePolicy.costBudget.maxInputTokens",
|
|
19690
|
+
message: `Runtime policy input token budget exceeded: ${usage.inputTokens ?? 0}/${budget.maxInputTokens}`
|
|
19691
|
+
});
|
|
19595
19692
|
}
|
|
19596
19693
|
if (budget.maxOutputTokens !== void 0 && (usage.outputTokens ?? 0) > budget.maxOutputTokens) {
|
|
19597
|
-
throw new
|
|
19598
|
-
|
|
19599
|
-
|
|
19694
|
+
throw new RuntimePolicyViolation({
|
|
19695
|
+
code: "output_tokens_exceeded",
|
|
19696
|
+
subject,
|
|
19697
|
+
tenantId: usage.tenantId,
|
|
19698
|
+
policyPath: "runtimePolicy.costBudget.maxOutputTokens",
|
|
19699
|
+
message: `Runtime policy output token budget exceeded: ${usage.outputTokens ?? 0}/${budget.maxOutputTokens}`
|
|
19700
|
+
});
|
|
19701
|
+
}
|
|
19702
|
+
if (budget.maxEstimatedCostUsd !== void 0 && (usage.estimatedCostUsd ?? 0) > budget.maxEstimatedCostUsd) {
|
|
19703
|
+
throw new RuntimePolicyViolation({
|
|
19704
|
+
code: "estimated_cost_exceeded",
|
|
19705
|
+
subject,
|
|
19706
|
+
tenantId: usage.tenantId,
|
|
19707
|
+
policyPath: "runtimePolicy.costBudget.maxEstimatedCostUsd",
|
|
19708
|
+
message: `Runtime policy estimated cost budget exceeded: ${usage.estimatedCostUsd ?? 0}/${budget.maxEstimatedCostUsd}`
|
|
19709
|
+
});
|
|
19600
19710
|
}
|
|
19601
19711
|
}
|
|
19712
|
+
function createRetentionCutoffs(policy, now = /* @__PURE__ */ new Date()) {
|
|
19713
|
+
const retention = policy?.retention;
|
|
19714
|
+
return {
|
|
19715
|
+
conversationBefore: cutoffIso(now, retention?.conversationDays),
|
|
19716
|
+
eventBefore: cutoffIso(now, retention?.eventDays),
|
|
19717
|
+
artifactBefore: cutoffIso(now, retention?.artifactDays)
|
|
19718
|
+
};
|
|
19719
|
+
}
|
|
19602
19720
|
function cloneRuntimePolicy(policy) {
|
|
19603
19721
|
return mergeRuntimePolicy(void 0, policy) ?? {};
|
|
19604
19722
|
}
|
|
19723
|
+
function cutoffIso(now, days) {
|
|
19724
|
+
if (days === void 0) return void 0;
|
|
19725
|
+
return new Date(now.getTime() - days * 24 * 60 * 60 * 1e3).toISOString();
|
|
19726
|
+
}
|
|
19605
19727
|
function riskRank(risk) {
|
|
19606
19728
|
switch (risk) {
|
|
19607
19729
|
case "read-only":
|
|
@@ -20043,6 +20165,7 @@ var LEGACY_ROLE_MAPPINGS = [
|
|
|
20043
20165
|
{ legacy: "coder", role: "coder", reason: "legacy executor role" },
|
|
20044
20166
|
{ legacy: "test", role: "tester", reason: "test authoring/execution" },
|
|
20045
20167
|
{ legacy: "tester", role: "tester", reason: "legacy executor role" },
|
|
20168
|
+
{ legacy: "verifier", role: "tester", reason: "verification maps to tester capability" },
|
|
20046
20169
|
{ legacy: "tdd", role: "tester", reason: "test-first implementation" },
|
|
20047
20170
|
{ legacy: "e2e", role: "tester", reason: "end-to-end testing" },
|
|
20048
20171
|
{ legacy: "review", role: "reviewer", reason: "code review" },
|
|
@@ -20778,7 +20901,7 @@ var NULL_EVENT_LOG = {
|
|
|
20778
20901
|
function graphNodeToTask(node, workflowInput) {
|
|
20779
20902
|
return {
|
|
20780
20903
|
id: node.id,
|
|
20781
|
-
role: node.agentRole ?? "coder",
|
|
20904
|
+
role: node.agentRole ?? mapLegacyAgentRole(node.id, "coder"),
|
|
20782
20905
|
objective: node.description,
|
|
20783
20906
|
context: {
|
|
20784
20907
|
workflowInput,
|
|
@@ -20964,6 +21087,239 @@ function cloneArtifact(artifact) {
|
|
|
20964
21087
|
};
|
|
20965
21088
|
}
|
|
20966
21089
|
|
|
21090
|
+
// src/runtime/agent-runner.ts
|
|
21091
|
+
var AgentRunner = class {
|
|
21092
|
+
constructor(options = {}) {
|
|
21093
|
+
this.options = options;
|
|
21094
|
+
}
|
|
21095
|
+
options;
|
|
21096
|
+
async run(input) {
|
|
21097
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21098
|
+
const trace = input.trace ?? createAgentTraceContext({ taskId: input.task.id });
|
|
21099
|
+
this.options.eventLog?.record("agent.started", {
|
|
21100
|
+
taskId: input.task.id,
|
|
21101
|
+
role: input.task.role,
|
|
21102
|
+
trace
|
|
21103
|
+
});
|
|
21104
|
+
try {
|
|
21105
|
+
const raw = await (this.options.executor ?? defaultExecutor)({
|
|
21106
|
+
task: input.task,
|
|
21107
|
+
capability: input.capability,
|
|
21108
|
+
trace,
|
|
21109
|
+
assertToolAllowed: (toolName) => {
|
|
21110
|
+
const decision = evaluateAgentToolPolicy({
|
|
21111
|
+
capability: input.capability,
|
|
21112
|
+
toolName,
|
|
21113
|
+
manifest: input.toolRiskManifest
|
|
21114
|
+
});
|
|
21115
|
+
this.options.eventLog?.record("agent.tool.called", {
|
|
21116
|
+
taskId: input.task.id,
|
|
21117
|
+
role: input.task.role,
|
|
21118
|
+
toolName,
|
|
21119
|
+
decision,
|
|
21120
|
+
trace
|
|
21121
|
+
});
|
|
21122
|
+
if (!decision.allowed) {
|
|
21123
|
+
throw new Error(decision.reason ?? `Tool '${toolName}' is not allowed.`);
|
|
21124
|
+
}
|
|
21125
|
+
}
|
|
21126
|
+
});
|
|
21127
|
+
const result = normalizeAgentRunResult({
|
|
21128
|
+
id: `${input.task.id}-run-${Date.now().toString(36)}`,
|
|
21129
|
+
taskId: input.task.id,
|
|
21130
|
+
role: input.task.role,
|
|
21131
|
+
success: raw.success ?? true,
|
|
21132
|
+
output: raw.output,
|
|
21133
|
+
turns: raw.turns,
|
|
21134
|
+
toolsUsed: raw.toolsUsed,
|
|
21135
|
+
usage: {
|
|
21136
|
+
inputTokens: raw.inputTokens ?? 0,
|
|
21137
|
+
outputTokens: raw.outputTokens ?? 0,
|
|
21138
|
+
estimated: raw.inputTokens === void 0 || raw.outputTokens === void 0
|
|
21139
|
+
},
|
|
21140
|
+
startedAt,
|
|
21141
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
21142
|
+
durationMs: Date.now() - Date.parse(startedAt),
|
|
21143
|
+
error: raw.error,
|
|
21144
|
+
metadata: { ...raw.metadata, trace }
|
|
21145
|
+
});
|
|
21146
|
+
this.options.eventLog?.record(result.success ? "agent.completed" : "agent.failed", {
|
|
21147
|
+
taskId: input.task.id,
|
|
21148
|
+
role: input.task.role,
|
|
21149
|
+
agentRunId: result.id,
|
|
21150
|
+
trace,
|
|
21151
|
+
error: result.error
|
|
21152
|
+
});
|
|
21153
|
+
return result;
|
|
21154
|
+
} catch (error) {
|
|
21155
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
21156
|
+
const result = normalizeAgentRunResult({
|
|
21157
|
+
id: `${input.task.id}-run-${Date.now().toString(36)}`,
|
|
21158
|
+
taskId: input.task.id,
|
|
21159
|
+
role: input.task.role,
|
|
21160
|
+
success: false,
|
|
21161
|
+
output: message,
|
|
21162
|
+
startedAt,
|
|
21163
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
21164
|
+
durationMs: Date.now() - Date.parse(startedAt),
|
|
21165
|
+
error: message,
|
|
21166
|
+
metadata: { trace }
|
|
21167
|
+
});
|
|
21168
|
+
this.options.eventLog?.record("agent.failed", {
|
|
21169
|
+
taskId: input.task.id,
|
|
21170
|
+
role: input.task.role,
|
|
21171
|
+
agentRunId: result.id,
|
|
21172
|
+
trace,
|
|
21173
|
+
error: message
|
|
21174
|
+
});
|
|
21175
|
+
return result;
|
|
21176
|
+
}
|
|
21177
|
+
}
|
|
21178
|
+
};
|
|
21179
|
+
function createAgentRunner(options) {
|
|
21180
|
+
return new AgentRunner(options);
|
|
21181
|
+
}
|
|
21182
|
+
async function defaultExecutor(context) {
|
|
21183
|
+
return {
|
|
21184
|
+
output: `Agent ${context.capability.role} accepted task '${context.task.objective}'.`
|
|
21185
|
+
};
|
|
21186
|
+
}
|
|
21187
|
+
|
|
21188
|
+
// src/runtime/runtime-agent-node-executor.ts
|
|
21189
|
+
var AgentDefinitionRegistry = class {
|
|
21190
|
+
definitionsByRole = /* @__PURE__ */ new Map();
|
|
21191
|
+
definitionsById = /* @__PURE__ */ new Map();
|
|
21192
|
+
constructor(definitions = []) {
|
|
21193
|
+
for (const definition of definitions) {
|
|
21194
|
+
this.register(definition);
|
|
21195
|
+
}
|
|
21196
|
+
}
|
|
21197
|
+
register(definition) {
|
|
21198
|
+
this.definitionsById.set(definition.id, cloneDefinition(definition));
|
|
21199
|
+
this.definitionsByRole.set(definition.role, cloneDefinition(definition));
|
|
21200
|
+
}
|
|
21201
|
+
get(id) {
|
|
21202
|
+
const definition = this.definitionsById.get(id);
|
|
21203
|
+
return definition ? cloneDefinition(definition) : void 0;
|
|
21204
|
+
}
|
|
21205
|
+
getByRole(role) {
|
|
21206
|
+
const definition = this.definitionsByRole.get(role);
|
|
21207
|
+
return definition ? cloneDefinition(definition) : void 0;
|
|
21208
|
+
}
|
|
21209
|
+
list() {
|
|
21210
|
+
return [...this.definitionsById.values()].map(cloneDefinition);
|
|
21211
|
+
}
|
|
21212
|
+
};
|
|
21213
|
+
var RuntimeAgentNodeExecutor = class {
|
|
21214
|
+
constructor(options) {
|
|
21215
|
+
this.options = options;
|
|
21216
|
+
this.runner = options.runner ?? new AgentRunner(options.runnerOptions);
|
|
21217
|
+
}
|
|
21218
|
+
options;
|
|
21219
|
+
runner;
|
|
21220
|
+
execute = async (execution) => {
|
|
21221
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
21222
|
+
const definition = this.options.registry.getByRole(execution.task.role);
|
|
21223
|
+
if (!definition) {
|
|
21224
|
+
return normalizeAgentRunResult({
|
|
21225
|
+
id: `${execution.workflowRunId}-${execution.node.id}-missing-definition`,
|
|
21226
|
+
taskId: execution.task.id,
|
|
21227
|
+
role: execution.task.role,
|
|
21228
|
+
success: false,
|
|
21229
|
+
output: "",
|
|
21230
|
+
startedAt,
|
|
21231
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
21232
|
+
error: `No agent definition registered for role '${execution.task.role}'.`,
|
|
21233
|
+
metadata: {
|
|
21234
|
+
workflowRunId: execution.workflowRunId,
|
|
21235
|
+
nodeId: execution.node.id,
|
|
21236
|
+
trace: execution.trace
|
|
21237
|
+
}
|
|
21238
|
+
});
|
|
21239
|
+
}
|
|
21240
|
+
const blockedTool = this.findBlockedTool(definition, execution);
|
|
21241
|
+
if (blockedTool) {
|
|
21242
|
+
return normalizeAgentRunResult({
|
|
21243
|
+
id: `${execution.workflowRunId}-${execution.node.id}-policy-blocked`,
|
|
21244
|
+
taskId: execution.task.id,
|
|
21245
|
+
role: execution.task.role,
|
|
21246
|
+
success: false,
|
|
21247
|
+
output: "",
|
|
21248
|
+
startedAt,
|
|
21249
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
21250
|
+
error: blockedTool,
|
|
21251
|
+
metadata: {
|
|
21252
|
+
workflowRunId: execution.workflowRunId,
|
|
21253
|
+
nodeId: execution.node.id,
|
|
21254
|
+
agentDefinitionId: definition.id,
|
|
21255
|
+
trace: execution.trace
|
|
21256
|
+
}
|
|
21257
|
+
});
|
|
21258
|
+
}
|
|
21259
|
+
const input = {
|
|
21260
|
+
task: {
|
|
21261
|
+
...execution.task,
|
|
21262
|
+
context: {
|
|
21263
|
+
...execution.task.context,
|
|
21264
|
+
instructions: definition.instructions,
|
|
21265
|
+
sharedState: execution.sharedState.readForRole(definition.role)
|
|
21266
|
+
}
|
|
21267
|
+
},
|
|
21268
|
+
capability: definition.capability,
|
|
21269
|
+
trace: execution.trace,
|
|
21270
|
+
toolRiskManifest: this.options.toolRiskManifest
|
|
21271
|
+
};
|
|
21272
|
+
const result = await this.runner.run(input);
|
|
21273
|
+
return normalizeAgentRunResult({
|
|
21274
|
+
...result,
|
|
21275
|
+
metadata: {
|
|
21276
|
+
...result.metadata,
|
|
21277
|
+
workflowRunId: execution.workflowRunId,
|
|
21278
|
+
nodeId: execution.node.id,
|
|
21279
|
+
agentDefinitionId: definition.id
|
|
21280
|
+
}
|
|
21281
|
+
});
|
|
21282
|
+
};
|
|
21283
|
+
findBlockedTool(definition, execution) {
|
|
21284
|
+
for (const toolName of execution.node.requiredTools ?? []) {
|
|
21285
|
+
const agentDecision = evaluateAgentToolPolicy({
|
|
21286
|
+
capability: definition.capability,
|
|
21287
|
+
toolName,
|
|
21288
|
+
manifest: this.options.toolRiskManifest
|
|
21289
|
+
});
|
|
21290
|
+
execution.eventLog.record("agent.tool.called", {
|
|
21291
|
+
workflowRunId: execution.workflowRunId,
|
|
21292
|
+
nodeId: execution.node.id,
|
|
21293
|
+
taskId: execution.task.id,
|
|
21294
|
+
role: execution.task.role,
|
|
21295
|
+
toolName,
|
|
21296
|
+
decision: agentDecision,
|
|
21297
|
+
trace: execution.trace
|
|
21298
|
+
});
|
|
21299
|
+
if (!agentDecision.allowed) {
|
|
21300
|
+
return agentDecision.reason ?? `Tool '${toolName}' is not allowed for agent.`;
|
|
21301
|
+
}
|
|
21302
|
+
const runtimeDecision = evaluateRuntimeToolPolicy(this.options.runtimePolicy, {
|
|
21303
|
+
toolName,
|
|
21304
|
+
risk: agentDecision.risk
|
|
21305
|
+
});
|
|
21306
|
+
if (!runtimeDecision.allowed) {
|
|
21307
|
+
return runtimeDecision.reason ?? `Tool '${toolName}' is blocked by runtime policy.`;
|
|
21308
|
+
}
|
|
21309
|
+
}
|
|
21310
|
+
return void 0;
|
|
21311
|
+
}
|
|
21312
|
+
};
|
|
21313
|
+
function createAgentDefinitionRegistry(definitions = []) {
|
|
21314
|
+
return new AgentDefinitionRegistry(definitions);
|
|
21315
|
+
}
|
|
21316
|
+
function createRuntimeAgentNodeExecutor(options) {
|
|
21317
|
+
return new RuntimeAgentNodeExecutor(options).execute;
|
|
21318
|
+
}
|
|
21319
|
+
function cloneDefinition(definition) {
|
|
21320
|
+
return structuredClone(definition);
|
|
21321
|
+
}
|
|
21322
|
+
|
|
20967
21323
|
// src/runtime/workflow-registry.ts
|
|
20968
21324
|
function cloneWorkflow(workflow) {
|
|
20969
21325
|
return {
|
|
@@ -21297,14 +21653,22 @@ var WorkflowEngine = class {
|
|
|
21297
21653
|
this.catalog = catalog;
|
|
21298
21654
|
this.eventLog = eventLog;
|
|
21299
21655
|
this.sharedState = options.sharedState ?? new InMemorySharedWorkspaceStore();
|
|
21300
|
-
this.nodeExecutor = options.nodeExecutor;
|
|
21301
21656
|
this.runtimePolicy = options.runtimePolicy;
|
|
21657
|
+
this.runtimeContext = options.runtimeContext;
|
|
21658
|
+
this.runtimeHostMode = options.runtimeHostMode ?? "local";
|
|
21659
|
+
this.nodeExecutor = options.nodeExecutor ?? (options.agentDefinitionRegistry ? createRuntimeAgentNodeExecutor({
|
|
21660
|
+
...options.agentNodeExecutorOptions,
|
|
21661
|
+
registry: options.agentDefinitionRegistry,
|
|
21662
|
+
runtimePolicy: options.runtimePolicy
|
|
21663
|
+
}) : void 0);
|
|
21302
21664
|
}
|
|
21303
21665
|
catalog;
|
|
21304
21666
|
eventLog;
|
|
21305
21667
|
handlers = /* @__PURE__ */ new Map();
|
|
21306
21668
|
sharedState;
|
|
21307
21669
|
runtimePolicy;
|
|
21670
|
+
runtimeContext;
|
|
21671
|
+
runtimeHostMode;
|
|
21308
21672
|
nodeExecutor;
|
|
21309
21673
|
registerHandler(workflowId, handler) {
|
|
21310
21674
|
if (!this.catalog.get(workflowId)) {
|
|
@@ -21319,6 +21683,7 @@ var WorkflowEngine = class {
|
|
|
21319
21683
|
return this.catalog.createPlan(workflowId, input, this.eventLog);
|
|
21320
21684
|
}
|
|
21321
21685
|
async run(request) {
|
|
21686
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "workflow.run");
|
|
21322
21687
|
const workflow = this.catalog.get(request.workflowId);
|
|
21323
21688
|
if (!workflow) {
|
|
21324
21689
|
throw new Error(`Unknown workflow: ${request.workflowId}`);
|
|
@@ -21438,7 +21803,14 @@ var AgentRuntime = class {
|
|
|
21438
21803
|
this.model = options.model ?? options.providerConfig?.model ?? getDefaultModel(options.providerType);
|
|
21439
21804
|
this.runtimeContext = options.runtimeContext ? createRuntimeRequestContext(options.runtimeContext) : void 0;
|
|
21440
21805
|
this.runtimePolicy = mergeRuntimePolicy(this.runtimeContext?.policy, options.runtimePolicy);
|
|
21441
|
-
this.
|
|
21806
|
+
this.runtimeHostMode = options.runtimeHostMode ?? "local";
|
|
21807
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "runtime.initialize");
|
|
21808
|
+
this.workflowEngine = options.workflowEngine ?? createWorkflowEngine(void 0, this.eventLog, {
|
|
21809
|
+
runtimePolicy: this.runtimePolicy,
|
|
21810
|
+
runtimeContext: this.runtimeContext,
|
|
21811
|
+
runtimeHostMode: this.runtimeHostMode,
|
|
21812
|
+
agentDefinitionRegistry: options.agentDefinitionRegistry
|
|
21813
|
+
});
|
|
21442
21814
|
}
|
|
21443
21815
|
options;
|
|
21444
21816
|
providerRegistry;
|
|
@@ -21454,6 +21826,9 @@ var AgentRuntime = class {
|
|
|
21454
21826
|
provider;
|
|
21455
21827
|
runtimeContext;
|
|
21456
21828
|
runtimePolicy;
|
|
21829
|
+
runtimeHostMode;
|
|
21830
|
+
requestTimestampsBySubject = /* @__PURE__ */ new Map();
|
|
21831
|
+
activeRuns = 0;
|
|
21457
21832
|
async initialize() {
|
|
21458
21833
|
const providerInjected = Boolean(this.options.provider);
|
|
21459
21834
|
const provider = this.options.provider ?? await this.providerRegistry.createProvider(this.providerType, {
|
|
@@ -21502,10 +21877,12 @@ var AgentRuntime = class {
|
|
|
21502
21877
|
},
|
|
21503
21878
|
modes: listAgentModes(),
|
|
21504
21879
|
context: this.runtimeContext,
|
|
21505
|
-
policy: this.runtimePolicy
|
|
21880
|
+
policy: this.runtimePolicy,
|
|
21881
|
+
hostMode: this.runtimeHostMode
|
|
21506
21882
|
};
|
|
21507
21883
|
}
|
|
21508
21884
|
createSession(options = {}) {
|
|
21885
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "session.create");
|
|
21509
21886
|
const session = this.runtimeSessionStore.create({
|
|
21510
21887
|
...options,
|
|
21511
21888
|
metadata: {
|
|
@@ -21529,6 +21906,27 @@ var AgentRuntime = class {
|
|
|
21529
21906
|
listSessions() {
|
|
21530
21907
|
return this.runtimeSessionStore.list();
|
|
21531
21908
|
}
|
|
21909
|
+
cleanupRetention(options = {}) {
|
|
21910
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "retention.cleanup");
|
|
21911
|
+
const dryRun = options.dryRun ?? true;
|
|
21912
|
+
const cutoffs = createRetentionCutoffs(this.runtimePolicy, options.now);
|
|
21913
|
+
const expiredSessionIds = cutoffs.conversationBefore ? this.runtimeSessionStore.list().filter((session) => session.updatedAt < cutoffs.conversationBefore).map((session) => session.id) : [];
|
|
21914
|
+
const deletedSessionIds = dryRun ? [] : expiredSessionIds.filter((id) => this.runtimeSessionStore.delete(id));
|
|
21915
|
+
this.eventLog.record("retention.cleanup", {
|
|
21916
|
+
dryRun,
|
|
21917
|
+
cutoffs,
|
|
21918
|
+
expiredSessionIds,
|
|
21919
|
+
deletedSessionIds,
|
|
21920
|
+
tenantId: this.runtimeContext?.tenant?.id,
|
|
21921
|
+
runtimeApi: true
|
|
21922
|
+
});
|
|
21923
|
+
return {
|
|
21924
|
+
dryRun,
|
|
21925
|
+
cutoffs,
|
|
21926
|
+
expiredSessionIds,
|
|
21927
|
+
deletedSessionIds
|
|
21928
|
+
};
|
|
21929
|
+
}
|
|
21532
21930
|
async runTurn(input) {
|
|
21533
21931
|
const provider = this.provider;
|
|
21534
21932
|
if (!provider) {
|
|
@@ -21539,6 +21937,12 @@ var AgentRuntime = class {
|
|
|
21539
21937
|
throw new Error(`Runtime session not found: ${input.sessionId}`);
|
|
21540
21938
|
}
|
|
21541
21939
|
const effectiveSession = input.mode && input.mode !== session.mode ? { ...session, mode: input.mode } : session;
|
|
21940
|
+
assertRuntimeTurnWithinPolicy(this.runtimePolicy, {
|
|
21941
|
+
subject: "turn.run",
|
|
21942
|
+
currentTurns: countUserTurns(effectiveSession),
|
|
21943
|
+
tenantId: this.runtimeContext?.tenant?.id
|
|
21944
|
+
});
|
|
21945
|
+
const releaseRuntimeRequest = this.beginRuntimeRequest("turn.run");
|
|
21542
21946
|
this.eventLog.record("turn.started", {
|
|
21543
21947
|
sessionId: effectiveSession.id,
|
|
21544
21948
|
provider: this.providerType,
|
|
@@ -21555,7 +21959,13 @@ var AgentRuntime = class {
|
|
|
21555
21959
|
permissionPolicy: this.permissionPolicy,
|
|
21556
21960
|
eventLog: this.eventLog
|
|
21557
21961
|
});
|
|
21558
|
-
|
|
21962
|
+
const estimatedCostUsd = this.estimateTurnCost(result);
|
|
21963
|
+
assertRuntimeUsageWithinPolicy(this.runtimePolicy, {
|
|
21964
|
+
...result.usage,
|
|
21965
|
+
estimatedCostUsd,
|
|
21966
|
+
tenantId: this.runtimeContext?.tenant?.id,
|
|
21967
|
+
subject: "turn.run"
|
|
21968
|
+
});
|
|
21559
21969
|
const updatedSession = this.runtimeSessionStore.update({
|
|
21560
21970
|
...effectiveSession,
|
|
21561
21971
|
messages: [
|
|
@@ -21572,6 +21982,7 @@ var AgentRuntime = class {
|
|
|
21572
21982
|
sessionId: updatedSession.id,
|
|
21573
21983
|
inputTokens: result.usage.inputTokens,
|
|
21574
21984
|
outputTokens: result.usage.outputTokens,
|
|
21985
|
+
estimatedCostUsd,
|
|
21575
21986
|
model: result.model,
|
|
21576
21987
|
runtimeApi: true
|
|
21577
21988
|
});
|
|
@@ -21583,6 +21994,8 @@ var AgentRuntime = class {
|
|
|
21583
21994
|
runtimeApi: true
|
|
21584
21995
|
});
|
|
21585
21996
|
throw error;
|
|
21997
|
+
} finally {
|
|
21998
|
+
releaseRuntimeRequest();
|
|
21586
21999
|
}
|
|
21587
22000
|
}
|
|
21588
22001
|
async *streamTurn(input) {
|
|
@@ -21595,6 +22008,12 @@ var AgentRuntime = class {
|
|
|
21595
22008
|
throw new Error(`Runtime session not found: ${input.sessionId}`);
|
|
21596
22009
|
}
|
|
21597
22010
|
const effectiveSession = input.mode && input.mode !== session.mode ? { ...session, mode: input.mode } : session;
|
|
22011
|
+
assertRuntimeTurnWithinPolicy(this.runtimePolicy, {
|
|
22012
|
+
subject: "turn.stream",
|
|
22013
|
+
currentTurns: countUserTurns(effectiveSession),
|
|
22014
|
+
tenantId: this.runtimeContext?.tenant?.id
|
|
22015
|
+
});
|
|
22016
|
+
const releaseRuntimeRequest = this.beginRuntimeRequest("turn.stream");
|
|
21598
22017
|
const messages = [
|
|
21599
22018
|
...effectiveSession.messages,
|
|
21600
22019
|
{
|
|
@@ -21644,7 +22063,13 @@ var AgentRuntime = class {
|
|
|
21644
22063
|
model: input.options?.model ?? this.getModel(),
|
|
21645
22064
|
mode: effectiveSession.mode
|
|
21646
22065
|
};
|
|
21647
|
-
|
|
22066
|
+
const estimatedCostUsd = this.estimateTurnCost(result);
|
|
22067
|
+
assertRuntimeUsageWithinPolicy(this.runtimePolicy, {
|
|
22068
|
+
...result.usage,
|
|
22069
|
+
estimatedCostUsd,
|
|
22070
|
+
tenantId: this.runtimeContext?.tenant?.id,
|
|
22071
|
+
subject: "turn.stream"
|
|
22072
|
+
});
|
|
21648
22073
|
const updatedSession = this.runtimeSessionStore.update({
|
|
21649
22074
|
...effectiveSession,
|
|
21650
22075
|
messages: [
|
|
@@ -21663,6 +22088,7 @@ var AgentRuntime = class {
|
|
|
21663
22088
|
sessionId: updatedSession.id,
|
|
21664
22089
|
inputTokens: result.usage.inputTokens,
|
|
21665
22090
|
outputTokens: result.usage.outputTokens,
|
|
22091
|
+
estimatedCostUsd,
|
|
21666
22092
|
model: result.model,
|
|
21667
22093
|
streaming: true,
|
|
21668
22094
|
runtimeApi: true
|
|
@@ -21692,9 +22118,11 @@ var AgentRuntime = class {
|
|
|
21692
22118
|
runtimeApi: true
|
|
21693
22119
|
});
|
|
21694
22120
|
}
|
|
22121
|
+
releaseRuntimeRequest();
|
|
21695
22122
|
}
|
|
21696
22123
|
}
|
|
21697
22124
|
async executeTool(input) {
|
|
22125
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "tool.execute");
|
|
21698
22126
|
const startedAt = performance.now();
|
|
21699
22127
|
const session = input.sessionId ? this.getSession(input.sessionId) : void 0;
|
|
21700
22128
|
if (input.sessionId && !session) {
|
|
@@ -21805,6 +22233,7 @@ var AgentRuntime = class {
|
|
|
21805
22233
|
};
|
|
21806
22234
|
}
|
|
21807
22235
|
assertToolAllowed(mode, toolName, input) {
|
|
22236
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, "tool.assertAllowed");
|
|
21808
22237
|
const tool = this.toolRegistry.get(toolName);
|
|
21809
22238
|
if (!tool) {
|
|
21810
22239
|
this.eventLog.record("tool.blocked", {
|
|
@@ -21834,109 +22263,69 @@ var AgentRuntime = class {
|
|
|
21834
22263
|
});
|
|
21835
22264
|
return allowed;
|
|
21836
22265
|
}
|
|
21837
|
-
|
|
21838
|
-
|
|
21839
|
-
|
|
21840
|
-
|
|
21841
|
-
|
|
21842
|
-
|
|
21843
|
-
|
|
21844
|
-
|
|
21845
|
-
|
|
21846
|
-
|
|
21847
|
-
|
|
22266
|
+
beginRuntimeRequest(subject) {
|
|
22267
|
+
assertRuntimeTenantBoundary(this.runtimeContext, this.runtimeHostMode, subject);
|
|
22268
|
+
this.assertWithinRateLimit(subject);
|
|
22269
|
+
this.assertWithinConcurrencyLimit(subject);
|
|
22270
|
+
this.activeRuns += 1;
|
|
22271
|
+
let released = false;
|
|
22272
|
+
return () => {
|
|
22273
|
+
if (released) return;
|
|
22274
|
+
released = true;
|
|
22275
|
+
this.activeRuns = Math.max(0, this.activeRuns - 1);
|
|
22276
|
+
};
|
|
21848
22277
|
}
|
|
21849
|
-
|
|
21850
|
-
|
|
21851
|
-
|
|
21852
|
-
const
|
|
21853
|
-
|
|
21854
|
-
|
|
21855
|
-
|
|
21856
|
-
|
|
21857
|
-
|
|
21858
|
-
|
|
21859
|
-
|
|
21860
|
-
|
|
21861
|
-
|
|
21862
|
-
|
|
21863
|
-
|
|
21864
|
-
|
|
21865
|
-
|
|
21866
|
-
toolName,
|
|
21867
|
-
manifest: input.toolRiskManifest
|
|
21868
|
-
});
|
|
21869
|
-
this.options.eventLog?.record("agent.tool.called", {
|
|
21870
|
-
taskId: input.task.id,
|
|
21871
|
-
role: input.task.role,
|
|
21872
|
-
toolName,
|
|
21873
|
-
decision,
|
|
21874
|
-
trace
|
|
21875
|
-
});
|
|
21876
|
-
if (!decision.allowed) {
|
|
21877
|
-
throw new Error(decision.reason ?? `Tool '${toolName}' is not allowed.`);
|
|
21878
|
-
}
|
|
21879
|
-
}
|
|
21880
|
-
});
|
|
21881
|
-
const result = normalizeAgentRunResult({
|
|
21882
|
-
id: `${input.task.id}-run-${Date.now().toString(36)}`,
|
|
21883
|
-
taskId: input.task.id,
|
|
21884
|
-
role: input.task.role,
|
|
21885
|
-
success: raw.success ?? true,
|
|
21886
|
-
output: raw.output,
|
|
21887
|
-
turns: raw.turns,
|
|
21888
|
-
toolsUsed: raw.toolsUsed,
|
|
21889
|
-
usage: {
|
|
21890
|
-
inputTokens: raw.inputTokens ?? 0,
|
|
21891
|
-
outputTokens: raw.outputTokens ?? 0,
|
|
21892
|
-
estimated: raw.inputTokens === void 0 || raw.outputTokens === void 0
|
|
21893
|
-
},
|
|
21894
|
-
startedAt,
|
|
21895
|
-
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
21896
|
-
durationMs: Date.now() - Date.parse(startedAt),
|
|
21897
|
-
error: raw.error,
|
|
21898
|
-
metadata: { ...raw.metadata, trace }
|
|
21899
|
-
});
|
|
21900
|
-
this.options.eventLog?.record(result.success ? "agent.completed" : "agent.failed", {
|
|
21901
|
-
taskId: input.task.id,
|
|
21902
|
-
role: input.task.role,
|
|
21903
|
-
agentRunId: result.id,
|
|
21904
|
-
trace,
|
|
21905
|
-
error: result.error
|
|
21906
|
-
});
|
|
21907
|
-
return result;
|
|
21908
|
-
} catch (error) {
|
|
21909
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
21910
|
-
const result = normalizeAgentRunResult({
|
|
21911
|
-
id: `${input.task.id}-run-${Date.now().toString(36)}`,
|
|
21912
|
-
taskId: input.task.id,
|
|
21913
|
-
role: input.task.role,
|
|
21914
|
-
success: false,
|
|
21915
|
-
output: message,
|
|
21916
|
-
startedAt,
|
|
21917
|
-
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
21918
|
-
durationMs: Date.now() - Date.parse(startedAt),
|
|
21919
|
-
error: message,
|
|
21920
|
-
metadata: { trace }
|
|
22278
|
+
assertWithinRateLimit(subject) {
|
|
22279
|
+
const maxRequestsPerMinute = this.runtimePolicy?.rateLimit?.maxRequestsPerMinute;
|
|
22280
|
+
if (maxRequestsPerMinute === void 0) return;
|
|
22281
|
+
const now = Date.now();
|
|
22282
|
+
const windowStart = now - 6e4;
|
|
22283
|
+
const key = `${this.runtimeContext?.tenant?.id ?? "global"}:${subject}`;
|
|
22284
|
+
const recent = (this.requestTimestampsBySubject.get(key) ?? []).filter(
|
|
22285
|
+
(timestamp) => timestamp > windowStart
|
|
22286
|
+
);
|
|
22287
|
+
if (recent.length >= maxRequestsPerMinute) {
|
|
22288
|
+
this.requestTimestampsBySubject.set(key, recent);
|
|
22289
|
+
throw new RuntimePolicyViolation({
|
|
22290
|
+
code: "rate_limit_exceeded",
|
|
22291
|
+
subject,
|
|
22292
|
+
tenantId: this.runtimeContext?.tenant?.id,
|
|
22293
|
+
policyPath: "runtimePolicy.rateLimit.maxRequestsPerMinute",
|
|
22294
|
+
message: `Runtime policy rate limit exceeded: ${recent.length}/${maxRequestsPerMinute} requests per minute.`
|
|
21921
22295
|
});
|
|
21922
|
-
|
|
21923
|
-
|
|
21924
|
-
|
|
21925
|
-
|
|
21926
|
-
|
|
21927
|
-
|
|
22296
|
+
}
|
|
22297
|
+
recent.push(now);
|
|
22298
|
+
this.requestTimestampsBySubject.set(key, recent);
|
|
22299
|
+
}
|
|
22300
|
+
assertWithinConcurrencyLimit(subject) {
|
|
22301
|
+
const maxConcurrentRuns = this.runtimePolicy?.rateLimit?.maxConcurrentRuns;
|
|
22302
|
+
if (maxConcurrentRuns === void 0) return;
|
|
22303
|
+
if (this.activeRuns >= maxConcurrentRuns) {
|
|
22304
|
+
throw new RuntimePolicyViolation({
|
|
22305
|
+
code: "concurrency_limit_exceeded",
|
|
22306
|
+
subject,
|
|
22307
|
+
tenantId: this.runtimeContext?.tenant?.id,
|
|
22308
|
+
policyPath: "runtimePolicy.rateLimit.maxConcurrentRuns",
|
|
22309
|
+
message: `Runtime policy concurrency limit exceeded: ${this.activeRuns}/${maxConcurrentRuns} active runs.`
|
|
21928
22310
|
});
|
|
21929
|
-
return result;
|
|
21930
22311
|
}
|
|
21931
22312
|
}
|
|
22313
|
+
estimateTurnCost(result) {
|
|
22314
|
+
return estimateCost(
|
|
22315
|
+
result.model,
|
|
22316
|
+
result.usage.inputTokens,
|
|
22317
|
+
result.usage.outputTokens,
|
|
22318
|
+
this.providerType
|
|
22319
|
+
).totalCost;
|
|
22320
|
+
}
|
|
21932
22321
|
};
|
|
21933
|
-
function
|
|
21934
|
-
return
|
|
22322
|
+
function countUserTurns(session) {
|
|
22323
|
+
return session.messages.filter((message) => message.role === "user").length;
|
|
21935
22324
|
}
|
|
21936
|
-
async function
|
|
21937
|
-
|
|
21938
|
-
|
|
21939
|
-
|
|
22325
|
+
async function createAgentRuntime(options) {
|
|
22326
|
+
const runtime = new AgentRuntime(options);
|
|
22327
|
+
await runtime.initialize();
|
|
22328
|
+
return runtime;
|
|
21940
22329
|
}
|
|
21941
22330
|
|
|
21942
22331
|
// src/runtime/tool-calling-turn-runner.ts
|
|
@@ -22146,6 +22535,314 @@ function createRuntimeHttpServer(runtime, options = {}) {
|
|
|
22146
22535
|
}
|
|
22147
22536
|
});
|
|
22148
22537
|
}
|
|
22538
|
+
function createSessionId2() {
|
|
22539
|
+
return `rt_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
22540
|
+
}
|
|
22541
|
+
function parseJson(value, fallback) {
|
|
22542
|
+
if (value === null || value === void 0) return fallback;
|
|
22543
|
+
if (typeof value === "string") return JSON.parse(value);
|
|
22544
|
+
return value;
|
|
22545
|
+
}
|
|
22546
|
+
function dateToIso(value) {
|
|
22547
|
+
return value instanceof Date ? value.toISOString() : new Date(value).toISOString();
|
|
22548
|
+
}
|
|
22549
|
+
function rowToSession(row) {
|
|
22550
|
+
return {
|
|
22551
|
+
id: row.id,
|
|
22552
|
+
createdAt: dateToIso(row.created_at),
|
|
22553
|
+
updatedAt: dateToIso(row.updated_at),
|
|
22554
|
+
mode: row.mode,
|
|
22555
|
+
messages: parseJson(row.messages, []),
|
|
22556
|
+
instructions: row.instructions ?? void 0,
|
|
22557
|
+
metadata: parseJson(row.metadata, {})
|
|
22558
|
+
};
|
|
22559
|
+
}
|
|
22560
|
+
function rowToEvent(row) {
|
|
22561
|
+
return {
|
|
22562
|
+
id: row.id,
|
|
22563
|
+
type: row.type,
|
|
22564
|
+
timestamp: dateToIso(row.timestamp),
|
|
22565
|
+
data: parseJson(row.data, {})
|
|
22566
|
+
};
|
|
22567
|
+
}
|
|
22568
|
+
function requireTenantId(options) {
|
|
22569
|
+
if (!options.tenantId) {
|
|
22570
|
+
throw new Error("Postgres hosted runtime stores require tenantId.");
|
|
22571
|
+
}
|
|
22572
|
+
return options.tenantId;
|
|
22573
|
+
}
|
|
22574
|
+
var AsyncPostgresRuntimeSessionStore = class {
|
|
22575
|
+
constructor(client, options) {
|
|
22576
|
+
this.client = client;
|
|
22577
|
+
this.tenantId = requireTenantId(options);
|
|
22578
|
+
}
|
|
22579
|
+
client;
|
|
22580
|
+
tenantId;
|
|
22581
|
+
async create(options = {}) {
|
|
22582
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
22583
|
+
const session = {
|
|
22584
|
+
id: options.id ?? createSessionId2(),
|
|
22585
|
+
createdAt: now,
|
|
22586
|
+
updatedAt: now,
|
|
22587
|
+
mode: options.mode ?? "ask",
|
|
22588
|
+
messages: options.messages ? options.messages.map((message) => ({ ...message })) : [],
|
|
22589
|
+
instructions: options.instructions,
|
|
22590
|
+
metadata: { ...options.metadata, tenantId: this.tenantId }
|
|
22591
|
+
};
|
|
22592
|
+
const result = await this.client.query(
|
|
22593
|
+
`insert into coco_runtime_sessions
|
|
22594
|
+
(id, tenant_id, created_at, updated_at, mode, messages, instructions, metadata)
|
|
22595
|
+
values ($1, $2, $3, $4, $5, $6::jsonb, $7, $8::jsonb)
|
|
22596
|
+
on conflict (id) do update set
|
|
22597
|
+
updated_at = excluded.updated_at,
|
|
22598
|
+
mode = excluded.mode,
|
|
22599
|
+
messages = excluded.messages,
|
|
22600
|
+
instructions = excluded.instructions,
|
|
22601
|
+
metadata = excluded.metadata
|
|
22602
|
+
where coco_runtime_sessions.tenant_id = excluded.tenant_id`,
|
|
22603
|
+
[
|
|
22604
|
+
session.id,
|
|
22605
|
+
this.tenantId,
|
|
22606
|
+
session.createdAt,
|
|
22607
|
+
session.updatedAt,
|
|
22608
|
+
session.mode,
|
|
22609
|
+
JSON.stringify(session.messages),
|
|
22610
|
+
session.instructions ?? null,
|
|
22611
|
+
JSON.stringify(session.metadata)
|
|
22612
|
+
]
|
|
22613
|
+
);
|
|
22614
|
+
if (result.rowCount === 0) {
|
|
22615
|
+
throw new Error(`Runtime session id is already owned by another tenant: ${session.id}`);
|
|
22616
|
+
}
|
|
22617
|
+
return structuredClone(session);
|
|
22618
|
+
}
|
|
22619
|
+
async get(id) {
|
|
22620
|
+
const result = await this.client.query(
|
|
22621
|
+
`select * from coco_runtime_sessions
|
|
22622
|
+
where id = $1 and tenant_id = $2
|
|
22623
|
+
limit 1`,
|
|
22624
|
+
[id, this.tenantId]
|
|
22625
|
+
);
|
|
22626
|
+
const row = result.rows[0];
|
|
22627
|
+
return row ? rowToSession(row) : void 0;
|
|
22628
|
+
}
|
|
22629
|
+
async update(session) {
|
|
22630
|
+
const updated = {
|
|
22631
|
+
...session,
|
|
22632
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22633
|
+
messages: session.messages.map((message) => ({ ...message })),
|
|
22634
|
+
metadata: { ...session.metadata, tenantId: this.tenantId }
|
|
22635
|
+
};
|
|
22636
|
+
const result = await this.client.query(
|
|
22637
|
+
`update coco_runtime_sessions
|
|
22638
|
+
set updated_at = $3, mode = $4, messages = $5::jsonb, instructions = $6, metadata = $7::jsonb
|
|
22639
|
+
where id = $1 and tenant_id = $2`,
|
|
22640
|
+
[
|
|
22641
|
+
updated.id,
|
|
22642
|
+
this.tenantId,
|
|
22643
|
+
updated.updatedAt,
|
|
22644
|
+
updated.mode,
|
|
22645
|
+
JSON.stringify(updated.messages),
|
|
22646
|
+
updated.instructions ?? null,
|
|
22647
|
+
JSON.stringify(updated.metadata)
|
|
22648
|
+
]
|
|
22649
|
+
);
|
|
22650
|
+
if (result.rowCount === 0) {
|
|
22651
|
+
throw new Error(`Runtime session not found for tenant ${this.tenantId}: ${updated.id}`);
|
|
22652
|
+
}
|
|
22653
|
+
return structuredClone(updated);
|
|
22654
|
+
}
|
|
22655
|
+
async list() {
|
|
22656
|
+
const result = await this.client.query(
|
|
22657
|
+
`select * from coco_runtime_sessions
|
|
22658
|
+
where tenant_id = $1
|
|
22659
|
+
order by updated_at desc`,
|
|
22660
|
+
[this.tenantId]
|
|
22661
|
+
);
|
|
22662
|
+
return result.rows.map(rowToSession);
|
|
22663
|
+
}
|
|
22664
|
+
async delete(id) {
|
|
22665
|
+
const result = await this.client.query(
|
|
22666
|
+
"delete from coco_runtime_sessions where id = $1 and tenant_id = $2",
|
|
22667
|
+
[id, this.tenantId]
|
|
22668
|
+
);
|
|
22669
|
+
return (result.rowCount ?? 0) > 0;
|
|
22670
|
+
}
|
|
22671
|
+
};
|
|
22672
|
+
var AsyncPostgresEventLog = class {
|
|
22673
|
+
constructor(client, options) {
|
|
22674
|
+
this.client = client;
|
|
22675
|
+
this.tenantId = requireTenantId(options);
|
|
22676
|
+
}
|
|
22677
|
+
client;
|
|
22678
|
+
tenantId;
|
|
22679
|
+
async record(type, data = {}) {
|
|
22680
|
+
const event = {
|
|
22681
|
+
id: randomUUID(),
|
|
22682
|
+
type,
|
|
22683
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22684
|
+
data: { ...data, tenantId: this.tenantId }
|
|
22685
|
+
};
|
|
22686
|
+
await this.client.query(
|
|
22687
|
+
`insert into coco_runtime_events (id, tenant_id, type, timestamp, data)
|
|
22688
|
+
values ($1, $2, $3, $4, $5::jsonb)`,
|
|
22689
|
+
[event.id, this.tenantId, event.type, event.timestamp, JSON.stringify(event.data)]
|
|
22690
|
+
);
|
|
22691
|
+
return event;
|
|
22692
|
+
}
|
|
22693
|
+
async list() {
|
|
22694
|
+
return listPostgresRuntimeEvents(this.client, { tenantId: this.tenantId });
|
|
22695
|
+
}
|
|
22696
|
+
async count() {
|
|
22697
|
+
const result = await this.client.query(
|
|
22698
|
+
"select count(*)::int as count from coco_runtime_events where tenant_id = $1",
|
|
22699
|
+
[this.tenantId]
|
|
22700
|
+
);
|
|
22701
|
+
return Number(result.rows[0]?.count ?? 0);
|
|
22702
|
+
}
|
|
22703
|
+
async clear() {
|
|
22704
|
+
await this.client.query("delete from coco_runtime_events where tenant_id = $1", [
|
|
22705
|
+
this.tenantId
|
|
22706
|
+
]);
|
|
22707
|
+
}
|
|
22708
|
+
};
|
|
22709
|
+
var PostgresRuntimeAuditStore = class {
|
|
22710
|
+
constructor(client, options) {
|
|
22711
|
+
this.client = client;
|
|
22712
|
+
this.tenantId = requireTenantId(options);
|
|
22713
|
+
}
|
|
22714
|
+
client;
|
|
22715
|
+
tenantId;
|
|
22716
|
+
async record(input) {
|
|
22717
|
+
const record = {
|
|
22718
|
+
id: randomUUID(),
|
|
22719
|
+
tenantId: this.tenantId,
|
|
22720
|
+
type: input.type,
|
|
22721
|
+
subject: input.subject,
|
|
22722
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
22723
|
+
data: { ...input.data }
|
|
22724
|
+
};
|
|
22725
|
+
await this.client.query(
|
|
22726
|
+
`insert into coco_runtime_audit_events
|
|
22727
|
+
(id, tenant_id, type, subject, timestamp, data)
|
|
22728
|
+
values ($1, $2, $3, $4, $5, $6::jsonb)`,
|
|
22729
|
+
[
|
|
22730
|
+
record.id,
|
|
22731
|
+
record.tenantId,
|
|
22732
|
+
record.type,
|
|
22733
|
+
record.subject ?? null,
|
|
22734
|
+
record.timestamp,
|
|
22735
|
+
JSON.stringify(record.data)
|
|
22736
|
+
]
|
|
22737
|
+
);
|
|
22738
|
+
return record;
|
|
22739
|
+
}
|
|
22740
|
+
async list() {
|
|
22741
|
+
const result = await this.client.query(
|
|
22742
|
+
`select * from coco_runtime_audit_events
|
|
22743
|
+
where tenant_id = $1
|
|
22744
|
+
order by timestamp asc`,
|
|
22745
|
+
[this.tenantId]
|
|
22746
|
+
);
|
|
22747
|
+
return result.rows.map((row) => ({
|
|
22748
|
+
id: row.id,
|
|
22749
|
+
tenantId: row.tenant_id,
|
|
22750
|
+
type: row.type,
|
|
22751
|
+
subject: row.subject ?? void 0,
|
|
22752
|
+
timestamp: dateToIso(row.timestamp),
|
|
22753
|
+
data: parseJson(row.data, {})
|
|
22754
|
+
}));
|
|
22755
|
+
}
|
|
22756
|
+
};
|
|
22757
|
+
function createAsyncPostgresRuntimeSessionStore(client, options) {
|
|
22758
|
+
return new AsyncPostgresRuntimeSessionStore(client, options);
|
|
22759
|
+
}
|
|
22760
|
+
function createAsyncPostgresEventLog(client, options) {
|
|
22761
|
+
return new AsyncPostgresEventLog(client, options);
|
|
22762
|
+
}
|
|
22763
|
+
function createPostgresRuntimeAuditStore(client, options) {
|
|
22764
|
+
return new PostgresRuntimeAuditStore(client, options);
|
|
22765
|
+
}
|
|
22766
|
+
async function listPostgresRuntimeEvents(client, options = {}) {
|
|
22767
|
+
const result = await client.query(
|
|
22768
|
+
`select * from coco_runtime_events
|
|
22769
|
+
where ($1::text is null or tenant_id = $1)
|
|
22770
|
+
and ($2::text is null or data->>'sessionId' = $2)
|
|
22771
|
+
order by timestamp asc`,
|
|
22772
|
+
[options.tenantId ?? null, options.sessionId ?? null]
|
|
22773
|
+
);
|
|
22774
|
+
return result.rows.map(rowToEvent);
|
|
22775
|
+
}
|
|
22776
|
+
|
|
22777
|
+
// src/runtime/tenant-scope.ts
|
|
22778
|
+
var TenantScopedRuntimeSessionStore = class {
|
|
22779
|
+
constructor(inner, options) {
|
|
22780
|
+
this.inner = inner;
|
|
22781
|
+
this.options = options;
|
|
22782
|
+
}
|
|
22783
|
+
inner;
|
|
22784
|
+
options;
|
|
22785
|
+
create(options = {}) {
|
|
22786
|
+
return this.inner.create({
|
|
22787
|
+
...options,
|
|
22788
|
+
metadata: this.withTenant(options.metadata)
|
|
22789
|
+
});
|
|
22790
|
+
}
|
|
22791
|
+
get(id) {
|
|
22792
|
+
const session = this.inner.get(id);
|
|
22793
|
+
return session && this.belongsToTenant(session) ? session : void 0;
|
|
22794
|
+
}
|
|
22795
|
+
update(session) {
|
|
22796
|
+
if (!this.belongsToTenant(session)) {
|
|
22797
|
+
throw new Error(
|
|
22798
|
+
`Runtime session ${session.id} does not belong to tenant ${this.options.tenantId}.`
|
|
22799
|
+
);
|
|
22800
|
+
}
|
|
22801
|
+
return this.inner.update({
|
|
22802
|
+
...session,
|
|
22803
|
+
metadata: this.withTenant(session.metadata)
|
|
22804
|
+
});
|
|
22805
|
+
}
|
|
22806
|
+
list() {
|
|
22807
|
+
return this.inner.list().filter((session) => this.belongsToTenant(session));
|
|
22808
|
+
}
|
|
22809
|
+
delete(id) {
|
|
22810
|
+
if (!this.get(id)) return false;
|
|
22811
|
+
return this.inner.delete(id);
|
|
22812
|
+
}
|
|
22813
|
+
withTenant(metadata) {
|
|
22814
|
+
return { ...metadata, tenantId: this.options.tenantId };
|
|
22815
|
+
}
|
|
22816
|
+
belongsToTenant(session) {
|
|
22817
|
+
return session.metadata["tenantId"] === this.options.tenantId;
|
|
22818
|
+
}
|
|
22819
|
+
};
|
|
22820
|
+
var TenantScopedEventLog = class {
|
|
22821
|
+
constructor(inner, options) {
|
|
22822
|
+
this.inner = inner;
|
|
22823
|
+
this.options = options;
|
|
22824
|
+
}
|
|
22825
|
+
inner;
|
|
22826
|
+
options;
|
|
22827
|
+
record(type, data = {}) {
|
|
22828
|
+
return this.inner.record(type, { ...data, tenantId: this.options.tenantId });
|
|
22829
|
+
}
|
|
22830
|
+
list() {
|
|
22831
|
+
return this.inner.list().filter((event) => event.data["tenantId"] === this.options.tenantId);
|
|
22832
|
+
}
|
|
22833
|
+
count() {
|
|
22834
|
+
return this.list().length;
|
|
22835
|
+
}
|
|
22836
|
+
clear() {
|
|
22837
|
+
throw new Error("Tenant-scoped event logs do not support partial clear.");
|
|
22838
|
+
}
|
|
22839
|
+
};
|
|
22840
|
+
function createTenantScopedRuntimeSessionStore(inner, tenantId) {
|
|
22841
|
+
return new TenantScopedRuntimeSessionStore(inner, { tenantId });
|
|
22842
|
+
}
|
|
22843
|
+
function createTenantScopedEventLog(inner, tenantId) {
|
|
22844
|
+
return new TenantScopedEventLog(inner, { tenantId });
|
|
22845
|
+
}
|
|
22149
22846
|
|
|
22150
22847
|
// src/runtime/extension-manifests.ts
|
|
22151
22848
|
function createMcpToolPolicy(server, tool, risk, allowedModes = ["ask", "plan", "build", "debug", "review", "architect"]) {
|
|
@@ -22239,7 +22936,7 @@ function runGuardrails(stage, content, config = {}) {
|
|
|
22239
22936
|
findings.push({
|
|
22240
22937
|
id,
|
|
22241
22938
|
stage,
|
|
22242
|
-
severity: "
|
|
22939
|
+
severity: actionToSeverity(config.promptInjectionAction ?? "warn"),
|
|
22243
22940
|
message: `Potential prompt-injection pattern detected: ${id}`
|
|
22244
22941
|
});
|
|
22245
22942
|
}
|
|
@@ -22262,6 +22959,26 @@ function runGuardrails(stage, content, config = {}) {
|
|
|
22262
22959
|
findings
|
|
22263
22960
|
};
|
|
22264
22961
|
}
|
|
22962
|
+
async function runGuardrailPipeline(steps, config = {}) {
|
|
22963
|
+
const outputs = [];
|
|
22964
|
+
const findings = [];
|
|
22965
|
+
for (const step of steps) {
|
|
22966
|
+
const effectiveConfig = { ...config, ...step.config };
|
|
22967
|
+
const result = runGuardrails(step.stage, step.content, effectiveConfig);
|
|
22968
|
+
const policyFindings = await effectiveConfig.policyProvider?.evaluate({
|
|
22969
|
+
stage: step.stage,
|
|
22970
|
+
content: result.content,
|
|
22971
|
+
findings: result.findings
|
|
22972
|
+
}) ?? [];
|
|
22973
|
+
outputs.push({ stage: step.stage, content: result.content });
|
|
22974
|
+
findings.push(...result.findings, ...policyFindings);
|
|
22975
|
+
}
|
|
22976
|
+
return {
|
|
22977
|
+
allowed: !findings.some((finding) => finding.severity === "blocked"),
|
|
22978
|
+
outputs,
|
|
22979
|
+
findings
|
|
22980
|
+
};
|
|
22981
|
+
}
|
|
22265
22982
|
function validateStructuredOutput(output, schema) {
|
|
22266
22983
|
if (!schema) return [];
|
|
22267
22984
|
const result = schema.safeParse(output);
|
|
@@ -22275,6 +22992,16 @@ function validateStructuredOutput(output, schema) {
|
|
|
22275
22992
|
}
|
|
22276
22993
|
];
|
|
22277
22994
|
}
|
|
22995
|
+
function actionToSeverity(action) {
|
|
22996
|
+
switch (action) {
|
|
22997
|
+
case "allow":
|
|
22998
|
+
return "info";
|
|
22999
|
+
case "warn":
|
|
23000
|
+
return "warning";
|
|
23001
|
+
case "block":
|
|
23002
|
+
return "blocked";
|
|
23003
|
+
}
|
|
23004
|
+
}
|
|
22278
23005
|
|
|
22279
23006
|
// src/runtime/blueprints.ts
|
|
22280
23007
|
function mapActionModeToRuntimeMode(mode) {
|
|
@@ -22372,7 +23099,7 @@ var InMemoryKnowledgeRetriever = class {
|
|
|
22372
23099
|
const limit = options.limit ?? 5;
|
|
22373
23100
|
const minScore = options.minScore ?? 0;
|
|
22374
23101
|
const tenantId = tenantIdFromRetrievalOptions(options);
|
|
22375
|
-
return this.documents.filter((document) =>
|
|
23102
|
+
return this.documents.filter((document) => sourceAccessible(document, { ...options, tenantId })).map((document) => ({
|
|
22376
23103
|
...document,
|
|
22377
23104
|
score: scoreDocument(document, terms)
|
|
22378
23105
|
})).filter((source) => source.score >= minScore && source.score > 0).sort((a, b) => b.score - a.score).slice(0, limit);
|
|
@@ -22397,7 +23124,24 @@ var SimpleTextChunker = class {
|
|
|
22397
23124
|
title: document.title,
|
|
22398
23125
|
content,
|
|
22399
23126
|
url: document.url,
|
|
22400
|
-
|
|
23127
|
+
tenantId: document.tenantId,
|
|
23128
|
+
sourceId: document.sourceId,
|
|
23129
|
+
acl: document.acl,
|
|
23130
|
+
classification: document.classification,
|
|
23131
|
+
version: document.version,
|
|
23132
|
+
updatedAt: document.updatedAt,
|
|
23133
|
+
deletedAt: document.deletedAt,
|
|
23134
|
+
metadata: {
|
|
23135
|
+
...document.metadata,
|
|
23136
|
+
tenantId: document.tenantId ?? document.metadata?.["tenantId"],
|
|
23137
|
+
sourceId: document.sourceId ?? document.metadata?.["sourceId"],
|
|
23138
|
+
acl: document.acl ?? document.metadata?.["acl"],
|
|
23139
|
+
classification: document.classification ?? document.metadata?.["classification"],
|
|
23140
|
+
version: document.version ?? document.metadata?.["version"],
|
|
23141
|
+
updatedAt: document.updatedAt ?? document.metadata?.["updatedAt"],
|
|
23142
|
+
deletedAt: document.deletedAt ?? document.metadata?.["deletedAt"],
|
|
23143
|
+
chunkIndex: index
|
|
23144
|
+
}
|
|
22401
23145
|
});
|
|
22402
23146
|
index++;
|
|
22403
23147
|
offset += maxChars - overlapChars;
|
|
@@ -22416,16 +23160,104 @@ var InMemoryVectorStore = class {
|
|
|
22416
23160
|
const limit = options.limit ?? 5;
|
|
22417
23161
|
const minScore = options.minScore ?? 0;
|
|
22418
23162
|
const tenantId = tenantIdFromRetrievalOptions(options);
|
|
22419
|
-
return this.chunks.filter((chunk2) =>
|
|
23163
|
+
return this.chunks.filter((chunk2) => sourceAccessible(chunk2, { ...options, tenantId })).map((chunk2) => ({
|
|
22420
23164
|
id: chunk2.id,
|
|
22421
23165
|
title: chunk2.title,
|
|
22422
23166
|
content: chunk2.content,
|
|
22423
23167
|
url: chunk2.url,
|
|
22424
23168
|
score: cosineSimilarity(embedding, chunk2.embedding),
|
|
22425
|
-
metadata: {
|
|
23169
|
+
metadata: {
|
|
23170
|
+
...chunk2.metadata,
|
|
23171
|
+
tenantId: chunk2.tenantId ?? chunk2.metadata?.["tenantId"],
|
|
23172
|
+
sourceId: chunk2.sourceId ?? chunk2.metadata?.["sourceId"],
|
|
23173
|
+
acl: chunk2.acl ?? chunk2.metadata?.["acl"],
|
|
23174
|
+
classification: chunk2.classification ?? chunk2.metadata?.["classification"],
|
|
23175
|
+
version: chunk2.version ?? chunk2.metadata?.["version"],
|
|
23176
|
+
updatedAt: chunk2.updatedAt ?? chunk2.metadata?.["updatedAt"],
|
|
23177
|
+
deletedAt: chunk2.deletedAt ?? chunk2.metadata?.["deletedAt"],
|
|
23178
|
+
documentId: chunk2.documentId
|
|
23179
|
+
}
|
|
22426
23180
|
})).filter((source) => source.score >= minScore).sort((a, b) => b.score - a.score).slice(0, limit);
|
|
22427
23181
|
}
|
|
22428
23182
|
};
|
|
23183
|
+
function createDocumentAccessPolicy(input) {
|
|
23184
|
+
return {
|
|
23185
|
+
canAccess({ document, options }) {
|
|
23186
|
+
const tenantId = options.tenantId ?? input.tenantId;
|
|
23187
|
+
const userId = options.userId ?? input.userId;
|
|
23188
|
+
const roles = options.roles ?? input.roles ?? [];
|
|
23189
|
+
const groups = options.groups ?? input.groups ?? [];
|
|
23190
|
+
const metadata = document.metadata ?? {};
|
|
23191
|
+
if (document.deletedAt ?? metadata["deletedAt"]) return false;
|
|
23192
|
+
const documentTenantId = document.tenantId ?? stringMetadata(metadata, "tenantId");
|
|
23193
|
+
const visibility = stringMetadata(metadata, "visibility");
|
|
23194
|
+
if (tenantId && documentTenantId !== tenantId && visibility !== "global") return false;
|
|
23195
|
+
const acl = document.acl ?? metadata["acl"];
|
|
23196
|
+
if (!acl) return input.requireAcl !== true;
|
|
23197
|
+
if (acl.public === true) return true;
|
|
23198
|
+
if (userId && acl.userIds?.includes(userId)) return true;
|
|
23199
|
+
if (acl.roles?.some((role) => roles.includes(role))) return true;
|
|
23200
|
+
if (acl.groups?.some((group) => groups.includes(group))) return true;
|
|
23201
|
+
return false;
|
|
23202
|
+
}
|
|
23203
|
+
};
|
|
23204
|
+
}
|
|
23205
|
+
function createRagIngestionJob(id, pipeline) {
|
|
23206
|
+
const job = {
|
|
23207
|
+
id,
|
|
23208
|
+
status: "pending",
|
|
23209
|
+
async run() {
|
|
23210
|
+
job.status = "running";
|
|
23211
|
+
job.startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
23212
|
+
try {
|
|
23213
|
+
job.result = await pipeline.ingest();
|
|
23214
|
+
job.status = "completed";
|
|
23215
|
+
} catch (error) {
|
|
23216
|
+
job.status = "failed";
|
|
23217
|
+
job.error = error instanceof Error ? error.message : String(error);
|
|
23218
|
+
} finally {
|
|
23219
|
+
job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
23220
|
+
}
|
|
23221
|
+
return { ...job };
|
|
23222
|
+
}
|
|
23223
|
+
};
|
|
23224
|
+
return job;
|
|
23225
|
+
}
|
|
23226
|
+
function verifyCitations(citations, sources) {
|
|
23227
|
+
const byId = new Map(sources.map((source) => [source.id, source]));
|
|
23228
|
+
const unsupportedCitations = [];
|
|
23229
|
+
const missingSourceIds = [];
|
|
23230
|
+
for (const citation of citations) {
|
|
23231
|
+
const source = byId.get(citation.sourceId);
|
|
23232
|
+
if (!source) {
|
|
23233
|
+
missingSourceIds.push(citation.sourceId);
|
|
23234
|
+
unsupportedCitations.push(citation);
|
|
23235
|
+
}
|
|
23236
|
+
}
|
|
23237
|
+
return {
|
|
23238
|
+
valid: unsupportedCitations.length === 0,
|
|
23239
|
+
unsupportedCitations,
|
|
23240
|
+
missingSourceIds
|
|
23241
|
+
};
|
|
23242
|
+
}
|
|
23243
|
+
function evaluateGroundedness(answer, sources) {
|
|
23244
|
+
const answerTerms = new Set(tokenize(answer));
|
|
23245
|
+
const sourceTerms = new Set(sources.flatMap((source) => tokenize(source.content)));
|
|
23246
|
+
const overlap = [...answerTerms].filter((term) => sourceTerms.has(term)).length;
|
|
23247
|
+
const score = answerTerms.size === 0 ? 0 : overlap / answerTerms.size;
|
|
23248
|
+
const injection = /ignore|override|bypass|reveal|exfiltrate/i.test(
|
|
23249
|
+
sources.map((source) => source.content).join("\n")
|
|
23250
|
+
);
|
|
23251
|
+
const reasons = [];
|
|
23252
|
+
if (score < 0.2) reasons.push("Answer has low lexical support in retrieved sources.");
|
|
23253
|
+
if (injection) reasons.push("Retrieved sources contain prompt-injection indicators.");
|
|
23254
|
+
return {
|
|
23255
|
+
grounded: score >= 0.2 && !injection,
|
|
23256
|
+
score,
|
|
23257
|
+
blocked: injection,
|
|
23258
|
+
reasons
|
|
23259
|
+
};
|
|
23260
|
+
}
|
|
22429
23261
|
function createInMemoryKnowledgeRetriever(documents) {
|
|
22430
23262
|
return new InMemoryKnowledgeRetriever(documents);
|
|
22431
23263
|
}
|
|
@@ -22492,10 +23324,15 @@ function mergeRetrievalOptionsWithRuntimeContext(options, runtimeContext) {
|
|
|
22492
23324
|
function tenantIdFromRetrievalOptions(options) {
|
|
22493
23325
|
return options.tenantId ?? options.runtimeContext?.tenant?.id;
|
|
22494
23326
|
}
|
|
22495
|
-
function
|
|
22496
|
-
if (
|
|
22497
|
-
|
|
22498
|
-
|
|
23327
|
+
function sourceAccessible(document, options) {
|
|
23328
|
+
if (options.documentAccessPolicy) {
|
|
23329
|
+
return options.documentAccessPolicy.canAccess({ document, options });
|
|
23330
|
+
}
|
|
23331
|
+
const metadata = document.metadata ?? {};
|
|
23332
|
+
if (document.deletedAt ?? metadata["deletedAt"]) return false;
|
|
23333
|
+
if (!options.tenantId || options.dataBoundary?.allowCrossTenantMemory === true) return true;
|
|
23334
|
+
const sourceTenantId = document.tenantId ?? metadata["tenantId"];
|
|
23335
|
+
return sourceTenantId === options.tenantId || metadata["visibility"] === "global";
|
|
22499
23336
|
}
|
|
22500
23337
|
async function retrieveFromVectorPipeline(query, options, retrievalOptions) {
|
|
22501
23338
|
if (!options.embeddingProvider || !options.vectorStore) return [];
|
|
@@ -22503,6 +23340,10 @@ async function retrieveFromVectorPipeline(query, options, retrievalOptions) {
|
|
|
22503
23340
|
if (!embedding) return [];
|
|
22504
23341
|
return options.vectorStore.search(embedding, retrievalOptions);
|
|
22505
23342
|
}
|
|
23343
|
+
function stringMetadata(metadata, key) {
|
|
23344
|
+
const value = metadata[key];
|
|
23345
|
+
return typeof value === "string" ? value : void 0;
|
|
23346
|
+
}
|
|
22506
23347
|
function cosineSimilarity(a, b) {
|
|
22507
23348
|
if (a.length === 0 || b.length === 0 || a.length !== b.length) return 0;
|
|
22508
23349
|
let dot = 0;
|
|
@@ -22627,6 +23468,187 @@ var RuntimeToolExecutor = class {
|
|
|
22627
23468
|
function createRuntimeToolExecutor(options) {
|
|
22628
23469
|
return new RuntimeToolExecutor(options);
|
|
22629
23470
|
}
|
|
23471
|
+
var InMemoryTraceExporter = class {
|
|
23472
|
+
spans = [];
|
|
23473
|
+
async export(span) {
|
|
23474
|
+
this.spans.push(structuredClone(span));
|
|
23475
|
+
}
|
|
23476
|
+
list() {
|
|
23477
|
+
return this.spans.map((span) => structuredClone(span));
|
|
23478
|
+
}
|
|
23479
|
+
clear() {
|
|
23480
|
+
this.spans = [];
|
|
23481
|
+
}
|
|
23482
|
+
};
|
|
23483
|
+
var FileTraceExporter = class {
|
|
23484
|
+
constructor(filePath) {
|
|
23485
|
+
this.filePath = filePath;
|
|
23486
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
23487
|
+
}
|
|
23488
|
+
filePath;
|
|
23489
|
+
async export(span) {
|
|
23490
|
+
appendFileSync(this.filePath, JSON.stringify(span) + "\n", "utf-8");
|
|
23491
|
+
}
|
|
23492
|
+
list() {
|
|
23493
|
+
try {
|
|
23494
|
+
return readFileSync(this.filePath, "utf-8").split("\n").filter(Boolean).map((line) => JSON.parse(line));
|
|
23495
|
+
} catch {
|
|
23496
|
+
return [];
|
|
23497
|
+
}
|
|
23498
|
+
}
|
|
23499
|
+
clear() {
|
|
23500
|
+
writeFileSync(this.filePath, "", "utf-8");
|
|
23501
|
+
}
|
|
23502
|
+
};
|
|
23503
|
+
var OpenTelemetryTraceExporter = class {
|
|
23504
|
+
spans = [];
|
|
23505
|
+
async export(span) {
|
|
23506
|
+
this.spans.push(structuredClone(span));
|
|
23507
|
+
}
|
|
23508
|
+
toOtlpJson() {
|
|
23509
|
+
return {
|
|
23510
|
+
resourceSpans: [
|
|
23511
|
+
{
|
|
23512
|
+
scopeSpans: [
|
|
23513
|
+
{
|
|
23514
|
+
spans: this.spans.map((span) => ({
|
|
23515
|
+
traceId: span.traceId,
|
|
23516
|
+
spanId: span.spanId,
|
|
23517
|
+
parentSpanId: span.parentSpanId,
|
|
23518
|
+
name: span.name,
|
|
23519
|
+
kind: span.kind,
|
|
23520
|
+
startTimeUnixNano: Date.parse(span.timestamp) * 1e6,
|
|
23521
|
+
endTimeUnixNano: Date.parse(span.timestamp) * 1e6,
|
|
23522
|
+
attributes: Object.entries(span.attributes).map(([key, value]) => ({
|
|
23523
|
+
key,
|
|
23524
|
+
value: { stringValue: JSON.stringify(value) }
|
|
23525
|
+
}))
|
|
23526
|
+
}))
|
|
23527
|
+
}
|
|
23528
|
+
]
|
|
23529
|
+
}
|
|
23530
|
+
]
|
|
23531
|
+
};
|
|
23532
|
+
}
|
|
23533
|
+
};
|
|
23534
|
+
async function exportRuntimeEventsAsSpans(events, exporter) {
|
|
23535
|
+
const spans = events.map(eventToSpan);
|
|
23536
|
+
for (const span of spans) {
|
|
23537
|
+
await exporter.export(span);
|
|
23538
|
+
}
|
|
23539
|
+
await exporter.flush?.();
|
|
23540
|
+
return spans;
|
|
23541
|
+
}
|
|
23542
|
+
function eventToSpan(event) {
|
|
23543
|
+
const trace = isRecord(event.data["trace"]) ? event.data["trace"] : {};
|
|
23544
|
+
const traceId = stringValue(trace["traceId"]) ?? stringValue(event.data["traceId"]) ?? event.id;
|
|
23545
|
+
const spanId = stringValue(trace["spanId"]) ?? stringValue(event.data["spanId"]) ?? event.id;
|
|
23546
|
+
return {
|
|
23547
|
+
id: event.id,
|
|
23548
|
+
traceId,
|
|
23549
|
+
spanId,
|
|
23550
|
+
parentSpanId: stringValue(trace["parentSpanId"]) ?? stringValue(event.data["parentSpanId"]),
|
|
23551
|
+
kind: inferSpanKind(event),
|
|
23552
|
+
name: event.type,
|
|
23553
|
+
timestamp: event.timestamp,
|
|
23554
|
+
attributes: redactTraceAttributes(event.data)
|
|
23555
|
+
};
|
|
23556
|
+
}
|
|
23557
|
+
function collectRuntimeMetrics(events) {
|
|
23558
|
+
const snapshot = {
|
|
23559
|
+
events: events.length,
|
|
23560
|
+
byKind: {
|
|
23561
|
+
workflow: 0,
|
|
23562
|
+
agent: 0,
|
|
23563
|
+
llm: 0,
|
|
23564
|
+
tool: 0,
|
|
23565
|
+
rag: 0,
|
|
23566
|
+
gate: 0,
|
|
23567
|
+
handoff: 0,
|
|
23568
|
+
state: 0,
|
|
23569
|
+
runtime: 0
|
|
23570
|
+
},
|
|
23571
|
+
tokens: { input: 0, output: 0 },
|
|
23572
|
+
estimatedCostUsd: 0,
|
|
23573
|
+
retries: 0,
|
|
23574
|
+
policyBlocks: 0,
|
|
23575
|
+
errorsByClass: {},
|
|
23576
|
+
toolsUsed: {},
|
|
23577
|
+
gatesFailed: 0,
|
|
23578
|
+
tenantUsage: {}
|
|
23579
|
+
};
|
|
23580
|
+
for (const event of events) {
|
|
23581
|
+
const kind = inferSpanKind(event);
|
|
23582
|
+
snapshot.byKind[kind] += 1;
|
|
23583
|
+
const inputTokens = numberValue(event.data["inputTokens"]);
|
|
23584
|
+
const outputTokens = numberValue(event.data["outputTokens"]);
|
|
23585
|
+
const estimatedCostUsd = numberValue(event.data["estimatedCostUsd"]);
|
|
23586
|
+
snapshot.tokens.input += inputTokens;
|
|
23587
|
+
snapshot.tokens.output += outputTokens;
|
|
23588
|
+
snapshot.estimatedCostUsd += estimatedCostUsd;
|
|
23589
|
+
if (event.data["attempt"] && numberValue(event.data["attempt"]) > 1) snapshot.retries += 1;
|
|
23590
|
+
if (event.type === "tool.blocked" || event.data["runtimePolicyBlocked"] === true) {
|
|
23591
|
+
snapshot.policyBlocks += 1;
|
|
23592
|
+
}
|
|
23593
|
+
if (event.type.endsWith(".failed") || event.type === "error") {
|
|
23594
|
+
const key = stringValue(event.data["error"]) ?? event.type;
|
|
23595
|
+
snapshot.errorsByClass[key] = (snapshot.errorsByClass[key] ?? 0) + 1;
|
|
23596
|
+
}
|
|
23597
|
+
const tool = stringValue(event.data["tool"]) ?? stringValue(event.data["toolName"]);
|
|
23598
|
+
if (tool) snapshot.toolsUsed[tool] = (snapshot.toolsUsed[tool] ?? 0) + 1;
|
|
23599
|
+
if (event.type === "workflow.gate.failed") snapshot.gatesFailed += 1;
|
|
23600
|
+
const tenantId = stringValue(event.data["tenantId"]);
|
|
23601
|
+
if (tenantId) {
|
|
23602
|
+
snapshot.tenantUsage[tenantId] ??= {
|
|
23603
|
+
events: 0,
|
|
23604
|
+
inputTokens: 0,
|
|
23605
|
+
outputTokens: 0,
|
|
23606
|
+
estimatedCostUsd: 0
|
|
23607
|
+
};
|
|
23608
|
+
snapshot.tenantUsage[tenantId].events += 1;
|
|
23609
|
+
snapshot.tenantUsage[tenantId].inputTokens += inputTokens;
|
|
23610
|
+
snapshot.tenantUsage[tenantId].outputTokens += outputTokens;
|
|
23611
|
+
snapshot.tenantUsage[tenantId].estimatedCostUsd += estimatedCostUsd;
|
|
23612
|
+
}
|
|
23613
|
+
}
|
|
23614
|
+
return snapshot;
|
|
23615
|
+
}
|
|
23616
|
+
function redactTraceAttributes(input) {
|
|
23617
|
+
return redactUnknown(input);
|
|
23618
|
+
}
|
|
23619
|
+
function inferSpanKind(event) {
|
|
23620
|
+
if (event.type.startsWith("workflow.gate")) return "gate";
|
|
23621
|
+
if (event.type.startsWith("workflow.")) return "workflow";
|
|
23622
|
+
if (event.type.startsWith("agent.handoff")) return "handoff";
|
|
23623
|
+
if (event.type.startsWith("agent.")) return "agent";
|
|
23624
|
+
if (event.type.startsWith("tool.") || event.type === "agent.tool.called") return "tool";
|
|
23625
|
+
if (event.type.startsWith("shared_state.") || event.type.startsWith("checkpoint.")) {
|
|
23626
|
+
return "state";
|
|
23627
|
+
}
|
|
23628
|
+
if (event.type.startsWith("turn.")) return "llm";
|
|
23629
|
+
return "runtime";
|
|
23630
|
+
}
|
|
23631
|
+
function redactUnknown(value) {
|
|
23632
|
+
if (typeof value === "string") {
|
|
23633
|
+
return redactSecrets(value, { enabled: true }).content;
|
|
23634
|
+
}
|
|
23635
|
+
if (Array.isArray(value)) return value.map(redactUnknown);
|
|
23636
|
+
if (isRecord(value)) {
|
|
23637
|
+
return Object.fromEntries(
|
|
23638
|
+
Object.entries(value).map(([key, nested]) => [key, redactUnknown(nested)])
|
|
23639
|
+
);
|
|
23640
|
+
}
|
|
23641
|
+
return value;
|
|
23642
|
+
}
|
|
23643
|
+
function isRecord(value) {
|
|
23644
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
23645
|
+
}
|
|
23646
|
+
function stringValue(value) {
|
|
23647
|
+
return typeof value === "string" ? value : void 0;
|
|
23648
|
+
}
|
|
23649
|
+
function numberValue(value) {
|
|
23650
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
23651
|
+
}
|
|
22630
23652
|
var PUBLIC_WEB_TOOLS = /* @__PURE__ */ new Set(["search_public_docs", "list_public_services"]);
|
|
22631
23653
|
var CUSTOMER_SUPPORT_TOOLS = /* @__PURE__ */ new Set([
|
|
22632
23654
|
"search_public_docs",
|
|
@@ -34597,8 +35619,6 @@ var AGENT_PRESETS = [
|
|
|
34597
35619
|
internalOpsAssistantPreset,
|
|
34598
35620
|
codingAgentPreset
|
|
34599
35621
|
];
|
|
34600
|
-
|
|
34601
|
-
// src/adapters/index.ts
|
|
34602
35622
|
function createHttpAssistantAdapter(runtime) {
|
|
34603
35623
|
return {
|
|
34604
35624
|
createSession(metadata = {}) {
|
|
@@ -34660,12 +35680,188 @@ function createWhatsAppAssistantAdapter(runtime) {
|
|
|
34660
35680
|
}
|
|
34661
35681
|
};
|
|
34662
35682
|
}
|
|
35683
|
+
var InMemoryChannelSessionMapper = class {
|
|
35684
|
+
sessions = /* @__PURE__ */ new Map();
|
|
35685
|
+
getSessionId(input) {
|
|
35686
|
+
return this.sessions.get(sessionKey(input));
|
|
35687
|
+
}
|
|
35688
|
+
setSessionId(input) {
|
|
35689
|
+
this.sessions.set(sessionKey(input), input.sessionId);
|
|
35690
|
+
}
|
|
35691
|
+
};
|
|
35692
|
+
var WhatsAppCloudAdapter = class {
|
|
35693
|
+
constructor(options) {
|
|
35694
|
+
this.options = options;
|
|
35695
|
+
this.mapper = options.sessionMapper ?? new InMemoryChannelSessionMapper();
|
|
35696
|
+
}
|
|
35697
|
+
options;
|
|
35698
|
+
mapper;
|
|
35699
|
+
processedMessageIds = /* @__PURE__ */ new Set();
|
|
35700
|
+
optOutSenders = /* @__PURE__ */ new Set();
|
|
35701
|
+
senderTimestamps = /* @__PURE__ */ new Map();
|
|
35702
|
+
validateSignature(rawBody, signature) {
|
|
35703
|
+
if (!signature?.startsWith("sha256=")) return false;
|
|
35704
|
+
const expected = createHmac("sha256", this.options.appSecret).update(rawBody).digest("hex");
|
|
35705
|
+
const actual = signature.slice("sha256=".length);
|
|
35706
|
+
const expectedBuffer = Buffer.from(expected, "hex");
|
|
35707
|
+
const actualBuffer = Buffer.from(actual, "hex");
|
|
35708
|
+
return expectedBuffer.length === actualBuffer.length && timingSafeEqual(expectedBuffer, actualBuffer);
|
|
35709
|
+
}
|
|
35710
|
+
async handleWebhook(input) {
|
|
35711
|
+
if (!this.validateSignature(input.rawBody, input.signature)) {
|
|
35712
|
+
throw new Error("Invalid WhatsApp webhook signature.");
|
|
35713
|
+
}
|
|
35714
|
+
const messages = parseWhatsAppCloudMessages(input.body ?? JSON.parse(input.rawBody));
|
|
35715
|
+
const outputs = [];
|
|
35716
|
+
for (const message of messages) {
|
|
35717
|
+
if (this.processedMessageIds.has(message.messageId)) {
|
|
35718
|
+
return { accepted: true, duplicate: true, outputs };
|
|
35719
|
+
}
|
|
35720
|
+
this.processedMessageIds.add(message.messageId);
|
|
35721
|
+
const senderKey = `${input.tenantId}:${message.from}`;
|
|
35722
|
+
const normalizedText = message.text.trim();
|
|
35723
|
+
if (this.isOptOut(normalizedText)) {
|
|
35724
|
+
this.optOutSenders.add(senderKey);
|
|
35725
|
+
return { accepted: true, optedOut: true, outputs };
|
|
35726
|
+
}
|
|
35727
|
+
if (this.isOptIn(normalizedText)) {
|
|
35728
|
+
this.optOutSenders.delete(senderKey);
|
|
35729
|
+
}
|
|
35730
|
+
if (this.optOutSenders.has(senderKey)) {
|
|
35731
|
+
return { accepted: true, optedOut: true, outputs };
|
|
35732
|
+
}
|
|
35733
|
+
if (!this.consumeRateLimit(senderKey)) {
|
|
35734
|
+
return { accepted: true, rateLimited: true, outputs };
|
|
35735
|
+
}
|
|
35736
|
+
const sessionId = this.getOrCreateSession(input.tenantId, message);
|
|
35737
|
+
const result = await this.options.runtime.runTurn({
|
|
35738
|
+
sessionId,
|
|
35739
|
+
content: normalizedText || mediaFallbackText(message.media),
|
|
35740
|
+
metadata: {
|
|
35741
|
+
surface: "whatsapp",
|
|
35742
|
+
channel: "whatsapp-cloud",
|
|
35743
|
+
tenantId: input.tenantId,
|
|
35744
|
+
phoneNumber: message.from,
|
|
35745
|
+
profileName: message.profileName,
|
|
35746
|
+
messageId: message.messageId,
|
|
35747
|
+
media: message.media
|
|
35748
|
+
}
|
|
35749
|
+
});
|
|
35750
|
+
outputs.push({ sessionId, content: result.content, metadata: { model: result.model } });
|
|
35751
|
+
}
|
|
35752
|
+
return { accepted: true, outputs };
|
|
35753
|
+
}
|
|
35754
|
+
getOrCreateSession(tenantId, message) {
|
|
35755
|
+
const existing = this.mapper.getSessionId({
|
|
35756
|
+
tenantId,
|
|
35757
|
+
channel: "whatsapp-cloud",
|
|
35758
|
+
senderId: message.from
|
|
35759
|
+
});
|
|
35760
|
+
if (existing) return existing;
|
|
35761
|
+
const session = this.options.runtime.createSession({
|
|
35762
|
+
mode: "ask",
|
|
35763
|
+
metadata: {
|
|
35764
|
+
surface: "whatsapp",
|
|
35765
|
+
channel: "whatsapp-cloud",
|
|
35766
|
+
tenantId,
|
|
35767
|
+
phoneNumber: message.from,
|
|
35768
|
+
profileName: message.profileName
|
|
35769
|
+
}
|
|
35770
|
+
});
|
|
35771
|
+
this.mapper.setSessionId({
|
|
35772
|
+
tenantId,
|
|
35773
|
+
channel: "whatsapp-cloud",
|
|
35774
|
+
senderId: message.from,
|
|
35775
|
+
sessionId: session.id
|
|
35776
|
+
});
|
|
35777
|
+
return session.id;
|
|
35778
|
+
}
|
|
35779
|
+
consumeRateLimit(senderKey) {
|
|
35780
|
+
const limit = this.options.maxMessagesPerMinutePerSender;
|
|
35781
|
+
if (!limit) return true;
|
|
35782
|
+
const now = Date.now();
|
|
35783
|
+
const recent = (this.senderTimestamps.get(senderKey) ?? []).filter(
|
|
35784
|
+
(timestamp) => timestamp > now - 6e4
|
|
35785
|
+
);
|
|
35786
|
+
if (recent.length >= limit) {
|
|
35787
|
+
this.senderTimestamps.set(senderKey, recent);
|
|
35788
|
+
return false;
|
|
35789
|
+
}
|
|
35790
|
+
recent.push(now);
|
|
35791
|
+
this.senderTimestamps.set(senderKey, recent);
|
|
35792
|
+
return true;
|
|
35793
|
+
}
|
|
35794
|
+
isOptOut(text2) {
|
|
35795
|
+
const keywords = this.options.optOutKeywords ?? ["stop", "unsubscribe", "baja"];
|
|
35796
|
+
return keywords.includes(text2.toLowerCase());
|
|
35797
|
+
}
|
|
35798
|
+
isOptIn(text2) {
|
|
35799
|
+
const keywords = this.options.optInKeywords ?? ["start", "subscribe", "alta"];
|
|
35800
|
+
return keywords.includes(text2.toLowerCase());
|
|
35801
|
+
}
|
|
35802
|
+
};
|
|
35803
|
+
function createWhatsAppCloudAdapter(options) {
|
|
35804
|
+
return new WhatsAppCloudAdapter(options);
|
|
35805
|
+
}
|
|
35806
|
+
function createInMemoryChannelSessionMapper() {
|
|
35807
|
+
return new InMemoryChannelSessionMapper();
|
|
35808
|
+
}
|
|
35809
|
+
function sessionKey(input) {
|
|
35810
|
+
return `${input.tenantId}:${input.channel}:${input.senderId}`;
|
|
35811
|
+
}
|
|
35812
|
+
function parseWhatsAppCloudMessages(body) {
|
|
35813
|
+
if (!body || typeof body !== "object") return [];
|
|
35814
|
+
const entries = Array.isArray(body.entry) ? body.entry : [];
|
|
35815
|
+
return entries.flatMap((entry) => {
|
|
35816
|
+
const changes = Array.isArray(entry.changes) ? entry.changes : [];
|
|
35817
|
+
return changes.flatMap((change) => {
|
|
35818
|
+
const value = change.value;
|
|
35819
|
+
const contacts = Array.isArray(value?.contacts) ? value.contacts : [];
|
|
35820
|
+
const profileByWaId = new Map(
|
|
35821
|
+
contacts.map((contact) => [
|
|
35822
|
+
contact.wa_id,
|
|
35823
|
+
contact.profile?.name
|
|
35824
|
+
])
|
|
35825
|
+
);
|
|
35826
|
+
const messages = Array.isArray(value?.messages) ? value.messages : [];
|
|
35827
|
+
return messages.map((message) => normalizeWhatsAppMessage(message, profileByWaId));
|
|
35828
|
+
});
|
|
35829
|
+
});
|
|
35830
|
+
}
|
|
35831
|
+
function normalizeWhatsAppMessage(message, profileByWaId) {
|
|
35832
|
+
const record = message;
|
|
35833
|
+
const from = String(record["from"] ?? "");
|
|
35834
|
+
const type = String(record["type"] ?? "text");
|
|
35835
|
+
const text2 = type === "text" ? String(record["text"]?.body ?? "") : "";
|
|
35836
|
+
const media = normalizeMedia(record, type);
|
|
35837
|
+
return {
|
|
35838
|
+
messageId: String(record["id"] ?? ""),
|
|
35839
|
+
from,
|
|
35840
|
+
text: text2 || media?.caption || "",
|
|
35841
|
+
profileName: profileByWaId.get(from),
|
|
35842
|
+
media
|
|
35843
|
+
};
|
|
35844
|
+
}
|
|
35845
|
+
function normalizeMedia(record, type) {
|
|
35846
|
+
if (!["image", "audio", "video", "document", "sticker"].includes(type)) return void 0;
|
|
35847
|
+
const mediaRecord = record[type];
|
|
35848
|
+
if (!mediaRecord) return void 0;
|
|
35849
|
+
return {
|
|
35850
|
+
id: String(mediaRecord["id"] ?? ""),
|
|
35851
|
+
type,
|
|
35852
|
+
mimeType: typeof mediaRecord["mime_type"] === "string" ? mediaRecord["mime_type"] : void 0,
|
|
35853
|
+
caption: typeof mediaRecord["caption"] === "string" ? mediaRecord["caption"] : void 0
|
|
35854
|
+
};
|
|
35855
|
+
}
|
|
35856
|
+
function mediaFallbackText(media) {
|
|
35857
|
+
return media ? `[${media.type}:${media.id}]` : "";
|
|
35858
|
+
}
|
|
34663
35859
|
|
|
34664
35860
|
// src/index.ts
|
|
34665
35861
|
init_errors();
|
|
34666
35862
|
init_logger();
|
|
34667
35863
|
init_proxy();
|
|
34668
35864
|
|
|
34669
|
-
export { ADRGenerator, AGENT_MODES, AGENT_PRESETS, AgentGraphEngine, AgentRunner, AgentRuntime, AnthropicProvider, ArchitectureGenerator, BacklogGenerator, CICDGenerator, CocoError, CodeGenerator, CodeReviewer, CompleteExecutor, ConfigError, ConvergeExecutor, DEFAULT_WORKFLOWS, DefaultPermissionPolicy, DefaultRuntimeTurnRunner, DiscoveryEngine, DockerGenerator, DocsGenerator, FileEventLog, FileRuntimeSessionStore, FileSharedWorkspaceStore, InMemoryEventLog, InMemoryKnowledgeRetriever, InMemoryRuntimeSessionStore, InMemorySharedWorkspaceStore, InMemoryVectorStore, OrchestrateExecutor, OutputExecutor, PhaseError, ProviderRegistry, RuntimeToolExecutor, SessionManager, SharedWorkspaceState, SimpleTextChunker, SpecificationGenerator, TaskError, TaskIterator, ToolCallingRuntimeTurnRunner, ToolRegistry, VERSION, WorkflowCatalog, WorkflowEngine, WorkflowRegistry, appointmentBookingAssistantPreset, codingAgentPreset, configExists, createADRGenerator, createAgentArtifact, createAgentFromBlueprint, createAgentGraphEngine, createAgentRunner, createAgentRuntime, createAgentTraceContext, createAnthropicProvider, createArchitectureGenerator, createBacklogGenerator, createBaseBlueprint, createCICDGenerator, createCodeGenerator, createCodeReviewer, createCodingToolRegistry, createCompleteExecutor, createConvergeExecutor, createCustomerSupportToolRegistry, createDefaultConfig, createDefaultRuntimeTurnRunner, createDiscoveryEngine, createDockerGenerator, createDocsGenerator, createEventLog, createFileEventLog, createFileRuntimeSessionStore, createFullToolRegistry, createHttpAssistantAdapter, createInMemoryKnowledgeRetriever, createInMemoryVectorStore, createLogger, createMcpToolPolicy, createNoToolRegistry, createOrchestrateExecutor, createOrchestrator, createOutputExecutor, createPermissionPolicy, createProvider, createProviderRegistry, createPublicWebToolRegistry, createRagPipeline, createRagToolRegistry, createRuntimeHttpServer, createRuntimeRequestContext, createRuntimeSessionStore, createRuntimeToolExecutor, createSafeToolRegistry, createSessionManager, createSimpleTextChunker, createSpecificationGenerator, createStreamingHttpAssistantAdapter, createSummaryArtifact, createSupportRagToolRegistry, createTaskIterator, createToolCallingRuntimeTurnRunner, createToolRegistry, createWebhookAssistantAdapter, createWhatsAppAssistantAdapter, createWorkflowCatalog, createWorkflowEngine, createWorkflowRegistry, customerSupportAssistantPreset, defaultPublicGuardrails, dryRunAgentGraphNodeExecutor, evaluateAgentToolPolicy, formatRetrievedSourcesForPrompt, getAgentMode, installProxyDispatcher, internalOpsAssistantPreset, isAgentMode, listAgentModes, listLegacyAgentRoleMappings, loadConfig, mapActionModeToRuntimeMode, mapLegacyAgentRole, mergeRuntimePolicy, normalizeAgentRunResult, publicWebsiteAssistantPreset, ragKnowledgeAssistantPreset, redactSecrets, registerAllTools, runGuardrails, runtimeContextToMetadata, salesIntakeAssistantPreset, saveConfig, supportRagAssistantPreset, validateAgentCapabilities, validateAgentGraph, validateStructuredOutput, workflowToAgentGraph };
|
|
35865
|
+
export { ADRGenerator, AGENT_MODES, AGENT_PRESETS, AgentDefinitionRegistry, AgentGraphEngine, AgentRunner, AgentRuntime, AnthropicProvider, ArchitectureGenerator, AsyncPostgresEventLog, AsyncPostgresRuntimeSessionStore, BacklogGenerator, CICDGenerator, CocoError, CodeGenerator, CodeReviewer, CompleteExecutor, ConfigError, ConvergeExecutor, DEFAULT_WORKFLOWS, DefaultPermissionPolicy, DefaultRuntimeTurnRunner, DiscoveryEngine, DockerGenerator, DocsGenerator, FileEventLog, FileRuntimeSessionStore, FileSharedWorkspaceStore, FileTraceExporter, InMemoryEventLog, InMemoryKnowledgeRetriever, InMemoryRuntimeSessionStore, InMemorySharedWorkspaceStore, InMemoryTraceExporter, InMemoryVectorStore, OpenTelemetryTraceExporter, OrchestrateExecutor, OutputExecutor, PhaseError, PostgresRuntimeAuditStore, ProviderRegistry, RuntimeAgentNodeExecutor, RuntimePolicyViolation, RuntimeToolExecutor, SessionManager, SharedWorkspaceState, SimpleTextChunker, SpecificationGenerator, TaskError, TaskIterator, TenantScopedEventLog, TenantScopedRuntimeSessionStore, ToolCallingRuntimeTurnRunner, ToolRegistry, VERSION, WorkflowCatalog, WorkflowEngine, WorkflowRegistry, appointmentBookingAssistantPreset, assertRuntimeTenantBoundary, assertRuntimeTurnWithinPolicy, codingAgentPreset, collectRuntimeMetrics, configExists, createADRGenerator, createAgentArtifact, createAgentDefinitionRegistry, createAgentFromBlueprint, createAgentGraphEngine, createAgentRunner, createAgentRuntime, createAgentTraceContext, createAnthropicProvider, createArchitectureGenerator, createAsyncPostgresEventLog, createAsyncPostgresRuntimeSessionStore, createBacklogGenerator, createBaseBlueprint, createCICDGenerator, createCodeGenerator, createCodeReviewer, createCodingToolRegistry, createCompleteExecutor, createConvergeExecutor, createCustomerSupportToolRegistry, createDefaultConfig, createDefaultRuntimeTurnRunner, createDiscoveryEngine, createDockerGenerator, createDocsGenerator, createDocumentAccessPolicy, createEventLog, createFileEventLog, createFileRuntimeSessionStore, createFullToolRegistry, createHttpAssistantAdapter, createInMemoryChannelSessionMapper, createInMemoryKnowledgeRetriever, createInMemoryVectorStore, createLogger, createMcpToolPolicy, createNoToolRegistry, createOrchestrateExecutor, createOrchestrator, createOutputExecutor, createPermissionPolicy, createPostgresRuntimeAuditStore, createProvider, createProviderRegistry, createPublicWebToolRegistry, createRagIngestionJob, createRagPipeline, createRagToolRegistry, createRetentionCutoffs, createRuntimeAgentNodeExecutor, createRuntimeHttpServer, createRuntimeRequestContext, createRuntimeSessionStore, createRuntimeTenantBoundary, createRuntimeToolExecutor, createSafeToolRegistry, createSessionManager, createSimpleTextChunker, createSpecificationGenerator, createStreamingHttpAssistantAdapter, createSummaryArtifact, createSupportRagToolRegistry, createTaskIterator, createTenantScopedEventLog, createTenantScopedRuntimeSessionStore, createToolCallingRuntimeTurnRunner, createToolRegistry, createWebhookAssistantAdapter, createWhatsAppAssistantAdapter, createWhatsAppCloudAdapter, createWorkflowCatalog, createWorkflowEngine, createWorkflowRegistry, customerSupportAssistantPreset, defaultPublicGuardrails, dryRunAgentGraphNodeExecutor, evaluateAgentToolPolicy, evaluateGroundedness, eventToSpan, exportRuntimeEventsAsSpans, formatRetrievedSourcesForPrompt, getAgentMode, installProxyDispatcher, internalOpsAssistantPreset, isAgentMode, listAgentModes, listLegacyAgentRoleMappings, loadConfig, mapActionModeToRuntimeMode, mapLegacyAgentRole, mergeRuntimePolicy, normalizeAgentRunResult, publicWebsiteAssistantPreset, ragKnowledgeAssistantPreset, redactSecrets, redactTraceAttributes, registerAllTools, runGuardrailPipeline, runGuardrails, runtimeContextToMetadata, salesIntakeAssistantPreset, saveConfig, supportRagAssistantPreset, validateAgentCapabilities, validateAgentGraph, validateStructuredOutput, verifyCitations, workflowToAgentGraph };
|
|
34670
35866
|
//# sourceMappingURL=index.js.map
|
|
34671
35867
|
//# sourceMappingURL=index.js.map
|