@abot-ai/runtime 1.9.0 → 2.0.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 (506) hide show
  1. package/README.md +5 -1
  2. package/dist/scripts/add-runtime-model.js +11 -5
  3. package/dist/scripts/init-runtime.js +15 -10
  4. package/dist/scripts/runtime-model-addition.js +6 -1
  5. package/dist/scripts/runtime-setup-command-options.d.ts +11 -0
  6. package/dist/scripts/runtime-setup-command-options.js +41 -0
  7. package/dist/scripts/runtime-setup-files.d.ts +3 -2
  8. package/dist/scripts/runtime-setup-files.js +19 -4
  9. package/dist/scripts/runtime-setup-model-options.d.ts +8 -0
  10. package/dist/scripts/runtime-setup-model-options.js +40 -0
  11. package/dist/scripts/runtime-setup-presentation.js +2 -2
  12. package/dist/scripts/runtime-setup-provider-options.d.ts +4 -0
  13. package/dist/scripts/runtime-setup-provider-options.js +20 -0
  14. package/dist/src/model-gateway/client/contracts.d.ts +3 -0
  15. package/dist/src/model-gateway/client/input-token-count.js +36 -16
  16. package/dist/src/model-gateway/client/message-projection.d.ts +2 -0
  17. package/dist/src/model-gateway/client/message-projection.js +1 -0
  18. package/dist/src/model-gateway/client/options.js +1 -1
  19. package/dist/src/model-gateway/client/raw.js +1 -0
  20. package/dist/src/model-gateway/index.d.ts +1 -1
  21. package/dist/src/model-gateway/observability/input-token-count-diagnostics.d.ts +26 -0
  22. package/dist/src/model-gateway/observability/input-token-count-diagnostics.js +178 -0
  23. package/dist/src/model-gateway/policy/invocation-policy.d.ts +1 -3
  24. package/dist/src/model-gateway/policy/invocation-policy.js +3 -30
  25. package/dist/src/model-gateway/policy/reasoning-mode-budget.d.ts +5 -0
  26. package/dist/src/model-gateway/policy/reasoning-mode-budget.js +13 -0
  27. package/dist/src/model-gateway/policy/reasoning-policy.d.ts +10 -0
  28. package/dist/src/model-gateway/policy/reasoning-policy.js +124 -0
  29. package/dist/src/model-gateway/protocol/openai-embedding-response.d.ts +1 -0
  30. package/dist/src/model-gateway/protocol/openai-embedding-response.js +28 -0
  31. package/dist/src/model-gateway/protocol/sse-data.d.ts +9 -0
  32. package/dist/src/model-gateway/protocol/sse-data.js +67 -0
  33. package/dist/src/model-gateway/providers/envelope-budget.js +10 -1
  34. package/dist/src/model-gateway/providers/llamacpp/adapter.d.ts +2 -0
  35. package/dist/src/model-gateway/providers/llamacpp/adapter.js +79 -0
  36. package/dist/src/model-gateway/providers/llamacpp/connection.d.ts +9 -0
  37. package/dist/src/model-gateway/providers/llamacpp/connection.js +73 -0
  38. package/dist/src/model-gateway/providers/llamacpp/diagnostics.d.ts +2 -0
  39. package/dist/src/model-gateway/providers/llamacpp/diagnostics.js +17 -0
  40. package/dist/src/model-gateway/providers/llamacpp/embeddings.d.ts +2 -0
  41. package/dist/src/model-gateway/providers/llamacpp/embeddings.js +56 -0
  42. package/dist/src/model-gateway/providers/llamacpp/input-token-count.d.ts +3 -0
  43. package/dist/src/model-gateway/providers/llamacpp/input-token-count.js +59 -0
  44. package/dist/src/model-gateway/providers/llamacpp/message-projection.d.ts +2 -0
  45. package/dist/src/model-gateway/providers/llamacpp/message-projection.js +33 -0
  46. package/dist/src/model-gateway/providers/llamacpp/payload.d.ts +2 -0
  47. package/dist/src/model-gateway/providers/llamacpp/payload.js +44 -0
  48. package/dist/src/model-gateway/providers/llamacpp/response-lifetime.d.ts +1 -0
  49. package/dist/src/model-gateway/providers/llamacpp/response-lifetime.js +56 -0
  50. package/dist/src/model-gateway/providers/llamacpp/schema-format.d.ts +2 -0
  51. package/dist/src/model-gateway/providers/llamacpp/schema-format.js +29 -0
  52. package/dist/src/model-gateway/providers/llamacpp/settings.d.ts +9 -0
  53. package/dist/src/model-gateway/providers/llamacpp/settings.js +25 -0
  54. package/dist/src/model-gateway/providers/llamacpp/stream-normalizer.d.ts +10 -0
  55. package/dist/src/model-gateway/providers/llamacpp/stream-normalizer.js +85 -0
  56. package/dist/src/model-gateway/providers/llamacpp/stream.d.ts +9 -0
  57. package/dist/src/model-gateway/providers/llamacpp/stream.js +33 -0
  58. package/dist/src/model-gateway/providers/openai/embeddings.js +2 -29
  59. package/dist/src/model-gateway/providers/openai/sse-data.d.ts +1 -9
  60. package/dist/src/model-gateway/providers/openai/sse-data.js +1 -67
  61. package/dist/src/model-gateway/providers/registry.js +2 -0
  62. package/dist/src/model-gateway/server/input-token-count-handler.js +10 -1
  63. package/dist/src/model-gateway/types.d.ts +11 -1
  64. package/dist/src/runtime/adapters/long-term-memory/onboarding-provider-availability.d.ts +4 -0
  65. package/dist/src/runtime/adapters/long-term-memory/onboarding-provider-availability.js +11 -0
  66. package/dist/src/runtime/adapters/long-term-memory/onboarding-service.js +28 -1
  67. package/dist/src/runtime/adapters/registered-tool-payload-related-artifacts.d.ts +1 -0
  68. package/dist/src/runtime/adapters/registered-tool-payload-related-artifacts.js +6 -1
  69. package/dist/src/runtime/adapters/registered-tool-worker-capabilities/contracts.d.ts +1 -0
  70. package/dist/src/runtime/adapters/registered-tool-worker-capabilities/execution.d.ts +1 -0
  71. package/dist/src/runtime/adapters/registered-tool-worker-capabilities/execution.js +2 -0
  72. package/dist/src/runtime/adapters/registered-tool-worker-capabilities/payload-lifecycle.d.ts +1 -0
  73. package/dist/src/runtime/adapters/registered-tool-worker-capabilities/payload-lifecycle.js +2 -0
  74. package/dist/src/runtime/adapters/registered-tool-worker-capabilities/payload-stages.d.ts +1 -0
  75. package/dist/src/runtime/adapters/registered-tool-worker-capabilities/payload-stages.js +1 -0
  76. package/dist/src/runtime/adapters/registered-tool-worker-capabilities.js +1 -0
  77. package/dist/src/runtime/adapters/scheduler-runtime.js +2 -0
  78. package/dist/src/runtime/automations/agent-step-executor.js +1 -0
  79. package/dist/src/runtime/automations/catalog.d.ts +3 -0
  80. package/dist/src/runtime/automations/catalog.js +2 -0
  81. package/dist/src/runtime/automations/definition-contracts.d.ts +2 -0
  82. package/dist/src/runtime/automations/definition-input.js +3 -1
  83. package/dist/src/runtime/automations/draft-mutations.js +5 -1
  84. package/dist/src/runtime/automations/model-dependency-projection.d.ts +3 -1
  85. package/dist/src/runtime/automations/model-dependency-projection.js +4 -2
  86. package/dist/src/runtime/automations/publication-validation.js +7 -0
  87. package/dist/src/runtime/automations/saved-agent-management.js +1 -0
  88. package/dist/src/runtime/automations/service.d.ts +3 -0
  89. package/dist/src/runtime/capabilities/automation-builder/payload-schema.js +7 -5
  90. package/dist/src/runtime/capabilities/automations/authoring-catalog.d.ts +9 -0
  91. package/dist/src/runtime/capabilities/automations/authoring-catalog.js +1 -0
  92. package/dist/src/runtime/capabilities/automations/authoring-preparation.d.ts +3 -0
  93. package/dist/src/runtime/capabilities/automations/tool-contract.js +3 -2
  94. package/dist/src/runtime/capabilities/automations/tool-module.js +16 -7
  95. package/dist/src/runtime/capabilities/model-reasoning-controls.d.ts +23 -0
  96. package/dist/src/runtime/capabilities/model-reasoning-controls.js +56 -0
  97. package/dist/src/runtime/capabilities/scheduling/create-operations.js +2 -0
  98. package/dist/src/runtime/capabilities/scheduling/job-list-page.d.ts +1 -0
  99. package/dist/src/runtime/capabilities/scheduling/tool-module.js +5 -2
  100. package/dist/src/runtime/capabilities/scheduling/update-operations.js +2 -0
  101. package/dist/src/runtime/config/builders.js +6 -0
  102. package/dist/src/runtime/config/effective-model-config-validation.js +4 -0
  103. package/dist/src/runtime/config/llamacpp-profile-validation.d.ts +3 -0
  104. package/dist/src/runtime/config/llamacpp-profile-validation.js +15 -0
  105. package/dist/src/runtime/config/model-reasoning-schema.d.ts +40 -0
  106. package/dist/src/runtime/config/model-reasoning-schema.js +38 -0
  107. package/dist/src/runtime/config/model-reasoning-validation.d.ts +3 -0
  108. package/dist/src/runtime/config/model-reasoning-validation.js +37 -0
  109. package/dist/src/runtime/config/runner/step-instructions.d.ts +4 -0
  110. package/dist/src/runtime/config/runner/step-instructions.js +10 -6
  111. package/dist/src/runtime/config/schema.js +3 -0
  112. package/dist/src/runtime/config/validation/model-invocation-config-validation.js +14 -0
  113. package/dist/src/runtime/context/compacted-capability-result-receipt.d.ts +2 -0
  114. package/dist/src/runtime/context/compacted-capability-result-receipt.js +8 -7
  115. package/dist/src/runtime/context/execution-compacted-evidence.d.ts +4 -0
  116. package/dist/src/runtime/context/execution-compacted-evidence.js +2 -23
  117. package/dist/src/runtime/context/execution-compaction-checkpoint-selection.d.ts +19 -0
  118. package/dist/src/runtime/context/execution-compaction-checkpoint-selection.js +104 -0
  119. package/dist/src/runtime/context/model-step-compaction-inheritance.d.ts +12 -0
  120. package/dist/src/runtime/context/model-step-compaction-inheritance.js +28 -0
  121. package/dist/src/runtime/context/model-step-compaction-projection.d.ts +12 -0
  122. package/dist/src/runtime/context/model-step-compaction-projection.js +322 -0
  123. package/dist/src/runtime/context/model-step-compaction.d.ts +2 -1
  124. package/dist/src/runtime/context/model-step-compaction.js +25 -316
  125. package/dist/src/runtime/context/operation-supervision-compacted-evidence.js +7 -1
  126. package/dist/src/runtime/context/request-context.d.ts +2 -0
  127. package/dist/src/runtime/context/request-context.js +16 -0
  128. package/dist/src/runtime/context/request-tool-results-checkpoint.d.ts +2 -1
  129. package/dist/src/runtime/context/request-tool-results-checkpoint.js +35 -6
  130. package/dist/src/runtime/context/request-tool-results.js +3 -1
  131. package/dist/src/runtime/context/semantic-compaction/checkpoint-message.d.ts +5 -1
  132. package/dist/src/runtime/context/semantic-compaction/checkpoint-message.js +10 -4
  133. package/dist/src/runtime/context/semantic-compaction/execution-evidence-instructions.d.ts +4 -0
  134. package/dist/src/runtime/context/semantic-compaction/execution-evidence-instructions.js +38 -0
  135. package/dist/src/runtime/context/semantic-compaction/generation-contracts.d.ts +3 -1
  136. package/dist/src/runtime/context/semantic-compaction/generation-input.js +15 -10
  137. package/dist/src/runtime/context/semantic-compaction/inherited-source-digests.d.ts +8 -0
  138. package/dist/src/runtime/context/semantic-compaction/inherited-source-digests.js +76 -0
  139. package/dist/src/runtime/context/semantic-compaction/replacement-budget.js +3 -1
  140. package/dist/src/runtime/context/semantic-compaction/run.js +6 -12
  141. package/dist/src/runtime/knowledge-skills/builtins/computer-use.js +1 -1
  142. package/dist/src/runtime/knowledge-skills/builtins/technical-work.js +20 -2
  143. package/dist/src/runtime/knowledge-skills/builtins/what-can-i-do.d.ts +2 -0
  144. package/dist/src/runtime/knowledge-skills/builtins/what-can-i-do.js +27 -0
  145. package/dist/src/runtime/knowledge-skills/catalog.js +2 -0
  146. package/dist/src/runtime/local-application.d.ts +5 -0
  147. package/dist/src/runtime/local-host/app-service-dispatch.d.ts +1 -1
  148. package/dist/src/runtime/local-host/app-service-dispatch.js +2 -0
  149. package/dist/src/runtime/local-host/client-services.d.ts +5 -0
  150. package/dist/src/runtime/local-host/saved-approvals.js +1 -0
  151. package/dist/src/runtime/long-term-memory/onboarding/configuration.js +5 -7
  152. package/dist/src/runtime/long-term-memory/onboarding/contracts.d.ts +26 -0
  153. package/dist/src/runtime/long-term-memory/onboarding/embedding-profile-id.d.ts +1 -0
  154. package/dist/src/runtime/long-term-memory/onboarding/embedding-profile-id.js +8 -0
  155. package/dist/src/runtime/long-term-memory/onboarding/saved-profiles.d.ts +17 -0
  156. package/dist/src/runtime/long-term-memory/onboarding/saved-profiles.js +77 -0
  157. package/dist/src/runtime/long-term-memory/onboarding/service.js +40 -10
  158. package/dist/src/runtime/model/input-token-count.js +1 -0
  159. package/dist/src/runtime/model/invoke-step.js +12 -0
  160. package/dist/src/runtime/model/invoke-structured-step.d.ts +4 -1
  161. package/dist/src/runtime/model/invoke-structured-step.js +4 -0
  162. package/dist/src/runtime/model/model-catalog.d.ts +3 -0
  163. package/dist/src/runtime/model/model-catalog.js +2 -0
  164. package/dist/src/runtime/model/model-context-budget.d.ts +5 -0
  165. package/dist/src/runtime/model/model-context-budget.js +2 -0
  166. package/dist/src/runtime/model/model-step-port.d.ts +7 -0
  167. package/dist/src/runtime/model/optional-context-admission.d.ts +18 -0
  168. package/dist/src/runtime/model/optional-context-admission.js +23 -0
  169. package/dist/src/runtime/ports.d.ts +3 -1
  170. package/dist/src/runtime/projects/contracts.d.ts +6 -0
  171. package/dist/src/runtime/projects/registry-format.d.ts +3 -0
  172. package/dist/src/runtime/projects/registry-format.js +50 -0
  173. package/dist/src/runtime/projects/repository.d.ts +6 -3
  174. package/dist/src/runtime/projects/repository.js +26 -19
  175. package/dist/src/runtime/projects/service.js +11 -0
  176. package/dist/src/runtime/request/approval-wait/preflight.js +1 -0
  177. package/dist/src/runtime/request/approval-wait/snapshot.d.ts +1 -1
  178. package/dist/src/runtime/request/approval-wait/snapshot.js +1 -0
  179. package/dist/src/runtime/request/contracts.d.ts +5 -1
  180. package/dist/src/runtime/request/execution-facets.js +2 -0
  181. package/dist/src/runtime/request/execution-payload-artifact-policy.d.ts +3 -0
  182. package/dist/src/runtime/request/execution-payload-artifact-policy.js +6 -0
  183. package/dist/src/runtime/request/execution-payload-compacted-evidence.js +1 -0
  184. package/dist/src/runtime/request/execution-scope-surfaces.d.ts +2 -0
  185. package/dist/src/runtime/request/execution-scope-surfaces.js +3 -0
  186. package/dist/src/runtime/request/execution-scope.d.ts +2 -0
  187. package/dist/src/runtime/request/execution-scope.js +2 -0
  188. package/dist/src/runtime/request/input.d.ts +1 -0
  189. package/dist/src/runtime/request/input.js +1 -0
  190. package/dist/src/runtime/request/prepared-execution.d.ts +1 -0
  191. package/dist/src/runtime/request/prepared-execution.js +3 -0
  192. package/dist/src/runtime/request/reasoning-preference.d.ts +10 -0
  193. package/dist/src/runtime/request/reasoning-preference.js +29 -0
  194. package/dist/src/runtime/request/root-reference-action.js +3 -3
  195. package/dist/src/runtime/request/root-skill-read-admission.d.ts +4 -0
  196. package/dist/src/runtime/request/root-skill-read-admission.js +14 -0
  197. package/dist/src/runtime/request/root-skill-read.js +13 -5
  198. package/dist/src/runtime/request/supervisor-skill-selection-window.d.ts +16 -0
  199. package/dist/src/runtime/request/supervisor-skill-selection-window.js +17 -0
  200. package/dist/src/runtime/request/worker-capability-composition.js +2 -0
  201. package/dist/src/runtime/scheduler/contracts.d.ts +7 -1
  202. package/dist/src/runtime/scheduler/job-management.js +7 -1
  203. package/dist/src/runtime/scheduler/run-records.js +2 -0
  204. package/dist/src/runtime/scheduler/schedule-validation.js +2 -0
  205. package/dist/src/runtime/scheduler/scheduler-engine.js +1 -0
  206. package/dist/src/runtime/scheduler/snapshot-validation.js +2 -0
  207. package/dist/src/runtime/steps/auditor-decision/projection.js +2 -0
  208. package/dist/src/runtime/steps/execution-agent/capability-controls-partition.d.ts +9 -0
  209. package/dist/src/runtime/steps/execution-agent/capability-controls-partition.js +29 -0
  210. package/dist/src/runtime/steps/execution-agent/capability-scope.d.ts +17 -0
  211. package/dist/src/runtime/steps/execution-agent/capability-scope.js +54 -0
  212. package/dist/src/runtime/steps/execution-agent/compaction.js +22 -6
  213. package/dist/src/runtime/steps/execution-agent/controls-compacted-evidence.js +2 -0
  214. package/dist/src/runtime/steps/execution-agent/evidence-reuse-instructions.d.ts +6 -0
  215. package/dist/src/runtime/steps/execution-agent/evidence-reuse-instructions.js +13 -0
  216. package/dist/src/runtime/steps/execution-agent/format.js +3 -6
  217. package/dist/src/runtime/steps/execution-agent/input.d.ts +5 -1
  218. package/dist/src/runtime/steps/execution-agent/input.js +10 -36
  219. package/dist/src/runtime/steps/execution-agent/observation-guidance.d.ts +11 -0
  220. package/dist/src/runtime/steps/execution-agent/observation-guidance.js +33 -0
  221. package/dist/src/runtime/steps/execution-agent/prompt.js +2 -0
  222. package/dist/src/runtime/steps/execution-agent/refinement.d.ts +3 -2
  223. package/dist/src/runtime/steps/execution-agent/refinement.js +17 -6
  224. package/dist/src/runtime/steps/execution-agent/run.js +7 -1
  225. package/dist/src/runtime/steps/skill-read-decision.d.ts +1 -0
  226. package/dist/src/runtime/steps/skill-read-decision.js +9 -4
  227. package/dist/src/runtime/steps/supervisor-decision/artifact-paths.d.ts +6 -1
  228. package/dist/src/runtime/steps/supervisor-decision/artifact-paths.js +15 -0
  229. package/dist/src/runtime/steps/supervisor-decision/contracts.d.ts +1 -1
  230. package/dist/src/runtime/steps/supervisor-decision/contracts.js +2 -0
  231. package/dist/src/runtime/steps/supervisor-decision/decision-phases.d.ts +3 -0
  232. package/dist/src/runtime/steps/supervisor-decision/decision-phases.js +22 -3
  233. package/dist/src/runtime/steps/supervisor-decision/delegation-contract.d.ts +9 -0
  234. package/dist/src/runtime/steps/supervisor-decision/delegation-contract.js +82 -0
  235. package/dist/src/runtime/steps/supervisor-decision/delegation-input.d.ts +7 -0
  236. package/dist/src/runtime/steps/supervisor-decision/delegation-input.js +105 -0
  237. package/dist/src/runtime/steps/supervisor-decision/delegation-prompt.d.ts +7 -0
  238. package/dist/src/runtime/steps/supervisor-decision/delegation-prompt.js +13 -0
  239. package/dist/src/runtime/steps/supervisor-decision/input.d.ts +1 -0
  240. package/dist/src/runtime/steps/supervisor-decision/preparation-input.d.ts +3 -5
  241. package/dist/src/runtime/steps/supervisor-decision/preparation-input.js +5 -21
  242. package/dist/src/runtime/steps/supervisor-decision/preparation.d.ts +4 -1
  243. package/dist/src/runtime/steps/supervisor-decision/preparation.js +58 -6
  244. package/dist/src/runtime/steps/supervisor-decision/procedure-entry.d.ts +22 -0
  245. package/dist/src/runtime/steps/supervisor-decision/procedure-entry.js +61 -0
  246. package/dist/src/runtime/steps/supervisor-decision/procedure-gate.d.ts +39 -0
  247. package/dist/src/runtime/steps/supervisor-decision/procedure-gate.js +146 -0
  248. package/dist/src/runtime/steps/supervisor-decision/procedure-memory.d.ts +9 -0
  249. package/dist/src/runtime/steps/supervisor-decision/procedure-memory.js +100 -0
  250. package/dist/src/runtime/steps/supervisor-decision/procedure-recall.d.ts +10 -0
  251. package/dist/src/runtime/steps/supervisor-decision/procedure-recall.js +52 -0
  252. package/dist/src/runtime/steps/supervisor-decision/prompt.js +3 -16
  253. package/dist/src/runtime/steps/supervisor-decision/response-recommendation.js +2 -2
  254. package/dist/src/runtime/steps/supervisor-decision/role-guidance.d.ts +3 -0
  255. package/dist/src/runtime/steps/supervisor-decision/role-guidance.js +20 -0
  256. package/dist/src/runtime/steps/supervisor-decision/run.js +50 -7
  257. package/dist/src/runtime/steps/supervisor-decision/skill-read-state.d.ts +10 -0
  258. package/dist/src/runtime/steps/supervisor-decision/skill-read-state.js +45 -0
  259. package/dist/src/runtime/steps/supervisor-decision/skill-selection-candidates.d.ts +15 -0
  260. package/dist/src/runtime/steps/supervisor-decision/skill-selection-candidates.js +25 -0
  261. package/dist/src/runtime/steps/supervisor-decision/skill-selection-catalog.d.ts +3 -0
  262. package/dist/src/runtime/steps/supervisor-decision/skill-selection-catalog.js +15 -0
  263. package/dist/src/runtime/steps/supervisor-decision/skill-selection-continuation.d.ts +10 -0
  264. package/dist/src/runtime/steps/supervisor-decision/skill-selection-continuation.js +65 -0
  265. package/dist/src/runtime/steps/supervisor-decision/skill-selection-input.d.ts +3 -1
  266. package/dist/src/runtime/steps/supervisor-decision/skill-selection-input.js +20 -22
  267. package/dist/src/runtime/steps/supervisor-decision/skill-selection.d.ts +3 -2
  268. package/dist/src/runtime/steps/supervisor-decision/skill-selection.js +62 -15
  269. package/dist/src/runtime/steps/supervisor-response/prompt.js +18 -4
  270. package/dist/src/shared/model-reasoning-modes.d.ts +5 -0
  271. package/dist/src/shared/model-reasoning-modes.js +20 -0
  272. package/dist/src/shared/model-reasoning-schema.d.ts +38 -0
  273. package/dist/src/shared/model-reasoning-schema.js +29 -0
  274. package/dist/src/shared/model-reasoning.d.ts +35 -0
  275. package/dist/src/shared/model-reasoning.js +100 -0
  276. package/dist/src/web-ui/app/ARCHITECTURE.md +13 -0
  277. package/dist/src/web-ui/app/app-bootstrap.js +9 -12
  278. package/dist/src/web-ui/app/app-dom.js +6 -1
  279. package/dist/src/web-ui/app/app-state.js +1 -0
  280. package/dist/src/web-ui/app/app.js +8 -3
  281. package/dist/src/web-ui/app/appearance-feature.js +28 -0
  282. package/dist/src/web-ui/app/automations-feature.js +20 -11
  283. package/dist/src/web-ui/app/components/appearance-dialog.js +79 -0
  284. package/dist/src/web-ui/app/components/automations/archive-actions.js +5 -3
  285. package/dist/src/web-ui/app/components/automations/authoring-entry.js +26 -7
  286. package/dist/src/web-ui/app/components/automations/confirmation-actions.js +78 -0
  287. package/dist/src/web-ui/app/components/automations/draft-recovery-actions.js +1 -0
  288. package/dist/src/web-ui/app/components/automations/node-inspector.js +5 -1
  289. package/dist/src/web-ui/app/components/automations/step-editor-dialog.js +4 -2
  290. package/dist/src/web-ui/app/components/automations/timeline.js +2 -2
  291. package/dist/src/web-ui/app/components/automations/workspace-navigation.js +37 -0
  292. package/dist/src/web-ui/app/components/automations/workspace.js +31 -46
  293. package/dist/src/web-ui/app/components/config-workspace/config-model.js +6 -0
  294. package/dist/src/web-ui/app/components/config-workspace/model-removal.js +4 -2
  295. package/dist/src/web-ui/app/components/config-workspace/model-rendering.js +8 -16
  296. package/dist/src/web-ui/app/components/config-workspace/reasoning-budget-edit.js +113 -0
  297. package/dist/src/web-ui/app/components/config-workspace/reasoning-budget.d.ts +16 -0
  298. package/dist/src/web-ui/app/components/config-workspace/reasoning-budget.js +67 -0
  299. package/dist/src/web-ui/app/components/config-workspace/reasoning-mode-budgets.d.ts +7 -0
  300. package/dist/src/web-ui/app/components/config-workspace/reasoning-mode-budgets.js +25 -0
  301. package/dist/src/web-ui/app/components/config-workspace/workspace-events.js +15 -7
  302. package/dist/src/web-ui/app/components/config-workspace/workspace-mutations.js +32 -12
  303. package/dist/src/web-ui/app/components/config-workspace/workspace-persistence.js +1 -1
  304. package/dist/src/web-ui/app/components/config-workspace.js +2 -1
  305. package/dist/src/web-ui/app/components/confirmation-dialog.js +88 -0
  306. package/dist/src/web-ui/app/components/conversation-activity.d.ts +2 -0
  307. package/dist/src/web-ui/app/components/conversation-activity.js +32 -3
  308. package/dist/src/web-ui/app/components/conversation-memory-activity.js +31 -0
  309. package/dist/src/web-ui/app/components/conversation-role-cards.d.ts +2 -0
  310. package/dist/src/web-ui/app/components/conversation-role-cards.js +14 -11
  311. package/dist/src/web-ui/app/components/conversation-skill-activity.js +67 -0
  312. package/dist/src/web-ui/app/components/conversation-tools.js +5 -5
  313. package/dist/src/web-ui/app/components/conversation-view.js +6 -0
  314. package/dist/src/web-ui/app/components/dashboard/approvals.js +13 -1
  315. package/dist/src/web-ui/app/components/long-term-memory/embedding-connection-dialog.d.ts +38 -0
  316. package/dist/src/web-ui/app/components/long-term-memory/embedding-connection-dialog.js +289 -0
  317. package/dist/src/web-ui/app/components/long-term-memory/embedding-connection-feature.js +75 -0
  318. package/dist/src/web-ui/app/components/long-term-memory/embedding-connection-rendering.js +31 -0
  319. package/dist/src/web-ui/app/components/long-term-memory/manager.js +15 -5
  320. package/dist/src/web-ui/app/components/long-term-memory/saved-embedding-profiles.js +114 -0
  321. package/dist/src/web-ui/app/components/long-term-memory/setup-rendering.js +55 -0
  322. package/dist/src/web-ui/app/components/long-term-memory-setup.js +141 -76
  323. package/dist/src/web-ui/app/components/model-setup/rendering.js +3 -2
  324. package/dist/src/web-ui/app/components/model-setup/validation.js +6 -2
  325. package/dist/src/web-ui/app/components/model-setup/wizard.d.ts +1 -0
  326. package/dist/src/web-ui/app/components/model-setup/wizard.js +28 -5
  327. package/dist/src/web-ui/app/components/passive-learning/memory.js +12 -5
  328. package/dist/src/web-ui/app/components/plugins/manager.js +14 -0
  329. package/dist/src/web-ui/app/components/plugins/removal.js +10 -2
  330. package/dist/src/web-ui/app/components/project-group-actions.js +35 -0
  331. package/dist/src/web-ui/app/components/project-session-groups.js +17 -31
  332. package/dist/src/web-ui/app/components/runtime-setup/commands.js +1 -1
  333. package/dist/src/web-ui/app/components/runtime-setup/connection-form.d.ts +15 -0
  334. package/dist/src/web-ui/app/components/runtime-setup/connection-form.js +32 -9
  335. package/dist/src/web-ui/app/components/runtime-setup/connection-input.js +23 -0
  336. package/dist/src/web-ui/app/components/runtime-setup/connection-inspection.js +57 -0
  337. package/dist/src/web-ui/app/components/runtime-setup/connection-state.js +18 -4
  338. package/dist/src/web-ui/app/components/runtime-setup/embedding-credential-status.js +3 -0
  339. package/dist/src/web-ui/app/components/runtime-setup/embedding-provider-options.js +54 -0
  340. package/dist/src/web-ui/app/components/runtime-setup/embedding-provider-receipt.js +3 -0
  341. package/dist/src/web-ui/app/components/runtime-setup/embedding-rendering.js +22 -22
  342. package/dist/src/web-ui/app/components/runtime-setup/embedding.js +60 -16
  343. package/dist/src/web-ui/app/components/runtime-setup/reasoning-fields.d.ts +17 -0
  344. package/dist/src/web-ui/app/components/runtime-setup/reasoning-fields.js +54 -0
  345. package/dist/src/web-ui/app/components/runtime-setup/validation.js +5 -1
  346. package/dist/src/web-ui/app/components/runtime-setup-guide.d.ts +9 -3
  347. package/dist/src/web-ui/app/components/runtime-setup-guide.js +20 -29
  348. package/dist/src/web-ui/app/components/schedules/details.js +2 -2
  349. package/dist/src/web-ui/app/components/schedules/form.js +12 -5
  350. package/dist/src/web-ui/app/components/schedules/workspace.js +30 -18
  351. package/dist/src/web-ui/app/components/session-list-viewport.js +49 -0
  352. package/dist/src/web-ui/app/components/session-search-disclosure.js +27 -0
  353. package/dist/src/web-ui/app/components/skills/workspace.js +7 -3
  354. package/dist/src/web-ui/app/components/spark-chat/panel.js +7 -3
  355. package/dist/src/web-ui/app/components/spark-chat/settings.js +57 -15
  356. package/dist/src/web-ui/app/components/tool-approval-card.d.ts +2 -1
  357. package/dist/src/web-ui/app/components/tool-approval-card.js +10 -2
  358. package/dist/src/web-ui/app/components/tool-approval-rejection-input.js +116 -0
  359. package/dist/src/web-ui/app/components/workspace-shell.js +30 -38
  360. package/dist/src/web-ui/app/components/workspace-transitions.js +42 -0
  361. package/dist/src/web-ui/app/configuration-feature.js +34 -4
  362. package/dist/src/web-ui/app/controllers/app-event-bindings.js +45 -29
  363. package/dist/src/web-ui/app/controllers/appearance-controller.js +105 -0
  364. package/dist/src/web-ui/app/controllers/automations-controller.js +9 -1
  365. package/dist/src/web-ui/app/controllers/composer-feature.d.ts +1 -1
  366. package/dist/src/web-ui/app/controllers/composer-feature.js +10 -3
  367. package/dist/src/web-ui/app/controllers/composer-queue-controller.d.ts +1 -1
  368. package/dist/src/web-ui/app/controllers/composer-queue-controller.js +9 -3
  369. package/dist/src/web-ui/app/controllers/composer-submission-lifecycle.d.ts +1 -1
  370. package/dist/src/web-ui/app/controllers/conversation-workspace-activation.js +8 -2
  371. package/dist/src/web-ui/app/controllers/dashboard-approvals-controller.js +10 -9
  372. package/dist/src/web-ui/app/controllers/environment-transition.js +2 -2
  373. package/dist/src/web-ui/app/controllers/environment-workspace-preparation.js +9 -7
  374. package/dist/src/web-ui/app/controllers/preference-view-sync.js +35 -0
  375. package/dist/src/web-ui/app/controllers/projects-controller.d.ts +4 -0
  376. package/dist/src/web-ui/app/controllers/projects-controller.js +64 -3
  377. package/dist/src/web-ui/app/controllers/reasoning-budget-controller.d.ts +17 -0
  378. package/dist/src/web-ui/app/controllers/reasoning-budget-controller.js +80 -0
  379. package/dist/src/web-ui/app/controllers/reasoning-budget-menu-events.js +45 -0
  380. package/dist/src/web-ui/app/controllers/reasoning-mode-controller.js +35 -40
  381. package/dist/src/web-ui/app/controllers/runtime-selection-controller.d.ts +6 -1
  382. package/dist/src/web-ui/app/controllers/runtime-selection-controller.js +16 -3
  383. package/dist/src/web-ui/app/controllers/session-controller.js +34 -9
  384. package/dist/src/web-ui/app/controllers/session-sidebar-controller.js +4 -3
  385. package/dist/src/web-ui/app/controllers/skills-controller.js +33 -16
  386. package/dist/src/web-ui/app/controllers/spark-chat-sync.js +1 -1
  387. package/dist/src/web-ui/app/controllers/spark-handoff-navigation.js +7 -1
  388. package/dist/src/web-ui/app/controllers/tool-approval-controller.d.ts +2 -1
  389. package/dist/src/web-ui/app/controllers/tool-approval-controller.js +36 -3
  390. package/dist/src/web-ui/app/controllers/workspace-conversation-opener.js +8 -2
  391. package/dist/src/web-ui/app/controllers/workspace-route-controller.js +41 -10
  392. package/dist/src/web-ui/app/index.html +38 -32
  393. package/dist/src/web-ui/app/lib/color-palettes.d.ts +17 -0
  394. package/dist/src/web-ui/app/lib/color-palettes.js +20 -0
  395. package/dist/src/web-ui/app/lib/memory-activity-model.d.ts +12 -0
  396. package/dist/src/web-ui/app/lib/memory-activity-model.js +61 -0
  397. package/dist/src/web-ui/app/lib/navigation-display.d.ts +8 -0
  398. package/dist/src/web-ui/app/lib/navigation-display.js +12 -0
  399. package/dist/src/web-ui/app/lib/reasoning-controls.js +47 -6
  400. package/dist/src/web-ui/app/lib/reasoning-preference.d.ts +9 -0
  401. package/dist/src/web-ui/app/lib/reasoning-preference.js +75 -0
  402. package/dist/src/web-ui/app/lib/session-composer-queue.d.ts +4 -0
  403. package/dist/src/web-ui/app/lib/session-composer-queue.js +4 -0
  404. package/dist/src/web-ui/app/lib/session-project-groups.js +28 -0
  405. package/dist/src/web-ui/app/lib/session-sidebar-order.js +7 -5
  406. package/dist/src/web-ui/app/lib/tool-activity-event.d.ts +1 -0
  407. package/dist/src/web-ui/app/lib/tool-activity-event.js +1 -0
  408. package/dist/src/web-ui/app/lib/tool-activity-model.d.ts +1 -0
  409. package/dist/src/web-ui/app/lib/tool-activity-model.js +1 -0
  410. package/dist/src/web-ui/app/lib/tool-approval-rejection-drafts.js +45 -0
  411. package/dist/src/web-ui/app/lib/tool-skill-activity-fields.js +1 -1
  412. package/dist/src/web-ui/app/notifications-feature.js +10 -2
  413. package/dist/src/web-ui/app/passive-learning-feature.js +2 -2
  414. package/dist/src/web-ui/app/projects-feature.js +40 -10
  415. package/dist/src/web-ui/app/runtime-onboarding-feature.js +1 -0
  416. package/dist/src/web-ui/app/schedules-feature.js +28 -5
  417. package/dist/src/web-ui/app/services/client-preferences.d.ts +4 -1
  418. package/dist/src/web-ui/app/services/client-preferences.js +2 -0
  419. package/dist/src/web-ui/app/services/conversation-reasoning-preferences.d.ts +11 -0
  420. package/dist/src/web-ui/app/services/conversation-reasoning-preferences.js +30 -0
  421. package/dist/src/web-ui/app/services/runtime-web-client/automations.js +6 -4
  422. package/dist/src/web-ui/app/services/runtime-web-client/configuration.js +5 -0
  423. package/dist/src/web-ui/app/services/runtime-web-client/memory.js +21 -0
  424. package/dist/src/web-ui/app/services/runtime-web-client/projects.d.ts +2 -1
  425. package/dist/src/web-ui/app/services/runtime-web-client/projects.js +4 -0
  426. package/dist/src/web-ui/app/services/runtime-web-client/tool-approvals.js +2 -0
  427. package/dist/src/web-ui/app/services/runtime-web-client.d.ts +16 -0
  428. package/dist/src/web-ui/app/services/runtime-web-client.js +2 -0
  429. package/dist/src/web-ui/app/services/session-sidebar-preferences.js +33 -13
  430. package/dist/src/web-ui/app/skills-feature.js +2 -3
  431. package/dist/src/web-ui/app/spark-chat-conversation.js +29 -3
  432. package/dist/src/web-ui/app/spark-chat-feature.js +13 -7
  433. package/dist/src/web-ui/app/styles/01-color-palettes.css +90 -0
  434. package/dist/src/web-ui/app/styles/11-product-links.css +6 -2
  435. package/dist/src/web-ui/app/styles/11-workspace-header-width.css +37 -25
  436. package/dist/src/web-ui/app/styles/12-conversation-sidebar.css +56 -22
  437. package/dist/src/web-ui/app/styles/13-projects.css +56 -19
  438. package/dist/src/web-ui/app/styles/19-runtime-setup.css +16 -0
  439. package/dist/src/web-ui/app/styles/22-reasoning-budget.css +39 -0
  440. package/dist/src/web-ui/app/styles/27-conversation-memory.css +45 -0
  441. package/dist/src/web-ui/app/styles/27-conversation-skills.css +96 -0
  442. package/dist/src/web-ui/app/styles/28-tool-approval-card.css +38 -1
  443. package/dist/src/web-ui/app/styles/35-embedding-profiles.css +159 -0
  444. package/dist/src/web-ui/app/styles/54-spark-chat.css +62 -46
  445. package/dist/src/web-ui/app/styles/65-appearance.css +60 -0
  446. package/dist/src/web-ui/app/styles/66-navigation-display.css +30 -0
  447. package/dist/src/web-ui/app/styles/67-confirmation-dialog.css +32 -0
  448. package/dist/src/web-ui/app/styles.css +8 -0
  449. package/dist/src/web-ui/client-state/preference-shapes.js +6 -1
  450. package/dist/src/web-ui/client-state/preferences.js +8 -2
  451. package/dist/src/web-ui/client-state/reasoning-preference-shape.d.ts +1 -0
  452. package/dist/src/web-ui/client-state/reasoning-preference-shape.js +18 -0
  453. package/dist/src/web-ui/local-runtime/api-router.d.ts +1 -0
  454. package/dist/src/web-ui/local-runtime/api-router.js +11 -0
  455. package/dist/src/web-ui/local-runtime/memory-embedding-connection-input.d.ts +7 -0
  456. package/dist/src/web-ui/local-runtime/memory-embedding-connection-input.js +22 -0
  457. package/dist/src/web-ui/local-runtime/memory-embedding-connection-service.d.ts +20 -0
  458. package/dist/src/web-ui/local-runtime/memory-embedding-connection-service.js +47 -0
  459. package/dist/src/web-ui/local-runtime/memory-onboarding-routes.js +32 -0
  460. package/dist/src/web-ui/local-runtime/model-connection-inspection.d.ts +7 -0
  461. package/dist/src/web-ui/local-runtime/model-connection-inspection.js +48 -0
  462. package/dist/src/web-ui/local-runtime/model-setup-catalog.d.ts +2 -1
  463. package/dist/src/web-ui/local-runtime/model-setup-catalog.js +3 -1
  464. package/dist/src/web-ui/local-runtime/model-setup-identity.js +1 -1
  465. package/dist/src/web-ui/local-runtime/model-setup-input.d.ts +5 -2
  466. package/dist/src/web-ui/local-runtime/model-setup-input.js +29 -6
  467. package/dist/src/web-ui/local-runtime/model-setup-provider.d.ts +1 -1
  468. package/dist/src/web-ui/local-runtime/model-setup-provider.js +9 -6
  469. package/dist/src/web-ui/local-runtime/model-setup-retry.js +4 -1
  470. package/dist/src/web-ui/local-runtime/model-setup-service.d.ts +2 -1
  471. package/dist/src/web-ui/local-runtime/pending-tool-approvals.js +4 -1
  472. package/dist/src/web-ui/local-runtime/project-routes.js +10 -2
  473. package/dist/src/web-ui/local-runtime/request-execution.js +1 -0
  474. package/dist/src/web-ui/local-runtime/runtime-setup-auth.d.ts +2 -0
  475. package/dist/src/web-ui/local-runtime/runtime-setup-auth.js +20 -0
  476. package/dist/src/web-ui/local-runtime/runtime-setup-connection-edit.js +3 -2
  477. package/dist/src/web-ui/local-runtime/runtime-setup-credential-completion.js +6 -1
  478. package/dist/src/web-ui/local-runtime/runtime-setup-input.d.ts +3 -2
  479. package/dist/src/web-ui/local-runtime/runtime-setup-input.js +17 -5
  480. package/dist/src/web-ui/local-runtime/runtime-setup-provider.d.ts +4 -1
  481. package/dist/src/web-ui/local-runtime/runtime-setup-provider.js +6 -2
  482. package/dist/src/web-ui/local-runtime/runtime-setup-routes.d.ts +11 -2
  483. package/dist/src/web-ui/local-runtime/runtime-setup-routes.js +11 -2
  484. package/dist/src/web-ui/local-runtime/runtime-setup-scaffold.js +3 -2
  485. package/dist/src/web-ui/local-runtime/runtime-setup-service.d.ts +25 -4
  486. package/dist/src/web-ui/local-runtime/runtime-setup-service.js +19 -9
  487. package/dist/src/web-ui/local-runtime/setup-embedding-input.d.ts +3 -1
  488. package/dist/src/web-ui/local-runtime/setup-embedding-input.js +38 -6
  489. package/dist/src/web-ui/local-runtime/setup-embedding-llamacpp.d.ts +11 -0
  490. package/dist/src/web-ui/local-runtime/setup-embedding-llamacpp.js +53 -0
  491. package/dist/src/web-ui/local-runtime/setup-embedding-provider.js +23 -9
  492. package/dist/src/web-ui/local-runtime/setup-embedding-routes.d.ts +7 -2
  493. package/dist/src/web-ui/local-runtime/setup-embedding-routes.js +5 -3
  494. package/dist/src/web-ui/local-runtime/setup-embedding-service.d.ts +1 -0
  495. package/docs/configuration.md +10 -8
  496. package/docs/installation.md +11 -5
  497. package/docs/llamacpp.md +248 -0
  498. package/docs/long-term-memory.md +12 -0
  499. package/docs/running-locally.md +7 -1
  500. package/package.json +2 -1
  501. package/plugins/project-orientation/source/index.ts +2 -3
  502. package/plugins/project-orientation/source/inspection-failure.ts +1 -1
  503. package/plugins/project-orientation/source/project-target.ts +29 -0
  504. package/plugins/project-orientation/src/index.cjs +21 -2
  505. package/runtime.config.schema.json +140 -0
  506. package/src/runtime/README.md +50 -4
