@sema-agent/client-core 0.97.1 → 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 (353) hide show
  1. package/CHANGELOG.md +607 -0
  2. package/README.md +96 -46
  3. package/dist/adapt/arms.d.ts +1 -0
  4. package/dist/adapt/arms.js +188 -53
  5. package/dist/adapt/ids.d.ts +12 -1
  6. package/dist/adapt/ids.js +59 -8
  7. package/dist/adapt/instanceLedger.d.ts +50 -0
  8. package/dist/adapt/instanceLedger.js +147 -0
  9. package/dist/adapt/panelTasks.d.ts +1 -1
  10. package/dist/adapt/panelTasks.js +2 -2
  11. package/dist/adapt/textStream.d.ts +1 -0
  12. package/dist/adapt/textStream.js +24 -7
  13. package/dist/adapt/toolCards.d.ts +27 -5
  14. package/dist/adapt/toolCards.js +39 -6
  15. package/dist/adapt/wireShapes.js +6 -2
  16. package/dist/adapt.d.ts +2 -0
  17. package/dist/adapt.js +8 -3
  18. package/dist/adapter/activeRunSelfHeal.d.ts +9 -3
  19. package/dist/adapter/activeRunSelfHeal.js +205 -313
  20. package/dist/adapter/downstream/eventToSdkMessage.d.ts +2 -5
  21. package/dist/adapter/downstream/eventToSdkMessage.js +77 -36
  22. package/dist/adapter/downstream/terminalToSdkResult.js +11 -4
  23. package/dist/adapter/downstream/turnUsageToModelUsage.d.ts +5 -2
  24. package/dist/adapter/downstream/turnUsageToModelUsage.js +2 -0
  25. package/dist/adapter/runStream.js +79 -48
  26. package/dist/adapter/types.d.ts +4 -4
  27. package/dist/adapter/types.js +2 -1
  28. package/dist/agentSession/backgroundView.js +2 -1
  29. package/dist/agentSession/engineAgentRegistryRead.d.ts +2 -2
  30. package/dist/agentSession/engineAgentRegistryRead.js +12 -13
  31. package/dist/agentSession/engineSessionBackgroundStop.js +16 -8
  32. package/dist/agentsWireCaps.d.ts +8 -11
  33. package/dist/agentsWireCaps.js +196 -194
  34. package/dist/approvalDecidedByCapability.d.ts +0 -4
  35. package/dist/approvalDecidedByCapability.js +0 -6
  36. package/dist/approvalsStreamLiveCapability.d.ts +0 -4
  37. package/dist/approvalsStreamLiveCapability.js +0 -6
  38. package/dist/assistantInbox.d.ts +34 -0
  39. package/dist/assistantInbox.js +118 -0
  40. package/dist/centerWiringCapability.js +9 -1
  41. package/dist/clientSlice.d.ts +0 -9
  42. package/dist/clientSlice.js +0 -3
  43. package/dist/cloudConfigWireCaps.d.ts +5 -3
  44. package/dist/cloudConfigWireCaps.js +106 -64
  45. package/dist/compensations.js +1 -1
  46. package/dist/connectorStatus.d.ts +21 -0
  47. package/dist/connectorStatus.js +112 -0
  48. package/dist/controlRouter.d.ts +18 -3
  49. package/dist/controlRouter.js +106 -67
  50. package/dist/coreValuePorts.d.ts +29 -4
  51. package/dist/coreValuePorts.js +10 -0
  52. package/dist/corruptSessionCopy.d.ts +2 -1
  53. package/dist/corruptSessionCopy.js +3 -3
  54. package/dist/decideReceipt.d.ts +2 -2
  55. package/dist/decideReceipt.js +5 -2
  56. package/dist/declared/supportFloorDeclared.js +3 -3
  57. package/dist/detachWire.js +3 -2
  58. package/dist/deviceExecutorManagementCapability.d.ts +0 -4
  59. package/dist/deviceExecutorManagementCapability.js +0 -6
  60. package/dist/deviceRebind.d.ts +49 -1
  61. package/dist/deviceRebind.js +221 -3
  62. package/dist/devicesFace.d.ts +34 -0
  63. package/dist/devicesFace.js +90 -0
  64. package/dist/displayUntrusted.d.ts +2 -0
  65. package/dist/displayUntrusted.js +253 -76
  66. package/dist/engineAgentAbsence.d.ts +1 -1
  67. package/dist/engineAgentPanelStore.d.ts +12 -4
  68. package/dist/engineAgentPanelStore.js +16 -11
  69. package/dist/engineCapReader.d.ts +2 -5
  70. package/dist/engineCapReader.js +8 -10
  71. package/dist/engineCapsCache.d.ts +12 -0
  72. package/dist/engineCapsCache.js +76 -18
  73. package/dist/engineCapsChange.d.ts +2 -0
  74. package/dist/engineCapsChange.js +9 -0
  75. package/dist/engineClosedSets.d.ts +1 -0
  76. package/dist/engineClosedSets.js +4 -1
  77. package/dist/engineErrorCodes.d.ts +11 -3
  78. package/dist/engineErrorCodes.js +11 -8
  79. package/dist/engineIdentity.d.ts +1 -0
  80. package/dist/engineIdentity.js +8 -0
  81. package/dist/engineRowRef.d.ts +28 -0
  82. package/dist/engineRowRef.js +114 -0
  83. package/dist/engineSessionMessages.d.ts +68 -0
  84. package/dist/engineSessionMessages.js +370 -0
  85. package/dist/engineTargetSeat.d.ts +27 -0
  86. package/dist/engineTargetSeat.js +199 -0
  87. package/dist/engineToolDirectory.d.ts +0 -9
  88. package/dist/engineToolDirectory.js +1 -94
  89. package/dist/engineUrl.d.ts +18 -0
  90. package/dist/engineUrl.js +52 -0
  91. package/dist/engineWireFor.js +3 -8
  92. package/dist/env/uiLanguage.d.ts +11 -1
  93. package/dist/env/uiLanguage.js +38 -2
  94. package/dist/eventLeg.d.ts +100 -0
  95. package/dist/eventLeg.js +305 -0
  96. package/dist/executionLaneCapability.d.ts +0 -4
  97. package/dist/executionLaneCapability.js +3 -16
  98. package/dist/fileHistoryCaptureCapability.d.ts +2 -5
  99. package/dist/fileHistoryCaptureCapability.js +13 -21
  100. package/dist/fileHistoryLegNotice.d.ts +2 -1
  101. package/dist/fileHistoryLegNotice.js +3 -3
  102. package/dist/fleet/fleetLedger.d.ts +0 -3
  103. package/dist/fleet/fleetLedger.js +21 -36
  104. package/dist/fleet/fleetProjection.d.ts +2 -2
  105. package/dist/fleet/fleetProjection.js +10 -8
  106. package/dist/frameBinding.d.ts +8 -0
  107. package/dist/frameBinding.js +35 -0
  108. package/dist/gateFailureCodes.d.ts +2 -0
  109. package/dist/gateFailureCodes.js +15 -0
  110. package/dist/gateOutcome.d.ts +3 -1
  111. package/dist/gateOutcome.js +41 -8
  112. package/dist/gateVocabulary.d.ts +10 -4
  113. package/dist/gateVocabulary.js +107 -47
  114. package/dist/generated/engineAskFaceTables.js +2 -2
  115. package/dist/generated/engineFactTables.d.ts +22 -3
  116. package/dist/generated/engineFactTables.js +51 -4
  117. package/dist/generated/engineNoticeTables.js +18 -3
  118. package/dist/generated/settingsSchemaFns.d.ts +6 -0
  119. package/dist/generated/settingsSchemaFns.js +57 -0
  120. package/dist/generated/settingsSchemaHooksClassifier.d.ts +2 -0
  121. package/dist/generated/settingsSchemaHooksClassifier.js +254 -0
  122. package/dist/generated/settingsSchemaTables.d.ts +1 -0
  123. package/dist/generated/settingsSchemaTables.js +4 -0
  124. package/dist/generated/settingsSchemaTypes.d.ts +105 -0
  125. package/dist/generated/settingsSchemaTypes.js +1 -0
  126. package/dist/generated/toolNameTables.d.ts +1 -0
  127. package/dist/generated/toolNameTables.js +1 -0
  128. package/dist/hitl/allowRuleShadow.d.ts +8 -2
  129. package/dist/hitl/allowRuleShadow.js +36 -29
  130. package/dist/hitl/approvalCardReading.d.ts +15 -0
  131. package/dist/hitl/approvalCardReading.js +154 -0
  132. package/dist/hitl/approvalCardReasons.d.ts +14 -0
  133. package/dist/hitl/approvalCardReasons.js +119 -0
  134. package/dist/hitl/approvalHolds.d.ts +50 -15
  135. package/dist/hitl/approvalHolds.js +177 -27
  136. package/dist/hitl/approvalResolution.d.ts +51 -26
  137. package/dist/hitl/approvalResolution.js +86 -122
  138. package/dist/hitl/approvalsFeed.js +6 -18
  139. package/dist/hitl/askClassPair.d.ts +2 -0
  140. package/dist/hitl/askClassPair.js +17 -0
  141. package/dist/hitl/askGateWire.d.ts +20 -2
  142. package/dist/hitl/askGateWire.js +50 -1
  143. package/dist/hitl/askParkRowRouting.d.ts +5 -0
  144. package/dist/hitl/askParkRowRouting.js +32 -1
  145. package/dist/hitl/askSettlementLine.d.ts +28 -0
  146. package/dist/hitl/askSettlementLine.js +99 -0
  147. package/dist/hitl/automaticAnswerVerdict.d.ts +3 -2
  148. package/dist/hitl/automaticAnswerVerdict.js +29 -13
  149. package/dist/hitl/crashConverged.d.ts +11 -20
  150. package/dist/hitl/crashConverged.js +56 -0
  151. package/dist/hitl/crashConvergedNotice.d.ts +6 -3
  152. package/dist/hitl/crashConvergedNotice.js +48 -24
  153. package/dist/hitl/decisionConflict.js +3 -10
  154. package/dist/hitl/decisionRefusal.d.ts +40 -1
  155. package/dist/hitl/decisionRefusal.js +199 -42
  156. package/dist/hitl/frameRouter.d.ts +5 -2
  157. package/dist/hitl/frameRouter.js +27 -24
  158. package/dist/hitl/gateLedger.d.ts +2 -0
  159. package/dist/hitl/gateLedger.js +50 -13
  160. package/dist/hitl/hitlBridge.d.ts +2 -2
  161. package/dist/hitl/hitlBridge.js +13 -10
  162. package/dist/hitl/livePendingAsk.d.ts +3 -3
  163. package/dist/hitl/livePendingAsk.js +7 -18
  164. package/dist/hitl/parkResolver.d.ts +2 -24
  165. package/dist/hitl/parkResolver.js +61 -97
  166. package/dist/hitl/persistedRulesWire.d.ts +25 -0
  167. package/dist/hitl/persistedRulesWire.js +104 -2
  168. package/dist/hitl/planReviewWire.d.ts +31 -13
  169. package/dist/hitl/planReviewWire.js +120 -78
  170. package/dist/hitl/refusedToolNameProse.d.ts +0 -1
  171. package/dist/hitl/refusedToolNameProse.js +0 -3
  172. package/dist/hitl/replayedApproval.d.ts +4 -3
  173. package/dist/hitl/replayedApproval.js +7 -4
  174. package/dist/hitl/sessionPolicyDeliverable.d.ts +2 -0
  175. package/dist/hitl/sessionPolicyDeliverable.js +48 -7
  176. package/dist/hitl/sessionPolicyWire.d.ts +34 -21
  177. package/dist/hitl/sessionPolicyWire.js +179 -70
  178. package/dist/hitl/standingRows.d.ts +20 -2
  179. package/dist/hitl/standingRows.js +69 -8
  180. package/dist/hitl/suspendedReopen.d.ts +2 -1
  181. package/dist/hitl/suspendedReopen.js +7 -10
  182. package/dist/hitl/toolApprovalWire.d.ts +103 -156
  183. package/dist/hitl/toolApprovalWire.js +661 -411
  184. package/dist/hookMatcherVerdict.d.ts +6 -1
  185. package/dist/hookMatcherVerdict.js +14 -7
  186. package/dist/hooksWireCaps.d.ts +2 -2
  187. package/dist/hooksWireCaps.js +174 -81
  188. package/dist/host.d.ts +21 -0
  189. package/dist/hostTurnSettings.d.ts +71 -0
  190. package/dist/hostTurnSettings.js +291 -0
  191. package/dist/humanTurn.d.ts +14 -1
  192. package/dist/humanTurn.js +100 -12
  193. package/dist/humanTurnRead.d.ts +2 -0
  194. package/dist/humanTurnRead.js +22 -1
  195. package/dist/i18n/messages.en.d.ts +703 -0
  196. package/dist/i18n/messages.en.js +701 -0
  197. package/dist/i18n/messages.zh.d.ts +3 -0
  198. package/dist/i18n/messages.zh.js +837 -0
  199. package/dist/i18n/translate.d.ts +25 -0
  200. package/dist/i18n/translate.js +127 -0
  201. package/dist/index.d.ts +78 -29
  202. package/dist/index.js +54 -18
  203. package/dist/inheritEnvCapability.d.ts +32 -0
  204. package/dist/inheritEnvCapability.js +104 -0
  205. package/dist/inheritEnvWire.d.ts +3 -2
  206. package/dist/inheritEnvWire.js +12 -14
  207. package/dist/interactiveHalt.js +17 -6
  208. package/dist/liveModelCatalog.d.ts +3 -3
  209. package/dist/liveModelCatalog.js +15 -13
  210. package/dist/liveQuestionStore.d.ts +2 -21
  211. package/dist/mcpLiveness.d.ts +2 -1
  212. package/dist/mcpPanel.d.ts +10 -1
  213. package/dist/mcpPanel.js +40 -13
  214. package/dist/mcpProbeCapability.d.ts +2 -1
  215. package/dist/mcpProbeCapability.js +7 -11
  216. package/dist/mcpProbeWire.d.ts +9 -2
  217. package/dist/mcpProbeWire.js +6 -1
  218. package/dist/mcpWireCaps.d.ts +47 -2
  219. package/dist/mcpWireCaps.js +164 -16
  220. package/dist/memoryEntriesWire.d.ts +4 -9
  221. package/dist/memoryEntriesWire.js +5 -10
  222. package/dist/model/modelSupplyRules.d.ts +0 -2
  223. package/dist/model/modelSupplyRules.js +3 -12
  224. package/dist/model/modelsPolicy.d.ts +0 -5
  225. package/dist/model/modelsPolicy.js +6 -36
  226. package/dist/model/onboardJudgement.d.ts +93 -0
  227. package/dist/model/onboardJudgement.js +415 -0
  228. package/dist/model/subagentModelWord.d.ts +31 -0
  229. package/dist/model/subagentModelWord.js +261 -0
  230. package/dist/model/tierVocabulary.d.ts +2 -0
  231. package/dist/model/tierVocabulary.js +17 -5
  232. package/dist/modelCapabilityProbe.d.ts +64 -0
  233. package/dist/modelCapabilityProbe.js +600 -0
  234. package/dist/modelIdentityResolvability.d.ts +3 -0
  235. package/dist/modelIdentityResolvability.js +26 -17
  236. package/dist/notifications.d.ts +6 -0
  237. package/dist/notifications.js +71 -23
  238. package/dist/outputStyleSeatCapability.d.ts +0 -3
  239. package/dist/outputStyleSeatCapability.js +0 -3
  240. package/dist/ownKey.d.ts +22 -0
  241. package/dist/ownKey.js +94 -3
  242. package/dist/panelReduce.d.ts +21 -10
  243. package/dist/panelReduce.js +728 -550
  244. package/dist/panelStateHolder.d.ts +3 -7
  245. package/dist/panelStateHolder.js +14 -130
  246. package/dist/peerLaneCapability.d.ts +0 -4
  247. package/dist/peerLaneCapability.js +0 -6
  248. package/dist/permissionRuleIssue.js +2 -0
  249. package/dist/permissionRulesWriteCapability.d.ts +2 -5
  250. package/dist/permissionRulesWriteCapability.js +8 -12
  251. package/dist/permissionWireCaps.d.ts +2 -2
  252. package/dist/permissionWireCaps.js +2 -0
  253. package/dist/permissionsAllowGrantCapability.d.ts +0 -4
  254. package/dist/permissionsAllowGrantCapability.js +0 -6
  255. package/dist/permissionsDeclaration.d.ts +0 -11
  256. package/dist/permissionsDeclaration.js +60 -53
  257. package/dist/pluginHooksWire.d.ts +46 -3
  258. package/dist/pluginHooksWire.js +219 -16
  259. package/dist/preemptWire.d.ts +44 -0
  260. package/dist/preemptWire.js +83 -0
  261. package/dist/printModelStatus.d.ts +63 -0
  262. package/dist/printModelStatus.js +155 -0
  263. package/dist/printToolResultFrame.js +15 -4
  264. package/dist/replayBody.d.ts +3 -0
  265. package/dist/replayBody.js +14 -0
  266. package/dist/request/taskRequest.d.ts +11 -6
  267. package/dist/request/taskRequest.js +112 -19
  268. package/dist/resumeRefusalCopy.d.ts +13 -9
  269. package/dist/resumeRefusalCopy.js +81 -118
  270. package/dist/retryStatus.d.ts +45 -0
  271. package/dist/retryStatus.js +185 -1
  272. package/dist/rewindArchiveCapability.d.ts +0 -4
  273. package/dist/rewindArchiveCapability.js +2 -10
  274. package/dist/rewindArchiveReading.d.ts +0 -1
  275. package/dist/rewindArchiveReading.js +0 -3
  276. package/dist/runCancelContext.d.ts +2 -1
  277. package/dist/runCancelContext.js +4 -2
  278. package/dist/runReattachPolicy.d.ts +31 -0
  279. package/dist/runReattachPolicy.js +46 -0
  280. package/dist/runTerminal.d.ts +3 -6
  281. package/dist/runTerminal.js +8 -9
  282. package/dist/sandboxWire.d.ts +3 -1
  283. package/dist/sandboxWire.js +76 -27
  284. package/dist/scenarioRefusal.d.ts +9 -0
  285. package/dist/scenarioRefusal.js +111 -0
  286. package/dist/scenarioWire.js +1 -1
  287. package/dist/seam.d.ts +48 -2
  288. package/dist/seam.js +25 -4
  289. package/dist/seatContract.d.ts +311 -18
  290. package/dist/seatContract.js +824 -100
  291. package/dist/selfOrchestrationDenial.js +7 -19
  292. package/dist/sessionIdSegment.d.ts +6 -0
  293. package/dist/sessionIdSegment.js +24 -0
  294. package/dist/sessionMemoryStatus.js +6 -11
  295. package/dist/sessionPolicyCapability.d.ts +2 -5
  296. package/dist/sessionPolicyCapability.js +8 -12
  297. package/dist/sessionSyncFileHistoryCapability.d.ts +0 -3
  298. package/dist/sessionSyncFileHistoryCapability.js +0 -3
  299. package/dist/settingsHooksSalvage.d.ts +44 -0
  300. package/dist/settingsHooksSalvage.js +211 -0
  301. package/dist/skillToolListsCapability.d.ts +2 -4
  302. package/dist/skillToolListsCapability.js +8 -9
  303. package/dist/sqlEngineCapability.d.ts +0 -4
  304. package/dist/sqlEngineCapability.js +0 -6
  305. package/dist/sseIdleTriage.js +3 -2
  306. package/dist/steerPriorityCapability.d.ts +0 -3
  307. package/dist/steerPriorityCapability.js +0 -3
  308. package/dist/streamDrainingLegs.d.ts +4 -0
  309. package/dist/streamDrainingLegs.js +6 -1
  310. package/dist/subagent/engineCompactWire.d.ts +0 -1
  311. package/dist/subagent/engineCompactWire.js +7 -5
  312. package/dist/subagent/engineSubagentResume.js +15 -9
  313. package/dist/subagent/engineTaskHandleWire.js +4 -7
  314. package/dist/subagentContentStore.d.ts +3 -0
  315. package/dist/subagentContentStore.js +22 -10
  316. package/dist/submitReopen.d.ts +24 -0
  317. package/dist/submitReopen.js +75 -0
  318. package/dist/terminalStatuses.d.ts +3 -0
  319. package/dist/terminalStatuses.js +10 -2
  320. package/dist/toolHistoryMismatch.js +3 -2
  321. package/dist/toolResult.d.ts +10 -1
  322. package/dist/toolResult.js +34 -6
  323. package/dist/toolRoster.d.ts +3 -4
  324. package/dist/toolRoster.js +21 -22
  325. package/dist/turnFailurePresentation.d.ts +39 -0
  326. package/dist/turnFailurePresentation.js +402 -0
  327. package/dist/usageAnalytics.js +6 -11
  328. package/dist/userAttachmentEnvelope.d.ts +1 -0
  329. package/dist/userAttachmentEnvelope.js +37 -7
  330. package/dist/userAttachmentSeat.d.ts +21 -0
  331. package/dist/userAttachmentSeat.js +75 -0
  332. package/dist/userInvokedSkillsCapability.d.ts +11 -4
  333. package/dist/userInvokedSkillsCapability.js +31 -10
  334. package/dist/webSearchBackendCapability.d.ts +0 -4
  335. package/dist/webSearchBackendCapability.js +0 -6
  336. package/dist/wireErrorTriage.d.ts +7 -0
  337. package/dist/wireErrorTriage.js +26 -23
  338. package/dist/wireFailureShape.d.ts +62 -5
  339. package/dist/wireFailureShape.js +106 -5
  340. package/dist/wireRefusalCopy.d.ts +25 -3
  341. package/dist/wireRefusalCopy.js +74 -80
  342. package/dist/workflowsJournalCapability.d.ts +2 -5
  343. package/dist/workflowsJournalCapability.js +8 -12
  344. package/dist/writeProtectionCapability.d.ts +0 -4
  345. package/dist/writeProtectionCapability.js +0 -6
  346. package/docs/INTEGRATION-CLIENTS.md +1775 -56
  347. package/package.json +6 -5
  348. package/dist/attachmentSeatCapability.d.ts +0 -12
  349. package/dist/attachmentSeatCapability.js +0 -23
  350. package/dist/hitl/approvalOutcomeNote.d.ts +0 -10
  351. package/dist/hitl/approvalOutcomeNote.js +0 -29
  352. package/dist/sessionReadRedactionCapability.d.ts +0 -13
  353. package/dist/sessionReadRedactionCapability.js +0 -35
