@cognipeer/agent-sdk 0.1.1 → 0.1.2

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/index.cjs CHANGED
@@ -1,60 +1,136 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
1
+ 'use strict';
29
2
 
30
- // src/index.ts
31
- var index_exports = {};
32
- __export(index_exports, {
33
- applyTokenLimits: () => applyTokenLimits,
34
- buildSystemPrompt: () => buildSystemPrompt,
35
- bumpStep: () => bumpStep,
36
- countApproxTokens: () => countApproxTokens,
37
- createAgent: () => createAgent,
38
- createAgentNode: () => createAgentNode,
39
- createContextSummarizeNode: () => createContextSummarizeNode,
40
- createContextTools: () => createContextTools,
41
- createDebugSession: () => createDebugSession,
42
- createResolverNode: () => createResolverNode,
43
- createSmartAgent: () => createSmartAgent,
44
- createSmartTool: () => createSmartTool,
45
- createTool: () => createTool,
46
- createToolLimitFinalizeNode: () => createToolLimitFinalizeNode,
47
- createToolsNode: () => createToolsNode,
48
- formatMarkdown: () => formatMarkdown,
49
- fromLangchainModel: () => fromLangchainModel,
50
- getModelName: () => getModelName,
51
- isSmartModel: () => isSmartModel,
52
- resolveLogsBaseDir: () => resolveLogsBaseDir,
53
- serializeAgentTools: () => serializeAgentTools,
54
- withTools: () => withTools,
55
- writeStepMarkdown: () => writeStepMarkdown
56
- });
57
- module.exports = __toCommonJS(index_exports);
3
+ var zod = require('zod');
4
+ var module$1 = require('module');
5
+ var fs = require('fs');
6
+ var path = require('path');
7
+ var buffer = require('buffer');
8
+ var nanoid = require('nanoid');
9
+ var AjvModule = require('ajv');
10
+
11
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
12
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
13
+
14
+ var fs__default = /*#__PURE__*/_interopDefault(fs);
15
+ var path__default = /*#__PURE__*/_interopDefault(path);
16
+ var AjvModule__default = /*#__PURE__*/_interopDefault(AjvModule);
17
+
18
+ // src/adapters/langchain.ts
19
+ var moduleName = "@langchain/core/tools";
20
+ var cachedToolFactory;
21
+ var cachedHasAttemptedFactory = false;
22
+ var requireFn = null;
23
+ try {
24
+ requireFn = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
25
+ } catch {
26
+ requireFn = null;
27
+ }
28
+ function getExecutor(tool) {
29
+ if (typeof tool.invoke === "function") return (input) => tool.invoke(input);
30
+ if (typeof tool.call === "function") return (input) => tool.call(input);
31
+ if (typeof tool.func === "function") return (input) => tool.func(input);
32
+ if (typeof tool.run === "function") return (input) => tool.run(input);
33
+ if (typeof tool === "function") {
34
+ return tool;
35
+ }
36
+ throw new Error(`Tool ${tool?.name ?? "<unnamed>"} is not invokable`);
37
+ }
38
+ function loadLangchainToolFactory() {
39
+ if (cachedHasAttemptedFactory) return cachedToolFactory ?? null;
40
+ cachedHasAttemptedFactory = true;
41
+ cachedToolFactory = null;
42
+ if (!requireFn) return null;
43
+ try {
44
+ const mod = requireFn(moduleName);
45
+ const factory = typeof mod?.tool === "function" ? mod.tool : void 0;
46
+ if (typeof factory === "function") {
47
+ cachedToolFactory = factory;
48
+ }
49
+ } catch {
50
+ cachedToolFactory = null;
51
+ }
52
+ return cachedToolFactory ?? null;
53
+ }
54
+ function ensureSchema(candidate) {
55
+ if (!candidate) return zod.z.any();
56
+ if (candidate instanceof zod.z.ZodType) return candidate;
57
+ return candidate;
58
+ }
59
+ function toLangchainTools(tools) {
60
+ const factory = loadLangchainToolFactory();
61
+ if (!factory) return tools;
62
+ return tools.map((tool) => {
63
+ if (!tool) return tool;
64
+ if (tool.__lcTool) return tool.__lcTool;
65
+ const executor = getExecutor(tool);
66
+ try {
67
+ const lcTool = factory(async (input) => executor(input), {
68
+ name: tool.name,
69
+ description: tool.description,
70
+ schema: ensureSchema(tool.schema)
71
+ });
72
+ tool.__lcTool = lcTool;
73
+ return lcTool;
74
+ } catch {
75
+ return tool;
76
+ }
77
+ });
78
+ }
79
+ function fromLangchainTools(tools) {
80
+ return tools.map((tool) => {
81
+ if (!tool) return tool;
82
+ if (tool.__source === "smart") return tool;
83
+ if (typeof tool === "function" && !tool.name) {
84
+ const wrapped2 = createSimpleTool({
85
+ name: "anonymous_tool",
86
+ description: void 0,
87
+ schema: zod.z.any(),
88
+ executor: tool
89
+ });
90
+ wrapped2.__source = "langchain";
91
+ wrapped2.__lc = tool;
92
+ return wrapped2;
93
+ }
94
+ const name = tool.name || tool?.lc_kwargs?.name || tool?.config?.name || "tool";
95
+ const description = tool.description || tool?.lc_kwargs?.description;
96
+ const schema = tool.schema || tool?.lc_kwargs?.schema || zod.z.any();
97
+ const executor = (input) => {
98
+ if (typeof tool.invoke === "function") return tool.invoke(input);
99
+ if (typeof tool.call === "function") return tool.call(input);
100
+ if (typeof tool._call === "function") return tool._call(input);
101
+ if (typeof tool.run === "function") return tool.run(input);
102
+ if (typeof tool.func === "function") return tool.func(input);
103
+ if (typeof tool === "function") return tool(input);
104
+ throw new Error(`LangChain tool ${name} is not invokable`);
105
+ };
106
+ const wrapped = createSimpleTool({
107
+ name,
108
+ description,
109
+ schema,
110
+ executor
111
+ });
112
+ wrapped.__source = "langchain";
113
+ wrapped.__lc = tool;
114
+ return wrapped;
115
+ });
116
+ }
117
+ function createSimpleTool({
118
+ name,
119
+ description,
120
+ schema,
121
+ executor
122
+ }) {
123
+ const invoke = async (input) => executor(input);
124
+ return {
125
+ name,
126
+ description,
127
+ schema,
128
+ invoke,
129
+ call: invoke,
130
+ run: invoke,
131
+ func: invoke
132
+ };
133
+ }
58
134
 
59
135
  // src/model.ts
