@qduc/term2 0.13.0 → 0.14.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 (284) hide show
  1. package/dist/app.d.ts.map +1 -1
  2. package/dist/app.js +1 -0
  3. package/dist/app.js.map +1 -1
  4. package/dist/commands/compact-command.d.ts +6 -0
  5. package/dist/commands/compact-command.d.ts.map +1 -0
  6. package/dist/commands/compact-command.js +12 -0
  7. package/dist/commands/compact-command.js.map +1 -0
  8. package/dist/components/input/ApplicationInputSurface.d.ts.map +1 -1
  9. package/dist/components/input/ApplicationInputSurface.js +2 -0
  10. package/dist/components/input/ApplicationInputSurface.js.map +1 -1
  11. package/dist/components/input/MentorPoolMenuSession.d.ts +9 -0
  12. package/dist/components/input/MentorPoolMenuSession.d.ts.map +1 -0
  13. package/dist/components/input/MentorPoolMenuSession.js +131 -0
  14. package/dist/components/input/MentorPoolMenuSession.js.map +1 -0
  15. package/dist/components/input/MenuSurface.d.ts.map +1 -1
  16. package/dist/components/input/MenuSurface.js +16 -3
  17. package/dist/components/input/MenuSurface.js.map +1 -1
  18. package/dist/components/input/SettingsMenuSession.d.ts.map +1 -1
  19. package/dist/components/input/SettingsMenuSession.js +35 -22
  20. package/dist/components/input/SettingsMenuSession.js.map +1 -1
  21. package/dist/components/input/menu-controller.d.ts.map +1 -1
  22. package/dist/components/input/menu-controller.js +18 -1
  23. package/dist/components/input/menu-controller.js.map +1 -1
  24. package/dist/components/input/menu-registry.d.ts.map +1 -1
  25. package/dist/components/input/menu-registry.js +2 -0
  26. package/dist/components/input/menu-registry.js.map +1 -1
  27. package/dist/components/input/menu-types.d.ts +5 -0
  28. package/dist/components/input/menu-types.d.ts.map +1 -1
  29. package/dist/components/input/triggers.d.ts.map +1 -1
  30. package/dist/components/input/triggers.js +33 -0
  31. package/dist/components/input/triggers.js.map +1 -1
  32. package/dist/components/layout/BackgroundTasksPanel.d.ts +2 -0
  33. package/dist/components/layout/BackgroundTasksPanel.d.ts.map +1 -1
  34. package/dist/components/layout/BackgroundTasksPanel.js +25 -4
  35. package/dist/components/layout/BackgroundTasksPanel.js.map +1 -1
  36. package/dist/components/menu/CopyMenu.d.ts +1 -0
  37. package/dist/components/menu/CopyMenu.d.ts.map +1 -1
  38. package/dist/components/menu/CopyMenu.js +15 -2
  39. package/dist/components/menu/CopyMenu.js.map +1 -1
  40. package/dist/components/menu/MentorPoolSelectionMenu.d.ts +13 -0
  41. package/dist/components/menu/MentorPoolSelectionMenu.d.ts.map +1 -0
  42. package/dist/components/menu/MentorPoolSelectionMenu.js +98 -0
  43. package/dist/components/menu/MentorPoolSelectionMenu.js.map +1 -0
  44. package/dist/components/menu/ModelSelectionMenu.d.ts +1 -0
  45. package/dist/components/menu/ModelSelectionMenu.d.ts.map +1 -1
  46. package/dist/components/menu/ModelSelectionMenu.js +4 -2
  47. package/dist/components/menu/ModelSelectionMenu.js.map +1 -1
  48. package/dist/components/menu/SlashCommandMenu.d.ts.map +1 -1
  49. package/dist/components/menu/SlashCommandMenu.js +12 -9
  50. package/dist/components/menu/SlashCommandMenu.js.map +1 -1
  51. package/dist/components/message/SubagentActivityMessage.d.ts +1 -0
  52. package/dist/components/message/SubagentActivityMessage.d.ts.map +1 -1
  53. package/dist/components/message/SubagentActivityMessage.js +14 -1
  54. package/dist/components/message/SubagentActivityMessage.js.map +1 -1
  55. package/dist/context/InputContext.d.ts +1 -1
  56. package/dist/context/InputContext.d.ts.map +1 -1
  57. package/dist/context/InputContext.js +2 -0
  58. package/dist/context/InputContext.js.map +1 -1
  59. package/dist/contracts/application-stream.d.ts +7 -0
  60. package/dist/contracts/application-stream.d.ts.map +1 -1
  61. package/dist/contracts/provider-input.d.ts +15 -0
  62. package/dist/contracts/provider-input.d.ts.map +1 -1
  63. package/dist/contracts/provider-input.js +6 -1
  64. package/dist/contracts/provider-input.js.map +1 -1
  65. package/dist/hooks/settings-completion-config.d.ts.map +1 -1
  66. package/dist/hooks/settings-completion-config.js +10 -2
  67. package/dist/hooks/settings-completion-config.js.map +1 -1
  68. package/dist/hooks/use-app-commands.d.ts +2 -1
  69. package/dist/hooks/use-app-commands.d.ts.map +1 -1
  70. package/dist/hooks/use-app-commands.js +4 -1
  71. package/dist/hooks/use-app-commands.js.map +1 -1
  72. package/dist/hooks/use-conversation.d.ts.map +1 -1
  73. package/dist/hooks/use-conversation.js +9 -2
  74. package/dist/hooks/use-conversation.js.map +1 -1
  75. package/dist/hooks/use-mentor-pool-selection.d.ts +103 -0
  76. package/dist/hooks/use-mentor-pool-selection.d.ts.map +1 -0
  77. package/dist/hooks/use-mentor-pool-selection.js +642 -0
  78. package/dist/hooks/use-mentor-pool-selection.js.map +1 -0
  79. package/dist/lib/agent-chat-service.d.ts +3 -6
  80. package/dist/lib/agent-chat-service.d.ts.map +1 -1
  81. package/dist/lib/agent-chat-service.js +11 -1
  82. package/dist/lib/agent-chat-service.js.map +1 -1
  83. package/dist/lib/agent-client.d.ts +13 -0
  84. package/dist/lib/agent-client.d.ts.map +1 -1
  85. package/dist/lib/agent-client.js +115 -0
  86. package/dist/lib/agent-client.js.map +1 -1
  87. package/dist/lib/agent-configuration.d.ts.map +1 -1
  88. package/dist/lib/agent-configuration.js +2 -0
  89. package/dist/lib/agent-configuration.js.map +1 -1
  90. package/dist/lib/agent-factory.d.ts.map +1 -1
  91. package/dist/lib/agent-factory.js +9 -1
  92. package/dist/lib/agent-factory.js.map +1 -1
  93. package/dist/prompts/context-compaction.d.ts +4 -0
  94. package/dist/prompts/context-compaction.d.ts.map +1 -0
  95. package/dist/prompts/context-compaction.js +18 -0
  96. package/dist/prompts/context-compaction.js.map +1 -0
  97. package/dist/prompts/context-compaction.ts +23 -0
  98. package/dist/prompts/explorer-delegation-contract.test.ts +22 -0
  99. package/dist/prompts/gpt-5.6.md +1 -1
  100. package/dist/prompts/kimi.md +1 -1
  101. package/dist/prompts/plan-mode-info.md +2 -2
  102. package/dist/prompts/subagent-delegation.d.ts.map +1 -1
  103. package/dist/prompts/subagent-delegation.js +4 -2
  104. package/dist/prompts/subagent-delegation.js.map +1 -1
  105. package/dist/prompts/subagent-delegation.test.ts +10 -0
  106. package/dist/prompts/subagent-delegation.ts +4 -2
  107. package/dist/prompts/subagents/explorer.md +10 -5
  108. package/dist/prompts/subagents/librarian.md +1 -1
  109. package/dist/prompts/subagents/worker.md +1 -1
  110. package/dist/providers/aborted-stream-recorder.d.ts +20 -0
  111. package/dist/providers/aborted-stream-recorder.d.ts.map +1 -0
  112. package/dist/providers/aborted-stream-recorder.js +63 -0
  113. package/dist/providers/aborted-stream-recorder.js.map +1 -0
  114. package/dist/providers/codex-responses-model.d.ts +7 -2
  115. package/dist/providers/codex-responses-model.d.ts.map +1 -1
  116. package/dist/providers/codex-responses-model.js +72 -41
  117. package/dist/providers/codex-responses-model.js.map +1 -1
  118. package/dist/providers/codex.provider.d.ts +3 -2
  119. package/dist/providers/codex.provider.d.ts.map +1 -1
  120. package/dist/providers/codex.provider.js +24 -11
  121. package/dist/providers/codex.provider.js.map +1 -1
  122. package/dist/providers/model-catalog/catalog.generated.d.ts +406 -166
  123. package/dist/providers/model-catalog/catalog.generated.d.ts.map +1 -1
  124. package/dist/providers/model-catalog/catalog.generated.js +406 -166
  125. package/dist/providers/model-catalog/catalog.generated.js.map +1 -1
  126. package/dist/providers/openai-responses-model.d.ts +9 -1
  127. package/dist/providers/openai-responses-model.d.ts.map +1 -1
  128. package/dist/providers/openai-responses-model.js +34 -12
  129. package/dist/providers/openai-responses-model.js.map +1 -1
  130. package/dist/scripts/eval-context-compaction/runner.d.ts +2 -0
  131. package/dist/scripts/eval-context-compaction/runner.d.ts.map +1 -0
  132. package/dist/scripts/eval-context-compaction/runner.js +159 -0
  133. package/dist/scripts/eval-context-compaction/runner.js.map +1 -0
  134. package/dist/services/agent-runtime/application-run-loop.d.ts +30 -0
  135. package/dist/services/agent-runtime/application-run-loop.d.ts.map +1 -1
  136. package/dist/services/agent-runtime/application-run-loop.js +221 -99
  137. package/dist/services/agent-runtime/application-run-loop.js.map +1 -1
  138. package/dist/services/agent-runtime/context-compaction/index.d.ts +56 -0
  139. package/dist/services/agent-runtime/context-compaction/index.d.ts.map +1 -0
  140. package/dist/services/agent-runtime/context-compaction/index.js +131 -0
  141. package/dist/services/agent-runtime/context-compaction/index.js.map +1 -0
  142. package/dist/services/agent-runtime/context-compaction/local-context-compactor.d.ts +76 -0
  143. package/dist/services/agent-runtime/context-compaction/local-context-compactor.d.ts.map +1 -0
  144. package/dist/services/agent-runtime/context-compaction/local-context-compactor.js +146 -0
  145. package/dist/services/agent-runtime/context-compaction/local-context-compactor.js.map +1 -0
  146. package/dist/services/agent-runtime/generation-guard.d.ts +15 -1
  147. package/dist/services/agent-runtime/generation-guard.d.ts.map +1 -1
  148. package/dist/services/agent-runtime/generation-guard.js +34 -2
  149. package/dist/services/agent-runtime/generation-guard.js.map +1 -1
  150. package/dist/services/conversation/conversation-events.d.ts +3 -0
  151. package/dist/services/conversation/conversation-events.d.ts.map +1 -1
  152. package/dist/services/conversation/conversation-message-projection.d.ts.map +1 -1
  153. package/dist/services/conversation/conversation-message-projection.js +7 -3
  154. package/dist/services/conversation/conversation-message-projection.js.map +1 -1
  155. package/dist/services/conversation/conversation-service.d.ts +1 -0
  156. package/dist/services/conversation/conversation-service.d.ts.map +1 -1
  157. package/dist/services/conversation/conversation-service.js +74 -0
  158. package/dist/services/conversation/conversation-service.js.map +1 -1
  159. package/dist/services/conversation/conversation-state-projector.d.ts +7 -1
  160. package/dist/services/conversation/conversation-state-projector.d.ts.map +1 -1
  161. package/dist/services/conversation/conversation-state-projector.js +20 -3
  162. package/dist/services/conversation/conversation-state-projector.js.map +1 -1
  163. package/dist/services/conversation/conversation-state-schema.d.ts +8 -4
  164. package/dist/services/conversation/conversation-state-schema.d.ts.map +1 -1
  165. package/dist/services/conversation/conversation-state-schema.js +24 -2
  166. package/dist/services/conversation/conversation-state-schema.js.map +1 -1
  167. package/dist/services/conversation/conversation-store.d.ts +2 -0
  168. package/dist/services/conversation/conversation-store.d.ts.map +1 -1
  169. package/dist/services/conversation/conversation-store.js +8 -0
  170. package/dist/services/conversation/conversation-store.js.map +1 -1
  171. package/dist/services/conversation-agent-client.d.ts +9 -0
  172. package/dist/services/conversation-agent-client.d.ts.map +1 -1
  173. package/dist/services/logging/conversation-log-events.d.ts +1 -1
  174. package/dist/services/logging/conversation-log-events.d.ts.map +1 -1
  175. package/dist/services/logging/provider-traffic.d.ts +1 -1
  176. package/dist/services/logging/provider-traffic.d.ts.map +1 -1
  177. package/dist/services/logging/provider-traffic.js +10 -3
  178. package/dist/services/logging/provider-traffic.js.map +1 -1
  179. package/dist/services/retry/recovery-executor.d.ts.map +1 -1
  180. package/dist/services/retry/recovery-executor.js +8 -9
  181. package/dist/services/retry/recovery-executor.js.map +1 -1
  182. package/dist/services/service-interfaces.d.ts +15 -0
  183. package/dist/services/service-interfaces.d.ts.map +1 -1
  184. package/dist/services/session/session-composition.d.ts +7 -0
  185. package/dist/services/session/session-composition.d.ts.map +1 -1
  186. package/dist/services/session/session-composition.js +79 -0
  187. package/dist/services/session/session-composition.js.map +1 -1
  188. package/dist/services/session/session-manager.d.ts +3 -0
  189. package/dist/services/session/session-manager.d.ts.map +1 -1
  190. package/dist/services/session/session-manager.js +6 -0
  191. package/dist/services/session/session-manager.js.map +1 -1
  192. package/dist/services/session/session-stream-processor.d.ts.map +1 -1
  193. package/dist/services/session/session-stream-processor.js +3 -1
  194. package/dist/services/session/session-stream-processor.js.map +1 -1
  195. package/dist/services/session/session-tool-tracker.d.ts +17 -6
  196. package/dist/services/session/session-tool-tracker.d.ts.map +1 -1
  197. package/dist/services/session/session-tool-tracker.js +19 -7
  198. package/dist/services/session/session-tool-tracker.js.map +1 -1
  199. package/dist/services/settings/settings-schema.d.ts +52 -0
  200. package/dist/services/settings/settings-schema.d.ts.map +1 -1
  201. package/dist/services/settings/settings-schema.js +31 -2
  202. package/dist/services/settings/settings-schema.js.map +1 -1
  203. package/dist/services/settings/settings-sources.d.ts.map +1 -1
  204. package/dist/services/settings/settings-sources.js +2 -0
  205. package/dist/services/settings/settings-sources.js.map +1 -1
  206. package/dist/services/stream-event-processor.d.ts.map +1 -1
  207. package/dist/services/stream-event-processor.js +27 -1
  208. package/dist/services/stream-event-processor.js.map +1 -1
  209. package/dist/services/subagents/execution-runner.d.ts.map +1 -1
  210. package/dist/services/subagents/execution-runner.js +26 -1
  211. package/dist/services/subagents/execution-runner.js.map +1 -1
  212. package/dist/services/subagents/mentor-runner.d.ts.map +1 -1
  213. package/dist/services/subagents/mentor-runner.js +111 -13
  214. package/dist/services/subagents/mentor-runner.js.map +1 -1
  215. package/dist/services/subagents/nested-runner.d.ts.map +1 -1
  216. package/dist/services/subagents/nested-runner.js +54 -25
  217. package/dist/services/subagents/nested-runner.js.map +1 -1
  218. package/dist/services/subagents/role-loader.d.ts +6 -0
  219. package/dist/services/subagents/role-loader.d.ts.map +1 -1
  220. package/dist/services/subagents/role-loader.js +6 -1
  221. package/dist/services/subagents/role-loader.js.map +1 -1
  222. package/dist/services/subagents/utils.d.ts +17 -0
  223. package/dist/services/subagents/utils.d.ts.map +1 -1
  224. package/dist/services/subagents/utils.js +36 -0
  225. package/dist/services/subagents/utils.js.map +1 -1
  226. package/dist/services/tool-execution-ledger.d.ts +26 -1
  227. package/dist/services/tool-execution-ledger.d.ts.map +1 -1
  228. package/dist/services/tool-execution-ledger.js +103 -33
  229. package/dist/services/tool-execution-ledger.js.map +1 -1
  230. package/dist/tools/agent/activate-skill.d.ts.map +1 -1
  231. package/dist/tools/agent/activate-skill.js +1 -0
  232. package/dist/tools/agent/activate-skill.js.map +1 -1
  233. package/dist/tools/agent/ask-mentor.d.ts.map +1 -1
  234. package/dist/tools/agent/ask-mentor.js +5 -1
  235. package/dist/tools/agent/ask-mentor.js.map +1 -1
  236. package/dist/tools/agent/run-subagent-async.d.ts.map +1 -1
  237. package/dist/tools/agent/run-subagent-async.js +2 -0
  238. package/dist/tools/agent/run-subagent-async.js.map +1 -1
  239. package/dist/tools/agent/run-subagent.d.ts.map +1 -1
  240. package/dist/tools/agent/run-subagent.js +15 -6
  241. package/dist/tools/agent/run-subagent.js.map +1 -1
  242. package/dist/tools/file/apply-patch.d.ts.map +1 -1
  243. package/dist/tools/file/apply-patch.js +6 -3
  244. package/dist/tools/file/apply-patch.js.map +1 -1
  245. package/dist/tools/file/code-context.d.ts.map +1 -1
  246. package/dist/tools/file/code-context.js +2 -0
  247. package/dist/tools/file/code-context.js.map +1 -1
  248. package/dist/tools/file/glob.d.ts.map +1 -1
  249. package/dist/tools/file/glob.js +1 -0
  250. package/dist/tools/file/glob.js.map +1 -1
  251. package/dist/tools/file/grep.d.ts.map +1 -1
  252. package/dist/tools/file/grep.js +1 -0
  253. package/dist/tools/file/grep.js.map +1 -1
  254. package/dist/tools/file/read-file.d.ts +2 -0
  255. package/dist/tools/file/read-file.d.ts.map +1 -1
  256. package/dist/tools/file/read-file.js +36 -15
  257. package/dist/tools/file/read-file.js.map +1 -1
  258. package/dist/tools/system/shell.d.ts.map +1 -1
  259. package/dist/tools/system/shell.js +1 -0
  260. package/dist/tools/system/shell.js.map +1 -1
  261. package/dist/tools/types.d.ts +5 -0
  262. package/dist/tools/types.d.ts.map +1 -1
  263. package/dist/tools/types.js.map +1 -1
  264. package/dist/tools/web/web-fetch.d.ts.map +1 -1
  265. package/dist/tools/web/web-fetch.js +10 -12
  266. package/dist/tools/web/web-fetch.js.map +1 -1
  267. package/dist/tools/web/web-search.d.ts.map +1 -1
  268. package/dist/tools/web/web-search.js +1 -0
  269. package/dist/tools/web/web-search.js.map +1 -1
  270. package/dist/utils/conversation/conversation-event-handler.d.ts.map +1 -1
  271. package/dist/utils/conversation/conversation-event-handler.js +13 -1
  272. package/dist/utils/conversation/conversation-event-handler.js.map +1 -1
  273. package/dist/utils/output/bound-tool-result.d.ts +42 -0
  274. package/dist/utils/output/bound-tool-result.d.ts.map +1 -0
  275. package/dist/utils/output/bound-tool-result.js +81 -0
  276. package/dist/utils/output/bound-tool-result.js.map +1 -0
  277. package/dist/utils/settings-command.d.ts.map +1 -1
  278. package/dist/utils/settings-command.js +17 -2
  279. package/dist/utils/settings-command.js.map +1 -1
  280. package/dist/utils/shell/shell-output.d.ts +11 -0
  281. package/dist/utils/shell/shell-output.d.ts.map +1 -1
  282. package/dist/utils/shell/shell-output.js +18 -8
  283. package/dist/utils/shell/shell-output.js.map +1 -1
  284. package/package.json +1 -1