@@ -0,0 +1,155 @@
1
+ import { retryStatusFromArm, retryStatusNotice } from './retryStatus.js';
2
+ import { guardedRead, readOwnDataFiniteNumber, readOwnDataNonEmptyString, readOwnDataValue } from './ownKey.js';
3
+ export const PRINT_MODEL_STATUS_SUBTYPE = '_sema_model_status';
4
+ export const PRINT_LAST_MODEL_STATUS_KEY = '_sema_last_model_status';
5
+ function httpStatusOf(v) {
6
+ return typeof v === 'number' && Number.isInteger(v) && v > 0 && v <= 999 ? v : undefined;
7
+ }
8
+ function ccRetryErrorCategory(status) {
9
+ const code = httpStatusOf(status.errorStatus);
10
+ if (code === 529 || status.providerCondition === 'overloaded')
11
+ return 'overloaded';
12
+ if (code === 429)
13
+ return 'rate_limit';
14
+ if (code === 401 || code === 403)
15
+ return 'authentication_failed';
16
+ if (code !== undefined && code >= 408)
17
+ return 'server_error';
18
+ return 'unknown';
19
+ }
20
+ function modelStatusPayload(status, ctx) {
21
+ const code = httpStatusOf(status.errorStatus);
22
+ const terminal = 'terminal' in status && status.terminal === true;
23
+ const sane = (v) => (typeof v === 'number' && Number.isFinite(v) && v >= 0 ? v : undefined);
24
+ const count = (v) => (typeof v === 'number' && Number.isInteger(v) && v >= 0 ? v : undefined);
25
+ const retryDelayMs = status.kind !== 'waiting' && !terminal ? sane(Math.max(0, status.deadline - ctx.nowMs)) : undefined;
26
+ const attempt = count(status.attempt);
27
+ const maxRetries = count(status.maxRetries);
28
+ const elapsed = sane(status.elapsedMs);
29
+ const ceiling = sane(status.timeoutMs);
30
+ const model = ctx.model !== undefined && ctx.model.length > 0 ? ctx.model : undefined;
31
+ const notice = retryStatusNotice(status, model !== undefined ? { modelName: model } : undefined);
32
+ return {
33
+ kind: status.kind,
34
+ ...(terminal ? { terminal: true } : {}),
35
+ ...(attempt !== undefined ? { attempt } : {}),
36
+ ...(maxRetries !== undefined ? { max_retries: maxRetries } : {}),
37
+ ...(retryDelayMs !== undefined ? { retry_delay_ms: retryDelayMs } : {}),
38
+ ...(code !== undefined ? { error_status: code } : {}),
39
+ ...(typeof status.providerCondition === 'string' ? { provider_condition: status.providerCondition } : {}),
40
+ ...(typeof status.errClass === 'string' ? { err_class: status.errClass } : {}),
41
+ ...(elapsed !== undefined ? { elapsed_ms: elapsed } : {}),
42
+ ...(ceiling !== undefined ? { timeout_ms: ceiling } : {}),
43
+ ...(model !== undefined ? { model } : {}),
44
+ phase: notice.phase,
45
+ ...(notice.recourse !== undefined ? { recourse: notice.recourse } : {}),
46
+ message: notice.line,
47
+ };
48
+ }
49
+ function apiRetryKeyOf(status) {
50
+ const terminal = 'terminal' in status && status.terminal === true;
51
+ const ok = (v) => typeof v === 'number' && Number.isInteger(v) && v >= 0;
52
+ if (status.kind === 'waiting' || terminal || !ok(status.attempt) || !ok(status.maxRetries))
53
+ return null;
54
+ return `${String(status.attempt)}/${String(status.maxRetries)}/${String(status.errClass ?? '')}/${String(status.errorStatus ?? '')}`;
55
+ }
56
+ function statusFrameOf(status, ctx, uuid, refresh) {
57
+ const payload = modelStatusPayload(status, ctx);
58
+ if (apiRetryKeyOf(status) !== null && !refresh) {
59
+ return {
60
+ type: 'system',
61
+ subtype: 'api_retry',
62
+ attempt: status.attempt ?? 0,
63
+ max_retries: status.maxRetries ?? 0,
64
+ retry_delay_ms: payload.retry_delay_ms ?? 0,
65
+ error_status: payload.error_status ?? null,
66
+ error: ccRetryErrorCategory(status),
67
+ ...(payload.provider_condition !== undefined ? { _sema_provider_condition: payload.provider_condition } : {}),
68
+ ...(payload.model !== undefined ? { _sema_model: payload.model } : {}),
69
+ _sema_message: payload.message,
70
+ uuid,
71
+ session_id: ctx.sessionId,
72
+ };
73
+ }
74
+ return { type: 'system', subtype: PRINT_MODEL_STATUS_SUBTYPE, _sema_model_status: { ...payload, ...(refresh ? { refresh: true } : {}) }, uuid, session_id: ctx.sessionId };
75
+ }
76
+ function isMainLaneArm(msg) {
77
+ const tri = (o, key) => {
78
+ try {
79
+ const d = Object.getOwnPropertyDescriptor(o, key);
80
+ if (d !== undefined && !('value' in d))
81
+ return { ok: false };
82
+ return { ok: true, v: readOwnDataValue(o, key) };
83
+ }
84
+ catch {
85
+ return { ok: false };
86
+ }
87
+ };
88
+ const top = tri(msg, 'parentToolCallId');
89
+ if (!top.ok)
90
+ return false;
91
+ const event = tri(msg, 'event');
92
+ if (!event.ok)
93
+ return false;
94
+ const nested = typeof event.v === 'object' && event.v !== null ? tri(event.v, 'parentToolCallId') : { ok: true, v: undefined };
95
+ if (!nested.ok)
96
+ return false;
97
+ return typeof top.v !== 'string' && typeof nested.v !== 'string';
98
+ }
99
+ export function createPrintModelStatusTracker() {
100
+ let last = null;
101
+ let lastApiRetryKey = null;
102
+ const clear = () => {
103
+ last = null;
104
+ lastApiRetryKey = null;
105
+ };
106
+ return {
107
+ take(msg, ctx) {
108
+ try {
109
+ const type = guardedRead(() => readOwnDataValue(msg, 'type'));
110
+ if (type === 'stream_event' || type === 'tool_end_result') {
111
+ if (msg !== null && msg !== undefined && isMainLaneArm(msg))
112
+ clear();
113
+ return null;
114
+ }
115
+ if (type !== 'retry_status')
116
+ return null;
117
+ const sessionId = readOwnDataNonEmptyString(ctx, 'sessionId');
118
+ const mintUuid = readOwnDataValue(ctx, 'mintUuid');
119
+ const nowMs = readOwnDataFiniteNumber(ctx, 'nowMs');
120
+ if (sessionId === undefined || typeof mintUuid !== 'function' || nowMs === undefined)
121
+ return null;
122
+ const status = retryStatusFromArm(msg, nowMs);
123
+ if (status === undefined)
124
+ return null;
125
+ if (status === null) {
126
+ clear();
127
+ return null;
128
+ }
129
+ const model = readOwnDataNonEmptyString(ctx, 'model');
130
+ const key = apiRetryKeyOf(status);
131
+ const refresh = key !== null && key === lastApiRetryKey;
132
+ const safeCtx = { sessionId, nowMs, mintUuid, ...(model !== undefined ? { model } : {}) };
133
+ const frame = statusFrameOf(status, safeCtx, mintUuid(), refresh);
134
+ lastApiRetryKey = key;
135
+ last = { status, model };
136
+ return frame;
137
+ }
138
+ catch {
139
+ return null;
140
+ }
141
+ },
142
+ beginTurn: clear,
143
+ resultFields(nowMs) {
144
+ try {
145
+ if (last === null)
146
+ return {};
147
+ const now = typeof nowMs === 'number' && Number.isFinite(nowMs) ? nowMs : 0;
148
+ return { _sema_last_model_status: modelStatusPayload(last.status, { ...(last.model !== undefined ? { model: last.model } : {}), nowMs: now }) };
149
+ }
150
+ catch {
151
+ return {};
152
+ }
153
+ },
154
+ };
155
+ }
@@ -1,11 +1,19 @@
1
1
  import { isCcToolDenialKind } from './gateVocabulary.js';