60
136
  function isSmartModel(m) {
@@ -115,8 +191,13 @@ function fromLangchainModel(lcModel) {
115
191
  return { role: "assistant", content: String(response ?? "") };
116
192
  },
117
193
  bindTools: (tools) => {
194
+ const lcReady = toLangchainTools(tools);
118
195
  if (typeof lcModel.bindTools === "function") {
119
- const bound = lcModel.bindTools(tools);
196
+ const bound = lcModel.bindTools(lcReady);
197
+ return fromLangchainModel(bound);
198
+ }
199
+ if (typeof lcModel.bind === "function") {
200
+ const bound = lcModel.bind({ tools: lcReady });
120
201
  return fromLangchainModel(bound);
121
202
  }
122
203
  return adapted;
@@ -128,28 +209,38 @@ function fromLangchainModel(lcModel) {
128
209
  }
129
210
 
130
211
  // src/tool.ts
131
- var import_tools = require("@langchain/core/tools");
132
- function createSmartTool({
212
+ function createTool({
133
213
  name,
134
214
  description,
135
215
  schema,
136
- func
216
+ func,
217
+ needsApproval,
218
+ approvalPrompt,
219
+ approvalDefaults
137
220
  }) {
138
- return (0, import_tools.tool)(async (input) => {
139
- return func(input);
140
- }, {
221
+ const execute = async (input) => func(input);
222
+ const toolRecord = {
141
223
  name,
142
224
  description,
143
- schema
144
- });
145
- }
146
- function createTool({
147
- name,
148
- description,
149
- schema,
150
- func
151
- }) {
152
- return createSmartTool({ name, description, schema, func });
225
+ schema,
226
+ // Our runtime prefers invoke but fallback helpers keep compatibility with LC-style tools.
227
+ invoke: execute,
228
+ call: execute,
229
+ run: execute,
230
+ func: execute
231
+ };
232
+ if (typeof needsApproval === "boolean") {
233
+ toolRecord.needsApproval = needsApproval;
234
+ }
235
+ if (approvalPrompt !== void 0) {
236
+ toolRecord.approvalPrompt = approvalPrompt;
237
+ }
238
+ if (approvalDefaults !== void 0) {
239
+ toolRecord.approvalDefaults = approvalDefaults;
240
+ }
241
+ toolRecord.__source = toolRecord.__source || "smart";
242
+ toolRecord.__impl = func;
243
+ return toolRecord;
153
244
  }
154
245
 
155
246
  // src/prompts.ts
@@ -181,8 +272,12 @@ Rules:
181
272
  ].filter(Boolean).join("\n");
182
273
  }
183
274
 
184
- // src/agent.ts
185
- var import_zod = require("zod");
275
+ // src/types.ts
276
+ var GuardrailPhase = /* @__PURE__ */ ((GuardrailPhase2) => {
277
+ GuardrailPhase2["Request"] = "request";
278
+ GuardrailPhase2["Response"] = "response";
279
+ return GuardrailPhase2;
280
+ })(GuardrailPhase || {});
186
281
 
187
282
  // src/nodes/resolver.ts
188
283
  function createResolverNode() {
@@ -196,6 +291,7 @@ function createResolverNode() {
196
291
  toolCache: state.toolCache || {},
197
292
  toolHistory: state.toolHistory || [],
198
293
  toolHistoryArchived: state.toolHistoryArchived || [],
294
+ pendingApprovals: state.pendingApprovals || [],
199
295
  plan: state.plan || null,
200
296
  planVersion: state.planVersion || 0
201
297
  };
@@ -247,157 +343,744 @@ function safe(v) {
247
343
  const n = Number(v);
248
344
  return Number.isFinite(n) && n >= 0 ? n : 0;
249
345
  }
250
-
251
- // src/utils/debugLogger.ts
252
- var import_node_fs = __toESM(require("fs"), 1);
253
- var import_node_path = __toESM(require("path"), 1);
254
- function ensureDir(p) {
255
- if (!import_node_fs.default.existsSync(p)) import_node_fs.default.mkdirSync(p, { recursive: true });
346
+ var DEFAULT_COGNIPEER_URL = "https://api.cognipeer.com/v1/client/tracing/sessions";
347
+ function fileSink(path2) {
348
+ return { type: "file", path: path2 };
349
+ }
350
+ function customSink(handler) {
351
+ if (typeof handler === "function") {
352
+ return { type: "custom", onEvent: handler };
353
+ }
354
+ return {
355
+ type: "custom",
356
+ onEvent: typeof handler?.onEvent === "function" ? handler.onEvent : void 0,
357
+ onSession: typeof handler?.onSession === "function" ? handler.onSession : void 0
358
+ };
359
+ }
360
+ function cognipeerSink(first, second) {
361
+ if (second === void 0) {
362
+ const apiKey = first ?? "";
363
+ return { type: "cognipeer", apiKey };
364
+ }
365
+ const url = typeof first === "string" && first.trim().length > 0 ? first.trim() : void 0;
366
+ return { type: "cognipeer", url, apiKey: second };
367
+ }
368
+ function httpSink(url, headers) {
369
+ return { type: "http", url, headers };
256
370
  }
257
- function resolveLogsBaseDir(customPath) {
371
+ function resolveLogsBaseDir(customPath, ensureDirectory = true) {
258
372
  const root = process.cwd();
259
- const base = customPath && customPath.trim().length > 0 ? customPath : import_node_path.default.join(root, "logs");
260
- ensureDir(base);
373
+ const base = customPath && customPath.trim().length > 0 ? customPath : path__default.default.join(root, "logs");
374
+ if (ensureDirectory) {
375
+ ensureDir(base);
376
+ }
261
377
  return base;
262
378
  }
263
- function createDebugSession(opts) {
264
- const dbg = opts.debug;
265
- if (!dbg?.enabled) return void 0;
266
- const baseDir = resolveLogsBaseDir(dbg.path);
267
- const sessionId = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
268
- const sessionDir = import_node_path.default.join(baseDir, sessionId);
269
- if (!dbg.callback) ensureDir(sessionDir);
270
- return { sessionId, baseDir, sessionDir, stepIndex: 0, callback: dbg.callback };
379
+ function coerceToString(value) {
380
+ if (value == null) return void 0;
381
+ if (typeof value === "string") {
382
+ const trimmed = value.trim();
383
+ return trimmed.length > 0 ? trimmed : void 0;
384
+ }
385
+ if (typeof value === "number" || typeof value === "boolean") {
386
+ return String(value);
387
+ }
388
+ if (typeof value === "function" && value.length === 0) {
389
+ try {
390
+ return coerceToString(value());
391
+ } catch {
392
+ return void 0;
393
+ }
394
+ }
395
+ if (Array.isArray(value)) {
396
+ for (const item of value) {
397
+ const normalized = coerceToString(item);
398
+ if (normalized) return normalized;
399
+ }
400
+ return void 0;
401
+ }
402
+ return void 0;
271
403
  }
272
- function bumpStep(session) {
273
- session.stepIndex += 1;
274
- return session.stepIndex - 1;
404
+ function firstNonEmptyString(...candidates) {
405
+ for (const candidate of candidates) {
406
+ const normalized = coerceToString(candidate);
407
+ if (normalized) return normalized;
408
+ }
409
+ return void 0;
275
410
  }
276
411
  function getModelName(model) {
277
- return model?.model ?? model?.modelName ?? model?.options?.model ?? model?.lc_alias ?? model?.constructor?.name ?? void 0;
412
+ if (!model) return void 0;
413
+ const maybeLc = model?._lc;
414
+ const direct = firstNonEmptyString(
415
+ model?.model,
416
+ model?.options?.model,
417
+ model?.params?.model,
418
+ model?.config?.model,
419
+ model?.configuration?.model,
420
+ model?.metadata?.model,
421
+ model?.lc_kwargs?.model,
422
+ maybeLc?.model,
423
+ maybeLc?.options?.model,
424
+ maybeLc?.params?.model,
425
+ maybeLc?.config?.model,
426
+ maybeLc?.configuration?.model,
427
+ maybeLc?.metadata?.model,
428
+ maybeLc?.lc_kwargs?.model,
429
+ model?.metadata?.modelName,
430
+ maybeLc?.metadata?.modelName,
431
+ model?.modelName,
432
+ maybeLc?.modelName,
433
+ model?.lc_alias,
434
+ model?.model_id,
435
+ model?.id,
436
+ maybeLc?.model_id,
437
+ maybeLc?.id,
438
+ model?._model,
439
+ model?._modelName,
440
+ model?.__model
441
+ );
442
+ if (direct) return direct;
443
+ const maybeClient = model?.client || model?.api || model?.service;
444
+ const clientValue = firstNonEmptyString(
445
+ maybeClient?.model,
446
+ maybeClient?.config?.model,
447
+ maybeClient?.options?.model,
448
+ maybeClient?.default?.model
449
+ );
450
+ if (clientValue) return clientValue;
451
+ const fnNames = firstNonEmptyString(model?._modelId, model?._llmType, maybeLc?._modelId, maybeLc?._llmType, model?.constructor?.name);
452
+ return fnNames;
278
453
  }
279
- function serializeAgentTools(tools) {
280
- return (tools || []).map((t) => {
281
- const name = t.name ?? t.lc_alias ?? t.constructor?.name ?? "tool";
282
- const description = t.description ?? t.lc_description ?? void 0;
283
- const params = t.schema ?? t.lc_kwargs?.schema ?? t.argsSchema ?? void 0;
284
- return {
285
- function: {
286
- name,
287
- description,
288
- parameters: params
289
- },
290
- type: "function"
291
- };
292
- });
454
+ function getProviderName(model) {
455
+ if (!model) return void 0;
456
+ const direct = firstNonEmptyString(
457
+ model?.provider,
458
+ model?.options?.provider,
459
+ model?.params?.provider,
460
+ model?.config?.provider,
461
+ model?.configuration?.provider,
462
+ model?.metadata?.provider,
463
+ model?.lc_kwargs?.provider,
464
+ model?.lc_alias,
465
+ model?.__provider
466
+ );
467
+ if (direct) return direct;
468
+ const maybeLc = model?._lc;
469
+ const lcValue = maybeLc ? firstNonEmptyString(
470
+ maybeLc?.provider,
471
+ maybeLc?.options?.provider,
472
+ maybeLc?.config?.provider,
473
+ maybeLc?.configuration?.provider,
474
+ maybeLc?.metadata?.provider,
475
+ maybeLc?.lc_kwargs?.provider,
476
+ maybeLc?.client?.config?.provider
477
+ ) : void 0;
478
+ if (lcValue) return lcValue;
479
+ const maybeClient = model?.client || model?.api || model?.service;
480
+ return firstNonEmptyString(
481
+ maybeClient?.provider,
482
+ maybeClient?.config?.provider,
483
+ maybeClient?.options?.provider,
484
+ maybeClient?.metadata?.provider
485
+ );
293
486
  }
294
- function formatTools(tools) {
295
- try {
296
- return JSON.stringify(
297
- tools.map((t) => ({
298
- function: t?.function ? {
299
- name: t.function.name,
300
- description: t.function.description,
301
- parameters: t.function.parameters
302
- } : void 0,
303
- type: t?.type
304
- })),
305
- null,
306
- 4
487
+ function inferModelFromMessages(messageList) {
488
+ if (!Array.isArray(messageList)) return void 0;
489
+ for (let i = messageList.length - 1; i >= 0; i -= 1) {
490
+ const message = messageList[i];
491
+ if (!message) continue;
492
+ const candidate = firstNonEmptyString(
493
+ message?.metadata?.model,
494
+ message?.metadata?.modelName,
495
+ message?.metadata?.modelNames,
496
+ message?.metadata?.model_id,
497
+ message?.response_metadata?.model,
498
+ message?.response_metadata?.modelName,
499
+ message?.response_metadata?.modelNames,
500
+ message?.response_metadata?.model_id,
501
+ message?.usage_metadata?.model,
502
+ message?.model,
503
+ message?.modelName,
504
+ message?.model_id,
505
+ message?.additional_kwargs?.model,
506
+ message?.additional_kwargs?.modelName,
507
+ message?.info?.model,
508
+ message?.annotations?.model
307
509
  );
308
- } catch {
309
- return "[]";
310
- }
311
- }
312
- function formatMessages(messages) {
313
- const lines = [];
314
- const push = (s = "") => lines.push(s);
315
- for (const m of messages) {
316
- const anyM = m;
317
- const role = anyM.role || (typeof anyM.getType === "function" ? anyM.getType() : void 0);
318
- if (role === "system") {
319
- push("### System\n");
320
- push(String(anyM.content));
321
- push("");
322
- } else if (role === "user" || role === "human") {
323
- push("### User\n");
324
- push(typeof anyM.content === "string" ? anyM.content : JSON.stringify(anyM.content, null, 2));
325
- push("");
326
- } else if (role === "assistant" || role === "ai") {
327
- push("### AI\n");
328
- const toolCalls = Array.isArray(anyM.tool_calls) ? anyM.tool_calls : [];
329
- if (toolCalls.length) {
330
- push("Tool Calls:");
331
- for (const tc of toolCalls) {
332
- push("```");
333
- push(JSON.stringify(tc, null, 2));
334
- push("```");
335
- }
510
+ if (candidate) return candidate;
511
+ }
512
+ return void 0;
513
+ }
514
+ function inferProviderFromMessages(messageList) {
515
+ if (!Array.isArray(messageList)) return void 0;
516
+ for (let i = messageList.length - 1; i >= 0; i -= 1) {
517
+ const message = messageList[i];
518
+ if (!message) continue;
519
+ const candidate = firstNonEmptyString(
520
+ message?.metadata?.provider,
521
+ message?.metadata?.providers,
522
+ message?.response_metadata?.provider,
523
+ message?.response_metadata?.providers,
524
+ message?.usage_metadata?.provider,
525
+ message?.provider,
526
+ message?.additional_kwargs?.provider,
527
+ message?.info?.provider,
528
+ message?.annotations?.provider
529
+ );
530
+ if (candidate) return candidate;
531
+ }
532
+ return void 0;
533
+ }
534
+ var DEFAULT_TRACE_CONFIG = {
535
+ logData: true
536
+ };
537
+ function ensureDir(p) {
538
+ if (!fs__default.default.existsSync(p)) {
539
+ fs__default.default.mkdirSync(p, { recursive: true });
540
+ }
541
+ }
542
+ function withDefaults(config) {
543
+ const enabled = Boolean(config?.enabled);
544
+ const logData = config?.logData ?? DEFAULT_TRACE_CONFIG.logData;
545
+ let sink;
546
+ try {
547
+ sink = resolveSink(config?.sink);
548
+ } catch (err) {
549
+ if (typeof console !== "undefined" && typeof console.warn === "function") {
550
+ console.warn("Invalid tracing sink configuration. Falling back to file sink.", err);
551
+ }
552
+ sink = resolveSink({ type: "file" });
553
+ }
554
+ return {
555
+ enabled,
556
+ logData,
557
+ mode: "batched",
558
+ sink
559
+ };
560
+ }
561
+ function resolveSink(sink) {
562
+ const candidate = sink ?? { type: "file" };
563
+ switch (candidate.type) {
564
+ case "file": {
565
+ const baseDir = resolveLogsBaseDir(candidate.path, false);
566
+ return { type: "file", baseDir };
567
+ }
568
+ case "custom": {
569
+ const onEvent = typeof candidate.onEvent === "function" ? candidate.onEvent : void 0;
570
+ const onSession = typeof candidate.onSession === "function" ? candidate.onSession : void 0;
571
+ return { type: "custom", onEvent, onSession };
572
+ }
573
+ case "cognipeer": {
574
+ const apiKey = typeof candidate.apiKey === "string" ? candidate.apiKey.trim() : "";
575
+ if (!apiKey) {
576
+ throw new Error("cognipeer sink requires a non-empty apiKey");
577
+ }
578
+ const url = typeof candidate.url === "string" && candidate.url.trim().length > 0 ? candidate.url.trim() : DEFAULT_COGNIPEER_URL;
579
+ return { type: "cognipeer", url, apiKey };
580
+ }
581
+ case "http": {
582
+ const url = typeof candidate.url === "string" ? candidate.url.trim() : "";
583
+ if (!url) {
584
+ throw new Error("http sink requires a non-empty url");
585
+ }
586
+ const headers = candidate.headers ? { ...candidate.headers } : void 0;
587
+ return headers ? { type: "http", url, headers } : { type: "http", url };
588
+ }
589
+ default: {
590
+ if (typeof console !== "undefined" && typeof console.warn === "function") {
591
+ console.warn("Unknown tracing sink type. Falling back to file sink.", candidate);
336
592
  }
337
- push(typeof anyM.content === "string" ? anyM.content : JSON.stringify(anyM.content, null, 2));
338
- push("");
339
- } else if (role === "tool") {
340
- push("### ToolResponse\n");
341
- const hdr = { name: anyM.name, tool_call_id: anyM.tool_call_id, executionId: anyM.executionId };
342
- push("```");
343
- push(JSON.stringify(hdr, null, 2));
344
- push("```");
345
- push(typeof anyM.content === "string" ? anyM.content : JSON.stringify(anyM.content, null, 2));
346
- push("");
593
+ return resolveSink({ type: "file" });
594
+ }
595
+ }
596
+ }
597
+ function snapshotSink(runtime) {
598
+ const sink = runtime.resolvedConfig.sink;
599
+ switch (sink.type) {
600
+ case "file":
601
+ return { type: "file", path: runtime.fileBaseDir || sink.baseDir };
602
+ case "custom":
603
+ return { type: "custom" };
604
+ case "cognipeer":
605
+ return { type: "cognipeer", url: sink.url };
606
+ case "http":
607
+ return { type: "http", url: sink.url };
608
+ default:
609
+ return { type: "custom" };
610
+ }
611
+ }
612
+ function buildConfigSnapshot(runtime) {
613
+ return {
614
+ enabled: runtime.resolvedConfig.enabled,
615
+ logData: runtime.resolvedConfig.logData,
616
+ sink: snapshotSink(runtime)
617
+ };
618
+ }
619
+ async function postTraceSession(url, headers, payload) {
620
+ const fetchFn = typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
621
+ if (!fetchFn) {
622
+ throw new Error("HTTP sink requires fetch to be available in this runtime.");
623
+ }
624
+ const finalHeaders = { ...headers || {} };
625
+ if (!Object.keys(finalHeaders).some((key) => key.toLowerCase() === "content-type")) {
626
+ finalHeaders["content-type"] = "application/json";
627
+ }
628
+ const response = await fetchFn(url, {
629
+ method: "POST",
630
+ headers: finalHeaders,
631
+ body: JSON.stringify(payload)
632
+ });
633
+ if (!response.ok) {
634
+ let responseText = "";
635
+ try {
636
+ responseText = await response.text();
637
+ } catch {
638
+ }
639
+ const statusLine = `HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ""}`;
640
+ const bodyPreview = responseText ? ` - ${responseText.slice(0, 200)}` : "";
641
+ throw new Error(`${statusLine}${bodyPreview}`);
642
+ }
643
+ }
644
+ function createEmptySummary() {
645
+ return {
646
+ totalDurationMs: 0,
647
+ totalInputTokens: 0,
648
+ totalOutputTokens: 0,
649
+ totalCachedInputTokens: 0,
650
+ totalBytesIn: 0,
651
+ totalBytesOut: 0,
652
+ eventCounts: {}
653
+ };
654
+ }
655
+ function generateSessionId() {
656
+ return `sess_${nanoid.nanoid(18)}`;
657
+ }
658
+ function generateEventId(sequence) {
659
+ return `evt_${String(sequence).padStart(4, "0")}_${nanoid.nanoid(4)}`;
660
+ }
661
+ function defaultEventLabel(type) {
662
+ switch (type) {
663
+ case "ai_call":
664
+ return "Assistant Response";
665
+ case "tool_call":
666
+ return "Tool Execution";
667
+ case "session":
668
+ return "Session Event";
669
+ default:
670
+ return type.replace(/_/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
671
+ }
672
+ }
673
+ function ensureUniqueSections(eventId, sections) {
674
+ if (!sections || sections.length === 0) return void 0;
675
+ const labelCounts = /* @__PURE__ */ new Map();
676
+ const normalized = [];
677
+ let counter = 1;
678
+ for (const section of sections) {
679
+ const baseLabel = section.label?.trim().length ? section.label.trim() : defaultSectionLabel(section.kind);
680
+ const nextCount = (labelCounts.get(baseLabel) || 0) + 1;
681
+ labelCounts.set(baseLabel, nextCount);
682
+ const finalLabel = nextCount > 1 ? `${baseLabel} (${nextCount})` : baseLabel;
683
+ let id = section.id?.trim();
684
+ if (!id) {
685
+ id = `${section.kind}-${eventId}-${String(counter).padStart(2, "0")}`;
347
686
  }
687
+ counter += 1;
688
+ normalized.push({
689
+ ...section,
690
+ id,
691
+ label: finalLabel
692
+ });
348
693
  }
349
- return lines.join("\n");
694
+ return normalized;
350
695
  }
351
- function formatMarkdown(params) {
352
- const { modelName, date, limits, usage, tools = [], messages } = params;
696
+ function defaultSectionLabel(kind) {
697
+ switch (kind) {
698
+ case "message":
699
+ return "Message";
700
+ case "tool_call":
701
+ return "Tool Call";
702
+ case "tool_result":
703
+ return "Tool Result";
704
+ case "tool_response":
705
+ return "Tool Response";
706
+ case "summary":
707
+ return "Summary";
708
+ case "metadata":
709
+ return "Details";
710
+ default:
711
+ return "Section";
712
+ }
713
+ }
714
+ function buildMessageLabel(role, index) {
715
+ const normalized = role?.trim().length ? role.trim() : "message";
716
+ const base = `${normalized.charAt(0).toUpperCase()}${normalized.slice(1)} Message`;
717
+ return index > 1 ? `${base} #${index}` : base;
718
+ }
719
+ function toDisplayString(value) {
720
+ const sanitized = sanitizeTracePayload(value);
721
+ if (sanitized == null) return "";
722
+ if (typeof sanitized === "string") return sanitized;
723
+ if (Array.isArray(sanitized)) {
724
+ return sanitized.map((item) => toDisplayString(item)).filter((part) => part && part.trim().length > 0).join("\n");
725
+ }
726
+ if (typeof sanitized === "object") {
727
+ if (typeof sanitized.text === "string" && Object.keys(sanitized).length === 1) {
728
+ return sanitized.text;
729
+ }
730
+ if (typeof sanitized.content === "string") {
731
+ return sanitized.content;
732
+ }
733
+ try {
734
+ return JSON.stringify(sanitized, null, 2);
735
+ } catch {
736
+ return String(sanitized);
737
+ }
738
+ }
739
+ return String(sanitized);
740
+ }
741
+ function parseToolArguments(args) {
742
+ if (args == null) return void 0;
743
+ if (typeof args === "string") {
744
+ try {
745
+ return JSON.parse(args);
746
+ } catch {
747
+ return args;
748
+ }
749
+ }
750
+ return args;
751
+ }
752
+ function collectToolCallSectionsFromMessage(message) {
353
753
  const sections = [];
354
- const add = (s = "") => sections.push(s);
355
- add(`# modelName`);
356
- add(String(modelName ?? "unknown"));
357
- add("");
358
- add(`# date`);
359
- add(date);
360
- add("");
361
- add(`# limitler`);
362
- add("```");
363
- add(JSON.stringify(limits ?? {}, null, 2));
364
- add("```");
365
- add("");
366
- add(`# usage`);
367
- if (usage) {
368
- add("```");
369
- add(JSON.stringify(usage));
370
- add("```");
371
- } else {
372
- add("(none)");
373
- }
374
- add("");
375
- add(`# tools`);
376
- add("```");
377
- add(formatTools(tools));
378
- add("```");
379
- add("");
380
- add(`# Messages`);
381
- add(formatMessages(messages));
382
- return sections.join("\n");
383
- }
384
- async function writeStepMarkdown(session, fileName, markdown, payload) {
385
- if (session.callback) {
386
- session.callback({
387
- sessionId: session.sessionId,
388
- stepIndex: session.stepIndex,
389
- fileName,
390
- markdown,
391
- messages: payload?.messages ?? [],
392
- usage: payload?.usage,
393
- modelName: payload?.modelName,
394
- limits: payload?.limits,
395
- tools: payload?.tools
754
+ if (!message) return sections;
755
+ const addCall = (call) => {
756
+ if (!call) return;
757
+ const toolName = call?.name || call?.tool || call?.function?.name || call?.function_call?.name || "tool";
758
+ const rawArgs = call?.arguments ?? call?.args ?? call?.input ?? call?.function?.arguments ?? call?.function_call?.arguments;
759
+ const parsedArgs = parseToolArguments(rawArgs);
760
+ const argumentsPayload = sanitizeTracePayload(parsedArgs ?? rawArgs ?? {});
761
+ sections.push({
762
+ kind: "tool_call",
763
+ label: `Tool Call: ${toolName}`,
764
+ tool: toolName,
765
+ arguments: argumentsPayload
766
+ });
767
+ };
768
+ const directCalls = Array.isArray(message?.tool_calls) ? message.tool_calls : void 0;
769
+ if (directCalls) {
770
+ directCalls.forEach((call) => addCall(call));
771
+ }
772
+ return sections;
773
+ }
774
+ function convertMessageListToSections(messageList) {
775
+ if (!Array.isArray(messageList) || messageList.length === 0) return void 0;
776
+ const sections = [];
777
+ const roleCounts = /* @__PURE__ */ new Map();
778
+ for (const message of messageList) {
779
+ if (!message) continue;
780
+ const toolSections = collectToolCallSectionsFromMessage(message);
781
+ if (toolSections.length > 0) {
782
+ sections.push(...toolSections);
783
+ continue;
784
+ }
785
+ const role = typeof message?.role === "string" ? message.role : "assistant";
786
+ const next = (roleCounts.get(role) || 0) + 1;
787
+ roleCounts.set(role, next);
788
+ let content = toDisplayString(message?.content ?? "");
789
+ if (!content || !content.trim().length) {
790
+ if (toolSections.length > 0) {
791
+ content = "[tool call]";
792
+ } else if (typeof message?.content === "undefined" || message?.content === null) {
793
+ continue;
794
+ } else {
795
+ content = toDisplayString(sanitizeTracePayload(message?.content));
796
+ if (!content || !content.trim().length) continue;
797
+ }
798
+ }
799
+ sections.push({
800
+ kind: "message",
801
+ label: buildMessageLabel(role, next),
802
+ role,
803
+ content,
804
+ metadata: typeof message?.name === "string" ? { name: message.name } : void 0
396
805
  });
397
- return;
398
806
  }
399
- const fp = import_node_path.default.join(session.sessionDir, fileName);
400
- await import_node_fs.default.promises.writeFile(fp, markdown, "utf8");
807
+ return sections.length > 0 ? sections : void 0;
808
+ }
809
+ function createTraceSession(opts) {
810
+ const cfg = withDefaults(opts.tracing);
811
+ if (!cfg.enabled) return void 0;
812
+ const sessionId = generateSessionId();
813
+ const runtime = {
814
+ sessionId,
815
+ startedAt: Date.now(),
816
+ resolvedConfig: cfg,
817
+ events: [],
818
+ summary: createEmptySummary(),
819
+ status: "in_progress",
820
+ errors: []
821
+ };
822
+ if (cfg.sink.type === "file") {
823
+ const baseDir = cfg.sink.baseDir;
824
+ ensureDir(baseDir);
825
+ const sessionDir = path__default.default.join(baseDir, sessionId);
826
+ ensureDir(sessionDir);
827
+ runtime.fileBaseDir = baseDir;
828
+ runtime.fileSessionDir = sessionDir;
829
+ }
830
+ return runtime;
831
+ }
832
+ function recordTraceEvent(session, event) {
833
+ if (!session) return void 0;
834
+ const sequence = session.events.length + 1;
835
+ const id = generateEventId(sequence);
836
+ const timestampIso = event.timestamp || (/* @__PURE__ */ new Date()).toISOString();
837
+ const status = event.status ?? "success";
838
+ const baseLabel = event.label?.trim().length ? event.label.trim() : defaultEventLabel(event.type);
839
+ const eventLabel = `${baseLabel} #${sequence}`;
840
+ const durationMs = event.durationMs !== void 0 ? Number(event.durationMs) : void 0;
841
+ if (!Number.isNaN(durationMs ?? NaN) && durationMs !== void 0) {
842
+ session.summary.totalDurationMs += durationMs;
843
+ }
844
+ const inputTokens = event.inputTokens !== void 0 ? Number(event.inputTokens) : void 0;
845
+ if (!Number.isNaN(inputTokens ?? NaN) && inputTokens !== void 0) {
846
+ session.summary.totalInputTokens += inputTokens;
847
+ }
848
+ const outputTokens = event.outputTokens !== void 0 ? Number(event.outputTokens) : void 0;
849
+ if (!Number.isNaN(outputTokens ?? NaN) && outputTokens !== void 0) {
850
+ session.summary.totalOutputTokens += outputTokens;
851
+ }
852
+ const cachedInputTokens = event.cachedInputTokens !== void 0 ? Number(event.cachedInputTokens) : void 0;
853
+ if (!Number.isNaN(cachedInputTokens ?? NaN) && cachedInputTokens !== void 0) {
854
+ session.summary.totalCachedInputTokens += cachedInputTokens;
855
+ }
856
+ const totalTokens = event.totalTokens !== void 0 ? Number(event.totalTokens) : void 0;
857
+ const requestBytes = event.requestBytes !== void 0 ? Number(event.requestBytes) : void 0;
858
+ if (!Number.isNaN(requestBytes ?? NaN) && requestBytes !== void 0) {
859
+ session.summary.totalBytesIn += requestBytes;
860
+ }
861
+ const responseBytes = event.responseBytes !== void 0 ? Number(event.responseBytes) : void 0;
862
+ if (!Number.isNaN(responseBytes ?? NaN) && responseBytes !== void 0) {
863
+ session.summary.totalBytesOut += responseBytes;
864
+ }
865
+ session.summary.eventCounts[event.type] = (session.summary.eventCounts[event.type] || 0) + 1;
866
+ let sections;
867
+ if (session.resolvedConfig.logData) {
868
+ const converted = convertMessageListToSections(event.messageList);
869
+ sections = ensureUniqueSections(id, converted);
870
+ }
871
+ const resolvedModel = event.model ?? inferModelFromMessages(event.messageList);
872
+ const resolvedProvider = event.provider ?? inferProviderFromMessages(event.messageList);
873
+ const isAiCall = event.type === "ai_call";
874
+ const record = {
875
+ sessionId: session.sessionId,
876
+ id,
877
+ type: event.type,
878
+ label: eventLabel,
879
+ sequence,
880
+ timestamp: timestampIso,
881
+ actor: event.actor,
882
+ status,
883
+ durationMs,
884
+ ...isAiCall ? {
885
+ inputTokens: inputTokens ?? 0,
886
+ outputTokens: outputTokens ?? 0,
887
+ totalTokens: totalTokens ?? 0,
888
+ cachedInputTokens: cachedInputTokens ?? 0
889
+ } : {
890
+ ...inputTokens !== void 0 && { inputTokens },
891
+ ...outputTokens !== void 0 && { outputTokens },
892
+ ...totalTokens !== void 0 && { totalTokens },
893
+ ...cachedInputTokens !== void 0 && { cachedInputTokens }
894
+ },
895
+ requestBytes,
896
+ responseBytes,
897
+ model: resolvedModel,
898
+ provider: resolvedProvider,
899
+ toolExecutionId: event.toolExecutionId,
900
+ retryOf: event.retryOf,
901
+ error: event.error ?? (status === "error" ? { message: "Unknown error" } : void 0) ?? void 0,
902
+ data: sections ? { sections } : void 0,
903
+ debug: event.debug
904
+ };
905
+ if (status === "error") {
906
+ const errorInfo = event.error ?? { message: "Unknown error" };
907
+ session.errors.push({
908
+ eventId: id,
909
+ message: errorInfo.message,
910
+ stack: errorInfo.stack,
911
+ type: event.type,
912
+ timestamp: timestampIso
913
+ });
914
+ }
915
+ session.events.push(record);
916
+ const sink = session.resolvedConfig.sink;
917
+ if (sink.type === "custom" && typeof sink.onEvent === "function") {
918
+ try {
919
+ const cloned = JSON.parse(JSON.stringify(record));
920
+ const result = sink.onEvent(cloned);
921
+ if (result && typeof result.then === "function") {
922
+ result.then(void 0, (error) => {
923
+ if (typeof console !== "undefined" && typeof console.warn === "function") {
924
+ console.warn("Trace custom sink onEvent rejected", error);
925
+ }
926
+ });
927
+ }
928
+ } catch (err) {
929
+ if (typeof console !== "undefined" && typeof console.warn === "function") {
930
+ console.warn("Trace custom sink onEvent failed", err);
931
+ }
932
+ }
933
+ }
934
+ return record;
935
+ }
936
+ async function finalizeTraceSession(session, params = {}) {
937
+ if (!session) return void 0;
938
+ const endedAtMs = Date.now();
939
+ const endedAtIso = new Date(endedAtMs).toISOString();
940
+ const durationMs = endedAtMs - session.startedAt;
941
+ const startedAtIso = new Date(session.startedAt).toISOString();
942
+ const agentInfo = params.agentRuntime ? {
943
+ name: params.agentRuntime.name,
944
+ version: params.agentRuntime.version,
945
+ model: getModelName(params.agentRuntime.model),
946
+ provider: getProviderName(params.agentRuntime.model)
947
+ } : void 0;
948
+ if (params.error) {
949
+ session.errors.push({
950
+ eventId: "session",
951
+ message: params.error.message || "Unknown error",
952
+ stack: params.error.stack,
953
+ type: "session",
954
+ timestamp: endedAtIso
955
+ });
956
+ }
957
+ const configSnapshot = buildConfigSnapshot(session);
958
+ const initialStatus = params.status ? params.status : session.errors.length > 0 ? "error" : "success";
959
+ const buildPayload = (status2) => ({
960
+ sessionId: session.sessionId,
961
+ startedAt: startedAtIso,
962
+ endedAt: endedAtIso,
963
+ durationMs,
964
+ agent: agentInfo,
965
+ config: configSnapshot,
966
+ summary: session.summary,
967
+ events: session.events,
968
+ status: status2,
969
+ errors: session.errors
970
+ });
971
+ const payloadForSink = buildPayload(initialStatus);
972
+ let sinkFailed = false;
973
+ const sink = session.resolvedConfig.sink;
974
+ if (sink.type === "cognipeer" || sink.type === "http") {
975
+ try {
976
+ const headers = sink.type === "cognipeer" ? { Authorization: `Bearer ${sink.apiKey}` } : sink.headers;
977
+ await postTraceSession(sink.url, headers, payloadForSink);
978
+ } catch (err) {
979
+ sinkFailed = true;
980
+ const message = err instanceof Error ? err.message : String(err);
981
+ session.errors.push({
982
+ eventId: "sink",
983
+ message,
984
+ type: "sink",
985
+ timestamp: endedAtIso
986
+ });
987
+ }
988
+ }
989
+ const hadNonSinkErrors = session.errors.some((error) => error.type && error.type !== "sink");
990
+ let status = params.status ?? (hadNonSinkErrors ? "error" : "success");
991
+ if (status === "success" && sinkFailed) {
992
+ status = "partial";
993
+ }
994
+ let finalPayload = buildPayload(status);
995
+ if (sink.type === "file" && session.fileSessionDir) {
996
+ try {
997
+ const filePath = path__default.default.join(session.fileSessionDir, "trace.session.json");
998
+ await fs__default.default.promises.writeFile(filePath, JSON.stringify(finalPayload, null, 2), "utf8");
999
+ } catch (err) {
1000
+ sinkFailed = true;
1001
+ const message = err instanceof Error ? err.message : String(err);
1002
+ session.errors.push({
1003
+ eventId: "sink",
1004
+ message,
1005
+ type: "sink",
1006
+ timestamp: endedAtIso
1007
+ });
1008
+ if (status === "success") {
1009
+ status = "partial";
1010
+ finalPayload = buildPayload(status);
1011
+ }
1012
+ }
1013
+ }
1014
+ if (sink.type === "custom" && typeof sink.onSession === "function") {
1015
+ try {
1016
+ const cloned = JSON.parse(JSON.stringify(finalPayload));
1017
+ await sink.onSession(cloned);
1018
+ } catch (err) {
1019
+ sinkFailed = true;
1020
+ const message = err instanceof Error ? err.message : String(err);
1021
+ session.errors.push({
1022
+ eventId: "sink",
1023
+ message,
1024
+ type: "sink",
1025
+ timestamp: endedAtIso
1026
+ });
1027
+ if (status === "success") {
1028
+ status = "partial";
1029
+ finalPayload = buildPayload(status);
1030
+ }
1031
+ }
1032
+ }
1033
+ if (!params.status) {
1034
+ const finalHadNonSinkErrors = session.errors.some((error) => error.type && error.type !== "sink");
1035
+ const hasSinkErrors = session.errors.some((error) => error.type === "sink");
1036
+ let computedStatus = finalHadNonSinkErrors ? "error" : "success";
1037
+ if (computedStatus === "success" && hasSinkErrors) {
1038
+ computedStatus = "partial";
1039
+ }
1040
+ if (computedStatus !== status) {
1041
+ status = computedStatus;
1042
+ finalPayload = buildPayload(status);
1043
+ }
1044
+ }
1045
+ return finalPayload;
1046
+ }
1047
+ function sanitizeTracePayload(value) {
1048
+ try {
1049
+ const cache = /* @__PURE__ */ new WeakSet();
1050
+ const json = JSON.stringify(
1051
+ value,
1052
+ (_key, val) => {
1053
+ if (typeof val === "function") return `[Function ${val.name || "anonymous"}]`;
1054
+ if (typeof val === "bigint") return val.toString();
1055
+ if (val instanceof Error) return { message: val.message, stack: val.stack };
1056
+ if (val && typeof val === "object") {
1057
+ if (cache.has(val)) return "[Circular]";
1058
+ cache.add(val);
1059
+ }
1060
+ return val;
1061
+ },
1062
+ 2
1063
+ );
1064
+ return JSON.parse(json);
1065
+ } catch {
1066
+ try {
1067
+ return typeof value === "string" ? value : String(value);
1068
+ } catch {
1069
+ return "[Unserializable]";
1070
+ }
1071
+ }
1072
+ }
1073
+ function estimatePayloadBytes(value) {
1074
+ try {
1075
+ const json = JSON.stringify(value);
1076
+ return buffer.Buffer.byteLength(json ?? "", "utf8");
1077
+ } catch {
1078
+ try {
1079
+ return buffer.Buffer.byteLength(String(value ?? ""), "utf8");
1080
+ } catch {
1081
+ return 0;
1082
+ }
1083
+ }
401
1084
  }
402
1085
 
403
1086
  // src/nodes/agentCore.ts
@@ -405,16 +1088,42 @@ function createAgentCoreNode(opts) {
405
1088
  return async (state) => {
406
1089
  const runtime = state.agent || {
407
1090
  name: opts.name,
1091
+ version: opts.version,
408
1092
  model: opts.model,
409
1093
  tools: opts.tools || [],
410
- systemPrompt: void 0,
1094
+ guardrails: opts.guardrails,
411
1095
  limits: opts.limits,
412
- useTodoList: void 0,
413
- outputSchema: opts.outputSchema
1096
+ outputSchema: opts.outputSchema,
1097
+ tracing: opts.tracing
414
1098
  };
415
1099
  const tools = runtime.tools ?? [];
416
1100
  const modelWithTools = runtime.model?.bindTools ? runtime.model.bindTools(tools) : runtime.model;
417
- const response = await modelWithTools.invoke([...state.messages]);
1101
+ const traceSession = state.ctx?.__traceSession;
1102
+ const actorName = runtime.name ?? opts.name ?? "agent";
1103
+ const actorVersion = runtime.version ?? opts.version;
1104
+ const start = Date.now();
1105
+ const shouldLogPrompt = !!traceSession && traceSession.resolvedConfig.logData;
1106
+ const promptPayload = shouldLogPrompt ? sanitizeTracePayload(state.messages) : void 0;
1107
+ const promptBytes = promptPayload !== void 0 ? estimatePayloadBytes(promptPayload) : void 0;
1108
+ let response;
1109
+ try {
1110
+ response = await modelWithTools.invoke([...state.messages]);
1111
+ } catch (err) {
1112
+ const durationMs2 = Date.now() - start;
1113
+ recordTraceEvent(traceSession, {
1114
+ type: "ai_call",
1115
+ label: "Assistant Error",
1116
+ actor: { scope: "agent", name: actorName, role: "assistant", version: actorVersion },
1117
+ status: "error",
1118
+ durationMs: durationMs2,
1119
+ requestBytes: promptBytes,
1120
+ model: getModelName(runtime.model || opts.model),
1121
+ provider: getProviderName(runtime.model || opts.model),
1122
+ error: { message: err?.message || String(err), stack: err?.stack },
1123
+ messageList: state.messages
1124
+ });
1125
+ throw err;
1126
+ }
418
1127
  const messagesWithResponse = [
419
1128
  ...state.messages,
420
1129
  response
@@ -422,6 +1131,25 @@ function createAgentCoreNode(opts) {
422
1131
  const rawUsage = response?.usage || response?.response_metadata?.token_usage || response?.response_metadata?.usage;
423
1132
  const normalized = normalizeUsage(rawUsage);
424
1133
  const modelName = getModelName(runtime.model || opts.model) || "unknown_model";
1134
+ const durationMs = Date.now() - start;
1135
+ const shouldLogResponse = !!traceSession && traceSession.resolvedConfig.logData;
1136
+ const responsePayload = shouldLogResponse ? sanitizeTracePayload(response) : void 0;
1137
+ const responseBytes = responsePayload !== void 0 ? estimatePayloadBytes(responsePayload) : void 0;
1138
+ recordTraceEvent(traceSession, {
1139
+ type: "ai_call",
1140
+ label: "Assistant Response",
1141
+ actor: { scope: "agent", name: actorName, role: "assistant", version: actorVersion },
1142
+ durationMs,
1143
+ inputTokens: normalized?.prompt_tokens,
1144
+ outputTokens: normalized?.completion_tokens,
1145
+ totalTokens: normalized?.total_tokens,
1146
+ cachedInputTokens: normalized?.prompt_tokens_details?.cached_tokens,
1147
+ requestBytes: promptBytes,
1148
+ responseBytes,
1149
+ model: modelName,
1150
+ provider: getProviderName(runtime.model || opts.model),
1151
+ messageList: messagesWithResponse
1152
+ });
425
1153
  if (normalized) {
426
1154
  const usageState = state.usage || { perRequest: [], totals: {} };
427
1155
  const id = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
@@ -445,10 +1173,6 @@ function createAgentCoreNode(opts) {
445
1173
  return { messages: messagesWithResponse, usage: state.usage };
446
1174
  };
447
1175
  }
448
-
449
- // src/nodes/tools.ts
450
- var import_nanoid = require("nanoid");
451
- var import_messages = require("@langchain/core/messages");
452
1176
  function createToolsNode(initialTools, opts) {
453
1177
  const baseToolByName = /* @__PURE__ */ new Map();
454
1178
  for (const t of initialTools) baseToolByName.set(t.name, t);
@@ -471,6 +1195,10 @@ function createToolsNode(initialTools, opts) {
471
1195
  };
472
1196
  const appended = [];
473
1197
  const onEvent = state.ctx?.__onEvent;
1198
+ const traceSession = state.ctx?.__traceSession;
1199
+ const pendingApprovals = Array.isArray(state.pendingApprovals) ? state.pendingApprovals.map((entry) => ({ ...entry })) : [];
1200
+ const pendingByCallId = new Map(pendingApprovals.map((entry) => [entry.toolCallId, entry]));
1201
+ let awaitingApproval = false;
474
1202
  for (const t of toolByName.values()) {
475
1203
  const anyT = t;
476
1204
  if (anyT._stateRef && typeof anyT._stateRef === "object") {
@@ -490,25 +1218,51 @@ function createToolsNode(initialTools, opts) {
490
1218
  const skipped = toolCalls.slice(remaining);
491
1219
  for (const tc of skipped) {
492
1220
  onEvent?.({ type: "tool_call", phase: "skipped", name: tc.name, id: tc.id, args: tc.args });
493
- appended.push(new import_messages.ToolMessage({
1221
+ const sanitizedArgs = sanitizeTracePayload(tc.args);
1222
+ const messageList = [
1223
+ {
1224
+ role: "assistant",
1225
+ name: tc.name,
1226
+ content: `Skipped tool due to tool-call limit: ${tc.name}`,
1227
+ tool_calls: [
1228
+ {
1229
+ id: tc.id,
1230
+ type: "function",
1231
+ function: {
1232
+ name: tc.name,
1233
+ arguments: sanitizedArgs
1234
+ }
1235
+ }
1236
+ ]
1237
+ }
1238
+ ];
1239
+ recordTraceEvent(traceSession, {
1240
+ type: "tool_call",
1241
+ label: `Tool Skipped - ${tc.name}`,
1242
+ actor: { scope: "tool", name: tc.name, role: "tool" },
1243
+ status: "skipped",
1244
+ toolExecutionId: tc.id,
1245
+ messageList
1246
+ });
1247
+ appended.push({
1248
+ role: "tool",
494
1249
  content: `Skipped tool due to tool-call limit: ${tc.name}`,
495
1250
  tool_call_id: tc.id || `${tc.name}_${appended.length}`,
496
1251
  name: tc.name
497
- }));
1252
+ });
498
1253
  }
499
1254
  const runOne = async (tc) => {
500
1255
  const t = toolByName.get(tc.name);
501
1256
  if (!t) {
502
1257
  onEvent?.({ type: "tool_call", phase: "error", name: tc.name, id: tc.id, args: tc.args, error: { message: "Tool not found" } });
503
- appended.push(
504
- new import_messages.ToolMessage({
505
- content: `Tool not found: ${tc.name}`,
506
- tool_call_id: tc.id || `${tc.name}_${appended.length}`,
507
- name: tc.name
508
- })
509
- );
1258
+ appended.push({
1259
+ role: "tool",
1260
+ content: `Tool not found: ${tc.name}`,
1261
+ tool_call_id: tc.id || `${tc.name}_${appended.length}`,
1262
+ name: tc.name
1263
+ });
510
1264
  toolCount += 1;
511
- return;
1265
+ return { status: "error" };
512
1266
  }
513
1267
  let args = tc.args;
514
1268
  if (typeof args === "string") {
@@ -517,9 +1271,67 @@ function createToolsNode(initialTools, opts) {
517
1271
  } catch (_) {
518
1272
  }
519
1273
  }
1274
+ const toolCallId = tc.id || `${tc.name}_${toolCount + 1}`;
1275
+ let approvalEntry = pendingByCallId.get(toolCallId);
1276
+ const needsApproval = Boolean(t.needsApproval);
1277
+ if (needsApproval) {
1278
+ if (!approvalEntry) {
1279
+ approvalEntry = {
1280
+ id: nanoid.nanoid(),
1281
+ toolCallId,
1282
+ toolName: t.name || tc.name,
1283
+ args,
1284
+ status: "pending",
1285
+ requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
1286
+ metadata: t.approvalPrompt || t.approvalDefaults ? { prompt: t.approvalPrompt, defaults: t.approvalDefaults } : void 0
1287
+ };
1288
+ pendingApprovals.push(approvalEntry);
1289
+ pendingByCallId.set(toolCallId, approvalEntry);
1290
+ onEvent?.({ type: "tool_approval", status: "pending", id: approvalEntry.id, toolName: approvalEntry.toolName, toolCallId: approvalEntry.toolCallId, args });
1291
+ } else if (!approvalEntry.args) {
1292
+ approvalEntry.args = args;
1293
+ }
1294
+ if (approvalEntry.status === "pending") {
1295
+ awaitingApproval = true;
1296
+ const ctx = state.ctx = state.ctx || {};
1297
+ ctx.__awaitingApproval = {
1298
+ approvalId: approvalEntry.id,
1299
+ toolCallId: approvalEntry.toolCallId,
1300
+ toolName: approvalEntry.toolName,
1301
+ requestedAt: approvalEntry.requestedAt
1302
+ };
1303
+ ctx.__resumeStage = "tools";
1304
+ return { status: "awaiting_approval", approval: approvalEntry };
1305
+ }
1306
+ if (approvalEntry.status === "rejected") {
1307
+ const rejectionMessage = approvalEntry.comment || "Tool call rejected by reviewer.";
1308
+ appended.push({
1309
+ role: "tool",
1310
+ content: `Tool call rejected: ${rejectionMessage}`,
1311
+ tool_call_id: toolCallId,
1312
+ name: tc.name
1313
+ });
1314
+ onEvent?.({ type: "tool_approval", status: "rejected", id: approvalEntry.id, toolName: approvalEntry.toolName, toolCallId: approvalEntry.toolCallId, comment: approvalEntry.comment, decidedBy: approvalEntry.decidedBy });
1315
+ approvalEntry.metadata = { ...approvalEntry.metadata || {}, resolution: "rejected" };
1316
+ approvalEntry.status = "executed";
1317
+ approvalEntry.resolvedAt = (/* @__PURE__ */ new Date()).toISOString();
1318
+ toolHistory.push({ executionId: nanoid.nanoid(), toolName: t.name, args, output: `Rejected: ${rejectionMessage}`, rawOutput: null, timestamp: (/* @__PURE__ */ new Date()).toISOString(), tool_call_id: tc.id });
1319
+ pendingByCallId.set(toolCallId, approvalEntry);
1320
+ toolCount += 1;
1321
+ return { status: "rejected", approval: approvalEntry };
1322
+ }
1323
+ if (approvalEntry.status === "approved") {
1324
+ if (approvalEntry.approvedArgs !== void 0) {
1325
+ args = approvalEntry.approvedArgs;
1326
+ }
1327
+ onEvent?.({ type: "tool_approval", status: "approved", id: approvalEntry.id, toolName: approvalEntry.toolName, toolCallId: approvalEntry.toolCallId, decidedBy: approvalEntry.decidedBy, comment: approvalEntry.comment });
1328
+ }
1329
+ }
1330
+ const start = Date.now();
520
1331
  try {
521
- const start = Date.now();
522
1332
  onEvent?.({ type: "tool_call", phase: "start", name: t.name, id: tc.id, args });
1333
+ const sanitizedArgs = sanitizeTracePayload(args);
1334
+ const inputBytes = traceSession?.resolvedConfig.logData ? estimatePayloadBytes(sanitizedArgs) : void 0;
523
1335
  let output;
524
1336
  const anyTool = t;
525
1337
  if (typeof anyTool.func === "function") output = await anyTool.func(args);
@@ -530,14 +1342,20 @@ function createToolsNode(initialTools, opts) {
530
1342
  else throw new Error("Tool is not invokable");
531
1343
  if (output && typeof output === "object" && output.__handoff && output.__handoff.runtime) {
532
1344
  const newRuntime = output.__handoff.runtime;
533
- const executionId2 = (0, import_nanoid.nanoid)();
1345
+ const executionId2 = nanoid.nanoid();
534
1346
  toolHistory.push({ executionId: executionId2, toolName: t.name, args, output: "handoff:ok", rawOutput: output, timestamp: (/* @__PURE__ */ new Date()).toISOString(), tool_call_id: tc.id });
535
- appended.push(new import_messages.ToolMessage({ content: "ok", tool_call_id: tc.id || `${tc.name}_${appended.length}`, name: tc.name }));
1347
+ appended.push({ role: "tool", content: "ok", tool_call_id: tc.id || `${tc.name}_${appended.length}`, name: tc.name });
536
1348
  onEvent?.({ type: "handoff", from: runtime.name, to: newRuntime.name, toolName: t.name });
537
1349
  state.agent = newRuntime;
538
1350
  onEvent?.({ type: "tool_call", phase: "success", name: t.name, id: tc.id, args, result: "handoff", durationMs: Date.now() - start });
539
1351
  toolCount += 1;
540
- return;
1352
+ if (needsApproval && approvalEntry) {
1353
+ approvalEntry.status = "executed";
1354
+ approvalEntry.resolvedAt = (/* @__PURE__ */ new Date()).toISOString();
1355
+ approvalEntry.executionId = executionId2;
1356
+ pendingByCallId.set(toolCallId, approvalEntry);
1357
+ }
1358
+ return { status: "success", approval: approvalEntry };
541
1359
  }
542
1360
  const content = typeof output === "string" ? output : JSON.stringify(output);
543
1361
  if (output && typeof output === "object" && output.__finalStructuredOutput) {
@@ -545,25 +1363,124 @@ function createToolsNode(initialTools, opts) {
545
1363
  state.ctx.__structuredOutputParsed = output.data;
546
1364
  state.ctx.__finalizedDueToStructuredOutput = true;
547
1365
  }
548
- const executionId = (0, import_nanoid.nanoid)();
1366
+ const durationMs = Date.now() - start;
1367
+ const executionId = nanoid.nanoid();
549
1368
  toolHistory.push({ executionId, toolName: t.name, args, output, rawOutput: output, timestamp: (/* @__PURE__ */ new Date()).toISOString(), tool_call_id: tc.id });
550
- appended.push(new import_messages.ToolMessage({ content, tool_call_id: tc.id || `${tc.name}_${appended.length}`, name: tc.name }));
551
- onEvent?.({ type: "tool_call", phase: "success", name: t.name, id: tc.id, args, result: output, durationMs: Date.now() - start });
1369
+ appended.push({ role: "tool", content, tool_call_id: tc.id || `${tc.name}_${appended.length}`, name: tc.name });
1370
+ onEvent?.({ type: "tool_call", phase: "success", name: t.name, id: tc.id, args, result: output, durationMs });
1371
+ if (needsApproval && approvalEntry) {
1372
+ approvalEntry.status = "executed";
1373
+ approvalEntry.resolvedAt = (/* @__PURE__ */ new Date()).toISOString();
1374
+ approvalEntry.executionId = executionId;
1375
+ pendingByCallId.set(toolCallId, approvalEntry);
1376
+ }
1377
+ const sanitizedOutput = sanitizeTracePayload(output);
1378
+ const outputBytes = traceSession?.resolvedConfig.logData ? estimatePayloadBytes(sanitizedOutput) : void 0;
1379
+ const toolName = t.name || tc.name;
1380
+ const messageList = [
1381
+ {
1382
+ role: "assistant",
1383
+ name: toolName,
1384
+ content: "",
1385
+ tool_calls: [
1386
+ {
1387
+ id: tc.id || executionId,
1388
+ type: "function",
1389
+ function: {
1390
+ name: toolName,
1391
+ arguments: sanitizedArgs
1392
+ }
1393
+ }
1394
+ ]
1395
+ },
1396
+ {
1397
+ role: "tool",
1398
+ name: toolName,
1399
+ content: sanitizedOutput ?? output ?? ""
1400
+ }
1401
+ ];
1402
+ recordTraceEvent(traceSession, {
1403
+ type: "tool_call",
1404
+ label: `Tool Execution - ${toolName}`,
1405
+ actor: { scope: "tool", name: toolName, role: "tool" },
1406
+ durationMs,
1407
+ requestBytes: inputBytes,
1408
+ responseBytes: outputBytes,
1409
+ toolExecutionId: executionId,
1410
+ messageList
1411
+ });
552
1412
  toolCount += 1;
1413
+ return { status: "success", approval: approvalEntry };
553
1414
  } catch (e) {
554
- const executionId = (0, import_nanoid.nanoid)();
1415
+ const durationMs = Date.now() - start;
1416
+ const executionId = nanoid.nanoid();
555
1417
  toolHistory.push({ executionId, toolName: t.name, args, output: `Error executing tool: ${e?.message || String(e)}`, rawOutput: null, timestamp: (/* @__PURE__ */ new Date()).toISOString(), tool_call_id: tc.id });
556
- appended.push(new import_messages.ToolMessage({ content: `Error executing tool: ${e?.message || String(e)}`, tool_call_id: tc.id || `${tc.name}_${appended.length}`, name: tc.name }));
1418
+ appended.push({ role: "tool", content: `Error executing tool: ${e?.message || String(e)}`, tool_call_id: tc.id || `${tc.name}_${appended.length}`, name: tc.name });
557
1419
  onEvent?.({ type: "tool_call", phase: "error", name: t.name, id: tc.id, args, error: { message: e?.message || String(e) } });
1420
+ const sanitizedArgs = sanitizeTracePayload(args);
1421
+ const inputBytes = traceSession?.resolvedConfig.logData ? estimatePayloadBytes(sanitizedArgs) : void 0;
1422
+ const toolName = t.name || tc.name;
1423
+ const errorMessage = e?.message || String(e);
1424
+ const messageList = [
1425
+ {
1426
+ role: "assistant",
1427
+ name: toolName,
1428
+ content: "",
1429
+ tool_calls: [
1430
+ {
1431
+ id: tc.id || executionId,
1432
+ type: "function",
1433
+ function: {
1434
+ name: toolName,
1435
+ arguments: sanitizedArgs
1436
+ }
1437
+ }
1438
+ ]
1439
+ },
1440
+ {
1441
+ role: "tool",
1442
+ name: toolName,
1443
+ content: `Error executing tool: ${errorMessage}`
1444
+ }
1445
+ ];
1446
+ recordTraceEvent(traceSession, {
1447
+ type: "tool_call",
1448
+ label: `Tool Error - ${toolName}`,
1449
+ actor: { scope: "tool", name: toolName, role: "tool" },
1450
+ status: "error",
1451
+ durationMs,
1452
+ requestBytes: inputBytes,
1453
+ toolExecutionId: executionId,
1454
+ error: { message: e?.message || String(e), stack: e?.stack },
1455
+ messageList
1456
+ });
558
1457
  toolCount += 1;
1458
+ return { status: "error", approval: approvalEntry };
559
1459
  }
560
1460
  };
561
- const concurrency = Math.max(1, limits.maxParallelTools);
562
- for (let i = 0; i < planned.length; i += concurrency) {
563
- const batch = planned.slice(i, i + concurrency);
564
- await Promise.all(batch.map(runOne));
1461
+ for (const tc of planned) {
1462
+ if (awaitingApproval) break;
1463
+ const result = await runOne(tc);
1464
+ if (result?.status === "awaiting_approval") {
1465
+ awaitingApproval = true;
1466
+ break;
1467
+ }
565
1468
  }
566
- return { messages: [...state.messages, ...appended], toolCallCount: toolCount, toolHistory, agent: state.agent };
1469
+ if (!awaitingApproval && state.ctx?.__awaitingApproval) {
1470
+ const ctx = { ...state.ctx };
1471
+ delete ctx.__awaitingApproval;
1472
+ if (!pendingApprovals.some((entry) => entry.status !== "executed")) {
1473
+ delete ctx.__resumeStage;
1474
+ }
1475
+ state.ctx = Object.keys(ctx).length > 0 ? ctx : void 0;
1476
+ }
1477
+ return {
1478
+ messages: [...state.messages, ...appended],
1479
+ toolCallCount: toolCount,
1480
+ toolHistory,
1481
+ agent: state.agent,
1482
+ pendingApprovals
1483
+ };
567
1484
  };
568
1485
  }
569
1486
 
@@ -575,6 +1492,207 @@ function createToolLimitFinalizeNode(_opts) {
575
1492
  return { messages: [...state.messages, notice], ctx };
576
1493
  };
577
1494
  }
1495
+ function ensureArray(value) {
1496
+ return Array.isArray(value) ? value : [];
1497
+ }
1498
+ function buildContext(params) {
1499
+ const latest = params.state.messages[params.state.messages.length - 1];
1500
+ return {
1501
+ phase: params.phase,
1502
+ messages: params.state.messages,
1503
+ latestMessage: latest,
1504
+ state: params.state,
1505
+ runtime: params.runtime,
1506
+ options: params.options
1507
+ };
1508
+ }
1509
+ function normalizeDisposition(passed, disposition) {
1510
+ if (disposition) return disposition;
1511
+ return passed ? "allow" : "block";
1512
+ }
1513
+ async function evaluateGuardrails(params) {
1514
+ const incidents = [];
1515
+ const guardrails = ensureArray(params.guardrails).filter(
1516
+ (guardrail) => ensureArray(guardrail.appliesTo).includes(params.phase)
1517
+ );
1518
+ if (guardrails.length === 0) {
1519
+ return { ok: true, incidents };
1520
+ }
1521
+ const context = buildContext(params);
1522
+ for (const guardrail of guardrails) {
1523
+ for (const rule of ensureArray(guardrail.rules)) {
1524
+ let result;
1525
+ try {
1526
+ result = await rule.evaluate(context);
1527
+ } catch (err) {
1528
+ result = {
1529
+ passed: false,
1530
+ reason: err instanceof Error ? err.message : String(err ?? "Unknown error"),
1531
+ details: { thrown: true },
1532
+ disposition: "block"
1533
+ };
1534
+ }
1535
+ const passed = result?.passed !== false;
1536
+ const disposition = normalizeDisposition(passed, result?.disposition);
1537
+ if (passed && disposition === "allow") {
1538
+ continue;
1539
+ }
1540
+ const incident = {
1541
+ guardrailId: guardrail.id ?? rule.id ?? nanoid.nanoid(8),
1542
+ guardrailTitle: guardrail.title,
1543
+ ruleId: rule.id,
1544
+ ruleTitle: rule.title,
1545
+ phase: params.phase,
1546
+ reason: result?.reason,
1547
+ details: result?.details,
1548
+ disposition
1549
+ };
1550
+ let effectiveDisposition = incident.disposition;
1551
+ if (typeof guardrail.onViolation === "function") {
1552
+ try {
1553
+ const override = await guardrail.onViolation(incident, context);
1554
+ if (override) {
1555
+ effectiveDisposition = override;
1556
+ incident.disposition = override;
1557
+ }
1558
+ } catch (err) {
1559
+ effectiveDisposition = "block";
1560
+ incident.disposition = "block";
1561
+ incident.details = {
1562
+ ...incident.details || {},
1563
+ onViolationError: err instanceof Error ? err.message : String(err ?? "Unknown error")
1564
+ };
1565
+ if (!incident.reason) {
1566
+ incident.reason = "Guardrail onViolation handler threw an error.";
1567
+ }
1568
+ }
1569
+ }
1570
+ incidents.push(incident);
1571
+ params.emit?.({
1572
+ type: "guardrail",
1573
+ phase: params.phase,
1574
+ guardrailId: incident.guardrailId,
1575
+ guardrailTitle: incident.guardrailTitle,
1576
+ ruleId: incident.ruleId,
1577
+ ruleTitle: incident.ruleTitle,
1578
+ disposition: effectiveDisposition,
1579
+ reason: incident.reason,
1580
+ details: incident.details
1581
+ });
1582
+ if (effectiveDisposition === "block" && guardrail.haltOnViolation !== false) {
1583
+ break;
1584
+ }
1585
+ }
1586
+ }
1587
+ const ok = incidents.every((incident) => incident.disposition !== "block");
1588
+ return { ok, incidents };
1589
+ }
1590
+ function createGuardrail(options) {
1591
+ const appliesTo = options.appliesTo?.length ? options.appliesTo : ["request" /* Request */, "response" /* Response */];
1592
+ return {
1593
+ id: options.id,
1594
+ title: options.title,
1595
+ description: options.description,
1596
+ appliesTo,
1597
+ rules: options.checks,
1598
+ haltOnViolation: options.haltOnViolation,
1599
+ onViolation: options.onViolation,
1600
+ metadata: options.metadata
1601
+ };
1602
+ }
1603
+
1604
+ // src/utils/stateSnapshot.ts
1605
+ var DISALLOWED_CTX_KEYS = /* @__PURE__ */ new Set(["__onEvent", "__traceSession", "__paused"]);
1606
+ var clone = (value) => {
1607
+ if (typeof globalThis.structuredClone === "function") {
1608
+ return globalThis.structuredClone(value);
1609
+ }
1610
+ return JSON.parse(JSON.stringify(value));
1611
+ };
1612
+ var cleanCtx = (ctx) => {
1613
+ if (!ctx) return void 0;
1614
+ const entries = Object.entries(ctx).filter(([key]) => !DISALLOWED_CTX_KEYS.has(key));
1615
+ if (entries.length === 0) return void 0;
1616
+ return Object.fromEntries(entries);
1617
+ };
1618
+ var runtimeHintFromAgent = (agent) => {
1619
+ if (!agent) return void 0;
1620
+ const tools = Array.isArray(agent.tools) ? agent.tools.map((tool) => tool?.name).filter(Boolean) : void 0;
1621
+ return {
1622
+ name: agent.name,
1623
+ version: agent.version,
1624
+ tools: tools && tools.length > 0 ? tools : void 0
1625
+ };
1626
+ };
1627
+ function captureSnapshot(state, options) {
1628
+ const { agent, ctx, ...rest } = state;
1629
+ const metadata = {
1630
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1631
+ tag: options?.tag,
1632
+ paused: ctx?.__paused ?? null
1633
+ };
1634
+ const safeState = clone({
1635
+ ...rest,
1636
+ ctx: cleanCtx(ctx)
1637
+ });
1638
+ if (safeState.ctx && "__paused" in safeState.ctx) {
1639
+ delete safeState.ctx.__paused;
1640
+ }
1641
+ return {
1642
+ state: safeState,
1643
+ runtimeHint: options?.includeRuntimeHint !== false ? runtimeHintFromAgent(agent) : void 0,
1644
+ metadata
1645
+ };
1646
+ }
1647
+ function restoreSnapshot(snapshot, restoreOptions) {
1648
+ const base = clone(snapshot.state);
1649
+ const incomingCtx = restoreOptions?.ctx;
1650
+ const mergedCtx = restoreOptions?.mergeCtx === false ? cleanCtx(incomingCtx) : {
1651
+ ...base.ctx || {},
1652
+ ...cleanCtx(incomingCtx)
1653
+ };
1654
+ const ctx = {
1655
+ ...mergedCtx || {},
1656
+ __restoredFromSnapshot: true
1657
+ };
1658
+ const restored = {
1659
+ ...base,
1660
+ ctx
1661
+ };
1662
+ if (restoreOptions?.agent) {
1663
+ restored.agent = restoreOptions.agent;
1664
+ }
1665
+ return restored;
1666
+ }
1667
+
1668
+ // src/utils/toolApprovals.ts
1669
+ var cloneApprovals = (approvals) => Array.isArray(approvals) ? approvals.map((entry) => ({ ...entry })) : [];
1670
+ function resolveToolApprovalState(state, resolution) {
1671
+ const approvals = cloneApprovals(state.pendingApprovals);
1672
+ const matchIndex = approvals.findIndex((entry2) => entry2.id === resolution.id || entry2.toolCallId === resolution.id);
1673
+ if (matchIndex === -1) {
1674
+ throw new Error(`Pending approval not found for id: ${resolution.id}`);
1675
+ }
1676
+ const entry = { ...approvals[matchIndex] };
1677
+ if (entry.status === "executed") {
1678
+ throw new Error(`Tool approval ${entry.id} already completed.`);
1679
+ }
1680
+ entry.status = resolution.approved ? "approved" : "rejected";
1681
+ entry.approvedArgs = resolution.approved ? resolution.approvedArgs ?? entry.args : void 0;
1682
+ entry.decidedBy = resolution.decidedBy;
1683
+ entry.comment = resolution.comment;
1684
+ entry.decidedAt = (/* @__PURE__ */ new Date()).toISOString();
1685
+ approvals[matchIndex] = entry;
1686
+ const ctx = { ...state.ctx || {} };
1687
+ delete ctx.__awaitingApproval;
1688
+ ctx.__resumeStage = "tools";
1689
+ ctx.__approvalResolved = { id: entry.id, status: entry.status };
1690
+ return {
1691
+ ...state,
1692
+ pendingApprovals: approvals,
1693
+ ctx
1694
+ };
1695
+ }
578
1696
 
579
1697
  // src/agent.ts
580
1698
  function createAgent(opts) {
@@ -582,7 +1700,7 @@ function createAgent(opts) {
582
1700
  const agentCore = createAgentCoreNode(opts);
583
1701
  const toolsBase = [...opts.tools ?? []];
584
1702
  if (opts.outputSchema) {
585
- const responseTool = createSmartTool({
1703
+ const responseTool = createTool({
586
1704
  name: "response",
587
1705
  description: "Finalize the answer by returning the final structured JSON matching the required schema. Call exactly once when you are fully done, then stop.",
588
1706
  schema: opts.outputSchema,
@@ -591,15 +1709,180 @@ function createAgent(opts) {
591
1709
  toolsBase.push(responseTool);
592
1710
  }
593
1711
  const toolsNode = createToolsNode(toolsBase, opts);
594
- const finalizeNode = createToolLimitFinalizeNode(opts);
595
- async function runLoop(initial, config) {
1712
+ const finalizeNode = createToolLimitFinalizeNode();
1713
+ const mergeGuardrailOutcomes = (prev, next) => {
1714
+ if (!prev) return next;
1715
+ return {
1716
+ ok: prev.ok && next.ok,
1717
+ incidents: [...prev.incidents, ...next.incidents]
1718
+ };
1719
+ };
1720
+ const ensureGuardrailStore = (state) => {
1721
+ const ctx = state.ctx = state.ctx || {};
1722
+ const existing = ctx.__guardrailStore || {
1723
+ lastRequestLength: -1,
1724
+ lastResponseLength: -1
1725
+ };
1726
+ ctx.__guardrailStore = existing;
1727
+ return existing;
1728
+ };
1729
+ const getGuardrailConfig = (state) => {
1730
+ const agentGuardrails = state.agent?.guardrails;
1731
+ return Array.isArray(agentGuardrails) ? agentGuardrails : Array.isArray(opts.guardrails) ? opts.guardrails : [];
1732
+ };
1733
+ const runtime = {
1734
+ name: opts.name,
1735
+ version: opts.version,
1736
+ model: opts.model,
1737
+ tools: toolsBase,
1738
+ guardrails: opts.guardrails,
1739
+ systemPrompt: void 0,
1740
+ limits: opts.limits,
1741
+ useTodoList: void 0,
1742
+ outputSchema: opts.outputSchema,
1743
+ tracing: opts.tracing
1744
+ };
1745
+ async function runLoop(initial, config, emit) {
596
1746
  let state = await resolver(initial);
1747
+ if (state.ctx?.__paused) {
1748
+ const nextCtx = { ...state.ctx };
1749
+ delete nextCtx.__paused;
1750
+ state = { ...state, ctx: Object.keys(nextCtx).length > 0 ? nextCtx : void 0 };
1751
+ }
1752
+ let resumeStage = null;
1753
+ if (state.ctx?.__resumeStage) {
1754
+ const nextCtx = { ...state.ctx };
1755
+ if (nextCtx.__resumeStage === "tools") {
1756
+ resumeStage = "tools";
1757
+ }
1758
+ delete nextCtx.__resumeStage;
1759
+ state = { ...state, ctx: Object.keys(nextCtx).length > 0 ? nextCtx : void 0 };
1760
+ }
597
1761
  const maxToolCalls = opts.limits?.maxToolCalls ?? 10;
598
1762
  const iterationLimit = Math.max(maxToolCalls * 3 + 10, 40);
599
1763
  let iterations = 0;
1764
+ const onStateChange = config?.onStateChange;
1765
+ const checkpointReason = config?.checkpointReason;
1766
+ let pausedStage = null;
1767
+ const checkpointIfRequested = (stage) => {
1768
+ if (typeof onStateChange !== "function") return false;
1769
+ let result = false;
1770
+ try {
1771
+ result = onStateChange(state);
1772
+ } catch {
1773
+ result = false;
1774
+ }
1775
+ if (!result) return false;
1776
+ const ctx = { ...state.ctx || {} };
1777
+ ctx.__paused = {
1778
+ stage,
1779
+ iteration: iterations,
1780
+ reason: checkpointReason,
1781
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1782
+ };
1783
+ state = { ...state, ctx };
1784
+ pausedStage = stage;
1785
+ return true;
1786
+ };
600
1787
  while (iterations < iterationLimit) {
601
1788
  iterations++;
602
- state = { ...state, ...await agentCore(state) };
1789
+ const skippingAgent = resumeStage === "tools";
1790
+ if (!skippingAgent) {
1791
+ if (checkpointIfRequested("before_guardrails")) break;
1792
+ const preGuardrails = getGuardrailConfig(state);
1793
+ if (preGuardrails.length > 0) {
1794
+ const store = ensureGuardrailStore(state);
1795
+ if (store.lastRequestLength !== state.messages.length) {
1796
+ const outcome = await evaluateGuardrails({
1797
+ guardrails: preGuardrails,
1798
+ phase: "request" /* Request */,
1799
+ state,
1800
+ runtime: state.agent || runtime,
1801
+ options: opts,
1802
+ emit
1803
+ });
1804
+ store.lastRequestLength = state.messages.length;
1805
+ state.guardrailResult = mergeGuardrailOutcomes(state.guardrailResult, outcome);
1806
+ const blocking = outcome.incidents.find((incident) => incident.disposition === "block");
1807
+ if (blocking) {
1808
+ const guardMessage = {
1809
+ role: "assistant",
1810
+ name: "guardrail",
1811
+ content: blocking.reason || "Request blocked by guardrail policy.",
1812
+ metadata: {
1813
+ guardrail: {
1814
+ phase: "request" /* Request */,
1815
+ incidents: outcome.incidents
1816
+ }
1817
+ }
1818
+ };
1819
+ state = { ...state, messages: [...state.messages, guardMessage] };
1820
+ const ctx = state.ctx = state.ctx || {};
1821
+ ctx.__guardrailBlocked = {
1822
+ phase: "request" /* Request */,
1823
+ incident: blocking
1824
+ };
1825
+ break;
1826
+ }
1827
+ }
1828
+ }
1829
+ state = { ...state, ...await agentCore(state) };
1830
+ if (checkpointIfRequested("after_agent")) break;
1831
+ const postGuardrails = getGuardrailConfig(state);
1832
+ if (postGuardrails.length > 0) {
1833
+ const store = ensureGuardrailStore(state);
1834
+ if (store.lastResponseLength !== state.messages.length) {
1835
+ const outcome = await evaluateGuardrails({
1836
+ guardrails: postGuardrails,
1837
+ phase: "response" /* Response */,
1838
+ state,
1839
+ runtime: state.agent || runtime,
1840
+ options: opts,
1841
+ emit
1842
+ });
1843
+ store.lastResponseLength = state.messages.length;
1844
+ state.guardrailResult = mergeGuardrailOutcomes(state.guardrailResult, outcome);
1845
+ const blocking = outcome.incidents.find((incident) => incident.disposition === "block");
1846
+ if (blocking) {
1847
+ const updatedMessages = [...state.messages];
1848
+ const replaced = updatedMessages.pop();
1849
+ updatedMessages.push({
1850
+ role: "assistant",
1851
+ name: "guardrail",
1852
+ content: blocking.reason || "Response blocked by guardrail policy.",
1853
+ metadata: {
1854
+ guardrail: {
1855
+ phase: "response" /* Response */,
1856
+ incidents: outcome.incidents,
1857
+ replaced
1858
+ }
1859
+ }
1860
+ });
1861
+ state = { ...state, messages: updatedMessages };
1862
+ const ctx = state.ctx = state.ctx || {};
1863
+ ctx.__guardrailBlocked = {
1864
+ phase: "response" /* Response */,
1865
+ incident: blocking,
1866
+ replaced
1867
+ };
1868
+ break;
1869
+ } else if (outcome.incidents.length > 0) {
1870
+ const last = state.messages[state.messages.length - 1];
1871
+ if (last) {
1872
+ last.metadata = {
1873
+ ...last.metadata || {},
1874
+ guardrail: {
1875
+ phase: "response" /* Response */,
1876
+ incidents: outcome.incidents
1877
+ }
1878
+ };
1879
+ }
1880
+ }
1881
+ }
1882
+ }
1883
+ } else {
1884
+ resumeStage = null;
1885
+ }
603
1886
  const lastMsg = state.messages[state.messages.length - 1];
604
1887
  const toolCalls = Array.isArray(lastMsg?.tool_calls) ? lastMsg.tool_calls : [];
605
1888
  const toolCallCount = state.toolCallCount || 0;
@@ -612,79 +1895,99 @@ function createAgent(opts) {
612
1895
  }
613
1896
  if (toolCalls.length === 0) break;
614
1897
  state = { ...state, ...await toolsNode(state) };
1898
+ if (state.ctx?.__awaitingApproval) break;
1899
+ if (checkpointIfRequested("after_tools")) break;
615
1900
  if (state.ctx?.__finalizedDueToStructuredOutput) break;
616
1901
  }
1902
+ if (!pausedStage && typeof onStateChange === "function" && onStateChange(state)) {
1903
+ checkpointIfRequested("after_loop");
1904
+ }
617
1905
  return state;
618
1906
  }
619
- const runtime = {
620
- name: opts.name,
621
- model: opts.model,
622
- tools: toolsBase,
623
- systemPrompt: void 0,
624
- limits: opts.limits,
625
- useTodoList: void 0,
626
- outputSchema: opts.outputSchema
1907
+ const invokeAgent = async (input, config) => {
1908
+ const onEvent = config?.onEvent;
1909
+ const emit = (e) => {
1910
+ try {
1911
+ onEvent?.(e);
1912
+ } catch {
1913
+ }
1914
+ };
1915
+ const traceSession = createTraceSession(opts);
1916
+ const ctx = { ...input.ctx || {}, __onEvent: onEvent };
1917
+ if (traceSession) ctx.__traceSession = traceSession;
1918
+ const initial = {
1919
+ messages: input.messages || [],
1920
+ toolCallCount: input.toolCallCount || 0,
1921
+ toolCache: input.toolCache || {},
1922
+ toolHistory: input.toolHistory || [],
1923
+ metadata: input.metadata,
1924
+ ctx,
1925
+ pendingApprovals: input.pendingApprovals || [],
1926
+ agent: input.agent || runtime,
1927
+ usage: input.usage || { perRequest: [], totals: {} }
1928
+ };
1929
+ let res;
1930
+ try {
1931
+ res = await runLoop(initial, config, emit);
1932
+ } catch (err) {
1933
+ await finalizeTraceSession(traceSession, {
1934
+ agentRuntime: runtime,
1935
+ status: "error",
1936
+ error: { message: err?.message, stack: err?.stack }
1937
+ });
1938
+ throw err;
1939
+ }
1940
+ await finalizeTraceSession(traceSession, {
1941
+ agentRuntime: res.agent || runtime,
1942
+ status: "success"
1943
+ });
1944
+ const finalMsg = res.messages[res.messages.length - 1];
1945
+ let content = "";
1946
+ if (typeof finalMsg?.content === "string") content = finalMsg.content;
1947
+ else if (Array.isArray(finalMsg?.content)) content = finalMsg.content.map((c) => typeof c === "string" ? c : c?.text ?? c?.content ?? "").join("");
1948
+ let parsed = void 0;
1949
+ const schema = opts.outputSchema;
1950
+ if (schema && res.ctx?.__structuredOutputParsed) {
1951
+ parsed = res.ctx.__structuredOutputParsed;
1952
+ } else if (schema && content) {
1953
+ let jsonText = null;
1954
+ const fenced = content.match(/```(?:json)?\n([\s\S]*?)```/i);
1955
+ if (fenced && fenced[1]) jsonText = fenced[1].trim();
1956
+ else {
1957
+ const braceIdx = content.indexOf("{");
1958
+ const bracketIdx = content.indexOf("[");
1959
+ const start = [braceIdx, bracketIdx].filter((i) => i >= 0).sort((a, b) => a - b)[0];
1960
+ if (start !== void 0) jsonText = content.slice(start).trim();
1961
+ }
1962
+ try {
1963
+ const raw = JSON.parse(jsonText ?? content);
1964
+ parsed = schema.parse(raw);
1965
+ } catch {
1966
+ }
1967
+ }
1968
+ emit({ type: "finalAnswer", content: typeof finalMsg?.content === "string" ? finalMsg.content : content });
1969
+ return {
1970
+ content,
1971
+ output: parsed,
1972
+ metadata: { usage: res.usage },
1973
+ messages: res.messages,
1974
+ state: res
1975
+ };
627
1976
  };
1977
+ const snapshotState = (state, options) => captureSnapshot(state, options);
1978
+ const resumeAgent = async (snapshot, config, restoreOptions) => {
1979
+ const restoredState = restoreSnapshot(snapshot, restoreOptions);
1980
+ return invokeAgent(restoredState, config);
1981
+ };
1982
+ const resolveToolApproval = (state, resolution) => resolveToolApprovalState(state, resolution);
628
1983
  const instance = {
629
- invoke: async (input, config) => {
630
- const onEvent = config?.onEvent;
631
- const emit = (e) => {
632
- try {
633
- onEvent?.(e);
634
- } catch {
635
- }
636
- };
637
- const initial = {
638
- messages: input.messages || [],
639
- summaries: input.summaries || [],
640
- toolCallCount: input.toolCallCount || 0,
641
- toolCache: input.toolCache || {},
642
- toolHistory: input.toolHistory || [],
643
- toolHistoryArchived: input.toolHistoryArchived || [],
644
- metadata: input.metadata,
645
- ctx: { ...input.ctx || {}, __onEvent: onEvent },
646
- plan: input.plan || null,
647
- planVersion: input.planVersion || 0,
648
- agent: input.agent || runtime,
649
- usage: input.usage || { perRequest: [], totals: {} }
650
- };
651
- const res = await runLoop(initial, config);
652
- const finalMsg = res.messages[res.messages.length - 1];
653
- let content = "";
654
- if (typeof finalMsg?.content === "string") content = finalMsg.content;
655
- else if (Array.isArray(finalMsg?.content)) content = finalMsg.content.map((c) => typeof c === "string" ? c : c?.text ?? c?.content ?? "").join("");
656
- let parsed = void 0;
657
- const schema = opts.outputSchema;
658
- if (schema && res.ctx?.__structuredOutputParsed) {
659
- parsed = res.ctx.__structuredOutputParsed;
660
- } else if (schema && content) {
661
- let jsonText = null;
662
- const fenced = content.match(/```(?:json)?\n([\s\S]*?)```/i);
663
- if (fenced && fenced[1]) jsonText = fenced[1].trim();
664
- else {
665
- const braceIdx = content.indexOf("{");
666
- const bracketIdx = content.indexOf("[");
667
- const start = [braceIdx, bracketIdx].filter((i) => i >= 0).sort((a, b) => a - b)[0];
668
- if (start !== void 0) jsonText = content.slice(start).trim();
669
- }
670
- try {
671
- const raw = JSON.parse(jsonText ?? content);
672
- parsed = schema.parse(raw);
673
- } catch {
674
- }
675
- }
676
- emit({ type: "finalAnswer", content: typeof finalMsg?.content === "string" ? finalMsg.content : content });
677
- return {
678
- content,
679
- output: parsed,
680
- metadata: { usage: res.usage },
681
- messages: res.messages,
682
- state: res
683
- };
684
- },
1984
+ invoke: invokeAgent,
1985
+ snapshot: snapshotState,
1986
+ resume: resumeAgent,
1987
+ resolveToolApproval,
685
1988
  asTool: ({ toolName, description, inputDescription }) => {
686
- const schema = import_zod.z.object({ input: import_zod.z.string().describe(inputDescription || "Input for delegated agent") });
687
- return createSmartTool({
1989
+ const schema = zod.z.object({ input: zod.z.string().describe(inputDescription || "Input for delegated agent") });
1990
+ return createTool({
688
1991
  name: toolName,
689
1992
  description: description || `Delegate task to agent ${opts.name || "Agent"}`,
690
1993
  schema,
@@ -696,8 +1999,8 @@ function createAgent(opts) {
696
1999
  },
697
2000
  asHandoff: ({ toolName, description, schema }) => {
698
2001
  const finalName = toolName || `handoff_to_${runtime.name || "agent"}`;
699
- const zschema = schema || import_zod.z.object({ reason: import_zod.z.string().describe("Reason for handoff") });
700
- const tool3 = createSmartTool({
2002
+ const zschema = schema || zod.z.object({ reason: zod.z.string().describe("Reason for handoff") });
2003
+ createTool({
701
2004
  name: finalName,
702
2005
  description: description || `Handoff control to agent ${runtime.name || "Agent"}`,
703
2006
  schema: zschema,
@@ -709,8 +2012,8 @@ function createAgent(opts) {
709
2012
  };
710
2013
  if (opts.handoffs && Array.isArray(opts.handoffs)) {
711
2014
  const handoffTools = opts.handoffs.map((h) => {
712
- const schema = h.schema || import_zod.z.object({ reason: import_zod.z.string().describe("Reason for handoff") });
713
- return createSmartTool({
2015
+ const schema = h.schema || zod.z.object({ reason: zod.z.string().describe("Reason for handoff") });
2016
+ return createTool({
714
2017
  name: h.toolName,
715
2018
  description: h.description || `Handoff to ${h.target.__runtime.name || "agent"}`,
716
2019
  schema,
@@ -727,6 +2030,7 @@ function createAgentNode(opts) {
727
2030
  return async (state) => {
728
2031
  const runtime = state.agent || {
729
2032
  name: opts.name,
2033
+ version: opts.version,
730
2034
  model: opts.model,
731
2035
  tools: opts.tools || [],
732
2036
  systemPrompt: opts.systemPrompt,
@@ -735,12 +2039,6 @@ function createAgentNode(opts) {
735
2039
  outputSchema: opts.outputSchema
736
2040
  };
737
2041
  const tools = runtime.tools ?? [];
738
- const limits = {
739
- maxToolCalls: runtime.limits?.maxToolCalls ?? 10,
740
- toolOutputTokenLimit: runtime.limits?.toolOutputTokenLimit ?? 5e3,
741
- contextTokenLimit: runtime.limits?.contextTokenLimit ?? 6e4,
742
- summaryTokenLimit: runtime.limits?.summaryTokenLimit ?? 5e4
743
- };
744
2042
  const modelWithTools = runtime.model?.bindTools ? runtime.model.bindTools(tools) : runtime.model;
745
2043
  const structuredOutputHint = runtime.outputSchema ? [
746
2044
  "A structured output schema is active.",
@@ -757,19 +2055,60 @@ function createAgentNode(opts) {
757
2055
  )
758
2056
  };
759
2057
  const messages = [systemMsg, ...state.messages];
760
- const debugSession = state.ctx?.__debugSession;
761
- const response = await modelWithTools.invoke([systemMsg, ...state.messages]);
2058
+ const traceSession = state.ctx?.__traceSession;
2059
+ const actorName = runtime.name ?? opts.name ?? "agent";
2060
+ const actorVersion = runtime.version ?? opts.version;
2061
+ const start = Date.now();
2062
+ const promptMessages = [systemMsg, ...state.messages];
2063
+ const shouldLogPrompt = !!traceSession && traceSession.resolvedConfig.logData;
2064
+ const promptPayload = shouldLogPrompt ? sanitizeTracePayload(promptMessages) : void 0;
2065
+ const promptBytes = promptPayload !== void 0 ? estimatePayloadBytes(promptPayload) : void 0;
2066
+ let response;
2067
+ try {
2068
+ response = await modelWithTools.invoke(promptMessages);
2069
+ } catch (err) {
2070
+ const durationMs2 = Date.now() - start;
2071
+ recordTraceEvent(traceSession, {
2072
+ type: "ai_call",
2073
+ label: "Assistant Error",
2074
+ actor: { scope: "agent", name: actorName, role: "assistant", version: actorVersion },
2075
+ status: "error",
2076
+ durationMs: durationMs2,
2077
+ requestBytes: promptBytes,
2078
+ model: getModelName(runtime.model || opts.model),
2079
+ provider: getProviderName(runtime.model || opts.model),
2080
+ error: { message: err?.message || String(err), stack: err?.stack },
2081
+ messageList: promptMessages
2082
+ });
2083
+ throw err;
2084
+ }
762
2085
  const messagesWithResponse = [
763
2086
  ...messages,
764
2087
  response
765
2088
  ];
766
- const messagesWithSystem = [
767
- systemMsg,
768
- ...messagesWithResponse
769
- ];
770
2089
  const rawUsage = response?.usage || response?.response_metadata?.token_usage || response?.response_metadata?.usage;
771
2090
  const normalized = normalizeUsage(rawUsage);
772
2091
  const modelName = getModelName(runtime.model || opts.model) || "unknown_model";
2092
+ const providerName = getProviderName(runtime.model || opts.model);
2093
+ const durationMs = Date.now() - start;
2094
+ const shouldLogResponse = !!traceSession && traceSession.resolvedConfig.logData;
2095
+ const responsePayload = shouldLogResponse ? sanitizeTracePayload(response) : void 0;
2096
+ const responseBytes = responsePayload !== void 0 ? estimatePayloadBytes(responsePayload) : void 0;
2097
+ recordTraceEvent(traceSession, {
2098
+ type: "ai_call",
2099
+ label: "Assistant Response",
2100
+ actor: { scope: "agent", name: actorName, role: "assistant", version: actorVersion },
2101
+ durationMs,
2102
+ inputTokens: normalized?.prompt_tokens,
2103
+ outputTokens: normalized?.completion_tokens,
2104
+ totalTokens: normalized?.total_tokens,
2105
+ cachedInputTokens: normalized?.prompt_tokens_details?.cached_tokens,
2106
+ requestBytes: promptBytes,
2107
+ responseBytes,
2108
+ model: modelName,
2109
+ provider: providerName,
2110
+ messageList: messagesWithResponse
2111
+ });
773
2112
  if (normalized) {
774
2113
  const usageState = state.usage || { perRequest: [], totals: {} };
775
2114
  const id = `${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
@@ -790,33 +2129,10 @@ function createAgentNode(opts) {
790
2129
  };
791
2130
  state.usage = usageState;
792
2131
  }
793
- if (debugSession) {
794
- const idx = bumpStep(debugSession);
795
- const fileName = `${String(idx).padStart(2, "0")}.md`;
796
- const markdown = formatMarkdown({
797
- modelName: getModelName(runtime.model || opts.model),
798
- date: (/* @__PURE__ */ new Date()).toISOString(),
799
- limits: runtime.limits,
800
- // IMPORTANT: log only per-request normalized usage
801
- usage: normalized,
802
- tools: serializeAgentTools(tools),
803
- messages: messagesWithSystem
804
- });
805
- await writeStepMarkdown(debugSession, fileName, markdown, {
806
- messages: messagesWithSystem,
807
- usage: normalized,
808
- modelName: getModelName(runtime.model || opts.model),
809
- limits: runtime.limits,
810
- tools: serializeAgentTools(tools)
811
- });
812
- }
813
2132
  return { messages: messagesWithResponse, usage: state.usage };
814
2133
  };
815
2134
  }
816
2135
 
817
- // src/nodes/contextSummarize.ts
818
- var import_nanoid2 = require("nanoid");
819
-
820
2136
  // src/utils/utilTokens.ts
821
2137
  function countApproxTokens(text) {
822
2138
  if (!text) return 0;
@@ -830,7 +2146,7 @@ var toolMessage = (name, content, tool_call_id) => ({ role: "tool", name, conten
830
2146
  function createContextSummarizeNode(opts) {
831
2147
  return async (state) => {
832
2148
  const messages = state.messages || [];
833
- const summaryTokenLimit = opts.limits?.summaryTokenLimit ?? opts.limits?.summary_token_limit ?? 1e5;
2149
+ const summaryTokenLimit = opts.limits?.summaryTokenLimit ?? 1e5;
834
2150
  const model = opts.model;
835
2151
  const archived = state.toolHistoryArchived ? [...state.toolHistoryArchived] : [];
836
2152
  const live = state.toolHistory ? [...state.toolHistory] : [];
@@ -842,7 +2158,7 @@ function createContextSummarizeNode(opts) {
842
2158
  if (item.tool_call_id) byCallId.set(item.tool_call_id, item);
843
2159
  }
844
2160
  for (const item of live) {
845
- if (!item.executionId) item.executionId = (0, import_nanoid2.nanoid)();
2161
+ if (!item.executionId) item.executionId = nanoid.nanoid();
846
2162
  }
847
2163
  const getText = (m) => {
848
2164
  if (!m) return "";
@@ -983,11 +2299,11 @@ Merged summary:`);
983
2299
  continue;
984
2300
  }
985
2301
  const callId = toolMessageObj.tool_call_id;
986
- const safeId = callId || `summarized_${(0, import_nanoid2.nanoid)(6)}`;
2302
+ const safeId = callId || `summarized_${nanoid.nanoid(6)}`;
987
2303
  let hist = callId ? byCallId.get(callId) : void 0;
988
2304
  if (!hist) {
989
2305
  hist = {
990
- executionId: (0, import_nanoid2.nanoid)(),
2306
+ executionId: nanoid.nanoid(),
991
2307
  toolName: toolMessageObj.name || "unknown_tool",
992
2308
  args: null,
993
2309
  output: typeof toolMessageObj.content === "string" ? toolMessageObj.content : Array.isArray(toolMessageObj.content) ? toolMessageObj.content.map((p) => typeof p === "string" ? p : p?.text ?? p?.content ?? "").join("") : String(toolMessageObj.content ?? ""),
@@ -1001,7 +2317,7 @@ Merged summary:`);
1001
2317
  if (callId) byCallId.set(callId, hist);
1002
2318
  archived.push({ ...hist });
1003
2319
  }
1004
- if (!hist.executionId) hist.executionId = (0, import_nanoid2.nanoid)();
2320
+ if (!hist.executionId) hist.executionId = nanoid.nanoid();
1005
2321
  hist.summarized = true;
1006
2322
  rewritten.push({
1007
2323
  role: "tool",
@@ -1013,7 +2329,7 @@ Merged summary:`);
1013
2329
  }
1014
2330
  rewritten.push(m);
1015
2331
  }
1016
- const summarizeCallId = `summarize_${(0, import_nanoid2.nanoid)(6)}`;
2332
+ const summarizeCallId = `summarize_${nanoid.nanoid(6)}`;
1017
2333
  const summarizeArgs = { reason: "Exceeded token limit: summarize prior tool outputs for context." };
1018
2334
  const syntheticAssistant = {
1019
2335
  role: "assistant",
@@ -1024,7 +2340,6 @@ Merged summary:`);
1024
2340
  ]
1025
2341
  }
1026
2342
  };
1027
- const summaryExecId = (0, import_nanoid2.nanoid)();
1028
2343
  const syntheticToolResp = {
1029
2344
  role: "tool",
1030
2345
  content: `${summaryText}`,
@@ -1053,7 +2368,6 @@ Merged summary:`);
1053
2368
  // src/utils/tokenManager.ts
1054
2369
  async function applyTokenLimits({
1055
2370
  state,
1056
- model,
1057
2371
  limits
1058
2372
  }) {
1059
2373
  const messages = state.messages || [];
@@ -1063,15 +2377,23 @@ async function applyTokenLimits({
1063
2377
  const newMessages = [...messages];
1064
2378
  return { ...state, messages: newMessages };
1065
2379
  }
1066
-
1067
- // src/contextTools.ts
1068
- var import_tools3 = require("@langchain/core/tools");
1069
- var import_zod2 = require("zod");
1070
2380
  function createContextTools(stateRef, opts) {
1071
2381
  const tools = [];
1072
2382
  if (opts?.planningEnabled) {
1073
- const manageTodo = (0, import_tools3.tool)(
1074
- async ({ operation, todoList }) => {
2383
+ const manageTodo = createTool({
2384
+ name: "manage_todo_list",
2385
+ description: "Manage a structured todo list to track progress and plan tasks throughout your coding session. Use this tool VERY frequently to ensure task visibility and proper planning.\n\nWhen to use this tool:\n- Complex multi-step work requiring planning and tracking\n- When user provides multiple tasks or requests (numbered/comma-separated)\n- After receiving new instructions that require multiple steps\n- BEFORE starting work on any todo (mark as in-progress)\n- IMMEDIATELY after completing each todo (mark completed individually)\n- When breaking down larger tasks into smaller actionable steps\n- To give users visibility into your progress and planning\n\nWhen NOT to use:\n- Single, trivial tasks that can be completed in one step\n- Purely conversational/informational requests\n- When just reading files or performing simple searches\n\nCRITICAL workflow:\n1. Plan tasks by writing todo list with specific, actionable items\n2. Complete the work for that specific todo\n3. Mark that todo as completed IMMEDIATELY\n4. Move to next todo and repeat\n\nTodo states:\n- not-started: Todo not yet begun\n- in-progress: Currently working (limit ONE at a time)\n- completed: Finished successfully\n\nIMPORTANT: Mark todos completed as soon as they are done. Do not batch completions.",
2386
+ schema: zod.z.object({
2387
+ operation: zod.z.enum(["write", "read"]),
2388
+ todoList: zod.z.array(zod.z.object({
2389
+ id: zod.z.number().int().positive().describe("Sequential id starting from 1"),
2390
+ title: zod.z.string().min(1),
2391
+ description: zod.z.string().min(1),
2392
+ status: zod.z.enum(["not-started", "in-progress", "completed"]),
2393
+ evidence: zod.z.string().max(200).optional()
2394
+ })).optional()
2395
+ }),
2396
+ func: async ({ operation, todoList }) => {
1075
2397
  const onEvent = manageTodo._stateRef?.__onEvent;
1076
2398
  if (operation === "read") {
1077
2399
  const list = stateRef.todoList || [];
@@ -1088,27 +2410,16 @@ function createContextTools(stateRef, opts) {
1088
2410
  };
1089
2411
  onEvent?.({ type: "plan", source: "manage_todo_list", operation: "write", todoList });
1090
2412
  return payload;
1091
- },
1092
- {
1093
- name: "manage_todo_list",
1094
- description: "Manage a structured todo list to track progress and plan tasks throughout your coding session. Use this tool VERY frequently to ensure task visibility and proper planning.\n\nWhen to use this tool:\n- Complex multi-step work requiring planning and tracking\n- When user provides multiple tasks or requests (numbered/comma-separated)\n- After receiving new instructions that require multiple steps\n- BEFORE starting work on any todo (mark as in-progress)\n- IMMEDIATELY after completing each todo (mark completed individually)\n- When breaking down larger tasks into smaller actionable steps\n- To give users visibility into your progress and planning\n\nWhen NOT to use:\n- Single, trivial tasks that can be completed in one step\n- Purely conversational/informational requests\n- When just reading files or performing simple searches\n\nCRITICAL workflow:\n1. Plan tasks by writing todo list with specific, actionable items\n2. Complete the work for that specific todo\n3. Mark that todo as completed IMMEDIATELY\n4. Move to next todo and repeat\n\nTodo states:\n- not-started: Todo not yet begun\n- in-progress: Currently working (limit ONE at a time)\n- completed: Finished successfully\n\nIMPORTANT: Mark todos completed as soon as they are done. Do not batch completions.",
1095
- schema: import_zod2.z.object({
1096
- operation: import_zod2.z.enum(["write", "read"]),
1097
- todoList: import_zod2.z.array(import_zod2.z.object({
1098
- id: import_zod2.z.number().int().positive().describe("Sequential id starting from 1"),
1099
- title: import_zod2.z.string().min(1),
1100
- description: import_zod2.z.string().min(1),
1101
- status: import_zod2.z.enum(["not-started", "in-progress", "completed"]),
1102
- evidence: import_zod2.z.string().max(200).optional()
1103
- })).optional()
1104
- })
1105
2413
  }
1106
- );
2414
+ });
1107
2415
  manageTodo._stateRef = stateRef;
1108
2416
  tools.push(manageTodo);
1109
2417
  }
1110
- const getTool = (0, import_tools3.tool)(
1111
- async ({ executionId }) => {
2418
+ const getTool = createTool({
2419
+ name: "get_tool_response",
2420
+ description: "RETRIEVE tool execution response: Use this to access the full output of a tool execution that shows as 'SUMMARIZED' in the tool history.",
2421
+ schema: zod.z.object({ executionId: zod.z.string().describe("Tool execution id") }),
2422
+ func: async ({ executionId }) => {
1112
2423
  let execution = stateRef.toolHistory?.find((t) => t.executionId === executionId);
1113
2424
  if (!execution) {
1114
2425
  execution = stateRef.toolHistoryArchived?.find((t) => t.executionId === executionId);
@@ -1117,32 +2428,24 @@ function createContextTools(stateRef, opts) {
1117
2428
  return execution.rawOutput || execution.output;
1118
2429
  }
1119
2430
  return "Execution not found. Please check the executionId.";
1120
- },
1121
- {
1122
- name: "get_tool_response",
1123
- description: "RETRIEVE tool execution response: Use this to access the full output of a tool execution that shows as 'SUMMARIZED' in the tool history.",
1124
- schema: import_zod2.z.object({ executionId: import_zod2.z.string().describe("Tool execution id") })
1125
2431
  }
1126
- );
2432
+ });
1127
2433
  getTool._stateRef = stateRef;
1128
2434
  tools.push(getTool);
1129
2435
  if (opts?.outputSchema) {
1130
- const responseTool = (0, import_tools3.tool)(
1131
- async (data) => {
2436
+ const responseTool = createTool({
2437
+ name: "response",
2438
+ description: "Finalize the answer by returning the final structured JSON matching the required schema. Call exactly once when you are fully done, then stop.",
2439
+ schema: opts.outputSchema.shape ? opts.outputSchema : zod.z.any(),
2440
+ func: async (data) => {
1132
2441
  try {
1133
2442
  const validated = opts.outputSchema.parse ? opts.outputSchema.parse(data) : data;
1134
2443
  return { __finalStructuredOutput: true, data: validated };
1135
2444
  } catch (e) {
1136
2445
  return { error: "Schema validation failed", details: e?.message };
1137
2446
  }
1138
- },
1139
- {
1140
- name: "response",
1141
- description: "Finalize the answer by returning the final structured JSON matching the required schema. Call exactly once when you are fully done, then stop.",
1142
- // Use schema directly; if not Zod, fall back to any-object
1143
- schema: opts.outputSchema.shape ? opts.outputSchema : import_zod2.z.any()
1144
2447
  }
1145
- );
2448
+ });
1146
2449
  responseTool._stateRef = stateRef;
1147
2450
  tools.push(responseTool);
1148
2451
  }
@@ -1236,36 +2539,326 @@ function createSmartAgent(opts) {
1236
2539
  }
1237
2540
  return lastResult;
1238
2541
  },
2542
+ snapshot: base.snapshot,
2543
+ resume: base.resume,
2544
+ resolveToolApproval: base.resolveToolApproval,
1239
2545
  asTool: base.asTool,
1240
2546
  asHandoff: base.asHandoff,
1241
2547
  __runtime: base.__runtime
1242
2548
  };
1243
2549
  return instance;
1244
2550
  }
1245
- // Annotate the CommonJS export names for ESM import in node:
1246
- 0 && (module.exports = {
1247
- applyTokenLimits,
1248
- buildSystemPrompt,
1249
- bumpStep,
1250
- countApproxTokens,
1251
- createAgent,
1252
- createAgentNode,
1253
- createContextSummarizeNode,
1254
- createContextTools,
1255
- createDebugSession,
1256
- createResolverNode,
1257
- createSmartAgent,
1258
- createSmartTool,
1259
- createTool,
1260
- createToolLimitFinalizeNode,
1261
- createToolsNode,
1262
- formatMarkdown,
1263
- fromLangchainModel,
1264
- getModelName,
1265
- isSmartModel,
1266
- resolveLogsBaseDir,
1267
- serializeAgentTools,
1268
- withTools,
1269
- writeStepMarkdown
2551
+
2552
+ // src/utils/content.ts
2553
+ function contentToString(content) {
2554
+ try {
2555
+ if (content == null) return "";
2556
+ if (typeof content === "string") return content;
2557
+ if (Array.isArray(content)) {
2558
+ return content.map((p) => {
2559
+ if (!p || typeof p !== "object") return String(p);
2560
+ if (p.type === "text") return String(p.text ?? "");
2561
+ if (p.type === "image_url") {
2562
+ const img = p.image_url;
2563
+ const url = typeof img === "string" ? img : img?.url;
2564
+ const detail = typeof img === "string" ? void 0 : img?.detail;
2565
+ return `[image:${url || "unknown"}${detail ? ` detail=${detail}` : ""}]`;
2566
+ }
2567
+ return JSON.stringify(p);
2568
+ }).join("\n");
2569
+ }
2570
+ return JSON.stringify(content);
2571
+ } catch {
2572
+ return String(content);
2573
+ }
2574
+ }
2575
+ function mergeContentsToString(contents) {
2576
+ return contents.map((c) => contentToString(c)).join("\n");
2577
+ }
2578
+
2579
+ // src/guardrails/checks.ts
2580
+ var Ajv = AjvModule__default.default?.default ?? AjvModule__default.default;
2581
+ var defaultAjv = new Ajv({ allErrors: true });
2582
+ defaultAjv.opts.strict = false;
2583
+ function ensureRegExp(pattern, flags) {
2584
+ if (pattern instanceof RegExp) return pattern;
2585
+ return new RegExp(pattern, flags ?? "i");
2586
+ }
2587
+ function latestText(context) {
2588
+ return contentToString(context.latestMessage?.content ?? "");
2589
+ }
2590
+ function threadText(context) {
2591
+ return mergeContentsToString(context.messages.map((msg) => msg.content));
2592
+ }
2593
+ function regexRule(options) {
2594
+ const regex = ensureRegExp(options.pattern, options.flags);
2595
+ const selector = options.selector || latestText;
2596
+ const failureMessage = options.failureMessage || `Message violates pattern: ${regex.toString()}`;
2597
+ const matchDisposition = options.matchDisposition || "block";
2598
+ const allowIfMatch = options.allowIfMatch === true;
2599
+ return {
2600
+ id: options.id,
2601
+ title: options.title || "Regex compliance",
2602
+ description: options.description,
2603
+ async evaluate(context) {
2604
+ const text = selector(context) ?? "";
2605
+ const matches = regex.test(text);
2606
+ const passed = allowIfMatch ? matches : !matches;
2607
+ const disposition = matches ? matchDisposition : "allow";
2608
+ return {
2609
+ passed,
2610
+ reason: matches ? failureMessage : void 0,
2611
+ disposition,
2612
+ details: matches ? { pattern: regex.toString(), textSnippet: text.slice(0, 200) } : void 0
2613
+ };
2614
+ }
2615
+ };
2616
+ }
2617
+ function compileValidator(schema) {
2618
+ if (schema?._def) {
2619
+ const typed = schema;
2620
+ return (input) => {
2621
+ const result = typed.safeParse(input);
2622
+ return {
2623
+ valid: result.success,
2624
+ errors: result.success ? void 0 : result.error.issues.map((issue) => issue.message)
2625
+ };
2626
+ };
2627
+ }
2628
+ const validator = defaultAjv.compile(schema);
2629
+ return (input) => {
2630
+ const valid = validator(input);
2631
+ const errors = validator.errors?.map((err) => {
2632
+ const path2 = "instancePath" in err && typeof err.instancePath === "string" && err.instancePath.length > 0 ? err.instancePath : err.dataPath;
2633
+ return `${path2 || "/"} ${err.message || "invalid"}`;
2634
+ });
2635
+ return { valid: !!valid, errors };
2636
+ };
2637
+ }
2638
+ function jsonSchemaRule(options) {
2639
+ const selector = options.selector || latestText;
2640
+ const disposition = options.disposition || "block";
2641
+ const validator = compileValidator(options.schema);
2642
+ return {
2643
+ id: options.id,
2644
+ title: options.title || "JSON schema validation",
2645
+ description: options.description,
2646
+ async evaluate(context) {
2647
+ const text = selector(context) ?? "";
2648
+ let parsed;
2649
+ try {
2650
+ parsed = JSON.parse(text);
2651
+ } catch (err) {
2652
+ if (options.allowOnParseError) {
2653
+ return { passed: true };
2654
+ }
2655
+ return {
2656
+ passed: false,
2657
+ disposition,
2658
+ reason: "Message content is not valid JSON.",
2659
+ details: { error: err instanceof Error ? err.message : String(err) }
2660
+ };
2661
+ }
2662
+ const result = validator(parsed);
2663
+ if (result.valid) {
2664
+ return { passed: true };
2665
+ }
2666
+ return {
2667
+ passed: false,
2668
+ disposition,
2669
+ reason: "Message JSON failed schema validation.",
2670
+ details: { errors: result.errors }
2671
+ };
2672
+ }
2673
+ };
2674
+ }
2675
+ function containsAllowListed(text, allowList) {
2676
+ if (!allowList?.length) return false;
2677
+ return allowList.some((pattern) => ensureRegExp(pattern).test(text));
2678
+ }
2679
+ var codePattern = /```[\s\S]*?```|\b(function|class|import|export|const|let|var)\b|<[^>]+>/i;
2680
+ function codePresenceRule(options = {}) {
2681
+ const selector = options.selector || latestText;
2682
+ const disposition = options.disposition || "warn";
2683
+ return {
2684
+ id: options.id,
2685
+ title: options.title || "Code presence detection",
2686
+ description: options.description,
2687
+ async evaluate(context) {
2688
+ const text = selector(context) ?? "";
2689
+ if (!text) return { passed: true };
2690
+ if (containsAllowListed(text, options.allowList)) {
2691
+ return { passed: true };
2692
+ }
2693
+ const matches = codePattern.test(text);
2694
+ if (!matches) return { passed: true };
2695
+ return {
2696
+ passed: false,
2697
+ disposition,
2698
+ reason: "Potential code content detected in message.",
2699
+ details: { snippet: text.slice(0, 200) }
2700
+ };
2701
+ }
2702
+ };
2703
+ }
2704
+ var guardianSchema = zod.z.object({
2705
+ allow: zod.z.boolean().describe("Whether the message should be allowed."),
2706
+ disposition: zod.z.enum(["allow", "warn", "block"]).optional(),
2707
+ reason: zod.z.string().max(400, "Reason must be 400 characters or fewer.").optional(),
2708
+ details: zod.z.record(zod.z.any()).optional()
1270
2709
  });
2710
+ function defaultPayload(context) {
2711
+ const latest = latestText(context);
2712
+ const transcript = threadText(context);
2713
+ return JSON.stringify(
2714
+ {
2715
+ phase: context.phase,
2716
+ latestMessage: latest,
2717
+ transcript,
2718
+ metadata: {
2719
+ runtime: {
2720
+ name: context.runtime?.name,
2721
+ version: context.runtime?.version
2722
+ }
2723
+ }
2724
+ },
2725
+ null,
2726
+ 2
2727
+ );
2728
+ }
2729
+ function agentVerdictRule(options) {
2730
+ const payloadBuilder = options.payloadBuilder || defaultPayload;
2731
+ const fallbackDisposition = options.dispositionFallback || "block";
2732
+ return {
2733
+ id: options.id,
2734
+ title: options.title || "Agent-based guardrail",
2735
+ description: options.description,
2736
+ async evaluate(context) {
2737
+ const payload = payloadBuilder(context);
2738
+ const systemPrompt = options.systemPrompt || "You are a safety auditor. Review the provided conversation payload and decide whether it should continue. Return JSON with keys allow (boolean), optional disposition ('allow' | 'warn' | 'block'), optional reason (string), and optional details (object).";
2739
+ const review = await options.agent.invoke({
2740
+ messages: [
2741
+ { role: "system", content: systemPrompt },
2742
+ { role: "user", content: payload }
2743
+ ]
2744
+ });
2745
+ let parsed = review.output;
2746
+ if (!parsed) {
2747
+ try {
2748
+ parsed = guardianSchema.parse(JSON.parse(review.content));
2749
+ } catch {
2750
+ parsed = guardianSchema.parse({ allow: false, reason: "Guard agent did not return structured output." });
2751
+ }
2752
+ }
2753
+ const disposition = parsed.disposition || (parsed.allow ? "allow" : fallbackDisposition);
2754
+ return {
2755
+ passed: parsed.allow,
2756
+ disposition,
2757
+ reason: parsed.reason,
2758
+ details: parsed.details
2759
+ };
2760
+ }
2761
+ };
2762
+ }
2763
+ function customCallbackRule(options) {
2764
+ const fallbackDisposition = options.defaultDisposition || "block";
2765
+ return {
2766
+ id: options.id,
2767
+ title: options.title || "Custom callback guardrail",
2768
+ description: options.description,
2769
+ async evaluate(context) {
2770
+ const outcome = await options.callback(context);
2771
+ if (typeof outcome === "boolean") {
2772
+ return {
2773
+ passed: outcome,
2774
+ disposition: outcome ? "allow" : fallbackDisposition
2775
+ };
2776
+ }
2777
+ return {
2778
+ passed: outcome.allow,
2779
+ disposition: outcome.disposition || (outcome.allow ? "allow" : fallbackDisposition),
2780
+ reason: outcome.reason,
2781
+ details: outcome.details
2782
+ };
2783
+ }
2784
+ };
2785
+ }
2786
+
2787
+ // src/guardrails/index.ts
2788
+ function createRegexGuardrail(pattern, options) {
2789
+ const rule = regexRule({ pattern, ...options?.rule || {} });
2790
+ return createGuardrail({
2791
+ id: options?.guardrailId,
2792
+ title: options?.guardrailTitle || options?.rule?.title || "Regex Guardrail",
2793
+ description: options?.guardrailDescription || options?.rule?.description,
2794
+ appliesTo: options?.phases,
2795
+ checks: [rule],
2796
+ haltOnViolation: options?.haltOnViolation,
2797
+ onViolation: options?.onViolation,
2798
+ metadata: options?.metadata
2799
+ });
2800
+ }
2801
+ function createJsonGuardrail(schema, options) {
2802
+ const rule = jsonSchemaRule({ schema, ...options?.rule || {} });
2803
+ return createGuardrail({
2804
+ id: options?.guardrailId,
2805
+ title: options?.guardrailTitle || options?.rule?.title || "JSON Schema Guardrail",
2806
+ description: options?.guardrailDescription || options?.rule?.description,
2807
+ appliesTo: options?.phases,
2808
+ checks: [rule],
2809
+ haltOnViolation: options?.haltOnViolation,
2810
+ onViolation: options?.onViolation,
2811
+ metadata: options?.metadata
2812
+ });
2813
+ }
2814
+ function createCodeGuardrail(options) {
2815
+ const ruleOptions = { disposition: "warn", ...options?.rule || {} };
2816
+ const rule = codePresenceRule(ruleOptions);
2817
+ return createGuardrail({
2818
+ id: options?.guardrailId,
2819
+ title: options?.guardrailTitle || ruleOptions.title || "Code Presence Guardrail",
2820
+ description: options?.guardrailDescription || ruleOptions.description,
2821
+ appliesTo: options?.phases,
2822
+ checks: [rule],
2823
+ haltOnViolation: options?.haltOnViolation,
2824
+ onViolation: options?.onViolation,
2825
+ metadata: options?.metadata
2826
+ });
2827
+ }
2828
+
2829
+ exports.GuardrailPhase = GuardrailPhase;
2830
+ exports.agentVerdictRule = agentVerdictRule;
2831
+ exports.applyTokenLimits = applyTokenLimits;
2832
+ exports.buildSystemPrompt = buildSystemPrompt;
2833
+ exports.captureSnapshot = captureSnapshot;
2834
+ exports.codePresenceRule = codePresenceRule;
2835
+ exports.cognipeerSink = cognipeerSink;
2836
+ exports.countApproxTokens = countApproxTokens;
2837
+ exports.createAgent = createAgent;
2838
+ exports.createAgentNode = createAgentNode;
2839
+ exports.createCodeGuardrail = createCodeGuardrail;
2840
+ exports.createContextSummarizeNode = createContextSummarizeNode;
2841
+ exports.createContextTools = createContextTools;
2842
+ exports.createGuardrail = createGuardrail;
2843
+ exports.createJsonGuardrail = createJsonGuardrail;
2844
+ exports.createRegexGuardrail = createRegexGuardrail;
2845
+ exports.createResolverNode = createResolverNode;
2846
+ exports.createSmartAgent = createSmartAgent;
2847
+ exports.createTool = createTool;
2848
+ exports.createToolLimitFinalizeNode = createToolLimitFinalizeNode;
2849
+ exports.createToolsNode = createToolsNode;
2850
+ exports.customCallbackRule = customCallbackRule;
2851
+ exports.customSink = customSink;
2852
+ exports.evaluateGuardrails = evaluateGuardrails;
2853
+ exports.fileSink = fileSink;
2854
+ exports.fromLangchainModel = fromLangchainModel;
2855
+ exports.fromLangchainTools = fromLangchainTools;
2856
+ exports.httpSink = httpSink;
2857
+ exports.isSmartModel = isSmartModel;
2858
+ exports.jsonSchemaRule = jsonSchemaRule;
2859
+ exports.regexRule = regexRule;
2860
+ exports.resolveToolApprovalState = resolveToolApprovalState;
2861
+ exports.restoreSnapshot = restoreSnapshot;
2862
+ exports.withTools = withTools;
2863
+ //# sourceMappingURL=index.cjs.map
1271
2864
  //# sourceMappingURL=index.cjs.map