@sema-agent/client-core 0.98.0 → 0.99.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 (192) hide show
  1. package/CHANGELOG.md +199 -0
  2. package/README.md +35 -22
  3. package/dist/adapt/arms.js +61 -20
  4. package/dist/adapt/panelTasks.d.ts +1 -1
  5. package/dist/adapt/panelTasks.js +2 -2
  6. package/dist/adapter/activeRunSelfHeal.d.ts +4 -3
  7. package/dist/adapter/activeRunSelfHeal.js +162 -293
  8. package/dist/adapter/downstream/eventToSdkMessage.js +52 -4
  9. package/dist/adapter/runStream.js +52 -37
  10. package/dist/adapter/types.js +2 -1
  11. package/dist/agentSession/engineSessionBackgroundStop.js +16 -8
  12. package/dist/agentsWireCaps.d.ts +0 -3
  13. package/dist/agentsWireCaps.js +33 -24
  14. package/dist/cloudConfigWireCaps.d.ts +1 -1
  15. package/dist/cloudConfigWireCaps.js +26 -4
  16. package/dist/controlRouter.d.ts +4 -2
  17. package/dist/controlRouter.js +39 -51
  18. package/dist/coreValuePorts.d.ts +26 -1
  19. package/dist/coreValuePorts.js +10 -0
  20. package/dist/corruptSessionCopy.d.ts +2 -1
  21. package/dist/corruptSessionCopy.js +3 -3
  22. package/dist/declared/supportFloorDeclared.js +1 -1
  23. package/dist/detachWire.js +3 -2
  24. package/dist/devicesFace.d.ts +34 -0
  25. package/dist/devicesFace.js +90 -0
  26. package/dist/displayUntrusted.d.ts +1 -0
  27. package/dist/displayUntrusted.js +3 -0
  28. package/dist/engineAgentPanelStore.d.ts +7 -0
  29. package/dist/engineAgentPanelStore.js +14 -0
  30. package/dist/engineCapReader.d.ts +2 -1
  31. package/dist/engineCapReader.js +7 -5
  32. package/dist/engineCapsCache.d.ts +8 -0
  33. package/dist/engineCapsCache.js +59 -6
  34. package/dist/engineCapsChange.d.ts +2 -0
  35. package/dist/engineCapsChange.js +9 -0
  36. package/dist/engineErrorCodes.d.ts +2 -1
  37. package/dist/engineErrorCodes.js +2 -7
  38. package/dist/engineRowRef.js +3 -0
  39. package/dist/engineSessionMessages.d.ts +1 -0
  40. package/dist/engineSessionMessages.js +7 -1
  41. package/dist/engineTargetSeat.d.ts +27 -0
  42. package/dist/engineTargetSeat.js +199 -0
  43. package/dist/engineWireFor.js +3 -8
  44. package/dist/env/uiLanguage.d.ts +2 -1
  45. package/dist/env/uiLanguage.js +3 -2
  46. package/dist/eventLeg.d.ts +8 -0
  47. package/dist/eventLeg.js +61 -41
  48. package/dist/fileHistoryCaptureCapability.d.ts +2 -1
  49. package/dist/fileHistoryCaptureCapability.js +12 -18
  50. package/dist/fileHistoryLegNotice.d.ts +2 -1
  51. package/dist/fileHistoryLegNotice.js +3 -3
  52. package/dist/frameBinding.d.ts +3 -0
  53. package/dist/frameBinding.js +12 -0
  54. package/dist/gateOutcome.js +16 -2
  55. package/dist/gateVocabulary.d.ts +8 -7
  56. package/dist/gateVocabulary.js +71 -73
  57. package/dist/generated/engineFactTables.d.ts +17 -1
  58. package/dist/generated/engineFactTables.js +29 -0
  59. package/dist/generated/engineNoticeTables.js +9 -3
  60. package/dist/generated/settingsSchemaFns.d.ts +6 -0
  61. package/dist/generated/settingsSchemaFns.js +57 -0
  62. package/dist/generated/settingsSchemaHooksClassifier.d.ts +2 -0
  63. package/dist/generated/settingsSchemaHooksClassifier.js +254 -0
  64. package/dist/generated/settingsSchemaTables.d.ts +1 -0
  65. package/dist/generated/settingsSchemaTables.js +4 -0
  66. package/dist/generated/settingsSchemaTypes.d.ts +105 -0
  67. package/dist/generated/settingsSchemaTypes.js +1 -0
  68. package/dist/hitl/allowRuleShadow.d.ts +2 -1
  69. package/dist/hitl/allowRuleShadow.js +17 -14
  70. package/dist/hitl/approvalCardReasons.d.ts +3 -2
  71. package/dist/hitl/approvalCardReasons.js +27 -28
  72. package/dist/hitl/approvalHolds.d.ts +3 -0
  73. package/dist/hitl/approvalHolds.js +73 -29
  74. package/dist/hitl/askClassPair.d.ts +1 -1
  75. package/dist/hitl/askClassPair.js +16 -0
  76. package/dist/hitl/askGateWire.js +2 -1
  77. package/dist/hitl/askSettlementLine.d.ts +14 -4
  78. package/dist/hitl/askSettlementLine.js +67 -47
  79. package/dist/hitl/automaticAnswerVerdict.d.ts +2 -1
  80. package/dist/hitl/automaticAnswerVerdict.js +8 -8
  81. package/dist/hitl/crashConvergedNotice.d.ts +5 -4
  82. package/dist/hitl/crashConvergedNotice.js +28 -41
  83. package/dist/hitl/frameRouter.js +7 -8
  84. package/dist/hitl/hitlBridge.d.ts +1 -0
  85. package/dist/hitl/hitlBridge.js +3 -3
  86. package/dist/hitl/persistedRulesWire.d.ts +6 -5
  87. package/dist/hitl/persistedRulesWire.js +55 -73
  88. package/dist/hitl/planReviewWire.d.ts +5 -0
  89. package/dist/hitl/planReviewWire.js +8 -0
  90. package/dist/hitl/sessionPolicyDeliverable.d.ts +2 -0
  91. package/dist/hitl/sessionPolicyDeliverable.js +46 -3
  92. package/dist/hitl/sessionPolicyWire.d.ts +2 -1
  93. package/dist/hitl/sessionPolicyWire.js +23 -24
  94. package/dist/hitl/suspendedReopen.d.ts +2 -1
  95. package/dist/hitl/suspendedReopen.js +7 -10
  96. package/dist/hitl/toolApprovalWire.d.ts +17 -5
  97. package/dist/hitl/toolApprovalWire.js +79 -40
  98. package/dist/hooksWireCaps.js +145 -56
  99. package/dist/host.d.ts +21 -0
  100. package/dist/hostTurnSettings.d.ts +71 -0
  101. package/dist/hostTurnSettings.js +291 -0
  102. package/dist/humanTurn.d.ts +14 -1
  103. package/dist/humanTurn.js +100 -12
  104. package/dist/humanTurnRead.d.ts +2 -0
  105. package/dist/humanTurnRead.js +22 -1
  106. package/dist/i18n/messages.en.d.ts +582 -0
  107. package/dist/i18n/messages.en.js +582 -0
  108. package/dist/i18n/messages.zh.js +718 -1
  109. package/dist/index.d.ts +29 -13
  110. package/dist/index.js +18 -9
  111. package/dist/inheritEnvCapability.d.ts +3 -2
  112. package/dist/inheritEnvCapability.js +3 -3
  113. package/dist/inheritEnvWire.d.ts +3 -2
  114. package/dist/inheritEnvWire.js +12 -14
  115. package/dist/interactiveHalt.js +17 -6
  116. package/dist/liveModelCatalog.d.ts +2 -1
  117. package/dist/liveModelCatalog.js +14 -8
  118. package/dist/mcpPanel.d.ts +10 -1
  119. package/dist/mcpPanel.js +40 -13
  120. package/dist/mcpProbeCapability.d.ts +2 -1
  121. package/dist/mcpProbeCapability.js +7 -11
  122. package/dist/mcpProbeWire.d.ts +3 -1
  123. package/dist/mcpProbeWire.js +5 -0
  124. package/dist/mcpWireCaps.d.ts +34 -0
  125. package/dist/mcpWireCaps.js +117 -17
  126. package/dist/memoryEntriesWire.js +5 -10
  127. package/dist/model/onboardJudgement.d.ts +93 -0
  128. package/dist/model/onboardJudgement.js +415 -0
  129. package/dist/model/tierVocabulary.d.ts +2 -0
  130. package/dist/model/tierVocabulary.js +17 -5
  131. package/dist/modelCapabilityProbe.d.ts +64 -0
  132. package/dist/modelCapabilityProbe.js +600 -0
  133. package/dist/modelIdentityResolvability.d.ts +3 -0
  134. package/dist/modelIdentityResolvability.js +26 -17
  135. package/dist/ownKey.d.ts +7 -0
  136. package/dist/ownKey.js +34 -0
  137. package/dist/panelReduce.d.ts +6 -1
  138. package/dist/panelReduce.js +50 -3
  139. package/dist/permissionRuleIssue.js +2 -0
  140. package/dist/permissionRulesWriteCapability.d.ts +2 -1
  141. package/dist/permissionRulesWriteCapability.js +8 -6
  142. package/dist/pluginHooksWire.d.ts +46 -3
  143. package/dist/pluginHooksWire.js +217 -11
  144. package/dist/printModelStatus.d.ts +63 -0
  145. package/dist/printModelStatus.js +155 -0
  146. package/dist/request/taskRequest.d.ts +11 -5
  147. package/dist/request/taskRequest.js +112 -16
  148. package/dist/resumeRefusalCopy.d.ts +12 -9
  149. package/dist/resumeRefusalCopy.js +70 -143
  150. package/dist/retryStatus.d.ts +37 -0
  151. package/dist/retryStatus.js +79 -0
  152. package/dist/scenarioRefusal.d.ts +9 -0
  153. package/dist/scenarioRefusal.js +111 -0
  154. package/dist/seam.d.ts +25 -1
  155. package/dist/seam.js +10 -1
  156. package/dist/seatContract.d.ts +260 -10
  157. package/dist/seatContract.js +692 -19
  158. package/dist/selfOrchestrationDenial.js +7 -19
  159. package/dist/sessionIdSegment.d.ts +6 -0
  160. package/dist/sessionIdSegment.js +24 -0
  161. package/dist/sessionMemoryStatus.js +6 -11
  162. package/dist/sessionPolicyCapability.d.ts +2 -1
  163. package/dist/sessionPolicyCapability.js +8 -6
  164. package/dist/settingsHooksSalvage.d.ts +44 -0
  165. package/dist/settingsHooksSalvage.js +211 -0
  166. package/dist/skillToolListsCapability.d.ts +2 -1
  167. package/dist/skillToolListsCapability.js +8 -6
  168. package/dist/sseIdleTriage.js +3 -2
  169. package/dist/subagent/engineSubagentResume.js +15 -9
  170. package/dist/subagentContentStore.d.ts +3 -0
  171. package/dist/subagentContentStore.js +22 -0
  172. package/dist/toolHistoryMismatch.js +3 -2
  173. package/dist/toolRoster.d.ts +3 -2
  174. package/dist/toolRoster.js +21 -20
  175. package/dist/turnFailurePresentation.d.ts +12 -1
  176. package/dist/turnFailurePresentation.js +212 -15
  177. package/dist/usageAnalytics.js +6 -11
  178. package/dist/userAttachmentEnvelope.d.ts +1 -0
  179. package/dist/userAttachmentEnvelope.js +37 -7
  180. package/dist/userAttachmentSeat.d.ts +21 -0
  181. package/dist/userAttachmentSeat.js +75 -0
  182. package/dist/userInvokedSkillsCapability.d.ts +11 -1
  183. package/dist/userInvokedSkillsCapability.js +31 -7
  184. package/dist/wireErrorTriage.d.ts +7 -0
  185. package/dist/wireErrorTriage.js +23 -1
  186. package/dist/wireFailureShape.js +2 -1
  187. package/dist/wireRefusalCopy.d.ts +13 -1
  188. package/dist/wireRefusalCopy.js +24 -28
  189. package/dist/workflowsJournalCapability.d.ts +2 -1
  190. package/dist/workflowsJournalCapability.js +8 -6
  191. package/docs/INTEGRATION-CLIENTS.md +542 -30
  192. package/package.json +5 -5
