@bikdotai/bik-component-library 0.0.875-beta.2 → 0.0.875-beta.3
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/components/ConfigToolPanel.js +11 -11
- package/dist/cjs/components/agent-builder/components/ConfigToolPanel.js.map +1 -1
- package/dist/cjs/components/agent-builder/components/CreateSubAgentPanel.js +2 -2
- package/dist/cjs/components/agent-builder/components/CreateSubAgentPanel.js.map +1 -1
- package/dist/cjs/components/agent-builder/components/RestApiToolPanel.js +4 -4
- package/dist/cjs/components/agent-builder/components/RestApiToolPanel.js.map +1 -1
- package/dist/cjs/components/agent-builder/utils/sourceIcons.js +1 -1
- package/dist/cjs/components/dropdown/OpenedDropdown/components/OpennedDropdown.js +1 -1
- package/dist/cjs/components/dropdown/OpenedDropdown/components/OpennedDropdown.js.map +1 -1
- package/dist/cjs/components/dropdown/OpenedDropdown/components/menu/MenuItem.js +27 -10
- package/dist/cjs/components/dropdown/OpenedDropdown/components/menu/MenuItem.js.map +1 -1
- package/dist/cjs/components/dropdown/OpenedDropdown/components/menu/MenuList.js +1 -1
- package/dist/cjs/components/dropdown/OpenedDropdown/components/menu/MenuList.js.map +1 -1
- package/dist/cjs/components/dropdown/OpenedDropdown/components/menu/SelectAllMenu.js +1 -1
- package/dist/cjs/components/dropdown/OpenedDropdown/components/menu/SelectAllMenu.js.map +1 -1
- package/dist/cjs/components/dropdown/OpenedDropdown/components/multiSelect/MultiSelectDropdownBottomBar.js +1 -1
- package/dist/cjs/components/dropdown/OpenedDropdown/components/multiSelect/MultiSelectDropdownBottomBar.js.map +1 -1
- package/dist/cjs/components/dropdown/OpenedDropdown/utils/iterationOnOptions.js +1 -1
- package/dist/cjs/components/dropdown/OpenedDropdown/utils/iterationOnOptions.js.map +1 -1
- package/dist/cjs/components/dropdown/hooks/useDropdown.js +1 -1
- package/dist/cjs/components/dropdown/hooks/useDropdown.js.map +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/esm/components/agent-builder/components/ConfigToolPanel.d.ts +0 -12
- package/dist/esm/components/agent-builder/components/ConfigToolPanel.js +145 -149
- package/dist/esm/components/agent-builder/components/ConfigToolPanel.js.map +1 -1
- package/dist/esm/components/agent-builder/components/CreateSubAgentPanel.d.ts +0 -12
- package/dist/esm/components/agent-builder/components/CreateSubAgentPanel.js +82 -86
- package/dist/esm/components/agent-builder/components/CreateSubAgentPanel.js.map +1 -1
- package/dist/esm/components/agent-builder/components/MentionPicker.js +5 -5
- package/dist/esm/components/agent-builder/components/RestApiToolPanel.d.ts +0 -12
- package/dist/esm/components/agent-builder/components/RestApiToolPanel.js +48 -52
- package/dist/esm/components/agent-builder/components/RestApiToolPanel.js.map +1 -1
- package/dist/esm/components/agent-builder/index.d.ts +2 -18
- package/dist/esm/components/agent-builder/utils/sourceIcons.js +43 -43
- package/dist/esm/components/agent-builder/utils/toolActions.js +3 -3
- package/dist/esm/components/dropdown/OpenedDropdown/components/OpennedDropdown.js +300 -278
- package/dist/esm/components/dropdown/OpenedDropdown/components/OpennedDropdown.js.map +1 -1
- package/dist/esm/components/dropdown/OpenedDropdown/components/menu/MenuItem.d.ts +8 -0
- package/dist/esm/components/dropdown/OpenedDropdown/components/menu/MenuItem.js +170 -126
- package/dist/esm/components/dropdown/OpenedDropdown/components/menu/MenuItem.js.map +1 -1
- package/dist/esm/components/dropdown/OpenedDropdown/components/menu/MenuList.d.ts +4 -0
- package/dist/esm/components/dropdown/OpenedDropdown/components/menu/MenuList.js +144 -112
- package/dist/esm/components/dropdown/OpenedDropdown/components/menu/MenuList.js.map +1 -1
- package/dist/esm/components/dropdown/OpenedDropdown/components/menu/SelectAllMenu.d.ts +1 -0
- package/dist/esm/components/dropdown/OpenedDropdown/components/menu/SelectAllMenu.js +32 -31
- package/dist/esm/components/dropdown/OpenedDropdown/components/menu/SelectAllMenu.js.map +1 -1
- package/dist/esm/components/dropdown/OpenedDropdown/components/multiSelect/MultiSelectDropdownBottomBar.d.ts +2 -0
- package/dist/esm/components/dropdown/OpenedDropdown/components/multiSelect/MultiSelectDropdownBottomBar.js +54 -39
- package/dist/esm/components/dropdown/OpenedDropdown/components/multiSelect/MultiSelectDropdownBottomBar.js.map +1 -1
- package/dist/esm/components/dropdown/OpenedDropdown/utils/iterationOnOptions.d.ts +18 -16
- package/dist/esm/components/dropdown/OpenedDropdown/utils/iterationOnOptions.js +73 -27
- package/dist/esm/components/dropdown/OpenedDropdown/utils/iterationOnOptions.js.map +1 -1
- package/dist/esm/components/dropdown/hooks/useDropdown.d.ts +4 -17
- package/dist/esm/components/dropdown/hooks/useDropdown.js +176 -163
- package/dist/esm/components/dropdown/hooks/useDropdown.js.map +1 -1
- package/dist/esm/components/dropdown/type.d.ts +22 -0
- package/dist/esm/index.js +772 -816
- package/dist/esm/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("react/jsx-runtime"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("react/jsx-runtime"),A=require("../../../assets/icons/cross.svg.js"),c=require("react"),$=require("styled-components"),O=require("../../TypographyStyle.js"),d=require("../../../constants/Theme.js"),F=require("../AgentBuilder.styled.js"),D=require("../constants/charLimits.js"),I=require("./DrawerHeaderText.js"),P=require("./ToolInstructionsField.js"),q=require("./VariableTriggerArea.js"),Y=require("../../side-modal/SideModal.js"),V=require("../../switch/Switch.js"),M=require("../../input/Input.js"),G=require("../../tag/Tag.js"),B=t=>t&&typeof t=="object"&&"default"in t?t:{default:t},z=B(c),R=B($),H={send_email:{title:"Send email",subtitle:"Notify someone by email when this agent can't continue. You pick the recipient, the AI drafts the message."},send_slack_message:{title:"Send Slack message",subtitle:"Post a message to a Slack channel. You pick the channel, the AI composes the message from the conversation."},google_sheet_get_data:{title:"Get data from sheet",subtitle:"Look up rows in a Google Sheet. You pick the sheet and describe its columns, the AI writes the query it needs."},google_sheet_add_row:{title:"Add row to sheet",subtitle:"Append a row to a Google Sheet. You pick the sheet and its columns, the AI fills them in from the conversation."}},W=({chips:t,onChange:a,placeholder:y,nativeID:h,hint:v,variablesData:w})=>{const[i,f]=c.useState(""),[j,s]=c.useState(!1),b=c.useRef(null),T=c.useRef(null),k=()=>{const n=i.split(",").map(l=>l.trim()).filter(Boolean);n.length&&a([...t,...n.filter(l=>!t.includes(l))]),f("")},x=c.useRef(k);x.current=k;const C=c.useRef(!1),u=c.useRef(!1);return r.jsxs(Q,{ref:b,children:[r.jsx(q.VariableTriggerArea,{addDataButton:!0,variablesData:w,onOpenChange:n=>{C.current=n,!n&&setTimeout(()=>{!u.current&&!b.current?.contains(document.activeElement)&&x.current(),u.current=!1},0)},onInsert:(n,l)=>{u.current=!0;const S=l??i.length;f(`${i.slice(0,S)}${n}${i.slice(S)}`),requestAnimationFrame(()=>{const p=T.current;p?.focus(),p?.setSelectionRange(S+n.length,S+n.length)})},children:r.jsx(U,{id:h,name:h,ref:T,type:"text",autoComplete:"off",placeholder:j&&i===""&&(w?.length??0)>0?"Enter text, type @ to add variable":y,value:i,onChange:n=>f(n.target.value),onFocus:()=>s(!0),onBlur:()=>{s(!1),setTimeout(()=>{!C.current&&!b.current?.contains(document.activeElement)&&x.current()},0)},onKeyDown:n=>{n.key==="Enter"||n.key===","?(n.preventDefault(),k()):n.key==="Backspace"&&i===""&&t.length>0&&a(t.slice(0,-1))}})}),v,t.length>0&&r.jsx(X,{children:t.map((n,l)=>r.jsx(G.Tag,{tagText:n.replace(/\{\{variable:([^}]+)\}\}/g,"{{$1}}"),theme:"light",type:"neutral",variant:"regular",TrailingIcon:A.default,onTrailingIconClicked:()=>a(t.filter((S,p)=>p!==l))},`${n}-${l}`))})]})},N=(t,a)=>{const y={};return Object.keys(t).forEach(h=>{y[h]=a?.params[h]?.value??t[h].value}),y},J=t=>String(t??"").split(",").map(a=>a.trim()).filter(Boolean),K=({toolKey:t,template:a,onClose:y,onSave:h,initial:v,onImprove:w,charLimits:i=D.AGENT_CHAR_LIMITS,variablesData:f,zIndex:j})=>{const[s,b]=c.useState(()=>N(a,v)),[T,k]=c.useState(!1),x=Object.values(a),C=t==="send_email",u=(e,g)=>b(m=>({...m,[e]:g})),n=x.every(e=>!(e.required&&String(s[e.key]??"").trim()===""||e.component==="MultilineInput"&&String(s[e.key]??"").length>i.instructions)),l=async()=>{if(!n||T)return;const e={};x.forEach(o=>{e[o.key]={...o,value:s[o.key]}});const g={id:v?.id??`${t}_${Date.now().toString(36)}`,tool_key:t,params:e},m=h(g);if(m&&typeof m.then=="function"){k(!0);try{await m}finally{k(!1)}}},S=e=>{const g=`config-tool-${e.key.toLowerCase()}`;switch(e.component){case"KeywordInput":if(!C)break;return r.jsxs(F.FieldBlock,{children:[r.jsx(O.TitleSmall,{color:d.COLORS.content.primary,children:e.title}),r.jsx(W,{nativeID:g,placeholder:e.hint??"",chips:J(s[e.key]),onChange:o=>u(e.key,o.join(",")),variablesData:f,hint:r.jsx(O.BodyCaption,{color:d.COLORS.content.secondary,children:"Press Enter or comma to add multiple emails"})})]},e.key);case"MultilineInput":return r.jsx(P.ToolInstructionsField,{"data-test":g,label:e.title,value:String(s[e.key]??""),onChange:o=>u(e.key,o),maxLength:i.instructions,placeholder:e.hint??"",onImprove:w,variablesData:f},e.key);case"Switch":return r.jsxs(Z,{children:[r.jsxs(ee,{children:[r.jsx(O.TitleSmall,{color:d.COLORS.content.primary,children:e.title}),e.hint&&r.jsx(O.BodyCaption,{color:d.COLORS.content.secondary,children:e.hint})]}),r.jsx(V.Switch,{"data-test":g,value:!!s[e.key],onValueChange:async o=>u(e.key,o)})]},e.key)}const m=r.jsx(M.Input,{"data-test":g,variant:"small",labelText:e.title,labelTextBold:!0,placeholder:e.hint??"",value:String(s[e.key]??""),onChangeText:o=>u(e.key,o)});return C?r.jsx(q.VariableTriggerArea,{addDataButton:!0,variablesData:f,onInsert:(o,L)=>{const _=String(s[e.key]??""),E=L??_.length;u(e.key,`${_.slice(0,E)}${o}${_.slice(E)}`)},children:m},e.key):r.jsx(z.default.Fragment,{children:m},e.key)},p=H[t];return r.jsx(Y.SideModal,{header:p.title,closeOnEscapeKey:!1,zIndex:j,headerCustomComponent:r.jsx(I.DrawerHeaderText,{title:p.title,subtitle:p.subtitle}),hideCrossButton:!1,width:"431px",headerStyle:I.DRAWER_HEADER_STYLE,bodyStyle:I.DRAWER_BODY_STYLE,onClose:y,saveButtonProps:{"data-test":"config-tool-save",buttonText:"Save",buttonType:"primary",size:"small",disabled:!n,isLoading:T,onClick:l},cancelButtonProps:{"data-test":"config-tool-cancel",buttonText:"Cancel",buttonType:"tertiaryGray",size:"small",onClick:y},children:x.map(S)})},Q=R.default.div`
|
|
2
2
|
display: flex;
|
|
3
3
|
flex-direction: column;
|
|
4
4
|
gap: 8px;
|
|
5
|
-
`,
|
|
5
|
+
`,U=R.default.input`
|
|
6
6
|
width: 100%;
|
|
7
7
|
min-width: 0;
|
|
8
8
|
box-sizing: border-box;
|
|
9
9
|
height: 32px;
|
|
10
10
|
padding: 0 8px;
|
|
11
|
-
border: 1px solid ${
|
|
11
|
+
border: 1px solid ${d.COLORS.stroke.primary};
|
|
12
12
|
border-radius: 4px;
|
|
13
13
|
font-family: 'Inter', sans-serif;
|
|
14
14
|
font-size: 14px;
|
|
15
|
-
color: ${
|
|
16
|
-
background: ${
|
|
15
|
+
color: ${d.COLORS.content.primary};
|
|
16
|
+
background: ${d.COLORS.surface.standard};
|
|
17
17
|
outline: none;
|
|
18
18
|
|
|
19
19
|
&::placeholder {
|
|
20
|
-
color: ${
|
|
20
|
+
color: ${d.COLORS.content.secondary};
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
&:focus {
|
|
24
|
-
border-color: ${
|
|
24
|
+
border-color: ${d.COLORS.stroke.brand};
|
|
25
25
|
}
|
|
26
|
-
`,
|
|
26
|
+
`,X=R.default.div`
|
|
27
27
|
display: flex;
|
|
28
28
|
flex-wrap: wrap;
|
|
29
29
|
gap: 6px;
|
|
30
|
-
`,
|
|
30
|
+
`,Z=R.default.div`
|
|
31
31
|
display: flex;
|
|
32
32
|
align-items: center;
|
|
33
33
|
justify-content: space-between;
|
|
34
34
|
gap: 12px;
|
|
35
|
-
`,
|
|
35
|
+
`,ee=R.default.div`
|
|
36
36
|
display: flex;
|
|
37
37
|
flex-direction: column;
|
|
38
38
|
gap: 4px;
|
|
39
39
|
min-width: 0;
|
|
40
|
-
`;exports.ConfigToolPanel=
|
|
40
|
+
`;exports.ConfigToolPanel=K;
|
|
41
41
|
//# sourceMappingURL=ConfigToolPanel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfigToolPanel.js","sources":["../../../../../src/components/agent-builder/components/ConfigToolPanel.tsx"],"sourcesContent":["import CrossIcon from '@src/assets/icons/cross.svg';\nimport React, { useRef, useState } from 'react';\nimport styled from 'styled-components';\nimport { Input } from '@src/components/input';\nimport { SideModal } from '@src/components/side-modal';\nimport { Switch } from '@src/components/switch';\nimport { Tag } from '@src/components/tag';\nimport { BodyCaption, TitleSmall } from '@src/components/TypographyStyle';\nimport { COLORS } from '@src/constants/Theme';\nimport type { VariableListInterfaceV3 } from '../../variable-picker-v3/model';\nimport {\n\tConfigToolConfig,\n\tConfigToolKey,\n\tParamField,\n\tParamsBlob,\n} from '../AgentBuilder.model';\nimport { FieldBlock } from '../AgentBuilder.styled';\nimport type { AgentCharLimits } from '../constants/charLimits';\nimport { AGENT_CHAR_LIMITS } from '../constants/charLimits';\nimport {\n\tDRAWER_BODY_STYLE,\n\tDRAWER_HEADER_STYLE,\n\tDrawerHeaderText,\n} from './DrawerHeaderText';\nimport { ToolInstructionsField } from './ToolInstructionsField';\nimport { VariableTriggerArea } from './VariableTriggerArea';\n\n/** Header copy per shared-drawer tool. */\nconst TOOL_COPY: Record<ConfigToolKey, { title: string; subtitle: string }> = {\n\tsend_email: {\n\t\ttitle: 'Send email',\n\t\tsubtitle:\n\t\t\t\"Notify someone by email when this agent can't continue. You pick the recipient, the AI drafts the message.\",\n\t},\n\tsend_slack_message: {\n\t\ttitle: 'Send Slack message',\n\t\tsubtitle:\n\t\t\t'Post a message to a Slack channel. You pick the channel, the AI composes the message from the conversation.',\n\t},\n\tgoogle_sheet_get_data: {\n\t\ttitle: 'Get data from sheet',\n\t\tsubtitle:\n\t\t\t'Look up rows in a Google Sheet. You pick the sheet and describe its columns, the AI writes the query it needs.',\n\t},\n\tgoogle_sheet_add_row: {\n\t\ttitle: 'Add row to sheet',\n\t\tsubtitle:\n\t\t\t'Append a row to a Google Sheet. You pick the sheet and its columns, the AI fills them in from the conversation.',\n\t},\n};\n\ninterface ConfigToolPanelProps {\n\t/** Which tool this drawer configures (drives copy + persistence). */\n\ttoolKey: ConfigToolKey;\n\t/**\n\t * The backend template (`list-catalog` → params) for `toolKey`. The form is\n\t * DYNAMIC: exactly these fields render, in this order, each by its\n\t * `component` kind (KeywordInput | MultilineInput | Switch | fallback input).\n\t */\n\ttemplate: ParamsBlob;\n\tonClose: () => void;\n\t/** Persist the filled template. A pending promise shows the Save loader. */\n\tonSave: (config: ConfigToolConfig) => void | Promise<void>;\n\t/** Seed values when editing an existing tool. */\n\tinitial?: ConfigToolConfig;\n\t/** Optional \"Improve with AI\" for multiline fields. Omit to hide it. */\n\tonImprove?: (text: string) => Promise<string>;\n\tcharLimits?: AgentCharLimits;\n\t/**\n\t * Variable catalog for the `@` trigger. When non-empty, `@` in the email\n\t * tool's Subject / Send To / Reply To / CC opens the variable picker\n\t * directly, and Message Instructions upgrades to the variables-only mention\n\t * editor. Absent → the drawer behaves exactly as before.\n\t */\n\tvariablesData?: VariableListInterfaceV3[];\n\t/**\n\t * Portal target for the drawer, passed straight to {@link SideModal}\n\t * (default `document.body`). Lets a host render it into its own positioned\n\t * slot rather than as a viewport overlay.\n\t */\n\telement?: Element | DocumentFragment;\n\t/**\n\t * Footer button order, passed straight to {@link SideModal} (default\n\t * `'row'`). Hosts that show this drawer beside their own footer can set\n\t * `'row-reverse'` to line the Cancel / Save order up with it.\n\t */\n\tfooterDirection?: 'row' | 'row-reverse';\n\t/** SideModal stacking order — raise it when opened over another drawer. */\n\tzIndex?: number;\n}\n\ninterface EmailChipsFieldProps {\n\tchips: string[];\n\tonChange: (next: string[]) => void;\n\tplaceholder: string;\n\tnativeID?: string;\n\t/** Optional helper caption shown between the input and the chips. */\n\thint?: React.ReactNode;\n\t/**\n\t * Variable catalog for the `@` trigger. A picked variable is interpolated\n\t * into the entry TEXT at the caret (so values can mix text and variables,\n\t * e.g. `ops-{{variable:store_name}}@acme.com`) — it becomes a chip on\n\t * Enter / comma like any typed value.\n\t */\n\tvariablesData?: VariableListInterfaceV3[];\n}\n\n/**\n * Email entry field: type an address and press Enter / comma (or blur) to add\n * it. Added emails render as removable chips BELOW the input — not inside it.\n * Backspace on an empty input removes the last chip.\n */\nconst EmailChipsField: React.FC<EmailChipsFieldProps> = ({\n\tchips,\n\tonChange,\n\tplaceholder,\n\tnativeID,\n\thint,\n\tvariablesData,\n}) => {\n\tconst [buffer, setBuffer] = useState('');\n\tconst [entryFocused, setEntryFocused] = useState(false);\n\tconst wrapRef = useRef<HTMLDivElement>(null);\n\tconst inputRef = useRef<HTMLInputElement>(null);\n\n\tconst commit = () => {\n\t\tconst parts = buffer\n\t\t\t.split(',')\n\t\t\t.map((s) => s.trim())\n\t\t\t.filter(Boolean);\n\t\tif (parts.length) {\n\t\t\tonChange([...chips, ...parts.filter((p) => !chips.includes(p))]);\n\t\t}\n\t\tsetBuffer('');\n\t};\n\t// The blur handler defers via setTimeout — read the LATEST commit (with the\n\t// current buffer), not the one captured when the blur fired.\n\tconst commitRef = useRef(commit);\n\tcommitRef.current = commit;\n\t// While the variable panel is open, focus bounces through it (search box,\n\t// rows) — blur must not commit the half-composed entry.\n\tconst panelOpenRef = useRef(false);\n\t// A variable was just picked — the panel-close commit below must not fire\n\t// (onInsert refocuses the entry, so its eventual blur commits instead).\n\tconst insertedRef = useRef(false);\n\n\treturn (\n\t\t<ChipsFieldWrap ref={wrapRef}>\n\t\t\t<VariableTriggerArea\n\t\t\t\taddDataButton\n\t\t\t\tvariablesData={variablesData}\n\t\t\t\tonOpenChange={(open) => {\n\t\t\t\t\tpanelOpenRef.current = open;\n\t\t\t\t\tif (open) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// Panel closed (Escape / outside click / pick). If the entry's\n\t\t\t\t\t// blur-commit was skipped while the panel was open and focus is\n\t\t\t\t\t// not coming back, the half-typed entry would be silently lost\n\t\t\t\t\t// on save — commit it now.\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!insertedRef.current &&\n\t\t\t\t\t\t\t!wrapRef.current?.contains(document.activeElement)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tcommitRef.current();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tinsertedRef.current = false;\n\t\t\t\t\t}, 0);\n\t\t\t\t}}\n\t\t\t\tonInsert={(token, caret) => {\n\t\t\t\t\tinsertedRef.current = true;\n\t\t\t\t\tconst at = caret ?? buffer.length;\n\t\t\t\t\tsetBuffer(`${buffer.slice(0, at)}${token}${buffer.slice(at)}`);\n\t\t\t\t\t// Put the caret after the inserted token so typing continues\n\t\t\t\t\t// naturally (e.g. `{{variable:store_name}}|@acme.com`).\n\t\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\t\tconst el = inputRef.current;\n\t\t\t\t\t\tel?.focus();\n\t\t\t\t\t\tel?.setSelectionRange(at + token.length, at + token.length);\n\t\t\t\t\t});\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<EmailInputBox\n\t\t\t\t\tid={nativeID}\n\t\t\t\t\tname={nativeID}\n\t\t\t\t\tref={inputRef}\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t\tautoComplete=\"off\"\n\t\t\t\t\t// Focused + empty → the @ hint (only when a catalog makes @ do\n\t\t\t\t\t// anything); otherwise the field's own text.\n\t\t\t\t\tplaceholder={\n\t\t\t\t\t\tentryFocused && buffer === '' && (variablesData?.length ?? 0) > 0\n\t\t\t\t\t\t\t? 'Enter text, type @ to add variable'\n\t\t\t\t\t\t\t: placeholder\n\t\t\t\t\t}\n\t\t\t\t\tvalue={buffer}\n\t\t\t\t\tonChange={(e) => setBuffer(e.target.value)}\n\t\t\t\t\tonFocus={() => setEntryFocused(true)}\n\t\t\t\t\tonBlur={() => {\n\t\t\t\t\t\tsetEntryFocused(false);\n\t\t\t\t\t\t// Focus moving into the variable panel / pill is not \"leaving\n\t\t\t\t\t\t// the field\" — committing then would chip a half-composed value.\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t!panelOpenRef.current &&\n\t\t\t\t\t\t\t\t!wrapRef.current?.contains(document.activeElement)\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tcommitRef.current();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, 0);\n\t\t\t\t\t}}\n\t\t\t\t\tonKeyDown={(e) => {\n\t\t\t\t\t\tif (e.key === 'Enter' || e.key === ',') {\n\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\tcommit();\n\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\te.key === 'Backspace' &&\n\t\t\t\t\t\t\tbuffer === '' &&\n\t\t\t\t\t\t\tchips.length > 0\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tonChange(chips.slice(0, -1));\n\t\t\t\t\t\t}\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t</VariableTriggerArea>\n\t\t\t{hint}\n\t\t\t{chips.length > 0 && (\n\t\t\t\t<ChipRow>\n\t\t\t\t\t{chips.map((email, i) => (\n\t\t\t\t\t\t<Tag\n\t\t\t\t\t\t\tkey={`${email}-${i}`}\n\t\t\t\t\t\t\t// Variable tokens display as the short {{name}} (values can mix\n\t\t\t\t\t\t\t// text and tokens); the stored value keeps {{variable:<name>}}.\n\t\t\t\t\t\t\ttagText={email.replace(/\\{\\{variable:([^}]+)\\}\\}/g, '{{$1}}')}\n\t\t\t\t\t\t\ttheme=\"light\"\n\t\t\t\t\t\t\ttype=\"neutral\"\n\t\t\t\t\t\t\tvariant=\"regular\"\n\t\t\t\t\t\t\tTrailingIcon={CrossIcon}\n\t\t\t\t\t\t\tonTrailingIconClicked={() =>\n\t\t\t\t\t\t\t\tonChange(chips.filter((_, idx) => idx !== i))\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t</ChipRow>\n\t\t\t)}\n\t\t</ChipsFieldWrap>\n\t);\n};\n\n/** Field values keyed by param key (the editable part of a {@link ParamsBlob}). */\ntype ParamValues = Record<string, string | boolean | number | object>;\n\nconst seedValues = (\n\ttemplate: ParamsBlob,\n\tinitial?: ConfigToolConfig,\n): ParamValues => {\n\tconst values: ParamValues = {};\n\tObject.keys(template).forEach((key) => {\n\t\tvalues[key] = initial?.params[key]?.value ?? template[key].value;\n\t});\n\treturn values;\n};\n\n/** Chips ↔ the string value KeywordInput fields carry (comma-separated). */\nconst toChips = (value: unknown): string[] =>\n\tString(value ?? '')\n\t\t.split(',')\n\t\t.map((s) => s.trim())\n\t\t.filter(Boolean);\n\n/**\n * Shared right-side drawer for the params-driven configurable tools (email /\n * Slack). Fully backend-driven: it renders the template fields by their\n * `component` kind and returns the same blob with values filled in. KeywordInput\n * renders as multi-value email chips only for `send_email`; every other tool\n * gets a plain single-line input. Mount it fresh per open (key it) so `initial`\n * seeds the state. Built on the shared `SideModal` shell.\n */\nexport const ConfigToolPanel: React.FC<ConfigToolPanelProps> = ({\n\ttoolKey,\n\ttemplate,\n\tonClose,\n\tonSave,\n\tinitial,\n\tonImprove,\n\tcharLimits = AGENT_CHAR_LIMITS,\n\tvariablesData,\n\tzIndex,\n\telement,\n\tfooterDirection,\n}) => {\n\tconst [values, setValues] = useState<ParamValues>(() =>\n\t\tseedValues(template, initial),\n\t);\n\tconst [saving, setSaving] = useState(false);\n\n\tconst fields = Object.values(template);\n\tconst isEmail = toolKey === 'send_email';\n\tconst setValue = (key: string, value: string | boolean | number | object) =>\n\t\tsetValues((prev) => ({ ...prev, [key]: value }));\n\n\tconst canSave = fields.every((f) => {\n\t\tif (f.required && String(values[f.key] ?? '').trim() === '') {\n\t\t\treturn false;\n\t\t}\n\t\t// MultilineInput renders the soft-limit editor (a paste may exceed the\n\t\t// cap, rendered grey) — gate the save so over-limit text can't persist.\n\t\tif (\n\t\t\tf.component === 'MultilineInput' &&\n\t\t\tString(values[f.key] ?? '').length > charLimits.instructions\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t});\n\n\tconst handleSave = async () => {\n\t\tif (!canSave || saving) {\n\t\t\treturn;\n\t\t}\n\t\tconst params: ParamsBlob = {};\n\t\tfields.forEach((f) => {\n\t\t\t// Save the FULL descriptor with only `value` changed — the backend\n\t\t\t// infers each field's type from `component` and reads `required`.\n\t\t\tparams[f.key] = { ...f, value: values[f.key] };\n\t\t});\n\t\tconst config: ConfigToolConfig = {\n\t\t\tid: initial?.id ?? `${toolKey}_${Date.now().toString(36)}`,\n\t\t\ttool_key: toolKey,\n\t\t\tparams,\n\t\t};\n\t\tconst result = onSave(config);\n\t\tif (result && typeof (result as Promise<void>).then === 'function') {\n\t\t\tsetSaving(true);\n\t\t\ttry {\n\t\t\t\tawait result;\n\t\t\t} finally {\n\t\t\t\tsetSaving(false);\n\t\t\t}\n\t\t}\n\t};\n\n\tconst renderField = (field: ParamField) => {\n\t\tconst testId = `config-tool-${field.key.toLowerCase()}`;\n\t\tswitch (field.component) {\n\t\t\t// Multi-value email chips — only for the email tool. Slack's KeywordInput\n\t\t\t// (channelId) falls through to the plain input below.\n\t\t\tcase 'KeywordInput':\n\t\t\t\tif (!isEmail) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\treturn (\n\t\t\t\t\t<FieldBlock key={field.key}>\n\t\t\t\t\t\t<TitleSmall color={COLORS.content.primary}>\n\t\t\t\t\t\t\t{field.title}\n\t\t\t\t\t\t</TitleSmall>\n\t\t\t\t\t\t{/* `@` at a word boundary (or the \"+ Add data\" pill) interpolates\n\t\t\t\t\t\t a variable into the entry TEXT at the caret — mixed values like\n\t\t\t\t\t\t ops-{{variable:store_name}}@acme.com chip on Enter / comma. */}\n\t\t\t\t\t\t<EmailChipsField\n\t\t\t\t\t\t\tnativeID={testId}\n\t\t\t\t\t\t\tplaceholder={field.hint ?? ''}\n\t\t\t\t\t\t\tchips={toChips(values[field.key])}\n\t\t\t\t\t\t\tonChange={(chips) => setValue(field.key, chips.join(','))}\n\t\t\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\t\t\thint={\n\t\t\t\t\t\t\t\t<BodyCaption color={COLORS.content.secondary}>\n\t\t\t\t\t\t\t\t\tPress Enter or comma to add multiple emails\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/>\n\t\t\t\t\t</FieldBlock>\n\t\t\t\t);\n\t\t\tcase 'MultilineInput':\n\t\t\t\treturn (\n\t\t\t\t\t<ToolInstructionsField\n\t\t\t\t\t\tkey={field.key}\n\t\t\t\t\t\tdata-test={testId}\n\t\t\t\t\t\tlabel={field.title}\n\t\t\t\t\t\tvalue={String(values[field.key] ?? '')}\n\t\t\t\t\t\tonChange={(text) => setValue(field.key, text)}\n\t\t\t\t\t\tmaxLength={charLimits.instructions}\n\t\t\t\t\t\tplaceholder={field.hint ?? ''}\n\t\t\t\t\t\tonImprove={onImprove}\n\t\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\t/>\n\t\t\t\t);\n\t\t\tcase 'Switch':\n\t\t\t\treturn (\n\t\t\t\t\t<SwitchRow key={field.key}>\n\t\t\t\t\t\t<SwitchText>\n\t\t\t\t\t\t\t<TitleSmall color={COLORS.content.primary}>\n\t\t\t\t\t\t\t\t{field.title}\n\t\t\t\t\t\t\t</TitleSmall>\n\t\t\t\t\t\t\t{field.hint && (\n\t\t\t\t\t\t\t\t<BodyCaption color={COLORS.content.secondary}>\n\t\t\t\t\t\t\t\t\t{field.hint}\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</SwitchText>\n\t\t\t\t\t\t<Switch\n\t\t\t\t\t\t\tdata-test={testId}\n\t\t\t\t\t\t\tvalue={Boolean(values[field.key])}\n\t\t\t\t\t\t\tonValueChange={async (next) => setValue(field.key, next)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</SwitchRow>\n\t\t\t\t);\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t\tconst plainInput = (\n\t\t\t<Input\n\t\t\t\tdata-test={testId}\n\t\t\t\tvariant=\"small\"\n\t\t\t\tlabelText={field.title}\n\t\t\t\tlabelTextBold\n\t\t\t\tplaceholder={field.hint ?? ''}\n\t\t\t\tvalue={String(values[field.key] ?? '')}\n\t\t\t\tonChangeText={(text) => setValue(field.key, text)}\n\t\t\t/>\n\t\t);\n\t\t// `@` variables only in the email tool's free-text fields (Subject) —\n\t\t// a Slack channel id can't hold a variable.\n\t\tif (!isEmail) {\n\t\t\treturn <React.Fragment key={field.key}>{plainInput}</React.Fragment>;\n\t\t}\n\t\treturn (\n\t\t\t<VariableTriggerArea\n\t\t\t\taddDataButton\n\t\t\t\tkey={field.key}\n\t\t\t\tvariablesData={variablesData}\n\t\t\t\tonInsert={(token, caret) => {\n\t\t\t\t\tconst current = String(values[field.key] ?? '');\n\t\t\t\t\tconst at = caret ?? current.length;\n\t\t\t\t\tsetValue(\n\t\t\t\t\t\tfield.key,\n\t\t\t\t\t\t`${current.slice(0, at)}${token}${current.slice(at)}`,\n\t\t\t\t\t);\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{plainInput}\n\t\t\t</VariableTriggerArea>\n\t\t);\n\t};\n\n\tconst copy = TOOL_COPY[toolKey];\n\n\treturn (\n\t\t<SideModal\n\t\t\theader={copy.title}\n\t\t\tcloseOnEscapeKey={false}\n\t\t\tzIndex={zIndex}\n\t\t\telement={element}\n\t\t\tfooterDirection={footerDirection}\n\t\t\theaderCustomComponent={\n\t\t\t\t<DrawerHeaderText title={copy.title} subtitle={copy.subtitle} />\n\t\t\t}\n\t\t\thideCrossButton={false}\n\t\t\twidth=\"431px\"\n\t\t\theaderStyle={DRAWER_HEADER_STYLE}\n\t\t\tbodyStyle={DRAWER_BODY_STYLE}\n\t\t\tonClose={onClose}\n\t\t\tsaveButtonProps={{\n\t\t\t\t'data-test': 'config-tool-save',\n\t\t\t\tbuttonText: 'Save',\n\t\t\t\tbuttonType: 'primary',\n\t\t\t\tsize: 'small',\n\t\t\t\tdisabled: !canSave,\n\t\t\t\tisLoading: saving,\n\t\t\t\tonClick: handleSave,\n\t\t\t}}\n\t\t\tcancelButtonProps={{\n\t\t\t\t'data-test': 'config-tool-cancel',\n\t\t\t\tbuttonText: 'Cancel',\n\t\t\t\tbuttonType: 'tertiaryGray',\n\t\t\t\tsize: 'small',\n\t\t\t\tonClick: onClose,\n\t\t\t}}\n\t\t>\n\t\t\t{fields.map(renderField)}\n\t\t</SideModal>\n\t);\n};\n\nconst ChipsFieldWrap = styled.div`\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n`;\n\nconst EmailInputBox = styled.input`\n\twidth: 100%;\n\tmin-width: 0;\n\tbox-sizing: border-box;\n\theight: 32px;\n\tpadding: 0 8px;\n\tborder: 1px solid ${COLORS.stroke.primary};\n\tborder-radius: 4px;\n\tfont-family: 'Inter', sans-serif;\n\tfont-size: 14px;\n\tcolor: ${COLORS.content.primary};\n\tbackground: ${COLORS.surface.standard};\n\toutline: none;\n\n\t&::placeholder {\n\t\tcolor: ${COLORS.content.secondary};\n\t}\n\n\t&:focus {\n\t\tborder-color: ${COLORS.stroke.brand};\n\t}\n`;\n\nconst ChipRow = styled.div`\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 6px;\n`;\n\nconst SwitchRow = styled.div`\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 12px;\n`;\n\nconst SwitchText = styled.div`\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tmin-width: 0;\n`;\n"],"names":["TOOL_COPY","EmailChipsField","chips","onChange","placeholder","nativeID","hint","variablesData","buffer","setBuffer","useState","entryFocused","setEntryFocused","wrapRef","useRef","inputRef","commit","parts","s","p","commitRef","panelOpenRef","insertedRef","jsxs","ChipsFieldWrap","jsx","VariableTriggerArea","open","token","caret","at","el","EmailInputBox","e","ChipRow","email","i","Tag","CrossIcon","_","idx","seedValues","template","initial","values","key","toChips","value","ConfigToolPanel","toolKey","onClose","onSave","onImprove","charLimits","AGENT_CHAR_LIMITS","zIndex","element","footerDirection","setValues","saving","setSaving","fields","isEmail","setValue","prev","canSave","f","handleSave","params","config","result","renderField","field","testId","FieldBlock","TitleSmall","COLORS","BodyCaption","ToolInstructionsField","text","SwitchRow","SwitchText","Switch","next","plainInput","Input","current","React","copy","SideModal","DrawerHeaderText","DRAWER_HEADER_STYLE","DRAWER_BODY_STYLE","styled"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ConfigToolPanel.js","sources":["../../../../../src/components/agent-builder/components/ConfigToolPanel.tsx"],"sourcesContent":["import CrossIcon from '@src/assets/icons/cross.svg';\nimport React, { useRef, useState } from 'react';\nimport styled from 'styled-components';\nimport { Input } from '@src/components/input';\nimport { SideModal } from '@src/components/side-modal';\nimport { Switch } from '@src/components/switch';\nimport { Tag } from '@src/components/tag';\nimport { BodyCaption, TitleSmall } from '@src/components/TypographyStyle';\nimport { COLORS } from '@src/constants/Theme';\nimport type { VariableListInterfaceV3 } from '../../variable-picker-v3/model';\nimport {\n\tConfigToolConfig,\n\tConfigToolKey,\n\tParamField,\n\tParamsBlob,\n} from '../AgentBuilder.model';\nimport { FieldBlock } from '../AgentBuilder.styled';\nimport type { AgentCharLimits } from '../constants/charLimits';\nimport { AGENT_CHAR_LIMITS } from '../constants/charLimits';\nimport {\n\tDRAWER_BODY_STYLE,\n\tDRAWER_HEADER_STYLE,\n\tDrawerHeaderText,\n} from './DrawerHeaderText';\nimport { ToolInstructionsField } from './ToolInstructionsField';\nimport { VariableTriggerArea } from './VariableTriggerArea';\n\n/** Header copy per shared-drawer tool. */\nconst TOOL_COPY: Record<ConfigToolKey, { title: string; subtitle: string }> = {\n\tsend_email: {\n\t\ttitle: 'Send email',\n\t\tsubtitle:\n\t\t\t\"Notify someone by email when this agent can't continue. You pick the recipient, the AI drafts the message.\",\n\t},\n\tsend_slack_message: {\n\t\ttitle: 'Send Slack message',\n\t\tsubtitle:\n\t\t\t'Post a message to a Slack channel. You pick the channel, the AI composes the message from the conversation.',\n\t},\n\tgoogle_sheet_get_data: {\n\t\ttitle: 'Get data from sheet',\n\t\tsubtitle:\n\t\t\t'Look up rows in a Google Sheet. You pick the sheet and describe its columns, the AI writes the query it needs.',\n\t},\n\tgoogle_sheet_add_row: {\n\t\ttitle: 'Add row to sheet',\n\t\tsubtitle:\n\t\t\t'Append a row to a Google Sheet. You pick the sheet and its columns, the AI fills them in from the conversation.',\n\t},\n};\n\ninterface ConfigToolPanelProps {\n\t/** Which tool this drawer configures (drives copy + persistence). */\n\ttoolKey: ConfigToolKey;\n\t/**\n\t * The backend template (`list-catalog` → params) for `toolKey`. The form is\n\t * DYNAMIC: exactly these fields render, in this order, each by its\n\t * `component` kind (KeywordInput | MultilineInput | Switch | fallback input).\n\t */\n\ttemplate: ParamsBlob;\n\tonClose: () => void;\n\t/** Persist the filled template. A pending promise shows the Save loader. */\n\tonSave: (config: ConfigToolConfig) => void | Promise<void>;\n\t/** Seed values when editing an existing tool. */\n\tinitial?: ConfigToolConfig;\n\t/** Optional \"Improve with AI\" for multiline fields. Omit to hide it. */\n\tonImprove?: (text: string) => Promise<string>;\n\tcharLimits?: AgentCharLimits;\n\t/**\n\t * Variable catalog for the `@` trigger. When non-empty, `@` in the email\n\t * tool's Subject / Send To / Reply To / CC opens the variable picker\n\t * directly, and Message Instructions upgrades to the variables-only mention\n\t * editor. Absent → the drawer behaves exactly as before.\n\t */\n\tvariablesData?: VariableListInterfaceV3[];\n\t/** SideModal stacking order — raise it when opened over another drawer. */\n\tzIndex?: number;\n}\n\ninterface EmailChipsFieldProps {\n\tchips: string[];\n\tonChange: (next: string[]) => void;\n\tplaceholder: string;\n\tnativeID?: string;\n\t/** Optional helper caption shown between the input and the chips. */\n\thint?: React.ReactNode;\n\t/**\n\t * Variable catalog for the `@` trigger. A picked variable is interpolated\n\t * into the entry TEXT at the caret (so values can mix text and variables,\n\t * e.g. `ops-{{variable:store_name}}@acme.com`) — it becomes a chip on\n\t * Enter / comma like any typed value.\n\t */\n\tvariablesData?: VariableListInterfaceV3[];\n}\n\n/**\n * Email entry field: type an address and press Enter / comma (or blur) to add\n * it. Added emails render as removable chips BELOW the input — not inside it.\n * Backspace on an empty input removes the last chip.\n */\nconst EmailChipsField: React.FC<EmailChipsFieldProps> = ({\n\tchips,\n\tonChange,\n\tplaceholder,\n\tnativeID,\n\thint,\n\tvariablesData,\n}) => {\n\tconst [buffer, setBuffer] = useState('');\n\tconst [entryFocused, setEntryFocused] = useState(false);\n\tconst wrapRef = useRef<HTMLDivElement>(null);\n\tconst inputRef = useRef<HTMLInputElement>(null);\n\n\tconst commit = () => {\n\t\tconst parts = buffer\n\t\t\t.split(',')\n\t\t\t.map((s) => s.trim())\n\t\t\t.filter(Boolean);\n\t\tif (parts.length) {\n\t\t\tonChange([...chips, ...parts.filter((p) => !chips.includes(p))]);\n\t\t}\n\t\tsetBuffer('');\n\t};\n\t// The blur handler defers via setTimeout — read the LATEST commit (with the\n\t// current buffer), not the one captured when the blur fired.\n\tconst commitRef = useRef(commit);\n\tcommitRef.current = commit;\n\t// While the variable panel is open, focus bounces through it (search box,\n\t// rows) — blur must not commit the half-composed entry.\n\tconst panelOpenRef = useRef(false);\n\t// A variable was just picked — the panel-close commit below must not fire\n\t// (onInsert refocuses the entry, so its eventual blur commits instead).\n\tconst insertedRef = useRef(false);\n\n\treturn (\n\t\t<ChipsFieldWrap ref={wrapRef}>\n\t\t\t<VariableTriggerArea\n\t\t\t\taddDataButton\n\t\t\t\tvariablesData={variablesData}\n\t\t\t\tonOpenChange={(open) => {\n\t\t\t\t\tpanelOpenRef.current = open;\n\t\t\t\t\tif (open) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// Panel closed (Escape / outside click / pick). If the entry's\n\t\t\t\t\t// blur-commit was skipped while the panel was open and focus is\n\t\t\t\t\t// not coming back, the half-typed entry would be silently lost\n\t\t\t\t\t// on save — commit it now.\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!insertedRef.current &&\n\t\t\t\t\t\t\t!wrapRef.current?.contains(document.activeElement)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tcommitRef.current();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tinsertedRef.current = false;\n\t\t\t\t\t}, 0);\n\t\t\t\t}}\n\t\t\t\tonInsert={(token, caret) => {\n\t\t\t\t\tinsertedRef.current = true;\n\t\t\t\t\tconst at = caret ?? buffer.length;\n\t\t\t\t\tsetBuffer(`${buffer.slice(0, at)}${token}${buffer.slice(at)}`);\n\t\t\t\t\t// Put the caret after the inserted token so typing continues\n\t\t\t\t\t// naturally (e.g. `{{variable:store_name}}|@acme.com`).\n\t\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\t\tconst el = inputRef.current;\n\t\t\t\t\t\tel?.focus();\n\t\t\t\t\t\tel?.setSelectionRange(at + token.length, at + token.length);\n\t\t\t\t\t});\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<EmailInputBox\n\t\t\t\t\tid={nativeID}\n\t\t\t\t\tname={nativeID}\n\t\t\t\t\tref={inputRef}\n\t\t\t\t\ttype=\"text\"\n\t\t\t\t\tautoComplete=\"off\"\n\t\t\t\t\t// Focused + empty → the @ hint (only when a catalog makes @ do\n\t\t\t\t\t// anything); otherwise the field's own text.\n\t\t\t\t\tplaceholder={\n\t\t\t\t\t\tentryFocused && buffer === '' && (variablesData?.length ?? 0) > 0\n\t\t\t\t\t\t\t? 'Enter text, type @ to add variable'\n\t\t\t\t\t\t\t: placeholder\n\t\t\t\t\t}\n\t\t\t\t\tvalue={buffer}\n\t\t\t\t\tonChange={(e) => setBuffer(e.target.value)}\n\t\t\t\t\tonFocus={() => setEntryFocused(true)}\n\t\t\t\t\tonBlur={() => {\n\t\t\t\t\t\tsetEntryFocused(false);\n\t\t\t\t\t\t// Focus moving into the variable panel / pill is not \"leaving\n\t\t\t\t\t\t// the field\" — committing then would chip a half-composed value.\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t!panelOpenRef.current &&\n\t\t\t\t\t\t\t\t!wrapRef.current?.contains(document.activeElement)\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tcommitRef.current();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}, 0);\n\t\t\t\t\t}}\n\t\t\t\t\tonKeyDown={(e) => {\n\t\t\t\t\t\tif (e.key === 'Enter' || e.key === ',') {\n\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\tcommit();\n\t\t\t\t\t\t} else if (\n\t\t\t\t\t\t\te.key === 'Backspace' &&\n\t\t\t\t\t\t\tbuffer === '' &&\n\t\t\t\t\t\t\tchips.length > 0\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tonChange(chips.slice(0, -1));\n\t\t\t\t\t\t}\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t</VariableTriggerArea>\n\t\t\t{hint}\n\t\t\t{chips.length > 0 && (\n\t\t\t\t<ChipRow>\n\t\t\t\t\t{chips.map((email, i) => (\n\t\t\t\t\t\t<Tag\n\t\t\t\t\t\t\tkey={`${email}-${i}`}\n\t\t\t\t\t\t\t// Variable tokens display as the short {{name}} (values can mix\n\t\t\t\t\t\t\t// text and tokens); the stored value keeps {{variable:<name>}}.\n\t\t\t\t\t\t\ttagText={email.replace(/\\{\\{variable:([^}]+)\\}\\}/g, '{{$1}}')}\n\t\t\t\t\t\t\ttheme=\"light\"\n\t\t\t\t\t\t\ttype=\"neutral\"\n\t\t\t\t\t\t\tvariant=\"regular\"\n\t\t\t\t\t\t\tTrailingIcon={CrossIcon}\n\t\t\t\t\t\t\tonTrailingIconClicked={() =>\n\t\t\t\t\t\t\t\tonChange(chips.filter((_, idx) => idx !== i))\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t</ChipRow>\n\t\t\t)}\n\t\t</ChipsFieldWrap>\n\t);\n};\n\n/** Field values keyed by param key (the editable part of a {@link ParamsBlob}). */\ntype ParamValues = Record<string, string | boolean | number | object>;\n\nconst seedValues = (\n\ttemplate: ParamsBlob,\n\tinitial?: ConfigToolConfig,\n): ParamValues => {\n\tconst values: ParamValues = {};\n\tObject.keys(template).forEach((key) => {\n\t\tvalues[key] = initial?.params[key]?.value ?? template[key].value;\n\t});\n\treturn values;\n};\n\n/** Chips ↔ the string value KeywordInput fields carry (comma-separated). */\nconst toChips = (value: unknown): string[] =>\n\tString(value ?? '')\n\t\t.split(',')\n\t\t.map((s) => s.trim())\n\t\t.filter(Boolean);\n\n/**\n * Shared right-side drawer for the params-driven configurable tools (email /\n * Slack). Fully backend-driven: it renders the template fields by their\n * `component` kind and returns the same blob with values filled in. KeywordInput\n * renders as multi-value email chips only for `send_email`; every other tool\n * gets a plain single-line input. Mount it fresh per open (key it) so `initial`\n * seeds the state. Built on the shared `SideModal` shell.\n */\nexport const ConfigToolPanel: React.FC<ConfigToolPanelProps> = ({\n\ttoolKey,\n\ttemplate,\n\tonClose,\n\tonSave,\n\tinitial,\n\tonImprove,\n\tcharLimits = AGENT_CHAR_LIMITS,\n\tvariablesData,\n\tzIndex,\n}) => {\n\tconst [values, setValues] = useState<ParamValues>(() =>\n\t\tseedValues(template, initial),\n\t);\n\tconst [saving, setSaving] = useState(false);\n\n\tconst fields = Object.values(template);\n\tconst isEmail = toolKey === 'send_email';\n\tconst setValue = (key: string, value: string | boolean | number | object) =>\n\t\tsetValues((prev) => ({ ...prev, [key]: value }));\n\n\tconst canSave = fields.every((f) => {\n\t\tif (f.required && String(values[f.key] ?? '').trim() === '') {\n\t\t\treturn false;\n\t\t}\n\t\t// MultilineInput renders the soft-limit editor (a paste may exceed the\n\t\t// cap, rendered grey) — gate the save so over-limit text can't persist.\n\t\tif (\n\t\t\tf.component === 'MultilineInput' &&\n\t\t\tString(values[f.key] ?? '').length > charLimits.instructions\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t});\n\n\tconst handleSave = async () => {\n\t\tif (!canSave || saving) {\n\t\t\treturn;\n\t\t}\n\t\tconst params: ParamsBlob = {};\n\t\tfields.forEach((f) => {\n\t\t\t// Save the FULL descriptor with only `value` changed — the backend\n\t\t\t// infers each field's type from `component` and reads `required`.\n\t\t\tparams[f.key] = { ...f, value: values[f.key] };\n\t\t});\n\t\tconst config: ConfigToolConfig = {\n\t\t\tid: initial?.id ?? `${toolKey}_${Date.now().toString(36)}`,\n\t\t\ttool_key: toolKey,\n\t\t\tparams,\n\t\t};\n\t\tconst result = onSave(config);\n\t\tif (result && typeof (result as Promise<void>).then === 'function') {\n\t\t\tsetSaving(true);\n\t\t\ttry {\n\t\t\t\tawait result;\n\t\t\t} finally {\n\t\t\t\tsetSaving(false);\n\t\t\t}\n\t\t}\n\t};\n\n\tconst renderField = (field: ParamField) => {\n\t\tconst testId = `config-tool-${field.key.toLowerCase()}`;\n\t\tswitch (field.component) {\n\t\t\t// Multi-value email chips — only for the email tool. Slack's KeywordInput\n\t\t\t// (channelId) falls through to the plain input below.\n\t\t\tcase 'KeywordInput':\n\t\t\t\tif (!isEmail) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\treturn (\n\t\t\t\t\t<FieldBlock key={field.key}>\n\t\t\t\t\t\t<TitleSmall color={COLORS.content.primary}>\n\t\t\t\t\t\t\t{field.title}\n\t\t\t\t\t\t</TitleSmall>\n\t\t\t\t\t\t{/* `@` at a word boundary (or the \"+ Add data\" pill) interpolates\n\t\t\t\t\t\t a variable into the entry TEXT at the caret — mixed values like\n\t\t\t\t\t\t ops-{{variable:store_name}}@acme.com chip on Enter / comma. */}\n\t\t\t\t\t\t<EmailChipsField\n\t\t\t\t\t\t\tnativeID={testId}\n\t\t\t\t\t\t\tplaceholder={field.hint ?? ''}\n\t\t\t\t\t\t\tchips={toChips(values[field.key])}\n\t\t\t\t\t\t\tonChange={(chips) => setValue(field.key, chips.join(','))}\n\t\t\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\t\t\thint={\n\t\t\t\t\t\t\t\t<BodyCaption color={COLORS.content.secondary}>\n\t\t\t\t\t\t\t\t\tPress Enter or comma to add multiple emails\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/>\n\t\t\t\t\t</FieldBlock>\n\t\t\t\t);\n\t\t\tcase 'MultilineInput':\n\t\t\t\treturn (\n\t\t\t\t\t<ToolInstructionsField\n\t\t\t\t\t\tkey={field.key}\n\t\t\t\t\t\tdata-test={testId}\n\t\t\t\t\t\tlabel={field.title}\n\t\t\t\t\t\tvalue={String(values[field.key] ?? '')}\n\t\t\t\t\t\tonChange={(text) => setValue(field.key, text)}\n\t\t\t\t\t\tmaxLength={charLimits.instructions}\n\t\t\t\t\t\tplaceholder={field.hint ?? ''}\n\t\t\t\t\t\tonImprove={onImprove}\n\t\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\t/>\n\t\t\t\t);\n\t\t\tcase 'Switch':\n\t\t\t\treturn (\n\t\t\t\t\t<SwitchRow key={field.key}>\n\t\t\t\t\t\t<SwitchText>\n\t\t\t\t\t\t\t<TitleSmall color={COLORS.content.primary}>\n\t\t\t\t\t\t\t\t{field.title}\n\t\t\t\t\t\t\t</TitleSmall>\n\t\t\t\t\t\t\t{field.hint && (\n\t\t\t\t\t\t\t\t<BodyCaption color={COLORS.content.secondary}>\n\t\t\t\t\t\t\t\t\t{field.hint}\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</SwitchText>\n\t\t\t\t\t\t<Switch\n\t\t\t\t\t\t\tdata-test={testId}\n\t\t\t\t\t\t\tvalue={Boolean(values[field.key])}\n\t\t\t\t\t\t\tonValueChange={async (next) => setValue(field.key, next)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</SwitchRow>\n\t\t\t\t);\n\t\t\tdefault:\n\t\t\t\tbreak;\n\t\t}\n\t\tconst plainInput = (\n\t\t\t<Input\n\t\t\t\tdata-test={testId}\n\t\t\t\tvariant=\"small\"\n\t\t\t\tlabelText={field.title}\n\t\t\t\tlabelTextBold\n\t\t\t\tplaceholder={field.hint ?? ''}\n\t\t\t\tvalue={String(values[field.key] ?? '')}\n\t\t\t\tonChangeText={(text) => setValue(field.key, text)}\n\t\t\t/>\n\t\t);\n\t\t// `@` variables only in the email tool's free-text fields (Subject) —\n\t\t// a Slack channel id can't hold a variable.\n\t\tif (!isEmail) {\n\t\t\treturn <React.Fragment key={field.key}>{plainInput}</React.Fragment>;\n\t\t}\n\t\treturn (\n\t\t\t<VariableTriggerArea\n\t\t\t\taddDataButton\n\t\t\t\tkey={field.key}\n\t\t\t\tvariablesData={variablesData}\n\t\t\t\tonInsert={(token, caret) => {\n\t\t\t\t\tconst current = String(values[field.key] ?? '');\n\t\t\t\t\tconst at = caret ?? current.length;\n\t\t\t\t\tsetValue(\n\t\t\t\t\t\tfield.key,\n\t\t\t\t\t\t`${current.slice(0, at)}${token}${current.slice(at)}`,\n\t\t\t\t\t);\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{plainInput}\n\t\t\t</VariableTriggerArea>\n\t\t);\n\t};\n\n\tconst copy = TOOL_COPY[toolKey];\n\n\treturn (\n\t\t<SideModal\n\t\t\theader={copy.title}\n\t\t\tcloseOnEscapeKey={false}\n\t\t\tzIndex={zIndex}\n\t\t\theaderCustomComponent={\n\t\t\t\t<DrawerHeaderText title={copy.title} subtitle={copy.subtitle} />\n\t\t\t}\n\t\t\thideCrossButton={false}\n\t\t\twidth=\"431px\"\n\t\t\theaderStyle={DRAWER_HEADER_STYLE}\n\t\t\tbodyStyle={DRAWER_BODY_STYLE}\n\t\t\tonClose={onClose}\n\t\t\tsaveButtonProps={{\n\t\t\t\t'data-test': 'config-tool-save',\n\t\t\t\tbuttonText: 'Save',\n\t\t\t\tbuttonType: 'primary',\n\t\t\t\tsize: 'small',\n\t\t\t\tdisabled: !canSave,\n\t\t\t\tisLoading: saving,\n\t\t\t\tonClick: handleSave,\n\t\t\t}}\n\t\t\tcancelButtonProps={{\n\t\t\t\t'data-test': 'config-tool-cancel',\n\t\t\t\tbuttonText: 'Cancel',\n\t\t\t\tbuttonType: 'tertiaryGray',\n\t\t\t\tsize: 'small',\n\t\t\t\tonClick: onClose,\n\t\t\t}}\n\t\t>\n\t\t\t{fields.map(renderField)}\n\t\t</SideModal>\n\t);\n};\n\nconst ChipsFieldWrap = styled.div`\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n`;\n\nconst EmailInputBox = styled.input`\n\twidth: 100%;\n\tmin-width: 0;\n\tbox-sizing: border-box;\n\theight: 32px;\n\tpadding: 0 8px;\n\tborder: 1px solid ${COLORS.stroke.primary};\n\tborder-radius: 4px;\n\tfont-family: 'Inter', sans-serif;\n\tfont-size: 14px;\n\tcolor: ${COLORS.content.primary};\n\tbackground: ${COLORS.surface.standard};\n\toutline: none;\n\n\t&::placeholder {\n\t\tcolor: ${COLORS.content.secondary};\n\t}\n\n\t&:focus {\n\t\tborder-color: ${COLORS.stroke.brand};\n\t}\n`;\n\nconst ChipRow = styled.div`\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tgap: 6px;\n`;\n\nconst SwitchRow = styled.div`\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tgap: 12px;\n`;\n\nconst SwitchText = styled.div`\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 4px;\n\tmin-width: 0;\n`;\n"],"names":["TOOL_COPY","EmailChipsField","chips","onChange","placeholder","nativeID","hint","variablesData","buffer","setBuffer","useState","entryFocused","setEntryFocused","wrapRef","useRef","inputRef","commit","parts","s","p","commitRef","panelOpenRef","insertedRef","jsxs","ChipsFieldWrap","jsx","VariableTriggerArea","open","token","caret","at","el","EmailInputBox","e","ChipRow","email","i","Tag","CrossIcon","_","idx","seedValues","template","initial","values","key","toChips","value","ConfigToolPanel","toolKey","onClose","onSave","onImprove","charLimits","AGENT_CHAR_LIMITS","zIndex","setValues","saving","setSaving","fields","isEmail","setValue","prev","canSave","f","handleSave","params","config","result","renderField","field","testId","FieldBlock","TitleSmall","COLORS","BodyCaption","ToolInstructionsField","text","SwitchRow","SwitchText","Switch","next","plainInput","Input","current","React","copy","SideModal","DrawerHeaderText","DRAWER_HEADER_STYLE","DRAWER_BODY_STYLE","styled"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("react/jsx-runtime"),o=require("react"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("react/jsx-runtime"),o=require("react"),De=require("styled-components"),me=require("../../../utils/arrayUtils.js"),Q=require("../../../constants/Theme.js"),Ge=require("../constants/charLimits.js"),a=require("../constants/tools.js"),h=require("../utils/mentionSerialization.js"),Ke=require("../utils/sourceGrouping.js"),S=require("../utils/sourceIcons.js"),Be=require("../utils/toolActions.js"),Pe=require("./ConfigToolPanel.js"),V=require("./DrawerHeaderText.js"),ge=require("./MentionEditor.js"),Ue=require("./RestApiToolPanel.js"),ze=require("./SelectableListSection.js"),He=require("../../side-modal/SideModal.js"),Fe=require("../../input/Input.js"),Ye=require("../../toaster/Toaster.js"),We=u=>u&&typeof u=="object"&&"default"in u?u:{default:u},$e=We(De),Xe=1e3,ee=1002,fe=(u,y)=>{const l=u??[];return l.some(d=>d.id===y.id)?l.map(d=>d.id===y.id?y:d):[...l,y]},he=$e.default.button`
|
|
2
2
|
align-self: flex-start;
|
|
3
3
|
border: 1px solid ${Q.COLORS.stroke.primary};
|
|
4
4
|
color: ${Q.COLORS.content.primary};
|
|
@@ -14,5 +14,5 @@
|
|
|
14
14
|
cursor: default;
|
|
15
15
|
opacity: 0.6;
|
|
16
16
|
}
|
|
17
|
-
`,
|
|
17
|
+
`,Ze=({onClose:u,onSave:y,availableTools:l,onImprove:d,onImproveToolInstructions:te,configToolTemplates:oe,integrationStatus:T,onConnectIntegration:x,title:ne="Create sub-agent",initial:C,existingNames:Se=[],appLabel:b="Manifest",charLimits:R=Ge.AGENT_CHAR_LIMITS,variablesData:O})=>{const[D,ye]=o.useState(C?.name??""),[A,E]=o.useState(C?.instructions??""),[_,w]=o.useState(C?.guardrail??""),[G,q]=o.useState(C?.tools??[]),[g,K]=o.useState(C?.configTools??[]),[p,B]=o.useState(C?.restApiTools??[]),[c,I]=o.useState(null),M=o.useRef(0),[se,re]=o.useState(!1),[Te,P]=o.useState(0),[Ce,U]=o.useState(0),[v,ie]=o.useState(null),z=o.useMemo(()=>[...h.buildAgentMentionItems(l,[],b),...h.buildCustomToolMentionItems(g,p)],[l,b,g,p]),N=o.useRef({}),H=o.useRef("instructions"),be=o.useCallback(e=>{N.current.instructions=e??void 0},[]),Ie=o.useCallback(e=>{N.current.guardrail=e??void 0},[]),xe=o.useCallback(()=>{H.current="instructions"},[]),Re=o.useCallback(()=>{H.current="guardrail"},[]),le=o.useRef(new Set);le.current=new Set([...g,...p].map(e=>e.id));const ae=o.useCallback((e,t)=>{e==="tool"&&!le.current.has(t)&&q(n=>me.addUnique(n,t))},[]),k=o.useCallback((e,t,n)=>{(N.current[H.current]??N.current.instructions)?.("tool",e,t,n)},[]),F=o.useCallback(e=>{M.current+=1,I({key:M.current,kind:"restapi",initialRest:e})},[]),Y=o.useCallback((e,t)=>{M.current+=1,I({key:M.current,kind:"config",toolKey:e,initialConfig:t})},[]),Ae=o.useCallback((e,t)=>{const n=t??a.CONFIG_TOOL_SOURCES[e]?.[0];n?Y(n):F()},[Y,F]),_e=o.useCallback(e=>{const t=!p.some(n=>n.id===e.id);B(n=>fe(n,e)),t&&k(e.id,h.restApiMentionItem(e).label,a.ToolSource.RestApi),I(null)},[p,k]),ve=o.useCallback(e=>{const t=!g.some(n=>n.id===e.id);K(n=>fe(n,e)),t&&k(e.id,h.configToolMentionItem(e).label,a.CONFIG_TOOL_SOURCE_BY_KEY[e.tool_key]),I(null)},[g,k]),[W,$]=o.useState(null),X=o.useRef(null),ce=o.useRef(0),ke=e=>{const t=l.find(s=>s.tool_id===e)?.display_name??p.find(s=>s.id===e)?.name??"Tool",n=`{{tool:${e}}}`,m=s=>s.split(n).join("");X.current={instructions:A,guardrail:_,tools:G,configTools:g,restApiTools:p},E(s=>m(s)),w(s=>m(s)),q(s=>s.filter(f=>f!==e)),K(s=>s.filter(f=>f.id!==e)),B(s=>s.filter(f=>f.id!==e)),P(s=>s+1),U(s=>s+1),ce.current+=1,$({id:ce.current,message:`Tool "${t}" removed`})},Oe=()=>{const e=X.current;e&&(E(e.instructions),w(e.guardrail),q(e.tools),K(e.configTools),B(e.restApiTools),P(t=>t+1),U(t=>t+1),X.current=null),$(null)},Z=D.trim(),J=Z.length>0&&Se.some(e=>e.trim().toLowerCase()===Z.toLowerCase()),ue=Z.length>0&&!J&&(A.trim().length>0||_.trim().length>0),Ee=G.map(e=>{const t=l.find(n=>n.tool_id===e);return t?{id:e,label:t.display_name,icon:S.sourceIcon(t.source??a.ToolSource.Manifest),authRequired:t.auth_required}:null}).filter(e=>e!==null),we=p.map(e=>({id:e.id,label:h.restApiToolName(e),icon:S.SOURCE_ICONS[a.ToolSource.RestApi],onConfigure:()=>F(e)})),qe=g.map(e=>({id:e.id,label:h.configToolName(e),icon:S.SOURCE_ICONS[e.tool_key==="send_slack_message"?a.ToolSource.Slack:a.ToolSource.EmailHandover],onConfigure:()=>Y(e.tool_key,e)})),Me=[...Ee,...we,...qe],j=Be.buildToolActions(oe,Ae,T,x),de=c?.kind==="config"&&c.toolKey?oe?.[c.toolKey]:void 0,Ne=l.map(e=>({label:e.display_name,value:e.tool_id,leadingIcon:S.renderSourceIcon(S.sourceIcon(e.source??a.ToolSource.Manifest))??void 0})),je=(()=>{const e=[],t=new Map;l.forEach(r=>{const L=r.source??a.ToolSource.Manifest;t.has(L)||(t.set(L,[]),e.push(L)),t.get(L)?.push({label:r.display_name,value:r.tool_id,leadingIcon:S.renderSourceIcon(S.sourceIcon(r.source??a.ToolSource.Manifest))??void 0})});const{outside:n,inside:m}=Ke.partitionSources([...e,...j.map(r=>r.source)],T),s=new Set(n),f=e.filter(r=>s.has(r)).map(r=>({source:r,label:h.toolSourceLabel(r,b),options:t.get(r)??[],connected:T?.[r],onConnect:()=>x?.(r)}));return m.length>0&&f.push({source:a.INTEGRATIONS_KEY,label:a.INTEGRATIONS_LABEL,options:[]}),f})(),Le=async()=>{if(!ue||se)return;const e=y({name:D.trim(),instructions:A,guardrail:_,tools:G,configTools:g,restApiTools:p});if(e&&typeof e.then=="function"){re(!0);try{await e}finally{re(!1)}}},pe=async e=>{if(!(!d||v)){ie(e);try{const n=await d(e,e==="instructions"?A:_);e==="instructions"?(E(n),P(m=>m+1)):(w(n),U(m=>m+1))}finally{ie(null)}}};return i.jsxs(i.Fragment,{children:[i.jsxs(He.SideModal,{header:ne,closeOnEscapeKey:!1,zIndex:Xe,headerCustomComponent:i.jsx(V.DrawerHeaderText,{title:ne,subtitle:"Each sub-agent handles one piece of the job. Use @ in the main instructions to call them."}),width:"421px",headerStyle:V.DRAWER_HEADER_STYLE,bodyStyle:V.DRAWER_BODY_STYLE,onClose:u,saveButtonProps:{"data-test":"subagent-save",buttonText:"Save",buttonType:"primary",size:"small",disabled:!ue,isLoading:se,onClick:Le},cancelButtonProps:{"data-test":"subagent-cancel",buttonText:"Cancel",buttonType:"tertiaryGray",size:"small",onClick:u},children:[i.jsx(Fe.Input,{"data-test":"subagent-name",labelText:"Agent name",labelTextBold:!0,placeholder:"Enter agent name",value:D,maxCharLimit:R.name,maxCharLimitPosition:"TOP",maxCharStyle:{fontSize:12,lineHeight:"16px"},state:J?"invalid":void 0,errorMessage:J?"A sub-agent with this name already exists":void 0,onChangeText:ye}),i.jsx(ge.MentionEditor,{"data-test":"subagent-instructions",label:"Instructions",value:A,onChange:E,maxLength:R.instructions,placeholder:"Write the steps in plain English. The agent will follow them exactly. The more specific you are, the better it performs.",minHeight:"160px",resetKey:`instr-${Te}`,mentionItems:z,tools:l,toolActions:j,variablesData:O,addDataButton:!0,integrationStatus:T,appLabel:b,onConnectIntegration:x,onMentionSelect:ae,onFocus:xe,registerInsert:be,action:d?i.jsx(he,{type:"button","data-test":"subagent-improve-instructions",disabled:v!==null,onClick:()=>pe("instructions"),children:v==="instructions"?"Improving…":"Improve with AI"}):void 0}),i.jsx(ge.MentionEditor,{"data-test":"subagent-guardrail",label:"Guardrails",value:_,onChange:w,maxLength:R.guardrail,placeholder:"e.g. Never discuss competitor pricing. Always stay within the cancellation policy. Do not process refunds above ₹10,000 without human approval.",minHeight:"160px",resetKey:`guard-${Ce}`,mentionItems:z,tools:l,toolActions:j,variablesData:O,addDataButton:!0,integrationStatus:T,appLabel:b,onConnectIntegration:x,onMentionSelect:ae,onFocus:Re,registerInsert:Ie,action:d?i.jsx(he,{type:"button","data-test":"subagent-improve-guardrail",disabled:v!==null,onClick:()=>pe("guardrail"),children:v==="guardrail"?"Improving…":"Improve with AI"}):void 0}),i.jsx(ze.SelectableListSection,{title:"Tools this agent can use",dataTestPrefix:"subagent-tools",items:Me,addableOptions:Ne,sourceGroups:je,integrationStatus:T,onConnectIntegration:e=>x?.(e),mentionItems:z,actionSources:j,emptyText:"No tools added yet.",appLabel:b,pickerOpensUp:!0,onAdd:e=>{k(e),q(t=>me.addUnique(t,e))},onRemove:ke,confirmDelete:{noun:"tool",zIndex:ee+1}})]}),c?.kind==="restapi"&&i.jsx(Ue.RestApiToolPanel,{initial:c.initialRest,charLimits:R,variablesData:O,onImprove:te,onClose:()=>I(null),onSave:_e,zIndex:ee},c.key),c?.kind==="config"&&c.toolKey&&de&&i.jsx(Pe.ConfigToolPanel,{toolKey:c.toolKey,template:de,initial:c.initialConfig,charLimits:R,variablesData:O,onImprove:te,onClose:()=>I(null),onSave:ve,zIndex:ee},c.key),W&&i.jsx(Ye.Toaster,{text:W.message,type:"info",position:"top-right",autoClose:5e3,hideCloseButton:!0,buttonProps:{buttonText:"Undo",showButton:!0,onButtonClick:()=>(Oe(),{})},onCloseToast:()=>$(null)},W.id)]})};exports.CreateSubAgentPanel=Ze;
|
|
18
18
|
//# sourceMappingURL=CreateSubAgentPanel.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateSubAgentPanel.js","sources":["../../../../../src/components/agent-builder/components/CreateSubAgentPanel.tsx"],"sourcesContent":["import React, { useCallback, useMemo, useRef, useState } from 'react';\nimport styled from 'styled-components';\nimport { SingleOption } from '@src/components/dropdown/type';\nimport { Input } from '@src/components/input';\nimport { SideModal } from '@src/components/side-modal';\nimport { Toaster } from '@src/components/toaster';\nimport { addUnique } from '@src/utils/arrayUtils';\nimport { COLORS } from '@src/constants/Theme';\nimport type { VariableListInterfaceV3 } from '../../variable-picker-v3/model';\nimport {\n\tAgentTool,\n\tConfigToolConfig,\n\tConfigToolKey,\n\tParamsBlob,\n\tRestApiToolConfig,\n\tSubAgentDraft,\n} from '../AgentBuilder.model';\nimport { AGENT_CHAR_LIMITS } from '../constants/charLimits';\nimport type { AgentCharLimits } from '../constants/charLimits';\nimport {\n\tCONFIG_TOOL_SOURCE_BY_KEY,\n\tCONFIG_TOOL_SOURCES,\n\tINTEGRATIONS_KEY,\n\tINTEGRATIONS_LABEL,\n\tToolSource,\n} from '../constants/tools';\nimport {\n\tbuildAgentMentionItems,\n\tbuildCustomToolMentionItems,\n\tconfigToolMentionItem,\n\tconfigToolName,\n\trestApiMentionItem,\n\trestApiToolName,\n\ttoolSourceLabel,\n} from '../utils/mentionSerialization';\nimport { partitionSources } from '../utils/sourceGrouping';\nimport {\n\trenderSourceIcon,\n\tSOURCE_ICONS,\n\tsourceIcon,\n} from '../utils/sourceIcons';\nimport { buildToolActions } from '../utils/toolActions';\nimport { ConfigToolPanel } from './ConfigToolPanel';\nimport {\n\tDRAWER_BODY_STYLE,\n\tDRAWER_HEADER_STYLE,\n\tDrawerHeaderText,\n} from './DrawerHeaderText';\nimport { MentionEditor } from './MentionEditor';\nimport { RestApiToolPanel } from './RestApiToolPanel';\nimport {\n\tSelectableItem,\n\tSelectableListSection,\n\tSourceGroup,\n} from './SelectableListSection';\n\n/**\n * The sub-agent drawer sits above the main builder; its own tool drawers\n * (Rest API / email / Slack) stack one level higher so they open ON TOP of it\n * rather than behind (SideModal defaults to z-index 10).\n */\nconst SUBAGENT_ZINDEX = 1000;\nconst TOOL_DRAWER_ZINDEX = 1002;\n\n/** Upsert an item by id (replace when present, append otherwise). */\nconst upsertById = <T extends { id: string }>(\n\tlist: T[] | undefined,\n\titem: T,\n): T[] => {\n\tconst arr = list ?? [];\n\treturn arr.some((x) => x.id === item.id)\n\t\t? arr.map((x) => (x.id === item.id ? item : x))\n\t\t: [...arr, item];\n};\n\n/** Config-tool / Rest API drawer state; `key` remounts fresh per open. */\ninterface ToolDrawerState {\n\tkey: number;\n\tkind: 'restapi' | 'config';\n\ttoolKey?: ConfigToolKey;\n\tinitialRest?: RestApiToolConfig;\n\tinitialConfig?: ConfigToolConfig;\n}\n\n/** Inline \"Improve with AI\" action rendered below a mention editor. */\nconst ImproveButton = styled.button`\n\talign-self: flex-start;\n\tborder: 1px solid ${COLORS.stroke.primary};\n\tcolor: ${COLORS.content.primary};\n\tbackground: ${COLORS.surface.standard};\n\tborder-radius: 8px;\n\tpadding: 6px 12px;\n\tfont-size: 13px;\n\tline-height: 1.1;\n\tfont-weight: 600;\n\tcursor: pointer;\n\n\t&:disabled {\n\t\tcursor: default;\n\t\topacity: 0.6;\n\t}\n`;\n\ntype InsertFn = (\n\tkind: 'tool' | 'subagent',\n\tid: string,\n\tlabel?: string,\n\tsource?: string,\n) => void;\n\ninterface CreateSubAgentPanelProps {\n\tonClose: () => void;\n\t/** Persist the draft. The drawer shows a loader while the returned promise is pending. */\n\tonSave: (draft: SubAgentDraft) => void | Promise<void>;\n\tavailableTools: AgentTool[];\n\t/** Optional \"Improve with AI\" for instructions / guardrails. Omit to hide the buttons. */\n\tonImprove?: (\n\t\tkind: 'instructions' | 'guardrail',\n\t\ttext: string,\n\t) => Promise<string>;\n\t/** Optional \"Improve with AI\" for the Rest API / config-tool drawers. */\n\tonImproveToolInstructions?: (text: string) => Promise<string>;\n\t/**\n\t * Backend templates (email / Slack) that drive the shared config-tool drawer.\n\t * Each present key enables its tool action in this drawer; absent → hidden.\n\t * Same prop the main builder gets — sub-agents can add the same tools.\n\t */\n\tconfigToolTemplates?: Partial<Record<ConfigToolKey, ParamsBlob>>;\n\t/**\n\t * Per-source integration connection state (today: Slack). A source mapped to\n\t * `false` shows a \"Connect\" affordance instead of drilling into its tools —\n\t * same gating the main builder's Step 3 tool section gets.\n\t */\n\tintegrationStatus?: Partial<Record<ToolSource, boolean>>;\n\t/** Open the consumer's connect flow for an unconnected integration source. */\n\tonConnectIntegration?: (source: ToolSource) => void;\n\t/** Header title — \"Create sub-agent\" (default) or \"Edit sub-agent\". */\n\ttitle?: string;\n\t/** Initial values, e.g. when configuring an existing sub-agent. */\n\tinitial?: SubAgentDraft;\n\t/**\n\t * Names of the other sub-agents already on this agent (exclude the one being\n\t * edited). Blocks saving a duplicate name — the LLM references sub-agents by it.\n\t */\n\texistingNames?: string[];\n\t/** Tool-source fallback label for chips (host app). */\n\tappLabel?: string;\n\t/** Resolved character limits (defaults to {@link AGENT_CHAR_LIMITS}). */\n\tcharLimits?: AgentCharLimits;\n\t/**\n\t * Portal target for the drawer, passed straight to {@link SideModal}\n\t * (default `document.body`). Lets a host render it into its own positioned\n\t * slot rather than as a viewport overlay.\n\t */\n\telement?: Element | DocumentFragment;\n\t/**\n\t * Footer button order, passed straight to {@link SideModal} (default\n\t * `'row'`). Hosts that show this drawer beside their own footer can set\n\t * `'row-reverse'` to line the Cancel / Save order up with it.\n\t */\n\tfooterDirection?: 'row' | 'row-reverse';\n\t/** Variable catalog for the editors' `@` picker \"Variables\" view. */\n\tvariablesData?: VariableListInterfaceV3[];\n}\n\n/**\n * Right-side drawer for creating / editing a sub-agent (name, instructions,\n * guardrails, tools). Instructions & Guardrails are `@`-mention editors (tools\n * only — sub-agents can't nest); adding a tool from the list inserts it at the\n * last-focused field's cursor. Mount it fresh per open (key it) so `initial`\n * seeds the draft.\n */\nexport const CreateSubAgentPanel: React.FC<CreateSubAgentPanelProps> = ({\n\tonClose,\n\tonSave,\n\tavailableTools,\n\tonImprove,\n\tonImproveToolInstructions,\n\tconfigToolTemplates,\n\tintegrationStatus,\n\tonConnectIntegration,\n\ttitle = 'Create sub-agent',\n\tinitial,\n\texistingNames = [],\n\tappLabel = 'Manifest',\n\tcharLimits = AGENT_CHAR_LIMITS,\n\tvariablesData,\n\telement,\n\tfooterDirection,\n}) => {\n\tconst [name, setName] = useState(initial?.name ?? '');\n\tconst [instructions, setInstructions] = useState(initial?.instructions ?? '');\n\tconst [guardrail, setGuardrail] = useState(initial?.guardrail ?? '');\n\tconst [tools, setTools] = useState<string[]>(initial?.tools ?? []);\n\t// Inline-configured tools owned by this sub-agent (same drawers as the main\n\t// agent). Local to the drawer; flow to the consumer via the saved draft.\n\tconst [configTools, setConfigTools] = useState<ConfigToolConfig[]>(\n\t\tinitial?.configTools ?? [],\n\t);\n\tconst [restApiTools, setRestApiTools] = useState<RestApiToolConfig[]>(\n\t\tinitial?.restApiTools ?? [],\n\t);\n\tconst [toolDrawer, setToolDrawer] = useState<ToolDrawerState | null>(null);\n\tconst toolDrawerKeyRef = useRef(0);\n\tconst [saving, setSaving] = useState(false);\n\t// Bumped to remount a field after its text is replaced (e.g. by Improve).\n\tconst [instrKey, setInstrKey] = useState(0);\n\tconst [guardKey, setGuardKey] = useState(0);\n\tconst [improving, setImproving] = useState<\n\t\t'instructions' | 'guardrail' | null\n\t>(null);\n\n\t// Tools-only mention list (sub-agents can't reference other sub-agents), PLUS\n\t// this drawer's inline custom tools so their `{{tool:<id>}}` tokens rehydrate\n\t// as chips on remount (they aren't in `availableTools`).\n\tconst mentionItems = useMemo(\n\t\t() => [\n\t\t\t...buildAgentMentionItems(availableTools, [], appLabel),\n\t\t\t...buildCustomToolMentionItems(configTools, restApiTools),\n\t\t],\n\t\t[availableTools, appLabel, configTools, restApiTools],\n\t);\n\n\t// Per-field insert + focus registry, so the Tools list inserts a chip into the\n\t// last-focused editor at its cursor.\n\tconst insertersRef = useRef<\n\t\tPartial<Record<'instructions' | 'guardrail', InsertFn>>\n\t>({});\n\tconst lastFocusedRef = useRef<'instructions' | 'guardrail'>('instructions');\n\tconst registerInstr = useCallback((fn: InsertFn | null) => {\n\t\tinsertersRef.current.instructions = fn ?? undefined;\n\t}, []);\n\tconst registerGuard = useCallback((fn: InsertFn | null) => {\n\t\tinsertersRef.current.guardrail = fn ?? undefined;\n\t}, []);\n\tconst focusInstr = useCallback(() => {\n\t\tlastFocusedRef.current = 'instructions';\n\t}, []);\n\tconst focusGuard = useCallback(() => {\n\t\tlastFocusedRef.current = 'guardrail';\n\t}, []);\n\t// Latest custom-tool ids, readable from the mount-captured `@` onSelect handler\n\t// (BikEditor captures it once) — mirrors the context's valueRef trick.\n\tconst customToolIdsRef = useRef<Set<string>>(new Set());\n\tcustomToolIdsRef.current = new Set(\n\t\t[...configTools, ...restApiTools].map((t) => t.id),\n\t);\n\tconst addToolMention = useCallback(\n\t\t(kind: 'tool' | 'subagent', id: string) => {\n\t\t\t// Only catalog tool ids belong in `tools`; custom tools (Rest API / email /\n\t\t\t// Slack) track themselves on their own lists. Picking an existing custom\n\t\t\t// tool from `@` must not leak its id in as a bogus native ref.\n\t\t\tif (kind === 'tool' && !customToolIdsRef.current.has(id)) {\n\t\t\t\tsetTools((prev) => addUnique(prev, id));\n\t\t\t}\n\t\t},\n\t\t[],\n\t);\n\tconst insertToolAtCursor = useCallback(\n\t\t(id: string, label?: string, source?: string) => {\n\t\t\tconst target =\n\t\t\t\tinsertersRef.current[lastFocusedRef.current] ??\n\t\t\t\tinsertersRef.current.instructions;\n\t\t\ttarget?.('tool', id, label, source);\n\t\t},\n\t\t[],\n\t);\n\n\t// Rest API (bespoke) + shared config-tool (email / Slack) drawers, same as the\n\t// main builder's Step 3 — here backed by the drawer's local state.\n\t// ponytail: mirrors Step3HowItResponds; kept local rather than sharing a hook\n\t// because Step3 is context-backed and this drawer is local-state.\n\tconst openRestApi = useCallback((tool?: RestApiToolConfig) => {\n\t\ttoolDrawerKeyRef.current += 1;\n\t\tsetToolDrawer({\n\t\t\tkey: toolDrawerKeyRef.current,\n\t\t\tkind: 'restapi',\n\t\t\tinitialRest: tool,\n\t\t});\n\t}, []);\n\tconst openConfigTool = useCallback(\n\t\t(toolKey: ConfigToolKey, tool?: ConfigToolConfig) => {\n\t\t\ttoolDrawerKeyRef.current += 1;\n\t\t\tsetToolDrawer({\n\t\t\t\tkey: toolDrawerKeyRef.current,\n\t\t\t\tkind: 'config',\n\t\t\t\ttoolKey,\n\t\t\t\tinitialConfig: tool,\n\t\t\t});\n\t\t},\n\t\t[],\n\t);\n\tconst openToolAction = useCallback(\n\t\t(source: ToolSource, toolKey?: ConfigToolKey) => {\n\t\t\tconst key = toolKey ?? CONFIG_TOOL_SOURCES[source]?.[0];\n\t\t\tif (key) {\n\t\t\t\topenConfigTool(key);\n\t\t\t} else {\n\t\t\t\topenRestApi();\n\t\t\t}\n\t\t},\n\t\t[openConfigTool, openRestApi],\n\t);\n\tconst handleSaveRestApi = useCallback(\n\t\t(tool: RestApiToolConfig) => {\n\t\t\tconst isNew = !restApiTools.some((t) => t.id === tool.id);\n\t\t\tsetRestApiTools((prev) => upsertById(prev, tool));\n\t\t\t// Drop a reference chip at the cursor on creation (edits keep the chip).\n\t\t\t// Pass the source so the fresh chip shows its icon (not yet in the list).\n\t\t\tif (isNew) {\n\t\t\t\tinsertToolAtCursor(\n\t\t\t\t\ttool.id,\n\t\t\t\t\trestApiMentionItem(tool).label,\n\t\t\t\t\tToolSource.RestApi,\n\t\t\t\t);\n\t\t\t}\n\t\t\tsetToolDrawer(null);\n\t\t},\n\t\t[restApiTools, insertToolAtCursor],\n\t);\n\tconst handleSaveConfigTool = useCallback(\n\t\t(tool: ConfigToolConfig) => {\n\t\t\tconst isNew = !configTools.some((t) => t.id === tool.id);\n\t\t\tsetConfigTools((prev) => upsertById(prev, tool));\n\t\t\tif (isNew) {\n\t\t\t\tinsertToolAtCursor(\n\t\t\t\t\ttool.id,\n\t\t\t\t\tconfigToolMentionItem(tool).label,\n\t\t\t\t\tCONFIG_TOOL_SOURCE_BY_KEY[tool.tool_key],\n\t\t\t\t);\n\t\t\t}\n\t\t\tsetToolDrawer(null);\n\t\t},\n\t\t[configTools, insertToolAtCursor],\n\t);\n\n\t// Local undo toast for tool removal (drawer state isn't in AgentValue).\n\tconst [undo, setUndo] = useState<{ id: number; message: string } | null>(\n\t\tnull,\n\t);\n\tconst undoSnapshotRef = useRef<{\n\t\tinstructions: string;\n\t\tguardrail: string;\n\t\ttools: string[];\n\t\tconfigTools: ConfigToolConfig[];\n\t\trestApiTools: RestApiToolConfig[];\n\t} | null>(null);\n\tconst undoIdRef = useRef(0);\n\n\t// Remove ANY tool by id: strip its `{{tool:<id>}}` tokens, remount the fields,\n\t// and drop it from whichever list holds it (catalog `tools` or an inline\n\t// custom-tool list). One undo restores all of it.\n\tconst removeTool = (id: string) => {\n\t\tconst label =\n\t\t\tavailableTools.find((t) => t.tool_id === id)?.display_name ??\n\t\t\trestApiTools.find((t) => t.id === id)?.name ??\n\t\t\t'Tool';\n\t\t// The token stores the tool id (a tool's id is its tool_id).\n\t\tconst token = `{{tool:${id}}}`;\n\t\tconst strip = (text: string) => text.split(token).join('');\n\t\tundoSnapshotRef.current = {\n\t\t\tinstructions,\n\t\t\tguardrail,\n\t\t\ttools,\n\t\t\tconfigTools,\n\t\t\trestApiTools,\n\t\t};\n\t\tsetInstructions((prev) => strip(prev));\n\t\tsetGuardrail((prev) => strip(prev));\n\t\tsetTools((prev) => prev.filter((t) => t !== id));\n\t\tsetConfigTools((prev) => prev.filter((t) => t.id !== id));\n\t\tsetRestApiTools((prev) => prev.filter((t) => t.id !== id));\n\t\tsetInstrKey((k) => k + 1);\n\t\tsetGuardKey((k) => k + 1);\n\t\tundoIdRef.current += 1;\n\t\tsetUndo({ id: undoIdRef.current, message: `Tool \"${label}\" removed` });\n\t};\n\n\tconst undoRemove = () => {\n\t\tconst snap = undoSnapshotRef.current;\n\t\tif (snap) {\n\t\t\tsetInstructions(snap.instructions);\n\t\t\tsetGuardrail(snap.guardrail);\n\t\t\tsetTools(snap.tools);\n\t\t\tsetConfigTools(snap.configTools);\n\t\t\tsetRestApiTools(snap.restApiTools);\n\t\t\tsetInstrKey((k) => k + 1);\n\t\t\tsetGuardKey((k) => k + 1);\n\t\t\tundoSnapshotRef.current = null;\n\t\t}\n\t\tsetUndo(null);\n\t};\n\n\tconst nameTrimmed = name.trim();\n\t// Case-insensitive: two sub-agents on the same agent can't share a name (the\n\t// LLM references them by it) — mirrors the Rest API tool-name check.\n\tconst isDuplicateName =\n\t\tnameTrimmed.length > 0 &&\n\t\texistingNames.some(\n\t\t\t(n) => n.trim().toLowerCase() === nameTrimmed.toLowerCase(),\n\t\t);\n\tconst canSave =\n\t\tnameTrimmed.length > 0 &&\n\t\t!isDuplicateName &&\n\t\t(instructions.trim().length > 0 || guardrail.trim().length > 0);\n\n\tconst toolItems: SelectableItem[] = tools\n\t\t.map((id): SelectableItem | null => {\n\t\t\tconst tool = availableTools.find((t) => t.tool_id === id);\n\t\t\treturn tool\n\t\t\t\t? {\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tlabel: tool.display_name,\n\t\t\t\t\t\ticon: sourceIcon(tool.source ?? ToolSource.Manifest),\n\t\t\t\t\t\t// Shield flags a tool that needs customer verification, same as\n\t\t\t\t\t\t// the main builder's Step 3 tool rows.\n\t\t\t\t\t\tauthRequired: tool.auth_required,\n\t\t\t\t }\n\t\t\t\t: null;\n\t\t})\n\t\t.filter((x): x is SelectableItem => x !== null);\n\n\t// Inline-configured tools (Rest API + email / Slack) render as rows in the same\n\t// list, each with its own Configure (edit) action that reopens its drawer.\n\tconst restApiItems: SelectableItem[] = restApiTools.map((t) => ({\n\t\tid: t.id,\n\t\tlabel: restApiToolName(t),\n\t\ticon: SOURCE_ICONS[ToolSource.RestApi],\n\t\tonConfigure: () => openRestApi(t),\n\t}));\n\tconst configToolItems: SelectableItem[] = configTools.map((t) => ({\n\t\tid: t.id,\n\t\tlabel: configToolName(t),\n\t\ticon: SOURCE_ICONS[\n\t\t\tt.tool_key === 'send_slack_message'\n\t\t\t\t? ToolSource.Slack\n\t\t\t\t: ToolSource.EmailHandover\n\t\t],\n\t\tonConfigure: () => openConfigTool(t.tool_key, t),\n\t}));\n\tconst allToolItems: SelectableItem[] = [\n\t\t...toolItems,\n\t\t...restApiItems,\n\t\t...configToolItems,\n\t];\n\n\t// Built-in tool actions (Rest API / email / Slack); the shared email / Slack\n\t// forms appear only when their backend template was provided. Integration\n\t// state drives the \"Connect\" affordance, same as the main builder's Step 3.\n\tconst toolActionSources = buildToolActions(\n\t\tconfigToolTemplates,\n\t\topenToolAction,\n\t\tintegrationStatus,\n\t\tonConnectIntegration,\n\t);\n\n\tconst openConfigTemplate =\n\t\ttoolDrawer?.kind === 'config' && toolDrawer.toolKey\n\t\t\t? configToolTemplates?.[toolDrawer.toolKey]\n\t\t\t: undefined;\n\n\t// Offer all tools (re-add allowed); the chip list stays deduped. Icon left of\n\t// the name, no description.\n\tconst toolOptions: SingleOption[] = availableTools.map((t) => ({\n\t\tlabel: t.display_name,\n\t\tvalue: t.tool_id,\n\t\tleadingIcon:\n\t\t\trenderSourceIcon(sourceIcon(t.source ?? ToolSource.Manifest)) ??\n\t\t\tundefined,\n\t}));\n\n\t// Group tools by source (Manifest / Shopify / …) so the empty state shows the\n\t// same per-source buttons as the main builder's side panel.\n\tconst toolSourceGroups: SourceGroup[] = (() => {\n\t\tconst order: string[] = [];\n\t\tconst bySource = new Map<string, SingleOption[]>();\n\t\tavailableTools.forEach((t) => {\n\t\t\tconst src = t.source ?? ToolSource.Manifest;\n\t\t\tif (!bySource.has(src)) {\n\t\t\t\tbySource.set(src, []);\n\t\t\t\torder.push(src);\n\t\t\t}\n\t\t\tbySource.get(src)?.push({\n\t\t\t\tlabel: t.display_name,\n\t\t\t\tvalue: t.tool_id,\n\t\t\t\tleadingIcon:\n\t\t\t\t\trenderSourceIcon(sourceIcon(t.source ?? ToolSource.Manifest)) ??\n\t\t\t\t\tundefined,\n\t\t\t});\n\t\t});\n\t\t// Same rule as the `@` picker: a source the store hasn't connected doesn't\n\t\t// get its own button — they all collapse into one \"Integrations\" button that\n\t\t// opens the picker on that group (SelectableListSection deep-links a source\n\t\t// button straight into the picker, and the umbrella key works like any other\n\t\t// source there). Action sources join the split too: Slack has no catalog\n\t\t// tools of its own, so without them an unconnected Slack would have nowhere\n\t\t// to live.\n\t\tconst { outside, inside } = partitionSources(\n\t\t\t[...order, ...toolActionSources.map((a) => a.source)],\n\t\t\tintegrationStatus,\n\t\t);\n\t\tconst shownOutside = new Set(outside);\n\t\tconst groups: SourceGroup[] = order\n\t\t\t.filter((src) => shownOutside.has(src))\n\t\t\t.map((src) => ({\n\t\t\t\tsource: src,\n\t\t\t\tlabel: toolSourceLabel(src, appLabel),\n\t\t\t\toptions: bySource.get(src) ?? [],\n\t\t\t\t// Reachable only when connected or ungated, so no connect flow needed —\n\t\t\t\t// kept for the picker's own gating, which reads these groups.\n\t\t\t\tconnected: integrationStatus?.[src as ToolSource],\n\t\t\t\tonConnect: () => onConnectIntegration?.(src as ToolSource),\n\t\t\t}));\n\t\tif (inside.length > 0) {\n\t\t\tgroups.push({\n\t\t\t\tsource: INTEGRATIONS_KEY,\n\t\t\t\tlabel: INTEGRATIONS_LABEL,\n\t\t\t\t// No options of its own: clicking opens the picker at the umbrella,\n\t\t\t\t// where each unconnected source offers \"Connect\".\n\t\t\t\toptions: [],\n\t\t\t});\n\t\t}\n\t\treturn groups;\n\t})();\n\n\tconst handleSave = async () => {\n\t\tif (!canSave || saving) {\n\t\t\treturn;\n\t\t}\n\t\tconst result = onSave({\n\t\t\tname: name.trim(),\n\t\t\tinstructions,\n\t\t\tguardrail,\n\t\t\ttools,\n\t\t\tconfigTools,\n\t\t\trestApiTools,\n\t\t});\n\t\tif (result && typeof (result as Promise<void>).then === 'function') {\n\t\t\tsetSaving(true);\n\t\t\ttry {\n\t\t\t\tawait result;\n\t\t\t} finally {\n\t\t\t\tsetSaving(false);\n\t\t\t}\n\t\t}\n\t};\n\n\tconst handleImprove = async (kind: 'instructions' | 'guardrail') => {\n\t\tif (!onImprove || improving) {\n\t\t\treturn;\n\t\t}\n\t\tsetImproving(kind);\n\t\ttry {\n\t\t\tconst current = kind === 'instructions' ? instructions : guardrail;\n\t\t\tconst improved = await onImprove(kind, current);\n\t\t\tif (kind === 'instructions') {\n\t\t\t\tsetInstructions(improved);\n\t\t\t\tsetInstrKey((k) => k + 1);\n\t\t\t} else {\n\t\t\t\tsetGuardrail(improved);\n\t\t\t\tsetGuardKey((k) => k + 1);\n\t\t\t}\n\t\t} finally {\n\t\t\tsetImproving(null);\n\t\t}\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<SideModal\n\t\t\t\theader={title}\n\t\t\t\tcloseOnEscapeKey={false}\n\t\t\t\tzIndex={SUBAGENT_ZINDEX}\n\t\t\t\telement={element}\n\t\t\t\tfooterDirection={footerDirection}\n\t\t\t\theaderCustomComponent={\n\t\t\t\t\t<DrawerHeaderText\n\t\t\t\t\t\ttitle={title}\n\t\t\t\t\t\tsubtitle=\"Each sub-agent handles one piece of the job. Use @ in the main instructions to call them.\"\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t\twidth=\"421px\"\n\t\t\t\theaderStyle={DRAWER_HEADER_STYLE}\n\t\t\t\tbodyStyle={DRAWER_BODY_STYLE}\n\t\t\t\tonClose={onClose}\n\t\t\t\tsaveButtonProps={{\n\t\t\t\t\t'data-test': 'subagent-save',\n\t\t\t\t\tbuttonText: 'Save',\n\t\t\t\t\tbuttonType: 'primary',\n\t\t\t\t\tsize: 'small',\n\t\t\t\t\tdisabled: !canSave,\n\t\t\t\t\tisLoading: saving,\n\t\t\t\t\tonClick: handleSave,\n\t\t\t\t}}\n\t\t\t\tcancelButtonProps={{\n\t\t\t\t\t'data-test': 'subagent-cancel',\n\t\t\t\t\tbuttonText: 'Cancel',\n\t\t\t\t\tbuttonType: 'tertiaryGray',\n\t\t\t\t\tsize: 'small',\n\t\t\t\t\tonClick: onClose,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<Input\n\t\t\t\t\tdata-test=\"subagent-name\"\n\t\t\t\t\tlabelText=\"Agent name\"\n\t\t\t\t\tlabelTextBold\n\t\t\t\t\tplaceholder=\"Enter agent name\"\n\t\t\t\t\tvalue={name}\n\t\t\t\t\tmaxCharLimit={charLimits.name}\n\t\t\t\t\tmaxCharLimitPosition=\"TOP\"\n\t\t\t\t\tmaxCharStyle={{ fontSize: 12, lineHeight: '16px' }}\n\t\t\t\t\tstate={isDuplicateName ? 'invalid' : undefined}\n\t\t\t\t\terrorMessage={\n\t\t\t\t\t\tisDuplicateName\n\t\t\t\t\t\t\t? 'A sub-agent with this name already exists'\n\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t}\n\t\t\t\t\tonChangeText={setName}\n\t\t\t\t/>\n\n\t\t\t\t<MentionEditor\n\t\t\t\t\tdata-test=\"subagent-instructions\"\n\t\t\t\t\tlabel=\"Instructions\"\n\t\t\t\t\tvalue={instructions}\n\t\t\t\t\tonChange={setInstructions}\n\t\t\t\t\tmaxLength={charLimits.instructions}\n\t\t\t\t\tplaceholder=\"Write the steps in plain English. The agent will follow them exactly. The more specific you are, the better it performs.\"\n\t\t\t\t\tminHeight=\"160px\"\n\t\t\t\t\tresetKey={`instr-${instrKey}`}\n\t\t\t\t\tmentionItems={mentionItems}\n\t\t\t\t\ttools={availableTools}\n\t\t\t\t\ttoolActions={toolActionSources}\n\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\taddDataButton\n\t\t\t\t\tintegrationStatus={integrationStatus}\n\t\t\t\t\tappLabel={appLabel}\n\t\t\t\t\tonConnectIntegration={onConnectIntegration}\n\t\t\t\t\tonMentionSelect={addToolMention}\n\t\t\t\t\tonFocus={focusInstr}\n\t\t\t\t\tregisterInsert={registerInstr}\n\t\t\t\t\taction={\n\t\t\t\t\t\tonImprove ? (\n\t\t\t\t\t\t\t<ImproveButton\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tdata-test=\"subagent-improve-instructions\"\n\t\t\t\t\t\t\t\tdisabled={improving !== null}\n\t\t\t\t\t\t\t\tonClick={() => handleImprove('instructions')}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{improving === 'instructions'\n\t\t\t\t\t\t\t\t\t? 'Improving…'\n\t\t\t\t\t\t\t\t\t: 'Improve with AI'}\n\t\t\t\t\t\t\t</ImproveButton>\n\t\t\t\t\t\t) : undefined\n\t\t\t\t\t}\n\t\t\t\t/>\n\n\t\t\t\t<MentionEditor\n\t\t\t\t\tdata-test=\"subagent-guardrail\"\n\t\t\t\t\tlabel=\"Guardrails\"\n\t\t\t\t\tvalue={guardrail}\n\t\t\t\t\tonChange={setGuardrail}\n\t\t\t\t\tmaxLength={charLimits.guardrail}\n\t\t\t\t\tplaceholder=\"e.g. Never discuss competitor pricing. Always stay within the cancellation policy. Do not process refunds above ₹10,000 without human approval.\"\n\t\t\t\t\tminHeight=\"160px\"\n\t\t\t\t\tresetKey={`guard-${guardKey}`}\n\t\t\t\t\tmentionItems={mentionItems}\n\t\t\t\t\ttools={availableTools}\n\t\t\t\t\ttoolActions={toolActionSources}\n\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\taddDataButton\n\t\t\t\t\tintegrationStatus={integrationStatus}\n\t\t\t\t\tappLabel={appLabel}\n\t\t\t\t\tonConnectIntegration={onConnectIntegration}\n\t\t\t\t\tonMentionSelect={addToolMention}\n\t\t\t\t\tonFocus={focusGuard}\n\t\t\t\t\tregisterInsert={registerGuard}\n\t\t\t\t\taction={\n\t\t\t\t\t\tonImprove ? (\n\t\t\t\t\t\t\t<ImproveButton\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tdata-test=\"subagent-improve-guardrail\"\n\t\t\t\t\t\t\t\tdisabled={improving !== null}\n\t\t\t\t\t\t\t\tonClick={() => handleImprove('guardrail')}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{improving === 'guardrail' ? 'Improving…' : 'Improve with AI'}\n\t\t\t\t\t\t\t</ImproveButton>\n\t\t\t\t\t\t) : undefined\n\t\t\t\t\t}\n\t\t\t\t/>\n\n\t\t\t\t<SelectableListSection\n\t\t\t\t\ttitle=\"Tools this agent can use\"\n\t\t\t\t\tdataTestPrefix=\"subagent-tools\"\n\t\t\t\t\titems={allToolItems}\n\t\t\t\t\taddableOptions={toolOptions}\n\t\t\t\t\tsourceGroups={toolSourceGroups}\n\t\t\t\t\tintegrationStatus={integrationStatus}\n\t\t\t\t\tonConnectIntegration={(source) =>\n\t\t\t\t\t\tonConnectIntegration?.(source as ToolSource)\n\t\t\t\t\t}\n\t\t\t\t\tmentionItems={mentionItems}\n\t\t\t\t\tactionSources={toolActionSources}\n\t\t\t\t\temptyText=\"No tools added yet.\"\n\t\t\t\t\tappLabel={appLabel}\n\t\t\t\t\tpickerOpensUp\n\t\t\t\t\tonAdd={(id) => {\n\t\t\t\t\t\tinsertToolAtCursor(id);\n\t\t\t\t\t\tsetTools((prev) => addUnique(prev, id));\n\t\t\t\t\t}}\n\t\t\t\t\tonRemove={removeTool}\n\t\t\t\t\tconfirmDelete={{ noun: 'tool', zIndex: TOOL_DRAWER_ZINDEX + 1 }}\n\t\t\t\t/>\n\t\t\t</SideModal>\n\n\t\t\t{toolDrawer?.kind === 'restapi' && (\n\t\t\t\t<RestApiToolPanel\n\t\t\t\t\tkey={toolDrawer.key}\n\t\t\t\t\tinitial={toolDrawer.initialRest}\n\t\t\t\t\tcharLimits={charLimits}\n\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\tonImprove={onImproveToolInstructions}\n\t\t\t\t\tonClose={() => setToolDrawer(null)}\n\t\t\t\t\tonSave={handleSaveRestApi}\n\t\t\t\t\tzIndex={TOOL_DRAWER_ZINDEX}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t{toolDrawer?.kind === 'config' &&\n\t\t\t\ttoolDrawer.toolKey &&\n\t\t\t\topenConfigTemplate && (\n\t\t\t\t\t<ConfigToolPanel\n\t\t\t\t\t\tkey={toolDrawer.key}\n\t\t\t\t\t\ttoolKey={toolDrawer.toolKey}\n\t\t\t\t\t\ttemplate={openConfigTemplate}\n\t\t\t\t\t\tinitial={toolDrawer.initialConfig}\n\t\t\t\t\t\tcharLimits={charLimits}\n\t\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\t\tonImprove={onImproveToolInstructions}\n\t\t\t\t\t\tonClose={() => setToolDrawer(null)}\n\t\t\t\t\t\tonSave={handleSaveConfigTool}\n\t\t\t\t\t\tzIndex={TOOL_DRAWER_ZINDEX}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\n\t\t\t{undo && (\n\t\t\t\t<Toaster\n\t\t\t\t\tkey={undo.id}\n\t\t\t\t\ttext={undo.message}\n\t\t\t\t\ttype=\"info\"\n\t\t\t\t\tposition=\"top-right\"\n\t\t\t\t\tautoClose={5000}\n\t\t\t\t\thideCloseButton\n\t\t\t\t\tbuttonProps={{\n\t\t\t\t\t\tbuttonText: 'Undo',\n\t\t\t\t\t\tshowButton: true,\n\t\t\t\t\t\tonButtonClick: () => {\n\t\t\t\t\t\t\tundoRemove();\n\t\t\t\t\t\t\treturn {} as Record<string, never>;\n\t\t\t\t\t\t},\n\t\t\t\t\t}}\n\t\t\t\t\tonCloseToast={() => setUndo(null)}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</>\n\t);\n};\n"],"names":["SUBAGENT_ZINDEX","TOOL_DRAWER_ZINDEX","upsertById","list","item","arr","x","ImproveButton","styled","COLORS","CreateSubAgentPanel","onClose","onSave","availableTools","onImprove","onImproveToolInstructions","configToolTemplates","integrationStatus","onConnectIntegration","title","initial","existingNames","appLabel","charLimits","AGENT_CHAR_LIMITS","variablesData","element","footerDirection","name","setName","useState","instructions","setInstructions","guardrail","setGuardrail","tools","setTools","configTools","setConfigTools","restApiTools","setRestApiTools","toolDrawer","setToolDrawer","toolDrawerKeyRef","useRef","saving","setSaving","instrKey","setInstrKey","guardKey","setGuardKey","improving","setImproving","mentionItems","useMemo","buildAgentMentionItems","buildCustomToolMentionItems","insertersRef","lastFocusedRef","registerInstr","useCallback","fn","registerGuard","focusInstr","focusGuard","customToolIdsRef","t","addToolMention","kind","id","prev","addUnique","insertToolAtCursor","label","source","openRestApi","tool","openConfigTool","toolKey","openToolAction","key","CONFIG_TOOL_SOURCES","handleSaveRestApi","isNew","restApiMentionItem","ToolSource","handleSaveConfigTool","configToolMentionItem","CONFIG_TOOL_SOURCE_BY_KEY","undo","setUndo","undoSnapshotRef","undoIdRef","removeTool","token","strip","text","k","undoRemove","snap","nameTrimmed","isDuplicateName","n","canSave","toolItems","sourceIcon","restApiItems","restApiToolName","SOURCE_ICONS","configToolItems","configToolName","allToolItems","toolActionSources","buildToolActions","openConfigTemplate","toolOptions","renderSourceIcon","toolSourceGroups","order","bySource","src","outside","inside","partitionSources","a","shownOutside","groups","toolSourceLabel","INTEGRATIONS_KEY","INTEGRATIONS_LABEL","handleSave","result","handleImprove","improved","jsxs","Fragment","SideModal","jsx","DrawerHeaderText","DRAWER_HEADER_STYLE","DRAWER_BODY_STYLE","Input","MentionEditor","SelectableListSection","RestApiToolPanel","ConfigToolPanel","Toaster"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CreateSubAgentPanel.js","sources":["../../../../../src/components/agent-builder/components/CreateSubAgentPanel.tsx"],"sourcesContent":["import React, { useCallback, useMemo, useRef, useState } from 'react';\nimport styled from 'styled-components';\nimport { SingleOption } from '@src/components/dropdown/type';\nimport { Input } from '@src/components/input';\nimport { SideModal } from '@src/components/side-modal';\nimport { Toaster } from '@src/components/toaster';\nimport { addUnique } from '@src/utils/arrayUtils';\nimport { COLORS } from '@src/constants/Theme';\nimport type { VariableListInterfaceV3 } from '../../variable-picker-v3/model';\nimport {\n\tAgentTool,\n\tConfigToolConfig,\n\tConfigToolKey,\n\tParamsBlob,\n\tRestApiToolConfig,\n\tSubAgentDraft,\n} from '../AgentBuilder.model';\nimport { AGENT_CHAR_LIMITS } from '../constants/charLimits';\nimport type { AgentCharLimits } from '../constants/charLimits';\nimport {\n\tCONFIG_TOOL_SOURCE_BY_KEY,\n\tCONFIG_TOOL_SOURCES,\n\tINTEGRATIONS_KEY,\n\tINTEGRATIONS_LABEL,\n\tToolSource,\n} from '../constants/tools';\nimport {\n\tbuildAgentMentionItems,\n\tbuildCustomToolMentionItems,\n\tconfigToolMentionItem,\n\tconfigToolName,\n\trestApiMentionItem,\n\trestApiToolName,\n\ttoolSourceLabel,\n} from '../utils/mentionSerialization';\nimport { partitionSources } from '../utils/sourceGrouping';\nimport {\n\trenderSourceIcon,\n\tSOURCE_ICONS,\n\tsourceIcon,\n} from '../utils/sourceIcons';\nimport { buildToolActions } from '../utils/toolActions';\nimport { ConfigToolPanel } from './ConfigToolPanel';\nimport {\n\tDRAWER_BODY_STYLE,\n\tDRAWER_HEADER_STYLE,\n\tDrawerHeaderText,\n} from './DrawerHeaderText';\nimport { MentionEditor } from './MentionEditor';\nimport { RestApiToolPanel } from './RestApiToolPanel';\nimport {\n\tSelectableItem,\n\tSelectableListSection,\n\tSourceGroup,\n} from './SelectableListSection';\n\n/**\n * The sub-agent drawer sits above the main builder; its own tool drawers\n * (Rest API / email / Slack) stack one level higher so they open ON TOP of it\n * rather than behind (SideModal defaults to z-index 10).\n */\nconst SUBAGENT_ZINDEX = 1000;\nconst TOOL_DRAWER_ZINDEX = 1002;\n\n/** Upsert an item by id (replace when present, append otherwise). */\nconst upsertById = <T extends { id: string }>(\n\tlist: T[] | undefined,\n\titem: T,\n): T[] => {\n\tconst arr = list ?? [];\n\treturn arr.some((x) => x.id === item.id)\n\t\t? arr.map((x) => (x.id === item.id ? item : x))\n\t\t: [...arr, item];\n};\n\n/** Config-tool / Rest API drawer state; `key` remounts fresh per open. */\ninterface ToolDrawerState {\n\tkey: number;\n\tkind: 'restapi' | 'config';\n\ttoolKey?: ConfigToolKey;\n\tinitialRest?: RestApiToolConfig;\n\tinitialConfig?: ConfigToolConfig;\n}\n\n/** Inline \"Improve with AI\" action rendered below a mention editor. */\nconst ImproveButton = styled.button`\n\talign-self: flex-start;\n\tborder: 1px solid ${COLORS.stroke.primary};\n\tcolor: ${COLORS.content.primary};\n\tbackground: ${COLORS.surface.standard};\n\tborder-radius: 8px;\n\tpadding: 6px 12px;\n\tfont-size: 13px;\n\tline-height: 1.1;\n\tfont-weight: 600;\n\tcursor: pointer;\n\n\t&:disabled {\n\t\tcursor: default;\n\t\topacity: 0.6;\n\t}\n`;\n\ntype InsertFn = (\n\tkind: 'tool' | 'subagent',\n\tid: string,\n\tlabel?: string,\n\tsource?: string,\n) => void;\n\ninterface CreateSubAgentPanelProps {\n\tonClose: () => void;\n\t/** Persist the draft. The drawer shows a loader while the returned promise is pending. */\n\tonSave: (draft: SubAgentDraft) => void | Promise<void>;\n\tavailableTools: AgentTool[];\n\t/** Optional \"Improve with AI\" for instructions / guardrails. Omit to hide the buttons. */\n\tonImprove?: (\n\t\tkind: 'instructions' | 'guardrail',\n\t\ttext: string,\n\t) => Promise<string>;\n\t/** Optional \"Improve with AI\" for the Rest API / config-tool drawers. */\n\tonImproveToolInstructions?: (text: string) => Promise<string>;\n\t/**\n\t * Backend templates (email / Slack) that drive the shared config-tool drawer.\n\t * Each present key enables its tool action in this drawer; absent → hidden.\n\t * Same prop the main builder gets — sub-agents can add the same tools.\n\t */\n\tconfigToolTemplates?: Partial<Record<ConfigToolKey, ParamsBlob>>;\n\t/**\n\t * Per-source integration connection state (today: Slack). A source mapped to\n\t * `false` shows a \"Connect\" affordance instead of drilling into its tools —\n\t * same gating the main builder's Step 3 tool section gets.\n\t */\n\tintegrationStatus?: Partial<Record<ToolSource, boolean>>;\n\t/** Open the consumer's connect flow for an unconnected integration source. */\n\tonConnectIntegration?: (source: ToolSource) => void;\n\t/** Header title — \"Create sub-agent\" (default) or \"Edit sub-agent\". */\n\ttitle?: string;\n\t/** Initial values, e.g. when configuring an existing sub-agent. */\n\tinitial?: SubAgentDraft;\n\t/**\n\t * Names of the other sub-agents already on this agent (exclude the one being\n\t * edited). Blocks saving a duplicate name — the LLM references sub-agents by it.\n\t */\n\texistingNames?: string[];\n\t/** Tool-source fallback label for chips (host app). */\n\tappLabel?: string;\n\t/** Resolved character limits (defaults to {@link AGENT_CHAR_LIMITS}). */\n\tcharLimits?: AgentCharLimits;\n\t/** Variable catalog for the editors' `@` picker \"Variables\" view. */\n\tvariablesData?: VariableListInterfaceV3[];\n}\n\n/**\n * Right-side drawer for creating / editing a sub-agent (name, instructions,\n * guardrails, tools). Instructions & Guardrails are `@`-mention editors (tools\n * only — sub-agents can't nest); adding a tool from the list inserts it at the\n * last-focused field's cursor. Mount it fresh per open (key it) so `initial`\n * seeds the draft.\n */\nexport const CreateSubAgentPanel: React.FC<CreateSubAgentPanelProps> = ({\n\tonClose,\n\tonSave,\n\tavailableTools,\n\tonImprove,\n\tonImproveToolInstructions,\n\tconfigToolTemplates,\n\tintegrationStatus,\n\tonConnectIntegration,\n\ttitle = 'Create sub-agent',\n\tinitial,\n\texistingNames = [],\n\tappLabel = 'Manifest',\n\tcharLimits = AGENT_CHAR_LIMITS,\n\tvariablesData,\n}) => {\n\tconst [name, setName] = useState(initial?.name ?? '');\n\tconst [instructions, setInstructions] = useState(initial?.instructions ?? '');\n\tconst [guardrail, setGuardrail] = useState(initial?.guardrail ?? '');\n\tconst [tools, setTools] = useState<string[]>(initial?.tools ?? []);\n\t// Inline-configured tools owned by this sub-agent (same drawers as the main\n\t// agent). Local to the drawer; flow to the consumer via the saved draft.\n\tconst [configTools, setConfigTools] = useState<ConfigToolConfig[]>(\n\t\tinitial?.configTools ?? [],\n\t);\n\tconst [restApiTools, setRestApiTools] = useState<RestApiToolConfig[]>(\n\t\tinitial?.restApiTools ?? [],\n\t);\n\tconst [toolDrawer, setToolDrawer] = useState<ToolDrawerState | null>(null);\n\tconst toolDrawerKeyRef = useRef(0);\n\tconst [saving, setSaving] = useState(false);\n\t// Bumped to remount a field after its text is replaced (e.g. by Improve).\n\tconst [instrKey, setInstrKey] = useState(0);\n\tconst [guardKey, setGuardKey] = useState(0);\n\tconst [improving, setImproving] = useState<\n\t\t'instructions' | 'guardrail' | null\n\t>(null);\n\n\t// Tools-only mention list (sub-agents can't reference other sub-agents), PLUS\n\t// this drawer's inline custom tools so their `{{tool:<id>}}` tokens rehydrate\n\t// as chips on remount (they aren't in `availableTools`).\n\tconst mentionItems = useMemo(\n\t\t() => [\n\t\t\t...buildAgentMentionItems(availableTools, [], appLabel),\n\t\t\t...buildCustomToolMentionItems(configTools, restApiTools),\n\t\t],\n\t\t[availableTools, appLabel, configTools, restApiTools],\n\t);\n\n\t// Per-field insert + focus registry, so the Tools list inserts a chip into the\n\t// last-focused editor at its cursor.\n\tconst insertersRef = useRef<\n\t\tPartial<Record<'instructions' | 'guardrail', InsertFn>>\n\t>({});\n\tconst lastFocusedRef = useRef<'instructions' | 'guardrail'>('instructions');\n\tconst registerInstr = useCallback((fn: InsertFn | null) => {\n\t\tinsertersRef.current.instructions = fn ?? undefined;\n\t}, []);\n\tconst registerGuard = useCallback((fn: InsertFn | null) => {\n\t\tinsertersRef.current.guardrail = fn ?? undefined;\n\t}, []);\n\tconst focusInstr = useCallback(() => {\n\t\tlastFocusedRef.current = 'instructions';\n\t}, []);\n\tconst focusGuard = useCallback(() => {\n\t\tlastFocusedRef.current = 'guardrail';\n\t}, []);\n\t// Latest custom-tool ids, readable from the mount-captured `@` onSelect handler\n\t// (BikEditor captures it once) — mirrors the context's valueRef trick.\n\tconst customToolIdsRef = useRef<Set<string>>(new Set());\n\tcustomToolIdsRef.current = new Set(\n\t\t[...configTools, ...restApiTools].map((t) => t.id),\n\t);\n\tconst addToolMention = useCallback(\n\t\t(kind: 'tool' | 'subagent', id: string) => {\n\t\t\t// Only catalog tool ids belong in `tools`; custom tools (Rest API / email /\n\t\t\t// Slack) track themselves on their own lists. Picking an existing custom\n\t\t\t// tool from `@` must not leak its id in as a bogus native ref.\n\t\t\tif (kind === 'tool' && !customToolIdsRef.current.has(id)) {\n\t\t\t\tsetTools((prev) => addUnique(prev, id));\n\t\t\t}\n\t\t},\n\t\t[],\n\t);\n\tconst insertToolAtCursor = useCallback(\n\t\t(id: string, label?: string, source?: string) => {\n\t\t\tconst target =\n\t\t\t\tinsertersRef.current[lastFocusedRef.current] ??\n\t\t\t\tinsertersRef.current.instructions;\n\t\t\ttarget?.('tool', id, label, source);\n\t\t},\n\t\t[],\n\t);\n\n\t// Rest API (bespoke) + shared config-tool (email / Slack) drawers, same as the\n\t// main builder's Step 3 — here backed by the drawer's local state.\n\t// ponytail: mirrors Step3HowItResponds; kept local rather than sharing a hook\n\t// because Step3 is context-backed and this drawer is local-state.\n\tconst openRestApi = useCallback((tool?: RestApiToolConfig) => {\n\t\ttoolDrawerKeyRef.current += 1;\n\t\tsetToolDrawer({\n\t\t\tkey: toolDrawerKeyRef.current,\n\t\t\tkind: 'restapi',\n\t\t\tinitialRest: tool,\n\t\t});\n\t}, []);\n\tconst openConfigTool = useCallback(\n\t\t(toolKey: ConfigToolKey, tool?: ConfigToolConfig) => {\n\t\t\ttoolDrawerKeyRef.current += 1;\n\t\t\tsetToolDrawer({\n\t\t\t\tkey: toolDrawerKeyRef.current,\n\t\t\t\tkind: 'config',\n\t\t\t\ttoolKey,\n\t\t\t\tinitialConfig: tool,\n\t\t\t});\n\t\t},\n\t\t[],\n\t);\n\tconst openToolAction = useCallback(\n\t\t(source: ToolSource, toolKey?: ConfigToolKey) => {\n\t\t\tconst key = toolKey ?? CONFIG_TOOL_SOURCES[source]?.[0];\n\t\t\tif (key) {\n\t\t\t\topenConfigTool(key);\n\t\t\t} else {\n\t\t\t\topenRestApi();\n\t\t\t}\n\t\t},\n\t\t[openConfigTool, openRestApi],\n\t);\n\tconst handleSaveRestApi = useCallback(\n\t\t(tool: RestApiToolConfig) => {\n\t\t\tconst isNew = !restApiTools.some((t) => t.id === tool.id);\n\t\t\tsetRestApiTools((prev) => upsertById(prev, tool));\n\t\t\t// Drop a reference chip at the cursor on creation (edits keep the chip).\n\t\t\t// Pass the source so the fresh chip shows its icon (not yet in the list).\n\t\t\tif (isNew) {\n\t\t\t\tinsertToolAtCursor(\n\t\t\t\t\ttool.id,\n\t\t\t\t\trestApiMentionItem(tool).label,\n\t\t\t\t\tToolSource.RestApi,\n\t\t\t\t);\n\t\t\t}\n\t\t\tsetToolDrawer(null);\n\t\t},\n\t\t[restApiTools, insertToolAtCursor],\n\t);\n\tconst handleSaveConfigTool = useCallback(\n\t\t(tool: ConfigToolConfig) => {\n\t\t\tconst isNew = !configTools.some((t) => t.id === tool.id);\n\t\t\tsetConfigTools((prev) => upsertById(prev, tool));\n\t\t\tif (isNew) {\n\t\t\t\tinsertToolAtCursor(\n\t\t\t\t\ttool.id,\n\t\t\t\t\tconfigToolMentionItem(tool).label,\n\t\t\t\t\tCONFIG_TOOL_SOURCE_BY_KEY[tool.tool_key],\n\t\t\t\t);\n\t\t\t}\n\t\t\tsetToolDrawer(null);\n\t\t},\n\t\t[configTools, insertToolAtCursor],\n\t);\n\n\t// Local undo toast for tool removal (drawer state isn't in AgentValue).\n\tconst [undo, setUndo] = useState<{ id: number; message: string } | null>(\n\t\tnull,\n\t);\n\tconst undoSnapshotRef = useRef<{\n\t\tinstructions: string;\n\t\tguardrail: string;\n\t\ttools: string[];\n\t\tconfigTools: ConfigToolConfig[];\n\t\trestApiTools: RestApiToolConfig[];\n\t} | null>(null);\n\tconst undoIdRef = useRef(0);\n\n\t// Remove ANY tool by id: strip its `{{tool:<id>}}` tokens, remount the fields,\n\t// and drop it from whichever list holds it (catalog `tools` or an inline\n\t// custom-tool list). One undo restores all of it.\n\tconst removeTool = (id: string) => {\n\t\tconst label =\n\t\t\tavailableTools.find((t) => t.tool_id === id)?.display_name ??\n\t\t\trestApiTools.find((t) => t.id === id)?.name ??\n\t\t\t'Tool';\n\t\t// The token stores the tool id (a tool's id is its tool_id).\n\t\tconst token = `{{tool:${id}}}`;\n\t\tconst strip = (text: string) => text.split(token).join('');\n\t\tundoSnapshotRef.current = {\n\t\t\tinstructions,\n\t\t\tguardrail,\n\t\t\ttools,\n\t\t\tconfigTools,\n\t\t\trestApiTools,\n\t\t};\n\t\tsetInstructions((prev) => strip(prev));\n\t\tsetGuardrail((prev) => strip(prev));\n\t\tsetTools((prev) => prev.filter((t) => t !== id));\n\t\tsetConfigTools((prev) => prev.filter((t) => t.id !== id));\n\t\tsetRestApiTools((prev) => prev.filter((t) => t.id !== id));\n\t\tsetInstrKey((k) => k + 1);\n\t\tsetGuardKey((k) => k + 1);\n\t\tundoIdRef.current += 1;\n\t\tsetUndo({ id: undoIdRef.current, message: `Tool \"${label}\" removed` });\n\t};\n\n\tconst undoRemove = () => {\n\t\tconst snap = undoSnapshotRef.current;\n\t\tif (snap) {\n\t\t\tsetInstructions(snap.instructions);\n\t\t\tsetGuardrail(snap.guardrail);\n\t\t\tsetTools(snap.tools);\n\t\t\tsetConfigTools(snap.configTools);\n\t\t\tsetRestApiTools(snap.restApiTools);\n\t\t\tsetInstrKey((k) => k + 1);\n\t\t\tsetGuardKey((k) => k + 1);\n\t\t\tundoSnapshotRef.current = null;\n\t\t}\n\t\tsetUndo(null);\n\t};\n\n\tconst nameTrimmed = name.trim();\n\t// Case-insensitive: two sub-agents on the same agent can't share a name (the\n\t// LLM references them by it) — mirrors the Rest API tool-name check.\n\tconst isDuplicateName =\n\t\tnameTrimmed.length > 0 &&\n\t\texistingNames.some(\n\t\t\t(n) => n.trim().toLowerCase() === nameTrimmed.toLowerCase(),\n\t\t);\n\tconst canSave =\n\t\tnameTrimmed.length > 0 &&\n\t\t!isDuplicateName &&\n\t\t(instructions.trim().length > 0 || guardrail.trim().length > 0);\n\n\tconst toolItems: SelectableItem[] = tools\n\t\t.map((id): SelectableItem | null => {\n\t\t\tconst tool = availableTools.find((t) => t.tool_id === id);\n\t\t\treturn tool\n\t\t\t\t? {\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tlabel: tool.display_name,\n\t\t\t\t\t\ticon: sourceIcon(tool.source ?? ToolSource.Manifest),\n\t\t\t\t\t\t// Shield flags a tool that needs customer verification, same as\n\t\t\t\t\t\t// the main builder's Step 3 tool rows.\n\t\t\t\t\t\tauthRequired: tool.auth_required,\n\t\t\t\t }\n\t\t\t\t: null;\n\t\t})\n\t\t.filter((x): x is SelectableItem => x !== null);\n\n\t// Inline-configured tools (Rest API + email / Slack) render as rows in the same\n\t// list, each with its own Configure (edit) action that reopens its drawer.\n\tconst restApiItems: SelectableItem[] = restApiTools.map((t) => ({\n\t\tid: t.id,\n\t\tlabel: restApiToolName(t),\n\t\ticon: SOURCE_ICONS[ToolSource.RestApi],\n\t\tonConfigure: () => openRestApi(t),\n\t}));\n\tconst configToolItems: SelectableItem[] = configTools.map((t) => ({\n\t\tid: t.id,\n\t\tlabel: configToolName(t),\n\t\ticon: SOURCE_ICONS[\n\t\t\tt.tool_key === 'send_slack_message'\n\t\t\t\t? ToolSource.Slack\n\t\t\t\t: ToolSource.EmailHandover\n\t\t],\n\t\tonConfigure: () => openConfigTool(t.tool_key, t),\n\t}));\n\tconst allToolItems: SelectableItem[] = [\n\t\t...toolItems,\n\t\t...restApiItems,\n\t\t...configToolItems,\n\t];\n\n\t// Built-in tool actions (Rest API / email / Slack); the shared email / Slack\n\t// forms appear only when their backend template was provided. Integration\n\t// state drives the \"Connect\" affordance, same as the main builder's Step 3.\n\tconst toolActionSources = buildToolActions(\n\t\tconfigToolTemplates,\n\t\topenToolAction,\n\t\tintegrationStatus,\n\t\tonConnectIntegration,\n\t);\n\n\tconst openConfigTemplate =\n\t\ttoolDrawer?.kind === 'config' && toolDrawer.toolKey\n\t\t\t? configToolTemplates?.[toolDrawer.toolKey]\n\t\t\t: undefined;\n\n\t// Offer all tools (re-add allowed); the chip list stays deduped. Icon left of\n\t// the name, no description.\n\tconst toolOptions: SingleOption[] = availableTools.map((t) => ({\n\t\tlabel: t.display_name,\n\t\tvalue: t.tool_id,\n\t\tleadingIcon:\n\t\t\trenderSourceIcon(sourceIcon(t.source ?? ToolSource.Manifest)) ??\n\t\t\tundefined,\n\t}));\n\n\t// Group tools by source (Manifest / Shopify / …) so the empty state shows the\n\t// same per-source buttons as the main builder's side panel.\n\tconst toolSourceGroups: SourceGroup[] = (() => {\n\t\tconst order: string[] = [];\n\t\tconst bySource = new Map<string, SingleOption[]>();\n\t\tavailableTools.forEach((t) => {\n\t\t\tconst src = t.source ?? ToolSource.Manifest;\n\t\t\tif (!bySource.has(src)) {\n\t\t\t\tbySource.set(src, []);\n\t\t\t\torder.push(src);\n\t\t\t}\n\t\t\tbySource.get(src)?.push({\n\t\t\t\tlabel: t.display_name,\n\t\t\t\tvalue: t.tool_id,\n\t\t\t\tleadingIcon:\n\t\t\t\t\trenderSourceIcon(sourceIcon(t.source ?? ToolSource.Manifest)) ??\n\t\t\t\t\tundefined,\n\t\t\t});\n\t\t});\n\t\t// Same rule as the `@` picker: a source the store hasn't connected doesn't\n\t\t// get its own button — they all collapse into one \"Integrations\" button that\n\t\t// opens the picker on that group (SelectableListSection deep-links a source\n\t\t// button straight into the picker, and the umbrella key works like any other\n\t\t// source there). Action sources join the split too: Slack has no catalog\n\t\t// tools of its own, so without them an unconnected Slack would have nowhere\n\t\t// to live.\n\t\tconst { outside, inside } = partitionSources(\n\t\t\t[...order, ...toolActionSources.map((a) => a.source)],\n\t\t\tintegrationStatus,\n\t\t);\n\t\tconst shownOutside = new Set(outside);\n\t\tconst groups: SourceGroup[] = order\n\t\t\t.filter((src) => shownOutside.has(src))\n\t\t\t.map((src) => ({\n\t\t\t\tsource: src,\n\t\t\t\tlabel: toolSourceLabel(src, appLabel),\n\t\t\t\toptions: bySource.get(src) ?? [],\n\t\t\t\t// Reachable only when connected or ungated, so no connect flow needed —\n\t\t\t\t// kept for the picker's own gating, which reads these groups.\n\t\t\t\tconnected: integrationStatus?.[src as ToolSource],\n\t\t\t\tonConnect: () => onConnectIntegration?.(src as ToolSource),\n\t\t\t}));\n\t\tif (inside.length > 0) {\n\t\t\tgroups.push({\n\t\t\t\tsource: INTEGRATIONS_KEY,\n\t\t\t\tlabel: INTEGRATIONS_LABEL,\n\t\t\t\t// No options of its own: clicking opens the picker at the umbrella,\n\t\t\t\t// where each unconnected source offers \"Connect\".\n\t\t\t\toptions: [],\n\t\t\t});\n\t\t}\n\t\treturn groups;\n\t})();\n\n\tconst handleSave = async () => {\n\t\tif (!canSave || saving) {\n\t\t\treturn;\n\t\t}\n\t\tconst result = onSave({\n\t\t\tname: name.trim(),\n\t\t\tinstructions,\n\t\t\tguardrail,\n\t\t\ttools,\n\t\t\tconfigTools,\n\t\t\trestApiTools,\n\t\t});\n\t\tif (result && typeof (result as Promise<void>).then === 'function') {\n\t\t\tsetSaving(true);\n\t\t\ttry {\n\t\t\t\tawait result;\n\t\t\t} finally {\n\t\t\t\tsetSaving(false);\n\t\t\t}\n\t\t}\n\t};\n\n\tconst handleImprove = async (kind: 'instructions' | 'guardrail') => {\n\t\tif (!onImprove || improving) {\n\t\t\treturn;\n\t\t}\n\t\tsetImproving(kind);\n\t\ttry {\n\t\t\tconst current = kind === 'instructions' ? instructions : guardrail;\n\t\t\tconst improved = await onImprove(kind, current);\n\t\t\tif (kind === 'instructions') {\n\t\t\t\tsetInstructions(improved);\n\t\t\t\tsetInstrKey((k) => k + 1);\n\t\t\t} else {\n\t\t\t\tsetGuardrail(improved);\n\t\t\t\tsetGuardKey((k) => k + 1);\n\t\t\t}\n\t\t} finally {\n\t\t\tsetImproving(null);\n\t\t}\n\t};\n\n\treturn (\n\t\t<>\n\t\t\t<SideModal\n\t\t\t\theader={title}\n\t\t\t\tcloseOnEscapeKey={false}\n\t\t\t\tzIndex={SUBAGENT_ZINDEX}\n\t\t\t\theaderCustomComponent={\n\t\t\t\t\t<DrawerHeaderText\n\t\t\t\t\t\ttitle={title}\n\t\t\t\t\t\tsubtitle=\"Each sub-agent handles one piece of the job. Use @ in the main instructions to call them.\"\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t\twidth=\"421px\"\n\t\t\t\theaderStyle={DRAWER_HEADER_STYLE}\n\t\t\t\tbodyStyle={DRAWER_BODY_STYLE}\n\t\t\t\tonClose={onClose}\n\t\t\t\tsaveButtonProps={{\n\t\t\t\t\t'data-test': 'subagent-save',\n\t\t\t\t\tbuttonText: 'Save',\n\t\t\t\t\tbuttonType: 'primary',\n\t\t\t\t\tsize: 'small',\n\t\t\t\t\tdisabled: !canSave,\n\t\t\t\t\tisLoading: saving,\n\t\t\t\t\tonClick: handleSave,\n\t\t\t\t}}\n\t\t\t\tcancelButtonProps={{\n\t\t\t\t\t'data-test': 'subagent-cancel',\n\t\t\t\t\tbuttonText: 'Cancel',\n\t\t\t\t\tbuttonType: 'tertiaryGray',\n\t\t\t\t\tsize: 'small',\n\t\t\t\t\tonClick: onClose,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<Input\n\t\t\t\t\tdata-test=\"subagent-name\"\n\t\t\t\t\tlabelText=\"Agent name\"\n\t\t\t\t\tlabelTextBold\n\t\t\t\t\tplaceholder=\"Enter agent name\"\n\t\t\t\t\tvalue={name}\n\t\t\t\t\tmaxCharLimit={charLimits.name}\n\t\t\t\t\tmaxCharLimitPosition=\"TOP\"\n\t\t\t\t\tmaxCharStyle={{ fontSize: 12, lineHeight: '16px' }}\n\t\t\t\t\tstate={isDuplicateName ? 'invalid' : undefined}\n\t\t\t\t\terrorMessage={\n\t\t\t\t\t\tisDuplicateName\n\t\t\t\t\t\t\t? 'A sub-agent with this name already exists'\n\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t}\n\t\t\t\t\tonChangeText={setName}\n\t\t\t\t/>\n\n\t\t\t\t<MentionEditor\n\t\t\t\t\tdata-test=\"subagent-instructions\"\n\t\t\t\t\tlabel=\"Instructions\"\n\t\t\t\t\tvalue={instructions}\n\t\t\t\t\tonChange={setInstructions}\n\t\t\t\t\tmaxLength={charLimits.instructions}\n\t\t\t\t\tplaceholder=\"Write the steps in plain English. The agent will follow them exactly. The more specific you are, the better it performs.\"\n\t\t\t\t\tminHeight=\"160px\"\n\t\t\t\t\tresetKey={`instr-${instrKey}`}\n\t\t\t\t\tmentionItems={mentionItems}\n\t\t\t\t\ttools={availableTools}\n\t\t\t\t\ttoolActions={toolActionSources}\n\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\taddDataButton\n\t\t\t\t\tintegrationStatus={integrationStatus}\n\t\t\t\t\tappLabel={appLabel}\n\t\t\t\t\tonConnectIntegration={onConnectIntegration}\n\t\t\t\t\tonMentionSelect={addToolMention}\n\t\t\t\t\tonFocus={focusInstr}\n\t\t\t\t\tregisterInsert={registerInstr}\n\t\t\t\t\taction={\n\t\t\t\t\t\tonImprove ? (\n\t\t\t\t\t\t\t<ImproveButton\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tdata-test=\"subagent-improve-instructions\"\n\t\t\t\t\t\t\t\tdisabled={improving !== null}\n\t\t\t\t\t\t\t\tonClick={() => handleImprove('instructions')}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{improving === 'instructions'\n\t\t\t\t\t\t\t\t\t? 'Improving…'\n\t\t\t\t\t\t\t\t\t: 'Improve with AI'}\n\t\t\t\t\t\t\t</ImproveButton>\n\t\t\t\t\t\t) : undefined\n\t\t\t\t\t}\n\t\t\t\t/>\n\n\t\t\t\t<MentionEditor\n\t\t\t\t\tdata-test=\"subagent-guardrail\"\n\t\t\t\t\tlabel=\"Guardrails\"\n\t\t\t\t\tvalue={guardrail}\n\t\t\t\t\tonChange={setGuardrail}\n\t\t\t\t\tmaxLength={charLimits.guardrail}\n\t\t\t\t\tplaceholder=\"e.g. Never discuss competitor pricing. Always stay within the cancellation policy. Do not process refunds above ₹10,000 without human approval.\"\n\t\t\t\t\tminHeight=\"160px\"\n\t\t\t\t\tresetKey={`guard-${guardKey}`}\n\t\t\t\t\tmentionItems={mentionItems}\n\t\t\t\t\ttools={availableTools}\n\t\t\t\t\ttoolActions={toolActionSources}\n\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\taddDataButton\n\t\t\t\t\tintegrationStatus={integrationStatus}\n\t\t\t\t\tappLabel={appLabel}\n\t\t\t\t\tonConnectIntegration={onConnectIntegration}\n\t\t\t\t\tonMentionSelect={addToolMention}\n\t\t\t\t\tonFocus={focusGuard}\n\t\t\t\t\tregisterInsert={registerGuard}\n\t\t\t\t\taction={\n\t\t\t\t\t\tonImprove ? (\n\t\t\t\t\t\t\t<ImproveButton\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tdata-test=\"subagent-improve-guardrail\"\n\t\t\t\t\t\t\t\tdisabled={improving !== null}\n\t\t\t\t\t\t\t\tonClick={() => handleImprove('guardrail')}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{improving === 'guardrail' ? 'Improving…' : 'Improve with AI'}\n\t\t\t\t\t\t\t</ImproveButton>\n\t\t\t\t\t\t) : undefined\n\t\t\t\t\t}\n\t\t\t\t/>\n\n\t\t\t\t<SelectableListSection\n\t\t\t\t\ttitle=\"Tools this agent can use\"\n\t\t\t\t\tdataTestPrefix=\"subagent-tools\"\n\t\t\t\t\titems={allToolItems}\n\t\t\t\t\taddableOptions={toolOptions}\n\t\t\t\t\tsourceGroups={toolSourceGroups}\n\t\t\t\t\tintegrationStatus={integrationStatus}\n\t\t\t\t\tonConnectIntegration={(source) =>\n\t\t\t\t\t\tonConnectIntegration?.(source as ToolSource)\n\t\t\t\t\t}\n\t\t\t\t\tmentionItems={mentionItems}\n\t\t\t\t\tactionSources={toolActionSources}\n\t\t\t\t\temptyText=\"No tools added yet.\"\n\t\t\t\t\tappLabel={appLabel}\n\t\t\t\t\tpickerOpensUp\n\t\t\t\t\tonAdd={(id) => {\n\t\t\t\t\t\tinsertToolAtCursor(id);\n\t\t\t\t\t\tsetTools((prev) => addUnique(prev, id));\n\t\t\t\t\t}}\n\t\t\t\t\tonRemove={removeTool}\n\t\t\t\t\tconfirmDelete={{ noun: 'tool', zIndex: TOOL_DRAWER_ZINDEX + 1 }}\n\t\t\t\t/>\n\t\t\t</SideModal>\n\n\t\t\t{toolDrawer?.kind === 'restapi' && (\n\t\t\t\t<RestApiToolPanel\n\t\t\t\t\tkey={toolDrawer.key}\n\t\t\t\t\tinitial={toolDrawer.initialRest}\n\t\t\t\t\tcharLimits={charLimits}\n\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\tonImprove={onImproveToolInstructions}\n\t\t\t\t\tonClose={() => setToolDrawer(null)}\n\t\t\t\t\tonSave={handleSaveRestApi}\n\t\t\t\t\tzIndex={TOOL_DRAWER_ZINDEX}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t{toolDrawer?.kind === 'config' &&\n\t\t\t\ttoolDrawer.toolKey &&\n\t\t\t\topenConfigTemplate && (\n\t\t\t\t\t<ConfigToolPanel\n\t\t\t\t\t\tkey={toolDrawer.key}\n\t\t\t\t\t\ttoolKey={toolDrawer.toolKey}\n\t\t\t\t\t\ttemplate={openConfigTemplate}\n\t\t\t\t\t\tinitial={toolDrawer.initialConfig}\n\t\t\t\t\t\tcharLimits={charLimits}\n\t\t\t\t\t\tvariablesData={variablesData}\n\t\t\t\t\t\tonImprove={onImproveToolInstructions}\n\t\t\t\t\t\tonClose={() => setToolDrawer(null)}\n\t\t\t\t\t\tonSave={handleSaveConfigTool}\n\t\t\t\t\t\tzIndex={TOOL_DRAWER_ZINDEX}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\n\t\t\t{undo && (\n\t\t\t\t<Toaster\n\t\t\t\t\tkey={undo.id}\n\t\t\t\t\ttext={undo.message}\n\t\t\t\t\ttype=\"info\"\n\t\t\t\t\tposition=\"top-right\"\n\t\t\t\t\tautoClose={5000}\n\t\t\t\t\thideCloseButton\n\t\t\t\t\tbuttonProps={{\n\t\t\t\t\t\tbuttonText: 'Undo',\n\t\t\t\t\t\tshowButton: true,\n\t\t\t\t\t\tonButtonClick: () => {\n\t\t\t\t\t\t\tundoRemove();\n\t\t\t\t\t\t\treturn {} as Record<string, never>;\n\t\t\t\t\t\t},\n\t\t\t\t\t}}\n\t\t\t\t\tonCloseToast={() => setUndo(null)}\n\t\t\t\t/>\n\t\t\t)}\n\t\t</>\n\t);\n};\n"],"names":["SUBAGENT_ZINDEX","TOOL_DRAWER_ZINDEX","upsertById","list","item","arr","x","ImproveButton","styled","COLORS","CreateSubAgentPanel","onClose","onSave","availableTools","onImprove","onImproveToolInstructions","configToolTemplates","integrationStatus","onConnectIntegration","title","initial","existingNames","appLabel","charLimits","AGENT_CHAR_LIMITS","variablesData","name","setName","useState","instructions","setInstructions","guardrail","setGuardrail","tools","setTools","configTools","setConfigTools","restApiTools","setRestApiTools","toolDrawer","setToolDrawer","toolDrawerKeyRef","useRef","saving","setSaving","instrKey","setInstrKey","guardKey","setGuardKey","improving","setImproving","mentionItems","useMemo","buildAgentMentionItems","buildCustomToolMentionItems","insertersRef","lastFocusedRef","registerInstr","useCallback","fn","registerGuard","focusInstr","focusGuard","customToolIdsRef","t","addToolMention","kind","id","prev","addUnique","insertToolAtCursor","label","source","openRestApi","tool","openConfigTool","toolKey","openToolAction","key","CONFIG_TOOL_SOURCES","handleSaveRestApi","isNew","restApiMentionItem","ToolSource","handleSaveConfigTool","configToolMentionItem","CONFIG_TOOL_SOURCE_BY_KEY","undo","setUndo","undoSnapshotRef","undoIdRef","removeTool","token","strip","text","k","undoRemove","snap","nameTrimmed","isDuplicateName","n","canSave","toolItems","sourceIcon","restApiItems","restApiToolName","SOURCE_ICONS","configToolItems","configToolName","allToolItems","toolActionSources","buildToolActions","openConfigTemplate","toolOptions","renderSourceIcon","toolSourceGroups","order","bySource","src","outside","inside","partitionSources","a","shownOutside","groups","toolSourceLabel","INTEGRATIONS_KEY","INTEGRATIONS_LABEL","handleSave","result","handleImprove","improved","jsxs","Fragment","SideModal","jsx","DrawerHeaderText","DRAWER_HEADER_STYLE","DRAWER_BODY_STYLE","Input","MentionEditor","SelectableListSection","RestApiToolPanel","ConfigToolPanel","Toaster"],"mappings":"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"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),X=require("../../../assets/icons/delete.svg.js"),Z=require("../../../assets/icons/plus.svg.js"),a=require("react"),ee=require("styled-components"),u=require("../../TypographyStyle.js"),l=require("../../../constants/Theme.js"),p=require("../AgentBuilder.styled.js"),te=require("../constants/charLimits.js"),C=require("./DrawerHeaderText.js"),re=require("./ToolInstructionsField.js"),A=require("./VariableInlineField.js"),se=require("../../side-modal/SideModal.js"),_=require("../../input/Input.js"),ne=require("../../dropdown/Dropdown.js"),ae=require("../../dropdown/utils.js"),oe=require("../../button/Button.js"),D=require("../../../editor/BikEditor.js"),le=s=>s&&typeof s=="object"&&"default"in s?s:{default:s},j=le(ee),ie=["GET","POST","PUT","PATCH","DELETE"],de=ie.map(s=>({label:s,value:s})),ce=s=>{if(!/^https?:\/\//i.test(s))return!1;let i;try{i=new URL(s).hostname}catch{return!1}return i.includes(".")&&!i.startsWith(".")&&!i.endsWith(".")},ue=({onClose:s,onSave:i,initial:o,onImprove:P,charLimits:m=te.AGENT_CHAR_LIMITS,zIndex:F,existingNames:M=[],variablesData:x})=>{const[y,U]=a.useState(o?.name??""),[S,N]=a.useState(o?.instructions??""),[f,V]=a.useState(o?.url??"https://"),[T,W]=a.useState(o?.method??"POST"),[O,g]=a.useState(o?.headers??[{key:"",value:""}]),[q,z]=a.useState(o?.requestBody??""),[L,J]=a.useState(o?.responseSample??""),[I,k]=a.useState(!1),d=a.useRef((o?.headers??[{key:"",value:""}]).map((t,r)=>r)),B=a.useRef(d.current.length),H=(t,r)=>g(n=>n.map((h,Q)=>Q===t?{...h,...r}:h)),$=()=>{d.current=[...d.current,B.current],B.current+=1,g(t=>[...t,{key:"",value:""}])},G=t=>{d.current=d.current.filter((r,n)=>n!==t),g(r=>r.filter((n,h)=>h!==t))},R=y.trim(),v=R.length>0&&M.some(t=>t.trim().toLowerCase()===R.toLowerCase()),c=f.trim(),w=c.includes("{{variable:")?/^https?:\/\/./.test(c):ce(c),Y=c.length>0&&c!=="https://"&&!w,E=R.length>0&&w&&!v&&S.length<=m.instructions,K=async()=>{if(!E||I)return;const t={id:o?.id??`restapi_${Date.now().toString(36)}`,name:y.trim(),instructions:S,url:f.trim(),method:T,headers:O.filter(n=>n.key.trim()||n.value.trim()),requestBody:q,responseSample:L},r=i(t);if(r&&typeof r.then=="function"){k(!0);try{await r}finally{k(!1)}}};return e.jsxs(se.SideModal,{header:"Rest API",closeOnEscapeKey:!1,zIndex:F,headerCustomComponent:e.jsx(C.DrawerHeaderText,{title:"Rest API",subtitle:"Connect to any API endpoint. Define the request and a sample response for the agent to reference."}),width:"431px",headerStyle:C.DRAWER_HEADER_STYLE,bodyStyle:C.DRAWER_BODY_STYLE,onClose:s,saveButtonProps:{"data-test":"restapi-save",buttonText:"Save",buttonType:"primary",size:"small",disabled:!E,isLoading:I,onClick:K},cancelButtonProps:{"data-test":"restapi-cancel",buttonText:"Cancel",buttonType:"tertiaryGray",size:"small",onClick:s},children:[e.jsx(_.Input,{"data-test":"restapi-name",variant:"small",labelText:"Name",labelTextBold:!0,placeholder:"Enter action name",value:y,maxCharLimit:m.name,state:v?"invalid":void 0,errorMessage:v?"A tool with this name already exists":void 0,onChangeText:U}),e.jsx(re.ToolInstructionsField,{"data-test":"restapi-instructions",label:"Instructions",value:S,onChange:N,maxLength:m.instructions,placeholder:"Describe how should the LLM generate the rest API",onImprove:P,variablesData:x}),e.jsxs(p.FieldBlock,{children:[e.jsx(A.VariableInlineField,{"data-test":"restapi-url",label:"Request URL",placeholder:"https://",value:f,onChange:V,variablesData:x}),Y&&e.jsx(u.BodyCaption,{color:l.COLORS.content.negative,children:"Enter a valid URL (including https://)"})]}),e.jsxs(p.FieldBlock,{children:[e.jsx(u.TitleSmall,{color:l.COLORS.content.primary,children:"HTTP method"}),e.jsx(ne.Dropdown,{"data-test":"restapi-method",size:"small",width:"100%",dropdownWidth:"399px",options:de,defaultOptions:[{label:T,value:T}],onSelect:t=>{const r=ae.unwrapDropdownValue(t);r&&W(r)}})]}),e.jsxs(p.FieldBlock,{children:[e.jsx(u.TitleSmall,{color:l.COLORS.content.primary,children:"Headers"}),O.map((t,r)=>e.jsxs(pe,{"data-test":`restapi-header-${r}`,children:[e.jsx(_.Input,{variant:"small",hideInputHeader:!0,placeholder:"Enter name",value:t.key,onChangeText:n=>H(r,{key:n})}),e.jsx(A.VariableInlineField,{placeholder:"Enter value",value:t.value,onChange:n=>H(r,{value:n}),variablesData:x}),e.jsx(me,{type:"button","aria-label":"Remove header","data-test":`restapi-header-remove-${r}`,onClick:()=>G(r),children:e.jsx(X.default,{width:16,height:16,color:l.COLORS.content.secondary})})]},d.current[r])),e.jsx(he,{children:e.jsx(oe.Button,{"data-test":"restapi-add-header",buttonType:"dashRegular",size:"small",LeadingIcon:Z.default,buttonText:"Add header",onClick:$})})]}),e.jsxs(p.FieldBlock,{children:[e.jsx(u.TitleSmall,{color:l.COLORS.content.primary,children:"Request "}),e.jsx(D.BikEditor,{features:{jsonMode:!0},initialContent:q,style:b,placeholder:"Type or paste JSON here",onChange:t=>z(t.text),minHeight:"120px",maxHeight:"240px"})]}),e.jsxs(p.FieldBlock,{children:[e.jsx(u.TitleSmall,{color:l.COLORS.content.primary,children:"Response "}),e.jsx(D.BikEditor,{features:{jsonMode:!0},style:b,initialContent:L,placeholder:"Type or paste JSON here",onChange:t=>J(t.text),minHeight:"120px",maxHeight:"240px"})]})]})},pe=j.default.div`
|
|
2
2
|
display: grid;
|
|
3
3
|
grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr) 32px;
|
|
4
4
|
align-items: center;
|
|
5
5
|
gap: 8px;
|
|
6
|
-
`,
|
|
6
|
+
`,he=j.default.div`
|
|
7
7
|
display: flex;
|
|
8
|
-
`,
|
|
8
|
+
`,me=j.default.button`
|
|
9
9
|
display: inline-flex;
|
|
10
10
|
align-items: center;
|
|
11
11
|
justify-content: center;
|
|
@@ -20,5 +20,5 @@
|
|
|
20
20
|
&:hover {
|
|
21
21
|
border-color: ${l.COLORS.content.secondary};
|
|
22
22
|
}
|
|
23
|
-
`,b={borderRadius:"4px",overflow:"hidden"};exports.JsonFieldBox=b;exports.RestApiToolPanel=
|
|
23
|
+
`,b={borderRadius:"4px",overflow:"hidden"};exports.JsonFieldBox=b;exports.RestApiToolPanel=ue;
|
|
24
24
|
//# sourceMappingURL=RestApiToolPanel.js.map
|