@sema-agent/client-core 0.84.0 → 0.85.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 (101) hide show
  1. package/CHANGELOG.md +247 -0
  2. package/README.md +27 -13
  3. package/dist/abortableSleep.d.ts +10 -0
  4. package/dist/abortableSleep.js +37 -0
  5. package/dist/adapt/arms.js +1 -1
  6. package/dist/adapt.d.ts +1 -1
  7. package/dist/adapt.js +1 -1
  8. package/dist/adapter/downstream/terminalToSdkResult.d.ts +1 -0
  9. package/dist/adapter/downstream/terminalToSdkResult.js +19 -10
  10. package/dist/adapter/runStream.js +6 -2
  11. package/dist/agentSession/engineSessionBackgroundStop.d.ts +50 -0
  12. package/dist/agentSession/engineSessionBackgroundStop.js +291 -0
  13. package/dist/agentsWireCaps.d.ts +2 -1
  14. package/dist/agentsWireCaps.js +8 -0
  15. package/dist/cloudConfigWireCaps.js +2 -1
  16. package/dist/corruptSession.d.ts +3 -0
  17. package/dist/corruptSession.js +29 -0
  18. package/dist/corruptSessionCopy.d.ts +1 -0
  19. package/dist/corruptSessionCopy.js +4 -0
  20. package/dist/decideFailureNote.d.ts +2 -1
  21. package/dist/decideFailureNote.js +8 -3
  22. package/dist/decideReceipt.d.ts +6 -0
  23. package/dist/decideReceipt.js +30 -1
  24. package/dist/detachWire.d.ts +1 -0
  25. package/dist/detachWire.js +13 -5
  26. package/dist/displayUntrusted.js +114 -18
  27. package/dist/effortWire.d.ts +2 -1
  28. package/dist/effortWire.js +2 -4
  29. package/dist/engineErrorCodes.d.ts +11 -0
  30. package/dist/engineErrorCodes.js +32 -0
  31. package/dist/engineNoticeCodes.d.ts +39 -4
  32. package/dist/engineNoticeCodes.js +117 -161
  33. package/dist/engineWireFor.d.ts +43 -0
  34. package/dist/engineWireFor.js +399 -0
  35. package/dist/engineWireSdk.d.ts +6 -0
  36. package/dist/fileHistoryCaptureCapability.d.ts +4 -1
  37. package/dist/fileHistoryCaptureCapability.js +43 -9
  38. package/dist/gateVocabulary.d.ts +1 -2
  39. package/dist/gateVocabulary.js +1 -22
  40. package/dist/generated/engineNoticeTables.d.ts +3 -0
  41. package/dist/generated/engineNoticeTables.js +156 -0
  42. package/dist/generated/toolNameTables.d.ts +2 -0
  43. package/dist/generated/toolNameTables.js +43 -0
  44. package/dist/headlessPermissionModeWire.js +2 -4
  45. package/dist/hitl/askGateWire.d.ts +1 -1
  46. package/dist/hitl/askGateWire.js +1 -1
  47. package/dist/hitl/frameRouter.js +4 -2
  48. package/dist/hitl/hitlHostSurface.js +1 -1
  49. package/dist/hitl/parkResolver.d.ts +1 -0
  50. package/dist/hitl/parkResolver.js +11 -3
  51. package/dist/hitl/planReviewWire.d.ts +41 -3
  52. package/dist/hitl/planReviewWire.js +264 -49
  53. package/dist/hitl/rosterMountedNames.d.ts +2 -0
  54. package/dist/hitl/rosterMountedNames.js +38 -0
  55. package/dist/hitl/sessionPolicyDeliverable.d.ts +8 -2
  56. package/dist/hitl/sessionPolicyDeliverable.js +39 -48
  57. package/dist/hitl/sessionPolicyWire.d.ts +40 -0
  58. package/dist/hitl/sessionPolicyWire.js +173 -0
  59. package/dist/hitl/toolApprovalWire.d.ts +4 -2
  60. package/dist/hitl/toolApprovalWire.js +6 -4
  61. package/dist/index.d.ts +10 -3
  62. package/dist/index.js +7 -2
  63. package/dist/liveInitToolFace.js +28 -10
  64. package/dist/permissionWireCaps.d.ts +2 -1
  65. package/dist/permissionWireCaps.js +2 -7
  66. package/dist/request/taskRequest.d.ts +2 -0
  67. package/dist/request/taskRequest.js +18 -1
  68. package/dist/resumeRefusalCopy.d.ts +11 -0
  69. package/dist/resumeRefusalCopy.js +42 -2
  70. package/dist/runTerminal.js +4 -0
  71. package/dist/sandboxWire.js +1 -1
  72. package/dist/sealedKeyCapability.d.ts +17 -0
  73. package/dist/sealedKeyCapability.js +42 -0
  74. package/dist/seatContract.d.ts +2 -1
  75. package/dist/seatContract.js +5 -21
  76. package/dist/subagent/engineCompactWire.d.ts +13 -2
  77. package/dist/subagent/engineCompactWire.js +48 -37
  78. package/dist/subagent/engineDelegatedPrompt.d.ts +9 -1
  79. package/dist/subagent/engineDelegatedPrompt.js +16 -16
  80. package/dist/subagent/engineRowStopGate.d.ts +2 -2
  81. package/dist/subagent/engineRowStopGate.js +4 -4
  82. package/dist/subagent/engineSubagentOutput.d.ts +8 -0
  83. package/dist/subagent/engineSubagentOutput.js +37 -18
  84. package/dist/subagent/engineSubagentResume.d.ts +11 -2
  85. package/dist/subagent/engineSubagentResume.js +28 -14
  86. package/dist/subagent/engineSubagentSteer.d.ts +10 -1
  87. package/dist/subagent/engineSubagentSteer.js +16 -11
  88. package/dist/subagent/engineSubagentTail.d.ts +10 -1
  89. package/dist/subagent/engineSubagentTail.js +35 -17
  90. package/dist/subagent/engineTaskHandleWire.d.ts +13 -0
  91. package/dist/subagent/engineTaskHandleWire.js +41 -20
  92. package/dist/systemReminderTag.d.ts +5 -0
  93. package/dist/systemReminderTag.js +20 -9
  94. package/dist/taskRequestWords.d.ts +5 -0
  95. package/dist/taskRequestWords.js +4 -0
  96. package/dist/wireErrorTriage.d.ts +1 -0
  97. package/dist/wireErrorTriage.js +3 -1
  98. package/dist/wireRefusalCopy.d.ts +10 -0
  99. package/dist/wireRefusalCopy.js +62 -2
  100. package/docs/INTEGRATION-CLIENTS.md +1128 -22
  101. package/package.json +1 -1
