@sema-agent/client-core 0.106.0 → 0.107.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/README.md +20 -16
  3. package/dist/adapter/activeRunSelfHeal.d.ts +8 -0
  4. package/dist/adapter/activeRunSelfHeal.js +50 -22
  5. package/dist/checkpointRowVerdict.d.ts +6 -0
  6. package/dist/checkpointRowVerdict.js +9 -0
  7. package/dist/decideReceipt.js +1 -1
  8. package/dist/displayUntrusted.d.ts +5 -3
  9. package/dist/displayUntrusted.js +50 -41
  10. package/dist/engineNoticeCodes.d.ts +12 -0
  11. package/dist/engineNoticeCodes.js +117 -6
  12. package/dist/errorSupplementRoles.js +2 -1
  13. package/dist/executionLaneCapability.js +3 -2
  14. package/dist/executionLaneWords.d.ts +1 -0
  15. package/dist/executionLaneWords.js +3 -0
  16. package/dist/generated/engineNoticeTables.js +9 -3
  17. package/dist/hitl/approvalResolution.d.ts +5 -1
  18. package/dist/hitl/approvalResolution.js +18 -1
  19. package/dist/hitl/approvalsFeed.js +2 -1
  20. package/dist/hitl/askParkRowRouting.js +12 -0
  21. package/dist/hitl/decisionSend.d.ts +2 -0
  22. package/dist/hitl/decisionSend.js +20 -6
  23. package/dist/hitl/hitlBridge.d.ts +5 -1
  24. package/dist/hitl/hitlBridge.js +27 -2
  25. package/dist/hitl/livePendingAsk.js +4 -2
  26. package/dist/hitl/parkOwnership.js +4 -5
  27. package/dist/hitl/parkResolver.js +9 -5
  28. package/dist/hitl/parkRowBirthWait.d.ts +7 -0
  29. package/dist/hitl/parkRowBirthWait.js +1 -1
  30. package/dist/hitl/parkRowDelegation.d.ts +6 -0
  31. package/dist/hitl/parkRowDelegation.js +33 -0
  32. package/dist/hitl/persistedRulesWire.d.ts +15 -3
  33. package/dist/hitl/persistedRulesWire.js +102 -20
  34. package/dist/hitl/planReviewWire.js +4 -2
  35. package/dist/hitl/sessionAllowRoute.d.ts +5 -0
  36. package/dist/hitl/sessionAllowRoute.js +42 -0
  37. package/dist/hitl/standingRows.js +10 -10
  38. package/dist/hitl/toolApprovalWire.js +22 -8
  39. package/dist/i18n/messages.en.d.ts +6 -0
  40. package/dist/i18n/messages.en.js +8 -2
  41. package/dist/i18n/messages.zh.js +9 -2
  42. package/dist/index.d.ts +1 -0
  43. package/dist/index.js +1 -0
  44. package/dist/injectionLaneNotice.js +2 -1
  45. package/dist/noticePresentation.js +2 -0
  46. package/dist/sdkWireTransit.d.ts +1 -1
  47. package/dist/seatContract.d.ts +1 -0
  48. package/dist/seatContract.js +3 -1
  49. package/dist/wireRefusalCopy.d.ts +6 -1
  50. package/dist/wireRefusalCopy.js +7 -1
  51. package/docs/INTEGRATION-CLIENTS.md +382 -13
  52. package/package.json +5 -5
@@ -3,6 +3,7 @@ import type { ActiveRunBusySignal } from './runStream.js';
3
3
  import type { RejectedSubmissionOrigin } from '../request/submissionIdentity.js';
4
4
  import type { PlanReviewReopenTrigger } from '../hitl/planReviewWire.js';
5
5
  import { type AskParkAutoReopenBlock } from '../hitl/askParkAutoReopenBlock.js';
6
+ import { type CheckpointRowVerdictReading } from '../checkpointRowVerdict.js';
6
7
  import { atMostOnceFailureClass } from '../atMostOnce.js';
7
8
  export declare const PLAN_REVIEW_GATE_KIND = "plan_review";
8
9
  export type DurableDecideLeg = 'approval' | 'plan_review' | 'other_gate' | 'unreadable';
