@theokit/agents 6.4.2 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  __name
3
- } from "./chunk-7QVYU63E.js";
3
+ } from "./chunk-Z4QWC7IK.js";
4
4
 
5
5
  // src/errors.ts
6
6
  import { ConfigurationError } from "@theokit/sdk/errors";
@@ -455,6 +455,198 @@ function generateAgentRoutes(ctx) {
455
455
  }
456
456
  __name(generateAgentRoutes, "generateAgentRoutes");
457
457
 
458
+ // src/guardrails/types.ts
459
+ var GuardrailViolationError = class extends Error {
460
+ static {
461
+ __name(this, "GuardrailViolationError");
462
+ }
463
+ guardName;
464
+ phase;
465
+ reason;
466
+ constructor(guardName, phase, reason) {
467
+ super(`Guardrail "${guardName}" blocked ${phase}: ${reason}`), this.guardName = guardName, this.phase = phase, this.reason = reason;
468
+ this.name = "GuardrailViolationError";
469
+ }
470
+ };
471
+ var CostBudgetExceededError = class extends Error {
472
+ static {
473
+ __name(this, "CostBudgetExceededError");
474
+ }
475
+ usedTokens;
476
+ maxTokens;
477
+ constructor(usedTokens, maxTokens) {
478
+ super(`Cost budget exceeded: ${usedTokens} > ${maxTokens} tokens`), this.usedTokens = usedTokens, this.maxTokens = maxTokens;
479
+ this.name = "CostBudgetExceededError";
480
+ }
481
+ };
482
+
483
+ // src/guardrails/detectors.ts
484
+ function estimateTokens(text) {
485
+ return Math.ceil(text.length / 4);
486
+ }
487
+ __name(estimateTokens, "estimateTokens");
488
+ var INJECTION_PHRASES = [
489
+ "previous instructions",
490
+ "disregard the above",
491
+ "you are now dan",
492
+ "system prompt",
493
+ "no restrictions",
494
+ "without restrictions",
495
+ "no rules",
496
+ "override your"
497
+ ];
498
+ function normalizeForMatch(text) {
499
+ return text.toLowerCase().replace(/\s+/g, " ");
500
+ }
501
+ __name(normalizeForMatch, "normalizeForMatch");
502
+ function promptInjectionDetector(options = {}) {
503
+ const phrases = [
504
+ ...INJECTION_PHRASES,
505
+ ...(options.extra ?? []).map((p) => p.toLowerCase())
506
+ ];
507
+ return {
508
+ name: "prompt-injection",
509
+ checkInput(text) {
510
+ const normalized = normalizeForMatch(text);
511
+ for (const phrase of phrases) {
512
+ if (normalized.includes(phrase)) {
513
+ return {
514
+ action: "block",
515
+ reason: `prompt injection phrase matched: "${phrase}"`
516
+ };
517
+ }
518
+ }
519
+ return {
520
+ action: "allow"
521
+ };
522
+ }
523
+ };
524
+ }
525
+ __name(promptInjectionDetector, "promptInjectionDetector");
526
+ var CPF = /\b\d{3}\.?\d{3}\.?\d{3}-?\d{2}\b/g;
527
+ var EMAIL = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g;
528
+ var PHONE = /\+?\d[\d\s()-]{7,13}\d/g;
529
+ function piiDetector(options = {}) {
530
+ const placeholder = options.placeholder ?? "[REDACTED]";
531
+ return {
532
+ name: "pii",
533
+ checkInput(text) {
534
+ let redacted = text;
535
+ redacted = redacted.replace(EMAIL, placeholder);
536
+ redacted = redacted.replace(CPF, placeholder);
537
+ redacted = redacted.replace(PHONE, placeholder);
538
+ if (redacted === text) return {
539
+ action: "allow"
540
+ };
541
+ return {
542
+ action: "redact",
543
+ text: redacted,
544
+ reason: "PII detected and redacted"
545
+ };
546
+ }
547
+ };
548
+ }
549
+ __name(piiDetector, "piiDetector");
550
+ var OBFUSCATION_CHARS = /[\u200B-\u200D\uFEFF\u202A-\u202E\u2066-\u2069]/g;
551
+ function unicodeNormalizer() {
552
+ return {
553
+ name: "unicode-normalizer",
554
+ checkInput(text) {
555
+ const cleaned = text.normalize("NFKC").replace(OBFUSCATION_CHARS, "");
556
+ if (cleaned === text) return {
557
+ action: "allow"
558
+ };
559
+ return {
560
+ action: "redact",
561
+ text: cleaned,
562
+ reason: "obfuscation characters normalized"
563
+ };
564
+ }
565
+ };
566
+ }
567
+ __name(unicodeNormalizer, "unicodeNormalizer");
568
+ function costGuard(options) {
569
+ let used = 0;
570
+ return {
571
+ name: "cost-guard",
572
+ // Returns a Promise explicitly (not `async`) so a budget breach REJECTS uniformly — never a
573
+ // sync throw — safe for direct callers and for the pipeline's `await g.checkInput()`.
574
+ checkInput(text) {
575
+ used += estimateTokens(text);
576
+ if (used > options.maxTokens) {
577
+ return Promise.reject(new CostBudgetExceededError(used, options.maxTokens));
578
+ }
579
+ return Promise.resolve({
580
+ action: "allow"
581
+ });
582
+ }
583
+ };
584
+ }
585
+ __name(costGuard, "costGuard");
586
+ function outputModeration(options) {
587
+ return {
588
+ name: "output-moderation",
589
+ async checkOutput(text) {
590
+ const flagged = await options.moderate(text);
591
+ return flagged ? {
592
+ action: "block",
593
+ reason: "output flagged by moderation predicate"
594
+ } : {
595
+ action: "allow"
596
+ };
597
+ }
598
+ };
599
+ }
600
+ __name(outputModeration, "outputModeration");
601
+
602
+ // src/guardrails/pipeline.ts
603
+ async function runInputGuards(text, guards) {
604
+ let current = text;
605
+ for (const g of guards) {
606
+ if (!g.checkInput) continue;
607
+ const r = await g.checkInput(current);
608
+ if (r.action === "block") {
609
+ throw new GuardrailViolationError(g.name, "input", r.reason ?? "blocked");
610
+ }
611
+ if (r.action === "redact" && r.text !== void 0) current = r.text;
612
+ }
613
+ return current;
614
+ }
615
+ __name(runInputGuards, "runInputGuards");
616
+ async function runOutputGuards(text, guards) {
617
+ let current = text;
618
+ for (const g of guards) {
619
+ if (!g.checkOutput) continue;
620
+ const r = await g.checkOutput(current);
621
+ if (r.action === "block") {
622
+ throw new GuardrailViolationError(g.name, "output", r.reason ?? "blocked");
623
+ }
624
+ if (r.action === "redact" && r.text !== void 0) current = r.text;
625
+ }
626
+ return current;
627
+ }
628
+ __name(runOutputGuards, "runOutputGuards");
629
+
630
+ // src/guardrails/stream.ts
631
+ async function* moderateOutputStream(inner, guards, extractText) {
632
+ const hasOutputGuard = guards.some((g) => g.checkOutput != null);
633
+ if (!hasOutputGuard) return yield* inner;
634
+ const buffered = [];
635
+ let accumulated = "";
636
+ let step = await inner.next();
637
+ while (!step.done) {
638
+ const event = step.value;
639
+ const text = extractText(event);
640
+ if (text !== void 0) accumulated += text;
641
+ buffered.push(event);
642
+ step = await inner.next();
643
+ }
644
+ await runOutputGuards(accumulated, guards);
645
+ for (const event of buffered) yield event;
646
+ return step.value;
647
+ }
648
+ __name(moderateOutputStream, "moderateOutputStream");
649
+
458
650
  // src/bridge/tool-hooks-plugin.ts
