ummaya 0.2.4 → 0.2.6

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 (482) hide show
  1. package/README.md +15 -2
  2. package/bin/ummaya +10 -1
  3. package/bun.lock +180 -244
  4. package/npm-shrinkwrap.json +760 -1760
  5. package/package.json +39 -22
  6. package/prompts/manifest.yaml +1 -1
  7. package/prompts/system_v1.md +1 -0
  8. package/pyproject.toml +27 -2
  9. package/specs/2803-document-production-hardening/contracts/document-tools.schema.json +1043 -0
  10. package/src/ummaya/_canonical/__init__.py +2 -0
  11. package/src/ummaya/_canonical/baselines.yaml +113 -0
  12. package/src/ummaya/engine/engine.py +29 -132
  13. package/src/ummaya/evidence/__init__.py +21 -2
  14. package/src/ummaya/evidence/dataset_contract.py +193 -0
  15. package/src/ummaya/evidence/document_authoring_cases.py +33 -0
  16. package/src/ummaya/evidence/document_harness.py +313 -0
  17. package/src/ummaya/evidence/document_viewer_ux.py +391 -0
  18. package/src/ummaya/evidence/gates.py +70 -0
  19. package/src/ummaya/evidence/json_types.py +20 -0
  20. package/src/ummaya/evidence/models.py +88 -1
  21. package/src/ummaya/evidence/output_payload.py +89 -0
  22. package/src/ummaya/evidence/payload_documents.py +233 -0
  23. package/src/ummaya/evidence/route_contracts.py +224 -0
  24. package/src/ummaya/evidence/route_helpers.py +150 -0
  25. package/src/ummaya/evidence/runner.py +81 -212
  26. package/src/ummaya/evidence/source_provenance.py +246 -0
  27. package/src/ummaya/evidence/source_provenance_redaction.py +176 -0
  28. package/src/ummaya/evidence/tool_layer.py +39 -0
  29. package/src/ummaya/evidence/tool_layer_models.py +151 -0
  30. package/src/ummaya/ipc/adapter_manifest_emitter.py +26 -10
  31. package/src/ummaya/ipc/document_intent_normalization.py +185 -0
  32. package/src/ummaya/ipc/frame_schema.py +5 -5
  33. package/src/ummaya/ipc/route_diagnostics.py +73 -0
  34. package/src/ummaya/ipc/stdio.py +1109 -477
  35. package/src/ummaya/llm/client.py +102 -3
  36. package/src/ummaya/llm/config.py +8 -3
  37. package/src/ummaya/primitives/__init__.py +6 -2
  38. package/src/ummaya/primitives/delegation.py +1 -1
  39. package/src/ummaya/primitives/document.py +28 -0
  40. package/src/ummaya/settings.py +0 -3
  41. package/src/ummaya/tools/discovery_bridge.py +17 -1
  42. package/src/ummaya/tools/documents/__init__.py +297 -0
  43. package/src/ummaya/tools/documents/adapter_registry.py +487 -0
  44. package/src/ummaya/tools/documents/archive_container_probe.py +167 -0
  45. package/src/ummaya/tools/documents/artifact_store.py +454 -0
  46. package/src/ummaya/tools/documents/authoring.py +283 -0
  47. package/src/ummaya/tools/documents/baselines.py +132 -0
  48. package/src/ummaya/tools/documents/capability.py +331 -0
  49. package/src/ummaya/tools/documents/contracts.py +112 -0
  50. package/src/ummaya/tools/documents/conversion.py +521 -0
  51. package/src/ummaya/tools/documents/diff.py +275 -0
  52. package/src/ummaya/tools/documents/engines.py +163 -0
  53. package/src/ummaya/tools/documents/evaluation.py +291 -0
  54. package/src/ummaya/tools/documents/explicit_values.py +108 -0
  55. package/src/ummaya/tools/documents/fixtures.py +174 -0
  56. package/src/ummaya/tools/documents/format_completion_audit.py +471 -0
  57. package/src/ummaya/tools/documents/formats/__init__.py +2 -0
  58. package/src/ummaya/tools/documents/formats/archive.py +528 -0
  59. package/src/ummaya/tools/documents/formats/base.py +41 -0
  60. package/src/ummaya/tools/documents/formats/code_file.py +211 -0
  61. package/src/ummaya/tools/documents/formats/data_file.py +272 -0
  62. package/src/ummaya/tools/documents/formats/hwp.py +284 -0
  63. package/src/ummaya/tools/documents/formats/hwpx.py +1837 -0
  64. package/src/ummaya/tools/documents/formats/odf.py +435 -0
  65. package/src/ummaya/tools/documents/formats/ooxml.py +1030 -0
  66. package/src/ummaya/tools/documents/formats/passive.py +766 -0
  67. package/src/ummaya/tools/documents/formats/pdf.py +702 -0
  68. package/src/ummaya/tools/documents/formats/text_web.py +268 -0
  69. package/src/ummaya/tools/documents/hwp_conversion_probe.py +178 -0
  70. package/src/ummaya/tools/documents/hwp_direct_candidate.py +141 -0
  71. package/src/ummaya/tools/documents/inspection.py +289 -0
  72. package/src/ummaya/tools/documents/intake.py +1079 -0
  73. package/src/ummaya/tools/documents/legacy_office_promotion_probe.py +366 -0
  74. package/src/ummaya/tools/documents/models.py +1598 -0
  75. package/src/ummaya/tools/documents/odf_promotion_probe.py +167 -0
  76. package/src/ummaya/tools/documents/orchestrator.py +96 -0
  77. package/src/ummaya/tools/documents/passive_capability_probe.py +251 -0
  78. package/src/ummaya/tools/documents/patch.py +170 -0
  79. package/src/ummaya/tools/documents/pdfa_conformance.py +284 -0
  80. package/src/ummaya/tools/documents/pdfa_promotion_probe.py +198 -0
  81. package/src/ummaya/tools/documents/permissions.py +110 -0
  82. package/src/ummaya/tools/documents/planner.py +616 -0
  83. package/src/ummaya/tools/documents/registry.py +2733 -0
  84. package/src/ummaya/tools/documents/render.py +978 -0
  85. package/src/ummaya/tools/documents/render_comparison.py +113 -0
  86. package/src/ummaya/tools/documents/render_comparison_models.py +74 -0
  87. package/src/ummaya/tools/documents/render_comparison_regions.py +73 -0
  88. package/src/ummaya/tools/documents/render_comparison_style.py +161 -0
  89. package/src/ummaya/tools/documents/reread.py +157 -0
  90. package/src/ummaya/tools/documents/runtime_authoring.py +244 -0
  91. package/src/ummaya/tools/documents/runtime_authoring_bundle.py +76 -0
  92. package/src/ummaya/tools/documents/scorecard.py +184 -0
  93. package/src/ummaya/tools/documents/socratic_planner.py +193 -0
  94. package/src/ummaya/tools/documents/style.py +48 -0
  95. package/src/ummaya/tools/documents/tool_defs.py +523 -0
  96. package/src/ummaya/tools/documents/validate.py +347 -0
  97. package/src/ummaya/tools/executor.py +29 -0
  98. package/src/ummaya/tools/live_proxy.py +0 -3
  99. package/src/ummaya/tools/models.py +5 -1
  100. package/src/ummaya/tools/register_all.py +8 -0
  101. package/src/ummaya/tools/registry.py +10 -1
  102. package/src/ummaya/tools/routing/__init__.py +59 -0
  103. package/src/ummaya/tools/routing/builder.py +105 -0
  104. package/src/ummaya/tools/routing/cards.py +29 -0
  105. package/src/ummaya/tools/routing/decision_service.py +534 -0
  106. package/src/ummaya/tools/routing/decision_types.py +74 -0
  107. package/src/ummaya/tools/routing/feasibility.py +122 -0
  108. package/src/ummaya/tools/routing/intent.py +17 -0
  109. package/src/ummaya/tools/routing/intent_extractor.py +207 -0
  110. package/src/ummaya/tools/routing/intent_patterns.py +160 -0
  111. package/src/ummaya/tools/routing/intent_public_data.py +150 -0
  112. package/src/ummaya/tools/routing/intent_types.py +48 -0
  113. package/src/ummaya/tools/routing/lint.py +78 -0
  114. package/src/ummaya/tools/routing/metadata.py +174 -0
  115. package/src/ummaya/tools/routing/projection.py +340 -0
  116. package/src/ummaya/tools/routing/retrieval_policy.py +629 -0
  117. package/src/ummaya/tools/routing/schema.py +81 -0
  118. package/src/ummaya/tools/routing/types.py +96 -0
  119. package/src/ummaya/tools/routing_index.py +2 -2
  120. package/src/ummaya/tools/search.py +34 -746
  121. package/tests/fixtures/documents/public_forms/baselines.yaml +113 -0
  122. package/tui/bun.lock +126 -305
  123. package/tui/package.json +35 -22
  124. package/tui/src/.cc-byte-identical-whitelist.yaml +266 -0
  125. package/tui/src/QueryEngine.ts +12 -8
  126. package/tui/src/bridge/inboundAttachments.ts +3 -3
  127. package/tui/src/cli/handlers/auth.ts +3 -12
  128. package/tui/src/cli/handlers/mcp.tsx +0 -1
  129. package/tui/src/cli/print.ts +8 -9
  130. package/tui/src/commands/insights.ts +1 -1
  131. package/tui/src/commands/install-github-app/types.ts +8 -30
  132. package/tui/src/commands/plugin/types.ts +6 -28
  133. package/tui/src/commands/plugin/unifiedTypes.ts +4 -26
  134. package/tui/src/commands/rename/generateSessionName.ts +1 -1
  135. package/tui/src/components/Feedback.tsx +1 -1
  136. package/tui/src/components/LogoV2/EmergencyTip.tsx +11 -2
  137. package/tui/src/components/LogoV2/WelcomeV2.tsx +1 -3
  138. package/tui/src/components/ScrollKeybindingHandler.tsx +6 -6
  139. package/tui/src/components/Spinner/types.ts +6 -28
  140. package/tui/src/components/agents/generateAgent.ts +1 -1
  141. package/tui/src/components/agents/new-agent-creation/types.ts +4 -26
  142. package/tui/src/components/config/EnvSecretIsolatedEditor.tsx +1 -1
  143. package/tui/src/components/mcp/types.ts +16 -38
  144. package/tui/src/components/messages/AssistantToolUseMessage.tsx +3 -2
  145. package/tui/src/components/messages/UserCrossSessionMessage.ts +16 -4
  146. package/tui/src/components/messages/UserForkBoilerplateMessage.ts +16 -4
  147. package/tui/src/components/messages/UserGitHubWebhookMessage.ts +16 -4
  148. package/tui/src/components/messages/UserToolResultMessage/utils.tsx +3 -2
  149. package/tui/src/components/permissions/MonitorPermissionRequest/MonitorPermissionRequest.ts +9 -4
  150. package/tui/src/components/permissions/ReviewArtifactPermissionRequest/ReviewArtifactPermissionRequest.ts +9 -4
  151. package/tui/src/components/primitive/DocumentSocraticReviewBlock.tsx +129 -0
  152. package/tui/src/components/primitive/DocumentToolResultCard.tsx +224 -0
  153. package/tui/src/components/primitive/documentSocraticReview.ts +215 -0
  154. package/tui/src/components/primitive/index.tsx +43 -1
  155. package/tui/src/components/primitive/types.ts +137 -0
  156. package/tui/src/components/ui/option.ts +4 -26
  157. package/tui/src/constants/common.ts +0 -2
  158. package/tui/src/constants/prompts.ts +4 -3
  159. package/tui/src/constants/querySource.ts +4 -26
  160. package/tui/src/entrypoints/sdk/controlTypes.ts +26 -48
  161. package/tui/src/entrypoints/sdk/coreTypes.generated.ts +3 -25
  162. package/tui/src/entrypoints/sdk/runtimeTypes.ts +38 -60
  163. package/tui/src/entrypoints/sdk/sdkUtilityTypes.ts +4 -26
  164. package/tui/src/entrypoints/sdk/settingsTypes.generated.ts +3 -25
  165. package/tui/src/entrypoints/sdk/toolTypes.ts +3 -25
  166. package/tui/src/hooks/toolPermission/handlers/interactiveHandler.ts +10 -0
  167. package/tui/src/hooks/useApiKeyVerification.ts +1 -1
  168. package/tui/src/hooks/useVirtualScroll.ts +1 -1
  169. package/tui/src/ink/ink.tsx +33 -14
  170. package/tui/src/ink/reconciler.ts +2 -3
  171. package/tui/src/ink/render-to-screen.ts +30 -10
  172. package/tui/src/ipc/bridge.ts +62 -15
  173. package/tui/src/ipc/bridgeSingleton.ts +5 -1
  174. package/tui/src/ipc/codec.ts +3 -3
  175. package/tui/src/ipc/frames.generated.ts +12 -12
  176. package/tui/src/ipc/llmClient.ts +151 -27
  177. package/tui/src/ipc/schema/frame.schema.json +1 -1
  178. package/tui/src/keybindings/defaultBindings.ts +4 -0
  179. package/tui/src/main.tsx +32 -15
  180. package/tui/src/native-ts/file-index/index.ts +33 -3
  181. package/tui/src/observability/surface.ts +2 -2
  182. package/tui/src/probes/toolRegistryProbe.tsx +3 -1
  183. package/tui/src/projectOnboardingState.ts +7 -6
  184. package/tui/src/query/chatMessageTypes.ts +18 -0
  185. package/tui/src/query/chatMessagesBuilder.ts +1 -1
  186. package/tui/src/query/deps.ts +1 -1
  187. package/tui/src/query/messageGuards.ts +106 -0
  188. package/tui/src/query/publicDataTerminalRepair.ts +384 -0
  189. package/tui/src/query/run.ts +1075 -0
  190. package/tui/src/query/supportBoundary.ts +168 -0
  191. package/tui/src/query/toolResultErrors.ts +103 -0
  192. package/tui/src/query/toolRunner.ts +687 -0
  193. package/tui/src/query/unavailableToolRepair.ts +118 -0
  194. package/tui/src/query.ts +9 -2186
  195. package/tui/src/screens/REPL.tsx +40 -29
  196. package/tui/src/services/api/adapterManifest.ts +4 -0
  197. package/tui/src/services/api/backendChat/events.ts +117 -0
  198. package/tui/src/services/api/backendChat/finalMessage.ts +40 -0
  199. package/tui/src/services/api/backendChat/frame.ts +9 -0
  200. package/tui/src/services/api/backendChat/streaming.ts +430 -0
  201. package/tui/src/services/api/backendChat/types.ts +62 -0
  202. package/tui/src/services/api/backendChat.ts +1 -0
  203. package/tui/src/services/api/client.ts +65 -2
  204. package/tui/src/services/api/errorUtils.ts +5 -5
  205. package/tui/src/services/api/errors.ts +1 -1
  206. package/tui/src/services/api/logging.ts +1 -1
  207. package/tui/src/services/api/ummaya/evidence.ts +194 -0
  208. package/tui/src/services/api/ummaya/messages.ts +255 -0
  209. package/tui/src/services/api/ummaya/nonStreaming.ts +66 -0
  210. package/tui/src/services/api/ummaya/provider.ts +200 -0
  211. package/tui/src/services/api/ummaya/reasoning.ts +24 -0
  212. package/tui/src/services/api/ummaya/request.ts +200 -0
  213. package/tui/src/services/api/ummaya/selectionContext.ts +240 -0
  214. package/tui/src/services/api/ummaya/streaming.ts +365 -0
  215. package/tui/src/services/api/ummaya/streamingPayload.ts +129 -0
  216. package/tui/src/services/api/ummaya/streamingReader.ts +40 -0
  217. package/tui/src/services/api/ummaya/toolSelection.ts +217 -0
  218. package/tui/src/services/api/ummaya/types.ts +110 -0
  219. package/tui/src/services/api/ummaya/usage.ts +30 -0
  220. package/tui/src/services/api/ummaya.ts +26 -418
  221. package/tui/src/services/api/withRetry.ts +1 -1
  222. package/tui/src/services/awaySummary.ts +2 -2
  223. package/tui/src/services/claudeAiLimits.ts +1 -1
  224. package/tui/src/services/compact/autoCompact.ts +1 -1
  225. package/tui/src/services/compact/compact.ts +1 -1
  226. package/tui/src/services/lsp/types.ts +8 -30
  227. package/tui/src/services/tips/types.ts +6 -28
  228. package/tui/src/services/tokenEstimation.ts +1 -1
  229. package/tui/src/services/toolRegistry/bootGuard.ts +5 -5
  230. package/tui/src/services/toolUseSummary/toolUseSummaryGenerator.ts +1 -1
  231. package/tui/src/services/tools/toolExecution.ts +94 -1
  232. package/tui/src/store/pendingPermissionSlot.ts +1 -1
  233. package/tui/src/store/session-store.ts +10 -36
  234. package/tui/src/stubs/any-stub.ts +15 -10
  235. package/tui/src/stubs/color-diff-napi.ts +37 -23
  236. package/tui/src/stubs/globals.d.ts +3 -3
  237. package/tui/src/stubs/macro-preload.ts +23 -12
  238. package/tui/src/tools/AdapterTool/AdapterTool.ts +1207 -714
  239. package/tui/src/tools/AdapterTool/routeDiagnostics.ts +75 -0
  240. package/tui/src/tools/AgentTool/AgentTool.tsx +84 -1371
  241. package/tui/src/tools/AgentTool/agentToolHandoff.ts +114 -0
  242. package/tui/src/tools/AgentTool/agentToolPartialResult.ts +16 -0
  243. package/tui/src/tools/AgentTool/agentToolProgress.ts +32 -0
  244. package/tui/src/tools/AgentTool/agentToolResolver.ts +161 -0
  245. package/tui/src/tools/AgentTool/agentToolResult.ts +163 -0
  246. package/tui/src/tools/AgentTool/agentToolUtils.ts +14 -686
  247. package/tui/src/tools/AgentTool/asyncAgentLifecycle.ts +208 -0
  248. package/tui/src/tools/AgentTool/asyncLifecycle.ts +153 -0
  249. package/tui/src/tools/AgentTool/backgroundedCompletion.ts +126 -0
  250. package/tui/src/tools/AgentTool/backgroundedLifecycle.ts +174 -0
  251. package/tui/src/tools/AgentTool/foregroundBackground.ts +83 -0
  252. package/tui/src/tools/AgentTool/foregroundDrain.tsx +133 -0
  253. package/tui/src/tools/AgentTool/foregroundFinalize.ts +98 -0
  254. package/tui/src/tools/AgentTool/foregroundLifecycle.tsx +237 -0
  255. package/tui/src/tools/AgentTool/foregroundProgress.tsx +169 -0
  256. package/tui/src/tools/AgentTool/foregroundTask.ts +89 -0
  257. package/tui/src/tools/AgentTool/forkSubagent.ts +1 -12
  258. package/tui/src/tools/AgentTool/forkSubagentGate.ts +34 -0
  259. package/tui/src/tools/AgentTool/launchRouting.ts +203 -0
  260. package/tui/src/tools/AgentTool/lifecycle.ts +244 -0
  261. package/tui/src/tools/AgentTool/mcpRouting.ts +73 -0
  262. package/tui/src/tools/AgentTool/orchestrationSupport.ts +70 -0
  263. package/tui/src/tools/AgentTool/permissions.ts +39 -0
  264. package/tui/src/tools/AgentTool/promptSetup.ts +181 -0
  265. package/tui/src/tools/AgentTool/remoteRouting.ts +62 -0
  266. package/tui/src/tools/AgentTool/resultMapping.ts +116 -0
  267. package/tui/src/tools/AgentTool/resumeAgent.ts +39 -107
  268. package/tui/src/tools/AgentTool/resumeAgentHelpers.ts +140 -0
  269. package/tui/src/tools/AgentTool/runAgent.ts +1 -1
  270. package/tui/src/tools/AgentTool/runtimeConfig.ts +57 -0
  271. package/tui/src/tools/AgentTool/schemas.ts +196 -0
  272. package/tui/src/tools/AgentTool/sourceVerificationPropagation.ts +263 -0
  273. package/tui/src/tools/AgentTool/worktreeLifecycle.ts +105 -0
  274. package/tui/src/tools/AskUserQuestionTool/AskUserQuestionTool.tsx +174 -202
  275. package/tui/src/tools/BashTool/BashTool.tsx +71 -1072
  276. package/tui/src/tools/BashTool/bashCommandHelpers.ts +12 -12
  277. package/tui/src/tools/BashTool/bashPermissions/astPreflight.ts +173 -0
  278. package/tui/src/tools/BashTool/bashPermissions/classifierChecks.ts +199 -0
  279. package/tui/src/tools/BashTool/bashPermissions/compoundGuards.ts +53 -0
  280. package/tui/src/tools/BashTool/bashPermissions/constants.ts +99 -0
  281. package/tui/src/tools/BashTool/bashPermissions/index.ts +38 -0
  282. package/tui/src/tools/BashTool/bashPermissions/legacyMisparsing.ts +62 -0
  283. package/tui/src/tools/BashTool/bashPermissions/main.ts +135 -0
  284. package/tui/src/tools/BashTool/bashPermissions/normalizedCommands.ts +33 -0
  285. package/tui/src/tools/BashTool/bashPermissions/operatorFlow.ts +98 -0
  286. package/tui/src/tools/BashTool/bashPermissions/permissionChecks.ts +200 -0
  287. package/tui/src/tools/BashTool/bashPermissions/prefixSuggestions.ts +88 -0
  288. package/tui/src/tools/BashTool/bashPermissions/promptClassifierRules.ts +125 -0
  289. package/tui/src/tools/BashTool/bashPermissions/ruleDelegates.ts +19 -0
  290. package/tui/src/tools/BashTool/bashPermissions/ruleMatching.ts +145 -0
  291. package/tui/src/tools/BashTool/bashPermissions/sandboxAutoAllow.ts +75 -0
  292. package/tui/src/tools/BashTool/bashPermissions/subcommandFlow.ts +205 -0
  293. package/tui/src/tools/BashTool/bashPermissions/subcommandGuards.ts +73 -0
  294. package/tui/src/tools/BashTool/bashPermissions/subcommandResultHelpers.ts +116 -0
  295. package/tui/src/tools/BashTool/bashPermissions/types.ts +26 -0
  296. package/tui/src/tools/BashTool/bashPermissions/wrapperStripping.ts +139 -0
  297. package/tui/src/tools/BashTool/bashPermissions.ts +26 -2621
  298. package/tui/src/tools/BashTool/call.ts +202 -0
  299. package/tui/src/tools/BashTool/callLoader.ts +35 -0
  300. package/tui/src/tools/BashTool/commandClassification.ts +151 -0
  301. package/tui/src/tools/BashTool/commandClassificationLoader.ts +40 -0
  302. package/tui/src/tools/BashTool/cwdReset.ts +33 -0
  303. package/tui/src/tools/BashTool/lineTruncation.ts +11 -0
  304. package/tui/src/tools/BashTool/modeValidation.ts +13 -1
  305. package/tui/src/tools/BashTool/outputPersistence.ts +42 -0
  306. package/tui/src/tools/BashTool/permissionClassification.ts +66 -0
  307. package/tui/src/tools/BashTool/permissionLoader.ts +44 -0
  308. package/tui/src/tools/BashTool/resultLoader.ts +29 -0
  309. package/tui/src/tools/BashTool/resultMapping.ts +83 -0
  310. package/tui/src/tools/BashTool/sandboxPolicy.ts +79 -0
  311. package/tui/src/tools/BashTool/schemas.ts +65 -0
  312. package/tui/src/tools/BashTool/sedEditExecution.ts +59 -0
  313. package/tui/src/tools/BashTool/shellExecution.tsx +245 -0
  314. package/tui/src/tools/BashTool/shellOutputUtils.ts +85 -0
  315. package/tui/src/tools/BashTool/shellPermissionGauntlet.ts +97 -0
  316. package/tui/src/tools/BashTool/uiLoader.ts +37 -0
  317. package/tui/src/tools/BriefTool/upload.ts +1 -1
  318. package/tui/src/tools/CalculatorTool/parser.ts +2 -2
  319. package/tui/src/tools/DocumentPrimitive/DocumentPrimitive.ts +262 -0
  320. package/tui/src/tools/DocumentPrimitive/dispatchNormalization.ts +270 -0
  321. package/tui/src/tools/DocumentPrimitive/documentDestinationPath.ts +18 -0
  322. package/tui/src/tools/DocumentPrimitive/documentMutationGuard.ts +22 -0
  323. package/tui/src/tools/DocumentPrimitive/documentPatchNormalization.ts +248 -0
  324. package/tui/src/tools/DocumentPrimitive/documentSourceVerification.ts +245 -0
  325. package/tui/src/tools/DocumentPrimitive/documentSourceVerificationFields.ts +103 -0
  326. package/tui/src/tools/DocumentPrimitive/modelVisibleOutput.ts +40 -0
  327. package/tui/src/tools/DocumentPrimitive/prompt.ts +35 -0
  328. package/tui/src/tools/FileEditTool/FileEditTool.ts +9 -507
  329. package/tui/src/tools/FileEditTool/call.ts +228 -0
  330. package/tui/src/tools/FileEditTool/validateInput.ts +196 -0
  331. package/tui/src/tools/FileReadTool/imageProcessor.ts +13 -0
  332. package/tui/src/tools/FileWriteTool/FileWriteTool.ts +7 -300
  333. package/tui/src/tools/FileWriteTool/call.ts +223 -0
  334. package/tui/src/tools/FileWriteTool/validateInput.ts +80 -0
  335. package/tui/src/tools/ListMcpResourcesTool/ListMcpResourcesTool.ts +19 -3
  336. package/tui/src/tools/LookupPrimitive/LookupPrimitive.ts +25 -32
  337. package/tui/src/tools/LookupPrimitive/prompt.ts +0 -2
  338. package/tui/src/tools/MCPTool/trustPolicy.ts +118 -0
  339. package/tui/src/tools/McpAuthTool/McpAuthTool.ts +21 -3
  340. package/tui/src/tools/NotebookEditTool/NotebookEditTool.ts +7 -326
  341. package/tui/src/tools/NotebookEditTool/call.ts +254 -0
  342. package/tui/src/tools/NotebookEditTool/notebookModel.ts +51 -0
  343. package/tui/src/tools/NotebookEditTool/validateInput.ts +142 -0
  344. package/tui/src/tools/PowerShellTool/PowerShellTool.tsx +46 -937
  345. package/tui/src/tools/PowerShellTool/acceptEditsCommandValidation.ts +162 -0
  346. package/tui/src/tools/PowerShellTool/call.ts +179 -0
  347. package/tui/src/tools/PowerShellTool/callLoader.ts +37 -0
  348. package/tui/src/tools/PowerShellTool/commandClassification.ts +86 -0
  349. package/tui/src/tools/PowerShellTool/modeValidation.ts +25 -332
  350. package/tui/src/tools/PowerShellTool/outputPersistence.ts +42 -0
  351. package/tui/src/tools/PowerShellTool/permissionClassification.ts +28 -0
  352. package/tui/src/tools/PowerShellTool/resultLoader.ts +31 -0
  353. package/tui/src/tools/PowerShellTool/resultMapping.ts +75 -0
  354. package/tui/src/tools/PowerShellTool/schemas.ts +40 -0
  355. package/tui/src/tools/PowerShellTool/shellExecution.tsx +258 -0
  356. package/tui/src/tools/PowerShellTool/symlinkModeValidation.ts +44 -0
  357. package/tui/src/tools/PowerShellTool/uiLoader.ts +37 -0
  358. package/tui/src/tools/PowerShellTool/validation.ts +39 -0
  359. package/tui/src/tools/ReadMcpResourceTool/ReadMcpResourceTool.ts +19 -3
  360. package/tui/src/tools/ResolveLocationPrimitive/ResolveLocationPrimitive.ts +1 -11
  361. package/tui/src/tools/ResolveLocationPrimitive/prompt.ts +2 -6
  362. package/tui/src/tools/SkillTool/SkillTool.ts +2 -2
  363. package/tui/src/tools/SubmitPrimitive/SubmitPrimitive.ts +27 -10
  364. package/tui/src/tools/TaskCreateTool/TaskCreateTool.ts +16 -2
  365. package/tui/src/tools/TaskGetTool/TaskGetTool.ts +23 -3
  366. package/tui/src/tools/TaskListTool/TaskListTool.ts +22 -4
  367. package/tui/src/tools/TaskOutputTool/TaskOutputTool.tsx +46 -547
  368. package/tui/src/tools/TaskOutputTool/lookup.ts +216 -0
  369. package/tui/src/tools/TaskOutputTool/render.tsx +257 -0
  370. package/tui/src/tools/TaskOutputTool/schemas.ts +55 -0
  371. package/tui/src/tools/TaskOutputTool/serialization.ts +36 -0
  372. package/tui/src/tools/TaskStopTool/TaskStopTool.ts +10 -0
  373. package/tui/src/tools/TaskUpdateTool/TaskUpdateTool.ts +14 -364
  374. package/tui/src/tools/TaskUpdateTool/completion.ts +62 -0
  375. package/tui/src/tools/TaskUpdateTool/schemas.ts +62 -0
  376. package/tui/src/tools/TaskUpdateTool/serialization.ts +46 -0
  377. package/tui/src/tools/TaskUpdateTool/statusUpdate.ts +247 -0
  378. package/tui/src/tools/TodoWriteTool/TodoWriteTool.ts +21 -2
  379. package/tui/src/tools/ToolSearchTool/ToolSearchTool.ts +21 -302
  380. package/tui/src/tools/ToolSearchTool/ccSupportTools.ts +223 -0
  381. package/tui/src/tools/ToolSearchTool/descriptionCache.ts +50 -0
  382. package/tui/src/tools/ToolSearchTool/keywordSearch.ts +216 -0
  383. package/tui/src/tools/ToolSearchTool/prompt.ts +10 -4
  384. package/tui/src/tools/ToolSearchTool/resultMapping.ts +30 -0
  385. package/tui/src/tools/ToolSearchTool/schemas.ts +30 -0
  386. package/tui/src/tools/ToolSearchTool/searchPool.ts +47 -0
  387. package/tui/src/tools/ToolSearchTool/supportIntentHints.ts +140 -0
  388. package/tui/src/tools/TranslateTool/TranslateTool.ts +1 -1
  389. package/tui/src/tools/VerifyPrimitive/VerifyPrimitive.ts +2 -1
  390. package/tui/src/tools/WebFetchTool/WebFetchTool.ts +43 -138
  391. package/tui/src/tools/WebFetchTool/call.ts +227 -0
  392. package/tui/src/tools/WebFetchTool/resolvedAddressSafety.ts +78 -0
  393. package/tui/src/tools/WebFetchTool/sourceVerification.ts +204 -0
  394. package/tui/src/tools/WebFetchTool/types.ts +23 -0
  395. package/tui/src/tools/WebFetchTool/urlSafety.ts +181 -0
  396. package/tui/src/tools/WebFetchTool/utils.ts +1 -1
  397. package/tui/src/tools/WebSearchTool/UI.tsx +0 -1
  398. package/tui/src/tools/WebSearchTool/WebSearchTool.ts +9 -313
  399. package/tui/src/tools/WebSearchTool/call.ts +33 -0
  400. package/tui/src/tools/WebSearchTool/responseMapping.ts +190 -0
  401. package/tui/src/tools/WebSearchTool/resultBlock.ts +47 -0
  402. package/tui/src/tools/WebSearchTool/schemas.ts +47 -0
  403. package/tui/src/tools/WebSearchTool/toolSchema.ts +12 -0
  404. package/tui/src/tools/WorkspaceToolAdapter/WorkspaceToolAdapter.ts +79 -0
  405. package/tui/src/tools/WorkspaceToolAdapter/allowedRootPolicy.ts +85 -0
  406. package/tui/src/tools/WorkspaceToolAdapter/documentFormatGuards.ts +73 -0
  407. package/tui/src/tools/WorkspaceToolAdapter/inputNormalization.ts +105 -0
  408. package/tui/src/tools/WorkspaceToolAdapter/mcpExposurePolicy.ts +64 -0
  409. package/tui/src/tools/WorkspaceToolAdapter/toolDefFactory.ts +215 -0
  410. package/tui/src/tools/WorkspaceToolAdapter/toolNames.ts +6 -0
  411. package/tui/src/tools/WorkspaceToolAdapter/workspacePolicy.ts +15 -0
  412. package/tui/src/tools/_shared/dispatchPrimitive.ts +6 -6
  413. package/tui/src/tools/_shared/documentChangeToPatch.ts +125 -0
  414. package/tui/src/tools/_shared/documentDispatchArguments.ts +87 -0
  415. package/tui/src/tools/_shared/documentPrimitiveTimeout.ts +13 -0
  416. package/tui/src/tools/_shared/documentToolResultRender.ts +98 -0
  417. package/tui/src/tools/_shared/pendingCallRegistry.ts +1 -6
  418. package/tui/src/tools/_shared/rootPrimitiveInput.ts +1 -0
  419. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPatterns.ts +58 -0
  420. package/tui/src/tools/_shared/toolChoiceRepair/documentCompletionPrompt.ts +271 -0
  421. package/tui/src/tools/_shared/toolChoiceRepair/documentRepair.ts +452 -0
  422. package/tui/src/tools/_shared/toolChoiceRepair/messageAccess.ts +80 -0
  423. package/tui/src/tools/_shared/toolChoiceRepair/publicDataRepair.ts +92 -0
  424. package/tui/src/tools/_shared/toolChoiceRepair/supportRepair.ts +135 -0
  425. package/tui/src/tools/_shared/toolChoiceRepair.ts +55 -860
  426. package/tui/src/tools/shared/mockDisclaimer.ts +1 -1
  427. package/tui/src/tools.ts +39 -190
  428. package/tui/src/types/fileSuggestion.ts +4 -26
  429. package/tui/src/types/generated/events_mono/claude_code/v1/claude_code_internal_event.ts +186 -148
  430. package/tui/src/types/generated/events_mono/common/v1/auth.ts +25 -11
  431. package/tui/src/types/generated/events_mono/growthbook/v1/growthbook_experiment_event.ts +47 -30
  432. package/tui/src/types/generated/google/protobuf/timestamp.ts +21 -7
  433. package/tui/src/types/message.ts +80 -102
  434. package/tui/src/types/messageQueueTypes.ts +6 -28
  435. package/tui/src/types/notebook.ts +16 -38
  436. package/tui/src/types/statusLine.ts +4 -26
  437. package/tui/src/types/tools.ts +24 -46
  438. package/tui/src/types/utils.ts +6 -28
  439. package/tui/src/upstreamproxy/relay.ts +7 -3
  440. package/tui/src/upstreamproxy/upstreamproxy.ts +1 -1
  441. package/tui/src/utils/assistantMessageFactories.ts +9 -3
  442. package/tui/src/utils/auth.ts +129 -139
  443. package/tui/src/utils/bash/ast.ts +23 -23
  444. package/tui/src/utils/bash/bashParser.ts +5 -5
  445. package/tui/src/utils/billing.ts +1 -1
  446. package/tui/src/utils/claudeDesktop.ts +4 -4
  447. package/tui/src/utils/collapseReadSearch.ts +3 -3
  448. package/tui/src/utils/cronTasks.ts +1 -1
  449. package/tui/src/utils/execFileNoThrow.ts +1 -1
  450. package/tui/src/utils/filePersistence/types.ts +16 -38
  451. package/tui/src/utils/forkedAgent.ts +1 -1
  452. package/tui/src/utils/gracefulShutdown.ts +4 -4
  453. package/tui/src/utils/heapDumpService.ts +12 -8
  454. package/tui/src/utils/hooks/apiQueryHookHelper.ts +1 -1
  455. package/tui/src/utils/hooks/execPromptHook.ts +1 -1
  456. package/tui/src/utils/hooks/skillImprovement.ts +1 -1
  457. package/tui/src/utils/mcp/dateTimeParser.ts +1 -1
  458. package/tui/src/utils/messages.ts +18 -0
  459. package/tui/src/utils/migrateSessions.ts +3 -3
  460. package/tui/src/utils/model/model.ts +6 -6
  461. package/tui/src/utils/permissions/yoloClassifier.ts +1 -1
  462. package/tui/src/utils/plugins/headlessPluginInstall.ts +1 -1
  463. package/tui/src/utils/plugins/mcpPluginIntegration.ts +1 -1
  464. package/tui/src/utils/plugins/mcpbHandler.ts +1 -1
  465. package/tui/src/utils/plugins/pluginLoader.ts +8 -8
  466. package/tui/src/utils/protectedNamespace.ts +5 -3
  467. package/tui/src/utils/rawJsonToolCall.ts +242 -0
  468. package/tui/src/utils/ripgrep.ts +16 -7
  469. package/tui/src/utils/sessionTitle.ts +1 -1
  470. package/tui/src/utils/settings/permissionValidation.ts +14 -2
  471. package/tui/src/utils/shell/prefix.ts +1 -1
  472. package/tui/src/utils/sideQuery.ts +1 -1
  473. package/tui/src/utils/systemThemeWatcher.ts +13 -3
  474. package/tui/src/utils/teleport.tsx +1 -1
  475. package/uv.lock +426 -45
  476. package/tui/src/services/api/claude.ts +0 -3540
  477. package/tui/src/tools/_shared/directPublicDataGuard.ts +0 -362
  478. package/tui/src/tools/_shared/kmaAnalysisGuard.ts +0 -197
  479. package/tui/src/tools/_shared/kmaAviationGuard.ts +0 -70
  480. package/tui/src/tools/_shared/nmcAedGuard.ts +0 -234
  481. package/tui/src/tools/_shared/protectedCheckGuard.ts +0 -207
  482. 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
+ }