@sema-agent/core 7.23.1 → 7.23.3

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 (124) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/agents/agent-transcript-tool.js +2 -1
  3. package/dist/agents/cascade.js +2 -1
  4. package/dist/agents/list-agents-tool.js +2 -1
  5. package/dist/agents/observer.js +3 -2
  6. package/dist/agents/peer-session-drain.js +2 -1
  7. package/dist/agents/retain-ledger.js +2 -1
  8. package/dist/agents/send-message-tool.js +11 -10
  9. package/dist/agents/subagent.js +18 -17
  10. package/dist/agents/teacher.js +5 -4
  11. package/dist/brain/circuit-breaker.js +2 -1
  12. package/dist/brain/degrading.js +2 -1
  13. package/dist/brain/errors.js +24 -15
  14. package/dist/brain/failover.js +2 -1
  15. package/dist/brain/stream-engine.js +2 -1
  16. package/dist/core/a2a.js +4 -3
  17. package/dist/core/artifact-host.js +2 -1
  18. package/dist/core/ask-question.js +3 -2
  19. package/dist/core/auto-promote.js +3 -2
  20. package/dist/core/gate-bounded-await.js +2 -1
  21. package/dist/core/gate-fold.js +4 -1
  22. package/dist/core/gate-lanes.js +4 -2
  23. package/dist/core/git-worktree-env.js +6 -5
  24. package/dist/core/hooks.js +4 -4
  25. package/dist/core/lsp-session.js +3 -2
  26. package/dist/core/mcp.js +4 -3
  27. package/dist/core/memory-admission.js +2 -1
  28. package/dist/core/memory-engine/consolidation-driver.js +5 -4
  29. package/dist/core/memory-engine/consolidation.js +2 -1
  30. package/dist/core/memory-engine/delegation-settlement.js +4 -3
  31. package/dist/core/memory-engine/distiller.js +8 -4
  32. package/dist/core/memory-engine/engine.js +63 -55
  33. package/dist/core/memory-engine/file-backend.js +11 -10
  34. package/dist/core/memory-engine/layout.js +5 -4
  35. package/dist/core/memory-engine/session-incarnation.js +2 -1
  36. package/dist/core/memory.js +2 -1
  37. package/dist/core/oracle-isolation.js +3 -2
  38. package/dist/core/permission-rule-store.js +2 -1
  39. package/dist/core/runner/announce-once-ledger.js +2 -1
  40. package/dist/core/runner/compaction-seams.js +3 -2
  41. package/dist/core/runner/gate-exit.d.ts +5 -0
  42. package/dist/core/runner/git-leg-delivery.js +4 -3
  43. package/dist/core/runner/git-status-frame.js +2 -1
  44. package/dist/core/runner/mcp-redial.js +2 -1
  45. package/dist/core/runner/memory-consolidation-driver.js +2 -1
  46. package/dist/core/runner/permission-rule-lanes.js +3 -2
  47. package/dist/core/runner/prepare-artifact.js +2 -1
  48. package/dist/core/runner/prepare-ask-lane.js +2 -1
  49. package/dist/core/runner/prepare-caps-and-workflow.js +4 -3
  50. package/dist/core/runner/prepare-inherited-gate.js +2 -1
  51. package/dist/core/runner/prepare-memory-engine-session.js +2 -1
  52. package/dist/core/runner/prepare-memory.js +5 -4
  53. package/dist/core/runner/prepare-policy-chain.js +3 -2
  54. package/dist/core/runner/prepare-project-context.js +3 -2
  55. package/dist/core/runner/prepare-protocol-tools.js +3 -2
  56. package/dist/core/runner/prepare-suspend-saga.js +2 -1
  57. package/dist/core/runner/prepare-task.js +6 -5
  58. package/dist/core/runner/prepare-turn-wiring.js +2 -1
  59. package/dist/core/runner/resume-apply.js +5 -4
  60. package/dist/core/runner/resume-preflight.js +3 -2
  61. package/dist/core/runner/run-git-lane.js +4 -3
  62. package/dist/core/runner/run-leg.js +4 -3
  63. package/dist/core/runner/run-recovery-lanes.js +3 -2
  64. package/dist/core/runner/run-settle-and-teardown.js +2 -1
  65. package/dist/core/runner/run-stop-and-final-verify.js +2 -1
  66. package/dist/core/runner/run-telemetry-and-budget-seats.js +2 -1
  67. package/dist/core/runner/run-terminal-adoption.js +6 -5
  68. package/dist/core/runner/run-turn-boundary.js +5 -4
  69. package/dist/core/runner/runtask.js +2 -1
  70. package/dist/core/runner/stream-settle-backstop.js +5 -4
  71. package/dist/core/runner/stream-steer-verb.js +2 -1
  72. package/dist/core/runner/strict-output-schema.js +2 -1
  73. package/dist/core/runner/teardown-bounded.js +2 -1
  74. package/dist/core/safe-notify.js +2 -1
  75. package/dist/core/skills-directory.js +2 -1
  76. package/dist/core/strategy-store.js +2 -1
  77. package/dist/core/task-registry-agent.js +2 -1
  78. package/dist/core/task-registry-monitor.js +2 -1
  79. package/dist/core/task-registry-workflow.js +2 -1
  80. package/dist/core/task-registry.js +3 -2
  81. package/dist/core/thrown-value.d.ts +79 -0
  82. package/dist/core/thrown-value.js +56 -0
  83. package/dist/core/tool-errors.d.ts +0 -6
  84. package/dist/core/tool-errors.js +36 -14
  85. package/dist/core/tool-model-gate.js +2 -1
  86. package/dist/core/tool-policy.js +6 -13
  87. package/dist/core/tool-result-store.js +2 -1
  88. package/dist/core/tool-spec.d.ts +12 -0
  89. package/dist/core/write-protect.js +3 -2
  90. package/dist/engine/compaction/compaction.js +3 -4
  91. package/dist/engine/harness/agent-harness.js +2 -1
  92. package/dist/engine/harness/types.js +8 -7
  93. package/dist/engine/loop/agent-loop.js +7 -6
  94. package/dist/engine/lsp/node-lsp-manager.js +5 -4
  95. package/dist/engine/lsp/stdio-lsp-transport.js +12 -5
  96. package/dist/orchestration/dev-vm-script-runner.js +2 -1
  97. package/dist/orchestration/run-workflow-tool.js +7 -6
  98. package/dist/orchestration/workflow-governance.js +2 -1
  99. package/dist/orchestration/workflow-sandbox-conformance.js +3 -2
  100. package/dist/orchestration/workflow-script-store.js +2 -1
  101. package/dist/orchestration/workflow.js +15 -14
  102. package/dist/server/http.js +3 -2
  103. package/dist/stores/file/adoption/adopt.js +3 -2
  104. package/dist/stores/file/fs-atomic.js +2 -1
  105. package/dist/stores/file/permission-rule-adopt.js +2 -1
  106. package/dist/stores/file/permission-rule-store.js +2 -1
  107. package/dist/stores/file/session-store.js +4 -3
  108. package/dist/stores/file/strategy-store.js +7 -6
  109. package/dist/tools/artifact/artifact-tool.js +3 -2
  110. package/dist/tools/artifact/conformance.js +4 -3
  111. package/dist/tools/fs/bash-readonly-classifier.d.ts +20 -9
  112. package/dist/tools/fs/bash-readonly-classifier.js +7 -3
  113. package/dist/tools/fs/fs-bash.d.ts +16 -10
  114. package/dist/tools/fs/fs-bash.js +84 -35
  115. package/dist/tools/fs/fs-write.js +3 -2
  116. package/dist/tools/fs/safety.js +2 -1
  117. package/dist/tools/fs/search.js +3 -2
  118. package/dist/tools/monitor.js +3 -2
  119. package/dist/tools/sql.js +2 -1
  120. package/dist/tools/web.js +5 -15
  121. package/dist/tools/worktree.js +12 -9
  122. package/package.json +2 -1
  123. package/wire-changes/core@7.23.2.json +42 -0
  124. package/wire-changes/core@7.23.3.json +25 -0
