@opengeni/react 0.23.0 → 0.25.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 (38) hide show
  1. package/dist/{chunk-UQS7OQDE.js → chunk-AVPU5PMC.js} +6 -4
  2. package/dist/chunk-AVPU5PMC.js.map +1 -0
  3. package/dist/{chunk-CATATY77.js → chunk-RDPDU4TA.js} +7 -6
  4. package/dist/chunk-RDPDU4TA.js.map +1 -0
  5. package/dist/{chunk-UAHPKLB6.js → chunk-SHOFILHJ.js} +18 -8
  6. package/dist/chunk-SHOFILHJ.js.map +1 -0
  7. package/dist/{composer-CVm5uoUI.d.ts → composer-BXb0Q1HF.d.ts} +18 -4
  8. package/dist/composer.d.ts +2 -2
  9. package/dist/composer.js +2 -2
  10. package/dist/fleet-decision-projection-SLNZMS42.js +241 -0
  11. package/dist/fleet-decision-projection-SLNZMS42.js.map +1 -0
  12. package/dist/fleet-decision-row-GGCAT4E4.js +351 -0
  13. package/dist/fleet-decision-row-GGCAT4E4.js.map +1 -0
  14. package/dist/index.d.ts +12 -9
  15. package/dist/index.js +332 -224
  16. package/dist/index.js.map +1 -1
  17. package/dist/{session-Db00TRwl.d.ts → session-BEvtFWhe.d.ts} +40 -14
  18. package/dist/session.d.ts +2 -2
  19. package/dist/session.js +2 -2
  20. package/dist/{use-composer-By1wn3MM.d.ts → use-composer-BnEzheSk.d.ts} +8 -2
  21. package/package.json +2 -2
  22. package/src/components/composer.tsx +7 -6
  23. package/src/components/message-timeline.tsx +2 -2
  24. package/src/hooks/use-composer.ts +15 -5
  25. package/src/hooks/use-file-attachments.ts +95 -2
  26. package/src/hooks/use-goal.ts +22 -4
  27. package/src/hooks/use-workspace-sessions.ts +30 -5
  28. package/src/timeline/activity-rail.tsx +17 -1
  29. package/src/timeline/fleet-decision-projection.ts +366 -0
  30. package/src/timeline/fleet-decision-row.tsx +412 -0
  31. package/src/timeline/index.ts +2 -0
  32. package/src/timeline/projection.ts +19 -8
  33. package/src/timeline/tool-display-name.ts +16 -0
  34. package/src/timeline/tool-renderers.tsx +1 -1
  35. package/src/timeline/types.ts +68 -1
  36. package/dist/chunk-CATATY77.js.map +0 -1
  37. package/dist/chunk-UAHPKLB6.js.map +0 -1
  38. package/dist/chunk-UQS7OQDE.js.map +0 -1