@@ -0,0 +1,642 @@
1
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
+ import { z } from 'zod';
3
+ import { useInputContext } from '../context/InputContext.js';
4
+ import { SETTING_KEYS } from '../services/settings/settings-service.js';
5
+ import { filterModels } from '../services/model-service.js';
6
+ import { ModelCatalogSession } from '../services/models/model-catalog-session.js';
7
+ import { loadProviderItems } from '../providers/provider-service.js';
8
+ import { resolveProviderCredentials } from '../utils/ai/provider-credentials.js';
9
+ import { useSelection } from './use-selection.js';
10
+ export const MENTOR_POOL_REASONING_EFFORTS = ['default', 'none', 'minimal', 'low', 'medium', 'high', 'xhigh'];
11
+ const mentorPoolEntrySchema = z.object({
12
+ model: z.string().min(1, 'Model is required'),
13
+ provider: z.string().min(1, 'Provider cannot be empty').optional(),
14
+ reasoningEffort: z.enum(MENTOR_POOL_REASONING_EFFORTS).optional(),
15
+ });
16
+ const mentorPoolSchema = z.array(mentorPoolEntrySchema).max(8, 'Mentor pool cannot contain more than 8 entries');
17
+ const noOpLoggingService = {
18
+ info: () => { },
19
+ warn: () => { },
20
+ error: () => { },
21
+ debug: () => { },
22
+ security: () => { },
23
+ setCorrelationId: () => { },
24
+ getCorrelationId: () => undefined,
25
+ clearCorrelationId: () => { },
26
+ };
27
+ const cloneEntries = (value) => {
28
+ const parsed = mentorPoolSchema.safeParse(value);
29
+ return parsed.success ? parsed.data.map((entry) => ({ ...entry })) : [];
30
+ };
31
+ export function formatMentorPoolProvider(provider) {
32
+ return provider || 'Inherit mentor provider';
33
+ }
34
+ export function formatMentorPoolReasoning(reasoningEffort) {
35
+ switch (reasoningEffort) {
36
+ case 'none':
37
+ return 'None';
38
+ case 'minimal':
39
+ return 'Minimal';
40
+ case 'low':
41
+ return 'Low';
42
+ case 'medium':
43
+ return 'Medium';
44
+ case 'high':
45
+ return 'High';
46
+ case 'xhigh':
47
+ return 'Extra high';
48
+ case undefined:
49
+ return 'Inherit mentor reasoning';
50
+ case 'default':
51
+ return 'Provider default';
52
+ }
53
+ }
54
+ export function mergeMentorPoolModels({ catalogModels, entries, provider, currentModel, }) {
55
+ const catalogIds = new Set(catalogModels.map((model) => model.id));
56
+ const suggestedIds = new Set();
57
+ const suggestions = [];
58
+ const addSuggestion = (id, name) => {
59
+ if (!id || catalogIds.has(id) || suggestedIds.has(id))
60
+ return;
61
+ suggestedIds.add(id);
62
+ suggestions.push({ id, name, provider });
63
+ };
64
+ addSuggestion(currentModel, 'Current model (not in catalog)');
65
+ for (const entry of entries) {
66
+ if (entry.provider === undefined || entry.provider === provider)
67
+ addSuggestion(entry.model, 'In mentor pool');
68
+ }
69
+ return [...suggestions, ...catalogModels];
70
+ }
71
+ export function resolveMentorPoolModelSelection(models, selectedIndex, typedModel) {
72
+ return models[selectedIndex]?.id ?? typedModel.trim();
73
+ }
74
+ /** Starting provider tab for the mentor-pool model browser. */
75
+ export function resolveMentorPoolBrowseProvider({ draftProvider, mentorProvider, agentProvider, }) {
76
+ return draftProvider || mentorProvider || agentProvider || '';
77
+ }
78
+ /** Apply a model catalog pick: pin both model id and the active provider tab. */
79
+ export function applyMentorPoolModelPick(draft, model, provider) {
80
+ return {
81
+ ...draft,
82
+ model,
83
+ ...(provider ? { provider } : {}),
84
+ };
85
+ }
86
+ export function formatMentorPoolEntry(entry) {
87
+ const provider = entry.provider ? ` @ ${entry.provider}` : '';
88
+ const effort = entry.reasoningEffort && entry.reasoningEffort !== 'default' ? ` (${entry.reasoningEffort})` : '';
89
+ return `${entry.model}${provider}${effort}`;
90
+ }
91
+ export function buildMentorPoolListItems(entries) {
92
+ const actions = [];
93
+ if (entries.length < 8)
94
+ actions.push({ kind: 'action', action: 'add', label: 'Add Entry' });
95
+ if (entries.length > 1)
96
+ actions.push({ kind: 'action', action: 'reorder', label: 'Reorder Entries' });
97
+ actions.push({ kind: 'action', action: 'save', label: 'Save Changes' });
98
+ return [
99
+ ...entries.map((entry, index) => ({
100
+ kind: 'entry',
101
+ entry,
102
+ index,
103
+ label: entry.model,
104
+ })),
105
+ ...actions,
106
+ ];
107
+ }
108
+ export function useMentorPoolSelection(settingsService, active, loggingService) {
109
+ const { input, setInput, replaceInput } = useInputContext();
110
+ const [phase, setPhase] = useState('list');
111
+ const [entries, setEntries] = useState([]);
112
+ const [draft, setDraft] = useState(null);
113
+ const [editingIndex, setEditingIndex] = useState(null);
114
+ const [reorderList, setReorderList] = useState([]);
115
+ const [providerItems, setProviderItems] = useState([]);
116
+ const [draftModified, setDraftModified] = useState(false);
117
+ const [discardFromPhase, setDiscardFromPhase] = useState(null);
118
+ const [errorMessage, setErrorMessage] = useState(null);
119
+ const [fieldErrors, setFieldErrors] = useState({});
120
+ const catalogSession = useMemo(() => new ModelCatalogSession({ settingsService, loggingService: loggingService ?? noOpLoggingService }), [loggingService, settingsService]);
121
+ const [catalogModels, setCatalogModels] = useState([]);
122
+ const [modelLoading, setModelLoading] = useState(false);
123
+ const [modelError, setModelError] = useState(null);
124
+ const [modelSelectedIndex, setModelSelectedIndex] = useState(0);
125
+ const [modelScrollOffset, setModelScrollOffset] = useState(0);
126
+ const [modelRefreshKey, setModelRefreshKey] = useState(0);
127
+ /** Provider tab currently browsed in the model menu (independent of draft until pick). */
128
+ const [browsingProvider, setBrowsingProvider] = useState(null);
129
+ const settingsServiceRef = useRef(settingsService);
130
+ settingsServiceRef.current = settingsService;
131
+ const fallbackModelProvider = resolveMentorPoolBrowseProvider({
132
+ draftProvider: draft?.provider,
133
+ mentorProvider: settingsService.get(SETTING_KEYS.AGENT_MENTOR_PROVIDER),
134
+ agentProvider: settingsService.get(SETTING_KEYS.AGENT_PROVIDER),
135
+ });
136
+ const modelProvider = browsingProvider ?? fallbackModelProvider;
137
+ const modelItems = useMemo(() => mergeMentorPoolModels({
138
+ catalogModels,
139
+ entries,
140
+ provider: modelProvider,
141
+ currentModel: draft?.model ?? '',
142
+ }), [catalogModels, draft?.model, entries, modelProvider]);
143
+ const filteredModels = useMemo(() => filterModels(modelItems, input), [input, modelItems]);
144
+ const activeItems = useMemo(() => {
145
+ if (phase === 'list') {
146
+ return buildMentorPoolListItems(entries);
147
+ }
148
+ if (phase === 'edit_fields') {
149
+ if (!draft)
150
+ return [];
151
+ return [
152
+ { kind: 'field', field: 'model', label: 'Model', detail: draft.model || '<empty>' },
153
+ { kind: 'field', field: 'provider', label: 'Provider', detail: formatMentorPoolProvider(draft.provider) },
154
+ {
155
+ kind: 'field',
156
+ field: 'reasoning',
157
+ label: 'Reasoning',
158
+ detail: formatMentorPoolReasoning(draft.reasoningEffort),
159
+ },
160
+ { kind: 'action', action: 'save', label: 'Save Changes' },
161
+ { kind: 'action', action: 'cancel', label: 'Cancel' },
162
+ ];
163
+ }
164
+ if (phase === 'edit_provider') {
165
+ return [
166
+ { kind: 'provider', id: '', label: 'Inherit (use mentor provider)' },
167
+ ...providerItems.map((provider) => ({ kind: 'provider', id: provider.id, label: provider.label })),
168
+ ];
169
+ }
170
+ if (phase === 'edit_reasoning') {
171
+ return [
172
+ { kind: 'reasoning', value: undefined, label: formatMentorPoolReasoning() },
173
+ ...MENTOR_POOL_REASONING_EFFORTS.map((value) => ({
174
+ kind: 'reasoning',
175
+ value,
176
+ label: formatMentorPoolReasoning(value),
177
+ })),
178
+ ];
179
+ }
180
+ if (phase === 'confirm_delete') {
181
+ return [
182
+ { kind: 'action', action: 'save', label: 'Yes, delete entry', tone: 'destructive' },
183
+ { kind: 'action', action: 'cancel', label: 'No, keep it' },
184
+ ];
185
+ }
186
+ if (phase === 'confirm_discard') {
187
+ return [
188
+ { kind: 'action', action: 'save', label: 'Yes, discard changes', tone: 'destructive' },
189
+ { kind: 'action', action: 'cancel', label: 'No, keep editing' },
190
+ ];
191
+ }
192
+ return reorderList.map((entry, index) => ({
193
+ kind: 'reorder-entry',
194
+ index,
195
+ entry,
196
+ label: entry.model,
197
+ }));
198
+ }, [draft, entries, phase, providerItems, reorderList]);
199
+ const selection = useSelection(activeItems);
200
+ useEffect(() => {
201
+ if (!active)
202
+ return;
203
+ const currentSettingsService = settingsServiceRef.current;
204
+ const loaded = cloneEntries(currentSettingsService.get(SETTING_KEYS.AGENT_MENTOR_POOL));
205
+ setEntries(loaded);
206
+ setProviderItems(loadProviderItems(currentSettingsService));
207
+ setPhase('list');
208
+ setDraft(null);
209
+ setEditingIndex(null);
210
+ setReorderList([]);
211
+ setDraftModified(false);
212
+ setDiscardFromPhase(null);
213
+ setErrorMessage(null);
214
+ setFieldErrors({});
215
+ }, [active]);
216
+ useEffect(() => {
217
+ if (!active || phase !== 'edit_model' || !modelProvider)
218
+ return;
219
+ /* eslint-disable react-hooks/set-state-in-effect */
220
+ const credentials = resolveProviderCredentials(settingsService, modelProvider);
221
+ const cachedModels = catalogSession.getCached(modelProvider);
222
+ setCatalogModels(cachedModels ?? []);
223
+ setModelSelectedIndex(0);
224
+ setModelScrollOffset(0);
225
+ setModelError(null);
226
+ if (credentials.required && !credentials.configured) {
227
+ setModelLoading(false);
228
+ return;
229
+ }
230
+ catalogSession.begin();
231
+ let disposed = false;
232
+ const load = async () => {
233
+ setModelLoading(!cachedModels);
234
+ try {
235
+ const result = await catalogSession.load(modelProvider);
236
+ if (disposed || result.kind === 'stale')
237
+ return;
238
+ setCatalogModels(result.models);
239
+ }
240
+ catch (error) {
241
+ if (!disposed)
242
+ setModelError(error instanceof Error ? error.message : String(error));
243
+ }
244
+ finally {
245
+ if (!disposed)
246
+ setModelLoading(false);
247
+ }
248
+ };
249
+ void load();
250
+ return () => {
251
+ disposed = true;
252
+ };
253
+ /* eslint-enable react-hooks/set-state-in-effect */
254
+ }, [active, catalogSession, modelProvider, modelRefreshKey, phase, settingsService]);
255
+ useEffect(() => {
256
+ // Changing the search text starts a new list navigation session.
257
+ // eslint-disable-next-line react-hooks/set-state-in-effect
258
+ setModelSelectedIndex(0);
259
+ setModelScrollOffset(0);
260
+ }, [input]);
261
+ useEffect(() => {
262
+ // eslint-disable-next-line react-hooks/set-state-in-effect
263
+ setModelSelectedIndex((index) => Math.min(index, Math.max(0, filteredModels.length - 1)));
264
+ }, [filteredModels.length]);
265
+ useEffect(() => {
266
+ if (modelSelectedIndex < modelScrollOffset) {
267
+ // eslint-disable-next-line react-hooks/set-state-in-effect
268
+ setModelScrollOffset(modelSelectedIndex);
269
+ }
270
+ else if (modelSelectedIndex >= modelScrollOffset + 10) {
271
+ setModelScrollOffset(modelSelectedIndex - 9);
272
+ }
273
+ }, [modelScrollOffset, modelSelectedIndex]);
274
+ useEffect(() => {
275
+ selection.setSelectedIndex(0);
276
+ }, [phase, selection.setSelectedIndex]);
277
+ const resolveBrowseProvider = useCallback((draftProvider) => resolveMentorPoolBrowseProvider({
278
+ draftProvider,
279
+ mentorProvider: settingsService.get(SETTING_KEYS.AGENT_MENTOR_PROVIDER),
280
+ agentProvider: settingsService.get(SETTING_KEYS.AGENT_PROVIDER),
281
+ }), [settingsService]);
282
+ const openDraft = useCallback((entry, index) => {
283
+ setDraft(entry ? { ...entry, _isNew: false } : { model: '', _isNew: true });
284
+ setEditingIndex(index);
285
+ setDraftModified(false);
286
+ setErrorMessage(null);
287
+ setFieldErrors({});
288
+ // New entries jump straight into the model menu (with provider tabs) so
289
+ // the user picks model + provider in one step instead of a separate
290
+ // provider field first.
291
+ if (entry === null) {
292
+ setBrowsingProvider(resolveBrowseProvider(undefined));
293
+ setPhase('edit_model');
294
+ replaceInput('');
295
+ }
296
+ else {
297
+ setBrowsingProvider(null);
298
+ setPhase('edit_fields');
299
+ setInput('');
300
+ }
301
+ }, [replaceInput, resolveBrowseProvider, setInput]);
302
+ const saveDraft = useCallback(() => {
303
+ if (!draft)
304
+ return;
305
+ const result = mentorPoolEntrySchema.safeParse({
306
+ model: draft.model.trim(),
307
+ ...(draft.provider === undefined ? {} : { provider: draft.provider.trim() }),
308
+ ...(draft.reasoningEffort === undefined ? {} : { reasoningEffort: draft.reasoningEffort }),
309
+ });
310
+ if (!result.success) {
311
+ const errors = {};
312
+ for (const issue of result.error.issues)
313
+ errors[String(issue.path[0] ?? 'model')] = issue.message;
314
+ setFieldErrors(errors);
315
+ setErrorMessage('Fix the highlighted fields before saving.');
316
+ return;
317
+ }
318
+ const next = { ...result.data };
319
+ setEntries((current) => {
320
+ if (draft._isNew || editingIndex === null)
321
+ return [...current, next];
322
+ return current.map((entry, index) => (index === editingIndex ? next : entry));
323
+ });
324
+ setDraft(null);
325
+ setEditingIndex(null);
326
+ setDraftModified(true);
327
+ setFieldErrors({});
328
+ setErrorMessage(null);
329
+ setPhase('list');
330
+ selection.setSelectedIndex(0);
331
+ setInput('');
332
+ }, [draft, editingIndex, setInput, selection.setSelectedIndex]);
333
+ const selectItem = useCallback(() => {
334
+ const item = activeItems[selection.selectedIndex];
335
+ if (!item)
336
+ return;
337
+ if (phase === 'list') {
338
+ if (item.kind === 'entry')
339
+ openDraft(item.entry, item.index);
340
+ else if (item.kind === 'action' && item.action === 'add')
341
+ openDraft(null, null);
342
+ else if (item.kind === 'action' && item.action === 'reorder') {
343
+ setReorderList(entries.map((entry) => ({ ...entry })));
344
+ setPhase('reorder');
345
+ selection.setSelectedIndex(0);
346
+ }
347
+ return;
348
+ }
349
+ if (phase === 'edit_fields' && draft) {
350
+ if (item.kind === 'field') {
351
+ setErrorMessage(null);
352
+ setFieldErrors({});
353
+ if (item.field === 'model') {
354
+ setBrowsingProvider(resolveBrowseProvider(draft.provider));
355
+ setPhase('edit_model');
356
+ replaceInput(draft.model);
357
+ }
358
+ else if (item.field === 'provider') {
359
+ setPhase('edit_provider');
360
+ selection.setSelectedIndex(draft.provider ? providerItems.findIndex((provider) => provider.id === draft.provider) + 1 : 0);
361
+ setInput('');
362
+ }
363
+ else {
364
+ setPhase('edit_reasoning');
365
+ selection.setSelectedIndex(draft.reasoningEffort === undefined ? 0 : MENTOR_POOL_REASONING_EFFORTS.indexOf(draft.reasoningEffort) + 1);
366
+ setInput('');
367
+ }
368
+ }
369
+ else if (item.kind === 'action' && item.action === 'save')
370
+ saveDraft();
371
+ else if (item.kind === 'action' && item.action === 'cancel') {
372
+ setDraft(null);
373
+ setEditingIndex(null);
374
+ setPhase('list');
375
+ selection.setSelectedIndex(0);
376
+ setInput('');
377
+ }
378
+ return;
379
+ }
380
+ if (phase === 'edit_provider' && item.kind === 'provider' && draft) {
381
+ setDraft({ ...draft, provider: item.id || undefined });
382
+ setDraftModified(true);
383
+ setPhase('edit_fields');
384
+ selection.setSelectedIndex(1);
385
+ setInput('');
386
+ return;
387
+ }
388
+ if (phase === 'edit_reasoning' && item.kind === 'reasoning' && draft) {
389
+ // Keep an explicitly stored `default` distinct from an omitted value:
390
+ // the runner treats an omitted value as falling back to the mentor
391
+ // setting, while `default` uses the provider default.
392
+ setDraft({ ...draft, reasoningEffort: item.value });
393
+ setDraftModified(true);
394
+ setPhase('edit_fields');
395
+ selection.setSelectedIndex(2);
396
+ setInput('');
397
+ return;
398
+ }
399
+ if (phase === 'confirm_delete' && item.kind === 'action') {
400
+ if (item.action === 'save' && editingIndex !== null) {
401
+ setEntries((current) => current.filter((_, index) => index !== editingIndex));
402
+ setDraftModified(true);
403
+ }
404
+ setDraft(null);
405
+ setEditingIndex(null);
406
+ setPhase('list');
407
+ selection.setSelectedIndex(0);
408
+ return;
409
+ }
410
+ if (phase === 'confirm_discard' && item.kind === 'action') {
411
+ if (item.action === 'save') {
412
+ setDraft(null);
413
+ setEditingIndex(null);
414
+ setPhase('list');
415
+ selection.setSelectedIndex(0);
416
+ setDraftModified(true);
417
+ }
418
+ else if (discardFromPhase) {
419
+ setPhase(discardFromPhase);
420
+ selection.setSelectedIndex(0);
421
+ }
422
+ setDiscardFromPhase(null);
423
+ }
424
+ }, [
425
+ activeItems,
426
+ draft,
427
+ discardFromPhase,
428
+ editingIndex,
429
+ entries,
430
+ openDraft,
431
+ phase,
432
+ providerItems,
433
+ replaceInput,
434
+ resolveBrowseProvider,
435
+ saveDraft,
436
+ selection.selectedIndex,
437
+ setInput,
438
+ selection.setSelectedIndex,
439
+ ]);
440
+ const requestDelete = useCallback(() => {
441
+ if (phase !== 'list')
442
+ return;
443
+ const item = activeItems[selection.selectedIndex];
444
+ if (item?.kind !== 'entry')
445
+ return;
446
+ setEditingIndex(item.index);
447
+ setPhase('confirm_delete');
448
+ selection.setSelectedIndex(1);
449
+ }, [activeItems, phase, selection.selectedIndex, selection.setSelectedIndex]);
450
+ const saveModel = useCallback((value) => {
451
+ if (phase !== 'edit_model' || !draft)
452
+ return false;
453
+ const model = value.trim();
454
+ if (!model) {
455
+ setFieldErrors({ model: 'Model is required' });
456
+ setErrorMessage('Fix the highlighted fields before saving.');
457
+ return false;
458
+ }
459
+ // Pin the active provider tab with the model so the separate "Select
460
+ // Provider" step is optional (only needed for Inherit).
461
+ setDraft(applyMentorPoolModelPick(draft, model, modelProvider));
462
+ setDraftModified(true);
463
+ setFieldErrors({});
464
+ setErrorMessage(null);
465
+ setBrowsingProvider(null);
466
+ setPhase('edit_fields');
467
+ selection.setSelectedIndex(0);
468
+ setInput('');
469
+ return true;
470
+ }, [draft, modelProvider, phase, setInput, selection.setSelectedIndex]);
471
+ const selectModel = useCallback((typedValue) => saveModel(resolveMentorPoolModelSelection(filteredModels, modelSelectedIndex, typedValue)), [filteredModels, modelSelectedIndex, saveModel]);
472
+ const moveModelUp = useCallback(() => {
473
+ setModelSelectedIndex((index) => filteredModels.length === 0 ? 0 : index > 0 ? index - 1 : filteredModels.length - 1);
474
+ }, [filteredModels.length]);
475
+ const moveModelDown = useCallback(() => {
476
+ setModelSelectedIndex((index) => filteredModels.length === 0 ? 0 : index < filteredModels.length - 1 ? index + 1 : 0);
477
+ }, [filteredModels.length]);
478
+ const moveModelHome = useCallback(() => setModelSelectedIndex(0), []);
479
+ const moveModelEnd = useCallback(() => setModelSelectedIndex(Math.max(0, filteredModels.length - 1)), [filteredModels.length]);
480
+ const pageModelUp = useCallback(() => setModelSelectedIndex((index) => Math.max(0, index - 10)), []);
481
+ const pageModelDown = useCallback(() => setModelSelectedIndex((index) => Math.min(Math.max(0, filteredModels.length - 1), index + 10)), [filteredModels.length]);
482
+ const refreshModels = useCallback(() => {
483
+ if (!modelProvider)
484
+ return;
485
+ catalogSession.refresh(modelProvider);
486
+ setModelRefreshKey((key) => key + 1);
487
+ }, [catalogSession, modelProvider]);
488
+ const toggleModelProvider = useCallback((direction = 'next') => {
489
+ if (phase !== 'edit_model')
490
+ return;
491
+ const next = catalogSession.nextProvider(modelProvider || null, direction);
492
+ if (!next || next === modelProvider)
493
+ return;
494
+ const cachedModels = catalogSession.getCached(next);
495
+ setCatalogModels(cachedModels ?? []);
496
+ setModelSelectedIndex(0);
497
+ setModelScrollOffset(0);
498
+ setModelLoading(!cachedModels);
499
+ setModelError(null);
500
+ setBrowsingProvider(next);
501
+ }, [catalogSession, modelProvider, phase]);
502
+ const movePoolUp = useCallback(() => {
503
+ if (phase !== 'reorder' || selection.selectedIndex <= 0)
504
+ return;
505
+ const index = selection.selectedIndex;
506
+ setReorderList((current) => {
507
+ const next = [...current];
508
+ [next[index - 1], next[index]] = [next[index], next[index - 1]];
509
+ return next;
510
+ });
511
+ selection.moveUp();
512
+ }, [phase, selection, selection.selectedIndex]);
513
+ const movePoolDown = useCallback(() => {
514
+ if (phase !== 'reorder' || selection.selectedIndex >= reorderList.length - 1)
515
+ return;
516
+ const index = selection.selectedIndex;
517
+ setReorderList((current) => {
518
+ const next = [...current];
519
+ [next[index], next[index + 1]] = [next[index + 1], next[index]];
520
+ return next;
521
+ });
522
+ selection.moveDown();
523
+ }, [phase, reorderList.length, selection, selection.selectedIndex]);
524
+ const saveReorder = useCallback(() => {
525
+ if (phase !== 'reorder')
526
+ return;
527
+ setEntries(reorderList.map((entry) => ({ ...entry })));
528
+ setReorderList([]);
529
+ setDraftModified(true);
530
+ setPhase('list');
531
+ selection.setSelectedIndex(0);
532
+ }, [phase, reorderList, selection.setSelectedIndex]);
533
+ const goBack = useCallback(() => {
534
+ setErrorMessage(null);
535
+ setInput('');
536
+ if (phase === 'list')
537
+ return;
538
+ if (phase === 'edit_model' || phase === 'edit_provider' || phase === 'edit_reasoning') {
539
+ // Esc from the initial "add entry → model menu" step cancels the add
540
+ // when nothing has been chosen yet.
541
+ if (phase === 'edit_model' && draft?._isNew && !draft.model && !draftModified) {
542
+ setDraft(null);
543
+ setEditingIndex(null);
544
+ setBrowsingProvider(null);
545
+ setPhase('list');
546
+ selection.setSelectedIndex(0);
547
+ return;
548
+ }
549
+ setBrowsingProvider(null);
550
+ setPhase('edit_fields');
551
+ selection.setSelectedIndex(phase === 'edit_model' ? 0 : phase === 'edit_provider' ? 1 : 2);
552
+ }
553
+ else if (phase === 'edit_fields') {
554
+ if (draftModified) {
555
+ setDiscardFromPhase('edit_fields');
556
+ setPhase('confirm_discard');
557
+ selection.setSelectedIndex(1);
558
+ }
559
+ else {
560
+ setDraft(null);
561
+ setEditingIndex(null);
562
+ setPhase('list');
563
+ selection.setSelectedIndex(0);
564
+ }
565
+ }
566
+ else if (phase === 'reorder') {
567
+ setReorderList([]);
568
+ setPhase('list');
569
+ selection.setSelectedIndex(0);
570
+ }
571
+ else if (phase === 'confirm_delete') {
572
+ setEditingIndex(null);
573
+ setPhase('list');
574
+ selection.setSelectedIndex(0);
575
+ }
576
+ else if (phase === 'confirm_discard') {
577
+ if (discardFromPhase)
578
+ setPhase(discardFromPhase);
579
+ setDiscardFromPhase(null);
580
+ selection.setSelectedIndex(0);
581
+ }
582
+ }, [discardFromPhase, draft, draftModified, phase, setInput, selection.setSelectedIndex]);
583
+ const saveIntent = useCallback((frameId) => {
584
+ const result = mentorPoolSchema.safeParse(entries);
585
+ if (!result.success) {
586
+ setErrorMessage(result.error.issues[0]?.message ?? 'Invalid mentor pool');
587
+ return null;
588
+ }
589
+ const persistence = settingsService.isRuntimeModifiable(SETTING_KEYS.AGENT_MENTOR_POOL) ? 'runtime' : 'restart';
590
+ return {
591
+ stack: { type: 'keep' },
592
+ intent: {
593
+ id: `apply-settings:${frameId}`,
594
+ sourceFrameId: frameId,
595
+ intent: {
596
+ type: 'apply-settings',
597
+ changes: [{ key: SETTING_KEYS.AGENT_MENTOR_POOL, value: result.data, persistence }],
598
+ },
599
+ },
600
+ };
601
+ }, [entries, settingsService]);
602
+ return {
603
+ phase,
604
+ entries,
605
+ draft,
606
+ selectedIndex: selection.selectedIndex,
607
+ activeItems,
608
+ selectedItem: activeItems[selection.selectedIndex],
609
+ getSelectedItem: selection.getSelectedItem,
610
+ errorMessage,
611
+ fieldErrors,
612
+ modelProvider,
613
+ filteredModels,
614
+ modelLoading,
615
+ modelError,
616
+ modelSelectedIndex,
617
+ modelScrollOffset,
618
+ selectItem,
619
+ goBack,
620
+ requestDelete,
621
+ selectModel,
622
+ moveModelUp,
623
+ moveModelDown,
624
+ moveModelHome,
625
+ moveModelEnd,
626
+ pageModelUp,
627
+ pageModelDown,
628
+ refreshModels,
629
+ toggleModelProvider,
630
+ moveUp: selection.moveUp,
631
+ moveDown: selection.moveDown,
632
+ moveHome: selection.moveHome,
633
+ moveEnd: selection.moveEnd,
634
+ pageUp: selection.pageUp,
635
+ pageDown: selection.pageDown,
636
+ movePoolUp,
637
+ movePoolDown,
638
+ saveReorder,
639
+ saveIntent,
640
+ };
641
+ }
642
+ //# sourceMappingURL=use-mentor-pool-selection.js.map