@@ -1,3 +1,4 @@
1
+ import { confirmDialog } from "../confirmation-dialog.js";
1
2
  import { updateLiveRegion } from "../../lib/live-region.js";
2
3
  import { escapeHtml } from "../../lib/text-format.js";
3
4
  import { scheduleTimeLabel } from "../../lib/schedule-message.js";
@@ -18,11 +19,13 @@ export function createSchedulesWorkspace({
18
19
  root,
19
20
  actions,
20
21
  getCurrentSessionId,
22
+ getEnvironmentId = () => "",
21
23
  getAgentModes,
22
24
  documentRoot = document,
23
- confirmDiscard = (message) => window.confirm(message),
25
+ confirmDiscard = (message) => confirmDialog(message, { title: "Unsaved schedule", confirmLabel: "Discard changes", tone: "danger" }),
24
26
  }) {
25
27
  let editorIdentity = null;
28
+ let leaveRevision = 0;
26
29
  root.innerHTML = `<div class="schedules-content"><div class="schedules-toolbar"><label class="schedule-search"><svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7"><circle cx="10.5" cy="10.5" r="6.5"/><path d="m16 16 4.5 4.5"/></svg><input type="search" placeholder="Search schedules…" aria-label="Search schedules"></label>
27
30
  <select aria-label="Filter schedule status"><option value="current">Active &amp; paused</option><option value="active">Active</option><option value="paused">Paused</option><option value="completed">Completed</option><option value="cancelled">Cancelled</option><option value="all">All statuses</option></select>
28
31
  <button type="button" data-refresh>Refresh</button><button type="button" class="primary-button" data-create>New schedule</button></div>
@@ -40,49 +43,58 @@ export function createSchedulesWorkspace({
40
43
  const workspaceState = root.querySelector(".schedule-workspace-state");
41
44
  search.addEventListener("input", applyFilter);
42
45
  filter.addEventListener("change", applyFilter);
43
- root.querySelector("[data-refresh]").addEventListener("click", () => {
44
- if (prepareLeave()) void actions.load();
46
+ root.querySelector("[data-refresh]").addEventListener("click", async () => {
47
+ if (await prepareLeave()) void actions.load();
45
48
  });
46
- createButton.addEventListener("click", () => {
47
- if (prepareLeave()) actions.beginEdit();
49
+ createButton.addEventListener("click", async () => {
50
+ if (await prepareLeave()) actions.beginEdit();
48
51
  });
49
52
 
50
- function prepareLeave() {
51
- const prepared = prepareEnvironmentChange();
52
- if (!prepared) return false;
53
+ async function prepareLeave() {
54
+ const prepared = await prepareEnvironmentChange();
55
+ if (!prepared || prepared.canCommit() === false) return false;
53
56
  prepared();
54
57
  return true;
55
58
  }
56
59
 
57
- function prepareEnvironmentChange() {
60
+ async function prepareEnvironmentChange() {
61
+ const request = ++leaveRevision;
62
+ const environmentId = getEnvironmentId();
58
63
  const editor = actions.snapshot().editor;
59
- if (editor && !canDiscardScheduleDraft()) return null;
60
64
  const form = details.querySelector(".schedule-editor");
61
65
  const fingerprint = scheduleDraftFingerprint(form);
62
- const commit = () => { if (editor) actions.cancelEdit(); };
66
+ const commit = () => {
67
+ if (!commit.canCommit()) return false;
68
+ if (editor) actions.cancelEdit();
69
+ return true;
70
+ };
63
71
  commit.canCommit = () => {
72
+ if (request !== leaveRevision) return false;
73
+ if (environmentId !== getEnvironmentId()) return false;
64
74
  if (actions.snapshot().mutation) return false;
65
75
  if (actions.snapshot().editor !== editor) return false;
66
76
  if (details.querySelector(".schedule-editor") !== form) return false;
67
77
  return scheduleDraftFingerprint(form) === fingerprint;
68
78
  };
69
- return commit;
79
+ if (editor && !await canDiscardScheduleDraft()) return null;
80
+ return commit.canCommit() ? commit : null;
70
81
  }
71
82
 
72
83
  function scheduleDraftFingerprint(form) {
73
84
  return form ? JSON.stringify([...new FormData(form)]) : "";
74
85
  }
75
86
 
76
- function canDiscardScheduleDraft() {
87
+ async function canDiscardScheduleDraft() {
77
88
  const form = details.querySelector(".schedule-editor");
78
89
  if (form?.dataset.dirty !== "true") return true;
79
- return confirmDiscard("Discard this unsaved schedule?");
90
+ return await confirmDiscard("Discard this unsaved schedule?");
80
91
  }
81
92
 
82
- function applyFilter() {
93
+ async function applyFilter() {
83
94
  const query = search.value;
84
95
  const status = filter.value;
85
- if (!prepareLeave()) {
96
+ if (!await prepareLeave()) {
97
+ if (search.value !== query || filter.value !== status) return;
86
98
  const snapshot = actions.snapshot();
87
99
  search.value = snapshot.query;
88
100
  filter.value = snapshot.filter;
@@ -93,9 +105,9 @@ export function createSchedulesWorkspace({
93
105
 
94
106
  function bindListActions() {
95
107
  for (const button of list.querySelectorAll("[data-job-id]")) {
96
- button.addEventListener("click", () => {
108
+ button.addEventListener("click", async () => {
97
109
  if (button.dataset.jobId === actions.snapshot().selectedId) return;
98
- if (prepareLeave()) void actions.select(button.dataset.jobId);
110
+ if (await prepareLeave()) void actions.select(button.dataset.jobId);
99
111
  });
100
112
  }
101
113
  }
@@ -0,0 +1,49 @@
1
+ const positions = new WeakMap();
2
+
3
+ function isSessionListVisible(root) {
4
+ if (!root) return false;
5
+ return root.getClientRects?.().length !== 0;
6
+ }
7
+
8
+ function captureSessionListFocus(root) {
9
+ const focusedElement = root.ownerDocument?.activeElement;
10
+ if (!root.contains?.(focusedElement)) return null;
11
+ return focusedElement;
12
+ }
13
+
14
+ function canRestoreSessionListFocus(root, focusedElement) {
15
+ if (!focusedElement) return false;
16
+ if (!root.contains?.(focusedElement)) return false;
17
+ if (focusedElement.getClientRects?.().length === 0) return false;
18
+ const activeElement = root.ownerDocument?.activeElement;
19
+ if (activeElement === focusedElement) return false;
20
+ if (!activeElement) return true;
21
+ return activeElement === root.ownerDocument?.body;
22
+ }
23
+
24
+ export function captureSessionListViewport(root, scope) {
25
+ if (!root) return;
26
+ const previous = positions.get(root);
27
+ if (scope !== undefined && previous?.scope !== scope) {
28
+ positions.set(root, { scope, scrollTop: 0 });
29
+ return;
30
+ }
31
+ if (!isSessionListVisible(root)) return;
32
+ positions.set(root, {
33
+ scope: previous?.scope,
34
+ scrollTop: Number(root.scrollTop) || 0,
35
+ focusedElement: captureSessionListFocus(root),
36
+ });
37
+ }
38
+
39
+ export function restoreSessionListViewport(root) {
40
+ const position = positions.get(root);
41
+ if (!position) return;
42
+ const focusedElement = position.focusedElement;
43
+ delete position.focusedElement;
44
+ if (!isSessionListVisible(root)) return;
45
+ if (canRestoreSessionListFocus(root, focusedElement)) {
46
+ focusedElement.focus({ preventScroll: true });
47
+ }
48
+ root.scrollTop = position.scrollTop;
49
+ }
@@ -0,0 +1,27 @@
1
+ export function bindSessionSearchDisclosure({ toggle, field, input }) {
2
+ function closeSearch() {
3
+ field.hidden = true;
4
+ toggle.setAttribute("aria-expanded", "false");
5
+ if (input.value) {
6
+ input.value = "";
7
+ input.dispatchEvent(new Event("input", { bubbles: true }));
8
+ }
9
+ toggle.focus();
10
+ }
11
+
12
+ toggle.addEventListener("click", () => {
13
+ if (!field.hidden) {
14
+ closeSearch();
15
+ return;
16
+ }
17
+ field.hidden = false;
18
+ toggle.setAttribute("aria-expanded", "true");
19
+ input.focus();
20
+ });
21
+ input.addEventListener("keydown", (event) => {
22
+ if (event.key !== "Escape") return;
23
+ event.preventDefault();
24
+ event.stopPropagation();
25
+ closeSearch();
26
+ });
27
+ }
@@ -1,3 +1,4 @@
1
+ import { confirmDialog } from "../confirmation-dialog.js";
1
2
  import { escapeAttribute, escapeHtml } from "../../lib/text-format.js";
2
3
 
3
4
  /** Mounts the existing shell's navigation/panel contract without growing index.html. */
@@ -30,7 +31,7 @@ export function renderSkillRows(snapshot) {
30
31
  return items.map((item) => `<button type="button" class="config-model-button skills-list-item" data-skill-id="${escapeAttribute(item.skillId)}" aria-pressed="${item.skillId === snapshot.skill?.skillId}"><strong dir="auto">${escapeHtml(item.name)}</strong><span dir="auto">${escapeHtml(item.description)}</span></button>`).join("");
31
32
  }
32
33
 
33
- export function createSkillsWorkspace({ root, actions, confirmArchive = (message) => window.confirm(message) }) {
34
+ export function createSkillsWorkspace({ root, actions, confirmArchive = (message) => confirmDialog(message, { title: "Archive Skill", confirmLabel: "Archive", tone: "danger" }) }) {
34
35
  root.innerHTML = `<div class="config-dashboard skills-workspace-content"><div class="skills-toolbar"><div class="skills-filters" role="group" aria-label="Skill status"><button type="button" class="config-category-tab" data-skills-filter="active" aria-pressed="true">Active</button><button type="button" class="config-category-tab" data-skills-filter="archived" aria-pressed="false">Archived</button></div><div class="skills-toolbar-actions"><button type="button" data-skills-refresh>Refresh</button><button type="button" class="primary-button" data-skills-new>New Skill</button></div></div><p class="skills-intro">Personal Skills guide how ABot works. Built-in Skills are maintained by ABot.</p><p class="skills-feedback" role="alert" data-skills-error hidden></p><p class="skills-feedback" role="status" data-skills-message hidden></p><div class="skills-layout"><div class="skills-list" data-skills-list></div><section class="skills-detail" data-skills-detail><p class="skills-empty" data-skills-placeholder>Select a Skill to read or edit it.</p><form data-skills-form hidden><div data-skills-creation-fields hidden><h3>New Skill</h3><label class="skills-creation-label">Name<input type="text" data-skills-new-name maxlength="160" dir="auto" required disabled></label><label class="skills-creation-label">Description<textarea data-skills-new-description rows="3" maxlength="512" dir="auto" required disabled></textarea></label></div><div data-skills-saved-metadata><h3 dir="auto" data-skills-name></h3><p dir="auto" class="skills-description" data-skills-description></p><p class="skills-id">ID: <span dir="ltr" data-skills-id></span></p></div><label class="skills-content-label">Content<textarea data-skills-content rows="16" dir="auto" maxlength="65536" required></textarea></label><p class="skills-archived-note" data-skills-archived-note hidden>Archived Skills are unavailable to models. Restore this Skill to use or edit it.</p><div class="skills-editor-actions"><button class="primary-button" type="submit" data-skills-save>Save changes</button><button type="button" data-skills-cancel hidden>Cancel</button><button type="button" data-skills-reload>Reload saved</button><button type="button" data-skills-archive>Archive</button><button type="button" data-skills-restore hidden>Restore</button></div></form></section></div></div>`;
35
36
  const find = (selector) => root.querySelector(selector);
36
37
  const list = find("[data-skills-list]");
@@ -40,7 +41,7 @@ export function createSkillsWorkspace({ root, actions, confirmArchive = (message
40
41
  const descriptionInput = find("[data-skills-new-description]");
41
42
  let current;
42
43
  let listMarkup = "";
43
- root.addEventListener("click", (event) => {
44
+ root.addEventListener("click", async (event) => {
44
45
  const selected = event.target.closest?.("[data-skill-id]");
45
46
  if (selected) void actions.select(selected.dataset.skillId);
46
47
  const filter = event.target.closest?.("[data-skills-filter]");
@@ -51,8 +52,11 @@ export function createSkillsWorkspace({ root, actions, confirmArchive = (message
51
52
  if (event.target.closest?.("[data-skills-reload]")) void actions.reloadSelected();
52
53
  if (event.target.closest?.("[data-skills-restore]")) void actions.restore();
53
54
  if (event.target.closest?.("[data-skills-archive]")) {
55
+ const original = current;
54
56
  const warning = current?.dirty ? " Unsaved edits will be discarded." : "";
55
- if (confirmArchive(`Archive this Skill? Models will no longer discover or read it.${warning}`)) void actions.archive();
57
+ if (!await confirmArchive(`Archive this Skill? Models will no longer discover or read it.${warning}`)) return;
58
+ if (current.skill !== original.skill || current.draft !== original.draft) return;
59
+ void actions.archive();
56
60
  }
57
61
  });
58
62
  nameInput.addEventListener("input", () => actions.setCreationField("name", nameInput.value));
@@ -6,9 +6,13 @@ export function createSparkChatPanel({ documentRoot = document, launcherAnchor }
6
6
  root.hidden = true;
7
7
  root.innerHTML = `
8
8
  <section class="spark-chat-panel" role="dialog" aria-label="ABot SPARK chat" hidden>
9
- <header class="spark-chat-header"><button type="button" class="spark-header-mascot" data-spark="mascotButton" aria-label="Minimize SPARK chat" title="Minimize SPARK chat">${mascot}</button><strong>ABot SPARK</strong>
10
- <button type="button" data-spark="settingsButton" aria-label="SPARK settings" title="SPARK settings">⚙</button>
11
- <button type="button" data-spark="closeButton" aria-label="Minimize SPARK chat" title="Minimize">−</button>
9
+ <header class="spark-chat-header">
10
+ <button type="button" class="spark-header-mascot" data-spark="mascotButton" aria-label="Minimize SPARK chat" title="Minimize SPARK chat">${mascot}</button>
11
+ <div class="spark-chat-identity"><strong>ABot SPARK</strong></div>
12
+ <div class="spark-header-actions">
13
+ <button type="button" data-spark="settingsButton" aria-label="SPARK settings" title="SPARK settings"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 7h16M4 17h16" /><circle cx="9" cy="7" r="3" /><circle cx="15" cy="17" r="3" /></svg></button>
14
+ <button type="button" data-spark="closeButton" aria-label="Minimize SPARK chat" title="Minimize"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M6 12h12" /></svg></button>
15
+ </div>
12
16
  </header>
13
17
  <div class="spark-chat-content">
14
18
  <div class="messages-list spark-messages" data-spark="messagesList" role="log" aria-label="SPARK messages" tabindex="0"></div>
@@ -1,7 +1,9 @@
1
+ import { confirmDialog } from "../confirmation-dialog.js";
2
+ import { canChooseReasoningBudget, readReasoningPreferenceField, renderReasoningPreferenceField, syncReasoningPreferenceField } from "../../lib/reasoning-preference.js";
1
3
  import { canChooseReasoning, reasoningModeOptions } from "../../lib/reasoning-controls.js";
2
4
  import { supportsFullPlus } from "../../lib/tool-permission-mode.js";
3
5
 
4
- export function createSparkChatSettings({ root, onSave, onClear, onOpen, onResetPosition, onOpenModelSettings, getAgentMode, onAgentModeChange, getWebConfig, documentRoot = document }) {
6
+ export function createSparkChatSettings({ root, onSave, onClear, onOpen, onResetPosition, onOpenModelSettings, getAgentMode, onAgentModeChange, getReasoningPreference = () => undefined, onReasoningPreferenceChange, getWebConfig, confirmClear = (message) => confirmDialog(message, { title: "Clear SPARK conversation", confirmLabel: "Clear messages", tone: "danger" }), documentRoot = document }) {
5
7
  const card = documentRoot.createElement("section");
6
8
  card.className = "spark-chat-settings";
7
9
  card.setAttribute("aria-label", "SPARK conversation settings");
@@ -12,10 +14,11 @@ export function createSparkChatSettings({ root, onSave, onClear, onOpen, onReset
12
14
  <div class="spark-settings-actions"><select id="spark-chat-permissions" data-spark-permissions aria-label="SPARK conversation permissions"><option value="ask">Ask</option><option value="full_access">Full</option><option value="full_plus">FULL+</option></select>
13
15
  <button type="submit" data-spark-save disabled>Save</button></div>
14
16
  </form>
15
- <div class="spark-settings-row">
16
- <label for="spark-agent-mode"><strong>Thinking mode</strong><span>Choose how deeply SPARK thinks before replying.</span></label>
17
+ <div class="spark-settings-row" data-spark-legacy-reasoning>
18
+ <label for="spark-agent-mode"><strong>Thinking mode</strong><span>Sets the default depth; model profile and calibration settings may override it. Token budgets are separate. Changing the mode turns Thinking Off back on.</span></label>
17
19
  <select id="spark-agent-mode" data-spark-agent-mode aria-label="SPARK thinking mode"><option value="fast">Low</option><option value="reasoning" selected>Reasoning</option><option value="deep">Deep</option></select>
18
20
  </div>
21
+ <div data-spark-thinking-budget></div>
19
22
  <div class="spark-settings-row"><div><strong>Chat shortcut</strong><p>Drag SPARK wherever feels right. Use Alt + arrow keys to move it.</p></div>
20
23
  <button type="button" data-spark-reset-position>Return to sidebar</button></div>
21
24
  <div class="spark-settings-row"><div><strong>Conversation history</strong><p>Clear messages while keeping SPARK’s memory and permissions.</p></div>
@@ -33,49 +36,88 @@ export function createSparkChatSettings({ root, onSave, onClear, onOpen, onReset
33
36
  let reasoningEnabled = false;
34
37
  let busy = false;
35
38
  let environmentId;
39
+ let thinkingProfile;
40
+ let thinkingScope;
41
+ let thinkingSaved;
42
+ let latestConfiguration;
43
+ let operationRevision = 0;
44
+ const budgetRoot = card.querySelector("[data-spark-thinking-budget]");
45
+ budgetRoot.addEventListener("change", () => syncReasoningPreferenceField(budgetRoot, thinkingProfile));
46
+ budgetRoot.addEventListener("click", (event) => {
47
+ if (busy || !event.target.matches("[data-spark-save-thinking]")) return;
48
+ void perform(() => onReasoningPreferenceChange(readReasoningPreferenceField(budgetRoot)), "Thinking preference saved for the next message.");
49
+ });
36
50
  function controls() {
37
51
  select.disabled = busy || !ready;
38
- agentModeSelect.disabled = !ready || !reasoningEnabled;
52
+ agentModeSelect.disabled = busy || !ready || !reasoningEnabled;
39
53
  save.disabled = busy || !ready || select.value === saved;
40
54
  clear.disabled = busy || !ready;
55
+ for (const selector of ["select", "button"])
56
+ for (const field of budgetRoot.querySelectorAll(selector)) field.disabled = busy || !ready;
57
+ const input = budgetRoot.querySelector("[data-reasoning-budget]");
58
+ if (input) input.disabled = busy || !ready || budgetRoot.querySelector("[data-reasoning-preference-mode]")?.value !== "budget";
41
59
  }
42
60
  async function perform(action, successMessage = "") {
43
61
  const environment = environmentId;
62
+ const revision = ++operationRevision;
44
63
  busy = true; feedback.textContent = ""; controls();
45
64
  try {
46
65
  await action();
47
- if (environment === environmentId) feedback.textContent = successMessage;
66
+ if (environment !== environmentId || revision !== operationRevision) return;
67
+ feedback.textContent = successMessage;
68
+ render(latestConfiguration, environmentId);
48
69
  }
49
70
  catch (error) {
50
- if (environment === environmentId) feedback.textContent = error.code === "spark_chat_busy"
71
+ if (environment !== environmentId || revision !== operationRevision) return;
72
+ render(latestConfiguration, environmentId);
73
+ feedback.textContent = error.code === "spark_chat_busy"
51
74
  ? "Stop the active request or resolve its approval before clearing SPARK chat."
52
75
  : error.message;
53
76
  }
54
- finally { if (environment === environmentId) { busy = false; controls(); } }
77
+ finally { if (environment === environmentId && revision === operationRevision) { busy = false; controls(); } }
55
78
  }
56
79
  select.addEventListener("change", controls);
57
- agentModeSelect.addEventListener("change", () => { if (reasoningEnabled) onAgentModeChange(agentModeSelect.value); });
80
+ agentModeSelect.addEventListener("change", () => {
81
+ if (busy || !reasoningEnabled || !agentModeSelect.value) return;
82
+ void perform(() => onAgentModeChange(agentModeSelect.value), "Reasoning mode selected.");
83
+ });
58
84
  card.querySelector("form").addEventListener("submit", (event) => {
59
85
  event.preventDefault();
60
86
  if (save.disabled) return;
61
87
  const mode = select.value;
62
88
  void perform(() => onSave(mode), "Permissions saved.");
63
89
  });
64
- clear.addEventListener("click", () => {
90
+ clear.addEventListener("click", async () => {
65
91
  if (clear.disabled) return;
66
- if (!window.confirm("Clear all messages in the SPARK conversation? Long-term memory and permissions will be kept.")) return;
67
- void perform(onClear);
92
+ const environment = environmentId;
93
+ const sessionId = latestConfiguration?.sessionId;
94
+ const revision = operationRevision;
95
+ if (!await confirmClear("Clear all messages in the SPARK conversation? Long-term memory and permissions will be kept.")) return;
96
+ if (environment !== environmentId || sessionId !== latestConfiguration?.sessionId) return;
97
+ if (revision !== operationRevision || clear.disabled) return;
98
+ await perform(onClear);
68
99
  });
69
100
  card.querySelector("[data-spark-open]").addEventListener("click", onOpen);
70
101
  card.querySelector("[data-spark-reset-position]").addEventListener("click", () => onResetPosition?.());
71
102
  card.querySelector("[data-spark-model-settings]").addEventListener("click", () => onOpenModelSettings?.());
72
- return {
73
- render(configuration, nextEnvironmentId) {
103
+ function render(configuration, nextEnvironmentId) {
104
+ latestConfiguration = configuration;
74
105
  if (environmentId !== nextEnvironmentId) {
75
106
  environmentId = nextEnvironmentId; busy = false; ready = false; feedback.textContent = "";
76
107
  select.value = configuration?.toolPermissionMode || "ask";
77
108
  }
78
109
  reasoningEnabled = canChooseReasoning(configuration);
110
+ thinkingProfile = { ...configuration, id: configuration?.modelProfileId };
111
+ const preference = getReasoningPreference();
112
+ const budgetAvailable = canChooseReasoningBudget(thinkingProfile);
113
+ const nextThinkingScope = JSON.stringify([nextEnvironmentId, configuration?.sessionId, configuration?.modelProfileId, budgetAvailable]);
114
+ const nextThinkingSaved = JSON.stringify(preference);
115
+ if (thinkingScope !== nextThinkingScope) { operationRevision += 1; busy = false; }
116
+ if (thinkingScope !== nextThinkingScope || thinkingSaved !== nextThinkingSaved) {
117
+ budgetRoot.innerHTML = budgetAvailable || preference
118
+ ? `${renderReasoningPreferenceField(thinkingProfile, preference)}<button type="button" data-spark-save-thinking>Apply to next message</button>` : "";
119
+ thinkingScope = nextThinkingScope; thinkingSaved = nextThinkingSaved;
120
+ }
79
121
  agentModeSelect.innerHTML = reasoningModeOptions(getAgentMode(), reasoningEnabled);
80
122
  agentModeSelect.title = reasoningEnabled ? "Reasoning depth" : "Enable reasoning controls for this model in Models.";
81
123
  const next = configuration?.toolPermissionMode || "ask";
@@ -83,6 +125,6 @@ export function createSparkChatSettings({ root, onSave, onClear, onOpen, onReset
83
125
  saved = next; ready = Boolean(configuration?.sessionId);
84
126
  select.querySelector('[value="full_plus"]').disabled = !supportsFullPlus(getWebConfig());
85
127
  controls();
86
- },
87
- };
128
+ }
129
+ return { render };
88
130
  }
@@ -13,7 +13,8 @@ export type ToolApprovalEvent = Record<string, unknown> & {
13
13
  export interface ToolApprovalCardOptions {
14
14
  event?: ToolApprovalEvent;
15
15
  submitted?: boolean;
16
- onDecision: (approvalId: string, approved: boolean) => void;
16
+ rejectionDraft?: { text: string; expanded: boolean };
17
+ onDecision: (approvalId: string, approved: boolean, reason?: string) => void;
17
18
  documentRoot?: Document;
18
19
  }
19
20
 
@@ -1,10 +1,12 @@
1
1
  import { formatToolName } from "../lib/event-presentation.js";
2
2
  import { textOf } from "../lib/text-format.js";
3
3
  import { createConversationToolEvidence } from "./conversation-tool-evidence.js";
4
+ import { createToolApprovalRejectionInput } from "./tool-approval-rejection-input.js";
4
5
 
5
6
  export function createToolApprovalCard({
6
7
  event,
7
8
  submitted = false,
9
+ rejectionDraft = { text: "", expanded: false },
8
10
  onDecision,
9
11
  documentRoot = document,
10
12
  }) {
@@ -67,8 +69,14 @@ export function createToolApprovalCard({
67
69
  rejectButton.textContent = "Reject";
68
70
  rejectButton.disabled = submitted;
69
71
  rejectButton.addEventListener("click", () => onDecision(approvalId, false));
70
- actions.append(approveButton, rejectButton);
71
- bubble.appendChild(actions);
72
+ const rejection = createToolApprovalRejectionInput({
73
+ draft: rejectionDraft,
74
+ submitted,
75
+ onReject: (reason) => onDecision(approvalId, false, reason),
76
+ documentRoot,
77
+ });
78
+ actions.append(approveButton, rejectButton, rejection.open);
79
+ bubble.append(actions, rejection.editor);
72
80
 
73
81
  row.appendChild(bubble);
74
82
  return row;
@@ -0,0 +1,116 @@
1
+ const rejectionControls = new WeakMap();
2
+
3
+ function canSendRejection(draft, submitted) {
4
+ if (submitted) return false;
5
+ return Boolean(draft.text.trim());
6
+ }
7
+
8
+ /** Frame only text authored through this action; existing rejection reasons stay intact. */
9
+ function userRejectionReason(text) {
10
+ return "The user rejected this action. User explanation:\n" + text.trim();
11
+ }
12
+
13
+ export function createToolApprovalRejectionInput({
14
+ draft,
15
+ submitted,
16
+ onReject,
17
+ documentRoot,
18
+ }) {
19
+ const open = documentRoot.createElement("button");
20
+ open.type = "button";
21
+ open.className = "tool-approval-button reject";
22
+ open.textContent = "Reject with message";
23
+ open.disabled = submitted;
24
+ open.setAttribute("aria-expanded", String(draft.expanded));
25
+
26
+ const editor = documentRoot.createElement("div");
27
+ editor.className = "tool-approval-rejection-editor";
28
+ editor.hidden = !draft.expanded;
29
+ const label = documentRoot.createElement("label");
30
+ label.className = "tool-approval-rejection-label";
31
+ const title = documentRoot.createElement("span");
32
+ title.textContent = "Why are you rejecting this action?";
33
+ const input = documentRoot.createElement("textarea");
34
+ input.className = "tool-approval-rejection-text";
35
+ input.dir = "auto";
36
+ input.rows = 3;
37
+ input.value = draft.text;
38
+ input.disabled = submitted;
39
+ label.append(title, input);
40
+
41
+ const controls = documentRoot.createElement("div");
42
+ controls.className = "tool-approval-rejection-controls";
43
+ const send = documentRoot.createElement("button");
44
+ send.type = "button";
45
+ send.className = "tool-approval-button reject";
46
+ send.textContent = "Reject and send message";
47
+ send.disabled = !canSendRejection(draft, submitted);
48
+ const cancel = documentRoot.createElement("button");
49
+ cancel.type = "button";
50
+ cancel.className = "tool-approval-button";
51
+ cancel.textContent = "Cancel";
52
+ cancel.disabled = submitted;
53
+ controls.append(send, cancel);
54
+ editor.append(label, controls);
55
+ for (const [kind, control] of Object.entries({ open, input, send, cancel })) {
56
+ rejectionControls.set(control, { draft, kind });
57
+ }
58
+
59
+ open.addEventListener("click", () => {
60
+ if (submitted) return;
61
+ draft.expanded = true;
62
+ editor.hidden = false;
63
+ open.setAttribute("aria-expanded", "true");
64
+ input.focus();
65
+ });
66
+ cancel.addEventListener("click", () => {
67
+ if (submitted) return;
68
+ draft.expanded = false;
69
+ editor.hidden = true;
70
+ open.setAttribute("aria-expanded", "false");
71
+ open.focus();
72
+ });
73
+ input.addEventListener("input", () => {
74
+ if (submitted) return;
75
+ draft.text = input.value;
76
+ send.disabled = !canSendRejection(draft, submitted);
77
+ });
78
+ send.addEventListener("click", () => {
79
+ if (!canSendRejection(draft, submitted)) return;
80
+ onReject(userRejectionReason(draft.text));
81
+ });
82
+
83
+ return { open, editor };
84
+ }
85
+
86
+ function canRestoreRejectionControl(control, kind, draft) {
87
+ if (!control || control.disabled) return false;
88
+ if (kind === "open") return true;
89
+ return draft.expanded;
90
+ }
91
+
92
+ /** Capture this editor's focus before its owning view rebuilds the DOM. */
93
+ export function captureApprovalRejectionFocus(root, documentRoot) {
94
+ const active = documentRoot?.activeElement;
95
+ const focused = rejectionControls.get(active);
96
+ if (!focused || !root.contains(active)) return () => {};
97
+ const { draft, kind } = focused;
98
+ const start = active.selectionStart;
99
+ const end = active.selectionEnd;
100
+ const direction = active.selectionDirection;
101
+ const scrollTop = active.scrollTop;
102
+ return () => {
103
+ const control = [...root.querySelectorAll("button, textarea")].find(
104
+ (candidate) => {
105
+ const entry = rejectionControls.get(candidate);
106
+ return entry?.draft === draft && entry.kind === kind;
107
+ },
108
+ );
109
+ if (!canRestoreRejectionControl(control, kind, draft)) return;
110
+ if (control === documentRoot.activeElement) return;
111
+ control.focus({ preventScroll: true });
112
+ if (kind !== "input") return;
113
+ control.setSelectionRange(start, end, direction);
114
+ control.scrollTop = scrollTop;
115
+ };
116
+ }