@@ -33,6 +33,8 @@ function useComposer(sessionId, options = {}) {
33
33
  const onDraftApplied = options.onDraftApplied;
34
34
  const sendExtrasRef = useRef(options.sendExtras);
35
35
  sendExtrasRef.current = options.sendExtras;
36
+ const sendBlockedRef = useRef(options.sendBlocked);
37
+ sendBlockedRef.current = options.sendBlocked;
36
38
  const liveExtrasVersion = JSON.stringify(resolveSendExtras(options.sendExtras));
37
39
  const targetKeyRef = useRef(targetKey);
38
40
  useLayoutEffect(() => {
@@ -246,7 +248,7 @@ function useComposer(sessionId, options = {}) {
246
248
  const hasText = rawText.trim().length > 0;
247
249
  const extras = resolveSendExtras(sendExtrasRef.current);
248
250
  const hasResources = restoredResources.length > 0 || (extras.resources?.length ?? 0) > 0;
249
- if (!hasText && !hasResources || !sessionId || sending || targetKeyRef.current !== ownedTargetKey) {
251
+ if (!hasText && !hasResources || !sessionId || sending || sendBlockedRef.current?.() === true || targetKeyRef.current !== ownedTargetKey) {
250
252
  return false;
251
253
  }
252
254
  pendingClientEventId.current ??= generateClientEventId();
@@ -299,7 +301,7 @@ function useComposer(sessionId, options = {}) {
299
301
  setValue("");
300
302
  }
301
303
  }
302
- onSent?.(sendText);
304
+ onSent?.(sendText, input);
303
305
  return true;
304
306
  } catch (cause) {
305
307
  if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
@@ -498,7 +500,7 @@ function useComposer(sessionId, options = {}) {
498
500
  send,
499
501
  steer,
500
502
  sending: identityMatches ? sending : false,
501
- canSend: identityMatches && Boolean(sessionId) && !sending && (value.trim().length > 0 || hasReadyResources),
503
+ canSend: identityMatches && Boolean(sessionId) && !sending && sendBlockedRef.current?.() !== true && (value.trim().length > 0 || hasReadyResources),
502
504
  pause,
503
505
  pausing: identityMatches ? pausing : false,
504
506
  resume,
@@ -588,4 +590,4 @@ export {
588
590
  shouldSubmitOnKey,
589
591
  shouldSteerOnKey
590
592
  };
591
- //# sourceMappingURL=chunk-UQS7OQDE.js.map
593
+ //# sourceMappingURL=chunk-AVPU5PMC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/use-composer.ts"],"sourcesContent":["import type {\n ComposerDraft,\n EffectiveControlResumeOption,\n EffectiveSessionControl,\n ResourceRef,\n SaveComposerDraftRequest,\n SendMessageInput,\n SessionEvent,\n} from \"@opengeni/sdk\";\nimport { useCallback, useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport { useEmbeddedSession, type EmbeddedSessionClientOverride } from \"../session-context\";\nimport { useSessionEventTrigger, type SessionEventFeedOptions } from \"./internal\";\n\nexport type ComposerSendExtras = Omit<SendMessageInput, \"text\" | \"clientEventId\">;\n\nexport type UseComposerOptions = EmbeddedSessionClientOverride &\n SessionEventFeedOptions & {\n /** Called with the exact accepted wire input after a successful send. */\n onSent?: ((text: string, input: SendMessageInput) => void) | undefined;\n /**\n * Extra message fields (resources, tools, model, reasoningEffort) merged\n * into every send. A function is evaluated at send time so it can read the\n * surrounding UI state (attachment pickers, model selectors, ...).\n */\n sendExtras?: ComposerSendExtras | (() => ComposerSendExtras) | undefined;\n /**\n * Fail-closed delivery guard evaluated at send time. Attachment hosts use\n * this to preserve unresolved upload cards until the operator waits,\n * retries, or removes them; direct hook callers cannot bypass the UI gate.\n */\n sendBlocked?: (() => boolean) | undefined;\n /** Latest server-derived workstream control; bound into Send/Steer OCC. */\n effectiveControl?: EffectiveSessionControl | null | undefined;\n /** Apply durable model/tool/reasoning settings in the host's controlled UI. */\n onDraftApplied?: ((draft: ComposerDraft) => void) | undefined;\n /** Disable remote composer-draft reads and writes for embedded hosts. */\n draftPersistence?: \"durable\" | \"disabled\" | undefined;\n };\n\nexport type ComposerState = {\n value: string;\n setValue: (value: string) => void;\n /** Read the current draft synchronously before a destructive replacement. */\n hasDraftContent: () => boolean;\n /** Append the draft behind prompts already visible in the queue. */\n send: (text?: string) => Promise<boolean>;\n /** Supersede current direction with the draft. */\n steer: (text?: string) => Promise<boolean>;\n sending: boolean;\n canSend: boolean;\n /** Pause the session without deleting its prompt queue. */\n pause: (reason?: string) => Promise<void>;\n pausing: boolean;\n resume: (reason?: string) => Promise<void>;\n resumeScope: (option: EffectiveControlResumeOption) => Promise<void>;\n resuming: boolean;\n draft: ComposerDraft | null;\n draftRevision: number;\n draftLoading: boolean;\n draftSaving: boolean;\n draftConflict: Error | null;\n /** Whether this controller owns a durable server-side draft. */\n draftPersistence?: \"durable\" | \"disabled\" | undefined;\n /** Apply an atomic queue Edit checkout without a second read. */\n applyDraft: (draft: ComposerDraft) => void;\n reloadDraft: () => Promise<void>;\n resolveDraftConflict: (choice: \"keep_mine\" | \"use_remote\") => Promise<void>;\n restoredResources: ResourceRef[];\n removeRestoredResource: (index: number) => void;\n error: Error | null;\n clearError: () => void;\n};\n\n/**\n * Draft + send + Pause/Resume state for the chat composer — the only\n * human-to-agent input surface. The draft survives a failed send (nothing is\n * more hostile than losing a typed message); each send carries a generated\n * `clientEventId` so retries stay idempotent server-side.\n */\nexport function useComposer(\n sessionId: string | null | undefined,\n options: UseComposerOptions = {},\n): ComposerState {\n const { client, workspaceId, registerSessionReconciler } = useEmbeddedSession(options);\n const durableDrafts = options.draftPersistence !== \"disabled\";\n const targetKey = `${workspaceId}\\u0000${sessionId ?? \"\"}\\u0000${durableDrafts ? \"durable\" : \"disabled\"}`;\n const [value, setValue] = useState(\"\");\n // Keep rendered state behind the committed target identity for one frame:\n // a parent may switch sessionId without remounting this public hook.\n const [stateTargetKey, setStateTargetKey] = useState(targetKey);\n const [sending, setSending] = useState(false);\n const [pausing, setPausing] = useState(false);\n const [resuming, setResuming] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [draft, setDraft] = useState<ComposerDraft | null>(null);\n const [draftLoading, setDraftLoading] = useState(Boolean(sessionId) && durableDrafts);\n const [draftSaving, setDraftSaving] = useState(false);\n const [draftConflict, setDraftConflict] = useState<Error | null>(null);\n const [restoredResources, setRestoredResources] = useState<ResourceRef[]>([]);\n const pendingClientEventId = useRef<string | null>(null);\n const valueRef = useRef(\"\");\n const draftRef = useRef<ComposerDraft | null>(null);\n const restoredResourcesRef = useRef<ResourceRef[]>([]);\n const localEditRevision = useRef(0);\n const targetGeneration = useRef(0);\n const draftReadGeneration = useRef(0);\n const lastSavedSignature = useRef<string | null>(null);\n const saveChain = useRef<Promise<void>>(Promise.resolve());\n const onSent = options.onSent;\n const onDraftApplied = options.onDraftApplied;\n // Read through a ref so a new extras closure (created every render by\n // callers passing inline functions) does not invalidate `send`.\n const sendExtrasRef = useRef(options.sendExtras);\n sendExtrasRef.current = options.sendExtras;\n const sendBlockedRef = useRef(options.sendBlocked);\n sendBlockedRef.current = options.sendBlocked;\n const liveExtrasVersion = JSON.stringify(resolveSendExtras(options.sendExtras));\n\n // A composer is bound to one session: switching targets must not leak the\n // previous session's draft, error, or retry idempotency key.\n const targetKeyRef = useRef(targetKey);\n useLayoutEffect(() => {\n if (targetKeyRef.current === targetKey) return;\n targetKeyRef.current = targetKey;\n targetGeneration.current += 1;\n draftReadGeneration.current += 1;\n pendingClientEventId.current = null;\n localEditRevision.current = 0;\n valueRef.current = \"\";\n draftRef.current = null;\n restoredResourcesRef.current = [];\n lastSavedSignature.current = null;\n // Old saves may still be awaiting the network. Their generation fence\n // prevents settlement, and a fresh chain avoids blocking this target.\n saveChain.current = Promise.resolve();\n setStateTargetKey(targetKey);\n setValue(\"\");\n setSending(false);\n setPausing(false);\n setResuming(false);\n setError(null);\n setDraft(null);\n setDraftLoading(Boolean(sessionId) && durableDrafts);\n setDraftSaving(false);\n setDraftConflict(null);\n setRestoredResources([]);\n }, [durableDrafts, sessionId, targetKey]);\n\n const applyDraft = useCallback(\n (next: ComposerDraft): void => {\n if (targetKeyRef.current !== targetKey) return;\n if (!durableDrafts) {\n pendingClientEventId.current = null;\n localEditRevision.current += 1;\n valueRef.current = next.text;\n restoredResourcesRef.current = next.resources;\n draftRef.current = null;\n lastSavedSignature.current = null;\n setDraft(null);\n setValue(next.text);\n setRestoredResources(next.resources);\n setDraftConflict(null);\n return;\n }\n valueRef.current = next.text;\n draftRef.current = next;\n restoredResourcesRef.current = next.resources;\n lastSavedSignature.current = draftSignature(draftPayload(next));\n localEditRevision.current += 1;\n pendingClientEventId.current = null;\n setDraft(next);\n setValue(next.text);\n setRestoredResources(next.resources);\n setDraftConflict(null);\n onDraftApplied?.(next);\n },\n [durableDrafts, onDraftApplied, targetKey],\n );\n\n const loadDraft = useCallback(\n async (replaceLocal: boolean): Promise<void> => {\n if (targetKeyRef.current !== targetKey) return;\n if (!sessionId || !durableDrafts) {\n setDraftLoading(false);\n return;\n }\n const generation = targetGeneration.current;\n const readTicket = ++draftReadGeneration.current;\n const localAtStart = localEditRevision.current;\n const baseAtStart = draftRef.current;\n const extrasAtStart = resolveSendExtras(sendExtrasRef.current);\n const localSignatureAtStart = baseAtStart\n ? draftSignature(\n composerDraftPayload(\n baseAtStart,\n valueRef.current,\n restoredResourcesRef.current,\n extrasAtStart,\n ),\n )\n : null;\n const localWasDirtyAtStart =\n localSignatureAtStart === null\n ? localAtStart !== 0\n : localSignatureAtStart !== lastSavedSignature.current;\n setDraftLoading(true);\n try {\n const fetched = await client.getComposerDraft(workspaceId, sessionId);\n if (\n generation !== targetGeneration.current ||\n targetKeyRef.current !== targetKey ||\n readTicket !== draftReadGeneration.current\n ) {\n return;\n }\n const currentRevision = draftRef.current?.revision ?? -1;\n if (fetched.revision >= currentRevision) {\n draftRef.current = fetched;\n setDraft(fetched);\n setDraftConflict(null);\n if (\n replaceLocal ||\n (!localWasDirtyAtStart && localAtStart === localEditRevision.current)\n ) {\n valueRef.current = fetched.text;\n restoredResourcesRef.current = fetched.resources;\n lastSavedSignature.current = draftSignature(draftPayload(fetched));\n setValue(fetched.text);\n setRestoredResources(fetched.resources);\n onDraftApplied?.(fetched);\n }\n }\n } catch (cause) {\n if (\n generation === targetGeneration.current &&\n targetKeyRef.current === targetKey &&\n readTicket === draftReadGeneration.current\n ) {\n setError(asError(cause));\n }\n } finally {\n if (\n generation === targetGeneration.current &&\n targetKeyRef.current === targetKey &&\n readTicket === draftReadGeneration.current\n ) {\n setDraftLoading(false);\n }\n }\n },\n [client, durableDrafts, onDraftApplied, sessionId, targetKey, workspaceId],\n );\n\n useEffect(() => {\n if (!sessionId || !durableDrafts) {\n setDraftLoading(false);\n return;\n }\n void loadDraft(false);\n }, [durableDrafts, loadDraft, sessionId]);\n useEffect(() => {\n if (!sessionId || !durableDrafts) return;\n return registerSessionReconciler(sessionId, \"composer\", async () => await loadDraft(false));\n }, [durableDrafts, loadDraft, registerSessionReconciler, sessionId]);\n useSessionEventTrigger(\n client,\n workspaceId,\n sessionId,\n isComposerDraftEvent,\n () => void loadDraft(false),\n {\n enabled: Boolean(sessionId) && durableDrafts,\n ...(options.events !== undefined ? { events: options.events } : {}),\n },\n );\n\n const currentDraftPayload = useCallback((): SaveComposerDraftRequest | null => {\n if (!durableDrafts || targetKeyRef.current !== targetKey) return null;\n const base = draftRef.current;\n if (!base) return null;\n const extras = resolveSendExtras(sendExtrasRef.current);\n return composerDraftPayload(base, value, restoredResources, extras);\n }, [durableDrafts, restoredResources, targetKey, value]);\n\n const persistPayload = useCallback(\n async (payload: SaveComposerDraftRequest): Promise<boolean> => {\n const ownedTargetKey = targetKey;\n const ownedGeneration = targetGeneration.current;\n if (!sessionId || !durableDrafts || targetKeyRef.current !== ownedTargetKey) {\n return false;\n }\n let success = false;\n const run = async () => {\n if (\n targetKeyRef.current !== ownedTargetKey ||\n targetGeneration.current !== ownedGeneration\n ) {\n return;\n }\n const current = draftRef.current;\n if (!current) return;\n const request = { ...payload, expectedRevision: current.revision };\n const signature = draftSignature(request);\n if (signature === lastSavedSignature.current) {\n success = true;\n return;\n }\n setDraftSaving(true);\n try {\n const saved = await client.saveComposerDraft(workspaceId, sessionId, request);\n if (\n targetKeyRef.current !== ownedTargetKey ||\n targetGeneration.current !== ownedGeneration\n ) {\n return;\n }\n draftRef.current = saved;\n setDraft(saved);\n lastSavedSignature.current = signature;\n setDraftConflict(null);\n success = true;\n } catch (cause) {\n if (\n targetKeyRef.current === ownedTargetKey &&\n targetGeneration.current === ownedGeneration\n ) {\n const problem = asError(cause);\n setDraftConflict(problem);\n setError(problem);\n }\n } finally {\n if (\n targetKeyRef.current === ownedTargetKey &&\n targetGeneration.current === ownedGeneration\n ) {\n setDraftSaving(false);\n }\n }\n };\n saveChain.current = saveChain.current.then(run, run);\n await saveChain.current;\n return success;\n },\n [client, durableDrafts, sessionId, targetKey, workspaceId],\n );\n\n // Private durable autosave. A newer local edit is never replaced by an older\n // response; saves serialize and each reads the latest acknowledged revision.\n useEffect(() => {\n if (\n !durableDrafts ||\n !sessionId ||\n draftLoading ||\n sending ||\n !draftRef.current ||\n draftConflict\n )\n return;\n const payload = currentDraftPayload();\n if (!payload || draftSignature(payload) === lastSavedSignature.current) return;\n const timer = window.setTimeout(() => void persistPayload(payload), 500);\n return () => window.clearTimeout(timer);\n }, [\n currentDraftPayload,\n durableDrafts,\n draftConflict,\n draftLoading,\n liveExtrasVersion,\n persistPayload,\n sending,\n sessionId,\n ]);\n\n const dispatch = useCallback(\n async (delivery: \"send\" | \"steer\", explicit?: string): Promise<boolean> => {\n const ownedTargetKey = targetKey;\n const ownedGeneration = targetGeneration.current;\n const draftAtSend = value;\n const rawText = explicit ?? draftAtSend;\n const hasText = rawText.trim().length > 0;\n // Resolve the extras once: a file-only message (empty text + ≥1 ready\n // resource) is legitimate, so we must not bail on empty text alone.\n const extras = resolveSendExtras(sendExtrasRef.current);\n const hasResources = restoredResources.length > 0 || (extras.resources?.length ?? 0) > 0;\n if (\n (!hasText && !hasResources) ||\n !sessionId ||\n sending ||\n sendBlockedRef.current?.() === true ||\n targetKeyRef.current !== ownedTargetKey\n ) {\n return false;\n }\n // Reuse the clientEventId across retries of the same draft so a\n // timeout + resend cannot double-deliver the message.\n pendingClientEventId.current ??= generateClientEventId();\n setSending(true);\n setError(null);\n try {\n // Trimming is only an emptiness check. A non-blank prompt is persisted\n // and submitted byte-for-byte, while file-only sends use the same\n // placeholder for both operations so the server content fence cannot\n // reject its own client.\n const sendText = hasText ? rawText : FILE_ONLY_MESSAGE_TEXT;\n const currentPayload = currentDraftPayload();\n const payload = currentPayload ? { ...currentPayload, text: sendText } : null;\n if (payload && !(await persistPayload(payload))) return false;\n if (\n targetKeyRef.current !== ownedTargetKey ||\n targetGeneration.current !== ownedGeneration\n ) {\n return false;\n }\n // The wire contract requires non-empty text (z.string().min(1)) and the\n // worker rejects whitespace-only text; a file-only message therefore\n // carries a minimal default so the attachments still get delivered.\n const acknowledgedDraft = draftRef.current;\n const sendExtras =\n acknowledgedDraft?.toolsProvided === true &&\n !Object.prototype.hasOwnProperty.call(extras, \"tools\")\n ? { ...extras, tools: acknowledgedDraft.tools }\n : extras;\n const input = composeSendInput(sendText, pendingClientEventId.current, sendExtras, {\n ...(options.effectiveControl?.controlEtag\n ? { controlEtag: options.effectiveControl.controlEtag }\n : {}),\n ...(durableDrafts && draftRef.current\n ? { expectedDraftRevision: draftRef.current.revision }\n : {}),\n resources: mergeResources(restoredResources, extras.resources ?? []),\n });\n if (delivery === \"steer\") {\n await client.steerMessage(workspaceId, sessionId, input);\n } else {\n await client.sendMessage(workspaceId, sessionId, input);\n }\n if (\n targetKeyRef.current !== ownedTargetKey ||\n targetGeneration.current !== ownedGeneration\n ) {\n return false;\n }\n pendingClientEventId.current = null;\n const previousDraft = draftRef.current;\n if (previousDraft) {\n const cleared = {\n ...previousDraft,\n revision: 0,\n text: \"\",\n resources: [],\n sourceTurnId: null,\n sourceTurnVersion: null,\n updatedAt: null,\n };\n draftRef.current = cleared;\n restoredResourcesRef.current = [];\n setDraft(cleared);\n setRestoredResources([]);\n lastSavedSignature.current = draftSignature(draftPayload(cleared));\n }\n if (explicit === undefined) {\n // Clear only the draft that was sent: edits made while the request\n // was in flight were never delivered and must survive.\n if (valueRef.current === draftAtSend) {\n valueRef.current = \"\";\n setValue(\"\");\n }\n }\n onSent?.(sendText, input);\n return true;\n } catch (cause) {\n if (\n targetKeyRef.current === ownedTargetKey &&\n targetGeneration.current === ownedGeneration\n ) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n }\n return false;\n } finally {\n if (\n targetKeyRef.current === ownedTargetKey &&\n targetGeneration.current === ownedGeneration\n ) {\n setSending(false);\n }\n }\n },\n [\n client,\n currentDraftPayload,\n durableDrafts,\n onSent,\n options.effectiveControl?.controlEtag,\n persistPayload,\n restoredResources,\n sending,\n sessionId,\n targetKey,\n value,\n workspaceId,\n ],\n );\n\n const send = useCallback(async (text?: string) => await dispatch(\"send\", text), [dispatch]);\n const steer = useCallback(async (text?: string) => await dispatch(\"steer\", text), [dispatch]);\n\n // A send is possible with non-empty text OR with ≥1 attached resource (a\n // file-only message). Resources ride in `sendExtras`, so we resolve them here\n // — keeping useComposer attachment-agnostic while still lighting up the send\n // affordance the moment a file is ready. Attachment hosts bind `sendBlocked`\n // to unresolved uploads so direct send()/steer() calls fail closed too.\n const hasReadyResources =\n restoredResources.length > 0 ||\n (resolveSendExtras(sendExtrasRef.current).resources?.length ?? 0) > 0;\n\n const pause = useCallback(\n async (reason?: string): Promise<void> => {\n const ownedTargetKey = targetKey;\n const ownedGeneration = targetGeneration.current;\n if (!sessionId || pausing || targetKeyRef.current !== ownedTargetKey) {\n return;\n }\n setPausing(true);\n setError(null);\n try {\n await client.pauseSession(workspaceId, sessionId, {\n ...(reason !== undefined ? { reason } : {}),\n ...(options.effectiveControl?.controlEtag\n ? { expectedControlEtag: options.effectiveControl.controlEtag }\n : {}),\n });\n } catch (cause) {\n if (\n targetKeyRef.current === ownedTargetKey &&\n targetGeneration.current === ownedGeneration\n ) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n }\n } finally {\n if (\n targetKeyRef.current === ownedTargetKey &&\n targetGeneration.current === ownedGeneration\n ) {\n setPausing(false);\n }\n }\n },\n [client, workspaceId, sessionId, pausing, options.effectiveControl?.controlEtag, targetKey],\n );\n\n const resume = useCallback(\n async (reason?: string): Promise<void> => {\n const ownedTargetKey = targetKey;\n const ownedGeneration = targetGeneration.current;\n if (!sessionId || resuming || targetKeyRef.current !== ownedTargetKey) return;\n setResuming(true);\n setError(null);\n try {\n await client.resumeSession(workspaceId, sessionId, {\n ...(reason !== undefined ? { reason } : {}),\n ...(options.effectiveControl?.controlEtag\n ? { expectedControlEtag: options.effectiveControl.controlEtag }\n : {}),\n });\n } catch (cause) {\n if (\n targetKeyRef.current === ownedTargetKey &&\n targetGeneration.current === ownedGeneration\n ) {\n setError(cause instanceof Error ? cause : new Error(String(cause)));\n }\n } finally {\n if (\n targetKeyRef.current === ownedTargetKey &&\n targetGeneration.current === ownedGeneration\n ) {\n setResuming(false);\n }\n }\n },\n [client, workspaceId, sessionId, resuming, options.effectiveControl?.controlEtag, targetKey],\n );\n\n const resumeScope = useCallback(\n async (option: EffectiveControlResumeOption): Promise<void> => {\n const ownedTargetKey = targetKey;\n const ownedGeneration = targetGeneration.current;\n if (!sessionId || resuming || targetKeyRef.current !== ownedTargetKey) return;\n setResuming(true);\n setError(null);\n try {\n if (option.scope === \"workspace\") {\n const workspaceBlocker = options.effectiveControl?.blockers.find(\n (blocker) => blocker.kind === \"workspace\",\n );\n if (!client.setWorkspaceInferenceState) {\n throw new Error(\n \"@opengeni/react: workspace-scoped resume requires setWorkspaceInferenceState.\",\n );\n }\n await client.setWorkspaceInferenceState(workspaceId, {\n action: \"resume\",\n clientEventId: generateClientEventId(),\n ...(workspaceBlocker ? { expectedRevision: workspaceBlocker.revision } : {}),\n });\n } else if (option.scope === \"session\" && option.targetId) {\n const target = await client.getQueue(workspaceId, option.targetId);\n if (\n targetKeyRef.current !== ownedTargetKey ||\n targetGeneration.current !== ownedGeneration\n ) {\n return;\n }\n await client.resumeSession(workspaceId, option.targetId, {\n expectedControlEtag: target.effectiveControl.controlEtag,\n });\n } else {\n await client.resumeSession(workspaceId, sessionId, {\n ...(options.effectiveControl?.controlEtag\n ? { expectedControlEtag: options.effectiveControl.controlEtag }\n : {}),\n });\n }\n } catch (cause) {\n if (\n targetKeyRef.current === ownedTargetKey &&\n targetGeneration.current === ownedGeneration\n ) {\n setError(asError(cause));\n }\n } finally {\n if (\n targetKeyRef.current === ownedTargetKey &&\n targetGeneration.current === ownedGeneration\n ) {\n setResuming(false);\n }\n }\n },\n [client, options.effectiveControl, resuming, sessionId, targetKey, workspaceId],\n );\n\n const updateValue = useCallback(\n (next: string) => {\n if (targetKeyRef.current !== targetKey) return;\n pendingClientEventId.current = null;\n localEditRevision.current += 1;\n valueRef.current = next;\n setValue(next);\n },\n [targetKey],\n );\n\n const removeRestoredResource = useCallback(\n (index: number) => {\n if (targetKeyRef.current !== targetKey) return;\n localEditRevision.current += 1;\n const next = restoredResourcesRef.current.filter((_, candidate) => candidate !== index);\n restoredResourcesRef.current = next;\n setRestoredResources(next);\n },\n [targetKey],\n );\n\n const hasDraftContent = useCallback((): boolean => {\n const current = draftRef.current;\n const extras = resolveSendExtras(sendExtrasRef.current);\n const toolsProvidedByHost = Object.prototype.hasOwnProperty.call(extras, \"tools\");\n const tools = toolsProvidedByHost ? (extras.tools ?? []) : (current?.tools ?? []);\n return (\n valueRef.current.length > 0 ||\n restoredResourcesRef.current.length > 0 ||\n (extras.resources?.length ?? 0) > 0 ||\n tools.length > 0 ||\n (current?.sourceTurnId !== null && current?.sourceTurnId !== undefined)\n );\n }, []);\n\n const resolveDraftConflict = useCallback(\n async (choice: \"keep_mine\" | \"use_remote\"): Promise<void> => {\n const ownedTargetKey = targetKey;\n const ownedGeneration = targetGeneration.current;\n if (!sessionId || !durableDrafts || targetKeyRef.current !== ownedTargetKey) return;\n const remote = await client.getComposerDraft(workspaceId, sessionId);\n if (targetKeyRef.current !== ownedTargetKey || targetGeneration.current !== ownedGeneration) {\n return;\n }\n if (choice === \"use_remote\") {\n applyDraft(remote);\n return;\n }\n draftRef.current = remote;\n setDraft(remote);\n setDraftConflict(null);\n const payload = currentDraftPayload();\n if (payload) await persistPayload({ ...payload, expectedRevision: remote.revision });\n },\n [\n applyDraft,\n client,\n currentDraftPayload,\n durableDrafts,\n persistPayload,\n sessionId,\n targetKey,\n workspaceId,\n ],\n );\n\n const identityMatches = stateTargetKey === targetKey;\n const reloadDraft = useCallback(async () => await loadDraft(true), [loadDraft]);\n const clearError = useCallback(() => {\n if (targetKeyRef.current !== targetKey) return;\n setError(null);\n setDraftConflict(null);\n }, [targetKey]);\n\n return {\n value: identityMatches ? value : \"\",\n setValue: updateValue,\n hasDraftContent,\n send,\n steer,\n sending: identityMatches ? sending : false,\n canSend:\n identityMatches &&\n Boolean(sessionId) &&\n !sending &&\n sendBlockedRef.current?.() !== true &&\n (value.trim().length > 0 || hasReadyResources),\n pause,\n pausing: identityMatches ? pausing : false,\n resume,\n resumeScope,\n resuming: identityMatches ? resuming : false,\n draft: identityMatches ? draft : null,\n draftRevision: identityMatches ? (draft?.revision ?? 0) : 0,\n draftLoading: identityMatches ? draftLoading : Boolean(sessionId) && durableDrafts,\n draftSaving: identityMatches ? draftSaving : false,\n draftConflict: identityMatches ? draftConflict : null,\n draftPersistence: durableDrafts ? \"durable\" : \"disabled\",\n applyDraft,\n reloadDraft,\n resolveDraftConflict,\n restoredResources: identityMatches ? restoredResources : [],\n removeRestoredResource,\n error: identityMatches ? error : null,\n clearError,\n };\n}\n\n/** Events that can atomically replace or clear this subject's durable draft. */\nexport function isComposerDraftEvent(event: Pick<SessionEvent, \"type\">): boolean {\n return event.type === \"user.message\" || event.type === \"session.queue.changed\";\n}\n\n/**\n * Default text for a file-only message (attachment(s) present, no typed draft).\n * Kept non-empty so the wire contract (`text: z.string().min(1)`) and the\n * worker's non-whitespace guard accept it; the attached files still ride in\n * `resources`. Exported for tests.\n */\nexport const FILE_ONLY_MESSAGE_TEXT = \"(see attached files)\";\n\n/** Resolve possibly-deferred extras to a concrete bag (function evaluated now). */\nexport function resolveSendExtras(\n extras: ComposerSendExtras | (() => ComposerSendExtras) | undefined,\n): ComposerSendExtras {\n return (typeof extras === \"function\" ? extras() : extras) ?? {};\n}\n\n/**\n * Merge the draft text + idempotency key with caller-provided extras. The\n * text and clientEventId always win over extras. Exported for tests.\n */\nexport function composeSendInput(\n text: string,\n clientEventId: string,\n extras: ComposerSendExtras | (() => ComposerSendExtras) | undefined,\n bound: Partial<SendMessageInput> = {},\n): SendMessageInput {\n return { ...resolveSendExtras(extras), ...bound, text, clientEventId };\n}\n\n/** Submit on plain Enter; Shift+Enter inserts a newline. Exported for tests. */\nexport function shouldSubmitOnKey(event: {\n key: string;\n shiftKey: boolean;\n metaKey?: boolean;\n ctrlKey?: boolean;\n nativeEvent?: { isComposing?: boolean };\n}): boolean {\n if (event.key !== \"Enter\" || event.shiftKey) {\n return false;\n }\n return event.nativeEvent?.isComposing !== true;\n}\n\n/** Cmd/Ctrl+Enter steers; ordinary Enter appends to the queue. */\nexport function shouldSteerOnKey(event: { metaKey?: boolean; ctrlKey?: boolean }): boolean {\n return event.metaKey === true || event.ctrlKey === true;\n}\n\nfunction generateClientEventId(): string {\n return globalThis.crypto.randomUUID();\n}\n\nfunction asError(cause: unknown): Error {\n return cause instanceof Error ? cause : new Error(String(cause));\n}\n\nfunction draftPayload(draft: ComposerDraft): SaveComposerDraftRequest {\n return {\n expectedRevision: draft.revision,\n text: draft.text,\n resources: draft.resources,\n tools: draft.tools,\n toolsProvided: draft.toolsProvided,\n model: draft.model,\n reasoningEffort: draft.reasoningEffort,\n };\n}\n\nfunction composerDraftPayload(\n base: ComposerDraft,\n text: string,\n restoredResources: ResourceRef[],\n extras: ComposerSendExtras,\n): SaveComposerDraftRequest {\n const toolsProvidedByHost = Object.prototype.hasOwnProperty.call(extras, \"tools\");\n return {\n expectedRevision: base.revision,\n text,\n resources: mergeResources(restoredResources, extras.resources ?? []),\n tools: toolsProvidedByHost ? (extras.tools ?? []) : base.tools,\n toolsProvided: toolsProvidedByHost ? true : base.toolsProvided,\n model: extras.model ?? base.model,\n reasoningEffort: extras.reasoningEffort ?? base.reasoningEffort,\n };\n}\n\nfunction draftSignature(payload: SaveComposerDraftRequest): string {\n const { expectedRevision: _revision, ...content } = payload;\n return JSON.stringify(content);\n}\n\nfunction mergeResources(base: ResourceRef[], additions: ResourceRef[]): ResourceRef[] {\n const seen = new Set<string>();\n return [...base, ...additions].filter((resource) => {\n const key = JSON.stringify(resource);\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n"],"mappings":"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","names":[]}
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  shouldSteerOnKey,
6
6
  shouldSubmitOnKey
7
- } from "./chunk-UQS7OQDE.js";
7
+ } from "./chunk-AVPU5PMC.js";
8
8
  import {
9
9
  formatBytes,
10
10
  formatRelativeTime
@@ -696,7 +696,7 @@ function useChatComposerController({
696
696
  document.addEventListener(OPEN_WORKSTREAM_CONTROL_EVENT, openControl);
697
697
  return () => document.removeEventListener(OPEN_WORKSTREAM_CONTROL_EVENT, openControl);
698
698
  }, [id, paused]);
699
- const blockedByUpload = attachments?.uploading === true;
699
+ const blockedByAttachment = attachments?.hasUnresolved === true;
700
700
  const hasReadyAttachment = (attachments?.readyResources.length ?? 0) > 0;
701
701
  const [dragging, setDragging] = useState2(false);
702
702
  const dragCarriesFiles = (event) => event.dataTransfer !== null && [...event.dataTransfer.types].includes("Files");
@@ -778,7 +778,7 @@ function useChatComposerController({
778
778
  });
779
779
  const paletteEnabled = commandContext !== void 0;
780
780
  const commandDraftBlocked = paletteEnabled && palette.isCommandDraft;
781
- const submitBlocker = disabled ? "disabled" : blockedByUpload ? "uploading" : delivery.sending || submitting ? "sending" : commandDraftBlocked ? "command" : delivery.canSend || hasReadyAttachment ? null : "empty";
781
+ const submitBlocker = disabled ? "disabled" : blockedByAttachment ? "attachment" : delivery.sending || submitting ? "sending" : commandDraftBlocked ? "command" : delivery.canSend || hasReadyAttachment ? null : "empty";
782
782
  const canSubmit = submitBlocker === null;
783
783
  const submit = useCallback2(
784
784
  async (mode) => {
@@ -787,7 +787,8 @@ function useChatComposerController({
787
787
  delivery.clearError();
788
788
  return false;
789
789
  }
790
- if (disabled || blockedByUpload || delivery.sending || submittingRef.current) return false;
790
+ if (disabled || blockedByAttachment || delivery.sending || submittingRef.current)
791
+ return false;
791
792
  if (!delivery.canSend && !hasReadyAttachment) return false;
792
793
  submittingRef.current = true;
793
794
  setSubmitting(true);
@@ -799,7 +800,7 @@ function useChatComposerController({
799
800
  }
800
801
  },
801
802
  [
802
- blockedByUpload,
803
+ blockedByAttachment,
803
804
  commandDraftBlocked,
804
805
  delivery,
805
806
  disabled,
@@ -2390,4 +2391,4 @@ export {
2390
2391
  useTranscription,
2391
2392
  ComposerTranscriptionControl
2392
2393
  };
2393
- //# sourceMappingURL=chunk-CATATY77.js.map
2394
+ //# sourceMappingURL=chunk-RDPDU4TA.js.map