@bikdotai/bik-component-library 0.0.863-beta.0 → 0.0.863-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/agent-builder/utils/mentionSerialization.js +2 -2
- package/dist/cjs/components/agent-builder/utils/mentionSerialization.js.map +1 -1
- package/dist/cjs/components/bik-copilot/BIKCopilot.js +2 -0
- package/dist/cjs/components/bik-copilot/BIKCopilot.js.map +1 -0
- package/dist/cjs/components/bik-copilot/ControlledCopilot.js +2 -0
- package/dist/cjs/components/bik-copilot/ControlledCopilot.js.map +1 -0
- package/dist/cjs/components/bik-copilot/ControlledCopilot.styled.js +27 -0
- package/dist/cjs/components/bik-copilot/ControlledCopilot.styled.js.map +1 -0
- package/dist/cjs/components/bik-copilot/CopilotBall.js +2 -0
- package/dist/cjs/components/bik-copilot/CopilotBall.js.map +1 -0
- package/dist/cjs/components/bik-copilot/CopilotBall.styled.js +42 -0
- package/dist/cjs/components/bik-copilot/CopilotBall.styled.js.map +1 -0
- package/dist/cjs/components/bik-copilot/CopilotPanel.js +2 -0
- package/dist/cjs/components/bik-copilot/CopilotPanel.js.map +1 -0
- package/dist/cjs/components/bik-copilot/CopilotPanel.styled.js +460 -0
- package/dist/cjs/components/bik-copilot/CopilotPanel.styled.js.map +1 -0
- package/dist/cjs/components/bik-copilot/copilotPlacement.js +2 -0
- package/dist/cjs/components/bik-copilot/copilotPlacement.js.map +1 -0
- package/dist/cjs/components/bik-copilot/services/copilotDb.js +2 -0
- package/dist/cjs/components/bik-copilot/services/copilotDb.js.map +1 -0
- package/dist/cjs/components/bik-copilot/services/copilotIcebreakersClient.js +2 -0
- package/dist/cjs/components/bik-copilot/services/copilotIcebreakersClient.js.map +1 -0
- package/dist/cjs/components/bik-copilot/services/copilotMessagesClient.js +2 -0
- package/dist/cjs/components/bik-copilot/services/copilotMessagesClient.js.map +1 -0
- package/dist/cjs/components/bik-copilot/services/copilotPageSession.js +2 -0
- package/dist/cjs/components/bik-copilot/services/copilotPageSession.js.map +1 -0
- package/dist/cjs/components/bik-copilot/services/copilotSseParser.js +7 -0
- package/dist/cjs/components/bik-copilot/services/copilotSseParser.js.map +1 -0
- package/dist/cjs/components/bik-copilot/services/copilotStreamClient.js +2 -0
- package/dist/cjs/components/bik-copilot/services/copilotStreamClient.js.map +1 -0
- package/dist/cjs/components/bik-copilot/useCopilotIcebreakers.js +2 -0
- package/dist/cjs/components/bik-copilot/useCopilotIcebreakers.js.map +1 -0
- package/dist/cjs/components/bik-copilot/useCopilotStreamChat.js +2 -0
- package/dist/cjs/components/bik-copilot/useCopilotStreamChat.js.map +1 -0
- package/dist/cjs/components/bik-copilot/useDraggableFloater.js +2 -0
- package/dist/cjs/components/bik-copilot/useDraggableFloater.js.map +1 -0
- package/dist/cjs/index.js +1 -1
- package/dist/esm/components/agent-builder/utils/mentionSerialization.d.ts +1 -3
- package/dist/esm/components/agent-builder/utils/mentionSerialization.js +14 -22
- package/dist/esm/components/agent-builder/utils/mentionSerialization.js.map +1 -1
- package/dist/esm/components/bik-copilot/BIKCopilot.d.ts +32 -0
- package/dist/esm/components/bik-copilot/BIKCopilot.js +114 -0
- package/dist/esm/components/bik-copilot/BIKCopilot.js.map +1 -0
- package/dist/esm/components/bik-copilot/ControlledCopilot.d.ts +14 -0
- package/dist/esm/components/bik-copilot/ControlledCopilot.js +170 -0
- package/dist/esm/components/bik-copilot/ControlledCopilot.js.map +1 -0
- package/dist/esm/components/bik-copilot/ControlledCopilot.styled.d.ts +7 -0
- package/dist/esm/components/bik-copilot/ControlledCopilot.styled.js +31 -0
- package/dist/esm/components/bik-copilot/ControlledCopilot.styled.js.map +1 -0
- package/dist/esm/components/bik-copilot/CopilotBall.d.ts +13 -0
- package/dist/esm/components/bik-copilot/CopilotBall.js +50 -0
- package/dist/esm/components/bik-copilot/CopilotBall.js.map +1 -0
- package/dist/esm/components/bik-copilot/CopilotBall.styled.d.ts +9 -0
- package/dist/esm/components/bik-copilot/CopilotBall.styled.js +46 -0
- package/dist/esm/components/bik-copilot/CopilotBall.styled.js.map +1 -0
- package/dist/esm/components/bik-copilot/CopilotPanel.d.ts +9 -0
- package/dist/esm/components/bik-copilot/CopilotPanel.js +379 -0
- package/dist/esm/components/bik-copilot/CopilotPanel.js.map +1 -0
- package/dist/esm/components/bik-copilot/CopilotPanel.styled.d.ts +64 -0
- package/dist/esm/components/bik-copilot/CopilotPanel.styled.js +496 -0
- package/dist/esm/components/bik-copilot/CopilotPanel.styled.js.map +1 -0
- package/dist/esm/components/bik-copilot/copilotPlacement.d.ts +24 -0
- package/dist/esm/components/bik-copilot/copilotPlacement.js +38 -0
- package/dist/esm/components/bik-copilot/copilotPlacement.js.map +1 -0
- package/dist/esm/components/bik-copilot/index.d.ts +16 -0
- package/dist/esm/components/bik-copilot/model.d.ts +674 -0
- package/dist/esm/components/bik-copilot/services/copilotDb.d.ts +90 -0
- package/dist/esm/components/bik-copilot/services/copilotDb.js +96 -0
- package/dist/esm/components/bik-copilot/services/copilotDb.js.map +1 -0
- package/dist/esm/components/bik-copilot/services/copilotIcebreakersClient.d.ts +11 -0
- package/dist/esm/components/bik-copilot/services/copilotIcebreakersClient.js +54 -0
- package/dist/esm/components/bik-copilot/services/copilotIcebreakersClient.js.map +1 -0
- package/dist/esm/components/bik-copilot/services/copilotMessagesClient.d.ts +23 -0
- package/dist/esm/components/bik-copilot/services/copilotMessagesClient.js +78 -0
- package/dist/esm/components/bik-copilot/services/copilotMessagesClient.js.map +1 -0
- package/dist/esm/components/bik-copilot/services/copilotPageSession.d.ts +37 -0
- package/dist/esm/components/bik-copilot/services/copilotPageSession.js +35 -0
- package/dist/esm/components/bik-copilot/services/copilotPageSession.js.map +1 -0
- package/dist/esm/components/bik-copilot/services/copilotSseParser.d.ts +22 -0
- package/dist/esm/components/bik-copilot/services/copilotSseParser.js +52 -0
- package/dist/esm/components/bik-copilot/services/copilotSseParser.js.map +1 -0
- package/dist/esm/components/bik-copilot/services/copilotStreamClient.d.ts +31 -0
- package/dist/esm/components/bik-copilot/services/copilotStreamClient.js +103 -0
- package/dist/esm/components/bik-copilot/services/copilotStreamClient.js.map +1 -0
- package/dist/esm/components/bik-copilot/useCopilotIcebreakers.d.ts +17 -0
- package/dist/esm/components/bik-copilot/useCopilotIcebreakers.js +60 -0
- package/dist/esm/components/bik-copilot/useCopilotIcebreakers.js.map +1 -0
- package/dist/esm/components/bik-copilot/useCopilotStreamChat.d.ts +20 -0
- package/dist/esm/components/bik-copilot/useCopilotStreamChat.js +333 -0
- package/dist/esm/components/bik-copilot/useCopilotStreamChat.js.map +1 -0
- package/dist/esm/components/bik-copilot/useDraggableFloater.d.ts +9 -0
- package/dist/esm/components/bik-copilot/useDraggableFloater.js +118 -0
- package/dist/esm/components/bik-copilot/useDraggableFloater.js.map +1 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +832 -782
- package/dist/esm/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("../constants/tools.js"),d=(e,t="Manifest")=>e?i.TOOL_SOURCE_LABELS[e]??e:t,L=e=>{const t=e?String(e):"";return t==="BIK"?"BIK":t==="BSP"?"BSP":"Manifest"}
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("../constants/tools.js"),d=(e,t="Manifest")=>e?i.TOOL_SOURCE_LABELS[e]??e:t,L=e=>{const t=e?String(e):"";return t==="BIK"?"BIK":t==="BSP"?"BSP":"Manifest"},$=(e,t,n="Manifest")=>[...e.map(a=>({id:a.tool_id,label:`${d(a.source,n)} : ${a.display_name}`,meta:{kind:"tool",plainLabel:a.display_name,source:a.source,authRequired:a.auth_required}})),...t.map(a=>({id:a.id,label:`sub-agent: ${a.name}`,meta:{kind:"subagent",plainLabel:a.name}}))],p=e=>e.replace(/^\{\{|\}\}$/g,""),f=(e=[])=>{const t=[],n=a=>{const o=a.actualValue;if(o){const l=p(o);t.push({id:l,label:`{{${l}}}`,meta:{kind:"variable",plainLabel:a.displayName}})}Object.values(a.variables??{}).forEach(n)};return e.forEach(n),t},b=e=>e.tool_key==="send_slack_message"?String(e.params.channelId?.value??"").trim()||"Send Slack message":String(e.params.sendTo?.value??"").split(",").map(t=>t.trim()).filter(Boolean)[0]||"Send email",g=e=>e.name||"Rest API",S=e=>{const t=g(e);return{id:e.id,label:`${i.TOOL_SOURCE_LABELS[i.ToolSource.RestApi]} : ${t}`,meta:{kind:"tool",plainLabel:t,source:i.ToolSource.RestApi}}},T=e=>{const t=e.tool_key==="send_slack_message"?i.ToolSource.Slack:i.ToolSource.EmailHandover,n=b(e);return{id:e.id,label:`${i.TOOL_SOURCE_LABELS[t]} : ${n}`,meta:{kind:"tool",plainLabel:n,source:t}}},_=(e=[],t=[])=>[...t.map(S),...e.map(T)],r=e=>e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"),s=e=>r(e).replace(/"/g,"""),k=(e,t,n,a)=>`<span data-type="mentionAgent" class="bik-mention bik-mention--agent" data-id="${s(e)}" data-label="${s(t)}" data-kind="${s(n)}"`+(a?` data-source="${s(a)}"`:"")+`>${r(t)}</span>`,E=(e,t,n,a)=>k(e,t,n,a),O=e=>{const t=new Map;for(const n of e){const a=n.meta;a?.kind==="tool"?t.set(`tool:${String(n.id)}`,n):a?.kind==="subagent"?t.set(`subagent:${String(n.id)}`,n):a?.kind==="variable"&&t.set(`variable:${String(n.id)}`,n)}return t},c=/\{\{((?:tool|subagent|variable):[^{}]+)\}\}/g,v=(e,t)=>{let n="",a=0;c.lastIndex=0;let o;for(;(o=c.exec(e))!==null;){n+=r(e.slice(a,o.index));const l=t.get(o[1]);if(l){const m=l.meta;n+=k(String(l.id),l.label,m.kind,m.source)}else n+=r(o[0]);a=c.lastIndex}return n+=r(e.slice(a)),n.replace(/\n/g,"<br>")},I=(e,t=[])=>{if(!e)return"";const n=O(t);return e.split(/\n{2,}/).map(a=>`<p>${v(a,n)}</p>`).join("")},M=(e,t,n)=>t==="variable"?`{{variable:${e}}}`:(t??(n.has(e)?"tool":"subagent"))==="tool"?`{{tool:${e}}}`:`{{subagent:${e}}}`,u=(e,t)=>{switch(e.type){case"text":return e.text??"";case"mentionAgent":case"mentionTeam":{const n=e.attrs?.id;if(n==null)return"";const a=e.attrs?.kind;return M(String(n),a==null?null:String(a),t)}case"variable":return`{{${String(e.attrs?.variableName??"")}}}`;case"hardBreak":return`
|
|
2
2
|
`;case"orderedList":case"bulletList":{const n=e.type==="orderedList";return(e.content??[]).map((a,o)=>`${n?`${o+1}.`:"-"} ${u(a,t).replace(/\n+$/,"")}`).join(`
|
|
3
3
|
`)+`
|
|
4
4
|
`}default:{const n=(e.content??[]).map(o=>u(o,t)).join("");return["paragraph","heading","listItem","blockquote"].includes(e.type)?`${n}
|
|
5
|
-
`:n}}},A=(e,t)=>{if(!e)return"";const n=new Set(t.map(a=>a.tool_id));return u(e,n).replace(/\n+$/,"")};exports.TOOL_SOURCE_LABELS=i.TOOL_SOURCE_LABELS;exports.appTypeLabel=L;exports.buildAgentMentionItems
|
|
5
|
+
`:n}}},A=(e,t)=>{if(!e)return"";const n=new Set(t.map(a=>a.tool_id));return u(e,n).replace(/\n+$/,"")};exports.TOOL_SOURCE_LABELS=i.TOOL_SOURCE_LABELS;exports.appTypeLabel=L;exports.buildAgentMentionItems=$;exports.buildCustomToolMentionItems=_;exports.buildMentionHtml=E;exports.buildVariableMentionItems=f;exports.configToolMentionItem=T;exports.configToolName=b;exports.editorDocToInstructions=A;exports.instructionsToEditorHtml=I;exports.restApiMentionItem=S;exports.restApiToolName=g;exports.toolSourceLabel=d;exports.variableTokenName=p;
|
|
6
6
|
//# sourceMappingURL=mentionSerialization.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mentionSerialization.js","sources":["../../../../../src/components/agent-builder/utils/mentionSerialization.ts"],"sourcesContent":["import type { ApplicationType } from '@bikdotai/bik-models/growth';\nimport { MentionItem } from '@src/editor';\nimport type {\n\tSubHeader,\n\tVariableListInterfaceV3,\n\tVariableV3,\n} from '../../variable-picker-v3/model';\nimport {\n\tAgentTool,\n\tConfigToolConfig,\n\tRestApiToolConfig,\n\tSubAgentRef,\n} from '../AgentBuilder.model';\nimport { TOOL_SOURCE_LABELS, ToolSource } from '../constants/tools';\n\n/**\n * Serialization helpers between the BikEditor document and the firebase\n * `instructions` string.\n *\n * Firebase stores `instructions` as PLAIN TEXT with inline reference tokens:\n * - `{{subagent:<agentId>}}` — hand-off to another agent\n * - `{{tool:<tool_id>}}` — an action the agent can call\n * - `{{variable:<name>}}` — a template variable picked from the catalog\n *\n * In the editor those references are inserted via the `@` mention menu (which we\n * populate with BOTH tools and sub-agents). Mention nodes keep their `id` in the\n * ProseMirror doc JSON (the rendered HTML drops it), so we serialize from the doc\n * JSON — not from HTML.\n */\n\nexport interface MentionKindMeta {\n\t/** Distinguishes a tool / sub-agent / variable reference. */\n\tkind: 'tool' | 'subagent' | 'variable';\n\t/** Plain item name (no prefix) shown in the picker dropdown rows. */\n\tplainLabel?: string;\n\t/** For tools: the source bucket (manifest / shopify / …) the picker groups by. */\n\tsource?: string;\n\t/** For tools: touches customer-private data → shows a shield in the picker. */\n\tauthRequired?: boolean;\n}\n\n// Source labels moved to constants/tools.ts; re-exported for existing importers.\nexport { TOOL_SOURCE_LABELS };\n\n/** Human label for a tool source; falls back to the host-app label, then the raw key. */\nexport const toolSourceLabel = (\n\tsource: string | undefined,\n\tfallback = 'Manifest',\n): string => {\n\tif (!source) {\n\t\treturn fallback;\n\t}\n\treturn TOOL_SOURCE_LABELS[source as ToolSource] ?? source;\n};\n\n/** Human label for the host application, used as the tool-chip prefix. */\nexport const appTypeLabel = (applicationType?: ApplicationType): string => {\n\tconst key = applicationType ? String(applicationType) : '';\n\tif (key === 'BIK') {\n\t\treturn 'BIK';\n\t}\n\tif (key === 'BSP') {\n\t\treturn 'BSP';\n\t}\n\treturn 'Manifest';\n};\n\n/**\n * Build the combined `@` mention list from the available tools + sub-agents.\n *\n * The `label` is the CHIP text shown once inserted — tools read\n * `\"<App> : <tool name>\"` (e.g. \"Manifest : Look up order\"), sub-agents read\n * `\"sub-agent: <name>\"`. `meta.plainLabel` is the un-prefixed name for the\n * picker rows, and `meta.kind` drives the `{{tool}}` / `{{subagent}}` colour.\n */\nexport const buildAgentMentionItems = (\n\ttools: AgentTool[],\n\tsubAgents: SubAgentRef[],\n\tappLabel = 'Manifest',\n): MentionItem[] => [\n\t...tools.map(\n\t\t(t): MentionItem => ({\n\t\t\tid: t.tool_id,\n\t\t\tlabel: `${toolSourceLabel(t.source, appLabel)} : ${t.display_name}`,\n\t\t\tmeta: {\n\t\t\t\tkind: 'tool',\n\t\t\t\tplainLabel: t.display_name,\n\t\t\t\tsource: t.source,\n\t\t\t\tauthRequired: t.auth_required,\n\t\t\t},\n\t\t}),\n\t),\n\t...subAgents.map(\n\t\t(s): MentionItem => ({\n\t\t\tid: s.id,\n\t\t\tlabel: `sub-agent: ${s.name}`,\n\t\t\tmeta: { kind: 'subagent', plainLabel: s.name },\n\t\t}),\n\t),\n];\n\n/** Strip the `{{ }}` wrapper from a variable token (`{{a.b}}` → `a.b`). */\nexport const variableTokenName = (actualValue: string): string =>\n\tactualValue.replace(/^\\{\\{|\\}\\}$/g, '');\n\n/**\n * Flatten the (nested) variable catalog into mention items, so stored\n * `{{<name>}}` tokens rehydrate as `Variable: <display name>` chips. The item\n * id is the BARE token name (no braces) — `resolveMentionToken` re-wraps it on\n * save. Merge alongside {@link buildAgentMentionItems} for serialization.\n */\nexport const buildVariableMentionItems = (\n\tvariablesData: VariableListInterfaceV3[] = [],\n): MentionItem[] => {\n\tconst items: MentionItem[] = [];\n\tconst walk = (entry: VariableListInterfaceV3 | SubHeader | VariableV3) => {\n\t\tconst actual = (entry as VariableV3).actualValue;\n\t\tif (actual) {\n\t\t\tconst name = variableTokenName(actual);\n\t\t\titems.push({\n\t\t\t\tid: name,\n\t\t\t\t// Chip text is the raw token — designers want variables to read as\n\t\t\t\t// {{a.b.c}} (styled purple by the editor), not a labelled chip.\n\t\t\t\tlabel: `{{${name}}}`,\n\t\t\t\tmeta: { kind: 'variable', plainLabel: entry.displayName },\n\t\t\t});\n\t\t}\n\t\tObject.values(entry.variables ?? {}).forEach(walk);\n\t};\n\tvariablesData.forEach(walk);\n\treturn items;\n};\n\n/** Display name for a shared config tool: the merchant's action name when set\n * (MAP-7245), else first recipient / channel (pre-action-name tools), else\n * generic. */\nexport const configToolName = (t: ConfigToolConfig): string => {\n\tif (t.tool_key === 'send_slack_message') {\n\t\treturn (\n\t\t\tString(t.params['channelId']?.value ?? '').trim() || 'Send Slack message'\n\t\t);\n\t}\n\tif (t.tool_key === 'send_email') {\n\t\tconst actionName = String(t.params['name']?.value ?? '').trim();\n\t\tif (actionName) {\n\t\t\treturn actionName;\n\t\t}\n\t\treturn (\n\t\t\tString(t.params['sendTo']?.value ?? '')\n\t\t\t\t.split(',')\n\t\t\t\t.map((s) => s.trim())\n\t\t\t\t.filter(Boolean)[0] || 'Send email'\n\t\t);\n\t}\n\t// Future config-tool keys: no bespoke naming yet — fall back to the key.\n\treturn t.tool_key;\n};\n\n/** Display name for a Rest API tool row / chip. */\nexport const restApiToolName = (t: RestApiToolConfig): string =>\n\tt.name || 'Rest API';\n\n/** The `@`-mention chip item for a Rest API tool (kind 'tool', restapi source). */\nexport const restApiMentionItem = (t: RestApiToolConfig): MentionItem => {\n\tconst name = restApiToolName(t);\n\treturn {\n\t\tid: t.id,\n\t\tlabel: `${TOOL_SOURCE_LABELS[ToolSource.RestApi]} : ${name}`,\n\t\tmeta: { kind: 'tool', plainLabel: name, source: ToolSource.RestApi },\n\t};\n};\n\n/** The `@`-mention chip item for a shared config tool (email / Slack). */\nexport const configToolMentionItem = (t: ConfigToolConfig): MentionItem => {\n\tconst source =\n\t\tt.tool_key === 'send_slack_message'\n\t\t\t? ToolSource.Slack\n\t\t\t: ToolSource.EmailHandover;\n\tconst name = configToolName(t);\n\treturn {\n\t\tid: t.id,\n\t\tlabel: `${TOOL_SOURCE_LABELS[source]} : ${name}`,\n\t\tmeta: { kind: 'tool', plainLabel: name, source },\n\t};\n};\n\n/**\n * Mention items for the inline-configured custom tools (Rest API + email / Slack)\n * so their `{{tool:<id>}}` tokens rehydrate as chips — they live on the agent\n * value, not in the catalog `availableTools`. Merge alongside\n * {@link buildAgentMentionItems} in the editor's mention list.\n */\nexport const buildCustomToolMentionItems = (\n\tconfigTools: ConfigToolConfig[] = [],\n\trestApiTools: RestApiToolConfig[] = [],\n): MentionItem[] => [\n\t...restApiTools.map(restApiMentionItem),\n\t...configTools.map(configToolMentionItem),\n];\n\nconst escapeHtml = (raw: string): string =>\n\traw.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n\nconst escapeAttr = (raw: string): string =>\n\tescapeHtml(raw).replace(/\"/g, '"');\n\n/**\n * The HTML for a single mention chip. Must round-trip through the TipTap mention\n * extension's `parseHTML` (`span[data-type=\"mentionAgent\"]`, reading\n * `data-id`/`data-label`/`data-kind`) — see MentionExtension.ts. `normalizeHtml`\n * is taught to keep `data-type=\"mention…\"` spans so this survives to the parser.\n */\nconst mentionSpanHtml = (\n\tid: string,\n\tlabel: string,\n\tkind: string,\n\tsource?: string,\n): string =>\n\t`<span data-type=\"mentionAgent\" class=\"bik-mention bik-mention--agent\"` +\n\t` data-id=\"${escapeAttr(id)}\" data-label=\"${escapeAttr(label)}\"` +\n\t` data-kind=\"${escapeAttr(kind)}\"` +\n\t(source ? ` data-source=\"${escapeAttr(source)}\"` : '') +\n\t`>${escapeHtml(label)}</span>`;\n\n/**\n * Public: HTML for one mention chip, for inserting at the cursor (e.g. when a\n * tool / sub-agent is added from the Step-3 side panel). Round-trips through the\n * same parser path as the rehydrated chips. `source` (tool source bucket) drives\n * the chip's leading icon.\n */\nexport const buildMentionHtml = (\n\tid: string,\n\tlabel: string,\n\tkind: 'tool' | 'subagent' | 'variable',\n\tsource?: string,\n): string => mentionSpanHtml(id, label, kind, source);\n\n/**\n * `{{tool:<id>}}` / `{{subagent:<id>}}` / `{{<variableName>}}` → the mention\n * item that produced them. The map key is the token's INNER text.\n */\nconst buildTokenLookup = (\n\tmentionItems: MentionItem[],\n): Map<string, MentionItem> => {\n\tconst byToken = new Map<string, MentionItem>();\n\tfor (const item of mentionItems) {\n\t\tconst meta = item.meta as unknown as MentionKindMeta | undefined;\n\t\t// Everything is keyed by its kind-prefixed id (a tool's id is its tool_id).\n\t\tif (meta?.kind === 'tool') {\n\t\t\tbyToken.set(`tool:${String(item.id)}`, item);\n\t\t} else if (meta?.kind === 'subagent') {\n\t\t\tbyToken.set(`subagent:${String(item.id)}`, item);\n\t\t} else if (meta?.kind === 'variable') {\n\t\t\tbyToken.set(`variable:${String(item.id)}`, item);\n\t\t}\n\t}\n\treturn byToken;\n};\n\n// Matches the kind-prefixed reference tokens we render as chips. Other\n// `{{var}}` tokens fall through untouched (left as literal text for the\n// variable decoration).\nconst REFERENCE_TOKEN = /\\{\\{((?:tool|subagent|variable):[^{}]+)\\}\\}/g;\n\n/** Escape plain text, swapping recognised reference tokens for mention spans. */\nconst inlineToHtml = (\n\tsegment: string,\n\tbyToken: Map<string, MentionItem>,\n): string => {\n\tlet out = '';\n\tlet lastIndex = 0;\n\tREFERENCE_TOKEN.lastIndex = 0;\n\tlet match: RegExpExecArray | null;\n\twhile ((match = REFERENCE_TOKEN.exec(segment)) !== null) {\n\t\tout += escapeHtml(segment.slice(lastIndex, match.index));\n\t\tconst item = byToken.get(match[1]);\n\t\tif (item) {\n\t\t\tconst meta = item.meta as unknown as MentionKindMeta;\n\t\t\tout += mentionSpanHtml(\n\t\t\t\tString(item.id),\n\t\t\t\titem.label,\n\t\t\t\tmeta.kind,\n\t\t\t\tmeta.source,\n\t\t\t);\n\t\t} else {\n\t\t\t// Not in any available list (removed tool / unknown variable) → keep the\n\t\t\t// raw token as literal text.\n\t\t\tout += escapeHtml(match[0]);\n\t\t}\n\t\tlastIndex = REFERENCE_TOKEN.lastIndex;\n\t}\n\tout += escapeHtml(segment.slice(lastIndex));\n\treturn out.replace(/\\n/g, '<br>');\n};\n\n/**\n * Convert the stored instructions string into HTML for `BikEditor.initialContent`.\n * `{{tool:KEY}}` / `{{subagent:ID}}` tokens are rehydrated into mention chips\n * (resolved via `mentionItems`); any other `{{…}}` token is left as literal text\n * for the editor's variable decoration. Newlines become paragraph / line breaks.\n */\nexport const instructionsToEditorHtml = (\n\ttext: string,\n\tmentionItems: MentionItem[] = [],\n): string => {\n\tif (!text) {\n\t\treturn '';\n\t}\n\tconst byToken = buildTokenLookup(mentionItems);\n\treturn text\n\t\t.split(/\\n{2,}/)\n\t\t.map((para) => `<p>${inlineToHtml(para, byToken)}</p>`)\n\t\t.join('');\n};\n\ninterface ProseMirrorNode {\n\ttype: string;\n\ttext?: string;\n\tattrs?: Record<string, unknown>;\n\tcontent?: ProseMirrorNode[];\n}\n\n/**\n * The token for a mention node. All kinds store their id in the node, so the\n * token value is just that id — the kind only picks the prefix. The node's\n * `kind` attr is authoritative; `toolIds` is a fallback for older content\n * saved before the kind attr existed.\n */\nconst resolveMentionToken = (\n\tid: string,\n\tkind: string | null,\n\ttoolIds: Set<string>,\n): string => {\n\tif (kind === 'variable') {\n\t\treturn `{{variable:${id}}}`;\n\t}\n\tconst resolved = kind ?? (toolIds.has(id) ? 'tool' : 'subagent');\n\treturn resolved === 'tool' ? `{{tool:${id}}}` : `{{subagent:${id}}}`;\n};\n\nconst nodeToText = (node: ProseMirrorNode, toolIds: Set<string>): string => {\n\tswitch (node.type) {\n\t\tcase 'text':\n\t\t\treturn node.text ?? '';\n\t\tcase 'mentionAgent':\n\t\tcase 'mentionTeam': {\n\t\t\tconst id = node.attrs?.['id'];\n\t\t\tif (id == null) {\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\tconst kind = node.attrs?.['kind'];\n\t\t\treturn resolveMentionToken(\n\t\t\t\tString(id),\n\t\t\t\tkind == null ? null : String(kind),\n\t\t\t\ttoolIds,\n\t\t\t);\n\t\t}\n\t\tcase 'variable':\n\t\t\treturn `{{${String(node.attrs?.['variableName'] ?? '')}}}`;\n\t\tcase 'hardBreak':\n\t\t\treturn '\\n';\n\t\tcase 'orderedList':\n\t\tcase 'bulletList': {\n\t\t\t// Flattening to plain text otherwise drops the list markers, so a\n\t\t\t// numbered / bulleted list looks \"removed\" after publish. Emit an\n\t\t\t// ordinal (\"1. \") / bullet (\"- \") prefix per item to preserve it.\n\t\t\tconst ordered = node.type === 'orderedList';\n\t\t\treturn (\n\t\t\t\t(node.content ?? [])\n\t\t\t\t\t.map(\n\t\t\t\t\t\t(item, i) =>\n\t\t\t\t\t\t\t`${ordered ? `${i + 1}.` : '-'} ${nodeToText(\n\t\t\t\t\t\t\t\titem,\n\t\t\t\t\t\t\t\ttoolIds,\n\t\t\t\t\t\t\t).replace(/\\n+$/, '')}`,\n\t\t\t\t\t)\n\t\t\t\t\t.join('\\n') + '\\n'\n\t\t\t);\n\t\t}\n\t\tdefault: {\n\t\t\tconst inner = (node.content ?? [])\n\t\t\t\t.map((child) => nodeToText(child, toolIds))\n\t\t\t\t.join('');\n\t\t\t// Block nodes terminate with a newline so paragraphs stay separated.\n\t\t\tconst BLOCK_NODES = ['paragraph', 'heading', 'listItem', 'blockquote'];\n\t\t\treturn BLOCK_NODES.includes(node.type) ? `${inner}\\n` : inner;\n\t\t}\n\t}\n};\n\n/**\n * Convert a BikEditor document (from `ref.getJSON()`) into the firebase\n * instructions string, replacing mention nodes with `{{subagent:<id>}}` /\n * `{{tool:<tool_id>}}` tokens.\n */\nexport const editorDocToInstructions = (\n\tdoc: Record<string, unknown> | null,\n\ttools: AgentTool[],\n): string => {\n\tif (!doc) {\n\t\treturn '';\n\t}\n\tconst toolIds = new Set(tools.map((t) => t.tool_id));\n\treturn nodeToText(doc as unknown as ProseMirrorNode, toolIds).replace(\n\t\t/\\n+$/,\n\t\t'',\n\t);\n};\n"],"names":["toolSourceLabel","source","fallback","TOOL_SOURCE_LABELS","appTypeLabel","applicationType","key","buildAgentMentionItems","tools","subAgents","appLabel","t","s","variableTokenName","actualValue","buildVariableMentionItems","variablesData","items","walk","entry","actual","name","configToolName","actionName","restApiToolName","restApiMentionItem","ToolSource","configToolMentionItem","buildCustomToolMentionItems","configTools","restApiTools","escapeHtml","raw","escapeAttr","mentionSpanHtml","id","label","kind","buildMentionHtml","buildTokenLookup","mentionItems","byToken","item","meta","REFERENCE_TOKEN","inlineToHtml","segment","out","lastIndex","match","instructionsToEditorHtml","text","para","resolveMentionToken","toolIds","nodeToText","node","ordered","i","inner","child","editorDocToInstructions","doc"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mentionSerialization.js","sources":["../../../../../src/components/agent-builder/utils/mentionSerialization.ts"],"sourcesContent":["import type { ApplicationType } from '@bikdotai/bik-models/growth';\nimport { MentionItem } from '@src/editor';\nimport type {\n\tSubHeader,\n\tVariableListInterfaceV3,\n\tVariableV3,\n} from '../../variable-picker-v3/model';\nimport {\n\tAgentTool,\n\tConfigToolConfig,\n\tRestApiToolConfig,\n\tSubAgentRef,\n} from '../AgentBuilder.model';\nimport { TOOL_SOURCE_LABELS, ToolSource } from '../constants/tools';\n\n/**\n * Serialization helpers between the BikEditor document and the firebase\n * `instructions` string.\n *\n * Firebase stores `instructions` as PLAIN TEXT with inline reference tokens:\n * - `{{subagent:<agentId>}}` — hand-off to another agent\n * - `{{tool:<tool_id>}}` — an action the agent can call\n * - `{{variable:<name>}}` — a template variable picked from the catalog\n *\n * In the editor those references are inserted via the `@` mention menu (which we\n * populate with BOTH tools and sub-agents). Mention nodes keep their `id` in the\n * ProseMirror doc JSON (the rendered HTML drops it), so we serialize from the doc\n * JSON — not from HTML.\n */\n\nexport interface MentionKindMeta {\n\t/** Distinguishes a tool / sub-agent / variable reference. */\n\tkind: 'tool' | 'subagent' | 'variable';\n\t/** Plain item name (no prefix) shown in the picker dropdown rows. */\n\tplainLabel?: string;\n\t/** For tools: the source bucket (manifest / shopify / …) the picker groups by. */\n\tsource?: string;\n\t/** For tools: touches customer-private data → shows a shield in the picker. */\n\tauthRequired?: boolean;\n}\n\n// Source labels moved to constants/tools.ts; re-exported for existing importers.\nexport { TOOL_SOURCE_LABELS };\n\n/** Human label for a tool source; falls back to the host-app label, then the raw key. */\nexport const toolSourceLabel = (\n\tsource: string | undefined,\n\tfallback = 'Manifest',\n): string => {\n\tif (!source) {\n\t\treturn fallback;\n\t}\n\treturn TOOL_SOURCE_LABELS[source as ToolSource] ?? source;\n};\n\n/** Human label for the host application, used as the tool-chip prefix. */\nexport const appTypeLabel = (applicationType?: ApplicationType): string => {\n\tconst key = applicationType ? String(applicationType) : '';\n\tif (key === 'BIK') {\n\t\treturn 'BIK';\n\t}\n\tif (key === 'BSP') {\n\t\treturn 'BSP';\n\t}\n\treturn 'Manifest';\n};\n\n/**\n * Build the combined `@` mention list from the available tools + sub-agents.\n *\n * The `label` is the CHIP text shown once inserted — tools read\n * `\"<App> : <tool name>\"` (e.g. \"Manifest : Look up order\"), sub-agents read\n * `\"sub-agent: <name>\"`. `meta.plainLabel` is the un-prefixed name for the\n * picker rows, and `meta.kind` drives the `{{tool}}` / `{{subagent}}` colour.\n */\nexport const buildAgentMentionItems = (\n\ttools: AgentTool[],\n\tsubAgents: SubAgentRef[],\n\tappLabel = 'Manifest',\n): MentionItem[] => [\n\t...tools.map(\n\t\t(t): MentionItem => ({\n\t\t\tid: t.tool_id,\n\t\t\tlabel: `${toolSourceLabel(t.source, appLabel)} : ${t.display_name}`,\n\t\t\tmeta: {\n\t\t\t\tkind: 'tool',\n\t\t\t\tplainLabel: t.display_name,\n\t\t\t\tsource: t.source,\n\t\t\t\tauthRequired: t.auth_required,\n\t\t\t},\n\t\t}),\n\t),\n\t...subAgents.map(\n\t\t(s): MentionItem => ({\n\t\t\tid: s.id,\n\t\t\tlabel: `sub-agent: ${s.name}`,\n\t\t\tmeta: { kind: 'subagent', plainLabel: s.name },\n\t\t}),\n\t),\n];\n\n/** Strip the `{{ }}` wrapper from a variable token (`{{a.b}}` → `a.b`). */\nexport const variableTokenName = (actualValue: string): string =>\n\tactualValue.replace(/^\\{\\{|\\}\\}$/g, '');\n\n/**\n * Flatten the (nested) variable catalog into mention items, so stored\n * `{{<name>}}` tokens rehydrate as `Variable: <display name>` chips. The item\n * id is the BARE token name (no braces) — `resolveMentionToken` re-wraps it on\n * save. Merge alongside {@link buildAgentMentionItems} for serialization.\n */\nexport const buildVariableMentionItems = (\n\tvariablesData: VariableListInterfaceV3[] = [],\n): MentionItem[] => {\n\tconst items: MentionItem[] = [];\n\tconst walk = (entry: VariableListInterfaceV3 | SubHeader | VariableV3) => {\n\t\tconst actual = (entry as VariableV3).actualValue;\n\t\tif (actual) {\n\t\t\tconst name = variableTokenName(actual);\n\t\t\titems.push({\n\t\t\t\tid: name,\n\t\t\t\t// Chip text is the raw token — designers want variables to read as\n\t\t\t\t// {{a.b.c}} (styled purple by the editor), not a labelled chip.\n\t\t\t\tlabel: `{{${name}}}`,\n\t\t\t\tmeta: { kind: 'variable', plainLabel: entry.displayName },\n\t\t\t});\n\t\t}\n\t\tObject.values(entry.variables ?? {}).forEach(walk);\n\t};\n\tvariablesData.forEach(walk);\n\treturn items;\n};\n\n/** Display name for a shared config tool: first recipient / channel, else generic. */\nexport const configToolName = (t: ConfigToolConfig): string => {\n\tif (t.tool_key === 'send_slack_message') {\n\t\treturn (\n\t\t\tString(t.params['channelId']?.value ?? '').trim() || 'Send Slack message'\n\t\t);\n\t}\n\treturn (\n\t\tString(t.params['sendTo']?.value ?? '')\n\t\t\t.split(',')\n\t\t\t.map((s) => s.trim())\n\t\t\t.filter(Boolean)[0] || 'Send email'\n\t);\n};\n\n/** Display name for a Rest API tool row / chip. */\nexport const restApiToolName = (t: RestApiToolConfig): string =>\n\tt.name || 'Rest API';\n\n/** The `@`-mention chip item for a Rest API tool (kind 'tool', restapi source). */\nexport const restApiMentionItem = (t: RestApiToolConfig): MentionItem => {\n\tconst name = restApiToolName(t);\n\treturn {\n\t\tid: t.id,\n\t\tlabel: `${TOOL_SOURCE_LABELS[ToolSource.RestApi]} : ${name}`,\n\t\tmeta: { kind: 'tool', plainLabel: name, source: ToolSource.RestApi },\n\t};\n};\n\n/** The `@`-mention chip item for a shared config tool (email / Slack). */\nexport const configToolMentionItem = (t: ConfigToolConfig): MentionItem => {\n\tconst source =\n\t\tt.tool_key === 'send_slack_message'\n\t\t\t? ToolSource.Slack\n\t\t\t: ToolSource.EmailHandover;\n\tconst name = configToolName(t);\n\treturn {\n\t\tid: t.id,\n\t\tlabel: `${TOOL_SOURCE_LABELS[source]} : ${name}`,\n\t\tmeta: { kind: 'tool', plainLabel: name, source },\n\t};\n};\n\n/**\n * Mention items for the inline-configured custom tools (Rest API + email / Slack)\n * so their `{{tool:<id>}}` tokens rehydrate as chips — they live on the agent\n * value, not in the catalog `availableTools`. Merge alongside\n * {@link buildAgentMentionItems} in the editor's mention list.\n */\nexport const buildCustomToolMentionItems = (\n\tconfigTools: ConfigToolConfig[] = [],\n\trestApiTools: RestApiToolConfig[] = [],\n): MentionItem[] => [\n\t...restApiTools.map(restApiMentionItem),\n\t...configTools.map(configToolMentionItem),\n];\n\nconst escapeHtml = (raw: string): string =>\n\traw.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n\nconst escapeAttr = (raw: string): string =>\n\tescapeHtml(raw).replace(/\"/g, '"');\n\n/**\n * The HTML for a single mention chip. Must round-trip through the TipTap mention\n * extension's `parseHTML` (`span[data-type=\"mentionAgent\"]`, reading\n * `data-id`/`data-label`/`data-kind`) — see MentionExtension.ts. `normalizeHtml`\n * is taught to keep `data-type=\"mention…\"` spans so this survives to the parser.\n */\nconst mentionSpanHtml = (\n\tid: string,\n\tlabel: string,\n\tkind: string,\n\tsource?: string,\n): string =>\n\t`<span data-type=\"mentionAgent\" class=\"bik-mention bik-mention--agent\"` +\n\t` data-id=\"${escapeAttr(id)}\" data-label=\"${escapeAttr(label)}\"` +\n\t` data-kind=\"${escapeAttr(kind)}\"` +\n\t(source ? ` data-source=\"${escapeAttr(source)}\"` : '') +\n\t`>${escapeHtml(label)}</span>`;\n\n/**\n * Public: HTML for one mention chip, for inserting at the cursor (e.g. when a\n * tool / sub-agent is added from the Step-3 side panel). Round-trips through the\n * same parser path as the rehydrated chips. `source` (tool source bucket) drives\n * the chip's leading icon.\n */\nexport const buildMentionHtml = (\n\tid: string,\n\tlabel: string,\n\tkind: 'tool' | 'subagent' | 'variable',\n\tsource?: string,\n): string => mentionSpanHtml(id, label, kind, source);\n\n/**\n * `{{tool:<id>}}` / `{{subagent:<id>}}` / `{{<variableName>}}` → the mention\n * item that produced them. The map key is the token's INNER text.\n */\nconst buildTokenLookup = (\n\tmentionItems: MentionItem[],\n): Map<string, MentionItem> => {\n\tconst byToken = new Map<string, MentionItem>();\n\tfor (const item of mentionItems) {\n\t\tconst meta = item.meta as unknown as MentionKindMeta | undefined;\n\t\t// Everything is keyed by its kind-prefixed id (a tool's id is its tool_id).\n\t\tif (meta?.kind === 'tool') {\n\t\t\tbyToken.set(`tool:${String(item.id)}`, item);\n\t\t} else if (meta?.kind === 'subagent') {\n\t\t\tbyToken.set(`subagent:${String(item.id)}`, item);\n\t\t} else if (meta?.kind === 'variable') {\n\t\t\tbyToken.set(`variable:${String(item.id)}`, item);\n\t\t}\n\t}\n\treturn byToken;\n};\n\n// Matches the kind-prefixed reference tokens we render as chips. Other\n// `{{var}}` tokens fall through untouched (left as literal text for the\n// variable decoration).\nconst REFERENCE_TOKEN = /\\{\\{((?:tool|subagent|variable):[^{}]+)\\}\\}/g;\n\n/** Escape plain text, swapping recognised reference tokens for mention spans. */\nconst inlineToHtml = (\n\tsegment: string,\n\tbyToken: Map<string, MentionItem>,\n): string => {\n\tlet out = '';\n\tlet lastIndex = 0;\n\tREFERENCE_TOKEN.lastIndex = 0;\n\tlet match: RegExpExecArray | null;\n\twhile ((match = REFERENCE_TOKEN.exec(segment)) !== null) {\n\t\tout += escapeHtml(segment.slice(lastIndex, match.index));\n\t\tconst item = byToken.get(match[1]);\n\t\tif (item) {\n\t\t\tconst meta = item.meta as unknown as MentionKindMeta;\n\t\t\tout += mentionSpanHtml(\n\t\t\t\tString(item.id),\n\t\t\t\titem.label,\n\t\t\t\tmeta.kind,\n\t\t\t\tmeta.source,\n\t\t\t);\n\t\t} else {\n\t\t\t// Not in any available list (removed tool / unknown variable) → keep the\n\t\t\t// raw token as literal text.\n\t\t\tout += escapeHtml(match[0]);\n\t\t}\n\t\tlastIndex = REFERENCE_TOKEN.lastIndex;\n\t}\n\tout += escapeHtml(segment.slice(lastIndex));\n\treturn out.replace(/\\n/g, '<br>');\n};\n\n/**\n * Convert the stored instructions string into HTML for `BikEditor.initialContent`.\n * `{{tool:KEY}}` / `{{subagent:ID}}` tokens are rehydrated into mention chips\n * (resolved via `mentionItems`); any other `{{…}}` token is left as literal text\n * for the editor's variable decoration. Newlines become paragraph / line breaks.\n */\nexport const instructionsToEditorHtml = (\n\ttext: string,\n\tmentionItems: MentionItem[] = [],\n): string => {\n\tif (!text) {\n\t\treturn '';\n\t}\n\tconst byToken = buildTokenLookup(mentionItems);\n\treturn text\n\t\t.split(/\\n{2,}/)\n\t\t.map((para) => `<p>${inlineToHtml(para, byToken)}</p>`)\n\t\t.join('');\n};\n\ninterface ProseMirrorNode {\n\ttype: string;\n\ttext?: string;\n\tattrs?: Record<string, unknown>;\n\tcontent?: ProseMirrorNode[];\n}\n\n/**\n * The token for a mention node. All kinds store their id in the node, so the\n * token value is just that id — the kind only picks the prefix. The node's\n * `kind` attr is authoritative; `toolIds` is a fallback for older content\n * saved before the kind attr existed.\n */\nconst resolveMentionToken = (\n\tid: string,\n\tkind: string | null,\n\ttoolIds: Set<string>,\n): string => {\n\tif (kind === 'variable') {\n\t\treturn `{{variable:${id}}}`;\n\t}\n\tconst resolved = kind ?? (toolIds.has(id) ? 'tool' : 'subagent');\n\treturn resolved === 'tool' ? `{{tool:${id}}}` : `{{subagent:${id}}}`;\n};\n\nconst nodeToText = (node: ProseMirrorNode, toolIds: Set<string>): string => {\n\tswitch (node.type) {\n\t\tcase 'text':\n\t\t\treturn node.text ?? '';\n\t\tcase 'mentionAgent':\n\t\tcase 'mentionTeam': {\n\t\t\tconst id = node.attrs?.['id'];\n\t\t\tif (id == null) {\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\tconst kind = node.attrs?.['kind'];\n\t\t\treturn resolveMentionToken(\n\t\t\t\tString(id),\n\t\t\t\tkind == null ? null : String(kind),\n\t\t\t\ttoolIds,\n\t\t\t);\n\t\t}\n\t\tcase 'variable':\n\t\t\treturn `{{${String(node.attrs?.['variableName'] ?? '')}}}`;\n\t\tcase 'hardBreak':\n\t\t\treturn '\\n';\n\t\tcase 'orderedList':\n\t\tcase 'bulletList': {\n\t\t\t// Flattening to plain text otherwise drops the list markers, so a\n\t\t\t// numbered / bulleted list looks \"removed\" after publish. Emit an\n\t\t\t// ordinal (\"1. \") / bullet (\"- \") prefix per item to preserve it.\n\t\t\tconst ordered = node.type === 'orderedList';\n\t\t\treturn (\n\t\t\t\t(node.content ?? [])\n\t\t\t\t\t.map(\n\t\t\t\t\t\t(item, i) =>\n\t\t\t\t\t\t\t`${ordered ? `${i + 1}.` : '-'} ${nodeToText(\n\t\t\t\t\t\t\t\titem,\n\t\t\t\t\t\t\t\ttoolIds,\n\t\t\t\t\t\t\t).replace(/\\n+$/, '')}`,\n\t\t\t\t\t)\n\t\t\t\t\t.join('\\n') + '\\n'\n\t\t\t);\n\t\t}\n\t\tdefault: {\n\t\t\tconst inner = (node.content ?? [])\n\t\t\t\t.map((child) => nodeToText(child, toolIds))\n\t\t\t\t.join('');\n\t\t\t// Block nodes terminate with a newline so paragraphs stay separated.\n\t\t\tconst BLOCK_NODES = ['paragraph', 'heading', 'listItem', 'blockquote'];\n\t\t\treturn BLOCK_NODES.includes(node.type) ? `${inner}\\n` : inner;\n\t\t}\n\t}\n};\n\n/**\n * Convert a BikEditor document (from `ref.getJSON()`) into the firebase\n * instructions string, replacing mention nodes with `{{subagent:<id>}}` /\n * `{{tool:<tool_id>}}` tokens.\n */\nexport const editorDocToInstructions = (\n\tdoc: Record<string, unknown> | null,\n\ttools: AgentTool[],\n): string => {\n\tif (!doc) {\n\t\treturn '';\n\t}\n\tconst toolIds = new Set(tools.map((t) => t.tool_id));\n\treturn nodeToText(doc as unknown as ProseMirrorNode, toolIds).replace(\n\t\t/\\n+$/,\n\t\t'',\n\t);\n};\n"],"names":["toolSourceLabel","source","fallback","TOOL_SOURCE_LABELS","appTypeLabel","applicationType","key","buildAgentMentionItems","tools","subAgents","appLabel","t","s","variableTokenName","actualValue","buildVariableMentionItems","variablesData","items","walk","entry","actual","name","configToolName","restApiToolName","restApiMentionItem","ToolSource","configToolMentionItem","buildCustomToolMentionItems","configTools","restApiTools","escapeHtml","raw","escapeAttr","mentionSpanHtml","id","label","kind","buildMentionHtml","buildTokenLookup","mentionItems","byToken","item","meta","REFERENCE_TOKEN","inlineToHtml","segment","out","lastIndex","match","instructionsToEditorHtml","text","para","resolveMentionToken","toolIds","nodeToText","node","ordered","i","inner","child","editorDocToInstructions","doc"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const V=require("react/jsx-runtime"),e=require("react"),W=require("./ControlledCopilot.js"),X=require("./useCopilotIcebreakers.js"),Y=require("./useCopilotStreamChat.js"),Z=({baseUrl:s,endpointPath:b,icebreakersPath:M,headers:o,authToken:t,getAuthToken:r,fetchImpl:i,storeId:n,agent:a,route:l,email:m,systemPrompt:h,model:q,maxOutputTokens:k,sessionId:y,persist:O,loadIcebreakers:R=!0,onError:j,onResponseComplete:H,onSessionIdChange:v,suggestions:B,inputDisabled:I,onRefresh:u,open:c,defaultOpen:C,onOpenChange:d,...K})=>{const[L,f]=e.useState(C===!0||c===!0),{messages:w,isThinking:x,isStreaming:g,isRestoring:D,error:N,isLoadingHistory:P,hasMoreHistory:z,sendMessage:E,loadOlderMessages:F,stopStreaming:G,startNewConversation:p}=Y.useCopilotStreamChat({baseUrl:s,endpointPath:b,headers:o,authToken:t,getAuthToken:r,fetchImpl:i,storeId:n,agent:a,route:l,email:m,systemPrompt:h,model:q,maxOutputTokens:k,sessionId:y,persist:O,onError:j,onResponseComplete:H,onSessionIdChange:v}),{icebreakers:J}=X.useCopilotIcebreakers({baseUrl:s,icebreakersPath:M,headers:o,authToken:t,getAuthToken:r,fetchImpl:i,agent:a,route:l,storeId:n,enabled:R&&L}),Q=e.useCallback(S=>{S&&f(!0),d?.(S)},[d]),T=e.useCallback(()=>{p(),u?.()},[u,p]);return V.jsx(W.ControlledCopilot,{...K,open:c,defaultOpen:C,onOpenChange:Q,messages:w,onSendMessage:E,isThinking:x,isStreaming:g,onStop:G,isLoadingHistory:P,hasMoreHistory:z,onLoadOlderMessages:F,errorMessage:N,suggestions:B??J,inputDisabled:I||D||g,onRefresh:T})};exports.BIKCopilot=Z;
|
|
2
|
+
//# sourceMappingURL=BIKCopilot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BIKCopilot.js","sources":["../../../../src/components/bik-copilot/BIKCopilot.tsx"],"sourcesContent":["import React, { useCallback, useState } from 'react';\nimport { ControlledCopilot } from './ControlledCopilot';\nimport { BIKCopilotProps } from './model';\nimport { useCopilotIcebreakers } from './useCopilotIcebreakers';\nimport { useCopilotStreamChat } from './useCopilotStreamChat';\n\n/**\n * The copilot ball and panel wired to the streaming `/bik-ai/copilot-chatbot`\n * endpoint, with the transcript persisted in IndexedDB and route-aware ice\n * breakers from `/bik-ai/copilot-icebreakers`.\n *\n * Chunks arrive as `STREAM` events and are appended live; the final `TEXT` event\n * replaces the bubble with the authoritative full message and carries the\n * `responseId` that threads the next turn. A session id is created on first use\n * and restored on reload, so a refresh resumes the same conversation. The\n * header's reset button starts a new session id and a new OpenAI thread.\n *\n * Ice breakers are fetched for the current `agent` + `route` the first time the\n * panel is opened, and refetched when the route changes.\n *\n * ```tsx\n * <BIKCopilot\n * baseUrl={AI_BACKEND_URL}\n * getAuthToken={() => firebaseUser.getIdToken()}\n * headers={{ 'bik-referer': 'dashboard' }}\n * storeId={storeId}\n * email={user.email}\n * route={currentRoute}\n * title=\"Copilot\"\n * badge=\"New\"\n * subtitle=\"Way smarter, wildly more capable\"\n * />\n * ```\n */\nexport const BIKCopilot: React.FC<BIKCopilotProps> = ({\n\t// Transport + turn config\n\tbaseUrl,\n\tendpointPath,\n\ticebreakersPath,\n\theaders,\n\tauthToken,\n\tgetAuthToken,\n\tfetchImpl,\n\tstoreId,\n\tagent,\n\troute,\n\temail,\n\tsystemPrompt,\n\tmodel,\n\tmaxOutputTokens,\n\tsessionId,\n\tpersist,\n\tloadIcebreakers = true,\n\tonError,\n\tonResponseComplete,\n\tonSessionIdChange,\n\t// Shell\n\tsuggestions,\n\tinputDisabled,\n\tonRefresh,\n\topen,\n\tdefaultOpen,\n\tonOpenChange,\n\t...shellProps\n}) => {\n\t// Ice breakers only matter once the panel is visible, so a merchant who never\n\t// opens the copilot costs no request.\n\tconst [hasOpened, setHasOpened] = useState(\n\t\tdefaultOpen === true || open === true,\n\t);\n\n\tconst {\n\t\tmessages,\n\t\tisThinking,\n\t\tisStreaming,\n\t\tisRestoring,\n\t\terror,\n\t\tisLoadingHistory,\n\t\thasMoreHistory,\n\t\tsendMessage,\n\t\tloadOlderMessages,\n\t\tstopStreaming,\n\t\tstartNewConversation,\n\t} = useCopilotStreamChat({\n\t\tbaseUrl,\n\t\tendpointPath,\n\t\theaders,\n\t\tauthToken,\n\t\tgetAuthToken,\n\t\tfetchImpl,\n\t\tstoreId,\n\t\tagent,\n\t\troute,\n\t\temail,\n\t\tsystemPrompt,\n\t\tmodel,\n\t\tmaxOutputTokens,\n\t\tsessionId,\n\t\tpersist,\n\t\tonError,\n\t\tonResponseComplete,\n\t\tonSessionIdChange,\n\t});\n\n\tconst { icebreakers } = useCopilotIcebreakers({\n\t\tbaseUrl,\n\t\ticebreakersPath,\n\t\theaders,\n\t\tauthToken,\n\t\tgetAuthToken,\n\t\tfetchImpl,\n\t\tagent,\n\t\troute,\n\t\tstoreId,\n\t\tenabled: loadIcebreakers && hasOpened,\n\t});\n\n\tconst handleOpenChange = useCallback(\n\t\t(nextOpen: boolean) => {\n\t\t\tif (nextOpen) {\n\t\t\t\tsetHasOpened(true);\n\t\t\t}\n\t\t\tonOpenChange?.(nextOpen);\n\t\t},\n\t\t[onOpenChange],\n\t);\n\n\tconst handleRefresh = useCallback(() => {\n\t\tstartNewConversation();\n\t\tonRefresh?.();\n\t}, [onRefresh, startNewConversation]);\n\n\treturn (\n\t\t<ControlledCopilot\n\t\t\t{...shellProps}\n\t\t\topen={open}\n\t\t\tdefaultOpen={defaultOpen}\n\t\t\tonOpenChange={handleOpenChange}\n\t\t\tmessages={messages}\n\t\t\tonSendMessage={sendMessage}\n\t\t\tisThinking={isThinking}\n\t\t\tisStreaming={isStreaming}\n\t\t\tonStop={stopStreaming}\n\t\t\tisLoadingHistory={isLoadingHistory}\n\t\t\thasMoreHistory={hasMoreHistory}\n\t\t\tonLoadOlderMessages={loadOlderMessages}\n\t\t\terrorMessage={error}\n\t\t\t// An explicit list wins; otherwise the route's fetched prompts show. A\n\t\t\t// failed or empty fetch simply leaves the empty state without chips.\n\t\t\tsuggestions={suggestions ?? icebreakers}\n\t\t\t// A second prompt mid-stream would race the thread's responseId.\n\t\t\tinputDisabled={inputDisabled || isRestoring || isStreaming}\n\t\t\tonRefresh={handleRefresh}\n\t\t/>\n\t);\n};\n\nexport default BIKCopilot;\n"],"names":["BIKCopilot","baseUrl","endpointPath","icebreakersPath","headers","authToken","getAuthToken","fetchImpl","storeId","agent","route","email","systemPrompt","model","maxOutputTokens","sessionId","persist","loadIcebreakers","onError","onResponseComplete","onSessionIdChange","suggestions","inputDisabled","onRefresh","open","defaultOpen","onOpenChange","shellProps","hasOpened","setHasOpened","useState","messages","isThinking","isStreaming","isRestoring","error","isLoadingHistory","hasMoreHistory","sendMessage","loadOlderMessages","stopStreaming","startNewConversation","useCopilotStreamChat","icebreakers","useCopilotIcebreakers","handleOpenChange","useCallback","nextOpen","handleRefresh","jsx","ControlledCopilot"],"mappings":"2PAkCaA,EAAwC,CAAC,CAErD,QAAAC,EACA,aAAAC,EACA,gBAAAC,EACA,QAAAC,EACA,UAAAC,EACA,aAAAC,EACA,UAAAC,EACA,QAAAC,EACA,MAAAC,EACA,MAAAC,EACA,MAAAC,EACA,aAAAC,EACA,MAAAC,EACA,gBAAAC,EACA,UAAAC,EACA,QAAAC,EACA,gBAAAC,EAAkB,GAClB,QAAAC,EACA,mBAAAC,EACA,kBAAAC,EAEA,YAAAC,EACA,cAAAC,EACA,UAAAC,EACA,KAAAC,EACA,YAAAC,EACA,aAAAC,EACA,GAAGC,CACJ,IAAM,CAGL,KAAM,CAACC,EAAWC,CAAY,EAAIC,EAAAA,SACjCL,IAAgB,IAAQD,IAAS,EAAA,EAG5B,CACL,SAAAO,EACA,WAAAC,EACA,YAAAC,EACA,YAAAC,EACA,MAAAC,EACA,iBAAAC,EACA,eAAAC,EACA,YAAAC,EACA,kBAAAC,EACA,cAAAC,EACA,qBAAAC,CAAA,EACGC,uBAAqB,CACxB,QAAAzC,EACA,aAAAC,EACA,QAAAE,EACA,UAAAC,EACA,aAAAC,EACA,UAAAC,EACA,QAAAC,EACA,MAAAC,EACA,MAAAC,EACA,MAAAC,EACA,aAAAC,EACA,MAAAC,EACA,gBAAAC,EACA,UAAAC,EACA,QAAAC,EACA,QAAAE,EACA,mBAAAC,EACA,kBAAAC,CAAA,CACA,EAEK,CAAE,YAAAuB,CAAA,EAAgBC,wBAAsB,CAC7C,QAAA3C,EACA,gBAAAE,EACA,QAAAC,EACA,UAAAC,EACA,aAAAC,EACA,UAAAC,EACA,MAAAE,EACA,MAAAC,EACA,QAAAF,EACA,QAASS,GAAmBW,CAAA,CAC5B,EAEKiB,EAAmBC,EAAAA,YACvBC,GAAsB,CAClBA,GACHlB,EAAa,EAAI,EAElBH,IAAeqB,CAAQ,CACxB,EACA,CAACrB,CAAY,CAAA,EAGRsB,EAAgBF,EAAAA,YAAY,IAAM,CACvCL,EAAA,EACAlB,IAAA,CACD,EAAG,CAACA,EAAWkB,CAAoB,CAAC,EAEpC,OACCQ,EAAAA,IAACC,EAAAA,kBAAA,CACC,GAAGvB,EACJ,KAAAH,EACA,YAAAC,EACA,aAAcoB,EACd,SAAAd,EACA,cAAeO,EACf,WAAAN,EACA,YAAAC,EACA,OAAQO,EACR,iBAAAJ,EACA,eAAAC,EACA,oBAAqBE,EACrB,aAAcJ,EAGd,YAAad,GAAesB,EAE5B,cAAerB,GAAiBY,GAAeD,EAC/C,UAAWe,CAAA,CAAA,CAGd"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("react/jsx-runtime"),n=require("react"),fe=require("../../constants/Theme.js"),pe=require("./ControlledCopilot.styled.js"),v=require("./CopilotBall.js"),ge=require("./CopilotPanel.js"),Ce=require("./copilotPlacement.js"),me=require("./useDraggableFloater.js"),he=({messages:P,onSendMessage:b,isThinking:w=!1,thinkingLabel:L,isStreaming:q=!1,onStop:E,interruptedLabel:k,followUpsLabel:y,hasMoreHistory:T=!1,isLoadingHistory:j=!1,onLoadOlderMessages:O,historyLoadingLabel:R,errorMessage:$,ballSize:s=56,corner:x="bottom-right",offset:B=24,initialPosition:D,draggable:u=!0,snapToEdge:I=!0,onPositionChange:F,ballIcon:S,ballOpenIcon:_,ballColor:A=fe.COLORS.background.brand,zIndex:d=1200,ballAriaLabel:U,panelWidth:z=400,panelHeight:H=700,panelGap:K=12,title:M="Copilot",badge:G,subtitle:J,avatar:N,placeholder:Q,disclaimer:V,emptyStateTitle:W,emptyStateSubtitle:X,suggestions:Y,onSuggestionClick:Z,showRefresh:ee=!0,onRefresh:te,inputDisabled:oe=!1,open:f,defaultOpen:ne=!1,onOpenChange:p,closeOnClickOutside:g=!1,className:re,style:le})=>{const[se,ie]=n.useState(ne),C=n.useRef(null),i=f!==void 0,e=i?f:se,o=n.useCallback(t=>{i||ie(t),p?.(t)},[i,p]),{position:m,isDragging:ae,viewport:ce,dragHandlers:ue,shouldIgnoreClick:h}=me.useDraggableFloater({size:s,corner:x,offset:B,enabled:u,snapToEdge:I,initialPosition:D,onPositionChange:F}),de=n.useCallback(()=>{h()||o(!e)},[e,o,h]);n.useEffect(()=>{if(!e)return;const t=a=>{a.key==="Escape"&&o(!1)};return document.addEventListener("keydown",t),()=>document.removeEventListener("keydown",t)},[e,o]),n.useEffect(()=>{if(!e||!g)return;const t=a=>{const c=a.target;c&&(C.current?.contains(c)||c.closest(`[${v.COPILOT_BALL_ATTRIBUTE}]`)||o(!1))};return document.addEventListener("pointerdown",t),()=>document.removeEventListener("pointerdown",t)},[g,e,o]);const l=Ce.getCopilotPanelPlacement({ballPosition:m,ballSize:s,panelWidth:z,panelHeight:H,gap:K,viewport:ce});return r.jsxs(r.Fragment,{children:[e&&r.jsx(pe.PanelPositioner,{ref:C,$left:l.left,$top:l.top,$width:l.width,$height:l.height,$zIndex:d,children:r.jsx(ge.CopilotPanel,{messages:P,onSend:b,onClose:()=>o(!1),title:M,badge:G,subtitle:J,avatar:N,placeholder:Q,disclaimer:V,emptyStateTitle:W,emptyStateSubtitle:X,suggestions:Y,onSuggestionClick:Z,showRefresh:ee,onRefresh:te,isThinking:w,thinkingLabel:L,isStreaming:q,onStop:E,interruptedLabel:k,followUpsLabel:y,hasMoreHistory:T,isLoadingHistory:j,onLoadOlderMessages:O,historyLoadingLabel:R,inputDisabled:oe,errorMessage:$,className:re,style:le})}),r.jsx(v.CopilotBall,{isOpen:e,onToggle:de,position:m,size:s,isDragging:ae,draggable:u,color:A,zIndex:d+1,icon:S,openIcon:_,ariaLabel:U,...ue})]})};exports.ControlledCopilot=he;
|
|
2
|
+
//# sourceMappingURL=ControlledCopilot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ControlledCopilot.js","sources":["../../../../src/components/bik-copilot/ControlledCopilot.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport { COLORS } from '@src/constants/Theme';\nimport { PanelPositioner } from './ControlledCopilot.styled';\nimport { COPILOT_BALL_ATTRIBUTE, CopilotBall } from './CopilotBall';\nimport { CopilotPanel } from './CopilotPanel';\nimport { getCopilotPanelPlacement } from './copilotPlacement';\nimport { ControlledCopilotProps } from './model';\nimport { useDraggableFloater } from './useDraggableFloater';\n\n/**\n * The presentational half of the copilot: a draggable floating ball that opens a\n * chat panel beside it.\n *\n * Fully controlled — it renders the `messages` it is handed and reports every\n * user action through callbacks, so it carries no backend knowledge. **Use\n * `BIKCopilot` instead** unless you are wiring a backend other than\n * `/bik-ai/copilot-chatbot`; `BIKCopilot` is this component plus the streaming\n * transport, IndexedDB history and route-aware ice breakers.\n */\nexport const ControlledCopilot: React.FC<ControlledCopilotProps> = ({\n\t// Conversation\n\tmessages,\n\tonSendMessage,\n\tisThinking = false,\n\tthinkingLabel,\n\tisStreaming = false,\n\tonStop,\n\tinterruptedLabel,\n\tfollowUpsLabel,\n\thasMoreHistory = false,\n\tisLoadingHistory = false,\n\tonLoadOlderMessages,\n\thistoryLoadingLabel,\n\terrorMessage,\n\t// Ball\n\tballSize = 56,\n\tcorner = 'bottom-right',\n\toffset = 24,\n\tinitialPosition,\n\tdraggable = true,\n\tsnapToEdge = true,\n\tonPositionChange,\n\tballIcon,\n\tballOpenIcon,\n\tballColor = COLORS.background.brand,\n\tzIndex = 1200,\n\tballAriaLabel,\n\t// Panel\n\tpanelWidth = 400,\n\tpanelHeight = 700,\n\tpanelGap = 12,\n\ttitle = 'Copilot',\n\tbadge,\n\tsubtitle,\n\tavatar,\n\tplaceholder,\n\tdisclaimer,\n\temptyStateTitle,\n\temptyStateSubtitle,\n\tsuggestions,\n\tonSuggestionClick,\n\tshowRefresh = true,\n\tonRefresh,\n\tinputDisabled = false,\n\t// Open state\n\topen,\n\tdefaultOpen = false,\n\tonOpenChange,\n\tcloseOnClickOutside = false,\n\tclassName,\n\tstyle,\n}) => {\n\tconst [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);\n\tconst panelRef = useRef<HTMLDivElement>(null);\n\n\tconst isControlled = open !== undefined;\n\tconst isOpen = isControlled ? open : uncontrolledOpen;\n\n\tconst setOpen = useCallback(\n\t\t(next: boolean) => {\n\t\t\tif (!isControlled) {\n\t\t\t\tsetUncontrolledOpen(next);\n\t\t\t}\n\t\t\tonOpenChange?.(next);\n\t\t},\n\t\t[isControlled, onOpenChange],\n\t);\n\n\tconst { position, isDragging, viewport, dragHandlers, shouldIgnoreClick } =\n\t\tuseDraggableFloater({\n\t\t\tsize: ballSize,\n\t\t\tcorner,\n\t\t\toffset,\n\t\t\tenabled: draggable,\n\t\t\tsnapToEdge,\n\t\t\tinitialPosition,\n\t\t\tonPositionChange,\n\t\t});\n\n\tconst handleBallClick = useCallback(() => {\n\t\t// The click that ends a drag gesture must not toggle the panel.\n\t\tif (shouldIgnoreClick()) {\n\t\t\treturn;\n\t\t}\n\t\tsetOpen(!isOpen);\n\t}, [isOpen, setOpen, shouldIgnoreClick]);\n\n\t// Escape closes the panel.\n\tuseEffect(() => {\n\t\tif (!isOpen) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst handleKeyDown = (event: KeyboardEvent) => {\n\t\t\tif (event.key === 'Escape') {\n\t\t\t\tsetOpen(false);\n\t\t\t}\n\t\t};\n\t\tdocument.addEventListener('keydown', handleKeyDown);\n\t\treturn () => document.removeEventListener('keydown', handleKeyDown);\n\t}, [isOpen, setOpen]);\n\n\tuseEffect(() => {\n\t\tif (!isOpen || !closeOnClickOutside) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst handlePointerDown = (event: PointerEvent) => {\n\t\t\tconst target = event.target as HTMLElement | null;\n\t\t\tif (!target) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (panelRef.current?.contains(target)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (target.closest(`[${COPILOT_BALL_ATTRIBUTE}]`)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsetOpen(false);\n\t\t};\n\t\tdocument.addEventListener('pointerdown', handlePointerDown);\n\t\treturn () => document.removeEventListener('pointerdown', handlePointerDown);\n\t}, [closeOnClickOutside, isOpen, setOpen]);\n\n\tconst placement = getCopilotPanelPlacement({\n\t\tballPosition: position,\n\t\tballSize,\n\t\tpanelWidth,\n\t\tpanelHeight,\n\t\tgap: panelGap,\n\t\tviewport,\n\t});\n\n\treturn (\n\t\t<>\n\t\t\t{isOpen && (\n\t\t\t\t<PanelPositioner\n\t\t\t\t\tref={panelRef}\n\t\t\t\t\t$left={placement.left}\n\t\t\t\t\t$top={placement.top}\n\t\t\t\t\t$width={placement.width}\n\t\t\t\t\t$height={placement.height}\n\t\t\t\t\t$zIndex={zIndex}\n\t\t\t\t>\n\t\t\t\t\t<CopilotPanel\n\t\t\t\t\t\tmessages={messages}\n\t\t\t\t\t\tonSend={onSendMessage}\n\t\t\t\t\t\tonClose={() => setOpen(false)}\n\t\t\t\t\t\ttitle={title}\n\t\t\t\t\t\tbadge={badge}\n\t\t\t\t\t\tsubtitle={subtitle}\n\t\t\t\t\t\tavatar={avatar}\n\t\t\t\t\t\tplaceholder={placeholder}\n\t\t\t\t\t\tdisclaimer={disclaimer}\n\t\t\t\t\t\temptyStateTitle={emptyStateTitle}\n\t\t\t\t\t\temptyStateSubtitle={emptyStateSubtitle}\n\t\t\t\t\t\tsuggestions={suggestions}\n\t\t\t\t\t\tonSuggestionClick={onSuggestionClick}\n\t\t\t\t\t\tshowRefresh={showRefresh}\n\t\t\t\t\t\tonRefresh={onRefresh}\n\t\t\t\t\t\tisThinking={isThinking}\n\t\t\t\t\t\tthinkingLabel={thinkingLabel}\n\t\t\t\t\t\tisStreaming={isStreaming}\n\t\t\t\t\t\tonStop={onStop}\n\t\t\t\t\t\tinterruptedLabel={interruptedLabel}\n\t\t\t\t\t\tfollowUpsLabel={followUpsLabel}\n\t\t\t\t\t\thasMoreHistory={hasMoreHistory}\n\t\t\t\t\t\tisLoadingHistory={isLoadingHistory}\n\t\t\t\t\t\tonLoadOlderMessages={onLoadOlderMessages}\n\t\t\t\t\t\thistoryLoadingLabel={historyLoadingLabel}\n\t\t\t\t\t\tinputDisabled={inputDisabled}\n\t\t\t\t\t\terrorMessage={errorMessage}\n\t\t\t\t\t\tclassName={className}\n\t\t\t\t\t\tstyle={style}\n\t\t\t\t\t/>\n\t\t\t\t</PanelPositioner>\n\t\t\t)}\n\n\t\t\t<CopilotBall\n\t\t\t\tisOpen={isOpen}\n\t\t\t\tonToggle={handleBallClick}\n\t\t\t\tposition={position}\n\t\t\t\tsize={ballSize}\n\t\t\t\tisDragging={isDragging}\n\t\t\t\tdraggable={draggable}\n\t\t\t\tcolor={ballColor}\n\t\t\t\tzIndex={zIndex + 1}\n\t\t\t\ticon={ballIcon}\n\t\t\t\topenIcon={ballOpenIcon}\n\t\t\t\tariaLabel={ballAriaLabel}\n\t\t\t\t{...dragHandlers}\n\t\t\t/>\n\t\t</>\n\t);\n};\n\nexport default ControlledCopilot;\n"],"names":["ControlledCopilot","messages","onSendMessage","isThinking","thinkingLabel","isStreaming","onStop","interruptedLabel","followUpsLabel","hasMoreHistory","isLoadingHistory","onLoadOlderMessages","historyLoadingLabel","errorMessage","ballSize","corner","offset","initialPosition","draggable","snapToEdge","onPositionChange","ballIcon","ballOpenIcon","ballColor","COLORS","zIndex","ballAriaLabel","panelWidth","panelHeight","panelGap","title","badge","subtitle","avatar","placeholder","disclaimer","emptyStateTitle","emptyStateSubtitle","suggestions","onSuggestionClick","showRefresh","onRefresh","inputDisabled","open","defaultOpen","onOpenChange","closeOnClickOutside","className","style","uncontrolledOpen","setUncontrolledOpen","useState","panelRef","useRef","isControlled","isOpen","setOpen","useCallback","next","position","isDragging","viewport","dragHandlers","shouldIgnoreClick","useDraggableFloater","handleBallClick","useEffect","handleKeyDown","event","handlePointerDown","target","COPILOT_BALL_ATTRIBUTE","placement","getCopilotPanelPlacement","jsxs","Fragment","jsx","PanelPositioner","CopilotPanel","CopilotBall"],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("styled-components"),o=t=>t&&typeof t=="object"&&"default"in t?t:{default:t},i=o(e),a=i.default.div`
|
|
2
|
+
position: fixed;
|
|
3
|
+
left: ${t=>t.$left}px;
|
|
4
|
+
top: ${t=>t.$top}px;
|
|
5
|
+
width: ${t=>t.$width}px;
|
|
6
|
+
height: ${t=>t.$height}px;
|
|
7
|
+
z-index: ${t=>t.$zIndex};
|
|
8
|
+
display: flex;
|
|
9
|
+
animation: bikCopilotPanelIn 0.16s ease-out;
|
|
10
|
+
|
|
11
|
+
> * {
|
|
12
|
+
flex: 1;
|
|
13
|
+
min-width: 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@keyframes bikCopilotPanelIn {
|
|
17
|
+
from {
|
|
18
|
+
opacity: 0;
|
|
19
|
+
transform: translateY(6px) scale(0.98);
|
|
20
|
+
}
|
|
21
|
+
to {
|
|
22
|
+
opacity: 1;
|
|
23
|
+
transform: translateY(0) scale(1);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
`;exports.PanelPositioner=a;
|
|
27
|
+
//# sourceMappingURL=ControlledCopilot.styled.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ControlledCopilot.styled.js","sources":["../../../../src/components/bik-copilot/ControlledCopilot.styled.ts"],"sourcesContent":["import styled from 'styled-components';\n\nexport const PanelPositioner = styled.div<{\n\t$left: number;\n\t$top: number;\n\t$width: number;\n\t$height: number;\n\t$zIndex: number;\n}>`\n\tposition: fixed;\n\tleft: ${(props) => props.$left}px;\n\ttop: ${(props) => props.$top}px;\n\twidth: ${(props) => props.$width}px;\n\theight: ${(props) => props.$height}px;\n\tz-index: ${(props) => props.$zIndex};\n\tdisplay: flex;\n\tanimation: bikCopilotPanelIn 0.16s ease-out;\n\n\t> * {\n\t\tflex: 1;\n\t\tmin-width: 0;\n\t}\n\n\t@keyframes bikCopilotPanelIn {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(6px) scale(0.98);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0) scale(1);\n\t\t}\n\t}\n`;\n"],"names":["PanelPositioner","styled","props"],"mappings":"oLAEaA,EAAkBC,EAAAA,QAAO;AAAA;AAAA,SAQ5BC,GAAUA,EAAM,KAAK;AAAA,QACtBA,GAAUA,EAAM,IAAI;AAAA,UAClBA,GAAUA,EAAM,MAAM;AAAA,WACrBA,GAAUA,EAAM,OAAO;AAAA,YACtBA,GAAUA,EAAM,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),I=require("../../assets/icons/bik_ai_stars_icon.svg.js"),$=require("../../assets/icons/chevronDown.svg.js"),p=require("./CopilotBall.styled.js"),n="data-bik-copilot-ball",L=({isOpen:o,onToggle:r,position:l,size:i,isDragging:c,draggable:s,color:u,zIndex:d,icon:g,openIcon:h,ariaLabel:B,onPointerDown:T,onPointerMove:b,onPointerUp:_,onPointerCancel:x})=>{const t=Math.round(i*.42),a=o?e.jsx($.default,{width:t,height:t}):e.jsx(I.default,{width:t,height:t}),C=o?h??a:g??a;return e.jsx(p.BallButton,{type:"button",[n]:"true",$size:i,$left:l.x,$top:l.y,$color:u,$zIndex:d,$isDragging:c,$draggable:s,"aria-label":B||"Copilot","aria-expanded":o,onClick:r,onPointerDown:T,onPointerMove:b,onPointerUp:_,onPointerCancel:x,children:C})};exports.COPILOT_BALL_ATTRIBUTE=n;exports.CopilotBall=L;
|
|
2
|
+
//# sourceMappingURL=CopilotBall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CopilotBall.js","sources":["../../../../src/components/bik-copilot/CopilotBall.tsx"],"sourcesContent":["import AiStarsIcon from '@src/assets/icons/bik_ai_stars_icon.svg';\nimport ChevronDownIcon from '@src/assets/icons/chevronDown.svg';\nimport React from 'react';\nimport { BallButton } from './CopilotBall.styled';\nimport { CopilotBallProps } from './model';\n\n/**\n * Marks the ball in the DOM so an outside-click handler can tell the ball apart\n * from the rest of the page and not fight the ball's own toggle.\n */\nexport const COPILOT_BALL_ATTRIBUTE = 'data-bik-copilot-ball';\n\n/**\n * The floating ball that opens the copilot panel. Purely presentational — the\n * drag gesture lives in `useDraggableFloater` and is passed in as handlers.\n */\nexport const CopilotBall: React.FC<CopilotBallProps> = ({\n\tisOpen,\n\tonToggle,\n\tposition,\n\tsize,\n\tisDragging,\n\tdraggable,\n\tcolor,\n\tzIndex,\n\ticon,\n\topenIcon,\n\tariaLabel,\n\tonPointerDown,\n\tonPointerMove,\n\tonPointerUp,\n\tonPointerCancel,\n}) => {\n\tconst iconSize = Math.round(size * 0.42);\n\tconst defaultIcon = isOpen ? (\n\t\t<ChevronDownIcon width={iconSize} height={iconSize} />\n\t) : (\n\t\t<AiStarsIcon width={iconSize} height={iconSize} />\n\t);\n\tconst activeIcon = isOpen ? openIcon ?? defaultIcon : icon ?? defaultIcon;\n\n\treturn (\n\t\t<BallButton\n\t\t\ttype=\"button\"\n\t\t\t{...{ [COPILOT_BALL_ATTRIBUTE]: 'true' }}\n\t\t\t$size={size}\n\t\t\t$left={position.x}\n\t\t\t$top={position.y}\n\t\t\t$color={color}\n\t\t\t$zIndex={zIndex}\n\t\t\t$isDragging={isDragging}\n\t\t\t$draggable={draggable}\n\t\t\t/* A disclosure button keeps a stable name and reports its state through\n\t\t\t aria-expanded, so this must not become \"Open/Close copilot\" — that\n\t\t\t would also collide with the panel's own close button. */\n\t\t\taria-label={ariaLabel || 'Copilot'}\n\t\t\taria-expanded={isOpen}\n\t\t\tonClick={onToggle}\n\t\t\tonPointerDown={onPointerDown}\n\t\t\tonPointerMove={onPointerMove}\n\t\t\tonPointerUp={onPointerUp}\n\t\t\tonPointerCancel={onPointerCancel}\n\t\t>\n\t\t\t{activeIcon}\n\t\t</BallButton>\n\t);\n};\n\nexport default CopilotBall;\n"],"names":["COPILOT_BALL_ATTRIBUTE","CopilotBall","isOpen","onToggle","position","size","isDragging","draggable","color","zIndex","icon","openIcon","ariaLabel","onPointerDown","onPointerMove","onPointerUp","onPointerCancel","iconSize","defaultIcon","jsx","ChevronDownIcon","AiStarsIcon","activeIcon","BallButton"],"mappings":"sQAUaA,EAAyB,wBAMzBC,EAA0C,CAAC,CACvD,OAAAC,EACA,SAAAC,EACA,SAAAC,EACA,KAAAC,EACA,WAAAC,EACA,UAAAC,EACA,MAAAC,EACA,OAAAC,EACA,KAAAC,EACA,SAAAC,EACA,UAAAC,EACA,cAAAC,EACA,cAAAC,EACA,YAAAC,EACA,gBAAAC,CACD,IAAM,CACL,MAAMC,EAAW,KAAK,MAAMZ,EAAO,GAAI,EACjCa,EAAchB,EACnBiB,EAAAA,IAACC,EAAAA,QAAA,CAAgB,MAAOH,EAAU,OAAQA,CAAA,CAAU,EAEpDE,EAAAA,IAACE,UAAA,CAAY,MAAOJ,EAAU,OAAQA,EAAU,EAE3CK,EAAapB,EAASS,GAAYO,EAAcR,GAAQQ,EAE9D,OACCC,EAAAA,IAACI,EAAAA,WAAA,CACA,KAAK,SACC,CAACvB,CAAsB,EAAG,OAChC,MAAOK,EACP,MAAOD,EAAS,EAChB,KAAMA,EAAS,EACf,OAAQI,EACR,QAASC,EACT,YAAaH,EACb,WAAYC,EAIZ,aAAYK,GAAa,UACzB,gBAAeV,EACf,QAASC,EACT,cAAAU,EACA,cAAAC,EACA,YAAAC,EACA,gBAAAC,EAEC,SAAAM,CAAA,CAAA,CAGJ"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("styled-components"),o=e=>e&&typeof e=="object"&&"default"in e?e:{default:e},s=o(t),n=s.default.button`
|
|
2
|
+
position: fixed;
|
|
3
|
+
left: ${e=>e.$left}px;
|
|
4
|
+
top: ${e=>e.$top}px;
|
|
5
|
+
width: ${e=>e.$size}px;
|
|
6
|
+
height: ${e=>e.$size}px;
|
|
7
|
+
z-index: ${e=>e.$zIndex};
|
|
8
|
+
|
|
9
|
+
display: flex;
|
|
10
|
+
align-items: center;
|
|
11
|
+
justify-content: center;
|
|
12
|
+
padding: 0;
|
|
13
|
+
border: none;
|
|
14
|
+
border-radius: 50%;
|
|
15
|
+
background: ${e=>e.$color};
|
|
16
|
+
color: #ffffff;
|
|
17
|
+
box-shadow: ${e=>e.$isDragging?"0 12px 32px rgba(40, 3, 78, 0.36)":"0 6px 20px rgba(40, 3, 78, 0.24)"};
|
|
18
|
+
|
|
19
|
+
cursor: ${e=>e.$isDragging?"grabbing":e.$draggable?"grab":"pointer"};
|
|
20
|
+
touch-action: none;
|
|
21
|
+
user-select: none;
|
|
22
|
+
-webkit-user-select: none;
|
|
23
|
+
|
|
24
|
+
/* Position changes animate on release but must track the pointer 1:1 while
|
|
25
|
+
the user is dragging. */
|
|
26
|
+
transition: ${e=>e.$isDragging?"box-shadow 0.15s ease, transform 0.15s ease":"left 0.22s ease, top 0.22s ease, box-shadow 0.15s ease, transform 0.15s ease"};
|
|
27
|
+
transform: ${e=>e.$isDragging?"scale(1.06)":"scale(1)"};
|
|
28
|
+
|
|
29
|
+
&:hover {
|
|
30
|
+
transform: scale(1.06);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&:focus-visible {
|
|
34
|
+
outline: 2px solid #ffffff;
|
|
35
|
+
outline-offset: 2px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
svg {
|
|
39
|
+
pointer-events: none;
|
|
40
|
+
}
|
|
41
|
+
`;exports.BallButton=n;
|
|
42
|
+
//# sourceMappingURL=CopilotBall.styled.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CopilotBall.styled.js","sources":["../../../../src/components/bik-copilot/CopilotBall.styled.ts"],"sourcesContent":["import styled from 'styled-components';\n\nexport const BallButton = styled.button<{\n\t$size: number;\n\t$left: number;\n\t$top: number;\n\t$color: string;\n\t$zIndex: number;\n\t$isDragging: boolean;\n\t$draggable: boolean;\n}>`\n\tposition: fixed;\n\tleft: ${(props) => props.$left}px;\n\ttop: ${(props) => props.$top}px;\n\twidth: ${(props) => props.$size}px;\n\theight: ${(props) => props.$size}px;\n\tz-index: ${(props) => props.$zIndex};\n\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tpadding: 0;\n\tborder: none;\n\tborder-radius: 50%;\n\tbackground: ${(props) => props.$color};\n\tcolor: #ffffff;\n\tbox-shadow: ${(props) =>\n\t\tprops.$isDragging\n\t\t\t? '0 12px 32px rgba(40, 3, 78, 0.36)'\n\t\t\t: '0 6px 20px rgba(40, 3, 78, 0.24)'};\n\n\tcursor: ${(props) =>\n\t\tprops.$isDragging ? 'grabbing' : props.$draggable ? 'grab' : 'pointer'};\n\ttouch-action: none;\n\tuser-select: none;\n\t-webkit-user-select: none;\n\n\t/* Position changes animate on release but must track the pointer 1:1 while\n\t the user is dragging. */\n\ttransition: ${(props) =>\n\t\tprops.$isDragging\n\t\t\t? 'box-shadow 0.15s ease, transform 0.15s ease'\n\t\t\t: 'left 0.22s ease, top 0.22s ease, box-shadow 0.15s ease, transform 0.15s ease'};\n\ttransform: ${(props) => (props.$isDragging ? 'scale(1.06)' : 'scale(1)')};\n\n\t&:hover {\n\t\ttransform: scale(1.06);\n\t}\n\n\t&:focus-visible {\n\t\toutline: 2px solid #ffffff;\n\t\toutline-offset: 2px;\n\t}\n\n\tsvg {\n\t\tpointer-events: none;\n\t}\n`;\n"],"names":["BallButton","styled","props"],"mappings":"oLAEaA,EAAaC,EAAAA,QAAO;AAAA;AAAA,SAUvBC,GAAUA,EAAM,KAAK;AAAA,QACtBA,GAAUA,EAAM,IAAI;AAAA,UAClBA,GAAUA,EAAM,KAAK;AAAA,WACpBA,GAAUA,EAAM,KAAK;AAAA,YACpBA,GAAUA,EAAM,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,eAQpBA,GAAUA,EAAM,MAAM;AAAA;AAAA,eAEtBA,GACdA,EAAM,YACH,oCACA,kCAAkC;AAAA;AAAA,WAE3BA,GACVA,EAAM,YAAc,WAAaA,EAAM,WAAa,OAAS,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,eAOxDA,GACdA,EAAM,YACH,8CACA,8EAA8E;AAAA,cACpEA,GAAWA,EAAM,YAAc,cAAgB,UAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),f=require("../../assets/icons/bik_ai_stars_icon.svg.js"),ye=require("../../assets/icons/cross.svg.js"),Ce=require("../../assets/icons/refresh.svg.js"),n=require("react"),h=require("../../constants/Theme.js"),ge=require("../bik-chatbot/utils/markdown.js"),w=require("../TypographyStyle.js"),o=require("./CopilotPanel.styled.js"),J=require("../dot-pulse/DotPulse.js"),ke=r=>r&&typeof r=="object"&&"default"in r?r:{default:r},ve=ke(n),Te=96,be=24,Se=1800,Ie=async r=>{try{if(navigator.clipboard?.writeText)return await navigator.clipboard.writeText(r),!0}catch{}try{const s=document.createElement("textarea");s.value=r,s.setAttribute("readonly",""),s.style.position="fixed",s.style.top="-1000px",s.style.opacity="0",document.body.appendChild(s),s.select();const y=document.execCommand("copy");return document.body.removeChild(s),y}catch{return!1}},me=48,Re=()=>e.jsxs("svg",{viewBox:"0 0 24 24",width:"16",height:"16",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[e.jsx("path",{d:"M12 19V5"}),e.jsx("path",{d:"M6 11l6-6 6 6"})]}),Ae=()=>e.jsxs("svg",{viewBox:"0 0 24 24",width:"14",height:"14",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[e.jsx("path",{d:"M5 12h14"}),e.jsx("path",{d:"M13 6l6 6-6 6"})]}),G=({size:r=16})=>e.jsx("svg",{viewBox:"0 0 24 24",width:r,height:r,fill:"currentColor","aria-hidden":"true",children:e.jsx("rect",{x:"7",y:"7",width:"10",height:"10",rx:"2"})}),Le=()=>e.jsxs("svg",{viewBox:"0 0 24 24",width:"14",height:"14",fill:"none",stroke:"currentColor",strokeWidth:"1.8",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[e.jsx("rect",{x:"9",y:"9",width:"11",height:"11",rx:"2"}),e.jsx("path",{d:"M15 5.5A1.5 1.5 0 0 0 13.5 4H5.5A1.5 1.5 0 0 0 4 5.5v8A1.5 1.5 0 0 0 5.5 15"})]}),Me=()=>e.jsx("svg",{viewBox:"0 0 24 24",width:"14",height:"14",fill:"none",stroke:"currentColor",strokeWidth:"2.2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:e.jsx("path",{d:"M5 13l4 4L19 7"})}),Be=()=>e.jsx("svg",{viewBox:"0 0 24 24",width:"14",height:"14",fill:"none",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:e.jsx("path",{d:"M6 9l6 6 6-6"})}),_e=({messages:r,onSend:s,onClose:y,title:C="Copilot",badge:L,subtitle:M,avatar:Q,placeholder:Y="Write your message...",disclaimer:B="AI can make mistakes, Verify the responses.",emptyStateTitle:Z,emptyStateSubtitle:_="Here are some things you can try",suggestions:g,onSuggestionClick:ee,showRefresh:te=!0,onRefresh:E,isThinking:u=!1,thinkingLabel:O="Thinking",isStreaming:oe=!1,onStop:F,interruptedLabel:P="This message was interrupted",followUpsLabel:H="Follow ups",hasMoreHistory:re=!1,isLoadingHistory:p=!1,onLoadOlderMessages:q,historyLoadingLabel:ne="Loading earlier messages",inputDisabled:i=!1,errorMessage:W,width:se,height:le,className:ie,style:ce})=>{const[k,$]=n.useState(""),[ae,D]=n.useState(!1),[v,T]=n.useState(!0),[x,N]=n.useState(null),U=n.useRef(null),a=n.useRef(null),b=n.useRef(null),S=n.useRef(null),I=n.useRef(0),m=n.useRef(null),j=r.filter(t=>t.content.length>0||t.wasInterrupted),V=j.length===0&&!u,c=u||oe,K=!i&&!c&&k.trim().length>0,d=c&&!!F,X=j[j.length-1],R=!c&&X?.role==="assistant"?X.followUps:void 0,A=!V&&!v;n.useEffect(()=>{v&&b.current?.scrollIntoView({behavior:"smooth"})},[r,u,v]),n.useEffect(()=>{const t=S.current,l=m.current;!t||l===null||p||(m.current=null,t.scrollTop=t.scrollHeight-l,I.current=t.scrollTop)},[r,p]);const de=()=>{const t=S.current;if(!t)return;const l=t.scrollHeight-t.scrollTop-t.clientHeight;t.scrollTop<=me&&re&&!p&&q&&(m.current=t.scrollHeight-t.scrollTop,q());const we=t.scrollTop<I.current-1;if(I.current=t.scrollTop,l<=be){T(!0);return}we&&T(!1)},he=()=>{T(!0),b.current?.scrollIntoView({behavior:"smooth"})};n.useEffect(()=>()=>{a.current&&window.clearTimeout(a.current)},[]);const ue=async t=>{await Ie(t.content)&&(a.current&&window.clearTimeout(a.current),N(t.id),a.current=window.setTimeout(()=>N(null),Se))},z=()=>{const t=k.trim();if(!t||i||c)return;s(t),$("");const l=U.current;l&&(l.style.height="auto")},pe=t=>{$(t.target.value);const l=t.target;l.style.height="auto",l.style.height=`${Math.min(l.scrollHeight,Te)}px`},xe=t=>{t.key==="Enter"&&!t.shiftKey&&(t.preventDefault(),z())},je=t=>{i||c||(ee?.(t),s(t.text))},fe=t=>{i||c||s(t)};return e.jsxs(o.PanelContainer,{className:ie,style:{width:se,height:le,...ce},role:"dialog","aria-label":C,children:[e.jsxs(o.PanelHeader,{children:[e.jsx(o.HeaderAvatar,{children:Q??e.jsx(f.default,{width:18,height:18})}),e.jsxs(o.HeaderText,{children:[e.jsxs(o.HeaderTitleRow,{children:[e.jsx(w.TitleSmall,{children:C}),L&&e.jsx(o.HeaderBadge,{children:L})]}),M&&e.jsx(w.BodyCaption,{color:h.COLORS.content.secondary,children:M})]}),e.jsxs(o.HeaderActions,{children:[te&&E&&e.jsx(o.IconAction,{type:"button",onClick:E,"aria-label":"Start a new conversation",children:e.jsx(Ce.default,{width:16,height:16})}),e.jsx(o.IconAction,{type:"button",onClick:y,"aria-label":"Close copilot",children:e.jsx(ye.default,{width:18,height:18})})]})]}),e.jsxs(o.MessagesViewport,{children:[e.jsx(o.MessagesArea,{ref:S,onScroll:de,role:"region","aria-label":"Conversation",children:V?e.jsxs(o.EmptyState,{children:[e.jsx(o.EmptyStateIcon,{children:e.jsx(f.default,{width:28,height:28})}),e.jsx(w.BodySecondary,{style:{fontWeight:600},children:Z||C}),_&&e.jsx(w.BodyCaption,{color:h.COLORS.content.secondary,children:_}),g&&g.length>0&&e.jsx(o.SuggestionList,{children:g.map(t=>e.jsxs(o.SuggestionChip,{type:"button",disabled:i||c,onClick:()=>je(t),children:[e.jsx(f.default,{width:14,height:14}),t.text]},t.id))})]}):e.jsxs(e.Fragment,{children:[p&&e.jsxs(o.HistoryLoader,{role:"status","aria-live":"polite",children:[e.jsx(J.DotPulse,{color:h.COLORS.content.placeholder,size:4}),ne]}),j.map(t=>e.jsxs(ve.default.Fragment,{children:[t.content.length>0&&e.jsx(o.MessageBubble,{$role:t.role,children:t.role==="assistant"?e.jsx("div",{dangerouslySetInnerHTML:{__html:ge.renderMarkdownLite(t.content)}}):e.jsx("div",{style:{whiteSpace:"pre-wrap"},children:t.content})}),t.wasInterrupted&&P&&e.jsxs(o.InterruptedNote,{children:[e.jsx(G,{size:12}),P]}),t.role==="assistant"&&t.content.length>0&&!t.isStreaming&&e.jsx(o.MessageActions,{children:e.jsx(o.MessageAction,{type:"button",onClick:()=>{ue(t)},"data-copied":x===t.id,title:x===t.id?"Copied":"Copy","aria-label":x===t.id?"Response copied to clipboard":"Copy response",children:x===t.id?e.jsx(Me,{}):e.jsx(Le,{})})})]},t.id)),R&&R.length>0&&e.jsxs(o.FollowUpList,{children:[H&&e.jsx(o.FollowUpsLabel,{children:H}),R.map(t=>e.jsxs(o.FollowUpChip,{type:"button",disabled:i,onClick:()=>fe(t),children:[e.jsx(Ae,{}),t]},t))]}),u&&e.jsxs(o.ThinkingBubble,{role:"status","aria-live":"polite",children:[e.jsx(f.default,{width:14,height:14,color:h.COLORS.content.brand}),O&&e.jsx(o.ThinkingLabel,{children:O}),e.jsx(J.DotPulse,{color:h.COLORS.background.brand,size:5})]}),e.jsx("div",{ref:b})]})}),e.jsx(o.ScrollFade,{$visible:A,"aria-hidden":"true"}),e.jsx(o.JumpToLatestButton,{type:"button",$visible:A,onClick:he,tabIndex:A?0:-1,"aria-label":"Scroll to the latest message",children:e.jsx(Be,{})})]}),W&&e.jsx(o.ErrorBanner,{role:"alert",children:W}),e.jsx(o.InputArea,{children:e.jsxs(o.InputWrapper,{$focused:ae,children:[e.jsx(o.MessageInput,{ref:U,rows:1,value:k,placeholder:Y,disabled:i,onChange:pe,onKeyDown:xe,onFocus:()=>D(!0),onBlur:()=>D(!1)}),e.jsx(o.SendButton,{type:"button",$active:d||K,disabled:!d&&!K,onClick:d?F:z,"aria-label":d?"Stop generating":"Send message",children:d?e.jsx(G,{}):e.jsx(Re,{})})]})}),B&&e.jsx(o.Disclaimer,{children:B})]})};exports.CopilotPanel=_e;
|
|
2
|
+
//# sourceMappingURL=CopilotPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CopilotPanel.js","sources":["../../../../src/components/bik-copilot/CopilotPanel.tsx"],"sourcesContent":["import AiStarsIcon from '@src/assets/icons/bik_ai_stars_icon.svg';\nimport CrossIcon from '@src/assets/icons/cross.svg';\nimport RefreshIcon from '@src/assets/icons/refresh.svg';\nimport React, { useEffect, useRef, useState } from 'react';\nimport { COLORS } from '@src/constants/Theme';\nimport { renderMarkdownLite } from '../bik-chatbot/utils/markdown';\nimport { DotPulse } from '../dot-pulse';\nimport { BodyCaption, BodySecondary, TitleSmall } from '../TypographyStyle';\nimport {\n\tDisclaimer,\n\tEmptyState,\n\tEmptyStateIcon,\n\tErrorBanner,\n\tFollowUpChip,\n\tFollowUpList,\n\tFollowUpsLabel,\n\tHeaderActions,\n\tHeaderAvatar,\n\tHeaderBadge,\n\tHeaderText,\n\tHeaderTitleRow,\n\tHistoryLoader,\n\tIconAction,\n\tInputArea,\n\tInputWrapper,\n\tInterruptedNote,\n\tJumpToLatestButton,\n\tMessageAction,\n\tMessageActions,\n\tMessageBubble,\n\tMessageInput,\n\tMessagesArea,\n\tMessagesViewport,\n\tPanelContainer,\n\tPanelHeader,\n\tScrollFade,\n\tSendButton,\n\tSuggestionChip,\n\tSuggestionList,\n\tThinkingBubble,\n\tThinkingLabel,\n} from './CopilotPanel.styled';\nimport { CopilotPanelProps } from './model';\n\nconst MAX_INPUT_HEIGHT_PX = 96;\n\n/** Slack at the bottom of the scroller that still counts as \"at the latest\". */\nconst AT_BOTTOM_TOLERANCE_PX = 24;\n\n/** How long the copy button shows its confirmation before reverting. */\nconst COPIED_FEEDBACK_MS = 1800;\n\n/**\n * Writes text to the clipboard.\n *\n * `navigator.clipboard` is missing outside a secure context and can reject when\n * the document is not focused, so a hidden-textarea `execCommand` fallback keeps\n * the button working there rather than failing silently.\n */\nconst writeToClipboard = async (text: string): Promise<boolean> => {\n\ttry {\n\t\tif (navigator.clipboard?.writeText) {\n\t\t\tawait navigator.clipboard.writeText(text);\n\t\t\treturn true;\n\t\t}\n\t} catch {\n\t\t// Fall through to the legacy path.\n\t}\n\n\ttry {\n\t\tconst textarea = document.createElement('textarea');\n\t\ttextarea.value = text;\n\t\t// Off-screen rather than hidden: `display: none` cannot be selected.\n\t\ttextarea.setAttribute('readonly', '');\n\t\ttextarea.style.position = 'fixed';\n\t\ttextarea.style.top = '-1000px';\n\t\ttextarea.style.opacity = '0';\n\t\tdocument.body.appendChild(textarea);\n\t\ttextarea.select();\n\t\tconst copied = document.execCommand('copy');\n\t\tdocument.body.removeChild(textarea);\n\t\treturn copied;\n\t} catch {\n\t\treturn false;\n\t}\n};\n\n/** How close to the top counts as asking for the previous page. */\nconst NEAR_TOP_TOLERANCE_PX = 48;\n\nconst SendArrowIcon = () => (\n\t<svg\n\t\tviewBox=\"0 0 24 24\"\n\t\twidth=\"16\"\n\t\theight=\"16\"\n\t\tfill=\"none\"\n\t\tstroke=\"currentColor\"\n\t\tstrokeWidth=\"2\"\n\t\tstrokeLinecap=\"round\"\n\t\tstrokeLinejoin=\"round\"\n\t\taria-hidden=\"true\"\n\t>\n\t\t<path d=\"M12 19V5\" />\n\t\t<path d=\"M6 11l6-6 6 6\" />\n\t</svg>\n);\n\nconst ArrowRightIcon = () => (\n\t<svg\n\t\tviewBox=\"0 0 24 24\"\n\t\twidth=\"14\"\n\t\theight=\"14\"\n\t\tfill=\"none\"\n\t\tstroke=\"currentColor\"\n\t\tstrokeWidth=\"2\"\n\t\tstrokeLinecap=\"round\"\n\t\tstrokeLinejoin=\"round\"\n\t\taria-hidden=\"true\"\n\t>\n\t\t<path d=\"M5 12h14\" />\n\t\t<path d=\"M13 6l6 6-6 6\" />\n\t</svg>\n);\n\nconst StopIcon = ({ size = 16 }: { size?: number }) => (\n\t<svg\n\t\tviewBox=\"0 0 24 24\"\n\t\twidth={size}\n\t\theight={size}\n\t\tfill=\"currentColor\"\n\t\taria-hidden=\"true\"\n\t>\n\t\t<rect x=\"7\" y=\"7\" width=\"10\" height=\"10\" rx=\"2\" />\n\t</svg>\n);\n\nconst CopyIcon = () => (\n\t<svg\n\t\tviewBox=\"0 0 24 24\"\n\t\twidth=\"14\"\n\t\theight=\"14\"\n\t\tfill=\"none\"\n\t\tstroke=\"currentColor\"\n\t\tstrokeWidth=\"1.8\"\n\t\tstrokeLinecap=\"round\"\n\t\tstrokeLinejoin=\"round\"\n\t\taria-hidden=\"true\"\n\t>\n\t\t<rect x=\"9\" y=\"9\" width=\"11\" height=\"11\" rx=\"2\" />\n\t\t<path d=\"M15 5.5A1.5 1.5 0 0 0 13.5 4H5.5A1.5 1.5 0 0 0 4 5.5v8A1.5 1.5 0 0 0 5.5 15\" />\n\t</svg>\n);\n\nconst CheckIcon = () => (\n\t<svg\n\t\tviewBox=\"0 0 24 24\"\n\t\twidth=\"14\"\n\t\theight=\"14\"\n\t\tfill=\"none\"\n\t\tstroke=\"currentColor\"\n\t\tstrokeWidth=\"2.2\"\n\t\tstrokeLinecap=\"round\"\n\t\tstrokeLinejoin=\"round\"\n\t\taria-hidden=\"true\"\n\t>\n\t\t<path d=\"M5 13l4 4L19 7\" />\n\t</svg>\n);\n\nconst ChevronDownIcon = () => (\n\t<svg\n\t\tviewBox=\"0 0 24 24\"\n\t\twidth=\"14\"\n\t\theight=\"14\"\n\t\tfill=\"none\"\n\t\tstroke=\"currentColor\"\n\t\tstrokeWidth=\"2.5\"\n\t\tstrokeLinecap=\"round\"\n\t\tstrokeLinejoin=\"round\"\n\t\taria-hidden=\"true\"\n\t>\n\t\t<path d=\"M6 9l6 6 6-6\" />\n\t</svg>\n);\n\n/**\n * Chat panel used by the copilot. Fully presentational: it renders the\n * transcript it is given and reports user intent through callbacks, so it works\n * against any backend.\n */\nexport const CopilotPanel: React.FC<CopilotPanelProps> = ({\n\tmessages,\n\tonSend,\n\tonClose,\n\ttitle = 'Copilot',\n\tbadge,\n\tsubtitle,\n\tavatar,\n\tplaceholder = 'Write your message...',\n\tdisclaimer = 'AI can make mistakes, Verify the responses.',\n\temptyStateTitle,\n\temptyStateSubtitle = 'Here are some things you can try',\n\tsuggestions,\n\tonSuggestionClick,\n\tshowRefresh = true,\n\tonRefresh,\n\tisThinking = false,\n\tthinkingLabel = 'Thinking',\n\tisStreaming = false,\n\tonStop,\n\tinterruptedLabel = 'This message was interrupted',\n\tfollowUpsLabel = 'Follow ups',\n\thasMoreHistory = false,\n\tisLoadingHistory = false,\n\tonLoadOlderMessages,\n\thistoryLoadingLabel = 'Loading earlier messages',\n\tinputDisabled = false,\n\terrorMessage,\n\twidth,\n\theight,\n\tclassName,\n\tstyle,\n}) => {\n\tconst [input, setInput] = useState('');\n\tconst [isInputFocused, setIsInputFocused] = useState(false);\n\tconst [isAtLatest, setIsAtLatest] = useState(true);\n\t// Which reply is showing \"Copied\" — per message, so copying one does not tick\n\t// the button under another.\n\tconst [copiedMessageId, setCopiedMessageId] = useState<string | null>(null);\n\tconst inputRef = useRef<HTMLTextAreaElement>(null);\n\tconst copiedTimeoutRef = useRef<number | null>(null);\n\tconst bottomRef = useRef<HTMLDivElement>(null);\n\tconst scrollerRef = useRef<HTMLDivElement>(null);\n\tconst lastScrollTopRef = useRef(0);\n\t// Distance from the bottom at the moment an older page was asked for. Older\n\t// messages land *above* the viewport, so without restoring against this the\n\t// content under the reader jumps down by the height of what arrived.\n\tconst anchorFromBottomRef = useRef<number | null>(null);\n\n\t// An assistant bubble is pushed the moment a turn starts, before any text has\n\t// arrived; the thinking indicator stands in for it until then, so rendering it\n\t// too would show an empty balloon next to the dots. A turn stopped before its\n\t// first token keeps its place, carrying only the interrupted note.\n\tconst visibleMessages = messages.filter(\n\t\t(message) => message.content.length > 0 || message.wasInterrupted,\n\t);\n\tconst isEmpty = visibleMessages.length === 0 && !isThinking;\n\tconst isTurnInFlight = isThinking || isStreaming;\n\tconst canSend = !inputDisabled && !isTurnInFlight && input.trim().length > 0;\n\t// Stopping is the only thing the button can do mid-answer, so it becomes the\n\t// stop button rather than sitting there disabled.\n\tconst canStop = isTurnInFlight && Boolean(onStop);\n\t// Only the newest reply's suggestions are on offer — older ones answer a\n\t// question the conversation has already moved past.\n\tconst newestMessage = visibleMessages[visibleMessages.length - 1];\n\tconst followUps =\n\t\t!isTurnInFlight && newestMessage?.role === 'assistant'\n\t\t\t? newestMessage.followUps\n\t\t\t: undefined;\n\t// A long answer that the reader has scrolled up from: the tail is clipped, so\n\t// the fade and the arrow say there is more below.\n\tconst showScrollAffordance = !isEmpty && !isAtLatest;\n\n\t// Following the conversation is the default, but a reader who has scrolled up\n\t// mid-answer must not be yanked back down by the next chunk.\n\tuseEffect(() => {\n\t\tif (!isAtLatest) {\n\t\t\treturn;\n\t\t}\n\t\tbottomRef.current?.scrollIntoView({ behavior: 'smooth' });\n\t}, [messages, isThinking, isAtLatest]);\n\n\t// Older messages have landed: put the reader back on the message they were\n\t// looking at, which is now that much further down.\n\tuseEffect(() => {\n\t\tconst scroller = scrollerRef.current;\n\t\tconst anchor = anchorFromBottomRef.current;\n\t\tif (!scroller || anchor === null || isLoadingHistory) {\n\t\t\treturn;\n\t\t}\n\t\tanchorFromBottomRef.current = null;\n\t\tscroller.scrollTop = scroller.scrollHeight - anchor;\n\t\tlastScrollTopRef.current = scroller.scrollTop;\n\t}, [messages, isLoadingHistory]);\n\n\tconst handleScroll = () => {\n\t\tconst scroller = scrollerRef.current;\n\t\tif (!scroller) {\n\t\t\treturn;\n\t\t}\n\t\tconst distanceFromBottom =\n\t\t\tscroller.scrollHeight - scroller.scrollTop - scroller.clientHeight;\n\n\t\t// Reaching the top asks for the page before this one. The threshold gives\n\t\t// the request a head start, so the page is usually there by the time the\n\t\t// reader arrives.\n\t\tif (\n\t\t\tscroller.scrollTop <= NEAR_TOP_TOLERANCE_PX &&\n\t\t\thasMoreHistory &&\n\t\t\t!isLoadingHistory &&\n\t\t\tonLoadOlderMessages\n\t\t) {\n\t\t\tanchorFromBottomRef.current = scroller.scrollHeight - scroller.scrollTop;\n\t\t\tonLoadOlderMessages();\n\t\t}\n\t\t// Scrolling *up* is the only thing that detaches from the latest message:\n\t\t// growing content also pushes the bottom away, and auto-scroll itself only\n\t\t// ever moves down, so distance alone would flap mid-stream.\n\t\tconst scrolledUp = scroller.scrollTop < lastScrollTopRef.current - 1;\n\t\tlastScrollTopRef.current = scroller.scrollTop;\n\n\t\tif (distanceFromBottom <= AT_BOTTOM_TOLERANCE_PX) {\n\t\t\tsetIsAtLatest(true);\n\t\t\treturn;\n\t\t}\n\t\tif (scrolledUp) {\n\t\t\tsetIsAtLatest(false);\n\t\t}\n\t};\n\n\tconst handleJumpToLatest = () => {\n\t\tsetIsAtLatest(true);\n\t\tbottomRef.current?.scrollIntoView({ behavior: 'smooth' });\n\t};\n\n\tuseEffect(\n\t\t() => () => {\n\t\t\tif (copiedTimeoutRef.current) {\n\t\t\t\twindow.clearTimeout(copiedTimeoutRef.current);\n\t\t\t}\n\t\t},\n\t\t[],\n\t);\n\n\tconst handleCopyMessage = async (\n\t\tmessage: CopilotPanelProps['messages'][number],\n\t) => {\n\t\t// The raw markdown, not the rendered HTML — that is what a reader wants to\n\t\t// paste into a doc or a ticket.\n\t\tconst copied = await writeToClipboard(message.content);\n\t\tif (!copied) {\n\t\t\treturn;\n\t\t}\n\t\tif (copiedTimeoutRef.current) {\n\t\t\twindow.clearTimeout(copiedTimeoutRef.current);\n\t\t}\n\t\tsetCopiedMessageId(message.id);\n\t\tcopiedTimeoutRef.current = window.setTimeout(\n\t\t\t() => setCopiedMessageId(null),\n\t\t\tCOPIED_FEEDBACK_MS,\n\t\t);\n\t};\n\n\tconst handleSend = () => {\n\t\tconst trimmed = input.trim();\n\t\tif (!trimmed || inputDisabled || isTurnInFlight) {\n\t\t\treturn;\n\t\t}\n\t\tonSend(trimmed);\n\t\tsetInput('');\n\t\tconst textarea = inputRef.current;\n\t\tif (textarea) {\n\t\t\ttextarea.style.height = 'auto';\n\t\t}\n\t};\n\n\tconst handleInputChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {\n\t\tsetInput(event.target.value);\n\t\tconst textarea = event.target;\n\t\ttextarea.style.height = 'auto';\n\t\ttextarea.style.height = `${Math.min(\n\t\t\ttextarea.scrollHeight,\n\t\t\tMAX_INPUT_HEIGHT_PX,\n\t\t)}px`;\n\t};\n\n\tconst handleKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n\t\tif (event.key === 'Enter' && !event.shiftKey) {\n\t\t\tevent.preventDefault();\n\t\t\thandleSend();\n\t\t}\n\t};\n\n\tconst handleSuggestionClick = (\n\t\tsuggestion: NonNullable<CopilotPanelProps['suggestions']>[number],\n\t) => {\n\t\tif (inputDisabled || isTurnInFlight) {\n\t\t\treturn;\n\t\t}\n\t\tonSuggestionClick?.(suggestion);\n\t\tonSend(suggestion.text);\n\t};\n\n\tconst handleFollowUpClick = (followUp: string) => {\n\t\tif (inputDisabled || isTurnInFlight) {\n\t\t\treturn;\n\t\t}\n\t\tonSend(followUp);\n\t};\n\n\treturn (\n\t\t<PanelContainer\n\t\t\tclassName={className}\n\t\t\tstyle={{ width, height, ...style }}\n\t\t\trole=\"dialog\"\n\t\t\taria-label={title}\n\t\t>\n\t\t\t<PanelHeader>\n\t\t\t\t<HeaderAvatar>\n\t\t\t\t\t{avatar ?? <AiStarsIcon width={18} height={18} />}\n\t\t\t\t</HeaderAvatar>\n\t\t\t\t<HeaderText>\n\t\t\t\t\t<HeaderTitleRow>\n\t\t\t\t\t\t<TitleSmall>{title}</TitleSmall>\n\t\t\t\t\t\t{badge && <HeaderBadge>{badge}</HeaderBadge>}\n\t\t\t\t\t</HeaderTitleRow>\n\t\t\t\t\t{subtitle && (\n\t\t\t\t\t\t<BodyCaption color={COLORS.content.secondary}>\n\t\t\t\t\t\t\t{subtitle}\n\t\t\t\t\t\t</BodyCaption>\n\t\t\t\t\t)}\n\t\t\t\t</HeaderText>\n\t\t\t\t<HeaderActions>\n\t\t\t\t\t{showRefresh && onRefresh && (\n\t\t\t\t\t\t<IconAction\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tonClick={onRefresh}\n\t\t\t\t\t\t\taria-label=\"Start a new conversation\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<RefreshIcon width={16} height={16} />\n\t\t\t\t\t\t</IconAction>\n\t\t\t\t\t)}\n\t\t\t\t\t<IconAction\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tonClick={onClose}\n\t\t\t\t\t\taria-label=\"Close copilot\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<CrossIcon width={18} height={18} />\n\t\t\t\t\t</IconAction>\n\t\t\t\t</HeaderActions>\n\t\t\t</PanelHeader>\n\n\t\t\t<MessagesViewport>\n\t\t\t\t<MessagesArea\n\t\t\t\t\tref={scrollerRef}\n\t\t\t\t\tonScroll={handleScroll}\n\t\t\t\t\trole=\"region\"\n\t\t\t\t\taria-label=\"Conversation\"\n\t\t\t\t>\n\t\t\t\t\t{isEmpty ? (\n\t\t\t\t\t\t<EmptyState>\n\t\t\t\t\t\t\t<EmptyStateIcon>\n\t\t\t\t\t\t\t\t<AiStarsIcon width={28} height={28} />\n\t\t\t\t\t\t\t</EmptyStateIcon>\n\t\t\t\t\t\t\t<BodySecondary style={{ fontWeight: 600 }}>\n\t\t\t\t\t\t\t\t{emptyStateTitle || title}\n\t\t\t\t\t\t\t</BodySecondary>\n\t\t\t\t\t\t\t{emptyStateSubtitle && (\n\t\t\t\t\t\t\t\t<BodyCaption color={COLORS.content.secondary}>\n\t\t\t\t\t\t\t\t\t{emptyStateSubtitle}\n\t\t\t\t\t\t\t\t</BodyCaption>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t{suggestions && suggestions.length > 0 && (\n\t\t\t\t\t\t\t\t<SuggestionList>\n\t\t\t\t\t\t\t\t\t{suggestions.map((suggestion) => (\n\t\t\t\t\t\t\t\t\t\t<SuggestionChip\n\t\t\t\t\t\t\t\t\t\t\tkey={suggestion.id}\n\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\tdisabled={inputDisabled || isTurnInFlight}\n\t\t\t\t\t\t\t\t\t\t\tonClick={() => handleSuggestionClick(suggestion)}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<AiStarsIcon width={14} height={14} />\n\t\t\t\t\t\t\t\t\t\t\t{suggestion.text}\n\t\t\t\t\t\t\t\t\t\t</SuggestionChip>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</SuggestionList>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</EmptyState>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t{isLoadingHistory && (\n\t\t\t\t\t\t\t\t<HistoryLoader role=\"status\" aria-live=\"polite\">\n\t\t\t\t\t\t\t\t\t<DotPulse color={COLORS.content.placeholder} size={4} />\n\t\t\t\t\t\t\t\t\t{historyLoadingLabel}\n\t\t\t\t\t\t\t\t</HistoryLoader>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t{visibleMessages.map((message) => (\n\t\t\t\t\t\t\t\t<React.Fragment key={message.id}>\n\t\t\t\t\t\t\t\t\t{message.content.length > 0 && (\n\t\t\t\t\t\t\t\t\t\t<MessageBubble $role={message.role}>\n\t\t\t\t\t\t\t\t\t\t\t{message.role === 'assistant' ? (\n\t\t\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\t\t\tdangerouslySetInnerHTML={{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t__html: renderMarkdownLite(message.content),\n\t\t\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t\t<div style={{ whiteSpace: 'pre-wrap' }}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{message.content}\n\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t</MessageBubble>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t{message.wasInterrupted && interruptedLabel && (\n\t\t\t\t\t\t\t\t\t\t<InterruptedNote>\n\t\t\t\t\t\t\t\t\t\t\t<StopIcon size={12} />\n\t\t\t\t\t\t\t\t\t\t\t{interruptedLabel}\n\t\t\t\t\t\t\t\t\t\t</InterruptedNote>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t{/* Only under a finished reply: mid-stream the text is still\n\t\t\t\t\t\t\t\t\t changing, so copying it would capture a partial answer. */}\n\t\t\t\t\t\t\t\t\t{message.role === 'assistant' &&\n\t\t\t\t\t\t\t\t\t\tmessage.content.length > 0 &&\n\t\t\t\t\t\t\t\t\t\t!message.isStreaming && (\n\t\t\t\t\t\t\t\t\t\t\t<MessageActions>\n\t\t\t\t\t\t\t\t\t\t\t\t<MessageAction\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tonClick={() => void handleCopyMessage(message)}\n\t\t\t\t\t\t\t\t\t\t\t\t\tdata-copied={copiedMessageId === message.id}\n\t\t\t\t\t\t\t\t\t\t\t\t\ttitle={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tcopiedMessageId === message.id ? 'Copied' : 'Copy'\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t// The label changes with the state, so a screen reader\n\t\t\t\t\t\t\t\t\t\t\t\t\t// hears the confirmation the tick shows visually.\n\t\t\t\t\t\t\t\t\t\t\t\t\taria-label={\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tcopiedMessageId === message.id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t? 'Response copied to clipboard'\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t: 'Copy response'\n\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t{copiedMessageId === message.id ? (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<CheckIcon />\n\t\t\t\t\t\t\t\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<CopyIcon />\n\t\t\t\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t\t\t\t</MessageAction>\n\t\t\t\t\t\t\t\t\t\t\t</MessageActions>\n\t\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</React.Fragment>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t{followUps && followUps.length > 0 && (\n\t\t\t\t\t\t\t\t<FollowUpList>\n\t\t\t\t\t\t\t\t\t{followUpsLabel && (\n\t\t\t\t\t\t\t\t\t\t<FollowUpsLabel>{followUpsLabel}</FollowUpsLabel>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t{followUps.map((followUp) => (\n\t\t\t\t\t\t\t\t\t\t<FollowUpChip\n\t\t\t\t\t\t\t\t\t\t\tkey={followUp}\n\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\tdisabled={inputDisabled}\n\t\t\t\t\t\t\t\t\t\t\tonClick={() => handleFollowUpClick(followUp)}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<ArrowRightIcon />\n\t\t\t\t\t\t\t\t\t\t\t{followUp}\n\t\t\t\t\t\t\t\t\t\t</FollowUpChip>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</FollowUpList>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t{isThinking && (\n\t\t\t\t\t\t\t\t<ThinkingBubble role=\"status\" aria-live=\"polite\">\n\t\t\t\t\t\t\t\t\t<AiStarsIcon\n\t\t\t\t\t\t\t\t\t\twidth={14}\n\t\t\t\t\t\t\t\t\t\theight={14}\n\t\t\t\t\t\t\t\t\t\tcolor={COLORS.content.brand}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t{thinkingLabel && (\n\t\t\t\t\t\t\t\t\t\t<ThinkingLabel>{thinkingLabel}</ThinkingLabel>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t\t<DotPulse color={COLORS.background.brand} size={5} />\n\t\t\t\t\t\t\t\t</ThinkingBubble>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t<div ref={bottomRef} />\n\t\t\t\t\t\t</>\n\t\t\t\t\t)}\n\t\t\t\t</MessagesArea>\n\n\t\t\t\t<ScrollFade $visible={showScrollAffordance} aria-hidden=\"true\" />\n\t\t\t\t<JumpToLatestButton\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t$visible={showScrollAffordance}\n\t\t\t\t\tonClick={handleJumpToLatest}\n\t\t\t\t\ttabIndex={showScrollAffordance ? 0 : -1}\n\t\t\t\t\taria-label=\"Scroll to the latest message\"\n\t\t\t\t>\n\t\t\t\t\t<ChevronDownIcon />\n\t\t\t\t</JumpToLatestButton>\n\t\t\t</MessagesViewport>\n\n\t\t\t{errorMessage && <ErrorBanner role=\"alert\">{errorMessage}</ErrorBanner>}\n\n\t\t\t<InputArea>\n\t\t\t\t<InputWrapper $focused={isInputFocused}>\n\t\t\t\t\t<MessageInput\n\t\t\t\t\t\tref={inputRef}\n\t\t\t\t\t\trows={1}\n\t\t\t\t\t\tvalue={input}\n\t\t\t\t\t\tplaceholder={placeholder}\n\t\t\t\t\t\tdisabled={inputDisabled}\n\t\t\t\t\t\tonChange={handleInputChange}\n\t\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\t\tonFocus={() => setIsInputFocused(true)}\n\t\t\t\t\t\tonBlur={() => setIsInputFocused(false)}\n\t\t\t\t\t/>\n\t\t\t\t\t<SendButton\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t$active={canStop || canSend}\n\t\t\t\t\t\tdisabled={!canStop && !canSend}\n\t\t\t\t\t\tonClick={canStop ? onStop : handleSend}\n\t\t\t\t\t\taria-label={canStop ? 'Stop generating' : 'Send message'}\n\t\t\t\t\t>\n\t\t\t\t\t\t{canStop ? <StopIcon /> : <SendArrowIcon />}\n\t\t\t\t\t</SendButton>\n\t\t\t\t</InputWrapper>\n\t\t\t</InputArea>\n\n\t\t\t{disclaimer && <Disclaimer>{disclaimer}</Disclaimer>}\n\t\t</PanelContainer>\n\t);\n};\n\nexport default CopilotPanel;\n"],"names":["MAX_INPUT_HEIGHT_PX","AT_BOTTOM_TOLERANCE_PX","COPIED_FEEDBACK_MS","writeToClipboard","text","textarea","copied","NEAR_TOP_TOLERANCE_PX","SendArrowIcon","jsxs","jsx","ArrowRightIcon","StopIcon","size","CopyIcon","CheckIcon","ChevronDownIcon","CopilotPanel","messages","onSend","onClose","title","badge","subtitle","avatar","placeholder","disclaimer","emptyStateTitle","emptyStateSubtitle","suggestions","onSuggestionClick","showRefresh","onRefresh","isThinking","thinkingLabel","isStreaming","onStop","interruptedLabel","followUpsLabel","hasMoreHistory","isLoadingHistory","onLoadOlderMessages","historyLoadingLabel","inputDisabled","errorMessage","width","height","className","style","input","setInput","useState","isInputFocused","setIsInputFocused","isAtLatest","setIsAtLatest","copiedMessageId","setCopiedMessageId","inputRef","useRef","copiedTimeoutRef","bottomRef","scrollerRef","lastScrollTopRef","anchorFromBottomRef","visibleMessages","message","isEmpty","isTurnInFlight","canSend","canStop","newestMessage","followUps","showScrollAffordance","useEffect","scroller","anchor","handleScroll","distanceFromBottom","scrolledUp","handleJumpToLatest","handleCopyMessage","handleSend","trimmed","handleInputChange","event","handleKeyDown","handleSuggestionClick","suggestion","handleFollowUpClick","followUp","PanelContainer","PanelHeader","HeaderAvatar","AiStarsIcon","HeaderText","HeaderTitleRow","TitleSmall","HeaderBadge","BodyCaption","COLORS","HeaderActions","IconAction","RefreshIcon","CrossIcon","MessagesViewport","MessagesArea","EmptyState","EmptyStateIcon","BodySecondary","SuggestionList","SuggestionChip","Fragment","HistoryLoader","DotPulse","React","MessageBubble","renderMarkdownLite","InterruptedNote","MessageActions","MessageAction","FollowUpList","FollowUpsLabel","FollowUpChip","ThinkingBubble","ThinkingLabel","ScrollFade","JumpToLatestButton","ErrorBanner","InputArea","InputWrapper","MessageInput","SendButton","Disclaimer"],"mappings":"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"}
|