@@ -44,6 +45,9 @@ export type ReopenCardVerdict = {
44
45
  _sema_errorCode?: string;
45
46
  _sema_reopenRefusal?: PlanReviewReopenRefusal;
46
47
  _sema_policyBlocked?: AskParkAutoReopenBlock;
48
+ _sema_rowVerdict?: Exclude<CheckpointRowVerdictReading, {
49
+ readonly kind: 'ok';
50
+ }>;
47
51
  } | {
48
52
  reopened: true;
49
53
  firstSight: boolean;
@@ -147,6 +151,9 @@ export type SelfHealOutcome = {
147
151
  noPresentationSurface?: true;
148
152
  errorCode?: string;
149
153
  policyBlocked?: AskParkAutoReopenBlock;
154
+ rowVerdict?: Exclude<CheckpointRowVerdictReading, {
155
+ readonly kind: 'ok';
156
+ }>;
150
157
  } | {
151
158
  kind: 'ask-decided-without-card';
152
159
  taskId: string;
@@ -162,6 +169,7 @@ export type SelfHealOutcome = {
162
169
  delivery: string | null;
163
170
  status: string | null;
164
171
  reopened: ReopenCardVerdict | null;
172
+ messageId?: string;
165
173
  } | {
166
174
  kind: 'running-steer-failed';
167
175
  taskId: string;
@@ -6,6 +6,7 @@ import { DEFAULT_SESSION_KEY } from '../sessionSlot.js';
6
6
  import { ASK_PARK_AUTO_REOPEN_BLOCKS, askParkAutoReopenBlockedContent } from '../hitl/askParkAutoReopenBlock.js';
7
7
  import { corruptStoredRowContent, corruptStoredRowWhere, effectiveWireErrorCode } from '../wireErrorTriage.js';
8
8
  import { readThrownStatusSlot } from '../wireFailureShape.js';
9
+ import { checkpointRowBarOf, checkpointRowBarSentence } from '../checkpointRowVerdict.js';
9
10
  import { guardedRead, readOwnDataNonEmptyString, readOwnDataValue } from '../ownKey.js';
10
11
  import { steerBodyOf, UNOBSERVED_STEER_PRIORITY } from '../controlRouter.js';
11
12
  import { atMostOnceFailureClass } from '../atMostOnce.js';
@@ -145,6 +146,12 @@ function injectedCarrierVerdict(items, busyTaskId) {
145
146
  return null;
146
147
  return allNameBusyRun && present === length ? 'redundant' : 'deferred';
147
148
  }
149
+ function injectedCarrierVerdictOf(deps, busyTaskId) {
150
+ return deps?.submissionOrigin === 'injected' ? injectedCarrierVerdict(guardedRead(() => deps?.injectedCarriers), busyTaskId) : null;
151
+ }
152
+ function runSettledOutcome(carrierVerdict, settled) {
153
+ return carrierVerdict === 'redundant' ? { kind: 'injected-redundant', taskId: settled.taskId } : settled;
154
+ }
148
155
  function sessionOpts(deps) {
149
156
  const sessionId = deps?.sessionId;
150
157
  return typeof sessionId === 'string' && sessionId.length > 0 ? { session: sessionId } : {};
@@ -207,6 +214,7 @@ const REOPEN_VERDICT_KEYS = [
207
214
  '_sema_errorCode',
208
215
  '_sema_reopenRefusal',
209
216
  '_sema_policyBlocked',
217
+ '_sema_rowVerdict',
210
218
  ];
211
219
  function snapshotReopenVerdict(raw) {
212
220
  if (raw === null || raw === undefined)
@@ -320,6 +328,16 @@ function reopenPolicyBlockedOf(verdict) {
320
328
  return undefined;
321
329
  }
322
330
  }
331
+ function reopenRowVerdictOf(verdict) {
332
+ try {
333
+ if (verdict.reopened !== false)
334
+ return undefined;
335
+ return checkpointRowBarOf({ rowVerdict: verdict._sema_rowVerdict });
336
+ }
337
+ catch {
338
+ return undefined;
339
+ }
340
+ }
323
341
  function reopenRefusalOf(verdict) {
324
342
  try {
325
343
  if (verdict.reopened !== false)
@@ -583,6 +601,7 @@ export async function attemptActiveRunSelfHeal(signal, runs, deps) {
583
601
  detail: 'the engine did not name the run that holds this session',
584
602
  };
585
603
  }
604
+ const carrierVerdict = injectedCarrierVerdictOf(deps, taskId);
586
605
  const gateKind = signal.pendingGate?.kind ?? null;
587
606
  const gateLeg = durableDecideLegOf({ gateKind });
588
607
  const pendingCp = signal.pendingGate?.checkpointId;
@@ -590,7 +609,7 @@ export async function attemptActiveRunSelfHeal(signal, runs, deps) {
590
609
  if (gateLeg === 'plan_review')
591
610
  return planReviewArm(taskId, signal, deps, sameTaskCp);
592
611
  if (gateLeg === 'approval')
593
- return askParkArm(taskId, signal, runs, deps);
612
+ return askParkArm(taskId, signal, runs, carrierVerdict, deps);
594
613
  let status = signal.activeTaskStatus;
595
614
  const statusFresh = status === null;
596
615
  if (status === null) {
@@ -610,16 +629,16 @@ export async function attemptActiveRunSelfHeal(signal, runs, deps) {
610
629
  return { kind: 'state-unknown', taskId, detail: 'the engine reported no status for that run' };
611
630
  }
612
631
  if (isSdkRunTerminal(status))
613
- return { kind: 'running-settled', taskId, status };
632
+ return runSettledOutcome(carrierVerdict, { kind: 'running-settled', taskId, status });
614
633
  const triageGate = signal.pendingGate && !statusFresh ? { pendingGateKind: signal.pendingGate.kind ?? null } : {};
615
634
  if (gateKind !== null)
616
635
  return { kind: 'not-parked', taskId, status, ...triageGate };
617
636
  if (PLAN_REVIEW_STATES.includes(status))
618
637
  return planReviewArm(taskId, signal, deps);
619
638
  if (ASK_PARK_STATES.includes(status))
620
- return askParkArm(taskId, signal, runs, deps);
639
+ return askParkArm(taskId, signal, runs, carrierVerdict, deps);
621
640
  if (RUNNING_STATES.includes(status)) {
622
- return runningChoiceArm(taskId, status, signal, signal.activeTaskStatus !== null, runs, deps);
641
+ return runningChoiceArm(taskId, status, signal, signal.activeTaskStatus !== null, runs, carrierVerdict, deps);
623
642
  }
624
643
  return { kind: 'not-parked', taskId, status, ...triageGate };
625
644
  }
@@ -668,7 +687,7 @@ async function planReviewArm(taskId, signal, deps, checkpointId) {
668
687
  ...(reopenRefusal !== undefined ? { reopenRefusal } : {}),
669
688
  };
670
689
  }
671
- async function askParkArm(taskId, signal, runs, deps) {
690
+ async function askParkArm(taskId, signal, runs, carrierVerdict, deps) {
672
691
  const verdict = await askVerdict(taskId, deps);
673
692
  if (reopenDelivered(verdict))
674
693
  return { kind: 'ask-reopened', taskId, firstSight: verdict.firstSight === true };
@@ -692,17 +711,18 @@ async function askParkArm(taskId, signal, runs, deps) {
692
711
  };
693
712
  }
694
713
  if (release.lastStatus !== null && RUNNING_STATES.includes(release.lastStatus)) {
695
- return runningChoiceArm(taskId, release.lastStatus, signal, false, runs, deps);
714
+ return runningChoiceArm(taskId, release.lastStatus, signal, false, runs, carrierVerdict, deps);
696
715
  }
697
716
  return { kind: 'ask-decided-release-unknown', taskId, lastStatus: release.lastStatus };
698
717
  }
699
718
  const inFlight = reopenRefusedForDecisionInFlight(verdict);
700
719
  if (verdict.reopened === false && verdict.decidedWithoutCard !== true && verdict.pendingRowGone === true && !inFlight) {
701
- return staleParkArm(taskId, signal, runs, deps);
720
+ return staleParkArm(taskId, signal, runs, carrierVerdict, deps);
702
721
  }
703
722
  const noView = reopenRefusedForNoPresentationSurface(verdict);
704
723
  const policyBlocked = inFlight || noView ? undefined : reopenPolicyBlockedOf(verdict);
705
- const errorCode = inFlight || noView || reopenRefusedForUserDismissal(verdict) || policyBlocked !== undefined ? undefined : reopenErrorCodeOf(verdict);
724
+ const rowVerdict = inFlight ? undefined : reopenRowVerdictOf(verdict);
725
+ const errorCode = inFlight || noView || reopenRefusedForUserDismissal(verdict) || policyBlocked !== undefined || rowVerdict !== undefined ? undefined : reopenErrorCodeOf(verdict);
706
726
  return {
707
727
  kind: 'ask-reopen-failed',
708
728
  taskId,
@@ -712,6 +732,7 @@ async function askParkArm(taskId, signal, runs, deps) {
712
732
  ...(noView ? { noPresentationSurface: true } : {}),
713
733
  ...(errorCode !== undefined ? { errorCode } : {}),
714
734
  ...(policyBlocked !== undefined ? { policyBlocked } : {}),
735
+ ...(rowVerdict !== undefined ? { rowVerdict } : {}),
715
736
  };
716
737
  }
717
738
  async function probeRunStatusOnce(taskId, durable, durableGet, deps) {
@@ -738,7 +759,7 @@ async function probeRunStatusOnce(taskId, durable, durableGet, deps) {
738
759
  status = readStatusGuarded(record);
739
760
  return errorCode !== undefined ? { status, ghost, errorCode } : { status, ghost };
740
761
  }
741
- async function staleParkArm(taskId, busy, runs, deps) {
762
+ async function staleParkArm(taskId, busy, runs, carrierVerdict, deps) {
742
763
  const reopenFailed = {
743
764
  kind: 'ask-reopen-failed',
744
765
  taskId,
@@ -766,11 +787,11 @@ async function staleParkArm(taskId, busy, runs, deps) {
766
787
  if (fresh === null)
767
788
  return withFailureCode(reopenFailed, first.errorCode);
768
789
  if (RUNNING_STATES.includes(fresh))
769
- return runningChoiceArm(taskId, fresh, busy, false, runs, deps);
790
+ return runningChoiceArm(taskId, fresh, busy, false, runs, carrierVerdict, deps);
770
791
  if (PLAN_REVIEW_STATES.includes(fresh))
771
792
  return planReviewArm(taskId, busy, deps);
772
793
  if (isSdkRunTerminal(fresh))
773
- return { kind: 'ask-run-settled', taskId, status: fresh };
794
+ return runSettledOutcome(carrierVerdict, { kind: 'ask-run-settled', taskId, status: fresh });
774
795
  if (!ASK_PARK_STATES.includes(fresh))
775
796
  return reopenFailed;
776
797
  const offer = deps?.offerStaleParkChoice;
@@ -809,7 +830,7 @@ async function staleParkArm(taskId, busy, runs, deps) {
809
830
  return withFailureCode(reopenFailedAfterCard, afterCard.errorCode);
810
831
  if (!ASK_PARK_STATES.includes(afterCard.status)) {
811
832
  if (isSdkRunTerminal(afterCard.status))
812
- return { kind: 'ask-run-settled', taskId, status: afterCard.status };
833
+ return runSettledOutcome(carrierVerdict, { kind: 'ask-run-settled', taskId, status: afterCard.status });
813
834
  if (RUNNING_STATES.includes(afterCard.status))
814
835
  return { kind: 'not-parked', taskId, status: afterCard.status };
815
836
  return !CLAIM_HELD_STATES.includes(afterCard.status) ? reopenFailed : reopenFailedAfterCard;
@@ -871,11 +892,10 @@ async function cancelAndConfirmRelease(taskId, durable, durableGet, deps) {
871
892
  (verdict.lastStatus !== null && CLAIM_HELD_STATES.includes(verdict.lastStatus)),
872
893
  };
873
894
  }
874
- async function runningChoiceArm(taskId, status, busy, statusFromWire, runs, deps) {
895
+ async function runningChoiceArm(taskId, status, busy, statusFromWire, runs, carrierVerdict, deps) {
875
896
  const notParked = { kind: 'not-parked', taskId, status };
876
897
  const offer = deps?.offerRunningChoice;
877
898
  const injected = deps?.submissionOrigin === 'injected';
878
- const carrierVerdict = injected ? injectedCarrierVerdict(guardedRead(() => deps?.injectedCarriers), taskId) : null;
879
899
  if (typeof offer !== 'function' && !injected)
880
900
  return notParked;
881
901
  const text = typeof deps?.deniedMessage === 'string' ? deps.deniedMessage : '';
@@ -895,7 +915,7 @@ async function runningChoiceArm(taskId, status, busy, statusFromWire, runs, deps
895
915
  if (probeCallerAborted())
896
916
  return notParked;
897
917
  if (fresh !== null) {
898
- const routed = await routeFreshNonRunning(fresh, taskId, busy, runs, deps);
918
+ const routed = await routeFreshNonRunning(fresh, taskId, busy, runs, deps, carrierVerdict);
899
919
  if (routed !== undefined)
900
920
  return routed;
901
921
  }
@@ -936,16 +956,17 @@ async function runningChoiceArm(taskId, status, busy, statusFromWire, runs, deps
936
956
  if (choice === 'steer' && canSteer && runs?.steer !== undefined) {
937
957
  try {
938
958
  const receipt = await runs.steer(taskId, steerBodyOf({ text }, UNOBSERVED_STEER_PRIORITY), sessionOpts(deps));
939
- const { delivery, status: receiptStatus } = readSteerReceipt(receipt);
959
+ const { delivery, status: receiptStatus, messageId } = readSteerReceipt(receipt);
960
+ const handedId = messageId !== undefined ? { messageId } : {};
940
961
  if (delivery === 'queued') {
941
962
  const verdict = receiptStatus !== null && PLAN_REVIEW_STATES.includes(receiptStatus)
942
963
  ? await planVerdict(taskId, deps)
943
964
  : receiptStatus !== null && ASK_PARK_STATES.includes(receiptStatus)
944
965
  ? await askVerdict(taskId, deps)
945
966
  : null;
946
- return { kind: 'running-steered', taskId, delivery, status: receiptStatus, reopened: verdict };
967
+ return { kind: 'running-steered', taskId, delivery, status: receiptStatus, reopened: verdict, ...handedId };
947
968
  }
948
- return { kind: 'running-steered', taskId, delivery, status: receiptStatus, reopened: null };
969
+ return { kind: 'running-steered', taskId, delivery, status: receiptStatus, reopened: null, ...handedId };
949
970
  }
950
971
  catch (e) {
951
972
  const delivery = atMostOnceFailureClass(e);
@@ -974,7 +995,7 @@ async function runningChoiceArm(taskId, status, busy, statusFromWire, runs, deps
974
995
  return { kind: 'running-not-found', taskId };
975
996
  if (probeCallerAborted() || preFire.status === null)
976
997
  return notParked;
977
- const rerouted = await routeFreshNonRunning(preFire.status, taskId, busy, runs, deps);
998
+ const rerouted = await routeFreshNonRunning(preFire.status, taskId, busy, runs, deps, carrierVerdict);
978
999
  if (rerouted !== undefined)
979
1000
  return rerouted;
980
1001
  const verdict = await cancelAndConfirmRelease(taskId, runs, runs.get, deps);
@@ -996,15 +1017,15 @@ async function runningChoiceArm(taskId, status, busy, statusFromWire, runs, deps
996
1017
  return { kind: 'running-attach', taskId };
997
1018
  return notParked;
998
1019
  }
999
- async function routeFreshNonRunning(fresh, taskId, busy, runs, deps) {
1020
+ async function routeFreshNonRunning(fresh, taskId, busy, runs, deps, carrierVerdict) {
1000
1021
  if (RUNNING_STATES.includes(fresh))
1001
1022
  return undefined;
1002
1023
  if (PLAN_REVIEW_STATES.includes(fresh))
1003
1024
  return planReviewArm(taskId, busy, deps);
1004
1025
  if (ASK_PARK_STATES.includes(fresh))
1005
- return askParkArm(taskId, busy, runs, deps);
1026
+ return askParkArm(taskId, busy, runs, carrierVerdict, deps);
1006
1027
  if (isSdkRunTerminal(fresh))
1007
- return { kind: 'running-settled', taskId, status: fresh };
1028
+ return runSettledOutcome(carrierVerdict, { kind: 'running-settled', taskId, status: fresh });
1008
1029
  return { kind: 'not-parked', taskId, status: fresh };
1009
1030
  }
1010
1031
  export const INTERACTIVE_WAY_OUT = EN_MESSAGES['session.selfHeal.wayOut.interactive'];
@@ -1190,6 +1211,13 @@ function activeRunSelfHealBaseRow(outcome, wayOut, following = false, keepSessio
1190
1211
  case 'ask-reopen-failed': {
1191
1212
  if (outcome.decisionInFlight === true)
1192
1213
  return decisionInFlightRow('ask', outcome.taskId, lang);
1214
+ if (outcome.rowVerdict !== undefined) {
1215
+ return say(lang, 'session.selfHeal.row.askReopenFailed.rowUnresumable', {
1216
+ taskId: outcome.taskId,
1217
+ sentence: checkpointRowBarSentence(outcome.rowVerdict),
1218
+ unbound: msg('approval.decide.unboundWayOut'),
1219
+ });
1220
+ }
1193
1221
  if (outcome.policyBlocked !== undefined)
1194
1222
  return askParkAutoReopenBlockedContent(outcome.policyBlocked, outcome.taskId, 'interactive', lang);
1195
1223
  const viaEngine = engineDecide && outcome.decidePath ? msg('session.selfHeal.viaEngine', { decidePath: outcome.decidePath }) : '';
@@ -21,3 +21,9 @@ export type CheckpointRequirementsDamagedReading = {
21
21
  readonly kind: 'row_mismatch';
22
22
  };
23
23
  export declare function checkpointRequirementsDamagedOf(failure: object | null | undefined): CheckpointRequirementsDamagedReading | undefined;
24
+ export type CheckpointRowBar = Exclude<CheckpointRowVerdictReading, {
25
+ readonly kind: 'ok';
26
+ }>;
27
+ export declare function checkpointRowBarOf(row: object | null | undefined): CheckpointRowBar | undefined;
28
+ export declare const CHECKPOINT_ROW_BAR_SENTENCE: string;
29
+ export declare function checkpointRowBarSentence(bar: CheckpointRowBar): string;
@@ -1,4 +1,5 @@
1
1
  import { readErrorString, slotReadOf } from './wireFailureShape.js';
2
+ import { msg, renderMessage } from './i18n/translate.js';
2
3
  const UNREADABLE = Object.freeze({ kind: 'unreadable' });
3
4
  const OK = Object.freeze({ kind: 'ok' });
4
5
  function ownNonEmptyString(o, key) {
@@ -87,3 +88,11 @@ export function checkpointRequirementsDamagedOf(failure) {
87
88
  return undefined;
88
89
  }
89
90
  }
91
+ export function checkpointRowBarOf(row) {
92
+ const v = checkpointRowVerdictOf(row);
93
+ return v === undefined || v.kind === 'ok' ? undefined : v;
94
+ }
95
+ export const CHECKPOINT_ROW_BAR_SENTENCE = renderMessage(msg('approval.rowUnresumable.fallback'));
96
+ export function checkpointRowBarSentence(bar) {
97
+ return bar.kind !== 'unreadable' && typeof bar.sentence === 'string' && bar.sentence !== '' ? bar.sentence : CHECKPOINT_ROW_BAR_SENTENCE;
98
+ }
@@ -162,7 +162,7 @@ export function decideRequiresBindingFromError(e) {
162
162
  }
163
163
  }
164
164
  export function decideRequiresBindingContent(_detail, lang) {
165
- return renderMessage(msg('approval.decide.requiresBinding'), isUiLanguage(lang) ? lang : undefined);
165
+ return renderMessage(msg('approval.decide.requiresBinding', { wayOut: msg('approval.decide.unboundWayOut') }), isUiLanguage(lang) ? lang : undefined);
166
166
  }
167
167
  function askGoneRawCause(e) {
168
168
  let top;
@@ -2,6 +2,7 @@ export declare const REDACTION_MARKER_PREFIX = "\u00ABredacted";
2
2
  export declare function looksLikeKnownSecret(s: string): boolean;
3
3
  export declare function isDiagnosticValueWord(value: string): boolean;
4
4
  export declare function percentBoundaryReadingOf(text: string): string;
5
+ type BlankNet = 0 | 1 | 2;
5
6
  interface WashStats {
6
7
  passes: number;
7
8
  capped: boolean;
@@ -13,7 +14,7 @@ export interface DisplayFace {
13
14
  readonly unsafe: RegExp | null;
14
15
  readonly fold: boolean;
15
16
  readonly mark: DisplayMark;
16
- readonly keepBlanks?: boolean;
17
+ readonly blanks?: BlankNet;
17
18
  readonly keepCrlf?: boolean;
18
19
  }
19
20
  export declare function applyDisplayFace(text: string, face: DisplayFace): string;
@@ -26,8 +27,8 @@ export interface DisplayUntrustedOptions {
26
27
  readonly keepLayout?: boolean | 'crlf';
27
28
  readonly mark?: DisplayMark;
28
29
  readonly max?: number;
29
- readonly escapeBackslashes?: boolean;
30
- readonly blanks?: boolean | 'fillers';
30
+ readonly escapeBackslashes?: boolean | 'auto';
31
+ readonly blanks?: boolean | 'except-ideographic';
31
32
  }
32
33
  export interface DisplayMarkSpan {
33
34
  readonly start: number;
@@ -37,6 +38,7 @@ export interface DisplayMarkSpan {
37
38
  export interface DisplayUntrustedMarked {
38
39
  readonly text: string;
39
40
  readonly marks: readonly DisplayMarkSpan[];
41
+ readonly exact: boolean;
40
42
  }
41
43
  export declare const DISPLAY_DECISION_BODY: Readonly<DisplayUntrustedOptions>;
42
44
  export declare const ESCAPE_FACE: DisplayFace;
@@ -957,13 +957,14 @@ function hiddenHostEnd(text, from, unitAt) {
957
957
  const c = text.charCodeAt(k);
958
958
  return endsSchemelessHost(c) || c === 0x40 ? k : -1;
959
959
  }
960
+ const IDEOGRAPHIC_SPACE = 0x3000;
960
961
  const NAME_BLANK_RANGES = [
961
962
  [0x00a0, 0x00a0],
962
963
  [0x1680, 0x1680],
963
964
  [0x2000, 0x200a],
964
965
  [0x202f, 0x202f],
965
966
  [0x205f, 0x205f],
966
- [0x3000, 0x3000],
967
+ [IDEOGRAPHIC_SPACE, IDEOGRAPHIC_SPACE],
967
968
  [0x115f, 0x1160],
968
969
  [0x3164, 0x3164],
969
970
  [0xffa0, 0xffa0],
@@ -3593,7 +3594,7 @@ const FACE_MARKED_CHAR = new RegExp(`^(?:[${C0_ALL}${DEL_C1}${LONE_SURROGATE}${L
3593
3594
  const isStrippableControl = (c) => (c <= 0x1f && (c < 0x09 || c > 0x0d)) || (c >= 0x7f && c <= 0x9f);
3594
3595
  class SequenceReader {
3595
3596
  text;
3596
- atomicBlanks;
3597
+ blanks;
3597
3598
  foldBlanks;
3598
3599
  terminator;
3599
3600
  lineBreak;
@@ -3602,9 +3603,9 @@ class SequenceReader {
3602
3603
  breakFrom = -1;
3603
3604
  breakAt = -1;
3604
3605
  foldSpaces;
3605
- constructor(text, atomicBlanks, foldBlanks = false, foldSpaces = false) {
3606
+ constructor(text, blanks, foldBlanks = false, foldSpaces = false) {
3606
3607
  this.text = text;
3607
- this.atomicBlanks = atomicBlanks;
3608
+ this.blanks = blanks;
3608
3609
  this.foldBlanks = foldBlanks;
3609
3610
  this.foldSpaces = foldSpaces;
3610
3611
  this.terminator = /[\u0007\u009c]|\u001b\\|\\u(?:0007|009[cC]|001[bB]\\)/g;
@@ -3615,12 +3616,7 @@ class SequenceReader {
3615
3616
  return false;
3616
3617
  if (escapeTokenAt(this.text, at) !== null)
3617
3618
  return true;
3618
- if (this.atomicBlanks === 'none')
3619
- return false;
3620
- const cp = nameBlankTokenAt(this.text, at);
3621
- if (this.atomicBlanks === 'fillers')
3622
- return cp !== -1 && !isFoldedBlank(cp);
3623
- return this.atomicBlanks === 'all' ? cp !== -1 : isFoldedBlank(cp);
3619
+ return isMarkedNameBlank(this.blanks, nameBlankTokenAt(this.text, at));
3624
3620
  }
3625
3621
  intermediateAt(at) {
3626
3622
  const c = this.text.charCodeAt(at);
@@ -3628,11 +3624,12 @@ class SequenceReader {
3628
3624
  return 1;
3629
3625
  if (this.foldSpaces && ((c >= 0x09 && c <= 0x0d) || c === 0x2028 || c === 0x2029))
3630
3626
  return 1;
3631
- if (!this.foldBlanks)
3632
- return 0;
3633
- if (isFoldedBlank(c))
3627
+ if (this.blankAsSpace(c))
3634
3628
  return 1;
3635
- return c === 0x5c && isFoldedBlank(nameBlankTokenAt(this.text, at)) ? 6 : 0;
3629
+ return c === 0x5c && this.blankAsSpace(nameBlankTokenAt(this.text, at)) ? 6 : 0;
3630
+ }
3631
+ blankAsSpace(cp) {
3632
+ return isFoldedBlank(cp) && (this.foldBlanks || isMarkedNameBlank(this.blanks, cp));
3636
3633
  }
3637
3634
  interruptsAt(at) {
3638
3635
  if (at >= this.text.length)
@@ -3738,7 +3735,7 @@ function nameBlankTokenAt(text, at) {
3738
3735
  return isNameBlank(cp) ? cp : -1;
3739
3736
  }
3740
3737
  function isMarkedNameBlank(net, c) {
3741
- return net === 1 ? isNameBlank(c) : net === 2 ? isNameBlank(c) && !isRegexSpace(c) : false;
3738
+ return net === 1 ? isNameBlank(c) : net === 2 ? isNameBlank(c) && c !== IDEOGRAPHIC_SPACE : false;
3742
3739
  }
3743
3740
  function buildScanView(text, o) {
3744
3741
  const chars = [];
@@ -3748,7 +3745,7 @@ function buildScanView(text, o) {
3748
3745
  const dropped = [];
3749
3746
  const spaceUnits = [];
3750
3747
  const contents = [];
3751
- const seq = new SequenceReader(text, o.blanks === 1 ? 'all' : o.blanks === 2 ? 'fillers' : 'none', o.blanks === 1 || o.fold, o.fold);
3748
+ const seq = new SequenceReader(text, o.blanks, o.fold, o.fold);
3752
3749
  const keep = (ch, s, e, unit = UNIT_NONE) => {
3753
3750
  chars.push(ch);
3754
3751
  starts.push(s);
@@ -3945,7 +3942,7 @@ function screenSurfaces(text, o) {
3945
3942
  if (face === null)
3946
3943
  return { surfaces: [], rawSoft: null, rawPlain: null, contents: [] };
3947
3944
  const unsafe = face.unsafe === null ? null : new RegExp(face.unsafe.source, 'u');
3948
- const keepBlanks = face.keepBlanks === true;
3945
+ const blankNet = face.blanks ?? 0;
3949
3946
  const chars = [];
3950
3947
  const ps = [];
3951
3948
  const pe = [];
@@ -3955,7 +3952,7 @@ function screenSurfaces(text, o) {
3955
3952
  let changed = false;
3956
3953
  const foldable = (at) => {
3957
3954
  const c = text.codePointAt(at) ?? 0;
3958
- return isRegexSpace(c) && !(keepBlanks && isNameBlank(c));
3955
+ return isRegexSpace(c) && !isMarkedNameBlank(blankNet, c);
3959
3956
  };
3960
3957
  let lo = 0;
3961
3958
  let hi = text.length;
@@ -4648,7 +4645,7 @@ export function washCredentials(text) {
4648
4645
  return scanAndMask(text, WASH_OPTIONS, false).text;
4649
4646
  }
4650
4647
  const NAME_BLANKS = NAME_BLANK_RANGES.map(([a, b]) => (a === b ? classEscape(a) : `${classEscape(a)}-${classEscape(b)}`)).join('');
4651
- const NAME_FILLERS = NAME_BLANK_RANGES.filter(([a, b]) => !isRegexSpace(a) && !isRegexSpace(b))
4648
+ const NAME_BLANKS_EXCEPT_IDEOGRAPHIC = NAME_BLANK_RANGES.filter(([a, b]) => !(a <= IDEOGRAPHIC_SPACE && IDEOGRAPHIC_SPACE <= b))
4652
4649
  .map(([a, b]) => (a === b ? classEscape(a) : `${classEscape(a)}-${classEscape(b)}`))
4653
4650
  .join('');
4654
4651
  function classEscape(cp) {
@@ -4777,17 +4774,17 @@ function markOf(ch, mark) {
4777
4774
  return code > 0xffff ? `\\u{${hex}}` : `\\u${hex.padStart(4, '0')}`;
4778
4775
  }
4779
4776
  const FOLD_RUN = /\s+/g;
4780
- const FOLD_RUN_KEEPING_BLANKS = new RegExp(`[^\\S${NAME_BLANKS}]+`, 'g');
4777
+ const FOLD_RUN_BY_NET = [FOLD_RUN, new RegExp(`[^\\S${NAME_BLANKS}]+`, 'g'), new RegExp(`[^\\S${NAME_BLANKS_EXCEPT_IDEOGRAPHIC}]+`, 'g')];
4781
4778
  const EDGE_SPACE = /^ | $/g;
4782
- const foldWhitespace = (s, keepBlanks = false) => keepBlanks ? s.replace(FOLD_RUN_KEEPING_BLANKS, ' ').replace(EDGE_SPACE, '') : s.replace(FOLD_RUN, ' ').trim();
4779
+ const foldWhitespace = (s, net = 0) => net !== 0 ? s.replace(FOLD_RUN_BY_NET[net] ?? FOLD_RUN, ' ').replace(EDGE_SPACE, '') : s.replace(FOLD_RUN, ' ').trim();
4783
4780
  export function applyDisplayFace(text, face) {
4784
4781
  const markAll = (s) => face.unsafe === null ? s : s.replace(face.unsafe, (ch, at, whole) => (faceHitKept(ch, at, whole, face.keepCrlf === true) ? ch : markOf(ch, face.mark)));
4785
- const keepBlanks = face.keepBlanks === true;
4782
+ const net = face.blanks ?? 0;
4786
4783
  if (face.mark === 'space') {
4787
4784
  const marked = markAll(text);
4788
- return face.fold ? foldWhitespace(marked, keepBlanks) : marked;
4785
+ return face.fold ? foldWhitespace(marked, net) : marked;
4789
4786
  }
4790
- return markAll(face.fold ? foldWhitespace(text, keepBlanks) : text);
4787
+ return markAll(face.fold ? foldWhitespace(text, net) : text);
4791
4788
  }
4792
4789
  function markTracked(t, re, mark, ledger, crlf = false) {
4793
4790
  const parts = [];
@@ -4820,11 +4817,11 @@ function markTracked(t, re, mark, ledger, crlf = false) {
4820
4817
  keep(cursor, t.text.length);
4821
4818
  return { text: parts.join(''), ids: Int32Array.from(ids) };
4822
4819
  }
4823
- function foldTracked(t, keepBlanks) {
4820
+ function foldTracked(t, net) {
4824
4821
  const parts = [];
4825
4822
  const ids = [];
4826
4823
  let cursor = 0;
4827
- for (const run of t.text.matchAll(keepBlanks ? FOLD_RUN_KEEPING_BLANKS : FOLD_RUN)) {
4824
+ for (const run of t.text.matchAll(FOLD_RUN_BY_NET[net] ?? FOLD_RUN)) {
4828
4825
  const at = run.index ?? 0;
4829
4826
  parts.push(t.text.slice(cursor, at));
4830
4827
  for (let k = cursor; k < at; k++)
@@ -4849,14 +4846,14 @@ function foldTracked(t, keepBlanks) {
4849
4846
  return { text: folded.slice(from, to), ids: Int32Array.from(ids.slice(from, to)) };
4850
4847
  }
4851
4848
  function faceTracked(t, face, ledger) {
4852
- const keepBlanks = face.keepBlanks === true;
4849
+ const net = face.blanks ?? 0;
4853
4850
  const unsafe = face.unsafe;
4854
4851
  const markAll = (x) => (unsafe === null ? x : markTracked(x, unsafe, face.mark, ledger, face.keepCrlf === true));
4855
4852
  if (face.mark === 'space') {
4856
4853
  const marked = markAll(t);
4857
- return face.fold ? foldTracked(marked, keepBlanks) : marked;
4854
+ return face.fold ? foldTracked(marked, net) : marked;
4858
4855
  }
4859
- return markAll(face.fold ? foldTracked(t, keepBlanks) : t);
4856
+ return markAll(face.fold ? foldTracked(t, net) : t);
4860
4857
  }
4861
4858
  function carryIds(ids, origin) {
4862
4859
  if (origin === undefined)
@@ -4933,7 +4930,7 @@ function collectMarks(t, ledger) {
4933
4930
  export const DISPLAY_DECISION_BODY = Object.freeze({
4934
4931
  foldLines: false,
4935
4932
  keepLayout: 'crlf',
4936
- blanks: 'fillers',
4933
+ blanks: 'except-ideographic',
4937
4934
  mark: 'escape',
4938
4935
  });
4939
4936
  const PUBLIC_UNSAFE_BY_NETS = Object.freeze(Array.from({ length: 24 }, (_, i) => {
@@ -4942,12 +4939,12 @@ const PUBLIC_UNSAFE_BY_NETS = Object.freeze(Array.from({ length: 24 }, (_, i) =>
4942
4939
  const controls = (rest & 4) !== 0;
4943
4940
  const bidi = (rest & 2) !== 0;
4944
4941
  const keep = (rest & 1) !== 0;
4945
- const blanks = net === 1 ? NAME_BLANKS : net === 2 ? NAME_FILLERS : '';
4942
+ const blanks = net === 1 ? NAME_BLANKS : net === 2 ? NAME_BLANKS_EXCEPT_IDEOGRAPHIC : '';
4946
4943
  const members = `${controls ? `${keep ? C0_KEEP_LAYOUT : C0_ALL}${DEL_C1}${LONE_SURROGATE}` : ''}${bidi ? LINE_SEPARATORS : ''}${blanks}`;
4947
4944
  return unsafeClass(members, bidi);
4948
4945
  }));
4949
4946
  function blankNetOf(opts) {
4950
- return opts.blanks === true ? 1 : opts.blanks === 'fillers' ? 2 : 0;
4947
+ return opts.blanks === true ? 1 : opts.blanks === 'except-ideographic' ? 2 : 0;
4951
4948
  }
4952
4949
  const keepsLayout = (opts) => opts.keepLayout === true || opts.keepLayout === 'crlf';
4953
4950
  function publicFace(opts) {
@@ -4955,7 +4952,7 @@ function publicFace(opts) {
4955
4952
  const keep = !fold && keepsLayout(opts);
4956
4953
  const net = blankNetOf(opts);
4957
4954
  const index = ((opts.controls !== false ? 4 : 0) + (opts.bidi !== false ? 2 : 0) + (keep ? 1 : 0)) * 3 + net;
4958
- const face = { unsafe: PUBLIC_UNSAFE_BY_NETS[index] ?? null, fold, mark: opts.mark ?? 'escape', keepBlanks: net === 1 };
4955
+ const face = { unsafe: PUBLIC_UNSAFE_BY_NETS[index] ?? null, fold, mark: opts.mark ?? 'escape', blanks: net };
4959
4956
  return keep && opts.keepLayout === 'crlf' && opts.controls !== false ? { ...face, keepCrlf: true } : face;
4960
4957
  }
4961
4958
  export const ESCAPE_FACE = Object.freeze({ ...publicFace({ foldLines: false }) });
@@ -5074,13 +5071,22 @@ function displayInputText(text) {
5074
5071
  return text === null ? '' : REDACTED_SECRET;
5075
5072
  }
5076
5073
  }
5074
+ const ENCODED_FORM = /\\\\|\\u(?:[0-9A-Fa-f]{4}|\{[0-9A-Fa-f]{1,6}\})/;
5075
+ function pairsByItself(form) {
5076
+ return ENCODED_FORM.test(form.text);
5077
+ }
5078
+ function pairModeOf(o, face) {
5079
+ if (face.mark === 'dot' || face.mark === 'space')
5080
+ return 'off';
5081
+ return o.escapeBackslashes === true ? 'on' : o.escapeBackslashes === 'auto' ? 'auto' : 'off';
5082
+ }
5077
5083
  function renderUntrusted(text, opts, ledger, queryByShape = false, wholeAddress = false) {
5078
5084
  const input = displayInputText(text);
5079
5085
  const o = opts ?? {};
5080
5086
  const face = publicFace(o);
5081
5087
  const scan = scanOptionsOf(o, face, queryByShape, wholeAddress);
5082
- const pairBackslashes = o.escapeBackslashes === true && face.mark !== 'dot' && face.mark !== 'space';
5083
- const book = ledger ?? (pairBackslashes ? { cps: [], lens: [] } : null);
5088
+ const mode = pairModeOf(o, face);
5089
+ const book = ledger ?? (mode !== 'off' ? { cps: [], lens: [] } : null);
5084
5090
  if (book === null) {
5085
5091
  return runDisplaySteps(input, {
5086
5092
  wash: (s) => scanAndMask(s, scan, false).text,
@@ -5089,6 +5095,7 @@ function renderUntrusted(text, opts, ledger, queryByShape = false, wholeAddress
5089
5095
  text: (s) => s,
5090
5096
  });
5091
5097
  }
5098
+ let paired = mode === 'on';
5092
5099
  const out = runDisplaySteps({ text: input, ids: new Int32Array(input.length).fill(-1) }, {
5093
5100
  wash: (t) => {
5094
5101
  const r = scanAndMask(t.text, scan, true);
@@ -5096,18 +5103,20 @@ function renderUntrusted(text, opts, ledger, queryByShape = false, wholeAddress
5096
5103
  },
5097
5104
  paint: (t) => faceTracked(t, face, book),
5098
5105
  cap: (t) => {
5099
- if (pairBackslashes)
5106
+ if (mode === 'auto' && !paired)
5107
+ paired = pairsByItself(t);
5108
+ if (paired)
5100
5109
  return capPaired(t, o.max);
5101
5110
  const cut = capDisplay(t.text, o.max, face.mark);
5102
5111
  return cut === t.text ? t : { text: cut, ids: t.ids.slice(0, cut.length) };
5103
5112
  },
5104
5113
  text: (t) => t.text,
5105
5114
  });
5106
- return pairBackslashes ? pairLiteralBackslashes(out) : out;
5115
+ return { tracked: paired ? pairLiteralBackslashes(out) : out, exact: paired };
5107
5116
  }
5108
5117
  export function displayUntrusted(text, opts = {}) {
5109
5118
  const out = renderUntrusted(text, opts, null);
5110
- return typeof out === 'string' ? out : out.text;
5119
+ return typeof out === 'string' ? out : out.tracked.text;
5111
5120
  }
5112
5121
  export function cleanUntrustedScalar(v) {
5113
5122
  return displayUntrusted(String(v ?? ''), { credentialUrls: false, credentialWords: false, foldLines: false });
@@ -5354,7 +5363,7 @@ export function queryCarriesCredential(query) {
5354
5363
  export function displayConfiguredUrl(url, opts = {}) {
5355
5364
  const reading = typeof url === 'string' ? configuredAddressReading(url) : null;
5356
5365
  const out = renderUntrusted(reading === null ? url : reading.withheld ? REDACTED_SECRET : reading.text, opts, null, 'relaxed', true);
5357
- return typeof out === 'string' ? out : out.text;
5366
+ return typeof out === 'string' ? out : out.tracked.text;
5358
5367
  }
5359
5368
  function parserViewOf(url) {
5360
5369
  return url.replace(/[\t\n\r]/g, '').replace(/^[\u0000-\u0020]+/, '');
@@ -5773,7 +5782,7 @@ export function displayUntrustedMarks(text, opts = {}) {
5773
5782
  const ledger = { cps: [], lens: [] };
5774
5783
  const out = renderUntrusted(text, opts, ledger);
5775
5784
  if (typeof out === 'string')
5776
- return { text: out, marks: [] };
5777
- return { text: out.text, marks: collectMarks(out, ledger) };
5785
+ return { text: out, marks: [], exact: false };
5786
+ return { text: out.tracked.text, marks: collectMarks(out.tracked, ledger), exact: out.exact };
5778
5787
  }
5779
5788
  const isQuoteChar = (c) => c.charCodeAt(0) === 0x22 || c.charCodeAt(0) === 0x27;
@@ -197,8 +197,19 @@ export interface UserInputUndrainedFactsView {
197
197
  sessionId?: string;
198
198
  runId?: string;
199
199
  childSessionId?: string;
200
+ inputIds?: readonly string[];
200
201
  }
201
202
  export declare function readUserInputUndrained(notice: unknown): UserInputUndrainedFactsView | undefined;
203
+ export interface UndrainedInputsLedger {
204
+ readonly handed?: readonly string[];
205
+ readonly redelivered?: readonly string[];
206
+ }
207
+ export interface UndrainedInputsVerdict {
208
+ readonly redeliver: readonly string[];
209
+ readonly askUser: readonly string[];
210
+ readonly unattributed: number;
211
+ }
212
+ export declare function undrainedInputsVerdict(facts: Pick<UserInputUndrainedFactsView, 'count' | 'cause' | 'inputIds' | 'childSessionId'> | null | undefined, ledger: UndrainedInputsLedger | null | undefined): UndrainedInputsVerdict | undefined;
202
213
  export declare function userInputUndrainedNotice(facts: Pick<UserInputUndrainedFactsView, 'kind' | 'count' | 'cause' | 'childSessionId'>): string | undefined;
203
214
  export interface TurnInterruptedFactsView {
204
215
  lane: 'input_now' | 'user_halt' | 'unrecognized';
@@ -285,6 +296,7 @@ export declare const ENGINE_NOTICE_FACT_READERS: Readonly<{
285
296
  readonly 'route.stream_end_ignored': typeof readStreamEndIgnored;
286
297
  readonly 'mcp.authorization_required': typeof readMcpAuthorizationRequired;
287
298
  readonly 'context.media_removed': typeof readContextMediaRemoved;
299
+ readonly 'context.image_removed': typeof readContextMediaRemoved;
288
300
  readonly 'session.lineage_rerooted': typeof readSessionLineageRerooted;
289
301
  }>;
290
302
  type FactReaderTable = typeof ENGINE_NOTICE_FACT_READERS;