@yadsh/dsh-qa-surface 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (276) hide show
  1. package/README.md +192 -15
  2. package/cordis.patch.yml +8 -0
  3. package/lib/account-remotes.js +100 -0
  4. package/lib/account-remotes.js.map +1 -0
  5. package/lib/accounts/credentials.js +35 -0
  6. package/lib/accounts/credentials.js.map +1 -0
  7. package/lib/accounts/errors.js +9 -0
  8. package/lib/accounts/errors.js.map +1 -0
  9. package/lib/accounts/file.js +101 -0
  10. package/lib/accounts/file.js.map +1 -0
  11. package/lib/accounts/store.js +159 -161
  12. package/lib/accounts/store.js.map +1 -1
  13. package/lib/accounts/token.js +61 -0
  14. package/lib/accounts/token.js.map +1 -0
  15. package/lib/approvals.js +179 -0
  16. package/lib/approvals.js.map +1 -0
  17. package/lib/attachment-rules.js +111 -0
  18. package/lib/attachment-rules.js.map +1 -0
  19. package/lib/cli.js +132 -9
  20. package/lib/cli.js.map +1 -1
  21. package/lib/client/QaAccountsController.js +32 -2
  22. package/lib/client/QaAccountsController.js.map +1 -1
  23. package/lib/client/QaSessionController.js +140 -65
  24. package/lib/client/QaSessionController.js.map +1 -1
  25. package/lib/client/QaSurface.js +134 -107
  26. package/lib/client/QaSurface.js.map +1 -1
  27. package/lib/client/QaTranscriptAdapter.js +71 -6
  28. package/lib/client/QaTranscriptAdapter.js.map +1 -1
  29. package/lib/client/approvals.js +104 -0
  30. package/lib/client/approvals.js.map +1 -0
  31. package/lib/client/attachments.js +150 -0
  32. package/lib/client/attachments.js.map +1 -0
  33. package/lib/client/attestation.js +4 -1
  34. package/lib/client/attestation.js.map +1 -1
  35. package/lib/client/base64.js +16 -0
  36. package/lib/client/base64.js.map +1 -0
  37. package/lib/client/chat-files.js +48 -0
  38. package/lib/client/chat-files.js.map +1 -0
  39. package/lib/client/components/Markdown.js +1 -1
  40. package/lib/client/components/Markdown.js.map +1 -1
  41. package/lib/client/components/QaApproval.js +23 -0
  42. package/lib/client/components/QaApproval.js.map +1 -0
  43. package/lib/client/components/QaChangelog.js +62 -19
  44. package/lib/client/components/QaChangelog.js.map +1 -1
  45. package/lib/client/components/QaComposer.js +56 -74
  46. package/lib/client/components/QaComposer.js.map +1 -1
  47. package/lib/client/components/QaFileAttachment.js +19 -0
  48. package/lib/client/components/QaFileAttachment.js.map +1 -0
  49. package/lib/client/components/QaFilesPanel.js +45 -0
  50. package/lib/client/components/QaFilesPanel.js.map +1 -0
  51. package/lib/client/components/QaHeader.js +34 -0
  52. package/lib/client/components/QaHeader.js.map +1 -0
  53. package/lib/client/components/QaMessage.js +17 -4
  54. package/lib/client/components/QaMessage.js.map +1 -1
  55. package/lib/client/components/QaModal.js +31 -0
  56. package/lib/client/components/QaModal.js.map +1 -0
  57. package/lib/client/components/QaProfile.js +64 -0
  58. package/lib/client/components/QaProfile.js.map +1 -0
  59. package/lib/client/components/QaQuestions.js +96 -0
  60. package/lib/client/components/QaQuestions.js.map +1 -0
  61. package/lib/client/components/QaRightRail.js +15 -0
  62. package/lib/client/components/QaRightRail.js.map +1 -0
  63. package/lib/client/components/QaSidebar.js +6 -1
  64. package/lib/client/components/QaSidebar.js.map +1 -1
  65. package/lib/client/components/{QaSourcesDrawer.js → QaSourcesPanel.js} +3 -3
  66. package/lib/client/components/QaSourcesPanel.js.map +1 -0
  67. package/lib/client/components/QaTurnRail.js +15 -0
  68. package/lib/client/components/QaTurnRail.js.map +1 -1
  69. package/lib/client/components/QaWidthHandle.js +25 -20
  70. package/lib/client/components/QaWidthHandle.js.map +1 -1
  71. package/lib/client/components/QaWorkGroup.js +19 -20
  72. package/lib/client/components/QaWorkGroup.js.map +1 -1
  73. package/lib/client/components/surface-utils.js +28 -0
  74. package/lib/client/components/surface-utils.js.map +1 -0
  75. package/lib/client/components/thinking-phrases.js +24 -0
  76. package/lib/client/components/thinking-phrases.js.map +1 -0
  77. package/lib/client/create-session.js +7 -32
  78. package/lib/client/create-session.js.map +1 -1
  79. package/lib/client/failure-copy.js +63 -0
  80. package/lib/client/failure-copy.js.map +1 -0
  81. package/lib/client/index.js +49 -7
  82. package/lib/client/index.js.map +1 -1
  83. package/lib/client/project-session-state.js +5 -3
  84. package/lib/client/project-session-state.js.map +1 -1
  85. package/lib/client/prompt-content.js +54 -0
  86. package/lib/client/prompt-content.js.map +1 -0
  87. package/lib/client/questions.js +114 -0
  88. package/lib/client/questions.js.map +1 -0
  89. package/lib/client/settings/card.js +143 -0
  90. package/lib/client/settings/card.js.map +1 -0
  91. package/lib/client/settings/fields.js +145 -0
  92. package/lib/client/settings/fields.js.map +1 -0
  93. package/lib/client/settings/format.js +255 -0
  94. package/lib/client/settings/format.js.map +1 -0
  95. package/lib/client/settings/sections/access.js +25 -0
  96. package/lib/client/settings/sections/access.js.map +1 -0
  97. package/lib/client/settings/sections/accounts.js +47 -0
  98. package/lib/client/settings/sections/accounts.js.map +1 -0
  99. package/lib/client/settings/sections/attachments.js +46 -0
  100. package/lib/client/settings/sections/attachments.js.map +1 -0
  101. package/lib/client/settings/sections/branding.js +28 -0
  102. package/lib/client/settings/sections/branding.js.map +1 -0
  103. package/lib/client/settings/sections/common.js +20 -0
  104. package/lib/client/settings/sections/common.js.map +1 -0
  105. package/lib/client/settings/sections/embedding.js +19 -0
  106. package/lib/client/settings/sections/embedding.js.map +1 -0
  107. package/lib/client/settings/sections/interface.js +60 -0
  108. package/lib/client/settings/sections/interface.js.map +1 -0
  109. package/lib/client/settings/sections/lockdown.js +82 -0
  110. package/lib/client/settings/sections/lockdown.js.map +1 -0
  111. package/lib/client/settings/sections/session.js +53 -0
  112. package/lib/client/settings/sections/session.js.map +1 -0
  113. package/lib/client/settings/sections/sources.js +74 -0
  114. package/lib/client/settings/sections/sources.js.map +1 -0
  115. package/lib/client/settings/sections/status.js +37 -0
  116. package/lib/client/settings/sections/status.js.map +1 -0
  117. package/lib/client/settings/sections.js +23 -0
  118. package/lib/client/settings/sections.js.map +1 -0
  119. package/lib/client/settings/styles.js +57 -0
  120. package/lib/client/settings/styles.js.map +1 -0
  121. package/lib/client/stream-publisher.js +47 -0
  122. package/lib/client/stream-publisher.js.map +1 -0
  123. package/lib/client/styles.js +127 -19
  124. package/lib/client/styles.js.map +1 -1
  125. package/lib/client/types.js +2 -0
  126. package/lib/client/types.js.map +1 -1
  127. package/lib/client/use-right-rail.js +96 -0
  128. package/lib/client/use-right-rail.js.map +1 -0
  129. package/lib/client/use-session-ui-state.js +26 -19
  130. package/lib/client/use-session-ui-state.js.map +1 -1
  131. package/lib/client.js +5694 -813
  132. package/lib/client.js.map +1 -1
  133. package/lib/config-resolvers/accounts.js +60 -0
  134. package/lib/config-resolvers/accounts.js.map +1 -0
  135. package/lib/config-resolvers/attachments.js +28 -0
  136. package/lib/config-resolvers/attachments.js.map +1 -0
  137. package/lib/config-resolvers/basics.js +61 -0
  138. package/lib/config-resolvers/basics.js.map +1 -0
  139. package/lib/config-resolvers/defaults.js +136 -0
  140. package/lib/config-resolvers/defaults.js.map +1 -0
  141. package/lib/config-resolvers/lockdown.js +90 -0
  142. package/lib/config-resolvers/lockdown.js.map +1 -0
  143. package/lib/config-resolvers/session.js +42 -0
  144. package/lib/config-resolvers/session.js.map +1 -0
  145. package/lib/config-resolvers/shared.js +51 -0
  146. package/lib/config-resolvers/shared.js.map +1 -0
  147. package/lib/config-resolvers/sources.js +83 -0
  148. package/lib/config-resolvers/sources.js.map +1 -0
  149. package/lib/config-resolvers/ui.js +20 -0
  150. package/lib/config-resolvers/ui.js.map +1 -0
  151. package/lib/config.js +76 -6
  152. package/lib/config.js.map +1 -1
  153. package/lib/entry-redirect.js +2 -1
  154. package/lib/entry-redirect.js.map +1 -1
  155. package/lib/index.js +198 -79
  156. package/lib/index.js.map +1 -1
  157. package/lib/profile.js +214 -0
  158. package/lib/profile.js.map +1 -0
  159. package/lib/prompt-notes.js +231 -0
  160. package/lib/prompt-notes.js.map +1 -0
  161. package/lib/provenance/host-store.js +25 -9
  162. package/lib/provenance/host-store.js.map +1 -1
  163. package/lib/provenance/reported.js +37 -12
  164. package/lib/provenance/reported.js.map +1 -1
  165. package/lib/questions.js +185 -0
  166. package/lib/questions.js.map +1 -0
  167. package/lib/resolve-config.js +35 -410
  168. package/lib/resolve-config.js.map +1 -1
  169. package/lib/secure-session.js +139 -21
  170. package/lib/secure-session.js.map +1 -1
  171. package/lib/session-ownership.js +55 -0
  172. package/lib/session-ownership.js.map +1 -0
  173. package/lib/shared/session-key.js +18 -0
  174. package/lib/shared/session-key.js.map +1 -0
  175. package/lib/shared/settings.js +10 -0
  176. package/lib/shared/settings.js.map +1 -0
  177. package/lib/thinking-phrases.js +68 -0
  178. package/lib/thinking-phrases.js.map +1 -0
  179. package/lib/typert.host.js +506 -21
  180. package/lib/typert.remote-client.d.ts +15 -1
  181. package/lib/typert.remote-client.js +407 -15
  182. package/lib/types/account-remotes.d.ts +42 -0
  183. package/lib/types/accounts/credentials.d.ts +20 -0
  184. package/lib/types/accounts/errors.d.ts +11 -0
  185. package/lib/types/accounts/file.d.ts +82 -0
  186. package/lib/types/accounts/store.d.ts +74 -43
  187. package/lib/types/accounts/token.d.ts +31 -0
  188. package/lib/types/approvals.d.ts +65 -0
  189. package/lib/types/attachment-rules.d.ts +44 -0
  190. package/lib/types/cli.d.ts +2 -2
  191. package/lib/types/client/QaAccountsController.d.ts +8 -1
  192. package/lib/types/client/QaSessionController.d.ts +53 -16
  193. package/lib/types/client/QaSurface.d.ts +14 -1
  194. package/lib/types/client/approvals.d.ts +39 -0
  195. package/lib/types/client/attachments.d.ts +54 -0
  196. package/lib/types/client/base64.d.ts +10 -0
  197. package/lib/types/client/chat-files.d.ts +30 -0
  198. package/lib/types/client/components/QaApproval.d.ts +13 -0
  199. package/lib/types/client/components/QaChangelog.d.ts +1 -1
  200. package/lib/types/client/components/QaComposer.d.ts +8 -4
  201. package/lib/types/client/components/QaFileAttachment.d.ts +14 -0
  202. package/lib/types/client/components/QaFilesPanel.d.ts +15 -0
  203. package/lib/types/client/components/QaHeader.d.ts +41 -0
  204. package/lib/types/client/components/QaMessage.d.ts +3 -1
  205. package/lib/types/client/components/QaModal.d.ts +26 -0
  206. package/lib/types/client/components/QaProfile.d.ts +25 -0
  207. package/lib/types/client/components/QaQuestions.d.ts +13 -0
  208. package/lib/types/client/components/QaRightRail.d.ts +23 -0
  209. package/lib/types/client/components/QaSidebar.d.ts +14 -0
  210. package/lib/types/client/components/{QaSourcesDrawer.d.ts → QaSourcesPanel.d.ts} +7 -4
  211. package/lib/types/client/components/QaTurnRail.d.ts +6 -0
  212. package/lib/types/client/components/QaWidthHandle.d.ts +14 -7
  213. package/lib/types/client/components/QaWorkGroup.d.ts +5 -3
  214. package/lib/types/client/components/surface-utils.d.ts +11 -0
  215. package/lib/types/client/components/thinking-phrases.d.ts +9 -0
  216. package/lib/types/client/create-session.d.ts +6 -9
  217. package/lib/types/client/failure-copy.d.ts +19 -0
  218. package/lib/types/client/project-session-state.d.ts +8 -1
  219. package/lib/types/client/prompt-content.d.ts +30 -0
  220. package/lib/types/client/questions.d.ts +45 -0
  221. package/lib/types/client/settings/card.d.ts +23 -0
  222. package/lib/types/client/settings/fields.d.ts +139 -0
  223. package/lib/types/client/settings/format.d.ts +108 -0
  224. package/lib/types/client/settings/sections/access.d.ts +9 -0
  225. package/lib/types/client/settings/sections/accounts.d.ts +9 -0
  226. package/lib/types/client/settings/sections/attachments.d.ts +15 -0
  227. package/lib/types/client/settings/sections/branding.d.ts +8 -0
  228. package/lib/types/client/settings/sections/common.d.ts +28 -0
  229. package/lib/types/client/settings/sections/embedding.d.ts +8 -0
  230. package/lib/types/client/settings/sections/interface.d.ts +9 -0
  231. package/lib/types/client/settings/sections/lockdown.d.ts +9 -0
  232. package/lib/types/client/settings/sections/session.d.ts +9 -0
  233. package/lib/types/client/settings/sections/sources.d.ts +9 -0
  234. package/lib/types/client/settings/sections/status.d.ts +22 -0
  235. package/lib/types/client/settings/sections.d.ts +25 -0
  236. package/lib/types/client/settings/styles.d.ts +8 -0
  237. package/lib/types/client/stream-publisher.d.ts +28 -0
  238. package/lib/types/client/types.d.ts +76 -1
  239. package/lib/types/client/use-right-rail.d.ts +56 -0
  240. package/lib/types/client/use-session-ui-state.d.ts +13 -7
  241. package/lib/types/config-resolvers/accounts.d.ts +15 -0
  242. package/lib/types/config-resolvers/attachments.d.ts +6 -0
  243. package/lib/types/config-resolvers/basics.d.ts +8 -0
  244. package/lib/types/config-resolvers/defaults.d.ts +4 -0
  245. package/lib/types/config-resolvers/lockdown.d.ts +10 -0
  246. package/lib/types/config-resolvers/session.d.ts +6 -0
  247. package/lib/types/config-resolvers/shared.d.ts +23 -0
  248. package/lib/types/config-resolvers/sources.d.ts +6 -0
  249. package/lib/types/config-resolvers/ui.d.ts +6 -0
  250. package/lib/types/index.d.ts +48 -15
  251. package/lib/types/profile.d.ts +76 -0
  252. package/lib/types/prompt-notes.d.ts +110 -0
  253. package/lib/types/provenance/reported.d.ts +9 -1
  254. package/lib/types/questions.d.ts +83 -0
  255. package/lib/types/resolve-config.d.ts +8 -3
  256. package/lib/types/secure-session.d.ts +46 -2
  257. package/lib/types/session-ownership.d.ts +30 -0
  258. package/lib/types/shared/session-key.d.ts +23 -0
  259. package/lib/types/shared/settings.d.ts +10 -0
  260. package/lib/types/thinking-phrases.d.ts +17 -0
  261. package/lib/types/types.d.ts +203 -9
  262. package/lib/types/user-workspace.d.ts +42 -0
  263. package/lib/user-workspace.js +246 -0
  264. package/lib/user-workspace.js.map +1 -0
  265. package/package.json +15 -8
  266. package/CHANGELOG.md +0 -176
  267. package/SPEC-dsh-qa-surface.md +0 -2425
  268. package/docs/ARCHITECTURE.md +0 -66
  269. package/docs/COMPATIBILITY.md +0 -14
  270. package/docs/CONFIGURATION.md +0 -199
  271. package/docs/EMBEDDING.md +0 -13
  272. package/docs/SOURCES-MIGRATION.md +0 -28
  273. package/docs/SOURCES-PROVENANCE-AUDIT.md +0 -88
  274. package/docs/SPEC-dsh-qa-surface-accounts.md +0 -219
  275. package/docs/SPEC-dsh-qa-surface-sources-provenance.md +0 -1692
  276. package/lib/client/components/QaSourcesDrawer.js.map +0 -1
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Composer-side attachment intake: which files are accepted, how a pasted
3
+ * blob turns into an attachment, and the browser-side ceilings. The Host
4
+ * remains authoritative — these checks exist so a refusal happens before a
5
+ * round trip, not to replace the Host's own admission.
6
+ */
7
+ import type { QaAttachmentDraft, QaFileDraft, QaImageMediaType, ResolvedQaSurfaceConfig } from "../types.js";
8
+ /** Raster formats the host attachment path accepts. */
9
+ export declare const QA_IMAGE_MEDIA_TYPES: readonly QaImageMediaType[];
10
+ /** Soft image ceiling; the Host stays authoritative at admission. */
11
+ export declare const QA_MAX_IMAGE_BYTES: number;
12
+ /** The attachment policy as the composer reads it. */
13
+ export interface QaAttachmentLimits {
14
+ readonly textFiles: boolean;
15
+ readonly pastedTextLines: number;
16
+ readonly maxFileBytes: number;
17
+ readonly maxPending: number;
18
+ readonly extensions: readonly string[];
19
+ }
20
+ /**
21
+ * Project the deployment's resolved configuration into the composer's policy.
22
+ * @param config - effective QA configuration.
23
+ * @returns the attachment ceilings the composer enforces.
24
+ */
25
+ export declare function attachmentLimits(config: ResolvedQaSurfaceConfig): QaAttachmentLimits;
26
+ /**
27
+ * The file picker's `accept` value: the raster formats plus either the
28
+ * configured text extensions or the browser's whole `text/*` family.
29
+ * @param limits - attachment policy in effect.
30
+ * @returns the accept attribute value.
31
+ */
32
+ export declare function attachmentAccept(limits: QaAttachmentLimits): string;
33
+ /** Whether a dropped payload may be attached as a text file at all. */
34
+ export declare function acceptsTextFile(name: string, mediaType: string, limits: QaAttachmentLimits): boolean;
35
+ /**
36
+ * Turn one dropped or picked file into a composer draft, or into the message
37
+ * the visitor sees when the file is not accepted.
38
+ * @param file - browser file from a picker, drop or paste.
39
+ * @param limits - attachment policy in effect.
40
+ * @returns the draft, or a refusal message.
41
+ */
42
+ export declare function draftFromFile(file: File, limits: QaAttachmentLimits): Promise<QaAttachmentDraft | string>;
43
+ /**
44
+ * Convert a large pasted blob into an attached file. Pasted text has no file
45
+ * name of its own, so the name states what it is; the model resolves it from
46
+ * the durable store like any other attachment.
47
+ * @param text - pasted plain text.
48
+ * @param limits - attachment policy in effect.
49
+ * @returns the draft, or null when the paste stays in the input field.
50
+ */
51
+ export declare function draftFromPaste(text: string, limits: QaAttachmentLimits): QaFileDraft | null;
52
+ /** Format one attachment size for a card, a chip or a refusal message. */
53
+ export declare function formatFileSize(bytes: number): string;
54
+ //# sourceMappingURL=attachments.d.ts.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Browser-side binary-to-base64. Chunked so `String.fromCharCode` never
3
+ * crosses the engine's argument limit on large attachments.
4
+ */
5
+ /**
6
+ * @param bytes - raw bytes to encode.
7
+ * @returns the canonical base64 text (no `data:` prefix, no padding tricks).
8
+ */
9
+ export declare function bytesToBase64(bytes: Uint8Array): string;
10
+ //# sourceMappingURL=base64.d.ts.map
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Attachment roster of one chat, projected for the rail's files tab: a pure
3
+ * scan of the durable transcript, newest message first. The browser never
4
+ * re-reads file bytes (the attachment route serves images), so a row keeps
5
+ * the same handle the transcript shows.
6
+ */
7
+ import type { QaImageView, QaMessage, QaFileView } from "../types.js";
8
+ /** Everything one user message carried, in prompt order. */
9
+ export interface QaChatFileGroup {
10
+ /** The user message id; doubles as the transcript turn anchor. */
11
+ readonly messageId: string;
12
+ /** Wall-clock send time, when the transcript recorded one. */
13
+ readonly timestamp?: number;
14
+ readonly files: readonly QaFileView[];
15
+ readonly images: readonly QaImageView[];
16
+ }
17
+ /** Whether the group carries at least one attachment of either kind. */
18
+ export declare function groupHasAttachments(group: QaChatFileGroup): boolean;
19
+ /** Total attachment count across groups; the header badge's value. */
20
+ export declare function countChatAttachments(groups: readonly QaChatFileGroup[]): number;
21
+ /**
22
+ * Group the attachments of a chat by their sending message. Only user
23
+ * messages can carry attachments; messages without any are dropped. The
24
+ * groups come out newest message first, matching a roster that grows at the
25
+ * bottom of the transcript.
26
+ * @param messages - the chat's projected transcript.
27
+ * @returns attachment groups, newest message first.
28
+ */
29
+ export declare function collectChatFiles(messages: readonly QaMessage[]): readonly QaChatFileGroup[];
30
+ //# sourceMappingURL=chat-files.d.ts.map
@@ -0,0 +1,13 @@
1
+ import type { QaApprovalDecision, QaPendingApproval } from "../../types.js";
2
+ export interface QaApprovalProps {
3
+ readonly approvals: readonly QaPendingApproval[];
4
+ readonly onAnswer: (requestId: string, decision: QaApprovalDecision) => Promise<void>;
5
+ }
6
+ /**
7
+ * The tool calls a composed gate parked for a person. One row per request, the
8
+ * gate's own reason on top, and the two answers stock DSH offers: refuse, or
9
+ * let this one call through. Nothing here decides on its own — an unanswered
10
+ * request simply keeps the turn waiting.
11
+ */
12
+ export declare const QaApproval: import("react").MemoExoticComponent<(props: QaApprovalProps) => import("react/jsx-runtime").JSX.Element | null>;
13
+ //# sourceMappingURL=QaApproval.d.ts.map
@@ -17,5 +17,5 @@ export interface QaChangelogModalProps {
17
17
  * The version/changelog dialog opened from the sidebar footer. Rendering is
18
18
  * a no-op while closed; Escape and a backdrop click close it.
19
19
  */
20
- export declare function QaChangelogModal(props: QaChangelogModalProps): import("react/jsx-runtime").JSX.Element | null;
20
+ export declare function QaChangelogModal(props: QaChangelogModalProps): import("react/jsx-runtime").JSX.Element;
21
21
  //# sourceMappingURL=QaChangelog.d.ts.map
@@ -1,4 +1,5 @@
1
- import type { QaImageDraft } from "../../types.js";
1
+ import type { QaAttachmentDraft } from "../../types.js";
2
+ import { type QaAttachmentLimits } from "../attachments.js";
2
3
  export interface QaComposerProps {
3
4
  readonly placeholder: string;
4
5
  readonly quickQuestions?: readonly string[];
@@ -7,15 +8,18 @@ export interface QaComposerProps {
7
8
  readonly running: boolean;
8
9
  readonly showStop: boolean;
9
10
  readonly status: string | null;
10
- readonly images: readonly QaImageDraft[];
11
- readonly onImagesChange: (images: readonly QaImageDraft[]) => void;
12
- readonly onSend: (text: string, images: readonly QaImageDraft[]) => Promise<boolean>;
11
+ readonly attachments: readonly QaAttachmentDraft[];
12
+ /** Deployment policy: accepted kinds, ceilings and the paste threshold. */
13
+ readonly limits: QaAttachmentLimits;
14
+ readonly onAttachmentsChange: (attachments: readonly QaAttachmentDraft[]) => void;
15
+ readonly onSend: (text: string, attachments: readonly QaAttachmentDraft[]) => Promise<boolean>;
13
16
  readonly onStop: () => Promise<void>;
14
17
  }
15
18
  /**
16
19
  * Memoized with the default shallow compare: every prop is a scalar, a
17
20
  * stable array or a stable callback, so a stream of transcript frames never
18
21
  * re-renders the composer and typing stays responsive while an answer runs.
22
+ * The caller owns the draft array identity: `limits` must be stable too.
19
23
  */
20
24
  export declare const QaComposer: import("react").MemoExoticComponent<(props: QaComposerProps) => import("react/jsx-runtime").JSX.Element>;
21
25
  //# sourceMappingURL=QaComposer.d.ts.map
@@ -0,0 +1,14 @@
1
+ export interface QaFileAttachmentProps {
2
+ readonly name: string;
3
+ readonly bytes: number;
4
+ /** Pending draft vs already-sent attachment: pending offers removal. */
5
+ readonly tone: "draft" | "sent";
6
+ readonly onRemove?: () => void;
7
+ }
8
+ /**
9
+ * One attached file: the extension badge, the name and the size. The browser
10
+ * never re-reads these bytes (the Host attachment route serves images), so
11
+ * both the composer card and the sent row show the same handle.
12
+ */
13
+ export declare function QaFileAttachment({ name, bytes, tone, onRemove, }: QaFileAttachmentProps): import("react/jsx-runtime").JSX.Element;
14
+ //# sourceMappingURL=QaFileAttachment.d.ts.map
@@ -0,0 +1,15 @@
1
+ import type { QaChatFileGroup } from "../chat-files.js";
2
+ export interface QaFilesPanelProps {
3
+ readonly groups: readonly QaChatFileGroup[];
4
+ /** Resolve an image attachment to an object URL; images render inert without it. */
5
+ readonly resolveImage?: (attachmentId: string) => Promise<string>;
6
+ /** Scroll the transcript to the group's user message. */
7
+ readonly onJumpToMessage: (messageId: string) => void;
8
+ }
9
+ /**
10
+ * The chat's attachment roster: one section per sending message, newest
11
+ * first. Rows mirror the transcript's handles — the browser never reads a
12
+ * file back, and the images are the same object URLs the message showed.
13
+ */
14
+ export declare function QaFilesPanel({ groups, resolveImage, onJumpToMessage, }: QaFilesPanelProps): import("react/jsx-runtime").JSX.Element;
15
+ //# sourceMappingURL=QaFilesPanel.d.ts.map
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The surface's header chrome: brand row, the derived conversation title, the
3
+ * agents/sources/files controls and the reset action. Plain (non-memoized)
4
+ * rendering — the badge counts move with the session state anyway, so
5
+ * reference guards would never pay off here.
6
+ */
7
+ /**
8
+ * The subagent indication for headerless deployments: a slim status line
9
+ * above the transcript with the way back to the parent chat. With a header,
10
+ * the same indication lives in the title row instead.
11
+ */
12
+ export declare function QaSubagentBanner({ onClose, }: {
13
+ readonly onClose: () => void;
14
+ }): import("react/jsx-runtime").JSX.Element;
15
+ export interface QaHeaderProps {
16
+ readonly logoUrl: string | null;
17
+ /** The derived conversation title; null hides the heading. */
18
+ readonly title: string | null;
19
+ /** A subagent view replaces the mode caption with its return control. */
20
+ readonly viewingSubagent: boolean;
21
+ readonly onCloseSubagent: () => void;
22
+ readonly agentPreset: string | null;
23
+ readonly agentCount: number;
24
+ readonly agentsOpen: boolean;
25
+ /** Toggles the agents drawer; also closes the right rail. */
26
+ readonly onToggleAgents: () => void;
27
+ /** Whether the deployment shows the sources control in the header at all. */
28
+ readonly sourcesVisible: boolean;
29
+ readonly sourcesCount: number;
30
+ readonly sourcesComplete: boolean;
31
+ readonly sourcesOpen: boolean;
32
+ readonly onOpenSources: () => void;
33
+ readonly fileCount: number;
34
+ readonly filesOpen: boolean;
35
+ readonly onOpenFiles: () => void;
36
+ readonly showReset: boolean;
37
+ readonly resetDisabled: boolean;
38
+ readonly onReset: () => void;
39
+ }
40
+ export declare function QaHeader({ logoUrl, title, viewingSubagent, onCloseSubagent, agentPreset, agentCount, agentsOpen, onToggleAgents, sourcesVisible, sourcesCount, sourcesComplete, sourcesOpen, onOpenSources, fileCount, filesOpen, onOpenFiles, showReset, resetDisabled, onReset, }: QaHeaderProps): import("react/jsx-runtime").JSX.Element;
41
+ //# sourceMappingURL=QaHeader.d.ts.map
@@ -16,6 +16,8 @@ export interface QaMessageProps {
16
16
  readonly onOpenSources?: (sources: readonly QaSource[], complete: boolean, incompleteOrigins: QaTurnSources["incompleteOrigins"]) => void;
17
17
  /** Open one path-backed source's detail (an inline footnote click). */
18
18
  readonly onSourceDetail?: (source: QaSource) => void;
19
+ /** Operator-configured running phrases; omitted reads the built-in list. */
20
+ readonly thinkingPhrases?: readonly string[];
19
21
  }
20
22
  /**
21
23
  * Whether two transcript messages render identically. The transcript
@@ -24,5 +26,5 @@ export interface QaMessageProps {
24
26
  * comparison is by value, which keeps fresh copies cheap to recognize.
25
27
  */
26
28
  export declare function sameMessage(a: QaMessageModel, b: QaMessageModel): boolean;
27
- export declare const QaMessage: import("react").MemoExoticComponent<({ message, renderMarkdown, showTimestamp, stateKey, onRegenerate, resolveImage, onOpenSources, onSourceDetail, }: QaMessageProps) => import("react/jsx-runtime").JSX.Element>;
29
+ export declare const QaMessage: import("react").MemoExoticComponent<({ message, renderMarkdown, showTimestamp, stateKey, onRegenerate, resolveImage, onOpenSources, onSourceDetail, thinkingPhrases, }: QaMessageProps) => import("react/jsx-runtime").JSX.Element>;
28
30
  //# sourceMappingURL=QaMessage.d.ts.map
@@ -0,0 +1,26 @@
1
+ import { type ReactNode } from "react";
2
+ export interface QaModalProps {
3
+ readonly open: boolean;
4
+ /** Dialog title; also the dialog's accessible name. */
5
+ readonly title: string;
6
+ /** Accessible label of the close control, e.g. "Закрыть профиль". */
7
+ readonly closeLabel: string;
8
+ readonly onClose: () => void;
9
+ readonly children: ReactNode;
10
+ /** Actions pinned under the body; omit for a body-only dialog. */
11
+ readonly footer?: ReactNode;
12
+ /**
13
+ * Wider panel, for a dialog whose prose must not wrap mid-sentence: the
14
+ * profile form and the changelog both take it. The default width stays with
15
+ * the text-list dialogs it was sized for.
16
+ */
17
+ readonly wide?: boolean;
18
+ }
19
+ /**
20
+ * The shared QA dialog shell: backdrop, panel, head with the close control,
21
+ * a scrolling body, and an optional footer. Escape and a backdrop click close
22
+ * it, and the close control takes focus on open. Rendering is a no-op while
23
+ * closed, so a closed dialog costs nothing.
24
+ */
25
+ export declare function QaModal(props: QaModalProps): import("react/jsx-runtime").JSX.Element | null;
26
+ //# sourceMappingURL=QaModal.d.ts.map
@@ -0,0 +1,25 @@
1
+ import type { QaAccountIdentityField, QaAccountProfile, QaAccountProfileInput } from "../../types.js";
2
+ export interface QaProfileModalProps {
3
+ readonly open: boolean;
4
+ readonly email: string;
5
+ readonly profile: QaAccountProfile;
6
+ /** Handle fields the deployment declares, in its configured order. */
7
+ readonly identities: readonly QaAccountIdentityField[];
8
+ readonly instructionsMaxLength: number;
9
+ readonly onClose: () => void;
10
+ /**
11
+ * Persist the edited profile. Resolves to audience-safe refusal copy, or
12
+ * null once the Host stored it.
13
+ */
14
+ readonly onSave: (input: QaAccountProfileInput) => Promise<string | null>;
15
+ }
16
+ /**
17
+ * The signed-in user's own profile: the full name, one field per declared
18
+ * external system, and the free-form instructions the assistant receives.
19
+ *
20
+ * The form is seeded from the stored profile each time it opens, so a closed
21
+ * dialog never keeps stale edits; limits mirror the Host's, which stays the
22
+ * authority — the browser only avoids a round trip for the obvious refusals.
23
+ */
24
+ export declare function QaProfileModal(props: QaProfileModalProps): import("react/jsx-runtime").JSX.Element;
25
+ //# sourceMappingURL=QaProfile.d.ts.map
@@ -0,0 +1,13 @@
1
+ import type { QaPendingQuestion, QaQuestionAnswerItem } from "../../types.js";
2
+ export interface QaQuestionsProps {
3
+ readonly questions: readonly QaPendingQuestion[];
4
+ readonly onAnswer: (requestId: string, answers: readonly QaQuestionAnswerItem[]) => Promise<void>;
5
+ readonly onCancel: (requestId: string) => Promise<void>;
6
+ }
7
+ /**
8
+ * The questions a running turn waits on. Answers are the operator's own: the
9
+ * form refuses to submit a question left blank, and a question explicitly
10
+ * skipped is reported as skipped rather than answered by guesswork.
11
+ */
12
+ export declare const QaQuestions: import("react").MemoExoticComponent<(props: QaQuestionsProps) => import("react/jsx-runtime").JSX.Element | null>;
13
+ //# sourceMappingURL=QaQuestions.d.ts.map
@@ -0,0 +1,23 @@
1
+ import type { ReactNode } from "react";
2
+ import type { QaRailTab } from "../use-session-ui-state.js";
3
+ /** One rail tab's strip chip: label, live count, and its body is the panel. */
4
+ export interface QaRailTabModel {
5
+ readonly id: QaRailTab;
6
+ readonly title: string;
7
+ /** Items the tab will show; 0 hides the badge. */
8
+ readonly count: number;
9
+ readonly body: ReactNode;
10
+ }
11
+ export interface QaRightRailProps {
12
+ readonly tabs: readonly QaRailTabModel[];
13
+ readonly activeTab: QaRailTab;
14
+ readonly onTabSelect: (tab: QaRailTab) => void;
15
+ readonly onClose: () => void;
16
+ }
17
+ /**
18
+ * The chat's right rail: a fixed column whose top edge is the tab strip,
19
+ * mirroring the Harness right Sidebar's chrome. Tabs are plain chips with
20
+ * counts; the strip's last control collapses the whole column.
21
+ */
22
+ export declare function QaRightRail({ tabs, activeTab, onTabSelect, onClose, }: QaRightRailProps): import("react/jsx-runtime").JSX.Element | null;
23
+ //# sourceMappingURL=QaRightRail.d.ts.map
@@ -1,4 +1,5 @@
1
1
  import type { SessionSummary } from "@deepseek-ai/dsh-api-session-controller/client";
2
+ import type { QaAccountIdentityField, QaAccountProfile, QaAccountProfileInput } from "../../types.js";
2
3
  /** One renderable row of the chat-history sidebar. */
3
4
  export interface QaChatRow {
4
5
  readonly id: string;
@@ -56,6 +57,19 @@ export interface QaSidebarProps {
56
57
  readonly email: string;
57
58
  readonly role: string;
58
59
  readonly onLogout: () => void;
60
+ /**
61
+ * Self-service profile editing. Omitted when the deployment turns the
62
+ * feature off, which also leaves the footer name as plain text. Memoized
63
+ * by the caller: this object is compared by reference.
64
+ */
65
+ readonly profileDialog?: {
66
+ readonly profile: QaAccountProfile;
67
+ /** Handle fields the dialog renders, in the deployment's order. */
68
+ readonly fields: readonly QaAccountIdentityField[];
69
+ readonly instructionsMaxLength: number;
70
+ /** Persist edited fields; resolves to refusal copy, or null. */
71
+ readonly onSave: (input: QaAccountProfileInput) => Promise<string | null>;
72
+ };
59
73
  };
60
74
  }
61
75
  /**
@@ -3,7 +3,7 @@ import type { QaBoundSourceApi } from "../types.js";
3
3
  export declare function SourceIcon({ kind }: {
4
4
  readonly kind: QaSource["kind"];
5
5
  }): import("react/jsx-runtime").JSX.Element;
6
- export interface QaSourcesDrawerProps {
6
+ export interface QaSourcesPanelProps {
7
7
  readonly sources: readonly QaSource[];
8
8
  readonly complete: boolean;
9
9
  readonly incompleteOrigins?: QaTurnSources["incompleteOrigins"];
@@ -13,8 +13,11 @@ export interface QaSourcesDrawerProps {
13
13
  readonly filePreview: ResolvedQaSurfaceConfig["sources"]["filePreview"];
14
14
  /** Open straight onto this source's detail (an inline footnote click). */
15
15
  readonly initialDetail?: QaSource | null;
16
- readonly onClose: () => void;
16
+ /** The list is a message-scoped subset rather than the whole chat. */
17
+ readonly pinned?: boolean;
18
+ /** Dismiss the pinned subset and show the whole chat's sources. */
19
+ readonly onShowAll?: () => void;
17
20
  }
18
21
  /** Canonical grouped source panel and safe local-file preview. */
19
- export declare function QaSourcesDrawer({ sources, complete, incompleteOrigins, sessionId, sourceApi, display, filePreview, initialDetail, onClose, }: QaSourcesDrawerProps): import("react/jsx-runtime").JSX.Element;
20
- //# sourceMappingURL=QaSourcesDrawer.d.ts.map
22
+ export declare function QaSourcesPanel({ sources, complete, incompleteOrigins, sessionId, sourceApi, display, filePreview, initialDetail, pinned, onShowAll, }: QaSourcesPanelProps): import("react/jsx-runtime").JSX.Element;
23
+ //# sourceMappingURL=QaSourcesPanel.d.ts.map
@@ -55,5 +55,11 @@ declare function QaTurnRailView({ items, activeTurn, busyTurn, scrollerRef, onNa
55
55
  export declare const QaTurnRail: import("react").MemoExoticComponent<typeof QaTurnRailView>;
56
56
  /** Land the transcript on a turn's prompt row, harness-style. */
57
57
  export declare function turnScrollTarget(scroller: HTMLElement, row: HTMLElement): number;
58
+ /**
59
+ * Find the message slot carrying `anchorId` and land the transcript on it,
60
+ * harness-style. Returns whether the anchor row exists; callers tie their
61
+ * near-bottom bookkeeping and rail-mark updates to that outcome.
62
+ */
63
+ export declare function scrollToTranscriptAnchor(scroller: HTMLElement, anchorId: string): boolean;
58
64
  export {};
59
65
  //# sourceMappingURL=QaTurnRail.d.ts.map
@@ -1,15 +1,21 @@
1
1
  import { type RefObject } from "react";
2
- /** DSH's dragged content-width floor; a lower operator cap still wins. */
3
- export declare const QA_CONTENT_MIN_WIDTH = 640;
4
2
  /**
5
3
  * Space kept outside the content: 88px per side leaves room for the handle,
6
- * its inset, and a safe zone that remains draggable in both directions.
4
+ * its inset, and a safe zone that remains draggable in both directions. It is
5
+ * the whole ceiling too: like DSH, the page bounds the width, so a wide column
6
+ * lets the transcript fill it.
7
7
  */
8
8
  export declare const QA_CONTENT_EDGE_BUDGET = 176;
9
9
  export declare function readQaContentWidth(storage: Pick<Storage, "getItem">, key: string): number | null;
10
10
  export declare function writeQaContentWidth(storage: Pick<Storage, "setItem">, key: string, width: number): void;
11
- /** Resolve the centered content width for the currently available column. */
12
- export declare function resolveQaContentWidth(columnWidth: number, preference: number | null, maxContentWidth: number): number;
11
+ /**
12
+ * Resolve the centered content width for the currently available column. The
13
+ * operator sets only the floor; the column is the ceiling, so the content may
14
+ * grow until its handles reach the edge budget and a wider window keeps
15
+ * widening it. A column too narrow even for the floor wins over the floor —
16
+ * there is nothing else to give up.
17
+ */
18
+ export declare function resolveQaContentWidth(columnWidth: number, preference: number | null, minContentWidth: number): number;
13
19
  interface QaWidthHandleProps {
14
20
  readonly side: "left" | "right";
15
21
  readonly onStart: () => number;
@@ -24,13 +30,14 @@ interface UseQaContentWidthOptions {
24
30
  readonly root: RefObject<HTMLDivElement | null>;
25
31
  readonly storage: Pick<Storage, "getItem" | "setItem">;
26
32
  readonly storageKey: string;
27
- readonly maxContentWidth: number;
33
+ readonly minContentWidth: number;
28
34
  }
29
- export declare function useQaContentWidth({ active, root, storage, storageKey, maxContentWidth, }: UseQaContentWidthOptions): {
35
+ export declare function useQaContentWidth({ active, root, storage, storageKey, minContentWidth, }: UseQaContentWidthOptions): {
30
36
  readonly onStart: () => number;
31
37
  readonly onDrag: (requestedWidth: number) => void;
32
38
  readonly onCommit: (requestedWidth: number) => void;
33
39
  readonly onEnd: () => void;
34
40
  };
41
+ export type UseQaContentWidthResult = ReturnType<typeof useQaContentWidth>;
35
42
  export {};
36
43
  //# sourceMappingURL=QaWidthHandle.d.ts.map
@@ -1,12 +1,14 @@
1
1
  import type { QaWorkItem } from "../../types.js";
2
2
  export interface QaWorkGroupProps {
3
- readonly status: "running" | "complete";
3
+ /** "error" marks a turn the host ended with a provider failure. */
4
+ readonly status: "running" | "complete" | "error";
4
5
  readonly startedAt?: number;
5
6
  readonly endedAt?: number;
6
7
  readonly items: readonly QaWorkItem[];
7
8
  readonly renderMarkdown: boolean;
9
+ /** Operator-configured running phrases; omitted reads the built-in list. */
10
+ readonly thinkingPhrases?: readonly string[];
8
11
  }
9
- export declare const THINKING_PHRASES: readonly string[];
10
12
  /**
11
13
  * Whether two work items render identically. The transcript projection
12
14
  * rebuilds every item object on each published frame, so memoized work rows
@@ -15,5 +17,5 @@ export declare const THINKING_PHRASES: readonly string[];
15
17
  export declare function sameWorkItem(a: QaWorkItem, b: QaWorkItem): boolean;
16
18
  /** Whether two work item lists render identically, item for item. */
17
19
  export declare function sameWorkItems(a: readonly QaWorkItem[], b: readonly QaWorkItem[]): boolean;
18
- export declare const QaWorkGroup: import("react").MemoExoticComponent<({ status, startedAt, endedAt, items, renderMarkdown, }: QaWorkGroupProps) => import("react/jsx-runtime").JSX.Element>;
20
+ export declare const QaWorkGroup: import("react").MemoExoticComponent<({ status, startedAt, endedAt, items, renderMarkdown, thinkingPhrases, }: QaWorkGroupProps) => import("react/jsx-runtime").JSX.Element>;
19
21
  //# sourceMappingURL=QaWorkGroup.d.ts.map
@@ -0,0 +1,11 @@
1
+ import type { QaSessionState } from "../../types.js";
2
+ /**
3
+ * Small pure projections of the session state shared by surface regions: the
4
+ * composer's status line and the conversation title. Keeping them out of
5
+ * QaSurface leaves that file pure composition.
6
+ */
7
+ /** The composer's status line, or null when nothing is due. */
8
+ export declare function statusText(state: QaSessionState, runningPhrase: string | null): string | null;
9
+ /** The conversation title derived from the first user prompt, clipped. */
10
+ export declare function titleFromMessages(state: QaSessionState): string | null;
11
+ //# sourceMappingURL=surface-utils.d.ts.map
@@ -0,0 +1,9 @@
1
+ import { DEFAULT_THINKING_PHRASES, thinkingPhrase } from "../../thinking-phrases.js";
2
+ export { DEFAULT_THINKING_PHRASES, thinkingPhrase };
3
+ /**
4
+ * Phrase for a turn that started at `startedAt`. Every reader that passes the
5
+ * same start time and phrase list lands on the same phrase, so the composer
6
+ * hint and the work list never disagree.
7
+ */
8
+ export declare function useThinkingPhrase(running: boolean, startedAt: number | undefined, phrases?: readonly string[]): string | null;
9
+ //# sourceMappingURL=thinking-phrases.d.ts.map
@@ -1,16 +1,13 @@
1
- import type { ResolvedQaSurfaceConfig } from "../types.js";
2
- import type { QaSessions, QaSessionsApi } from "./types.js";
1
+ import type { QaCreateSession } from "./types.js";
3
2
  /**
4
- * Create one Host session and pin the configured preset and model onto the
5
- * still-blank session. The creation wire takes no preset, so
6
- * agentPresets/select recomposes the agent and durably logs
7
- * `agent-preset/selected`, which the client projection replays. The session
3
+ * Ask the QA Host boundary to create a fully composed session. The browser
4
+ * supplies only its account token and cannot select cwd, workspace, owner,
5
+ * preset, model, or permission policy. The resulting session
8
6
  * is addressed only here — no prompt can run before the caller attests the
9
7
  * composed preset.
10
8
  */
11
9
  export declare function createQaSession(args: {
12
- readonly sessions: QaSessions;
13
- readonly api: QaSessionsApi;
14
- readonly config: ResolvedQaSurfaceConfig;
10
+ readonly createSession: QaCreateSession;
11
+ readonly token: string;
15
12
  }): Promise<string>;
16
13
  //# sourceMappingURL=create-session.d.ts.map
@@ -0,0 +1,19 @@
1
+ /**
2
+ * QA-facing copy for provider failures, keyed by the stable failure code the
3
+ * host records on retry and turn-end events. Raw provider messages never
4
+ * reach these rows — they can carry stack traces and local paths — so every
5
+ * text here derives from the code alone.
6
+ */
7
+ /** Terminal turn-failure row shown after the work group. */
8
+ export declare function turnErrorCopy(code: string | undefined): string;
9
+ export interface RetryCopySource {
10
+ readonly mode: "normal" | "always";
11
+ readonly retry: number;
12
+ readonly maxRetries?: number;
13
+ readonly delayMs: number;
14
+ readonly retryState: "scheduled" | "started" | "cancelled";
15
+ readonly failureCode?: string;
16
+ }
17
+ /** Work-group row for one host-scheduled model-request retry. */
18
+ export declare function retryWorkCopy(node: RetryCopySource): string;
19
+ //# sourceMappingURL=failure-copy.d.ts.map
@@ -1,6 +1,6 @@
1
1
  import type { SessionFace } from "@deepseek-ai/dsh-api-session-controller/client";
2
2
  import type { ConversationSnapshot } from "@deepseek-ai/dsh-client-ui-conversation/client";
3
- import type { QaSessionState, QaSubagentView, QaTurnSources, ResolvedQaSurfaceConfig } from "../types.js";
3
+ import type { QaPendingApproval, QaPendingQuestion, QaSessionState, QaSubagentView, QaTurnSources, ResolvedQaSurfaceConfig } from "../types.js";
4
4
  /** Everything the bound-chat projection reads; the computation is pure. */
5
5
  export interface QaBoundProjectionInput {
6
6
  readonly connected: boolean;
@@ -9,6 +9,13 @@ export interface QaBoundProjectionInput {
9
9
  readonly conversationSnapshot: ConversationSnapshot | undefined;
10
10
  /** Turn bundles with the Host provenance already merged in (Host wins). */
11
11
  readonly sourceBundles: readonly QaTurnSources[];
12
+ /**
13
+ * Tool calls and questions the Host parked for the operator. They are
14
+ * host-side state, not part of the session snapshot, so the controller polls
15
+ * them separately.
16
+ */
17
+ readonly approvals: readonly QaPendingApproval[];
18
+ readonly questions: readonly QaPendingQuestion[];
12
19
  readonly operationError: string | null;
13
20
  readonly policyReady: boolean;
14
21
  readonly admissionPending: boolean;
@@ -0,0 +1,30 @@
1
+ import type { SessionFace } from "@deepseek-ai/dsh-api-session-controller/client";
2
+ import type { QaAttachmentDraft, QaFileDraft } from "../types.js";
3
+ import type { QaFileUpload, QaPromptContent } from "./types.js";
4
+ /**
5
+ * Stage every pending file on the Host and collect the receipts the prompt
6
+ * cites. Sequential on purpose: a partial batch must be attributable to the
7
+ * exact file that failed, and the visitor's file counts are small.
8
+ * `service` is undefined on a page the deployment serves without the upload
9
+ * plugin, which leaves attachments unavailable rather than broken. The
10
+ * receipt is opaque and host-minted — the upload service answers with a
11
+ * plain string, and only the session wire brand knows it as an id.
12
+ */
13
+ export declare function stageQaFiles(service: QaFileUpload | undefined, session: SessionFace, files: readonly QaFileDraft[]): Promise<{
14
+ readonly kind: "ok";
15
+ readonly receipts: Map<string, string>;
16
+ } | {
17
+ readonly kind: "unavailable";
18
+ } | {
19
+ readonly kind: "failed";
20
+ }>;
21
+ /**
22
+ * Assemble the wire content of one prompt: the text part, images riding the
23
+ * prompt inline, and files cited by their staged receipts. The visitor's own
24
+ * order decides the prompt order, so images and files are assembled from one
25
+ * walk over the drafts; an unpaired file receipt (a draft kept while its
26
+ * staging failed elsewhere) degrades to an empty receipt rather than
27
+ * dropping the attachment.
28
+ */
29
+ export declare function buildQaPromptContent(prompt: string, attachments: readonly QaAttachmentDraft[], receipts: ReadonlyMap<string, string>): QaPromptContent;
30
+ //# sourceMappingURL=prompt-content.d.ts.map
@@ -0,0 +1,45 @@
1
+ import type { QaPendingQuestion, QaQuestionAnswerItem } from "../types.js";
2
+ import type { QaQuestionApi } from "./types.js";
3
+ /**
4
+ * The operator's side of a parked `ask_user_question` call.
5
+ *
6
+ * Like a parked approval, the request lives on the Host: it survives a reload,
7
+ * and the surface learns about it by asking while a turn runs. Unlike an
8
+ * approval, an answer is a whole form — every question of the request, with the
9
+ * operator's selections and free text — so the bridge forwards the form and
10
+ * re-reads the list afterwards.
11
+ */
12
+ export declare class QaHostQuestionBridge {
13
+ private readonly questionApi;
14
+ private questions;
15
+ private signature;
16
+ private refreshing;
17
+ private answering;
18
+ /** Bumped on reset so a stale in-flight response never lands. */
19
+ private generation;
20
+ constructor(questionApi: QaQuestionApi | undefined);
21
+ /** Leave the chat: a chat switch drops the previous chat's requests. */
22
+ reset(): void;
23
+ /** The last list this bridge saw; empty when the deployment refuses them. */
24
+ list(): readonly QaPendingQuestion[];
25
+ /** Whether this page can ask the Host about questions at all. */
26
+ get available(): boolean;
27
+ /**
28
+ * Re-read the chat's pending questions; a changed list republishes through
29
+ * the callback. Overlapping calls coalesce, and a response that outlives its
30
+ * chat is dropped.
31
+ */
32
+ refresh(sessionId: string, token: string, onChanged: () => void): Promise<void>;
33
+ /** Send the operator's answers to one request and re-read the list. */
34
+ answer(sessionId: string, token: string, requestId: string, answers: readonly QaQuestionAnswerItem[]): Promise<void>;
35
+ /** Close one request without answering it. */
36
+ cancel(sessionId: string, token: string, requestId: string): Promise<void>;
37
+ /**
38
+ * Run one write against a request, then re-read the list it belonged to. A
39
+ * refusal is not an error: the request was already settled (the turn was
40
+ * stopped, the call went away), so the refresh — not the write — is what the
41
+ * surface shows.
42
+ */
43
+ private settle;
44
+ }
45
+ //# sourceMappingURL=questions.d.ts.map