@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
@@ -23,6 +23,7 @@ export const REQUEST_FIELD_MATRIX = [
23
23
  { field: 'memoryCapture', lanes: ['interactive', 'print', 'utility'], live: true, why: '本会话永远不进长期记忆的**声明形**(server §12.4 body 键,单成员闭集 "off");每条车道都是提交面 ⇒ 都能声明。与 memoryWrite:false 不是一个轴(那是「本 run 只读平面」)。⚠️ parked 续跑腿结构性拿不到声明(决策/续跑端点从持久 body 重建 spec),那是引擎侧事实,不是本层的漏', whyUtilityLane: '有座:side-channel 提交是壳自己的一次性问答,**绝不该**进用户的长期记忆 —— 这一位正是那句声明,且它是收紧方向,带上去只会更严' },
24
24
  { field: 'memory', lanes: ['interactive', 'print', 'utility'], live: true, why: '这一次运行不挂记忆面的**请求级**开关(server §12.7 body 键,单成员闭集 "off");每条车道都是提交面 ⇒ 都能声明。与 memoryCapture(采集面)不是一个轴、可并存;与 memoryWrite:false(只读平面)也不是一个轴', whyUtilityLane: '有座:side-channel 提交不需要挂记忆面(不挂记忆段 / 索引 / 三只记忆工具),省 token 且零记忆写入;与 memoryCapture 不是一个轴,两条都带' },
25
25
  { field: 'approverPosture', lanes: ['interactive', 'print'], live: true, why: '宿主对这个 run 的**审批姿态声明**(「这个 run 的审批卡由我自己自动答」;单成员闭集 `"bypass"`)。🔴 它不授权任何东西、也不是一只门:引擎只把这句声明**渲**给模型(它自己的标记块,首个回合),没有任何裁决腿读它 —— 与 `permissionMode` 的 `bypassPermissions`(选门的形状)**不是一回事**,两键在请求体上各自原样过境、**互不派生**:宿主完全可以一边留着缺省权限模式、一边自己自动答这个 run 的审批卡。🔴 **声明它的唯一条件是「宿主确实自己自动答这个 run 的审批卡」,不许据此推导或改动 `permissionMode`** —— 拿这一位当理由去把门放宽,是把一句只渲给模型看的话读成了授权。宿主并不自动答卡却声明了它 ⇒ 那是对模型说了一句与实际不符的话,修法是**别声明**,不是去动门。加座的理由是**一个事实一处铸点**:同样一句话,要么由引擎在它自己的标记块里说,要么由壳把提醒形文本拼进本 turn 的输入 —— 后者在模型眼里是一段**没有引擎标记**的提醒形副本,按标记声明它该当**数据**处理并报出来。所以壳从此停拼,交这一位。两条用户车道都是提交面 ⇒ 都能声明。坏词由引擎响亮拒(单成员闭集,打错字不许被折成缺席),本层同律在构造期就拒(见 `refuseBadApproverPosture`)。⚠️ 上游的**提交体**与**引擎规格**两层都真读这一键,而装着的 sdk 型面尚未镜像它 ⇒ 本层的字面按提交体的形声明,不从 sdk 取型', whyUtilityLane: '无座:审批姿态是**用户**对他自己那条会话的声明,而 side-channel 是壳自己的提交 —— 把用户的 bypass 姿态带进一条他没参与的提交,等于替他重申一句他没说过的话;况且零工具面根本产不出审批卡' },
26
+ { field: 'fileHistory', lanes: ['interactive', 'print'], live: true, why: '「这一次运行别捕获文件历史」的**请求级声明**(server 7.104.0 提交体键,单成员闭集 "disabled";`POST /v1/tasks` · `/v1/tasks/stream` · `/v1/runs` 同收,子代继承)。两条用户车道都是提交面、都跑在用户的文件上 ⇒ 都能声明;「本会话不捕获」= 每个提交都带(续跑腿重放同一个体)。🔴 只在能力读数 `on-optional` 时发(老 server 对表外键 400),值由片段口 `fileHistoryDeclarationField` 唯一铸出。与 rewind 还原键同交 ⇒ 上游 400 `request.field_conflict`', whyUtilityLane: '无座:side-channel 强制零工具面(`excludeAllTools`),不会改任何文件 ⇒ 没有可捕获的东西;带上它只会在不认识这一键的老 server 上给这条提交多一种 400' },
26
27
  { field: 'finalVerification', lanes: ['print'], live: true, why: 'P1-1 终验:无人值守车道才需要引擎自证;交互 REPL 由人当场看结果。#106 裁 B(让位+告知)后交互面默认关', whyUtilityLane: '无座:终验让引擎再跑一轮自证,而 side-channel 要的是一次小提交的即时答案;「无人值守才需要引擎自证」这条理由在本车道上让位给「小预算优先」' },
27
28
  { field: 'limits', lanes: ['print', 'utility'], live: true, why: 'P2-3-b:`-p` 的预算护栏(--max-* flag 族),交互 REPL 由人随时 Esc', whyUtilityLane: '有座:side-channel 必须带预算护栏(墙钟 / 输出 token / 轮数)—— 它同样没有人看着,而且没有后续回合可以中断' },
28
29
  { field: 'interactiveTools', lanes: ['print', 'utility'], live: true, why: '[909]B 件3:无人值守 stamp false,从 roster 源头灭掉 AskUserQuestion/plan 门。交互车道 stamp false 等于自废武功', whyUtilityLane: '有座:side-channel 绝不该弹交互问答 / plan 门(没有人在看这条提交)。它与 excludeAllTools 是**两条独立**的收紧声明、在这条车道上**并存**(本车道强制带卸载声明,见 `refuseUtilityWithoutToolUnload`;这一位是它旁边那条「连问都别问」的声明,不是它的降级替身)' },
@@ -125,6 +126,7 @@ const INPUT_KEY_ROUTES = {
125
126
  memoryCapture: row('memoryCapture'),
126
127
  memory: row('memory'),
127
128
  approverPosture: row('approverPosture'),
129
+ fileHistory: row('fileHistory'),
128
130
  rewind: row('resumeAt/resumeAtMode/restoreFiles/rewindFilesTo'),
129
131
  repo: row('repo'),
130
132
  council: row('council'),
@@ -197,6 +199,7 @@ const VALUE_LEVEL_IN_PLAY = Object.freeze({
197
199
  memoryCapture: (v) => v === 'off',
198
200
  memory: (v) => v === 'off',
199
201
  approverPosture: (v) => v === APPROVER_POSTURE_BYPASS,
202
+ fileHistory: (v) => v === FILE_HISTORY_DISABLED,
200
203
  rewind: (v) => typeof v === 'object' && v !== null && rewindSubKeys().some((k) => hasOwn(v, k) && present(v[k])),
201
204
  });
202
205
  const inPlay = (key, v) => present(v) && (VALUE_LEVEL_IN_PLAY[key]?.(v) ?? true);
@@ -377,6 +380,7 @@ void true;
377
380
  export function approverPostureDeclarationField(declared) {
378
381
  return declared ? { approverPosture: APPROVER_POSTURE_BYPASS } : {};
379
382
  }
383
+ export const FILE_HISTORY_DISABLED = 'disabled';
380
384
  export function memoryOffDeclared(input) {
381
385
  if (typeof input !== 'object' || input === null)
382
386
  return false;
@@ -426,6 +430,15 @@ const refuseBadApproverPosture = (v) => {
426
430
  '**响亮拒**,刻意不把打错的词折回缺席。本层若静默删键,这一次提交的模型不会被告知姿态,而声明人不会知道。' +
427
431
  '错误文本只报形状,不回显值。');
428
432
  };
433
+ const refuseBadFileHistory = (v) => {
434
+ if (v === undefined || v === null)
435
+ return;
436
+ if (v === FILE_HISTORY_DISABLED)
437
+ return;
438
+ throw new TypeError('buildTaskRequest: fileHistory 只接受字面量 `\'disabled\'` 或缺席(undefined/null)—— ' +
439
+ `收到 ${coarseShape(v)}。这一位是「这一次运行别捕获文件历史」的收紧声明,上游是**单成员闭集**(没有第二个词)且对坏值` +
440
+ '**响亮拒**。本层若静默删键,这一次运行照常捕获而声明人不会知道。错误文本只报形状,不回显值。');
441
+ };
429
442
  const refuseBadMaxTokens = (v) => {
430
443
  if (v === undefined || v === null)
431
444
  return;
@@ -495,7 +508,7 @@ export function parseMaxCostUsd(text) {
495
508
  return { ok: false, why: 'not_positive' };
496
509
  return { ok: true, value };
497
510
  }
498
- const ACCESSOR_READ_ORDER = ['live', 'memoryCapture', 'memory', 'settings', 'maxCostUsd', 'excludeAllTools', 'approverPosture', 'maxTokens', 'outputRetries'];
511
+ const ACCESSOR_READ_ORDER = ['live', 'memoryCapture', 'memory', 'settings', 'maxCostUsd', 'excludeAllTools', 'approverPosture', 'maxTokens', 'outputRetries', 'fileHistory'];
499
512
  function dataFirstSnapshot(input, afterData) {
500
513
  let descs;
501
514
  try {
@@ -563,6 +576,7 @@ export function assembleTaskRequest(input, lane) {
563
576
  const approverPostureIn = src.approverPosture;
564
577
  const maxTokensIn = src.maxTokens;
565
578
  const outputRetriesIn = src.outputRetries;
579
+ const fileHistoryIn = src.fileHistory;
566
580
  const INPUT_KEYS = Object.keys(INPUT_KEY_ROUTES);
567
581
  const i = snapshotByName(src, INPUT_KEYS, {
568
582
  live,
@@ -573,6 +587,7 @@ export function assembleTaskRequest(input, lane) {
573
587
  excludeAllTools: excludeAllToolsIn,
574
588
  approverPosture: approverPostureIn,
575
589
  outputRetries: outputRetriesIn,
590
+ fileHistory: fileHistoryIn,
576
591
  settings: settingsIn,
577
592
  });
578
593
  const SETTINGS_KEYS = Object.keys(SETTINGS_KEY_ROUTES);
@@ -584,6 +599,7 @@ export function assembleTaskRequest(input, lane) {
584
599
  refuseBadApproverPosture(approverPostureIn);
585
600
  refuseBadMaxTokens(maxTokensIn);
586
601
  refuseBadOutputRetries(outputRetriesIn);
602
+ refuseBadFileHistory(fileHistoryIn);
587
603
  const rewindRoute = INPUT_KEY_ROUTES.rewind;
588
604
  const RETIRED_REWIND_FILES_KEY = 'rewindFiles';
589
605
  const REWIND_KEYS = rewindRoute.via === 'matrix' ? rewindRoute.field.split('/') : [];
@@ -733,6 +749,7 @@ export function assembleTaskRequest(input, lane) {
733
749
  ...(on('memoryCapture') ? { memoryCapture: 'off' } : {}),
734
750
  ...(on('memory') ? { memory: 'off' } : {}),
735
751
  ...(on('approverPosture') ? { approverPosture: APPROVER_POSTURE_BYPASS } : {}),
752
+ ...(on('fileHistory') ? { fileHistory: FILE_HISTORY_DISABLED } : {}),
736
753
  ...(Object.keys(settingsOut).length > 0 ? { settings: settingsOut } : {}),
737
754
  };
738
755
  return Object.freeze({ request: out, omitted: Object.freeze([...omitted, ...lateOmitted]) });
@@ -33,3 +33,14 @@ export interface ResumeContextUnavailableDetail {
33
33
  }
34
34
  export declare function resumeContextUnavailableFromError(err: unknown): ResumeContextUnavailableDetail | null;
35
35
  export declare function resumeContextUnavailableContent(d: ResumeContextUnavailableDetail): string;
36
+ export type ParkedResumeStartupDecision = 'approve' | 'deny';
37
+ export type ParkedResumeStartupCause = 'resume_rejected' | 'undetermined';
38
+ export interface ParkedResumeStartupDetail {
39
+ code: string;
40
+ cause: ParkedResumeStartupCause;
41
+ taskId?: string;
42
+ resendable: false;
43
+ denyStaysOpen: true;
44
+ }
45
+ export declare function parkedResumeStartupFromError(err: unknown, decision?: ParkedResumeStartupDecision): ParkedResumeStartupDetail | null;
46
+ export declare function parkedResumeStartupContent(detail: ParkedResumeStartupDetail): string;
@@ -1,5 +1,5 @@
1
1
  import { readErrorNumber, readErrorString } from './wireFailureShape.js';
2
- import { RESUME_CONTEXT_UNAVAILABLE, RESUME_PLACEMENT_MISMATCH, RESUME_PREFLIGHT_REJECTED, RESUME_REOPEN_CODES, RESUME_ENV_FAILED, RESUME_TOOL_UNAVAILABLE, RESUME_POLICY_FOLD_CODE, } from './engineErrorCodes.js';
2
+ import { RESUME_CONTEXT_UNAVAILABLE, RESUME_PLACEMENT_MISMATCH, RESUME_PREFLIGHT_REJECTED, RESUME_REOPEN_CODES, RESUME_ENV_FAILED, RESUME_TOOL_UNAVAILABLE, RESUME_POLICY_FOLD_CODE, PARKED_RESUME_STARTUP_FAILED, isStatusDerivedCoarseCode, } from './engineErrorCodes.js';
3
3
  import { capForDisplay } from './fleetTaskDesc.js';
4
4
  import { resumeRetryLaterFromError } from './wireErrorTriage.js';
5
5
  export const RESUME_REFUSAL_CODES = Object.freeze([
@@ -73,7 +73,9 @@ export function resumePolicyBlockFromError(err) {
73
73
  export function resumePolicyBlockContent(detail) {
74
74
  const b = detail.blockedBy;
75
75
  const reason = b.kind === 'named'
76
- ? `The check that refused it: ${capForDisplay(b.code, 80)}`
76
+ ? isStatusDerivedCoarseCode(b.code)
77
+ ? `The refusal did not name a more specific check (it carried only the generic code for its HTTP status: ${b.code})`
78
+ : `The check that refused it: ${capForDisplay(b.code, 80)}`
77
79
  : b.kind === 'absent'
78
80
  ? 'The refusal did not name a more specific check'
79
81
  : 'The refusal carried a more specific reason that could not be read';
@@ -134,3 +136,41 @@ export function resumeContextUnavailableContent(d) {
134
136
  third,
135
137
  ].join(' · ');
136
138
  }
139
+ export function parkedResumeStartupFromError(err, decision) {
140
+ if (typeof err !== 'object' || err === null)
141
+ return null;
142
+ let code;
143
+ try {
144
+ code = err.errorCode;
145
+ }
146
+ catch {
147
+ return null;
148
+ }
149
+ if (code !== PARKED_RESUME_STARTUP_FAILED)
150
+ return null;
151
+ const rawTaskId = readErrorString(err, 'taskId');
152
+ const taskId = rawTaskId !== undefined && rawTaskId.length > 0 ? rawTaskId : undefined;
153
+ return {
154
+ code: PARKED_RESUME_STARTUP_FAILED,
155
+ cause: decision === 'deny' ? 'resume_rejected' : 'undetermined',
156
+ ...(taskId !== undefined ? { taskId } : {}),
157
+ resendable: false,
158
+ denyStaysOpen: true,
159
+ };
160
+ }
161
+ const PARKED_RESUME_STARTUP_STATE = 'This refusal does not say whether the card is still waiting — re-fetch the pending approvals';
162
+ const PARKED_RESUME_STARTUP_SENTENCES = Object.freeze({
163
+ resume_rejected: [
164
+ 'The engine could not start the parked work to apply this decision (its session may be gone, or the engine rejected the decision itself)',
165
+ PARKED_RESUME_STARTUP_STATE,
166
+ 'If the card is still there, decide it again from the fresh list',
167
+ ].join(' · '),
168
+ undetermined: [
169
+ 'The engine could not start the parked work to apply this decision',
170
+ PARKED_RESUME_STARTUP_STATE,
171
+ 'If the card is still there: when the engine rejected the decision itself (for example an answer given to the wrong question), correct it and decide again; when the approved tool is one the agent inherits from the task that started it, approving it again will not work on this server — deny the card, or wait for a server upgrade',
172
+ ].join(' · '),
173
+ });
174
+ export function parkedResumeStartupContent(detail) {
175
+ return detail.cause === 'resume_rejected' ? PARKED_RESUME_STARTUP_SENTENCES.resume_rejected : PARKED_RESUME_STARTUP_SENTENCES.undetermined;
176
+ }
@@ -32,6 +32,10 @@ export function readRunTerminal(result) {
32
32
  const kind = str(c.kind);
33
33
  if (kind === undefined)
34
34
  return { kind: 'unknown', plane: 'cause' };
35
+ const parkWord = str(r.status);
36
+ if (parkWord !== undefined && FLAT_PAUSED_STATUSES.includes(parkWord)) {
37
+ return { kind: 'paused', plane: 'cause', flatStatus: parkWord, ...(kind === 'paused' ? (pauseOf(c) ?? {}) : {}) };
38
+ }
35
39
  switch (kind) {
36
40
  case 'completed':
37
41
  return { kind: 'completed', plane: 'cause' };
@@ -55,7 +55,7 @@ export function sandboxDegradeHint(err) {
55
55
  'Re-run without --sandbox (worker default image), or point the shell at a k8s-lane worker (sema cloud engine connect <url>).');
56
56
  }
57
57
  if (e.status === 400 && msg.includes(SANDBOX_NO_IMAGE_INDEX_400_ANCHOR)) {
58
- return ('This worker has no sandbox image index configured (sema-registry backend absent), so per-task profiles cannot resolve.\n' +
58
+ return ('This worker has no sandbox image index configured (the sema-web-admin config center is not attached), so per-task profiles cannot resolve.\n' +
59
59
  'Re-run without --sandbox, or use a worker with the image index enabled.');
60
60
  }
61
61
  if (e.status === 404 && msg.includes(SANDBOX_NO_PUBLISHED_IMAGE_404_ANCHOR)) {
@@ -0,0 +1,17 @@
1
+ export type SealedKeyReading = {
2
+ kind: 'unobserved';
3
+ } | {
4
+ kind: 'not_reported';
5
+ } | {
6
+ kind: 'present';
7
+ alg: string;
8
+ publicKeyId: string;
9
+ publicKey: string;
10
+ };
11
+ export declare function projectSealedKeyCapability(caps: unknown): SealedKeyReading | undefined;
12
+ export declare function noteEngineCapsForSealedKey(baseUrl: string, caps: unknown, opts?: {
13
+ generation?: number;
14
+ }): void;
15
+ export declare function observedSealedKey(baseUrl?: string | undefined): SealedKeyReading;
16
+ export declare function forgetSealedKeyReading(baseUrl: string | undefined): void;
17
+ export declare function __resetSealedKeyReadingsForTests(): void;
@@ -0,0 +1,42 @@
1
+ import { engineWireTarget } from './engineWireTarget.js';
2
+ import { createEngineCapReader } from './engineCapReader.js';
3
+ function ownNonEmpty(seg, key) {
4
+ if (!Object.hasOwn(seg, key))
5
+ return undefined;
6
+ const v = seg[key];
7
+ return typeof v === 'string' && v.length > 0 ? v : undefined;
8
+ }
9
+ export function projectSealedKeyCapability(caps) {
10
+ if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
11
+ return undefined;
12
+ if (!Object.hasOwn(caps, 'sealedKey'))
13
+ return { kind: 'not_reported' };
14
+ const seg = caps.sealedKey;
15
+ if (seg === undefined)
16
+ return { kind: 'not_reported' };
17
+ if (seg === null || typeof seg !== 'object' || Array.isArray(seg))
18
+ return undefined;
19
+ const alg = ownNonEmpty(seg, 'alg');
20
+ const publicKeyId = ownNonEmpty(seg, 'publicKeyId');
21
+ const publicKey = ownNonEmpty(seg, 'publicKey');
22
+ if (alg === undefined || publicKeyId === undefined || publicKey === undefined)
23
+ return undefined;
24
+ return { kind: 'present', alg, publicKeyId, publicKey };
25
+ }
26
+ const reader = createEngineCapReader({
27
+ name: 'sealedKey',
28
+ project: projectSealedKeyCapability,
29
+ makeUnobserved: () => ({ kind: 'unobserved' }),
30
+ });
31
+ export function noteEngineCapsForSealedKey(baseUrl, caps, opts) {
32
+ reader.note(baseUrl, caps, opts);
33
+ }
34
+ export function observedSealedKey(baseUrl = engineWireTarget()?.baseUrl) {
35
+ return reader.observed(baseUrl);
36
+ }
37
+ export function forgetSealedKeyReading(baseUrl) {
38
+ reader.forget(baseUrl);
39
+ }
40
+ export function __resetSealedKeyReadingsForTests() {
41
+ reader.__resetForTests();
42
+ }
@@ -1,4 +1,5 @@
1
1
  import type { ReasoningEffort } from "./effortWire.js";
2
+ import type { PermissionMode } from "./permissionWireCaps.js";
2
3
  import type { LaneProof } from "./seam.js";
3
4
  import type { QuestionAnswer } from "./liveQuestionStore.js";
4
5
  import type { ToolApprovalDelegation } from "./hitl/toolApprovalWire.js";
@@ -101,7 +102,7 @@ export interface StartSessionOptions {
101
102
  cwd?: string;
102
103
  excludeTools?: string[];
103
104
  }
104
- export type PermissionModeIntent = "default" | "plan" | "acceptEdits" | "bypassPermissions" | "auto";
105
+ export type PermissionModeIntent = PermissionMode;
105
106
  export declare const PERMISSION_MODE_INTENTS: readonly PermissionModeIntent[];
106
107
  export declare const ATTACHMENT_IDS_PER_TASK_CAP = 16;
107
108
  export declare const SEAT_REASONING_EFFORTS: readonly ReasoningEffort[];
@@ -1,3 +1,4 @@
1
+ import { PERMISSION_MODE_WORDS, REASONING_EFFORT_WORDS } from "./taskRequestWords.js";
1
2
  const bad = (reason, field) => field === undefined ? { reason } : { reason, field };
2
3
  const nested = (prefix, verdict) => {
3
4
  const path = verdict.field === undefined
@@ -71,25 +72,9 @@ export const HITL_RESOLUTION_OUTCOMES = [
71
72
  "decline",
72
73
  "cancel",
73
74
  ];
74
- const PERMISSION_MODE_INTENT_TUPLE = [
75
- "default",
76
- "plan",
77
- "acceptEdits",
78
- "bypassPermissions",
79
- "auto",
80
- ];
81
- export const PERMISSION_MODE_INTENTS = PERMISSION_MODE_INTENT_TUPLE;
75
+ export const PERMISSION_MODE_INTENTS = [...PERMISSION_MODE_WORDS];
82
76
  export const ATTACHMENT_IDS_PER_TASK_CAP = 16;
83
- const SEAT_REASONING_EFFORT_TUPLE = [
84
- "off",
85
- "minimal",
86
- "low",
87
- "medium",
88
- "high",
89
- "xhigh",
90
- "max",
91
- ];
92
- export const SEAT_REASONING_EFFORTS = SEAT_REASONING_EFFORT_TUPLE;
77
+ export const SEAT_REASONING_EFFORTS = [...REASONING_EFFORT_WORDS];
93
78
  export const SEAT_TURN_SETTINGS_KEYS = ["ultracode"];
94
79
  export const ATTACHMENT_UPLOAD_REQUEST_KEYS = ["name", "mimeType", "bytes"];
95
80
  export const SESSION_SEARCH_RESULT_KEYS = ["sessionId", "title", "matches"];
@@ -224,8 +209,8 @@ const checkLocalSessionEvent = (v) => {
224
209
  }
225
210
  if (!isAbsent(v.permissionMode)) {
226
211
  const mode = v.permissionMode;
227
- if (typeof mode !== "string" || !inTuple(PERMISSION_MODE_INTENT_TUPLE, mode)) {
228
- return bad(`permissionMode must be one of ${PERMISSION_MODE_INTENT_TUPLE.join("|")}`, "permissionMode");
212
+ if (typeof mode !== "string" || !inTuple(PERMISSION_MODE_INTENTS, mode)) {
213
+ return bad(`permissionMode must be one of ${PERMISSION_MODE_INTENTS.join("|")}`, "permissionMode");
229
214
  }
230
215
  }
231
216
  if (!isAbsent(v.session)) {
@@ -718,7 +703,6 @@ const _seatContractPins = [
718
703
  true, true,
719
704
  true, true,
720
705
  true, true, true, true,
721
- true, true, true, true,
722
706
  true, true,
723
707
  true, true,
724
708
  true, true,
@@ -1,5 +1,16 @@
1
+ import type { AgentClient } from '@sema-agent/sdk';
2
+ import type { EngineWireInjection } from '../engineWireSdk.js';
3
+ export type EngineCompactWireClient = {
4
+ capabilities: AgentClient['capabilities'];
5
+ runs: Pick<AgentClient['runs'], 'compact'>;
6
+ };
7
+ export type EngineCompactWire = EngineWireInjection<EngineCompactWireClient>;
1
8
  export declare function isEngineCompactPending(sessionKey?: string): boolean;
2
9
  export declare function resetManualCompactCapability(): void;
3
10
  export declare function __resetEngineCompactArmForTests(): void;
4
- export declare function requestEngineCompact(sessionKey?: string): 'fired' | 'armed' | 'offline' | 'unsupported';
5
- export declare function onEngineTaskBound(taskId: string, sessionKey?: string): void;
11
+ export declare function requestEngineCompact(sessionKey?: string, opts?: {
12
+ wire?: EngineCompactWire;
13
+ }): 'fired' | 'armed' | 'offline' | 'unsupported';
14
+ export declare function onEngineTaskBound(taskId: string, sessionKey?: string, opts?: {
15
+ wire?: EngineCompactWire;
16
+ }): void;
@@ -1,34 +1,38 @@
1
1
  import { hostLog, hostTimersFor } from '../host.js';
2
- import { makeEngineWireClient } from '../engineWireSdk.js';
3
- import { engineWireTargetFor } from '../engineWireTarget.js';
2
+ import { clientHasVerbs, engineWireFor, INJECTED_WIRE_SETTLE_MS, settleInjected, } from '../engineWireFor.js';
4
3
  import { activeEngineRunIdFor, engineSessionParamFor } from '../engineSessionParam.js';
5
4
  import { DEFAULT_SESSION_KEY } from '../sessionSlot.js';
5
+ function usableCompactClient(client) {
6
+ return clientHasVerbs(client, [['capabilities'], ['runs', 'compact']]);
7
+ }
8
+ const COMPACT_PROBE_SETTLE_MS = 5000;
6
9
  const pendingCompactKeys = new Set();
7
10
  export function isEngineCompactPending(sessionKey = DEFAULT_SESSION_KEY) {
8
11
  return pendingCompactKeys.has(sessionKey);
9
12
  }
10
13
  const manualCompactCapableByBase = new Map();
11
14
  const capabilitiesProbeByBase = new Map();
12
- function probeManualCompactCapability(sessionKey = DEFAULT_SESSION_KEY) {
13
- const cfg = engineWireTargetFor(sessionKey);
14
- if (!cfg)
15
+ function probeManualCompactCapability(wire) {
16
+ const base = wire.kind === 'injected' ? wire.capsBaseUrl : wire.target.baseUrl;
17
+ if (base === undefined)
15
18
  return;
16
- const base = cfg.baseUrl;
17
19
  if (capabilitiesProbeByBase.has(base))
18
20
  return;
19
21
  capabilitiesProbeByBase.set(base, (async () => {
20
22
  try {
21
- const client = makeEngineWireClient({
22
- baseUrl: base,
23
- ...(cfg.token ? { token: cfg.token } : {}),
24
- principal: cfg.principal,
25
- timeoutMs: 5000,
26
- });
27
- if (!client) {
28
- capabilitiesProbeByBase.delete(base);
29
- return;
23
+ let caps;
24
+ if (wire.kind === 'injected') {
25
+ const injected = wire.client;
26
+ caps = await settleInjected(COMPACT_PROBE_SETTLE_MS, undefined, (signal) => injected.capabilities({ signal }));
27
+ }
28
+ else {
29
+ const client = wire.make({ timeoutMs: 5000 });
30
+ if (!client) {
31
+ capabilitiesProbeByBase.delete(base);
32
+ return;
33
+ }
34
+ caps = await client.capabilities();
30
35
  }
31
- const caps = await client.capabilities();
32
36
  if (typeof caps.manualCompact === 'boolean')
33
37
  manualCompactCapableByBase.set(base, caps.manualCompact);
34
38
  else
@@ -55,31 +59,35 @@ function deferFire(ms, fn, why, sessionKey) {
55
59
  timers.setTimer(ms, fn);
56
60
  return true;
57
61
  }
58
- function freezeCompactShot(taskId, sessionKey) {
59
- const cfg = engineWireTargetFor(sessionKey);
60
- if (!cfg)
62
+ function freezeCompactShot(taskId, sessionKey, wire) {
63
+ if (wire.kind === 'no-target' || wire.kind === 'injected-unusable')
61
64
  return null;
62
65
  const sid = engineSessionParamFor(sessionKey);
66
+ let client;
67
+ if (wire.kind === 'injected') {
68
+ const injected = wire.client;
69
+ client = () => injected;
70
+ }
71
+ else {
72
+ const make = wire.make;
73
+ client = () => make();
74
+ }
63
75
  return {
64
76
  taskId,
65
77
  sessionKey,
66
- baseUrl: cfg.baseUrl,
67
- ...(cfg.token !== undefined ? { token: cfg.token } : {}),
68
- ...(cfg.principal !== undefined ? { principal: cfg.principal } : {}),
78
+ client,
79
+ injected: wire.kind === 'injected',
69
80
  ...(sid !== undefined ? { session: sid } : {}),
70
81
  };
71
82
  }
72
83
  async function postCompact(shot, retriesLeft = 1) {
73
- const client = makeEngineWireClient({
74
- baseUrl: shot.baseUrl,
75
- ...(shot.token ? { token: shot.token } : {}),
76
- principal: shot.principal,
77
- });
84
+ const client = shot.client();
78
85
  if (!client)
79
86
  return;
80
87
  const taskId = shot.taskId;
81
88
  try {
82
- const ack = await client.runs.compact(taskId, shot.session !== undefined ? { session: shot.session } : {});
89
+ const fire = (signal) => client.runs.compact(taskId, { ...(shot.session !== undefined ? { session: shot.session } : {}), ...(signal ? { signal } : {}) });
90
+ const ack = shot.injected ? await settleInjected(INJECTED_WIRE_SETTLE_MS, undefined, fire) : await fire(undefined);
83
91
  hostLog('debug', `engineCompactWire: POST compact ${taskId} → ok${ack?.status ? ` (${ack.status})` : ''}`);
84
92
  }
85
93
  catch (e) {
@@ -94,18 +102,19 @@ async function postCompact(shot, retriesLeft = 1) {
94
102
  hostLog('debug', `engineCompactWire: compact fire failed (best-effort): ${String(e)}`);
95
103
  }
96
104
  }
97
- export function requestEngineCompact(sessionKey = DEFAULT_SESSION_KEY) {
98
- const cfg = engineWireTargetFor(sessionKey);
99
- if (!cfg)
105
+ export function requestEngineCompact(sessionKey = DEFAULT_SESSION_KEY, opts) {
106
+ const wire = engineWireFor(opts?.wire, sessionKey, usableCompactClient);
107
+ if (wire.kind === 'no-target' || wire.kind === 'injected-unusable')
100
108
  return 'offline';
101
- probeManualCompactCapability(sessionKey);
102
- if (manualCompactCapableByBase.get(cfg.baseUrl) === false) {
109
+ probeManualCompactCapability(wire);
110
+ const capsKey = wire.kind === 'injected' ? wire.capsBaseUrl : wire.target.baseUrl;
111
+ if (capsKey !== undefined && manualCompactCapableByBase.get(capsKey) === false) {
103
112
  hostLog('debug', 'engineCompactWire: engine capabilities report manualCompact:false — verb suppressed (TOC-local runStore-less engine, [488])');
104
113
  return 'unsupported';
105
114
  }
106
115
  const taskId = activeEngineRunIdFor(sessionKey);
107
116
  if (taskId) {
108
- const shot = freezeCompactShot(taskId, sessionKey);
117
+ const shot = freezeCompactShot(taskId, sessionKey, wire);
109
118
  if (shot !== null)
110
119
  void postCompact(shot);
111
120
  return 'fired';
@@ -114,11 +123,13 @@ export function requestEngineCompact(sessionKey = DEFAULT_SESSION_KEY) {
114
123
  return 'armed';
115
124
  }
116
125
  const BOUND_FIRE_DELAY_MS = 1500;
117
- export function onEngineTaskBound(taskId, sessionKey = DEFAULT_SESSION_KEY) {
118
- probeManualCompactCapability(sessionKey);
126
+ export function onEngineTaskBound(taskId, sessionKey = DEFAULT_SESSION_KEY, opts) {
127
+ const wire = engineWireFor(opts?.wire, sessionKey, usableCompactClient);
128
+ if (wire.kind !== 'no-target' && wire.kind !== 'injected-unusable')
129
+ probeManualCompactCapability(wire);
119
130
  if (!pendingCompactKeys.has(sessionKey))
120
131
  return;
121
- const shot = freezeCompactShot(taskId, sessionKey);
132
+ const shot = freezeCompactShot(taskId, sessionKey, wire);
122
133
  if (shot === null)
123
134
  return;
124
135
  if (deferFire(BOUND_FIRE_DELAY_MS, () => void postCompact(shot), 'bind 后发射', sessionKey)) {
@@ -1,3 +1,9 @@
1
+ import type { AgentClient } from '@sema-agent/sdk';
2
+ import type { EngineWireInjection } from '../engineWireSdk.js';
3
+ export type DelegatedPromptWireClient = {
4
+ sessions: Pick<AgentClient['sessions'], 'get'>;
5
+ };
6
+ export type DelegatedPromptWire = EngineWireInjection<DelegatedPromptWireClient>;
1
7
  export declare function recordEngineTranscriptId(taskId: string, transcriptId: string): void;
2
8
  export declare function getEngineTranscriptId(taskId: string): string | undefined;
3
9
  export declare function __resetEngineDelegatedPromptForTests(): void;
@@ -9,5 +15,7 @@ export interface DelegatedPromptFetch {
9
15
  prompt?: string;
10
16
  outcome: 'hit' | 'skipped' | 'unreadable' | 'absent';
11
17
  }
12
- export declare function fetchDelegatedPrompt(taskId: string): Promise<DelegatedPromptFetch>;
18
+ export declare function fetchDelegatedPrompt(taskId: string, opts?: {
19
+ wire?: DelegatedPromptWire;
20
+ }): Promise<DelegatedPromptFetch>;
13
21
  export {};
@@ -1,8 +1,10 @@
1
1
  import { stripSystemReminderBlocks } from '../systemReminderTag.js';
2
2
  import { hostLog } from '../host.js';
3
- import { makeEngineWireClient } from '../engineWireSdk.js';
4
- import { engineWireTargetFor } from '../engineWireTarget.js';
3
+ import { clientHasVerbs, engineWireFor, INJECTED_WIRE_SETTLE_MS, settleInjected } from '../engineWireFor.js';
5
4
  import { resolveOwnerContext } from './engineSubagentResume.js';
5
+ function usableDelegatedPromptClient(client) {
6
+ return clientHasVerbs(client, [['sessions', 'get']]);
7
+ }
6
8
  const TAIL_WINDOW = 200;
7
9
  const BLOB_CAP = 8 * 1024;
8
10
  const transcriptIdByTask = new Map();
@@ -89,27 +91,25 @@ let transcriptWindowReader = null;
89
91
  export function __setTranscriptWindowReaderForTests(r) {
90
92
  transcriptWindowReader = r;
91
93
  }
92
- async function readTranscriptWindow(transcriptId, sessionKey) {
94
+ async function readTranscriptWindow(transcriptId, sessionKey, injectedWire) {
93
95
  if (transcriptWindowReader)
94
96
  return transcriptWindowReader(transcriptId);
95
- const cfg = engineWireTargetFor(sessionKey);
96
- if (!cfg)
97
+ const wire = engineWireFor(injectedWire, sessionKey, usableDelegatedPromptClient);
98
+ if (wire.kind === 'no-target' || wire.kind === 'injected-unusable')
97
99
  return null;
98
- const client = makeEngineWireClient({
99
- baseUrl: cfg.baseUrl,
100
- ...(cfg.token ? { token: cfg.token } : {}),
101
- principal: cfg.principal,
102
- });
100
+ const client = wire.kind === 'injected' ? wire.client : wire.make();
103
101
  if (!client)
104
102
  return null;
105
- const rec = await client.sessions.get(transcriptId, {
106
- tail: TAIL_WINDOW,
107
- blobCap: BLOB_CAP,
108
- });
103
+ const rec = wire.kind === 'injected'
104
+ ? await settleInjected(INJECTED_WIRE_SETTLE_MS, undefined, (signal) => client.sessions.get(transcriptId, { tail: TAIL_WINDOW, blobCap: BLOB_CAP, signal }))
105
+ : await client.sessions.get(transcriptId, {
106
+ tail: TAIL_WINDOW,
107
+ blobCap: BLOB_CAP,
108
+ });
109
109
  const msgs = rec.messages;
110
110
  return Array.isArray(msgs) ? msgs : null;
111
111
  }
112
- export async function fetchDelegatedPrompt(taskId) {
112
+ export async function fetchDelegatedPrompt(taskId, opts) {
113
113
  if (promptHydrateInFlight.has(taskId))
114
114
  return { outcome: 'skipped' };
115
115
  const transcriptId = transcriptIdByTask.get(taskId);
@@ -118,7 +118,7 @@ export async function fetchDelegatedPrompt(taskId) {
118
118
  promptHydrateInFlight.add(taskId);
119
119
  let msgs = null;
120
120
  try {
121
- msgs = await readTranscriptWindow(transcriptId, resolveOwnerContext(taskId).key);
121
+ msgs = await readTranscriptWindow(transcriptId, resolveOwnerContext(taskId).key, opts?.wire);
122
122
  }
123
123
  catch (e) {
124
124
  promptHydrateInFlight.delete(taskId);
@@ -1,5 +1,5 @@
1
1
  export declare const engineOwnedRowIds: Set<string>;
2
2
  export declare const fleetViewStubRowIds: Set<string>;
3
3
  export declare function isEngineViewRow(taskId: string): boolean;
4
- export declare function engineTaskHandlesCapable(sessionKey?: string): boolean;
5
- export declare function engineRowNeedsStopConfirm(taskId: string, sessionKey?: string): boolean;
4
+ export declare function engineTaskHandlesCapable(sessionKey?: string, capsBaseUrl?: string): boolean;
5
+ export declare function engineRowNeedsStopConfirm(taskId: string, sessionKey?: string, capsBaseUrl?: string): boolean;
@@ -6,9 +6,9 @@ export const fleetViewStubRowIds = new Set();
6
6
  export function isEngineViewRow(taskId) {
7
7
  return engineOwnedRowIds.has(taskId) || fleetViewStubRowIds.has(taskId);
8
8
  }
9
- export function engineTaskHandlesCapable(sessionKey = DEFAULT_SESSION_KEY) {
10
- return engineCapTrue(engineWireTargetFor(sessionKey)?.baseUrl, 'taskHandles');
9
+ export function engineTaskHandlesCapable(sessionKey = DEFAULT_SESSION_KEY, capsBaseUrl) {
10
+ return engineCapTrue(capsBaseUrl ?? engineWireTargetFor(sessionKey)?.baseUrl, 'taskHandles');
11
11
  }
12
- export function engineRowNeedsStopConfirm(taskId, sessionKey) {
13
- return isEngineViewRow(taskId) && engineTaskHandlesCapable(sessionKey ?? DEFAULT_SESSION_KEY);
12
+ export function engineRowNeedsStopConfirm(taskId, sessionKey, capsBaseUrl) {
13
+ return isEngineViewRow(taskId) && engineTaskHandlesCapable(sessionKey ?? DEFAULT_SESSION_KEY, capsBaseUrl);
14
14
  }
@@ -1,3 +1,10 @@
1
+ import type { AgentClient } from '@sema-agent/sdk';
2
+ import type { EngineWireInjection } from '../engineWireSdk.js';
3
+ export type SubagentReportWireClient = {
4
+ capabilities: AgentClient['capabilities'];
5
+ runs: Pick<AgentClient['runs'], 'subagentOutput'>;
6
+ };
7
+ export type SubagentReportWire = EngineWireInjection<SubagentReportWireClient>;
1
8
  export declare function __resetSubagentOutputCapCacheForTests(): void;
2
9
  export interface EngineSubagentReport {
3
10
  content: string;
@@ -5,4 +12,5 @@ export interface EngineSubagentReport {
5
12
  }
6
13
  export declare function fetchEngineSubagentReport(taskId: string, opts?: {
7
14
  signal?: AbortSignal;
15
+ wire?: SubagentReportWire;
8
16
  }): Promise<EngineSubagentReport | null>;