@@ -0,0 +1,156 @@
1
+ export const CORE_ENGINE_NOTICE_CODES = Object.freeze([
2
+ "config.autocompact_window_clamped",
3
+ "config.env_timeout_discarded",
4
+ "config.materialize_env_discarded",
5
+ "config.models_swapped",
6
+ "config.context_settings_swapped",
7
+ "config.read_face_swapped",
8
+ "config.read_face_deployment_clamped",
9
+ "config.write_face_swapped",
10
+ "config.write_face_deployment_clamped",
11
+ "config.tool_model_gate_removed",
12
+ "config.tool_model_gate_unknown_class",
13
+ "config.tool_model_gate_env_invalid",
14
+ "config.artifact_host_invalid",
15
+ "config.task_root_not_canonical",
16
+ "config.write_protection_target_view_absent",
17
+ "config.write_protection_unresolved",
18
+ "config.execution_env_capability_invalid",
19
+ "config.tool_card_undeclared",
20
+ "config.tool_face_undeclared",
21
+ "config.tool_face_invalid",
22
+ "config.forward_sink_failed",
23
+ "config.durable_gate_unavailable",
24
+ "config.peer_admission_out_of_range",
25
+ "config.peer_lane_unmounted",
26
+ "config.secret_env_scrubbed",
27
+ "peer.inbound_disposition",
28
+ "peer.held_settled",
29
+ "peer.idle_subscription",
30
+ "classifier.denial_limit",
31
+ "classifier.fallback",
32
+ "classifier.role_defaulted",
33
+ "classifier.contract_broken",
34
+ "checkpoint.execution_outcome_unrecorded",
35
+ "delegation.transcript_integrity",
36
+ "delegation.ask_unresolvable",
37
+ "mcp.injection_dropped",
38
+ "mcp.revocation_probe_failed",
39
+ "mcp.server_redialed",
40
+ "workflow.governance_key_stripped",
41
+ "workflow.agent_option_ignored",
42
+ "memory.session_polluted",
43
+ "memory.harvest_quarantined",
44
+ "memory.delegation_static_mark_waived",
45
+ "memory.content_class_declared",
46
+ "memory.hold_opened",
47
+ "memory.hold_released",
48
+ "memory.hold_disposed",
49
+ "memory.consolidation_recommended",
50
+ "memory.consolidation_committed",
51
+ "memory.consolidation_conflict",
52
+ "memory.consolidation_incomplete",
53
+ "memory.consolidation_refused",
54
+ "memory.consolidation_withheld",
55
+ "memory.restore_withheld",
56
+ "memory.project_scope_absent",
57
+ "route.fallback_to_primary",
58
+ "route.classifier_unroutable",
59
+ "route.base_url_changed_key_unchanged",
60
+ "route.response_model_mismatch",
61
+ "task.user_steer_undrained",
62
+ "task.user_followup_undrained",
63
+ "steering.parked_input_blocked",
64
+ "task.turn_interrupted",
65
+ "task.halt_unconsumed",
66
+ "task.late_approval",
67
+ "task.interrupt_unconsumed",
68
+ "approval.read_root_granted",
69
+ "approval.read_root_grant_rejected",
70
+ "memory.capture_opted_out",
71
+ "memory.capture_optout_unpersisted",
72
+ "skills.listing_truncated",
73
+ "agents.listing_truncated",
74
+ "tool_result.offload_put_failed",
75
+ ]);
76
+ export const CORE_NOTICE_AUDIENCE = Object.freeze({
77
+ "config.autocompact_window_clamped": "operator",
78
+ "config.env_timeout_discarded": "operator",
79
+ "config.materialize_env_discarded": "operator",
80
+ "config.models_swapped": "operator",
81
+ "config.context_settings_swapped": "operator",
82
+ "config.read_face_swapped": "operator",
83
+ "config.read_face_deployment_clamped": "operator",
84
+ "config.write_face_swapped": "operator",
85
+ "config.write_face_deployment_clamped": "operator",
86
+ "config.tool_model_gate_removed": "operator",
87
+ "config.tool_model_gate_unknown_class": "operator",
88
+ "config.tool_model_gate_env_invalid": "operator",
89
+ "config.artifact_host_invalid": "operator",
90
+ "config.task_root_not_canonical": "operator",
91
+ "config.write_protection_target_view_absent": "operator",
92
+ "config.write_protection_unresolved": "operator",
93
+ "config.execution_env_capability_invalid": "operator",
94
+ "config.tool_card_undeclared": "operator",
95
+ "config.tool_face_undeclared": "operator",
96
+ "config.tool_face_invalid": "operator",
97
+ "config.forward_sink_failed": "operator",
98
+ "config.durable_gate_unavailable": "user",
99
+ "config.peer_admission_out_of_range": "operator",
100
+ "config.peer_lane_unmounted": "operator",
101
+ "config.secret_env_scrubbed": "operator",
102
+ "peer.inbound_disposition": "user",
103
+ "peer.held_settled": "user",
104
+ "peer.idle_subscription": "user",
105
+ "classifier.denial_limit": "user",
106
+ "classifier.fallback": "operator",
107
+ "classifier.role_defaulted": "operator",
108
+ "classifier.contract_broken": "operator",
109
+ "checkpoint.execution_outcome_unrecorded": "operator",
110
+ "delegation.transcript_integrity": "operator",
111
+ "delegation.ask_unresolvable": "user",
112
+ "mcp.injection_dropped": "user",
113
+ "mcp.revocation_probe_failed": "operator",
114
+ "mcp.server_redialed": "operator",
115
+ "workflow.governance_key_stripped": "operator",
116
+ "workflow.agent_option_ignored": "operator",
117
+ "memory.session_polluted": "user",
118
+ "memory.harvest_quarantined": "user",
119
+ "memory.delegation_static_mark_waived": "user",
120
+ "memory.content_class_declared": "operator",
121
+ "memory.hold_opened": "user",
122
+ "memory.hold_released": "user",
123
+ "memory.hold_disposed": "user",
124
+ "memory.consolidation_recommended": "operator",
125
+ "memory.consolidation_committed": "operator",
126
+ "memory.consolidation_conflict": "operator",
127
+ "memory.consolidation_incomplete": "operator",
128
+ "memory.consolidation_refused": "operator",
129
+ "memory.consolidation_withheld": "operator",
130
+ "memory.restore_withheld": "operator",
131
+ "memory.project_scope_absent": "operator",
132
+ "route.fallback_to_primary": "operator",
133
+ "route.classifier_unroutable": "operator",
134
+ "route.base_url_changed_key_unchanged": "operator",
135
+ "route.response_model_mismatch": "operator",
136
+ "task.user_steer_undrained": "user",
137
+ "task.user_followup_undrained": "user",
138
+ "steering.parked_input_blocked": "user",
139
+ "task.turn_interrupted": "user",
140
+ "task.halt_unconsumed": "user",
141
+ "task.late_approval": "user",
142
+ "task.interrupt_unconsumed": "user",
143
+ "approval.read_root_granted": "user",
144
+ "approval.read_root_grant_rejected": "user",
145
+ "memory.capture_opted_out": "user",
146
+ "memory.capture_optout_unpersisted": "user",
147
+ "skills.listing_truncated": "operator",
148
+ "agents.listing_truncated": "operator",
149
+ "tool_result.offload_put_failed": "operator",
150
+ });
151
+ export const CORE_MCP_INJECTION_DROP_REASONS = Object.freeze([
152
+ "malformed_entry",
153
+ "name_reserved_by_deployment",
154
+ "gate_closed",
155
+ "over_cap",
156
+ ]);
@@ -0,0 +1,2 @@
1
+ export declare const CORE_PROTOCOL_PREFIXES: readonly ["mcp__", "a2a__"];
2
+ export declare const CORE_RETIRED_TOOL_CURRENT_NAMES: ReadonlyMap<string, string | null>;
@@ -0,0 +1,43 @@
1
+ export const CORE_PROTOCOL_PREFIXES = ["mcp__", "a2a__"];
2
+ export const CORE_RETIRED_TOOL_CURRENT_NAMES = new Map([
3
+ ["read_file", "Read"],
4
+ ["edit_file", "Edit"],
5
+ ["write_file", "Write"],
6
+ ["bash", "Bash"],
7
+ ["bash_readonly", null],
8
+ ["glob", "Glob"],
9
+ ["grep", "Grep"],
10
+ ["web_fetch", "WebFetch"],
11
+ ["tool_search", "ToolSearch"],
12
+ ["skill", "Skill"],
13
+ ["present_plan", "ExitPlanMode"],
14
+ ["enter_plan_mode", "EnterPlanMode"],
15
+ ["spawn_subagent", "Agent"],
16
+ ["CronCancel", "CronDelete"],
17
+ ["lsp", "LSP"],
18
+ ["submit_output", "StructuredOutput"],
19
+ ["repo_map", "RepoMap"],
20
+ ["read_tool_result", "ReadToolResult"],
21
+ ["report_blocked", "ReportBlocked"],
22
+ ["declare_done", "DeclareDone"],
23
+ ["run_workflow", "Workflow"],
24
+ ["RunWorkflow", "Workflow"],
25
+ ["Task", "Agent"],
26
+ ["BashOutput", "TaskOutput"],
27
+ ["AgentOutputTool", "TaskOutput"],
28
+ ["BashOutputTool", "TaskOutput"],
29
+ ["AgentOutput", "TaskOutput"],
30
+ ["WorkflowStatus", null],
31
+ ["KillShell", "TaskStop"],
32
+ ["KillBash", "TaskStop"],
33
+ ["ListMcpResources", "ListMcpResourcesTool"],
34
+ ["ReadMcpResource", "ReadMcpResourceTool"],
35
+ ["ReadMcpResourceDir", "ReadMcpResourceDirTool"],
36
+ ["MultiEdit", null],
37
+ ["Fork", null],
38
+ ["Sleep", null],
39
+ ["Remember", null],
40
+ ["remember", null],
41
+ ["Recall", null],
42
+ ["recall", null],
43
+ ]);
@@ -1,11 +1,9 @@
1
1
  import { permissionModeField } from './permissionWireCaps.js';
