@sema-agent/client-core 0.98.0 → 0.100.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 (236) hide show
  1. package/CHANGELOG.md +376 -0
  2. package/README.md +61 -35
  3. package/dist/adapt/arms.js +120 -55
  4. package/dist/adapt/panelTasks.d.ts +3 -2
  5. package/dist/adapt/panelTasks.js +34 -11
  6. package/dist/adapt/textStream.d.ts +1 -1
  7. package/dist/adapt/textStream.js +51 -28
  8. package/dist/adapter/activeRunSelfHeal.d.ts +11 -3
  9. package/dist/adapter/activeRunSelfHeal.js +210 -294
  10. package/dist/adapter/downstream/eventToSdkMessage.d.ts +25 -6
  11. package/dist/adapter/downstream/eventToSdkMessage.js +176 -12
  12. package/dist/adapter/downstream/terminalToSdkResult.js +10 -0
  13. package/dist/adapter/downstream/wiringManifestView.d.ts +3 -1
  14. package/dist/adapter/downstream/wiringManifestView.js +1 -0
  15. package/dist/adapter/runStream.js +82 -40
  16. package/dist/adapter/types.d.ts +2 -0
  17. package/dist/adapter/types.js +2 -1
  18. package/dist/agentSession/engineSessionBackgroundStop.js +16 -8
  19. package/dist/agentsWireCaps.d.ts +7 -3
  20. package/dist/agentsWireCaps.js +133 -39
  21. package/dist/cloudConfigWireCaps.d.ts +10 -1
  22. package/dist/cloudConfigWireCaps.js +181 -65
  23. package/dist/compactionStatus.d.ts +34 -0
  24. package/dist/compactionStatus.js +196 -0
  25. package/dist/controlRouter.d.ts +4 -2
  26. package/dist/controlRouter.js +39 -51
  27. package/dist/coreValuePorts.d.ts +26 -1
  28. package/dist/coreValuePorts.js +10 -0
  29. package/dist/corruptSessionCopy.d.ts +2 -1
  30. package/dist/corruptSessionCopy.js +3 -3
  31. package/dist/decideFailureNote.js +3 -3
  32. package/dist/declared/supportFloorDeclared.js +1 -1
  33. package/dist/detachWire.js +3 -2
  34. package/dist/devicesFace.d.ts +34 -0
  35. package/dist/devicesFace.js +90 -0
  36. package/dist/displayUntrusted.d.ts +1 -0
  37. package/dist/displayUntrusted.js +153 -5
  38. package/dist/engineAgentPanelStore.d.ts +14 -4
  39. package/dist/engineAgentPanelStore.js +14 -0
  40. package/dist/engineCapReader.d.ts +2 -1
  41. package/dist/engineCapReader.js +7 -5
  42. package/dist/engineCapsCache.d.ts +8 -0
  43. package/dist/engineCapsCache.js +59 -6
  44. package/dist/engineCapsChange.d.ts +2 -0
  45. package/dist/engineCapsChange.js +9 -0
  46. package/dist/engineErrorCodes.d.ts +11 -2
  47. package/dist/engineErrorCodes.js +11 -12
  48. package/dist/engineRowRef.js +4 -0
  49. package/dist/engineSessionMessages.d.ts +1 -0
  50. package/dist/engineSessionMessages.js +7 -1
  51. package/dist/engineTargetSeat.d.ts +27 -0
  52. package/dist/engineTargetSeat.js +199 -0
  53. package/dist/engineToolDirectory.d.ts +3 -0
  54. package/dist/engineToolDirectory.js +4 -2
  55. package/dist/engineWireFor.js +3 -8
  56. package/dist/env/uiLanguage.d.ts +2 -1
  57. package/dist/env/uiLanguage.js +3 -2
  58. package/dist/eventLeg.d.ts +7 -5
  59. package/dist/eventLeg.js +68 -49
  60. package/dist/fileHistoryCaptureCapability.d.ts +2 -4
  61. package/dist/fileHistoryCaptureCapability.js +12 -22
  62. package/dist/fileHistoryLegNotice.d.ts +2 -1
  63. package/dist/fileHistoryLegNotice.js +3 -3
  64. package/dist/frameBinding.d.ts +3 -0
  65. package/dist/frameBinding.js +12 -0
  66. package/dist/gateOutcome.js +16 -2
  67. package/dist/gateVocabulary.d.ts +8 -7
  68. package/dist/gateVocabulary.js +71 -73
  69. package/dist/generated/engineFactTables.d.ts +18 -1
  70. package/dist/generated/engineFactTables.js +56 -0
  71. package/dist/generated/engineNoticeTables.js +12 -3
  72. package/dist/generated/settingsSchemaFns.d.ts +18 -0
  73. package/dist/generated/settingsSchemaFns.js +70 -0
  74. package/dist/generated/settingsSchemaHooksClassifier.d.ts +2 -0
  75. package/dist/generated/settingsSchemaHooksClassifier.js +254 -0
  76. package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -0
  77. package/dist/generated/settingsSchemaMcpRequestEntry.js +162 -0
  78. package/dist/generated/settingsSchemaTables.d.ts +2 -0
  79. package/dist/generated/settingsSchemaTables.js +9 -0
  80. package/dist/generated/settingsSchemaTypes.d.ts +133 -0
  81. package/dist/generated/settingsSchemaTypes.js +1 -0
  82. package/dist/hitl/allowRuleShadow.d.ts +2 -1
  83. package/dist/hitl/allowRuleShadow.js +18 -15
  84. package/dist/hitl/approvalCardReasons.d.ts +3 -2
  85. package/dist/hitl/approvalCardReasons.js +29 -30
  86. package/dist/hitl/approvalHolds.d.ts +17 -0
  87. package/dist/hitl/approvalHolds.js +114 -29
  88. package/dist/hitl/askClassPair.d.ts +2 -2
  89. package/dist/hitl/askClassPair.js +16 -0
  90. package/dist/hitl/askGateWire.js +2 -1
  91. package/dist/hitl/askSettlementLine.d.ts +14 -4
  92. package/dist/hitl/askSettlementLine.js +67 -47
  93. package/dist/hitl/attributionLadder.d.ts +23 -0
  94. package/dist/hitl/attributionLadder.js +67 -0
  95. package/dist/hitl/automaticAnswerVerdict.d.ts +2 -1
  96. package/dist/hitl/automaticAnswerVerdict.js +8 -8
  97. package/dist/hitl/crashConvergedNotice.d.ts +5 -4
  98. package/dist/hitl/crashConvergedNotice.js +28 -41
  99. package/dist/hitl/decisionLedger.d.ts +55 -0
  100. package/dist/hitl/decisionLedger.js +156 -0
  101. package/dist/hitl/decisionRefusal.d.ts +1 -0
  102. package/dist/hitl/decisionRefusal.js +1 -1
  103. package/dist/hitl/decisionSend.d.ts +113 -0
  104. package/dist/hitl/decisionSend.js +579 -0
  105. package/dist/hitl/frameRouter.js +7 -8
  106. package/dist/hitl/hitlBridge.d.ts +1 -0
  107. package/dist/hitl/hitlBridge.js +21 -9
  108. package/dist/hitl/persistedRulesWire.d.ts +6 -5
  109. package/dist/hitl/persistedRulesWire.js +55 -73
  110. package/dist/hitl/planReviewWire.d.ts +5 -0
  111. package/dist/hitl/planReviewWire.js +53 -76
  112. package/dist/hitl/sessionPolicyDeliverable.d.ts +2 -0
  113. package/dist/hitl/sessionPolicyDeliverable.js +49 -9
  114. package/dist/hitl/sessionPolicyWire.d.ts +2 -1
  115. package/dist/hitl/sessionPolicyWire.js +23 -24
  116. package/dist/hitl/suspendedReopen.d.ts +2 -1
  117. package/dist/hitl/suspendedReopen.js +7 -10
  118. package/dist/hitl/toolApprovalWire.d.ts +17 -5
  119. package/dist/hitl/toolApprovalWire.js +120 -147
  120. package/dist/hooksWireCaps.js +145 -56
  121. package/dist/host.d.ts +21 -0
  122. package/dist/hostTurnSettings.d.ts +110 -0
  123. package/dist/hostTurnSettings.js +692 -0
  124. package/dist/humanTurn.d.ts +15 -1
  125. package/dist/humanTurn.js +100 -12
  126. package/dist/humanTurnRead.d.ts +2 -0
  127. package/dist/humanTurnRead.js +22 -1
  128. package/dist/i18n/messages.en.d.ts +713 -0
  129. package/dist/i18n/messages.en.js +713 -0
  130. package/dist/i18n/messages.zh.js +854 -1
  131. package/dist/index.d.ts +45 -13
  132. package/dist/index.js +27 -9
  133. package/dist/inheritEnvCapability.d.ts +4 -2
  134. package/dist/inheritEnvCapability.js +12 -5
  135. package/dist/inheritEnvWire.d.ts +3 -2
  136. package/dist/inheritEnvWire.js +14 -16
  137. package/dist/injectionLaneNotice.d.ts +5 -0
  138. package/dist/injectionLaneNotice.js +46 -0
  139. package/dist/interactiveHalt.js +17 -6
  140. package/dist/liveModelCatalog.d.ts +2 -1
  141. package/dist/liveModelCatalog.js +14 -8
  142. package/dist/mcpPanel.d.ts +10 -1
  143. package/dist/mcpPanel.js +42 -13
  144. package/dist/mcpProbeCapability.d.ts +2 -1
  145. package/dist/mcpProbeCapability.js +7 -11
  146. package/dist/mcpProbeWire.d.ts +3 -1
  147. package/dist/mcpProbeWire.js +5 -0
  148. package/dist/mcpReconnect.js +2 -2
  149. package/dist/mcpToolToggles.d.ts +6 -0
  150. package/dist/mcpToolToggles.js +46 -0
  151. package/dist/mcpWireCaps.d.ts +43 -3
  152. package/dist/mcpWireCaps.js +194 -59
  153. package/dist/mcpWireTransport.d.ts +4 -0
  154. package/dist/mcpWireTransport.js +18 -0
  155. package/dist/memoryEntriesWire.js +5 -10
  156. package/dist/model/onboardJudgement.d.ts +93 -0
  157. package/dist/model/onboardJudgement.js +415 -0
  158. package/dist/model/tierVocabulary.d.ts +2 -0
  159. package/dist/model/tierVocabulary.js +17 -5
  160. package/dist/modelCapabilityProbe.d.ts +65 -0
  161. package/dist/modelCapabilityProbe.js +601 -0
  162. package/dist/modelIdentityResolvability.d.ts +5 -0
  163. package/dist/modelIdentityResolvability.js +49 -22
  164. package/dist/ownKey.d.ts +33 -0
  165. package/dist/ownKey.js +109 -0
  166. package/dist/panelReduce.d.ts +11 -1
  167. package/dist/panelReduce.js +95 -16
  168. package/dist/panelStateHolder.d.ts +1 -0
  169. package/dist/panelStateHolder.js +10 -1
  170. package/dist/permissionRuleIssue.d.ts +2 -1
  171. package/dist/permissionRuleIssue.js +23 -20
  172. package/dist/permissionRulesWriteCapability.d.ts +2 -1
  173. package/dist/permissionRulesWriteCapability.js +8 -6
  174. package/dist/pluginHooksWire.d.ts +46 -3
  175. package/dist/pluginHooksWire.js +220 -12
  176. package/dist/prepareRefusal.d.ts +8 -0
  177. package/dist/prepareRefusal.js +72 -0
  178. package/dist/printModelStatus.d.ts +63 -0
  179. package/dist/printModelStatus.js +155 -0
  180. package/dist/request/taskRequest.d.ts +16 -10
  181. package/dist/request/taskRequest.js +195 -58
  182. package/dist/resumeRefusalCopy.d.ts +14 -9
  183. package/dist/resumeRefusalCopy.js +89 -144
  184. package/dist/retryStatus.d.ts +55 -0
  185. package/dist/retryStatus.js +155 -19
  186. package/dist/ruleRefusalSentence.d.ts +4 -0
  187. package/dist/ruleRefusalSentence.js +58 -0
  188. package/dist/sandboxWire.d.ts +2 -1
  189. package/dist/sandboxWire.js +55 -21
  190. package/dist/scenarioRefusal.d.ts +10 -0
  191. package/dist/scenarioRefusal.js +111 -0
  192. package/dist/seam.d.ts +48 -9
  193. package/dist/seam.js +54 -5
  194. package/dist/seatContract.d.ts +272 -14
  195. package/dist/seatContract.js +711 -23
  196. package/dist/selfOrchestrationDenial.js +7 -19
  197. package/dist/sessionIdSegment.d.ts +6 -0
  198. package/dist/sessionIdSegment.js +24 -0
  199. package/dist/sessionMemoryStatus.js +6 -11
  200. package/dist/sessionPolicyCapability.d.ts +2 -1
  201. package/dist/sessionPolicyCapability.js +8 -6
  202. package/dist/settingsCredentialKeyPaths.d.ts +8 -0
  203. package/dist/settingsCredentialKeyPaths.js +219 -0
  204. package/dist/settingsHooksSalvage.d.ts +44 -0
  205. package/dist/settingsHooksSalvage.js +211 -0
  206. package/dist/skillToolListsCapability.d.ts +2 -1
  207. package/dist/skillToolListsCapability.js +8 -6
  208. package/dist/skillsWireCaps.d.ts +0 -3
  209. package/dist/skillsWireCaps.js +1 -2
  210. package/dist/sseIdleTriage.js +3 -2
  211. package/dist/subagent/engineSubagentResume.js +15 -9
  212. package/dist/subagentContentStore.d.ts +4 -0
  213. package/dist/subagentContentStore.js +157 -27
  214. package/dist/toolHistoryMismatch.js +3 -2
  215. package/dist/toolRoster.d.ts +3 -2
  216. package/dist/toolRoster.js +21 -20
  217. package/dist/toolsFlagNames.d.ts +8 -0
  218. package/dist/toolsFlagNames.js +110 -0
  219. package/dist/turnFailurePresentation.d.ts +12 -1
  220. package/dist/turnFailurePresentation.js +220 -15
  221. package/dist/usageAnalytics.js +6 -11
  222. package/dist/userAttachmentEnvelope.d.ts +1 -0
  223. package/dist/userAttachmentEnvelope.js +37 -7
  224. package/dist/userAttachmentSeat.d.ts +21 -0
  225. package/dist/userAttachmentSeat.js +75 -0
  226. package/dist/userInvokedSkillsCapability.d.ts +11 -1
  227. package/dist/userInvokedSkillsCapability.js +31 -7
  228. package/dist/wireErrorTriage.d.ts +7 -0
  229. package/dist/wireErrorTriage.js +23 -1
  230. package/dist/wireFailureShape.js +2 -1
  231. package/dist/wireRefusalCopy.d.ts +62 -16
  232. package/dist/wireRefusalCopy.js +307 -148
  233. package/dist/workflowsJournalCapability.d.ts +2 -1
  234. package/dist/workflowsJournalCapability.js +8 -6
  235. package/docs/INTEGRATION-CLIENTS.md +951 -42
  236. 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, UNWIRED_HOST_TURN_SETTINGS, buildHostTurnSettings, hostIntakeSnapshotOf, hostProjectionNotice, hostTurnSettingsOf, intersectHostHooks, 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'),
