@pgege/kaboo-react 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/integrations/KabooAssistantMessage.tsx","../src/context/TurnBinding.tsx","../src/integrations/KabooMessageView.tsx"],"sourcesContent":["import {\n CopilotChatAssistantMessage,\n type CopilotChatAssistantMessageProps,\n} from \"@copilotkit/react-core/v2\";\nimport { AgentCard } from \"../components/AgentCard\";\nimport { useTurnBinding } from \"../context/TurnBinding\";\n\n/**\n * Drop-in replacement for CopilotKit's assistant-message renderer that prepends\n * a first-class swarm/graph turn's member cards ABOVE the assistant's text —\n * inside the chat transcript, as part of the same turn.\n *\n * Wire it via the `messageView` slot of `CopilotChat`:\n *\n * ```tsx\n * <CopilotChat messageView={{ assistantMessage: KabooAssistantMessage }} />\n * ```\n *\n * This is used instead of `renderCustomMessages` because the `CopilotKit`\n * convenience provider hard-overrides that prop; the `messageView`/\n * `assistantMessage` slot is the supported customization surface and is not\n * clobbered.\n *\n * Which cards to show is decided by the turn binding (provided by\n * {@link KabooMessageView}), which resolves each reply message to its turn's\n * member cards — robust to an interrupt/resume splitting the turn across\n * multiple runIds. Delegate cards keep their tool-call path (they carry a\n * `toolCallId` and are excluded from `chatRootGroups`).\n */\nexport function KabooAssistantMessage(props: CopilotChatAssistantMessageProps) {\n const { message } = props;\n const { rootsByMessageId } = useTurnBinding();\n const messageId = (message as { id?: string })?.id;\n const mine = messageId ? rootsByMessageId.get(messageId) ?? [] : [];\n\n return (\n <>\n {mine.length > 0 && (\n <div className=\"kaboo-inline-cards\">\n {mine.map(([groupId, group]) => (\n <AgentCard key={groupId} groupId={groupId} group={group} showChildren />\n ))}\n </div>\n )}\n <CopilotChatAssistantMessage {...props} />\n </>\n );\n}\n","import { createContext, useContext, type ReactNode } from \"react\";\nimport type { GroupEntry } from \"../utils/groups\";\n\n/**\n * Binds each assistant reply message to the swarm/graph member cards its turn\n * produced, so those cards render *inside* that message (above its reply text)\n * in one chronological block — and a turn's cards never bleed onto a different\n * turn's reply.\n *\n * The mapping is by turn, not `runId`: an interrupt/resume changes the `runId`\n * mid-turn, so a reply's `runId` may only match the `chat_output` member while\n * earlier members carry the pre-resume `runId`. Both, however, share the\n * server-stamped `turnId` ({@link groupTurnKey}). {@link KabooMessageView}\n * resolves each reply message → its run → that run's `turnId`, then collects all\n * roots of that turn — so every member binds to the right reply regardless of\n * how many runs the turn spanned.\n *\n * `rootsByMessageId` holds the resolved cards per assistant message id; a turn\n * whose reply hasn't streamed yet isn't in the map — {@link KabooMessageView}\n * renders those roots live beneath the transcript instead.\n */\nexport interface TurnBinding {\n rootsByMessageId: Map<string, GroupEntry[]>;\n}\n\nconst TurnBindingContext = createContext<TurnBinding>({\n rootsByMessageId: new Map(),\n});\n\nexport function TurnBindingProvider({\n value,\n children,\n}: {\n value: TurnBinding;\n children: ReactNode;\n}) {\n return (\n <TurnBindingContext.Provider value={value}>\n {children}\n </TurnBindingContext.Provider>\n );\n}\n\nexport function useTurnBinding(): TurnBinding {\n return useContext(TurnBindingContext);\n}\n","import {\n CopilotChatMessageView,\n CopilotChatAssistantMessage,\n useCopilotKit,\n useCopilotChatConfiguration,\n type CopilotChatMessageViewProps,\n} from \"@copilotkit/react-core/v2\";\nimport { useActivity } from \"../hooks/useActivity\";\nimport { AgentCard } from \"../components/AgentCard\";\nimport { chatRootGroups, groupTurnKey, type GroupEntry } from \"../utils/groups\";\nimport { TurnBindingProvider } from \"../context/TurnBinding\";\nimport { KabooAssistantMessage } from \"./KabooAssistantMessage\";\n\nfunction KabooMessageViewImpl(props: CopilotChatMessageViewProps) {\n const { groups } = useActivity();\n const { copilotkit } = useCopilotKit();\n const config = useCopilotChatConfiguration();\n const agentId = config?.agentId;\n const threadId = config?.threadId;\n\n return (\n <CopilotChatMessageView\n {...props}\n assistantMessage={\n KabooAssistantMessage as unknown as typeof CopilotChatAssistantMessage\n }\n >\n {({ messages, messageElements, interruptElement, isRunning }) => {\n const roots = chatRootGroups(groups);\n\n // Bucket this turn's member cards by their stable turn key, and map each\n // AG-UI run to its turn key so a reply (whose run may be the post-resume\n // one) resolves to the whole turn — not just its chat_output member.\n const rootsByTurn = new Map<string, GroupEntry[]>();\n for (const entry of roots) {\n const key = groupTurnKey(entry[1]);\n if (!key) continue;\n const bucket = rootsByTurn.get(key);\n if (bucket) bucket.push(entry);\n else rootsByTurn.set(key, [entry]);\n }\n const runToTurn = new Map<string, string>();\n for (const g of Object.values(groups)) {\n const key = groupTurnKey(g);\n if (g.runId && key) runToTurn.set(g.runId, key);\n }\n\n // Resolve each assistant reply → its run → its turn's roots. A turn\n // whose reply hasn't streamed yet stays unbound and renders live below.\n const rootsByMessageId = new Map<string, GroupEntry[]>();\n const boundTurns = new Set<string>();\n const list = messages as Array<{ id?: string; role?: string }>;\n for (const m of list) {\n if (m?.role !== \"assistant\" || !m.id) continue;\n const runId =\n agentId && threadId\n ? copilotkit.getRunIdForMessage(agentId, threadId, m.id)\n : undefined;\n const key = runId ? runToTurn.get(runId) ?? runId : undefined;\n if (!key) continue;\n const turnRoots = rootsByTurn.get(key);\n if (turnRoots) {\n rootsByMessageId.set(m.id, turnRoots);\n boundTurns.add(key);\n }\n }\n\n const pending = roots.filter(([, g]) => {\n const key = groupTurnKey(g);\n return !key || !boundTurns.has(key);\n });\n const showStartCursor = isRunning && pending.length === 0;\n\n return (\n <TurnBindingProvider value={{ rootsByMessageId }}>\n {messageElements}\n {pending.length > 0 && (\n <div className=\"kaboo-inline-cards\">\n {pending.map(([groupId, group]) => (\n <AgentCard key={groupId} groupId={groupId} group={group} showChildren />\n ))}\n </div>\n )}\n {interruptElement}\n {showStartCursor && <CopilotChatMessageView.Cursor />}\n </TurnBindingProvider>\n );\n }}\n </CopilotChatMessageView>\n );\n}\n\n/**\n * Drop-in replacement for `CopilotChat`'s `messageView` that renders swarm/graph\n * member cards **live, inside the chat, from the moment the first agent starts**\n * — not only once the final answer streams.\n *\n * Why this exists: cards attached purely to the assistant message\n * ({@link KabooAssistantMessage}) can't appear until an assistant bubble exists,\n * which for a swarm/graph is when the `chat_output` node streams — i.e. at the\n * very end. During the earlier nodes (planner, researcher, …) there is no\n * assistant message, so the chat would show only a spinner while real work is\n * happening.\n *\n * This view renders the normal message list (with {@link KabooAssistantMessage}\n * for settled turns) and, beneath it, an \"in-progress\" block for any run whose\n * activity groups have appeared but which has **no assistant bubble yet**. As\n * soon as the run's assistant message mounts, that run becomes \"covered\" and its\n * cards render inside the message instead — so there's a seamless hand-off with\n * no duplication.\n *\n * Wire it via the `messageView` slot of `CopilotChat`:\n *\n * @example\n * ```tsx\n * import { CopilotChat } from \"@copilotkit/react-core/v2\";\n * import { KabooMessageView } from \"@pgege/kaboo-react/copilotkit\";\n *\n * function Chat() {\n * return <CopilotChat messageView={KabooMessageView} />;\n * }\n * ```\n */\nexport const KabooMessageView = Object.assign(KabooMessageViewImpl, {\n /**\n * The streaming cursor slot, re-exported from CopilotKit so `KabooMessageView`\n * is a drop-in `messageView` (the slot expects a component carrying `Cursor`).\n */\n Cursor: CopilotChatMessageView.Cursor,\n});\n"],"mappings":"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","names":["jsx","jsx","jsxs"]}