ummaya 0.2.4 → 0.2.5

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 (477) hide show
  1. package/README.md +15 -2
  2. package/bin/ummaya +10 -1
  3. package/npm-shrinkwrap.json +253 -2
  4. package/package.json +5 -1
  5. package/prompts/manifest.yaml +1 -1
  6. package/prompts/system_v1.md +1 -0
  7. package/pyproject.toml +26 -2
  8. package/specs/2803-document-production-hardening/contracts/document-tools.schema.json +1043 -0
  9. package/src/ummaya/_canonical/__init__.py +2 -0
  10. package/src/ummaya/engine/engine.py +29 -132
  11. package/src/ummaya/evidence/__init__.py +21 -2
  12. package/src/ummaya/evidence/dataset_contract.py +193 -0
  13. package/src/ummaya/evidence/document_authoring_cases.py +33 -0
  14. package/src/ummaya/evidence/document_harness.py +313 -0
  15. package/src/ummaya/evidence/document_viewer_ux.py +391 -0
  16. package/src/ummaya/evidence/gates.py +70 -0
  17. package/src/ummaya/evidence/json_types.py +20 -0
  18. package/src/ummaya/evidence/models.py +88 -1
  19. package/src/ummaya/evidence/output_payload.py +89 -0
  20. package/src/ummaya/evidence/payload_documents.py +233 -0
  21. package/src/ummaya/evidence/route_contracts.py +224 -0
  22. package/src/ummaya/evidence/route_helpers.py +150 -0
  23. package/src/ummaya/evidence/runner.py +81 -212
  24. package/src/ummaya/evidence/source_provenance.py +246 -0
  25. package/src/ummaya/evidence/source_provenance_redaction.py +176 -0
  26. package/src/ummaya/evidence/tool_layer.py +39 -0
  27. package/src/ummaya/evidence/tool_layer_models.py +151 -0
  28. package/src/ummaya/ipc/adapter_manifest_emitter.py +26 -10
  29. package/src/ummaya/ipc/document_intent_normalization.py +185 -0
  30. package/src/ummaya/ipc/frame_schema.py +5 -5
  31. package/src/ummaya/ipc/route_diagnostics.py +73 -0
  32. package/src/ummaya/ipc/stdio.py +1109 -477
  33. package/src/ummaya/llm/client.py +102 -3
  34. package/src/ummaya/llm/config.py +8 -3
  35. package/src/ummaya/primitives/__init__.py +6 -2
  36. package/src/ummaya/primitives/delegation.py +1 -1
  37. package/src/ummaya/primitives/document.py +28 -0
  38. package/src/ummaya/settings.py +0 -3
  39. package/src/ummaya/tools/discovery_bridge.py +17 -1
  40. package/src/ummaya/tools/documents/__init__.py +297 -0
  41. package/src/ummaya/tools/documents/adapter_registry.py +487 -0
  42. package/src/ummaya/tools/documents/archive_container_probe.py +167 -0
  43. package/src/ummaya/tools/documents/artifact_store.py +454 -0
  44. package/src/ummaya/tools/documents/authoring.py +283 -0
  45. package/src/ummaya/tools/documents/baselines.py +114 -0
  46. package/src/ummaya/tools/documents/capability.py +331 -0
  47. package/src/ummaya/tools/documents/contracts.py +112 -0
  48. package/src/ummaya/tools/documents/conversion.py +521 -0
  49. package/src/ummaya/tools/documents/diff.py +275 -0
  50. package/src/ummaya/tools/documents/engines.py +163 -0
  51. package/src/ummaya/tools/documents/evaluation.py +291 -0
  52. package/src/ummaya/tools/documents/explicit_values.py +108 -0
  53. package/src/ummaya/tools/documents/fixtures.py +174 -0
  54. package/src/ummaya/tools/documents/format_completion_audit.py +471 -0
  55. package/src/ummaya/tools/documents/formats/__init__.py +2 -0
  56. package/src/ummaya/tools/documents/formats/archive.py +528 -0
  57. package/src/ummaya/tools/documents/formats/base.py +41 -0
  58. package/src/ummaya/tools/documents/formats/code_file.py +211 -0
  59. package/src/ummaya/tools/documents/formats/data_file.py +272 -0
  60. package/src/ummaya/tools/documents/formats/hwp.py +284 -0
  61. package/src/ummaya/tools/documents/formats/hwpx.py +1837 -0
  62. package/src/ummaya/tools/documents/formats/odf.py +435 -0
  63. package/src/ummaya/tools/documents/formats/ooxml.py +1030 -0
  64. package/src/ummaya/tools/documents/formats/passive.py +766 -0
  65. package/src/ummaya/tools/documents/formats/pdf.py +702 -0
  66. package/src/ummaya/tools/documents/formats/text_web.py +268 -0
  67. package/src/ummaya/tools/documents/hwp_conversion_probe.py +178 -0
  68. package/src/ummaya/tools/documents/hwp_direct_candidate.py +141 -0
  69. package/src/ummaya/tools/documents/inspection.py +289 -0
  70. package/src/ummaya/tools/documents/intake.py +1079 -0
  71. package/src/ummaya/tools/documents/legacy_office_promotion_probe.py +366 -0
  72. package/src/ummaya/tools/documents/models.py +1598 -0
  73. package/src/ummaya/tools/documents/odf_promotion_probe.py +167 -0
  74. package/src/ummaya/tools/documents/orchestrator.py +96 -0
  75. package/src/ummaya/tools/documents/passive_capability_probe.py +251 -0
  76. package/src/ummaya/tools/documents/patch.py +170 -0
  77. package/src/ummaya/tools/documents/pdfa_conformance.py +284 -0
  78. package/src/ummaya/tools/documents/pdfa_promotion_probe.py +198 -0
  79. package/src/ummaya/tools/documents/permissions.py +110 -0
  80. package/src/ummaya/tools/documents/planner.py +616 -0
  81. package/src/ummaya/tools/documents/registry.py +2733 -0
  82. package/src/ummaya/tools/documents/render.py +978 -0
  83. package/src/ummaya/tools/documents/render_comparison.py +113 -0
  84. package/src/ummaya/tools/documents/render_comparison_models.py +74 -0
  85. package/src/ummaya/tools/documents/render_comparison_regions.py +73 -0
  86. package/src/ummaya/tools/documents/render_comparison_style.py +161 -0
  87. package/src/ummaya/tools/documents/reread.py +157 -0
  88. package/src/ummaya/tools/documents/runtime_authoring.py +244 -0
  89. package/src/ummaya/tools/documents/runtime_authoring_bundle.py +76 -0
  90. package/src/ummaya/tools/documents/scorecard.py +184 -0
  91. package/src/ummaya/tools/documents/socratic_planner.py +193 -0
  92. package/src/ummaya/tools/documents/style.py +48 -0
  93. package/src/ummaya/tools/documents/tool_defs.py +523 -0
  94. package/src/ummaya/tools/documents/validate.py +347 -0
  95. package/src/ummaya/tools/executor.py +29 -0
  96. package/src/ummaya/tools/live_proxy.py +0 -3
  97. package/src/ummaya/tools/models.py +5 -1
  98. package/src/ummaya/tools/register_all.py +8 -0
  99. package/src/ummaya/tools/registry.py +10 -1
  100. package/src/ummaya/tools/routing/__init__.py +59 -0
  101. package/src/ummaya/tools/routing/builder.py +105 -0
  102. package/src/ummaya/tools/routing/cards.py +29 -0
  103. package/src/ummaya/tools/routing/decision_service.py +534 -0
  104. package/src/ummaya/tools/routing/decision_types.py +74 -0
  105. package/src/ummaya/tools/routing/feasibility.py +122 -0
  106. package/src/ummaya/tools/routing/intent.py +17 -0
  107. package/src/ummaya/tools/routing/intent_extractor.py +207 -0
  108. package/src/ummaya/tools/routing/intent_patterns.py +160 -0
  109. package/src/ummaya/tools/routing/intent_public_data.py +150 -0
  110. package/src/ummaya/tools/routing/intent_types.py +48 -0
  111. package/src/ummaya/tools/routing/lint.py +78 -0
  112. package/src/ummaya/tools/routing/metadata.py +174 -0
  113. package/src/ummaya/tools/routing/projection.py +340 -0
  114. package/src/ummaya/tools/routing/retrieval_policy.py +629 -0
  115. package/src/ummaya/tools/routing/schema.py +81 -0
  116. package/src/ummaya/tools/routing/types.py +96 -0
  117. package/src/ummaya/tools/routing_index.py +2 -2
  118. package/src/ummaya/tools/search.py +34 -746
  119. package/tests/fixtures/documents/public_forms/baselines.yaml +113 -0
  120. package/tui/package.json +1 -1
  121. package/tui/src/.cc-byte-identical-whitelist.yaml +266 -0
  122. package/tui/src/QueryEngine.ts +12 -8
  123. package/tui/src/bridge/inboundAttachments.ts +3 -3
  124. package/tui/src/cli/handlers/auth.ts +3 -12
  125. package/tui/src/cli/print.ts +7 -7
  126. package/tui/src/commands/insights.ts +1 -1
  127. package/tui/src/commands/install-github-app/types.ts +8 -30
  128. package/tui/src/commands/plugin/types.ts +6 -28
  129. package/tui/src/commands/plugin/unifiedTypes.ts +4 -26
  130. package/tui/src/commands/rename/generateSessionName.ts +1 -1
  131. package/tui/src/components/Feedback.tsx +1 -1
  132. package/tui/src/components/LogoV2/EmergencyTip.tsx +11 -2
  133. package/tui/src/components/LogoV2/WelcomeV2.tsx +1 -3
  134. package/tui/src/components/ScrollKeybindingHandler.tsx +6 -6
  135. package/tui/src/components/Spinner/types.ts +6 -28
  136. package/tui/src/components/agents/generateAgent.ts +1 -1
  137. package/tui/src/components/agents/new-agent-creation/types.ts +4 -26
  138. package/tui/src/components/config/EnvSecretIsolatedEditor.tsx +1 -1
  139. package/tui/src/components/mcp/types.ts +16 -38
  140. package/tui/src/components/messages/AssistantToolUseMessage.tsx +3 -2
  141. package/tui/src/components/messages/UserCrossSessionMessage.ts +16 -4
  142. package/tui/src/components/messages/UserForkBoilerplateMessage.ts +16 -4
  143. package/tui/src/components/messages/UserGitHubWebhookMessage.ts +16 -4
  144. package/tui/src/components/messages/UserToolResultMessage/utils.tsx +3 -2
  145. package/tui/src/components/permissions/MonitorPermissionRequest/MonitorPermissionRequest.ts +9 -4
  146. package/tui/src/components/permissions/ReviewArtifactPermissionRequest/ReviewArtifactPermissionRequest.ts +9 -4
  147. package/tui/src/components/primitive/DocumentSocraticReviewBlock.tsx +129 -0
  148. package/tui/src/components/primitive/DocumentToolResultCard.tsx +224 -0
  149. package/tui/src/components/primitive/documentSocraticReview.ts +215 -0
  150. package/tui/src/components/primitive/index.tsx +43 -1
  151. package/tui/src/components/primitive/types.ts +137 -0
  152. package/tui/src/components/ui/option.ts +4 -26
  153. package/tui/src/constants/common.ts +0 -2
  154. package/tui/src/constants/prompts.ts +4 -3
  155. package/tui/src/constants/querySource.ts +4 -26
  156. package/tui/src/entrypoints/sdk/controlTypes.ts +26 -48
  157. package/tui/src/entrypoints/sdk/coreTypes.generated.ts +3 -25
  158. package/tui/src/entrypoints/sdk/runtimeTypes.ts +38 -60
  159. package/tui/src/entrypoints/sdk/sdkUtilityTypes.ts +4 -26
  160. package/tui/src/entrypoints/sdk/settingsTypes.generated.ts +3 -25
  161. package/tui/src/entrypoints/sdk/toolTypes.ts +3 -25
  162. package/tui/src/hooks/toolPermission/handlers/interactiveHandler.ts +10 -0
  163. package/tui/src/hooks/useApiKeyVerification.ts +1 -1
  164. package/tui/src/hooks/useVirtualScroll.ts +1 -1
  165. package/tui/src/ink/ink.tsx +33 -14
  166. package/tui/src/ink/reconciler.ts +2 -3
  167. package/tui/src/ink/render-to-screen.ts +30 -10
  168. package/tui/src/ipc/bridge.ts +62 -15
  169. package/tui/src/ipc/bridgeSingleton.ts +5 -1
  170. package/tui/src/ipc/codec.ts +3 -3
  171. package/tui/src/ipc/frames.generated.ts +12 -12
  172. package/tui/src/ipc/llmClient.ts +151 -27
  173. package/tui/src/ipc/schema/frame.schema.json +1 -1
  174. package/tui/src/keybindings/defaultBindings.ts +4 -0
  175. package/tui/src/main.tsx +29 -11
  176. package/tui/src/native-ts/file-index/index.ts +33 -3
  177. package/tui/src/observability/surface.ts +2 -2
  178. package/tui/src/probes/toolRegistryProbe.tsx +3 -1
  179. package/tui/src/projectOnboardingState.ts +7 -6
  180. package/tui/src/query/chatMessageTypes.ts +18 -0
  181. package/tui/src/query/chatMessagesBuilder.ts +1 -1
  182. package/tui/src/query/deps.ts +1 -1
  183. package/tui/src/query/messageGuards.ts +106 -0
  184. package/tui/src/query/publicDataTerminalRepair.ts +384 -0
  185. package/tui/src/query/run.ts +1075 -0
  186. package/tui/src/query/supportBoundary.ts +168 -0
  187. package/tui/src/query/toolResultErrors.ts +103 -0
  188. package/tui/src/query/toolRunner.ts +687 -0
  189. package/tui/src/query/unavailableToolRepair.ts +118 -0
  190. package/tui/src/query.ts +9 -2186
  191. package/tui/src/screens/REPL.tsx +40 -29
  192. package/tui/src/services/api/adapterManifest.ts +4 -0
  193. package/tui/src/services/api/backendChat/events.ts +117 -0
  194. package/tui/src/services/api/backendChat/finalMessage.ts +40 -0
  195. package/tui/src/services/api/backendChat/frame.ts +9 -0
  196. package/tui/src/services/api/backendChat/streaming.ts +430 -0
  197. package/tui/src/services/api/backendChat/types.ts +62 -0
  198. package/tui/src/services/api/backendChat.ts +1 -0
  199. package/tui/src/services/api/client.ts +65 -2
  200. package/tui/src/services/api/errorUtils.ts +5 -5
  201. package/tui/src/services/api/errors.ts +1 -1
  202. package/tui/src/services/api/logging.ts +1 -1
  203. package/tui/src/services/api/ummaya/evidence.ts +194 -0
  204. package/tui/src/services/api/ummaya/messages.ts +255 -0
  205. package/tui/src/services/api/ummaya/nonStreaming.ts +66 -0
  206. package/tui/src/services/api/ummaya/provider.ts +200 -0
  207. package/tui/src/services/api/ummaya/reasoning.ts +24 -0
  208. package/tui/src/services/api/ummaya/request.ts +200 -0
  209. package/tui/src/services/api/ummaya/selectionContext.ts +240 -0
  210. package/tui/src/services/api/ummaya/streaming.ts +365 -0
  211. package/tui/src/services/api/ummaya/streamingPayload.ts +129 -0
  212. package/tui/src/services/api/ummaya/streamingReader.ts +40 -0
  213. package/tui/src/services/api/ummaya/toolSelection.ts +217 -0
  214. package/tui/src/services/api/ummaya/types.ts +110 -0
  215. package/tui/src/services/api/ummaya/usage.ts +30 -0
  216. package/tui/src/services/api/ummaya.ts +26 -418
  217. package/tui/src/services/api/withRetry.ts +1 -1
  218. package/tui/src/services/awaySummary.ts +2 -2
  219. package/tui/src/services/claudeAiLimits.ts +1 -1
  220. package/tui/src/services/compact/autoCompact.ts +1 -1
  221. package/tui/src/services/compact/compact.ts +1 -1
  222. package/tui/src/services/lsp/types.ts +8 -30
  223. package/tui/src/services/tips/types.ts +6 -28
  224. package/tui/src/services/tokenEstimation.ts +1 -1
  225. package/tui/src/services/toolRegistry/bootGuard.ts +5 -5
  226. package/tui/src/services/toolUseSummary/toolUseSummaryGenerator.ts +1 -1
  227. package/tui/src/services/tools/toolExecution.ts +94 -1
  228. package/tui/src/store/pendingPermissionSlot.ts +1 -1
  229. package/tui/src/store/session-store.ts +10 -36
  230. package/tui/src/stubs/any-stub.ts +15 -10
  231. package/tui/src/stubs/color-diff-napi.ts +37 -23
  232. package/tui/src/stubs/globals.d.ts +3 -3
  233. package/tui/src/stubs/macro-preload.ts +23 -12
  234. package/tui/src/tools/AdapterTool/AdapterTool.ts +1207 -714
  235. package/tui/src/tools/AdapterTool/routeDiagnostics.ts +75 -0
  236. package/tui/src/tools/AgentTool/AgentTool.tsx +84 -1371
  237. package/tui/src/tools/AgentTool/agentToolHandoff.ts +114 -0
  238. package/tui/src/tools/AgentTool/agentToolPartialResult.ts +16 -0
  239. package/tui/src/tools/AgentTool/agentToolProgress.ts +32 -0
  240. package/tui/src/tools/AgentTool/agentToolResolver.ts +161 -0
  241. package/tui/src/tools/AgentTool/agentToolResult.ts +163 -0
  242. package/tui/src/tools/AgentTool/agentToolUtils.ts +14 -686
  243. package/tui/src/tools/AgentTool/asyncAgentLifecycle.ts +208 -0
  244. package/tui/src/tools/AgentTool/asyncLifecycle.ts +153 -0
  245. package/tui/src/tools/AgentTool/backgroundedCompletion.ts +126 -0
  246. package/tui/src/tools/AgentTool/backgroundedLifecycle.ts +174 -0
  247. package/tui/src/tools/AgentTool/foregroundBackground.ts +83 -0
  248. package/tui/src/tools/AgentTool/foregroundDrain.tsx +133 -0
  249. package/tui/src/tools/AgentTool/foregroundFinalize.ts +98 -0
  250. package/tui/src/tools/AgentTool/foregroundLifecycle.tsx +237 -0
  251. package/tui/src/tools/AgentTool/foregroundProgress.tsx +169 -0
  252. package/tui/src/tools/AgentTool/foregroundTask.ts +89 -0
  253. package/tui/src/tools/AgentTool/forkSubagent.ts +1 -12
  254. package/tui/src/tools/AgentTool/forkSubagentGate.ts +34 -0
  255. package/tui/src/tools/AgentTool/launchRouting.ts +203 -0
  256. package/tui/src/tools/AgentTool/lifecycle.ts +244 -0
  257. package/tui/src/tools/AgentTool/mcpRouting.ts +73 -0
  258. package/tui/src/tools/AgentTool/orchestrationSupport.ts +70 -0
  259. package/tui/src/tools/AgentTool/permissions.ts +39 -0
  260. package/tui/src/tools/AgentTool/promptSetup.ts +181 -0
  261. package/tui/src/tools/AgentTool/remoteRouting.ts +62 -0
  262. package/tui/src/tools/AgentTool/resultMapping.ts +116 -0
  263. package/tui/src/tools/AgentTool/resumeAgent.ts +39 -107
  264. package/tui/src/tools/AgentTool/resumeAgentHelpers.ts +140 -0
  265. package/tui/src/tools/AgentTool/runAgent.ts +1 -1
  266. package/tui/src/tools/AgentTool/runtimeConfig.ts +57 -0
  267. package/tui/src/tools/AgentTool/schemas.ts +196 -0
  268. package/tui/src/tools/AgentTool/sourceVerificationPropagation.ts +263 -0
  269. package/tui/src/tools/AgentTool/worktreeLifecycle.ts +105 -0
  270. package/tui/src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx +174 -202
  271. package/tui/src/tools/BashTool/BashTool.tsx +71 -1072
  272. package/tui/src/tools/BashTool/bashCommandHelpers.ts +12 -12
  273. package/tui/src/tools/BashTool/bashPermissions/astPreflight.ts +173 -0
  274. package/tui/src/tools/BashTool/bashPermissions/classifierChecks.ts +199 -0
  275. package/tui/src/tools/BashTool/bashPermissions/compoundGuards.ts +53 -0
  276. package/tui/src/tools/BashTool/bashPermissions/constants.ts +99 -0
  277. package/tui/src/tools/BashTool/bashPermissions/index.ts +38 -0
  278. package/tui/src/tools/BashTool/bashPermissions/legacyMisparsing.ts +62 -0
  279. package/tui/src/tools/BashTool/bashPermissions/main.ts +135 -0
  280. package/tui/src/tools/BashTool/bashPermissions/normalizedCommands.ts +33 -0
  281. package/tui/src/tools/BashTool/bashPermissions/operatorFlow.ts +98 -0
  282. package/tui/src/tools/BashTool/bashPermissions/permissionChecks.ts +200 -0
  283. package/tui/src/tools/BashTool/bashPermissions/prefixSuggestions.ts +88 -0
  284. package/tui/src/tools/BashTool/bashPermissions/promptClassifierRules.ts +125 -0
  285. package/tui/src/tools/BashTool/bashPermissions/ruleDelegates.ts +19 -0
  286. package/tui/src/tools/BashTool/bashPermissions/ruleMatching.ts +145 -0
  287. package/tui/src/tools/BashTool/bashPermissions/sandboxAutoAllow.ts +75 -0
  288. package/tui/src/tools/BashTool/bashPermissions/subcommandFlow.ts +205 -0
  289. package/tui/src/tools/BashTool/bashPermissions/subcommandGuards.ts +73 -0
  290. package/tui/src/tools/BashTool/bashPermissions/subcommandResultHelpers.ts +116 -0
  291. package/tui/src/tools/BashTool/bashPermissions/types.ts +26 -0
  292. package/tui/src/tools/BashTool/bashPermissions/wrapperStripping.ts +139 -0
  293. package/tui/src/tools/BashTool/bashPermissions.ts +26 -2621
  294. package/tui/src/tools/BashTool/call.ts +202 -0
  295. package/tui/src/tools/BashTool/callLoader.ts +35 -0
  296. package/tui/src/tools/BashTool/commandClassification.ts +151 -0
  297. package/tui/src/tools/BashTool/commandClassificationLoader.ts +40 -0
  298. package/tui/src/tools/BashTool/cwdReset.ts +33 -0
  299. package/tui/src/tools/BashTool/lineTruncation.ts +11 -0
  300. package/tui/src/tools/BashTool/modeValidation.ts +13 -1
  301. package/tui/src/tools/BashTool/outputPersistence.ts +42 -0
  302. package/tui/src/tools/BashTool/permissionClassification.ts +66 -0
  303. package/tui/src/tools/BashTool/permissionLoader.ts +44 -0
  304. package/tui/src/tools/BashTool/resultLoader.ts +29 -0
  305. package/tui/src/tools/BashTool/resultMapping.ts +83 -0
  306. package/tui/src/tools/BashTool/sandboxPolicy.ts +79 -0
  307. package/tui/src/tools/BashTool/schemas.ts +65 -0
  308. package/tui/src/tools/BashTool/sedEditExecution.ts +59 -0
  309. package/tui/src/tools/BashTool/shellExecution.tsx +245 -0
  310. package/tui/src/tools/BashTool/shellOutputUtils.ts +85 -0
  311. package/tui/src/tools/BashTool/shellPermissionGauntlet.ts +97 -0
  312. package/tui/src/tools/BashTool/uiLoader.ts +37 -0
  313. package/tui/src/tools/BriefTool/upload.ts +1 -1
  314. package/tui/src/tools/CalculatorTool/parser.ts +2 -2
  315. package/tui/src/tools/DocumentPrimitive/DocumentPrimitive.ts +262 -0
  316. package/tui/src/tools/DocumentPrimitive/dispatchNormalization.ts +270 -0
  317. package/tui/src/tools/DocumentPrimitive/documentDestinationPath.ts +18 -0
  318. package/tui/src/tools/DocumentPrimitive/documentMutationGuard.ts +22 -0
  319. package/tui/src/tools/DocumentPrimitive/documentPatchNormalization.ts +248 -0
  320. package/tui/src/tools/DocumentPrimitive/documentSourceVerification.ts +245 -0
  321. package/tui/src/tools/DocumentPrimitive/documentSourceVerificationFields.ts +103 -0
  322. package/tui/src/tools/DocumentPrimitive/modelVisibleOutput.ts +40 -0
  323. package/tui/src/tools/DocumentPrimitive/prompt.ts +35 -0
  324. package/tui/src/tools/FileEditTool/FileEditTool.ts +9 -507
  325. package/tui/src/tools/FileEditTool/call.ts +228 -0
  326. package/tui/src/tools/FileEditTool/validateInput.ts +196 -0
  327. package/tui/src/tools/FileReadTool/imageProcessor.ts +13 -0
  328. package/tui/src/tools/FileWriteTool/FileWriteTool.ts +7 -300
  329. package/tui/src/tools/FileWriteTool/call.ts +223 -0
  330. package/tui/src/tools/FileWriteTool/validateInput.ts +80 -0
  331. package/tui/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts +19 -3
  332. package/tui/src/tools/LookupPrimitive/LookupPrimitive.ts +25 -32
  333. package/tui/src/tools/LookupPrimitive/prompt.ts +0 -2
  334. package/tui/src/tools/MCPTool/trustPolicy.ts +118 -0
  335. package/tui/src/tools/McpAuthTool/McpAuthTool.ts +21 -3
  336. package/tui/src/tools/NotebookEditTool/NotebookEditTool.ts +7 -326
  337. package/tui/src/tools/NotebookEditTool/call.ts +254 -0
  338. package/tui/src/tools/NotebookEditTool/notebookModel.ts +51 -0
  339. package/tui/src/tools/NotebookEditTool/validateInput.ts +142 -0
  340. package/tui/src/tools/PowerShellTool/PowerShellTool.tsx +46 -937
  341. package/tui/src/tools/PowerShellTool/acceptEditsCommandValidation.ts +162 -0
  342. package/tui/src/tools/PowerShellTool/call.ts +179 -0
  343. package/tui/src/tools/PowerShellTool/callLoader.ts +37 -0
  344. package/tui/src/tools/PowerShellTool/commandClassification.ts +86 -0
  345. package/tui/src/tools/PowerShellTool/modeValidation.ts +25 -332
  346. package/tui/src/tools/PowerShellTool/outputPersistence.ts +42 -0
  347. package/tui/src/tools/PowerShellTool/permissionClassification.ts +28 -0
  348. package/tui/src/tools/PowerShellTool/resultLoader.ts +31 -0
  349. package/tui/src/tools/PowerShellTool/resultMapping.ts +75 -0
  350. package/tui/src/tools/PowerShellTool/schemas.ts +40 -0
  351. package/tui/src/tools/PowerShellTool/shellExecution.tsx +258 -0
  352. package/tui/src/tools/PowerShellTool/symlinkModeValidation.ts +44 -0
  353. package/tui/src/tools/PowerShellTool/uiLoader.ts +37 -0
  354. package/tui/src/tools/PowerShellTool/validation.ts +39 -0
  355. package/tui/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts +19 -3
  356. package/tui/src/tools/ResolveLocationPrimitive/ResolveLocationPrimitive.ts +1 -11
  357. package/tui/src/tools/ResolveLocationPrimitive/prompt.ts +2 -6
  358. package/tui/src/tools/SkillTool/SkillTool.ts +2 -2
  359. package/tui/src/tools/SubmitPrimitive/SubmitPrimitive.ts +27 -10
  360. package/tui/src/tools/TaskCreateTool/TaskCreateTool.ts +16 -2
  361. package/tui/src/tools/TaskGetTool/TaskGetTool.ts +23 -3
  362. package/tui/src/tools/TaskListTool/TaskListTool.ts +22 -4
  363. package/tui/src/tools/TaskOutputTool/TaskOutputTool.tsx +46 -547
  364. package/tui/src/tools/TaskOutputTool/lookup.ts +216 -0
  365. package/tui/src/tools/TaskOutputTool/render.tsx +257 -0
  366. package/tui/src/tools/TaskOutputTool/schemas.ts +55 -0
  367. package/tui/src/tools/TaskOutputTool/serialization.ts +36 -0
  368. package/tui/src/tools/TaskStopTool/TaskStopTool.ts +10 -0
  369. package/tui/src/tools/TaskUpdateTool/TaskUpdateTool.ts +14 -364
  370. package/tui/src/tools/TaskUpdateTool/completion.ts +62 -0
  371. package/tui/src/tools/TaskUpdateTool/schemas.ts +62 -0
  372. package/tui/src/tools/TaskUpdateTool/serialization.ts +46 -0
  373. package/tui/src/tools/TaskUpdateTool/statusUpdate.ts +247 -0
  374. package/tui/src/tools/TodoWriteTool/TodoWriteTool.ts +21 -2
  375. package/tui/src/tools/ToolSearchTool/ToolSearchTool.ts +21 -302
  376. package/tui/src/tools/ToolSearchTool/ccSupportTools.ts +223 -0
  377. package/tui/src/tools/ToolSearchTool/descriptionCache.ts +50 -0
  378. package/tui/src/tools/ToolSearchTool/keywordSearch.ts +216 -0
  379. package/tui/src/tools/ToolSearchTool/prompt.ts +10 -4
  380. package/tui/src/tools/ToolSearchTool/resultMapping.ts +30 -0
  381. package/tui/src/tools/ToolSearchTool/schemas.ts +30 -0
  382. package/tui/src/tools/ToolSearchTool/searchPool.ts +47 -0
  383. package/tui/src/tools/ToolSearchTool/supportIntentHints.ts +140 -0
  384. package/tui/src/tools/TranslateTool/TranslateTool.ts +1 -1
  385. package/tui/src/tools/VerifyPrimitive/VerifyPrimitive.ts +2 -1
  386. package/tui/src/tools/WebFetchTool/WebFetchTool.ts +43 -138
  387. package/tui/src/tools/WebFetchTool/call.ts +227 -0
  388. package/tui/src/tools/WebFetchTool/resolvedAddressSafety.ts +78 -0
  389. package/tui/src/tools/WebFetchTool/sourceVerification.ts +204 -0
  390. package/tui/src/tools/WebFetchTool/types.ts +23 -0
  391. package/tui/src/tools/WebFetchTool/urlSafety.ts +181 -0
  392. package/tui/src/tools/WebFetchTool/utils.ts +1 -1
  393. package/tui/src/tools/WebSearchTool/UI.tsx +0 -1
  394. package/tui/src/tools/WebSearchTool/WebSearchTool.ts +9 -313
  395. package/tui/src/tools/WebSearchTool/call.ts +33 -0
  396. package/tui/src/tools/WebSearchTool/responseMapping.ts +190 -0
  397. package/tui/src/tools/WebSearchTool/resultBlock.ts +47 -0
  398. package/tui/src/tools/WebSearchTool/schemas.ts +47 -0
  399. package/tui/src/tools/WebSearchTool/toolSchema.ts +12 -0
  400. package/tui/src/tools/WorkspaceToolAdapter/WorkspaceToolAdapter.ts +79 -0
  401. package/tui/src/tools/WorkspaceToolAdapter/allowedRootPolicy.ts +85 -0
  402. package/tui/src/tools/WorkspaceToolAdapter/documentFormatGuards.ts +73 -0
  403. package/tui/src/tools/WorkspaceToolAdapter/inputNormalization.ts +105 -0
  404. package/tui/src/tools/WorkspaceToolAdapter/mcpExposurePolicy.ts +64 -0
  405. package/tui/src/tools/WorkspaceToolAdapter/toolDefFactory.ts +215 -0
  406. package/tui/src/tools/WorkspaceToolAdapter/toolNames.ts +6 -0
  407. package/tui/src/tools/WorkspaceToolAdapter/workspacePolicy.ts +15 -0
  408. package/tui/src/tools/_shared/dispatchPrimitive.ts +6 -6
  409. package/tui/src/tools/_shared/documentChangeToPatch.ts +125 -0
  410. package/tui/src/tools/_shared/documentDispatchArguments.ts +87 -0
  411. package/tui/src/tools/_shared/documentPrimitiveTimeout.ts +13 -0
  412. package/tui/src/tools/_shared/documentToolResultRender.ts +98 -0
  413. package/tui/src/tools/_shared/pendingCallRegistry.ts +1 -6
  414. package/tui/src/tools/_shared/rootPrimitiveInput.ts +1 -0
  415. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPatterns.ts +58 -0
  416. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPrompt.ts +271 -0
  417. package/tui/src/tools/_shared/toolChoiceRepair/documentRepair.ts +452 -0
  418. package/tui/src/tools/_shared/toolChoiceRepair/messageAccess.ts +80 -0
  419. package/tui/src/tools/_shared/toolChoiceRepair/publicDataRepair.ts +92 -0
  420. package/tui/src/tools/_shared/toolChoiceRepair/supportRepair.ts +135 -0
  421. package/tui/src/tools/_shared/toolChoiceRepair.ts +55 -860
  422. package/tui/src/tools/shared/mockDisclaimer.ts +1 -1
  423. package/tui/src/tools.ts +39 -190
  424. package/tui/src/types/fileSuggestion.ts +4 -26
  425. package/tui/src/types/generated/events_mono/claude_code/v1/claude_code_internal_event.ts +186 -148
  426. package/tui/src/types/generated/events_mono/common/v1/auth.ts +25 -11
  427. package/tui/src/types/generated/events_mono/growthbook/v1/growthbook_experiment_event.ts +47 -30
  428. package/tui/src/types/generated/google/protobuf/timestamp.ts +21 -7
  429. package/tui/src/types/message.ts +80 -102
  430. package/tui/src/types/messageQueueTypes.ts +6 -28
  431. package/tui/src/types/notebook.ts +16 -38
  432. package/tui/src/types/statusLine.ts +4 -26
  433. package/tui/src/types/tools.ts +24 -46
  434. package/tui/src/types/utils.ts +6 -28
  435. package/tui/src/upstreamproxy/relay.ts +7 -3
  436. package/tui/src/upstreamproxy/upstreamproxy.ts +1 -1
  437. package/tui/src/utils/assistantMessageFactories.ts +9 -3
  438. package/tui/src/utils/auth.ts +129 -139
  439. package/tui/src/utils/bash/ast.ts +23 -23
  440. package/tui/src/utils/bash/bashParser.ts +5 -5
  441. package/tui/src/utils/billing.ts +1 -1
  442. package/tui/src/utils/collapseReadSearch.ts +3 -3
  443. package/tui/src/utils/cronTasks.ts +1 -1
  444. package/tui/src/utils/execFileNoThrow.ts +1 -1
  445. package/tui/src/utils/filePersistence/types.ts +16 -38
  446. package/tui/src/utils/forkedAgent.ts +1 -1
  447. package/tui/src/utils/gracefulShutdown.ts +4 -4
  448. package/tui/src/utils/heapDumpService.ts +12 -8
  449. package/tui/src/utils/hooks/apiQueryHookHelper.ts +1 -1
  450. package/tui/src/utils/hooks/execPromptHook.ts +1 -1
  451. package/tui/src/utils/hooks/skillImprovement.ts +1 -1
  452. package/tui/src/utils/mcp/dateTimeParser.ts +1 -1
  453. package/tui/src/utils/messages.ts +18 -0
  454. package/tui/src/utils/migrateSessions.ts +3 -3
  455. package/tui/src/utils/model/model.ts +6 -6
  456. package/tui/src/utils/permissions/yoloClassifier.ts +1 -1
  457. package/tui/src/utils/plugins/headlessPluginInstall.ts +1 -1
  458. package/tui/src/utils/plugins/mcpPluginIntegration.ts +1 -1
  459. package/tui/src/utils/plugins/mcpbHandler.ts +1 -1
  460. package/tui/src/utils/plugins/pluginLoader.ts +8 -8
  461. package/tui/src/utils/protectedNamespace.ts +5 -3
  462. package/tui/src/utils/rawJsonToolCall.ts +242 -0
  463. package/tui/src/utils/ripgrep.ts +16 -7
  464. package/tui/src/utils/sessionTitle.ts +1 -1
  465. package/tui/src/utils/settings/permissionValidation.ts +14 -2
  466. package/tui/src/utils/shell/prefix.ts +1 -1
  467. package/tui/src/utils/sideQuery.ts +1 -1
  468. package/tui/src/utils/systemThemeWatcher.ts +13 -3
  469. package/tui/src/utils/teleport.tsx +1 -1
  470. package/uv.lock +400 -14
  471. package/tui/src/services/api/claude.ts +0 -3540
  472. package/tui/src/tools/_shared/directPublicDataGuard.ts +0 -362
  473. package/tui/src/tools/_shared/kmaAnalysisGuard.ts +0 -197
  474. package/tui/src/tools/_shared/kmaAviationGuard.ts +0 -70
  475. package/tui/src/tools/_shared/nmcAedGuard.ts +0 -234
  476. package/tui/src/tools/_shared/protectedCheckGuard.ts +0 -207
  477. package/tui/src/tools/_shared/textToolCallGuard.ts +0 -91
