@contractspec/lib.ai-agent 7.0.7 → 8.0.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/README.md +45 -4
- package/dist/agent/agent-factory.d.ts +14 -3
- package/dist/agent/agent-factory.js +676 -111
- package/dist/agent/contract-spec-agent.d.ts +16 -2
- package/dist/agent/contract-spec-agent.js +672 -110
- package/dist/agent/index.js +685 -118
- package/dist/agent/json-runner.d.ts +1 -1
- package/dist/agent/json-runner.js +672 -110
- package/dist/agent/unified-agent.d.ts +2 -2
- package/dist/agent/unified-agent.js +685 -118
- package/dist/approval/index.js +6 -1
- package/dist/approval/workflow.js +5 -1
- package/dist/exporters/claude-agent-exporter.d.ts +1 -1
- package/dist/exporters/claude-agent-exporter.js +3 -51
- package/dist/exporters/index.js +8 -54
- package/dist/exporters/opencode-exporter.d.ts +1 -1
- package/dist/exporters/opencode-exporter.js +3 -51
- package/dist/exporters/types.d.ts +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3805 -71
- package/dist/interop/index.js +3 -51
- package/dist/interop/spec-consumer.d.ts +1 -1
- package/dist/interop/spec-consumer.js +3 -51
- package/dist/interop/tool-consumer.d.ts +1 -1
- package/dist/interop/types.d.ts +1 -1
- package/dist/knowledge/injector.d.ts +1 -1
- package/dist/node/agent/agent-factory.js +676 -111
- package/dist/node/agent/contract-spec-agent.js +672 -110
- package/dist/node/agent/index.js +685 -118
- package/dist/node/agent/json-runner.js +672 -110
- package/dist/node/agent/unified-agent.js +685 -118
- package/dist/node/approval/index.js +6 -1
- package/dist/node/approval/workflow.js +5 -1
- package/dist/node/exporters/claude-agent-exporter.js +3 -51
- package/dist/node/exporters/index.js +8 -54
- package/dist/node/exporters/opencode-exporter.js +3 -51
- package/dist/node/index.js +3805 -71
- package/dist/node/interop/index.js +3 -51
- package/dist/node/interop/spec-consumer.js +3 -51
- package/dist/node/providers/claude-agent-sdk/adapter.js +3 -51
- package/dist/node/providers/claude-agent-sdk/index.js +3 -51
- package/dist/node/providers/index.js +8 -53
- package/dist/node/providers/opencode-sdk/adapter.js +4 -51
- package/dist/node/providers/opencode-sdk/index.js +4 -51
- package/dist/node/session/index.js +26 -1
- package/dist/node/session/store.js +26 -1
- package/dist/node/telemetry/adapter.js +2 -0
- package/dist/node/telemetry/index.js +2 -0
- package/dist/providers/claude-agent-sdk/adapter.d.ts +1 -1
- package/dist/providers/claude-agent-sdk/adapter.js +3 -51
- package/dist/providers/claude-agent-sdk/index.js +3 -51
- package/dist/providers/claude-agent-sdk/tool-bridge.d.ts +1 -8
- package/dist/providers/index.js +8 -53
- package/dist/providers/opencode-sdk/adapter.d.ts +1 -13
- package/dist/providers/opencode-sdk/adapter.js +4 -51
- package/dist/providers/opencode-sdk/agent-bridge.d.ts +1 -10
- package/dist/providers/opencode-sdk/index.js +4 -51
- package/dist/providers/opencode-sdk/tool-bridge.d.ts +1 -4
- package/dist/providers/types.d.ts +1 -8
- package/dist/session/index.js +26 -1
- package/dist/session/store.d.ts +2 -2
- package/dist/session/store.js +26 -1
- package/dist/telemetry/adapter.d.ts +1 -0
- package/dist/telemetry/adapter.js +2 -0
- package/dist/telemetry/index.js +2 -0
- package/dist/tools/knowledge-tool.d.ts +1 -1
- package/dist/tools/mcp-server.d.ts +1 -1
- package/dist/tools/operation-tool-handler.d.ts +1 -1
- package/dist/tools/tool-adapter.d.ts +1 -1
- package/dist/types.d.ts +13 -0
- package/package.json +8 -44
- package/dist/node/spec/index.js +0 -2233
- package/dist/node/spec/registry.js +0 -2178
- package/dist/node/spec/spec.js +0 -2188
- package/dist/spec/index.d.ts +0 -2
- package/dist/spec/index.js +0 -2233
- package/dist/spec/registry.d.ts +0 -41
- package/dist/spec/registry.js +0 -2178
- package/dist/spec/spec.d.ts +0 -218
- package/dist/spec/spec.js +0 -2188
- /package/dist/{spec/spec.test.d.ts → session/store.test.d.ts} +0 -0
|
@@ -2131,6 +2131,148 @@ var init_i18n = __esm(() => {
|
|
|
2131
2131
|
init_messages();
|
|
2132
2132
|
});
|
|
2133
2133
|
|
|
2134
|
+
// src/approval/workflow.ts
|
|
2135
|
+
import { randomUUID } from "crypto";
|
|
2136
|
+
|
|
2137
|
+
class InMemoryApprovalStore {
|
|
2138
|
+
items = new Map;
|
|
2139
|
+
maxItems;
|
|
2140
|
+
constructor(options = {}) {
|
|
2141
|
+
this.maxItems = options.maxItems ?? 1000;
|
|
2142
|
+
}
|
|
2143
|
+
async create(request) {
|
|
2144
|
+
this.evictIfNeeded();
|
|
2145
|
+
this.items.set(request.id, request);
|
|
2146
|
+
}
|
|
2147
|
+
async get(id) {
|
|
2148
|
+
return this.items.get(id) ?? null;
|
|
2149
|
+
}
|
|
2150
|
+
async getByToolCallId(toolCallId) {
|
|
2151
|
+
for (const request of this.items.values()) {
|
|
2152
|
+
if (request.toolCallId === toolCallId) {
|
|
2153
|
+
return request;
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
return null;
|
|
2157
|
+
}
|
|
2158
|
+
async update(id, updates) {
|
|
2159
|
+
const existing = this.items.get(id);
|
|
2160
|
+
if (existing) {
|
|
2161
|
+
this.items.set(id, { ...existing, ...updates });
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
async list(options) {
|
|
2165
|
+
let results = [...this.items.values()];
|
|
2166
|
+
if (options?.status) {
|
|
2167
|
+
results = results.filter((r) => r.status === options.status);
|
|
2168
|
+
}
|
|
2169
|
+
if (options?.agentId) {
|
|
2170
|
+
results = results.filter((r) => r.agentId === options.agentId);
|
|
2171
|
+
}
|
|
2172
|
+
if (options?.tenantId) {
|
|
2173
|
+
results = results.filter((r) => r.tenantId === options.tenantId);
|
|
2174
|
+
}
|
|
2175
|
+
return results.sort((a, b) => b.requestedAt.getTime() - a.requestedAt.getTime());
|
|
2176
|
+
}
|
|
2177
|
+
clear() {
|
|
2178
|
+
this.items.clear();
|
|
2179
|
+
}
|
|
2180
|
+
evictIfNeeded() {
|
|
2181
|
+
if (this.items.size < this.maxItems) {
|
|
2182
|
+
return;
|
|
2183
|
+
}
|
|
2184
|
+
let oldestId = null;
|
|
2185
|
+
let oldestTimestamp = Number.POSITIVE_INFINITY;
|
|
2186
|
+
for (const [id, request] of this.items.entries()) {
|
|
2187
|
+
const ts = request.requestedAt.getTime();
|
|
2188
|
+
if (ts < oldestTimestamp) {
|
|
2189
|
+
oldestTimestamp = ts;
|
|
2190
|
+
oldestId = id;
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
if (oldestId) {
|
|
2194
|
+
this.items.delete(oldestId);
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
|
|
2199
|
+
class ApprovalWorkflow {
|
|
2200
|
+
store;
|
|
2201
|
+
constructor(store = new InMemoryApprovalStore) {
|
|
2202
|
+
this.store = store;
|
|
2203
|
+
}
|
|
2204
|
+
async requestApproval(params) {
|
|
2205
|
+
const request = {
|
|
2206
|
+
id: randomUUID(),
|
|
2207
|
+
sessionId: params.sessionId,
|
|
2208
|
+
agentId: params.agentId,
|
|
2209
|
+
tenantId: params.tenantId,
|
|
2210
|
+
toolName: params.toolName,
|
|
2211
|
+
toolCallId: params.toolCallId,
|
|
2212
|
+
toolArgs: params.toolArgs,
|
|
2213
|
+
reason: params.reason,
|
|
2214
|
+
requestedAt: new Date,
|
|
2215
|
+
status: "pending",
|
|
2216
|
+
payload: params.payload
|
|
2217
|
+
};
|
|
2218
|
+
await this.store.create(request);
|
|
2219
|
+
return request;
|
|
2220
|
+
}
|
|
2221
|
+
async requestApprovalFromToolCall(toolCall, context) {
|
|
2222
|
+
return this.requestApproval({
|
|
2223
|
+
sessionId: context.sessionId,
|
|
2224
|
+
agentId: context.agentId,
|
|
2225
|
+
tenantId: context.tenantId,
|
|
2226
|
+
toolName: toolCall.toolName,
|
|
2227
|
+
toolCallId: toolCall.toolCallId,
|
|
2228
|
+
toolArgs: toolCall.args,
|
|
2229
|
+
reason: context.reason ?? createAgentI18n(context.locale).t("approval.toolRequiresApproval", {
|
|
2230
|
+
name: toolCall.toolName
|
|
2231
|
+
})
|
|
2232
|
+
});
|
|
2233
|
+
}
|
|
2234
|
+
async approve(id, reviewer, notes) {
|
|
2235
|
+
await this.store.update(id, {
|
|
2236
|
+
status: "approved",
|
|
2237
|
+
reviewer,
|
|
2238
|
+
resolvedAt: new Date,
|
|
2239
|
+
notes
|
|
2240
|
+
});
|
|
2241
|
+
}
|
|
2242
|
+
async reject(id, reviewer, notes) {
|
|
2243
|
+
await this.store.update(id, {
|
|
2244
|
+
status: "rejected",
|
|
2245
|
+
reviewer,
|
|
2246
|
+
resolvedAt: new Date,
|
|
2247
|
+
notes
|
|
2248
|
+
});
|
|
2249
|
+
}
|
|
2250
|
+
async getStatus(toolCallId) {
|
|
2251
|
+
const request = await this.store.getByToolCallId(toolCallId);
|
|
2252
|
+
return request?.status ?? null;
|
|
2253
|
+
}
|
|
2254
|
+
async isApproved(toolCallId) {
|
|
2255
|
+
const status = await this.getStatus(toolCallId);
|
|
2256
|
+
return status === "approved";
|
|
2257
|
+
}
|
|
2258
|
+
async listPending(options) {
|
|
2259
|
+
return this.store.list({ ...options, status: "pending" });
|
|
2260
|
+
}
|
|
2261
|
+
async get(id) {
|
|
2262
|
+
return this.store.get(id);
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
function createApprovalWorkflow(store) {
|
|
2266
|
+
if (store && typeof store === "object" && "create" in store && typeof store.create === "function") {
|
|
2267
|
+
return new ApprovalWorkflow(store);
|
|
2268
|
+
}
|
|
2269
|
+
const options = store;
|
|
2270
|
+
return new ApprovalWorkflow(new InMemoryApprovalStore(options));
|
|
2271
|
+
}
|
|
2272
|
+
var init_workflow = __esm(() => {
|
|
2273
|
+
init_i18n();
|
|
2274
|
+
});
|
|
2275
|
+
|
|
2134
2276
|
// src/knowledge/injector.ts
|
|
2135
2277
|
async function injectStaticKnowledge(instructions, knowledgeRefs, retriever, locale) {
|
|
2136
2278
|
if (!retriever)
|
|
@@ -2288,59 +2430,34 @@ class InMemorySessionStore {
|
|
|
2288
2430
|
function createInMemorySessionStore(options) {
|
|
2289
2431
|
return new InMemorySessionStore(options);
|
|
2290
2432
|
}
|
|
2291
|
-
function
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
throw new Error(i18n.t("error.agentMissingVersion", { key: spec.meta.key }));
|
|
2303
|
-
}
|
|
2304
|
-
if (!spec.instructions?.trim()) {
|
|
2305
|
-
throw new Error(i18n.t("error.agentRequiresInstructions", { key: spec.meta.key }));
|
|
2306
|
-
}
|
|
2307
|
-
if (!spec.tools?.length) {
|
|
2308
|
-
throw new Error(i18n.t("error.agentRequiresTool", { key: spec.meta.key }));
|
|
2309
|
-
}
|
|
2310
|
-
for (const [portName, portRef] of Object.entries(spec.runtime?.ports ?? {})) {
|
|
2311
|
-
if (portRef !== undefined && portRef.trim().length === 0) {
|
|
2312
|
-
throw new Error(`Agent ${spec.meta.key} has invalid runtime config: port "${portName}" must not be empty`);
|
|
2433
|
+
function createSecureSessionToken() {
|
|
2434
|
+
const cryptoApi = globalThis.crypto;
|
|
2435
|
+
if (typeof cryptoApi?.randomUUID === "function") {
|
|
2436
|
+
return cryptoApi.randomUUID();
|
|
2437
|
+
}
|
|
2438
|
+
if (typeof cryptoApi?.getRandomValues === "function") {
|
|
2439
|
+
const bytes = cryptoApi.getRandomValues(new Uint8Array(16));
|
|
2440
|
+
const versionByte = bytes.at(6);
|
|
2441
|
+
const variantByte = bytes.at(8);
|
|
2442
|
+
if (versionByte === undefined || variantByte === undefined) {
|
|
2443
|
+
throw new Error("Secure session token generation requires 16 random bytes.");
|
|
2313
2444
|
}
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
}
|
|
2327
|
-
const outputRefCount = [
|
|
2328
|
-
tool.outputPresentation,
|
|
2329
|
-
tool.outputForm,
|
|
2330
|
-
tool.outputDataView
|
|
2331
|
-
].filter(Boolean).length;
|
|
2332
|
-
if (outputRefCount > 1) {
|
|
2333
|
-
throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
|
|
2334
|
-
}
|
|
2335
|
-
}
|
|
2336
|
-
return Object.freeze(spec);
|
|
2445
|
+
bytes[6] = versionByte & 15 | 64;
|
|
2446
|
+
bytes[8] = variantByte & 63 | 128;
|
|
2447
|
+
const hex = [...bytes].map((byte) => byte.toString(16).padStart(2, "0"));
|
|
2448
|
+
return [
|
|
2449
|
+
hex.slice(0, 4).join(""),
|
|
2450
|
+
hex.slice(4, 6).join(""),
|
|
2451
|
+
hex.slice(6, 8).join(""),
|
|
2452
|
+
hex.slice(8, 10).join(""),
|
|
2453
|
+
hex.slice(10, 16).join("")
|
|
2454
|
+
].join("-");
|
|
2455
|
+
}
|
|
2456
|
+
throw new Error("Secure session IDs require Web Crypto support.");
|
|
2337
2457
|
}
|
|
2338
|
-
function
|
|
2339
|
-
return
|
|
2458
|
+
function generateSessionId() {
|
|
2459
|
+
return `sess_${createSecureSessionToken()}`;
|
|
2340
2460
|
}
|
|
2341
|
-
var init_spec = __esm(() => {
|
|
2342
|
-
init_i18n();
|
|
2343
|
-
});
|
|
2344
2461
|
|
|
2345
2462
|
// src/telemetry/adapter.ts
|
|
2346
2463
|
function parseAgentId(agentId) {
|
|
@@ -2409,6 +2526,7 @@ async function trackAgentStep(collector, agentId, step, durationMs, context) {
|
|
|
2409
2526
|
agentId,
|
|
2410
2527
|
actorId: context?.actorId,
|
|
2411
2528
|
tenantId: context?.tenantId,
|
|
2529
|
+
workflowId: context?.workflowId,
|
|
2412
2530
|
stepIndex: context?.stepIndex,
|
|
2413
2531
|
toolName: toolCall.toolName,
|
|
2414
2532
|
toolCallArgs: toolCall.input,
|
|
@@ -2434,6 +2552,7 @@ async function trackAgentStep(collector, agentId, step, durationMs, context) {
|
|
|
2434
2552
|
agentId,
|
|
2435
2553
|
actorId: context?.actorId,
|
|
2436
2554
|
tenantId: context?.tenantId,
|
|
2555
|
+
workflowId: context?.workflowId,
|
|
2437
2556
|
stepIndex: context?.stepIndex,
|
|
2438
2557
|
stepStartedAt: context?.stepStartedAt,
|
|
2439
2558
|
finishReason: step.finishReason,
|
|
@@ -3352,7 +3471,10 @@ var exports_contract_spec_agent = {};
|
|
|
3352
3471
|
__export(exports_contract_spec_agent, {
|
|
3353
3472
|
ContractSpecAgent: () => ContractSpecAgent
|
|
3354
3473
|
});
|
|
3355
|
-
import { randomUUID } from "crypto";
|
|
3474
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
3475
|
+
import {
|
|
3476
|
+
agentKey
|
|
3477
|
+
} from "@contractspec/lib.contracts-spec/agent";
|
|
3356
3478
|
import {
|
|
3357
3479
|
stepCountIs,
|
|
3358
3480
|
Experimental_Agent as ToolLoopAgent
|
|
@@ -3377,7 +3499,10 @@ class ContractSpecAgent {
|
|
|
3377
3499
|
this.mcpCleanup = mcpCleanup;
|
|
3378
3500
|
}
|
|
3379
3501
|
static async create(config) {
|
|
3380
|
-
const effectiveConfig =
|
|
3502
|
+
const effectiveConfig = {
|
|
3503
|
+
...config,
|
|
3504
|
+
approvalWorkflow: config.approvalWorkflow ?? (config.spec.policy?.escalation?.approvalWorkflow ? createApprovalWorkflow() : undefined)
|
|
3505
|
+
};
|
|
3381
3506
|
let mcpToolset = null;
|
|
3382
3507
|
if ((effectiveConfig.mcpServers?.length ?? 0) > 0) {
|
|
3383
3508
|
mcpToolset = await createMcpToolsets(effectiveConfig.mcpServers ?? [], {
|
|
@@ -3430,34 +3555,27 @@ class ContractSpecAgent {
|
|
|
3430
3555
|
}
|
|
3431
3556
|
async generate(params) {
|
|
3432
3557
|
const sessionId = params.options?.sessionId ?? generateSessionId();
|
|
3433
|
-
const traceId = params.options?.metadata?.["traceId"] ?? this.config.posthogConfig?.tracingOptions?.posthogTraceId ??
|
|
3558
|
+
const traceId = params.options?.metadata?.["traceId"] ?? this.config.posthogConfig?.tracingOptions?.posthogTraceId ?? randomUUID2();
|
|
3559
|
+
const workflowId = params.options?.workflowId ?? params.options?.metadata?.["workflowId"];
|
|
3560
|
+
const threadId = params.options?.threadId ?? params.options?.metadata?.["threadId"];
|
|
3561
|
+
const runtimeAdapter = this.resolveRuntimeAdapter();
|
|
3434
3562
|
this.activeStepContexts.set(sessionId, {
|
|
3435
3563
|
traceId,
|
|
3436
3564
|
tenantId: params.options?.tenantId,
|
|
3437
3565
|
actorId: params.options?.actorId,
|
|
3566
|
+
workflowId,
|
|
3567
|
+
threadId,
|
|
3438
3568
|
stepIndex: 0,
|
|
3439
3569
|
stepStartedAt: new Date
|
|
3440
3570
|
});
|
|
3441
|
-
if (
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
tenantId: params.options?.tenantId,
|
|
3448
|
-
actorId: params.options?.actorId,
|
|
3449
|
-
status: "running",
|
|
3450
|
-
messages: [],
|
|
3451
|
-
steps: [],
|
|
3452
|
-
metadata: params.options?.metadata
|
|
3453
|
-
});
|
|
3454
|
-
} else if (existing.status !== "running") {
|
|
3455
|
-
await this.config.sessionStore.update(sessionId, { status: "running" });
|
|
3456
|
-
}
|
|
3457
|
-
await this.config.sessionStore.appendMessage(sessionId, {
|
|
3458
|
-
role: "user",
|
|
3459
|
-
content: params.prompt ?? ""
|
|
3571
|
+
if (!params.messages?.length) {
|
|
3572
|
+
await this.ensureSession({
|
|
3573
|
+
sessionId,
|
|
3574
|
+
prompt: params.prompt ?? "",
|
|
3575
|
+
options: params.options,
|
|
3576
|
+
traceId
|
|
3460
3577
|
});
|
|
3578
|
+
await this.runSessionMiddleware(sessionId, runtimeAdapter?.middleware?.beforeModel);
|
|
3461
3579
|
}
|
|
3462
3580
|
const model = await this.resolveModelForCall({
|
|
3463
3581
|
sessionId,
|
|
@@ -3472,6 +3590,8 @@ class ContractSpecAgent {
|
|
|
3472
3590
|
tenantId: params.options?.tenantId,
|
|
3473
3591
|
actorId: params.options?.actorId,
|
|
3474
3592
|
sessionId,
|
|
3593
|
+
workflowId,
|
|
3594
|
+
threadId,
|
|
3475
3595
|
metadata: params.options?.metadata
|
|
3476
3596
|
}
|
|
3477
3597
|
};
|
|
@@ -3494,26 +3614,94 @@ ${params.prompt}` : params.prompt ?? "";
|
|
|
3494
3614
|
});
|
|
3495
3615
|
}
|
|
3496
3616
|
} catch (error) {
|
|
3617
|
+
const executionError = toAgentExecutionError(error);
|
|
3497
3618
|
if (this.config.sessionStore) {
|
|
3498
3619
|
await this.config.sessionStore.update(sessionId, {
|
|
3499
|
-
status: "failed"
|
|
3620
|
+
status: "failed",
|
|
3621
|
+
traceId,
|
|
3622
|
+
workflowId,
|
|
3623
|
+
threadId,
|
|
3624
|
+
lastError: executionError
|
|
3500
3625
|
});
|
|
3626
|
+
await this.syncSessionCheckpoint(sessionId);
|
|
3501
3627
|
}
|
|
3628
|
+
await this.emitAgentEvent("agent.failed", {
|
|
3629
|
+
sessionId,
|
|
3630
|
+
tenantId: params.options?.tenantId,
|
|
3631
|
+
workflowId,
|
|
3632
|
+
traceId,
|
|
3633
|
+
metadata: {
|
|
3634
|
+
error: executionError.message,
|
|
3635
|
+
code: executionError.code ?? executionError.kind
|
|
3636
|
+
}
|
|
3637
|
+
});
|
|
3502
3638
|
this.activeStepContexts.delete(sessionId);
|
|
3503
3639
|
throw error;
|
|
3504
3640
|
}
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3641
|
+
if (!params.messages?.length) {
|
|
3642
|
+
await this.runSessionMiddleware(sessionId, runtimeAdapter?.middleware?.afterModel);
|
|
3643
|
+
}
|
|
3644
|
+
let pendingApproval = this.activeStepContexts.get(sessionId)?.pendingApproval;
|
|
3645
|
+
const escalationError = pendingApproval ? undefined : resolveEscalationError(this.spec, result.finishReason);
|
|
3646
|
+
if (this.config.sessionStore && result.text.trim().length > 0) {
|
|
3647
|
+
const currentSession = await this.config.sessionStore.get(sessionId);
|
|
3648
|
+
const lastMessage = currentSession?.messages.at(-1);
|
|
3649
|
+
const lastContent = lastMessage && "content" in lastMessage ? lastMessage.content : undefined;
|
|
3650
|
+
if (lastMessage?.role !== "assistant" || lastContent !== result.text) {
|
|
3651
|
+
await this.config.sessionStore.appendMessage(sessionId, {
|
|
3652
|
+
role: "assistant",
|
|
3653
|
+
content: result.text
|
|
3654
|
+
});
|
|
3655
|
+
}
|
|
3656
|
+
}
|
|
3657
|
+
if (!pendingApproval && escalationError) {
|
|
3658
|
+
pendingApproval = await this.requestApproval(sessionId, {
|
|
3659
|
+
toolName: this.spec.policy?.escalation?.approvalWorkflow ?? "approval_required",
|
|
3660
|
+
toolCallId: `approval_${sessionId}`,
|
|
3661
|
+
args: {
|
|
3662
|
+
finishReason: result.finishReason,
|
|
3663
|
+
threshold: this.spec.policy?.escalation?.confidenceThreshold ?? this.spec.policy?.confidence?.min
|
|
3664
|
+
},
|
|
3665
|
+
reason: escalationError.message,
|
|
3666
|
+
error: escalationError
|
|
3511
3667
|
});
|
|
3668
|
+
}
|
|
3669
|
+
const finalStatus = pendingApproval ? "escalated" : "completed";
|
|
3670
|
+
if (this.config.sessionStore) {
|
|
3512
3671
|
await this.config.sessionStore.update(sessionId, {
|
|
3513
|
-
status:
|
|
3672
|
+
status: finalStatus,
|
|
3673
|
+
traceId,
|
|
3674
|
+
workflowId,
|
|
3675
|
+
threadId,
|
|
3676
|
+
pendingApprovalRequestId: pendingApproval?.id,
|
|
3677
|
+
lastError: pendingApproval ? escalationError : undefined
|
|
3678
|
+
});
|
|
3679
|
+
await this.syncSessionCheckpoint(sessionId);
|
|
3680
|
+
}
|
|
3681
|
+
if (pendingApproval) {
|
|
3682
|
+
await this.emitAgentEvent("agent.escalated", {
|
|
3683
|
+
sessionId,
|
|
3684
|
+
tenantId: params.options?.tenantId,
|
|
3685
|
+
workflowId,
|
|
3686
|
+
traceId,
|
|
3687
|
+
metadata: {
|
|
3688
|
+
approvalRequestId: pendingApproval.id,
|
|
3689
|
+
reason: pendingApproval.reason
|
|
3690
|
+
}
|
|
3691
|
+
});
|
|
3692
|
+
} else {
|
|
3693
|
+
await this.emitAgentEvent("agent.completed", {
|
|
3694
|
+
sessionId,
|
|
3695
|
+
tenantId: params.options?.tenantId,
|
|
3696
|
+
workflowId,
|
|
3697
|
+
traceId,
|
|
3698
|
+
metadata: {
|
|
3699
|
+
finishReason: result.finishReason
|
|
3700
|
+
}
|
|
3514
3701
|
});
|
|
3515
3702
|
}
|
|
3516
3703
|
const session = this.config.sessionStore ? await this.config.sessionStore.get(sessionId) : null;
|
|
3704
|
+
this.activeStepContexts.delete(sessionId);
|
|
3517
3705
|
return {
|
|
3518
3706
|
text: result.text,
|
|
3519
3707
|
steps: result.steps,
|
|
@@ -3532,23 +3720,25 @@ ${params.prompt}` : params.prompt ?? "";
|
|
|
3532
3720
|
finishReason: result.finishReason,
|
|
3533
3721
|
usage: result.usage,
|
|
3534
3722
|
session: session ?? undefined,
|
|
3535
|
-
pendingApproval:
|
|
3536
|
-
toolName:
|
|
3537
|
-
toolCallId:
|
|
3538
|
-
args:
|
|
3539
|
-
reason: escalationError.message,
|
|
3540
|
-
code: escalationError.code
|
|
3541
|
-
}
|
|
3723
|
+
pendingApproval: pendingApproval ? {
|
|
3724
|
+
toolName: pendingApproval.toolName,
|
|
3725
|
+
toolCallId: pendingApproval.toolCallId,
|
|
3726
|
+
args: pendingApproval.toolArgs
|
|
3542
3727
|
} : undefined
|
|
3543
3728
|
};
|
|
3544
3729
|
}
|
|
3545
3730
|
async stream(params) {
|
|
3546
3731
|
const sessionId = params.options?.sessionId ?? generateSessionId();
|
|
3547
|
-
const traceId = params.options?.metadata?.["traceId"] ?? this.config.posthogConfig?.tracingOptions?.posthogTraceId ??
|
|
3732
|
+
const traceId = params.options?.metadata?.["traceId"] ?? this.config.posthogConfig?.tracingOptions?.posthogTraceId ?? randomUUID2();
|
|
3733
|
+
const workflowId = params.options?.workflowId ?? params.options?.metadata?.["workflowId"];
|
|
3734
|
+
const threadId = params.options?.threadId ?? params.options?.metadata?.["threadId"];
|
|
3735
|
+
const runtimeAdapter = this.resolveRuntimeAdapter();
|
|
3548
3736
|
this.activeStepContexts.set(sessionId, {
|
|
3549
3737
|
traceId,
|
|
3550
3738
|
tenantId: params.options?.tenantId,
|
|
3551
3739
|
actorId: params.options?.actorId,
|
|
3740
|
+
workflowId,
|
|
3741
|
+
threadId,
|
|
3552
3742
|
stepIndex: 0,
|
|
3553
3743
|
stepStartedAt: new Date
|
|
3554
3744
|
});
|
|
@@ -3557,6 +3747,13 @@ ${params.prompt}` : params.prompt ?? "";
|
|
|
3557
3747
|
${params.systemOverride}
|
|
3558
3748
|
|
|
3559
3749
|
${params.prompt}` : params.prompt ?? "";
|
|
3750
|
+
await this.ensureSession({
|
|
3751
|
+
sessionId,
|
|
3752
|
+
prompt,
|
|
3753
|
+
options: params.options,
|
|
3754
|
+
traceId
|
|
3755
|
+
});
|
|
3756
|
+
await this.runSessionMiddleware(sessionId, runtimeAdapter?.middleware?.beforeModel);
|
|
3560
3757
|
const model = await this.resolveModelForCall({
|
|
3561
3758
|
sessionId,
|
|
3562
3759
|
traceId,
|
|
@@ -3564,26 +3761,6 @@ ${params.prompt}` : params.prompt ?? "";
|
|
|
3564
3761
|
});
|
|
3565
3762
|
const effectiveMaxSteps = resolveMaxSteps(params.maxSteps, this.spec.maxSteps);
|
|
3566
3763
|
const inner = this.createInnerAgent(model, effectiveMaxSteps);
|
|
3567
|
-
if (this.config.sessionStore) {
|
|
3568
|
-
const existing = await this.config.sessionStore.get(sessionId);
|
|
3569
|
-
if (!existing) {
|
|
3570
|
-
await this.config.sessionStore.create({
|
|
3571
|
-
sessionId,
|
|
3572
|
-
agentId: this.id,
|
|
3573
|
-
tenantId: params.options?.tenantId,
|
|
3574
|
-
actorId: params.options?.actorId,
|
|
3575
|
-
status: "running",
|
|
3576
|
-
messages: [],
|
|
3577
|
-
steps: [],
|
|
3578
|
-
metadata: params.options?.metadata
|
|
3579
|
-
});
|
|
3580
|
-
}
|
|
3581
|
-
await this.config.sessionStore.appendMessage(sessionId, {
|
|
3582
|
-
role: "user",
|
|
3583
|
-
content: prompt
|
|
3584
|
-
});
|
|
3585
|
-
await this.config.sessionStore.update(sessionId, { status: "running" });
|
|
3586
|
-
}
|
|
3587
3764
|
return inner.stream({
|
|
3588
3765
|
prompt,
|
|
3589
3766
|
abortSignal: params.signal,
|
|
@@ -3591,21 +3768,92 @@ ${params.prompt}` : params.prompt ?? "";
|
|
|
3591
3768
|
tenantId: params.options?.tenantId,
|
|
3592
3769
|
actorId: params.options?.actorId,
|
|
3593
3770
|
sessionId,
|
|
3771
|
+
workflowId,
|
|
3772
|
+
threadId,
|
|
3594
3773
|
metadata: params.options?.metadata
|
|
3595
3774
|
}
|
|
3596
3775
|
});
|
|
3597
3776
|
}
|
|
3598
3777
|
async handleStepFinish(step) {
|
|
3599
3778
|
const sessionId = step.options?.sessionId;
|
|
3779
|
+
const context = sessionId ? this.activeStepContexts.get(sessionId) : undefined;
|
|
3600
3780
|
if (sessionId && this.config.sessionStore) {
|
|
3601
3781
|
await this.config.sessionStore.appendStep(sessionId, step);
|
|
3782
|
+
if (step.text.trim().length > 0) {
|
|
3783
|
+
await this.config.sessionStore.appendMessage(sessionId, {
|
|
3784
|
+
role: "assistant",
|
|
3785
|
+
content: step.text
|
|
3786
|
+
});
|
|
3787
|
+
}
|
|
3788
|
+
for (const toolCall of step.toolCalls ?? []) {
|
|
3789
|
+
await this.emitAgentEvent("agent.tool.called", {
|
|
3790
|
+
sessionId,
|
|
3791
|
+
tenantId: context?.tenantId,
|
|
3792
|
+
workflowId: context?.workflowId,
|
|
3793
|
+
traceId: context?.traceId,
|
|
3794
|
+
stepIndex: context?.stepIndex,
|
|
3795
|
+
toolName: toolCall.toolName,
|
|
3796
|
+
metadata: {
|
|
3797
|
+
toolCallId: toolCall.toolCallId
|
|
3798
|
+
}
|
|
3799
|
+
});
|
|
3800
|
+
}
|
|
3801
|
+
for (const toolResult of step.toolResults ?? []) {
|
|
3802
|
+
const toolCall = step.toolCalls?.find((candidate) => candidate.toolCallId === toolResult.toolCallId);
|
|
3803
|
+
const toolError = extractToolExecutionError(toolResult.output);
|
|
3804
|
+
await this.config.sessionStore.appendMessage(sessionId, {
|
|
3805
|
+
role: "tool",
|
|
3806
|
+
content: stringifyToolResult(toolResult.toolName, toolResult.output)
|
|
3807
|
+
});
|
|
3808
|
+
if (toolError) {
|
|
3809
|
+
await this.emitAgentEvent("agent.tool.failed", {
|
|
3810
|
+
sessionId,
|
|
3811
|
+
tenantId: context?.tenantId,
|
|
3812
|
+
workflowId: context?.workflowId,
|
|
3813
|
+
traceId: context?.traceId,
|
|
3814
|
+
stepIndex: context?.stepIndex,
|
|
3815
|
+
toolName: toolResult.toolName,
|
|
3816
|
+
metadata: {
|
|
3817
|
+
toolCallId: toolResult.toolCallId,
|
|
3818
|
+
error: toolError.message,
|
|
3819
|
+
code: toolError.code
|
|
3820
|
+
}
|
|
3821
|
+
});
|
|
3822
|
+
const shouldEscalate = toolError.kind === "timeout" && this.spec.policy?.escalation?.onTimeout || toolError.kind !== "timeout" && this.spec.policy?.escalation?.onToolFailure;
|
|
3823
|
+
if (shouldEscalate && toolCall && !context?.pendingApproval) {
|
|
3824
|
+
await this.requestApproval(sessionId, {
|
|
3825
|
+
toolName: toolCall.toolName,
|
|
3826
|
+
toolCallId: toolCall.toolCallId,
|
|
3827
|
+
args: toolCall.input,
|
|
3828
|
+
reason: toolError.message,
|
|
3829
|
+
error: toolError
|
|
3830
|
+
});
|
|
3831
|
+
}
|
|
3832
|
+
} else {
|
|
3833
|
+
await this.emitAgentEvent("agent.tool.completed", {
|
|
3834
|
+
sessionId,
|
|
3835
|
+
tenantId: context?.tenantId,
|
|
3836
|
+
workflowId: context?.workflowId,
|
|
3837
|
+
traceId: context?.traceId,
|
|
3838
|
+
stepIndex: context?.stepIndex,
|
|
3839
|
+
toolName: toolResult.toolName,
|
|
3840
|
+
metadata: {
|
|
3841
|
+
toolCallId: toolResult.toolCallId
|
|
3842
|
+
}
|
|
3843
|
+
});
|
|
3844
|
+
}
|
|
3845
|
+
}
|
|
3602
3846
|
await this.config.sessionStore.update(sessionId, {
|
|
3603
|
-
status: step.finishReason === "tool-calls" ? "waiting" : "running"
|
|
3847
|
+
status: context?.pendingApproval ? "escalated" : step.finishReason === "tool-calls" ? "waiting" : "running",
|
|
3848
|
+
workflowId: context?.workflowId,
|
|
3849
|
+
threadId: context?.threadId,
|
|
3850
|
+
traceId: context?.traceId,
|
|
3851
|
+
pendingApprovalRequestId: context?.pendingApproval?.id
|
|
3604
3852
|
});
|
|
3853
|
+
await this.syncSessionCheckpoint(sessionId);
|
|
3605
3854
|
}
|
|
3606
3855
|
if (this.config.telemetryCollector) {
|
|
3607
3856
|
const now = new Date;
|
|
3608
|
-
const context = sessionId ? this.activeStepContexts.get(sessionId) : undefined;
|
|
3609
3857
|
const stepStartedAt = context?.stepStartedAt ?? now;
|
|
3610
3858
|
const durationMs = Math.max(now.getTime() - stepStartedAt.getTime(), 0);
|
|
3611
3859
|
if (context) {
|
|
@@ -3616,6 +3864,7 @@ ${params.prompt}` : params.prompt ?? "";
|
|
|
3616
3864
|
sessionId,
|
|
3617
3865
|
tenantId: context?.tenantId,
|
|
3618
3866
|
actorId: context?.actorId,
|
|
3867
|
+
workflowId: context?.workflowId,
|
|
3619
3868
|
traceId: context?.traceId,
|
|
3620
3869
|
stepIndex: context?.stepIndex,
|
|
3621
3870
|
stepStartedAt
|
|
@@ -3625,6 +3874,215 @@ ${params.prompt}` : params.prompt ?? "";
|
|
|
3625
3874
|
}
|
|
3626
3875
|
}
|
|
3627
3876
|
}
|
|
3877
|
+
async ensureSession(params) {
|
|
3878
|
+
if (!this.config.sessionStore) {
|
|
3879
|
+
return;
|
|
3880
|
+
}
|
|
3881
|
+
const runtimeAdapter = this.resolveRuntimeAdapter();
|
|
3882
|
+
let session = await this.config.sessionStore.get(params.sessionId);
|
|
3883
|
+
const previousStatus = session?.status;
|
|
3884
|
+
if (!session && runtimeAdapter?.checkpoint) {
|
|
3885
|
+
const checkpoint = await runtimeAdapter.checkpoint.load(params.sessionId);
|
|
3886
|
+
if (checkpoint) {
|
|
3887
|
+
session = await this.config.sessionStore.create({
|
|
3888
|
+
...omitSessionTimestamps(checkpoint.state),
|
|
3889
|
+
workflowId: params.options?.workflowId ?? checkpoint.state.workflowId,
|
|
3890
|
+
threadId: params.options?.threadId ?? checkpoint.state.threadId,
|
|
3891
|
+
traceId: params.traceId,
|
|
3892
|
+
checkpointId: checkpoint.checkpointId,
|
|
3893
|
+
status: "running",
|
|
3894
|
+
pendingApprovalRequestId: undefined,
|
|
3895
|
+
lastError: undefined,
|
|
3896
|
+
metadata: params.options?.metadata ?? checkpoint.state.metadata
|
|
3897
|
+
});
|
|
3898
|
+
}
|
|
3899
|
+
}
|
|
3900
|
+
if (!session) {
|
|
3901
|
+
session = await this.config.sessionStore.create({
|
|
3902
|
+
sessionId: params.sessionId,
|
|
3903
|
+
agentId: this.id,
|
|
3904
|
+
tenantId: params.options?.tenantId,
|
|
3905
|
+
actorId: params.options?.actorId,
|
|
3906
|
+
workflowId: params.options?.workflowId,
|
|
3907
|
+
threadId: params.options?.threadId,
|
|
3908
|
+
traceId: params.traceId,
|
|
3909
|
+
status: "running",
|
|
3910
|
+
messages: [],
|
|
3911
|
+
steps: [],
|
|
3912
|
+
metadata: params.options?.metadata
|
|
3913
|
+
});
|
|
3914
|
+
await this.emitAgentEvent("agent.session.created", {
|
|
3915
|
+
sessionId: params.sessionId,
|
|
3916
|
+
tenantId: params.options?.tenantId,
|
|
3917
|
+
workflowId: params.options?.workflowId,
|
|
3918
|
+
traceId: params.traceId
|
|
3919
|
+
});
|
|
3920
|
+
} else {
|
|
3921
|
+
await this.config.sessionStore.update(params.sessionId, {
|
|
3922
|
+
status: "running",
|
|
3923
|
+
workflowId: params.options?.workflowId ?? session.workflowId,
|
|
3924
|
+
threadId: params.options?.threadId ?? session.threadId,
|
|
3925
|
+
traceId: params.traceId,
|
|
3926
|
+
metadata: params.options?.metadata ?? session.metadata,
|
|
3927
|
+
pendingApprovalRequestId: undefined,
|
|
3928
|
+
lastError: undefined
|
|
3929
|
+
});
|
|
3930
|
+
await this.emitAgentEvent("agent.session.updated", {
|
|
3931
|
+
sessionId: params.sessionId,
|
|
3932
|
+
tenantId: params.options?.tenantId ?? session.tenantId,
|
|
3933
|
+
workflowId: params.options?.workflowId ?? session.workflowId,
|
|
3934
|
+
traceId: params.traceId,
|
|
3935
|
+
metadata: {
|
|
3936
|
+
previousStatus: previousStatus ?? "idle",
|
|
3937
|
+
nextStatus: "running"
|
|
3938
|
+
}
|
|
3939
|
+
});
|
|
3940
|
+
}
|
|
3941
|
+
await this.config.sessionStore.appendMessage(params.sessionId, {
|
|
3942
|
+
role: "user",
|
|
3943
|
+
content: params.prompt
|
|
3944
|
+
});
|
|
3945
|
+
if (runtimeAdapter?.suspendResume && (previousStatus === "waiting" || previousStatus === "escalated")) {
|
|
3946
|
+
await runtimeAdapter.suspendResume.resume({
|
|
3947
|
+
sessionId: params.sessionId,
|
|
3948
|
+
input: params.prompt,
|
|
3949
|
+
metadata: compactStringRecord({
|
|
3950
|
+
traceId: params.traceId,
|
|
3951
|
+
workflowId: params.options?.workflowId,
|
|
3952
|
+
threadId: params.options?.threadId
|
|
3953
|
+
})
|
|
3954
|
+
});
|
|
3955
|
+
}
|
|
3956
|
+
await this.syncSessionCheckpoint(params.sessionId);
|
|
3957
|
+
}
|
|
3958
|
+
resolveRuntimeAdapter() {
|
|
3959
|
+
return resolveRuntimeAdapterBundle(this.spec, this.config.runtimeAdapters);
|
|
3960
|
+
}
|
|
3961
|
+
async syncSessionCheckpoint(sessionId) {
|
|
3962
|
+
if (!this.config.sessionStore) {
|
|
3963
|
+
return null;
|
|
3964
|
+
}
|
|
3965
|
+
const runtimeAdapter = this.resolveRuntimeAdapter();
|
|
3966
|
+
const session = await this.config.sessionStore.get(sessionId);
|
|
3967
|
+
if (!runtimeAdapter?.checkpoint || !session) {
|
|
3968
|
+
return session;
|
|
3969
|
+
}
|
|
3970
|
+
const checkpointId = `${sessionId}:${Date.now()}`;
|
|
3971
|
+
await runtimeAdapter.checkpoint.save({
|
|
3972
|
+
sessionId,
|
|
3973
|
+
threadId: session.threadId,
|
|
3974
|
+
state: session,
|
|
3975
|
+
checkpointId,
|
|
3976
|
+
createdAt: new Date
|
|
3977
|
+
});
|
|
3978
|
+
await this.config.sessionStore.update(sessionId, {
|
|
3979
|
+
checkpointId
|
|
3980
|
+
});
|
|
3981
|
+
return this.config.sessionStore.get(sessionId);
|
|
3982
|
+
}
|
|
3983
|
+
async runSessionMiddleware(sessionId, hook) {
|
|
3984
|
+
if (!hook || !this.config.sessionStore) {
|
|
3985
|
+
return;
|
|
3986
|
+
}
|
|
3987
|
+
const session = await this.config.sessionStore.get(sessionId);
|
|
3988
|
+
if (!session) {
|
|
3989
|
+
return;
|
|
3990
|
+
}
|
|
3991
|
+
const next = await hook(session);
|
|
3992
|
+
if (!next) {
|
|
3993
|
+
return;
|
|
3994
|
+
}
|
|
3995
|
+
await this.config.sessionStore.update(sessionId, {
|
|
3996
|
+
status: next.status,
|
|
3997
|
+
metadata: next.metadata,
|
|
3998
|
+
workflowId: next.workflowId,
|
|
3999
|
+
threadId: next.threadId,
|
|
4000
|
+
traceId: next.traceId,
|
|
4001
|
+
checkpointId: next.checkpointId,
|
|
4002
|
+
pendingApprovalRequestId: next.pendingApprovalRequestId,
|
|
4003
|
+
lastError: next.lastError
|
|
4004
|
+
});
|
|
4005
|
+
await this.syncSessionCheckpoint(sessionId);
|
|
4006
|
+
}
|
|
4007
|
+
async requestApproval(sessionId, params) {
|
|
4008
|
+
const approvalWorkflow = this.config.approvalWorkflow;
|
|
4009
|
+
const context = this.activeStepContexts.get(sessionId);
|
|
4010
|
+
if (!approvalWorkflow || !context || context.pendingApproval) {
|
|
4011
|
+
return context?.pendingApproval;
|
|
4012
|
+
}
|
|
4013
|
+
const request = await approvalWorkflow.requestApproval({
|
|
4014
|
+
sessionId,
|
|
4015
|
+
agentId: this.id,
|
|
4016
|
+
tenantId: context.tenantId,
|
|
4017
|
+
toolName: params.toolName,
|
|
4018
|
+
toolCallId: params.toolCallId,
|
|
4019
|
+
toolArgs: params.args,
|
|
4020
|
+
reason: params.reason,
|
|
4021
|
+
payload: {
|
|
4022
|
+
traceId: context.traceId,
|
|
4023
|
+
workflowId: context.workflowId,
|
|
4024
|
+
threadId: context.threadId,
|
|
4025
|
+
code: params.error?.code
|
|
4026
|
+
}
|
|
4027
|
+
});
|
|
4028
|
+
context.pendingApproval = request;
|
|
4029
|
+
if (this.config.sessionStore) {
|
|
4030
|
+
await this.config.sessionStore.update(sessionId, {
|
|
4031
|
+
status: "escalated",
|
|
4032
|
+
pendingApprovalRequestId: request.id,
|
|
4033
|
+
lastError: params.error
|
|
4034
|
+
});
|
|
4035
|
+
await this.syncSessionCheckpoint(sessionId);
|
|
4036
|
+
}
|
|
4037
|
+
await this.emitAgentEvent("agent.tool.approval_requested", {
|
|
4038
|
+
sessionId,
|
|
4039
|
+
tenantId: context.tenantId,
|
|
4040
|
+
workflowId: context.workflowId,
|
|
4041
|
+
traceId: context.traceId,
|
|
4042
|
+
stepIndex: context.stepIndex,
|
|
4043
|
+
toolName: params.toolName,
|
|
4044
|
+
metadata: {
|
|
4045
|
+
approvalRequestId: request.id,
|
|
4046
|
+
toolCallId: params.toolCallId,
|
|
4047
|
+
reason: params.reason
|
|
4048
|
+
}
|
|
4049
|
+
});
|
|
4050
|
+
await this.emitAgentEvent("agent.escalated", {
|
|
4051
|
+
sessionId,
|
|
4052
|
+
tenantId: context.tenantId,
|
|
4053
|
+
workflowId: context.workflowId,
|
|
4054
|
+
traceId: context.traceId,
|
|
4055
|
+
stepIndex: context.stepIndex,
|
|
4056
|
+
toolName: params.toolName,
|
|
4057
|
+
metadata: {
|
|
4058
|
+
approvalRequestId: request.id,
|
|
4059
|
+
reason: params.reason
|
|
4060
|
+
}
|
|
4061
|
+
});
|
|
4062
|
+
const runtimeAdapter = this.resolveRuntimeAdapter();
|
|
4063
|
+
if (runtimeAdapter?.suspendResume) {
|
|
4064
|
+
await runtimeAdapter.suspendResume.suspend({
|
|
4065
|
+
sessionId,
|
|
4066
|
+
reason: params.reason,
|
|
4067
|
+
metadata: compactStringRecord({
|
|
4068
|
+
traceId: context.traceId,
|
|
4069
|
+
workflowId: context.workflowId,
|
|
4070
|
+
threadId: context.threadId,
|
|
4071
|
+
approvalRequestId: request.id
|
|
4072
|
+
})
|
|
4073
|
+
});
|
|
4074
|
+
}
|
|
4075
|
+
return request;
|
|
4076
|
+
}
|
|
4077
|
+
async emitAgentEvent(event, payload) {
|
|
4078
|
+
if (!this.config.eventEmitter) {
|
|
4079
|
+
return;
|
|
4080
|
+
}
|
|
4081
|
+
await this.config.eventEmitter(event, {
|
|
4082
|
+
agentId: this.id,
|
|
4083
|
+
...payload
|
|
4084
|
+
});
|
|
4085
|
+
}
|
|
3628
4086
|
createInnerAgent(model, maxSteps) {
|
|
3629
4087
|
return new ToolLoopAgent({
|
|
3630
4088
|
model,
|
|
@@ -3654,7 +4112,9 @@ ${params.prompt}` : params.prompt ?? "";
|
|
|
3654
4112
|
contractspec_trace_id: params.traceId,
|
|
3655
4113
|
contractspec_agent_id: this.id,
|
|
3656
4114
|
contractspec_tenant_id: params.options?.tenantId,
|
|
3657
|
-
contractspec_actor_id: params.options?.actorId
|
|
4115
|
+
contractspec_actor_id: params.options?.actorId,
|
|
4116
|
+
contractspec_workflow_id: params.options?.workflowId,
|
|
4117
|
+
contractspec_thread_id: params.options?.threadId
|
|
3658
4118
|
};
|
|
3659
4119
|
const tracingOptions = {
|
|
3660
4120
|
...posthogConfig.tracingOptions,
|
|
@@ -3666,6 +4126,106 @@ ${params.prompt}` : params.prompt ?? "";
|
|
|
3666
4126
|
return createPostHogTracedModel2(this.config.model, posthogConfig, tracingOptions);
|
|
3667
4127
|
}
|
|
3668
4128
|
}
|
|
4129
|
+
function omitSessionTimestamps(session) {
|
|
4130
|
+
const { createdAt: _createdAt, updatedAt: _updatedAt, ...rest } = session;
|
|
4131
|
+
return rest;
|
|
4132
|
+
}
|
|
4133
|
+
function resolveRuntimeAdapterBundle(spec, runtimeAdapters) {
|
|
4134
|
+
if (!runtimeAdapters) {
|
|
4135
|
+
return;
|
|
4136
|
+
}
|
|
4137
|
+
const preferredKeys = [
|
|
4138
|
+
"langgraph",
|
|
4139
|
+
"langchain",
|
|
4140
|
+
"workflow-devkit"
|
|
4141
|
+
];
|
|
4142
|
+
for (const key of preferredKeys) {
|
|
4143
|
+
if (spec.runtime?.capabilities?.adapters?.[key] && runtimeAdapters[key]) {
|
|
4144
|
+
return runtimeAdapters[key];
|
|
4145
|
+
}
|
|
4146
|
+
}
|
|
4147
|
+
for (const key of preferredKeys) {
|
|
4148
|
+
if (runtimeAdapters[key]) {
|
|
4149
|
+
return runtimeAdapters[key];
|
|
4150
|
+
}
|
|
4151
|
+
}
|
|
4152
|
+
return;
|
|
4153
|
+
}
|
|
4154
|
+
function compactStringRecord(input) {
|
|
4155
|
+
return Object.fromEntries(Object.entries(input).filter((entry) => typeof entry[1] === "string" && entry[1].length > 0));
|
|
4156
|
+
}
|
|
4157
|
+
function toAgentExecutionError(error) {
|
|
4158
|
+
if (error && typeof error === "object" && "kind" in error && typeof error.kind === "string" && "message" in error && typeof error.message === "string") {
|
|
4159
|
+
return {
|
|
4160
|
+
kind: error.kind,
|
|
4161
|
+
message: error.message,
|
|
4162
|
+
code: "code" in error && typeof error.code === "string" ? error.code : undefined,
|
|
4163
|
+
retryAfterMs: "retryAfterMs" in error && typeof error.retryAfterMs === "number" ? error.retryAfterMs : undefined
|
|
4164
|
+
};
|
|
4165
|
+
}
|
|
4166
|
+
if (error instanceof Error) {
|
|
4167
|
+
return {
|
|
4168
|
+
kind: error.message.toLowerCase().includes("timeout") || error.code === "TOOL_EXECUTION_TIMEOUT" ? "timeout" : "fatal",
|
|
4169
|
+
message: error.message,
|
|
4170
|
+
code: error.code
|
|
4171
|
+
};
|
|
4172
|
+
}
|
|
4173
|
+
return {
|
|
4174
|
+
kind: "fatal",
|
|
4175
|
+
message: String(error)
|
|
4176
|
+
};
|
|
4177
|
+
}
|
|
4178
|
+
function extractToolExecutionError(output) {
|
|
4179
|
+
if (!output) {
|
|
4180
|
+
return;
|
|
4181
|
+
}
|
|
4182
|
+
if (typeof output === "string") {
|
|
4183
|
+
if (output.toLowerCase().includes("error")) {
|
|
4184
|
+
return {
|
|
4185
|
+
kind: output.toLowerCase().includes("timeout") ? "timeout" : "retryable",
|
|
4186
|
+
message: output
|
|
4187
|
+
};
|
|
4188
|
+
}
|
|
4189
|
+
return;
|
|
4190
|
+
}
|
|
4191
|
+
if (typeof output !== "object") {
|
|
4192
|
+
return;
|
|
4193
|
+
}
|
|
4194
|
+
const record2 = output;
|
|
4195
|
+
const nestedError = record2["error"];
|
|
4196
|
+
if (nestedError instanceof Error) {
|
|
4197
|
+
return toAgentExecutionError(nestedError);
|
|
4198
|
+
}
|
|
4199
|
+
if (nestedError && typeof nestedError === "object") {
|
|
4200
|
+
return toAgentExecutionError(nestedError);
|
|
4201
|
+
}
|
|
4202
|
+
if (typeof record2["message"] === "string" && typeof record2["kind"] === "string") {
|
|
4203
|
+
return {
|
|
4204
|
+
kind: record2["kind"],
|
|
4205
|
+
message: record2["message"],
|
|
4206
|
+
code: typeof record2["code"] === "string" ? record2["code"] : undefined,
|
|
4207
|
+
retryAfterMs: typeof record2["retryAfterMs"] === "number" ? record2["retryAfterMs"] : undefined
|
|
4208
|
+
};
|
|
4209
|
+
}
|
|
4210
|
+
if (typeof record2["errorMessage"] === "string") {
|
|
4211
|
+
return {
|
|
4212
|
+
kind: typeof record2["errorCode"] === "string" && record2["errorCode"].includes("TIMEOUT") ? "timeout" : "retryable",
|
|
4213
|
+
message: record2["errorMessage"],
|
|
4214
|
+
code: typeof record2["errorCode"] === "string" ? record2["errorCode"] : undefined
|
|
4215
|
+
};
|
|
4216
|
+
}
|
|
4217
|
+
return;
|
|
4218
|
+
}
|
|
4219
|
+
function stringifyToolResult(toolName, output) {
|
|
4220
|
+
if (typeof output === "string") {
|
|
4221
|
+
return `[${toolName}] ${output}`;
|
|
4222
|
+
}
|
|
4223
|
+
try {
|
|
4224
|
+
return `[${toolName}] ${JSON.stringify(output)}`;
|
|
4225
|
+
} catch {
|
|
4226
|
+
return `[${toolName}] [unserializable result]`;
|
|
4227
|
+
}
|
|
4228
|
+
}
|
|
3669
4229
|
function resolveMaxSteps(overrideMaxSteps, specMaxSteps) {
|
|
3670
4230
|
const candidate = overrideMaxSteps ?? specMaxSteps ?? 10;
|
|
3671
4231
|
if (!Number.isFinite(candidate)) {
|
|
@@ -3708,8 +4268,8 @@ function resolveEscalationError(spec, finishReason) {
|
|
|
3708
4268
|
}
|
|
3709
4269
|
var ContractSpecCallOptionsSchema;
|
|
3710
4270
|
var init_contract_spec_agent = __esm(() => {
|
|
4271
|
+
init_workflow();
|
|
3711
4272
|
init_injector();
|
|
3712
|
-
init_spec();
|
|
3713
4273
|
init_adapter();
|
|
3714
4274
|
init_knowledge_tool();
|
|
3715
4275
|
init_mcp_client();
|
|
@@ -3719,6 +4279,8 @@ var init_contract_spec_agent = __esm(() => {
|
|
|
3719
4279
|
tenantId: z4.string().optional(),
|
|
3720
4280
|
actorId: z4.string().optional(),
|
|
3721
4281
|
sessionId: z4.string().optional(),
|
|
4282
|
+
workflowId: z4.string().optional(),
|
|
4283
|
+
threadId: z4.string().optional(),
|
|
3722
4284
|
metadata: z4.record(z4.string(), z4.unknown()).optional()
|
|
3723
4285
|
});
|
|
3724
4286
|
});
|
|
@@ -3986,7 +4548,10 @@ var init_tool_bridge = __esm(() => {
|
|
|
3986
4548
|
});
|
|
3987
4549
|
|
|
3988
4550
|
// src/providers/claude-agent-sdk/adapter.ts
|
|
3989
|
-
import { randomUUID as
|
|
4551
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
4552
|
+
import {
|
|
4553
|
+
agentKey as agentKey2
|
|
4554
|
+
} from "@contractspec/lib.contracts-spec/agent";
|
|
3990
4555
|
|
|
3991
4556
|
class ClaudeAgentSDKProvider {
|
|
3992
4557
|
name = "claude-agent-sdk";
|
|
@@ -4038,7 +4603,7 @@ class ClaudeAgentSDKProvider {
|
|
|
4038
4603
|
}
|
|
4039
4604
|
}
|
|
4040
4605
|
const instructions = await injectStaticKnowledge(spec.instructions, spec.knowledge ?? [], undefined);
|
|
4041
|
-
const contextId = `claude-${
|
|
4606
|
+
const contextId = `claude-${agentKey2(spec.meta)}-${Date.now()}`;
|
|
4042
4607
|
const metadata = {
|
|
4043
4608
|
computerUseEnabled: this.config.computerUse ?? false,
|
|
4044
4609
|
extendedThinkingEnabled: this.config.extendedThinking ?? false,
|
|
@@ -4252,7 +4817,7 @@ ${params.systemOverride}` : context.spec.instructions;
|
|
|
4252
4817
|
}));
|
|
4253
4818
|
}
|
|
4254
4819
|
return tool4.execute(input, {
|
|
4255
|
-
toolCallId: `mcp-${
|
|
4820
|
+
toolCallId: `mcp-${randomUUID3()}`,
|
|
4256
4821
|
messages: []
|
|
4257
4822
|
});
|
|
4258
4823
|
}
|
|
@@ -4342,7 +4907,6 @@ ${params.systemOverride}` : context.spec.instructions;
|
|
|
4342
4907
|
var init_adapter2 = __esm(() => {
|
|
4343
4908
|
init_i18n();
|
|
4344
4909
|
init_injector();
|
|
4345
|
-
init_spec();
|
|
4346
4910
|
init_mcp_client();
|
|
4347
4911
|
init_types();
|
|
4348
4912
|
init_tool_bridge();
|
|
@@ -4665,6 +5229,10 @@ var init_agent_bridge = __esm(() => {
|
|
|
4665
5229
|
});
|
|
4666
5230
|
|
|
4667
5231
|
// src/providers/opencode-sdk/adapter.ts
|
|
5232
|
+
import {
|
|
5233
|
+
agentKey as agentKey3
|
|
5234
|
+
} from "@contractspec/lib.contracts-spec/agent";
|
|
5235
|
+
|
|
4668
5236
|
class OpenCodeSDKProvider {
|
|
4669
5237
|
name = "opencode-sdk";
|
|
4670
5238
|
version = "1.0.0";
|
|
@@ -4715,7 +5283,7 @@ class OpenCodeSDKProvider {
|
|
|
4715
5283
|
toolSet[tool4.name] = specToolToExternalToolForOpenCode(tool4);
|
|
4716
5284
|
}
|
|
4717
5285
|
const instructions = await injectStaticKnowledge(spec.instructions, spec.knowledge ?? [], undefined);
|
|
4718
|
-
const contextId = `opencode-${
|
|
5286
|
+
const contextId = `opencode-${agentKey3(spec.meta)}-${Date.now()}`;
|
|
4719
5287
|
const metadata = {
|
|
4720
5288
|
sessionId: session.id,
|
|
4721
5289
|
agentType: this.config.agentType ?? inferAgentType(spec),
|
|
@@ -4930,7 +5498,6 @@ ${params.systemOverride}` : context.spec.instructions;
|
|
|
4930
5498
|
var init_adapter3 = __esm(() => {
|
|
4931
5499
|
init_i18n();
|
|
4932
5500
|
init_injector();
|
|
4933
|
-
init_spec();
|
|
4934
5501
|
init_types();
|
|
4935
5502
|
init_agent_bridge();
|
|
4936
5503
|
init_tool_bridge2();
|