@burdenoff/microfe-proserviceworld 2026.706.3 → 2026.709.1

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 (91) hide show
  1. package/dist/dev/main.d.ts +2 -0
  2. package/dist/dev/main.d.ts.map +1 -0
  3. package/dist/generated/global-operations.d.ts +2 -0
  4. package/dist/generated/global-operations.d.ts.map +1 -0
  5. package/dist/generated/global-types.d.ts +18199 -0
  6. package/dist/generated/global-types.d.ts.map +1 -0
  7. package/dist/generated/wspace-operations.d.ts +2 -0
  8. package/dist/generated/wspace-operations.d.ts.map +1 -0
  9. package/dist/generated/wspace-types.d.ts +43046 -0
  10. package/dist/generated/wspace-types.d.ts.map +1 -0
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +2 -1
  14. package/dist/proserviceworld/ProServiceWorldRoot.d.ts +5 -0
  15. package/dist/proserviceworld/ProServiceWorldRoot.d.ts.map +1 -0
  16. package/dist/proserviceworld/ProServiceWorldRoutes.d.ts +2 -0
  17. package/dist/proserviceworld/ProServiceWorldRoutes.d.ts.map +1 -0
  18. package/dist/proserviceworld/components/DiscussionThread.d.ts +12 -0
  19. package/dist/proserviceworld/components/DiscussionThread.d.ts.map +1 -0
  20. package/dist/proserviceworld/components/ui.d.ts +82 -0
  21. package/dist/proserviceworld/components/ui.d.ts.map +1 -0
  22. package/dist/proserviceworld/hooks/useAnalytics.d.ts +18 -0
  23. package/dist/proserviceworld/hooks/useAnalytics.d.ts.map +1 -0
  24. package/dist/proserviceworld/hooks/useAnalytics.js +21 -0
  25. package/dist/proserviceworld/hooks/useAnalytics.js.map +1 -0
  26. package/dist/proserviceworld/hooks/useEntityComments.d.ts +27 -0
  27. package/dist/proserviceworld/hooks/useEntityComments.d.ts.map +1 -0
  28. package/dist/proserviceworld/hooks/useFiles.d.ts +23 -0
  29. package/dist/proserviceworld/hooks/useFiles.d.ts.map +1 -0
  30. package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts +351 -0
  31. package/dist/proserviceworld/hooks/useProServiceWorldApi.d.ts.map +1 -0
  32. package/dist/proserviceworld/index.d.ts +5 -0
  33. package/dist/proserviceworld/index.d.ts.map +1 -0
  34. package/dist/proserviceworld/index.js +1 -0
  35. package/dist/proserviceworld/pages/AnalyticsPage.d.ts +4 -0
  36. package/dist/proserviceworld/pages/AnalyticsPage.d.ts.map +1 -0
  37. package/dist/proserviceworld/pages/ClientDetailPage.d.ts +4 -0
  38. package/dist/proserviceworld/pages/ClientDetailPage.d.ts.map +1 -0
  39. package/dist/proserviceworld/pages/ClientsPage.d.ts +9 -0
  40. package/dist/proserviceworld/pages/ClientsPage.d.ts.map +1 -0
  41. package/dist/proserviceworld/pages/ClientsPage.js +157 -146
  42. package/dist/proserviceworld/pages/ClientsPage.js.map +1 -1
  43. package/dist/proserviceworld/pages/CompliancePage.d.ts +4 -0
  44. package/dist/proserviceworld/pages/CompliancePage.d.ts.map +1 -0
  45. package/dist/proserviceworld/pages/ConflictsPage.d.ts +4 -0
  46. package/dist/proserviceworld/pages/ConflictsPage.d.ts.map +1 -0
  47. package/dist/proserviceworld/pages/DashboardPage.d.ts +4 -0
  48. package/dist/proserviceworld/pages/DashboardPage.d.ts.map +1 -0
  49. package/dist/proserviceworld/pages/DocumentsPage.d.ts +4 -0
  50. package/dist/proserviceworld/pages/DocumentsPage.d.ts.map +1 -0
  51. package/dist/proserviceworld/pages/EngagementDetailPage.d.ts +4 -0
  52. package/dist/proserviceworld/pages/EngagementDetailPage.d.ts.map +1 -0
  53. package/dist/proserviceworld/pages/EngagementDetailPage.js +162 -156
  54. package/dist/proserviceworld/pages/EngagementDetailPage.js.map +1 -1
  55. package/dist/proserviceworld/pages/EngagementsPage.d.ts +4 -0
  56. package/dist/proserviceworld/pages/EngagementsPage.d.ts.map +1 -0
  57. package/dist/proserviceworld/pages/EngagementsPage.js +141 -128
  58. package/dist/proserviceworld/pages/EngagementsPage.js.map +1 -1
  59. package/dist/proserviceworld/pages/InvoicesPage.d.ts +4 -0
  60. package/dist/proserviceworld/pages/InvoicesPage.d.ts.map +1 -0
  61. package/dist/proserviceworld/pages/MattersPage.d.ts +4 -0
  62. package/dist/proserviceworld/pages/MattersPage.d.ts.map +1 -0
  63. package/dist/proserviceworld/pages/MattersPage.js +165 -150
  64. package/dist/proserviceworld/pages/MattersPage.js.map +1 -1
  65. package/dist/proserviceworld/pages/PracticeAreasPage.d.ts +4 -0
  66. package/dist/proserviceworld/pages/PracticeAreasPage.d.ts.map +1 -0
  67. package/dist/proserviceworld/pages/TimePage.d.ts +4 -0
  68. package/dist/proserviceworld/pages/TimePage.d.ts.map +1 -0
  69. package/dist/proserviceworld/providers/ProServiceWorldProvider.d.ts +6 -0
  70. package/dist/proserviceworld/providers/ProServiceWorldProvider.d.ts.map +1 -0
  71. package/dist/proserviceworld/services/assistantApi.d.ts +74 -0
  72. package/dist/proserviceworld/services/assistantApi.d.ts.map +1 -0
  73. package/dist/proserviceworld/services/assistantApi.js +203 -0
  74. package/dist/proserviceworld/services/assistantApi.js.map +1 -0
  75. package/dist/proserviceworld/services/createSandboxAssistantTransport.d.ts +28 -0
  76. package/dist/proserviceworld/services/createSandboxAssistantTransport.d.ts.map +1 -0
  77. package/dist/proserviceworld/services/createSandboxAssistantTransport.js +120 -0
  78. package/dist/proserviceworld/services/createSandboxAssistantTransport.js.map +1 -0
  79. package/dist/proserviceworld/types/index.d.ts +57 -0
  80. package/dist/proserviceworld/types/index.d.ts.map +1 -0
  81. package/dist/proserviceworld/utils/cn.d.ts +4 -0
  82. package/dist/proserviceworld/utils/cn.d.ts.map +1 -0
  83. package/dist/proserviceworld/utils/nav.d.ts +6 -0
  84. package/dist/proserviceworld/utils/nav.d.ts.map +1 -0
  85. package/dist/proserviceworld/utils/navigation.d.ts +2 -0
  86. package/dist/proserviceworld/utils/navigation.d.ts.map +1 -0
  87. package/dist/proserviceworld/utils/pageContext.d.ts +12 -0
  88. package/dist/proserviceworld/utils/pageContext.d.ts.map +1 -0
  89. package/dist/proserviceworld/utils/pageContext.js +74 -0
  90. package/dist/proserviceworld/utils/pageContext.js.map +1 -0
  91. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"MattersPage.js","names":[],"sources":["../../../src/proserviceworld/pages/MattersPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport {\n Plus,\n Search,\n FolderKanban,\n Lock,\n CheckCircle2,\n CircleDot,\n AlertTriangle,\n} from 'lucide-react';\nimport {\n useMatters,\n useCreateMatter,\n useCloseMatter,\n useClients,\n usePracticeAreas,\n type PswMatterStatus,\n} from '../hooks/useProServiceWorldApi';\nimport {\n PageHeader,\n SectionCard,\n MetricCard,\n LoadingBlock,\n ErrorState,\n Empty,\n StatusPill,\n Modal,\n Field,\n TextInput,\n TextArea,\n NativeSelect,\n Banner,\n TableWrap,\n Th,\n Td,\n enumOptions,\n fmtDate,\n} from '../components/ui';\n\nconst STATUSES: PswMatterStatus[] = ['OPEN', 'ON_HOLD', 'CLOSED', 'ARCHIVED'];\nconst PRIORITIES = ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'] as const;\n\n/** Amber padlock chip that flags privileged / confidential matters. */\nconst PrivilegeLock: FC = () => (\n <span\n className=\"inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-md bg-status-warning-bg-subtle text-status-warning-text\"\n title=\"Privileged / confidential\"\n aria-label=\"Privileged\"\n >\n <Lock className=\"h-3 w-3\" />\n </span>\n);\n\nexport const MattersPage: FC = () => {\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState<PswMatterStatus | ''>('');\n const [creating, setCreating] = useState(false);\n const [banner, setBanner] = useState<{ tone: 'success' | 'danger'; text: string } | null>(null);\n const { data, isLoading, error, refetch } = useMatters({\n search: search.trim() || undefined,\n status: statusFilter || undefined,\n });\n const close = useCloseMatter();\n\n const items = data?.items ?? [];\n const openCount = items.filter((m) => m.status === 'OPEN').length;\n const privilegedCount = items.filter((m) => m.isPrivileged).length;\n const highCount = items.filter((m) => m.priority === 'HIGH' || m.priority === 'CRITICAL').length;\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title=\"Matters\"\n subtitle=\"The regulated threads of work — legal matters, audits, filings — with their own deadlines and sensitive-document handling.\"\n icon={<FolderKanban className=\"h-6 w-6\" />}\n actions={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New matter\n </Button>\n }\n />\n\n {banner && (\n <Banner tone={banner.tone} onClose={() => setBanner(null)}>\n {banner.text}\n </Banner>\n )}\n\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary\" />\n <TextInput\n placeholder=\"Search matters…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n className=\"pl-9\"\n />\n </div>\n <NativeSelect\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value as PswMatterStatus | '')}\n className=\"sm:w-48\"\n >\n <option value=\"\">All statuses</option>\n {enumOptions(STATUSES)}\n </NativeSelect>\n </div>\n\n {isLoading ? (\n <LoadingBlock />\n ) : error ? (\n <ErrorState error={error} onRetry={() => void refetch()} />\n ) : !data || data.items.length === 0 ? (\n <Empty\n title=\"No matters yet\"\n description=\"Open a matter to track a regulated thread of work for a client.\"\n icon={<FolderKanban className=\"h-8 w-8\" />}\n action={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New matter\n </Button>\n }\n />\n ) : (\n <>\n <div className=\"grid grid-cols-2 gap-3 lg:grid-cols-4\">\n <MetricCard\n label=\"Matters\"\n value={data.totalCount}\n icon={<FolderKanban className=\"h-4 w-4\" />}\n />\n <MetricCard\n label=\"Open\"\n value={openCount}\n icon={<CircleDot className=\"h-4 w-4\" />}\n tone=\"accent\"\n />\n <MetricCard\n label=\"Privileged\"\n value={privilegedCount}\n icon={<Lock className=\"h-4 w-4\" />}\n tone=\"warning\"\n />\n <MetricCard\n label=\"High priority\"\n value={highCount}\n icon={<AlertTriangle className=\"h-4 w-4\" />}\n tone={highCount ? 'danger' : 'neutral'}\n />\n </div>\n\n <SectionCard title={`${data.totalCount} matter${data.totalCount === 1 ? '' : 's'}`}>\n <TableWrap>\n <thead>\n <tr>\n <Th>Matter</Th>\n <Th>Client</Th>\n <Th>Priority</Th>\n <Th>Status</Th>\n <Th>Due</Th>\n <Th className=\"text-right\">Actions</Th>\n </tr>\n </thead>\n <tbody>\n {data.items.map((m) => (\n <tr key={m.id} className=\"transition-colors hover:bg-bg-sunken/60\">\n <Td>\n <span className=\"flex items-center gap-2 font-medium text-text-primary\">\n {m.isPrivileged && <PrivilegeLock />}\n <span className=\"truncate\">{m.title}</span>\n </span>\n {m.reference ? (\n <div className=\"mt-0.5 pl-0 text-xs text-text-tertiary\">\n Ref: {m.reference}\n </div>\n ) : null}\n </Td>\n <Td className=\"text-text-primary\">{m.client?.name ?? '—'}</Td>\n <Td>\n <StatusPill status={m.priority} />\n </Td>\n <Td>\n <StatusPill status={m.status} />\n </Td>\n <Td>{fmtDate(m.dueDate)}</Td>\n <Td className=\"text-right\">\n {m.status !== 'CLOSED' && m.status !== 'ARCHIVED' ? (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n disabled={close.isPending}\n onClick={() =>\n close.mutate(m.id, {\n onSuccess: () =>\n setBanner({ tone: 'success', text: `${m.title} closed.` }),\n onError: (e) =>\n setBanner({\n tone: 'danger',\n text: e instanceof Error ? e.message : 'Failed.',\n }),\n })\n }\n >\n <CheckCircle2 className=\"mr-1 h-4 w-4\" /> Close\n </Button>\n ) : (\n <span className=\"text-xs text-text-tertiary\">\n {m.closedAt ? `Closed ${fmtDate(m.closedAt)}` : '—'}\n </span>\n )}\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n </SectionCard>\n </>\n )}\n\n {creating && (\n <MatterModal\n onClose={() => setCreating(false)}\n onSaved={(t) => setBanner({ tone: 'success', text: `${t} opened.` })}\n />\n )}\n </div>\n );\n};\n\nconst MatterModal: FC<{ onClose: () => void; onSaved: (title: string) => void }> = ({\n onClose,\n onSaved,\n}) => {\n const create = useCreateMatter();\n const clients = useClients({ pagination: { limit: 100 } });\n const practiceAreas = usePracticeAreas();\n const [form, setForm] = useState({\n clientId: '',\n practiceAreaId: '',\n title: '',\n reference: '',\n description: '',\n priority: 'MEDIUM',\n dueDate: '',\n isPrivileged: false,\n });\n const [err, setErr] = useState<string | null>(null);\n const set = (k: keyof typeof form) => (e: { target: { value: string } }) =>\n setForm((f) => ({ ...f, [k]: e.target.value }));\n\n const submit = () => {\n setErr(null);\n if (!form.clientId) return setErr('Select a client.');\n if (!form.title.trim()) return setErr('Matter title is required.');\n create.mutate(\n {\n clientId: form.clientId,\n practiceAreaId: form.practiceAreaId || null,\n title: form.title.trim(),\n reference: form.reference.trim() || null,\n description: form.description.trim() || null,\n priority: form.priority,\n isPrivileged: form.isPrivileged,\n dueDate: form.dueDate ? new Date(form.dueDate).toISOString() : null,\n },\n {\n onSuccess: () => {\n onSaved(form.title.trim());\n onClose();\n },\n onError: (e) => setErr(e instanceof Error ? e.message : 'Failed.'),\n }\n );\n };\n\n return (\n <Modal\n open\n onClose={onClose}\n title=\"New matter\"\n footer={\n <>\n <Button variant=\"outline\" onClick={onClose} disabled={create.isPending}>\n Cancel\n </Button>\n <Button onClick={submit} disabled={create.isPending}>\n {create.isPending ? 'Opening…' : 'Open matter'}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label=\"Client\" required>\n <NativeSelect value={form.clientId} onChange={set('clientId')}>\n <option value=\"\">Select a client…</option>\n {clients.data?.items.map((c) => (\n <option key={c.id} value={c.id}>\n {c.name}\n </option>\n ))}\n </NativeSelect>\n </Field>\n <Field label=\"Title\" required>\n <TextInput\n value={form.title}\n onChange={set('title')}\n placeholder=\"Regulatory investigation — SEC inquiry\"\n />\n </Field>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Reference\">\n <TextInput\n value={form.reference}\n onChange={set('reference')}\n placeholder=\"MAT-2026-014\"\n />\n </Field>\n <Field label=\"Priority\">\n <NativeSelect value={form.priority} onChange={set('priority')}>\n {enumOptions(PRIORITIES)}\n </NativeSelect>\n </Field>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Practice area\">\n <NativeSelect value={form.practiceAreaId} onChange={set('practiceAreaId')}>\n <option value=\"\">Unassigned</option>\n {practiceAreas.data?.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </NativeSelect>\n </Field>\n <Field label=\"Due date\">\n <TextInput type=\"date\" value={form.dueDate} onChange={set('dueDate')} />\n </Field>\n </div>\n <Field label=\"Description\">\n <TextArea value={form.description} onChange={set('description')} />\n </Field>\n <label className=\"flex items-center gap-2.5 rounded-lg border border-border-seam bg-bg-canvas px-3 py-2.5 text-sm text-text-secondary\">\n <input\n type=\"checkbox\"\n checked={form.isPrivileged}\n onChange={(e) => setForm((f) => ({ ...f, isPrivileged: e.target.checked }))}\n />\n <span className=\"flex items-center gap-1.5\">\n <Lock className=\"h-3.5 w-3.5 text-status-warning-text\" />\n Privileged / confidential matter\n </span>\n </label>\n </div>\n </Modal>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"MattersPage.js","names":[],"sources":["../../../src/proserviceworld/pages/MattersPage.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { useState } from 'react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport {\n Plus,\n Search,\n FolderKanban,\n Lock,\n CheckCircle2,\n CircleDot,\n AlertTriangle,\n} from 'lucide-react';\nimport {\n useMatters,\n useCreateMatter,\n useCloseMatter,\n useClients,\n usePracticeAreas,\n type PswMatterStatus,\n type PswMatter,\n} from '../hooks/useProServiceWorldApi';\nimport { useAnalytics } from '../hooks/useAnalytics';\nimport {\n PageHeader,\n SectionCard,\n MetricCard,\n LoadingBlock,\n ErrorState,\n Empty,\n StatusPill,\n Modal,\n Field,\n TextInput,\n TextArea,\n NativeSelect,\n Banner,\n TableWrap,\n Th,\n Td,\n enumOptions,\n fmtDate,\n} from '../components/ui';\n\nconst STATUSES: PswMatterStatus[] = ['OPEN', 'ON_HOLD', 'CLOSED', 'ARCHIVED'];\nconst PRIORITIES = ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'] as const;\n\n/** Amber padlock chip that flags privileged / confidential matters. */\nconst PrivilegeLock: FC = () => (\n <span\n className=\"inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-md bg-status-warning-bg-subtle text-status-warning-text\"\n title=\"Privileged / confidential\"\n aria-label=\"Privileged\"\n >\n <Lock className=\"h-3 w-3\" />\n </span>\n);\n\nexport const MattersPage: FC = () => {\n const { emitIntent, emitFact } = useAnalytics();\n const [search, setSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState<PswMatterStatus | ''>('');\n const [creating, setCreating] = useState(false);\n const [banner, setBanner] = useState<{ tone: 'success' | 'danger'; text: string } | null>(null);\n const { data, isLoading, error, refetch } = useMatters({\n search: search.trim() || undefined,\n status: statusFilter || undefined,\n });\n const close = useCloseMatter();\n\n const items = data?.items ?? [];\n const openCount = items.filter((m) => m.status === 'OPEN').length;\n const privilegedCount = items.filter((m) => m.isPrivileged).length;\n const highCount = items.filter((m) => m.priority === 'HIGH' || m.priority === 'CRITICAL').length;\n\n return (\n <div className=\"space-y-6\">\n <PageHeader\n title=\"Matters\"\n subtitle=\"The regulated threads of work — legal matters, audits, filings — with their own deadlines and sensitive-document handling.\"\n icon={<FolderKanban className=\"h-6 w-6\" />}\n actions={\n <Button\n onClick={() => {\n emitIntent('psw.matter.create_clicked');\n setCreating(true);\n }}\n >\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New matter\n </Button>\n }\n />\n\n {banner && (\n <Banner tone={banner.tone} onClose={() => setBanner(null)}>\n {banner.text}\n </Banner>\n )}\n\n <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center\">\n <div className=\"relative flex-1\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-tertiary\" />\n <TextInput\n placeholder=\"Search matters…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && search.trim()) {\n emitFact('psw.search.performed', {\n entityType: 'matter',\n queryLength: search.trim().length,\n });\n }\n }}\n className=\"pl-9\"\n />\n </div>\n <NativeSelect\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value as PswMatterStatus | '')}\n className=\"sm:w-48\"\n >\n <option value=\"\">All statuses</option>\n {enumOptions(STATUSES)}\n </NativeSelect>\n </div>\n\n {isLoading ? (\n <LoadingBlock />\n ) : error ? (\n <ErrorState error={error} onRetry={() => void refetch()} />\n ) : !data || data.items.length === 0 ? (\n <Empty\n title=\"No matters yet\"\n description=\"Open a matter to track a regulated thread of work for a client.\"\n icon={<FolderKanban className=\"h-8 w-8\" />}\n action={\n <Button onClick={() => setCreating(true)}>\n <Plus className=\"mr-1.5 h-4 w-4\" />\n New matter\n </Button>\n }\n />\n ) : (\n <>\n <div className=\"grid grid-cols-2 gap-3 lg:grid-cols-4\">\n <MetricCard\n label=\"Matters\"\n value={data.totalCount}\n icon={<FolderKanban className=\"h-4 w-4\" />}\n />\n <MetricCard\n label=\"Open\"\n value={openCount}\n icon={<CircleDot className=\"h-4 w-4\" />}\n tone=\"accent\"\n />\n <MetricCard\n label=\"Privileged\"\n value={privilegedCount}\n icon={<Lock className=\"h-4 w-4\" />}\n tone=\"warning\"\n />\n <MetricCard\n label=\"High priority\"\n value={highCount}\n icon={<AlertTriangle className=\"h-4 w-4\" />}\n tone={highCount ? 'danger' : 'neutral'}\n />\n </div>\n\n <SectionCard title={`${data.totalCount} matter${data.totalCount === 1 ? '' : 's'}`}>\n <TableWrap>\n <thead>\n <tr>\n <Th>Matter</Th>\n <Th>Client</Th>\n <Th>Priority</Th>\n <Th>Status</Th>\n <Th>Due</Th>\n <Th className=\"text-right\">Actions</Th>\n </tr>\n </thead>\n <tbody>\n {data.items.map((m) => (\n <tr key={m.id} className=\"transition-colors hover:bg-bg-sunken/60\">\n <Td>\n <span className=\"flex items-center gap-2 font-medium text-text-primary\">\n {m.isPrivileged && <PrivilegeLock />}\n <span className=\"truncate\">{m.title}</span>\n </span>\n {m.reference ? (\n <div className=\"mt-0.5 pl-0 text-xs text-text-tertiary\">\n Ref: {m.reference}\n </div>\n ) : null}\n </Td>\n <Td className=\"text-text-primary\">{m.client?.name ?? '—'}</Td>\n <Td>\n <StatusPill status={m.priority} />\n </Td>\n <Td>\n <StatusPill status={m.status} />\n </Td>\n <Td>{fmtDate(m.dueDate)}</Td>\n <Td className=\"text-right\">\n {m.status !== 'CLOSED' && m.status !== 'ARCHIVED' ? (\n <Button\n variant=\"ghost\"\n size=\"sm\"\n disabled={close.isPending}\n onClick={() =>\n close.mutate(m.id, {\n onSuccess: () => {\n emitFact('psw.matter.closed', { matterId: m.id });\n setBanner({ tone: 'success', text: `${m.title} closed.` });\n },\n onError: (e) =>\n setBanner({\n tone: 'danger',\n text: e instanceof Error ? e.message : 'Failed.',\n }),\n })\n }\n >\n <CheckCircle2 className=\"mr-1 h-4 w-4\" /> Close\n </Button>\n ) : (\n <span className=\"text-xs text-text-tertiary\">\n {m.closedAt ? `Closed ${fmtDate(m.closedAt)}` : '—'}\n </span>\n )}\n </Td>\n </tr>\n ))}\n </tbody>\n </TableWrap>\n </SectionCard>\n </>\n )}\n\n {creating && (\n <MatterModal\n onClose={() => setCreating(false)}\n onSaved={(t) => setBanner({ tone: 'success', text: `${t} opened.` })}\n />\n )}\n </div>\n );\n};\n\nconst MatterModal: FC<{ onClose: () => void; onSaved: (title: string) => void }> = ({\n onClose,\n onSaved,\n}) => {\n const create = useCreateMatter();\n const { emitFact } = useAnalytics();\n const clients = useClients({ pagination: { limit: 100 } });\n const practiceAreas = usePracticeAreas();\n const [form, setForm] = useState({\n clientId: '',\n practiceAreaId: '',\n title: '',\n reference: '',\n description: '',\n priority: 'MEDIUM',\n dueDate: '',\n isPrivileged: false,\n });\n const [err, setErr] = useState<string | null>(null);\n const set = (k: keyof typeof form) => (e: { target: { value: string } }) =>\n setForm((f) => ({ ...f, [k]: e.target.value }));\n\n const submit = () => {\n setErr(null);\n if (!form.clientId) return setErr('Select a client.');\n if (!form.title.trim()) return setErr('Matter title is required.');\n create.mutate(\n {\n clientId: form.clientId,\n practiceAreaId: form.practiceAreaId || null,\n title: form.title.trim(),\n reference: form.reference.trim() || null,\n description: form.description.trim() || null,\n priority: form.priority,\n isPrivileged: form.isPrivileged,\n dueDate: form.dueDate ? new Date(form.dueDate).toISOString() : null,\n },\n {\n onSuccess: (created) => {\n const matter = (created as { pswCreateMatter: PswMatter }).pswCreateMatter;\n emitFact('psw.matter.created', {\n matterId: matter.id,\n clientId: form.clientId,\n });\n onSaved(form.title.trim());\n onClose();\n },\n onError: (e) => setErr(e instanceof Error ? e.message : 'Failed.'),\n }\n );\n };\n\n return (\n <Modal\n open\n onClose={onClose}\n title=\"New matter\"\n footer={\n <>\n <Button variant=\"outline\" onClick={onClose} disabled={create.isPending}>\n Cancel\n </Button>\n <Button onClick={submit} disabled={create.isPending}>\n {create.isPending ? 'Opening…' : 'Open matter'}\n </Button>\n </>\n }\n >\n <div className=\"space-y-3\">\n {err && <Banner tone=\"danger\">{err}</Banner>}\n <Field label=\"Client\" required>\n <NativeSelect value={form.clientId} onChange={set('clientId')}>\n <option value=\"\">Select a client…</option>\n {clients.data?.items.map((c) => (\n <option key={c.id} value={c.id}>\n {c.name}\n </option>\n ))}\n </NativeSelect>\n </Field>\n <Field label=\"Title\" required>\n <TextInput\n value={form.title}\n onChange={set('title')}\n placeholder=\"Regulatory investigation — SEC inquiry\"\n />\n </Field>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Reference\">\n <TextInput\n value={form.reference}\n onChange={set('reference')}\n placeholder=\"MAT-2026-014\"\n />\n </Field>\n <Field label=\"Priority\">\n <NativeSelect value={form.priority} onChange={set('priority')}>\n {enumOptions(PRIORITIES)}\n </NativeSelect>\n </Field>\n </div>\n <div className=\"grid grid-cols-2 gap-3\">\n <Field label=\"Practice area\">\n <NativeSelect value={form.practiceAreaId} onChange={set('practiceAreaId')}>\n <option value=\"\">Unassigned</option>\n {practiceAreas.data?.map((p) => (\n <option key={p.id} value={p.id}>\n {p.name}\n </option>\n ))}\n </NativeSelect>\n </Field>\n <Field label=\"Due date\">\n <TextInput type=\"date\" value={form.dueDate} onChange={set('dueDate')} />\n </Field>\n </div>\n <Field label=\"Description\">\n <TextArea value={form.description} onChange={set('description')} />\n </Field>\n <label className=\"flex items-center gap-2.5 rounded-lg border border-border-seam bg-bg-canvas px-3 py-2.5 text-sm text-text-secondary\">\n <input\n type=\"checkbox\"\n checked={form.isPrivileged}\n onChange={(e) => setForm((f) => ({ ...f, isPrivileged: e.target.checked }))}\n />\n <span className=\"flex items-center gap-1.5\">\n <Lock className=\"h-3.5 w-3.5 text-status-warning-text\" />\n Privileged / confidential matter\n </span>\n </label>\n </div>\n </Modal>\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { FC } from 'react';
2
+
3
+ export declare const PracticeAreasPage: FC;
4
+ //# sourceMappingURL=PracticeAreasPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PracticeAreasPage.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/pages/PracticeAreasPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAwBhC,eAAO,MAAM,iBAAiB,EAAE,EA2F/B,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { FC } from 'react';
2
+
3
+ export declare const TimePage: FC;
4
+ //# sourceMappingURL=TimePage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TimePage.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/pages/TimePage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAmDhC,eAAO,MAAM,QAAQ,EAAE,EAuKtB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { FC, PropsWithChildren } from 'react';
2
+ import { ProServiceWorldRootProps } from '../types';
3
+
4
+ export declare const useProServiceWorld: () => ProServiceWorldRootProps;
5
+ export declare const ProServiceWorldProvider: FC<PropsWithChildren<ProServiceWorldRootProps>>;
6
+ //# sourceMappingURL=ProServiceWorldProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProServiceWorldProvider.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/providers/ProServiceWorldProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAInD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAMzD,eAAO,MAAM,kBAAkB,gCAI9B,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,EAAE,CAAC,iBAAiB,CAAC,wBAAwB,CAAC,CAsBnF,CAAC"}
@@ -0,0 +1,74 @@
1
+ import { AssistantArtifact, AssistantMode, PageContext } from '../types';
2
+
3
+ export interface AssistantPromptResult {
4
+ response: string;
5
+ tokens?: {
6
+ input: number;
7
+ output: number;
8
+ };
9
+ artifacts?: AssistantArtifact[];
10
+ }
11
+ export interface AssistantRawMessagePart {
12
+ type?: string;
13
+ text?: string;
14
+ tool?: string;
15
+ state?: {
16
+ status?: string;
17
+ input?: unknown;
18
+ output?: unknown;
19
+ raw?: unknown;
20
+ };
21
+ }
22
+ export interface AssistantRawMessage {
23
+ info?: {
24
+ id?: string;
25
+ role?: string;
26
+ providerID?: string;
27
+ modelID?: string;
28
+ tokens?: {
29
+ input: number;
30
+ output: number;
31
+ };
32
+ time?: {
33
+ created?: number;
34
+ completed?: number;
35
+ };
36
+ };
37
+ parts?: AssistantRawMessagePart[];
38
+ }
39
+ export interface AssistantSandboxAuthContext {
40
+ accessToken?: string | null;
41
+ workspaceToken?: string | null;
42
+ userId?: string | null;
43
+ organizationId?: string | null;
44
+ }
45
+ export interface AssistantSessionInfo {
46
+ id: string;
47
+ mode: string;
48
+ }
49
+ export declare function findExistingSandbox(baseUrl: string | undefined, workspaceId: string, mode: AssistantMode, authContext?: AssistantSandboxAuthContext): Promise<string | null>;
50
+ export declare function createAssistantSandbox(baseUrl: string | undefined, mode: AssistantMode, workspaceId: string, authContext?: AssistantSandboxAuthContext): Promise<string>;
51
+ export declare function waitForSandboxReady(baseUrl: string | undefined, sandboxId: string, workspaceId: string, authContext?: AssistantSandboxAuthContext, maxWaitMs?: number, onProgress?: (message: string) => void): Promise<void>;
52
+ export declare function waitForAssistantServiceReady(baseUrl: string | undefined, sandboxId: string, workspaceId: string, authContext?: AssistantSandboxAuthContext, maxWaitMs?: number, onProgress?: (message: string) => void): Promise<void>;
53
+ export declare function createAssistantSession(baseUrl: string | undefined, sandboxId: string, workspaceId: string, mode: AssistantMode, authContext?: AssistantSandboxAuthContext): Promise<{
54
+ sessionId: string;
55
+ }>;
56
+ export declare function sendAssistantPromptAsync(baseUrl: string | undefined, sandboxId: string, workspaceId: string, sessionId: string, prompt: string, mode: AssistantMode, pageContext?: PageContext, authContext?: AssistantSandboxAuthContext): Promise<void>;
57
+ export declare function getAssistantMessages(baseUrl: string | undefined, sandboxId: string, workspaceId: string, sessionId: string, authContext?: AssistantSandboxAuthContext, limit?: number): Promise<AssistantRawMessage[]>;
58
+ export declare function extendAssistantSandboxTTL(baseUrl: string | undefined, sandboxId: string, workspaceId: string, additionalSeconds?: number, authContext?: AssistantSandboxAuthContext): Promise<void>;
59
+ /**
60
+ * Pre-flight AI-credit gate. Resolves to `true` when the caller still has
61
+ * AI-credit budget; throws a quota error when the monthly token budget is
62
+ * depleted.
63
+ */
64
+ export declare function checkAssistantAiCredits(baseUrl: string | undefined, workspaceId: string, authContext?: AssistantSandboxAuthContext): Promise<boolean>;
65
+ /**
66
+ * Post-turn charge. Reports raw input/output token counts + the model so the
67
+ * service computes cost-weighted credits server-side. Best-effort — callers
68
+ * must not block the displayed answer on it.
69
+ */
70
+ export declare function reportAssistantAiTokenUsage(baseUrl: string | undefined, workspaceId: string, sessionId: string, messageId: string, model: string | undefined, tokens: {
71
+ input: number;
72
+ output: number;
73
+ }, authContext?: AssistantSandboxAuthContext): Promise<void>;
74
+ //# sourceMappingURL=assistantApi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assistantApi.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/services/assistantApi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,203 @@
1
+ import { graphqlFetch as e } from "@burdenoff/fe-libs/shared/graphql";
2
+ //#region src/proserviceworld/services/assistantApi.ts
3
+ var t = "burdenoffregistry.azurecr.io";
4
+ function n() {
5
+ return "prod";
6
+ }
7
+ var r = n(), i = "sandbox-app-client-headers-v1";
8
+ function a(e) {
9
+ return `${t}/wspace/ai-assistant-${e === "assistant" ? "api-calls" : e}:${r}`;
10
+ }
11
+ function o() {
12
+ return {
13
+ cpuRequest: "150m",
14
+ cpuLimit: "750m",
15
+ memoryRequest: "384Mi",
16
+ memoryLimit: "1536Mi"
17
+ };
18
+ }
19
+ function s(e) {
20
+ let t = e.metadata?.assistantMode;
21
+ if (t === "assistant" || t === "general" || t === "api-calls" || t === "vibe-plugins") return t;
22
+ let n = e.name ?? "";
23
+ return n.startsWith("ai-assistant-vibe-plugins-") ? "vibe-plugins" : n.startsWith("ai-assistant-api-calls-") ? "api-calls" : n.startsWith("ai-assistant-general-") ? "general" : n.startsWith("ai-assistant-assistant-") ? "assistant" : null;
24
+ }
25
+ function c(e, t) {
26
+ return {
27
+ workspaceId: e,
28
+ ...t?.organizationId ? { custom: { organizationId: t.organizationId } } : {}
29
+ };
30
+ }
31
+ function l(e, t) {
32
+ let n = {};
33
+ return t?.accessToken && (n.authorization = `Bearer ${t.accessToken}`), t?.workspaceToken && (n["x-workspace-authorization"] = `Bearer ${t.workspaceToken}`), n["x-workspace-id"] = e, t?.userId && (n["x-actor-id"] = t.userId, n["x-actor-type"] = "user"), t?.organizationId && (n["x-org-id"] = t.organizationId), n;
34
+ }
35
+ async function u(t) {
36
+ let n = await e({
37
+ gateway: "workspace",
38
+ baseUrl: t.baseUrl,
39
+ query: t.query,
40
+ variables: t.variables,
41
+ workspaceToken: !0,
42
+ extraHeaders: l(t.workspaceId, t.authContext),
43
+ suppressGlobalErrorEvent: !0
44
+ });
45
+ if (n.errors?.length) {
46
+ let e = Error(n.errors[0]?.message ?? "Sandbox GraphQL request failed");
47
+ throw e.result = n, e;
48
+ }
49
+ if (!n.data) throw Error("Sandbox GraphQL returned no data");
50
+ return n.data;
51
+ }
52
+ async function d(e, t, n, a) {
53
+ return ((await u({
54
+ query: "\n query GetActiveSandboxes($context: ContextInput!) {\n getActiveSandboxes(context: $context) {\n id\n name\n status\n metadata\n template\n createdBy\n }\n }\n ",
55
+ variables: { context: c(t, a) },
56
+ workspaceId: t,
57
+ authContext: a,
58
+ baseUrl: e
59
+ })).getActiveSandboxes ?? []).find((e) => (e.status === "RUNNING" || e.status === "PROVISIONING" || e.status === "PENDING") && e.template === "AI_BUILDER" && s(e) === n && (!a?.userId || e.createdBy === a.userId) && e.metadata?.authStrategy === i && e.metadata?.imageTag === r)?.id ?? null;
60
+ }
61
+ async function f(e, t, n, s) {
62
+ let l = o(), d = [
63
+ {
64
+ name: "AI_ASSISTANT_MODE",
65
+ value: t
66
+ },
67
+ {
68
+ name: "HOSTNAME",
69
+ value: "0.0.0.0"
70
+ },
71
+ {
72
+ name: "WORKSPACE_ID",
73
+ value: n
74
+ },
75
+ {
76
+ name: "AI_ASSISTANT_PRODUCT",
77
+ value: "proserviceworld"
78
+ }
79
+ ], f = await u({
80
+ query: "\n mutation CreateSandbox($input: CreateSandboxInput!) {\n createSandbox(input: $input) { id }\n }\n ",
81
+ variables: { input: {
82
+ name: `ai-assistant-${t}-${Date.now()}`,
83
+ description: `AI Assistant sandbox (${t} mode)`,
84
+ template: "AI_BUILDER",
85
+ mode: "DEPLOYMENT",
86
+ containers: [{
87
+ name: "ai-assistant",
88
+ image: a(t),
89
+ ports: [{
90
+ containerPort: 8080,
91
+ name: "http"
92
+ }],
93
+ env: d
94
+ }],
95
+ resources: {
96
+ cpuRequest: l.cpuRequest,
97
+ cpuLimit: l.cpuLimit,
98
+ memoryRequest: l.memoryRequest,
99
+ memoryLimit: l.memoryLimit
100
+ },
101
+ ttlSeconds: 600,
102
+ metadata: {
103
+ assistantMode: t,
104
+ assistantOwnerUserId: s?.userId ?? null,
105
+ assistantOrganizationId: s?.organizationId ?? null,
106
+ authStrategy: i,
107
+ imageTag: r
108
+ },
109
+ context: c(n, s)
110
+ } },
111
+ workspaceId: n,
112
+ authContext: s,
113
+ baseUrl: e
114
+ });
115
+ if (!f?.createSandbox?.id) throw Error("createSandbox returned empty response");
116
+ return f.createSandbox.id;
117
+ }
118
+ async function p(e, t, n, r, i = 3e5, a) {
119
+ let o = Date.now();
120
+ for (; Date.now() - o < i;) {
121
+ let i = await u({
122
+ query: "\n query GetSandbox($id: ID!, $context: ContextInput!) {\n getSandbox(id: $id, context: $context) { status errorMessage }\n }\n ",
123
+ variables: {
124
+ id: t,
125
+ context: c(n, r)
126
+ },
127
+ workspaceId: n,
128
+ authContext: r,
129
+ baseUrl: e
130
+ }), s = i?.getSandbox?.status, l = i?.getSandbox?.errorMessage;
131
+ if (s === "RUNNING") return;
132
+ if (s === "FAILED" || s === "STOPPED" || s === "EXPIRED") throw Error(l ? `Sandbox ${s.toLowerCase()}: ${l}` : `Sandbox ${s.toLowerCase()}`);
133
+ let d = Math.max(1, Math.round((Date.now() - o) / 1e3));
134
+ a?.(`Starting assistant environment... (${d}s)`), await new Promise((e) => setTimeout(e, 2e3));
135
+ }
136
+ throw Error("Sandbox startup timed out");
137
+ }
138
+ async function m(e, t, n, r, i, a, o) {
139
+ let s = (await u({
140
+ query: "\n mutation ProxySandboxRequest($input: ProxySandboxRequestInput!) {\n proxySandboxRequest(input: $input) { status body }\n }\n ",
141
+ variables: { input: {
142
+ sandboxId: t,
143
+ path: r,
144
+ method: i,
145
+ body: a,
146
+ context: c(n, o)
147
+ } },
148
+ workspaceId: n,
149
+ authContext: o,
150
+ baseUrl: e
151
+ })).proxySandboxRequest;
152
+ if (!s || s.status >= 400) {
153
+ let e = s?.body;
154
+ throw Error(e?.error ?? `Proxy error: ${s?.status ?? "unknown"}`);
155
+ }
156
+ return s.body;
157
+ }
158
+ async function h(e, t, n, r, i = 9e4, a) {
159
+ let o = Date.now();
160
+ for (; Date.now() - o < i;) {
161
+ try {
162
+ await m(e, t, n, "/health", "GET", void 0, r);
163
+ return;
164
+ } catch (e) {
165
+ let t = e instanceof Error ? e.message : String(e);
166
+ if (!/proxy error: 502|proxy error: 503|proxy error: 404|service not available/i.test(t)) throw e;
167
+ }
168
+ let i = Math.max(1, Math.round((Date.now() - o) / 1e3));
169
+ a?.(`Connecting to assistant... (${i}s)`), await new Promise((e) => setTimeout(e, 2e3));
170
+ }
171
+ throw Error("Assistant service did not become healthy before timeout");
172
+ }
173
+ async function g(e, t, n, r, i) {
174
+ return { sessionId: (await m(e, t, n, "/sessions", "POST", { mode: r }, i)).session.id };
175
+ }
176
+ async function _(e, t, n, r, i, a, o, s) {
177
+ let c = {
178
+ mode: a,
179
+ prompt: i,
180
+ pageContext: o ?? void 0
181
+ };
182
+ await m(e, t, n, `/sessions/${r}/prompt-async`, "POST", c, s);
183
+ }
184
+ async function v(e, t, n, r, i, a = 50) {
185
+ return (await m(e, t, n, `/sessions/${r}/messages?limit=${a}`, "GET", void 0, i)).messages ?? [];
186
+ }
187
+ async function y(e, t, n, r = 600, i) {
188
+ await u({
189
+ query: "\n mutation ExtendSandboxTTL($id: ID!, $additionalSeconds: Int!, $context: ContextInput!) {\n extendSandboxTTL(id: $id, additionalSeconds: $additionalSeconds, context: $context) { id }\n }\n ",
190
+ variables: {
191
+ id: t,
192
+ additionalSeconds: r,
193
+ context: c(n, i)
194
+ },
195
+ workspaceId: n,
196
+ authContext: i,
197
+ baseUrl: e
198
+ });
199
+ }
200
+ //#endregion
201
+ export { f as createAssistantSandbox, g as createAssistantSession, y as extendAssistantSandboxTTL, d as findExistingSandbox, v as getAssistantMessages, _ as sendAssistantPromptAsync, h as waitForAssistantServiceReady, p as waitForSandboxReady };
202
+
203
+ //# sourceMappingURL=assistantApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assistantApi.js","names":[],"sources":["../../../src/proserviceworld/services/assistantApi.ts"],"sourcesContent":["/**\n * AI Assistant API service for ProServiceWorld.\n *\n * All requests go through the workspace GraphQL gateway:\n * Frontend → wspace-public-gateway → wspace-sandbox-svc → ai-assistant container\n *\n * Uses the host app's graphqlFetch helper so auth/workspace headers are attached\n * automatically; extra headers are supplied for sandbox-specific auth context.\n */\n\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\nimport type { AssistantArtifact, AssistantMode, PageContext } from '../types';\n\nconst HARBOR_REGISTRY = 'burdenoffregistry.azurecr.io';\n\nfunction resolveImageTag(): string {\n if (import.meta.env.VITE_APP_ENV === 'prod') return 'prod';\n if (import.meta.env.VITE_DEPLOY_ENV === 'prod') return 'prod';\n if (import.meta.env.PROD) return 'prod';\n return 'alpha';\n}\n\nconst DEFAULT_IMAGE_TAG = resolveImageTag();\nconst ASSISTANT_API_AUTH_STRATEGY = 'sandbox-app-client-headers-v1';\n\nfunction getImageForMode(mode: AssistantMode): string {\n const imageMode = mode === 'assistant' ? 'api-calls' : mode;\n return `${HARBOR_REGISTRY}/wspace/ai-assistant-${imageMode}:${DEFAULT_IMAGE_TAG}`;\n}\n\nfunction getResourcesForMode(): {\n cpuRequest: string;\n cpuLimit: string;\n memoryRequest: string;\n memoryLimit: string;\n} {\n return {\n cpuRequest: '150m',\n cpuLimit: '750m',\n memoryRequest: '384Mi',\n memoryLimit: '1536Mi',\n };\n}\n\nfunction resolveSandboxAssistantMode(sandbox: {\n metadata?: Record<string, unknown> | null;\n name?: string | null;\n}): AssistantMode | null {\n const metadataMode = sandbox.metadata?.assistantMode;\n if (\n metadataMode === 'assistant' ||\n metadataMode === 'general' ||\n metadataMode === 'api-calls' ||\n metadataMode === 'vibe-plugins'\n ) {\n return metadataMode;\n }\n\n const name = sandbox.name ?? '';\n if (name.startsWith('ai-assistant-vibe-plugins-')) return 'vibe-plugins';\n if (name.startsWith('ai-assistant-api-calls-')) return 'api-calls';\n if (name.startsWith('ai-assistant-general-')) return 'general';\n if (name.startsWith('ai-assistant-assistant-')) return 'assistant';\n return null;\n}\n\nexport interface AssistantPromptResult {\n response: string;\n tokens?: { input: number; output: number };\n artifacts?: AssistantArtifact[];\n}\n\nexport interface AssistantRawMessagePart {\n type?: string;\n text?: string;\n tool?: string;\n state?: {\n status?: string;\n input?: unknown;\n output?: unknown;\n raw?: unknown;\n };\n}\n\nexport interface AssistantRawMessage {\n info?: {\n id?: string;\n role?: string;\n providerID?: string;\n modelID?: string;\n tokens?: { input: number; output: number };\n time?: {\n created?: number;\n completed?: number;\n };\n };\n parts?: AssistantRawMessagePart[];\n}\n\nexport interface AssistantSandboxAuthContext {\n accessToken?: string | null;\n workspaceToken?: string | null;\n userId?: string | null;\n organizationId?: string | null;\n}\n\nexport interface AssistantSessionInfo {\n id: string;\n mode: string;\n}\n\ninterface GraphQLResponse<TData> {\n data?: TData;\n errors?: Array<{ message: string }>;\n}\n\nfunction buildContextInput(\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext\n): { workspaceId: string; custom?: { organizationId?: string } } {\n return {\n workspaceId,\n ...(authContext?.organizationId\n ? { custom: { organizationId: authContext.organizationId } }\n : {}),\n };\n}\n\nfunction buildExtraHeaders(\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext\n): Record<string, string> {\n const headers: Record<string, string> = {};\n\n if (authContext?.accessToken) {\n headers.authorization = `Bearer ${authContext.accessToken}`;\n }\n\n if (authContext?.workspaceToken) {\n headers['x-workspace-authorization'] = `Bearer ${authContext.workspaceToken}`;\n }\n\n headers['x-workspace-id'] = workspaceId;\n\n if (authContext?.userId) {\n headers['x-actor-id'] = authContext.userId;\n headers['x-actor-type'] = 'user';\n }\n\n if (authContext?.organizationId) {\n headers['x-org-id'] = authContext.organizationId;\n }\n\n return headers;\n}\n\nasync function executeSandboxGraphQL<TData>(params: {\n query: string;\n variables: Record<string, unknown>;\n workspaceId: string;\n authContext?: AssistantSandboxAuthContext;\n baseUrl?: string;\n}): Promise<TData> {\n const response = await graphqlFetch<TData>({\n gateway: 'workspace',\n baseUrl: params.baseUrl,\n query: params.query,\n variables: params.variables,\n workspaceToken: true,\n extraHeaders: buildExtraHeaders(params.workspaceId, params.authContext),\n suppressGlobalErrorEvent: true,\n });\n\n if (response.errors?.length) {\n const err = new Error(\n response.errors[0]?.message ?? 'Sandbox GraphQL request failed'\n ) as Error & {\n result?: unknown;\n };\n err.result = response as unknown as GraphQLResponse<TData>;\n throw err;\n }\n\n if (!response.data) {\n throw new Error('Sandbox GraphQL returned no data');\n }\n\n return response.data;\n}\n\nexport async function findExistingSandbox(\n baseUrl: string | undefined,\n workspaceId: string,\n mode: AssistantMode,\n authContext?: AssistantSandboxAuthContext\n): Promise<string | null> {\n const data = await executeSandboxGraphQL<{\n getActiveSandboxes: Array<{\n id: string;\n name: string;\n status: string;\n metadata: Record<string, unknown> | null;\n template: string;\n createdBy: string;\n }>;\n }>({\n query: `\n query GetActiveSandboxes($context: ContextInput!) {\n getActiveSandboxes(context: $context) {\n id\n name\n status\n metadata\n template\n createdBy\n }\n }\n `,\n variables: { context: buildContextInput(workspaceId, authContext) },\n workspaceId,\n authContext,\n baseUrl,\n });\n const sandboxes = data.getActiveSandboxes ?? [];\n\n return (\n sandboxes.find(\n (s) =>\n (s.status === 'RUNNING' || s.status === 'PROVISIONING' || s.status === 'PENDING') &&\n s.template === 'AI_BUILDER' &&\n resolveSandboxAssistantMode(s) === mode &&\n (!authContext?.userId || s.createdBy === authContext.userId) &&\n (s.metadata?.authStrategy as string | undefined) === ASSISTANT_API_AUTH_STRATEGY &&\n (s.metadata?.imageTag as string | undefined) === DEFAULT_IMAGE_TAG\n )?.id ?? null\n );\n}\n\nexport async function createAssistantSandbox(\n baseUrl: string | undefined,\n mode: AssistantMode,\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext\n): Promise<string> {\n const resources = getResourcesForMode();\n const env = [\n { name: 'AI_ASSISTANT_MODE', value: mode },\n { name: 'HOSTNAME', value: '0.0.0.0' },\n { name: 'WORKSPACE_ID', value: workspaceId },\n { name: 'AI_ASSISTANT_PRODUCT', value: 'proserviceworld' },\n ];\n\n const data = await executeSandboxGraphQL<{ createSandbox: { id: string } }>({\n query: `\n mutation CreateSandbox($input: CreateSandboxInput!) {\n createSandbox(input: $input) { id }\n }\n `,\n variables: {\n input: {\n name: `ai-assistant-${mode}-${Date.now()}`,\n description: `AI Assistant sandbox (${mode} mode)`,\n template: 'AI_BUILDER',\n mode: 'DEPLOYMENT',\n containers: [\n {\n name: 'ai-assistant',\n image: getImageForMode(mode),\n ports: [{ containerPort: 8080, name: 'http' }],\n env,\n },\n ],\n resources: {\n cpuRequest: resources.cpuRequest,\n cpuLimit: resources.cpuLimit,\n memoryRequest: resources.memoryRequest,\n memoryLimit: resources.memoryLimit,\n },\n ttlSeconds: 600,\n metadata: {\n assistantMode: mode,\n assistantOwnerUserId: authContext?.userId ?? null,\n assistantOrganizationId: authContext?.organizationId ?? null,\n authStrategy: ASSISTANT_API_AUTH_STRATEGY,\n imageTag: DEFAULT_IMAGE_TAG,\n },\n context: buildContextInput(workspaceId, authContext),\n },\n },\n workspaceId,\n authContext,\n baseUrl,\n });\n\n if (!data?.createSandbox?.id) {\n throw new Error('createSandbox returned empty response');\n }\n return data.createSandbox.id;\n}\n\nexport async function waitForSandboxReady(\n baseUrl: string | undefined,\n sandboxId: string,\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext,\n maxWaitMs = 300_000,\n onProgress?: (message: string) => void\n): Promise<void> {\n const start = Date.now();\n while (Date.now() - start < maxWaitMs) {\n const data = await executeSandboxGraphQL<{\n getSandbox: { status?: string; errorMessage?: string } | null;\n }>({\n query: `\n query GetSandbox($id: ID!, $context: ContextInput!) {\n getSandbox(id: $id, context: $context) { status errorMessage }\n }\n `,\n variables: { id: sandboxId, context: buildContextInput(workspaceId, authContext) },\n workspaceId,\n authContext,\n baseUrl,\n });\n const status = data?.getSandbox?.status;\n const errorMessage = data?.getSandbox?.errorMessage;\n if (status === 'RUNNING') return;\n if (status === 'FAILED' || status === 'STOPPED' || status === 'EXPIRED') {\n throw new Error(\n errorMessage\n ? `Sandbox ${status.toLowerCase()}: ${errorMessage}`\n : `Sandbox ${status.toLowerCase()}`\n );\n }\n const elapsedSeconds = Math.max(1, Math.round((Date.now() - start) / 1000));\n onProgress?.(`Starting assistant environment... (${elapsedSeconds}s)`);\n await new Promise((r) => setTimeout(r, 2000));\n }\n throw new Error('Sandbox startup timed out');\n}\n\ninterface ProxyResponse {\n proxySandboxRequest: {\n status: number;\n body: Record<string, unknown>;\n };\n}\n\nasync function proxyToSandbox(\n baseUrl: string | undefined,\n sandboxId: string,\n workspaceId: string,\n path: string,\n method: string,\n body?: unknown,\n authContext?: AssistantSandboxAuthContext\n): Promise<Record<string, unknown>> {\n const result = await executeSandboxGraphQL<ProxyResponse>({\n query: `\n mutation ProxySandboxRequest($input: ProxySandboxRequestInput!) {\n proxySandboxRequest(input: $input) { status body }\n }\n `,\n variables: {\n input: {\n sandboxId,\n path,\n method,\n body,\n context: buildContextInput(workspaceId, authContext),\n },\n },\n workspaceId,\n authContext,\n baseUrl,\n });\n\n const proxyResult = result.proxySandboxRequest;\n if (!proxyResult || proxyResult.status >= 400) {\n const errBody = proxyResult?.body as Record<string, unknown> | undefined;\n throw new Error(\n (errBody?.error as string) ?? `Proxy error: ${proxyResult?.status ?? 'unknown'}`\n );\n }\n\n return proxyResult.body;\n}\n\nexport async function waitForAssistantServiceReady(\n baseUrl: string | undefined,\n sandboxId: string,\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext,\n maxWaitMs = 90_000,\n onProgress?: (message: string) => void\n): Promise<void> {\n const startedAt = Date.now();\n\n while (Date.now() - startedAt < maxWaitMs) {\n try {\n await proxyToSandbox(\n baseUrl,\n sandboxId,\n workspaceId,\n '/health',\n 'GET',\n undefined,\n authContext\n );\n return;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n if (\n !/proxy error: 502|proxy error: 503|proxy error: 404|service not available/i.test(message)\n ) {\n throw error;\n }\n }\n\n const elapsedSeconds = Math.max(1, Math.round((Date.now() - startedAt) / 1000));\n onProgress?.(`Connecting to assistant... (${elapsedSeconds}s)`);\n await new Promise((resolve) => setTimeout(resolve, 2000));\n }\n\n throw new Error('Assistant service did not become healthy before timeout');\n}\n\nexport async function createAssistantSession(\n baseUrl: string | undefined,\n sandboxId: string,\n workspaceId: string,\n mode: AssistantMode,\n authContext?: AssistantSandboxAuthContext\n): Promise<{ sessionId: string }> {\n const body = await proxyToSandbox(\n baseUrl,\n sandboxId,\n workspaceId,\n '/sessions',\n 'POST',\n { mode },\n authContext\n );\n const session = body.session as Record<string, unknown>;\n return { sessionId: session.id as string };\n}\n\nexport async function sendAssistantPromptAsync(\n baseUrl: string | undefined,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n prompt: string,\n mode: AssistantMode,\n pageContext?: PageContext,\n authContext?: AssistantSandboxAuthContext\n): Promise<void> {\n const requestBody = {\n mode,\n prompt,\n pageContext: pageContext ?? undefined,\n };\n\n await proxyToSandbox(\n baseUrl,\n sandboxId,\n workspaceId,\n `/sessions/${sessionId}/prompt-async`,\n 'POST',\n requestBody,\n authContext\n );\n}\n\nexport async function getAssistantMessages(\n baseUrl: string | undefined,\n sandboxId: string,\n workspaceId: string,\n sessionId: string,\n authContext?: AssistantSandboxAuthContext,\n limit = 50\n): Promise<AssistantRawMessage[]> {\n const body = await proxyToSandbox(\n baseUrl,\n sandboxId,\n workspaceId,\n `/sessions/${sessionId}/messages?limit=${limit}`,\n 'GET',\n undefined,\n authContext\n );\n\n return (body.messages as AssistantRawMessage[] | undefined) ?? [];\n}\n\nexport async function extendAssistantSandboxTTL(\n baseUrl: string | undefined,\n sandboxId: string,\n workspaceId: string,\n additionalSeconds = 600,\n authContext?: AssistantSandboxAuthContext\n): Promise<void> {\n await executeSandboxGraphQL<{ extendSandboxTTL: { id: string } }>({\n query: `\n mutation ExtendSandboxTTL($id: ID!, $additionalSeconds: Int!, $context: ContextInput!) {\n extendSandboxTTL(id: $id, additionalSeconds: $additionalSeconds, context: $context) { id }\n }\n `,\n variables: {\n id: sandboxId,\n additionalSeconds,\n context: buildContextInput(workspaceId, authContext),\n },\n workspaceId,\n authContext,\n baseUrl,\n });\n}\n\n/**\n * Pre-flight AI-credit gate. Resolves to `true` when the caller still has\n * AI-credit budget; throws a quota error when the monthly token budget is\n * depleted.\n */\nexport async function checkAssistantAiCredits(\n baseUrl: string | undefined,\n workspaceId: string,\n authContext?: AssistantSandboxAuthContext\n): Promise<boolean> {\n const data = await executeSandboxGraphQL<{ checkAiCredits: boolean }>({\n query: `mutation CheckAiCredits { checkAiCredits }`,\n variables: {},\n workspaceId,\n authContext,\n baseUrl,\n });\n return data.checkAiCredits;\n}\n\n/**\n * Post-turn charge. Reports raw input/output token counts + the model so the\n * service computes cost-weighted credits server-side. Best-effort — callers\n * must not block the displayed answer on it.\n */\nexport async function reportAssistantAiTokenUsage(\n baseUrl: string | undefined,\n workspaceId: string,\n sessionId: string,\n messageId: string,\n model: string | undefined,\n tokens: { input: number; output: number },\n authContext?: AssistantSandboxAuthContext\n): Promise<void> {\n const inputTokens = Math.max(0, Math.round(tokens.input ?? 0));\n const outputTokens = Math.max(0, Math.round(tokens.output ?? 0));\n if (inputTokens + outputTokens === 0) return;\n if (!model) return;\n\n await executeSandboxGraphQL<{ reportAiTokenUsage: boolean }>({\n query: `\n mutation ReportAiTokenUsage($input: ReportAiTokenUsageInput!) {\n reportAiTokenUsage(input: $input)\n }\n `,\n variables: {\n input: { sessionId, messageId, model, inputTokens, outputTokens },\n },\n workspaceId,\n authContext,\n baseUrl,\n });\n}\n"],"mappings":"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AM,IAAI,SAAS,MAAY,WAAW,GAAS,IAAK,CAAC;;AAG3D,OAAU,MAAM,0DAA0D;;AAG5E,eAAsB,EACpB,GACA,GACA,GACA,GACA,GACgC;AAWhC,QAAO,EAAE,YAVI,MAAM,EACjB,GACA,GACA,GACA,aACA,QACA,EAAE,SAAM,EACR,EACD,EACoB,QACO,IAAc;;AAG5C,eAAsB,EACpB,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACe;CACf,IAAM,IAAc;EAClB;EACA;EACA,aAAa,KAAe,KAAA;EAC7B;AAED,OAAM,EACJ,GACA,GACA,GACA,aAAa,EAAU,gBACvB,QACA,GACA,EACD;;AAGH,eAAsB,EACpB,GACA,GACA,GACA,GACA,GACA,IAAQ,IACwB;AAWhC,SAVa,MAAM,EACjB,GACA,GACA,GACA,aAAa,EAAU,kBAAkB,KACzC,OACA,KAAA,GACA,EACD,EAEY,YAAkD,EAAE;;AAGnE,eAAsB,EACpB,GACA,GACA,GACA,IAAoB,KACpB,GACe;AACf,OAAM,EAA4D;EAChE,OAAO;EAKP,WAAW;GACT,IAAI;GACJ;GACA,SAAS,EAAkB,GAAa,EAAY;GACrD;EACD;EACA;EACA;EACD,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * ProServiceWorld adapter for the shared fe-libs AssistantWidget.
3
+ *
4
+ * The floating widget (Layer 1) is backend-agnostic — it calls an injected
5
+ * `AssistantTransport`. This hook builds a transport that reuses the sandbox
6
+ * `api-calls` agent: it provisions/reuses a sandbox, opens a session, dispatches
7
+ * the prompt async, then polls for the streamed answer. The agent introspects
8
+ * the GraphQL schema and performs API calls on the user's behalf using their
9
+ * workspace token, contextual to the current screen (via `gatherPageContext`).
10
+ */
11
+ interface AssistantSendArgs {
12
+ prompt: string;
13
+ onProgress: (partialText: string) => void;
14
+ signal: AbortSignal;
15
+ }
16
+ export interface AssistantTransport {
17
+ sendPrompt: (args: AssistantSendArgs) => Promise<{
18
+ text: string;
19
+ }>;
20
+ }
21
+ /**
22
+ * Returns a memoized `AssistantTransport` wired to the ProServiceWorld sandbox
23
+ * `api-calls` agent. The sandbox + session are cached in refs so follow-up
24
+ * turns reuse the warm environment for the lifetime of the host shell.
25
+ */
26
+ export declare function useSandboxAssistantTransport(): AssistantTransport;
27
+ export {};
28
+ //# sourceMappingURL=createSandboxAssistantTransport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createSandboxAssistantTransport.d.ts","sourceRoot":"","sources":["../../../src/proserviceworld/services/createSandboxAssistantTransport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAoBH,UAAU,iBAAiB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpE;AAmHD;;;;GAIG;AACH,wBAAgB,4BAA4B,IAAI,kBAAkB,CAiIjE"}
@@ -0,0 +1,120 @@
1
+ import { useProServiceWorld as e } from "../providers/ProServiceWorldProvider.js";
2
+ import { createAssistantSandbox as t, createAssistantSession as n, extendAssistantSandboxTTL as r, findExistingSandbox as i, getAssistantMessages as a, sendAssistantPromptAsync as o, waitForAssistantServiceReady as s, waitForSandboxReady as c } from "./assistantApi.js";
3
+ import { gatherPageContext as l } from "../utils/pageContext.js";
4
+ import { useCallback as u, useMemo as d, useRef as f } from "react";
5
+ import { useAuthToken as p } from "@burdenoff/fe-libs/shared/providers/shell";
6
+ //#region src/proserviceworld/services/createSandboxAssistantTransport.ts
7
+ var m = "assistant", h = 18e4, g = 1500, _ = 3e4;
8
+ function v(e) {
9
+ try {
10
+ let t = e === "workspaceId" ? "burdenoff-active-context-workspace" : "burdenoff-active-context-organization", n = localStorage.getItem(t);
11
+ if (n) return n;
12
+ let r = sessionStorage.getItem("bf-active-profile");
13
+ if (!r) return "";
14
+ let i = localStorage.getItem(`bf-p-${r}-context`);
15
+ return i ? JSON.parse(i)[e] ?? "" : "";
16
+ } catch {
17
+ return "";
18
+ }
19
+ }
20
+ function y() {
21
+ return new URLSearchParams(window.location.search).get("workspace") ?? v("workspaceId");
22
+ }
23
+ function b() {
24
+ return new URLSearchParams(window.location.search).get("org") ?? v("organizationId");
25
+ }
26
+ function x(e) {
27
+ return e.info?.time?.created ?? 0;
28
+ }
29
+ function S(e) {
30
+ return (e ?? []).filter((e) => e.type === "text" && typeof e.text == "string").map((e) => e.text?.trim() ?? "").filter(Boolean).join("\n");
31
+ }
32
+ function C(e) {
33
+ return (e ?? []).filter((e) => e.type === "tool" && e.tool).map((e) => {
34
+ let t = e.state?.status ?? "running", n = e.tool ?? "tool";
35
+ return t === "completed" ? `Completed: ${n}` : t === "failed" ? `Failed: ${n}` : `Running: ${n}`;
36
+ });
37
+ }
38
+ function w(e, t) {
39
+ let n = e.filter((e) => e.info?.role === "assistant" && x(e) >= t).sort((e, t) => x(e) - x(t));
40
+ if (n.length === 0) return {
41
+ content: "Thinking…",
42
+ done: !1
43
+ };
44
+ let r = n[n.length - 1], i = S(r.parts), a = C(r.parts);
45
+ return {
46
+ content: [i, ...a].filter(Boolean).join("\n\n") || "Thinking…",
47
+ done: !!r.info?.time?.completed && (!!i || a.length > 0)
48
+ };
49
+ }
50
+ function T(e) {
51
+ return e.replace(/(Authorization\s*:\s*Bearer\s+)[^\s\n]+/gi, "$1[REDACTED]").replace(/(X-Workspace-Authorization\s*:\s*Bearer\s+)[^\s\n]+/gi, "$1[REDACTED]").replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9._-]+\.[A-Za-z0-9._-]+\b/g, "[REDACTED_JWT]").replace(/\bsk-ant-[A-Za-z0-9-]+\b/g, "[REDACTED_API_KEY]");
52
+ }
53
+ function E(e) {
54
+ let t = e instanceof Error ? e.message.toLowerCase() : String(e).toLowerCase();
55
+ return t.includes("rate limit exceeded") || t.includes("unauthorized") || t.includes("k8s api error 401") ? !1 : [
56
+ "sandbox not found",
57
+ "sandbox is not running",
58
+ "sandbox service not available yet",
59
+ "sandbox failed",
60
+ "sandbox startup timed out",
61
+ "assistant service did not become healthy",
62
+ "proxy error: 404",
63
+ "proxy error: 502",
64
+ "proxy error: 503"
65
+ ].some((e) => t.includes(e));
66
+ }
67
+ function D() {
68
+ let { apiGatewayUrl: v } = e(), { getAccessToken: x, getWorkspaceToken: S, userId: C } = p(), D = f(null), O = f(null), k = u(async (e, r) => {
69
+ let a = D.current;
70
+ if (!a) {
71
+ if (a = await i(v, e, m, r), !a) {
72
+ if (!x()) throw Error("API Calls mode requires an authenticated session. Please sign in again.");
73
+ a = await t(v, m, e, r);
74
+ }
75
+ await c(v, a, e, r), await s(v, a, e, r), D.current = a;
76
+ }
77
+ let o = O.current;
78
+ return o || (o = (await n(v, a, e, m, r)).sessionId, O.current = o), {
79
+ sandboxId: a,
80
+ sessionId: o
81
+ };
82
+ }, [v, x]), A = u(async ({ prompt: e, onProgress: t, signal: n }) => {
83
+ let i = y();
84
+ if (!i) throw Error("The assistant needs an active workspace. Open a workspace and try again.");
85
+ let s = {
86
+ accessToken: x(),
87
+ workspaceToken: S(),
88
+ userId: C,
89
+ organizationId: b()
90
+ }, c = async (u) => {
91
+ try {
92
+ let { sandboxId: c, sessionId: u } = await k(i, s), d = Date.now();
93
+ await o(v, c, i, u, e, m, l(), s);
94
+ let f = Date.now() + h, p = Date.now(), y = w([], d);
95
+ for (; Date.now() < f;) {
96
+ if (n.aborted) throw Error("Cancelled");
97
+ if (y = w(await a(v, c, i, u, s, 50), d), t(T(y.content)), y.done) break;
98
+ Date.now() - p > _ && (await r(v, c, i, 600, s).catch(() => void 0), p = Date.now()), await new Promise((e) => setTimeout(e, g));
99
+ }
100
+ if (!y.done) throw Error("The assistant timed out while responding. Please try again.");
101
+ return { text: T(y.content) };
102
+ } catch (e) {
103
+ if (u === 1 && E(e)) return D.current = null, O.current = null, c(2);
104
+ throw e;
105
+ }
106
+ };
107
+ return c(1);
108
+ }, [
109
+ v,
110
+ k,
111
+ x,
112
+ S,
113
+ C
114
+ ]);
115
+ return d(() => ({ sendPrompt: A }), [A]);
116
+ }
117
+ //#endregion
118
+ export { D as useSandboxAssistantTransport };
119
+
120
+ //# sourceMappingURL=createSandboxAssistantTransport.js.map