@@ -0,0 +1,365 @@
1
+ import {
2
+ createAssistantAPIErrorMessage,
3
+ createAssistantMessage,
4
+ } from '../../../utils/messages.js'
5
+ import { logError } from '../../../utils/log.js'
6
+ import {
7
+ classifyRawJsonToolCallProposal,
8
+ extractTextualToolCallProposals,
9
+ parseTrailingRawJsonToolCallProposal,
10
+ RAW_JSON_REGISTERED_TOOL_USE_ID_PREFIX,
11
+ RAW_JSON_UNREGISTERED_TOOL_USE_ID_PREFIX,
12
+ textContainsMalformedToolCallProposal,
13
+ } from '../../../utils/rawJsonToolCall.js'
14
+ import type { RawJsonToolCallProposal } from '../../../utils/rawJsonToolCall.js'
15
+ import type { Message, StreamEvent } from '../../../types/message.js'
16
+ import type { OpenAIToolCall } from './types.js'
17
+ import {
18
+ cancelReader,
19
+ dataIdleDeadline,
20
+ dataIdleTimeoutRemaining,
21
+ readNextStreamChunk,
22
+ } from './streamingReader.js'
23
+ import {
24
+ chunkFromPayload,
25
+ completedToolCalls,
26
+ parseJsonLine,
27
+ parseToolArguments,
28
+ providerFailureMessage,
29
+ } from './streamingPayload.js'
30
+
31
+ const PROVIDER_EMPTY_COMPLETION_HANDOFF =
32
+ 'K-EXAONE 응답이 비어 있어 이번 요청을 이어갈 수 없습니다. 잠시 후 다시 시도해 주세요.'
33
+ const PROVIDER_MALFORMED_TOOL_CALL_HANDOFF =
34
+ 'K-EXAONE emitted malformed tool-call JSON. Retry with a registered tool call instead of raw JSON prose.'
35
+ const TEXTUAL_TOOL_CALL_OPEN = '<tool_call>'
36
+
37
+ export type StreamResponseOptions = {
38
+ readonly dataIdleTimeoutMs?: number
39
+ readonly availableToolNames?: readonly string[]
40
+ readonly includeReasoning?: boolean
41
+ }
42
+
43
+ type ToolCallState = {
44
+ id?: string
45
+ name?: string
46
+ arguments: string
47
+ }
48
+
49
+ export class ProviderStreamIdleTimeoutError extends Error {
50
+ constructor(timeoutMs: number) {
51
+ super(`FriendliAI SSE data idle timeout after ${timeoutMs}ms`)
52
+ this.name = 'ProviderStreamIdleTimeoutError'
53
+ }
54
+ }
55
+
56
+ export async function* streamResponseToMessages(
57
+ response: Response,
58
+ options: StreamResponseOptions = {},
59
+ ): AsyncGenerator<StreamEvent | Message> {
60
+ yield streamEvent({ type: 'message_start' })
61
+ let text = ''
62
+ let thinking = ''
63
+ let thinkingBlockStarted = false
64
+ let shouldBufferTextDeltas = false
65
+ let emittedTextLength = 0
66
+ let sawTextDelta = false
67
+ const toolCallStates = new Map<number, ToolCallState>()
68
+ if (!response.ok) {
69
+ const body = await response.text()
70
+ const message = providerFailureMessage(response, body)
71
+ logError(new Error(message))
72
+ yield createAssistantAPIErrorMessage({
73
+ content: message,
74
+ apiError: 'api_error',
75
+ })
76
+ return
77
+ }
78
+ if (response.body === null) {
79
+ const message =
80
+ 'FriendliAI response did not include a stream body. Check provider configuration and retry.'
81
+ logError(new Error(message))
82
+ yield createAssistantAPIErrorMessage({
83
+ content: message,
84
+ apiError: 'api_error',
85
+ })
86
+ return
87
+ }
88
+ let sawStreamData = false
89
+ const reader = response.body.getReader()
90
+ const decoder = new TextDecoder()
91
+ let buffer = ''
92
+ let streamDone = false
93
+ let nextDataDeadline = dataIdleDeadline(options.dataIdleTimeoutMs)
94
+ while (!streamDone) {
95
+ const timeoutMs = dataIdleTimeoutRemaining(
96
+ options.dataIdleTimeoutMs,
97
+ nextDataDeadline,
98
+ )
99
+ const read = await readNextStreamChunk(reader, timeoutMs)
100
+ if (read === 'timeout') {
101
+ void cancelReader(reader)
102
+ throw new ProviderStreamIdleTimeoutError(options.dataIdleTimeoutMs ?? 0)
103
+ }
104
+ if (read.done) {
105
+ buffer += decoder.decode()
106
+ streamDone = true
107
+ } else {
108
+ buffer += decoder.decode(read.value, { stream: true })
109
+ }
110
+ const lines = buffer.split(/\n/u)
111
+ buffer = streamDone ? '' : lines.pop() ?? ''
112
+ for (const line of lines) {
113
+ const trimmed = line.trim()
114
+ if (!trimmed.startsWith('data:')) continue
115
+ nextDataDeadline = dataIdleDeadline(options.dataIdleTimeoutMs)
116
+ const data = trimmed.slice(5).trim()
117
+ if (data === '[DONE]') {
118
+ streamDone = true
119
+ void cancelReader(reader)
120
+ break
121
+ }
122
+ const payload = parseJsonLine(data)
123
+ if (!payload) continue
124
+ sawStreamData = true
125
+ const chunk = chunkFromPayload(payload)
126
+ if (chunk.reasoning.length > 0 && options.includeReasoning === true) {
127
+ thinking += chunk.reasoning
128
+ if (!thinkingBlockStarted) {
129
+ thinkingBlockStarted = true
130
+ yield streamEvent({
131
+ type: 'content_block_start',
132
+ index: 0,
133
+ content_block: { type: 'thinking', thinking: '' },
134
+ })
135
+ }
136
+ yield streamEvent({
137
+ type: 'content_block_delta',
138
+ index: 0,
139
+ delta: { type: 'thinking_delta', thinking: chunk.reasoning },
140
+ })
141
+ }
142
+ if (chunk.text.length > 0) {
143
+ const previousTextLength = text.length
144
+ const bufferOffset = firstToolCallTextOffset(chunk.text)
145
+ const startsBuffering = !shouldBufferTextDeltas && bufferOffset >= 0
146
+ if (startsBuffering) {
147
+ shouldBufferTextDeltas = true
148
+ }
149
+ sawTextDelta = true
150
+ text += chunk.text
151
+ if (startsBuffering) {
152
+ if (bufferOffset > 0) {
153
+ const prefix = chunk.text.slice(0, bufferOffset)
154
+ yield streamEvent({
155
+ type: 'content_block_delta',
156
+ delta: { type: 'text_delta', text: prefix },
157
+ })
158
+ emittedTextLength = previousTextLength + prefix.length
159
+ }
160
+ } else if (!shouldBufferTextDeltas) {
161
+ yield streamEvent({
162
+ type: 'content_block_delta',
163
+ delta: { type: 'text_delta', text: chunk.text },
164
+ })
165
+ emittedTextLength = text.length
166
+ }
167
+ }
168
+ for (const toolCallDelta of chunk.toolCallDeltas) {
169
+ const state = toolCallStates.get(toolCallDelta.index) ?? { arguments: '' }
170
+ if (toolCallDelta.id !== undefined) state.id = toolCallDelta.id
171
+ if (toolCallDelta.name !== undefined) state.name = toolCallDelta.name
172
+ if (toolCallDelta.argumentsDelta !== undefined) {
173
+ state.arguments += toolCallDelta.argumentsDelta
174
+ }
175
+ toolCallStates.set(toolCallDelta.index, state)
176
+ }
177
+ }
178
+ }
179
+
180
+ let toolCalls = completedToolCalls(toolCallStates)
181
+ const textualToolCallExtraction = toolCalls.length === 0
182
+ ? extractTextualToolCallProposals({ text })
183
+ : undefined
184
+ const rawJsonToolCallClassification =
185
+ toolCalls.length === 0 && textualToolCallExtraction === undefined
186
+ ? classifyRawJsonToolCallProposal({
187
+ text,
188
+ availableToolNames: options.availableToolNames ?? [],
189
+ })
190
+ : undefined
191
+ const trailingRawJsonToolCall =
192
+ rawJsonToolCallClassification?.kind === 'non_proposal'
193
+ ? parseTrailingRawJsonToolCallProposal({
194
+ text,
195
+ })
196
+ : undefined
197
+ if (textualToolCallExtraction !== undefined) {
198
+ const remainingPrelude = textualToolCallExtraction.text.slice(
199
+ emittedTextLength,
200
+ )
201
+ if (remainingPrelude.length > 0) {
202
+ yield streamEvent({
203
+ type: 'content_block_delta',
204
+ delta: { type: 'text_delta', text: remainingPrelude },
205
+ })
206
+ }
207
+ text = textualToolCallExtraction.text
208
+ toolCalls = textualToolCallExtraction.proposals.map((proposal, index) => ({
209
+ id: rawJsonToolCallId({
210
+ name: proposal.name,
211
+ index,
212
+ availableToolNames: options.availableToolNames ?? [],
213
+ }),
214
+ type: 'function' as const,
215
+ function: {
216
+ name: proposal.name,
217
+ arguments: JSON.stringify(proposal.input),
218
+ },
219
+ }))
220
+ } else if (rawJsonToolCallClassification !== undefined) {
221
+ switch (rawJsonToolCallClassification.kind) {
222
+ case 'registered':
223
+ case 'unregistered':
224
+ text = ''
225
+ toolCalls = [toolCallFromRawJsonProposal({
226
+ id: rawJsonToolCallId({
227
+ name: rawJsonToolCallClassification.proposal.name,
228
+ index: 0,
229
+ availableToolNames: options.availableToolNames ?? [],
230
+ }),
231
+ proposal: rawJsonToolCallClassification.proposal,
232
+ })]
233
+ break
234
+ case 'malformed_input':
235
+ yield streamEvent({
236
+ type: 'content_block_delta',
237
+ delta: {
238
+ type: 'text_delta',
239
+ text: PROVIDER_MALFORMED_TOOL_CALL_HANDOFF,
240
+ },
241
+ })
242
+ text = PROVIDER_MALFORMED_TOOL_CALL_HANDOFF
243
+ emittedTextLength = text.length
244
+ break
245
+ case 'non_proposal':
246
+ if (trailingRawJsonToolCall !== undefined) {
247
+ const remainingPrelude = trailingRawJsonToolCall.prelude.slice(
248
+ emittedTextLength,
249
+ )
250
+ if (remainingPrelude.length > 0) {
251
+ yield streamEvent({
252
+ type: 'content_block_delta',
253
+ delta: { type: 'text_delta', text: remainingPrelude },
254
+ })
255
+ }
256
+ text = trailingRawJsonToolCall.prelude
257
+ toolCalls = [toolCallFromRawJsonProposal({
258
+ id: rawJsonToolCallId({
259
+ name: trailingRawJsonToolCall.proposal.name,
260
+ index: 0,
261
+ availableToolNames: options.availableToolNames ?? [],
262
+ }),
263
+ proposal: trailingRawJsonToolCall.proposal,
264
+ })]
265
+ } else if (shouldBufferTextDeltas && text.length > emittedTextLength) {
266
+ const bufferedText = text.slice(emittedTextLength)
267
+ if (textContainsMalformedToolCallProposal(bufferedText)) {
268
+ yield streamEvent({
269
+ type: 'content_block_delta',
270
+ delta: {
271
+ type: 'text_delta',
272
+ text: PROVIDER_MALFORMED_TOOL_CALL_HANDOFF,
273
+ },
274
+ })
275
+ text = [
276
+ text.slice(0, emittedTextLength).trimEnd(),
277
+ PROVIDER_MALFORMED_TOOL_CALL_HANDOFF,
278
+ ]
279
+ .filter(part => part.length > 0)
280
+ .join('\n')
281
+ emittedTextLength = text.length
282
+ } else {
283
+ yield streamEvent({
284
+ type: 'content_block_delta',
285
+ delta: { type: 'text_delta', text: bufferedText },
286
+ })
287
+ emittedTextLength = text.length
288
+ }
289
+ }
290
+ break
291
+ }
292
+ } else if (shouldBufferTextDeltas && text.length > emittedTextLength) {
293
+ yield streamEvent({
294
+ type: 'content_block_delta',
295
+ delta: { type: 'text_delta', text: text.slice(emittedTextLength) },
296
+ })
297
+ }
298
+ if (text.length === 0 && toolCalls.length === 0) {
299
+ if (sawStreamData) {
300
+ yield createAssistantMessage({ content: PROVIDER_EMPTY_COMPLETION_HANDOFF })
301
+ return
302
+ }
303
+ const message =
304
+ 'FriendliAI response did not contain stream data. Check provider configuration and retry.'
305
+ logError(new Error(message))
306
+ yield createAssistantAPIErrorMessage({
307
+ content: message,
308
+ apiError: 'api_error',
309
+ })
310
+ return
311
+ }
312
+
313
+ const blocks = []
314
+ if (thinking.length > 0) {
315
+ blocks.push({ type: 'thinking' as const, thinking })
316
+ }
317
+ if (text.length > 0) blocks.push({ type: 'text' as const, text })
318
+ for (const call of toolCalls) {
319
+ blocks.push({
320
+ type: 'tool_use' as const,
321
+ id: call.id,
322
+ name: call.function.name,
323
+ input: parseToolArguments(call.function.arguments),
324
+ })
325
+ }
326
+ yield createAssistantMessage({ content: blocks })
327
+ }
328
+
329
+ function streamEvent(event: Record<string, unknown>): StreamEvent {
330
+ return { type: 'stream_event', event }
331
+ }
332
+
333
+ function firstToolCallTextOffset(text: string): number {
334
+ const braceOffset = text.indexOf('{')
335
+ const tagOffset = text.indexOf(TEXTUAL_TOOL_CALL_OPEN)
336
+ if (braceOffset < 0) return tagOffset
337
+ if (tagOffset < 0) return braceOffset
338
+ return Math.min(braceOffset, tagOffset)
339
+ }
340
+
341
+ function rawJsonToolCallId(params: {
342
+ readonly name: string
343
+ readonly index: number
344
+ readonly availableToolNames: readonly string[]
345
+ }): string {
346
+ const availableToolNames = new Set(params.availableToolNames)
347
+ const prefix = availableToolNames.has(params.name)
348
+ ? RAW_JSON_REGISTERED_TOOL_USE_ID_PREFIX
349
+ : RAW_JSON_UNREGISTERED_TOOL_USE_ID_PREFIX
350
+ return `${prefix}${params.index}`
351
+ }
352
+
353
+ function toolCallFromRawJsonProposal(params: {
354
+ readonly id: string
355
+ readonly proposal: RawJsonToolCallProposal
356
+ }): OpenAIToolCall {
357
+ return {
358
+ id: params.id,
359
+ type: 'function',
360
+ function: {
361
+ name: params.proposal.name,
362
+ arguments: JSON.stringify(params.proposal.input),
363
+ },
364
+ }
365
+ }
@@ -0,0 +1,129 @@
1
+ import type { OpenAIToolCall } from './types.js'
2
+
3
+ export type ToolCallDelta = {
4
+ readonly index: number
5
+ readonly id?: string
6
+ readonly name?: string
7
+ readonly argumentsDelta?: string
8
+ }
9
+
10
+ export type ParsedChunk = {
11
+ readonly text: string
12
+ readonly reasoning: string
13
+ readonly toolCallDeltas: readonly ToolCallDelta[]
14
+ readonly done: boolean
15
+ }
16
+
17
+ type ToolCallState = {
18
+ id?: string
19
+ name?: string
20
+ arguments: string
21
+ }
22
+
23
+ export function isRecord(value: unknown): value is Record<string, unknown> {
24
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
25
+ }
26
+
27
+ export function parseJsonLine(
28
+ line: string,
29
+ ): Record<string, unknown> | undefined {
30
+ try {
31
+ const parsed: unknown = JSON.parse(line)
32
+ return isRecord(parsed) ? parsed : undefined
33
+ } catch (error) {
34
+ if (error instanceof SyntaxError) return undefined
35
+ throw error
36
+ }
37
+ }
38
+
39
+ export function providerFailureMessage(
40
+ response: Response,
41
+ body: string,
42
+ ): string {
43
+ const status = [String(response.status), response.statusText]
44
+ .filter(part => part.trim().length > 0)
45
+ .join(' ')
46
+ const requestId = response.headers.get('x-request-id')
47
+ const detail = providerErrorDetail(body)
48
+ return [
49
+ `FriendliAI request failed (${status}).`,
50
+ detail ? `Provider message: ${detail}.` : undefined,
51
+ requestId ? `Request ID: ${requestId}.` : undefined,
52
+ 'Check /login or UMMAYA_FRIENDLI_TOKEN before sending another request.',
53
+ ]
54
+ .filter(Boolean)
55
+ .join(' ')
56
+ }
57
+
58
+ export function chunkFromPayload(
59
+ payload: Record<string, unknown>,
60
+ ): ParsedChunk {
61
+ const choices = Array.isArray(payload.choices) ? payload.choices : []
62
+ const firstChoice = choices.find(isRecord)
63
+ const delta = isRecord(firstChoice?.delta) ? firstChoice.delta : {}
64
+ const text = typeof delta.content === 'string' ? delta.content : ''
65
+ const reasoning =
66
+ typeof delta.reasoning_content === 'string' ? delta.reasoning_content : ''
67
+ const toolCallDeltas = Array.isArray(delta.tool_calls)
68
+ ? delta.tool_calls.filter(isRecord).map(toolCallDeltaFromPayload)
69
+ : []
70
+ return {
71
+ text,
72
+ reasoning,
73
+ toolCallDeltas,
74
+ done:
75
+ firstChoice?.finish_reason === 'stop' ||
76
+ firstChoice?.finish_reason === 'tool_calls',
77
+ }
78
+ }
79
+
80
+ export function parseToolArguments(value: string): Record<string, unknown> {
81
+ const parsed = parseJsonLine(value)
82
+ return parsed ?? {}
83
+ }
84
+
85
+ export function completedToolCalls(
86
+ states: ReadonlyMap<number, ToolCallState>,
87
+ ): readonly OpenAIToolCall[] {
88
+ return Array.from(states.entries())
89
+ .sort(([left], [right]) => left - right)
90
+ .flatMap(([, state]) => {
91
+ if (state.id === undefined || state.name === undefined) return []
92
+ return [{
93
+ id: state.id,
94
+ type: 'function' as const,
95
+ function: {
96
+ name: state.name,
97
+ arguments: state.arguments.length > 0 ? state.arguments : '{}',
98
+ },
99
+ }]
100
+ })
101
+ }
102
+
103
+ function textField(value: unknown): string | undefined {
104
+ return typeof value === 'string' && value.trim().length > 0
105
+ ? value.trim()
106
+ : undefined
107
+ }
108
+
109
+ function providerErrorDetail(body: string): string | undefined {
110
+ const parsed = parseJsonLine(body.trim())
111
+ const topLevelMessage = textField(parsed?.message)
112
+ if (topLevelMessage) return topLevelMessage
113
+ const error = parsed?.error
114
+ if (typeof error === 'string') return textField(error)
115
+ if (!isRecord(error)) return undefined
116
+ return textField(error.message) ?? textField(error.detail)
117
+ }
118
+
119
+ function toolCallDeltaFromPayload(
120
+ delta: Record<string, unknown>,
121
+ ): ToolCallDelta {
122
+ const fn = isRecord(delta.function) ? delta.function : {}
123
+ return {
124
+ index: typeof delta.index === 'number' ? delta.index : 0,
125
+ id: typeof delta.id === 'string' ? delta.id : undefined,
126
+ name: typeof fn.name === 'string' ? fn.name : undefined,
127
+ argumentsDelta: typeof fn.arguments === 'string' ? fn.arguments : undefined,
128
+ }
129
+ }
@@ -0,0 +1,40 @@
1
+ import { logError } from '../../../utils/log.js'
2
+
3
+ export function dataIdleDeadline(timeoutMs: number | undefined): number {
4
+ return timeoutMs === undefined
5
+ ? Number.POSITIVE_INFINITY
6
+ : performance.now() + timeoutMs
7
+ }
8
+
9
+ export function dataIdleTimeoutRemaining(
10
+ timeoutMs: number | undefined,
11
+ deadline: number,
12
+ ): number | undefined {
13
+ if (timeoutMs === undefined) return undefined
14
+ return deadline - performance.now()
15
+ }
16
+
17
+ export async function readNextStreamChunk(
18
+ reader: ReadableStreamDefaultReader<Uint8Array>,
19
+ timeoutMs: number | undefined,
20
+ ): Promise<ReadableStreamReadResult<Uint8Array> | 'timeout'> {
21
+ if (timeoutMs === undefined) return await reader.read()
22
+ if (timeoutMs <= 0) return 'timeout'
23
+ let timeoutId: ReturnType<typeof setTimeout> | undefined
24
+ const timeout = new Promise<'timeout'>(resolve => {
25
+ timeoutId = setTimeout(() => resolve('timeout'), timeoutMs)
26
+ })
27
+ const result = await Promise.race([reader.read(), timeout])
28
+ if (timeoutId !== undefined) clearTimeout(timeoutId)
29
+ return result
30
+ }
31
+
32
+ export async function cancelReader(
33
+ reader: ReadableStreamDefaultReader<Uint8Array>,
34
+ ): Promise<void> {
35
+ try {
36
+ await reader.cancel()
37
+ } catch (error) {
38
+ logError(error instanceof Error ? error : new Error(String(error)))
39
+ }
40
+ }