@@ -162,16 +168,26 @@ const INPUT_KEY_ROUTES = {
162
168
  why: '思考 token 数上限:sdk `TaskRequest` 上思考强度只有档位词(`reasoningEffort` 七词闭集),没有 token 数这一位;把数字折成档位词 = 替用户编一个他没说过的档位',
163
169
  },
164
170
  memoryCapture: row('memoryCapture'),
165
- memory: row('memory'),
166
- fileHistory: row('fileHistory'),
167
171
  inheritEnv: row('inheritEnv'),
168
172
  requireExistingSession: row('requireExistingSession'),
169
173
  disableSkills: row('disableSkills'),
170
174
  rewind: row('resumeAt/resumeAtMode/restoreFiles/rewindFilesTo'),
171
175
  repo: row('repo'),
172
176
  allowTools: row('allowTools'),
177
+ hostSettings: { via: 'control' },
173
178
  settings: { via: 'settings' },
174
179
  };
180
+ const HOST_TOP_KEY_ROUTES = {
181
+ memory: row('memory'),
182
+ fileHistory: row('fileHistory'),
183
+ };
184
+ const HOST_TOP_KEYS = Object.freeze(Object.keys(HOST_TOP_KEY_ROUTES));
185
+ const _hostTopKeysPin = [true];
186
+ void _hostTopKeysPin;
187
+ const HOST_TOP_ASK_AFTER = 'memoryCapture';
188
+ const HOST_SETTINGS_SUBKEYS = Object.freeze(HOST_SUPPLIED_KEYS.filter((k) => k.startsWith('settings.')).map((k) => k.slice('settings.'.length)));
189
+ const _hostSubkeysPin = [true, true, true];
190
+ void _hostSubkeysPin;
175
191
  const SETTINGS_KEY_ROUTES = {
176
192
  resolved: row('settings.<resolved>'),
177
193
  webSearch: row('settings.webSearch'),
@@ -185,6 +201,8 @@ const liveDefaultKeyNames = () => new Set(LIVE_DEFAULT_FIELDS.flatMap(item => it
185
201
  const routeOfTopLevelKey = (key) => {
186
202
  if (hasOwn(INPUT_KEY_ROUTES, key))
187
203
  return INPUT_KEY_ROUTES[key];
204
+ if (hasOwn(HOST_TOP_KEY_ROUTES, key))
205
+ return HOST_TOP_KEY_ROUTES[key];
188
206
  if (!key.includes('.') && liveDefaultKeyNames().has(key))
189
207
  return { via: 'fixed', cause: 'other_channel' };
190
208
  return undefined;
@@ -211,6 +229,42 @@ const OMISSION_JUDGES = {
211
229
  not_live: (s, _lane, live) => s.via === 'matrix' && s.spec.live && !live,
212
230
  };
213
231
  const omissionCauseOf = (s, lane, live) => TASK_REQUEST_OMISSION_CAUSES.find(cause => OMISSION_JUDGES[cause](s, lane, live));
232
+ const hostRefusalNoticeOf = (intake, lane, live) => {
233
+ const verdictNotice = intake.notice ?? hostProjectionNotice();
234
+ try {
235
+ const refusing = intake.refusingKeys;
236
+ if (refusing.length === 0)
237
+ return verdictNotice;
238
+ const turnNotices = intake.turnNotices;
239
+ const aligned = turnNotices !== undefined && turnNotices.length === refusing.length;
240
+ for (const [i, key] of refusing.entries()) {
241
+ if (!hostRefuseRowSeated(key, lane, live))
242
+ continue;
243
+ return aligned ? (turnNotices[i] ?? verdictNotice) : verdictNotice;
244
+ }
245
+ return undefined;
246
+ }
247
+ catch {
248
+ return verdictNotice;
249
+ }
250
+ };
251
+ const hostRefuseRowSeated = (key, lane, live) => {
252
+ if (hasOwn(HOST_TOP_KEY_ROUTES, key)) {
253
+ const top = HOST_TOP_KEY_ROUTES[key];
254
+ return top === undefined || (top.via !== 'matrix' && top.via !== 'fixed') || omissionCauseOf(standingOf(top), lane, live) === undefined;
255
+ }
256
+ if (!key.startsWith('settings.'))
257
+ return true;
258
+ const sub = key.slice('settings.'.length);
259
+ if (!hasOwn(SETTINGS_KEY_ROUTES, sub))
260
+ return true;
261
+ const route = SETTINGS_KEY_ROUTES[sub];
262
+ if (route === undefined || route.via === 'always')
263
+ return true;
264
+ if (route.via === 'matrix' || route.via === 'fixed')
265
+ return omissionCauseOf(standingOf(route), lane, live) === undefined;
266
+ return true;
267
+ };
214
268
  const REQUEST_LANE_SET = { interactive: true, print: true, utility: true };
215
269
  export const REQUEST_LANES = Object.freeze(Object.keys(REQUEST_LANE_SET));
216
270
  const refuseBadLane = (lane) => {
@@ -228,6 +282,8 @@ const VALUE_LEVEL_IN_PLAY = Object.freeze({
228
282
  oneShot: (v) => v === true,
229
283
  interactiveTools: (v) => v === false,
230
284
  images: (v) => Array.isArray(v) && v.length > 0,
285
+ userAttachments: (v) => Array.isArray(v) && v.length > 0,
286
+ userInvokedSkills: (v) => Array.isArray(v) && v.length > 0,
231
287
  attachmentIds: (v) => Array.isArray(v) && v.length > 0,
232
288
  excludeTools: (v) => Array.isArray(v) && v.length > 0,
233
289
  excludeAllTools: (v) => v === true,
@@ -402,14 +458,50 @@ const resolvedSnapshotForWire = (resolved) => {
402
458
  }
403
459
  return out;
404
460
  };
461
+ export function hostTurnSettings(input) {
462
+ return buildHostTurnSettings(input, { materialize: (snapshot) => resolvedSnapshotForWire(snapshot), memoryOffDeclared });
463
+ }
464
+ export function refilterHostSettings(request, fresh, lane) {
465
+ refuseBadLane(lane);
466
+ const host = hostTurnSettingsOf(fresh);
467
+ const intake = host === undefined || host === UNWIRED_HOST_TURN_SETTINGS ? undefined : hostIntakeSnapshotOf(host);
468
+ if (host === undefined || intake === undefined) {
469
+ throw new TypeError(renderMessage(msg('config.taskRequest.hostSettingsMalformed', { shape: coarseShape(fresh) })));
470
+ }
471
+ const refuseNotice = () => intake.notice ?? hostProjectionNotice();
472
+ if (intake.refuses) {
473
+ const refusing = hostRefusalNoticeOf(intake, lane, true);
474
+ if (refusing !== undefined)
475
+ return Object.freeze({ kind: 'refuse', notice: refusing });
476
+ }
477
+ const settings = request.settings;
478
+ if (!isPlainRecord(settings) || !Object.hasOwn(settings, 'hooks'))
479
+ return Object.freeze({ kind: 'send', request, hooksDropped: 0 });
480
+ const disposition = intake.dispositions['settings.hooks'];
481
+ if (disposition === 'unwired')
482
+ return Object.freeze({ kind: 'send', request, hooksDropped: 0 });
483
+ const now = intake.carried.hooks;
484
+ const sentHooks = settings.hooks;
485
+ if (!isPlainRecord(sentHooks))
486
+ return Object.freeze({ kind: 'refuse', notice: refuseNotice() });
487
+ const cut = intersectHostHooks(sentHooks, now);
488
+ if (!cut.judged)
489
+ return Object.freeze({ kind: 'refuse', notice: refuseNotice() });
490
+ if (cut.dropped === 0)
491
+ return Object.freeze({ kind: 'send', request, hooksDropped: 0 });
492
+ const { hooks: _sentHooks, ...restSettings } = settings;
493
+ void _sentHooks;
494
+ const nextSettings = cut.hooks === undefined ? restSettings : { ...restSettings, hooks: cut.hooks };
495
+ const { settings: _sentSettings, ...restRequest } = request;
496
+ void _sentSettings;
497
+ const next = Object.keys(nextSettings).length > 0 ? { ...restRequest, settings: nextSettings } : restRequest;
498
+ return Object.freeze({ kind: 'send', request: next, hooksDropped: cut.dropped });
499
+ }
405
500
  export const MEMORY_CAPTURE_OFF = 'off';
406
501
  export function memoryCaptureDeclarationField(declared) {
407
502
  return declared ? { memoryCapture: MEMORY_CAPTURE_OFF } : {};
408
503
  }
409
504
  export const MEMORY_OFF = 'off';
410
- export function memoryOffDeclarationField(declared) {
411
- return declared ? { memory: MEMORY_OFF } : {};
412
- }
413
505
  export const FILE_HISTORY_DISABLED = 'disabled';
414
506
  export const INHERIT_ENV_WORDS = Object.freeze(['all', 'scrub']);
415
507
  export function isInheritEnvWord(v) {
@@ -427,26 +519,16 @@ export function memoryOffDeclared(input) {
427
519
  const sm = input.settingsMemory;
428
520
  if (sm !== undefined && sm !== null) {
429
521
  if (typeof sm !== 'object' || Array.isArray(sm)) {
430
- throw new TypeError(`memoryOffDeclared: settings 的 memory 段必须是对象 —— 收到 ${coarseShape(sm)}。`);
522
+ throw new TypeError(renderMessage(msg('config.taskRequest.memoryOff.settingsSectionNotObject', { shape: coarseShape(sm) })));
431
523
  }
432
524
  const enabled = sm.enabled;
433
525
  if (enabled !== undefined && typeof enabled !== 'boolean') {
434
- throw new TypeError(`memoryOffDeclared: settings memory.enabled 在场时必须是布尔 —— 收到 ${coarseShape(enabled)}。`);
526
+ throw new TypeError(renderMessage(msg('config.taskRequest.memoryOff.enabledNotBoolean', { shape: coarseShape(enabled) })));
435
527
  }
436
528
  fromSettings = enabled === false;
437
529
  }
438
530
  return flag === MEMORY_OFF || fromSettings;
439
531
  }
440
- const refuseBadMemoryOff = (v) => {
441
- if (v === undefined || v === null)
442
- return;
443
- if (v === 'off')
444
- return;
445
- throw new TypeError('buildTaskRequest: memory 只接受字面量 `\'off\'` 或缺席(undefined/null)—— ' +
446
- `收到 ${coarseShape(v)}。这一位是**请求级整面开关**(「这一次别给我记忆」),上游是**单成员闭集**(没有 ` +
447
- '`"on"`,`{ enabled: false }` 对象形也不是 wire 拼法)且对坏拼写**响亮拒**(server 400 `request.field_invalid`)。' +
448
- '本层若静默删键,这一次运行会照常挂上记忆面而声明人不会知道 —— 与 memoryCapture 同一条纪律。错误文本只报形状,不回显值。');
449
- };
450
532
  const withoutRetiredAttachmentsKeys = (v) => {
451
533
  if (typeof v !== 'object' || v === null)
452
534
  return v;
@@ -530,6 +612,23 @@ const refuseBadAllowTools = (v) => {
530
612
  `收到 ${coarseShape(v)}。这一位是**可用性选择器**(收紧声明):本层若把坏形静默删键,这一次运行会挂上声明人以为已经收窄掉的全部工具。` +
531
613
  '错误文本只报形状,不回显值。');
532
614
  };
615
+ const refuseBadUserInvokedSkills = (v) => {
616
+ if (v === undefined || v === null)
617
+ return;
618
+ if (Array.isArray(v) && v.length <= ALLOW_TOOLS_MAX_LENGTH) {
619
+ let ok = true;
620
+ for (let k = 0; k < v.length; k += 1) {
621
+ const d = Object.getOwnPropertyDescriptor(v, k);
622
+ if (d === undefined || !('value' in d) || typeof d.value !== 'string') {
623
+ ok = false;
624
+ break;
625
+ }
626
+ }
627
+ if (ok)
628
+ return;
629
+ }
630
+ throw new TypeError(renderMessage(msg('config.taskRequest.userInvokedSkillsMalformed', { shape: coarseShape(v) })));
631
+ };
533
632
  const refuseBadExcludeAllTools = (v) => {
534
633
  if (v === undefined || v === null || v === true || v === false)
535
634
  return;
@@ -537,15 +636,6 @@ const refuseBadExcludeAllTools = (v) => {
537
636
  `收到 ${coarseShape(v)}。这一位是**整只工具面卸载**的收紧声明:本层若把坏值静默删键,这一次运行会挂上声明人以为已经卸掉的全部工具。` +
538
637
  '错误文本只报形状,不回显值。');
539
638
  };
540
- const refuseBadFileHistory = (v) => {
541
- if (v === undefined || v === null)
542
- return;
543
- if (v === FILE_HISTORY_DISABLED)
544
- return;
545
- throw new TypeError('buildTaskRequest: fileHistory 只接受字面量 `\'disabled\'` 或缺席(undefined/null)—— ' +
546
- `收到 ${coarseShape(v)}。这一位是「这一次运行别捕获文件历史」的收紧声明,上游是**单成员闭集**(没有第二个词)且对坏值` +
547
- '**响亮拒**。本层若静默删键,这一次运行照常捕获而声明人不会知道。错误文本只报形状,不回显值。');
548
- };
549
639
  const refuseBadInheritEnv = (v) => {
550
640
  if (v === undefined || v === null)
551
641
  return;
@@ -563,13 +653,16 @@ const refuseBadRequireExistingSession = (v) => {
563
653
  '上游对非布尔值同样拒收。错误文本只报形状,不回显值。');
564
654
  };
565
655
  const hasResumableSessionId = (sid) => typeof sid === 'string' && sid.length > 0;
566
- const refuseRequireExistingWithoutSession = (requireExisting, sessionId) => {
656
+ const refuseRequireExistingWithoutSession = (requireExisting, sessionId, where = 'buildTaskRequest') => {
567
657
  if (requireExisting !== true || hasResumableSessionId(sessionId))
568
658
  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)。错误文本只报形状,不回显值。');
659
+ const shape = sessionId === undefined
660
+ ? renderMessage(msg('config.taskRequest.requireExisting.shapeAbsent'))
661
+ : typeof sessionId === 'string'
662
+ ? renderMessage(msg('config.taskRequest.requireExisting.shapeEmpty'))
663
+ : coarseShape(sessionId);
664
+ const layer = renderMessage(msg(where === 'buildTaskRequest' ? 'config.taskRequest.requireExisting.layerAssembly' : 'config.taskRequest.requireExisting.layerLive'));
665
+ throw new TypeError(renderMessage(msg('config.taskRequest.requireExisting.noSession', { where, shape, layer })));
573
666
  };
574
667
  const refuseBadMaxTokens = (v) => {
575
668
  if (v === undefined || v === null)
@@ -640,15 +733,15 @@ export function parseMaxCostUsd(text) {
640
733
  return { ok: false, why: 'not_positive' };
641
734
  return { ok: true, value };
642
735
  }
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) });
736
+ const ACCESSOR_READ_ORDER = ['live', 'memoryCapture', 'hostSettings', 'settings', 'maxCostUsd', 'excludeAllTools', 'maxTokens', 'outputRetries', 'inheritEnv', 'requireExistingSession', 'disableSkills', 'approvalReach', 'allowTools', 'userInvokedSkills'];
737
+ const MATERIALIZE_AT_READ = Object.freeze({ allowTools: (v) => allowToolsSnapshot(v), userInvokedSkills: (v) => allowToolsSnapshot(v) });
645
738
  function dataFirstSnapshot(input, afterData) {
646
739
  let descs;
647
740
  try {
648
741
  descs = Object.getOwnPropertyDescriptors(input);
649
742
  }
650
743
  catch {
651
- throw new TypeError('buildTaskRequest: 入参的键集 / 属性描述符读不出(代理 trap 抛)—— 无法安全快照声明,拒绝装配。错误文本只报形状,不回显值。');
744
+ throw new TypeError(renderMessage(msg('config.taskRequest.inputKeysUnreadable')));
652
745
  }
653
746
  const bag = Object.create(null);
654
747
  const accessors = [];
@@ -678,39 +771,52 @@ export function assembleTaskRequest(input, lane) {
678
771
  let resolvedMaterialized;
679
772
  let resolvedMaterializeError;
680
773
  let resolvedHookRan = false;
774
+ let intakeEarly;
775
+ const materializeAtRead = (product) => (raw) => {
776
+ resolvedInEarly = raw;
777
+ try {
778
+ rethrowHostResolvedDeferred(product);
779
+ resolvedMaterialized = resolvedSnapshotForWire(resolvedInEarly);
780
+ }
781
+ catch (e) {
782
+ resolvedMaterializeError = e;
783
+ }
784
+ };
681
785
  const src = dataFirstSnapshot(input, (bag) => {
682
- const st = bag['settings'];
683
- if (present(st) && typeof st === 'object' && !Array.isArray(st)) {
786
+ if (!Object.hasOwn(bag, 'hostSettings'))
787
+ return;
788
+ const product = hostTurnSettingsOf(bag['hostSettings'], 'shape');
789
+ if (product !== undefined) {
684
790
  resolvedHookRan = true;
685
- resolvedInEarly = st.resolved;
686
- try {
687
- resolvedMaterialized = resolvedSnapshotForWire(resolvedInEarly);
688
- }
689
- catch (e) {
690
- resolvedMaterializeError = e;
691
- }
791
+ intakeEarly = hostIntakeSnapshotOf(product, materializeAtRead(product));
692
792
  }
693
793
  });
694
794
  const live = src.live;
695
795
  const memoryCaptureIn = src.memoryCapture;
696
- const memoryIn = src.memory;
697
796
  const settingsIn = src.settings;
698
797
  if (present(settingsIn) && (typeof settingsIn !== 'object' || Array.isArray(settingsIn))) {
699
798
  throw new TypeError(`buildTaskRequest: settings 只接受对象或缺席(undefined/null)—— 收到 ${coarseShape(settingsIn)}。` +
700
799
  '这一位装着已解析权限面与 hooks:把畸形容器当成「没给」= 请求带着被剥掉的权限面照发。错误文本只报形状,不回显值。');
701
800
  }
702
801
  const settingsObj = present(settingsIn) ? settingsIn : {};
703
- const resolvedIn = resolvedHookRan ? resolvedInEarly : settingsObj.resolved;
802
+ const hostIn = src.hostSettings;
803
+ const host = hostTurnSettingsOf(hostIn);
804
+ if (host === undefined) {
805
+ throw new TypeError(renderMessage(msg('config.taskRequest.hostSettingsMalformed', { shape: coarseShape(hostIn) })));
806
+ }
807
+ const intake = resolvedHookRan ? intakeEarly : hostIntakeSnapshotOf(host, materializeAtRead(host));
808
+ if (intake === undefined)
809
+ throw new TypeError(renderMessage(msg('config.taskRequest.hostSettingsMalformed', { shape: coarseShape(hostIn) })));
810
+ const resolvedIn = resolvedInEarly;
704
811
  const resolvedRoute = SETTINGS_KEY_ROUTES.resolved;
705
812
  const resolvedOpen = resolvedRoute.via === 'matrix' && omissionCauseOf(standingOf(resolvedRoute), lane, live) === undefined;
706
- if (resolvedOpen && resolvedHookRan && resolvedMaterializeError !== undefined)
813
+ if (resolvedOpen && resolvedMaterializeError !== undefined)
707
814
  throw resolvedMaterializeError;
708
815
  const resolvedWire = resolvedOpen ? (resolvedMaterialized ?? resolvedSnapshotForWire(resolvedIn)) : {};
709
816
  const maxCostUsdIn = src.maxCostUsd;
710
817
  const excludeAllToolsIn = src.excludeAllTools;
711
818
  const maxTokensIn = src.maxTokens;
712
819
  const outputRetriesIn = src.outputRetries;
713
- const fileHistoryIn = src.fileHistory;
714
820
  const inheritEnvIn = src.inheritEnv;
715
821
  const requireExistingSessionIn = src.requireExistingSession;
716
822
  const disableSkillsIn = src.disableSkills;
@@ -720,12 +826,10 @@ export function assembleTaskRequest(input, lane) {
720
826
  const i = snapshotByName(src, INPUT_KEYS, {
721
827
  live,
722
828
  memoryCapture: memoryCaptureIn,
723
- memory: memoryIn,
724
829
  maxCostUsd: maxCostUsdIn,
725
830
  maxTokens: maxTokensIn,
726
831
  excludeAllTools: excludeAllToolsIn,
727
832
  outputRetries: outputRetriesIn,
728
- fileHistory: fileHistoryIn,
729
833
  inheritEnv: inheritEnvIn,
730
834
  requireExistingSession: requireExistingSessionIn,
731
835
  disableSkills: disableSkillsIn,
@@ -734,19 +838,26 @@ export function assembleTaskRequest(input, lane) {
734
838
  settings: settingsIn,
735
839
  });
736
840
  const SETTINGS_KEYS = Object.keys(SETTINGS_KEY_ROUTES);
737
- const s = snapshotByName(settingsObj, SETTINGS_KEYS, { resolved: resolvedIn });
841
+ const hostSettingsKeysIn = HOST_SETTINGS_SUBKEYS.filter((k) => hasOwn(settingsObj, k) && present(Reflect.get(settingsObj, k)));
842
+ const hostTopKeysIn = HOST_TOP_KEYS.filter((k) => hasOwn(src, k) && present(Reflect.get(src, k)));
843
+ const s = {
844
+ resolved: resolvedIn,
845
+ webSearch: intake.carried.webSearch,
846
+ ultracode: snapshotByName(settingsObj, ['ultracode']).ultracode,
847
+ hooks: intake.carried.hooks,
848
+ outputStyle: intake.carried.outputStyle,
849
+ };
738
850
  refuseBadMemoryCapture(memoryCaptureIn);
739
- refuseBadMemoryOff(memoryIn);
740
851
  refuseBadMaxCostUsd(maxCostUsdIn);
741
852
  refuseBadExcludeAllTools(excludeAllToolsIn);
742
853
  refuseBadMaxTokens(maxTokensIn);
743
854
  refuseBadOutputRetries(outputRetriesIn);
744
- refuseBadFileHistory(fileHistoryIn);
745
855
  refuseBadInheritEnv(inheritEnvIn);
746
856
  refuseBadRequireExistingSession(requireExistingSessionIn);
747
857
  refuseBadDisableSkills(disableSkillsIn, 'buildTaskRequest');
748
858
  refuseBadApprovalReach(approvalReachIn, 'buildTaskRequest');
749
859
  refuseBadAllowTools(allowToolsIn);
860
+ refuseBadUserInvokedSkills(i.userInvokedSkills);
750
861
  const rewindRoute = INPUT_KEY_ROUTES.rewind;
751
862
  const RETIRED_REWIND_FILES_KEY = 'rewindFiles';
752
863
  const REWIND_KEYS = rewindRoute.via === 'matrix' ? rewindRoute.field.split('/') : [];
@@ -774,6 +885,8 @@ export function assembleTaskRequest(input, lane) {
774
885
  for (const key of Object.keys(src)) {
775
886
  if (hasOwn(INPUT_KEY_ROUTES, key))
776
887
  continue;
888
+ if (hasOwn(HOST_TOP_KEY_ROUTES, key))
889
+ continue;
777
890
  const stray = Reflect.get(src, key);
778
891
  if (!present(stray))
779
892
  continue;
@@ -813,6 +926,12 @@ export function assembleTaskRequest(input, lane) {
813
926
  '处置:删掉这个键;要在回退会话时一并还原文件,改交 ' +
814
927
  'rewind.restoreFiles: true(必须与 rewind.resumeAt 同交);只还原文件、不动会话,交 rewind.rewindFilesTo。错误文本只报键名,不回显值。');
815
928
  }
929
+ if (hostSettingsKeysIn.length > 0 || hostTopKeysIn.length > 0) {
930
+ throw new TypeError(renderMessage(msg('config.taskRequest.hostSuppliedKeysByHand', {
931
+ keys: [...hostSettingsKeysIn.map((k) => `settings.${k}`), ...hostTopKeysIn].join(', '),
932
+ fields: [...hostSettingsKeysIn, ...hostTopKeysIn].map((k) => `${k}: …`).join(', '),
933
+ })));
934
+ }
816
935
  if (unknownKeys.length > 0) {
817
936
  const shown = unknownKeys.slice(0, MAX_UNKNOWN_KEYS_SHOWN).map(keyForDisplay).join(', ');
818
937
  const more = unknownKeys.length > MAX_UNKNOWN_KEYS_SHOWN ? ` 等共 ${unknownKeys.length} 个` : '';
@@ -826,6 +945,11 @@ export function assembleTaskRequest(input, lane) {
826
945
  refuseRequireExistingWithoutSession(requireExistingSessionIn, i.sessionId);
827
946
  refuseDisableSkillsConflict(disableSkillsIn, i.skills, Reflect.get(src, 'agents'), 'buildTaskRequest');
828
947
  refuseUtilityWithoutToolUnload(lane, excludeAllToolsIn);
948
+ if (intake.refuses) {
949
+ const refusing = hostRefusalNoticeOf(intake, lane, live);
950
+ if (refusing !== undefined)
951
+ throw new HostSettingsRefused(refusing);
952
+ }
829
953
  const carries = (route, value, key) => {
830
954
  if (route.via === 'always')
831
955
  return present(value);
@@ -840,15 +964,25 @@ export function assembleTaskRequest(input, lane) {
840
964
  return false;
841
965
  };
842
966
  const gate = Object.create(null);
843
- for (const key of INPUT_KEYS) {
967
+ const askInput = (key) => {
844
968
  const route = INPUT_KEY_ROUTES[key];
845
969
  if (route.via === 'settings') {
846
970
  for (const sub of SETTINGS_KEYS)
847
971
  gate[`settings.${sub}`] = carries(SETTINGS_KEY_ROUTES[sub], s[sub], `settings.${sub}`);
848
- continue;
972
+ return;
849
973
  }
850
974
  gate[key] = carries(route, key === 'rewind' ? rewindForGate : i[key], key);
851
- }
975
+ };
976
+ const anchorAt = INPUT_KEYS.indexOf(HOST_TOP_ASK_AFTER);
977
+ const hostTopAt = anchorAt < 0 ? INPUT_KEYS.length : anchorAt + 1;
978
+ for (const key of INPUT_KEYS.slice(0, hostTopAt))
979
+ askInput(key);
980
+ const hostTopGate = {
981
+ memory: carries(HOST_TOP_KEY_ROUTES.memory, intake.carried.memory, 'memory'),
982
+ fileHistory: carries(HOST_TOP_KEY_ROUTES.fileHistory, intake.carried.fileHistory, 'fileHistory'),
983
+ };
984
+ for (const key of INPUT_KEYS.slice(hostTopAt))
985
+ askInput(key);
852
986
  const on = (key) => gate[key] === true;
853
987
  const onSetting = (sub) => gate[`settings.${sub}`] === true;
854
988
  const settingsOut = {
@@ -867,7 +1001,9 @@ export function assembleTaskRequest(input, lane) {
867
1001
  ...(on('reasoningEffort') ? { reasoningEffort: i.reasoningEffort } : {}),
868
1002
  ...(on('model') ? { model: i.model } : {}),
869
1003
  ...(on('images') ? { images: i.images } : {}),
1004
+ ...(on('userAttachments') ? { userAttachments: [...(i.userAttachments ?? [])] } : {}),
870
1005
  ...(on('skills') ? { skills: i.skills } : {}),
1006
+ ...(on('userInvokedSkills') ? { userInvokedSkills: allowToolsCopy(i.userInvokedSkills) } : {}),
871
1007
  ...(on('mcpServers') ? { mcpServers: i.mcpServers } : {}),
872
1008
  ...(on('rewind') ? rewindWire : {}),
873
1009
  ...(on('permissionMode') ? { permissionMode: i.permissionMode } : {}),
@@ -894,15 +1030,15 @@ export function assembleTaskRequest(input, lane) {
894
1030
  ...(on('maxCostUsd') ? { maxCostUsd: maxCostUsdIn } : {}),
895
1031
  ...(on('maxTokens') ? { maxTokens: i.maxTokens } : {}),
896
1032
  ...(on('memoryCapture') ? { memoryCapture: 'off' } : {}),
897
- ...(on('memory') ? { memory: 'off' } : {}),
898
- ...(on('fileHistory') ? { fileHistory: FILE_HISTORY_DISABLED } : {}),
1033
+ ...(hostTopGate.memory ? { memory: 'off' } : {}),
1034
+ ...(hostTopGate.fileHistory ? { fileHistory: FILE_HISTORY_DISABLED } : {}),
899
1035
  ...(on('inheritEnv') ? { inheritEnv: inheritEnvIn } : {}),
900
1036
  ...(on('requireExistingSession') ? { requireExistingSession: true } : {}),
901
1037
  ...(on('disableSkills') ? { disableSkills: true } : {}),
902
1038
  ...(on('approvalReach') ? { approvalReach: approvalReachIn } : {}),
903
1039
  ...(Object.keys(settingsOut).length > 0 ? { settings: settingsOut } : {}),
904
1040
  };
905
- return Object.freeze({ request: out, omitted: Object.freeze([...omitted, ...lateOmitted]) });
1041
+ return Object.freeze({ request: out, omitted: Object.freeze([...omitted, ...lateOmitted]), host });
906
1042
  }
907
1043
  export function buildTaskRequest(input, lane) {
908
1044
  return assembleTaskRequest(input, lane).request;
@@ -955,6 +1091,7 @@ export function applyLiveRequestDefaults(req, host) {
955
1091
  out.sessionId === host.mockSessionIdConstant) {
956
1092
  delete out.sessionId;
957
1093
  }
1094
+ refuseRequireExistingWithoutSession(out.requireExistingSession, out.sessionId, 'applyLiveRequestDefaults');
958
1095
  return out;
959
1096
  }
960
1097
  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 = Exclude<(typeof RESUME_CAUSE_CORE_AHEAD)[number], ResumeStartupCause>;
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,12 +63,14 @@ 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;
67
70
  readonly field?: string;
68
71
  readonly stillPending?: boolean;
72
+ readonly blockedBy?: string;
73
+ readonly reason?: string;
69
74
  }
70
75
  export declare function refusedParkFromError(failure: unknown): RefusedParkFacts | null;
71
76
  export interface RefusedParkContentInput {
@@ -74,5 +79,5 @@ export interface RefusedParkContentInput {
74
79
  readonly lane: 'interactive' | 'print';
75
80
  readonly runId?: string;
76
81
  }
77
- export declare function refusedParkContent(input: RefusedParkContentInput): string;
78
- export declare function refusedParkBlockedContent(taskId: string, lane?: 'interactive' | 'print'): string;
82
+ export declare function refusedParkContent(input: RefusedParkContentInput, lang?: UiLanguage): string;
83
+ export declare function refusedParkBlockedContent(taskId: string, lane?: 'interactive' | 'print', lang?: UiLanguage): string;