2
2
  import { hostEnv } from './hostEnv.js';
3
3
  import { lastFlagValue } from './argvFlagValue.js';
4
+ import { PERMISSION_MODE_WORDS } from './taskRequestWords.js';
4
5
  export const HEADLESS_PERMISSION_MODE_ENV = 'SEMA_HEADLESS_PERMISSION_MODE';
5
- const HEADLESS_PERMISSION_WIRE_MODE_TUPLE = ['default', 'plan', 'acceptEdits', 'bypassPermissions', 'auto'];
6
- const _headlessPermissionModePins = [true, true];
7
- void _headlessPermissionModePins;
8
- export const HEADLESS_PERMISSION_WIRE_MODES = HEADLESS_PERMISSION_WIRE_MODE_TUPLE;
6
+ export const HEADLESS_PERMISSION_WIRE_MODES = [...PERMISSION_MODE_WORDS];
9
7
  const SHELL_INTERNAL_MODE_TO_WIRE = new Map([
10
8
  ['manual', 'default'],
11
9
  ['dontAsk', 'default'],
@@ -8,7 +8,7 @@ export type { AskAnsweredOutput } from './gateLedger.js';
8
8
  export { SEMA_COLLATERAL_ABORT_KEY } from './gateLedger.js';
9
9
  export { SEMA_DENIAL_KIND_KEY } from './gateLedger.js';
10
10
  export type { GateDenyAttribution } from './gateLedger.js';
11
- export { toAnsweredOutput, isAlreadyResolvedGateReason, isGateStandingErrorCode, GATE_FAILURE_CODES, nextHopBudget, MAX_GATE_HOPS, MAX_TOTAL_PARKS } from './parkResolver.js';
11
+ export { toAnsweredOutput, isAlreadyResolvedGateReason, isGateStandingErrorCode, isCodeClassifiedGateFailure, GATE_FAILURE_CODES, nextHopBudget, MAX_GATE_HOPS, MAX_TOTAL_PARKS } from './parkResolver.js';
12
12
  export type { HopBudget, HopRound } from './parkResolver.js';
13
13
  export type { GateOutcome, GateFailureCode } from './parkResolver.js';
14
14
  export declare function bridgeAskUserQuestionGates(source: AsyncGenerator<AgentEvent>, deps: AskGateWireDeps, opts?: {
@@ -6,7 +6,7 @@ export { HITL_INTERRUPT_MESSAGE_FOR_TOOL_USE } from './frameRouter.js';
6
6
  export { HITL_POLICY_DENY_MESSAGE } from './frameRouter.js';
7
7
  export { SEMA_COLLATERAL_ABORT_KEY } from './gateLedger.js';
8
8
  export { SEMA_DENIAL_KIND_KEY } from './gateLedger.js';
9
- export { toAnsweredOutput, isAlreadyResolvedGateReason, isGateStandingErrorCode, GATE_FAILURE_CODES, nextHopBudget, MAX_GATE_HOPS, MAX_TOTAL_PARKS } from './parkResolver.js';
9
+ export { toAnsweredOutput, isAlreadyResolvedGateReason, isGateStandingErrorCode, isCodeClassifiedGateFailure, GATE_FAILURE_CODES, nextHopBudget, MAX_GATE_HOPS, MAX_TOTAL_PARKS } from './parkResolver.js';
10
10
  export async function* bridgeAskUserQuestionGates(source, deps, opts) {
11
11
  const led = createGateLedger();
12
12
  const taskId = { current: opts?.taskId };
@@ -6,7 +6,9 @@ import { readRunTerminal, runTerminalCode, runTerminalGateKind, runTerminalGateT
6
6
  import { surfaceForCurrentSession } from './hitlHostSurface.js';
7
7
  import { SEMA_DENIAL_KIND_KEY } from './gateLedger.js';
8
8
  import { ccToolDenialKindForSettledBy } from '../gateVocabulary.js';
9
- export const HITL_REJECT_MESSAGE = "The user doesn't want to proceed with this tool use. The tool use was rejected (eg. if it was a file edit, the new_string was NOT written to the file). STOP what you are doing and wait for the user to tell you how to proceed.";
9
+ import { REJECT_MESSAGE } from '../adapt/wireShapes.js';
10
+ import { RUN_CANCELLED_CODE } from '../runCancelContext.js';
11
+ export const HITL_REJECT_MESSAGE = REJECT_MESSAGE;
10
12
  export const HITL_POLICY_DENY_MESSAGE = 'Permission for this tool use was denied: it requires interactive approval, and permission prompts are ' +
11
13
  'not available in this session. The action was NOT performed. Do not claim it succeeded, and do not retry ' +
12
14
  'it in this session \u2014 report the limitation to the user, or suggest an alternative.';
@@ -31,7 +33,7 @@ function denyStampedEnd(ev, attribution) {
31
33
  };
32
34
  }
33
35
  export const HITL_INTERRUPT_MESSAGE_FOR_TOOL_USE = '[Request interrupted by user for tool use]';
34
- const RUN_CANCELLED_ERROR_CODE = 'cancelled';
36
+ const RUN_CANCELLED_ERROR_CODE = RUN_CANCELLED_CODE;
35
37
  export const ENGINE_ABORT_TOOL_RESULT = 'Operation aborted';
36
38
  export function toolEndOutputText(output) {
37
39
  if (typeof output === 'string')
@@ -113,7 +113,7 @@ export function observeCancelByDeny(settle, taskId) {
113
113
  hostLog('debug', `[hitl-cancel-deny] cancel-by-deny no_pending for run ${taskId} (benign — already resolved)`);
114
114
  return;
115
115
  }
116
- const rowNote = decideFailureNote(e);
116
+ const rowNote = decideFailureNote(e, 'deny');
117
117
  hostLog('error', `[hitl-cancel-deny] cancel-by-deny FAILED for run ${taskId}: ${String(e)}${rowNote}`);
118
118
  surfaceCancelDenyWarn(`${CANCEL_DENY_WARN_TEXT}${rowNote}`);
119
119
  })
@@ -34,6 +34,7 @@ export type GateOutcome = {
34
34
  };
35
35
  export declare function isAlreadyResolvedGateReason(reason: unknown): boolean;
36
36
  export declare function isGateStandingErrorCode(code: string | null | undefined): boolean;
37
+ export declare function isCodeClassifiedGateFailure(code: string | null | undefined): boolean;
37
38
  export declare function toAnsweredOutput(questions: unknown[], answer: QuestionAnswer): AskAnsweredOutput;
38
39
  export type ParkResolution = {
39
40
  kind: 'reattach';
@@ -1,6 +1,6 @@
1
1
  import { putOwnKey } from '../ownKey.js';
2
2
  import { DecideTransportRetryExhaustedError, HitlBridge, HitlSafetyError, findPendingForTask, readDecideCurrentPending, readWireErrorCode, } from './hitlBridge.js';
3
- import { RESUME_POLICY_FOLD_CODE } from '../engineErrorCodes.js';
3
+ import { PARKED_RESUME_STARTUP_FAILED, RESUME_POLICY_FOLD_CODE, isDecideParkMovedCode } from '../engineErrorCodes.js';
4
4
  import { publishQuestionFrame, registerLocalQuestionResponder, hasQuestionOverlay, } from '../liveQuestionStore.js';
5
5
  import { hostLog } from '../host.js';
6
6
  import { surfaceFsApprovalAndDecide } from './toolApprovalWire.js';
@@ -44,13 +44,18 @@ function isAlreadyResolvedFailure(outcome) {
44
44
  const code = 'code' in outcome && isGateFailureCode(outcome.code) ? outcome.code : undefined;
45
45
  if (code !== undefined)
46
46
  return code === 'no_pending';
47
- if ('errorCode' in outcome && isGateStandingErrorCode(outcome.errorCode))
47
+ if ('errorCode' in outcome && isCodeClassifiedGateFailure(outcome.errorCode))
48
48
  return false;
49
+ if ('errorCode' in outcome && isDecideParkMovedCode(outcome.errorCode))
50
+ return true;
49
51
  return isAlreadyResolvedGateReason(outcome.reason);
50
52
  }
51
53
  export function isGateStandingErrorCode(code) {
52
54
  return code === RESUME_POLICY_FOLD_CODE || code === 'corrupt';
53
55
  }
56
+ export function isCodeClassifiedGateFailure(code) {
57
+ return isGateStandingErrorCode(code) || code === PARKED_RESUME_STARTUP_FAILED;
58
+ }
54
59
  export function toAnsweredOutput(questions, answer) {
55
60
  const answers = {};
56
61
  const annotations = {};
@@ -122,10 +127,12 @@ async function surfaceGateAndDecide(deps, taskId, askArgsByCall, signal, parkGat
122
127
  return { kind: 'aborted', gatedCallId };
123
128
  }
124
129
  let declinedReceipt;
130
+ let attemptedDecision;
125
131
  try {
126
132
  const entries = answer.answers ?? [];
127
133
  const hasContent = entries.some(a => (a.selected?.length ?? 0) > 0 || (a.note?.length ?? 0) > 0);
128
134
  if (hasContent) {
135
+ attemptedDecision = 'approve';
129
136
  const raw = await bridge.answerQuestion(entries, gatedCallId, signal ? { signal } : undefined, pending);
130
137
  const receipt = readDecideReceipt(raw);
131
138
  return {
@@ -136,6 +143,7 @@ async function surfaceGateAndDecide(deps, taskId, askArgsByCall, signal, parkGat
136
143
  };
137
144
  }
138
145
  else {
146
+ attemptedDecision = 'deny';
139
147
  const raw = await bridge.decideTool({ decision: 'deny', reason: 'User declined to answer' }, gatedCallId, signal ? { signal } : undefined, pending);
140
148
  declinedReceipt = readDecideReceipt(raw);
141
149
  }
@@ -149,7 +157,7 @@ async function surfaceGateAndDecide(deps, taskId, askArgsByCall, signal, parkGat
149
157
  kind: 'failed',
150
158
  stage: 'decide',
151
159
  gatedCallId,
152
- reason: `decide failed: ${String(e)}${decideFailureNote(e)}`,
160
+ reason: `decide failed: ${String(e)}${decideFailureNote(e, attemptedDecision)}`,
153
161
  ...(code !== undefined ? { code } : {}),
154
162
  ...(e instanceof DecideTransportRetryExhaustedError ? { retryExhausted: true } : {}),
155
163
  ...(currentPending !== undefined ? { currentPending } : {}),
@@ -1,5 +1,6 @@
1
1
  import { type QuestionAnswer } from '../liveQuestionStore.js';
2
2
  import { type PlanReviewModeAfter } from './hitlBridge.js';
3
+ import type { AgentClient } from '@sema-agent/sdk';
3
4
  import type { ReopenCardVerdict } from '../adapter/activeRunSelfHeal.js';
4
5
  export declare const PLAN_REVIEW_APPROVE_LABEL = "Yes, approve and run the plan";
5
6
  export declare const PLAN_REVIEW_REJECT_LABEL = "No, reject it (keep planning)";
@@ -28,10 +29,13 @@ export declare function _resetArmedPlanReviewsForTest(): void;
28
29
  export type PlanReviewReopenTrigger = 'user' | 'automatic';
29
30
  export type PlanReviewGateInstanceReader = (taskId: string) => Promise<ReadonlySet<string> | null>;
30
31
  export declare function clearPlanReviewUserDismissals(sessionKey?: string): void;
31
- export declare function armPlanReviewApproval(result: unknown, sessionKey?: string, opts?: {
32
+ export interface ArmPlanReviewOptions {
32
33
  submittedInPlanMode?: boolean;
33
34
  readGateInstanceKeys?: PlanReviewGateInstanceReader;
34
- }): boolean;
35
+ wire?: PlanReviewWire;
36
+ onOutcome?: PlanReviewDeliveryOptions['onOutcome'];
37
+ }
38
+ export declare function armPlanReviewApproval(result: unknown, sessionKey?: string, opts?: ArmPlanReviewOptions): boolean;
35
39
  export type PlanReviewDecisionEffect = 'took_effect' | 'advanced' | 'still_parked' | 'not_sent' | 'not_applied' | 'unconfirmed';
36
40
  export interface PlanReviewOutcomeMeta {
37
41
  taskId: string;
@@ -40,16 +44,50 @@ export interface PlanReviewOutcomeMeta {
40
44
  effect: PlanReviewDecisionEffect;
41
45
  }
42
46
  export declare function planReviewOutcomeTail(taskId: string, decision: 'approve' | 'reject', effect: PlanReviewDecisionEffect): string;
47
+ export type PlanReviewWireClient = {
48
+ assistant: Pick<AgentClient['assistant'], 'planReview'>;
49
+ runs: Pick<AgentClient['runs'], 'get'>;
50
+ };
51
+ export interface PlanReviewWire {
52
+ client: PlanReviewWireClient;
53
+ capsBaseUrl?: string;
54
+ }
55
+ export interface PlanReviewDecisionOutcome extends PlanReviewOutcomeMeta {
56
+ detail: string;
57
+ tail: string;
58
+ prompt: string;
59
+ status?: string;
60
+ }
61
+ export interface PlanReviewDeliveryOptions {
62
+ wire?: PlanReviewWire;
63
+ onOutcome?: (outcome: PlanReviewDecisionOutcome) => void;
64
+ }
65
+ export interface DecidePlanReviewOptions extends PlanReviewDeliveryOptions {
66
+ reason?: string;
67
+ }
68
+ export interface PlanReviewDecisionHandle {
69
+ settle(): void;
70
+ revoke(): void;
71
+ }
72
+ export declare function notePlanReviewDecisionHandedOver(taskId: string): PlanReviewDecisionHandle | null;
73
+ export declare function planReviewPendingReadMark(): number;
74
+ export declare function planReviewDecisionInFlight(taskId: string, pendingReadStartedAt?: number): boolean;
75
+ export declare function notePlanReviewDecisionNotApplied(taskId: string): void;
76
+ export declare function notePlanReviewGateLeft(taskId: string): void;
77
+ export declare function latestPlanReviewDecisionMark(taskId: string): number | null;
43
78
  export declare function __resetPlanReviewDecisionLatchForTests(): void;
44
- export declare function decidePlanReview(taskId: string, decision: 'approve' | 'reject', permissionModeAfter?: string): Promise<void>;
79
+ export declare function decidePlanReview(taskId: string, decision: 'approve' | 'reject', permissionModeAfter?: string, opts?: DecidePlanReviewOptions): Promise<void>;
45
80
  export interface ReopenPlanReviewOpts {
46
81
  mintFreshQuestionId?: boolean;
47
82
  deliverDecision?: (taskId: string, decision: 'approve' | 'reject') => void | Promise<void>;
48
83
  sessionKey?: string;
84
+ wire?: PlanReviewWire;
85
+ onOutcome?: PlanReviewDeliveryOptions['onOutcome'];
49
86
  presentationReceiptMs?: number;
50
87
  trigger?: PlanReviewReopenTrigger;
51
88
  readGateInstanceKeys?: PlanReviewGateInstanceReader;
52
89
  decisionHandedOver?: (taskId: string) => boolean;
90
+ pendingReadStartedAt?: number;
53
91
  }
54
92
  export declare function _resetActiveReopenRespondersForTest(): void;
55
93
  export declare function reopenPlanReviewCard(taskId: string, opts: ReopenPlanReviewOpts & {