@@ -1,8 +1,10 @@
1
1
  import { refuseBadDisableSkills, refuseDisableSkillsConflict } from '../disableSkillsWire.js';
2
2
  import { ATTACHMENTS_SPEC_KEYS, AttachmentsSpecRefused } from '../attachmentsWireCaps.js';
3
3
  import { retiredAttachmentsKeyOf } from '../taskRequestWords.js';
4
+ import { msg, renderMessage } from '../i18n/translate.js';
4
5
  import { outputStyleSeatAdmitted } from '../outputStyleSeatCapability.js';
5
6
  import { refuseBadApprovalReach } from '../approvalReachWire.js';
7
+ import { HOST_SUPPLIED_KEYS, HostSettingsRefused, buildHostTurnSettings, hostTurnSettingsOf, rethrowHostResolvedDeferred, } from '../hostTurnSettings.js';
6
8
  export const REQUEST_FIELD_MATRIX = [
7
9
  { field: 'objective', lanes: ['interactive', 'print', 'utility'], live: false, why: '本 turn 的真实输入,每条车道都必需', whyUtilityLane: '恒座:三条车道都必须带上本次提交的模型面输入' },
8
10
  { field: 'sessionId', lanes: ['interactive', 'print', 'utility'], live: false, why: '单命名空间(TP-A Step 2):壳 id 即引擎 session id;print 在非 live 下保留 mock 常量', whyUtilityLane: '恒座:side-channel 提交走**独立**会话 id(壳另铸一个,绝不复用用户会话那一个 —— 复用会把这次提交的转录混进用户会话)' },
@@ -16,6 +18,7 @@ export const REQUEST_FIELD_MATRIX = [
16
18
  { field: 'enableFork', lanes: ['interactive', 'print'], live: true, why: '显式布尔才 stamp([503]② fail-OPEN 教训:off 必须显式)', whyUtilityLane: '无座:分叉是会话面的动作,而 side-channel 提交是一次性的独立会话' },
17
19
  { field: 'attachments', lanes: ['interactive', 'print'], live: true, why: 'design/133 + G1 缺省开的 turn 边界 attachment', whyUtilityLane: '无座:turn 边界的附件配置属用户会话;side-channel 提交不带附件' },
18
20
  { field: 'skills', lanes: ['interactive', 'print'], live: true, why: '本地技能目录投影(布局取 CC 同款);两条车道都由 launchRepl 载入面注入', whyUtilityLane: '无座:技能挂的是工具,与零工具面矛盾' },
21
+ { field: 'userInvokedSkills', lanes: ['interactive', 'print'], live: true, why: '人用名字点过的技能(sdk `TaskRequest.userInvokedSkills`:非空串数组;这些技能的 allowedTools / disallowedTools 开跑即生效、不出技能卡,只管这一次 run)。两条用户车道都有「人敲 /技能名」的入口 ⇒ 都有座。🔴 放宽方向:值只经片段口给(能力读数 present 才给键);空数组 = 没点名 ⇒ 不 stamp;坏形(不是串数组)装配期响亮拒;名字对不对归引擎判(`config.user_invoked_skill_unknown`)', whyUtilityLane: '无座:技能挂的是工具,与零工具面矛盾(与 skills 一行同理)' },
19
22
  { field: 'mcpServers', lanes: ['interactive', 'print'], live: true, why: '本地 .mcp.json 投影;service 单用户门决定是否兑现', whyUtilityLane: '无座:MCP 服务挂的是工具,与零工具面矛盾' },
20
23
  { field: 'settings.webSearch', lanes: ['interactive', 'print'], live: true, why: 'SEMA_WEBSEARCH_* / settings.json;per-request 配置赢过部署 env', whyUtilityLane: '无座:联网检索是一只工具,与零工具面矛盾' },
21
24
  { field: 'settings.hooks', lanes: ['interactive', 'print'], live: true, why: '[495]① 用户 settings 文件 hooks 逐字上 wire', whyUtilityLane: '无座:hook 挂在工具门上(零工具面没有门),而且 side-channel 是壳自己的提交,不该继承用户那份 hook 表' },
@@ -44,6 +47,7 @@ export const REQUEST_FIELD_MATRIX = [
44
47
  { field: 'reasoningEffort', lanes: ['interactive', 'print', 'utility'], live: false, why: '思考档位(sdk `TaskRequest.reasoningEffort` 七词闭集;上游对表外词 400 响亮拒 ⇒ 本层不预铸第二判官)。档位是请求级的位、与车道无关:交互面 = `/effort` 拨盘,无人值守面 = 档位旗。🔴 端交的必须是**档位词**:「思考 token 数」今天没有上游对位(见 `UPSTREAM_ABSENT_REQUEST_INTENTS` 的 `maxThinkingTokens`),别把一个数字折成档位词发出去', whyUtilityLane: '有座:side-channel 该用显式低档(省钱省时);与 model 同一条理由 —— 本车道上这两位都由壳显式给,不跟用户会话的拨盘走' },
45
48
  { field: 'model', lanes: ['interactive', 'print', 'utility'], live: false, why: '模型选择(sdk `TaskRequest.model`;交互面 = `/model` 中途换模型的拨盘,无人值守面 = 模型旗 / 部署缺省那一路,side-channel 面 = 壳显式挑的那一只)。三条车道都有来源、都是提交面。🔴 0.79.0 改口:修前「print 的模型走另一条路」这句理由被用户面实测证伪 —— 无人值守车道传了模型名却整键不上请求体,于是同一个坏名字在交互态被引擎 400 点名、在无人值守态却安静换成部署缺省并在首帧回显一个没生效的名字。一个**选择**类声明被静默丢掉,后果与收紧类声明被静默丢掉同形(端不读回执就以为生效)—— 与 `excludeTools` 补 print 座同律。本层原样透传、不预判模型名(名字的合法性归引擎,本层不铸第二判官)', whyUtilityLane: '有座:side-channel 显式挑便宜的那只模型(不跟用户会话的 `/model` 拨盘走)' },
46
49
  { field: 'images', lanes: ['interactive', 'print'], live: false, why: '图片输入(sdk `TaskRequest.images`;base64 / url 两形,原样透传)。两条用户车道都是提交面、都有来源:交互面 = 粘贴图与 `@` 图片像素,一次性车道 = 结构化输入里的图片块。张数、单张与合计的座位判定归人类提交装配口 `encodeHumanTurn`(两条车道同一份判定,本表不另判);请求体与图片张数的上限归上游判', whyUtilityLane: '无座:贴图是交互动作,side-channel 的提交体里没有图片块' },
50
+ { field: 'userAttachments', lanes: ['interactive', 'print'], live: false, why: '请求层附件(sdk `TaskRequest.userAttachments`:挂在这次提交目标上的 `@` 文本类附件条目,引擎铸帧、在第一次模型调用之前判形)。两条用户车道都是提交面、都经同一只装配口 `encodeHumanTurn`(条目只在这台引擎的席位读数判 `yes` 时出;老服务端对这一键 400,所以没有条目就不发);空数组 = 没带附件 ⇒ 整键不 stamp。座位集与 `images` 一行逐字相同', whyUtilityLane: '无座:side-channel 是壳自己的一次性提交,没有用户 `@` 附件' },
47
51
  { field: 'resumeAt/resumeAtMode/restoreFiles/rewindFilesTo', lanes: ['interactive'], live: false, why: 'E18 `/rewind` 是交互命令;四键同生同灭(CC-145:core 6.0.0 起 both 臂发 restoreFiles;CC-223 起退役键 rewindFiles 不再有座 —— 交它按表外子键响亮拒;resumeAtMode 是 both/conversation 两臂恒带的排他截语义位)', whyUtilityLane: '无座:回退是交互命令,而 side-channel 是一次性的独立会话,没有可回退的历史' },
48
52
  { field: 'clientContext', lanes: ['interactive'], live: false, why: 'IANA 时区 + 可选邮箱 → core 本地化 `# Environment` 的 today;print 同样跑在用户机器上,缺席让引擎误标 (UTC)', gap: true, whyUtilityLane: '无座:本地化 today 的用途在用户会话的环境段,而 side-channel 的系统提示由壳整段给出 —— 这一列我判不准要不要(与本行 `gap` 同一条待办:要补先单独立项)' },
49
53
  { field: 'scratchpadDir', lanes: ['interactive'], live: true, why: '[816]③ per-session 暂存目录;print 也有 session,缺席让 `-p` 的工具写不进 exemptDir', gap: true, whyUtilityLane: '无座:per-session 暂存目录是给**工具**写的,零工具面上没人写' },
@@ -122,7 +126,9 @@ const INPUT_KEY_ROUTES = {
122
126
  reasoningEffort: row('reasoningEffort'),
123
127
  model: row('model'),
124
128
  images: row('images'),
129
+ userAttachments: row('userAttachments'),
125
130
  skills: row('skills'),
131
+ userInvokedSkills: row('userInvokedSkills'),
126
132
  mcpServers: row('mcpServers'),
127
133
  clientContext: row('clientContext'),
128
134
  scratchpadDir: row('scratchpadDir'),
@@ -170,8 +176,12 @@ const INPUT_KEY_ROUTES = {
170
176
  rewind: row('resumeAt/resumeAtMode/restoreFiles/rewindFilesTo'),
171
177
  repo: row('repo'),
172
178
  allowTools: row('allowTools'),
179
+ hostSettings: { via: 'control' },
173
180
  settings: { via: 'settings' },
174
181
  };
182
+ const HOST_SETTINGS_SUBKEYS = Object.freeze(HOST_SUPPLIED_KEYS.filter((k) => k.startsWith('settings.')).map((k) => k.slice('settings.'.length)));
183
+ const _hostSubkeysPin = [true, true, true, true];
184
+ void _hostSubkeysPin;
175
185
  const SETTINGS_KEY_ROUTES = {
176
186
  resolved: row('settings.<resolved>'),
177
187
  webSearch: row('settings.webSearch'),
@@ -211,6 +221,35 @@ const OMISSION_JUDGES = {
211
221
  not_live: (s, _lane, live) => s.via === 'matrix' && s.spec.live && !live,
212
222
  };
213
223
  const omissionCauseOf = (s, lane, live) => TASK_REQUEST_OMISSION_CAUSES.find(cause => OMISSION_JUDGES[cause](s, lane, live));
224
+ const hostRefusalNoticeOf = (host, lane, live, verdictNotice) => {
225
+ try {
226
+ const refusing = host.rows.filter((row) => row.disposition === 'refuse_turn');
227
+ if (refusing.length === 0)
228
+ return verdictNotice;
229
+ const turnNotices = host.notices.filter((n) => n.plane === 'turn');
230
+ const aligned = turnNotices.length === refusing.length;
231
+ for (const [i, row] of refusing.entries()) {
232
+ if (!hostRefuseRowSeated(row.key, lane, live))
233
+ continue;
234
+ return aligned ? (turnNotices[i] ?? verdictNotice) : verdictNotice;
235
+ }
236
+ return undefined;
237
+ }
238
+ catch {
239
+ return verdictNotice;
240
+ }
241
+ };
242
+ const hostRefuseRowSeated = (key, lane, live) => {
243
+ const sub = key.slice('settings.'.length);
244
+ if (!hasOwn(SETTINGS_KEY_ROUTES, sub))
245
+ return true;
246
+ const route = SETTINGS_KEY_ROUTES[sub];
247
+ if (route === undefined || route.via === 'always')
248
+ return true;
249
+ if (route.via === 'matrix' || route.via === 'fixed')
250
+ return omissionCauseOf(standingOf(route), lane, live) === undefined;
251
+ return true;
252
+ };
214
253
  const REQUEST_LANE_SET = { interactive: true, print: true, utility: true };
215
254
  export const REQUEST_LANES = Object.freeze(Object.keys(REQUEST_LANE_SET));
216
255
  const refuseBadLane = (lane) => {
@@ -228,6 +267,8 @@ const VALUE_LEVEL_IN_PLAY = Object.freeze({
228
267
  oneShot: (v) => v === true,
229
268
  interactiveTools: (v) => v === false,
230
269
  images: (v) => Array.isArray(v) && v.length > 0,
270
+ userAttachments: (v) => Array.isArray(v) && v.length > 0,
271
+ userInvokedSkills: (v) => Array.isArray(v) && v.length > 0,
231
272
  attachmentIds: (v) => Array.isArray(v) && v.length > 0,
232
273
  excludeTools: (v) => Array.isArray(v) && v.length > 0,
233
274
  excludeAllTools: (v) => v === true,
@@ -402,6 +443,9 @@ const resolvedSnapshotForWire = (resolved) => {
402
443
  }
403
444
  return out;
404
445
  };
446
+ export function hostTurnSettings(input) {
447
+ return buildHostTurnSettings(input, (snapshot) => resolvedSnapshotForWire(snapshot));
448
+ }
405
449
  export const MEMORY_CAPTURE_OFF = 'off';
406
450
  export function memoryCaptureDeclarationField(declared) {
407
451
  return declared ? { memoryCapture: MEMORY_CAPTURE_OFF } : {};
@@ -427,11 +471,11 @@ export function memoryOffDeclared(input) {
427
471
  const sm = input.settingsMemory;
428
472
  if (sm !== undefined && sm !== null) {
429
473
  if (typeof sm !== 'object' || Array.isArray(sm)) {
430
- throw new TypeError(`memoryOffDeclared: settings 的 memory 段必须是对象 —— 收到 ${coarseShape(sm)}。`);
474
+ throw new TypeError(renderMessage(msg('config.taskRequest.memoryOff.settingsSectionNotObject', { shape: coarseShape(sm) })));
431
475
  }
432
476
  const enabled = sm.enabled;
433
477
  if (enabled !== undefined && typeof enabled !== 'boolean') {
434
- throw new TypeError(`memoryOffDeclared: settings memory.enabled 在场时必须是布尔 —— 收到 ${coarseShape(enabled)}。`);
478
+ throw new TypeError(renderMessage(msg('config.taskRequest.memoryOff.enabledNotBoolean', { shape: coarseShape(enabled) })));
435
479
  }
436
480
  fromSettings = enabled === false;
437
481
  }
@@ -530,6 +574,23 @@ const refuseBadAllowTools = (v) => {
530
574
  `收到 ${coarseShape(v)}。这一位是**可用性选择器**(收紧声明):本层若把坏形静默删键,这一次运行会挂上声明人以为已经收窄掉的全部工具。` +
531
575
  '错误文本只报形状,不回显值。');
532
576
  };
577
+ const refuseBadUserInvokedSkills = (v) => {
578
+ if (v === undefined || v === null)
579
+ return;
580
+ if (Array.isArray(v) && v.length <= ALLOW_TOOLS_MAX_LENGTH) {
581
+ let ok = true;
582
+ for (let k = 0; k < v.length; k += 1) {
583
+ const d = Object.getOwnPropertyDescriptor(v, k);
584
+ if (d === undefined || !('value' in d) || typeof d.value !== 'string') {
585
+ ok = false;
586
+ break;
587
+ }
588
+ }
589
+ if (ok)
590
+ return;
591
+ }
592
+ throw new TypeError(renderMessage(msg('config.taskRequest.userInvokedSkillsMalformed', { shape: coarseShape(v) })));
593
+ };
533
594
  const refuseBadExcludeAllTools = (v) => {
534
595
  if (v === undefined || v === null || v === true || v === false)
535
596
  return;
@@ -563,13 +624,16 @@ const refuseBadRequireExistingSession = (v) => {
563
624
  '上游对非布尔值同样拒收。错误文本只报形状,不回显值。');
564
625
  };
565
626
  const hasResumableSessionId = (sid) => typeof sid === 'string' && sid.length > 0;
566
- const refuseRequireExistingWithoutSession = (requireExisting, sessionId) => {
627
+ const refuseRequireExistingWithoutSession = (requireExisting, sessionId, where = 'buildTaskRequest') => {
567
628
  if (requireExisting !== true || hasResumableSessionId(sessionId))
568
629
  return;
569
- const shape = sessionId === undefined ? '缺席' : typeof sessionId === 'string' ? '空串' : coarseShape(sessionId);
570
- throw new TypeError(`buildTaskRequest: requireExistingSession: true 要求续一个已存在的会话,但 sessionId ${shape} —— 没有可续的会话。` +
571
- '上游对这一形同样拒收(不会新开会话,也不会续上任何东西);本层在装配前拒,不让它走一次往返。' +
572
- '处置:要续哪个会话,就把它的 id 交在 sessionId 上;要开新会话,就别带 requireExistingSession(或给 false)。错误文本只报形状,不回显值。');
630
+ const shape = sessionId === undefined
631
+ ? renderMessage(msg('config.taskRequest.requireExisting.shapeAbsent'))
632
+ : typeof sessionId === 'string'
633
+ ? renderMessage(msg('config.taskRequest.requireExisting.shapeEmpty'))
634
+ : coarseShape(sessionId);
635
+ const layer = renderMessage(msg(where === 'buildTaskRequest' ? 'config.taskRequest.requireExisting.layerAssembly' : 'config.taskRequest.requireExisting.layerLive'));
636
+ throw new TypeError(renderMessage(msg('config.taskRequest.requireExisting.noSession', { where, shape, layer })));
573
637
  };
574
638
  const refuseBadMaxTokens = (v) => {
575
639
  if (v === undefined || v === null)
@@ -640,15 +704,15 @@ export function parseMaxCostUsd(text) {
640
704
  return { ok: false, why: 'not_positive' };
641
705
  return { ok: true, value };
642
706
  }
643
- const ACCESSOR_READ_ORDER = ['live', 'memoryCapture', 'memory', 'settings', 'maxCostUsd', 'excludeAllTools', 'maxTokens', 'outputRetries', 'fileHistory', 'inheritEnv', 'requireExistingSession', 'disableSkills', 'approvalReach', 'allowTools'];
644
- const MATERIALIZE_AT_READ = Object.freeze({ allowTools: (v) => allowToolsSnapshot(v) });
707
+ const ACCESSOR_READ_ORDER = ['live', 'memoryCapture', 'memory', 'hostSettings', 'settings', 'maxCostUsd', 'excludeAllTools', 'maxTokens', 'outputRetries', 'fileHistory', 'inheritEnv', 'requireExistingSession', 'disableSkills', 'approvalReach', 'allowTools', 'userInvokedSkills'];
708
+ const MATERIALIZE_AT_READ = Object.freeze({ allowTools: (v) => allowToolsSnapshot(v), userInvokedSkills: (v) => allowToolsSnapshot(v) });
645
709
  function dataFirstSnapshot(input, afterData) {
646
710
  let descs;
647
711
  try {
648
712
  descs = Object.getOwnPropertyDescriptors(input);
649
713
  }
650
714
  catch {
651
- throw new TypeError('buildTaskRequest: 入参的键集 / 属性描述符读不出(代理 trap 抛)—— 无法安全快照声明,拒绝装配。错误文本只报形状,不回显值。');
715
+ throw new TypeError(renderMessage(msg('config.taskRequest.inputKeysUnreadable')));
652
716
  }
653
717
  const bag = Object.create(null);
654
718
  const accessors = [];
@@ -679,11 +743,14 @@ export function assembleTaskRequest(input, lane) {
679
743
  let resolvedMaterializeError;
680
744
  let resolvedHookRan = false;
681
745
  const src = dataFirstSnapshot(input, (bag) => {
682
- const st = bag['settings'];
683
- if (present(st) && typeof st === 'object' && !Array.isArray(st)) {
746
+ if (!Object.hasOwn(bag, 'hostSettings'))
747
+ return;
748
+ const product = hostTurnSettingsOf(bag['hostSettings'], 'shape');
749
+ if (product !== undefined) {
684
750
  resolvedHookRan = true;
685
- resolvedInEarly = st.resolved;
751
+ resolvedInEarly = product.carried.resolved;
686
752
  try {
753
+ rethrowHostResolvedDeferred(product);
687
754
  resolvedMaterialized = resolvedSnapshotForWire(resolvedInEarly);
688
755
  }
689
756
  catch (e) {
@@ -700,11 +767,18 @@ export function assembleTaskRequest(input, lane) {
700
767
  '这一位装着已解析权限面与 hooks:把畸形容器当成「没给」= 请求带着被剥掉的权限面照发。错误文本只报形状,不回显值。');
701
768
  }
702
769
  const settingsObj = present(settingsIn) ? settingsIn : {};
703
- const resolvedIn = resolvedHookRan ? resolvedInEarly : settingsObj.resolved;
770
+ const hostIn = src.hostSettings;
771
+ const host = hostTurnSettingsOf(hostIn);
772
+ if (host === undefined) {
773
+ throw new TypeError(renderMessage(msg('config.taskRequest.hostSettingsMalformed', { shape: coarseShape(hostIn) })));
774
+ }
775
+ const resolvedIn = resolvedHookRan ? resolvedInEarly : host.carried.resolved;
704
776
  const resolvedRoute = SETTINGS_KEY_ROUTES.resolved;
705
777
  const resolvedOpen = resolvedRoute.via === 'matrix' && omissionCauseOf(standingOf(resolvedRoute), lane, live) === undefined;
706
778
  if (resolvedOpen && resolvedHookRan && resolvedMaterializeError !== undefined)
707
779
  throw resolvedMaterializeError;
780
+ if (resolvedOpen && !resolvedHookRan)
781
+ rethrowHostResolvedDeferred(host);
708
782
  const resolvedWire = resolvedOpen ? (resolvedMaterialized ?? resolvedSnapshotForWire(resolvedIn)) : {};
709
783
  const maxCostUsdIn = src.maxCostUsd;
710
784
  const excludeAllToolsIn = src.excludeAllTools;
@@ -734,7 +808,14 @@ export function assembleTaskRequest(input, lane) {
734
808
  settings: settingsIn,
735
809
  });
736
810
  const SETTINGS_KEYS = Object.keys(SETTINGS_KEY_ROUTES);
737
- const s = snapshotByName(settingsObj, SETTINGS_KEYS, { resolved: resolvedIn });
811
+ const hostSettingsKeysIn = HOST_SETTINGS_SUBKEYS.filter((k) => hasOwn(settingsObj, k) && present(Reflect.get(settingsObj, k)));
812
+ const s = {
813
+ resolved: resolvedIn,
814
+ webSearch: host.carried.webSearch,
815
+ ultracode: snapshotByName(settingsObj, ['ultracode']).ultracode,
816
+ hooks: host.carried.hooks,
817
+ outputStyle: host.carried.outputStyle,
818
+ };
738
819
  refuseBadMemoryCapture(memoryCaptureIn);
739
820
  refuseBadMemoryOff(memoryIn);
740
821
  refuseBadMaxCostUsd(maxCostUsdIn);
@@ -747,6 +828,7 @@ export function assembleTaskRequest(input, lane) {
747
828
  refuseBadDisableSkills(disableSkillsIn, 'buildTaskRequest');
748
829
  refuseBadApprovalReach(approvalReachIn, 'buildTaskRequest');
749
830
  refuseBadAllowTools(allowToolsIn);
831
+ refuseBadUserInvokedSkills(i.userInvokedSkills);
750
832
  const rewindRoute = INPUT_KEY_ROUTES.rewind;
751
833
  const RETIRED_REWIND_FILES_KEY = 'rewindFiles';
752
834
  const REWIND_KEYS = rewindRoute.via === 'matrix' ? rewindRoute.field.split('/') : [];
@@ -813,6 +895,12 @@ export function assembleTaskRequest(input, lane) {
813
895
  '处置:删掉这个键;要在回退会话时一并还原文件,改交 ' +
814
896
  'rewind.restoreFiles: true(必须与 rewind.resumeAt 同交);只还原文件、不动会话,交 rewind.rewindFilesTo。错误文本只报键名,不回显值。');
815
897
  }
898
+ if (hostSettingsKeysIn.length > 0) {
899
+ throw new TypeError(renderMessage(msg('config.taskRequest.hostSuppliedKeysByHand', {
900
+ keys: hostSettingsKeysIn.map((k) => `settings.${k}`).join(', '),
901
+ fields: hostSettingsKeysIn.map((k) => `${k}: …`).join(', '),
902
+ })));
903
+ }
816
904
  if (unknownKeys.length > 0) {
817
905
  const shown = unknownKeys.slice(0, MAX_UNKNOWN_KEYS_SHOWN).map(keyForDisplay).join(', ');
818
906
  const more = unknownKeys.length > MAX_UNKNOWN_KEYS_SHOWN ? ` 等共 ${unknownKeys.length} 个` : '';
@@ -826,6 +914,11 @@ export function assembleTaskRequest(input, lane) {
826
914
  refuseRequireExistingWithoutSession(requireExistingSessionIn, i.sessionId);
827
915
  refuseDisableSkillsConflict(disableSkillsIn, i.skills, Reflect.get(src, 'agents'), 'buildTaskRequest');
828
916
  refuseUtilityWithoutToolUnload(lane, excludeAllToolsIn);
917
+ if (host.verdict.kind === 'refuse') {
918
+ const refusing = hostRefusalNoticeOf(host, lane, live, host.verdict.notice);
919
+ if (refusing !== undefined)
920
+ throw new HostSettingsRefused(refusing);
921
+ }
829
922
  const carries = (route, value, key) => {
830
923
  if (route.via === 'always')
831
924
  return present(value);
@@ -867,7 +960,9 @@ export function assembleTaskRequest(input, lane) {
867
960
  ...(on('reasoningEffort') ? { reasoningEffort: i.reasoningEffort } : {}),
868
961
  ...(on('model') ? { model: i.model } : {}),
869
962
  ...(on('images') ? { images: i.images } : {}),
963
+ ...(on('userAttachments') ? { userAttachments: [...(i.userAttachments ?? [])] } : {}),
870
964
  ...(on('skills') ? { skills: i.skills } : {}),
965
+ ...(on('userInvokedSkills') ? { userInvokedSkills: allowToolsCopy(i.userInvokedSkills) } : {}),
871
966
  ...(on('mcpServers') ? { mcpServers: i.mcpServers } : {}),
872
967
  ...(on('rewind') ? rewindWire : {}),
873
968
  ...(on('permissionMode') ? { permissionMode: i.permissionMode } : {}),
@@ -902,7 +997,7 @@ export function assembleTaskRequest(input, lane) {
902
997
  ...(on('approvalReach') ? { approvalReach: approvalReachIn } : {}),
903
998
  ...(Object.keys(settingsOut).length > 0 ? { settings: settingsOut } : {}),
904
999
  };
905
- return Object.freeze({ request: out, omitted: Object.freeze([...omitted, ...lateOmitted]) });
1000
+ return Object.freeze({ request: out, omitted: Object.freeze([...omitted, ...lateOmitted]), host });
906
1001
  }
907
1002
  export function buildTaskRequest(input, lane) {
908
1003
  return assembleTaskRequest(input, lane).request;
@@ -955,6 +1050,7 @@ export function applyLiveRequestDefaults(req, host) {
955
1050
  out.sessionId === host.mockSessionIdConstant) {
956
1051
  delete out.sessionId;
957
1052
  }
1053
+ refuseRequireExistingWithoutSession(out.requireExistingSession, out.sessionId, 'applyLiveRequestDefaults');
958
1054
  return out;
959
1055
  }
960
1056
  export function unregisteredRequestKeys(req, lane) {
@@ -1,3 +1,4 @@
1
+ import type { UiLanguage } from './env/uiLanguage.js';
1
2
  import type { ResumeStartupCause } from '@sema-agent/sdk';
2
3
  import { RESUME_CONTEXT_UNAVAILABLE, CHECKPOINT_UNSUPPORTED_VERSION, CHECKPOINT_WALLTIME_AXIS_RETIRED, CHECKPOINT_CONFIG_REFUSED } from './engineErrorCodes.js';
3
4
  export declare const RESUME_REFUSAL_CODES: readonly string[];
@@ -7,7 +8,7 @@ export interface ResumeRefusalDetail {
7
8
  waitable: boolean;
8
9
  }
9
10
  export declare function resumeRefusalFromError(err: unknown): ResumeRefusalDetail | null;
10
- export declare function resumeRefusalContent(detail: ResumeRefusalDetail): string;
11
+ export declare function resumeRefusalContent(detail: ResumeRefusalDetail, lang?: UiLanguage): string;
11
12
  export interface ResumePolicyBlockDetail {
12
13
  blockedBy: {
13
14
  kind: 'named';
@@ -19,7 +20,7 @@ export interface ResumePolicyBlockDetail {
19
20
  };
20
21
  }
21
22
  export declare function resumePolicyBlockFromError(err: unknown): ResumePolicyBlockDetail | null;
22
- export declare function resumePolicyBlockContent(detail: ResumePolicyBlockDetail): string;
23
+ export declare function resumePolicyBlockContent(detail: ResumePolicyBlockDetail, lang?: UiLanguage): string;
23
24
  export { resumeReopenFromError, resumeReopenContent } from './hitl/suspendedReopen.js';
24
25
  export type { ResumeReopenDetail } from './hitl/suspendedReopen.js';
25
26
  export type RequireExistingSessionRefusalForm = 'session_not_found' | 'session_id_missing';
@@ -28,26 +29,28 @@ export interface RequireExistingSessionRefusalDetail {
28
29
  readonly form: RequireExistingSessionRefusalForm;
29
30
  }
30
31
  export declare function requireExistingSessionRefusalFromError(err: unknown): RequireExistingSessionRefusalDetail | null;
31
- export declare function requireExistingSessionRefusalContent(detail: Pick<RequireExistingSessionRefusalDetail, 'form'>): string;
32
+ export declare function requireExistingSessionRefusalContent(detail: Pick<RequireExistingSessionRefusalDetail, 'form'>, lang?: UiLanguage): string;
32
33
  export interface ResumeContextUnavailableDetail {
33
34
  code: typeof RESUME_CONTEXT_UNAVAILABLE;
34
35
  staleAfterSec?: number;
35
36
  runId?: string;
36
37
  }
37
38
  export declare function resumeContextUnavailableFromError(err: unknown): ResumeContextUnavailableDetail | null;
38
- export declare function resumeContextUnavailableContent(d: ResumeContextUnavailableDetail): string;
39
+ export declare function resumeContextUnavailableContent(d: ResumeContextUnavailableDetail, lang?: UiLanguage): string;
39
40
  export type ParkedResumeStartupDecision = 'approve' | 'deny';
40
41
  export type ParkedResumeStartupCause = 'resume_rejected' | 'undetermined';
41
42
  export interface ParkedResumeStartupDetail {
42
43
  code: string;
43
44
  cause: ParkedResumeStartupCause;
44
45
  taskId?: string;
45
- startupCause?: ResumeStartupCause;
46
+ startupCause?: ResumeStartupCause | ResumeCauseCoreAhead;
46
47
  resendable: false;
47
48
  denyStaysOpen: true;
48
49
  }
50
+ declare const RESUME_CAUSE_CORE_AHEAD: readonly ["transcript_corrupt"];
51
+ type ResumeCauseCoreAhead = (typeof RESUME_CAUSE_CORE_AHEAD)[number];
49
52
  export declare function parkedResumeStartupFromError(err: unknown, decision?: ParkedResumeStartupDecision): ParkedResumeStartupDetail | null;
50
- export declare function parkedResumeStartupContent(detail: ParkedResumeStartupDetail): string;
53
+ export declare function parkedResumeStartupContent(detail: ParkedResumeStartupDetail, lang?: UiLanguage): string;
51
54
  export interface CheckpointUnsupportedVersionDetail {
52
55
  code: 'checkpoint.unsupported_version';
53
56
  retriable: true;
@@ -60,7 +63,7 @@ export interface CheckpointUnsupportedVersionContext {
60
63
  readonly parkKind?: CheckpointUnsupportedParkKind;
61
64
  readonly runId?: string;
62
65
  }
63
- export declare function checkpointUnsupportedVersionContent(detail: CheckpointUnsupportedVersionDetail, ctx?: CheckpointUnsupportedVersionContext): string;
66
+ export declare function checkpointUnsupportedVersionContent(detail: CheckpointUnsupportedVersionDetail, ctx?: CheckpointUnsupportedVersionContext, lang?: UiLanguage): string;
64
67
  export type RefusedParkCode = typeof CHECKPOINT_UNSUPPORTED_VERSION | typeof CHECKPOINT_WALLTIME_AXIS_RETIRED | typeof CHECKPOINT_CONFIG_REFUSED;
65
68
  export interface RefusedParkFacts {
66
69
  readonly code: RefusedParkCode;
@@ -74,5 +77,5 @@ export interface RefusedParkContentInput {
74
77
  readonly lane: 'interactive' | 'print';
75
78
  readonly runId?: string;
76
79
  }
77
- export declare function refusedParkContent(input: RefusedParkContentInput): string;
78
- export declare function refusedParkBlockedContent(taskId: string, lane?: 'interactive' | 'print'): string;
80
+ export declare function refusedParkContent(input: RefusedParkContentInput, lang?: UiLanguage): string;
81
+ export declare function refusedParkBlockedContent(taskId: string, lane?: 'interactive' | 'print', lang?: UiLanguage): string;