459
651
  function createToolHooksPlugin(hooks) {
460
652
  return {
@@ -508,6 +700,33 @@ function createToolHooksPlugin(hooks) {
508
700
  }
509
701
  __name(createToolHooksPlugin, "createToolHooksPlugin");
510
702
 
703
+ // src/bridge/model-selection.ts
704
+ var PARAM_THINKING = "thinking";
705
+ function buildModelSelection(model, effort) {
706
+ const base = typeof model === "string" ? {
707
+ id: model
708
+ } : {
709
+ ...model
710
+ };
711
+ if (!effort) return base;
712
+ return {
713
+ ...base,
714
+ params: [
715
+ ...base.params ?? [],
716
+ {
717
+ id: PARAM_THINKING,
718
+ value: effort
719
+ }
720
+ ]
721
+ };
722
+ }
723
+ __name(buildModelSelection, "buildModelSelection");
724
+ function reasoningEffortOf(model) {
725
+ const params = typeof model === "string" ? void 0 : model.params;
726
+ return params?.find((p) => p.id === PARAM_THINKING)?.value;
727
+ }
728
+ __name(reasoningEffortOf, "reasoningEffortOf");
729
+
511
730
  // src/bridge/event-translator.ts
512
731
  function asString(value, fallback) {
513
732
  if (typeof value === "string") return value;
@@ -551,7 +770,11 @@ function translateAssistantEvent(msg) {
551
770
  if (b.type === "tool_use") {
552
771
  events.push({
553
772
  type: "tool_call",
554
- callId: b.id ?? `tc-${Date.now()}`,
773
+ // #138 era `tc-${Date.now()}`. Um id novo a cada chamada NUNCA está no conjunto de
774
+ // dedup, então o fallback derrotava a dedup por construção — e ainda parecia um id de
775
+ // verdade para quem lê. String vazia é honesta: `isDuplicatedByDelta` a trata como
776
+ // "não sei identificar" e prefere um duplo-render visível a uma supressão silenciosa.
777
+ callId: b.id ?? "",
555
778
  toolName: b.name ?? "unknown",
556
779
  input: b.input ?? {}
557
780
  });
@@ -562,7 +785,7 @@ function translateAssistantEvent(msg) {
562
785
  __name(translateAssistantEvent, "translateAssistantEvent");
563
786
  function translateToolCallEvent(msg) {
564
787
  const status = msg.status;
565
- const callId = asString(msg.call_id, `tc-${Date.now()}`);
788
+ const callId = asString(msg.call_id, "");
566
789
  const toolName = asString(msg.name, "unknown");
567
790
  if (status === "completed") {
568
791
  return [
@@ -631,6 +854,22 @@ function translateStatusEvent(msg) {
631
854
  return [];
632
855
  }
633
856
  __name(translateStatusEvent, "translateStatusEvent");
857
+ var jaAvisados = /* @__PURE__ */ new Set();
858
+ function avisarSeDesconhecido(tipo, ignoradosDeProposito) {
859
+ if (ignoradosDeProposito.has(tipo) || jaAvisados.has(tipo)) return;
860
+ jaAvisados.add(tipo);
861
+ console.warn(`[theokit] agents.bridge: evento "${tipo}" do SDK n\xE3o \xE9 traduzido e foi descartado. Se ele carrega informa\xE7\xE3o que a UI precisa, o tradutor precisa de um caso para ele (#141).`);
862
+ }
863
+ __name(avisarSeDesconhecido, "avisarSeDesconhecido");
864
+ var SDK_MESSAGE_IGNORADOS = /* @__PURE__ */ new Set([
865
+ "user"
866
+ ]);
867
+ var INTERACTION_UPDATE_IGNORADOS = /* @__PURE__ */ new Set([
868
+ "thinking-completed",
869
+ "token-delta",
870
+ "step-started",
871
+ "step-completed"
872
+ ]);
634
873
  function translateSdkEvent(msg, runId) {
635
874
  switch (msg.type) {
636
875
  case "system":
@@ -648,7 +887,31 @@ function translateSdkEvent(msg, runId) {
648
887
  ];
649
888
  case "status":
650
889
  return translateStatusEvent(msg);
890
+ case "request":
891
+ return [
892
+ {
893
+ type: "input_requested",
894
+ requestId: asString(msg.request_id, "")
895
+ }
896
+ ];
897
+ case "task": {
898
+ const status = typeof msg.status === "string" ? msg.status : void 0;
899
+ const text = typeof msg.text === "string" ? msg.text : void 0;
900
+ if (status === void 0 && text === void 0) return [];
901
+ return [
902
+ {
903
+ type: "task_progress",
904
+ ...status !== void 0 ? {
905
+ status
906
+ } : {},
907
+ ...text !== void 0 ? {
908
+ text
909
+ } : {}
910
+ }
911
+ ];
912
+ }
651
913
  default:
914
+ avisarSeDesconhecido(msg.type, SDK_MESSAGE_IGNORADOS);
652
915
  return [];
653
916
  }
654
917
  }
@@ -698,39 +961,20 @@ function translateInteractionUpdate(update) {
698
961
  isError: false
699
962
  }
700
963
  ];
964
+ case "shell-output-delta":
965
+ return [
966
+ {
967
+ type: "shell_output",
968
+ event: update.event
969
+ }
970
+ ];
701
971
  default:
972
+ avisarSeDesconhecido(update.type, INTERACTION_UPDATE_IGNORADOS);
702
973
  return [];
703
974
  }
704
975
  }
705
976
  __name(translateInteractionUpdate, "translateInteractionUpdate");
706
977
 
707
- // src/bridge/model-selection.ts
708
- var PARAM_THINKING = "thinking";
709
- function buildModelSelection(model, effort) {
710
- const base = typeof model === "string" ? {
711
- id: model
712
- } : {
713
- ...model
714
- };
715
- if (!effort) return base;
716
- return {
717
- ...base,
718
- params: [
719
- ...base.params ?? [],
720
- {
721
- id: PARAM_THINKING,
722
- value: effort
723
- }
724
- ]
725
- };
726
- }
727
- __name(buildModelSelection, "buildModelSelection");
728
- function reasoningEffortOf(model) {
729
- const params = typeof model === "string" ? void 0 : model.params;
730
- return params?.find((p) => p.id === PARAM_THINKING)?.value;
731
- }
732
- __name(reasoningEffortOf, "reasoningEffortOf");
733
-
734
978
  // src/bridge/think-tag-extractor.ts
735
979
  var TAG = "think";
736
980
  var OPEN = `<${TAG}>`;
@@ -1059,6 +1303,134 @@ function realUsageDone(result, t0) {
1059
1303
  }
1060
1304
  __name(realUsageDone, "realUsageDone");
1061
1305
 
1306
+ // src/bridge/sdk-adapter-merge.ts
1307
+ function createAsyncQueue() {
1308
+ const items = [];
1309
+ let wake = null;
1310
+ let closed = false;
1311
+ return {
1312
+ push(item) {
1313
+ items.push(item);
1314
+ if (wake) {
1315
+ wake();
1316
+ wake = null;
1317
+ }
1318
+ },
1319
+ close() {
1320
+ closed = true;
1321
+ if (wake) {
1322
+ wake();
1323
+ wake = null;
1324
+ }
1325
+ },
1326
+ async *[Symbol.asyncIterator]() {
1327
+ for (; ; ) {
1328
+ while (items.length > 0) {
1329
+ const next = items.shift();
1330
+ if (next !== void 0) yield next;
1331
+ }
1332
+ if (closed) return;
1333
+ await new Promise((resolve) => {
1334
+ wake = resolve;
1335
+ });
1336
+ }
1337
+ }
1338
+ };
1339
+ }
1340
+ __name(createAsyncQueue, "createAsyncQueue");
1341
+ function streamCallId(ev) {
1342
+ return typeof ev.callId === "string" ? ev.callId : "";
1343
+ }
1344
+ __name(streamCallId, "streamCallId");
1345
+ function idsDaMesmaChamada(ev, update) {
1346
+ const ids = [];
1347
+ const call = streamCallId(ev);
1348
+ if (call !== "") ids.push(call);
1349
+ const model = update?.modelCallId;
1350
+ if (typeof model === "string" && model !== "" && model !== call) ids.push(model);
1351
+ return ids;
1352
+ }
1353
+ __name(idsDaMesmaChamada, "idsDaMesmaChamada");
1354
+ function isDuplicatedByDelta(ev, state) {
1355
+ if (ev.type === "text_delta") return state.sawTextDelta;
1356
+ if (ev.type === "thinking") return state.sawThinkingDelta;
1357
+ if (ev.type === "tool_call") {
1358
+ const id = streamCallId(ev);
1359
+ return id !== "" && state.emittedToolCallIds.has(id);
1360
+ }
1361
+ if (ev.type === "tool_result") {
1362
+ const id = streamCallId(ev);
1363
+ return id !== "" && state.emittedToolResultIds.has(id);
1364
+ }
1365
+ return false;
1366
+ }
1367
+ __name(isDuplicatedByDelta, "isDuplicatedByDelta");
1368
+ async function* mergeDeltaStream(queue, openStream, runId, state) {
1369
+ let pumpError;
1370
+ const pump = (async () => {
1371
+ try {
1372
+ const stream = await openStream();
1373
+ for await (const msg of stream) queue.push({
1374
+ kind: "sdk",
1375
+ msg
1376
+ });
1377
+ } finally {
1378
+ queue.close();
1379
+ }
1380
+ })().catch((thrown) => {
1381
+ pumpError = {
1382
+ thrown
1383
+ };
1384
+ });
1385
+ for await (const item of queue) {
1386
+ if (item.kind === "delta") {
1387
+ state.lastEventType = item.event.type;
1388
+ yield item.event;
1389
+ continue;
1390
+ }
1391
+ for (const out of translateSdkEvent(item.msg, runId)) {
1392
+ if (out.type === "done") continue;
1393
+ if (isDuplicatedByDelta(out, state)) continue;
1394
+ if (out.type === "error") state.sawError = true;
1395
+ state.lastEventType = out.type;
1396
+ yield out;
1397
+ }
1398
+ }
1399
+ await pump;
1400
+ if (pumpError) throw pumpError.thrown;
1401
+ }
1402
+ __name(mergeDeltaStream, "mergeDeltaStream");
1403
+ function createDeltaSink(queue) {
1404
+ const state = {
1405
+ sawTextDelta: false,
1406
+ sawThinkingDelta: false,
1407
+ emittedToolCallIds: /* @__PURE__ */ new Set(),
1408
+ emittedToolResultIds: /* @__PURE__ */ new Set(),
1409
+ sawError: false,
1410
+ lastEventType: ""
1411
+ };
1412
+ const onDelta = /* @__PURE__ */ __name((d) => {
1413
+ for (const event of translateInteractionUpdate(d.update)) {
1414
+ if (event.type === "text_delta") state.sawTextDelta = true;
1415
+ else if (event.type === "thinking") state.sawThinkingDelta = true;
1416
+ else if (event.type === "tool_call") {
1417
+ for (const id of idsDaMesmaChamada(event, d.update)) state.emittedToolCallIds.add(id);
1418
+ } else if (event.type === "tool_result") {
1419
+ for (const id of idsDaMesmaChamada(event, d.update)) state.emittedToolResultIds.add(id);
1420
+ }
1421
+ queue.push({
1422
+ kind: "delta",
1423
+ event
1424
+ });
1425
+ }
1426
+ }, "onDelta");
1427
+ return {
1428
+ state,
1429
+ onDelta
1430
+ };
1431
+ }
1432
+ __name(createDeltaSink, "createDeltaSink");
1433
+
1062
1434
  // src/bridge/tool-dialect-stripper.ts
1063
1435
  var OPEN2 = "<function=";
1064
1436
  var CLOSE2 = "</tool_call>";
@@ -1207,122 +1579,6 @@ async function loadSdkRuntime() {
1207
1579
  }
1208
1580
  }
1209
1581
  __name(loadSdkRuntime, "loadSdkRuntime");
1210
- function createAsyncQueue() {
1211
- const items = [];
1212
- let wake = null;
1213
- let closed = false;
1214
- return {
1215
- push(item) {
1216
- items.push(item);
1217
- if (wake) {
1218
- wake();
1219
- wake = null;
1220
- }
1221
- },
1222
- close() {
1223
- closed = true;
1224
- if (wake) {
1225
- wake();
1226
- wake = null;
1227
- }
1228
- },
1229
- async *[Symbol.asyncIterator]() {
1230
- for (; ; ) {
1231
- while (items.length > 0) {
1232
- const next = items.shift();
1233
- if (next !== void 0) yield next;
1234
- }
1235
- if (closed) return;
1236
- await new Promise((resolve) => {
1237
- wake = resolve;
1238
- });
1239
- }
1240
- }
1241
- };
1242
- }
1243
- __name(createAsyncQueue, "createAsyncQueue");
1244
- function streamCallId(ev) {
1245
- return typeof ev.callId === "string" ? ev.callId : "";
1246
- }
1247
- __name(streamCallId, "streamCallId");
1248
- function isDuplicatedByDelta(ev, state) {
1249
- if (ev.type === "text_delta") return state.sawTextDelta;
1250
- if (ev.type === "thinking") return state.sawThinkingDelta;
1251
- if (ev.type === "tool_call") {
1252
- const id = streamCallId(ev);
1253
- return id !== "" && state.emittedToolCallIds.has(id);
1254
- }
1255
- if (ev.type === "tool_result") {
1256
- const id = streamCallId(ev);
1257
- return id !== "" && state.emittedToolResultIds.has(id);
1258
- }
1259
- return false;
1260
- }
1261
- __name(isDuplicatedByDelta, "isDuplicatedByDelta");
1262
- async function* mergeDeltaStream(queue, openStream, runId, state) {
1263
- let pumpError;
1264
- const pump = (async () => {
1265
- try {
1266
- const stream = await openStream();
1267
- for await (const msg of stream) queue.push({
1268
- kind: "sdk",
1269
- msg
1270
- });
1271
- } finally {
1272
- queue.close();
1273
- }
1274
- })().catch((thrown) => {
1275
- pumpError = {
1276
- thrown
1277
- };
1278
- });
1279
- for await (const item of queue) {
1280
- if (item.kind === "delta") {
1281
- yield item.event;
1282
- continue;
1283
- }
1284
- for (const out of translateSdkEvent(item.msg, runId)) {
1285
- if (out.type === "done") continue;
1286
- if (isDuplicatedByDelta(out, state)) continue;
1287
- if (out.type === "error") state.sawError = true;
1288
- yield out;
1289
- }
1290
- }
1291
- await pump;
1292
- if (pumpError) throw pumpError.thrown;
1293
- }
1294
- __name(mergeDeltaStream, "mergeDeltaStream");
1295
- function createDeltaSink(queue) {
1296
- const state = {
1297
- sawTextDelta: false,
1298
- sawThinkingDelta: false,
1299
- emittedToolCallIds: /* @__PURE__ */ new Set(),
1300
- emittedToolResultIds: /* @__PURE__ */ new Set(),
1301
- sawError: false
1302
- };
1303
- const onDelta = /* @__PURE__ */ __name((d) => {
1304
- for (const event of translateInteractionUpdate(d.update)) {
1305
- if (event.type === "text_delta") state.sawTextDelta = true;
1306
- else if (event.type === "thinking") state.sawThinkingDelta = true;
1307
- else if (event.type === "tool_call") {
1308
- const id = streamCallId(event);
1309
- if (id !== "") state.emittedToolCallIds.add(id);
1310
- } else if (event.type === "tool_result") {
1311
- const id = streamCallId(event);
1312
- if (id !== "") state.emittedToolResultIds.add(id);
1313
- }
1314
- queue.push({
1315
- kind: "delta",
1316
- event
1317
- });
1318
- }
1319
- }, "onDelta");
1320
- return {
1321
- state,
1322
- onDelta
1323
- };
1324
- }
1325
- __name(createDeltaSink, "createDeltaSink");
1326
1582
  function resolveTextTransformFlags(compiled, overrides) {
1327
1583
  return {
1328
1584
  parseThinkTags: overrides.parseThinkTags ?? compiled.parseThinkTags ?? false,
@@ -1466,6 +1722,7 @@ async function* streamSdkAgent(rt, compiled, sdkTools, opts) {
1466
1722
  onDelta
1467
1723
  };
1468
1724
  if (factoryOpts?.disableTools === true) sendOptions.toolChoice = "none";
1725
+ if (overrides.onRunEvent !== void 0) sendOptions.onRunEvent = overrides.onRunEvent;
1469
1726
  const sendInput = overrides.images && overrides.images.length > 0 ? {
1470
1727
  text: message,
1471
1728
  images: overrides.images
@@ -1479,7 +1736,16 @@ async function* streamSdkAgent(rt, compiled, sdkTools, opts) {
1479
1736
  })) {
1480
1737
  yield event;
1481
1738
  }
1482
- if (!state.sawError) {
1739
+ if (state.sawError) {
1740
+ if (state.lastEventType !== "error") {
1741
+ yield {
1742
+ type: "error",
1743
+ code: "RUN_FAILED",
1744
+ message: "O turno terminou com erro; veja o evento `error` anterior.",
1745
+ retryable: false
1746
+ };
1747
+ }
1748
+ } else {
1483
1749
  yield realUsageDone(await (await sendPromise).wait(), t0);
1484
1750
  }
1485
1751
  } finally {
@@ -1519,10 +1785,34 @@ function toAgentFactory(def, opts) {
1519
1785
  ...m8,
1520
1786
  ...extra
1521
1787
  });
1522
- return agent;
1788
+ return withGuardrails(agent, compiled.guardrails);
1523
1789
  };
1524
1790
  }
1525
1791
  __name(toAgentFactory, "toAgentFactory");
1792
+ function withGuardrails(handle, guardrails) {
1793
+ if (guardrails === void 0 || guardrails.length === 0) return handle;
1794
+ return {
1795
+ get agentId() {
1796
+ return handle.agentId;
1797
+ },
1798
+ dispose: /* @__PURE__ */ __name(() => handle.dispose(), "dispose"),
1799
+ send: /* @__PURE__ */ __name(async (msg, sendOpts) => {
1800
+ const guarded = await runInputGuards(msg, guardrails);
1801
+ const turn = await handle.send(guarded, sendOpts);
1802
+ return {
1803
+ wait: /* @__PURE__ */ __name(async () => {
1804
+ const out = await turn.wait();
1805
+ if (out.result === void 0) return out;
1806
+ return {
1807
+ ...out,
1808
+ result: await runOutputGuards(out.result, guardrails)
1809
+ };
1810
+ }, "wait")
1811
+ };
1812
+ }, "send")
1813
+ };
1814
+ }
1815
+ __name(withGuardrails, "withGuardrails");
1526
1816
 
1527
1817
  // ../presenter/dist/index.js
1528
1818
  var __defProp = Object.defineProperty;
@@ -2089,6 +2379,61 @@ function doneToMetadata(event) {
2089
2379
  };
2090
2380
  }
2091
2381
  __name(doneToMetadata, "doneToMetadata");
2382
+ var ERROR_CODE_DATA_PART = "data-error-code";
2383
+ var INPUT_REQUESTED_DATA_PART = "data-input-requested";
2384
+ var TASK_PROGRESS_DATA_PART = "data-task-progress";
2385
+ var SHELL_OUTPUT_DATA_PART = "data-shell-output";
2386
+ function dataPart(type, data) {
2387
+ return {
2388
+ type,
2389
+ data,
2390
+ transient: true
2391
+ };
2392
+ }
2393
+ __name(dataPart, "dataPart");
2394
+ function* errorChunks(errorText, code) {
2395
+ if (code !== void 0) yield dataPart(ERROR_CODE_DATA_PART, {
2396
+ code
2397
+ });
2398
+ yield {
2399
+ type: "error",
2400
+ errorText
2401
+ };
2402
+ }
2403
+ __name(errorChunks, "errorChunks");
2404
+ function diagnosticDataPart(event) {
2405
+ switch (event.type) {
2406
+ case "checkpoint_saved":
2407
+ return dataPart("data-checkpoint", {
2408
+ checkpointId: event.checkpointId,
2409
+ resumeToken: event.resumeToken,
2410
+ step: event.step
2411
+ });
2412
+ // theokit#141 — without these cases the three restored events would be dropped by the loop's
2413
+ // catch-all, which is the reported defect one layer down: translating an event and never
2414
+ // presenting it leaves the consumer just as blind, minus even the warning.
2415
+ case "input_requested":
2416
+ return dataPart(INPUT_REQUESTED_DATA_PART, {
2417
+ requestId: event.requestId
2418
+ });
2419
+ case "task_progress":
2420
+ return dataPart(TASK_PROGRESS_DATA_PART, {
2421
+ ...event.status !== void 0 ? {
2422
+ status: event.status
2423
+ } : {},
2424
+ ...event.text !== void 0 ? {
2425
+ text: event.text
2426
+ } : {}
2427
+ });
2428
+ case "shell_output":
2429
+ return dataPart(SHELL_OUTPUT_DATA_PART, {
2430
+ event: event.event
2431
+ });
2432
+ default:
2433
+ return null;
2434
+ }
2435
+ }
2436
+ __name(diagnosticDataPart, "diagnosticDataPart");
2092
2437
  async function* presentUIMessageStream(events, opts) {
2093
2438
  const presenter = new UIMessageStreamPresenter({
2094
2439
  textId: opts.textId
@@ -2123,28 +2468,14 @@ async function* presentUIMessageStream(events, opts) {
2123
2468
  };
2124
2469
  continue;
2125
2470
  }
2126
- if (event.type === "checkpoint_saved") {
2471
+ const diagnostic = diagnosticDataPart(event);
2472
+ if (diagnostic !== null) {
2127
2473
  yield* presenter.closeBlock();
2128
- yield {
2129
- type: "data-checkpoint",
2130
- data: {
2131
- checkpointId: event.checkpointId,
2132
- resumeToken: event.resumeToken,
2133
- step: event.step
2134
- },
2135
- transient: true
2136
- };
2474
+ yield diagnostic;
2137
2475
  continue;
2138
2476
  }
2139
2477
  if (event.type === "error") {
2140
- const code = event.code;
2141
- yield {
2142
- type: "error",
2143
- errorText: event.message,
2144
- ...code !== void 0 ? {
2145
- errorCode: code
2146
- } : {}
2147
- };
2478
+ yield* errorChunks(event.message, event.code);
2148
2479
  break;
2149
2480
  }
2150
2481
  if (event.type === "done") {
@@ -2154,13 +2485,7 @@ async function* presentUIMessageStream(events, opts) {
2154
2485
  }
2155
2486
  } catch (err) {
2156
2487
  const code = err.code;
2157
- yield {
2158
- type: "error",
2159
- errorText: String(err),
2160
- ...typeof code === "string" ? {
2161
- errorCode: code
2162
- } : {}
2163
- };
2488
+ yield* errorChunks(String(err), typeof code === "string" ? code : void 0);
2164
2489
  }
2165
2490
  yield* presenter.finish(turnMetadata);
2166
2491
  }
@@ -2364,6 +2689,7 @@ function streamAgentUIMessages(compiled, apiKey, input) {
2364
2689
  if (input.cwd !== void 0) overrides.cwd = input.cwd;
2365
2690
  if (input.baseDir !== void 0) overrides.baseDir = input.baseDir;
2366
2691
  if (input.images !== void 0) overrides.images = input.images;
2692
+ if (input.onRunEvent !== void 0) overrides.onRunEvent = input.onRunEvent;
2367
2693
  let source;
2368
2694
  if (!input.hitl || input.hitl.gated.size === 0) {
2369
2695
  const events2 = createSdkAgentStream(compiled, compiled.tools, apiKey, overrides)(input.message, input.sessionId);
@@ -2414,198 +2740,6 @@ function streamAgentUIMessages(compiled, apiKey, input) {
2414
2740
  }
2415
2741
  __name(streamAgentUIMessages, "streamAgentUIMessages");
2416
2742
 
2417
- // src/guardrails/types.ts
2418
- var GuardrailViolationError = class extends Error {
2419
- static {
2420
- __name(this, "GuardrailViolationError");
2421
- }
2422
- guardName;
2423
- phase;
2424
- reason;
2425
- constructor(guardName, phase, reason) {
2426
- super(`Guardrail "${guardName}" blocked ${phase}: ${reason}`), this.guardName = guardName, this.phase = phase, this.reason = reason;
2427
- this.name = "GuardrailViolationError";
2428
- }
2429
- };
2430
- var CostBudgetExceededError = class extends Error {
2431
- static {
2432
- __name(this, "CostBudgetExceededError");
2433
- }
2434
- usedTokens;
2435
- maxTokens;
2436
- constructor(usedTokens, maxTokens) {
2437
- super(`Cost budget exceeded: ${usedTokens} > ${maxTokens} tokens`), this.usedTokens = usedTokens, this.maxTokens = maxTokens;
2438
- this.name = "CostBudgetExceededError";
2439
- }
2440
- };
2441
-
2442
- // src/guardrails/detectors.ts
2443
- function estimateTokens(text) {
2444
- return Math.ceil(text.length / 4);
2445
- }
2446
- __name(estimateTokens, "estimateTokens");
2447
- var INJECTION_PHRASES = [
2448
- "previous instructions",
2449
- "disregard the above",
2450
- "you are now dan",
2451
- "system prompt",
2452
- "no restrictions",
2453
- "without restrictions",
2454
- "no rules",
2455
- "override your"
2456
- ];
2457
- function normalizeForMatch(text) {
2458
- return text.toLowerCase().replace(/\s+/g, " ");
2459
- }
2460
- __name(normalizeForMatch, "normalizeForMatch");
2461
- function promptInjectionDetector(options = {}) {
2462
- const phrases = [
2463
- ...INJECTION_PHRASES,
2464
- ...(options.extra ?? []).map((p) => p.toLowerCase())
2465
- ];
2466
- return {
2467
- name: "prompt-injection",
2468
- checkInput(text) {
2469
- const normalized = normalizeForMatch(text);
2470
- for (const phrase of phrases) {
2471
- if (normalized.includes(phrase)) {
2472
- return {
2473
- action: "block",
2474
- reason: `prompt injection phrase matched: "${phrase}"`
2475
- };
2476
- }
2477
- }
2478
- return {
2479
- action: "allow"
2480
- };
2481
- }
2482
- };
2483
- }
2484
- __name(promptInjectionDetector, "promptInjectionDetector");
2485
- var CPF = /\b\d{3}\.?\d{3}\.?\d{3}-?\d{2}\b/g;
2486
- var EMAIL = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g;
2487
- var PHONE = /\+?\d[\d\s()-]{7,13}\d/g;
2488
- function piiDetector(options = {}) {
2489
- const placeholder = options.placeholder ?? "[REDACTED]";
2490
- return {
2491
- name: "pii",
2492
- checkInput(text) {
2493
- let redacted = text;
2494
- redacted = redacted.replace(EMAIL, placeholder);
2495
- redacted = redacted.replace(CPF, placeholder);
2496
- redacted = redacted.replace(PHONE, placeholder);
2497
- if (redacted === text) return {
2498
- action: "allow"
2499
- };
2500
- return {
2501
- action: "redact",
2502
- text: redacted,
2503
- reason: "PII detected and redacted"
2504
- };
2505
- }
2506
- };
2507
- }
2508
- __name(piiDetector, "piiDetector");
2509
- var OBFUSCATION_CHARS = /[\u200B-\u200D\uFEFF\u202A-\u202E\u2066-\u2069]/g;
2510
- function unicodeNormalizer() {
2511
- return {
2512
- name: "unicode-normalizer",
2513
- checkInput(text) {
2514
- const cleaned = text.normalize("NFKC").replace(OBFUSCATION_CHARS, "");
2515
- if (cleaned === text) return {
2516
- action: "allow"
2517
- };
2518
- return {
2519
- action: "redact",
2520
- text: cleaned,
2521
- reason: "obfuscation characters normalized"
2522
- };
2523
- }
2524
- };
2525
- }
2526
- __name(unicodeNormalizer, "unicodeNormalizer");
2527
- function costGuard(options) {
2528
- let used = 0;
2529
- return {
2530
- name: "cost-guard",
2531
- // Returns a Promise explicitly (not `async`) so a budget breach REJECTS uniformly — never a
2532
- // sync throw — safe for direct callers and for the pipeline's `await g.checkInput()`.
2533
- checkInput(text) {
2534
- used += estimateTokens(text);
2535
- if (used > options.maxTokens) {
2536
- return Promise.reject(new CostBudgetExceededError(used, options.maxTokens));
2537
- }
2538
- return Promise.resolve({
2539
- action: "allow"
2540
- });
2541
- }
2542
- };
2543
- }
2544
- __name(costGuard, "costGuard");
2545
- function outputModeration(options) {
2546
- return {
2547
- name: "output-moderation",
2548
- async checkOutput(text) {
2549
- const flagged = await options.moderate(text);
2550
- return flagged ? {
2551
- action: "block",
2552
- reason: "output flagged by moderation predicate"
2553
- } : {
2554
- action: "allow"
2555
- };
2556
- }
2557
- };
2558
- }
2559
- __name(outputModeration, "outputModeration");
2560
-
2561
- // src/guardrails/pipeline.ts
2562
- async function runInputGuards(text, guards) {
2563
- let current = text;
2564
- for (const g of guards) {
2565
- if (!g.checkInput) continue;
2566
- const r = await g.checkInput(current);
2567
- if (r.action === "block") {
2568
- throw new GuardrailViolationError(g.name, "input", r.reason ?? "blocked");
2569
- }
2570
- if (r.action === "redact" && r.text !== void 0) current = r.text;
2571
- }
2572
- return current;
2573
- }
2574
- __name(runInputGuards, "runInputGuards");
2575
- async function runOutputGuards(text, guards) {
2576
- let current = text;
2577
- for (const g of guards) {
2578
- if (!g.checkOutput) continue;
2579
- const r = await g.checkOutput(current);
2580
- if (r.action === "block") {
2581
- throw new GuardrailViolationError(g.name, "output", r.reason ?? "blocked");
2582
- }
2583
- if (r.action === "redact" && r.text !== void 0) current = r.text;
2584
- }
2585
- return current;
2586
- }
2587
- __name(runOutputGuards, "runOutputGuards");
2588
-
2589
- // src/guardrails/stream.ts
2590
- async function* moderateOutputStream(inner, guards, extractText) {
2591
- const hasOutputGuard = guards.some((g) => g.checkOutput != null);
2592
- if (!hasOutputGuard) return yield* inner;
2593
- const buffered = [];
2594
- let accumulated = "";
2595
- let step = await inner.next();
2596
- while (!step.done) {
2597
- const event = step.value;
2598
- const text = extractText(event);
2599
- if (text !== void 0) accumulated += text;
2600
- buffered.push(event);
2601
- step = await inner.next();
2602
- }
2603
- await runOutputGuards(accumulated, guards);
2604
- for (const event of buffered) yield event;
2605
- return step.value;
2606
- }
2607
- __name(moderateOutputStream, "moderateOutputStream");
2608
-
2609
2743
  // src/loop/compaction-strategy.ts
2610
2744
  import { compactTranscript } from "@theokit/sdk/compaction";
2611
2745
  import { z } from "zod";
@@ -3415,13 +3549,13 @@ __name(mcpToolApprovals, "mcpToolApprovals");
3415
3549
  import { existsSync, readFileSync } from "fs";
3416
3550
  import { join } from "path";
3417
3551
  import { TheokitAgentError } from "@theokit/sdk/errors";
3418
- function canalDeAviso(opts) {
3419
- return opts.onWarn ?? ((aviso) => {
3420
- process.stderr.write(`[@theokit/agents] ${aviso}
3552
+ function warningChannel(opts) {
3553
+ return opts.onWarn ?? ((warning) => {
3554
+ process.stderr.write(`[@theokit/agents] ${warning}
3421
3555
  `);
3422
3556
  });
3423
3557
  }
3424
- __name(canalDeAviso, "canalDeAviso");
3558
+ __name(warningChannel, "warningChannel");
3425
3559
  var McpFileError = class extends TheokitAgentError {
3426
3560
  static {
3427
3561
  __name(this, "McpFileError");
@@ -3447,7 +3581,7 @@ function loadMcpJson(cwd, opts = {}) {
3447
3581
  } catch (err) {
3448
3582
  throw new McpFileError(`${path} is not valid JSON: ${descrever(err)}`);
3449
3583
  }
3450
- return parseMcpJson(parsed, path, canalDeAviso(opts));
3584
+ return parseMcpJson(parsed, path, warningChannel(opts));
3451
3585
  }
3452
3586
  __name(loadMcpJson, "loadMcpJson");
3453
3587
  function parseMcpJson(raw, source, onWarn) {
@@ -3466,7 +3600,7 @@ function parseMcpJson(raw, source, onWarn) {
3466
3600
  onWarn(`${source}: server "${name}" ignorado \u2014 ${motivo}`);
3467
3601
  continue;
3468
3602
  }
3469
- out[name] = montarEntrada(entryRaw);
3603
+ out[name] = buildEntry(entryRaw);
3470
3604
  }
3471
3605
  return out;
3472
3606
  }
@@ -3514,16 +3648,16 @@ function validarRemoto(entry) {
3514
3648
  return void 0;
3515
3649
  }
3516
3650
  __name(validarRemoto, "validarRemoto");
3517
- function montarEntrada(entry) {
3651
+ function buildEntry(entry) {
3518
3652
  if (entry.url !== void 0) {
3519
- const remoto = {
3653
+ const remote = {
3520
3654
  url: entry.url
3521
3655
  };
3522
- if (entry.type !== void 0) remoto.type = entry.type;
3523
- if (entry.headers !== void 0) remoto.headers = entry.headers;
3524
- if (entry.auth !== void 0) remoto.auth = entry.auth;
3525
- if (entry.requestTimeoutMs !== void 0) remoto.requestTimeoutMs = entry.requestTimeoutMs;
3526
- return remoto;
3656
+ if (entry.type !== void 0) remote.type = entry.type;
3657
+ if (entry.headers !== void 0) remote.headers = entry.headers;
3658
+ if (entry.auth !== void 0) remote.auth = entry.auth;
3659
+ if (entry.requestTimeoutMs !== void 0) remote.requestTimeoutMs = entry.requestTimeoutMs;
3660
+ return remote;
3527
3661
  }
3528
3662
  const stdio = {
3529
3663
  command: entry.command
@@ -3533,7 +3667,7 @@ function montarEntrada(entry) {
3533
3667
  if (entry.cwd !== void 0) stdio.cwd = entry.cwd;
3534
3668
  return stdio;
3535
3669
  }
3536
- __name(montarEntrada, "montarEntrada");
3670
+ __name(buildEntry, "buildEntry");
3537
3671
  function descrever(err) {
3538
3672
  return err instanceof Error ? err.message : String(err);
3539
3673
  }
@@ -3704,10 +3838,21 @@ export {
3704
3838
  isError,
3705
3839
  isApprovalRequired,
3706
3840
  generateAgentRoutes,
3841
+ GuardrailViolationError,
3842
+ CostBudgetExceededError,
3843
+ estimateTokens,
3844
+ promptInjectionDetector,
3845
+ piiDetector,
3846
+ unicodeNormalizer,
3847
+ costGuard,
3848
+ outputModeration,
3849
+ runInputGuards,
3850
+ runOutputGuards,
3851
+ moderateOutputStream,
3707
3852
  createToolHooksPlugin,
3708
- translateSdkEvent,
3709
3853
  buildModelSelection,
3710
3854
  reasoningEffortOf,
3855
+ translateSdkEvent,
3711
3856
  createThinkTagExtractor,
3712
3857
  extractThinkTagStream,
3713
3858
  createSdkAgentStream,
@@ -3718,17 +3863,6 @@ export {
3718
3863
  AgentDefinitionError,
3719
3864
  compileAgentModule,
3720
3865
  streamAgentUIMessages,
3721
- GuardrailViolationError,
3722
- CostBudgetExceededError,
3723
- estimateTokens,
3724
- promptInjectionDetector,
3725
- piiDetector,
3726
- unicodeNormalizer,
3727
- costGuard,
3728
- outputModeration,
3729
- runInputGuards,
3730
- runOutputGuards,
3731
- moderateOutputStream,
3732
3866
  DEFAULT_KEEP_TOKENS,
3733
3867
  compactionStrategyConfigSchema,
3734
3868
  resolveCompactionStrategy,
@@ -3759,4 +3893,4 @@ export {
3759
3893
  generateAgentManifest,
3760
3894
  agentsPlugin
3761
3895
  };
3762
- //# sourceMappingURL=chunk-UJPG3K26.js.map
3896
+ //# sourceMappingURL=chunk-3YPKTOJ6.js.map