2
2
  export { flattenWireOutput as flattenToolOutput } from './adapt/wireShapes.js';
3
3
  import { flattenWireOutput } from './adapt/wireShapes.js';
4
- import { toolResultEnvelopeParts, toolResultOutcomeOf } from './adapt/toolCards.js';
5
- import { readFrameTrueMark } from './ownKey.js';
4
+ import { toolResultEnvelopeParts, toolResultOutcomeOf, toolResultRowFlagParts, toolResultRowIdentity } from './adapt/toolCards.js';
5
+ import { engineRefOf } from './engineRowRef.js';
6
+ import { guardedRead } from './ownKey.js';
7
+ import { gateOutcomeOf } from './gateOutcome.js';
8
+ import { isUnsettledHeldToolEnd } from './engineRowRef.js';
6
9
  export function toolEndResultToUserFrame(arm) {
7
10
  if (typeof arm.toolCallId !== 'string' || arm.toolCallId.length === 0)
8
11
  return null;
12
+ if (isUnsettledHeldToolEnd(arm))
13
+ return null;
14
+ const armEventId = arm.eventId;
15
+ const callId = arm.toolCallId;
16
+ const rowIdentity = toolResultRowIdentity([{ eventId: typeof armEventId === 'string' ? armEventId : undefined, engineRef: engineRefOf(arm) }], callId, { uuid: () => callId });
9
17
  const text = flattenWireOutput(arm.output);
10
18
  const parent = typeof arm.parentToolCallId === 'string' ? arm.parentToolCallId : null;
11
19
  const outcome = toolResultOutcomeOf(typeof arm.toolName === 'string' ? arm.toolName : '', {
@@ -15,6 +23,7 @@ export function toolEndResultToUserFrame(arm) {
15
23
  isError: arm.isError === true,
16
24
  }, undefined, parent === null ? 'leader' : 'subagent');
17
25
  const envelope = toolResultEnvelopeParts(outcome);
26
+ const gateView = guardedRead(() => gateOutcomeOf(arm));
18
27
  const content = Array.isArray(outcome.body.content) ? outcome.body.content : arm.truncated === true ? `${text}\n…(truncated)` : text;
19
28
  return {
20
29
  type: 'user',
@@ -31,10 +40,12 @@ export function toolEndResultToUserFrame(arm) {
31
40
  },
32
41
  parent_tool_use_id: parent,
33
42
  ...(isCcToolDenialKind(arm._sema_denial_kind) ? { _sema_denial_kind: arm._sema_denial_kind } : {}),
34
- ...(readFrameTrueMark(arm, 'notExecuted') ? { _sema_not_executed: true } : {}),
43
+ ...(gateView !== undefined ? { _sema_gate: gateView } : {}),
44
+ ...toolResultRowFlagParts(arm),
35
45
  ...(Object.hasOwn(envelope, 'tool_use_result') ? { tool_use_result: envelope.tool_use_result } : {}),
36
46
  ...(Object.hasOwn(envelope, '_sema_degraded') ? { _sema_degraded: envelope._sema_degraded } : {}),
37
- uuid: arm.uuid,
47
+ uuid: rowIdentity.uuid,
38
48
  session_id: arm.session_id,
49
+ ...(rowIdentity.engineRef !== undefined ? { _sema_engine_ref: rowIdentity.engineRef } : {}),
39
50
  };
40
51
  }
@@ -10,3 +10,6 @@ export interface DoneResultView {
10
10
  readonly row?: ReplayRowView;
11
11
  }
12
12
  export declare function doneResultView(result: unknown): DoneResultView;
13
+ export declare function isReplayedTerminal(frame: object | null | undefined): boolean;
14
+ export declare function isReplayMarked(message: object | null | undefined): boolean;
15
+ export declare const RESULT_REPLAYED_TEXT = "No new run was started: this request's idempotency key matched an earlier submission.";
@@ -1,3 +1,4 @@
1
+ import { readFrameTrueMark } from './ownKey.js';
1
2
  function guarded(o, k) {
2
3
  try {
3
4
  return o[k];
@@ -23,3 +24,16 @@ export function doneResultView(result) {
23
24
  }
24
25
  return { replay: true, engine: guarded(result, 'result'), row };
25
26
  }
27
+ export function isReplayedTerminal(frame) {
28
+ if (frame === null || typeof frame !== 'object' || Array.isArray(frame))
29
+ return false;
30
+ if (guarded(frame, 'type') !== 'done')
31
+ return false;
32
+ if (readFrameTrueMark(frame, 'replay'))
33
+ return true;
34
+ return doneResultView(guarded(frame, 'result')).replay;
35
+ }
36
+ export function isReplayMarked(message) {
37
+ return readFrameTrueMark(message, '_sema_replay');
38
+ }
39
+ export const RESULT_REPLAYED_TEXT = "No new run was started: this request's idempotency key matched an earlier submission.";
@@ -1,6 +1,7 @@
1
- import type { TaskRequest } from '@sema-agent/sdk';
1
+ import type { TaskRequest, UserAttachment } from '@sema-agent/sdk';
2
2
  import { type OutputStyleSeatReading } from '../outputStyleSeatCapability.js';
3
3
  import { type ApprovalReachWord } from '../approvalReachWire.js';
4
+ import { type HostTurnSettings, type HostTurnSettingsInput } from '../hostTurnSettings.js';
4
5
  export type RequestLane = 'interactive' | 'print' | 'utility';
5
6
  export type TaskRequestLike = Record<string, unknown>;
6
7
  export interface RequestFieldSpec {
@@ -22,7 +23,9 @@ export interface TaskRequestInput {
22
23
  reasoningEffort?: string;
23
24
  model?: string;
24
25
  images?: readonly unknown[];
26
+ userAttachments?: readonly UserAttachment[];
25
27
  skills?: unknown;
28
+ userInvokedSkills?: readonly string[];
26
29
  mcpServers?: unknown;
27
30
  clientContext?: Record<string, unknown>;
28
31
  scratchpadDir?: string;
@@ -58,12 +61,13 @@ export interface TaskRequestInput {
58
61
  disableSkills?: TaskRequest['disableSkills'];
59
62
  rewind?: Record<string, unknown>;
60
63
  repo?: string;
64
+ hostSettings: HostTurnSettings;
61
65
  settings?: {
62
- resolved?: Record<string, unknown>;
63
- webSearch?: Record<string, unknown>;
66
+ resolved?: never;
67
+ webSearch?: never;
64
68
  ultracode?: boolean;
65
- hooks?: Record<string, unknown>;
66
- outputStyle?: string;
69
+ hooks?: never;
70
+ outputStyle?: never;
67
71
  };
68
72
  }
69
73
  export declare const TASK_REQUEST_OMISSION_CAUSES: readonly ["upstream_absent", "other_channel", "off_lane", "not_live"];
@@ -75,10 +79,10 @@ export interface TaskRequestOmission {
75
79
  export declare function taskRequestOmissionCauseDetail(cause: unknown): string;
76
80
  export declare const TASK_REQUEST_OMISSION_CAUSE_NOTICES: Readonly<Record<TaskRequestOmissionCause, string>>;
77
81
  export declare function taskRequestOmissionCauseNotice(cause: unknown): string;
78
- export declare function taskRequestOmissionCausePhrase(cause: unknown): string;
79
82
  export interface TaskRequestAssembly {
80
83
  readonly request: TaskRequestLike;
81
84
  readonly omitted: readonly TaskRequestOmission[];
85
+ readonly host: HostTurnSettings;
82
86
  }
83
87
  export type TaskRequestSeatReading = {
84
88
  readonly seat: 'seated';
@@ -96,6 +100,7 @@ export interface UpstreamAbsentRequestIntent {
96
100
  export declare const UPSTREAM_ABSENT_REQUEST_INTENTS: readonly UpstreamAbsentRequestIntent[];
97
101
  export declare const REQUEST_LANES: readonly RequestLane[];
98
102
  export declare function taskRequestSeatOf(key: string, lane: RequestLane): TaskRequestSeatReading;
103
+ export declare function hostTurnSettings(input: HostTurnSettingsInput): HostTurnSettings;
99
104
  export declare const MEMORY_CAPTURE_OFF: "off";
100
105
  export declare function memoryCaptureDeclarationField(declared: boolean): {
101
106
  memoryCapture: 'off';
@@ -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 暂存目录是给**工具**写的,零工具面上没人写' },
@@ -112,9 +116,6 @@ export function taskRequestOmissionCauseNotice(cause) {
112
116
  ? TASK_REQUEST_OMISSION_CAUSE_NOTICES[cause]
113
117
  : TASK_REQUEST_OMISSION_UNKNOWN_CAUSE_NOTICE;
114
118
  }
115
- export function taskRequestOmissionCausePhrase(cause) {
116
- return omissionNoticePartsOf(cause)?.reason ?? TASK_REQUEST_OMISSION_UNKNOWN_CAUSE_REASON;
117
- }
118
119
  const row = (field) => ({ via: 'matrix', field });
119
120
  const INPUT_KEY_ROUTES = {
120
121
  objective: { via: 'always' },
@@ -125,7 +126,9 @@ const INPUT_KEY_ROUTES = {
125
126
  reasoningEffort: row('reasoningEffort'),
126
127
  model: row('model'),
127
128
  images: row('images'),
129
+ userAttachments: row('userAttachments'),
128
130
  skills: row('skills'),
131
+ userInvokedSkills: row('userInvokedSkills'),
129
132
  mcpServers: row('mcpServers'),
130
133
  clientContext: row('clientContext'),
131
134
  scratchpadDir: row('scratchpadDir'),
@@ -173,8 +176,12 @@ const INPUT_KEY_ROUTES = {
173
176
  rewind: row('resumeAt/resumeAtMode/restoreFiles/rewindFilesTo'),
174
177
  repo: row('repo'),
175
178
  allowTools: row('allowTools'),
179
+ hostSettings: { via: 'control' },
176
180
  settings: { via: 'settings' },
177
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;
178
185
  const SETTINGS_KEY_ROUTES = {
179
186
  resolved: row('settings.<resolved>'),
180
187
  webSearch: row('settings.webSearch'),
@@ -214,6 +221,35 @@ const OMISSION_JUDGES = {
214
221
  not_live: (s, _lane, live) => s.via === 'matrix' && s.spec.live && !live,
215
222
  };
216
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
+ };
217
253
  const REQUEST_LANE_SET = { interactive: true, print: true, utility: true };
218
254
  export const REQUEST_LANES = Object.freeze(Object.keys(REQUEST_LANE_SET));
219
255
  const refuseBadLane = (lane) => {
@@ -231,6 +267,8 @@ const VALUE_LEVEL_IN_PLAY = Object.freeze({
231
267
  oneShot: (v) => v === true,
232
268
  interactiveTools: (v) => v === false,
233
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,
234
272
  attachmentIds: (v) => Array.isArray(v) && v.length > 0,
235
273
  excludeTools: (v) => Array.isArray(v) && v.length > 0,
236
274
  excludeAllTools: (v) => v === true,
@@ -405,6 +443,9 @@ const resolvedSnapshotForWire = (resolved) => {
405
443
  }
406
444
  return out;
407
445
  };
446
+ export function hostTurnSettings(input) {
447
+ return buildHostTurnSettings(input, (snapshot) => resolvedSnapshotForWire(snapshot));
448
+ }
408
449
  export const MEMORY_CAPTURE_OFF = 'off';
409
450
  export function memoryCaptureDeclarationField(declared) {
410
451
  return declared ? { memoryCapture: MEMORY_CAPTURE_OFF } : {};
@@ -430,11 +471,11 @@ export function memoryOffDeclared(input) {
430
471
  const sm = input.settingsMemory;
431
472
  if (sm !== undefined && sm !== null) {
432
473
  if (typeof sm !== 'object' || Array.isArray(sm)) {
433
- throw new TypeError(`memoryOffDeclared: settings 的 memory 段必须是对象 —— 收到 ${coarseShape(sm)}。`);
474
+ throw new TypeError(renderMessage(msg('config.taskRequest.memoryOff.settingsSectionNotObject', { shape: coarseShape(sm) })));
434
475
  }
435
476
  const enabled = sm.enabled;
436
477
  if (enabled !== undefined && typeof enabled !== 'boolean') {
437
- throw new TypeError(`memoryOffDeclared: settings memory.enabled 在场时必须是布尔 —— 收到 ${coarseShape(enabled)}。`);
478
+ throw new TypeError(renderMessage(msg('config.taskRequest.memoryOff.enabledNotBoolean', { shape: coarseShape(enabled) })));
438
479
  }
439
480
  fromSettings = enabled === false;
440
481
  }
@@ -533,6 +574,23 @@ const refuseBadAllowTools = (v) => {
533
574
  `收到 ${coarseShape(v)}。这一位是**可用性选择器**(收紧声明):本层若把坏形静默删键,这一次运行会挂上声明人以为已经收窄掉的全部工具。` +
534
575
  '错误文本只报形状,不回显值。');
535
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
+ };
536
594
  const refuseBadExcludeAllTools = (v) => {
537
595
  if (v === undefined || v === null || v === true || v === false)
538
596
  return;
@@ -566,13 +624,16 @@ const refuseBadRequireExistingSession = (v) => {
566
624
  '上游对非布尔值同样拒收。错误文本只报形状,不回显值。');
567
625
  };
568
626
  const hasResumableSessionId = (sid) => typeof sid === 'string' && sid.length > 0;
569
- const refuseRequireExistingWithoutSession = (requireExisting, sessionId) => {
627
+ const refuseRequireExistingWithoutSession = (requireExisting, sessionId, where = 'buildTaskRequest') => {
570
628
  if (requireExisting !== true || hasResumableSessionId(sessionId))
571
629
  return;
572
- const shape = sessionId === undefined ? '缺席' : typeof sessionId === 'string' ? '空串' : coarseShape(sessionId);
573
- throw new TypeError(`buildTaskRequest: requireExistingSession: true 要求续一个已存在的会话,但 sessionId ${shape} —— 没有可续的会话。` +
574
- '上游对这一形同样拒收(不会新开会话,也不会续上任何东西);本层在装配前拒,不让它走一次往返。' +
575
- '处置:要续哪个会话,就把它的 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 })));
576
637
  };
577
638
  const refuseBadMaxTokens = (v) => {
578
639
  if (v === undefined || v === null)
@@ -643,15 +704,15 @@ export function parseMaxCostUsd(text) {
643
704
  return { ok: false, why: 'not_positive' };
644
705
  return { ok: true, value };
645
706
  }
646
- const ACCESSOR_READ_ORDER = ['live', 'memoryCapture', 'memory', 'settings', 'maxCostUsd', 'excludeAllTools', 'maxTokens', 'outputRetries', 'fileHistory', 'inheritEnv', 'requireExistingSession', 'disableSkills', 'approvalReach', 'allowTools'];
647
- 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) });
648
709
  function dataFirstSnapshot(input, afterData) {
649
710
  let descs;
650
711
  try {
651
712
  descs = Object.getOwnPropertyDescriptors(input);
652
713
  }
653
714
  catch {
654
- throw new TypeError('buildTaskRequest: 入参的键集 / 属性描述符读不出(代理 trap 抛)—— 无法安全快照声明,拒绝装配。错误文本只报形状,不回显值。');
715
+ throw new TypeError(renderMessage(msg('config.taskRequest.inputKeysUnreadable')));
655
716
  }
656
717
  const bag = Object.create(null);
657
718
  const accessors = [];
@@ -682,11 +743,14 @@ export function assembleTaskRequest(input, lane) {
682
743
  let resolvedMaterializeError;
683
744
  let resolvedHookRan = false;
684
745
  const src = dataFirstSnapshot(input, (bag) => {
685
- const st = bag['settings'];
686
- 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) {
687
750
  resolvedHookRan = true;
688
- resolvedInEarly = st.resolved;
751
+ resolvedInEarly = product.carried.resolved;
689
752
  try {
753
+ rethrowHostResolvedDeferred(product);
690
754
  resolvedMaterialized = resolvedSnapshotForWire(resolvedInEarly);
691
755
  }
692
756
  catch (e) {
@@ -703,11 +767,18 @@ export function assembleTaskRequest(input, lane) {
703
767
  '这一位装着已解析权限面与 hooks:把畸形容器当成「没给」= 请求带着被剥掉的权限面照发。错误文本只报形状,不回显值。');
704
768
  }
705
769
  const settingsObj = present(settingsIn) ? settingsIn : {};
706
- 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;
707
776
  const resolvedRoute = SETTINGS_KEY_ROUTES.resolved;
708
777
  const resolvedOpen = resolvedRoute.via === 'matrix' && omissionCauseOf(standingOf(resolvedRoute), lane, live) === undefined;
709
778
  if (resolvedOpen && resolvedHookRan && resolvedMaterializeError !== undefined)
710
779
  throw resolvedMaterializeError;
780
+ if (resolvedOpen && !resolvedHookRan)
781
+ rethrowHostResolvedDeferred(host);
711
782
  const resolvedWire = resolvedOpen ? (resolvedMaterialized ?? resolvedSnapshotForWire(resolvedIn)) : {};
712
783
  const maxCostUsdIn = src.maxCostUsd;
713
784
  const excludeAllToolsIn = src.excludeAllTools;
@@ -737,7 +808,14 @@ export function assembleTaskRequest(input, lane) {
737
808
  settings: settingsIn,
738
809
  });
739
810
  const SETTINGS_KEYS = Object.keys(SETTINGS_KEY_ROUTES);
740
- 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
+ };
741
819
  refuseBadMemoryCapture(memoryCaptureIn);
742
820
  refuseBadMemoryOff(memoryIn);
743
821
  refuseBadMaxCostUsd(maxCostUsdIn);
@@ -750,6 +828,7 @@ export function assembleTaskRequest(input, lane) {
750
828
  refuseBadDisableSkills(disableSkillsIn, 'buildTaskRequest');
751
829
  refuseBadApprovalReach(approvalReachIn, 'buildTaskRequest');
752
830
  refuseBadAllowTools(allowToolsIn);
831
+ refuseBadUserInvokedSkills(i.userInvokedSkills);
753
832
  const rewindRoute = INPUT_KEY_ROUTES.rewind;
754
833
  const RETIRED_REWIND_FILES_KEY = 'rewindFiles';
755
834
  const REWIND_KEYS = rewindRoute.via === 'matrix' ? rewindRoute.field.split('/') : [];
@@ -816,6 +895,12 @@ export function assembleTaskRequest(input, lane) {
816
895
  '处置:删掉这个键;要在回退会话时一并还原文件,改交 ' +
817
896
  'rewind.restoreFiles: true(必须与 rewind.resumeAt 同交);只还原文件、不动会话,交 rewind.rewindFilesTo。错误文本只报键名,不回显值。');
818
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
+ }
819
904
  if (unknownKeys.length > 0) {
820
905
  const shown = unknownKeys.slice(0, MAX_UNKNOWN_KEYS_SHOWN).map(keyForDisplay).join(', ');
821
906
  const more = unknownKeys.length > MAX_UNKNOWN_KEYS_SHOWN ? ` 等共 ${unknownKeys.length} 个` : '';
@@ -829,6 +914,11 @@ export function assembleTaskRequest(input, lane) {
829
914
  refuseRequireExistingWithoutSession(requireExistingSessionIn, i.sessionId);
830
915
  refuseDisableSkillsConflict(disableSkillsIn, i.skills, Reflect.get(src, 'agents'), 'buildTaskRequest');
831
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
+ }
832
922
  const carries = (route, value, key) => {
833
923
  if (route.via === 'always')
834
924
  return present(value);
@@ -870,7 +960,9 @@ export function assembleTaskRequest(input, lane) {
870
960
  ...(on('reasoningEffort') ? { reasoningEffort: i.reasoningEffort } : {}),
871
961
  ...(on('model') ? { model: i.model } : {}),
872
962
  ...(on('images') ? { images: i.images } : {}),
963
+ ...(on('userAttachments') ? { userAttachments: [...(i.userAttachments ?? [])] } : {}),
873
964
  ...(on('skills') ? { skills: i.skills } : {}),
965
+ ...(on('userInvokedSkills') ? { userInvokedSkills: allowToolsCopy(i.userInvokedSkills) } : {}),
874
966
  ...(on('mcpServers') ? { mcpServers: i.mcpServers } : {}),
875
967
  ...(on('rewind') ? rewindWire : {}),
876
968
  ...(on('permissionMode') ? { permissionMode: i.permissionMode } : {}),
@@ -905,7 +997,7 @@ export function assembleTaskRequest(input, lane) {
905
997
  ...(on('approvalReach') ? { approvalReach: approvalReachIn } : {}),
906
998
  ...(Object.keys(settingsOut).length > 0 ? { settings: settingsOut } : {}),
907
999
  };
908
- return Object.freeze({ request: out, omitted: Object.freeze([...omitted, ...lateOmitted]) });
1000
+ return Object.freeze({ request: out, omitted: Object.freeze([...omitted, ...lateOmitted]), host });
909
1001
  }
910
1002
  export function buildTaskRequest(input, lane) {
911
1003
  return assembleTaskRequest(input, lane).request;
@@ -958,6 +1050,7 @@ export function applyLiveRequestDefaults(req, host) {
958
1050
  out.sessionId === host.mockSessionIdConstant) {
959
1051
  delete out.sessionId;
960
1052
  }
1053
+ refuseRequireExistingWithoutSession(out.requireExistingSession, out.sessionId, 'applyLiveRequestDefaults');
961
1054
  return out;
962
1055
  }
963
1056
  export function unregisteredRequestKeys(req, lane) {