@dxos/plugin-assistant 0.13.0 → 0.14.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.
- package/PLUGIN.mdl +25 -0
- package/dist/lib/AssistantCapabilities.mjs +8 -1
- package/dist/lib/AssistantCapabilities.mjs.map +1 -1
- package/dist/lib/Settings.mjs +4 -0
- package/dist/lib/Settings.mjs.map +1 -1
- package/dist/lib/TurnReviewSkill.mjs +55 -0
- package/dist/lib/TurnReviewSkill.mjs.map +1 -0
- package/dist/lib/chunk-AgentArticle.mjs +1 -1
- package/dist/lib/chunk-AssistantSettings.mjs +1 -1
- package/dist/lib/chunk-AssistantSettings.mjs.map +1 -1
- package/dist/lib/chunk-Chat.mjs +322 -174
- package/dist/lib/chunk-Chat.mjs.map +1 -1
- package/dist/lib/chunk-ChatArticle.mjs +14 -7
- package/dist/lib/chunk-ChatArticle.mjs.map +1 -1
- package/dist/lib/chunk-ChatDialog.mjs +5 -4
- package/dist/lib/chunk-ChatDialog.mjs.map +1 -1
- package/dist/lib/chunk-IntegrationPrompt.mjs +1 -1
- package/dist/lib/chunk-PLUGIN.mjs +1 -1
- package/dist/lib/chunk-PluginUrlPrompt.mjs +1 -1
- package/dist/lib/chunk-QuestionSurface.mjs +1 -1
- package/dist/lib/chunk-SpaceHomePrompt.mjs +116 -60
- package/dist/lib/chunk-SpaceHomePrompt.mjs.map +1 -1
- package/dist/lib/chunk-TriggerStatus.mjs +1 -1
- package/dist/lib/chunk-agent-service.mjs +3 -1
- package/dist/lib/chunk-agent-service.mjs.map +1 -1
- package/dist/lib/chunk-analyze-turn.mjs +220 -0
- package/dist/lib/chunk-analyze-turn.mjs.map +1 -0
- package/dist/lib/{chunk-processor.mjs → chunk-chat-model.mjs} +95 -43
- package/dist/lib/chunk-chat-model.mjs.map +1 -0
- package/dist/lib/chunk-context.mjs.map +1 -1
- package/dist/lib/chunk-create-chat.mjs +5 -19
- package/dist/lib/chunk-create-chat.mjs.map +1 -1
- package/dist/lib/chunk-create-object.mjs +1 -1
- package/dist/lib/chunk-default-skills.mjs +28 -0
- package/dist/lib/chunk-default-skills.mjs.map +1 -0
- package/dist/lib/chunk-generate-home-suggestions.mjs +8 -6
- package/dist/lib/chunk-generate-home-suggestions.mjs.map +1 -1
- package/dist/lib/chunk-presets.mjs +1 -1
- package/dist/lib/chunk-presets.mjs.map +1 -1
- package/dist/lib/chunk-question-resumer.mjs +1 -1
- package/dist/lib/chunk-react-surface.mjs +1 -1
- package/dist/lib/chunk-run-prompt-in-chat.mjs +2 -1
- package/dist/lib/chunk-run-prompt-in-chat.mjs.map +1 -1
- package/dist/lib/chunk-run-prompt-in-new-chat.mjs +1 -1
- package/dist/lib/chunk-schema-defs.mjs +2 -2
- package/dist/lib/chunk-skill-definition.mjs +3 -2
- package/dist/lib/chunk-skill-definition.mjs.map +1 -1
- package/dist/lib/components.mjs +13 -13
- package/dist/lib/components.mjs.map +1 -1
- package/dist/lib/hooks.mjs +40 -31
- package/dist/lib/hooks.mjs.map +1 -1
- package/dist/lib/operations.mjs +3 -1
- package/dist/lib/operations.mjs.map +1 -1
- package/dist/lib/skills.mjs +2 -1
- package/dist/lib/translations.mjs +4 -2
- package/dist/lib/translations.mjs.map +1 -1
- package/dist/types/src/Chat.d.ts +1 -1
- package/dist/types/src/capabilities/agent-service.d.ts.map +1 -1
- package/dist/types/src/capabilities/skill-definition.d.ts.map +1 -1
- package/dist/types/src/{processor/processor.d.ts → chat-model/chat-model.d.ts} +24 -22
- package/dist/types/src/chat-model/chat-model.d.ts.map +1 -0
- package/dist/types/src/chat-model/chat-model.edge.test.d.ts +2 -0
- package/dist/types/src/chat-model/chat-model.edge.test.d.ts.map +1 -0
- package/dist/types/src/chat-model/chat-model.node.test.d.ts +2 -0
- package/dist/types/src/chat-model/chat-model.node.test.d.ts.map +1 -0
- package/dist/types/src/chat-model/chat-model.scripted.node.test.d.ts +2 -0
- package/dist/types/src/chat-model/chat-model.scripted.node.test.d.ts.map +1 -0
- package/dist/types/src/{processor → chat-model}/index.d.ts +1 -1
- package/dist/types/src/chat-model/index.d.ts.map +1 -0
- package/dist/types/src/chat-model/outbox.d.ts.map +1 -0
- package/dist/types/src/chat-model/outbox.test.d.ts.map +1 -0
- package/dist/types/src/chat-model/presets.d.ts.map +1 -0
- package/dist/types/src/chat-model/presets.test.d.ts.map +1 -0
- package/dist/types/src/{processor → chat-model}/prompt.d.ts +2 -2
- package/dist/types/src/chat-model/prompt.d.ts.map +1 -0
- package/dist/types/src/chat-model/prompt.test.d.ts.map +1 -0
- package/dist/types/src/chat-model/streaming.node.test.d.ts.map +1 -0
- package/dist/types/src/chat-model/testing/chat-model-recorder.d.ts +58 -0
- package/dist/types/src/chat-model/testing/chat-model-recorder.d.ts.map +1 -0
- package/dist/types/src/chat-model/testing/harness.d.ts +22 -0
- package/dist/types/src/chat-model/testing/harness.d.ts.map +1 -0
- package/dist/types/src/chat-model/thread.d.ts.map +1 -0
- package/dist/types/src/chat-model/thread.test.d.ts.map +1 -0
- package/dist/types/src/components/Chat/Chat.d.ts +6 -6
- package/dist/types/src/components/Chat/Chat.d.ts.map +1 -1
- package/dist/types/src/components/Chat/context.d.ts +5 -3
- package/dist/types/src/components/Chat/context.d.ts.map +1 -1
- package/dist/types/src/components/ChatPrompt/ChatActions.d.ts +1 -1
- package/dist/types/src/components/ChatPrompt/ChatActions.d.ts.map +1 -1
- package/dist/types/src/components/ChatPrompt/ChatMcpErrors.d.ts +3 -3
- package/dist/types/src/components/ChatPrompt/ChatMcpErrors.d.ts.map +1 -1
- package/dist/types/src/components/ChatPrompt/ChatOptions.d.ts +3 -1
- package/dist/types/src/components/ChatPrompt/ChatOptions.d.ts.map +1 -1
- package/dist/types/src/components/ChatPrompt/ChatOptions.stories.d.ts +4 -3
- package/dist/types/src/components/ChatPrompt/ChatOptions.stories.d.ts.map +1 -1
- package/dist/types/src/components/ChatPrompt/ChatPrompt.d.ts +15 -5
- package/dist/types/src/components/ChatPrompt/ChatPrompt.d.ts.map +1 -1
- package/dist/types/src/components/ChatPrompt/ChatPrompt.stories.d.ts +1 -1
- package/dist/types/src/components/ChatPrompt/ChatStatus.d.ts +1 -1
- package/dist/types/src/components/ChatPrompt/ChatStatus.d.ts.map +1 -1
- package/dist/types/src/components/ConnectorAuthMenu/ConnectorAuthMenu.stories.d.ts +9 -0
- package/dist/types/src/components/ConnectorAuthMenu/ConnectorAuthMenu.stories.d.ts.map +1 -1
- package/dist/types/src/components/Toolbox/Toolbox.d.ts +3 -3
- package/dist/types/src/components/Toolbox/Toolbox.d.ts.map +1 -1
- package/dist/types/src/containers/ChatArticle/ChatArticle.d.ts.map +1 -1
- package/dist/types/src/containers/ChatArticle/ChatArticle.stories.d.ts +1 -1
- package/dist/types/src/containers/SpaceHomePrompt/SpaceHomePrompt.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +2 -2
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/{useChatProcessor.d.ts → useChatModel.d.ts} +6 -6
- package/dist/types/src/hooks/useChatModel.d.ts.map +1 -0
- package/dist/types/src/hooks/useDebug.d.ts +3 -3
- package/dist/types/src/hooks/useDebug.d.ts.map +1 -1
- package/dist/types/src/hooks/useHomeSuggestions.d.ts +3 -3
- package/dist/types/src/hooks/useHomeSuggestions.d.ts.map +1 -1
- package/dist/types/src/hooks/usePresets.d.ts +1 -1
- package/dist/types/src/hooks/usePresets.d.ts.map +1 -1
- package/dist/types/src/hooks/useSelectionContext.d.ts +3 -3
- package/dist/types/src/hooks/useSelectionContext.d.ts.map +1 -1
- package/dist/types/src/operations/analyze-turn.d.ts +5 -0
- package/dist/types/src/operations/analyze-turn.d.ts.map +1 -0
- package/dist/types/src/operations/analyze-turn.test.d.ts +2 -0
- package/dist/types/src/operations/analyze-turn.test.d.ts.map +1 -0
- package/dist/types/src/operations/create-chat.d.ts.map +1 -1
- package/dist/types/src/operations/generate-home-suggestions.d.ts.map +1 -1
- package/dist/types/src/operations/index.d.ts.map +1 -1
- package/dist/types/src/operations/run-prompt-in-chat.d.ts.map +1 -1
- package/dist/types/src/review/turn-review.d.ts +58 -0
- package/dist/types/src/review/turn-review.d.ts.map +1 -0
- package/dist/types/src/review/turn-review.test.d.ts +2 -0
- package/dist/types/src/review/turn-review.test.d.ts.map +1 -0
- package/dist/types/src/skills/index.d.ts +1 -0
- package/dist/types/src/skills/index.d.ts.map +1 -1
- package/dist/types/src/skills/turn-review/TurnReviewSkill.d.ts +21 -0
- package/dist/types/src/skills/turn-review/TurnReviewSkill.d.ts.map +1 -0
- package/dist/types/src/skills/turn-review/index.d.ts +2 -0
- package/dist/types/src/skills/turn-review/index.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Assistant.d.ts +1 -0
- package/dist/types/src/types/Assistant.d.ts.map +1 -1
- package/dist/types/src/types/AssistantCapabilities.d.ts +7 -1
- package/dist/types/src/types/AssistantCapabilities.d.ts.map +1 -1
- package/dist/types/src/types/Settings.d.ts +1 -0
- package/dist/types/src/types/Settings.d.ts.map +1 -1
- package/dist/types/src/util/agent-options.d.ts +27 -0
- package/dist/types/src/util/agent-options.d.ts.map +1 -0
- package/dist/types/src/util/agent-options.test.d.ts +2 -0
- package/dist/types/src/util/agent-options.test.d.ts.map +1 -0
- package/dist/types/src/util/default-skills.d.ts +10 -0
- package/dist/types/src/util/default-skills.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +89 -80
- package/src/capabilities/agent-service.ts +2 -1
- package/src/capabilities/skill-definition.ts +2 -1
- package/src/chat-model/chat-model.edge.test.ts +301 -0
- package/src/{processor/processor.node.test.ts → chat-model/chat-model.node.test.ts} +19 -9
- package/src/chat-model/chat-model.scripted.node.test.ts +441 -0
- package/src/{processor/processor.ts → chat-model/chat-model.ts} +140 -45
- package/src/{processor → chat-model}/index.ts +1 -1
- package/src/{processor → chat-model}/prompt.ts +2 -2
- package/src/{processor → chat-model}/streaming.node.test.ts +108 -116
- package/src/chat-model/testing/chat-model-recorder.ts +249 -0
- package/src/chat-model/testing/harness.ts +81 -0
- package/src/{processor → chat-model}/thread.test.ts +1 -1
- package/src/components/Chat/Chat.tsx +44 -38
- package/src/components/Chat/Error.stories.tsx +1 -1
- package/src/components/Chat/context.ts +5 -3
- package/src/components/ChatPrompt/ChatActions.tsx +1 -1
- package/src/components/ChatPrompt/ChatMcpErrors.tsx +6 -6
- package/src/components/ChatPrompt/ChatOptions.stories.tsx +37 -3
- package/src/components/ChatPrompt/ChatOptions.tsx +118 -10
- package/src/components/ChatPrompt/ChatPrompt.stories.tsx +10 -10
- package/src/components/ChatPrompt/ChatPrompt.tsx +44 -27
- package/src/components/ChatPrompt/ChatStatus.tsx +8 -7
- package/src/components/Toolbox/Toolbox.tsx +12 -13
- package/src/containers/AssistantSettings/AssistantSettings.tsx +1 -1
- package/src/containers/ChatArticle/ChatArticle.stories.tsx +1 -1
- package/src/containers/ChatArticle/ChatArticle.tsx +16 -6
- package/src/containers/ChatDialog/ChatDialog.tsx +4 -4
- package/src/containers/SpaceHomePrompt/SpaceHomePrompt.tsx +110 -57
- package/src/hooks/index.ts +2 -2
- package/src/hooks/{useChatProcessor.ts → useChatModel.ts} +16 -14
- package/src/hooks/useDebug.ts +8 -8
- package/src/hooks/useHomeSuggestions.ts +14 -9
- package/src/hooks/usePresets.ts +2 -2
- package/src/hooks/useProcessEphemeralStatus.ts +1 -1
- package/src/hooks/useSelectionContext.ts +3 -5
- package/src/operations/analyze-turn.test.ts +194 -0
- package/src/operations/analyze-turn.ts +96 -0
- package/src/operations/create-chat.ts +4 -36
- package/src/operations/generate-home-suggestions.test.ts +1 -2
- package/src/operations/generate-home-suggestions.ts +17 -9
- package/src/operations/index.ts +2 -0
- package/src/operations/run-prompt-in-chat.ts +3 -2
- package/src/review/turn-review.test.ts +92 -0
- package/src/review/turn-review.ts +213 -0
- package/src/skills/index.ts +1 -0
- package/src/skills/turn-review/TurnReviewSkill.ts +46 -0
- package/src/skills/turn-review/index.ts +5 -0
- package/src/translations.ts +2 -0
- package/src/types/AssistantCapabilities.ts +8 -1
- package/src/types/Settings.ts +7 -0
- package/src/util/agent-options.test.ts +54 -0
- package/src/util/agent-options.ts +60 -0
- package/src/util/default-skills.ts +35 -0
- package/dist/lib/chunk-processor.mjs.map +0 -1
- package/dist/types/src/hooks/useChatProcessor.d.ts.map +0 -1
- package/dist/types/src/processor/index.d.ts.map +0 -1
- package/dist/types/src/processor/outbox.d.ts.map +0 -1
- package/dist/types/src/processor/outbox.test.d.ts.map +0 -1
- package/dist/types/src/processor/presets.d.ts.map +0 -1
- package/dist/types/src/processor/presets.test.d.ts.map +0 -1
- package/dist/types/src/processor/processor.d.ts.map +0 -1
- package/dist/types/src/processor/processor.node.test.d.ts +0 -2
- package/dist/types/src/processor/processor.node.test.d.ts.map +0 -1
- package/dist/types/src/processor/prompt.d.ts.map +0 -1
- package/dist/types/src/processor/prompt.test.d.ts.map +0 -1
- package/dist/types/src/processor/streaming.node.test.d.ts.map +0 -1
- package/dist/types/src/processor/thread.d.ts.map +0 -1
- package/dist/types/src/processor/thread.test.d.ts.map +0 -1
- /package/dist/types/src/{processor → chat-model}/outbox.d.ts +0 -0
- /package/dist/types/src/{processor → chat-model}/outbox.test.d.ts +0 -0
- /package/dist/types/src/{processor → chat-model}/presets.d.ts +0 -0
- /package/dist/types/src/{processor → chat-model}/presets.test.d.ts +0 -0
- /package/dist/types/src/{processor → chat-model}/prompt.test.d.ts +0 -0
- /package/dist/types/src/{processor → chat-model}/streaming.node.test.d.ts +0 -0
- /package/dist/types/src/{processor → chat-model}/thread.d.ts +0 -0
- /package/dist/types/src/{processor → chat-model}/thread.test.d.ts +0 -0
- /package/src/{processor → chat-model}/outbox.test.ts +0 -0
- /package/src/{processor → chat-model}/outbox.ts +0 -0
- /package/src/{processor → chat-model}/presets.test.ts +0 -0
- /package/src/{processor → chat-model}/presets.ts +0 -0
- /package/src/{processor → chat-model}/prompt.test.ts +0 -0
- /package/src/{processor → chat-model}/thread.ts +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-Chat.mjs","names":[],"sources":["../../src/commands/task-commands.ts","../../src/components/ChatPrompt/ChatActions.tsx","../../src/components/ChatPrompt/ChatActivity.tsx","../../src/components/ChatPrompt/ChatMcpErrors.tsx","../../src/components/ChatPrompt/ChatOptions.tsx","../../src/components/ChatPrompt/ChatReferences.tsx","../../src/components/ChatPrompt/useChatVoiceInput.ts","../../src/components/ChatPrompt/ChatPrompt.tsx","../../src/components/ChatPrompt/ChatStatus.tsx","../../src/components/Chat/ObjectCardWidget.tsx","../../src/components/Chat/SurfaceWidget.tsx","../../src/components/Chat/Chat.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as SlashCommand from '@dxos/assistant-toolkit/SlashCommand';\nimport * as Chat from '@dxos/assistant/Chat';\nimport * as Operation from '@dxos/compute/Operation';\nimport { Ref } from '@dxos/echo';\nimport { type SpaceId } from '@dxos/keys';\nimport * as TaskOperation from '@dxos/plugin-tasks/TaskOperation';\nimport { type Task } from '@dxos/types';\nimport { trim } from '@dxos/util';\n\n/** Membership writes go through the `Chat` primitives because the chat, not a `TaskSet`, is the container. */\nexport const TaskSlashCommands: SlashCommand.SlashCommand[] = [\n {\n command: '/task:create',\n description: 'Create a task',\n execute: async (args, { db, chat }) => {\n const title = args.trim();\n if (title.length === 0) {\n return new Error('Usage: /task:create <description>');\n }\n Chat.addTask(db, chat, title);\n await db.flush();\n return { summary: `Created task “${title}”.` };\n },\n },\n {\n command: '/task:delete',\n description: 'Delete task(s) by number or quoted title',\n execute: async (args, { db, chat }) => {\n const tasks = await hydrate(chat);\n const resolved = resolveSelectors(args, tasks);\n if (resolved instanceof Error) {\n return resolved;\n }\n if (resolved.length === 0) {\n return new Error('Usage: /task:delete <number | \"exact title\"> [...]');\n }\n\n // Sub-tasks go with their parent, so a later selector may already have been swept.\n const deleted: Task.Task[] = [];\n const seen = new Set<string>();\n for (const task of resolved) {\n if (seen.has(task.id)) {\n continue;\n }\n for (const member of Chat.deleteTask(db, chat, tasks, task)) {\n seen.add(member.id);\n }\n deleted.push(task);\n }\n await db.flush();\n return { summary: summarize('Deleted', deleted) };\n },\n },\n {\n command: '/task:run',\n description: 'Delegate task(s) by number or quoted title',\n execute: async (args, { db, chat, invoke }) => {\n const resolved = resolveSelectors(args, await hydrate(chat));\n if (resolved instanceof Error) {\n return resolved;\n }\n if (resolved.length === 0) {\n return new Error('Usage: /task:run <number | \"exact title\"> [...]');\n }\n\n // A terminal task has nothing left to run, and delegating a running one would fork it.\n const runnable = resolved.filter(\n (task) => task.status !== 'done' && task.status !== 'cancelled' && task.status !== 'started',\n );\n if (runnable.length === 0) {\n return { summary: 'Nothing to run: every named task is already done, cancelled, or running.' };\n }\n\n // An agent assignee on a `todo` task is what the supervisor's reconcile picks up.\n for (const task of runnable) {\n const failure = await run(\n invoke,\n TaskOperation.UpdateTask,\n {\n task: Ref.make(task),\n assignee: { role: 'assistant' as const },\n status: 'todo' as const,\n },\n db.spaceId,\n );\n if (failure) {\n return failure;\n }\n }\n\n return {\n summary: summarize('Delegated', runnable),\n followUp: trim`\n The user delegated EXACTLY these task(s) with the /task:run command: ${runnable.map((task) => `\"${task.title}\"`).join(', ')}.\n They are queued and will execute in the background. Acknowledge in one short\n sentence now, and when their completion is reported, acknowledge briefly and stop —\n the user scoped this run to those tasks only, so never delegate, start, or work on\n any other task.\n `,\n };\n },\n },\n];\n\n/**\n * `invokePromise` reports a handler failure in its result rather than by rejecting, so an\n * unexamined call reads as success and the command would claim an effect it never had.\n */\nconst run = async <I, O>(\n invoke: SlashCommand.OperationInvoke,\n operation: Operation.Definition<I, O>,\n input: I,\n spaceId: SpaceId | undefined,\n): Promise<Error | undefined> => {\n const { error } = await invoke(operation, input as never, { spaceId });\n return error;\n};\n\n/**\n * The checklist in full: a reopened chat's refs are unresolved until loaded, and an unresolved\n * entry is invisible to both selector matching and the subtree sweep.\n */\nconst hydrate = async (chat: Chat.Chat): Promise<Task.Task[]> => {\n // `tryLoad`, not `load`: the latter throws on an entry whose object is gone, failing the whole\n // command instead of proceeding with the tasks that do resolve.\n await Promise.all(chat.tasks.map((ref) => ref.tryLoad()));\n return Chat.resolveTasks(chat);\n};\n\n/** Resolves selectors against `tasks`, in the order the user named them. */\nconst resolveSelectors = (args: string, tasks: readonly Task.Task[]) => {\n const selectors = SlashCommand.parseTaskSelectors(args);\n if (selectors.length === 0) {\n return [];\n }\n\n const resolved: Task.Task[] = [];\n for (const selector of selectors) {\n const task =\n 'ordinal' in selector\n ? tasks[selector.ordinal - 1]\n : tasks.find((candidate) => candidate.title === selector.title.trim());\n if (!task) {\n const named = 'ordinal' in selector ? selector.ordinal : `\"${selector.title}\"`;\n return new Error(`No matching task for: ${named}. Select by 1-based number, or by exact title in quotes.`);\n }\n resolved.push(task);\n }\n return resolved;\n};\n\nconst summarize = (verb: string, tasks: readonly Task.Task[]): string =>\n `${verb} ${tasks.map((task) => `“${task.title}”`).join(', ')}.`;\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport type * as Atom from 'effect/reactivity/Atom';\nimport React, { type PropsWithChildren, type ReactNode } from 'react';\n\nimport { type ActionGraphProps, ActionToolbar, useMenuActions } from '@dxos/react-ui-menu';\nimport * as Button from '@dxos/react-ui/Button';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport * as Toolbar from '@dxos/react-ui/Toolbar';\nimport type * as Util from '@dxos/react-ui/Util';\nimport { mx } from '@dxos/ui-theme';\n\nimport { meta } from '#meta';\n\nimport { type ChatEvent } from '../Chat/events.ts';\n\n/**\n * 44px at the 16px (pointer: fine) root font-size, the iOS HIG minimum touch target; the density\n * knobs cap a control at 40px, so a finger-driven control has to be sized past them. Applied only\n * where a finger is plausibly the pointer, so the desktop row keeps its density rhythm.\n */\nconst TOUCH_TARGET = 'max-md:size-11 pointer-coarse:size-11';\n\nexport type ChatActionsProps = Util.ThemedClassName<\n PropsWithChildren<{\n /** Content before the actions in the same toolbar (the prompt's options and context chips). */\n leading?: ReactNode;\n /** The prompt's graph node, which is what contributed actions are filed under. */\n attendableId?: string;\n /**\n * Toolbar actions other plugins filed on this chat's node — the microphone among them. Sourced\n * the way `MarkdownArticle` sources its own, so a contributor reaches the prompt without either\n * side importing the other.\n */\n customActions?: Atom.Atom<ActionGraphProps>;\n processing?: boolean;\n debug?: boolean;\n /** Whether the prompt holds text and the processor would accept it; drives the send control's enablement. */\n canSend?: boolean;\n /** Whether the checklist beside the prompt is shown; the toggle renders only when provided. */\n tasksVisible?: boolean;\n /** Submits the current prompt; the send control renders only when provided. */\n onSend?: () => void;\n onEvent?: (event: ChatEvent) => void;\n }>\n>;\n\nexport const ChatActions = ({\n classNames,\n children,\n leading,\n attendableId,\n customActions,\n processing,\n debug,\n canSend,\n tasksVisible,\n onSend,\n onEvent,\n}: ChatActionsProps) => {\n const { t } = Hooks.useTranslation(meta.profile.key);\n // While a turn runs the primary control interrupts it — unless there is text waiting, in which\n // case sending it (which queues it behind the running turn) is what the reader is asking for.\n const showStop = processing && !canSend;\n const controls = (\n <>\n {children}\n {debug && (\n <Button.Root\n variant='ghost'\n icon='ph--wrench--regular'\n iconOnly\n label={t('debug.button')}\n onClick={() => onEvent?.({ type: 'toggle-debug' })}\n />\n )}\n\n {tasksVisible != null && (\n <Button.Root\n variant='ghost'\n classNames={TOUCH_TARGET}\n icon='ph--list-checks--regular'\n iconOnly\n aria-pressed={tasksVisible}\n label={t(tasksVisible ? 'hide-tasks.button' : 'show-tasks.button')}\n data-testid='assistant.toggle-tasks'\n onClick={() => onEvent?.({ type: 'toggle-tasks' })}\n />\n )}\n\n {/* One control, not two: send and stop are the same affordance at two moments of a turn, and\n as separate buttons one of them was always present and dead. Enter is the only other way to\n submit, and a touch keyboard offers no such affordance. */}\n {onSend && (\n // TODO(dmaretskyi): Set processing state correctly on rehydrated agents.\n <Button.Root\n disabled={!showStop && !canSend}\n variant='ghost'\n classNames={mx(TOUCH_TARGET, 'transition duration-300 ease-in-out', canSend && 'text-accent-text rotate-90')}\n icon={showStop ? 'ph--stop-circle--duotone' : 'ph--paper-plane--regular'}\n iconOnly\n label={t(showStop ? 'cancel-processing.button' : 'send.label')}\n onClick={() => (showStop ? onEvent?.({ type: 'cancel' }) : onSend())}\n // One stable handle for the prompt's primary action; its mode is the accessible label,\n // which is also how a reader tells the two apart.\n data-testid='assistant.send'\n />\n )}\n </>\n );\n\n // One toolbar for the whole row, so the contributed actions and the prompt's own controls share its roving focus.\n return customActions ? (\n <ContributedActions actions={customActions} attendableId={attendableId} start={leading} classNames={classNames}>\n {controls}\n </ContributedActions>\n ) : (\n <Toolbar.Root classNames={classNames}>\n {leading}\n {controls}\n </Toolbar.Root>\n );\n};\n\n/**\n * The prompt's toolbar with the contributed actions first, rendered through the menu's own item dispatch rather than a\n * local copy of it — that is what makes a `variant: 'custom'` contribution (the mic's press-and-hold and its options\n * menu) render here exactly as it does in a document toolbar.\n *\n * Its own component so the hook is unconditional; the row renders it only when a caller supplies actions.\n */\nconst ContributedActions = ({\n actions,\n attendableId,\n start,\n classNames,\n children,\n}: Util.ThemedClassName<\n PropsWithChildren<{\n actions: Atom.Atom<ActionGraphProps>;\n attendableId?: string;\n start?: ReactNode;\n }>\n>) => {\n const menuActions = useMenuActions(actions);\n return (\n <ActionToolbar {...menuActions} attendableId={attendableId} alwaysActive start={start} classNames={classNames}>\n {children}\n </ActionToolbar>\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { useEffect, useState } from 'react';\n\nimport type * as Trace from '@dxos/compute/Trace';\nimport { ChatStatus as NaturalChatStatus } from '@dxos/react-ui-chat';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport type * as Util from '@dxos/react-ui/Util';\n\nimport { meta } from '#meta';\n\nconst CHAT_ACTIVITY_NAME = 'Chat.Activity';\n\nconst SECOND = 1_000;\nconst MINUTE = 60 * SECOND;\nconst HOUR = 60 * MINUTE;\n\nconst activityLabelKey = (phase: Trace.RequestPhaseName): string => `activity.${phase}.label`;\n\n/**\n * Phases whose `detail` reads as part of the sentence (\"Calling tool search\") rather than as a\n * separate field, so the label interpolates it and the detail chip is suppressed.\n */\nconst INLINE_DETAIL_PHASES: ReadonlySet<Trace.RequestPhaseName> = new Set<Trace.RequestPhaseName>(['calling-tool']);\n\nexport type ChatActivityProps = Util.ThemedClassName<{\n activity?: Trace.PayloadType<typeof Trace.RequestPhase>;\n /**\n * Epoch milliseconds the agent is scheduled to wake at, when an alarm is pending. Rendered as a\n * counting-down line while the agent is idle or reports `sleeping`; any other live phase\n * supersedes it, since a running turn is the more immediate answer to \"what is it doing\".\n */\n wakeAt?: number;\n}>;\n\n/**\n * What the agent is doing, given a resolved phase or a pending alarm.\n *\n * The line stays up for as long as there is something to report: the setup stages before the first\n * token (a cold MCP server, a summarization pass, a re-issued request), the generation, each tool\n * call, and — once the turn settles with an alarm pending — the wait until the agent wakes itself.\n * Only a fully idle agent renders nothing.\n *\n * The phase and the wake time arrive as props rather than being read from the chat context, so every\n * state can be mounted in a story without a live agent process; `Chat.Activity` is the bound form.\n */\nexport const ChatActivity = ({ classNames, activity, wakeAt }: ChatActivityProps) => {\n const { t } = Hooks.useTranslation(meta.profile.key);\n // `sleeping` is the agent saying the turn is over and only the alarm is left, so the countdown\n // replaces it rather than competing with it.\n const waking = !activity || activity.phase === 'sleeping';\n const remaining = useCountdown(waking ? wakeAt : undefined);\n // A wake time in the past is an alarm that has already fired: its record outlives the firing (and\n // the projection that drops it can lag a beat), so a countdown driven off it alone would sit on\n // \"Waking up\" forever after the agent had moved on.\n const counting = remaining !== undefined && remaining >= SECOND;\n const label = waking\n ? counting\n ? formatWaking(t, remaining)\n : activity && t(activityLabelKey(activity.phase))\n : t(activityLabelKey(activity.phase), { detail: activity.detail ?? '' });\n if (!label) {\n return null;\n }\n\n return (\n // `font-body` overrides the pill root's `font-mono`, which suits the status pill's token counts\n // and elapsed clock but renders a sentence as debug output. One line: a long tool detail truncates\n // rather than wrapping, so the prompt below does not jump as the phase changes.\n <NaturalChatStatus.Root\n defaultRunning={false}\n classNames={['py-1 px-2 gap-2 text-sm font-body max-w-full min-w-0 whitespace-nowrap', classNames]}\n >\n <NaturalChatStatus.Icon classNames='shrink-0' />\n <NaturalChatStatus.Text classNames='min-w-0 truncate'>\n <span data-testid='assistant.chat-activity'>{label}</span>\n </NaturalChatStatus.Text>\n {/* Only a re-issued request has an attempt worth naming; the first one is just the request. */}\n {activity?.attempt != null && activity.attempt > 1 && (\n <>\n <NaturalChatStatus.Separator classNames='shrink-0' />\n <NaturalChatStatus.Text classNames='shrink-0'>\n <span data-testid='assistant.chat-activity.attempt'>\n {t('activity.attempt', { attempt: activity.attempt })}\n </span>\n </NaturalChatStatus.Text>\n </>\n )}\n {activity?.detail && !INLINE_DETAIL_PHASES.has(activity.phase) && (\n <>\n <NaturalChatStatus.Separator classNames='shrink-0' />\n <NaturalChatStatus.Text classNames='min-w-0 truncate'>{activity.detail}</NaturalChatStatus.Text>\n </>\n )}\n </NaturalChatStatus.Root>\n );\n};\n\nChatActivity.displayName = CHAT_ACTIVITY_NAME;\n\n/**\n * Milliseconds until `wakeAt`, re-read every second, or `undefined` when nothing is scheduled.\n *\n * The alarm is a fixed instant rather than a stream of events, so the countdown is the client's to\n * run; ticking on a plain interval keeps it a rendering concern and leaves the agent silent while\n * it sleeps.\n */\nconst useCountdown = (wakeAt?: number): number | undefined => {\n // The value is read during render and the state only forces the next read, so a changed `wakeAt`\n // shows its own countdown on the first render rather than the previous one until the effect runs.\n const [, setTick] = useState(0);\n useEffect(() => {\n if (wakeAt === undefined) {\n return;\n }\n\n const interval = setInterval(() => setTick((tick) => tick + 1), SECOND);\n return () => clearInterval(interval);\n }, [wakeAt]);\n\n return wakeAt === undefined ? undefined : wakeAt - Date.now();\n};\n\n/**\n * The countdown line, at the coarsest unit that still carries information: a wake an hour out does\n * not become more legible counted in seconds.\n */\nconst formatWaking = (t: (key: string, options?: Record<string, unknown>) => string, remaining: number): string => {\n if (remaining < MINUTE) {\n return t('activity.waking.seconds.label', { count: Math.round(remaining / SECOND) });\n }\n if (remaining < HOUR) {\n return t('activity.waking.minutes.label', { count: Math.round(remaining / MINUTE) });\n }\n return t('activity.waking.hours.label', { count: Math.round(remaining / HOUR) });\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport React, { useCallback } from 'react';\n\nimport { Listbox } from '@dxos/react-ui-list';\nimport * as Banner from '@dxos/react-ui/Banner';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport type * as Util from '@dxos/react-ui/Util';\n\nimport { meta } from '#meta';\n\nimport { type AiChatProcessor } from '../../processor/index.ts';\n\nexport type ChatMcpErrorsProps = Util.ThemedClassName<{\n processor: AiChatProcessor;\n}>;\n\n/**\n * Inline banner that lists MCP servers that failed to connect during the most recent request.\n * The chat itself keeps working without these servers — this just lets the user see what was dropped.\n */\nexport const ChatMcpErrors = ({ classNames, processor }: ChatMcpErrorsProps) => {\n const { t } = Hooks.useTranslation(meta.profile.key);\n const errors = useAtomValue(processor.mcpErrors);\n\n const handleDismiss = useCallback(() => {\n processor.dismissMcpErrors();\n }, [processor]);\n\n if (errors.length === 0) {\n return null;\n }\n\n return (\n <Banner.Root valence='warning'>\n <Banner.Title onClose={handleDismiss}>{t('mcp-server-error.label')}</Banner.Title>\n <Banner.Body>\n <Listbox.Root\n items={errors.map((error) => ({\n value: `${error.url}::${error.protocol}`,\n label: `${error.url}::${error.protocol}`,\n }))}\n >\n <Listbox.Content aria-label={t('mcp-server-error.label')} classNames='gap-0.5 text-sm'>\n {errors.map((error) => (\n <Listbox.Item key={`${error.url}::${error.protocol}`} id={`${error.url}::${error.protocol}`}>\n {/* `min-w-0`: the item is a flex child, so without it `truncate` never shrinks below\n the content's intrinsic width. */}\n <span className='truncate min-w-0'>\n <span className='font-mono'>{error.url}</span>\n {' — '}\n <span>{error.unauthorized ? t('mcp-server-error.unauthorized') : error.message}</span>\n </span>\n </Listbox.Item>\n ))}\n </Listbox.Content>\n </Listbox.Root>\n </Banner.Body>\n </Banner.Root>\n );\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { type JSX, useCallback, useMemo, useState } from 'react';\n\nimport { Provider } from '@dxos/ai';\nimport * as Hooks from '@dxos/app-framework/Hooks';\nimport { type AiContext } from '@dxos/assistant';\nimport type * as Chat from '@dxos/assistant/Chat';\nimport * as McpServer from '@dxos/compute/McpServer';\nimport { type Database, Filter, Obj, Ref, type Registry, Type, URI } from '@dxos/echo';\nimport { useObject, useQuery } from '@dxos/echo-react';\nimport { AccessToken } from '@dxos/link';\nimport * as ClientCapabilities from '@dxos/plugin-client/ClientCapabilities';\nimport { type ChatView } from '@dxos/react-ui-assistant';\nimport { Listbox } from '@dxos/react-ui-list';\nimport { SearchList, useSearchListResults } from '@dxos/react-ui-search';\nimport * as Button from '@dxos/react-ui/Button';\nimport * as Field from '@dxos/react-ui/Field';\nimport * as UiHooks from '@dxos/react-ui/Hooks';\nimport * as Input from '@dxos/react-ui/Input';\nimport * as Layout from '@dxos/react-ui/Layout';\nimport * as Popover from '@dxos/react-ui/Popover';\nimport * as Select from '@dxos/react-ui/Select';\nimport * as SystemButton from '@dxos/react-ui/SystemButton';\nimport * as Tabs from '@dxos/react-ui/Tabs';\nimport * as Toolbar from '@dxos/react-ui/Toolbar';\nimport { getStyles, mx } from '@dxos/ui-theme';\n\nimport {\n getSkillId,\n useActiveSkills,\n useContextObjects,\n useFilteredTypes,\n useMcpServerSignIn,\n useMcpServerStatus,\n useSkillHandlers,\n useSkills,\n} from '#hooks';\nimport { meta } from '#meta';\nimport { Assistant, AssistantCapabilities, AssistantPreset } from '#types';\n\nimport { resolveProvider } from '../../processor/index.ts';\n\nconst styles = {\n panel: 'w-[calc(100dvw-.5rem)] sm:w-max max-w-document-width',\n};\n\nexport type ChatOptionsProps = AssistantPreset.ChatPresetProps & {\n db: Database.Database;\n chat?: Chat.Chat;\n context?: AiContext.Binder;\n registry?: Registry.Registry;\n};\n\n/**\n * Manages the runtime context for the chat.\n */\nexport const ChatOptions = ({ db, chat, context, registry, presets, preset, onPresetChange }: ChatOptionsProps) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n\n return (\n <Layout.Flex>\n <Popover.Root positioning={{ placement: 'top' }}>\n <Popover.Trigger asChild>\n <Button.Root\n variant='ghost'\n icon='ph--plus--regular'\n iconOnly\n label={t('context-objects.button')}\n disabled={!context}\n />\n </Popover.Trigger>\n <Popover.Content classNames={styles.panel}>\n {/* No Body: the list scrolls itself above its filter controls, in the popover's column. */}\n {context && <ObjectsPanel db={db} context={context} />}\n </Popover.Content>\n </Popover.Root>\n\n <Popover.Root positioning={{ placement: 'top' }}>\n <Popover.Trigger asChild>\n <Button.Root\n variant='ghost'\n icon='ph--sliders-horizontal--regular'\n iconOnly\n label={t('context-settings.button')}\n data-testid='assistant.options'\n disabled={!context}\n />\n </Popover.Trigger>\n <Popover.Content classNames={styles.panel}>\n {/* No Body: each tab's list and the tab bar share the popover's own padding. */}\n <Tabs.Root orientation='horizontal' defaultValue='view' classNames='grid grid-rows-[1fr_40px] w-full'>\n <Tabs.Content tabIndex={-1} classNames='dx-focus-ring-inset overflow-hidden' value='view'>\n <ViewPanel chat={chat} />\n </Tabs.Content>\n <Tabs.Content tabIndex={-1} classNames='dx-focus-ring-inset overflow-hidden' value='skills'>\n {context && <SkillsPanel registry={registry} db={db} context={context} />}\n </Tabs.Content>\n <Tabs.Content tabIndex={-1} classNames='dx-focus-ring-inset overflow-hidden' value='mcp-servers'>\n <McpServersPanel db={db} />\n </Tabs.Content>\n <Tabs.Content tabIndex={-1} classNames='dx-focus-ring-inset overflow-hidden' value='model'>\n <ModelsPanel presets={presets} preset={preset} onPresetChange={onPresetChange} />\n </Tabs.Content>\n <Tabs.Content tabIndex={-1} classNames='dx-focus-ring-inset overflow-hidden' value='environment'>\n <EnvironmentPanel chat={chat} />\n </Tabs.Content>\n <Tabs.List classNames='p-1 gap-1 border-t border-separator'>\n <Tabs.Trigger value='view' icon='ph--eye--regular' label={t('chat-view.title')} />\n <Tabs.Trigger value='skills' icon='ph--student--regular' label={t('options.skills.title')} />\n <Tabs.Trigger value='mcp-servers' icon='ph--plugs-connected--regular' label={t('options.mcp.title')} />\n <Tabs.Trigger\n value='model'\n icon='ph--cpu--regular'\n label={t('options.chat-model.title')}\n data-testid='assistant.options.model'\n />\n <Tabs.Trigger\n value='environment'\n icon='ph--hard-drives--regular'\n label={t('options.environment.title')}\n />\n </Tabs.List>\n </Tabs.Root>\n </Popover.Content>\n </Popover.Root>\n </Layout.Flex>\n );\n};\n\nconst SkillsPanel = ({ registry, db, context }: Pick<ChatOptionsProps, 'registry' | 'db' | 'context'>) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n\n const skills = useSkills({ registry, db });\n const activeSkills = useActiveSkills({ context });\n const { onUpdateSkill } = useSkillHandlers({ context });\n const { results, handleSearch } = useSearchListResults({\n items: skills,\n extract: (skill) => skill.name,\n });\n\n return (\n <SearchList.Root onSearch={handleSearch}>\n <SearchList.Content classNames='flex flex-col'>\n {/* Flush to the popover edge, like the sibling `Listbox` panels: this is a menu, not a\n centered search surface, so the scroll strip is not reserved on both sides. */}\n <SearchList.Viewport padding={false}>\n {results.map((skill) => {\n const skillId = getSkillId(skill);\n const isActive = activeSkills.has(skillId);\n return (\n <SearchList.Item\n classNames='flex items-center overflow-hidden'\n key={skillId}\n value={skillId}\n label={skill.name}\n checked={isActive}\n onSelect={() => onUpdateSkill?.(skill, !isActive)}\n />\n );\n })}\n </SearchList.Viewport>\n <Toolbar.Root>\n <SearchList.Input placeholder={t('search.placeholder')} classNames='border-t border-separator' autoFocus />\n </Toolbar.Root>\n </SearchList.Content>\n </SearchList.Root>\n );\n};\n\nconst ViewPanel = ({ chat }: Pick<ChatOptionsProps, 'chat'>) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const [view, setView] = useObject(chat, 'viewType');\n const value = (view as ChatView | undefined) ?? 'normal';\n\n return (\n <Listbox.Root\n value={value}\n onValueChange={setView}\n autoFocus\n items={Assistant.ChatViews.map((view) => ({\n value: view,\n label: t(`chat-view.${view}.label`, { defaultValue: view }),\n }))}\n >\n {/* No gutter: the popover's padding is the inset, shared with the tab bar below. */}\n <Listbox.Content gutter='none' aria-label={t('chat-view.title')}>\n {Assistant.ChatViews.map((view) => (\n <Listbox.Item key={view} id={view} classNames='dx-focus-ring rounded-xs'>\n <Listbox.ItemText>{t(`chat-view.${view}.label`, { defaultValue: view })}</Listbox.ItemText>\n <Listbox.ItemIndicator />\n </Listbox.Item>\n ))}\n </Listbox.Content>\n </Listbox.Root>\n );\n};\n\n/**\n * Where this conversation's agent runs. A per-chat property rather than a setting, mirroring a\n * trigger's own `remote` flag: `edge` keeps the conversation running with the client closed.\n * `AgentService` reads the location at spawn, so switching tears the running process down and\n * respawns it on the other host.\n */\nconst EnvironmentPanel = ({ chat }: Pick<ChatOptionsProps, 'chat'>) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const [remote, setRemote] = useObject(chat, 'remote');\n const client = Hooks.useOptionalCapability(ClientCapabilities.Client);\n // Offered only where an edge service is configured, which is the same condition that decides\n // whether `RemoteProcessManager` is the real manager or `layerNoop`: against the noop a spawn has\n // no `list` or `spawn`, so choosing `remote` would persist a flag the next prompt cannot honour.\n const environments = client?.config.values.runtime?.services?.edge?.url\n ? CHAT_ENVIRONMENTS\n : CHAT_ENVIRONMENTS.filter((environment) => environment !== 'remote');\n const value: ChatEnvironment = remote ? 'remote' : 'local';\n const handleChange = useCallback((value: string) => setRemote(value === 'remote'), [setRemote]);\n\n return (\n <Listbox.Root\n value={value}\n onValueChange={handleChange}\n autoFocus\n items={environments.map((environment) => ({\n value: environment,\n label: t(`chat-environment.${environment}.label`),\n }))}\n >\n {/* No gutter: the popover's padding is the inset, shared with the tab bar below. */}\n <Listbox.Content gutter='none' aria-label={t('options.environment.title')}>\n {environments.map((environment) => (\n <Listbox.Item key={environment} id={environment} classNames='dx-focus-ring rounded-xs'>\n <Listbox.ItemText>{t(`chat-environment.${environment}.label`)}</Listbox.ItemText>\n <Listbox.ItemIndicator />\n </Listbox.Item>\n ))}\n </Listbox.Content>\n </Listbox.Root>\n );\n};\n\nconst CHAT_ENVIRONMENTS = ['local', 'remote'] as const;\n\ntype ChatEnvironment = (typeof CHAT_ENVIRONMENTS)[number];\n\nconst ModelsPanel = ({\n presets,\n preset,\n onPresetChange,\n}: Pick<ChatOptionsProps, 'presets' | 'preset' | 'onPresetChange'>) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n\n return (\n <Layout.Flex column classNames='dx-expand'>\n <Listbox.Root\n value={preset}\n onValueChange={onPresetChange}\n autoFocus\n items={(presets ?? []).map(({ id, label }) => ({ value: id, label: label }))}\n >\n <Listbox.Content gutter='none' aria-label={t('options.chat-model.title')} data-testid='assistant.models'>\n {presets?.map(({ id, label }) => (\n <Listbox.Item key={id} id={id} classNames='dx-focus-ring rounded-xs' data-testid={`assistant.models.${id}`}>\n <Listbox.ItemText>{label}</Listbox.ItemText>\n <Listbox.ItemIndicator />\n </Listbox.Item>\n ))}\n </Listbox.Content>\n </Listbox.Root>\n <Toolbar.Root>\n <OnlineSwitch />\n </Toolbar.Root>\n </Layout.Flex>\n );\n};\n\n/**\n * Online/offline as the control it looks like. It used to sit on the prompt row as a disabled\n * switch, which read as broken: the provider is one setting, so it belongs beside the model list\n * that setting chooses from.\n *\n * Off selects whichever local provider this build has — the bundled sidecar on desktop, an external\n * Ollama elsewhere — which is the same reconciliation `usePresets` does when it reads the setting.\n */\nconst OnlineSwitch = () => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const [settings, setSettings] = Hooks.useAtomCapabilityState(AssistantCapabilities.Settings);\n const hasBuiltIn = Hooks.useOptionalCapability(AssistantCapabilities.OllamaManager) !== undefined;\n const online = resolveProvider(settings.modelProvider, hasBuiltIn) === Provider.edge.id;\n\n const handleChange = useCallback(\n (checked: boolean) => {\n const provider = checked ? Provider.edge.id : hasBuiltIn ? Provider.builtIn.id : Provider.ollama.id;\n setSettings((current) => ({ ...current, modelProvider: provider }));\n },\n [setSettings, hasBuiltIn],\n );\n\n return (\n <Input.Switch\n checked={online}\n onCheckedChange={({ checked }) => handleChange(checked)}\n data-testid='assistant.online'\n label={t('online-switch.label')}\n />\n );\n};\n\ntype McpServerDraft = {\n name: string;\n url: string;\n protocol: McpServer.Spec['protocol'];\n apiKey?: string;\n};\n\ntype McpServersPanelProps = {\n db: Database.Database;\n};\n\nconst McpServersPanel = ({ db }: McpServersPanelProps) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const servers = useQuery(db, Filter.type(McpServer.McpServer));\n const [adding, setAdding] = useState(false);\n\n const handleAdd = useCallback(\n ({ name, url, protocol, apiKey }: McpServerDraft) => {\n // The key goes in an `AccessToken` rather than on the server, so it resolves through the\n // credentials service like every other secret in the space.\n const accessToken = apiKey\n ? db.add(AccessToken.make({ source: new URL(url).hostname, account: name, token: apiKey }))\n : undefined;\n db.add(\n Obj.make(McpServer.McpServer, {\n name,\n url,\n protocol,\n enabled: true,\n ...(accessToken && { accessToken: Ref.make(accessToken) }),\n }),\n );\n setAdding(false);\n },\n [db],\n );\n\n const handleRemove = useCallback(\n (server: McpServer.McpServer) => {\n const accessToken = server.accessToken?.peek();\n db.remove(server);\n if (accessToken) {\n db.remove(accessToken);\n }\n },\n [db],\n );\n\n return (\n <Layout.Flex column data-testid='assistant.mcp-servers'>\n <Listbox.Root items={servers.map((server) => ({ value: server.id, label: server.name ?? server.id }))}>\n <Listbox.Content aria-label={t('options.mcp.title')} classNames='gap-1'>\n {servers.map((server) => (\n <McpServerRow key={server.id} server={server} onRemove={handleRemove} />\n ))}\n </Listbox.Content>\n </Listbox.Root>\n {adding ? (\n <McpForm onSubmit={handleAdd} onCancel={() => setAdding(false)} />\n ) : (\n <Layout.Flex classNames='p-1'>\n <Button.Root\n variant='ghost'\n icon='ph--plus--regular'\n label={t('mcp-server-add.label')}\n onClick={() => setAdding(true)}\n data-testid='assistant.mcp-server.add'\n />\n </Layout.Flex>\n )}\n </Layout.Flex>\n );\n};\n\ntype McpServerRowProps = {\n server: McpServer.McpServer;\n onRemove: (server: McpServer.McpServer) => void;\n};\n\n/**\n * `useQuery` returns live objects but only re-renders on result-identity changes,\n * so we must subscribe to the per-server `enabled`/`oauth`/`name`/`url` fields via `useObject`\n * to keep the row in sync with mutations made through the returned setters (or elsewhere).\n */\nconst McpServerRow = ({ server, onRemove }: McpServerRowProps) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const [enabled, setEnabled] = useObject(server, 'enabled');\n // Subscribed so the status re-checks once a sign-in stores tokens.\n useObject(server, 'oauth');\n const [name] = useObject(server, 'name');\n const [url] = useObject(server, 'url');\n const [revision, setRevision] = useState(0);\n const status = useMcpServerStatus(server, { enabled: enabled !== false, revision });\n const { signIn, pending, error } = useMcpServerSignIn(server);\n const handleSignIn = useCallback(() => {\n void signIn().then(() => setRevision((revision) => revision + 1));\n }, [signIn]);\n\n const statusLabel =\n status.state === 'connected'\n ? t('mcp-server-status.connected', { count: status.tools.length })\n : status.state === 'error'\n ? status.message\n : t(`mcp-server-status.${status.state}`);\n\n return (\n <Listbox.Item id={server.id} classNames='flex-col items-stretch px-form-chrome' data-testid='assistant.mcp-server'>\n <Layout.Flex align='center' gap='sm'>\n <Field.Root>\n <Field.Label srOnly>{name}</Field.Label>\n <Input.Switch checked={enabled !== false} onCheckedChange={({ checked }) => setEnabled(!!checked)} />\n </Field.Root>\n <Layout.Flex column grow classNames='min-w-0'>\n <span className='truncate text-sm'>{name}</span>\n <span className='truncate text-xs text-fg-muted'>{url}</span>\n </Layout.Flex>\n {status.state === 'unauthorized' && (\n <Button.Root\n variant='primary'\n icon='ph--sign-in--regular'\n label={t('mcp-server-sign-in.label')}\n disabled={pending}\n onClick={handleSignIn}\n data-testid='assistant.mcp-server.sign-in'\n />\n )}\n {(status.state === 'error' || status.state === 'unauthorized') && (\n <Button.Root\n variant='ghost'\n icon='ph--arrow-clockwise--regular'\n iconOnly\n label={t('mcp-server-retry.label')}\n onClick={() => setRevision((revision) => revision + 1)}\n />\n )}\n <Button.Root\n variant='ghost'\n icon='ph--x--regular'\n iconOnly\n label={t('mcp-server-remove.label')}\n onClick={() => onRemove(server)}\n />\n </Layout.Flex>\n <span\n className={mx(\n 'text-xs truncate',\n status.state === 'connected' && 'text-success-text',\n (status.state === 'error' || status.state === 'unauthorized' || error) && 'text-error-text',\n )}\n title={error ?? statusLabel}\n data-testid='assistant.mcp-server.status'\n data-state={status.state}\n >\n {error ?? statusLabel}\n </span>\n </Listbox.Item>\n );\n};\n\ntype McpFormProps = {\n onSubmit: (draft: McpServerDraft) => void;\n onCancel: () => void;\n};\n\nconst McpForm = ({ onSubmit, onCancel }: McpFormProps) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const [name, setName] = useState('');\n const [url, setUrl] = useState('');\n // Streamable HTTP is the current transport; the client falls back to SSE when a server answers 405.\n const [protocol, setProtocol] = useState<McpServer.Spec['protocol']>('http');\n const [apiKey, setApiKey] = useState('');\n\n const validUrl = URL.canParse(url.trim());\n const canSubmit = name.trim().length > 0 && validUrl;\n const handleSubmit = useCallback(() => {\n if (canSubmit) {\n onSubmit({ name: name.trim(), url: url.trim(), protocol, apiKey: apiKey.trim() || undefined });\n }\n }, [canSubmit, name, url, protocol, apiKey, onSubmit]);\n\n return (\n <form\n className='space-y-2 px-form-chrome'\n onSubmit={(event) => {\n event.preventDefault();\n handleSubmit();\n }}\n >\n <Field.Root>\n <Field.Label srOnly>{t('mcp-server-name.label')}</Field.Label>\n <Input.Root\n placeholder={t('mcp-server-name.placeholder')}\n value={name}\n onChange={(event) => setName(event.target.value)}\n autoFocus\n data-testid='assistant.mcp-server.name'\n />\n </Field.Root>\n <Field.Root>\n <Field.Label srOnly>{t('mcp-server-url.label')}</Field.Label>\n <Input.Root\n type='url'\n placeholder={t('mcp-server-url.placeholder')}\n value={url}\n onChange={(event) => setUrl(event.target.value)}\n data-testid='assistant.mcp-server.url'\n />\n </Field.Root>\n <Select.Root\n value={[protocol]}\n onValueChange={({ value: [value] }) => setProtocol(value === 'sse' ? 'sse' : 'http')}\n items={[\n { value: 'http', label: 'HTTP' },\n { value: 'sse', label: 'SSE' },\n ]}\n >\n <Select.Trigger placeholder={t('mcp-server-protocol.label')} />\n <Select.Content>\n <Select.Item item={{ value: 'http', label: 'HTTP' }} />\n <Select.Item item={{ value: 'sse', label: 'SSE' }} />\n </Select.Content>\n </Select.Root>\n <Field.Root>\n <Field.Label srOnly>{t('mcp-server-api-key.label')}</Field.Label>\n <Input.Password\n ignorePasswordManagers\n placeholder={t('mcp-server-api-key.placeholder')}\n value={apiKey}\n onValueChange={setApiKey}\n data-testid='assistant.mcp-server.api-key'\n />\n </Field.Root>\n <Layout.Flex justify='end'>\n <SystemButton.Save\n type='submit'\n variant='ghost'\n disabled={!canSubmit}\n data-testid='assistant.mcp-server.save'\n />\n <SystemButton.Cancel type='button' variant='ghost' onClick={onCancel} />\n </Layout.Flex>\n </form>\n );\n};\n\nconst ANY = '__any__' as const;\n\n/** @private */\nexport const ObjectsPanel = ({ db, context }: Pick<ChatOptionsProps, 'db' | 'context'>): JSX.Element => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n\n // Item types sorted by label.\n const types = useFilteredTypes(db);\n const typeOptions = useMemo(() => {\n const options = types.map((type) => {\n const typename = Type.getTypename(type);\n return {\n uri: Type.getURI(type),\n label: t('typename.label', { ns: typename, defaultValue: typename }),\n };\n });\n\n options.sort((a, b) => a.label.localeCompare(b.label));\n return options;\n }, [types, t]);\n\n const typeItems = useMemo(\n () => [\n { value: ANY, label: t('any-type-filter.label') },\n ...typeOptions.map(({ uri, label }) => ({ value: uri, label })),\n ],\n [typeOptions, t],\n );\n\n // Current type URI and filter.\n const [selectedUri, setSelectedUri] = useState<URI.URI | typeof ANY>(ANY);\n const anyFilter = useMemo(() => Filter.or(...typeOptions.map(({ uri }) => Filter.type(uri))), [typeOptions]);\n\n // Context objects.\n const objects = useQuery(db, selectedUri === ANY ? anyFilter : Filter.type(selectedUri));\n const { objects: contextObjects, onUpdateObject } = useContextObjects({ db, context });\n const { results, handleSearch } = useSearchListResults({\n items: objects,\n extract: (object) => Obj.getLabel(object) ?? Obj.getTypename(object) ?? object.id,\n });\n\n return (\n <Layout.Flex column classNames='min-h-0 divide-y divide-separator'>\n {/* Shrinks to the popover's height, so the list scrolls rather than pushing the filter out of it. */}\n <SearchList.Root onSearch={handleSearch}>\n {/* No chrome padding: the rows align with the toolbar below, which is a sibling of\n `Content` and so sits flush against the panel edge. */}\n <SearchList.Content classNames='flex flex-col'>\n <SearchList.Viewport padding={false} classNames='min-h-0 flex-auto'>\n {results.length ? (\n results.map((object) => {\n const isActive = contextObjects.findIndex((obj) => obj.id === object.id) !== -1;\n const { icon, hue } = Obj.getIcon(object) ?? { icon: 'ph--cube--regular', hue: undefined };\n const styles = hue ? getStyles(hue) : undefined;\n return (\n <SearchList.Item\n classNames='flex items-center overflow-hidden'\n key={object.id}\n value={object.id}\n icon={icon}\n iconClassNames={styles?.text}\n label={Obj.getLabel(object) ?? Obj.getTypename(object) ?? object.id}\n checked={isActive}\n onSelect={() => onUpdateObject?.(Obj.getURI(object), !isActive)}\n />\n );\n })\n ) : (\n <SearchList.Item value='__empty__' label={t('no-results.message')} />\n )}\n </SearchList.Viewport>\n </SearchList.Content>\n\n <Toolbar.Root>\n <SearchList.Input placeholder={t('search.placeholder')} autoFocus />\n <Select.Root\n items={typeItems}\n value={selectedUri === ANY ? [] : [selectedUri]}\n onValueChange={({ value: [value] }) =>\n setSelectedUri(typeOptions.find(({ uri }) => uri === value)?.uri ?? ANY)\n }\n >\n <Select.Trigger fixed placeholder={t('type-filter.placeholder')} />\n <Select.Content>\n {typeItems.map((item) => (\n <Select.Item key={item.value} item={item} />\n ))}\n </Select.Content>\n </Select.Root>\n </Toolbar.Root>\n </SearchList.Root>\n </Layout.Flex>\n );\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport React from 'react';\n\nimport { type AiContext } from '@dxos/assistant';\nimport { type Database, Obj } from '@dxos/echo';\nimport * as Button from '@dxos/react-ui/Button';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport * as Icon from '@dxos/react-ui/Icon';\nimport * as Theme from '@dxos/react-ui/Theme';\nimport type * as Util from '@dxos/react-ui/Util';\nimport { getStyles, mx } from '@dxos/ui-theme';\n\nimport { useContextObjects } from '#hooks';\nimport { meta } from '#meta';\n\nexport type ChatReferencesProps = Util.ThemedClassName<{\n context: AiContext.Binder;\n db: Database.Database;\n}>;\n\nexport const ChatReferences = ({ classNames, context, db }: ChatReferencesProps) => {\n const { t } = Hooks.useTranslation(meta.profile.key);\n const { objects, onUpdateObject } = useContextObjects({ db, context });\n\n return (\n <ul className={mx('flex gap-1', classNames)}>\n {objects.map((obj) => {\n const uri = Obj.getURI(obj);\n const typename = Obj.getTypename(obj);\n const label: Theme.Label =\n Obj.getLabel(obj) ?? (typename ? ['object-name.placeholder', { ns: typename }] : obj.id);\n const { icon, hue } = Obj.getIcon(obj) ?? { icon: DEFAULT_OBJECT_ICON, hue: undefined };\n const styles = hue ? getStyles(hue) : undefined;\n return (\n <li key={uri.toString()} className='dx-tag dx-tag-inline py-0 flex items-center gap-1' data-hue='neutral'>\n <Icon.Icon icon={icon} size='md' />\n {Theme.toLocalizedString(label, t)}\n <Button.Root\n icon='ph--x--bold'\n iconOnly\n variant='ghost'\n label={t('remove-object.label')}\n classNames='p-0 hover:bg-transparent'\n iconSize='xs'\n onClick={() => onUpdateObject?.(uri, false)}\n />\n </li>\n );\n })}\n </ul>\n );\n};\n\n// TODO(dmaretskyi): Extract those somewhere else.\nconst DEFAULT_OBJECT_ICON = 'ph--cube--regular';\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type RefObject, useCallback, useEffect, useMemo, useRef } from 'react';\n\nimport * as Hooks from '@dxos/app-framework/Hooks';\nimport { EdgeServiceName } from '@dxos/config';\nimport { log } from '@dxos/log';\nimport * as TranscriptionCapabilities from '@dxos/plugin-transcription/TranscriptionCapabilities';\nimport { useEdgeServiceEndpoint } from '@dxos/react-client';\nimport { type ChatEditorController } from '@dxos/react-ui-chat';\nimport { isNativeAudioInput, useAudioTrack, useTranscriber } from '@dxos/react-ui-transcription';\nimport * as UiHooks from '@dxos/react-ui/Hooks';\nimport { type ContentBlock } from '@dxos/types';\nimport { PendingTextStreamer, cancelPendingText, editorPendingTextSink, pendingTextState } from '@dxos/ui-editor';\n\nimport { meta } from '#meta';\n\n// Recorder chunk interval; the transcriber's chunk threshold is derived from the buffering setting.\nconst RECORDER_INTERVAL_MS = 200;\n\n/**\n * Drives word-by-word streaming transcription into the chat editor via PendingTextStreamer.\n * Reads the active RecordingSession and Settings capabilities; activates when the session id\n * matches the given docId and the session is recording.\n */\nexport const useChatVoiceInput = (docId: string, editorRef: RefObject<ChatEditorController | null>): void => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n // Voice input is optional: tolerate the transcription plugin being absent (no session ⇒ inactive).\n const [session, setSession] = Hooks.useOptionalAtomCapabilityState(TranscriptionCapabilities.RecordingSession);\n const [settings] = Hooks.useOptionalAtomCapabilityState(TranscriptionCapabilities.Settings);\n const endpoint = useEdgeServiceEndpoint(EdgeServiceName.Transcription);\n\n const active = !!session?.recording && session.id === docId;\n\n const streamerRef = useRef<PendingTextStreamer | null>(null);\n // Where the pending block will be opened, captured when recording begins: by the time the first\n // transcription lands the selection may have moved.\n const anchorRef = useRef<number | undefined>(undefined);\n const startedRef = useRef(false);\n\n // Create/destroy the streamer when active transitions.\n useEffect(() => {\n if (!active) {\n return;\n }\n const view = editorRef.current?.view;\n if (!view) {\n return;\n }\n\n const streamer = new PendingTextStreamer(editorPendingTextSink(view), {\n // Batch by default: a transcription arrives as a finished phrase, and revealing it word by word\n // lags the speaker by the length of what they just said.\n mode: settings?.streamMode ?? 'batch',\n wordIntervalMs: settings?.wordIntervalMs ?? 80,\n });\n // Deliberately not started here. `start` opens the pending-text block, which paints the\n // \"Recording…\" placeholder and its confirm/discard affordances the moment the mic is tapped —\n // occupying the prompt before there is anything to confirm. The block is opened lazily by the\n // first transcription instead (see `handleSegments`), so tapping the mic changes nothing visible\n // and text simply appears when it arrives.\n anchorRef.current = view.state.selection.main.head;\n startedRef.current = false;\n streamerRef.current = streamer;\n\n return () => {\n streamer.dispose();\n streamerRef.current = null;\n startedRef.current = false;\n // Drop the placeholder if nothing was transcribed; otherwise leave it for review.\n const currentView = editorRef.current?.view;\n if (currentView) {\n const pending = currentView.state.field(pendingTextState, false);\n if (pending && pending.final.length === 0) {\n currentView.dispatch({ effects: cancelPendingText.of() });\n }\n }\n };\n }, [active, settings?.streamMode, settings?.wordIntervalMs]);\n\n const handleSegments = useCallback(async (segments: ContentBlock.Transcript[]) => {\n const text = segments\n .map((segment) => segment.text)\n .join(' ')\n .trim();\n if (text.length > 0) {\n if (!startedRef.current) {\n startedRef.current = true;\n // No placeholder: the arriving text is the feedback.\n streamerRef.current?.start({ anchor: anchorRef.current });\n }\n streamerRef.current?.push(text);\n }\n }, []);\n\n // Derive the transcriber's chunk threshold from the configured initial buffering time.\n const transcriberConfig = useMemo(\n () => ({\n transcribeAfterChunksAmount: Math.max(\n 1,\n Math.round((settings?.transcribeAfterMs ?? 4000) / RECORDER_INTERVAL_MS),\n ),\n endpoint,\n }),\n [settings?.transcribeAfterMs, endpoint],\n );\n\n // Stable identity: a fresh object would change useTranscriber's memo deps every render.\n const recorderConfig = useMemo(() => ({ interval: RECORDER_INTERVAL_MS }), []);\n\n const audioConstraints = useMemo<MediaTrackConstraints | undefined>(\n () =>\n // A native selection is routed through the audio session, not through constraints: WebKit\n // rejects an id it did not issue, and the rejection stops capture entirely.\n settings?.audioDeviceId && !isNativeAudioInput(settings.audioDeviceId)\n ? { deviceId: { exact: settings.audioDeviceId } }\n : undefined,\n [settings?.audioDeviceId],\n );\n\n // Gate the mic on the endpoint: `useAudioTrack` calls `getUserMedia` as soon as its flag is\n // true, so without this the permission prompt and recording indicator appear before `open()`\n // rejects for a transcription service that was never configured.\n const track = useAudioTrack(active && !!endpoint, audioConstraints);\n\n const transcriber = useTranscriber({\n audioStreamTrack: track,\n transcriberConfig,\n recorderConfig,\n onSegments: handleSegments,\n });\n\n // `useTranscriber` only constructs (and eventually closes) the transcriber — opening it is the\n // consumer's job, and this hook never did, so `Transcriber._open` never ran, its recorder never\n // started, and no audio was captured. The placeholder appeared and nothing ever replaced it.\n useEffect(() => {\n if (!transcriber) {\n return;\n }\n let cancelled = false;\n void transcriber.open().then(\n () => {\n if (!cancelled && active) {\n transcriber.startChunksRecording();\n }\n },\n (err) => {\n // Clear the session on failure (e.g. the microphone was refused) so the prompt does not sit\n // showing \"recording\" against a transcriber that never opened.\n if (!cancelled) {\n log.catch(err);\n setSession?.(() => null);\n }\n },\n );\n\n return () => {\n cancelled = true;\n };\n }, [transcriber, active, setSession]);\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { EditorView } from '@codemirror/view';\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport * as Option from 'effect/Option';\nimport type * as Atom from 'effect/reactivity/Atom';\nimport React, { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';\n\nimport type * as Chat from '@dxos/assistant/Chat';\nimport { type Event } from '@dxos/async';\nimport * as Project from '@dxos/compute/Project';\nimport { type Database, Obj } from '@dxos/echo';\nimport { useObject } from '@dxos/echo-react';\nimport {\n ChatEditor,\n type ChatEditorController,\n type ChatEditorProps,\n ChatStatusIndicator,\n commands,\n} from '@dxos/react-ui-chat';\nimport type { ActionGraphProps } from '@dxos/react-ui-menu';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport type * as Util from '@dxos/react-ui/Util';\nimport { pendingText } from '@dxos/ui-editor';\nimport { mx } from '@dxos/ui-theme';\nimport { type Merge } from '@dxos/util';\n\nimport { useChatKeymapExtensions } from '#hooks';\nimport { meta } from '#meta';\nimport { AssistantPreset } from '#types';\n\nimport { TaskSlashCommands } from '../../commands/index.ts';\nimport { type AiChatProcessor, getProcessorState } from '../../processor/index.ts';\nimport { type ChatEvent } from '../Chat/index.ts';\nimport { ChatActions, type ChatActionsProps } from './ChatActions.tsx';\nimport { ChatMcpErrors } from './ChatMcpErrors.tsx';\nimport { ChatOptions } from './ChatOptions.tsx';\nimport { ChatReferences } from './ChatReferences.tsx';\nimport { useChatVoiceInput } from './useChatVoiceInput.ts';\n\n/** Prompts that may wait behind a running turn, by default. */\nexport const DEFAULT_MAX_QUEUE = 3;\n\nexport type ChatPromptProps = Merge<\n Util.ThemedClassName<{\n outline?: boolean;\n settings?: boolean;\n expandable?: boolean;\n db?: Database.Database;\n chat?: Chat.Chat;\n /** Undefined while the processor is still opening: the prompt takes text but holds it until then. */\n processor?: AiChatProcessor;\n event: Event<ChatEvent>;\n /** Whether the checklist beside the prompt is shown; the toggle renders only when provided. */\n tasksVisible?: boolean;\n /** The prompt's graph node, which is what contributed actions are filed under. */\n attendableId?: string;\n /** Toolbar actions other plugins filed on this chat's node (see `ChatActions`). */\n customActions?: Atom.Atom<ActionGraphProps>;\n /**\n * The graph node those actions were filed on. Keys the dictation session, because the mic that\n * opens it is one of them and carries the same id — anything else here is a session this prompt\n * would never hear.\n */\n nodeId?: string;\n placeholder?: ChatEditorProps['placeholder'];\n autoFocus?: boolean;\n /** How many prompts are waiting behind the running turn. */\n queueSize?: number;\n /** The most prompts that may wait behind a running turn; past it the prompt takes no more until one is taken up. */\n maxQueue?: number;\n /** Object the chat is attached to; its project instructions (if any) supply sentinel-command completion. */\n companionTo?: Obj.Unknown;\n }>,\n AssistantPreset.ChatPresetProps\n>;\n\nexport const ChatPrompt = ({\n classNames,\n outline,\n db,\n chat,\n processor,\n event,\n tasksVisible,\n attendableId,\n customActions,\n nodeId,\n placeholder,\n autoFocus = true,\n queueSize = 0,\n maxQueue = DEFAULT_MAX_QUEUE,\n settings = true,\n presets,\n preset,\n companionTo,\n onPresetChange,\n}: ChatPromptProps) => {\n const { t } = Hooks.useTranslation(meta.profile.key);\n const processorState = getProcessorState(processor);\n const error = useAtomValue(processorState.error).pipe(Option.getOrUndefined);\n const streaming = useAtomValue(processorState.streaming);\n const active = useAtomValue(processorState.active);\n\n const editorRef = useRef<ChatEditorController>(null);\n useEffect(() => {\n return event.on((ev) => {\n if (ev.type === 'update-prompt' && !editorRef.current?.getText()?.length) {\n editorRef.current?.setText(ev.text);\n editorRef.current?.focus();\n }\n });\n }, [event]);\n\n const fallbackDocId = useId();\n // The node the mic action was filed on, which is what it keys the recording session by. A chat\n // rendered as a companion is a companion node, not the chat object's own, so the object id is only\n // the fallback for a prompt rendered outside a plank.\n const docId = nodeId ?? (chat ? Obj.getURI(chat) : fallbackDocId);\n useChatVoiceInput(docId, editorRef);\n\n const keymapExtensions = useChatKeymapExtensions({ event });\n\n // Command completion: `$` sentinels come from the bound project's instructions; `/` commands\n // are the deterministic operation shortcuts (see assistant-toolkit `SlashCommands`).\n const [companion] = useObject(companionTo);\n const [instructions] = useObject(Obj.instanceOf(Project.Project, companion) ? companion.instructions : undefined);\n const commandsRef = Hooks.useDynamicRef(instructions?.commands ?? []);\n const commandsExtension = useMemo(\n () =>\n commands({\n getCommands: () => [\n ...commandsRef.current.map(({ sentinel, description }) => ({ sentinel, description })),\n ...TaskSlashCommands.map(({ command, description }) => ({ sentinel: command, description })),\n ],\n }),\n [commandsRef],\n );\n\n // The editor owns the prompt text; only its emptiness is mirrored into React so the send control\n // can disable itself without re-rendering the prompt on every keystroke's content. Dictation is\n // deliberately not counted: pending text lives in a StateField and reaches the document only when\n // the user confirms it, which is the same point at which Enter would stop committing and start\n // submitting.\n const [hasText, setHasText] = useState(false);\n const emptinessExtension = useMemo(\n () =>\n EditorView.updateListener.of((update) => {\n if (update.docChanged) {\n setHasText(update.state.doc.toString().trim().length > 0);\n }\n }),\n [],\n );\n\n // A full queue stops taking prompts: what is typed stays in the editor until the agent takes one up.\n const queueFull = active && queueSize >= maxQueue;\n const canSend = hasText && processor != null && !queueFull;\n\n const extensions = useMemo(\n () => [keymapExtensions, pendingText(), commandsExtension, emptinessExtension],\n [keymapExtensions, commandsExtension, emptinessExtension],\n );\n\n // Submits while a turn is running too: the agent's input queue is feed state, so the prompt is\n // queued behind the running turn rather than dropped (`Chat.Root` sends it through the processor's\n // outbox, which queues it while the agent is busy).\n const handleSubmit = useCallback<NonNullable<ChatEditorProps['onSubmit']>>(\n (text) => {\n if (!processor || queueFull) {\n return false;\n }\n event.emit({ type: 'submit', text });\n return true;\n },\n [event, processor, queueFull],\n );\n\n // Routed through `handleSubmit` so the button and the Enter keybinding share one submit path;\n // the reset and refocus mirror what the `submit()` extension does for Enter.\n const handleSend = useCallback(() => {\n const text = editorRef.current?.getText().trim();\n if (!text?.length) {\n return;\n }\n if (handleSubmit(text)) {\n editorRef.current?.setText('', true);\n }\n }, [handleSubmit]);\n\n const handleEvent = useCallback<NonNullable<ChatActionsProps['onEvent']>>(\n (ev) => {\n event.emit(ev);\n },\n [event],\n );\n\n return (\n <div\n data-testid='assistant.prompt'\n role='group'\n className={mx(\n 'flex flex-col w-full dx-density-md',\n outline &&\n 'dx-group-surface rounded-sm border border-separator-subtle transition transition-border [&:has(.cm-content:focus)]:border-separator',\n classNames,\n )}\n >\n {processor && <ChatMcpErrors processor={processor} />}\n\n <div className='flex p-2 gap-2'>\n <ChatStatusIndicator classNames='p-1' preset={preset} error={error} processing={streaming} />\n <ChatEditor\n ref={editorRef}\n autoFocus={autoFocus}\n markdown\n lineWrapping\n classNames='col-span-2 pt-0.5'\n placeholder={placeholder ?? t('prompt.placeholder')}\n extensions={extensions}\n onSubmit={handleSubmit}\n />\n </div>\n\n {db &&\n settings && (\n // One toolbar for the row: the options and context chips lead, the chips' track takes the slack, the actions end it.\n <ChatActions\n classNames='p-1.5'\n attendableId={attendableId}\n customActions={customActions}\n // `active`, not `streaming`: a turn parked in a tool call streams nothing,\n // and the reader still needs a way to stop it.\n processing={active}\n canSend={canSend}\n tasksVisible={tasksVisible}\n onSend={handleSend}\n onEvent={handleEvent}\n leading={\n <>\n <ChatOptions\n db={db}\n chat={chat}\n registry={processor?.registry}\n context={processor?.context}\n preset={preset}\n presets={presets}\n onPresetChange={onPresetChange}\n />\n <div className='flex h-6 grow overflow-x-auto scrollbar-none'>\n {processor && <ChatReferences db={db} context={processor.context} />}\n </div>\n </>\n }\n />\n )}\n </div>\n );\n};\n\nChatPrompt.displayName = 'Chat.Prompt';\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { useEffect, useMemo, useState } from 'react';\n\nimport { Alarm } from '@dxos/assistant';\nimport { ChatStatus as NaturalChatStatus, formatElapsed } from '@dxos/react-ui-chat';\nimport { Matrix } from '@dxos/react-ui-experimental';\nimport * as Icon from '@dxos/react-ui/Icon';\nimport type * as Util from '@dxos/react-ui/Util';\nimport { type ContentBlock } from '@dxos/types';\nimport { Unit } from '@dxos/util';\n\nimport { type ChatRequestTiming, useChatThreadContext } from '../Chat/context.ts';\n\nconst CHAT_STREAM_STATUS_NAME = 'Chat.StreamStatus';\nconst TICK_MS = 1_000;\n\nexport type ChatStreamStatusProps = Util.ThemedClassName<{\n icon?: boolean;\n}>;\n\nexport type ChatStatusViewProps = ChatStreamStatusProps & {\n /** Start/end of the most recent request; `endedAt: null` while it runs. */\n requestTiming?: ChatRequestTiming | null;\n /** Output tokens of the last completed turn. */\n lastOutputTokens?: number;\n /** Cumulative tokens across the session. */\n sessionTotalTokens?: number;\n /**\n * When the agent will next wake itself, if an alarm is pending. Plain values rather than the feed\n * record: this component only renders, and a live ECHO object cannot survive being passed as a\n * Storybook arg (its proxy rejects the mutation Storybook's arg handling performs).\n */\n alarm?: { wakeAt: number; message?: string };\n /** Alarms that have woken the agent since the last user prompt, shown against `Alarm.MAX_SELF_WAKES`. */\n selfWakes?: number;\n};\n\n/**\n * Live status pill rendered at the bottom of the chat thread.\n *\n * The block-widget host re-mounts this component each time wire's drip queue toggles\n * (`wireDrainingEffect`) — so all visible state is derived from chat-context values that\n * survive the unmount: the latest `stats` block on the chat context's `messages` for token counts,\n * and `requestTiming` (start/end wall-clock timestamps) for the elapsed value.\n *\n * Shows:\n * - elapsed seconds since the most recent request started (frozen at end-of-request)\n * - last completed turn's output token count (from the most recent `stats` content block)\n * - cumulative session total tokens across all `stats` content blocks\n */\nexport const ChatStatus = ({ classNames, icon }: ChatStreamStatusProps) => {\n // Read `messages` from the chat context (combines `useQuery(queue)` + the processor's\n // pending atom) rather than `processor.messages` directly — the latter only contains\n // blocks streamed via the ephemeral `PartialBlock` channel, while finalized blocks\n // (including the per-turn `stats` block we read for token counts) are submitted to the\n // feed via `_submitMessage` and only show up through `useQuery`.\n const { messages, requestTiming, alarms, selfWakes } = useChatThreadContext(CHAT_STREAM_STATUS_NAME);\n\n const { lastOutputTokens, sessionTotalTokens } = useMemo(() => {\n let last: number | undefined;\n let total = 0;\n for (const message of messages) {\n for (const block of message.blocks) {\n if (isStats(block) && block.usage) {\n last = block.usage.outputTokens;\n total += block.usage.totalTokens ?? 0;\n }\n }\n }\n\n return { lastOutputTokens: last, sessionTotalTokens: total };\n }, [messages]);\n\n const nextAlarm = alarms.at(0);\n\n return (\n <ChatStatusView\n classNames={classNames}\n icon={icon}\n requestTiming={requestTiming}\n lastOutputTokens={lastOutputTokens}\n sessionTotalTokens={sessionTotalTokens}\n // The earliest pending alarm is the one that wakes the agent next, so it is the one worth a slot.\n alarm={nextAlarm && { wakeAt: nextAlarm.wakeAt, message: nextAlarm.message }}\n selfWakes={selfWakes}\n />\n );\n};\n\n/**\n * The pill itself, given resolved values. Split from {@link ChatStatus} so each slot — elapsed,\n * tokens, the next alarm — can be mounted and asserted in a story without a live processor.\n */\nexport const ChatStatusView = ({\n classNames,\n icon,\n requestTiming,\n lastOutputTokens,\n sessionTotalTokens = 0,\n alarm,\n selfWakes = 0,\n}: ChatStatusViewProps) => {\n const isRunning = requestTiming != null && requestTiming.endedAt == null;\n const show = requestTiming || lastOutputTokens || sessionTotalTokens > 0 || alarm != null;\n if (!show) {\n return null;\n }\n\n return (\n <NaturalChatStatus.Root defaultRunning={false} classNames={['p-1.5 gap-2 text-sm', classNames]}>\n {icon && (\n <NaturalChatStatus.Icon>\n <Matrix\n classNames='size-5'\n dotClassNames='bg-primary-500'\n dim={4}\n dotSize={3}\n count={10}\n interval={500}\n active={isRunning}\n />\n </NaturalChatStatus.Icon>\n )}\n {show && (\n <div className='flex items-center'>\n {requestTiming && (\n <NaturalChatStatus.Text classNames={isRunning && 'text-sky-500'}>\n <Elapsed timing={requestTiming} />\n </NaturalChatStatus.Text>\n )}\n {lastOutputTokens != null && (\n <>\n {requestTiming && <NaturalChatStatus.Separator />}\n <NaturalChatStatus.Text>↓ {Unit.Thousand(lastOutputTokens).toString()}</NaturalChatStatus.Text>\n </>\n )}\n {sessionTotalTokens > 0 && (\n <>\n {(requestTiming || lastOutputTokens != null) && <NaturalChatStatus.Separator />}\n <NaturalChatStatus.Text>Σ {Unit.Thousand(sessionTotalTokens).toString()}</NaturalChatStatus.Text>\n </>\n )}\n {alarm && (\n <>\n {(requestTiming || lastOutputTokens != null || sessionTotalTokens > 0) && <NaturalChatStatus.Separator />}\n <NaturalChatStatus.Text>\n <span\n data-testid='assistant.chat-status.alarm'\n className='flex items-center gap-1'\n title={alarm.message}\n >\n <Icon.Icon icon='ph--alarm--regular' size='md' />\n {formatWakeAt(alarm.wakeAt)}\n {selfWakes > 0 && (\n <span data-testid='assistant.chat-status.self-wakes' className='text-fg-muted'>\n {selfWakes}/{Alarm.MAX_SELF_WAKES}\n </span>\n )}\n </span>\n </NaturalChatStatus.Text>\n </>\n )}\n </div>\n )}\n </NaturalChatStatus.Root>\n );\n};\n\n/**\n * Wall-clock-derived elapsed display. Tick interval forces a re-render every second while\n * the request is active so the displayed value advances; once `endedAt` is set, the value\n * is frozen and the interval is no longer scheduled.\n */\nconst Elapsed = ({ timing }: { timing: ChatRequestTiming }) => {\n const isRunning = timing.endedAt == null;\n const [now, setNow] = useState(Date.now());\n useEffect(() => {\n if (!isRunning) {\n return;\n }\n\n const id = setInterval(() => setNow(Date.now()), TICK_MS);\n return () => clearInterval(id);\n }, [isRunning]);\n\n return <>{formatElapsed((timing.endedAt ?? now) - timing.startedAt)}</>;\n};\n\nconst isStats = (block: ContentBlock.Any): block is ContentBlock.Stats => block._tag === 'stats';\n\n/**\n * Wall-clock time an alarm fires. The clock is what the reader needs to act on (\"it will wake at\n * 14:20\"); a countdown would have to tick, and the alarm can be days out.\n */\nexport const formatWakeAt = (wakeAt: number): string =>\n new Date(wakeAt).toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { useMemo } from 'react';\n\nimport * as Surface from '@dxos/app-framework/Surface';\nimport * as AppSurface from '@dxos/app-toolkit/AppSurface';\nimport * as ToolkitObjectCard from '@dxos/app-toolkit/ObjectCard';\nimport { type Database, Obj } from '@dxos/echo';\nimport { useObject, useResolveRef } from '@dxos/echo-react';\nimport { URI } from '@dxos/keys';\nimport { type ObjectLinkProps, type WidgetDef } from '@dxos/ui-editor';\n\nexport type ObjectCardProps = {\n /** The object's URI. */\n eid: string;\n /** What the header reads while the object has no label of its own. */\n label?: string;\n /** The database the URI is resolved against; the chat's, so space-relative URIs resolve. */\n db?: Database.Database;\n};\n\n/**\n * An object, named by URI, as its card: the header names it, the body is the object's `CardContent`\n * surface. Resolved through the host's database, so a reference the model wrote before the object\n * loaded still lands once it does.\n */\nexport const ObjectCard = ({ db, eid, label }: ObjectCardProps) => {\n const uri = useMemo(() => (eid ? URI.make(eid) : undefined), [eid]);\n const ref = useMemo(() => (uri && db ? db.makeRef<Obj.Unknown>(uri) : undefined), [uri, db]);\n const object = useResolveRef(ref);\n const [subject] = useObject(object);\n if (!subject) {\n return null;\n }\n\n const title = Obj.getLabel(subject)?.trim() || label || '';\n return (\n <ToolkitObjectCard.Root>\n <ToolkitObjectCard.Header subject={subject} lines={1}>\n {title}\n </ToolkitObjectCard.Header>\n <Surface.Surface type={AppSurface.CardContent} data={{ subject }} limit={1} />\n </ToolkitObjectCard.Root>\n );\n};\n\nObjectCard.displayName = 'ObjectCard';\n\nexport type ObjectCardWidgetProps = ObjectLinkProps & Pick<ObjectCardProps, 'db'>;\n\n/** An object embedded in a message (``) as its card. */\nexport const ObjectCardWidget = ({ db, eid, label }: ObjectCardWidgetProps) => (\n <ObjectCard db={db} eid={eid} label={label} />\n);\n\nObjectCardWidget.displayName = 'ObjectCardWidget';\n\n/** The rough height of a card with a one-row body, so the row is measured near its size before the card resolves. */\nconst CARD_ESTIMATED_HEIGHT = 96;\n\n/** The `objectImage` widget for a thread whose objects live in `db`. */\nexport const objectCardWidget = (db?: Database.Database): WidgetDef<ObjectLinkProps> => ({\n block: true,\n estimatedHeight: () => CARD_ESTIMATED_HEIGHT,\n heightMode: 'min',\n Component: (props) => <ObjectCardWidget {...props} db={db} />,\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { useMemo } from 'react';\n\nimport * as Surface from '@dxos/app-framework/Surface';\nimport { log } from '@dxos/log';\nimport { type WidgetProps, getXmlTextChild } from '@dxos/ui-editor';\n\nimport { ChatSurface } from '#types';\n\n/**\n * Renders an agent-requested UI surface (the `<surface>` content block) by dispatching to a\n * registered {@link ChatSurface.ChatSurface} surface keyed on its `role`. The payload is carried as JSON in the\n * tag's text content; a malformed payload renders the surface with no data rather than throwing.\n */\nexport const SurfaceWidget = ({ role, children }: WidgetProps<{ role?: string }>) => {\n const data = useMemo(() => {\n const raw = getXmlTextChild(children ?? []);\n if (!raw) {\n return undefined;\n }\n try {\n const parsed: unknown = JSON.parse(raw);\n // Model-supplied JSON payload: narrowed to a non-array object; no typed schema exists at this boundary.\n return parsed != null && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : undefined;\n } catch (err) {\n log.warn('failed to parse surface data', { raw, err });\n return undefined;\n }\n }, [children]);\n\n if (!role) {\n return null;\n }\n\n return <Surface.Surface type={ChatSurface.ChatSurface} data={{ role, data }} limit={1} />;\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { Collapsible } from '@ark-ui/react/collapsible';\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport * as Option from 'effect/Option';\nimport * as Atom from 'effect/reactivity/Atom';\nimport React, { type PropsWithChildren, useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { SessionConfig } from '@dxos/ai';\nimport * as Hooks from '@dxos/app-framework/Hooks';\nimport { Alarm } from '@dxos/assistant';\nimport * as SlashCommand from '@dxos/assistant-toolkit/SlashCommand';\nimport * as AssistantChat from '@dxos/assistant/Chat';\nimport { Event } from '@dxos/async';\nimport { type Database, Filter, Obj, Query } from '@dxos/echo';\nimport { useObject, useQuery } from '@dxos/echo-react';\nimport { useIdentity } from '@dxos/halo-react';\nimport { PublicKey, type URI } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport {\n type ChatThreadController,\n type ChatThreadEvent,\n type ChatView,\n ChatThread as NaturalChatThread,\n} from '@dxos/react-ui-assistant';\nimport {\n type MessageRange,\n type OutlineMarker,\n Outline as OutlineRail,\n isPrompt,\n useFeedModel,\n} from '@dxos/react-ui-feed';\nimport { ActionToolbar, type ActionToolbarProps, createMenuAction } from '@dxos/react-ui-menu';\nimport { TaskList, TaskQuestion } from '@dxos/react-ui-task';\nimport * as UiHooks from '@dxos/react-ui/Hooks';\nimport * as Toast from '@dxos/react-ui/Toast';\nimport * as Util from '@dxos/react-ui/Util';\nimport { Message, Task } from '@dxos/types';\nimport { keyToFallback, markWork } from '@dxos/util';\n\nimport { type ChatSwitcher, useChatToolbarActions, useDebug } from '#hooks';\nimport { meta } from '#meta';\nimport { AssistantOperation } from '#types';\n\nimport { TaskSlashCommands } from '../../commands/index.ts';\nimport {\n AiUsageQuotaError,\n type ProcessorRequestContext,\n getProcessorState,\n projectAlarms,\n projectSelfWakes,\n resolveRewind,\n} from '../../processor/index.ts';\nimport {\n ChatStatus,\n DEFAULT_MAX_QUEUE,\n ChatActivity as NaturalChatActivity,\n ChatPrompt as NaturalChatPrompt,\n type ChatPromptProps as NaturalChatPromptProps,\n} from '../ChatPrompt/index.ts';\nimport {\n ChatContextProvider,\n type ChatContextValue,\n ChatReportContextProvider,\n type ChatRequestTiming,\n ChatThreadContextProvider,\n useChatContext,\n useChatThreadContext,\n} from './context.ts';\nimport { type ChatEvent } from './events.ts';\nimport { objectCardWidget } from './ObjectCardWidget.tsx';\nimport { SurfaceWidget } from './SurfaceWidget.tsx';\n\n//\n// Root\n//\n\ntype ChatRootProps = PropsWithChildren<\n Pick<ChatContextValue, 'chat' | 'processor' | 'debug'> & {\n /** Fallback database when the chat is transient (not yet persisted). */\n db?: Database.Database;\n onEvent?: (event: ChatEvent) => void;\n /**\n * Runs (and is awaited) before the request fires on submit. Lets a transient chat\n * persist and flush its conversation feed so the agent can resolve it.\n */\n onSubmit?: (text: string) => Promise<void> | void;\n /** Called at submit time to capture ephemeral request context (e.g. companion selection). */\n getContext?: () => ProcessorRequestContext | undefined;\n }\n>;\n\nconst ChatRoot = ({\n children,\n chat,\n processor,\n db: dbFallback,\n debug: debugProp,\n onEvent,\n onSubmit,\n getContext,\n ...props\n}: ChatRootProps) => {\n const [debug, setDebug] = useState(debugProp ?? false);\n // Slash commands run their operations through the same invoker the rest of the UI uses.\n const { invokePromise } = Hooks.useOperationInvoker();\n const processorState = getProcessorState(processor);\n const streaming = useAtomValue(processorState.streaming);\n const active = useAtomValue(processorState.active);\n const requestTiming = useRequestTiming({ active });\n const lastPrompt = useRef<string | undefined>(undefined);\n // A slash command runs outside the processor, so `streaming` does not cover it.\n const commandPending = useRef(false);\n // Transient chats have no database of their own; fall back to the supplied space db so\n // the message query and context controls operate before the chat is persisted.\n const db = (chat && Obj.getDatabase(chat)) || dbFallback;\n\n // Reactive subscription — re-renders when the feed ref resolves. Direct `.target` reads are not reactive.\n const [feedSnapshot] = useObject(chat?.feed);\n const feed = Obj.getReactiveOrUndefined(feedSnapshot);\n\n // Event sink.\n const event = useMemo(() => new Event<ChatEvent>(), []);\n\n // The thread controller and visible range are produced by `Chat.Thread` and consumed by\n // `Chat.Outline`; lifted here so both sub-components share the same instance.\n const [controller, setController] = useState<ChatThreadController | null>(null);\n const [visibleRange, setVisibleRange] = useState<MessageRange | undefined>(undefined);\n\n const feedAlarms = useQuery(\n db,\n feed ? Query.select(Filter.type(Alarm.Alarm)).from(feed) : Query.select(Filter.nothing()),\n );\n // The processor queries the feed and reconciles it with the streamed turn and the outbox.\n const { messages, delivery, queued, tail } = useAtomValue(processorState.thread);\n const alarms = useMemo(() => projectAlarms({ feedAlarms }), [feedAlarms]);\n const selfWakes = useMemo(() => projectSelfWakes({ feedAlarms, messages }), [feedAlarms, messages]);\n\n const dump = useDebug({ processor });\n\n // Surface processor failures (e.g., AI service unavailable) to subscribers via the event bus.\n const error = useAtomValue(processorState.error);\n useEffect(() => {\n if (Option.isSome(error)) {\n event.emit({ type: 'error', error: error.value });\n }\n }, [event, error]);\n\n useEffect(() => {\n return event.on((ev) => {\n switch (ev.type) {\n case 'toggle-debug': {\n setDebug((debug) => {\n if (debug) {\n return false;\n } else {\n void dump();\n return true;\n }\n });\n break;\n }\n\n case 'rewind': {\n // Edit-and-resend: discard the prompt and everything after it, and put its text back in the\n // composer so it can be revised. Recorded on the feed rather than the chat because the\n // continuation is appended by the agent's process, which resolves the feed and never sees the\n // chat. A stale click (message already gone) resolves to nothing and is a no-op. A prompt sent\n // from here keeps its own row id, so the feed is pointed at its turn's message.\n const rewind = feed && resolveRewind(messages, ev.id);\n if (rewind) {\n Obj.update(feed, (feed) => {\n feed.rewindFrom = delivery.get(rewind.rewindFrom)?.turnId ?? rewind.rewindFrom;\n });\n event.emit({ type: 'update-prompt', text: rewind.text });\n }\n break;\n }\n\n case 'remove-prompt': {\n // Withdrawing a prompt the agent has not taken up: the queue is feed state, so removing the\n // entry is what takes it out of the agent's queue, and the outbox forgets this client's copy.\n const row = delivery.get(ev.id);\n if (row?.status === 'failed' || row?.status === 'delivered') {\n if (row.entryId && db && feed) {\n void db.removeFeedItemsByIds(feed, [row.entryId]).catch((err) => log.catch(err));\n }\n if (row.outboxId) {\n processor?.removePrompt(row.outboxId);\n }\n }\n break;\n }\n }\n\n onEvent?.(ev);\n });\n // `feed`, `messages` and `delivery` are dependencies because the rewind and prompt branches read\n // them: without them the handler would keep resolving against whatever was mounted first.\n }, [event, dump, onEvent, db, feed, messages, delivery, processor]);\n\n useEffect(() => {\n return event.on((ev) => {\n if (ev.type !== 'respond' || !chat) {\n return;\n }\n const { messageId, requestId, optionId } = ev;\n // The operation reads the chat's feed, so it runs in the chat's space.\n const spaceId = Obj.getDatabase(chat)?.spaceId;\n void invokePromise(\n AssistantOperation.RespondToRequest,\n { chat, messageId, requestId, optionId },\n spaceId ? { spaceId } : undefined,\n ).then(({ error }) => {\n if (error) {\n event.emit({ type: 'error', error });\n }\n });\n });\n }, [event, chat, invokePromise]);\n\n useEffect(() => {\n if (!processor) {\n return;\n }\n\n return event.on((ev) => {\n switch (ev.type) {\n case 'submit': {\n const text = ev.text.trim();\n if (text.length) {\n // A leading /command is a deterministic shortcut — executed directly, no model in\n // the loop; an unknown command falls through to the model as plain text.\n const resolved = SlashCommand.resolveSlashCommand(text, TaskSlashCommands);\n if (resolved) {\n // One command at a time: `invokePromise` does not queue, so two quick submissions\n // would interleave their operations and land their summaries out of order.\n if (commandPending.current) {\n break;\n }\n commandPending.current = true;\n // One rejection handler for the whole chain: `onSubmit` can throw synchronously and\n // `appendToFeed` can reject, and either would otherwise be lost with no error shown.\n void (async () => {\n await Promise.resolve(onSubmit?.(text));\n // Re-read after `onSubmit`: that is what persists a transient chat, so a chat that\n // began without a database has one only now.\n const currentDb = (chat && Obj.getDatabase(chat)) || db;\n if (!chat || !currentDb) {\n throw new Error('Command requires a persisted chat.');\n }\n\n const result = await resolved.command.execute(resolved.args, {\n db: currentDb,\n chat,\n invoke: invokePromise,\n });\n if (result instanceof Error) {\n throw result;\n }\n\n // The command's effect is otherwise invisible in the conversation: the prompt was\n // never sent, so nothing records that the user ran it. The feed is re-read here\n // because `onSubmit` is what persists a transient chat, creating it.\n const currentFeed = feed ?? chat.feed?.target;\n if (currentFeed && result.summary) {\n await currentDb.appendToFeed(currentFeed, [\n Message.make({ sender: { role: 'user' }, blocks: [{ _tag: 'text', text }] }),\n Message.make({ sender: { role: 'assistant' }, blocks: [{ _tag: 'text', text: result.summary }] }),\n ]);\n }\n\n if (result.followUp) {\n // Some effects run on the supervisor loop (delegation spawns post-turn), so the\n // command wakes the conversation with a short synthetic prompt.\n void processor.request({ message: result.followUp });\n }\n })()\n .catch((error) => {\n event.emit({ type: 'error', error: error instanceof Error ? error : new Error(String(error)) });\n })\n .finally(() => {\n commandPending.current = false;\n });\n break;\n }\n // The prompt's own guard does not cover submits emitted elsewhere (a checklist's execute action).\n if (active && queued >= DEFAULT_MAX_QUEUE) {\n break;\n }\n markWork('chat.submit');\n lastPrompt.current = ev.text;\n // Optimistic: the prompt is in the thread from this call on, before `onSubmit` persists a\n // transient chat and before the agent acknowledges it. The processor requests it when the\n // agent is idle and queues it behind a running turn otherwise.\n processor.send({ message: text, context: getContext?.() }, { prepare: () => onSubmit?.(text) });\n }\n break;\n }\n\n case 'report': {\n const text = ev.text.trim();\n if (text.length) {\n // Same seam as a submitted prompt (persist first, queue while a turn runs), but the\n // content is synthetic — nobody typed it.\n void Promise.resolve(onSubmit?.(text)).then(() =>\n active\n ? processor.enqueue({ message: text, disposition: 'synthetic' })\n : processor.request({ message: text, disposition: 'synthetic' }),\n );\n }\n break;\n }\n\n case 'retry': {\n if (!streaming) {\n void processor.retry();\n }\n break;\n }\n\n case 'cancel': {\n void processor.cancel();\n if (streaming) {\n if (lastPrompt.current) {\n event.emit({ type: 'update-prompt', text: lastPrompt.current });\n }\n }\n break;\n }\n }\n });\n }, [event, processor, streaming, active, queued, onSubmit, getContext, invokePromise, chat, db, feed]);\n\n // An inline surface (connector prompt, plugin prompt) reports its completed flow as a synthetic\n // turn, so the agent resumes without the report reading as something the user typed.\n const handleReport = useCallback((text: string) => event.emit({ type: 'report', text }), [event]);\n\n return (\n <ChatContextProvider\n debug={debug}\n event={event}\n db={db}\n chat={chat}\n processor={processor}\n queueSize={queued}\n setController={setController}\n setVisibleRange={setVisibleRange}\n {...props}\n >\n <ChatThreadContextProvider\n messages={messages}\n tail={tail}\n alarms={alarms}\n selfWakes={selfWakes}\n requestTiming={requestTiming}\n controller={controller}\n visibleRange={visibleRange}\n >\n <ChatReportContextProvider submit={handleReport}>{children}</ChatReportContextProvider>\n </ChatThreadContextProvider>\n </ChatContextProvider>\n );\n};\n\nChatRoot.displayName = 'Chat.Root';\n\nconst useRequestTiming = ({ active }: { active: boolean }) => {\n const [requestTiming, setRequestTiming] = useState<ChatRequestTiming | null>(null);\n useEffect(() => {\n if (active) {\n setRequestTiming({ startedAt: Date.now(), endedAt: null });\n } else {\n setRequestTiming((prev) => (prev && prev.endedAt == null ? { ...prev, endedAt: Date.now() } : prev));\n }\n }, [active]);\n\n return requestTiming;\n};\n\n//\n// Toolbar\n//\n\nconst CHAT_TOOLBAR_NAME = 'Chat.Toolbar';\n\ntype ChatToolbarProps = Pick<ActionToolbarProps, 'attendableId' | 'alwaysActive'> &\n PropsWithChildren<{\n companionTo?: Obj.Unknown;\n /** Scopes the chat switcher; defaults to the companion chats of `companionTo`. */\n switcher?: ChatSwitcher;\n }>;\n\nconst ChatToolbar = Util.composable<HTMLDivElement, ChatToolbarProps>(\n ({ children, attendableId, alwaysActive, companionTo, switcher, ...props }, forwardedRef) => {\n const { chat } = useChatContext(CHAT_TOOLBAR_NAME);\n const menuActions = useChatToolbarActions({ chat, companionTo, switcher });\n\n return (\n <ActionToolbar\n {...menuActions}\n attendableId={attendableId}\n alwaysActive={alwaysActive}\n {...Util.composableProps(props)}\n ref={forwardedRef}\n >\n {children}\n </ActionToolbar>\n );\n },\n);\n\nChatToolbar.displayName = CHAT_TOOLBAR_NAME;\n\n//\n// Content\n//\n\nconst CHAT_CONTENT_NAME = 'Chat.Content';\n\ntype ChatContentProps = {};\n\nconst ChatContent = Util.composable<HTMLDivElement, ChatContentProps>(({ children, ...props }, forwardedRef) => {\n return (\n <div {...Util.composableProps(props, { classNames: 'dx-expand flex flex-col' })} ref={forwardedRef}>\n {children}\n </div>\n );\n});\n\nChatContent.displayName = CHAT_CONTENT_NAME;\n\n//\n// Markers\n//\n\nconst PROMPT_SNIPPET_LINES = 3;\nconst PROMPT_SNIPPET_CHARS = 280;\nconst PROMPT_TITLE_CHARS = 100;\n\n/**\n * The text the reader actually wrote. Synthetic blocks carry injected context and tool results, so\n * titling a marker from them would name the machinery rather than the prompt.\n */\nconst authoredText = (message: Message.Message): string =>\n message.blocks\n .flatMap((block) => (block._tag === 'text' && block.disposition !== 'synthetic' ? [block.text] : []))\n .join('\\n');\n\n/** First non-empty line of a message's text, truncated for the marker title. */\nconst promptTitle = (message: Message.Message): string => {\n const text = authoredText(message).trim();\n const firstLine = text.split('\\n').find((line) => line.trim().length) ?? '';\n return firstLine.length > PROMPT_TITLE_CHARS ? `${firstLine.slice(0, PROMPT_TITLE_CHARS)}…` : firstLine;\n};\n\n/** First few text lines of an assistant reply (tool calls, reasoning and status are excluded). */\nconst replySnippet = (message: Message.Message): string | undefined => {\n // `extractText` keeps only `text` blocks, so tool calls / reasoning / status are dropped.\n const text = Message.extractText(message).trim();\n if (!text.length) {\n return undefined;\n }\n const snippet = text\n .split('\\n')\n .filter((line) => line.trim().length)\n .slice(0, PROMPT_SNIPPET_LINES)\n .join('\\n');\n return snippet.length > PROMPT_SNIPPET_CHARS ? `${snippet.slice(0, PROMPT_SNIPPET_CHARS)}…` : snippet;\n};\n\n/**\n * Build one outline marker per user-prompt turn: title = the prompt text, description = a snippet\n * of the following assistant reply, range = the turn's index span (prompt → next prompt). Message\n * indices, not document offsets: the feed navigates by index, so no range table exists any more.\n */\nconst buildMarkers = (messages: Message.Message[]): OutlineMarker[] => {\n const markers: OutlineMarker[] = [];\n for (let index = 0; index < messages.length; index++) {\n const message = messages[index];\n // Role alone would also match tool results and injected context, which travel back as\n // `user`-role messages; `isPrompt` is the feed's single definition of a stop.\n if (!isPrompt(message)) {\n continue;\n }\n\n // Extend the turn up to the next prompt: a tool-result turn belongs to the turn it serves, so\n // stopping on any `user`-role message would cut the range at the first tool call.\n let turnTo = index + 1;\n let description: string | undefined;\n for (let next = index + 1; next < messages.length; next++) {\n const nextMessage = messages[next];\n if (isPrompt(nextMessage)) {\n break;\n }\n turnTo = next + 1;\n if (!description && nextMessage.sender.role === 'assistant') {\n description = replySnippet(nextMessage);\n }\n }\n\n markers.push({\n id: message.id,\n title: promptTitle(message) || 'Prompt',\n description,\n range: { from: index, to: turnTo },\n });\n }\n return markers;\n};\n\n//\n// Thread\n//\n\nconst CHAT_THREAD_NAME = 'Chat.Thread';\n\n/** The plugin's `surface` widget layered over the package registry: it can dispatch a Surface. */\nconst chatRegistry = {\n surface: {\n block: true,\n Component: SurfaceWidget,\n },\n} as const;\n\ntype ChatThreadProps = Util.ThemedClassName<{\n viewType?: ChatView;\n /** Blank lines kept below the tail at rest — breathing room above the composer. */\n tailLines?: number;\n /** Hue of the user's messages; defaults to the identity's hue. */\n userHue?: string;\n /** Invoked from the over-quota error toast to open the usage dashboard. */\n onViewUsage?: () => void;\n}>;\n\nconst ChatThread = ({ classNames, viewType, tailLines, userHue: userHueProp, onViewUsage }: ChatThreadProps) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const { chat, db, debug, event, processor, setController, setVisibleRange } = useChatContext(CHAT_THREAD_NAME);\n const { messages, tail } = useChatThreadContext(CHAT_THREAD_NAME);\n const identity = useIdentity();\n // Embedded objects resolve against the chat's database (the fallback one while it is transient).\n const objectImage = useMemo(() => objectCardWidget(db), [db]);\n // A block reference's chip reads the object's name once it is loaded — resolved through the\n // database's own ref, which honours the URI's space and the DXN forms — and the package default's\n // bare \"Object\" until then; the thread re-renders as the message's blocks settle.\n const getObjectLabel = useCallback(\n (uri: URI.URI): string => {\n let object: Obj.Unknown | undefined;\n try {\n object = db?.makeRef<Obj.Unknown>(uri).target;\n } catch {\n object = undefined;\n }\n return (object && Obj.getLabel(object)) || 'Object';\n },\n [db],\n );\n const [toastError, setToastError] = useState<Error | undefined>(undefined);\n // The toast renders whatever action the error declares (data-driven) rather than branching on type.\n const toastAction = toastError instanceof AiUsageQuotaError ? toastError.action : undefined;\n\n // The model is the adapter: the projected array is folded in with `replace`, streaming chunks\n // arrive as updates on one identity, and the window is told — the old `MessageSyncer`'s cursor\n // and range table have no equivalent left.\n const model = useFeedModel(messages, { stops: 'prompt' });\n const streaming = useAtomValue(getProcessorState(processor).streaming);\n useEffect(() => {\n // The answer streams above any prompts still waiting for the agent, which end the thread.\n const last = messages[messages.length - 1 - tail];\n model.setStreaming(streaming && last?.sender.role === 'assistant' ? last.id : undefined);\n }, [model, streaming, messages, tail]);\n\n const userHue = useMemo(\n () =>\n userHueProp ||\n identity?.data?.hue ||\n keyToFallback(identity?.identityKey ? PublicKey.fromHex(identity.identityKey) : PublicKey.random()).hue,\n [userHueProp, identity],\n );\n\n const controllerRef = useRef<ChatThreadController | null>(null);\n // Share the controller with `Chat.Outline` (and keep the local ref for event handling).\n const handleControllerRef = useCallback(\n (instance: ChatThreadController | null) => {\n controllerRef.current = instance;\n setController(instance);\n },\n [setController],\n );\n\n useEffect(() => {\n return event.on((event) => {\n switch (event.type) {\n case 'submit':\n case 'scroll-to-bottom':\n controllerRef.current?.scrollToBottom();\n break;\n case 'nav-previous':\n controllerRef.current?.navigation.step(-1);\n break;\n case 'nav-next':\n controllerRef.current?.navigation.step(1);\n break;\n case 'error':\n setToastError(event.error);\n break;\n default:\n log.info('no handled', event);\n }\n });\n }, [event]);\n\n // Rewind (the prompt toolbar) and submit (suggestion/select widgets) land on the shared bus,\n // where `Chat.Root` already resolves them.\n const handleEvent = useCallback((ev: ChatThreadEvent) => event.emit(ev), [event]);\n\n if (!identity) {\n return <div className='dx-expand' />;\n }\n\n return (\n <>\n <NaturalChatThread.Root\n model={model}\n viewType={viewType}\n registry={chatRegistry}\n objectImage={objectImage}\n getObjectLabel={getObjectLabel}\n userHue={userHue}\n tailLines={tailLines}\n debug={debug}\n // An external agent keeps its own context, which a rewind of the transcript cannot reach.\n rewind={SessionConfig.harnessOf(chat?.session) === SessionConfig.COMPOSER_HARNESS}\n onEvent={handleEvent}\n onRangeChange={setVisibleRange}\n controllerRef={handleControllerRef}\n >\n <NaturalChatThread.Viewport classNames={classNames} />\n </NaturalChatThread.Root>\n\n {/* TODO(burdon): Why is this required? */}\n <Toast.Root\n data-testid='assistant.error'\n open={!!toastError}\n duration={20_000}\n onOpenChange={(open) => !open && setToastError(undefined)}\n >\n <Toast.Header icon='ph--warning--regular'>{t('ai-service-error.label')}</Toast.Header>\n <Toast.Description>{toastError?.message}</Toast.Description>\n {toastAction && onViewUsage && (\n <Toast.Footer>\n <Toast.ActionTrigger\n onClick={() => {\n setToastError(undefined);\n onViewUsage();\n }}\n >\n {t(toastAction.labelKey)}\n </Toast.ActionTrigger>\n </Toast.Footer>\n )}\n </Toast.Root>\n </>\n );\n};\n\nChatThread.displayName = CHAT_THREAD_NAME;\n\n//\n// Outline\n//\n\nconst CHAT_OUTLINE_NAME = 'Chat.Outline';\n\ntype ChatOutlineProps = Util.ThemedClassName<{}>;\n\n/**\n * Anchor-marker rail for the thread: one tick per user-prompt turn. Reads the shared controller\n * and the visible index range from context; clicking a tick jumps the thread to that turn, on the\n * same navigation seam as the toolbar and the arrow keys.\n */\nconst ChatOutline = ({ classNames }: ChatOutlineProps) => {\n const { messages, visibleRange, controller } = useChatThreadContext(CHAT_OUTLINE_NAME);\n\n const markers = useMemo(() => buildMarkers(messages), [messages]);\n const handleSelect = useCallback(\n (marker: OutlineMarker) => {\n controller?.navigation.jumpTo(marker.range.from, 'smooth');\n },\n [controller],\n );\n const handleNavigate = useCallback((delta: number) => controller?.navigation.step(delta), [controller]);\n\n if (markers.length < 2) {\n return null;\n }\n\n return (\n <OutlineRail\n classNames={classNames}\n markers={markers}\n // `endIndex` is inclusive; the rail's `to` is exclusive.\n visibleRange={visibleRange ? { from: visibleRange.startIndex, to: visibleRange.endIndex + 1 } : undefined}\n onSelect={handleSelect}\n onNavigate={handleNavigate}\n />\n );\n};\n\nChatOutline.displayName = CHAT_OUTLINE_NAME;\n\n//\n// Prompt\n//\n\nconst CHAT_PROMPT_NAME = 'Chat.Prompt';\n\ntype ChatPromptProps = Omit<NaturalChatPromptProps, 'chat' | 'db' | 'processor' | 'event' | 'tasksVisible'> & {\n /** Whether the checklist is disclosed on mount. */\n defaultTasksVisible?: boolean;\n};\n\n/**\n * The composer with the chat's checklist disclosed above it.\n *\n * One component rather than two siblings: they share a border and a rounded shell, and the control\n * that discloses the checklist lives in the composer's own action bar — so a host that placed them\n * side by side had to hold the disclosure state between them and coordinate the corner radius.\n *\n * Ark's `Collapsible` owns the disclosure (it measures the height the animation ramps against). Its\n * trigger is not used: the toggle is a button inside the composer, which reports through the chat\n * event rather than being wrapped in a `Collapsible.Trigger` it cannot reach.\n */\nconst ChatPrompt = ({ classNames, defaultTasksVisible = false, ...props }: ChatPromptProps) => {\n const { chat, db, processor, event, queueSize } = useChatContext(CHAT_PROMPT_NAME);\n\n // A chat with no checklist at all has nothing to disclose, so the toggle is withheld rather than\n // shown pointing at nothing — `ChatActions` renders it only when `tasksVisible` is defined.\n const [tasks] = useObject(chat, 'tasks');\n const hasTasks = tasks != null;\n\n // Collapsed by default: the checklist is the assistant's working state, not the reader's, so the\n // prompt keeps the room and the toggle is how they ask for it. Per mount rather than persisted —\n // it is a glance, not a preference.\n const [tasksVisible, setTasksVisible] = useState(chat?.tasks?.length ? defaultTasksVisible : false);\n useEffect(() => {\n return event.on((ev) => {\n if (ev.type === 'toggle-tasks') {\n setTasksVisible((visible) => !visible);\n }\n });\n }, [event]);\n\n return (\n <Collapsible.Root\n open={tasksVisible}\n onOpenChange={({ open }) => setTasksVisible(open)}\n // Clipped rather than unmounted: the list holds its own subscriptions, and remounting it on\n // every toggle would refetch the checklist to show what the reader just hid.\n lazyMount={false}\n >\n {/* The height the machine measures is what the ramp animates against, so the region clips. */}\n {hasTasks && (\n <Collapsible.Content className='overflow-hidden data-[state=closed]:animate-slide-up data-[state=open]:animate-slide-down'>\n {/* The same surface and border as the prompt below, so the two read as one shell. */}\n <ChatTaskList classNames='shrink-0 dx-group-surface border border-separator-subtle border-b-0 rounded-t-sm text-fg-muted' />\n </Collapsible.Content>\n )}\n <NaturalChatPrompt\n {...props}\n // Square where the checklist meets it, so the two read as one shell rather than two cards.\n classNames={[tasksVisible && 'rounded-t-none', classNames]}\n db={db}\n chat={chat}\n processor={processor}\n event={event}\n queueSize={queueSize}\n tasksVisible={hasTasks ? tasksVisible : undefined}\n />\n </Collapsible.Root>\n );\n};\n\nChatPrompt.displayName = CHAT_PROMPT_NAME;\n\n//\n// TaskList\n//\n\nconst CHAT_TASK_LIST_NAME = 'Chat.TaskList';\n\n/** Rows the chat's checklist shows before it scrolls. */\nconst CHAT_TASK_ROWS = 4;\n\nconst ChatTaskList = Util.composable<HTMLDivElement>((props, forwardedRef) => {\n const { chat, event } = useChatContext(CHAT_TASK_LIST_NAME);\n const { t } = UiHooks.useTranslation(meta.profile.key);\n\n // Both the chat (membership) and each ref (row objects): a query re-emits only on membership.\n const [chatSnapshot] = useObject(chat);\n const taskRefs = chatSnapshot?.tasks;\n const tasks = useAtomValue(\n useMemo(() => Atom.make((get) => Task.dedupeById((taskRefs ?? []).map((ref) => get(ref.atom)))), [taskRefs]),\n );\n\n // The same primitive the task commands use, so the parent edge and the refs cannot diverge.\n const handleCreate = useCallback(\n ({ title, ...props }: Task.Draft) => {\n const db = chat && Obj.getDatabase(chat);\n if (chat && db) {\n AssistantChat.addTask(db, chat, title, props);\n }\n },\n [chat],\n );\n\n // The same primitive the task commands use: it sweeps the checklist and destroys only what the\n // chat owns, so a delegated task keeps the set that parents it.\n const handleDelete = useCallback(\n (task: Task.Task) => {\n const db = chat && Obj.getDatabase(chat);\n if (chat && db) {\n AssistantChat.deleteTask(db, chat, tasks, task);\n }\n },\n [chat, tasks],\n );\n\n const handleUpdate = useCallback((task: Task.Task, patch: Task.Edit) => {\n Task.update(task, patch);\n }, []);\n\n // Execution is a prompt, not a direct write: the agent owns the task's lifecycle (assignment,\n // delegation, status), so the row asks for the work the way the reader would, by ordinal — the\n // number the row shows, and the one `/task:run` and the agent's selectors resolve.\n const handleExecute = useCallback(\n (task: Task.Task) => {\n const ordinal = tasks.findIndex(({ id }) => id === task.id) + 1;\n event.emit({ type: 'submit', text: t('execute-task.prompt', { ordinal }) });\n },\n [tasks, event, t],\n );\n\n // Contributed actions rather than fixed chrome, matching `TaskSetArticle`: two items, so the row\n // shows one overflow menu rather than a bare delete button.\n const getTaskActions = useCallback(\n (task: Task.Task) => [\n createMenuAction(`execute-${task.id}`, () => handleExecute(task), {\n label: t('execute-task.label'),\n icon: 'ph--play--regular',\n // A finished task has nothing left to implement.\n disabled: task.status === 'done' || task.status === 'cancelled',\n testId: 'tasks.task.execute',\n }),\n createMenuAction(`delete-${task.id}`, () => handleDelete(task), {\n label: t('delete-task.label'),\n icon: 'ph--trash--regular',\n testId: 'tasks.task.delete',\n }),\n ],\n [handleExecute, handleDelete, t],\n );\n\n if (!chat) {\n return null;\n }\n\n return (\n <TaskList.Root\n tasks={tasks}\n showGroupLabels={false}\n showOrdinals\n showEstimates\n // The prompt frames the list, and its rows are too narrow for who holds a task or its mnemonic.\n flush\n showAssignees={false}\n showMnemonics={false}\n onTaskCreate={handleCreate}\n onTaskUpdate={handleUpdate}\n getTaskActions={getTaskActions}\n >\n <div {...Util.composableProps(props, { classNames: 'flex flex-col dx-grow' })} ref={forwardedRef}>\n {/* Sized to its rows up to four tasks; only a longer list scrolls, never showing a partial row. */}\n <TaskList.Viewport rows={CHAT_TASK_ROWS}>\n <TaskList.Content />\n </TaskList.Viewport>\n {/* What the agent is blocked on, under the list it asked about: the list itself carries no\n questions — a row replaying them grew by a line each — but a chat is where the asking\n happened, so the answer is given here rather than in a pane the reader has to open. */}\n <ChatTaskQuestions tasks={tasks} />\n {/* Only creates: a task is changed through its own row controls, not by selecting it into the strip. */}\n <TaskList.Editor createOnly />\n </div>\n </TaskList.Root>\n );\n});\n\nChatTaskList.displayName = CHAT_TASK_LIST_NAME;\n\n/**\n * The open questions across the chat's tasks, each with the means to answer it.\n *\n * Answers go through the operation rather than `Task.answer`, so the conversation that asked is\n * resumed — which is the whole point of answering here instead of on the task.\n */\nconst ChatTaskQuestions = ({ tasks }: { tasks: readonly Task.Task[] }) => {\n const { invokePromise } = Hooks.useOperationInvoker();\n const threads = useMemo(\n () =>\n tasks.flatMap((task) =>\n Task.getQuestions(task.history)\n .filter(({ answer }) => !answer)\n .map((thread) => ({ task, thread })),\n ),\n [tasks],\n );\n\n const handleAnswer = useCallback(\n (task: Task.Task, questionId: string, answer: string) => {\n const spaceId = Obj.getDatabase(task)?.spaceId;\n if (spaceId) {\n // The operation reports a refused write in its result, not only by rejecting, so both are checked.\n invokePromise(AssistantOperation.AnswerQuestion, { task, question: questionId, answer }, { spaceId })\n .then((result) => {\n if (result.error || !result.data?.accepted) {\n log.warn('question was not answered', { task: task.id, question: questionId, error: result.error });\n }\n })\n .catch((err) => log.catch(err));\n }\n },\n [invokePromise],\n );\n\n if (threads.length === 0) {\n return null;\n }\n\n return (\n <div className='flex flex-col gap-2 p-2' data-testid='chat.taskQuestions'>\n {threads.map(({ task, thread }) => (\n <TaskQuestion\n key={thread.question.id}\n thread={thread}\n onAnswer={(answer) => handleAnswer(task, thread.question.id, answer)}\n />\n ))}\n </div>\n );\n};\n\nChatTaskQuestions.displayName = 'Chat.TaskQuestions';\n\n//\n// Activity\n//\n\nconst CHAT_ACTIVITY_NAME = 'Chat.Activity';\n\n/**\n * The activity line bound to the chat's processor and the chat's pending alarms: what the agent is\n * doing, for as long as it is doing anything. The line itself takes resolved values, so it lives\n * beside the prompt with the rest of the presentational parts and only the binding is here.\n */\nconst ChatActivity = ({ classNames }: Util.ThemedClassName) => {\n const { processor } = useChatContext(CHAT_ACTIVITY_NAME);\n const { alarms } = useChatThreadContext(CHAT_ACTIVITY_NAME);\n const activity = useAtomValue(getProcessorState(processor).activity);\n\n // Earliest pending alarm: the agent wakes at the first one, so a later one says nothing about the\n // wait in front of the reader.\n return <NaturalChatActivity classNames={classNames} activity={activity} wakeAt={alarms[0]?.wakeAt} />;\n};\n\nChatActivity.displayName = CHAT_ACTIVITY_NAME;\n\n//\n// Chat\n//\n\nexport const Chat = {\n Root: ChatRoot,\n Toolbar: ChatToolbar,\n Content: ChatContent,\n Prompt: ChatPrompt,\n Activity: ChatActivity,\n Status: ChatStatus,\n Thread: ChatThread,\n Outline: ChatOutline,\n};\n\nexport type {\n ChatContentProps,\n ChatEvent,\n ChatOutlineProps,\n ChatPromptProps,\n ChatRootProps,\n ChatThreadProps,\n ChatToolbarProps,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAcA,IAAa,oBAAiD;CAC5D;EACE,SAAS;EACT,aAAa;EACb,SAAS,OAAO,MAAM,EAAE,IAAI,WAAW;GACrC,MAAM,QAAQ,KAAK,KAAK;GACxB,IAAI,MAAM,WAAW,GACnB,uBAAO,IAAI,MAAM,mCAAmC;GAEtD,OAAK,QAAQ,IAAI,MAAM,KAAK;GAC5B,MAAM,GAAG,MAAM;GACf,OAAO,EAAE,SAAS,iBAAiB,MAAM,IAAI;EAC/C;CACF;CACA;EACE,SAAS;EACT,aAAa;EACb,SAAS,OAAO,MAAM,EAAE,IAAI,WAAW;GACrC,MAAM,QAAQ,MAAM,QAAQ,IAAI;GAChC,MAAM,WAAW,iBAAiB,MAAM,KAAK;GAC7C,IAAI,oBAAoB,OACtB,OAAO;GAET,IAAI,SAAS,WAAW,GACtB,uBAAO,IAAI,MAAM,sDAAoD;GAIvE,MAAM,UAAuB,CAAC;GAC9B,MAAM,uBAAO,IAAI,IAAY;GAC7B,KAAK,MAAM,QAAQ,UAAU;IAC3B,IAAI,KAAK,IAAI,KAAK,EAAE,GAClB;IAEF,KAAK,MAAM,UAAU,OAAK,WAAW,IAAI,MAAM,OAAO,IAAI,GACxD,KAAK,IAAI,OAAO,EAAE;IAEpB,QAAQ,KAAK,IAAI;GACnB;GACA,MAAM,GAAG,MAAM;GACf,OAAO,EAAE,SAAS,UAAU,WAAW,OAAO,EAAE;EAClD;CACF;CACA;EACE,SAAS;EACT,aAAa;EACb,SAAS,OAAO,MAAM,EAAE,IAAI,MAAM,aAAa;GAC7C,MAAM,WAAW,iBAAiB,MAAM,MAAM,QAAQ,IAAI,CAAC;GAC3D,IAAI,oBAAoB,OACtB,OAAO;GAET,IAAI,SAAS,WAAW,GACtB,uBAAO,IAAI,MAAM,mDAAiD;GAIpE,MAAM,WAAW,SAAS,QACvB,SAAS,KAAK,WAAW,UAAU,KAAK,WAAW,eAAe,KAAK,WAAW,SACrF;GACA,IAAI,SAAS,WAAW,GACtB,OAAO,EAAE,SAAS,2EAA2E;GAI/F,KAAK,MAAM,QAAQ,UAAU;IAC3B,MAAM,UAAU,MAAM,IACpB,QACA,cAAc,YACd;KACE,MAAM,IAAI,KAAK,IAAI;KACnB,UAAU,EAAE,MAAM,YAAqB;KACvC,QAAQ;IACV,GACA,GAAG,OACL;IACA,IAAI,SACF,OAAO;GAEX;GAEA,OAAO;IACL,SAAS,UAAU,aAAa,QAAQ;IACxC,UAAU,IAAI;iFAC2D,SAAS,KAAK,SAAS,IAAI,KAAK,MAAM,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE;;;;;;GAMhI;EACF;CACF;AACF;;;;;AAMA,IAAM,MAAM,OACV,QACA,WACA,OACA,YAC+B;CAC/B,MAAM,EAAE,UAAU,MAAM,OAAO,WAAW,OAAgB,EAAE,QAAQ,CAAC;CACrE,OAAO;AACT;;;;;AAMA,IAAM,UAAU,OAAO,SAA0C;CAG/D,MAAM,QAAQ,IAAI,KAAK,MAAM,KAAK,QAAQ,IAAI,QAAQ,CAAC,CAAC;CACxD,OAAO,OAAK,aAAa,IAAI;AAC/B;;AAGA,IAAM,oBAAoB,MAAc,UAAgC;CACtE,MAAM,YAAY,aAAa,mBAAmB,IAAI;CACtD,IAAI,UAAU,WAAW,GACvB,OAAO,CAAC;CAGV,MAAM,WAAwB,CAAC;CAC/B,KAAK,MAAM,YAAY,WAAW;EAChC,MAAM,OACJ,aAAa,WACT,MAAM,SAAS,UAAU,KACzB,MAAM,MAAM,cAAc,UAAU,UAAU,SAAS,MAAM,KAAK,CAAC;EACzE,IAAI,CAAC,MAAM;GACT,MAAM,QAAQ,aAAa,WAAW,SAAS,UAAU,IAAI,SAAS,MAAM;GAC5E,uBAAO,IAAI,MAAM,yBAAyB,MAAM,yDAAyD;EAC3G;EACA,SAAS,KAAK,IAAI;CACpB;CACA,OAAO;AACT;AAEA,IAAM,aAAa,MAAc,UAC/B,GAAG,KAAK,GAAG,MAAM,KAAK,SAAS,IAAI,KAAK,MAAM,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE;;;;;;;;ACrI/D,IAAM,eAAe;AA0BrB,IAAa,eAAe,EAC1B,YACA,UACA,SACA,cACA,eACA,YACA,OACA,SACA,cACA,QACA,cACsB;CACtB,MAAM,EAAE,MAAM,QAAM,eAAe,KAAK,QAAQ,GAAG;CAGnD,MAAM,WAAW,cAAc,CAAC;CAChC,MAAM,WACJ,qBAAA,YAAA,EAAA,UAAA;EACG;EACA,SACC,oBAAC,OAAO,MAAR;GACE,SAAQ;GACR,MAAK;GACL,UAAA;GACA,OAAO,EAAE,cAAc;GACvB,eAAe,UAAU,EAAE,MAAM,eAAe,CAAC;EAClD,CAAA;EAGF,gBAAgB,QACf,oBAAC,OAAO,MAAR;GACE,SAAQ;GACR,YAAY;GACZ,MAAK;GACL,UAAA;GACA,gBAAc;GACd,OAAO,EAAE,eAAe,sBAAsB,mBAAmB;GACjE,eAAY;GACZ,eAAe,UAAU,EAAE,MAAM,eAAe,CAAC;EAClD,CAAA;EAMF,UAEC,oBAAC,OAAO,MAAR;GACE,UAAU,CAAC,YAAY,CAAC;GACxB,SAAQ;GACR,YAAY,GAAG,cAAc,uCAAuC,WAAW,4BAA4B;GAC3G,MAAM,WAAW,6BAA6B;GAC9C,UAAA;GACA,OAAO,EAAE,WAAW,6BAA6B,YAAY;GAC7D,eAAgB,WAAW,UAAU,EAAE,MAAM,SAAS,CAAC,IAAI,OAAO;GAGlE,eAAY;EACb,CAAA;CAEH,EAAA,CAAA;CAIJ,OAAO,gBACL,oBAAC,oBAAD;EAAoB,SAAS;EAA6B;EAAc,OAAO;EAAqB;EACjG,UAAA;CACiB,CAAA,IAEpB,qBAAC,QAAQ,MAAT;EAA0B;EAA1B,UAAA,CACG,SACA,QACW;;AAElB;;;;;;;;AASA,IAAM,sBAAsB,EAC1B,SACA,cACA,OACA,YACA,eAOI;CACJ,MAAM,cAAc,eAAe,OAAO;CAC1C,OACE,oBAAC,eAAD;EAAe,GAAI;EAA2B;EAAc,cAAA;EAAoB;EAAmB;EAChG;CACY,CAAA;AAEnB;;;AC3IA,IAAM,uBAAqB;AAE3B,IAAM,SAAS;AACf,IAAM,SAAS,KAAK;AACpB,IAAM,OAAO,KAAK;AAElB,IAAM,oBAAoB,UAA0C,YAAY,MAAM;;;;;AAMtF,IAAM,uCAA4D,IAAI,IAA4B,CAAC,cAAc,CAAC;;;;;;;;;;;;AAuBlH,IAAa,kBAAgB,EAAE,YAAY,UAAU,aAAgC;CACnF,MAAM,EAAE,MAAM,QAAM,eAAe,KAAK,QAAQ,GAAG;CAGnD,MAAM,SAAS,CAAC,YAAY,SAAS,UAAU;CAC/C,MAAM,YAAY,aAAa,SAAS,SAAS,KAAA,CAAS;CAK1D,MAAM,QAAQ,SADG,cAAc,KAAA,KAAa,aAAa,SAGnD,aAAa,GAAG,SAAS,IACzB,YAAY,EAAE,iBAAiB,SAAS,KAAK,CAAC,IAChD,EAAE,iBAAiB,SAAS,KAAK,GAAG,EAAE,QAAQ,SAAS,UAAU,GAAG,CAAC;CACzE,IAAI,CAAC,OACH,OAAO;CAGT,OAIE,qBAAC,WAAkB,MAAnB;EACE,gBAAgB;EAChB,YAAY,CAAC,0EAA0E,UAAU;EAFnG,UAAA;GAIE,oBAAC,WAAkB,MAAnB,EAAwB,YAAW,WAAY,CAAA;GAC/C,oBAAC,WAAkB,MAAnB;IAAwB,YAAW;IACjC,UAAA,oBAAC,QAAD;KAAM,eAAY;KAA2B,UAAA;IAAY,CAAA;GACnC,CAAA;GAEvB,UAAU,WAAW,QAAQ,SAAS,UAAU,KAC/C,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,WAAkB,WAAnB,EAA6B,YAAW,WAAY,CAAA,GACpD,oBAAC,WAAkB,MAAnB;IAAwB,YAAW;IACjC,UAAA,oBAAC,QAAD;KAAM,eAAY;KACf,UAAA,EAAE,oBAAoB,EAAE,SAAS,SAAS,QAAQ,CAAC;IAChD,CAAA;GACgB,CAAA,CACxB,EAAA,CAAA;GAEH,UAAU,UAAU,CAAC,qBAAqB,IAAI,SAAS,KAAK,KAC3D,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,WAAkB,WAAnB,EAA6B,YAAW,WAAY,CAAA,GACpD,oBAAC,WAAkB,MAAnB;IAAwB,YAAW;IAAoB,UAAA,SAAS;GAA+B,CAAA,CAC/F,EAAA,CAAA;EAEkB;;AAE5B;AAEA,eAAa,cAAc;;;;;;;;AAS3B,IAAM,gBAAgB,WAAwC;CAG5D,MAAM,GAAG,WAAW,SAAS,CAAC;CAC9B,gBAAgB;EACd,IAAI,WAAW,KAAA,GACb;EAGF,MAAM,WAAW,kBAAkB,SAAS,SAAS,OAAO,CAAC,GAAG,MAAM;EACtE,aAAa,cAAc,QAAQ;CACrC,GAAG,CAAC,MAAM,CAAC;CAEX,OAAO,WAAW,KAAA,IAAY,KAAA,IAAY,SAAS,KAAK,IAAI;AAC9D;;;;;AAMA,IAAM,gBAAgB,GAA+D,cAA8B;CACjH,IAAI,YAAY,QACd,OAAO,EAAE,iCAAiC,EAAE,OAAO,KAAK,MAAM,YAAY,MAAM,EAAE,CAAC;CAErF,IAAI,YAAY,MACd,OAAO,EAAE,iCAAiC,EAAE,OAAO,KAAK,MAAM,YAAY,MAAM,EAAE,CAAC;CAErF,OAAO,EAAE,+BAA+B,EAAE,OAAO,KAAK,MAAM,YAAY,IAAI,EAAE,CAAC;AACjF;;;;;;;ACjHA,IAAa,iBAAiB,EAAE,YAAY,gBAAoC;CAC9E,MAAM,EAAE,MAAM,QAAM,eAAe,KAAK,QAAQ,GAAG;CACnD,MAAM,SAAS,aAAa,UAAU,SAAS;CAE/C,MAAM,gBAAgB,kBAAkB;EACtC,UAAU,iBAAiB;CAC7B,GAAG,CAAC,SAAS,CAAC;CAEd,IAAI,OAAO,WAAW,GACpB,OAAO;CAGT,OACE,qBAAC,OAAO,MAAR;EAAa,SAAQ;EAArB,UAAA,CACE,oBAAC,OAAO,OAAR;GAAc,SAAS;GAAgB,UAAA,EAAE,wBAAwB;EAAgB,CAAA,GACjF,oBAAC,OAAO,MAAR,EAAA,UACE,oBAAC,QAAQ,MAAT;GACE,OAAO,OAAO,KAAK,WAAW;IAC5B,OAAO,GAAG,MAAM,IAAI,IAAI,MAAM;IAC9B,OAAO,GAAG,MAAM,IAAI,IAAI,MAAM;GAChC,EAAE;GAEF,UAAA,oBAAC,QAAQ,SAAT;IAAiB,cAAY,EAAE,wBAAwB;IAAG,YAAW;IAClE,UAAA,OAAO,KAAK,UACX,oBAAC,QAAQ,MAAT;KAAsD,IAAI,GAAG,MAAM,IAAI,IAAI,MAAM;KAG/E,UAAA,qBAAC,QAAD;MAAM,WAAU;MAAhB,UAAA;OACE,oBAAC,QAAD;QAAM,WAAU;QAAa,UAAA,MAAM;OAAU,CAAA;OAC5C;OACD,oBAAC,QAAD,EAAA,UAAO,MAAM,eAAe,EAAE,+BAA+B,IAAI,MAAM,QAAc,CAAA;MACjF;;IACM,GARK,GAAG,MAAM,IAAI,IAAI,MAAM,UAQ5B,CACf;GACc,CAAA;EACL,CAAA,EACH,CAAA,CACF;;AAEjB;;;AClBA,IAAM,SAAS,EACb,OAAO,uDACT;;;;AAYA,IAAa,eAAe,EAAE,IAAI,MAAM,SAAS,UAAU,SAAS,QAAQ,qBAAuC;CACjH,MAAM,EAAE,MAAM,QAAQ,eAAe,KAAK,QAAQ,GAAG;CAErD,OACE,qBAAC,OAAO,MAAR,EAAA,UAAA,CACE,qBAAC,QAAQ,MAAT;EAAc,aAAa,EAAE,WAAW,MAAM;EAA9C,UAAA,CACE,oBAAC,QAAQ,SAAT;GAAiB,SAAA;GACf,UAAA,oBAAC,OAAO,MAAR;IACE,SAAQ;IACR,MAAK;IACL,UAAA;IACA,OAAO,EAAE,wBAAwB;IACjC,UAAU,CAAC;GACZ,CAAA;EACc,CAAA,GACjB,oBAAC,QAAQ,SAAT;GAAiB,YAAY,OAAO;GAEjC,UAAA,WAAW,oBAAC,cAAD;IAAkB;IAAa;GAAU,CAAA;EACtC,CAAA,CACL;CAEd,CAAA,GAAA,qBAAC,QAAQ,MAAT;EAAc,aAAa,EAAE,WAAW,MAAM;EAA9C,UAAA,CACE,oBAAC,QAAQ,SAAT;GAAiB,SAAA;GACf,UAAA,oBAAC,OAAO,MAAR;IACE,SAAQ;IACR,MAAK;IACL,UAAA;IACA,OAAO,EAAE,yBAAyB;IAClC,eAAY;IACZ,UAAU,CAAC;GACZ,CAAA;EACc,CAAA,GACjB,oBAAC,QAAQ,SAAT;GAAiB,YAAY,OAAO;GAElC,UAAA,qBAAC,KAAK,MAAN;IAAW,aAAY;IAAa,cAAa;IAAO,YAAW;IAAnE,UAAA;KACE,oBAAC,KAAK,SAAN;MAAc,UAAU;MAAI,YAAW;MAAsC,OAAM;MACjF,UAAA,oBAAC,WAAD,EAAiB,KAAO,CAAA;KACZ,CAAA;KACd,oBAAC,KAAK,SAAN;MAAc,UAAU;MAAI,YAAW;MAAsC,OAAM;MAChF,UAAA,WAAW,oBAAC,aAAD;OAAuB;OAAc;OAAa;MAAU,CAAA;KAC5D,CAAA;KACd,oBAAC,KAAK,SAAN;MAAc,UAAU;MAAI,YAAW;MAAsC,OAAM;MACjF,UAAA,oBAAC,iBAAD,EAAqB,GAAK,CAAA;KACd,CAAA;KACd,oBAAC,KAAK,SAAN;MAAc,UAAU;MAAI,YAAW;MAAsC,OAAM;MACjF,UAAA,oBAAC,aAAD;OAAsB;OAAiB;OAAwB;MAAiB,CAAA;KACpE,CAAA;KACd,oBAAC,KAAK,SAAN;MAAc,UAAU;MAAI,YAAW;MAAsC,OAAM;MACjF,UAAA,oBAAC,kBAAD,EAAwB,KAAO,CAAA;KACnB,CAAA;KACd,qBAAC,KAAK,MAAN;MAAW,YAAW;MAAtB,UAAA;OACE,oBAAC,KAAK,SAAN;QAAc,OAAM;QAAO,MAAK;QAAmB,OAAO,EAAE,iBAAiB;OAAI,CAAA;OACjF,oBAAC,KAAK,SAAN;QAAc,OAAM;QAAS,MAAK;QAAuB,OAAO,EAAE,sBAAsB;OAAI,CAAA;OAC5F,oBAAC,KAAK,SAAN;QAAc,OAAM;QAAc,MAAK;QAA+B,OAAO,EAAE,mBAAmB;OAAI,CAAA;OACtG,oBAAC,KAAK,SAAN;QACE,OAAM;QACN,MAAK;QACL,OAAO,EAAE,0BAA0B;QACnC,eAAY;OACb,CAAA;OACD,oBAAC,KAAK,SAAN;QACE,OAAM;QACN,MAAK;QACL,OAAO,EAAE,2BAA2B;OACrC,CAAA;MACQ;;IACF;;EACI,CAAA,CACL;CACH,CAAA,CAAA,EAAA,CAAA;AAEjB;AAEA,IAAM,eAAe,EAAE,UAAU,IAAI,cAAqE;CACxG,MAAM,EAAE,MAAM,QAAQ,eAAe,KAAK,QAAQ,GAAG;CAErD,MAAM,SAAS,UAAU;EAAE;EAAU;CAAG,CAAC;CACzC,MAAM,eAAe,gBAAgB,EAAE,QAAQ,CAAC;CAChD,MAAM,EAAE,kBAAkB,iBAAiB,EAAE,QAAQ,CAAC;CACtD,MAAM,EAAE,SAAS,iBAAiB,qBAAqB;EACrD,OAAO;EACP,UAAU,UAAU,MAAM;CAC5B,CAAC;CAED,OACE,oBAAC,WAAW,MAAZ;EAAiB,UAAU;EACzB,UAAA,qBAAC,WAAW,SAAZ;GAAoB,YAAW;GAA/B,UAAA,CAGE,oBAAC,WAAW,UAAZ;IAAqB,SAAS;IAC3B,UAAA,QAAQ,KAAK,UAAU;KACtB,MAAM,UAAU,WAAW,KAAK;KAChC,MAAM,WAAW,aAAa,IAAI,OAAO;KACzC,OACE,oBAAC,WAAW,MAAZ;MACE,YAAW;MAEX,OAAO;MACP,OAAO,MAAM;MACb,SAAS;MACT,gBAAgB,gBAAgB,OAAO,CAAC,QAAQ;KACjD,GALM,OAKN;IAEL,CAAC;GACkB,CAAA,GACrB,oBAAC,QAAQ,MAAT,EAAA,UACE,oBAAC,WAAW,OAAZ;IAAkB,aAAa,EAAE,oBAAoB;IAAG,YAAW;IAA4B,WAAA;GAAW,CAAA,EAC9F,CAAA,CACI;;CACL,CAAA;AAErB;AAEA,IAAM,aAAa,EAAE,WAA2C;CAC9D,MAAM,EAAE,MAAM,QAAQ,eAAe,KAAK,QAAQ,GAAG;CACrD,MAAM,CAAC,MAAM,WAAW,UAAU,MAAM,UAAU;CAClD,MAAM,QAAS,QAAiC;CAEhD,OACE,oBAAC,QAAQ,MAAT;EACS;EACP,eAAe;EACf,WAAA;EACA,OAAO,UAAU,UAAU,KAAK,UAAU;GACxC,OAAO;GACP,OAAO,EAAE,aAAa,KAAK,SAAS,EAAE,cAAc,KAAK,CAAC;EAC5D,EAAE;EAGF,UAAA,oBAAC,QAAQ,SAAT;GAAiB,QAAO;GAAO,cAAY,EAAE,iBAAiB;GAC3D,UAAA,UAAU,UAAU,KAAK,SACxB,qBAAC,QAAQ,MAAT;IAAyB,IAAI;IAAM,YAAW;IAA9C,UAAA,CACE,oBAAC,QAAQ,UAAT,EAAA,UAAmB,EAAE,aAAa,KAAK,SAAS,EAAE,cAAc,KAAK,CAAC,EAAoB,CAAA,GAC1F,oBAAC,QAAQ,eAAT,CAAwB,CAAA,CACZ;GAHK,GAAA,IAGL,CACf;EACc,CAAA;CACL,CAAA;AAElB;;;;;;;AAQA,IAAM,oBAAoB,EAAE,WAA2C;CACrE,MAAM,EAAE,MAAM,QAAQ,eAAe,KAAK,QAAQ,GAAG;CACrD,MAAM,CAAC,QAAQ,aAAa,UAAU,MAAM,QAAQ;CAKpD,MAAM,eAJS,MAAM,sBAAsB,mBAAmB,MAIzC,CAAA,EAAQ,OAAO,OAAO,SAAS,UAAU,MAAM,MAChE,oBACA,kBAAkB,QAAQ,gBAAgB,gBAAgB,QAAQ;CACtE,MAAM,QAAyB,SAAS,WAAW;CACnD,MAAM,eAAe,aAAa,UAAkB,UAAU,UAAU,QAAQ,GAAG,CAAC,SAAS,CAAC;CAE9F,OACE,oBAAC,QAAQ,MAAT;EACS;EACP,eAAe;EACf,WAAA;EACA,OAAO,aAAa,KAAK,iBAAiB;GACxC,OAAO;GACP,OAAO,EAAE,oBAAoB,YAAY,OAAO;EAClD,EAAE;EAGF,UAAA,oBAAC,QAAQ,SAAT;GAAiB,QAAO;GAAO,cAAY,EAAE,2BAA2B;GACrE,UAAA,aAAa,KAAK,gBACjB,qBAAC,QAAQ,MAAT;IAAgC,IAAI;IAAa,YAAW;IAA5D,UAAA,CACE,oBAAC,QAAQ,UAAT,EAAA,UAAmB,EAAE,oBAAoB,YAAY,OAAO,EAAoB,CAAA,GAChF,oBAAC,QAAQ,eAAT,CAAwB,CAAA,CACZ;GAHK,GAAA,WAGL,CACf;EACc,CAAA;CACL,CAAA;AAElB;AAEA,IAAM,oBAAoB,CAAC,SAAS,QAAQ;AAI5C,IAAM,eAAe,EACnB,SACA,QACA,qBACqE;CACrE,MAAM,EAAE,MAAM,QAAQ,eAAe,KAAK,QAAQ,GAAG;CAErD,OACE,qBAAC,OAAO,MAAR;EAAa,QAAA;EAAO,YAAW;EAA/B,UAAA,CACE,oBAAC,QAAQ,MAAT;GACE,OAAO;GACP,eAAe;GACf,WAAA;GACA,QAAQ,WAAW,CAAC,EAAA,CAAG,KAAK,EAAE,IAAI,aAAa;IAAE,OAAO;IAAW;GAAM,EAAE;GAE3E,UAAA,oBAAC,QAAQ,SAAT;IAAiB,QAAO;IAAO,cAAY,EAAE,0BAA0B;IAAG,eAAY;IACnF,UAAA,SAAS,KAAK,EAAE,IAAI,YACnB,qBAAC,QAAQ,MAAT;KAA2B;KAAI,YAAW;KAA2B,eAAa,oBAAoB;KAAtG,UAAA,CACE,oBAAC,QAAQ,UAAT,EAAA,UAAmB,MAAwB,CAAA,GAC3C,oBAAC,QAAQ,eAAT,CAAwB,CAAA,CACZ;IAHK,GAAA,EAGL,CACf;GACc,CAAA;EACL,CAAA,GACd,oBAAC,QAAQ,MAAT,EAAA,UACE,oBAAC,cAAD,CAAe,CAAA,EACH,CAAA,CACH;;AAEjB;;;;;;;;;AAUA,IAAM,qBAAqB;CACzB,MAAM,EAAE,MAAM,QAAQ,eAAe,KAAK,QAAQ,GAAG;CACrD,MAAM,CAAC,UAAU,eAAe,MAAM,uBAAuB,sBAAsB,QAAQ;CAC3F,MAAM,aAAa,MAAM,sBAAsB,sBAAsB,aAAa,MAAM,KAAA;CACxF,MAAM,SAAS,gBAAgB,SAAS,eAAe,UAAU,MAAM,SAAS,KAAK;CAErF,MAAM,eAAe,aAClB,YAAqB;EACpB,MAAM,WAAW,UAAU,SAAS,KAAK,KAAK,aAAa,SAAS,QAAQ,KAAK,SAAS,OAAO;EACjG,aAAa,aAAa;GAAE,GAAG;GAAS,eAAe;EAAS,EAAE;CACpE,GACA,CAAC,aAAa,UAAU,CAC1B;CAEA,OACE,oBAAC,MAAM,QAAP;EACE,SAAS;EACT,kBAAkB,EAAE,cAAc,aAAa,OAAO;EACtD,eAAY;EACZ,OAAO,EAAE,qBAAqB;CAC/B,CAAA;AAEL;AAaA,IAAM,mBAAmB,EAAE,SAA+B;CACxD,MAAM,EAAE,MAAM,QAAQ,eAAe,KAAK,QAAQ,GAAG;CACrD,MAAM,UAAU,SAAS,IAAI,OAAO,KAAK,UAAU,SAAS,CAAC;CAC7D,MAAM,CAAC,QAAQ,aAAa,SAAS,KAAK;CAE1C,MAAM,YAAY,aACf,EAAE,MAAM,KAAK,UAAU,aAA6B;EAGnD,MAAM,cAAc,SAChB,GAAG,IAAI,YAAY,KAAK;GAAE,QAAQ,IAAI,IAAI,GAAG,CAAC,CAAC;GAAU,SAAS;GAAM,OAAO;EAAO,CAAC,CAAC,IACxF,KAAA;EACJ,GAAG,IACD,IAAI,KAAK,UAAU,WAAW;GAC5B;GACA;GACA;GACA,SAAS;GACT,GAAI,eAAe,EAAE,aAAa,IAAI,KAAK,WAAW,EAAE;EAC1D,CAAC,CACH;EACA,UAAU,KAAK;CACjB,GACA,CAAC,EAAE,CACL;CAEA,MAAM,eAAe,aAClB,WAAgC;EAC/B,MAAM,cAAc,OAAO,aAAa,KAAK;EAC7C,GAAG,OAAO,MAAM;EAChB,IAAI,aACF,GAAG,OAAO,WAAW;CAEzB,GACA,CAAC,EAAE,CACL;CAEA,OACE,qBAAC,OAAO,MAAR;EAAa,QAAA;EAAO,eAAY;EAAhC,UAAA,CACE,oBAAC,QAAQ,MAAT;GAAc,OAAO,QAAQ,KAAK,YAAY;IAAE,OAAO,OAAO;IAAI,OAAO,OAAO,QAAQ,OAAO;GAAG,EAAE;GAClG,UAAA,oBAAC,QAAQ,SAAT;IAAiB,cAAY,EAAE,mBAAmB;IAAG,YAAW;IAC7D,UAAA,QAAQ,KAAK,WACZ,oBAAC,cAAD;KAAsC;KAAQ,UAAU;IAAe,GAApD,OAAO,EAA6C,CACxE;GACc,CAAA;EACL,CAAA,GACb,SACC,oBAAC,SAAD;GAAS,UAAU;GAAW,gBAAgB,UAAU,KAAK;EAAI,CAAA,IAEjE,oBAAC,OAAO,MAAR;GAAa,YAAW;GACtB,UAAA,oBAAC,OAAO,MAAR;IACE,SAAQ;IACR,MAAK;IACL,OAAO,EAAE,sBAAsB;IAC/B,eAAe,UAAU,IAAI;IAC7B,eAAY;GACb,CAAA;EACU,CAAA,CAEJ;;AAEjB;;;;;;AAYA,IAAM,gBAAgB,EAAE,QAAQ,eAAkC;CAChE,MAAM,EAAE,MAAM,QAAQ,eAAe,KAAK,QAAQ,GAAG;CACrD,MAAM,CAAC,SAAS,cAAc,UAAU,QAAQ,SAAS;CAEzD,UAAU,QAAQ,OAAO;CACzB,MAAM,CAAC,QAAQ,UAAU,QAAQ,MAAM;CACvC,MAAM,CAAC,OAAO,UAAU,QAAQ,KAAK;CACrC,MAAM,CAAC,UAAU,eAAe,SAAS,CAAC;CAC1C,MAAM,SAAS,mBAAmB,QAAQ;EAAE,SAAS,YAAY;EAAO;CAAS,CAAC;CAClF,MAAM,EAAE,QAAQ,SAAS,UAAU,mBAAmB,MAAM;CAC5D,MAAM,eAAe,kBAAkB;EACrC,OAAY,CAAC,CAAC,WAAW,aAAa,aAAa,WAAW,CAAC,CAAC;CAClE,GAAG,CAAC,MAAM,CAAC;CAEX,MAAM,cACJ,OAAO,UAAU,cACb,EAAE,+BAA+B,EAAE,OAAO,OAAO,MAAM,OAAO,CAAC,IAC/D,OAAO,UAAU,UACf,OAAO,UACP,EAAE,qBAAqB,OAAO,OAAO;CAE7C,OACE,qBAAC,QAAQ,MAAT;EAAc,IAAI,OAAO;EAAI,YAAW;EAAwC,eAAY;EAA5F,UAAA,CACE,qBAAC,OAAO,MAAR;GAAa,OAAM;GAAS,KAAI;GAAhC,UAAA;IACE,qBAAC,MAAM,MAAP,EAAA,UAAA,CACE,oBAAC,MAAM,OAAP;KAAa,QAAA;KAAQ,UAAA;IAAkB,CAAA,GACvC,oBAAC,MAAM,QAAP;KAAc,SAAS,YAAY;KAAO,kBAAkB,EAAE,cAAc,WAAW,CAAC,CAAC,OAAO;IAAI,CAAA,CAC1F,EAAA,CAAA;IACZ,qBAAC,OAAO,MAAR;KAAa,QAAA;KAAO,MAAA;KAAK,YAAW;KAApC,UAAA,CACE,oBAAC,QAAD;MAAM,WAAU;MAAoB,UAAA;KAAW,CAAA,GAC/C,oBAAC,QAAD;MAAM,WAAU;MAAkC,UAAA;KAAU,CAAA,CACjD;;IACZ,OAAO,UAAU,kBAChB,oBAAC,OAAO,MAAR;KACE,SAAQ;KACR,MAAK;KACL,OAAO,EAAE,0BAA0B;KACnC,UAAU;KACV,SAAS;KACT,eAAY;IACb,CAAA;KAED,OAAO,UAAU,WAAW,OAAO,UAAU,mBAC7C,oBAAC,OAAO,MAAR;KACE,SAAQ;KACR,MAAK;KACL,UAAA;KACA,OAAO,EAAE,wBAAwB;KACjC,eAAe,aAAa,aAAa,WAAW,CAAC;IACtD,CAAA;IAEH,oBAAC,OAAO,MAAR;KACE,SAAQ;KACR,MAAK;KACL,UAAA;KACA,OAAO,EAAE,yBAAyB;KAClC,eAAe,SAAS,MAAM;IAC/B,CAAA;GACU;EACb,CAAA,GAAA,oBAAC,QAAD;GACE,WAAW,GACT,oBACA,OAAO,UAAU,eAAe,sBAC/B,OAAO,UAAU,WAAW,OAAO,UAAU,kBAAkB,UAAU,iBAC5E;GACA,OAAO,SAAS;GAChB,eAAY;GACZ,cAAY,OAAO;GAElB,UAAA,SAAS;EACN,CAAA,CACM;;AAElB;AAOA,IAAM,WAAW,EAAE,UAAU,eAA6B;CACxD,MAAM,EAAE,MAAM,QAAQ,eAAe,KAAK,QAAQ,GAAG;CACrD,MAAM,CAAC,MAAM,WAAW,SAAS,EAAE;CACnC,MAAM,CAAC,KAAK,UAAU,SAAS,EAAE;CAEjC,MAAM,CAAC,UAAU,eAAe,SAAqC,MAAM;CAC3E,MAAM,CAAC,QAAQ,aAAa,SAAS,EAAE;CAEvC,MAAM,WAAW,IAAI,SAAS,IAAI,KAAK,CAAC;CACxC,MAAM,YAAY,KAAK,KAAK,CAAC,CAAC,SAAS,KAAK;CAC5C,MAAM,eAAe,kBAAkB;EACrC,IAAI,WACF,SAAS;GAAE,MAAM,KAAK,KAAK;GAAG,KAAK,IAAI,KAAK;GAAG;GAAU,QAAQ,OAAO,KAAK,KAAK,KAAA;EAAU,CAAC;CAEjG,GAAG;EAAC;EAAW;EAAM;EAAK;EAAU;EAAQ;CAAQ,CAAC;CAErD,OACE,qBAAC,QAAD;EACE,WAAU;EACV,WAAW,UAAU;GACnB,MAAM,eAAe;GACrB,aAAa;EACf;EALF,UAAA;GAOE,qBAAC,MAAM,MAAP,EAAA,UAAA,CACE,oBAAC,MAAM,OAAP;IAAa,QAAA;IAAQ,UAAA,EAAE,uBAAuB;GAAe,CAAA,GAC7D,oBAAC,MAAM,MAAP;IACE,aAAa,EAAE,6BAA6B;IAC5C,OAAO;IACP,WAAW,UAAU,QAAQ,MAAM,OAAO,KAAK;IAC/C,WAAA;IACA,eAAY;GACb,CAAA,CACS,EAAA,CAAA;GACZ,qBAAC,MAAM,MAAP,EAAA,UAAA,CACE,oBAAC,MAAM,OAAP;IAAa,QAAA;IAAQ,UAAA,EAAE,sBAAsB;GAAe,CAAA,GAC5D,oBAAC,MAAM,MAAP;IACE,MAAK;IACL,aAAa,EAAE,4BAA4B;IAC3C,OAAO;IACP,WAAW,UAAU,OAAO,MAAM,OAAO,KAAK;IAC9C,eAAY;GACb,CAAA,CACS,EAAA,CAAA;GACZ,qBAAC,OAAO,MAAR;IACE,OAAO,CAAC,QAAQ;IAChB,gBAAgB,EAAE,OAAO,CAAC,aAAa,YAAY,UAAU,QAAQ,QAAQ,MAAM;IACnF,OAAO,CACL;KAAE,OAAO;KAAQ,OAAO;IAAO,GAC/B;KAAE,OAAO;KAAO,OAAO;IAAM,CAC/B;IANF,UAAA,CAQE,oBAAC,OAAO,SAAR,EAAgB,aAAa,EAAE,2BAA2B,EAAI,CAAA,GAC9D,qBAAC,OAAO,SAAR,EAAA,UAAA,CACE,oBAAC,OAAO,MAAR,EAAa,MAAM;KAAE,OAAO;KAAQ,OAAO;IAAO,EAAI,CAAA,GACtD,oBAAC,OAAO,MAAR,EAAa,MAAM;KAAE,OAAO;KAAO,OAAO;IAAM,EAAI,CAAA,CACtC,EAAA,CAAA,CACL;;GACb,qBAAC,MAAM,MAAP,EAAA,UAAA,CACE,oBAAC,MAAM,OAAP;IAAa,QAAA;IAAQ,UAAA,EAAE,0BAA0B;GAAe,CAAA,GAChE,oBAAC,MAAM,UAAP;IACE,wBAAA;IACA,aAAa,EAAE,gCAAgC;IAC/C,OAAO;IACP,eAAe;IACf,eAAY;GACb,CAAA,CACS,EAAA,CAAA;GACZ,qBAAC,OAAO,MAAR;IAAa,SAAQ;IAArB,UAAA,CACE,oBAAC,aAAa,MAAd;KACE,MAAK;KACL,SAAQ;KACR,UAAU,CAAC;KACX,eAAY;IACb,CAAA,GACD,oBAAC,aAAa,QAAd;KAAqB,MAAK;KAAS,SAAQ;KAAQ,SAAS;IAAW,CAAA,CAC5D;;EACT;;AAEV;AAEA,IAAM,MAAM;;AAGZ,IAAa,gBAAgB,EAAE,IAAI,cAAqE;CACtG,MAAM,EAAE,MAAM,QAAQ,eAAe,KAAK,QAAQ,GAAG;CAGrD,MAAM,QAAQ,iBAAiB,EAAE;CACjC,MAAM,cAAc,cAAc;EAChC,MAAM,UAAU,MAAM,KAAK,SAAS;GAClC,MAAM,WAAW,KAAK,YAAY,IAAI;GACtC,OAAO;IACL,KAAK,KAAK,OAAO,IAAI;IACrB,OAAO,EAAE,kBAAkB;KAAE,IAAI;KAAU,cAAc;IAAS,CAAC;GACrE;EACF,CAAC;EAED,QAAQ,MAAM,GAAG,MAAM,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;EACrD,OAAO;CACT,GAAG,CAAC,OAAO,CAAC,CAAC;CAEb,MAAM,YAAY,cACV,CACJ;EAAE,OAAO;EAAK,OAAO,EAAE,uBAAuB;CAAE,GAChD,GAAG,YAAY,KAAK,EAAE,KAAK,aAAa;EAAE,OAAO;EAAK;CAAM,EAAE,CAChE,GACA,CAAC,aAAa,CAAC,CACjB;CAGA,MAAM,CAAC,aAAa,kBAAkB,SAA+B,GAAG;CACxE,MAAM,YAAY,cAAc,OAAO,GAAG,GAAG,YAAY,KAAK,EAAE,UAAU,OAAO,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC;CAG3G,MAAM,UAAU,SAAS,IAAI,gBAAgB,MAAM,YAAY,OAAO,KAAK,WAAW,CAAC;CACvF,MAAM,EAAE,SAAS,gBAAgB,mBAAmB,kBAAkB;EAAE;EAAI;CAAQ,CAAC;CACrF,MAAM,EAAE,SAAS,iBAAiB,qBAAqB;EACrD,OAAO;EACP,UAAU,WAAW,IAAI,SAAS,MAAM,KAAK,IAAI,YAAY,MAAM,KAAK,OAAO;CACjF,CAAC;CAED,OACE,oBAAC,OAAO,MAAR;EAAa,QAAA;EAAO,YAAW;EAE7B,UAAA,qBAAC,WAAW,MAAZ;GAAiB,UAAU;GAA3B,UAAA,CAGE,oBAAC,WAAW,SAAZ;IAAoB,YAAW;IAC7B,UAAA,oBAAC,WAAW,UAAZ;KAAqB,SAAS;KAAO,YAAW;KAC7C,UAAA,QAAQ,SACP,QAAQ,KAAK,WAAW;MACtB,MAAM,WAAW,eAAe,WAAW,QAAQ,IAAI,OAAO,OAAO,EAAE,MAAM;MAC7E,MAAM,EAAE,MAAM,QAAQ,IAAI,QAAQ,MAAM,KAAK;OAAE,MAAM;OAAqB,KAAK,KAAA;MAAU;MACzF,MAAM,SAAS,MAAM,UAAU,GAAG,IAAI,KAAA;MACtC,OACE,oBAAC,WAAW,MAAZ;OACE,YAAW;OAEX,OAAO,OAAO;OACR;OACN,gBAAgB,QAAQ;OACxB,OAAO,IAAI,SAAS,MAAM,KAAK,IAAI,YAAY,MAAM,KAAK,OAAO;OACjE,SAAS;OACT,gBAAgB,iBAAiB,IAAI,OAAO,MAAM,GAAG,CAAC,QAAQ;MAC/D,GAPM,OAAO,EAOb;KAEL,CAAC,IAED,oBAAC,WAAW,MAAZ;MAAiB,OAAM;MAAY,OAAO,EAAE,oBAAoB;KAAI,CAAA;IAEnD,CAAA;GACH,CAAA,GAEpB,qBAAC,QAAQ,MAAT,EAAA,UAAA,CACE,oBAAC,WAAW,OAAZ;IAAkB,aAAa,EAAE,oBAAoB;IAAG,WAAA;GAAW,CAAA,GACnE,qBAAC,OAAO,MAAR;IACE,OAAO;IACP,OAAO,gBAAgB,MAAM,CAAC,IAAI,CAAC,WAAW;IAC9C,gBAAgB,EAAE,OAAO,CAAC,aACxB,eAAe,YAAY,MAAM,EAAE,UAAU,QAAQ,KAAK,CAAC,EAAE,OAAO,GAAG;IAJ3E,UAAA,CAOE,oBAAC,OAAO,SAAR;KAAgB,OAAA;KAAM,aAAa,EAAE,yBAAyB;IAAI,CAAA,GAClE,oBAAC,OAAO,SAAR,EAAA,UACG,UAAU,KAAK,SACd,oBAAC,OAAO,MAAR,EAAoC,KAAO,GAAzB,KAAK,KAAoB,CAC5C,EACa,CAAA,CACL;GACD,CAAA,CAAA,EAAA,CAAA,CACC;;CACN,CAAA;AAEjB;;;AChnBA,IAAa,kBAAkB,EAAE,YAAY,SAAS,SAA8B;CAClF,MAAM,EAAE,MAAM,QAAM,eAAe,KAAK,QAAQ,GAAG;CACnD,MAAM,EAAE,SAAS,mBAAmB,kBAAkB;EAAE;EAAI;CAAQ,CAAC;CAErE,OACE,oBAAC,MAAD;EAAI,WAAW,GAAG,cAAc,UAAU;EACvC,UAAA,QAAQ,KAAK,QAAQ;GACpB,MAAM,MAAM,IAAI,OAAO,GAAG;GAC1B,MAAM,WAAW,IAAI,YAAY,GAAG;GACpC,MAAM,QACJ,IAAI,SAAS,GAAG,MAAM,WAAW,CAAC,2BAA2B,EAAE,IAAI,SAAS,CAAC,IAAI,IAAI;GACvF,MAAM,EAAE,MAAM,QAAQ,IAAI,QAAQ,GAAG,KAAK;IAAE,MAAM;IAAqB,KAAK,KAAA;GAAU;GACvE,OAAM,UAAU,GAAG;GAClC,OACE,qBAAC,MAAD;IAAyB,WAAU;IAAoD,YAAS;IAAhG,UAAA;KACE,oBAAC,KAAK,MAAN;MAAiB;MAAM,MAAK;KAAM,CAAA;KACjC,MAAM,kBAAkB,OAAO,CAAC;KACjC,oBAAC,OAAO,MAAR;MACE,MAAK;MACL,UAAA;MACA,SAAQ;MACR,OAAO,EAAE,qBAAqB;MAC9B,YAAW;MACX,UAAS;MACT,eAAe,iBAAiB,KAAK,KAAK;KAC3C,CAAA;IACC;GAZK,GAAA,IAAI,SAAS,CAYlB;EAER,CAAC;CACC,CAAA;AAER;AAGA,IAAM,sBAAsB;;;;ACrC5B,IAAM,uBAAuB;;;;;;AAO7B,IAAa,qBAAqB,OAAe,cAA4D;CAC3G,MAAM,EAAE,MAAM,QAAQ,eAAe,KAAK,QAAQ,GAAG;CAErD,MAAM,CAAC,SAAS,cAAc,MAAM,+BAA+B,0BAA0B,gBAAgB;CAC7G,MAAM,CAAC,YAAY,MAAM,+BAA+B,0BAA0B,QAAQ;CAC1F,MAAM,WAAW,uBAAuB,gBAAgB,aAAa;CAErE,MAAM,SAAS,CAAC,CAAC,SAAS,aAAa,QAAQ,OAAO;CAEtD,MAAM,cAAc,OAAmC,IAAI;CAG3D,MAAM,YAAY,OAA2B,KAAA,CAAS;CACtD,MAAM,aAAa,OAAO,KAAK;CAG/B,gBAAgB;EACd,IAAI,CAAC,QACH;EAEF,MAAM,OAAO,UAAU,SAAS;EAChC,IAAI,CAAC,MACH;EAGF,MAAM,WAAW,IAAI,oBAAoB,sBAAsB,IAAI,GAAG;GAGpE,MAAM,UAAU,cAAc;GAC9B,gBAAgB,UAAU,kBAAkB;EAC9C,CAAC;EAMD,UAAU,UAAU,KAAK,MAAM,UAAU,KAAK;EAC9C,WAAW,UAAU;EACrB,YAAY,UAAU;EAEtB,aAAa;GACX,SAAS,QAAQ;GACjB,YAAY,UAAU;GACtB,WAAW,UAAU;GAErB,MAAM,cAAc,UAAU,SAAS;GACvC,IAAI,aAAa;IACf,MAAM,UAAU,YAAY,MAAM,MAAM,kBAAkB,KAAK;IAC/D,IAAI,WAAW,QAAQ,MAAM,WAAW,GACtC,YAAY,SAAS,EAAE,SAAS,kBAAkB,GAAG,EAAE,CAAC;GAE5D;EACF;CACF,GAAG;EAAC;EAAQ,UAAU;EAAY,UAAU;CAAc,CAAC;CAE3D,MAAM,iBAAiB,YAAY,OAAO,aAAwC;EAChF,MAAM,OAAO,SACV,KAAK,YAAY,QAAQ,IAAI,CAAA,CAC7B,KAAK,GAAG,CAAA,CACR,KAAK;EACR,IAAI,KAAK,SAAS,GAAG;GACnB,IAAI,CAAC,WAAW,SAAS;IACvB,WAAW,UAAU;IAErB,YAAY,SAAS,MAAM,EAAE,QAAQ,UAAU,QAAQ,CAAC;GAC1D;GACA,YAAY,SAAS,KAAK,IAAI;EAChC;CACF,GAAG,CAAC,CAAC;CAGL,MAAM,oBAAoB,eACjB;EACL,6BAA6B,KAAK,IAChC,GACA,KAAK,OAAO,UAAU,qBAAqB,OAAQ,oBAAoB,CACzE;EACA;CACF,IACA,CAAC,UAAU,mBAAmB,QAAQ,CACxC;CAGA,MAAM,iBAAiB,eAAe,EAAE,UAAU,qBAAqB,IAAI,CAAC,CAAC;CAE7E,MAAM,mBAAmB,cAIrB,UAAU,iBAAiB,CAAC,mBAAmB,SAAS,aAAa,IACjE,EAAE,UAAU,EAAE,OAAO,SAAS,cAAc,EAAE,IAC9C,KAAA,GACN,CAAC,UAAU,aAAa,CAC1B;CAKA,MAAM,QAAQ,cAAc,UAAU,CAAC,CAAC,UAAU,gBAAgB;CAElE,MAAM,cAAc,eAAe;EACjC,kBAAkB;EAClB;EACA;EACA,YAAY;CACd,CAAC;CAKD,gBAAgB;EACd,IAAI,CAAC,aACH;EAEF,IAAI,YAAY;EAChB,YAAiB,KAAK,CAAC,CAAC,WAChB;GACJ,IAAI,CAAC,aAAa,QAChB,YAAY,qBAAqB;EAErC,IACC,QAAQ;GAGP,IAAI,CAAC,WAAW;IACd,IAAI,MAAM,KAAE,KAAA,GAAA;KAAA,YAAA;KAAA,GAAA;KAAA,GAAA;KAAA,GAAA,KAAA;IAAA,CAAC;IACb,mBAAmB,IAAI;GACzB;EACF,CACF;EAEA,aAAa;GACX,YAAY;EACd;CACF,GAAG;EAAC;EAAa;EAAQ;CAAU,CAAC;AACtC;ACnFA,IAAa,gBAAc,EACzB,YACA,SACA,IACA,MACA,WACA,OACA,cACA,cACA,eACA,QACA,aACA,YAAY,MACZ,YAAY,GACZ,WAAA,GACA,WAAW,MACX,SACA,QACA,aACA,qBACqB;CACrB,MAAM,EAAE,MAAM,QAAM,eAAe,KAAK,QAAQ,GAAG;CACnD,MAAM,iBAAiB,kBAAkB,SAAS;CAClD,MAAM,QAAQ,aAAa,eAAe,KAAK,CAAC,CAAC,KAAK,OAAO,cAAc;CAC3E,MAAM,YAAY,aAAa,eAAe,SAAS;CACvD,MAAM,SAAS,aAAa,eAAe,MAAM;CAEjD,MAAM,YAAY,OAA6B,IAAI;CACnD,gBAAgB;EACd,OAAO,MAAM,IAAI,OAAO;GACtB,IAAI,GAAG,SAAS,mBAAmB,CAAC,UAAU,SAAS,QAAQ,CAAC,EAAE,QAAQ;IACxE,UAAU,SAAS,QAAQ,GAAG,IAAI;IAClC,UAAU,SAAS,MAAM;GAC3B;EACF,CAAC;CACH,GAAG,CAAC,KAAK,CAAC;CAEV,MAAM,gBAAgB,MAAM;CAK5B,kBADc,WAAW,OAAO,IAAI,OAAO,IAAI,IAAI,gBAC1B,SAAS;CAElC,MAAM,mBAAmB,wBAAwB,EAAE,MAAM,CAAC;CAI1D,MAAM,CAAC,aAAa,UAAU,WAAW;CACzC,MAAM,CAAC,gBAAgB,UAAU,IAAI,WAAW,QAAQ,SAAS,SAAS,IAAI,UAAU,eAAe,KAAA,CAAS;CAChH,MAAM,cAAc,QAAM,cAAc,cAAc,YAAY,CAAC,CAAC;CACpE,MAAM,oBAAoB,cAEtB,SAAS,EACP,mBAAmB,CACjB,GAAG,YAAY,QAAQ,KAAK,EAAE,UAAU,mBAAmB;EAAE;EAAU;CAAY,EAAE,GACrF,GAAG,kBAAkB,KAAK,EAAE,SAAS,mBAAmB;EAAE,UAAU;EAAS;CAAY,EAAE,CAC7F,EACF,CAAC,GACH,CAAC,WAAW,CACd;CAOA,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,MAAM,qBAAqB,cAEvB,WAAW,eAAe,IAAI,WAAW;EACvC,IAAI,OAAO,YACT,WAAW,OAAO,MAAM,IAAI,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC;CAE5D,CAAC,GACH,CAAC,CACH;CAGA,MAAM,YAAY,UAAU,aAAa;CACzC,MAAM,UAAU,WAAW,aAAa,QAAQ,CAAC;CAEjD,MAAM,aAAa,cACX;EAAC;EAAkB,YAAY;EAAG;EAAmB;CAAkB,GAC7E;EAAC;EAAkB;EAAmB;CAAkB,CAC1D;CAKA,MAAM,eAAe,aAClB,SAAS;EACR,IAAI,CAAC,aAAa,WAChB,OAAO;EAET,MAAM,KAAK;GAAE,MAAM;GAAU;EAAK,CAAC;EACnC,OAAO;CACT,GACA;EAAC;EAAO;EAAW;CAAS,CAC9B;CAIA,MAAM,aAAa,kBAAkB;EACnC,MAAM,OAAO,UAAU,SAAS,QAAQ,CAAC,CAAC,KAAK;EAC/C,IAAI,CAAC,MAAM,QACT;EAEF,IAAI,aAAa,IAAI,GACnB,UAAU,SAAS,QAAQ,IAAI,IAAI;CAEvC,GAAG,CAAC,YAAY,CAAC;CAEjB,MAAM,cAAc,aACjB,OAAO;EACN,MAAM,KAAK,EAAE;CACf,GACA,CAAC,KAAK,CACR;CAEA,OACE,qBAAC,OAAD;EACE,eAAY;EACZ,MAAK;EACL,WAAW,GACT,sCACA,WACE,uIACF,UACF;EARF,UAAA;GAUG,aAAa,oBAAC,eAAD,EAA0B,UAAY,CAAA;GAEpD,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,oBAAC,qBAAD;KAAqB,YAAW;KAAc;KAAe;KAAO,YAAY;IAAY,CAAA,GAC5F,oBAAC,YAAD;KACE,KAAK;KACM;KACX,UAAA;KACA,cAAA;KACA,YAAW;KACX,aAAa,eAAe,EAAE,oBAAoB;KACtC;KACZ,UAAU;IACX,CAAA,CACE;;GAEJ,MACC,YAEE,oBAAC,aAAD;IACE,YAAW;IACG;IACC;IAGf,YAAY;IACH;IACK;IACd,QAAQ;IACR,SAAS;IACT,SACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,aAAD;KACM;KACE;KACN,UAAU,WAAW;KACrB,SAAS,WAAW;KACZ;KACC;KACO;IACjB,CAAA,GACD,oBAAC,OAAD;KAAK,WAAU;KACZ,UAAA,aAAa,oBAAC,gBAAD;MAAoB;MAAI,SAAS,UAAU;KAAU,CAAA;IAChE,CAAA,CACL,EAAA,CAAA;GAEL,CAAA;EAEF;;AAET;AAEA,aAAW,cAAc;;;ACtPzB,IAAM,0BAA0B;AAChC,IAAM,UAAU;;;;;;;;;;;;;;AAoChB,IAAa,gBAAc,EAAE,YAAY,WAAkC;CAMzE,MAAM,EAAE,UAAU,eAAe,QAAQ,cAAc,qBAAqB,uBAAuB;CAEnG,MAAM,EAAE,kBAAkB,uBAAuB,cAAc;EAC7D,IAAI;EACJ,IAAI,QAAQ;EACZ,KAAK,MAAM,WAAW,UACpB,KAAK,MAAM,SAAS,QAAQ,QAC1B,IAAI,QAAQ,KAAK,KAAK,MAAM,OAAO;GACjC,OAAO,MAAM,MAAM;GACnB,SAAS,MAAM,MAAM,eAAe;EACtC;EAIJ,OAAO;GAAE,kBAAkB;GAAM,oBAAoB;EAAM;CAC7D,GAAG,CAAC,QAAQ,CAAC;CAEb,MAAM,YAAY,OAAO,GAAG,CAAC;CAE7B,OACE,oBAAC,gBAAD;EACc;EACN;EACS;EACG;EACE;EAEpB,OAAO,aAAa;GAAE,QAAQ,UAAU;GAAQ,SAAS,UAAU;EAAQ;EAChE;CACZ,CAAA;AAEL;;;;;AAMA,IAAa,kBAAkB,EAC7B,YACA,MACA,eACA,kBACA,qBAAqB,GACrB,OACA,YAAY,QACa;CACzB,MAAM,YAAY,iBAAiB,QAAQ,cAAc,WAAW;CACpE,MAAM,OAAO,iBAAiB,oBAAoB,qBAAqB,KAAK,SAAS;CACrF,IAAI,CAAC,MACH,OAAO;CAGT,OACE,qBAAC,WAAkB,MAAnB;EAAwB,gBAAgB;EAAO,YAAY,CAAC,uBAAuB,UAAU;EAA7F,UAAA,CACG,QACC,oBAAC,WAAkB,MAAnB,EAAA,UACE,oBAAC,QAAD;GACE,YAAW;GACX,eAAc;GACd,KAAK;GACL,SAAS;GACT,OAAO;GACP,UAAU;GACV,QAAQ;EACT,CAAA,EACqB,CAAA,GAEzB,QACC,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACG,iBACC,oBAAC,WAAkB,MAAnB;KAAwB,YAAY,aAAa;KAC/C,UAAA,oBAAC,SAAD,EAAS,QAAQ,cAAgB,CAAA;IACX,CAAA;IAEzB,oBAAoB,QACnB,qBAAA,YAAA,EAAA,UAAA,CACG,iBAAiB,oBAAC,WAAkB,WAAnB,CAA8B,CAAA,GAChD,qBAAC,WAAkB,MAAnB,EAAA,UAAA,CAAwB,MAAG,KAAK,SAAS,gBAAgB,CAAC,CAAC,SAAS,CAA0B,EAAA,CAAA,CAC9F,EAAA,CAAA;IAEH,qBAAqB,KACpB,qBAAA,YAAA,EAAA,UAAA,EACI,iBAAiB,oBAAoB,SAAS,oBAAC,WAAkB,WAAnB,CAA8B,CAAA,GAC9E,qBAAC,WAAkB,MAAnB,EAAA,UAAA,CAAwB,MAAG,KAAK,SAAS,kBAAkB,CAAC,CAAC,SAAS,CAA0B,EAAA,CAAA,CAChG,EAAA,CAAA;IAEH,SACC,qBAAA,YAAA,EAAA,UAAA,EACI,iBAAiB,oBAAoB,QAAQ,qBAAqB,MAAM,oBAAC,WAAkB,WAAnB,CAA8B,CAAA,GACxG,oBAAC,WAAkB,MAAnB,EAAA,UACE,qBAAC,QAAD;KACE,eAAY;KACZ,WAAU;KACV,OAAO,MAAM;KAHf,UAAA;MAKE,oBAAC,KAAK,MAAN;OAAW,MAAK;OAAqB,MAAK;MAAM,CAAA;MAC/C,aAAa,MAAM,MAAM;MACzB,YAAY,KACX,qBAAC,QAAD;OAAM,eAAY;OAAmC,WAAU;OAA/D,UAAA;QACG;QAAU;QAAE,MAAM;OACf;;KAEJ;IACgB,CAAA,EAAA,CAAA,CACxB,EAAA,CAAA;GAED;EAEe,CAAA,CAAA;;AAE5B;;;;;;AAOA,IAAM,WAAW,EAAE,aAA4C;CAC7D,MAAM,YAAY,OAAO,WAAW;CACpC,MAAM,CAAC,KAAK,UAAU,SAAS,KAAK,IAAI,CAAC;CACzC,gBAAgB;EACd,IAAI,CAAC,WACH;EAGF,MAAM,KAAK,kBAAkB,OAAO,KAAK,IAAI,CAAC,GAAG,OAAO;EACxD,aAAa,cAAc,EAAE;CAC/B,GAAG,CAAC,SAAS,CAAC;CAEd,OAAO,oBAAA,YAAA,EAAA,UAAG,eAAe,OAAO,WAAW,OAAO,OAAO,SAAS,EAAI,CAAA;AACxE;AAEA,IAAM,WAAW,UAAyD,MAAM,SAAS;;;;;AAMzF,IAAa,gBAAgB,WAC3B,IAAI,KAAK,MAAM,CAAC,CAAC,mBAAmB,KAAA,GAAW;CAAE,MAAM;CAAW,QAAQ;AAAU,CAAC;;;;;;;;AC1KvF,IAAa,cAAc,EAAE,IAAI,KAAK,YAA6B;CACjE,MAAM,MAAM,cAAe,MAAM,MAAI,KAAK,GAAG,IAAI,KAAA,GAAY,CAAC,GAAG,CAAC;CAClE,MAAM,MAAM,cAAe,OAAO,KAAK,GAAG,QAAqB,GAAG,IAAI,KAAA,GAAY,CAAC,KAAK,EAAE,CAAC;CAC3F,MAAM,SAAS,cAAc,GAAG;CAChC,MAAM,CAAC,WAAW,UAAU,MAAM;CAClC,IAAI,CAAC,SACH,OAAO;CAGT,MAAM,QAAQ,IAAI,SAAS,OAAO,CAAC,EAAE,KAAK,KAAK,SAAS;CACxD,OACE,qBAAC,kBAAkB,MAAnB,EAAA,UAAA,CACE,oBAAC,kBAAkB,QAAnB;EAAmC;EAAS,OAAO;EAChD,UAAA;CACuB,CAAA,GAC1B,oBAAC,QAAQ,SAAT;EAAiB,MAAM,WAAW;EAAa,MAAM,EAAE,QAAQ;EAAG,OAAO;CAAI,CAAA,CACvD,EAAA,CAAA;AAE5B;AAEA,WAAW,cAAc;;AAKzB,IAAa,oBAAoB,EAAE,IAAI,KAAK,YAC1C,oBAAC,YAAD;CAAgB;CAAS;CAAY;AAAQ,CAAA;AAG/C,iBAAiB,cAAc;;AAG/B,IAAM,wBAAwB;;AAG9B,IAAa,oBAAoB,QAAwD;CACvF,OAAO;CACP,uBAAuB;CACvB,YAAY;CACZ,YAAY,UAAU,oBAAC,kBAAD;EAAkB,GAAI;EAAW;CAAK,CAAA;AAC9D;;;;;;;;;ACnDA,IAAa,iBAAiB,EAAE,MAAM,eAA+C;CACnF,MAAM,OAAO,cAAc;EACzB,MAAM,MAAM,gBAAgB,YAAY,CAAC,CAAC;EAC1C,IAAI,CAAC,KACH;EAEF,IAAI;GACF,MAAM,SAAkB,KAAK,MAAM,GAAG;GAEtC,OAAO,UAAU,QAAQ,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,IACvE,SACD,KAAA;EACN,SAAS,KAAK;GACZ,IAAI,KAAK,gCAAgC;IAAE;IAAK;GAAI,GAAA;IAAA,YAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA,KAAA;GAAA,CAAC;GACrD;EACF;CACF,GAAG,CAAC,QAAQ,CAAC;CAEb,IAAI,CAAC,MACH,OAAO;CAGT,OAAO,oBAAC,QAAQ,SAAT;EAAiB,MAAM,YAAY;EAAa,MAAM;GAAE;GAAM;EAAK;EAAG,OAAO;CAAI,CAAA;AAC1F;;;;ACsDA,IAAM,YAAY,EAChB,UACA,MACA,WACA,IAAI,YACJ,OAAO,WACP,SACA,UACA,YACA,GAAG,YACgB;CACnB,MAAM,CAAC,OAAO,YAAY,SAAS,aAAa,KAAK;CAErD,MAAM,EAAE,kBAAkB,MAAM,oBAAoB;CACpD,MAAM,iBAAiB,kBAAkB,SAAS;CAClD,MAAM,YAAY,aAAa,eAAe,SAAS;CACvD,MAAM,SAAS,aAAa,eAAe,MAAM;CACjD,MAAM,gBAAgB,iBAAiB,EAAE,OAAO,CAAC;CACjD,MAAM,aAAa,OAA2B,KAAA,CAAS;CAEvD,MAAM,iBAAiB,OAAO,KAAK;CAGnC,MAAM,KAAM,QAAQ,IAAI,YAAY,IAAI,KAAM;CAG9C,MAAM,CAAC,gBAAgB,UAAU,MAAM,IAAI;CAC3C,MAAM,OAAO,IAAI,uBAAuB,YAAY;CAGpD,MAAM,QAAQ,cAAc,IAAI,MAAiB,GAAG,CAAC,CAAC;CAItD,MAAM,CAAC,YAAY,iBAAiB,SAAsC,IAAI;CAC9E,MAAM,CAAC,cAAc,mBAAmB,SAAmC,KAAA,CAAS;CAEpF,MAAM,aAAa,SACjB,IACA,OAAO,MAAM,OAAO,OAAO,KAAK,MAAM,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,MAAM,OAAO,OAAO,QAAQ,CAAC,CAC1F;CAEA,MAAM,EAAE,UAAU,UAAU,QAAQ,SAAS,aAAa,eAAe,MAAM;CAC/E,MAAM,SAAS,cAAc,cAAc,EAAE,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC;CACxE,MAAM,YAAY,cAAc,iBAAiB;EAAE;EAAY;CAAS,CAAC,GAAG,CAAC,YAAY,QAAQ,CAAC;CAElG,MAAM,OAAO,SAAS,EAAE,UAAU,CAAC;CAGnC,MAAM,QAAQ,aAAa,eAAe,KAAK;CAC/C,gBAAgB;EACd,IAAI,OAAO,OAAO,KAAK,GACrB,MAAM,KAAK;GAAE,MAAM;GAAS,OAAO,MAAM;EAAM,CAAC;CAEpD,GAAG,CAAC,OAAO,KAAK,CAAC;CAEjB,gBAAgB;EACd,OAAO,MAAM,IAAI,OAAO;GACtB,QAAQ,GAAG,MAAX;IACE,KAAK;KACH,UAAU,UAAU;MAClB,IAAI,OACF,OAAO;WACF;OACL,KAAU;OACV,OAAO;MACT;KACF,CAAC;KACD;IAGF,KAAK,UAAU;KAMb,MAAM,SAAS,QAAQ,cAAc,UAAU,GAAG,EAAE;KACpD,IAAI,QAAQ;MACV,IAAI,OAAO,OAAO,SAAS;OACzB,KAAK,aAAa,SAAS,IAAI,OAAO,UAAU,CAAC,EAAE,UAAU,OAAO;MACtE,CAAC;MACD,MAAM,KAAK;OAAE,MAAM;OAAiB,MAAM,OAAO;MAAK,CAAC;KACzD;KACA;IACF;IAEA,KAAK,iBAAiB;KAGpB,MAAM,MAAM,SAAS,IAAI,GAAG,EAAE;KAC9B,IAAI,KAAK,WAAW,YAAY,KAAK,WAAW,aAAa;MAC3D,IAAI,IAAI,WAAW,MAAM,MACvB,GAAQ,qBAAqB,MAAM,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,QAAQ,IAAI,MAAM,KAAE,KAAA,GAAA;OAAA,YAAA;OAAA,GAAA;OAAA,GAAA;OAAA,GAAA,KAAA;MAAA,CAAC,CAAC;MAEjF,IAAI,IAAI,UACN,WAAW,aAAa,IAAI,QAAQ;KAExC;KACA;IACF;GACF;GAEA,UAAU,EAAE;EACd,CAAC;CAGH,GAAG;EAAC;EAAO;EAAM;EAAS;EAAI;EAAM;EAAU;EAAU;CAAS,CAAC;CAElE,gBAAgB;EACd,OAAO,MAAM,IAAI,OAAO;GACtB,IAAI,GAAG,SAAS,aAAa,CAAC,MAC5B;GAEF,MAAM,EAAE,WAAW,WAAW,aAAa;GAE3C,MAAM,UAAU,IAAI,YAAY,IAAI,CAAC,EAAE;GACvC,cACE,mBAAmB,kBACnB;IAAE;IAAM;IAAW;IAAW;GAAS,GACvC,UAAU,EAAE,QAAQ,IAAI,KAAA,CAC1B,CAAC,CAAC,MAAM,EAAE,YAAY;IACpB,IAAI,OACF,MAAM,KAAK;KAAE,MAAM;KAAS;IAAM,CAAC;GAEvC,CAAC;EACH,CAAC;CACH,GAAG;EAAC;EAAO;EAAM;CAAa,CAAC;CAE/B,gBAAgB;EACd,IAAI,CAAC,WACH;EAGF,OAAO,MAAM,IAAI,OAAO;GACtB,QAAQ,GAAG,MAAX;IACE,KAAK,UAAU;KACb,MAAM,OAAO,GAAG,KAAK,KAAK;KAC1B,IAAI,KAAK,QAAQ;MAGf,MAAM,WAAW,aAAa,oBAAoB,MAAM,iBAAiB;MACzE,IAAI,UAAU;OAGZ,IAAI,eAAe,SACjB;OAEF,eAAe,UAAU;OAGzB,CAAM,YAAY;QAChB,MAAM,QAAQ,QAAQ,WAAW,IAAI,CAAC;QAGtC,MAAM,YAAa,QAAQ,IAAI,YAAY,IAAI,KAAM;QACrD,IAAI,CAAC,QAAQ,CAAC,WACZ,MAAM,IAAI,MAAM,oCAAoC;QAGtD,MAAM,SAAS,MAAM,SAAS,QAAQ,QAAQ,SAAS,MAAM;SAC3D,IAAI;SACJ;SACA,QAAQ;QACV,CAAC;QACD,IAAI,kBAAkB,OACpB,MAAM;QAMR,MAAM,cAAc,QAAQ,KAAK,MAAM;QACvC,IAAI,eAAe,OAAO,SACxB,MAAM,UAAU,aAAa,aAAa,CACxC,QAAQ,KAAK;SAAE,QAAQ,EAAE,MAAM,OAAO;SAAG,QAAQ,CAAC;UAAE,MAAM;UAAQ;SAAK,CAAC;QAAE,CAAC,GAC3E,QAAQ,KAAK;SAAE,QAAQ,EAAE,MAAM,YAAY;SAAG,QAAQ,CAAC;UAAE,MAAM;UAAQ,MAAM,OAAO;SAAQ,CAAC;QAAE,CAAC,CAClG,CAAC;QAGH,IAAI,OAAO,UAGT,UAAe,QAAQ,EAAE,SAAS,OAAO,SAAS,CAAC;OAEvD,EAAA,CAAG,CAAA,CACA,OAAO,UAAU;QAChB,MAAM,KAAK;SAAE,MAAM;SAAS,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;QAAE,CAAC;OAChG,CAAC,CAAA,CACA,cAAc;QACb,eAAe,UAAU;OAC3B,CAAC;OACH;MACF;MAEA,IAAI,UAAU,UAAA,GACZ;MAEF,SAAS,aAAa;MACtB,WAAW,UAAU,GAAG;MAIxB,UAAU,KAAK;OAAE,SAAS;OAAM,SAAS,aAAa;MAAE,GAAG,EAAE,eAAe,WAAW,IAAI,EAAE,CAAC;KAChG;KACA;IACF;IAEA,KAAK,UAAU;KACb,MAAM,OAAO,GAAG,KAAK,KAAK;KAC1B,IAAI,KAAK,QAGP,QAAa,QAAQ,WAAW,IAAI,CAAC,CAAC,CAAC,WACrC,SACI,UAAU,QAAQ;MAAE,SAAS;MAAM,aAAa;KAAY,CAAC,IAC7D,UAAU,QAAQ;MAAE,SAAS;MAAM,aAAa;KAAY,CAAC,CACnE;KAEF;IACF;IAEA,KAAK;KACH,IAAI,CAAC,WACH,UAAe,MAAM;KAEvB;IAGF,KAAK;KACH,UAAe,OAAO;KACtB,IAAI,WACE;UAAA,WAAW,SACb,MAAM,KAAK;OAAE,MAAM;OAAiB,MAAM,WAAW;MAAQ,CAAC;KAAA;GAKtE;EACF,CAAC;CACH,GAAG;EAAC;EAAO;EAAW;EAAW;EAAQ;EAAQ;EAAU;EAAY;EAAe;EAAM;EAAI;CAAI,CAAC;CAIrG,MAAM,eAAe,aAAa,SAAiB,MAAM,KAAK;EAAE,MAAM;EAAU;CAAK,CAAC,GAAG,CAAC,KAAK,CAAC;CAEhG,OACE,oBAAC,qBAAD;EACS;EACA;EACH;EACE;EACK;EACX,WAAW;EACI;EACE;EACjB,GAAI;EAEJ,UAAA,oBAAC,2BAAD;GACY;GACJ;GACE;GACG;GACI;GACH;GACE;GAEd,UAAA,oBAAC,2BAAD;IAA2B,QAAQ;IAAe;GAAoC,CAAA;EAC7D,CAAA;CACR,CAAA;AAEzB;AAEA,SAAS,cAAc;AAEvB,IAAM,oBAAoB,EAAE,aAAkC;CAC5D,MAAM,CAAC,eAAe,oBAAoB,SAAmC,IAAI;CACjF,gBAAgB;EACd,IAAI,QACF,iBAAiB;GAAE,WAAW,KAAK,IAAI;GAAG,SAAS;EAAK,CAAC;OAEzD,kBAAkB,SAAU,QAAQ,KAAK,WAAW,OAAO;GAAE,GAAG;GAAM,SAAS,KAAK,IAAI;EAAE,IAAI,IAAK;CAEvG,GAAG,CAAC,MAAM,CAAC;CAEX,OAAO;AACT;AAMA,IAAM,oBAAoB;AAS1B,IAAM,cAAc,KAAK,YACtB,EAAE,UAAU,cAAc,cAAc,aAAa,UAAU,GAAG,SAAS,iBAAiB;CAC3F,MAAM,EAAE,SAAS,eAAe,iBAAiB;CACjD,MAAM,cAAc,sBAAsB;EAAE;EAAM;EAAa;CAAS,CAAC;CAEzE,OACE,oBAAC,eAAD;EACE,GAAI;EACU;EACA;EACd,GAAI,KAAK,gBAAgB,KAAK;EAC9B,KAAK;EAEJ;CACY,CAAA;AAEnB,CACF;AAEA,YAAY,cAAc;AAM1B,IAAM,oBAAoB;AAI1B,IAAM,cAAc,KAAK,YAA8C,EAAE,UAAU,GAAG,SAAS,iBAAiB;CAC9G,OACE,oBAAC,OAAD;EAAK,GAAI,KAAK,gBAAgB,OAAO,EAAE,YAAY,0BAA0B,CAAC;EAAG,KAAK;EACnF;CACE,CAAA;AAET,CAAC;AAED,YAAY,cAAc;AAM1B,IAAM,uBAAuB;AAC7B,IAAM,uBAAuB;AAC7B,IAAM,qBAAqB;;;;;AAM3B,IAAM,gBAAgB,YACpB,QAAQ,OACL,SAAS,UAAW,MAAM,SAAS,UAAU,MAAM,gBAAgB,cAAc,CAAC,MAAM,IAAI,IAAI,CAAC,CAAE,CAAA,CACnG,KAAK,IAAI;;AAGd,IAAM,eAAe,YAAqC;CAExD,MAAM,YADO,aAAa,OAAO,CAAC,CAAC,KACjB,CAAA,CAAK,MAAM,IAAI,CAAC,CAAC,MAAM,SAAS,KAAK,KAAK,CAAC,CAAC,MAAM,KAAK;CACzE,OAAO,UAAU,SAAS,qBAAqB,GAAG,UAAU,MAAM,GAAG,kBAAkB,EAAE,KAAK;AAChG;;AAGA,IAAM,gBAAgB,YAAiD;CAErE,MAAM,OAAO,QAAQ,YAAY,OAAO,CAAC,CAAC,KAAK;CAC/C,IAAI,CAAC,KAAK,QACR;CAEF,MAAM,UAAU,KACb,MAAM,IAAI,CAAA,CACV,QAAQ,SAAS,KAAK,KAAK,CAAC,CAAC,MAAM,CAAA,CACnC,MAAM,GAAG,oBAAoB,CAAA,CAC7B,KAAK,IAAI;CACZ,OAAO,QAAQ,SAAS,uBAAuB,GAAG,QAAQ,MAAM,GAAG,oBAAoB,EAAE,KAAK;AAChG;;;;;;AAOA,IAAM,gBAAgB,aAAiD;CACrE,MAAM,UAA2B,CAAC;CAClC,KAAK,IAAI,QAAQ,GAAG,QAAQ,SAAS,QAAQ,SAAS;EACpD,MAAM,UAAU,SAAS;EAGzB,IAAI,CAAC,SAAS,OAAO,GACnB;EAKF,IAAI,SAAS,QAAQ;EACrB,IAAI;EACJ,KAAK,IAAI,OAAO,QAAQ,GAAG,OAAO,SAAS,QAAQ,QAAQ;GACzD,MAAM,cAAc,SAAS;GAC7B,IAAI,SAAS,WAAW,GACtB;GAEF,SAAS,OAAO;GAChB,IAAI,CAAC,eAAe,YAAY,OAAO,SAAS,aAC9C,cAAc,aAAa,WAAW;EAE1C;EAEA,QAAQ,KAAK;GACX,IAAI,QAAQ;GACZ,OAAO,YAAY,OAAO,KAAK;GAC/B;GACA,OAAO;IAAE,MAAM;IAAO,IAAI;GAAO;EACnC,CAAC;CACH;CACA,OAAO;AACT;AAMA,IAAM,mBAAmB;;AAGzB,IAAM,eAAe,EACnB,SAAS;CACP,OAAO;CACP,WAAW;AACb,EACF;AAYA,IAAM,gBAAc,EAAE,YAAY,UAAU,WAAW,SAAS,aAAa,kBAAmC;CAC9G,MAAM,EAAE,MAAM,QAAQ,eAAe,KAAK,QAAQ,GAAG;CACrD,MAAM,EAAE,MAAM,IAAI,OAAO,OAAO,WAAW,eAAe,oBAAoB,eAAe,gBAAgB;CAC7G,MAAM,EAAE,UAAU,SAAS,qBAAqB,gBAAgB;CAChE,MAAM,WAAW,YAAY;CAE7B,MAAM,cAAc,cAAc,iBAAiB,EAAE,GAAG,CAAC,EAAE,CAAC;CAI5D,MAAM,iBAAiB,aACpB,QAAyB;EACxB,IAAI;EACJ,IAAI;GACF,SAAS,IAAI,QAAqB,GAAG,CAAC,CAAC;EACzC,QAAQ;GACN,SAAS,KAAA;EACX;EACA,OAAQ,UAAU,IAAI,SAAS,MAAM,KAAM;CAC7C,GACA,CAAC,EAAE,CACL;CACA,MAAM,CAAC,YAAY,iBAAiB,SAA4B,KAAA,CAAS;CAEzE,MAAM,cAAc,sBAAsB,oBAAoB,WAAW,SAAS,KAAA;CAKlF,MAAM,QAAQ,aAAa,UAAU,EAAE,OAAO,SAAS,CAAC;CACxD,MAAM,YAAY,aAAa,kBAAkB,SAAS,CAAC,CAAC,SAAS;CACrE,gBAAgB;EAEd,MAAM,OAAO,SAAS,SAAS,SAAS,IAAI;EAC5C,MAAM,aAAa,aAAa,MAAM,OAAO,SAAS,cAAc,KAAK,KAAK,KAAA,CAAS;CACzF,GAAG;EAAC;EAAO;EAAW;EAAU;CAAI,CAAC;CAErC,MAAM,UAAU,cAEZ,eACA,UAAU,MAAM,OAChB,cAAc,UAAU,cAAc,UAAU,QAAQ,SAAS,WAAW,IAAI,UAAU,OAAO,CAAC,CAAC,CAAC,KACtG,CAAC,aAAa,QAAQ,CACxB;CAEA,MAAM,gBAAgB,OAAoC,IAAI;CAE9D,MAAM,sBAAsB,aACzB,aAA0C;EACzC,cAAc,UAAU;EACxB,cAAc,QAAQ;CACxB,GACA,CAAC,aAAa,CAChB;CAEA,gBAAgB;EACd,OAAO,MAAM,IAAI,UAAU;GACzB,QAAQ,MAAM,MAAd;IACE,KAAK;IACL,KAAK;KACH,cAAc,SAAS,eAAe;KACtC;IACF,KAAK;KACH,cAAc,SAAS,WAAW,KAAK,EAAE;KACzC;IACF,KAAK;KACH,cAAc,SAAS,WAAW,KAAK,CAAC;KACxC;IACF,KAAK;KACH,cAAc,MAAM,KAAK;KACzB;IACF,SACE,IAAI,KAAK,cAAc,OAAI;KAAA,YAAA;KAAA,GAAA;KAAA,GAAA;KAAA,GAAA,KAAA;IAAA,CAAC;GAChC;EACF,CAAC;CACH,GAAG,CAAC,KAAK,CAAC;CAIV,MAAM,cAAc,aAAa,OAAwB,MAAM,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC;CAEhF,IAAI,CAAC,UACH,OAAO,oBAAC,OAAD,EAAK,WAAU,YAAa,CAAA;CAGrC,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,WAAkB,MAAnB;EACS;EACG;EACV,UAAU;EACG;EACG;EACP;EACE;EACJ;EAEP,QAAQ,cAAc,UAAU,MAAM,OAAO,MAAM,cAAc;EACjE,SAAS;EACT,eAAe;EACf,eAAe;EAEf,UAAA,oBAAC,WAAkB,UAAnB,EAAwC,WAAa,CAAA;CAC/B,CAAA,GAGxB,qBAAC,MAAM,MAAP;EACE,eAAY;EACZ,MAAM,CAAC,CAAC;EACR,UAAU;EACV,eAAe,SAAS,CAAC,QAAQ,cAAc,KAAA,CAAS;EAJ1D,UAAA;GAME,oBAAC,MAAM,QAAP;IAAc,MAAK;IAAwB,UAAA,EAAE,wBAAwB;GAAgB,CAAA;GACrF,oBAAC,MAAM,aAAP,EAAA,UAAoB,YAAY,QAA2B,CAAA;GAC1D,eAAe,eACd,oBAAC,MAAM,QAAP,EAAA,UACE,oBAAC,MAAM,eAAP;IACE,eAAe;KACb,cAAc,KAAA,CAAS;KACvB,YAAY;IACd;IAEC,UAAA,EAAE,YAAY,QAAQ;GACJ,CAAA,EACT,CAAA;EAEN;CACZ,CAAA,CAAA,EAAA,CAAA;AAEN;AAEA,aAAW,cAAc;AAMzB,IAAM,oBAAoB;;;;;;AAS1B,IAAM,eAAe,EAAE,iBAAmC;CACxD,MAAM,EAAE,UAAU,cAAc,eAAe,qBAAqB,iBAAiB;CAErF,MAAM,UAAU,cAAc,aAAa,QAAQ,GAAG,CAAC,QAAQ,CAAC;CAChE,MAAM,eAAe,aAClB,WAA0B;EACzB,YAAY,WAAW,OAAO,OAAO,MAAM,MAAM,QAAQ;CAC3D,GACA,CAAC,UAAU,CACb;CACA,MAAM,iBAAiB,aAAa,UAAkB,YAAY,WAAW,KAAK,KAAK,GAAG,CAAC,UAAU,CAAC;CAEtG,IAAI,QAAQ,SAAS,GACnB,OAAO;CAGT,OACE,oBAAC,SAAD;EACc;EACH;EAET,cAAc,eAAe;GAAE,MAAM,aAAa;GAAY,IAAI,aAAa,WAAW;EAAE,IAAI,KAAA;EAChG,UAAU;EACV,YAAY;CACb,CAAA;AAEL;AAEA,YAAY,cAAc;AAM1B,IAAM,mBAAmB;;;;;;;;;;;;AAkBzB,IAAM,cAAc,EAAE,YAAY,sBAAsB,OAAO,GAAG,YAA6B;CAC7F,MAAM,EAAE,MAAM,IAAI,WAAW,OAAO,cAAc,eAAe,gBAAgB;CAIjF,MAAM,CAAC,SAAS,UAAU,MAAM,OAAO;CACvC,MAAM,WAAW,SAAS;CAK1B,MAAM,CAAC,cAAc,mBAAmB,SAAS,MAAM,OAAO,SAAS,sBAAsB,KAAK;CAClG,gBAAgB;EACd,OAAO,MAAM,IAAI,OAAO;GACtB,IAAI,GAAG,SAAS,gBACd,iBAAiB,YAAY,CAAC,OAAO;EAEzC,CAAC;CACH,GAAG,CAAC,KAAK,CAAC;CAEV,OACE,qBAAC,YAAY,MAAb;EACE,MAAM;EACN,eAAe,EAAE,WAAW,gBAAgB,IAAI;EAGhD,WAAW;EALb,UAAA,CAQG,YACC,oBAAC,YAAY,SAAb;GAAqB,WAAU;GAE7B,UAAA,oBAAC,cAAD,EAAc,YAAW,iGAAkG,CAAA;EACxG,CAAA,GAEvB,oBAAC,cAAD;GACE,GAAI;GAEJ,YAAY,CAAC,gBAAgB,kBAAkB,UAAU;GACrD;GACE;GACK;GACJ;GACI;GACX,cAAc,WAAW,eAAe,KAAA;EACzC,CAAA,CACe;;AAEtB;AAEA,WAAW,cAAc;AAMzB,IAAM,sBAAsB;;AAG5B,IAAM,iBAAiB;AAEvB,IAAM,eAAe,KAAK,YAA4B,OAAO,iBAAiB;CAC5E,MAAM,EAAE,MAAM,UAAU,eAAe,mBAAmB;CAC1D,MAAM,EAAE,MAAM,QAAQ,eAAe,KAAK,QAAQ,GAAG;CAGrD,MAAM,CAAC,gBAAgB,UAAU,IAAI;CACrC,MAAM,WAAW,cAAc;CAC/B,MAAM,QAAQ,aACZ,cAAc,KAAK,MAAM,QAAQ,KAAK,YAAY,YAAY,CAAC,EAAA,CAAG,KAAK,QAAQ,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAC7G;CAGA,MAAM,eAAe,aAClB,EAAE,OAAO,GAAG,YAAwB;EACnC,MAAM,KAAK,QAAQ,IAAI,YAAY,IAAI;EACvC,IAAI,QAAQ,IACV,OAAc,QAAQ,IAAI,MAAM,OAAO,KAAK;CAEhD,GACA,CAAC,IAAI,CACP;CAIA,MAAM,eAAe,aAClB,SAAoB;EACnB,MAAM,KAAK,QAAQ,IAAI,YAAY,IAAI;EACvC,IAAI,QAAQ,IACV,OAAc,WAAW,IAAI,MAAM,OAAO,IAAI;CAElD,GACA,CAAC,MAAM,KAAK,CACd;CAEA,MAAM,eAAe,aAAa,MAAiB,UAAqB;EACtE,KAAK,OAAO,MAAM,KAAK;CACzB,GAAG,CAAC,CAAC;CAKL,MAAM,gBAAgB,aACnB,SAAoB;EACnB,MAAM,UAAU,MAAM,WAAW,EAAE,SAAS,OAAO,KAAK,EAAE,IAAI;EAC9D,MAAM,KAAK;GAAE,MAAM;GAAU,MAAM,EAAE,uBAAuB,EAAE,QAAQ,CAAC;EAAE,CAAC;CAC5E,GACA;EAAC;EAAO;EAAO;CAAC,CAClB;CAIA,MAAM,iBAAiB,aACpB,SAAoB,CACnB,iBAAiB,WAAW,KAAK,YAAY,cAAc,IAAI,GAAG;EAChE,OAAO,EAAE,oBAAoB;EAC7B,MAAM;EAEN,UAAU,KAAK,WAAW,UAAU,KAAK,WAAW;EACpD,QAAQ;CACV,CAAC,GACD,iBAAiB,UAAU,KAAK,YAAY,aAAa,IAAI,GAAG;EAC9D,OAAO,EAAE,mBAAmB;EAC5B,MAAM;EACN,QAAQ;CACV,CAAC,CACH,GACA;EAAC;EAAe;EAAc;CAAC,CACjC;CAEA,IAAI,CAAC,MACH,OAAO;CAGT,OACE,oBAAC,SAAS,MAAV;EACS;EACP,iBAAiB;EACjB,cAAA;EACA,eAAA;EAEA,OAAA;EACA,eAAe;EACf,eAAe;EACf,cAAc;EACd,cAAc;EACE;EAEhB,UAAA,qBAAC,OAAD;GAAK,GAAI,KAAK,gBAAgB,OAAO,EAAE,YAAY,wBAAwB,CAAC;GAAG,KAAK;GAApF,UAAA;IAEE,oBAAC,SAAS,UAAV;KAAmB,MAAM;KACvB,UAAA,oBAAC,SAAS,SAAV,CAAmB,CAAA;IACF,CAAA;IAInB,oBAAC,mBAAD,EAA0B,MAAQ,CAAA;IAElC,oBAAC,SAAS,QAAV,EAAiB,YAAA,KAAY,CAAA;GAC1B;;CACQ,CAAA;AAEnB,CAAC;AAED,aAAa,cAAc;;;;;;;AAQ3B,IAAM,qBAAqB,EAAE,YAA6C;CACxE,MAAM,EAAE,kBAAkB,MAAM,oBAAoB;CACpD,MAAM,UAAU,cAEZ,MAAM,SAAS,SACb,KAAK,aAAa,KAAK,OAAO,CAAA,CAC3B,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAA,CAC9B,KAAK,YAAY;EAAE;EAAM;CAAO,EAAE,CACvC,GACF,CAAC,KAAK,CACR;CAEA,MAAM,eAAe,aAClB,MAAiB,YAAoB,WAAmB;EACvD,MAAM,UAAU,IAAI,YAAY,IAAI,CAAC,EAAE;EACvC,IAAI,SAEF,cAAc,mBAAmB,gBAAgB;GAAE;GAAM,UAAU;GAAY;EAAO,GAAG,EAAE,QAAQ,CAAC,CAAA,CACjG,MAAM,WAAW;GAChB,IAAI,OAAO,SAAS,CAAC,OAAO,MAAM,UAChC,IAAI,KAAK,6BAA6B;IAAE,MAAM,KAAK;IAAI,UAAU;IAAY,OAAO,OAAO;GAAM,GAAA;IAAA,YAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA,KAAA;GAAA,CAAC;EAEtG,CAAC,CAAA,CACA,OAAO,QAAQ,IAAI,MAAM,KAAE,KAAA,GAAA;GAAA,YAAA;GAAA,GAAA;GAAA,GAAA;GAAA,GAAA,KAAA;EAAA,CAAC,CAAC;CAEpC,GACA,CAAC,aAAa,CAChB;CAEA,IAAI,QAAQ,WAAW,GACrB,OAAO;CAGT,OACE,oBAAC,OAAD;EAAK,WAAU;EAA0B,eAAY;EAClD,UAAA,QAAQ,KAAK,EAAE,MAAM,aACpB,oBAAC,cAAD;GAEU;GACR,WAAW,WAAW,aAAa,MAAM,OAAO,SAAS,IAAI,MAAM;EACpE,GAHM,OAAO,SAAS,EAGtB,CACF;CACE,CAAA;AAET;AAEA,kBAAkB,cAAc;AAMhC,IAAM,qBAAqB;;;;;;AAO3B,IAAM,gBAAgB,EAAE,iBAAuC;CAC7D,MAAM,EAAE,cAAc,eAAe,kBAAkB;CACvD,MAAM,EAAE,WAAW,qBAAqB,kBAAkB;CAC1D,MAAM,WAAW,aAAa,kBAAkB,SAAS,CAAC,CAAC,QAAQ;CAInE,OAAO,oBAAC,gBAAD;EAAiC;EAAsB;EAAU,QAAQ,OAAO,EAAE,EAAE;CAAS,CAAA;AACtG;AAEA,aAAa,cAAc;AAM3B,IAAa,OAAO;CAClB,MAAM;CACN,SAAS;CACT,SAAS;CACT,QAAQ;CACR,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,SAAS;AACX"}
|
|
1
|
+
{"version":3,"file":"chunk-Chat.mjs","names":[],"sources":["../../src/commands/task-commands.ts","../../src/components/ChatPrompt/ChatActions.tsx","../../src/components/ChatPrompt/ChatActivity.tsx","../../src/components/ChatPrompt/ChatMcpErrors.tsx","../../src/util/agent-options.ts","../../src/components/ChatPrompt/ChatOptions.tsx","../../src/components/ChatPrompt/ChatReferences.tsx","../../src/components/ChatPrompt/useChatVoiceInput.ts","../../src/components/ChatPrompt/ChatPrompt.tsx","../../src/components/ChatPrompt/ChatStatus.tsx","../../src/components/Chat/ObjectCardWidget.tsx","../../src/components/Chat/SurfaceWidget.tsx","../../src/components/Chat/Chat.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as SlashCommand from '@dxos/assistant-toolkit/SlashCommand';\nimport * as Chat from '@dxos/assistant/Chat';\nimport * as Operation from '@dxos/compute/Operation';\nimport { Ref } from '@dxos/echo';\nimport { type SpaceId } from '@dxos/keys';\nimport * as TaskOperation from '@dxos/plugin-tasks/TaskOperation';\nimport { type Task } from '@dxos/types';\nimport { trim } from '@dxos/util';\n\n/** Membership writes go through the `Chat` primitives because the chat, not a `TaskSet`, is the container. */\nexport const TaskSlashCommands: SlashCommand.SlashCommand[] = [\n {\n command: '/task:create',\n description: 'Create a task',\n execute: async (args, { db, chat }) => {\n const title = args.trim();\n if (title.length === 0) {\n return new Error('Usage: /task:create <description>');\n }\n Chat.addTask(db, chat, title);\n await db.flush();\n return { summary: `Created task “${title}”.` };\n },\n },\n {\n command: '/task:delete',\n description: 'Delete task(s) by number or quoted title',\n execute: async (args, { db, chat }) => {\n const tasks = await hydrate(chat);\n const resolved = resolveSelectors(args, tasks);\n if (resolved instanceof Error) {\n return resolved;\n }\n if (resolved.length === 0) {\n return new Error('Usage: /task:delete <number | \"exact title\"> [...]');\n }\n\n // Sub-tasks go with their parent, so a later selector may already have been swept.\n const deleted: Task.Task[] = [];\n const seen = new Set<string>();\n for (const task of resolved) {\n if (seen.has(task.id)) {\n continue;\n }\n for (const member of Chat.deleteTask(db, chat, tasks, task)) {\n seen.add(member.id);\n }\n deleted.push(task);\n }\n await db.flush();\n return { summary: summarize('Deleted', deleted) };\n },\n },\n {\n command: '/task:run',\n description: 'Delegate task(s) by number or quoted title',\n execute: async (args, { db, chat, invoke }) => {\n const resolved = resolveSelectors(args, await hydrate(chat));\n if (resolved instanceof Error) {\n return resolved;\n }\n if (resolved.length === 0) {\n return new Error('Usage: /task:run <number | \"exact title\"> [...]');\n }\n\n // A terminal task has nothing left to run, and delegating a running one would fork it.\n const runnable = resolved.filter(\n (task) => task.status !== 'done' && task.status !== 'cancelled' && task.status !== 'started',\n );\n if (runnable.length === 0) {\n return { summary: 'Nothing to run: every named task is already done, cancelled, or running.' };\n }\n\n // An agent assignee on a `todo` task is what the supervisor's reconcile picks up.\n for (const task of runnable) {\n const failure = await run(\n invoke,\n TaskOperation.UpdateTask,\n {\n task: Ref.make(task),\n assignee: { role: 'assistant' as const },\n status: 'todo' as const,\n },\n db.spaceId,\n );\n if (failure) {\n return failure;\n }\n }\n\n return {\n summary: summarize('Delegated', runnable),\n followUp: trim`\n The user delegated EXACTLY these task(s) with the /task:run command: ${runnable.map((task) => `\"${task.title}\"`).join(', ')}.\n They are queued and will execute in the background. Acknowledge in one short\n sentence now, and when their completion is reported, acknowledge briefly and stop —\n the user scoped this run to those tasks only, so never delegate, start, or work on\n any other task.\n `,\n };\n },\n },\n];\n\n/**\n * `invokePromise` reports a handler failure in its result rather than by rejecting, so an\n * unexamined call reads as success and the command would claim an effect it never had.\n */\nconst run = async <I, O>(\n invoke: SlashCommand.OperationInvoke,\n operation: Operation.Definition<I, O>,\n input: I,\n spaceId: SpaceId | undefined,\n): Promise<Error | undefined> => {\n const { error } = await invoke(operation, input as never, { spaceId });\n return error;\n};\n\n/**\n * The checklist in full: a reopened chat's refs are unresolved until loaded, and an unresolved\n * entry is invisible to both selector matching and the subtree sweep.\n */\nconst hydrate = async (chat: Chat.Chat): Promise<Task.Task[]> => {\n // `tryLoad`, not `load`: the latter throws on an entry whose object is gone, failing the whole\n // command instead of proceeding with the tasks that do resolve.\n await Promise.all(chat.tasks.map((ref) => ref.tryLoad()));\n return Chat.resolveTasks(chat);\n};\n\n/** Resolves selectors against `tasks`, in the order the user named them. */\nconst resolveSelectors = (args: string, tasks: readonly Task.Task[]) => {\n const selectors = SlashCommand.parseTaskSelectors(args);\n if (selectors.length === 0) {\n return [];\n }\n\n const resolved: Task.Task[] = [];\n for (const selector of selectors) {\n const task =\n 'ordinal' in selector\n ? tasks[selector.ordinal - 1]\n : tasks.find((candidate) => candidate.title === selector.title.trim());\n if (!task) {\n const named = 'ordinal' in selector ? selector.ordinal : `\"${selector.title}\"`;\n return new Error(`No matching task for: ${named}. Select by 1-based number, or by exact title in quotes.`);\n }\n resolved.push(task);\n }\n return resolved;\n};\n\nconst summarize = (verb: string, tasks: readonly Task.Task[]): string =>\n `${verb} ${tasks.map((task) => `“${task.title}”`).join(', ')}.`;\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport type * as Atom from 'effect/reactivity/Atom';\nimport React, { type PropsWithChildren, type ReactNode } from 'react';\n\nimport { type ActionGraphProps, ActionToolbar, useMenuActions } from '@dxos/react-ui-menu';\nimport * as Button from '@dxos/react-ui/Button';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport * as Toolbar from '@dxos/react-ui/Toolbar';\nimport type * as Util from '@dxos/react-ui/Util';\nimport { mx } from '@dxos/ui-theme';\n\nimport { meta } from '#meta';\n\nimport { type ChatEvent } from '../Chat/events.ts';\n\n/**\n * 44px at the 16px (pointer: fine) root font-size, the iOS HIG minimum touch target; the density\n * knobs cap a control at 40px, so a finger-driven control has to be sized past them. Applied only\n * where a finger is plausibly the pointer, so the desktop row keeps its density rhythm.\n */\nconst TOUCH_TARGET = 'max-md:size-11 pointer-coarse:size-11';\n\nexport type ChatActionsProps = Util.ThemedClassName<\n PropsWithChildren<{\n /** Content before the actions in the same toolbar (the prompt's options and context chips). */\n leading?: ReactNode;\n /** The prompt's graph node, which is what contributed actions are filed under. */\n attendableId?: string;\n /**\n * Toolbar actions other plugins filed on this chat's node — the microphone among them. Sourced\n * the way `MarkdownArticle` sources its own, so a contributor reaches the prompt without either\n * side importing the other.\n */\n customActions?: Atom.Atom<ActionGraphProps>;\n processing?: boolean;\n debug?: boolean;\n /** Whether the prompt holds text and the chat model would accept it; drives the send control's enablement. */\n canSend?: boolean;\n /** Whether the checklist beside the prompt is shown; the toggle renders only when provided. */\n tasksVisible?: boolean;\n /** Submits the current prompt; the send control renders only when provided. */\n onSend?: () => void;\n onEvent?: (event: ChatEvent) => void;\n }>\n>;\n\nexport const ChatActions = ({\n classNames,\n children,\n leading,\n attendableId,\n customActions,\n processing,\n debug,\n canSend,\n tasksVisible,\n onSend,\n onEvent,\n}: ChatActionsProps) => {\n const { t } = Hooks.useTranslation(meta.profile.key);\n // While a turn runs the primary control interrupts it — unless there is text waiting, in which\n // case sending it (which queues it behind the running turn) is what the reader is asking for.\n const showStop = processing && !canSend;\n const controls = (\n <>\n {children}\n {debug && (\n <Button.Root\n variant='ghost'\n icon='ph--wrench--regular'\n iconOnly\n label={t('debug.button')}\n onClick={() => onEvent?.({ type: 'toggle-debug' })}\n />\n )}\n\n {tasksVisible != null && (\n <Button.Root\n variant='ghost'\n classNames={TOUCH_TARGET}\n icon='ph--list-checks--regular'\n iconOnly\n aria-pressed={tasksVisible}\n label={t(tasksVisible ? 'hide-tasks.button' : 'show-tasks.button')}\n data-testid='assistant.toggle-tasks'\n onClick={() => onEvent?.({ type: 'toggle-tasks' })}\n />\n )}\n\n {/* One control, not two: send and stop are the same affordance at two moments of a turn, and\n as separate buttons one of them was always present and dead. Enter is the only other way to\n submit, and a touch keyboard offers no such affordance. */}\n {onSend && (\n // TODO(dmaretskyi): Set processing state correctly on rehydrated agents.\n <Button.Root\n disabled={!showStop && !canSend}\n variant='ghost'\n classNames={mx(TOUCH_TARGET, 'transition duration-300 ease-in-out', canSend && 'text-accent-text rotate-90')}\n icon={showStop ? 'ph--stop-circle--duotone' : 'ph--paper-plane--regular'}\n iconOnly\n label={t(showStop ? 'cancel-processing.button' : 'send.label')}\n onClick={() => (showStop ? onEvent?.({ type: 'cancel' }) : onSend())}\n // One stable handle for the prompt's primary action; its mode is the accessible label,\n // which is also how a reader tells the two apart.\n data-testid='assistant.send'\n />\n )}\n </>\n );\n\n // One toolbar for the whole row, so the contributed actions and the prompt's own controls share its roving focus.\n return customActions ? (\n <ContributedActions actions={customActions} attendableId={attendableId} start={leading} classNames={classNames}>\n {controls}\n </ContributedActions>\n ) : (\n <Toolbar.Root classNames={classNames}>\n {leading}\n {controls}\n </Toolbar.Root>\n );\n};\n\n/**\n * The prompt's toolbar with the contributed actions first, rendered through the menu's own item dispatch rather than a\n * local copy of it — that is what makes a `variant: 'custom'` contribution (the mic's press-and-hold and its options\n * menu) render here exactly as it does in a document toolbar.\n *\n * Its own component so the hook is unconditional; the row renders it only when a caller supplies actions.\n */\nconst ContributedActions = ({\n actions,\n attendableId,\n start,\n classNames,\n children,\n}: Util.ThemedClassName<\n PropsWithChildren<{\n actions: Atom.Atom<ActionGraphProps>;\n attendableId?: string;\n start?: ReactNode;\n }>\n>) => {\n const menuActions = useMenuActions(actions);\n return (\n <ActionToolbar {...menuActions} attendableId={attendableId} alwaysActive start={start} classNames={classNames}>\n {children}\n </ActionToolbar>\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { useEffect, useState } from 'react';\n\nimport type * as Trace from '@dxos/compute/Trace';\nimport { ChatStatus as NaturalChatStatus } from '@dxos/react-ui-chat';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport type * as Util from '@dxos/react-ui/Util';\n\nimport { meta } from '#meta';\n\nconst CHAT_ACTIVITY_NAME = 'Chat.Activity';\n\nconst SECOND = 1_000;\nconst MINUTE = 60 * SECOND;\nconst HOUR = 60 * MINUTE;\n\nconst activityLabelKey = (phase: Trace.RequestPhaseName): string => `activity.${phase}.label`;\n\n/**\n * Phases whose `detail` reads as part of the sentence (\"Calling tool search\") rather than as a\n * separate field, so the label interpolates it and the detail chip is suppressed.\n */\nconst INLINE_DETAIL_PHASES: ReadonlySet<Trace.RequestPhaseName> = new Set<Trace.RequestPhaseName>(['calling-tool']);\n\nexport type ChatActivityProps = Util.ThemedClassName<{\n activity?: Trace.PayloadType<typeof Trace.RequestPhase>;\n /**\n * Epoch milliseconds the agent is scheduled to wake at, when an alarm is pending. Rendered as a\n * counting-down line while the agent is idle or reports `sleeping`; any other live phase\n * supersedes it, since a running turn is the more immediate answer to \"what is it doing\".\n */\n wakeAt?: number;\n}>;\n\n/**\n * What the agent is doing, given a resolved phase or a pending alarm.\n *\n * The line stays up for as long as there is something to report: the setup stages before the first\n * token (a cold MCP server, a summarization pass, a re-issued request), the generation, each tool\n * call, and — once the turn settles with an alarm pending — the wait until the agent wakes itself.\n * Only a fully idle agent renders nothing.\n *\n * The phase and the wake time arrive as props rather than being read from the chat context, so every\n * state can be mounted in a story without a live agent process; `Chat.Activity` is the bound form.\n */\nexport const ChatActivity = ({ classNames, activity, wakeAt }: ChatActivityProps) => {\n const { t } = Hooks.useTranslation(meta.profile.key);\n // `sleeping` is the agent saying the turn is over and only the alarm is left, so the countdown\n // replaces it rather than competing with it.\n const waking = !activity || activity.phase === 'sleeping';\n const remaining = useCountdown(waking ? wakeAt : undefined);\n // A wake time in the past is an alarm that has already fired: its record outlives the firing (and\n // the projection that drops it can lag a beat), so a countdown driven off it alone would sit on\n // \"Waking up\" forever after the agent had moved on.\n const counting = remaining !== undefined && remaining >= SECOND;\n const label = waking\n ? counting\n ? formatWaking(t, remaining)\n : activity && t(activityLabelKey(activity.phase))\n : t(activityLabelKey(activity.phase), { detail: activity.detail ?? '' });\n if (!label) {\n return null;\n }\n\n return (\n // `font-body` overrides the pill root's `font-mono`, which suits the status pill's token counts\n // and elapsed clock but renders a sentence as debug output. One line: a long tool detail truncates\n // rather than wrapping, so the prompt below does not jump as the phase changes.\n <NaturalChatStatus.Root\n defaultRunning={false}\n classNames={['py-1 px-2 gap-2 text-sm font-body max-w-full min-w-0 whitespace-nowrap', classNames]}\n >\n <NaturalChatStatus.Icon classNames='shrink-0' />\n <NaturalChatStatus.Text classNames='min-w-0 truncate'>\n <span data-testid='assistant.chat-activity'>{label}</span>\n </NaturalChatStatus.Text>\n {/* Only a re-issued request has an attempt worth naming; the first one is just the request. */}\n {activity?.attempt != null && activity.attempt > 1 && (\n <>\n <NaturalChatStatus.Separator classNames='shrink-0' />\n <NaturalChatStatus.Text classNames='shrink-0'>\n <span data-testid='assistant.chat-activity.attempt'>\n {t('activity.attempt', { attempt: activity.attempt })}\n </span>\n </NaturalChatStatus.Text>\n </>\n )}\n {activity?.detail && !INLINE_DETAIL_PHASES.has(activity.phase) && (\n <>\n <NaturalChatStatus.Separator classNames='shrink-0' />\n <NaturalChatStatus.Text classNames='min-w-0 truncate'>{activity.detail}</NaturalChatStatus.Text>\n </>\n )}\n </NaturalChatStatus.Root>\n );\n};\n\nChatActivity.displayName = CHAT_ACTIVITY_NAME;\n\n/**\n * Milliseconds until `wakeAt`, re-read every second, or `undefined` when nothing is scheduled.\n *\n * The alarm is a fixed instant rather than a stream of events, so the countdown is the client's to\n * run; ticking on a plain interval keeps it a rendering concern and leaves the agent silent while\n * it sleeps.\n */\nconst useCountdown = (wakeAt?: number): number | undefined => {\n // The value is read during render and the state only forces the next read, so a changed `wakeAt`\n // shows its own countdown on the first render rather than the previous one until the effect runs.\n const [, setTick] = useState(0);\n useEffect(() => {\n if (wakeAt === undefined) {\n return;\n }\n\n const interval = setInterval(() => setTick((tick) => tick + 1), SECOND);\n return () => clearInterval(interval);\n }, [wakeAt]);\n\n return wakeAt === undefined ? undefined : wakeAt - Date.now();\n};\n\n/**\n * The countdown line, at the coarsest unit that still carries information: a wake an hour out does\n * not become more legible counted in seconds.\n */\nconst formatWaking = (t: (key: string, options?: Record<string, unknown>) => string, remaining: number): string => {\n if (remaining < MINUTE) {\n return t('activity.waking.seconds.label', { count: Math.round(remaining / SECOND) });\n }\n if (remaining < HOUR) {\n return t('activity.waking.minutes.label', { count: Math.round(remaining / MINUTE) });\n }\n return t('activity.waking.hours.label', { count: Math.round(remaining / HOUR) });\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport React, { useCallback } from 'react';\n\nimport { Listbox } from '@dxos/react-ui-list';\nimport * as Banner from '@dxos/react-ui/Banner';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport type * as Util from '@dxos/react-ui/Util';\n\nimport { meta } from '#meta';\n\nimport { type ChatModel } from '../../chat-model/index.ts';\n\nexport type ChatMcpErrorsProps = Util.ThemedClassName<{\n chatModel: ChatModel;\n}>;\n\n/**\n * Inline banner that lists MCP servers that failed to connect during the most recent request.\n * The chat itself keeps working without these servers — this just lets the user see what was dropped.\n */\nexport const ChatMcpErrors = ({ classNames, chatModel }: ChatMcpErrorsProps) => {\n const { t } = Hooks.useTranslation(meta.profile.key);\n const errors = useAtomValue(chatModel.mcpErrors);\n\n const handleDismiss = useCallback(() => {\n chatModel.dismissMcpErrors();\n }, [chatModel]);\n\n if (errors.length === 0) {\n return null;\n }\n\n return (\n <Banner.Root valence='warning'>\n <Banner.Title onClose={handleDismiss}>{t('mcp-server-error.label')}</Banner.Title>\n <Banner.Body>\n <Listbox.Root\n items={errors.map((error) => ({\n value: `${error.url}::${error.protocol}`,\n label: `${error.url}::${error.protocol}`,\n }))}\n >\n <Listbox.Content aria-label={t('mcp-server-error.label')} classNames='gap-0.5 text-sm'>\n {errors.map((error) => (\n <Listbox.Item key={`${error.url}::${error.protocol}`} id={`${error.url}::${error.protocol}`}>\n {/* `min-w-0`: the item is a flex child, so without it `truncate` never shrinks below\n the content's intrinsic width. */}\n <span className='truncate min-w-0'>\n <span className='font-mono'>{error.url}</span>\n {' — '}\n <span>{error.unauthorized ? t('mcp-server-error.unauthorized') : error.message}</span>\n </span>\n </Listbox.Item>\n ))}\n </Listbox.Content>\n </Listbox.Root>\n </Banner.Body>\n </Banner.Root>\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { SessionConfig } from '@dxos/ai';\n\nimport type * as AssistantCapabilities from '../types/AssistantCapabilities.ts';\n\n/** One row of the chat's agent picker. */\nexport type AgentOption = {\n value: string;\n label: string;\n icon: string;\n disabled: boolean;\n /** Why the row cannot be picked, shown under its name. */\n description?: string;\n};\n\nexport type AgentOptionsProps = {\n agents: readonly Pick<AssistantCapabilities.Agent, 'id' | 'label' | 'icon'>[];\n /** Availability of each agent, by index into `agents`. */\n availability: readonly AssistantCapabilities.AgentAvailability[];\n /** The agent the chat names (`chat.session.harness`). */\n current: string;\n};\n\n/** Reason shown for an agent a chat names that no plugin registers on this device. */\nexport const NOT_INSTALLED = 'not installed here';\n\n/**\n * The rows of the agent picker: Composer's own loop first, as the default, then the rest in\n * registration order, with an unavailable agent disabled and its reason as the description. An\n * agent the chat already names but this device does not register is kept, so the picker still\n * shows what the chat runs on.\n */\nexport const agentOptions = ({ agents, availability, current }: AgentOptionsProps): AgentOption[] => {\n const options = agents.map((agent, index): AgentOption => {\n const status = availability[index];\n return status && !status.available\n ? { value: agent.id, label: agent.label, icon: agent.icon, disabled: true, description: status.reason }\n : { value: agent.id, label: agent.label, icon: agent.icon, disabled: false };\n });\n\n const sorted = [\n ...options.filter(({ value }) => value === SessionConfig.COMPOSER_HARNESS),\n ...options.filter(({ value }) => value !== SessionConfig.COMPOSER_HARNESS),\n ];\n\n if (!sorted.some(({ value }) => value === current)) {\n sorted.push({\n value: current,\n label: current,\n icon: 'ph--robot--regular',\n disabled: true,\n description: NOT_INSTALLED,\n });\n }\n\n return sorted;\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport * as Atom from 'effect/reactivity/Atom';\nimport React, { type JSX, useCallback, useMemo, useState } from 'react';\n\nimport { Provider, SessionConfig } from '@dxos/ai';\nimport * as Hooks from '@dxos/app-framework/Hooks';\nimport { type AiContext } from '@dxos/assistant';\nimport * as Agent from '@dxos/assistant/Agent';\nimport type * as Chat from '@dxos/assistant/Chat';\nimport * as McpServer from '@dxos/compute/McpServer';\nimport { type Database, Filter, Obj, Ref, type Registry, Type, URI } from '@dxos/echo';\nimport { useObject, useQuery } from '@dxos/echo-react';\nimport { AccessToken } from '@dxos/link';\nimport * as ClientCapabilities from '@dxos/plugin-client/ClientCapabilities';\nimport { type ChatView } from '@dxos/react-ui-assistant';\nimport { Listbox } from '@dxos/react-ui-list';\nimport { SearchList, useSearchListResults } from '@dxos/react-ui-search';\nimport * as Button from '@dxos/react-ui/Button';\nimport * as Field from '@dxos/react-ui/Field';\nimport * as UiHooks from '@dxos/react-ui/Hooks';\nimport * as Icon from '@dxos/react-ui/Icon';\nimport * as Input from '@dxos/react-ui/Input';\nimport * as Layout from '@dxos/react-ui/Layout';\nimport * as Popover from '@dxos/react-ui/Popover';\nimport * as Select from '@dxos/react-ui/Select';\nimport * as SystemButton from '@dxos/react-ui/SystemButton';\nimport * as Tabs from '@dxos/react-ui/Tabs';\nimport * as Toolbar from '@dxos/react-ui/Toolbar';\nimport { getStyles, mx } from '@dxos/ui-theme';\n\nimport {\n getSkillId,\n useActiveSkills,\n useContextObjects,\n useFilteredTypes,\n useMcpServerSignIn,\n useMcpServerStatus,\n useSkillHandlers,\n useSkills,\n} from '#hooks';\nimport { meta } from '#meta';\nimport { Assistant, AssistantCapabilities, AssistantPreset } from '#types';\n\nimport { resolveProvider } from '../../chat-model/index.ts';\nimport { agentOptions } from '../../util/agent-options.ts';\n\nconst styles = {\n panel: 'w-[calc(100dvw-.5rem)] sm:w-max max-w-document-width',\n};\n\nexport type ChatOptionsProps = AssistantPreset.ChatPresetProps & {\n db: Database.Database;\n chat?: Chat.Chat;\n context?: AiContext.Binder;\n registry?: Registry.Registry;\n /** Whether the conversation has begun; its agent is fixed from then on. */\n started?: boolean;\n};\n\n/**\n * Manages the runtime context for the chat.\n */\nexport const ChatOptions = ({\n db,\n chat,\n context,\n registry,\n started,\n presets,\n preset,\n onPresetChange,\n}: ChatOptionsProps) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n\n return (\n <Layout.Flex>\n <Popover.Root positioning={{ placement: 'top' }}>\n <Popover.Trigger asChild>\n <Button.Root\n variant='ghost'\n icon='ph--plus--regular'\n iconOnly\n label={t('context-objects.button')}\n disabled={!context}\n />\n </Popover.Trigger>\n <Popover.Content classNames={styles.panel}>\n {/* No Body: the list scrolls itself above its filter controls, in the popover's column. */}\n {context && <ObjectsPanel db={db} context={context} />}\n </Popover.Content>\n </Popover.Root>\n\n <Popover.Root positioning={{ placement: 'top' }}>\n <Popover.Trigger asChild>\n <Button.Root\n variant='ghost'\n icon='ph--sliders-horizontal--regular'\n iconOnly\n label={t('context-settings.button')}\n data-testid='assistant.options'\n disabled={!context}\n />\n </Popover.Trigger>\n <Popover.Content classNames={styles.panel}>\n {/* No Body: each tab's list and the tab bar share the popover's own padding. */}\n {/* A chat that has not begun opens on its agent, since that is the choice it is about to lose. */}\n <Tabs.Root\n orientation='horizontal'\n defaultValue={started ? 'view' : 'agent'}\n classNames='grid grid-rows-[1fr_40px] w-full'\n >\n <Tabs.Content tabIndex={-1} classNames='dx-focus-ring-inset overflow-hidden' value='agent'>\n <AgentPanel chat={chat} started={started} />\n </Tabs.Content>\n <Tabs.Content tabIndex={-1} classNames='dx-focus-ring-inset overflow-hidden' value='view'>\n <ViewPanel chat={chat} />\n </Tabs.Content>\n <Tabs.Content tabIndex={-1} classNames='dx-focus-ring-inset overflow-hidden' value='skills'>\n {context && <SkillsPanel registry={registry} db={db} context={context} />}\n </Tabs.Content>\n <Tabs.Content tabIndex={-1} classNames='dx-focus-ring-inset overflow-hidden' value='mcp-servers'>\n <McpServersPanel db={db} />\n </Tabs.Content>\n <Tabs.Content tabIndex={-1} classNames='dx-focus-ring-inset overflow-hidden' value='model'>\n <ModelsPanel presets={presets} preset={preset} onPresetChange={onPresetChange} />\n </Tabs.Content>\n <Tabs.Content tabIndex={-1} classNames='dx-focus-ring-inset overflow-hidden' value='environment'>\n <EnvironmentPanel chat={chat} />\n </Tabs.Content>\n <Tabs.List classNames='p-1 gap-1 border-t border-separator'>\n <Tabs.Trigger\n value='agent'\n icon='ph--robot--regular'\n label={t('options.agent.title')}\n data-testid='assistant.options.agent'\n />\n <Tabs.Trigger value='view' icon='ph--eye--regular' label={t('chat-view.title')} />\n <Tabs.Trigger value='skills' icon='ph--student--regular' label={t('options.skills.title')} />\n <Tabs.Trigger value='mcp-servers' icon='ph--plugs-connected--regular' label={t('options.mcp.title')} />\n <Tabs.Trigger\n value='model'\n icon='ph--cpu--regular'\n label={t('options.chat-model.title')}\n data-testid='assistant.options.model'\n />\n <Tabs.Trigger\n value='environment'\n icon='ph--hard-drives--regular'\n label={t('options.environment.title')}\n />\n </Tabs.List>\n </Tabs.Root>\n </Popover.Content>\n </Popover.Root>\n\n <AgentBadge chat={chat} />\n </Layout.Flex>\n );\n};\n\n/** The chat's agent and the picker's rows, live with each agent's availability. */\nconst useChatAgent = (chat: Chat.Chat | undefined) => {\n const agents = Hooks.useOptionalCapabilities(AssistantCapabilities.Agent);\n const availabilityAtom = useMemo(() => Atom.make((get) => agents.map((agent) => get(agent.availability))), [agents]);\n const availability = useAtomValue(availabilityAtom);\n const [session] = useObject(chat, 'session');\n const current = SessionConfig.harnessOf(session);\n const options = useMemo(() => agentOptions({ agents, availability, current }), [agents, availability, current]);\n return { current, options };\n};\n\n/**\n * Which agent runs this chat. Picked before the first message only: an agent keeps its own session\n * with the model, so one switched in mid-conversation would answer without the turns before it.\n */\nconst AgentPanel = ({ chat, started }: Pick<ChatOptionsProps, 'chat' | 'started'>) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const { current, options } = useChatAgent(chat);\n const handleChange = useCallback(\n (harness: string) => {\n if (chat) {\n Obj.update(chat, (chat) => {\n chat.session = { ...chat.session, harness };\n });\n }\n },\n [chat],\n );\n\n return (\n <Layout.Flex column classNames='dx-expand' data-testid='assistant.agents'>\n <Listbox.Root value={current} onValueChange={handleChange} disabled={!chat || started} autoFocus items={options}>\n <Listbox.Content gutter='none' aria-label={t('options.agent.title')}>\n {options.map(({ value }) => (\n <Listbox.Item\n key={value}\n id={value}\n classNames='dx-focus-ring rounded-xs'\n data-testid={`assistant.agents.${value}`}\n />\n ))}\n </Listbox.Content>\n </Listbox.Root>\n {started && <p className='px-form-chrome py-1 text-xs text-fg-muted'>{t('agent-locked.message')}</p>}\n </Layout.Flex>\n );\n};\n\n/** Names the agent beside the options when it is not Composer's own, so a reader knows who answers. */\nconst AgentBadge = ({ chat }: Pick<ChatOptionsProps, 'chat'>) => {\n const { current, options } = useChatAgent(chat);\n const agent = options.find(({ value }) => value === current);\n if (!agent || agent.value === SessionConfig.COMPOSER_HARNESS) {\n return null;\n }\n\n return (\n <Layout.Flex\n align='center'\n gap='xs'\n classNames='text-xs text-fg-muted whitespace-nowrap'\n data-testid='assistant.agent'\n >\n <Icon.Icon icon={agent.icon} size='sm' />\n <span>{agent.label}</span>\n </Layout.Flex>\n );\n};\n\nconst SkillsPanel = ({ registry, db, context }: Pick<ChatOptionsProps, 'registry' | 'db' | 'context'>) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n\n const skills = useSkills({ registry, db });\n const activeSkills = useActiveSkills({ context });\n const { onUpdateSkill } = useSkillHandlers({ context });\n const { results, handleSearch } = useSearchListResults({\n items: skills,\n extract: (skill) => skill.name,\n });\n\n return (\n <SearchList.Root onSearch={handleSearch}>\n <SearchList.Content classNames='flex flex-col'>\n {/* Flush to the popover edge, like the sibling `Listbox` panels: this is a menu, not a\n centered search surface, so the scroll strip is not reserved on both sides. */}\n <SearchList.Viewport padding={false}>\n {results.map((skill) => {\n const skillId = getSkillId(skill);\n const isActive = activeSkills.has(skillId);\n return (\n <SearchList.Item\n classNames='overflow-hidden'\n key={skillId}\n value={skillId}\n label={skill.name}\n checked={isActive}\n onSelect={() => onUpdateSkill?.(skill, !isActive)}\n />\n );\n })}\n </SearchList.Viewport>\n <Toolbar.Root>\n <SearchList.Input placeholder={t('search.placeholder')} classNames='border-t border-separator' autoFocus />\n </Toolbar.Root>\n </SearchList.Content>\n </SearchList.Root>\n );\n};\n\nconst ViewPanel = ({ chat }: Pick<ChatOptionsProps, 'chat'>) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const [view, setView] = useObject(chat, 'viewType');\n const value = (view as ChatView | undefined) ?? 'normal';\n\n return (\n <Listbox.Root\n value={value}\n onValueChange={setView}\n autoFocus\n items={Assistant.ChatViews.map((view) => ({\n value: view,\n label: t(`chat-view.${view}.label`, { defaultValue: view }),\n }))}\n >\n {/* No gutter: the popover's padding is the inset, shared with the tab bar below. */}\n <Listbox.Content gutter='none' aria-label={t('chat-view.title')}>\n {Assistant.ChatViews.map((view) => (\n <Listbox.Item key={view} id={view} classNames='dx-focus-ring rounded-xs'>\n <Listbox.ItemText>{t(`chat-view.${view}.label`, { defaultValue: view })}</Listbox.ItemText>\n <Listbox.ItemIndicator />\n </Listbox.Item>\n ))}\n </Listbox.Content>\n </Listbox.Root>\n );\n};\n\n/**\n * Where this conversation's agent runs. A per-chat property rather than a setting, mirroring a\n * trigger's own `remote` flag: `edge` keeps the conversation running with the client closed.\n * `AgentService` reads the location at spawn, so switching tears the running process down and\n * respawns it on the other host.\n */\nconst EnvironmentPanel = ({ chat }: Pick<ChatOptionsProps, 'chat'>) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const [remote, setRemote] = useObject(chat, 'remote');\n const client = Hooks.useOptionalCapability(ClientCapabilities.Client);\n // Offered only where an edge service is configured, which is the same condition that decides\n // whether `RemoteProcessManager` is the real manager or `layerNoop`: against the noop a spawn has\n // no `list` or `spawn`, so choosing `remote` would persist a flag the next prompt cannot honour.\n // An agent's chat runs on EDGE (`Agent.chatLocation`) unless explicitly kept local: with EDGE configured local is\n // no choice there, and without it local stays offered so the chat can be moved somewhere it can run.\n const edgeConfigured = Boolean(client?.config.values.runtime?.services?.edge?.url);\n const agentOnEdge = chat !== undefined && Agent.isAgentChat(chat) && chat.remote !== false;\n const environments =\n agentOnEdge && edgeConfigured\n ? CHAT_ENVIRONMENTS.filter((environment) => environment === 'remote')\n : agentOnEdge || edgeConfigured\n ? CHAT_ENVIRONMENTS\n : CHAT_ENVIRONMENTS.filter((environment) => environment !== 'remote');\n const value: ChatEnvironment = remote || agentOnEdge ? 'remote' : 'local';\n const handleChange = useCallback((value: string) => setRemote(value === 'remote'), [setRemote]);\n\n return (\n <Listbox.Root\n value={value}\n onValueChange={handleChange}\n autoFocus\n items={environments.map((environment) => ({\n value: environment,\n label: t(`chat-environment.${environment}.label`),\n }))}\n >\n {/* No gutter: the popover's padding is the inset, shared with the tab bar below. */}\n <Listbox.Content gutter='none' aria-label={t('options.environment.title')}>\n {environments.map((environment) => (\n <Listbox.Item key={environment} id={environment} classNames='dx-focus-ring rounded-xs'>\n <Listbox.ItemText>{t(`chat-environment.${environment}.label`)}</Listbox.ItemText>\n <Listbox.ItemIndicator />\n </Listbox.Item>\n ))}\n </Listbox.Content>\n </Listbox.Root>\n );\n};\n\nconst CHAT_ENVIRONMENTS = ['local', 'remote'] as const;\n\ntype ChatEnvironment = (typeof CHAT_ENVIRONMENTS)[number];\n\nconst ModelsPanel = ({\n presets,\n preset,\n onPresetChange,\n}: Pick<ChatOptionsProps, 'presets' | 'preset' | 'onPresetChange'>) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n\n return (\n <Layout.Flex column classNames='dx-expand'>\n <Listbox.Root\n value={preset}\n onValueChange={onPresetChange}\n autoFocus\n items={(presets ?? []).map(({ id, label }) => ({ value: id, label: label }))}\n >\n <Listbox.Content gutter='none' aria-label={t('options.chat-model.title')} data-testid='assistant.models'>\n {presets?.map(({ id, label }) => (\n <Listbox.Item key={id} id={id} classNames='dx-focus-ring rounded-xs' data-testid={`assistant.models.${id}`}>\n <Listbox.ItemText>{label}</Listbox.ItemText>\n <Listbox.ItemIndicator />\n </Listbox.Item>\n ))}\n </Listbox.Content>\n </Listbox.Root>\n <Toolbar.Root>\n <OnlineSwitch />\n </Toolbar.Root>\n </Layout.Flex>\n );\n};\n\n/**\n * Online/offline as the control it looks like. It used to sit on the prompt row as a disabled\n * switch, which read as broken: the provider is one setting, so it belongs beside the model list\n * that setting chooses from.\n *\n * Off selects whichever local provider this build has — the bundled sidecar on desktop, an external\n * Ollama elsewhere — which is the same reconciliation `usePresets` does when it reads the setting.\n */\nconst OnlineSwitch = () => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const [settings, setSettings] = Hooks.useAtomCapabilityState(AssistantCapabilities.Settings);\n const hasBuiltIn = Hooks.useOptionalCapability(AssistantCapabilities.OllamaManager) !== undefined;\n const online = resolveProvider(settings.modelProvider, hasBuiltIn) === Provider.edge.id;\n\n const handleChange = useCallback(\n (checked: boolean) => {\n const provider = checked ? Provider.edge.id : hasBuiltIn ? Provider.builtIn.id : Provider.ollama.id;\n setSettings((current) => ({ ...current, modelProvider: provider }));\n },\n [setSettings, hasBuiltIn],\n );\n\n return (\n <Input.Switch\n checked={online}\n onCheckedChange={({ checked }) => handleChange(checked)}\n data-testid='assistant.online'\n label={t('online-switch.label')}\n />\n );\n};\n\ntype McpServerDraft = {\n name: string;\n url: string;\n protocol: McpServer.Spec['protocol'];\n apiKey?: string;\n};\n\ntype McpServersPanelProps = {\n db: Database.Database;\n};\n\nconst McpServersPanel = ({ db }: McpServersPanelProps) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const servers = useQuery(db, Filter.type(McpServer.McpServer));\n const [adding, setAdding] = useState(false);\n\n const handleAdd = useCallback(\n ({ name, url, protocol, apiKey }: McpServerDraft) => {\n // The key goes in an `AccessToken` rather than on the server, so it resolves through the\n // credentials service like every other secret in the space.\n const accessToken = apiKey\n ? db.add(AccessToken.make({ source: new URL(url).hostname, account: name, token: apiKey }))\n : undefined;\n db.add(\n Obj.make(McpServer.McpServer, {\n name,\n url,\n protocol,\n enabled: true,\n ...(accessToken && { accessToken: Ref.make(accessToken) }),\n }),\n );\n setAdding(false);\n },\n [db],\n );\n\n const handleRemove = useCallback(\n (server: McpServer.McpServer) => {\n const accessToken = server.accessToken?.peek();\n db.remove(server);\n if (accessToken) {\n db.remove(accessToken);\n }\n },\n [db],\n );\n\n return (\n <Layout.Flex column data-testid='assistant.mcp-servers'>\n <Listbox.Root items={servers.map((server) => ({ value: server.id, label: server.name ?? server.id }))}>\n <Listbox.Content aria-label={t('options.mcp.title')} classNames='gap-1'>\n {servers.map((server) => (\n <McpServerRow key={server.id} server={server} onRemove={handleRemove} />\n ))}\n </Listbox.Content>\n </Listbox.Root>\n {adding ? (\n <McpForm onSubmit={handleAdd} onCancel={() => setAdding(false)} />\n ) : (\n <Layout.Flex classNames='p-1'>\n <Button.Root\n variant='ghost'\n icon='ph--plus--regular'\n label={t('mcp-server-add.label')}\n onClick={() => setAdding(true)}\n data-testid='assistant.mcp-server.add'\n />\n </Layout.Flex>\n )}\n </Layout.Flex>\n );\n};\n\ntype McpServerRowProps = {\n server: McpServer.McpServer;\n onRemove: (server: McpServer.McpServer) => void;\n};\n\n/**\n * `useQuery` returns live objects but only re-renders on result-identity changes,\n * so we must subscribe to the per-server `enabled`/`oauth`/`name`/`url` fields via `useObject`\n * to keep the row in sync with mutations made through the returned setters (or elsewhere).\n */\nconst McpServerRow = ({ server, onRemove }: McpServerRowProps) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const [enabled, setEnabled] = useObject(server, 'enabled');\n // Subscribed so the status re-checks once a sign-in stores tokens.\n useObject(server, 'oauth');\n const [name] = useObject(server, 'name');\n const [url] = useObject(server, 'url');\n const [revision, setRevision] = useState(0);\n const status = useMcpServerStatus(server, { enabled: enabled !== false, revision });\n const { signIn, pending, error } = useMcpServerSignIn(server);\n const handleSignIn = useCallback(() => {\n void signIn().then(() => setRevision((revision) => revision + 1));\n }, [signIn]);\n\n const statusLabel =\n status.state === 'connected'\n ? t('mcp-server-status.connected', { count: status.tools.length })\n : status.state === 'error'\n ? status.message\n : t(`mcp-server-status.${status.state}`);\n\n return (\n <Listbox.Item id={server.id} classNames='flex-col items-stretch px-form-chrome' data-testid='assistant.mcp-server'>\n <Layout.Flex align='center' gap='sm'>\n <Field.Root>\n <Field.Label srOnly>{name}</Field.Label>\n <Input.Switch checked={enabled !== false} onCheckedChange={({ checked }) => setEnabled(!!checked)} />\n </Field.Root>\n <Layout.Flex column grow classNames='min-w-0'>\n <span className='truncate text-sm'>{name}</span>\n <span className='truncate text-xs text-fg-muted'>{url}</span>\n </Layout.Flex>\n {status.state === 'unauthorized' && (\n <Button.Root\n variant='primary'\n icon='ph--sign-in--regular'\n label={t('mcp-server-sign-in.label')}\n disabled={pending}\n onClick={handleSignIn}\n data-testid='assistant.mcp-server.sign-in'\n />\n )}\n {(status.state === 'error' || status.state === 'unauthorized') && (\n <Button.Root\n variant='ghost'\n icon='ph--arrow-clockwise--regular'\n iconOnly\n label={t('mcp-server-retry.label')}\n onClick={() => setRevision((revision) => revision + 1)}\n />\n )}\n <Button.Root\n variant='ghost'\n icon='ph--x--regular'\n iconOnly\n label={t('mcp-server-remove.label')}\n onClick={() => onRemove(server)}\n />\n </Layout.Flex>\n <span\n className={mx(\n 'text-xs truncate',\n status.state === 'connected' && 'text-success-text',\n (status.state === 'error' || status.state === 'unauthorized' || error) && 'text-error-text',\n )}\n title={error ?? statusLabel}\n data-testid='assistant.mcp-server.status'\n data-state={status.state}\n >\n {error ?? statusLabel}\n </span>\n </Listbox.Item>\n );\n};\n\ntype McpFormProps = {\n onSubmit: (draft: McpServerDraft) => void;\n onCancel: () => void;\n};\n\nconst McpForm = ({ onSubmit, onCancel }: McpFormProps) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const [name, setName] = useState('');\n const [url, setUrl] = useState('');\n // Streamable HTTP is the current transport; the client falls back to SSE when a server answers 405.\n const [protocol, setProtocol] = useState<McpServer.Spec['protocol']>('http');\n const [apiKey, setApiKey] = useState('');\n\n const validUrl = URL.canParse(url.trim());\n const canSubmit = name.trim().length > 0 && validUrl;\n const handleSubmit = useCallback(() => {\n if (canSubmit) {\n onSubmit({ name: name.trim(), url: url.trim(), protocol, apiKey: apiKey.trim() || undefined });\n }\n }, [canSubmit, name, url, protocol, apiKey, onSubmit]);\n\n return (\n <form\n className='space-y-2 px-form-chrome'\n onSubmit={(event) => {\n event.preventDefault();\n handleSubmit();\n }}\n >\n <Field.Root>\n <Field.Label srOnly>{t('mcp-server-name.label')}</Field.Label>\n <Input.Root\n placeholder={t('mcp-server-name.placeholder')}\n value={name}\n onChange={(event) => setName(event.target.value)}\n autoFocus\n data-testid='assistant.mcp-server.name'\n />\n </Field.Root>\n <Field.Root>\n <Field.Label srOnly>{t('mcp-server-url.label')}</Field.Label>\n <Input.Root\n type='url'\n placeholder={t('mcp-server-url.placeholder')}\n value={url}\n onChange={(event) => setUrl(event.target.value)}\n data-testid='assistant.mcp-server.url'\n />\n </Field.Root>\n <Select.Root\n value={[protocol]}\n onValueChange={({ value: [value] }) => setProtocol(value === 'sse' ? 'sse' : 'http')}\n items={[\n { value: 'http', label: 'HTTP' },\n { value: 'sse', label: 'SSE' },\n ]}\n >\n <Select.Trigger placeholder={t('mcp-server-protocol.label')} />\n <Select.Content>\n <Select.Item item={{ value: 'http', label: 'HTTP' }} />\n <Select.Item item={{ value: 'sse', label: 'SSE' }} />\n </Select.Content>\n </Select.Root>\n <Field.Root>\n <Field.Label srOnly>{t('mcp-server-api-key.label')}</Field.Label>\n <Input.Password\n ignorePasswordManagers\n placeholder={t('mcp-server-api-key.placeholder')}\n value={apiKey}\n onValueChange={setApiKey}\n data-testid='assistant.mcp-server.api-key'\n />\n </Field.Root>\n <Layout.Flex justify='end'>\n <SystemButton.Save\n type='submit'\n variant='ghost'\n disabled={!canSubmit}\n data-testid='assistant.mcp-server.save'\n />\n <SystemButton.Cancel type='button' variant='ghost' onClick={onCancel} />\n </Layout.Flex>\n </form>\n );\n};\n\nconst ANY = '__any__' as const;\n\n/** @private */\nexport const ObjectsPanel = ({ db, context }: Pick<ChatOptionsProps, 'db' | 'context'>): JSX.Element => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n\n // Item types sorted by label.\n const types = useFilteredTypes(db);\n const typeOptions = useMemo(() => {\n const options = types.map((type) => {\n const typename = Type.getTypename(type);\n return {\n uri: Type.getURI(type),\n label: t('typename.label', { ns: typename, defaultValue: typename }),\n };\n });\n\n options.sort((a, b) => a.label.localeCompare(b.label));\n return options;\n }, [types, t]);\n\n const typeItems = useMemo(\n () => [\n { value: ANY, label: t('any-type-filter.label') },\n ...typeOptions.map(({ uri, label }) => ({ value: uri, label })),\n ],\n [typeOptions, t],\n );\n\n // Current type URI and filter.\n const [selectedUri, setSelectedUri] = useState<URI.URI | typeof ANY>(ANY);\n const anyFilter = useMemo(() => Filter.or(...typeOptions.map(({ uri }) => Filter.type(uri))), [typeOptions]);\n\n // Context objects.\n const objects = useQuery(db, selectedUri === ANY ? anyFilter : Filter.type(selectedUri));\n const { objects: contextObjects, onUpdateObject } = useContextObjects({ db, context });\n const { results, handleSearch } = useSearchListResults({\n items: objects,\n extract: (object) => Obj.getLabel(object) ?? Obj.getTypename(object) ?? object.id,\n });\n\n return (\n <Layout.Flex column classNames='min-h-0 divide-y divide-separator'>\n {/* Shrinks to the popover's height, so the list scrolls rather than pushing the filter out of it. */}\n <SearchList.Root onSearch={handleSearch}>\n {/* No chrome padding: the rows align with the toolbar below, which is a sibling of\n `Content` and so sits flush against the panel edge. */}\n <SearchList.Content classNames='flex flex-col'>\n <SearchList.Viewport padding={false} classNames='min-h-0 flex-auto'>\n {results.length ? (\n results.map((object) => {\n const isActive = contextObjects.findIndex((obj) => obj.id === object.id) !== -1;\n const { icon, hue } = Obj.getIcon(object) ?? { icon: 'ph--cube--regular', hue: undefined };\n const styles = hue ? getStyles(hue) : undefined;\n return (\n <SearchList.Item\n classNames='overflow-hidden'\n key={object.id}\n value={object.id}\n icon={icon}\n iconClassNames={styles?.text}\n label={Obj.getLabel(object) ?? Obj.getTypename(object) ?? object.id}\n checked={isActive}\n onSelect={() => onUpdateObject?.(Obj.getURI(object), !isActive)}\n />\n );\n })\n ) : (\n <SearchList.Item value='__empty__' label={t('no-results.message')} />\n )}\n </SearchList.Viewport>\n </SearchList.Content>\n\n <Toolbar.Root>\n <SearchList.Input placeholder={t('search.placeholder')} autoFocus />\n <Select.Root\n items={typeItems}\n value={selectedUri === ANY ? [] : [selectedUri]}\n onValueChange={({ value: [value] }) =>\n setSelectedUri(typeOptions.find(({ uri }) => uri === value)?.uri ?? ANY)\n }\n >\n <Select.Trigger fixed placeholder={t('type-filter.placeholder')} />\n <Select.Content>\n {typeItems.map((item) => (\n <Select.Item key={item.value} item={item} />\n ))}\n </Select.Content>\n </Select.Root>\n </Toolbar.Root>\n </SearchList.Root>\n </Layout.Flex>\n );\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport React from 'react';\n\nimport { type AiContext } from '@dxos/assistant';\nimport { type Database, Obj } from '@dxos/echo';\nimport * as Button from '@dxos/react-ui/Button';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport * as Icon from '@dxos/react-ui/Icon';\nimport * as Theme from '@dxos/react-ui/Theme';\nimport type * as Util from '@dxos/react-ui/Util';\nimport { getStyles, mx } from '@dxos/ui-theme';\n\nimport { useContextObjects } from '#hooks';\nimport { meta } from '#meta';\n\nexport type ChatReferencesProps = Util.ThemedClassName<{\n context: AiContext.Binder;\n db: Database.Database;\n}>;\n\nexport const ChatReferences = ({ classNames, context, db }: ChatReferencesProps) => {\n const { t } = Hooks.useTranslation(meta.profile.key);\n const { objects, onUpdateObject } = useContextObjects({ db, context });\n\n return (\n <ul className={mx('flex gap-1', classNames)}>\n {objects.map((obj) => {\n const uri = Obj.getURI(obj);\n const typename = Obj.getTypename(obj);\n const label: Theme.Label =\n Obj.getLabel(obj) ?? (typename ? ['object-name.placeholder', { ns: typename }] : obj.id);\n const { icon, hue } = Obj.getIcon(obj) ?? { icon: DEFAULT_OBJECT_ICON, hue: undefined };\n const styles = hue ? getStyles(hue) : undefined;\n return (\n <li key={uri.toString()} className='dx-tag dx-tag-inline py-0 flex items-center gap-1' data-hue='neutral'>\n <Icon.Icon icon={icon} size='md' />\n {Theme.toLocalizedString(label, t)}\n <Button.Root\n icon='ph--x--bold'\n iconOnly\n variant='ghost'\n label={t('remove-object.label')}\n classNames='p-0 hover:bg-transparent'\n iconSize='xs'\n onClick={() => onUpdateObject?.(uri, false)}\n />\n </li>\n );\n })}\n </ul>\n );\n};\n\n// TODO(dmaretskyi): Extract those somewhere else.\nconst DEFAULT_OBJECT_ICON = 'ph--cube--regular';\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type RefObject, useCallback, useEffect, useMemo, useRef } from 'react';\n\nimport * as Hooks from '@dxos/app-framework/Hooks';\nimport { EdgeServiceName } from '@dxos/config';\nimport { log } from '@dxos/log';\nimport * as TranscriptionCapabilities from '@dxos/plugin-transcription/TranscriptionCapabilities';\nimport { useEdgeServiceEndpoint } from '@dxos/react-client';\nimport { type ChatEditorController } from '@dxos/react-ui-chat';\nimport { isNativeAudioInput, useAudioTrack, useTranscriber } from '@dxos/react-ui-transcription';\nimport * as UiHooks from '@dxos/react-ui/Hooks';\nimport { type ContentBlock } from '@dxos/types';\nimport { PendingTextStreamer, cancelPendingText, editorPendingTextSink, pendingTextState } from '@dxos/ui-editor';\n\nimport { meta } from '#meta';\n\n// Recorder chunk interval; the transcriber's chunk threshold is derived from the buffering setting.\nconst RECORDER_INTERVAL_MS = 200;\n\n/**\n * Drives word-by-word streaming transcription into the chat editor via PendingTextStreamer.\n * Reads the active RecordingSession and Settings capabilities; activates when the session id\n * matches the given docId and the session is recording.\n */\nexport const useChatVoiceInput = (docId: string, editorRef: RefObject<ChatEditorController | null>): void => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n // Voice input is optional: tolerate the transcription plugin being absent (no session ⇒ inactive).\n const [session, setSession] = Hooks.useOptionalAtomCapabilityState(TranscriptionCapabilities.RecordingSession);\n const [settings] = Hooks.useOptionalAtomCapabilityState(TranscriptionCapabilities.Settings);\n const endpoint = useEdgeServiceEndpoint(EdgeServiceName.Transcription);\n\n const active = !!session?.recording && session.id === docId;\n\n const streamerRef = useRef<PendingTextStreamer | null>(null);\n // Where the pending block will be opened, captured when recording begins: by the time the first\n // transcription lands the selection may have moved.\n const anchorRef = useRef<number | undefined>(undefined);\n const startedRef = useRef(false);\n\n // Create/destroy the streamer when active transitions.\n useEffect(() => {\n if (!active) {\n return;\n }\n const view = editorRef.current?.view;\n if (!view) {\n return;\n }\n\n const streamer = new PendingTextStreamer(editorPendingTextSink(view), {\n // Batch by default: a transcription arrives as a finished phrase, and revealing it word by word\n // lags the speaker by the length of what they just said.\n mode: settings?.streamMode ?? 'batch',\n wordIntervalMs: settings?.wordIntervalMs ?? 80,\n });\n // Deliberately not started here. `start` opens the pending-text block, which paints the\n // \"Recording…\" placeholder and its confirm/discard affordances the moment the mic is tapped —\n // occupying the prompt before there is anything to confirm. The block is opened lazily by the\n // first transcription instead (see `handleSegments`), so tapping the mic changes nothing visible\n // and text simply appears when it arrives.\n anchorRef.current = view.state.selection.main.head;\n startedRef.current = false;\n streamerRef.current = streamer;\n\n return () => {\n streamer.dispose();\n streamerRef.current = null;\n startedRef.current = false;\n // Drop the placeholder if nothing was transcribed; otherwise leave it for review.\n const currentView = editorRef.current?.view;\n if (currentView) {\n const pending = currentView.state.field(pendingTextState, false);\n if (pending && pending.final.length === 0) {\n currentView.dispatch({ effects: cancelPendingText.of() });\n }\n }\n };\n }, [active, settings?.streamMode, settings?.wordIntervalMs]);\n\n const handleSegments = useCallback(async (segments: ContentBlock.Transcript[]) => {\n const text = segments\n .map((segment) => segment.text)\n .join(' ')\n .trim();\n if (text.length > 0) {\n if (!startedRef.current) {\n startedRef.current = true;\n // No placeholder: the arriving text is the feedback.\n streamerRef.current?.start({ anchor: anchorRef.current });\n }\n streamerRef.current?.push(text);\n }\n }, []);\n\n // Derive the transcriber's chunk threshold from the configured initial buffering time.\n const transcriberConfig = useMemo(\n () => ({\n transcribeAfterChunksAmount: Math.max(\n 1,\n Math.round((settings?.transcribeAfterMs ?? 4000) / RECORDER_INTERVAL_MS),\n ),\n endpoint,\n }),\n [settings?.transcribeAfterMs, endpoint],\n );\n\n // Stable identity: a fresh object would change useTranscriber's memo deps every render.\n const recorderConfig = useMemo(() => ({ interval: RECORDER_INTERVAL_MS }), []);\n\n const audioConstraints = useMemo<MediaTrackConstraints | undefined>(\n () =>\n // A native selection is routed through the audio session, not through constraints: WebKit\n // rejects an id it did not issue, and the rejection stops capture entirely.\n settings?.audioDeviceId && !isNativeAudioInput(settings.audioDeviceId)\n ? { deviceId: { exact: settings.audioDeviceId } }\n : undefined,\n [settings?.audioDeviceId],\n );\n\n // Gate the mic on the endpoint: `useAudioTrack` calls `getUserMedia` as soon as its flag is\n // true, so without this the permission prompt and recording indicator appear before `open()`\n // rejects for a transcription service that was never configured.\n const track = useAudioTrack(active && !!endpoint, audioConstraints);\n\n const transcriber = useTranscriber({\n audioStreamTrack: track,\n transcriberConfig,\n recorderConfig,\n onSegments: handleSegments,\n });\n\n // `useTranscriber` only constructs (and eventually closes) the transcriber — opening it is the\n // consumer's job, and this hook never did, so `Transcriber._open` never ran, its recorder never\n // started, and no audio was captured. The placeholder appeared and nothing ever replaced it.\n useEffect(() => {\n if (!transcriber) {\n return;\n }\n let cancelled = false;\n void transcriber.open().then(\n () => {\n if (!cancelled && active) {\n transcriber.startChunksRecording();\n }\n },\n (err) => {\n // Clear the session on failure (e.g. the microphone was refused) so the prompt does not sit\n // showing \"recording\" against a transcriber that never opened.\n if (!cancelled) {\n log.catch(err);\n setSession?.(() => null);\n }\n },\n );\n\n return () => {\n cancelled = true;\n };\n }, [transcriber, active, setSession]);\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { EditorView } from '@codemirror/view';\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport * as Option from 'effect/Option';\nimport type * as Atom from 'effect/reactivity/Atom';\nimport React, { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';\n\nimport { type AiContext } from '@dxos/assistant';\nimport type * as Chat from '@dxos/assistant/Chat';\nimport { type Event } from '@dxos/async';\nimport * as Project from '@dxos/compute/Project';\nimport { type Database, Obj, type Registry } from '@dxos/echo';\nimport { useObject } from '@dxos/echo-react';\nimport {\n ChatEditor,\n type ChatEditorController,\n type ChatEditorProps,\n ChatStatusIndicator,\n commands,\n} from '@dxos/react-ui-chat';\nimport type { ActionGraphProps } from '@dxos/react-ui-menu';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport * as Layout from '@dxos/react-ui/Layout';\nimport type * as Util from '@dxos/react-ui/Util';\nimport { pendingText } from '@dxos/ui-editor';\nimport { type Merge } from '@dxos/util';\n\nimport { useChatKeymapExtensions } from '#hooks';\nimport { meta } from '#meta';\nimport { AssistantPreset } from '#types';\n\nimport { type ChatModel, getChatModelState } from '../../chat-model/index.ts';\nimport { TaskSlashCommands } from '../../commands/index.ts';\nimport { type ChatEvent } from '../Chat/index.ts';\nimport { ChatActions, type ChatActionsProps } from './ChatActions.tsx';\nimport { ChatMcpErrors } from './ChatMcpErrors.tsx';\nimport { ChatOptions } from './ChatOptions.tsx';\nimport { ChatReferences } from './ChatReferences.tsx';\nimport { useChatVoiceInput } from './useChatVoiceInput.ts';\n\n/** Prompts that may wait behind a running turn, by default. */\nexport const DEFAULT_MAX_QUEUE = 3;\n\nexport type ChatPromptProps = Merge<\n Util.ThemedClassName<{\n outline?: boolean;\n settings?: boolean;\n expandable?: boolean;\n db?: Database.Database;\n chat?: Chat.Chat;\n /** Undefined while the chat model is still opening: the prompt takes text but holds it until then. */\n chatModel?: ChatModel;\n /**\n * Bindings for a draft with no chat model, whose caller handles the submit event: backs the context\n * controls and lets the prompt send.\n */\n context?: AiContext.Binder;\n /** Skill registry for the context controls when there is no chat model. */\n registry?: Registry.Registry;\n event: Event<ChatEvent>;\n /** Whether the checklist beside the prompt is shown; the toggle renders only when provided. */\n tasksVisible?: boolean;\n /** The prompt's graph node, which is what contributed actions are filed under. */\n attendableId?: string;\n /** Toolbar actions other plugins filed on this chat's node (see `ChatActions`). */\n customActions?: Atom.Atom<ActionGraphProps>;\n /**\n * The graph node those actions were filed on. Keys the dictation session, because the mic that\n * opens it is one of them and carries the same id — anything else here is a session this prompt\n * would never hear.\n */\n nodeId?: string;\n placeholder?: ChatEditorProps['placeholder'];\n autoFocus?: boolean;\n /** How many prompts are waiting behind the running turn. */\n queueSize?: number;\n /** The most prompts that may wait behind a running turn; past it the prompt takes no more until one is taken up. */\n maxQueue?: number;\n /** Whether the conversation has begun, which fixes its agent. */\n started?: boolean;\n /** Object the chat is attached to; its project instructions (if any) supply sentinel-command completion. */\n companionTo?: Obj.Unknown;\n }>,\n AssistantPreset.ChatPresetProps\n>;\n\nexport const ChatPrompt = ({\n classNames,\n outline,\n db,\n chat,\n chatModel,\n context: draftContext,\n registry: draftRegistry,\n event,\n tasksVisible,\n attendableId,\n customActions,\n nodeId,\n placeholder,\n autoFocus = true,\n queueSize = 0,\n maxQueue = DEFAULT_MAX_QUEUE,\n settings = true,\n presets,\n preset,\n companionTo,\n started,\n onPresetChange,\n}: ChatPromptProps) => {\n const { t } = Hooks.useTranslation(meta.profile.key);\n const chatModelState = getChatModelState(chatModel);\n const error = useAtomValue(chatModelState.error).pipe(Option.getOrUndefined);\n const streaming = useAtomValue(chatModelState.streaming);\n const active = useAtomValue(chatModelState.active);\n const context = chatModel?.context ?? draftContext;\n const registry = chatModel?.registry ?? draftRegistry;\n\n const editorRef = useRef<ChatEditorController>(null);\n useEffect(() => {\n return event.on((ev) => {\n if (ev.type === 'update-prompt' && !editorRef.current?.getText()?.length) {\n editorRef.current?.setText(ev.text);\n editorRef.current?.focus();\n }\n });\n }, [event]);\n\n const fallbackDocId = useId();\n // The node the mic action was filed on, which is what it keys the recording session by. A chat\n // rendered as a companion is a companion node, not the chat object's own, so the object id is only\n // the fallback for a prompt rendered outside a plank.\n const docId = nodeId ?? (chat ? Obj.getURI(chat) : fallbackDocId);\n useChatVoiceInput(docId, editorRef);\n\n const keymapExtensions = useChatKeymapExtensions({ event });\n\n // Command completion: `$` sentinels come from the bound project's instructions; `/` commands\n // are the deterministic operation shortcuts (see assistant-toolkit `SlashCommands`).\n const [companion] = useObject(companionTo);\n const [instructions] = useObject(Obj.instanceOf(Project.Project, companion) ? companion.instructions : undefined);\n const commandsRef = Hooks.useDynamicRef(instructions?.commands ?? []);\n const commandsExtension = useMemo(\n () =>\n commands({\n getCommands: () => [\n ...commandsRef.current.map(({ sentinel, description }) => ({ sentinel, description })),\n ...TaskSlashCommands.map(({ command, description }) => ({ sentinel: command, description })),\n ],\n }),\n [commandsRef],\n );\n\n // The editor owns the prompt text; only its emptiness is mirrored into React so the send control\n // can disable itself without re-rendering the prompt on every keystroke's content. Dictation is\n // deliberately not counted: pending text lives in a StateField and reaches the document only when\n // the user confirms it, which is the same point at which Enter would stop committing and start\n // submitting.\n const [hasText, setHasText] = useState(false);\n const emptinessExtension = useMemo(\n () =>\n EditorView.updateListener.of((update) => {\n if (update.docChanged) {\n setHasText(update.state.doc.toString().trim().length > 0);\n }\n }),\n [],\n );\n\n // A full queue stops taking prompts: what is typed stays in the editor until the agent takes one up.\n const queueFull = active && queueSize >= maxQueue;\n const canSend = hasText && context != null && !queueFull;\n\n const extensions = useMemo(\n () => [keymapExtensions, pendingText(), commandsExtension, emptinessExtension],\n [keymapExtensions, commandsExtension, emptinessExtension],\n );\n\n // Submits while a turn is running too: the agent's input queue is feed state, so the prompt is\n // queued behind the running turn rather than dropped (`Chat.Root` sends it through the chat model's\n // outbox, which queues it while the agent is busy).\n const handleSubmit = useCallback<NonNullable<ChatEditorProps['onSubmit']>>(\n (text) => {\n if (!context || queueFull) {\n return false;\n }\n event.emit({ type: 'submit', text });\n return true;\n },\n [event, context, queueFull],\n );\n\n // Routed through `handleSubmit` so the button and the Enter keybinding share one submit path;\n // the reset and refocus mirror what the `submit()` extension does for Enter.\n const handleSend = useCallback(() => {\n const text = editorRef.current?.getText().trim();\n if (!text?.length) {\n return;\n }\n if (handleSubmit(text)) {\n editorRef.current?.setText('', true);\n }\n }, [handleSubmit]);\n\n const handleEvent = useCallback<NonNullable<ChatActionsProps['onEvent']>>(\n (ev) => {\n event.emit(ev);\n },\n [event],\n );\n\n return (\n <Layout.Flex\n column\n data-testid='assistant.prompt'\n role='group'\n classNames={[\n 'w-full dx-density-md',\n outline &&\n 'dx-group-surface rounded-sm border border-separator-subtle transition transition-border [&:has(.cm-content:focus)]:border-separator',\n classNames,\n ]}\n >\n {chatModel && <ChatMcpErrors chatModel={chatModel} />}\n\n <Layout.Flex gap='sm' classNames='p-2'>\n <ChatStatusIndicator classNames='p-1' preset={preset} error={error} processing={streaming} />\n <ChatEditor\n ref={editorRef}\n autoFocus={autoFocus}\n markdown\n lineWrapping\n classNames='col-span-2 pt-0.5'\n placeholder={placeholder ?? t('prompt.placeholder')}\n extensions={extensions}\n onSubmit={handleSubmit}\n />\n </Layout.Flex>\n\n {db &&\n settings && (\n // One toolbar for the row: the options and context chips lead, the chips' track takes the slack, the actions end it.\n <ChatActions\n classNames='p-1.5'\n attendableId={attendableId}\n customActions={customActions}\n // `active`, not `streaming`: a turn parked in a tool call streams nothing,\n // and the reader still needs a way to stop it.\n processing={active}\n canSend={canSend}\n tasksVisible={tasksVisible}\n onSend={handleSend}\n onEvent={handleEvent}\n leading={\n <>\n <ChatOptions\n db={db}\n chat={chat}\n registry={registry}\n context={context}\n started={started}\n preset={preset}\n presets={presets}\n onPresetChange={onPresetChange}\n />\n <Layout.Flex classNames='h-6 grow overflow-x-auto scrollbar-none'>\n {context && <ChatReferences db={db} context={context} />}\n </Layout.Flex>\n </>\n }\n />\n )}\n </Layout.Flex>\n );\n};\n\nChatPrompt.displayName = 'Chat.Prompt';\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { useEffect, useMemo, useState } from 'react';\n\nimport { Alarm } from '@dxos/assistant';\nimport { ChatStatus as NaturalChatStatus, formatElapsed } from '@dxos/react-ui-chat';\nimport { Matrix } from '@dxos/react-ui-experimental';\nimport * as Icon from '@dxos/react-ui/Icon';\nimport * as Layout from '@dxos/react-ui/Layout';\nimport type * as Util from '@dxos/react-ui/Util';\nimport { type ContentBlock } from '@dxos/types';\nimport { Unit } from '@dxos/util';\n\nimport { type ChatRequestTiming, useChatThreadContext } from '../Chat/context.ts';\n\nconst CHAT_STREAM_STATUS_NAME = 'Chat.StreamStatus';\nconst TICK_MS = 1_000;\n\nexport type ChatStreamStatusProps = Util.ThemedClassName<{\n icon?: boolean;\n}>;\n\nexport type ChatStatusViewProps = ChatStreamStatusProps & {\n /** Start/end of the most recent request; `endedAt: null` while it runs. */\n requestTiming?: ChatRequestTiming | null;\n /** Output tokens of the last completed turn. */\n lastOutputTokens?: number;\n /** Cumulative tokens across the session. */\n sessionTotalTokens?: number;\n /**\n * When the agent will next wake itself, if an alarm is pending. Plain values rather than the feed\n * record: this component only renders, and a live ECHO object cannot survive being passed as a\n * Storybook arg (its proxy rejects the mutation Storybook's arg handling performs).\n */\n alarm?: { wakeAt: number; message?: string };\n /** Alarms that have woken the agent since the last user prompt, shown against `Alarm.MAX_SELF_WAKES`. */\n selfWakes?: number;\n};\n\n/**\n * Live status pill rendered at the bottom of the chat thread.\n *\n * The block-widget host re-mounts this component each time wire's drip queue toggles\n * (`wireDrainingEffect`) — so all visible state is derived from chat-context values that\n * survive the unmount: the latest `stats` block on the chat context's `messages` for token counts,\n * and `requestTiming` (start/end wall-clock timestamps) for the elapsed value.\n *\n * Shows:\n * - elapsed seconds since the most recent request started (frozen at end-of-request)\n * - last completed turn's output token count (from the most recent `stats` content block)\n * - cumulative session total tokens across all `stats` content blocks\n */\nexport const ChatStatus = ({ classNames, icon }: ChatStreamStatusProps) => {\n // Read `messages` from the chat context (combines `useQuery(queue)` + the chat model's\n // pending atom) rather than `chatModel.messages` directly — the latter only contains\n // blocks streamed via the ephemeral `PartialBlock` channel, while finalized blocks\n // (including the per-turn `stats` block we read for token counts) are submitted to the\n // feed via `_submitMessage` and only show up through `useQuery`.\n const { messages, requestTiming, alarms, selfWakes } = useChatThreadContext(CHAT_STREAM_STATUS_NAME);\n\n const { lastOutputTokens, sessionTotalTokens } = useMemo(() => {\n let last: number | undefined;\n let total = 0;\n for (const message of messages) {\n for (const block of message.blocks) {\n if (isStats(block) && block.usage) {\n last = block.usage.outputTokens;\n total += block.usage.totalTokens ?? 0;\n }\n }\n }\n\n return { lastOutputTokens: last, sessionTotalTokens: total };\n }, [messages]);\n\n const nextAlarm = alarms.at(0);\n\n return (\n <ChatStatusView\n classNames={classNames}\n icon={icon}\n requestTiming={requestTiming}\n lastOutputTokens={lastOutputTokens}\n sessionTotalTokens={sessionTotalTokens}\n // The earliest pending alarm is the one that wakes the agent next, so it is the one worth a slot.\n alarm={nextAlarm && { wakeAt: nextAlarm.wakeAt, message: nextAlarm.message }}\n selfWakes={selfWakes}\n />\n );\n};\n\n/**\n * The pill itself, given resolved values. Split from {@link ChatStatus} so each slot — elapsed,\n * tokens, the next alarm — can be mounted and asserted in a story without a live chat model.\n */\nexport const ChatStatusView = ({\n classNames,\n icon,\n requestTiming,\n lastOutputTokens,\n sessionTotalTokens = 0,\n alarm,\n selfWakes = 0,\n}: ChatStatusViewProps) => {\n const isRunning = requestTiming != null && requestTiming.endedAt == null;\n const show = requestTiming || lastOutputTokens || sessionTotalTokens > 0 || alarm != null;\n if (!show) {\n return null;\n }\n\n return (\n <NaturalChatStatus.Root defaultRunning={false} classNames={['p-1.5 gap-2 text-sm', classNames]}>\n {icon && (\n <NaturalChatStatus.Icon>\n <Matrix\n classNames='size-5'\n dotClassNames='bg-primary-bg'\n dim={4}\n dotSize={3}\n count={10}\n interval={500}\n active={isRunning}\n />\n </NaturalChatStatus.Icon>\n )}\n {show && (\n <Layout.Flex align='center'>\n {requestTiming && (\n <NaturalChatStatus.Text classNames={isRunning && 'text-sky-text'}>\n <Elapsed timing={requestTiming} />\n </NaturalChatStatus.Text>\n )}\n {lastOutputTokens != null && (\n <>\n {requestTiming && <NaturalChatStatus.Separator />}\n <NaturalChatStatus.Text>↓ {Unit.Thousand(lastOutputTokens).toString()}</NaturalChatStatus.Text>\n </>\n )}\n {sessionTotalTokens > 0 && (\n <>\n {(requestTiming || lastOutputTokens != null) && <NaturalChatStatus.Separator />}\n <NaturalChatStatus.Text>Σ {Unit.Thousand(sessionTotalTokens).toString()}</NaturalChatStatus.Text>\n </>\n )}\n {alarm && (\n <>\n {(requestTiming || lastOutputTokens != null || sessionTotalTokens > 0) && <NaturalChatStatus.Separator />}\n <NaturalChatStatus.Text>\n <span\n data-testid='assistant.chat-status.alarm'\n className='flex items-center gap-1'\n title={alarm.message}\n >\n <Icon.Icon icon='ph--alarm--regular' size='md' />\n {formatWakeAt(alarm.wakeAt)}\n {selfWakes > 0 && (\n <span data-testid='assistant.chat-status.self-wakes' className='text-fg-muted'>\n {selfWakes}/{Alarm.MAX_SELF_WAKES}\n </span>\n )}\n </span>\n </NaturalChatStatus.Text>\n </>\n )}\n </Layout.Flex>\n )}\n </NaturalChatStatus.Root>\n );\n};\n\n/**\n * Wall-clock-derived elapsed display. Tick interval forces a re-render every second while\n * the request is active so the displayed value advances; once `endedAt` is set, the value\n * is frozen and the interval is no longer scheduled.\n */\nconst Elapsed = ({ timing }: { timing: ChatRequestTiming }) => {\n const isRunning = timing.endedAt == null;\n const [now, setNow] = useState(Date.now());\n useEffect(() => {\n if (!isRunning) {\n return;\n }\n\n const id = setInterval(() => setNow(Date.now()), TICK_MS);\n return () => clearInterval(id);\n }, [isRunning]);\n\n return <>{formatElapsed((timing.endedAt ?? now) - timing.startedAt)}</>;\n};\n\nconst isStats = (block: ContentBlock.Any): block is ContentBlock.Stats => block._tag === 'stats';\n\n/**\n * Wall-clock time an alarm fires. The clock is what the reader needs to act on (\"it will wake at\n * 14:20\"); a countdown would have to tick, and the alarm can be days out.\n */\nexport const formatWakeAt = (wakeAt: number): string =>\n new Date(wakeAt).toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { useMemo } from 'react';\n\nimport * as Surface from '@dxos/app-framework/Surface';\nimport * as AppSurface from '@dxos/app-toolkit/AppSurface';\nimport * as ToolkitObjectCard from '@dxos/app-toolkit/ObjectCard';\nimport { type Database, Obj } from '@dxos/echo';\nimport { useObject, useResolveRef } from '@dxos/echo-react';\nimport { URI } from '@dxos/keys';\nimport { type ObjectLinkProps, type WidgetDef } from '@dxos/ui-editor';\n\nexport type ObjectCardProps = {\n /** The object's URI. */\n eid: string;\n /** What the header reads while the object has no label of its own. */\n label?: string;\n /** The database the URI is resolved against; the chat's, so space-relative URIs resolve. */\n db?: Database.Database;\n};\n\n/**\n * An object, named by URI, as its card: the header names it, the body is the object's `CardContent`\n * surface. Resolved through the host's database, so a reference the model wrote before the object\n * loaded still lands once it does.\n */\nexport const ObjectCard = ({ db, eid, label }: ObjectCardProps) => {\n const uri = useMemo(() => (eid ? URI.make(eid) : undefined), [eid]);\n const ref = useMemo(() => (uri && db ? db.makeRef<Obj.Unknown>(uri) : undefined), [uri, db]);\n const object = useResolveRef(ref);\n const [subject] = useObject(object);\n if (!subject) {\n return null;\n }\n\n const title = Obj.getLabel(subject)?.trim() || label || '';\n return (\n <ToolkitObjectCard.Root>\n <ToolkitObjectCard.Header subject={subject} lines={1}>\n {title}\n </ToolkitObjectCard.Header>\n <Surface.Surface type={AppSurface.CardContent} data={{ subject }} limit={1} />\n </ToolkitObjectCard.Root>\n );\n};\n\nObjectCard.displayName = 'ObjectCard';\n\nexport type ObjectCardWidgetProps = ObjectLinkProps & Pick<ObjectCardProps, 'db'>;\n\n/** An object embedded in a message (``) as its card. */\nexport const ObjectCardWidget = ({ db, eid, label }: ObjectCardWidgetProps) => (\n <ObjectCard db={db} eid={eid} label={label} />\n);\n\nObjectCardWidget.displayName = 'ObjectCardWidget';\n\n/** The rough height of a card with a one-row body, so the row is measured near its size before the card resolves. */\nconst CARD_ESTIMATED_HEIGHT = 96;\n\n/** The `objectImage` widget for a thread whose objects live in `db`. */\nexport const objectCardWidget = (db?: Database.Database): WidgetDef<ObjectLinkProps> => ({\n block: true,\n estimatedHeight: () => CARD_ESTIMATED_HEIGHT,\n heightMode: 'min',\n Component: (props) => <ObjectCardWidget {...props} db={db} />,\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { useMemo } from 'react';\n\nimport * as Surface from '@dxos/app-framework/Surface';\nimport { log } from '@dxos/log';\nimport { type WidgetProps, getXmlTextChild } from '@dxos/ui-editor';\n\nimport { ChatSurface } from '#types';\n\n/**\n * Renders an agent-requested UI surface (the `<surface>` content block) by dispatching to a\n * registered {@link ChatSurface.ChatSurface} surface keyed on its `role`. The payload is carried as JSON in the\n * tag's text content; a malformed payload renders the surface with no data rather than throwing.\n */\nexport const SurfaceWidget = ({ role, children }: WidgetProps<{ role?: string }>) => {\n const data = useMemo(() => {\n const raw = getXmlTextChild(children ?? []);\n if (!raw) {\n return undefined;\n }\n try {\n const parsed: unknown = JSON.parse(raw);\n // Model-supplied JSON payload: narrowed to a non-array object; no typed schema exists at this boundary.\n return parsed != null && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : undefined;\n } catch (err) {\n log.warn('failed to parse surface data', { raw, err });\n return undefined;\n }\n }, [children]);\n\n if (!role) {\n return null;\n }\n\n return <Surface.Surface type={ChatSurface.ChatSurface} data={{ role, data }} limit={1} />;\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport { Collapsible } from '@ark-ui/react/collapsible';\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport * as Option from 'effect/Option';\nimport * as Atom from 'effect/reactivity/Atom';\nimport React, { type PropsWithChildren, useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { SessionConfig } from '@dxos/ai';\nimport * as Hooks from '@dxos/app-framework/Hooks';\nimport { Alarm } from '@dxos/assistant';\nimport * as SlashCommand from '@dxos/assistant-toolkit/SlashCommand';\nimport * as AssistantChat from '@dxos/assistant/Chat';\nimport { Event } from '@dxos/async';\nimport { type Database, Filter, Obj, Query } from '@dxos/echo';\nimport { useObject, useQuery } from '@dxos/echo-react';\nimport { useIdentity } from '@dxos/halo-react';\nimport { PublicKey, type URI } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport {\n type ChatThreadController,\n type ChatThreadEvent,\n type ChatView,\n ChatThread as NaturalChatThread,\n} from '@dxos/react-ui-assistant';\nimport {\n type MessageRange,\n type OutlineMarker,\n Outline as OutlineRail,\n isPrompt,\n useFeedModel,\n} from '@dxos/react-ui-feed';\nimport { ActionToolbar, type ActionToolbarProps, createMenuAction } from '@dxos/react-ui-menu';\nimport { TaskList, TaskQuestion } from '@dxos/react-ui-task';\nimport * as UiHooks from '@dxos/react-ui/Hooks';\nimport * as Layout from '@dxos/react-ui/Layout';\nimport * as Toast from '@dxos/react-ui/Toast';\nimport * as Util from '@dxos/react-ui/Util';\nimport { Message, Task } from '@dxos/types';\nimport { keyToFallback, markWork } from '@dxos/util';\n\nimport { type ChatSwitcher, useChatToolbarActions, useDebug } from '#hooks';\nimport { meta } from '#meta';\nimport { AssistantOperation } from '#types';\n\nimport {\n AiUsageQuotaError,\n type ChatRequestContext,\n getChatModelState,\n projectAlarms,\n projectSelfWakes,\n resolveRewind,\n} from '../../chat-model/index.ts';\nimport { TaskSlashCommands } from '../../commands/index.ts';\nimport {\n ChatStatus,\n DEFAULT_MAX_QUEUE,\n ChatActivity as NaturalChatActivity,\n ChatPrompt as NaturalChatPrompt,\n type ChatPromptProps as NaturalChatPromptProps,\n} from '../ChatPrompt/index.ts';\nimport {\n ChatContextProvider,\n type ChatContextValue,\n ChatReportContextProvider,\n type ChatRequestTiming,\n ChatThreadContextProvider,\n useChatContext,\n useChatThreadContext,\n} from './context.ts';\nimport { type ChatEvent } from './events.ts';\nimport { objectCardWidget } from './ObjectCardWidget.tsx';\nimport { SurfaceWidget } from './SurfaceWidget.tsx';\n\n//\n// Root\n//\n\ntype ChatRootProps = PropsWithChildren<\n Pick<ChatContextValue, 'chat' | 'chatModel' | 'debug'> & {\n /** Fallback database when the chat is transient (not yet persisted). */\n db?: Database.Database;\n onEvent?: (event: ChatEvent) => void;\n /**\n * Runs (and is awaited) before the request fires on submit. Lets a transient chat\n * persist and flush its conversation feed so the agent can resolve it.\n */\n onSubmit?: (text: string) => Promise<void> | void;\n /** Called at submit time to capture ephemeral request context (e.g. companion selection). */\n getContext?: () => ChatRequestContext | undefined;\n }\n>;\n\nconst ChatRoot = ({\n children,\n chat,\n chatModel,\n db: dbFallback,\n debug: debugProp,\n onEvent,\n onSubmit,\n getContext,\n ...props\n}: ChatRootProps) => {\n const [debug, setDebug] = useState(debugProp ?? false);\n // Slash commands run their operations through the same invoker the rest of the UI uses.\n const { invokePromise } = Hooks.useOperationInvoker();\n const chatModelState = getChatModelState(chatModel);\n const streaming = useAtomValue(chatModelState.streaming);\n const active = useAtomValue(chatModelState.active);\n const requestTiming = useRequestTiming({ active });\n const lastPrompt = useRef<string | undefined>(undefined);\n // A slash command runs outside the chat model, so `streaming` does not cover it.\n const commandPending = useRef(false);\n // Transient chats have no database of their own; fall back to the supplied space db so\n // the message query and context controls operate before the chat is persisted.\n const db = (chat && Obj.getDatabase(chat)) || dbFallback;\n\n // Reactive subscription — re-renders when the feed ref resolves. Direct `.target` reads are not reactive.\n const [feedSnapshot] = useObject(chat?.feed);\n const feed = Obj.getReactiveOrUndefined(feedSnapshot);\n\n // Event sink.\n const event = useMemo(() => new Event<ChatEvent>(), []);\n\n // The thread controller and visible range are produced by `Chat.Thread` and consumed by\n // `Chat.Outline`; lifted here so both sub-components share the same instance.\n const [controller, setController] = useState<ChatThreadController | null>(null);\n const [visibleRange, setVisibleRange] = useState<MessageRange | undefined>(undefined);\n\n const feedAlarms = useQuery(\n db,\n feed ? Query.select(Filter.type(Alarm.Alarm)).from(feed) : Query.select(Filter.nothing()),\n );\n // The chat model queries the feed and reconciles it with the streamed turn and the outbox.\n const { messages, delivery, queued, tail } = useAtomValue(chatModelState.thread);\n const alarms = useMemo(() => projectAlarms({ feedAlarms }), [feedAlarms]);\n const selfWakes = useMemo(() => projectSelfWakes({ feedAlarms, messages }), [feedAlarms, messages]);\n\n const dump = useDebug({ chatModel });\n\n // Surface chat model failures (e.g., AI service unavailable) to subscribers via the event bus.\n const error = useAtomValue(chatModelState.error);\n useEffect(() => {\n if (Option.isSome(error)) {\n event.emit({ type: 'error', error: error.value });\n }\n }, [event, error]);\n\n useEffect(() => {\n return event.on((ev) => {\n switch (ev.type) {\n case 'toggle-debug': {\n setDebug((debug) => {\n if (debug) {\n return false;\n } else {\n void dump();\n return true;\n }\n });\n break;\n }\n\n case 'rewind': {\n // Edit-and-resend: discard the prompt and everything after it, and put its text back in the\n // composer so it can be revised. Recorded on the feed rather than the chat because the\n // continuation is appended by the agent's process, which resolves the feed and never sees the\n // chat. A stale click (message already gone) resolves to nothing and is a no-op. A prompt sent\n // from here keeps its own row id, so the feed is pointed at its turn's message.\n const rewind = feed && resolveRewind(messages, ev.id);\n if (rewind) {\n Obj.update(feed, (feed) => {\n feed.rewindFrom = delivery.get(rewind.rewindFrom)?.turnId ?? rewind.rewindFrom;\n });\n event.emit({ type: 'update-prompt', text: rewind.text });\n }\n break;\n }\n\n case 'remove-prompt': {\n // Withdrawing a prompt the agent has not taken up: the queue is feed state, so removing the\n // entry is what takes it out of the agent's queue, and the outbox forgets this client's copy.\n const row = delivery.get(ev.id);\n if (row?.status === 'failed' || row?.status === 'delivered') {\n if (row.entryId && db && feed) {\n void db.removeFeedItemsByIds(feed, [row.entryId]).catch((err) => log.catch(err));\n }\n if (row.outboxId) {\n chatModel?.removePrompt(row.outboxId);\n }\n }\n break;\n }\n }\n\n onEvent?.(ev);\n });\n // `feed`, `messages` and `delivery` are dependencies because the rewind and prompt branches read\n // them: without them the handler would keep resolving against whatever was mounted first.\n }, [event, dump, onEvent, db, feed, messages, delivery, chatModel]);\n\n useEffect(() => {\n return event.on((ev) => {\n if (ev.type !== 'respond' || !chat) {\n return;\n }\n const { messageId, requestId, optionId } = ev;\n // The operation reads the chat's feed, so it runs in the chat's space.\n const spaceId = Obj.getDatabase(chat)?.spaceId;\n void invokePromise(\n AssistantOperation.RespondToRequest,\n { chat, messageId, requestId, optionId },\n spaceId ? { spaceId } : undefined,\n ).then(({ error }) => {\n if (error) {\n event.emit({ type: 'error', error });\n }\n });\n });\n }, [event, chat, invokePromise]);\n\n useEffect(() => {\n if (!chatModel) {\n return;\n }\n\n return event.on((ev) => {\n switch (ev.type) {\n case 'submit': {\n const text = ev.text.trim();\n if (text.length) {\n // A leading /command is a deterministic shortcut — executed directly, no model in\n // the loop; an unknown command falls through to the model as plain text.\n const resolved = SlashCommand.resolveSlashCommand(text, TaskSlashCommands);\n if (resolved) {\n // One command at a time: `invokePromise` does not queue, so two quick submissions\n // would interleave their operations and land their summaries out of order.\n if (commandPending.current) {\n break;\n }\n commandPending.current = true;\n // One rejection handler for the whole chain: `onSubmit` can throw synchronously and\n // `appendToFeed` can reject, and either would otherwise be lost with no error shown.\n void (async () => {\n await Promise.resolve(onSubmit?.(text));\n // Re-read after `onSubmit`: that is what persists a transient chat, so a chat that\n // began without a database has one only now.\n const currentDb = (chat && Obj.getDatabase(chat)) || db;\n if (!chat || !currentDb) {\n throw new Error('Command requires a persisted chat.');\n }\n\n const result = await resolved.command.execute(resolved.args, {\n db: currentDb,\n chat,\n invoke: invokePromise,\n });\n if (result instanceof Error) {\n throw result;\n }\n\n // The command's effect is otherwise invisible in the conversation: the prompt was\n // never sent, so nothing records that the user ran it. The feed is re-read here\n // because `onSubmit` is what persists a transient chat, creating it.\n const currentFeed = feed ?? chat.feed?.target;\n if (currentFeed && result.summary) {\n await currentDb.appendToFeed(currentFeed, [\n Message.make({ sender: { role: 'user' }, blocks: [{ _tag: 'text', text }] }),\n Message.make({ sender: { role: 'assistant' }, blocks: [{ _tag: 'text', text: result.summary }] }),\n ]);\n }\n\n if (result.followUp) {\n // Some effects run on the supervisor loop (delegation spawns post-turn), so the\n // command wakes the conversation with a short synthetic prompt.\n void chatModel.request({ message: result.followUp });\n }\n })()\n .catch((error) => {\n event.emit({ type: 'error', error: error instanceof Error ? error : new Error(String(error)) });\n })\n .finally(() => {\n commandPending.current = false;\n });\n break;\n }\n // The prompt's own guard does not cover submits emitted elsewhere (a checklist's execute action).\n if (active && queued >= DEFAULT_MAX_QUEUE) {\n break;\n }\n markWork('chat.submit');\n lastPrompt.current = ev.text;\n // Optimistic: the prompt is in the thread from this call on, before `onSubmit` persists a\n // transient chat and before the agent acknowledges it. The chat model requests it when the\n // agent is idle and queues it behind a running turn otherwise.\n chatModel.send({ message: text, context: getContext?.() }, { prepare: () => onSubmit?.(text) });\n }\n break;\n }\n\n case 'report': {\n const text = ev.text.trim();\n if (text.length) {\n // Same seam as a submitted prompt (persist first, queue while a turn runs), but the\n // content is synthetic — nobody typed it.\n void Promise.resolve(onSubmit?.(text)).then(() =>\n active\n ? chatModel.enqueue({ message: text, disposition: 'synthetic' })\n : chatModel.request({ message: text, disposition: 'synthetic' }),\n );\n }\n break;\n }\n\n case 'retry': {\n if (!streaming) {\n void chatModel.retry();\n }\n break;\n }\n\n case 'cancel': {\n void chatModel.cancel();\n if (streaming) {\n if (lastPrompt.current) {\n event.emit({ type: 'update-prompt', text: lastPrompt.current });\n }\n }\n break;\n }\n }\n });\n }, [event, chatModel, streaming, active, queued, onSubmit, getContext, invokePromise, chat, db, feed]);\n\n // An inline surface (connector prompt, plugin prompt) reports its completed flow as a synthetic\n // turn, so the agent resumes without the report reading as something the user typed.\n const handleReport = useCallback((text: string) => event.emit({ type: 'report', text }), [event]);\n\n return (\n <ChatContextProvider\n debug={debug}\n event={event}\n db={db}\n chat={chat}\n chatModel={chatModel}\n queueSize={queued}\n started={messages.length > 0 || queued > 0}\n setController={setController}\n setVisibleRange={setVisibleRange}\n {...props}\n >\n <ChatThreadContextProvider\n messages={messages}\n tail={tail}\n alarms={alarms}\n selfWakes={selfWakes}\n requestTiming={requestTiming}\n controller={controller}\n visibleRange={visibleRange}\n >\n <ChatReportContextProvider submit={handleReport}>{children}</ChatReportContextProvider>\n </ChatThreadContextProvider>\n </ChatContextProvider>\n );\n};\n\nChatRoot.displayName = 'Chat.Root';\n\nconst useRequestTiming = ({ active }: { active: boolean }) => {\n const [requestTiming, setRequestTiming] = useState<ChatRequestTiming | null>(null);\n useEffect(() => {\n if (active) {\n setRequestTiming({ startedAt: Date.now(), endedAt: null });\n } else {\n setRequestTiming((prev) => (prev && prev.endedAt == null ? { ...prev, endedAt: Date.now() } : prev));\n }\n }, [active]);\n\n return requestTiming;\n};\n\n//\n// Toolbar\n//\n\nconst CHAT_TOOLBAR_NAME = 'Chat.Toolbar';\n\ntype ChatToolbarProps = Pick<ActionToolbarProps, 'attendableId' | 'alwaysActive'> &\n PropsWithChildren<{\n companionTo?: Obj.Unknown;\n /** Scopes the chat switcher; defaults to the companion chats of `companionTo`. */\n switcher?: ChatSwitcher;\n }>;\n\nconst ChatToolbar = Util.composable<HTMLDivElement, ChatToolbarProps>(\n ({ children, attendableId, alwaysActive, companionTo, switcher, ...props }, forwardedRef) => {\n const { chat } = useChatContext(CHAT_TOOLBAR_NAME);\n const menuActions = useChatToolbarActions({ chat, companionTo, switcher });\n\n return (\n <ActionToolbar\n {...menuActions}\n attendableId={attendableId}\n alwaysActive={alwaysActive}\n {...Util.composableProps(props)}\n ref={forwardedRef}\n >\n {children}\n </ActionToolbar>\n );\n },\n);\n\nChatToolbar.displayName = CHAT_TOOLBAR_NAME;\n\n//\n// Content\n//\n\nconst CHAT_CONTENT_NAME = 'Chat.Content';\n\ntype ChatContentProps = {};\n\nconst ChatContent = Util.composable<HTMLDivElement, ChatContentProps>(({ children, ...props }, forwardedRef) => {\n return (\n <div {...Util.composableProps(props, { classNames: 'dx-expand flex flex-col' })} ref={forwardedRef}>\n {children}\n </div>\n );\n});\n\nChatContent.displayName = CHAT_CONTENT_NAME;\n\n//\n// Markers\n//\n\nconst PROMPT_SNIPPET_LINES = 3;\nconst PROMPT_SNIPPET_CHARS = 280;\nconst PROMPT_TITLE_CHARS = 100;\n\n/**\n * The text the reader actually wrote. Synthetic blocks carry injected context and tool results, so\n * titling a marker from them would name the machinery rather than the prompt.\n */\nconst authoredText = (message: Message.Message): string =>\n message.blocks\n .flatMap((block) => (block._tag === 'text' && block.disposition !== 'synthetic' ? [block.text] : []))\n .join('\\n');\n\n/** First non-empty line of a message's text, truncated for the marker title. */\nconst promptTitle = (message: Message.Message): string => {\n const text = authoredText(message).trim();\n const firstLine = text.split('\\n').find((line) => line.trim().length) ?? '';\n return firstLine.length > PROMPT_TITLE_CHARS ? `${firstLine.slice(0, PROMPT_TITLE_CHARS)}…` : firstLine;\n};\n\n/** First few text lines of an assistant reply (tool calls, reasoning and status are excluded). */\nconst replySnippet = (message: Message.Message): string | undefined => {\n // `extractText` keeps only `text` blocks, so tool calls / reasoning / status are dropped.\n const text = Message.extractText(message).trim();\n if (!text.length) {\n return undefined;\n }\n const snippet = text\n .split('\\n')\n .filter((line) => line.trim().length)\n .slice(0, PROMPT_SNIPPET_LINES)\n .join('\\n');\n return snippet.length > PROMPT_SNIPPET_CHARS ? `${snippet.slice(0, PROMPT_SNIPPET_CHARS)}…` : snippet;\n};\n\n/**\n * Build one outline marker per user-prompt turn: title = the prompt text, description = a snippet\n * of the following assistant reply, range = the turn's index span (prompt → next prompt). Message\n * indices, not document offsets: the feed navigates by index, so no range table exists any more.\n */\nconst buildMarkers = (messages: Message.Message[]): OutlineMarker[] => {\n const markers: OutlineMarker[] = [];\n for (let index = 0; index < messages.length; index++) {\n const message = messages[index];\n // Role alone would also match tool results and injected context, which travel back as\n // `user`-role messages; `isPrompt` is the feed's single definition of a stop.\n if (!isPrompt(message)) {\n continue;\n }\n\n // Extend the turn up to the next prompt: a tool-result turn belongs to the turn it serves, so\n // stopping on any `user`-role message would cut the range at the first tool call.\n let turnTo = index + 1;\n let description: string | undefined;\n for (let next = index + 1; next < messages.length; next++) {\n const nextMessage = messages[next];\n if (isPrompt(nextMessage)) {\n break;\n }\n turnTo = next + 1;\n if (!description && nextMessage.sender.role === 'assistant') {\n description = replySnippet(nextMessage);\n }\n }\n\n markers.push({\n id: message.id,\n title: promptTitle(message) || 'Prompt',\n description,\n range: { from: index, to: turnTo },\n });\n }\n return markers;\n};\n\n//\n// Thread\n//\n\nconst CHAT_THREAD_NAME = 'Chat.Thread';\n\n/** The plugin's `surface` widget layered over the package registry: it can dispatch a Surface. */\nconst chatRegistry = {\n surface: {\n block: true,\n Component: SurfaceWidget,\n },\n} as const;\n\ntype ChatThreadProps = Util.ThemedClassName<{\n viewType?: ChatView;\n /** Blank lines kept below the tail at rest — breathing room above the composer. */\n tailLines?: number;\n /** Hue of the user's messages; defaults to the identity's hue. */\n userHue?: string;\n /** Invoked from the over-quota error toast to open the usage dashboard. */\n onViewUsage?: () => void;\n}>;\n\nconst ChatThread = ({ classNames, viewType, tailLines, userHue: userHueProp, onViewUsage }: ChatThreadProps) => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const { chat, db, debug, event, chatModel, setController, setVisibleRange } = useChatContext(CHAT_THREAD_NAME);\n const { messages, tail } = useChatThreadContext(CHAT_THREAD_NAME);\n const identity = useIdentity();\n // Embedded objects resolve against the chat's database (the fallback one while it is transient).\n const objectImage = useMemo(() => objectCardWidget(db), [db]);\n // A block reference's chip reads the object's name once it is loaded — resolved through the\n // database's own ref, which honours the URI's space and the DXN forms — and the package default's\n // bare \"Object\" until then; the thread re-renders as the message's blocks settle.\n const getObjectLabel = useCallback(\n (uri: URI.URI): string => {\n let object: Obj.Unknown | undefined;\n try {\n object = db?.makeRef<Obj.Unknown>(uri).target;\n } catch {\n object = undefined;\n }\n return (object && Obj.getLabel(object)) || 'Object';\n },\n [db],\n );\n const [toastError, setToastError] = useState<Error | undefined>(undefined);\n // The toast renders whatever action the error declares (data-driven) rather than branching on type.\n const toastAction = toastError instanceof AiUsageQuotaError ? toastError.action : undefined;\n\n // The model is the adapter: the projected array is folded in with `replace`, streaming chunks\n // arrive as updates on one identity, and the window is told — the old `MessageSyncer`'s cursor\n // and range table have no equivalent left.\n const model = useFeedModel(messages, { stops: 'prompt' });\n const streaming = useAtomValue(getChatModelState(chatModel).streaming);\n useEffect(() => {\n // The answer streams above any prompts still waiting for the agent, which end the thread.\n const last = messages[messages.length - 1 - tail];\n model.setStreaming(streaming && last?.sender.role === 'assistant' ? last.id : undefined);\n }, [model, streaming, messages, tail]);\n\n const userHue = useMemo(\n () =>\n userHueProp ||\n identity?.data?.hue ||\n keyToFallback(identity?.identityKey ? PublicKey.fromHex(identity.identityKey) : PublicKey.random()).hue,\n [userHueProp, identity],\n );\n\n const controllerRef = useRef<ChatThreadController | null>(null);\n // Share the controller with `Chat.Outline` (and keep the local ref for event handling).\n const handleControllerRef = useCallback(\n (instance: ChatThreadController | null) => {\n controllerRef.current = instance;\n setController(instance);\n },\n [setController],\n );\n\n useEffect(() => {\n return event.on((event) => {\n switch (event.type) {\n case 'submit':\n case 'scroll-to-bottom':\n controllerRef.current?.scrollToBottom();\n break;\n case 'nav-previous':\n controllerRef.current?.navigation.step(-1);\n break;\n case 'nav-next':\n controllerRef.current?.navigation.step(1);\n break;\n case 'error':\n setToastError(event.error);\n break;\n default:\n log.info('no handled', event);\n }\n });\n }, [event]);\n\n // Rewind (the prompt toolbar) and submit (suggestion/select widgets) land on the shared bus,\n // where `Chat.Root` already resolves them.\n const handleEvent = useCallback((ev: ChatThreadEvent) => event.emit(ev), [event]);\n\n if (!identity) {\n return <div className='dx-expand' />;\n }\n\n return (\n <>\n <NaturalChatThread.Root\n model={model}\n viewType={viewType}\n registry={chatRegistry}\n objectImage={objectImage}\n getObjectLabel={getObjectLabel}\n userHue={userHue}\n tailLines={tailLines}\n debug={debug}\n // An external agent keeps its own context, which a rewind of the transcript cannot reach.\n rewind={SessionConfig.harnessOf(chat?.session) === SessionConfig.COMPOSER_HARNESS}\n onEvent={handleEvent}\n onRangeChange={setVisibleRange}\n controllerRef={handleControllerRef}\n >\n <NaturalChatThread.Viewport classNames={classNames} />\n </NaturalChatThread.Root>\n\n {/* TODO(burdon): Why is this required? */}\n <Toast.Root\n data-testid='assistant.error'\n open={!!toastError}\n duration={20_000}\n onOpenChange={(open) => !open && setToastError(undefined)}\n >\n <Toast.Header icon='ph--warning--regular'>{t('ai-service-error.label')}</Toast.Header>\n <Toast.Description>{toastError?.message}</Toast.Description>\n {toastAction && onViewUsage && (\n <Toast.Footer>\n <Toast.ActionTrigger\n onClick={() => {\n setToastError(undefined);\n onViewUsage();\n }}\n >\n {t(toastAction.labelKey)}\n </Toast.ActionTrigger>\n </Toast.Footer>\n )}\n </Toast.Root>\n </>\n );\n};\n\nChatThread.displayName = CHAT_THREAD_NAME;\n\n//\n// Outline\n//\n\nconst CHAT_OUTLINE_NAME = 'Chat.Outline';\n\ntype ChatOutlineProps = Util.ThemedClassName<{}>;\n\n/**\n * Anchor-marker rail for the thread: one tick per user-prompt turn. Reads the shared controller\n * and the visible index range from context; clicking a tick jumps the thread to that turn, on the\n * same navigation seam as the toolbar and the arrow keys.\n */\nconst ChatOutline = ({ classNames }: ChatOutlineProps) => {\n const { messages, visibleRange, controller } = useChatThreadContext(CHAT_OUTLINE_NAME);\n\n const markers = useMemo(() => buildMarkers(messages), [messages]);\n const handleSelect = useCallback(\n (marker: OutlineMarker) => {\n controller?.navigation.jumpTo(marker.range.from, 'smooth');\n },\n [controller],\n );\n const handleNavigate = useCallback((delta: number) => controller?.navigation.step(delta), [controller]);\n\n if (markers.length < 2) {\n return null;\n }\n\n return (\n <OutlineRail\n classNames={classNames}\n markers={markers}\n // `endIndex` is inclusive; the rail's `to` is exclusive.\n visibleRange={visibleRange ? { from: visibleRange.startIndex, to: visibleRange.endIndex + 1 } : undefined}\n onSelect={handleSelect}\n onNavigate={handleNavigate}\n />\n );\n};\n\nChatOutline.displayName = CHAT_OUTLINE_NAME;\n\n//\n// Prompt\n//\n\nconst CHAT_PROMPT_NAME = 'Chat.Prompt';\n\ntype ChatPromptProps = Omit<\n NaturalChatPromptProps,\n 'chat' | 'db' | 'chatModel' | 'event' | 'tasksVisible' | 'started'\n> & {\n /** Whether the checklist is disclosed on mount. */\n defaultTasksVisible?: boolean;\n};\n\n/**\n * The composer with the chat's checklist disclosed above it.\n *\n * One component rather than two siblings: they share a border and a rounded shell, and the control\n * that discloses the checklist lives in the composer's own action bar — so a host that placed them\n * side by side had to hold the disclosure state between them and coordinate the corner radius.\n *\n * Ark's `Collapsible` owns the disclosure (it measures the height the animation ramps against). Its\n * trigger is not used: the toggle is a button inside the composer, which reports through the chat\n * event rather than being wrapped in a `Collapsible.Trigger` it cannot reach.\n */\nconst ChatPrompt = ({ classNames, defaultTasksVisible = false, ...props }: ChatPromptProps) => {\n const { chat, db, chatModel, event, queueSize, started } = useChatContext(CHAT_PROMPT_NAME);\n\n // A chat with no checklist at all has nothing to disclose, so the toggle is withheld rather than\n // shown pointing at nothing — `ChatActions` renders it only when `tasksVisible` is defined.\n const [tasks] = useObject(chat, 'tasks');\n const hasTasks = tasks != null;\n\n // Collapsed by default: the checklist is the assistant's working state, not the reader's, so the\n // prompt keeps the room and the toggle is how they ask for it. Per mount rather than persisted —\n // it is a glance, not a preference.\n const [tasksVisible, setTasksVisible] = useState(chat?.tasks?.length ? defaultTasksVisible : false);\n useEffect(() => {\n return event.on((ev) => {\n if (ev.type === 'toggle-tasks') {\n setTasksVisible((visible) => !visible);\n }\n });\n }, [event]);\n\n return (\n <Collapsible.Root\n open={tasksVisible}\n onOpenChange={({ open }) => setTasksVisible(open)}\n // Clipped rather than unmounted: the list holds its own subscriptions, and remounting it on\n // every toggle would refetch the checklist to show what the reader just hid.\n lazyMount={false}\n >\n {/* The height the machine measures is what the ramp animates against, so the region clips. */}\n {hasTasks && (\n <Collapsible.Content className='overflow-hidden data-[state=closed]:animate-slide-up data-[state=open]:animate-slide-down'>\n {/* The same surface and border as the prompt below, so the two read as one shell. */}\n <ChatTaskList classNames='shrink-0 dx-group-surface border border-separator-subtle border-b-0 rounded-t-sm text-fg-muted' />\n </Collapsible.Content>\n )}\n <NaturalChatPrompt\n {...props}\n // Square where the checklist meets it, so the two read as one shell rather than two cards.\n classNames={[tasksVisible && 'rounded-t-none', classNames]}\n db={db}\n chat={chat}\n chatModel={chatModel}\n event={event}\n queueSize={queueSize}\n started={started}\n tasksVisible={hasTasks ? tasksVisible : undefined}\n />\n </Collapsible.Root>\n );\n};\n\nChatPrompt.displayName = CHAT_PROMPT_NAME;\n\n//\n// TaskList\n//\n\nconst CHAT_TASK_LIST_NAME = 'Chat.TaskList';\n\n/** Rows the chat's checklist shows before it scrolls. */\nconst CHAT_TASK_ROWS = 4;\n\nconst ChatTaskList = Util.composable<HTMLDivElement>((props, forwardedRef) => {\n const { chat, event } = useChatContext(CHAT_TASK_LIST_NAME);\n const { t } = UiHooks.useTranslation(meta.profile.key);\n\n // Both the chat (membership) and each ref (row objects): a query re-emits only on membership.\n const [chatSnapshot] = useObject(chat);\n const taskRefs = chatSnapshot?.tasks;\n const tasks = useAtomValue(\n useMemo(() => Atom.make((get) => Task.dedupeById((taskRefs ?? []).map((ref) => get(ref.atom)))), [taskRefs]),\n );\n\n // The same primitive the task commands use, so the parent edge and the refs cannot diverge.\n const handleCreate = useCallback(\n ({ title, ...props }: Task.Draft) => {\n const db = chat && Obj.getDatabase(chat);\n if (chat && db) {\n AssistantChat.addTask(db, chat, title, props);\n }\n },\n [chat],\n );\n\n // The same primitive the task commands use: it sweeps the checklist and destroys only what the\n // chat owns, so a delegated task keeps the set that parents it.\n const handleDelete = useCallback(\n (task: Task.Task) => {\n const db = chat && Obj.getDatabase(chat);\n if (chat && db) {\n AssistantChat.deleteTask(db, chat, tasks, task);\n }\n },\n [chat, tasks],\n );\n\n const handleUpdate = useCallback((task: Task.Task, patch: Task.Edit) => {\n Task.update(task, patch);\n }, []);\n\n // Execution is a prompt, not a direct write: the agent owns the task's lifecycle (assignment,\n // delegation, status), so the row asks for the work the way the reader would, by ordinal — the\n // number the row shows, and the one `/task:run` and the agent's selectors resolve.\n const handleExecute = useCallback(\n (task: Task.Task) => {\n const ordinal = tasks.findIndex(({ id }) => id === task.id) + 1;\n event.emit({ type: 'submit', text: t('execute-task.prompt', { ordinal }) });\n },\n [tasks, event, t],\n );\n\n // Contributed actions rather than fixed chrome, matching `TaskSetArticle`: two items, so the row\n // shows one overflow menu rather than a bare delete button.\n const getTaskActions = useCallback(\n (task: Task.Task) => [\n createMenuAction(`execute-${task.id}`, () => handleExecute(task), {\n label: t('execute-task.label'),\n icon: 'ph--play--regular',\n // A finished task has nothing left to implement.\n disabled: task.status === 'done' || task.status === 'cancelled',\n testId: 'tasks.task.execute',\n }),\n createMenuAction(`delete-${task.id}`, () => handleDelete(task), {\n label: t('delete-task.label'),\n icon: 'ph--trash--regular',\n testId: 'tasks.task.delete',\n }),\n ],\n [handleExecute, handleDelete, t],\n );\n\n if (!chat) {\n return null;\n }\n\n return (\n <TaskList.Root\n tasks={tasks}\n showGroupLabels={false}\n showOrdinals\n showEstimates\n // The prompt frames the list, and its rows are too narrow for who holds a task or its mnemonic.\n flush\n showAssignees={false}\n showMnemonics={false}\n onTaskCreate={handleCreate}\n onTaskUpdate={handleUpdate}\n getTaskActions={getTaskActions}\n >\n <div {...Util.composableProps(props, { classNames: 'flex flex-col dx-grow' })} ref={forwardedRef}>\n {/* Sized to its rows up to four tasks; only a longer list scrolls, never showing a partial row. */}\n <TaskList.Viewport rows={CHAT_TASK_ROWS}>\n <TaskList.Content />\n </TaskList.Viewport>\n {/* What the agent is blocked on, under the list it asked about: the list itself carries no\n questions — a row replaying them grew by a line each — but a chat is where the asking\n happened, so the answer is given here rather than in a pane the reader has to open. */}\n <ChatTaskQuestions tasks={tasks} />\n {/* Only creates: a task is changed through its own row controls, not by selecting it into the strip. */}\n <TaskList.Editor createOnly />\n </div>\n </TaskList.Root>\n );\n});\n\nChatTaskList.displayName = CHAT_TASK_LIST_NAME;\n\n/**\n * The open questions across the chat's tasks, each with the means to answer it.\n *\n * Answers go through the operation rather than `Task.answer`, so the conversation that asked is\n * resumed — which is the whole point of answering here instead of on the task.\n */\nconst ChatTaskQuestions = ({ tasks }: { tasks: readonly Task.Task[] }) => {\n const { invokePromise } = Hooks.useOperationInvoker();\n const threads = useMemo(\n () =>\n tasks.flatMap((task) =>\n Task.getQuestions(task.history)\n .filter(({ answer }) => !answer)\n .map((thread) => ({ task, thread })),\n ),\n [tasks],\n );\n\n const handleAnswer = useCallback(\n (task: Task.Task, questionId: string, answer: string) => {\n const spaceId = Obj.getDatabase(task)?.spaceId;\n if (spaceId) {\n // The operation reports a refused write in its result, not only by rejecting, so both are checked.\n invokePromise(AssistantOperation.AnswerQuestion, { task, question: questionId, answer }, { spaceId })\n .then((result) => {\n if (result.error || !result.data?.accepted) {\n log.warn('question was not answered', { task: task.id, question: questionId, error: result.error });\n }\n })\n .catch((err) => log.catch(err));\n }\n },\n [invokePromise],\n );\n\n if (threads.length === 0) {\n return null;\n }\n\n return (\n <Layout.Flex column gap='sm' classNames='p-2' data-testid='chat.taskQuestions'>\n {threads.map(({ task, thread }) => (\n <TaskQuestion\n key={thread.question.id}\n thread={thread}\n onAnswer={(answer) => handleAnswer(task, thread.question.id, answer)}\n />\n ))}\n </Layout.Flex>\n );\n};\n\nChatTaskQuestions.displayName = 'Chat.TaskQuestions';\n\n//\n// Activity\n//\n\nconst CHAT_ACTIVITY_NAME = 'Chat.Activity';\n\n/**\n * The activity line bound to the chat's chat model and the chat's pending alarms: what the agent is\n * doing, for as long as it is doing anything. The line itself takes resolved values, so it lives\n * beside the prompt with the rest of the presentational parts and only the binding is here.\n */\nconst ChatActivity = ({ classNames }: Util.ThemedClassName) => {\n const { chatModel } = useChatContext(CHAT_ACTIVITY_NAME);\n const { alarms } = useChatThreadContext(CHAT_ACTIVITY_NAME);\n const activity = useAtomValue(getChatModelState(chatModel).activity);\n\n // Earliest pending alarm: the agent wakes at the first one, so a later one says nothing about the\n // wait in front of the reader.\n return <NaturalChatActivity classNames={classNames} activity={activity} wakeAt={alarms[0]?.wakeAt} />;\n};\n\nChatActivity.displayName = CHAT_ACTIVITY_NAME;\n\n//\n// Chat\n//\n\nexport const Chat = {\n Root: ChatRoot,\n Toolbar: ChatToolbar,\n Content: ChatContent,\n Prompt: ChatPrompt,\n Activity: ChatActivity,\n Status: ChatStatus,\n Thread: ChatThread,\n Outline: ChatOutline,\n};\n\nexport type {\n ChatContentProps,\n ChatEvent,\n ChatOutlineProps,\n ChatPromptProps,\n ChatRootProps,\n ChatThreadProps,\n ChatToolbarProps,\n};\n"],"mappings":"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"}
|