@@ -4,6 +4,7 @@ import { hasDestroy } from "../remote-env.js";
4
4
  import { inlineUntrusted } from "../untrusted-text.js";
5
5
  import { describeSuppliedValue } from "./decide-continuation.js";
6
6
  import { settleTeardownLeg } from "./teardown-bounded.js";
7
+ import { asThrownError } from "../thrown-value.js";
7
8
  const RESUME_PREFLIGHT_DEFAULT_TIMEOUT_MS = 10_000;
8
9
  export async function resumePreflight(input) {
9
10
  const { token, cp, resumeSignal, recheckGovernanceWindow, store, runner, locallyClaimedTokens, parentConstraintRegistry, suspendedEnvReaps } = input;
@@ -40,7 +41,7 @@ export async function resumePreflight(input) {
40
41
  abortEnds: true,
41
42
  onBadTimeout: (badErr) => {
42
43
  try {
43
- runner.deps.onError?.(badErr instanceof Error ? badErr : new Error(String(badErr)), { phase: "hook", sessionId: cp.sessionId });
44
+ runner.deps.onError?.(asThrownError(badErr), { phase: "hook", sessionId: cp.sessionId });
44
45
  }
45
46
  catch {
46
47
  }
@@ -57,7 +58,7 @@ export async function resumePreflight(input) {
57
58
  catch (preflightErr) {
58
59
  if (preflightErr instanceof CheckpointError)
59
60
  throw preflightErr;
60
- const err = preflightErr instanceof Error ? preflightErr : new Error(String(preflightErr));
61
+ const err = asThrownError(preflightErr);
61
62
  try {
62
63
  runner.deps.onError?.(err, { phase: "hook", sessionId: cp.sessionId });
63
64
  }
@@ -1,5 +1,6 @@
1
1
  import { GIT_STATUS_ECHO_PREVIEW } from "./git-status-frame.js";
2
2
  import { wrapGitFrame } from "./git-leg-delivery.js";
3
+ import { thrownText } from "../thrown-value.js";
3
4
  export function runGitLane(input) {
4
5
  const { prepared, queue, rs, ident, onMessageUpdate, onMessageEnd, onToolStart, onToolEnd, onTurnEnd, onTurnBoundary, runner } = input;
5
6
  prepared.gitStatusRef.reassert = async () => {
@@ -34,7 +35,7 @@ export function runGitLane(input) {
34
35
  }
35
36
  catch (mirrorErr) {
36
37
  try {
37
- runner.deps.onError?.(new Error(`git announcement mirror write failed (frame delivered; next leg re-announces): ${mirrorErr instanceof Error ? mirrorErr.message : String(mirrorErr)}`), { phase: "degraded", sessionId: prepared.sessionId });
38
+ runner.deps.onError?.(new Error(`git announcement mirror write failed (frame delivered; next leg re-announces): ${thrownText(mirrorErr)}`), { phase: "degraded", sessionId: prepared.sessionId });
38
39
  }
39
40
  catch {
40
41
  }
@@ -43,7 +44,7 @@ export function runGitLane(input) {
43
44
  catch (err) {
44
45
  ref.announced = { kind: use.kind, hash: use.hash, pending: true };
45
46
  try {
46
- runner.deps.onError?.(new Error(`git status frame re-assert append failed (pending; retried at the next boundary): ${err instanceof Error ? err.message : String(err)}`), { phase: "degraded", sessionId: prepared.sessionId });
47
+ runner.deps.onError?.(new Error(`git status frame re-assert append failed (pending; retried at the next boundary): ${thrownText(err)}`), { phase: "degraded", sessionId: prepared.sessionId });
47
48
  }
48
49
  catch {
49
50
  }
@@ -64,7 +65,7 @@ export function runGitLane(input) {
64
65
  catch (mirrorErr) {
65
66
  prepared.gitStatusRef.mirrorOwed = owed;
66
67
  try {
67
- runner.deps.onError?.(new Error(`git announcement mirror write failed (frame delivered; retried at the next serialization point): ${mirrorErr instanceof Error ? mirrorErr.message : String(mirrorErr)}`), { phase: "degraded", sessionId: prepared.sessionId });
68
+ runner.deps.onError?.(new Error(`git announcement mirror write failed (frame delivered; retried at the next serialization point): ${thrownText(mirrorErr)}`), { phase: "degraded", sessionId: prepared.sessionId });
68
69
  }
69
70
  catch {
70
71
  }
@@ -29,6 +29,7 @@ import { toolEndBodyFrom, toolResultMsg } from "./tool-end-body.js";
29
29
  import { announceListingTruncation } from "../skill-listing-budget.js";
30
30
  import { attachmentEnvelopeTags, commitAgentListing, commitSkillsListing, reduceToolEnd, renderAgentListingFrame, renderOrphanedBackgroundTasks, renderSkillsListingFrame, stampWriteAnchor } from "./turn-attachments.js";
31
31
  import { flushOwedAnnouncedSnapshot } from "./announce-once-ledger.js";
32
+ import { asThrownError, thrownText } from "../thrown-value.js";
32
33
  export async function runLeg(input) {
33
34
  const { spec, queue, prepared, resume, rs, isDelegatedChild, entryActor, effectiveTimeoutMs, timeout, pushContent, ident, emitCommitted, writeFamilyOf, startedToolCallIds, announceWorkspaceMove, withBrainSinks, flushGitMirror, loopLatch, notificationLane, unsubscribeTaskNotifications, unsubGitRetry, unsubBoundary, unsub, runner, next } = input;
34
35
  let final;
@@ -164,7 +165,7 @@ export async function runLeg(input) {
164
165
  : { ...(seat.value?.additionalContext !== undefined && seat.value.additionalContext !== "" ? { context: seat.value.additionalContext } : {}) };
165
166
  }
166
167
  catch (hookErr) {
167
- const err = hookErr instanceof Error ? hookErr : new Error(String(hookErr));
168
+ const err = asThrownError(hookErr);
168
169
  try {
169
170
  runner.deps.onError?.(err, { phase: "hook", sessionId: prepared.sessionId });
170
171
  }
@@ -301,7 +302,7 @@ export async function runLeg(input) {
301
302
  }
302
303
  }
303
304
  catch (hookErr) {
304
- const err = hookErr instanceof Error ? hookErr : new Error(String(hookErr));
305
+ const err = asThrownError(hookErr);
305
306
  try {
306
307
  runner.deps.onError?.(err, { phase: "hook", sessionId: prepared.sessionId });
307
308
  }
@@ -691,7 +692,7 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
691
692
  res = await tool.execute(pendingAction.toolCallId, args, prepared.abortController.signal);
692
693
  }
693
694
  catch (err) {
694
- const execError = `Error: ${err instanceof Error ? err.message : String(err)}`;
695
+ const execError = `Error: ${thrownText(err)}`;
695
696
  const marks = (() => {
696
697
  if (err === null || typeof err !== "object")
697
698
  return undefined;
@@ -9,6 +9,7 @@ import { buildWorkingFileAttachments, centerAdoptionOption, contextInstructionFi
9
9
  import { gitRestateOption } from "./git-leg-delivery.js";
10
10
  import { COMPACTION_FREED_EPSILON, COMPACTION_REGROWTH_FACTOR, MAX_CONSECUTIVE_COMPACTION_FAILURES } from "./compaction-knobs.js";
11
11
  import { compactionHookOptions, recordCompactionReuse, seamCCompactionOptions } from "./compaction-seams.js";
12
+ import { asThrownError, thrownText } from "../thrown-value.js";
12
13
  export function runRecoveryLanes(input) {
13
14
  const { spec, prepared, queue, rs, ident, compactionBrain, compactionBreaker, windowSafetyOptions, runner } = input;
14
15
  const runForcedCompactionPass = async (lane, turnSignal) => {
@@ -108,8 +109,8 @@ export function runRecoveryLanes(input) {
108
109
  return false;
109
110
  }
110
111
  compactionBreaker.failures += 1;
111
- runner.deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "compaction", sessionId: prepared.sessionId });
112
- const msg = String(err instanceof Error ? err.message : err);
112
+ runner.deps.onError?.(asThrownError(err), { phase: "compaction", sessionId: prepared.sessionId });
113
+ const msg = thrownText(err);
113
114
  queue.push({ type: "compaction_outcome", outcome: "failed", trigger: "forced", reason: msg.length > 512 ? `${msg.slice(0, 512)}…` : msg, ...ident() });
114
115
  return false;
115
116
  }
@@ -20,6 +20,7 @@ import { generatePromptSuggestions } from "./prompt-suggestions.js";
20
20
  import { settleTeardownLeg } from "./teardown-bounded.js";
21
21
  import { autoRunConsolidationFromRecommendation, autoRunOnRecommendationEffective, scopeHasUnconsumedRecommendation } from "./memory-consolidation-driver.js";
22
22
  import { amendTerminal, terminalProjection } from "./terminal-projection.js";
23
+ import { asThrownError } from "../thrown-value.js";
23
24
  export async function runSettleAndTeardown(input) {
24
25
  const { spec, queue, prepared, resume, internals, rs, stats, ident, parentToolCallId, subagentName, loopLatch, timeout, ownCommittedTailRef, emitDelegationLifecycle, taskIdRef, manualCompactRef, drainManualCompact, final, threw, abortedLive, userInterruptedLive, answerSettled, strandedHumanAnswers, reasoningResolution, comp, owedUserInput, setResult, onSuggestions, onSuspend, runner, sessions } = input;
25
26
  try {
@@ -204,7 +205,7 @@ export async function runSettleAndTeardown(input) {
204
205
  }
205
206
  catch (err) {
206
207
  try {
207
- runner.deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "hook", sessionId: prepared.sessionId });
208
+ runner.deps.onError?.(asThrownError(err), { phase: "hook", sessionId: prepared.sessionId });
208
209
  }
209
210
  catch {
210
211
  }
@@ -1,5 +1,6 @@
1
1
  import { openSystemReminder } from "../reminder-mint.js";
2
2
  import { formatHookFeedback, hookSeatExpiredError, runHookSeat } from "../hooks.js";
3
+ import { asThrownError } from "../thrown-value.js";
3
4
  const STOP_HOOK_BLOCK_CAP = 8;
4
5
  export function runStopAndFinalVerify(input) {
5
6
  const { spec, prepared, queue, rs, stats, ident, walltimeMonotonicDeadline, runner } = input;
@@ -120,7 +121,7 @@ export function runStopAndFinalVerify(input) {
120
121
  result = stopSeat.value;
121
122
  }
122
123
  catch (err) {
123
- runner.deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "hook", sessionId: prepared.sessionId });
124
+ runner.deps.onError?.(asThrownError(err), { phase: "hook", sessionId: prepared.sessionId });
124
125
  return [];
125
126
  }
126
127
  const messages = [];
@@ -6,6 +6,7 @@ import { emitTrace } from "../trace.js";
6
6
  import { resolveMaxTurns } from "./clock-and-limits.js";
7
7
  import { resolveOutputRetries } from "./synthetic-tools.js";
8
8
  import { cacheFamilyOf } from "./usage-accounting.js";
9
+ import { asThrownError } from "../thrown-value.js";
9
10
  export function runTelemetryAndBudgetSeats(input) {
10
11
  const { spec, prepared, resume, stats, taskIdRef, entryTracer, modelCatalog, runSourceTaskId, rs, runner, sessions } = input;
11
12
  prepared.liveSpendRef.get = () => ({ costMicroUsd: stats.costMicroUsd, tokens: stats.tokens, turns: stats.turns, walltimeMs: Math.round(performance.now() - rs.telemetry.taskStartMonotonic) });
@@ -66,7 +67,7 @@ export function runTelemetryAndBudgetSeats(input) {
66
67
  rs.telemetry.taskStartMonotonic = performance.now();
67
68
  const discloseNoteTaskRunFailure = (err) => {
68
69
  try {
69
- runner.deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "config", sessionId: prepared.sessionId });
70
+ runner.deps.onError?.(asThrownError(err), { phase: "config", sessionId: prepared.sessionId });
70
71
  }
71
72
  catch {
72
73
  }
@@ -10,6 +10,7 @@ import { compactionHookOptions, recordCompactionReuse, seamCCompactionOptions }
10
10
  import { gitRestateOption } from "./git-leg-delivery.js";
11
11
  import { MAX_CONSECUTIVE_COMPACTION_FAILURES } from "./compaction-knobs.js";
12
12
  import { reconciledToolEndBody } from "./tool-end-body.js";
13
+ import { asThrownError, thrownText } from "../thrown-value.js";
13
14
  export async function runTerminalAdoption(input) {
14
15
  const { spec, queue, prepared, rs, stats, ident, emitCommitted, startedToolCallIds, toolLabels, timeout, compactionBrain, compactionBreaker, windowSafetyOptions, undrainedUserAtEnd, userInputLostAtEnd, final, abortedLive, userInterruptedLive, runner, sessions, next } = input;
15
16
  let { threw } = input;
@@ -48,7 +49,7 @@ export async function runTerminalAdoption(input) {
48
49
  reconcileComplete = true;
49
50
  }
50
51
  catch (reconcileErr) {
51
- runner.deps.onError?.(reconcileErr instanceof Error ? reconcileErr : new Error(String(reconcileErr)), {
52
+ runner.deps.onError?.(asThrownError(reconcileErr), {
52
53
  phase: "interrupt-reconcile",
53
54
  sessionId: prepared.sessionId,
54
55
  });
@@ -57,7 +58,7 @@ export async function runTerminalAdoption(input) {
57
58
  await prepared.harness.flushQueuedSessionWrites();
58
59
  }
59
60
  catch (flushErr) {
60
- runner.deps.onError?.(flushErr instanceof Error ? flushErr : new Error(String(flushErr)), {
61
+ runner.deps.onError?.(asThrownError(flushErr), {
61
62
  phase: "interrupt-reconcile",
62
63
  sessionId: prepared.sessionId,
63
64
  });
@@ -69,7 +70,7 @@ export async function runTerminalAdoption(input) {
69
70
  emitCommitted(entryId, "user");
70
71
  }
71
72
  catch (markerErr) {
72
- runner.deps.onError?.(markerErr instanceof Error ? markerErr : new Error(String(markerErr)), {
73
+ runner.deps.onError?.(asThrownError(markerErr), {
73
74
  phase: "interrupt-reconcile",
74
75
  sessionId: prepared.sessionId,
75
76
  });
@@ -96,7 +97,7 @@ export async function runTerminalAdoption(input) {
96
97
  carriedContinuation += 1;
97
98
  }
98
99
  catch (parkErr) {
99
- runner.deps.onError?.(parkErr instanceof Error ? parkErr : new Error(String(parkErr)), {
100
+ runner.deps.onError?.(asThrownError(parkErr), {
100
101
  phase: "config",
101
102
  sessionId: prepared.sessionId,
102
103
  });
@@ -161,7 +162,7 @@ async function finish(spec, prepared, opts, runner, sessions) {
161
162
  comp = finishComp;
162
163
  }
163
164
  catch (err) {
164
- const failMsg = String(err instanceof Error ? err.message : err);
165
+ const failMsg = thrownText(err);
165
166
  const failReason = failMsg.length > 512 ? `${failMsg.slice(0, 512)}…` : failMsg;
166
167
  emitTrace(opts?.telemetry?.tracer ?? spec.tracer ?? runner.deps.tracer, () => ({
167
168
  kind: "compaction.failed",
@@ -17,6 +17,7 @@ import { gitRestateOption } from "./git-leg-delivery.js";
17
17
  import { COMPACTION_FREED_EPSILON, COMPACTION_REGROWTH_FACTOR, MAX_CONSECUTIVE_COMPACTION_FAILURES } from "./compaction-knobs.js";
18
18
  import { compactionHookOptions, recordCompactionReuse, seamCCompactionOptions } from "./compaction-seams.js";
19
19
  import { contextUsageSections } from "../../prompt-assembly/section-usage.js";
20
+ import { asThrownError, thrownText } from "../thrown-value.js";
20
21
  const BATCH_CONTEXT_MIN_KEEP_BYTES = 160;
21
22
  const BATCH_TRUNCATION_MARKER = "\n…[truncated]";
22
23
  export function createTurnBoundary(input) {
@@ -49,7 +50,7 @@ export function createTurnBoundary(input) {
49
50
  if (answer === GOVERNANCE_READ_STALLED) {
50
51
  void windowRead.catch((lateErr) => {
51
52
  try {
52
- runnerHooks.onError?.(lateErr instanceof Error ? lateErr : new Error(String(lateErr)), { phase: "config", sessionId: prepared.sessionId });
53
+ runnerHooks.onError?.(asThrownError(lateErr), { phase: "config", sessionId: prepared.sessionId });
53
54
  }
54
55
  catch {
55
56
  }
@@ -71,7 +72,7 @@ export function createTurnBoundary(input) {
71
72
  }
72
73
  }
73
74
  catch (govErr) {
74
- rs.limits.platformTerminal = govErr instanceof Error ? govErr : new Error(String(govErr));
75
+ rs.limits.platformTerminal = asThrownError(govErr);
75
76
  void prepared.harness.abort();
76
77
  prepared.abortController.abort();
77
78
  return undefined;
@@ -479,7 +480,7 @@ export function createTurnBoundary(input) {
479
480
  }
480
481
  catch (err) {
481
482
  try {
482
- runnerHooks.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "hook", sessionId: prepared.sessionId });
483
+ runnerHooks.onError?.(asThrownError(err), { phase: "hook", sessionId: prepared.sessionId });
483
484
  }
484
485
  catch {
485
486
  }
@@ -689,7 +690,7 @@ export function createTurnBoundary(input) {
689
690
  else if (!prepared.abortController.signal.aborted) {
690
691
  compactionBreaker.failures += 1;
691
692
  runnerHooks.onError?.(err, { phase: "compaction", sessionId: prepared.sessionId });
692
- const msg = String(err instanceof Error ? err.message : err);
693
+ const msg = thrownText(err);
693
694
  const failReason = msg.length > 512 ? `${msg.slice(0, 512)}…` : msg;
694
695
  emitTrace(rs.telemetry.tracer, () => ({
695
696
  kind: "compaction.failed",
@@ -56,6 +56,7 @@ import { runCompactionMachinery } from "./run-compaction-machinery.js";
56
56
  import { runStopAndFinalVerify } from "./run-stop-and-final-verify.js";
57
57
  import { runRecoveryLanes } from "./run-recovery-lanes.js";
58
58
  import { runGitLane } from "./run-git-lane.js";
59
+ import { thrownText } from "../thrown-value.js";
59
60
  export class Runner {
60
61
  deps;
61
62
  sessions;
@@ -83,7 +84,7 @@ export class Runner {
83
84
  version: 1,
84
85
  sessionId: context.sessionId,
85
86
  phase: context.phase,
86
- reason: (sinkErr instanceof Error ? sinkErr.message : String(sinkErr)).slice(0, 256),
87
+ reason: (thrownText(sinkErr)).slice(0, 256),
87
88
  ts: Date.now(),
88
89
  }));
89
90
  }
@@ -6,6 +6,7 @@ import { createSafeNotifier } from "../safe-notify.js";
6
6
  import { settleTeardownLeg } from "./teardown-bounded.js";
7
7
  import { emitTrace } from "../trace.js";
8
8
  import { deliverDelegationLifecycle } from "../types.js";
9
+ import { asThrownError, thrownText } from "../thrown-value.js";
9
10
  export function streamSettleBackstop(input) {
10
11
  const { spec, resume, queue, taskIdRef, entryTracer, runStartedAt, live, runner, sessions, locallyClaimedTokens, parentConstraintRegistry, suspendedEnvReaps } = input;
11
12
  const onRunRejected = async (err) => {
@@ -21,8 +22,8 @@ export function streamSettleBackstop(input) {
21
22
  }
22
23
  catch (reopenErr) {
23
24
  parentConstraintRegistry.delete(resume.cp.token);
24
- const original = err instanceof Error ? err : new Error(String(err));
25
- const reopenMsg = reopenErr instanceof Error ? reopenErr.message : String(reopenErr);
25
+ const original = asThrownError(err);
26
+ const reopenMsg = thrownText(reopenErr);
26
27
  const definitive = errorCodeOf(reopenErr) === "checkpoint.reopen_failed";
27
28
  reopenStateUnknown = !definitive;
28
29
  err = Object.assign(new Error(definitive
@@ -47,7 +48,7 @@ export function streamSettleBackstop(input) {
47
48
  }
48
49
  if (live.resultValue !== undefined) {
49
50
  try {
50
- runner.deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "config", sessionId: live.resultValue.sessionId });
51
+ runner.deps.onError?.(asThrownError(err), { phase: "config", sessionId: live.resultValue.sessionId });
51
52
  }
52
53
  catch {
53
54
  }
@@ -68,7 +69,7 @@ export function streamSettleBackstop(input) {
68
69
  taskId: taskIdRef.current ?? "unknown",
69
70
  sessionId: taskIdRef.sessionId ?? "unknown",
70
71
  ...(taskIdRef.runId !== undefined ? { runId: taskIdRef.runId } : {}),
71
- terminal: { kind: "failed", ...(code !== undefined ? { code } : {}), message: err instanceof Error ? err.message : String(err) },
72
+ terminal: { kind: "failed", ...(code !== undefined ? { code } : {}), message: thrownText(err) },
72
73
  result: "",
73
74
  ...(remoteEnvFailure !== undefined ? { remoteEnvFailures: remoteEnvFailure } : {}),
74
75
  ...(taskIdRef.effectiveMemoryScopes !== undefined ? { effectiveMemoryScopes: taskIdRef.effectiveMemoryScopes } : {}),
@@ -7,6 +7,7 @@ import { isSystemInjectionPriority, SYSTEM_INJECTION_PRIORITIES } from "../task-
7
7
  import { deliverEngineNotice } from "../types.js";
8
8
  import { inlineUntrusted, sanitizeUntrustedText } from "../untrusted-text.js";
9
9
  import { nextHumanInputSeq, sameAcceptedSteerInput } from "./steer-admission.js";
10
+ import { asThrownError } from "../thrown-value.js";
10
11
  export function streamSteerVerb(input) {
11
12
  const { spec, internals, queue, acceptedSteerInputs, live, ready, orTimeout, readyTimeoutMs: READY_TIMEOUT_MS, steeringError, runner } = input;
12
13
  let steerChain = Promise.resolve();
@@ -111,7 +112,7 @@ export function streamSteerVerb(input) {
111
112
  catch (hookErr) {
112
113
  if (hookErr instanceof Error && hookErr.code === "steering.blocked_by_hook")
113
114
  throw hookErr;
114
- const err = hookErr instanceof Error ? hookErr : new Error(String(hookErr));
115
+ const err = asThrownError(hookErr);
115
116
  try {
116
117
  runner.deps.onError?.(err, { phase: "hook", sessionId: h.sessionId });
117
118
  }
@@ -1,3 +1,4 @@
1
+ import { thrownText } from "../thrown-value.js";
1
2
  const STRICT_KEYWORDS = new Set([
2
3
  "$schema",
3
4
  "type",
@@ -298,6 +299,6 @@ function compileUncached(schema) {
298
299
  return { modelSchema: schema, strict: false, fallbackReason: derived.reason };
299
300
  }
300
301
  catch (err) {
301
- return { modelSchema: schema, strict: false, fallbackReason: `derivation_error: ${err instanceof Error ? err.message : String(err)}` };
302
+ return { modelSchema: schema, strict: false, fallbackReason: `derivation_error: ${thrownText(err)}` };
302
303
  }
303
304
  }
@@ -1,3 +1,4 @@
1
+ import { asThrownError } from "../thrown-value.js";
1
2
  export const TEARDOWN_LEG_MAX_MS = 15_000;
2
3
  let teardownLegBudgetMs = TEARDOWN_LEG_MAX_MS;
3
4
  export function setTeardownLegBudgetForTests(ms) {
@@ -24,7 +25,7 @@ export async function settleTeardownLeg(leg, label, report) {
24
25
  }
25
26
  catch (e) {
26
27
  try {
27
- report?.(e instanceof Error ? e : new Error(String(e)));
28
+ report?.(asThrownError(e));
28
29
  }
29
30
  catch {
30
31
  }
@@ -1,3 +1,4 @@
1
+ import { thrownText } from "./thrown-value.js";
1
2
  function containedError(thrown) {
2
3
  try {
3
4
  if (thrown instanceof Error && typeof thrown.message === "string")
@@ -13,7 +14,7 @@ export function safeErrorMessage(error) {
13
14
  const m = error?.message;
14
15
  if (typeof m === "string")
15
16
  return m;
16
- return String(error);
17
+ return thrownText(error);
17
18
  }
18
19
  catch {
19
20
  return "a failure whose message could not be read";
@@ -2,6 +2,7 @@ import { readFileSync, readdirSync, statSync } from "node:fs";
2
2
  import { isAbsolute, join, relative } from "node:path";
3
3
  import { physicalPathOf } from "./physical-path.js";
4
4
  import { isSkillSpecifierEnforced, parseSkillToolEntry } from "./skill-tool-specifier.js";
5
+ import { thrownText } from "./thrown-value.js";
5
6
  const SKILL_FILE = "SKILL.md";
6
7
  const RESOURCE_DIRS = ["assets", "references", "scripts"];
7
8
  const NAME_MAX_CHARS = 64;
@@ -282,7 +283,7 @@ function isDecodableText(bytes) {
282
283
  return Buffer.byteLength(decoded, "utf8") === bytes.byteLength;
283
284
  }
284
285
  function errText(err) {
285
- return err instanceof Error ? err.message : String(err);
286
+ return thrownText(err);
286
287
  }
287
288
  const ALL_TOOLS_WILDCARD = "*";
288
289
  function splitToolNames(declared) {
@@ -1,4 +1,5 @@
1
1
  import { termSet } from "./memory-vector.js";
2
+ import { thrownText } from "./thrown-value.js";
2
3
  function invalidKnob(message, code) {
3
4
  const e = new Error(message);
4
5
  e.code = code;
@@ -244,7 +245,7 @@ export async function seedStrategies(store, scope, entries) {
244
245
  await store.save(s);
245
246
  }
246
247
  catch (err) {
247
- return { written, failedAt: { id: s.id, error: String(err.message ?? err) } };
248
+ return { written, failedAt: { id: s.id, error: thrownText(err) } };
248
249
  }
249
250
  written++;
250
251
  }
@@ -7,6 +7,7 @@ import { delimitUntrusted } from "./untrusted-text.js";
7
7
  import { boundedRedactedSummary } from "./untrusted-egress.js";
8
8
  import { mintCompletionId, commitCompletionIdIfEmpty, clipTaskOutput, assertOwnership, sleepPollStep, alreadyTerminalStopNote, canAccess, normalizeAgentName, closestName, DURABLE_AGENT_HEARTBEAT_MS, DURABLE_AGENT_HANDLE_RE, BG_AGENT_REAP_STOP_ERROR, } from "./task-registry-shared.js";
9
9
  import { buildToolResultRef, OFFLOAD_TOOL_NAME, toolResultProvenanceOf } from "./tool-result-store.js";
10
+ import { thrownLabel } from "./thrown-value.js";
10
11
  export function activeDelegationHandlesLane(core, scope, rootSessionId) {
11
12
  const out = [];
12
13
  for (const h of core.handles.values()) {
@@ -140,7 +141,7 @@ export function durableAgentWriteLane(handle, patch, clear) {
140
141
  poison("handle collision (foreign durable row left untouched)");
141
142
  return;
142
143
  }
143
- shutdownDebug(`durable-agents write failed for ${lane.record.handle} (attempt ${attempt + 1}/3)`, { error: String(e) });
144
+ shutdownDebug(`durable-agents write failed for ${lane.record.handle} (attempt ${attempt + 1}/3)`, { error: thrownLabel(e) });
144
145
  }
145
146
  }
146
147
  lane.flushFailed = true;
@@ -1,6 +1,7 @@
1
1
  import { delimitUntrusted } from "./untrusted-text.js";
2
2
  import { assertOwnership, defaultMonitorTimers, MONITOR_MAX_TIMEOUT_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_BATCH_WINDOW_MS, MONITOR_MAX_BATCHES_PER_MINUTE, MONITOR_STORM_BURST, MONITOR_STORM_KILL_AFTER_MS, MONITOR_LINE_BUF_CAP, MONITOR_SPILL_CAP_CHARS, TASK_OUTPUT_MAX_CHARS, mintCompletionId, clipMonitorEvent, clipMonitorLine, terminalTaskSummary, accountDroppedBytes, renderSpoolBody, rollSpoolText, statusFromBackground, droppedGapNote, firstDropNote, alreadyTerminalStopNote, clipTaskOutput, sleepPollStep, } from "./task-registry-shared.js";
3
3
  import { buildToolResultRef, OFFLOAD_TOOL_NAME, toolResultProvenanceOf } from "./tool-result-store.js";
4
+ import { thrownText } from "./thrown-value.js";
4
5
  export function registerMonitorLane(core, input) {
5
6
  assertOwnership(input, "registerMonitor");
6
7
  const id = core.mintTaskId("monitor");
@@ -289,7 +290,7 @@ export function startMonitorWatcherLane(core, id) {
289
290
  if (++pollFailures <= MAX_RETRYABLE_POLL_FAILURES)
290
291
  return;
291
292
  handle.status = "failed";
292
- terminal("failed", `monitor watcher crashed (${e instanceof Error ? e.message : String(e)}); watch ended.${pendingSuppressionNote()}`, pendingFinalLines([]));
293
+ terminal("failed", `monitor watcher crashed (${thrownText(e)}); watch ended.${pendingSuppressionNote()}`, pendingFinalLines([]));
293
294
  }
294
295
  finally {
295
296
  ticking = false;
@@ -1,5 +1,6 @@
1
1
  import { boundedRedactedSummary } from "./untrusted-egress.js";
2
2
  import { delimitUntrusted } from "./untrusted-text.js";
3
+ import { thrownText } from "./thrown-value.js";
3
4
  import { assertOwnership, canAccessWorkflowRun, formatWorkflowRun, sleepPollStep, } from "./task-registry-shared.js";
4
5
  export function registerWorkflowLane(core, input) {
5
6
  assertOwnership(input, "registerWorkflow");
@@ -37,7 +38,7 @@ export function registerWorkflowLane(core, input) {
37
38
  }, (err) => {
38
39
  if (handle.status !== "cancelled")
39
40
  handle.status = "failed";
40
- handle.error = boundedRedactedSummary(err instanceof Error ? err.message : String(err), 500);
41
+ handle.error = boundedRedactedSummary(thrownText(err), 500);
41
42
  const rejectedRun = err !== null && (typeof err === "object" || typeof err === "function")
42
43
  ? err.workflowRun
43
44
  : undefined;
@@ -13,6 +13,7 @@ export { normalizeAgentName, DURABLE_AGENT_HEARTBEAT_MS, DURABLE_AGENT_HANDLE_RE
13
13
  import { TASK_OUTPUT_TOOL_NAME, TASK_STOP_TOOL_NAME, TASK_OUTPUT_MISSING_ID_MESSAGE, TASK_STOP_MISSING_ID_MESSAGE, TASK_STOP_PARAMS, resolveTaskIdArg, REGISTRY_TASK_TOOL_CAPS, composeTaskOutputDescription, composeTaskOutputParams, composeTaskStopDescription, } from "./task-tool-shape.js";
14
14
  import { durableAgentArmedLane, durableAgentRowProbeLane, beginDurableClaimLane, endDurableClaimLane, reapDurableAgentsLane, noteBackgroundAgentActivityLane, reapStaleSessionBackgroundAgentsLane, releaseDurableTranscriptAnchorLane, bindBackgroundAgentSessionLane, registerBackgroundAgentLane, recordBackgroundAgentOrgAdmissionLane, parkBackgroundAgentLane, reconcileParkedAgentsLane, claimParkedAgentLane, rollbackParkedClaimLane, consumeParkedFlipLane, finalizeParkedResumeLane, settleBackgroundAgentLane, abortBackgroundAgentsForOwnerLane, serveDurableAgentRowLane, resolveBackgroundAgentByNameLane, backgroundAgentCycleSeqLane, activeDelegationHandlesLane, markRetainedContinuationLane, reviveBackgroundAgentLane, settleRevivedAgentLane, unmarkRetainedContinuationLane, attachAgentNotifyLane, deliverToRunningAgentLane, runningBackgroundAgentLabelsLane, runningAgentFooterLane, notFoundRunningAgentsTail, pollBackgroundAgentLane, stopBackgroundAgentLane, } from "./task-registry-agent.js";
15
15
  import { toolFace } from "./tool-catalog-entries.js";
16
+ import { thrownText } from "./thrown-value.js";
16
17
  export { canAccessWorkflowRun, clipTaskOutput, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE };
17
18
  const BLOCK_DEFAULT_TIMEOUT_MS = 30_000;
18
19
  const BLOCK_MAX_TIMEOUT_MS = 600_000;
@@ -498,7 +499,7 @@ export class TaskRegistry {
498
499
  }
499
500
  }
500
501
  catch (err) {
501
- shutdownDebug("session reap: kill threw", { kind, id: handle.id, shellId: handle.shellId, error: err instanceof Error ? err.message : String(err) });
502
+ shutdownDebug("session reap: kill threw", { kind, id: handle.id, shellId: handle.shellId, error: thrownText(err) });
502
503
  }
503
504
  }
504
505
  reapSessionBackground(sessionId, scope) {
@@ -764,7 +765,7 @@ export class TaskRegistry {
764
765
  ...(handle.toolUseId !== undefined ? { toolUseId: handle.toolUseId } : {}),
765
766
  ...(handle.outputFile !== undefined ? { output_file: handle.outputFile } : {}),
766
767
  status: "failed",
767
- summary: `${terminalTaskSummary("bash", (handle.description ?? "background command").slice(0, 200), "failed")} — lost its background process (poll failed: ${e instanceof Error ? e.message : String(e)}); no further output will arrive.${bashMirrorGapNote(handle)}`,
768
+ summary: `${terminalTaskSummary("bash", (handle.description ?? "background command").slice(0, 200), "failed")} — lost its background process (poll failed: ${thrownText(e)}); no further output will arrive.${bashMirrorGapNote(handle)}`,
768
769
  ...(crashedResult.length > 0 ? { result: crashedResult } : {}),
769
770
  ...(handle.completionId !== undefined ? { completionId: handle.completionId } : {}),
770
771
  }));
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Turning a value that was THROWN at us into text — the ONE rule, for the whole engine.
3
+ *
4
+ * The idiom this replaces is `err instanceof Error ? err.message : String(err)` (and its template-literal
5
+ * twin, `` `${err}` ``). Both spell a PARTIAL function on the non-Error arm: `String` calls the value's own
6
+ * `toString` / `Symbol.toPrimitive`, so it throws on a value that has neither (a null-prototype object) and
7
+ * on one whose own hook throws. The thrower is not ours — a deployment hook, a plugin callback, a model-
8
+ * supplied tool body may reject with any value at all — so the rendering step was the one step that could
9
+ * destroy the report it exists to produce. Where the render sat inside a promise rejection handler, the
10
+ * resulting `TypeError` was an unhandled rejection and took the whole process down: a caller's choice of
11
+ * rejection value decided whether the engine stayed alive.
12
+ *
13
+ * Totality is therefore the contract, and it is met the same way the engine's structural describer already
14
+ * meets it: the value is never asked to say what it is. Three arms, in this order, chosen so that the
15
+ * dominant shapes keep their EXACT previous bytes and only the shapes that used to be useless or fatal move:
16
+ * - a thrown STRING is its own message (a bare `throw "…"`), returned verbatim — the describer would quote
17
+ * it, which is right when rejecting a config value and wrong when relaying a message someone threw;
18
+ * - an ERROR hands over `message` verbatim — no cap, no one-lining, no quoting. This is the arm nearly all
19
+ * production traffic takes, and the text on it is byte-for-byte what the old idiom produced;
20
+ * - anything else is DESCRIBED structurally, by the one describer, which guards every read it makes.
21
+ *
22
+ * Empty is a legitimate answer: `new Error("")` returns `""`, exactly as `err.message` did, because callers
23
+ * fold that into their own wording (`… || "unknown"`). Two callers want something else and have their own
24
+ * face for it: {@link thrownLabel} when the previous text was `String(err)` (which names the error CLASS),
25
+ * and `describeThrown` when the text must be non-empty and contained for a model-facing frame.
26
+ */
27
+ export declare function thrownText(err: unknown): string;
28
+ /**
29
+ * The LABELLED face of the same rule: what `String(err)` used to produce, made total.
30
+ *
31
+ * `String` on an Error does not yield its message — it yields `"TypeError: boom"`, the class AND the message
32
+ * (and just `"TypeError"` when the message is empty). Sites that spelled a bare `String(err)` were therefore
33
+ * saying something the message-only face cannot say, and at least one of them is load-bearing rather than
34
+ * decorative: a stuck-detector keyed its signature on this text, so collapsing two distinct error classes
35
+ * with equal messages into one string would have changed when a run gets abandoned. Preserving those bytes
36
+ * is the whole reason this face exists as well as {@link thrownText}.
37
+ *
38
+ * Fidelity is obtained by calling `String` itself rather than reassembling `name` and `message` by hand —
39
+ * the spelling rules for an empty name or an empty message live in `Error.prototype.toString`, and a second
40
+ * copy of them here would be a second rule to keep in step. It is called INSIDE the guard, so a subclass
41
+ * whose own `toString`/`name`/`message` misbehaves falls back to the structural description instead of
42
+ * escaping. Non-Errors never reach `String` at all; they go to {@link thrownText}, which is the fix.
43
+ */
44
+ export declare function thrownLabel(err: unknown): string;
45
+ /**
46
+ * The same rule for callers that need an `Error` OBJECT rather than text — the normalizing half of
47
+ * `err instanceof Error ? err : new Error(String(err))`, which carries the identical defect on the identical
48
+ * arm and appears wherever an unknown rejection has to be handed to a seat typed `Error` (a deployment's
49
+ * error lane, a promise `reject`, a report callback).
50
+ *
51
+ * An `Error` of THIS realm is passed through by IDENTITY — same object, same stack, same own properties — so
52
+ * the arm that carries nearly all traffic is unchanged in every observable way, not merely in its message.
53
+ * A cross-realm Error is WRAPPED rather than passed through, which is what the old idiom did too: the seat's
54
+ * type says `Error`, and an object that fails `instanceof` here would break the first consumer that trusts
55
+ * it. Its message survives the wrap, because the new message is the {@link thrownLabel} of the original —
56
+ * the same text `String(err)` produced.
57
+ *
58
+ * The original value is deliberately NOT attached as `cause`: `cause` chains are walked elsewhere to
59
+ * attribute error codes, so attaching one here would let an arbitrary thrown object start supplying codes
60
+ * to readers that never saw it before. Preserving it is a worthwhile change on its own terms and belongs
61
+ * with those readers, not smuggled in by a rendering fix.
62
+ */
63
+ export declare function asThrownError(err: unknown): Error;
64
+ /**
65
+ * Read ONE member of an untrusted value, once, and hand back an inert snapshot.
66
+ *
67
+ * Inspecting a thrown value is attacker-reachable in the same way coercing it is: any property can be an
68
+ * accessor that throws, or one that answers differently on a second read. Sites that need a member — a
69
+ * shell error's `exitCode`, a refusal's `code`, a transport error's `cause` — were each wrapping their own
70
+ * `try`, and a guard written per SITE is coarse: one hostile member took the readable ones down with it,
71
+ * so a report lost an exit code it had already read because a later `stdout` threw.
72
+ *
73
+ * One guarded read, per member, is the finer and the smaller rule: the caller keeps what it could read and
74
+ * loses only what it could not, and nothing it holds afterwards can run the value's code again. The result
75
+ * is `undefined` for BOTH "absent" and "unreadable" — deliberately, because a caller that must tell those
76
+ * apart is asking a question an untrusted value is not obliged to answer; what it does instead is fall back
77
+ * to describing the value, which {@link thrownText} already does totally.
78
+ */
79
+ export declare function readMember(value: unknown, key: string): unknown;
@@ -0,0 +1,56 @@
1
+ import { describeRejectedValue } from "./tool-search-setting.js";
2
+ function isErrorLike(value) {
3
+ try {
4
+ if (value instanceof Error)
5
+ return true;
6
+ return Object.prototype.toString.call(value) === "[object Error]";
7
+ }
8
+ catch {
9
+ return false;
10
+ }
11
+ }
12
+ export function thrownText(err) {
13
+ try {
14
+ if (typeof err === "string")
15
+ return err;
16
+ if (isErrorLike(err)) {
17
+ const message = err.message;
18
+ if (typeof message === "string")
19
+ return message;
20
+ }
21
+ }
22
+ catch {
23
+ }
24
+ return describeRejectedValue(err);
25
+ }
26
+ export function thrownLabel(err) {
27
+ try {
28
+ if (isErrorLike(err)) {
29
+ const label = String(err);
30
+ if (label !== "")
31
+ return label;
32
+ }
33
+ }
34
+ catch {
35
+ }
36
+ return thrownText(err);
37
+ }
38
+ export function asThrownError(err) {
39
+ try {
40
+ if (err instanceof Error)
41
+ return err;
42
+ }
43
+ catch {
44
+ }
45
+ return new Error(thrownLabel(err));
46
+ }
47
+ export function readMember(value, key) {
48
+ try {
49
+ if (value === null || value === undefined)
50
+ return undefined;
51
+ return value[key];
52
+ }
53
+ catch {
54
+ return undefined;
55
+ }
56
+ }