{ "of:baedreiahv63wxwgaem4hzjkizl4qncfgvca7pj5cvdon7cukumfon3ioye": { "application/json": { "ba4jcbh6lzzotnm42ta6zwopiqiq5lgo7dugaeoujgagwxidvxmujvw6c": { "is": { "value": [ { "/": { "link@1": { "path": [], "id": "of:baedreihffyh4263hchjbcx4vqsyctgf6frmgaryrflbdtkezhzzyn5itde", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, { "/": { "link@1": { "path": [], "id": "of:baedreibl64qzbhgkvpuxbfc657ugjeyidc62hixjybt5dpci2ddkkhs26m", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, { "/": { "link@1": { "path": [], "id": "of:baedreidvk42ywcn6n6ucdpfg2pvi5o6p3njkk6rltyvydkkbjcco5m4wcu", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, { "/": { "link@1": { "path": [], "id": "of:baedreibninu5twfm72l6gs5sbaghg6gdtmn2365encfoinebrvnsmavrr4", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, { "/": { "link@1": { "path": [], "id": "of:baedreibyolwzasa3njbwrwexvtolf7b7x5wh5lkwkepa5jbc6paghoc5ua", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, { "/": { "link@1": { "path": [], "id": "of:baedreigyxxqptxd2vlfwxnhzdwdha32i4ou5onzw6ruunaqudg5u42agva", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } } ] }, "since": 90 } } }, "of:baedreihffyh4263hchjbcx4vqsyctgf6frmgaryrflbdtkezhzzyn5itde": { "application/json": { "ba4jcbpoemlwuyl4oy3nf7ns7q4jzih2nzufd7pmroo6z6qscbmmonvz4": { "is": { "source": { "/": "baedreiaonvkt2jjlnav7hj7y6aknizkoxywahej6u4zqswof2jhe6yqtue" }, "value": { "$NAME": { "$alias": { "path": [ "internal", "$NAME" ], "cell": { "/": "baedreiaonvkt2jjlnav7hj7y6aknizkoxywahej6u4zqswof2jhe6yqtue" } } }, "$UI": { "type": "vnode", "name": "ct-screen", "props": { }, "children": [ { "type": "vnode", "name": "ct-keybind", "props": { "code": "KeyN", "alt": true, "preventDefault": true, "onct-keybind": { "$alias": { "path": [ "internal", "__#4stream" ], "schema": { "type": "object", "properties": { }, "additionalProperties": false }, "rootSchema": { "type": "object", "properties": { }, "additionalProperties": false }, "cell": { "/": "baedreiaonvkt2jjlnav7hj7y6aknizkoxywahej6u4zqswof2jhe6yqtue" } } } }, "children": [] }, { "type": "vnode", "name": "ct-vstack", "props": { "gap": "4", "padding": "6" }, "children": [ { "type": "vnode", "name": "ct-hstack", "props": { "gap": "2", "align": "center" }, "children": [ { "type": "vnode", "name": "h3", "props": { }, "children": [ "Quicklaunch:" ] }, { "type": "vnode", "name": "ct-button", "props": { "onClick": { "$alias": { "path": [ "internal", "$event" ], "schema": { "type": "object", "properties": { }, "additionalProperties": false }, "rootSchema": { "type": "object", "properties": { }, "additionalProperties": false }, "cell": { "/": "baedreiaonvkt2jjlnav7hj7y6aknizkoxywahej6u4zqswof2jhe6yqtue" } } } }, "children": [ "📂 Chat List" ] }, { "type": "vnode", "name": "ct-button", "props": { "onClick": { "$alias": { "path": [ "internal", "__#5stream" ], "schema": { "type": "object", "properties": { }, "additionalProperties": false }, "rootSchema": { "type": "object", "properties": { }, "additionalProperties": false }, "cell": { "/": "baedreiaonvkt2jjlnav7hj7y6aknizkoxywahej6u4zqswof2jhe6yqtue" } } } }, "children": [ "💬 Chatbot" ] }, { "type": "vnode", "name": "ct-button", "props": { "onClick": { "$alias": { "path": [ "internal", "__#0stream" ], "schema": { "type": "object", "properties": { }, "additionalProperties": false }, "rootSchema": { "type": "object", "properties": { }, "additionalProperties": false }, "cell": { "/": "baedreiaonvkt2jjlnav7hj7y6aknizkoxywahej6u4zqswof2jhe6yqtue" } } } }, "children": [ "📝 Chatbot Outliner" ] }, { "type": "vnode", "name": "ct-button", "props": { "onClick": { "$alias": { "path": [ "internal", "__#1stream" ], "schema": { "type": "object", "properties": { }, "additionalProperties": false }, "rootSchema": { "type": "object", "properties": { }, "additionalProperties": false }, "cell": { "/": "baedreiaonvkt2jjlnav7hj7y6aknizkoxywahej6u4zqswof2jhe6yqtue" } } } }, "children": [ "📄 Note" ] } ] }, { "type": "vnode", "name": "h2", "props": { }, "children": [ "Charms (", { "$alias": { "path": [ "internal", "__#2" ], "cell": { "/": "baedreiaonvkt2jjlnav7hj7y6aknizkoxywahej6u4zqswof2jhe6yqtue" } } }, ")" ] }, { "type": "vnode", "name": "ct-table", "props": { "full-width": true, "hover": true }, "children": [ { "type": "vnode", "name": "thead", "props": { }, "children": [ { "type": "vnode", "name": "tr", "props": { }, "children": [ { "type": "vnode", "name": "th", "props": { }, "children": [ "Charm Name" ] }, { "type": "vnode", "name": "th", "props": { }, "children": [ "Actions" ] } ] } ] }, { "type": "vnode", "name": "tbody", "props": { }, "children": [ { "$alias": { "path": [ "internal", "__#3" ], "cell": { "/": "baedreiaonvkt2jjlnav7hj7y6aknizkoxywahej6u4zqswof2jhe6yqtue" } } } ] } ] } ] } ] } } }, "since": 1 } } }, "of:baedreiaonvkt2jjlnav7hj7y6aknizkoxywahej6u4zqswof2jhe6yqtue": { "application/json": { "ba4jcbzc2lvlflhxcxxwnquxf2qtz3k56un573e2cyjzc23pmr4it7fkh": { "is": { "value": { "$TYPE": "ba4jcb4prfy3g4uxr7jnm6ci6jgyeuutzoqebdsbx5isxoiejvxyfp6am", "resultRef": { "/": { "link@1": { "path": [], "id": "of:baedreihffyh4263hchjbcx4vqsyctgf6frmgaryrflbdtkezhzzyn5itde" } } }, "internal": { "$event": { "$stream": true }, "__#0stream": { "$stream": true }, "__#1stream": { "$stream": true }, "__#4stream": { "$stream": true }, "__#5stream": { "$stream": true }, "$NAME": "DefaultCharmList (6)", "__#2": 6, "__#3": { "/": { "link@1": { "path": [], "id": "of:baedreieihgsgvlmhz43c4zozooeyokvkudejkntefpglpz3vwq5odsan2e" } } } }, "spell": { "/": { "link@1": { "id": "of:baedreiad5fq3onjttfqdd6ege2gfs5u4myvuimauebcwijlfpo2kxcouvy" } } }, "argument": { "allCharms": { "/": { "link@1": { "path": [], "id": "of:baedreiahv63wxwgaem4hzjkizl4qncfgvca7pj5cvdon7cukumfon3ioye", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } } } } }, "since": 94 } } }, "of:baedreiad5fq3onjttfqdd6ege2gfs5u4myvuimauebcwijlfpo2kxcouvy": { "application/json": { "ba4jcaptvazfqxe2zletz66l6dq2judrkw3cwrdfsgpawcyxstuouphnv": { "is": { "value": { "id": "ba4jcb4prfy3g4uxr7jnm6ci6jgyeuutzoqebdsbx5isxoiejvxyfp6am", "program": { "main": "/default-app.tsx", "files": [ { "name": "/default-app.tsx", "contents": "/// \nimport {\n Cell,\n Default,\n derive,\n h,\n handler,\n NAME,\n navigateTo,\n Opaque,\n OpaqueRef,\n recipe,\n str,\n UI,\n} from \"commontools\";\n\n// Import recipes we want to be launchable from the default app.\nimport Chatbot from \"./chatbot.tsx\";\nimport ChatbotOutliner from \"./chatbot-outliner.tsx\";\nimport { type MentionableCharm } from \"./chatbot-note-composed.tsx\";\nimport { default as Note } from \"./note.tsx\";\nimport ChatList from \"./chatbot-list-view.tsx\";\n\nexport type Charm = {\n [NAME]?: string;\n [UI]?: unknown;\n [key: string]: any;\n};\n\ntype CharmsListInput = {\n allCharms: Default;\n};\n\n// Recipe returns only UI, no data outputs (only symbol properties)\ninterface CharmsListOutput {\n [key: string]: unknown;\n}\n\nconst visit = handler<\n Record,\n { charm: any }\n>((_, state) => {\n return navigateTo(state.charm);\n}, { proxy: true });\n\nconst removeCharm = handler<\n Record,\n {\n charm: any;\n allCharms: Cell;\n }\n>((_, state) => {\n const charmName = state.charm[NAME];\n const allCharmsValue = state.allCharms.get();\n const index = allCharmsValue.findIndex((c: any) => c[NAME] === charmName);\n\n if (index !== -1) {\n const charmListCopy = [...allCharmsValue];\n console.log(\"charmListCopy before\", charmListCopy);\n charmListCopy.splice(index, 1);\n console.log(\"charmListCopy after\", charmListCopy);\n state.allCharms.set(charmListCopy);\n }\n});\n\nconst spawnChatList = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(ChatList({\n selectedCharm: { charm: undefined },\n charmsList: [],\n allCharms: state.allCharms, // we should handle empty here\n }));\n});\n\nconst spawnChatbot = handler<\n Record,\n Record\n>((_, state) => {\n return navigateTo(Chatbot({\n messages: [],\n tools: undefined,\n }));\n});\n\nconst spawnChatbotOutliner = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(ChatbotOutliner({\n title: \"Chatbot Outliner\",\n expandChat: false,\n messages: [],\n outline: {\n root: { body: \"\", children: [], attachments: [] },\n },\n allCharms: state.allCharms,\n }));\n});\n\nconst spawnNote = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(Note({\n title: \"New Note\",\n content: \"\",\n allCharms: state.allCharms,\n }));\n});\n\nexport default recipe(\n \"DefaultCharmList\",\n ({ allCharms }) => {\n return {\n [NAME]: str`DefaultCharmList (${allCharms.length})`,\n [UI]: (\n \n ,\n })}\n />\n\n \n {/* Quick Launch Toolbar */}\n \n

Quicklaunch:

\n ,\n })}\n >\n 📂 Chat List\n \n \n 💬 Chatbot\n \n \n 📝 Chatbot Outliner\n \n ,\n })}\n >\n 📄 Note\n \n
\n\n

Charms ({allCharms.length})

\n\n \n \n \n Charm Name\n Actions\n \n \n \n {derive(allCharms, (allCharms) =>\n allCharms.map((charm: any) => (\n \n {charm[NAME] || \"Untitled Charm\"}\n \n \n \n Visit\n \n \n Remove\n \n \n \n \n )))}\n \n \n
\n
\n ),\n };\n },\n);\n" }, { "name": "/chatbot.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n generateObject,\n h,\n handler,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n recipe,\n str,\n Stream,\n UI,\n} from \"commontools\";\n\nconst sendMessage = handler<\n { detail: { message: string } },\n {\n addMessage: Stream;\n }\n>((event, { addMessage }) => {\n addMessage.send({\n role: \"user\",\n content: [{ type: \"text\", text: event.detail.message }],\n });\n});\n\nconst clearChat = handler(\n (\n _: never,\n { messages, pending }: {\n messages: Cell>;\n pending: Cell;\n },\n ) => {\n messages.set([]);\n pending.set(false);\n },\n);\n\ntype ChatInput = {\n messages: Default, []>;\n tools: any;\n theme?: any;\n};\n\ntype ChatOutput = {\n messages: Array;\n pending: boolean | undefined;\n addMessage: Stream;\n cancelGeneration: Stream;\n title?: string;\n};\n\nexport const TitleGenerator = recipe<\n { model?: string; messages: Array }\n>(\"Title Generator\", ({ model, messages }) => {\n const titleMessages = derive(messages, (m) => {\n if (!m || m.length === 0) return \"\";\n\n const messageCount = 2;\n const selectedMessages = m.slice(0, messageCount).filter(Boolean);\n\n if (selectedMessages.length === 0) return \"\";\n\n return selectedMessages.map((msg) => JSON.stringify(msg)).join(\"\\n\");\n });\n\n const { result } = generateObject({\n system:\n \"Generate at most a 3-word title based on the following content, respond with NOTHING but the literal title text.\",\n prompt: titleMessages,\n model,\n schema: {\n type: \"object\",\n properties: {\n title: {\n type: \"string\",\n description: \"The title of the chat\",\n },\n },\n required: [\"title\"],\n },\n });\n\n const title = derive(result, (t) => {\n return t?.title || \"Untitled Chat\";\n });\n\n return title;\n});\n\nexport default recipe(\n \"Chat\",\n ({ messages, tools, theme }) => {\n const model = cell(\"anthropic:claude-sonnet-4-5\");\n\n const { addMessage, cancelGeneration, pending } = llmDialog({\n system: \"You are a helpful assistant with some tools.\",\n messages,\n tools,\n model,\n });\n\n const { result } = fetchData({\n url: \"/api/ai/llm/models\",\n mode: \"json\",\n });\n\n const items = derive(result, (models) => {\n if (!models) return [];\n const items = Object.keys(models as any).map((key) => ({\n label: key,\n value: key,\n }));\n return items;\n });\n\n const title = TitleGenerator({ model, messages });\n\n return {\n [NAME]: title,\n [UI]: (\n \n \n {title}\n \n \n\n \n \n \n\n
\n \n \n
\n
\n ),\n messages,\n pending,\n addMessage,\n cancelGeneration,\n title,\n };\n },\n);\n" }, { "name": "/chatbot-outliner.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n getRecipeEnvironment,\n h,\n handler,\n ID,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n str,\n Stream,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot.tsx\";\n\ntype Charm = any;\n\ntype OutlinerNode = {\n body: Default;\n children: Default;\n attachments: Default[], []>;\n};\n\ntype Outliner = {\n root: OutlinerNode;\n};\n\ntype PageResult = {\n outline: Default<\n Outliner,\n { root: { body: \"\"; children: []; attachments: [] } }\n >;\n};\n\nexport type PageInput = {\n outline: Outliner;\n allCharms: Cell;\n};\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nexport const Page = recipe(\n \"Page\",\n ({ outline, allCharms }) => {\n return {\n [NAME]: \"Page\",\n [UI]: (\n \n ),\n outline,\n };\n },\n);\n\ntype LLMTestInput = {\n title: Default;\n messages: Default, []>;\n expandChat: Default;\n outline: Default<\n Outliner,\n { root: { body: \"Untitled Page\"; children: []; attachments: [] } }\n >;\n allCharms: Cell;\n};\n\ntype LLMTestResult = {\n messages: Default, []>;\n};\n\n// put a node at the end of the outline (by appending to root.children)\nconst appendOutlinerNode = handler<\n {\n /** The text content/title of the outliner node to be appended */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { outline: Cell }\n>(\n (args, state) => {\n try {\n (state.outline.key(\"root\").key(\"children\")).push({\n body: args.body,\n children: [],\n attachments: [],\n });\n\n args.result.set(\n `${state.outline.key(\"root\").key(\"children\").get().length} nodes`,\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport default recipe(\n \"Outliner\",\n ({ title, expandChat, messages, outline, allCharms }) => {\n const tools = {\n appendOutlinerNode: {\n description: \"Add a new outliner node.\",\n inputSchema: {\n type: \"object\",\n properties: {\n body: {\n type: \"string\",\n description: \"The title of the new node.\",\n },\n },\n required: [\"body\"],\n } as JSONSchema,\n handler: appendOutlinerNode({ outline }),\n },\n };\n\n const chat = Chat({ messages, tools });\n const { addMessage, cancelGeneration, pending } = chat;\n\n return {\n [NAME]: title,\n [UI]: (\n \n \n
\n
\n Show Chat\n
\n
\n\n \n \n
\n \n
\n\n \n \n \n \n \n
\n\n {ifElse(\n expandChat,\n chat,\n null,\n )}\n
\n
\n ),\n messages,\n };\n },\n);\n" }, { "name": "/chatbot-note-composed.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n getRecipeEnvironment,\n h,\n handler,\n ID,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n str,\n Stream,\n toSchema,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot.tsx\";\nimport Note from \"./note.tsx\";\nimport Tools, {\n addListItem,\n calculator,\n ListItem,\n readListItems,\n readWebpage,\n searchWeb,\n} from \"./common-tools.tsx\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\n// export type ChatbotNoteInput = {\n// content: Default;\n// allCharms?: Cell;\n// };\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\ntype ChatbotNoteInput = {\n title: Default;\n messages: Default, []>;\n content: Default;\n allCharms: Cell;\n};\n\ntype ChatbotNoteResult = {\n messages: Default, []>;\n mentioned: Default, []>;\n backlinks: Default, []>;\n content: Default;\n note: any;\n chat: any;\n list: Default;\n};\n\nconst newNote = handler<\n {\n /** The text content of the note */\n title: string;\n content?: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const n = Note({\n title: args.title,\n content: args.content || \"\",\n allCharms: state.allCharms,\n });\n\n args.result.set(\n `Created note ${args.title}!`,\n );\n\n state.allCharms.push(n as unknown as MentionableCharm);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\n// put a note at the end of the outline (by appending to root.children)\nconst editNote = handler<\n {\n /** The text content of the note */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { content: Cell }\n>(\n (args, state) => {\n try {\n state.content.set(args.body);\n\n args.result.set(\n `Updated note!`,\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst readNote = handler<\n {\n /** A cell to store the result text */\n result: Cell;\n },\n { content: string }\n>(\n (args, state) => {\n try {\n args.result.set(state.content);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst listMentionable = handler<\n {\n /** A cell to store the result text */\n result: Cell;\n },\n { allCharms: { [NAME]: string }[] }\n>(\n (args, state) => {\n try {\n const namesList = state.allCharms.map((charm) => charm[NAME]);\n args.result.set(JSON.stringify(namesList));\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst readNoteByIndex = handler<\n {\n /** A cell to store the result text */\n index: number;\n result: Cell;\n },\n { allCharms: { [NAME]: string; content?: string }[] }\n>(\n (args, state) => {\n try {\n args.result.set(\n state.allCharms[args.index]?.content || \"No content found\",\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst editNoteByIndex = handler<\n {\n /** The index of the note to edit */\n index: number;\n /** The new text content of the note */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const charms = state.allCharms.get();\n if (args.index < 0 || args.index >= charms.length) {\n args.result.set(`Error: Invalid index ${args.index}`);\n return;\n }\n\n state.allCharms.key(args.index).key(\"content\").set(args.body);\n args.result.set(`Updated note at index ${args.index}!`);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst navigateToNote = handler<\n {\n /** The index of the note to navigate to */\n index: number;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const charms = state.allCharms.get();\n if (args.index < 0 || args.index >= charms.length) {\n args.result.set(`Error: Invalid index ${args.index}`);\n return;\n }\n\n const targetCharm = charms[args.index];\n args.result.set(`Navigating to note: ${targetCharm[NAME]}`);\n\n return navigateTo(state.allCharms.key(args.index));\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport default recipe(\n \"Chatbot + Note\",\n ({ title, messages, content, allCharms }) => {\n const list = cell([]);\n\n const tools = {\n searchWeb: {\n pattern: searchWeb,\n },\n readWebpage: {\n pattern: readWebpage,\n },\n calculator: {\n pattern: calculator,\n },\n addListItem: {\n handler: addListItem({ list }),\n },\n readListItems: {\n handler: readListItems({ list }),\n },\n editActiveNote: {\n description: \"Modify the shared note.\",\n inputSchema: {\n type: \"object\",\n properties: {\n body: {\n type: \"string\",\n description: \"The content of the note.\",\n },\n },\n required: [\"body\"],\n } as JSONSchema,\n handler: editNote({ content }),\n },\n readActiveNote: {\n description: \"Read the currently focused note.\",\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n } as JSONSchema,\n handler: readNote({ content }),\n },\n listNotes: {\n description:\n \"List all mentionable note titles (read the body with readNoteByIndex).\",\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n } as JSONSchema,\n handler: listMentionable({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n readNoteByIndex: {\n description:\n \"Read the body of a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n },\n required: [\"index\"],\n } as JSONSchema,\n handler: readNoteByIndex({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n editNoteByIndex: {\n description:\n \"Edit the body of a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n body: {\n type: \"string\",\n description: \"The new content of the note.\",\n },\n },\n required: [\"index\", \"body\"],\n } as JSONSchema,\n handler: editNoteByIndex({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n navigateToNote: {\n description: \"Navigate to a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n },\n required: [\"index\"],\n } as JSONSchema,\n handler: navigateToNote({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n newNote: {\n description: \"Read the shared note.\",\n inputSchema: {\n type: \"object\",\n properties: {\n title: {\n type: \"string\",\n description: \"The title of the note.\",\n },\n content: {\n type: \"string\",\n description: \"The content of the note.\",\n },\n },\n required: [\"title\"],\n } as JSONSchema,\n handler: newNote({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n };\n\n const chat = Chat({ messages, tools });\n const note = Note({ title, content, allCharms });\n\n return {\n [NAME]: title,\n chat,\n note,\n content,\n messages,\n mentioned: note.mentioned,\n backlinks: note.backlinks,\n list,\n };\n },\n);\n" }, { "name": "/note.tsx", "contents": "/// \nimport {\n Cell,\n cell,\n Default,\n derive,\n h,\n handler,\n lift,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n toSchema,\n UI,\n} from \"commontools\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\ntype Input = {\n title: Default;\n content: Default;\n allCharms: Cell;\n};\n\ntype Output = {\n mentioned: Default, []>;\n content: Default;\n backlinks: Default, []>;\n};\n\nconst updateTitle = handler<\n { detail: { value: string } },\n { title: Cell }\n>(\n (event, state) => {\n state.title.set(event.detail?.value ?? \"\");\n },\n);\n\nconst updateContent = handler<\n { detail: { value: string } },\n { content: Cell }\n>(\n (event, state) => {\n state.content.set(event.detail?.value ?? \"\");\n },\n);\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nconst handleNewBacklink = handler<\n {\n detail: {\n text: string;\n charmId: any;\n charm: Cell;\n navigate: boolean;\n };\n },\n {\n allCharms: Cell;\n }\n>(({ detail }, { allCharms }) => {\n console.log(\"new charm\", detail.text, detail.charmId);\n\n if (detail.navigate) {\n return navigateTo(detail.charm);\n } else {\n allCharms.push(detail.charm as unknown as MentionableCharm);\n }\n});\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\nconst Note = recipe(\n \"Note\",\n ({ title, content, allCharms }) => {\n const mentioned = cell([]);\n\n const computeBacklinks = lift<\n { allCharms: Cell; content: Cell },\n MentionableCharm[]\n >(\n ({ allCharms, content }) => {\n const cs = allCharms.get();\n if (!cs) return [];\n\n const self = cs.find((c) => c.content === content.get());\n\n const results = self\n ? cs.filter((c) =>\n c.mentioned?.some((m) => m.content === self.content) ?? false\n )\n : [];\n\n return results;\n },\n );\n\n const backlinks: OpaqueRef = computeBacklinks({\n allCharms,\n content: content as unknown as Cell, // TODO(bf): this is valid, but types complain\n });\n\n // The only way to serialize a pattern, apparently?\n const pattern = derive(undefined, () => JSON.stringify(Note));\n\n return {\n [NAME]: title,\n [UI]: (\n \n
\n \n
\n\n \n
\n ),\n title,\n content,\n mentioned,\n backlinks,\n };\n },\n);\n\nexport default Note;\n" }, { "name": "/chatbot-list-view.tsx", "contents": "/// \nimport {\n Cell,\n cell,\n Default,\n derive,\n h,\n handler,\n ID,\n ifElse,\n lift,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n toSchema,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot-note-composed.tsx\";\nimport { ListItem } from \"./common-tools.tsx\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\ntype CharmEntry = {\n [ID]: string; // randomId is a string\n local_id: string; // same as ID but easier to access\n charm: any;\n};\n\ntype Input = {\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\n charmsList: Default;\n allCharms: Cell;\n theme?: {\n accentColor: Default;\n fontFace: Default;\n borderRadius: Default;\n };\n};\n\ntype Output = {\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\n};\n\nconst removeChat = handler<\n unknown,\n {\n charmsList: Cell;\n id: string;\n selectedCharm: Cell>;\n }\n>(\n (\n _,\n { charmsList, id, selectedCharm },\n ) => {\n const list = charmsList.get();\n const index = list.findIndex((entry) => entry.local_id === id);\n if (index === -1) return;\n\n const removed = list[index];\n const next = [...list];\n next.splice(index, 1);\n charmsList.set(next);\n\n // If we removed the currently selected charm, choose a new selection.\n const current = selectedCharm.get();\n if (current?.charm === removed.charm) {\n const replacement = next[index] ?? next[index - 1];\n if (replacement) {\n selectedCharm.set({ charm: replacement.charm });\n } else {\n selectedCharm.set({ charm: undefined as unknown as any });\n }\n }\n },\n);\n\n// this will be called whenever charm or selectedCharm changes\n// pass isInitialized to make sure we dont call this each time\n// we change selectedCharm, otherwise creates a loop\nconst storeCharm = lift(\n toSchema<{\n charm: any;\n selectedCharm: Cell>;\n charmsList: Cell;\n allCharms: Cell;\n theme?: {\n accentColor: Default;\n fontFace: Default;\n borderRadius: Default;\n };\n isInitialized: Cell;\n }>(),\n undefined,\n ({ charm, selectedCharm, charmsList, isInitialized, allCharms }) => { // Not including `allCharms` is a compile error...\n if (!isInitialized.get()) {\n console.log(\n \"storeCharm storing charm:\",\n charm,\n );\n selectedCharm.set({ charm });\n\n // create the chat charm with a custom name including a random suffix\n const randomId = Math.random().toString(36).substring(2, 10); // Random 8-char string\n charmsList.push({ [ID]: randomId, local_id: randomId, charm });\n\n isInitialized.set(true);\n return charm;\n } else {\n console.log(\"storeCharm: already initialized\");\n }\n return undefined;\n },\n);\n\nconst populateChatList = lift(\n toSchema<{\n charmsList: CharmEntry[];\n allCharms: Cell;\n selectedCharm: Cell<{ charm: any }>;\n }>(),\n undefined,\n (\n { charmsList, allCharms, selectedCharm },\n ) => {\n if (charmsList.length === 0) {\n const isInitialized = cell(false);\n return storeCharm({\n charm: Chat({\n title: \"New Chat\",\n messages: [],\n content: \"\",\n allCharms,\n }),\n selectedCharm,\n charmsList,\n allCharms,\n isInitialized: isInitialized as unknown as Cell,\n });\n }\n\n return charmsList;\n },\n);\n\nconst createChatRecipe = handler<\n unknown,\n {\n selectedCharm: Cell<{ charm: any }>;\n charmsList: Cell;\n allCharms: Cell;\n }\n>(\n (_, { selectedCharm, charmsList, allCharms }) => {\n const isInitialized = cell(false);\n\n const charm = Chat({\n title: \"New Chat\",\n messages: [],\n content: \"\",\n allCharms,\n });\n // store the charm ref in a cell (pass isInitialized to prevent recursive calls)\n return storeCharm({\n charm,\n selectedCharm,\n charmsList: charmsList as unknown as OpaqueRef,\n allCharms,\n isInitialized: isInitialized as unknown as Cell,\n });\n },\n);\n\nconst selectCharm = handler<\n unknown,\n { selectedCharm: Cell<{ charm: any }>; charm: any }\n>(\n (_, { selectedCharm, charm }) => {\n console.log(\"selectCharm: updating selectedCharm to \", charm);\n selectedCharm.set({ charm });\n return selectedCharm;\n },\n);\n\nconst logCharmsList = lift<\n { charmsList: Cell },\n Cell\n>(\n ({ charmsList }) => {\n console.log(\"logCharmsList: \", charmsList.get());\n return charmsList;\n },\n);\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\nconst combineLists = lift(\n (\n { allCharms, charmsList }: { allCharms: any[]; charmsList: CharmEntry[] },\n ) => {\n return [...charmsList.map((c) => c.charm), ...allCharms];\n },\n);\n\nconst getSelectedCharm = lift<\n { entry: { charm: any | undefined } },\n {\n chat: unknown;\n note: unknown;\n list: ListItem[];\n backlinks: MentionableCharm[];\n mentioned: MentionableCharm[];\n } | undefined\n>(\n ({ entry }) => {\n return entry?.charm;\n },\n);\n\nconst getCharmName = lift(({ charm }: { charm: any }) => {\n return charm?.[NAME] || \"Unknown\";\n});\n\n// create the named cell inside the recipe body, so we do it just once\nexport default recipe(\n \"Launcher\",\n ({ selectedCharm, charmsList, allCharms, theme }) => {\n logCharmsList({ charmsList: charmsList as unknown as Cell });\n\n populateChatList({\n selectedCharm: selectedCharm as unknown as Cell<\n Pick\n >,\n charmsList,\n allCharms,\n });\n\n const combined = combineLists({\n allCharms: allCharms as unknown as any[],\n charmsList,\n });\n\n const selected = getSelectedCharm({ entry: selectedCharm });\n\n const localTheme = theme ?? {\n accentColor: cell(\"#3b82f6\"),\n fontFace: cell(\"system-ui, -apple-system, sans-serif\"),\n borderRadius: cell(\"0.5rem\"),\n };\n\n return {\n [NAME]: \"Launcher\",\n [UI]: (\n \n \n
\n \n
\n \n Create New Chat\n alt+N\n \n
\n
\n\n {/* Keyboard shortcuts */}\n \n
\n \n {/* workaround: this seems to correctly start the sub-recipes on a refresh while directly rendering does not */}\n {/* this should be fixed after the builder-refactor (DX1) */}\n \n \n \n \n \n \n\n \n\n \n \n
\n
\n ),\n selectedCharm,\n charmsList,\n };\n },\n);\n" }, { "name": "/common-tools.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n BuiltInLLMTool,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n h,\n handler,\n ifElse,\n llmDialog,\n NAME,\n recipe,\n Stream,\n UI,\n} from \"commontools\";\n\n///// COMMON TOOLS (get it?) ////\n\n/**\n * Calculate the result of a mathematical expression.\n * Supports +, -, *, /, and parentheses.\n */\ntype CalculatorRequest = {\n /** The mathematical expression to evaluate. */\n expression: string;\n};\n\nexport const calculator = recipe<\n CalculatorRequest,\n string | { error: string }\n>(\"Calculator\", ({ expression }) => {\n return derive(expression, (expr) => {\n const sanitized = expr.replace(/[^0-9+\\-*/().\\s]/g, \"\");\n let result;\n try {\n result = Function(`\"use strict\"; return (${sanitized})`)();\n } catch (error) {\n result = { error: (error as any)?.message || \"\" };\n }\n return result;\n });\n});\n\n/** Add an item to the list. */\ntype AddListItemRequest = {\n /** The item to add to the list. */\n item: string;\n result: Cell;\n};\n\n/** Read all items from the list. */\ntype ReadListItemsRequest = {\n result: Cell;\n};\n\nexport type ListItem = {\n title: string;\n};\n\nexport const addListItem = handler<\n AddListItemRequest,\n { list: Cell }\n>(\n (args, state) => {\n try {\n state.list.push({ title: args.item });\n args.result.set(`${state.list.get().length} items`);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport const readListItems = handler<\n ReadListItemsRequest,\n { list: ListItem[] }\n>(\n (args, state) => {\n try {\n const items = state.list;\n if (items.length === 0) {\n args.result.set(\"The list is empty\");\n } else {\n const itemList = items.map((item, index) =>\n `${index + 1}. ${item.title}`\n ).join(\"\\n\");\n args.result.set(`List items (${items.length} total):\\n${itemList}`);\n }\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\n/** Search the web for information. */\ntype SearchQuery = {\n /** The query to search the web for. */\n query: string;\n};\n\ntype SearchWebResult = {\n results: {\n title: string;\n url: string;\n description: string;\n }[];\n};\n\nexport const searchWeb = recipe<\n SearchQuery,\n SearchWebResult | { error: string }\n>(\"Search Web\", ({ query }) => {\n const { result, error } = fetchData({\n url: \"/api/agent-tools/web-search\",\n mode: \"json\",\n options: {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: {\n query,\n max_results: 5,\n },\n },\n });\n\n // TODO(seefeld): Should we instead return { result, error }? Or allocate a\n // special [ERROR] for errors? Ideally this isn\\'t specific to using recipes as\n // tools but a general pattern.\n return ifElse(error, { error }, result);\n});\n\n/** Read and extract content from a specific webpage URL. */\ntype ReadWebRequest = {\n /** The URL of the webpage to read and extract content from. */\n url: string;\n};\n\ntype ReadWebResult = {\n content: string;\n metadata: {\n title?: string;\n author?: string;\n date?: string;\n word_count: number;\n };\n};\n\nexport const readWebpage = recipe<\n ReadWebRequest,\n ReadWebResult | { error: string }\n>(\"Read Webpage\", ({ url }) => {\n const { result, error } = fetchData({\n url: \"/api/agent-tools/web-read\",\n mode: \"json\",\n options: {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: {\n url,\n max_tokens: 4000,\n include_code: true,\n },\n },\n });\n\n return ifElse(error, { error }, result);\n});\n\ntype ToolsInput = {\n list: ListItem[];\n};\n\nexport default recipe(\"Tools\", ({ list }) => {\n const tools: Record = {\n search_web: {\n pattern: searchWeb,\n },\n read_webpage: {\n pattern: readWebpage,\n },\n calculator: {\n pattern: calculator,\n },\n addListItem: {\n handler: addListItem({ list }),\n },\n };\n\n return { tools, list };\n});\n" } ] }, "spec": "recipe" } }, "since": 0 } } }, "of:baedreieihgsgvlmhz43c4zozooeyokvkudejkntefpglpz3vwq5odsan2e": { "application/json": { "ba4jcabiglpjllxplgrrg7h6fgqhdak5fsvaye7g4joomjfu5mzj7xbt3": { "is": { "source": { "/": "baedreidfn3ztoouromccp4sqiqspbigzvenj7diywcvmmxf2jw7z5a5dju" }, "value": [ { "type": "vnode", "name": "tr", "props": { }, "children": [ { "type": "vnode", "name": "td", "props": { }, "children": [ "DefaultCharmList (6)" ] }, { "type": "vnode", "name": "td", "props": { }, "children": [ { "type": "vnode", "name": "ct-hstack", "props": { "gap": "2" }, "children": [ { "type": "vnode", "name": "ct-button", "props": { "size": "sm", "onClick": { "$alias": { "path": [ "internal", "$event" ], "schema": { "type": "object", "properties": { }, "additionalProperties": false }, "rootSchema": { "type": "object", "properties": { }, "additionalProperties": false }, "cell": { "/": "baedreidfn3ztoouromccp4sqiqspbigzvenj7diywcvmmxf2jw7z5a5dju" } } } }, "children": [ "Visit" ] }, { "type": "vnode", "name": "ct-button", "props": { "size": "sm", "variant": "destructive", "onClick": { "$alias": { "path": [ "internal", "__#10stream" ], "schema": { "type": "object", "properties": { }, "additionalProperties": false }, "rootSchema": { "type": "object", "properties": { }, "additionalProperties": false }, "cell": { "/": "baedreidfn3ztoouromccp4sqiqspbigzvenj7diywcvmmxf2jw7z5a5dju" } } } }, "children": [ "Remove" ] } ] } ] } ] }, { "type": "vnode", "name": "tr", "props": { }, "children": [ { "type": "vnode", "name": "td", "props": { }, "children": [ "Launcher" ] }, { "type": "vnode", "name": "td", "props": { }, "children": [ { "type": "vnode", "name": "ct-hstack", "props": { "gap": "2" }, "children": [ { "type": "vnode", "name": "ct-button", "props": { "size": "sm", "onClick": { "$alias": { "path": [ "internal", "__#0stream" ], "schema": { "type": "object", "properties": { }, "additionalProperties": false }, "rootSchema": { "type": "object", "properties": { }, "additionalProperties": false }, "cell": { "/": "baedreidfn3ztoouromccp4sqiqspbigzvenj7diywcvmmxf2jw7z5a5dju" } } } }, "children": [ "Visit" ] }, { "type": "vnode", "name": "ct-button", "props": { "size": "sm", "variant": "destructive", "onClick": { "$alias": { "path": [ "internal", "__#1stream" ], "schema": { "type": "object", "properties": { }, "additionalProperties": false }, "rootSchema": { "type": "object", "properties": { }, "additionalProperties": false }, "cell": { "/": "baedreidfn3ztoouromccp4sqiqspbigzvenj7diywcvmmxf2jw7z5a5dju" } } } }, "children": [ "Remove" ] } ] } ] } ] }, { "type": "vnode", "name": "tr", "props": { }, "children": [ { "type": "vnode", "name": "td", "props": { }, "children": [ "one" ] }, { "type": "vnode", "name": "td", "props": { }, "children": [ { "type": "vnode", "name": "ct-hstack", "props": { "gap": "2" }, "children": [ { "type": "vnode", "name": "ct-button", "props": { "size": "sm", "onClick": { "$alias": { "path": [ "internal", "__#2stream" ], "schema": { "type": "object", "properties": { }, "additionalProperties": false }, "rootSchema": { "type": "object", "properties": { }, "additionalProperties": false }, "cell": { "/": "baedreidfn3ztoouromccp4sqiqspbigzvenj7diywcvmmxf2jw7z5a5dju" } } } }, "children": [ "Visit" ] }, { "type": "vnode", "name": "ct-button", "props": { "size": "sm", "variant": "destructive", "onClick": { "$alias": { "path": [ "internal", "__#3stream" ], "schema": { "type": "object", "properties": { }, "additionalProperties": false }, "rootSchema": { "type": "object", "properties": { }, "additionalProperties": false }, "cell": { "/": "baedreidfn3ztoouromccp4sqiqspbigzvenj7diywcvmmxf2jw7z5a5dju" } } } }, "children": [ "Remove" ] } ] } ] } ] }, { "type": "vnode", "name": "tr", "props": { }, "children": [ { "type": "vnode", "name": "td", "props": { }, "children": [ "two" ] }, { "type": "vnode", "name": "td", "props": { }, "children": [ { "type": "vnode", "name": "ct-hstack", "props": { "gap": "2" }, "children": [ { "type": "vnode", "name": "ct-button", "props": { "size": "sm", "onClick": { "$alias": { "path": [ "internal", "__#4stream" ], "schema": { "type": "object", "properties": { }, "additionalProperties": false }, "rootSchema": { "type": "object", "properties": { }, "additionalProperties": false }, "cell": { "/": "baedreidfn3ztoouromccp4sqiqspbigzvenj7diywcvmmxf2jw7z5a5dju" } } } }, "children": [ "Visit" ] }, { "type": "vnode", "name": "ct-button", "props": { "size": "sm", "variant": "destructive", "onClick": { "$alias": { "path": [ "internal", "__#5stream" ], "schema": { "type": "object", "properties": { }, "additionalProperties": false }, "rootSchema": { "type": "object", "properties": { }, "additionalProperties": false }, "cell": { "/": "baedreidfn3ztoouromccp4sqiqspbigzvenj7diywcvmmxf2jw7z5a5dju" } } } }, "children": [ "Remove" ] } ] } ] } ] }, { "type": "vnode", "name": "tr", "props": { }, "children": [ { "type": "vnode", "name": "td", "props": { }, "children": [ "three" ] }, { "type": "vnode", "name": "td", "props": { }, "children": [ { "type": "vnode", "name": "ct-hstack", "props": { "gap": "2" }, "children": [ { "type": "vnode", "name": "ct-button", "props": { "size": "sm", "onClick": { "$alias": { "path": [ "internal", "__#6stream" ], "schema": { "type": "object", "properties": { }, "additionalProperties": false }, "rootSchema": { "type": "object", "properties": { }, "additionalProperties": false }, "cell": { "/": "baedreidfn3ztoouromccp4sqiqspbigzvenj7diywcvmmxf2jw7z5a5dju" } } } }, "children": [ "Visit" ] }, { "type": "vnode", "name": "ct-button", "props": { "size": "sm", "variant": "destructive", "onClick": { "$alias": { "path": [ "internal", "__#7stream" ], "schema": { "type": "object", "properties": { }, "additionalProperties": false }, "rootSchema": { "type": "object", "properties": { }, "additionalProperties": false }, "cell": { "/": "baedreidfn3ztoouromccp4sqiqspbigzvenj7diywcvmmxf2jw7z5a5dju" } } } }, "children": [ "Remove" ] } ] } ] } ] }, { "type": "vnode", "name": "tr", "props": { }, "children": [ { "type": "vnode", "name": "td", "props": { }, "children": [ "four" ] }, { "type": "vnode", "name": "td", "props": { }, "children": [ { "type": "vnode", "name": "ct-hstack", "props": { "gap": "2" }, "children": [ { "type": "vnode", "name": "ct-button", "props": { "size": "sm", "onClick": { "$alias": { "path": [ "internal", "__#8stream" ], "schema": { "type": "object", "properties": { }, "additionalProperties": false }, "rootSchema": { "type": "object", "properties": { }, "additionalProperties": false }, "cell": { "/": "baedreidfn3ztoouromccp4sqiqspbigzvenj7diywcvmmxf2jw7z5a5dju" } } } }, "children": [ "Visit" ] }, { "type": "vnode", "name": "ct-button", "props": { "size": "sm", "variant": "destructive", "onClick": { "$alias": { "path": [ "internal", "__#9stream" ], "schema": { "type": "object", "properties": { }, "additionalProperties": false }, "rootSchema": { "type": "object", "properties": { }, "additionalProperties": false }, "cell": { "/": "baedreidfn3ztoouromccp4sqiqspbigzvenj7diywcvmmxf2jw7z5a5dju" } } } }, "children": [ "Remove" ] } ] } ] } ] } ] }, "since": 96 } } }, "of:baedreidfn3ztoouromccp4sqiqspbigzvenj7diywcvmmxf2jw7z5a5dju": { "application/json": { "ba4jcaxr4hmppcrvidrvp2dlynonnsymakjek24ch6awlkyccxt7jww76": { "is": { "value": { "$TYPE": "ba4jcbmwg4wrwkea6vw7pc7agu5dn3iockwv2g5vzdquavlueltwsseaj", "resultRef": { "/": { "link@1": { "path": [], "id": "of:baedreieihgsgvlmhz43c4zozooeyokvkudejkntefpglpz3vwq5odsan2e" } } }, "internal": { "$event": { "$stream": true }, "__#0stream": { "$stream": true }, "__#1stream": { "$stream": true }, "__#2stream": { "$stream": true }, "__#3stream": { "$stream": true }, "__#4stream": { "$stream": true }, "__#5stream": { "$stream": true }, "__#6stream": { "$stream": true }, "__#7stream": { "$stream": true }, "__#8stream": { "$stream": true }, "__#9stream": { "$stream": true }, "__#10stream": { "$stream": true } }, "spell": { "/": { "link@1": { "id": "of:baedreialup6quosxdoqitoe77j4nmoxjnfhbmexxg7w26h57zm5efz6fdu" } } }, "argument": { } } }, "since": 96 } } }, "of:baedreibl64qzbhgkvpuxbfc657ugjeyidc62hixjybt5dpci2ddkkhs26m": { "application/json": { "ba4jcao7dyu5ju4wyovrxttgby75p35fzoptz5gowhnz432kscf2j5kje": { "is": { "source": { "/": "baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u" }, "value": { "$NAME": "Launcher", "$UI": { "type": "vnode", "name": "ct-theme", "props": { "theme": { "$alias": { "path": [ "argument", "theme" ], "schema": { "type": "object", "properties": { "accentColor": { "type": "string", "default": "#3b82f6" }, "fontFace": { "type": "string", "default": "system-ui, -apple-system, sans-serif" }, "borderRadius": { "type": "string", "default": "0.5rem" } }, "required": [ "accentColor", "fontFace", "borderRadius" ] }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "selectedCharm": { "type": "object", "properties": { "charm": true }, "required": [ "charm" ], "default": { } }, "charmsList": { "type": "array", "items": { "$ref": "#/$defs/CharmEntry" }, "default": [] }, "allCharms": { "type": "array", "items": true }, "theme": { "type": "object", "properties": { "accentColor": { "type": "string", "default": "#3b82f6" }, "fontFace": { "type": "string", "default": "system-ui, -apple-system, sans-serif" }, "borderRadius": { "type": "string", "default": "0.5rem" } }, "required": [ "accentColor", "fontFace", "borderRadius" ] } }, "required": [ "selectedCharm", "charmsList", "allCharms" ], "$defs": { "CharmEntry": { "type": "object", "properties": { "local_id": { "type": "string" }, "charm": true }, "required": [ "local_id", "charm" ] } } }, "cell": { "/": "baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u" } } } }, "children": [ { "type": "vnode", "name": "ct-screen", "props": { }, "children": [ { "type": "vnode", "name": "div", "props": { "slot": "header" }, "children": [ { "type": "vnode", "name": "ct-toolbar", "props": { "dense": true, "sticky": true }, "children": [ { "type": "vnode", "name": "div", "props": { "slot": "start" }, "children": [ { "type": "vnode", "name": "ct-button", "props": { "id": "new-chat-btn", "onClick": { "$alias": { "path": [ "internal", "__#4stream" ], "schema": true, "rootSchema": true, "cell": { "/": "baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u" } } } }, "children": [ "Create New Chat", { "type": "vnode", "name": "ct-kbd", "props": { }, "children": [ "alt+N" ] } ] } ] } ] }, { "type": "vnode", "name": "ct-keybind", "props": { "code": "KeyN", "alt": true, "preventDefault": true, "onct-keybind": { "$alias": { "path": [ "internal", "$event" ], "schema": true, "rootSchema": true, "cell": { "/": "baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u" } } } }, "children": [] } ] }, { "type": "vnode", "name": "ct-autolayout", "props": { "leftOpen": true, "rightOpen": false, "tabNames": [ "Chat", "Note" ] }, "children": [ { "type": "vnode", "name": "ct-screen", "props": { }, "children": [ { "type": "vnode", "name": "ct-render", "props": { "$cell": { "$alias": { "path": [ "internal", "list", "chat" ], "cell": { "/": "baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u" } } } }, "children": [] } ] }, { "type": "vnode", "name": "ct-screen", "props": { }, "children": [ { "type": "vnode", "name": "ct-render", "props": { "$cell": { "$alias": { "path": [ "internal", "list", "note" ], "cell": { "/": "baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u" } } } }, "children": [] } ] }, { "type": "vnode", "name": "aside", "props": { "slot": "left" }, "children": [ { "type": "vnode", "name": "div", "props": { }, "children": [ { "type": "vnode", "name": "ct-heading", "props": { "level": 3 }, "children": [ "Chat List" ] } ] }, { "type": "vnode", "name": "div", "props": { "role": "list" }, "children": [ { "$alias": { "path": [ "internal", "__#5" ], "cell": { "/": "baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u" } } } ] } ] }, { "type": "vnode", "name": "aside", "props": { "slot": "right" }, "children": [ { "$alias": { "path": [ "internal", "__#2" ], "cell": { "/": "baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u" } } }, { "type": "vnode", "name": "ct-collapsible", "props": { }, "children": [ { "type": "vnode", "name": "ct-heading", "props": { "slot": "trigger", "level": 5, "no-margin": true }, "children": [ "Theme" ] }, { "type": "vnode", "name": "ct-vstack", "props": { "style": "padding: 0.5rem 0; gap: 0.5rem;" }, "children": [ { "type": "vnode", "name": "ct-vstack", "props": { }, "children": [ { "type": "vnode", "name": "ct-text", "props": { }, "children": [ "Font Family" ] }, { "type": "vnode", "name": "ct-select", "props": { "items": [ { "label": "System", "value": "system-ui, -apple-system, sans-serif" }, { "label": "Monospace", "value": "ui-monospace, Consolas, monospace" }, { "label": "Serif", "value": "Georgia, Times, serif" }, { "label": "Sans Serif", "value": "Arial, Helvetica, sans-serif" } ], "$value": { "$alias": { "path": [ "argument", "theme", "fontFace" ], "schema": { "type": "string", "default": "system-ui, -apple-system, sans-serif" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "selectedCharm": { "type": "object", "properties": { "charm": true }, "required": [ "charm" ], "default": { } }, "charmsList": { "type": "array", "items": { "$ref": "#/$defs/CharmEntry" }, "default": [] }, "allCharms": { "type": "array", "items": true }, "theme": { "type": "object", "properties": { "accentColor": { "type": "string", "default": "#3b82f6" }, "fontFace": { "type": "string", "default": "system-ui, -apple-system, sans-serif" }, "borderRadius": { "type": "string", "default": "0.5rem" } }, "required": [ "accentColor", "fontFace", "borderRadius" ] } }, "required": [ "selectedCharm", "charmsList", "allCharms" ], "$defs": { "CharmEntry": { "type": "object", "properties": { "local_id": { "type": "string" }, "charm": true }, "required": [ "local_id", "charm" ] } } }, "cell": { "/": "baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u" } } } }, "children": [] } ] }, { "type": "vnode", "name": "ct-vstack", "props": { }, "children": [ { "type": "vnode", "name": "ct-text", "props": { }, "children": [ "Accent Color" ] }, { "type": "vnode", "name": "ct-select", "props": { "items": [ { "label": "Blue", "value": "#3b82f6" }, { "label": "Purple", "value": "#8b5cf6" }, { "label": "Green", "value": "#10b981" }, { "label": "Red", "value": "#ef4444" }, { "label": "Orange", "value": "#f97316" }, { "label": "Pink", "value": "#ec4899" }, { "label": "Indigo", "value": "#6366f1" }, { "label": "Teal", "value": "#14b8a6" } ], "$value": { "$alias": { "path": [ "argument", "theme", "accentColor" ], "schema": { "type": "string", "default": "#3b82f6" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "selectedCharm": { "type": "object", "properties": { "charm": true }, "required": [ "charm" ], "default": { } }, "charmsList": { "type": "array", "items": { "$ref": "#/$defs/CharmEntry" }, "default": [] }, "allCharms": { "type": "array", "items": true }, "theme": { "type": "object", "properties": { "accentColor": { "type": "string", "default": "#3b82f6" }, "fontFace": { "type": "string", "default": "system-ui, -apple-system, sans-serif" }, "borderRadius": { "type": "string", "default": "0.5rem" } }, "required": [ "accentColor", "fontFace", "borderRadius" ] } }, "required": [ "selectedCharm", "charmsList", "allCharms" ], "$defs": { "CharmEntry": { "type": "object", "properties": { "local_id": { "type": "string" }, "charm": true }, "required": [ "local_id", "charm" ] } } }, "cell": { "/": "baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u" } } } }, "children": [] } ] }, { "type": "vnode", "name": "ct-vstack", "props": { }, "children": [ { "type": "vnode", "name": "ct-text", "props": { }, "children": [ "Border Radius" ] }, { "type": "vnode", "name": "ct-select", "props": { "items": [ { "label": "None", "value": "0px" }, { "label": "Small", "value": "0.25rem" }, { "label": "Medium", "value": "0.5rem" }, { "label": "Large", "value": "0.75rem" }, { "label": "Extra Large", "value": "1rem" }, { "label": "Rounded", "value": "1.5rem" } ], "$value": { "$alias": { "path": [ "argument", "theme", "borderRadius" ], "schema": { "type": "string", "default": "0.5rem" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "selectedCharm": { "type": "object", "properties": { "charm": true }, "required": [ "charm" ], "default": { } }, "charmsList": { "type": "array", "items": { "$ref": "#/$defs/CharmEntry" }, "default": [] }, "allCharms": { "type": "array", "items": true }, "theme": { "type": "object", "properties": { "accentColor": { "type": "string", "default": "#3b82f6" }, "fontFace": { "type": "string", "default": "system-ui, -apple-system, sans-serif" }, "borderRadius": { "type": "string", "default": "0.5rem" } }, "required": [ "accentColor", "fontFace", "borderRadius" ] } }, "required": [ "selectedCharm", "charmsList", "allCharms" ], "$defs": { "CharmEntry": { "type": "object", "properties": { "local_id": { "type": "string" }, "charm": true }, "required": [ "local_id", "charm" ] } } }, "cell": { "/": "baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u" } } } }, "children": [] } ] } ] } ] } ] } ] } ] } ] }, "selectedCharm": { "$alias": { "path": [ "argument", "selectedCharm" ], "schema": { "type": "object", "properties": { "charm": true }, "required": [ "charm" ], "default": { } }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "selectedCharm": { "type": "object", "properties": { "charm": true }, "required": [ "charm" ], "default": { } }, "charmsList": { "type": "array", "items": { "$ref": "#/$defs/CharmEntry" }, "default": [] }, "allCharms": { "type": "array", "items": true }, "theme": { "type": "object", "properties": { "accentColor": { "type": "string", "default": "#3b82f6" }, "fontFace": { "type": "string", "default": "system-ui, -apple-system, sans-serif" }, "borderRadius": { "type": "string", "default": "0.5rem" } }, "required": [ "accentColor", "fontFace", "borderRadius" ] } }, "required": [ "selectedCharm", "charmsList", "allCharms" ], "$defs": { "CharmEntry": { "type": "object", "properties": { "local_id": { "type": "string" }, "charm": true }, "required": [ "local_id", "charm" ] } } }, "cell": { "/": "baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u" } } }, "charmsList": { "$alias": { "path": [ "argument", "charmsList" ], "schema": { "type": "array", "items": { "$ref": "#/$defs/CharmEntry" }, "default": [] }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "selectedCharm": { "type": "object", "properties": { "charm": true }, "required": [ "charm" ], "default": { } }, "charmsList": { "type": "array", "items": { "$ref": "#/$defs/CharmEntry" }, "default": [] }, "allCharms": { "type": "array", "items": true }, "theme": { "type": "object", "properties": { "accentColor": { "type": "string", "default": "#3b82f6" }, "fontFace": { "type": "string", "default": "system-ui, -apple-system, sans-serif" }, "borderRadius": { "type": "string", "default": "0.5rem" } }, "required": [ "accentColor", "fontFace", "borderRadius" ] } }, "required": [ "selectedCharm", "charmsList", "allCharms" ], "$defs": { "CharmEntry": { "type": "object", "properties": { "local_id": { "type": "string" }, "charm": true }, "required": [ "local_id", "charm" ] } } }, "cell": { "/": "baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u" } } } } }, "since": 11 } } }, "of:baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u": { "application/json": { "ba4jcbhfr2tyzidydfnga5qzitmilvjy4exc5oyke2mih3sxqczls6aki": { "is": { "value": { "$TYPE": "ba4jcakiq2gsbkigfeo5q6ime4d4we5sqgr6gwdnopq4dl2fmss65o4bm", "resultRef": { "/": { "link@1": { "path": [], "id": "of:baedreibl64qzbhgkvpuxbfc657ugjeyidc62hixjybt5dpci2ddkkhs26m" } } }, "internal": { "$event": { "$stream": true }, "__#4stream": { "$stream": true }, "__#7": { "/": { "link@1": { "path": [ "argument", "charmsList" ], "id": "of:baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, "__#6": { "/": { "link@1": { "path": [ "argument", "charmsList" ], "id": "of:baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, "__#3": [ { "/": { "link@1": { "path": [], "id": "of:baedreih3s7r744kith3ntkg6oooklw2sy2vyycy22zlmm4l7rnizislpqa", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, { "/": { "link@1": { "path": [], "id": "of:baedreihffyh4263hchjbcx4vqsyctgf6frmgaryrflbdtkezhzzyn5itde", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, { "/": { "link@1": { "path": [], "id": "of:baedreibl64qzbhgkvpuxbfc657ugjeyidc62hixjybt5dpci2ddkkhs26m", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, { "/": { "link@1": { "path": [], "id": "of:baedreidvk42ywcn6n6ucdpfg2pvi5o6p3njkk6rltyvydkkbjcco5m4wcu", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, { "/": { "link@1": { "path": [], "id": "of:baedreibninu5twfm72l6gs5sbaghg6gdtmn2365encfoinebrvnsmavrr4", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, { "/": { "link@1": { "path": [], "id": "of:baedreibyolwzasa3njbwrwexvtolf7b7x5wh5lkwkepa5jbc6paghoc5ua", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, { "/": { "link@1": { "path": [], "id": "of:baedreigyxxqptxd2vlfwxnhzdwdha32i4ou5onzw6ruunaqudg5u42agva", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } } ], "__#0": { "/": { "link@1": { "path": [], "id": "of:baedreid6gonxx2y2poyw67zd636ijtv5iwc76kqfhhdd5zn4kbdpfr7tpe", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, "__#1": { "/": { "link@1": { "path": [], "id": "of:baedreihfxjcb2la3k4kuof4uvlgr4zdoll3mgksfi5vf2zmf7pnvgrk2tu", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, "__#5": { "/": { "link@1": { "path": [], "id": "of:baedreicv3mllykrlg2ahbgffulevsda4qxjipyuntyfs7fdi4nzrxfiw6u", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, "__#2": { "/": { "link@1": { "path": [], "id": "of:baedreihsyzn7myhp646sdiyb4ixi76jihj27hsgg3mcmlea6hqz72zaexe", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, "list": { "/": { "link@1": { "path": [], "id": "of:baedreih3s7r744kith3ntkg6oooklw2sy2vyycy22zlmm4l7rnizislpqa", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } } }, "spell": { "/": { "link@1": { "id": "of:baedreie4tj7mfuztjpercxelbluysbd3omwxwa47cckwludt3ayhabtjru" } } }, "argument": { "selectedCharm": { "charm": { "/": { "link@1": { "path": [], "id": "of:baedreih3s7r744kith3ntkg6oooklw2sy2vyycy22zlmm4l7rnizislpqa", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } } }, "charmsList": [ { "/": { "link@1": { "path": [], "id": "of:baedreiboekykwgdbufsup3shixvj6g2lbzlxy666g5lbhvdivuj7x375ae" } } } ], "allCharms": { "$alias": { "cell": { "/": "baedreiahv63wxwgaem4hzjkizl4qncfgvca7pj5cvdon7cukumfon3ioye" }, "path": [] } }, "theme": { "accentColor": "#3b82f6", "fontFace": "system-ui, -apple-system, sans-serif", "borderRadius": "0.5rem" } } } }, "since": 95 } } }, "of:baedreie4tj7mfuztjpercxelbluysbd3omwxwa47cckwludt3ayhabtjru": { "application/json": { "ba4jcbu5hn6fzsenqsllsfejs5vtahh7orfvwsxk7rlkkown5hpo4fxzk": { "is": { "value": { "id": "ba4jcakiq2gsbkigfeo5q6ime4d4we5sqgr6gwdnopq4dl2fmss65o4bm", "program": { "main": "/chatbot-list-view.tsx", "mainExport": "default", "files": [ { "name": "/default-app.tsx", "contents": "/// \nimport {\n Cell,\n Default,\n derive,\n h,\n handler,\n NAME,\n navigateTo,\n Opaque,\n OpaqueRef,\n recipe,\n str,\n UI,\n} from \"commontools\";\n\n// Import recipes we want to be launchable from the default app.\nimport Chatbot from \"./chatbot.tsx\";\nimport ChatbotOutliner from \"./chatbot-outliner.tsx\";\nimport { type MentionableCharm } from \"./chatbot-note-composed.tsx\";\nimport { default as Note } from \"./note.tsx\";\nimport ChatList from \"./chatbot-list-view.tsx\";\n\nexport type Charm = {\n [NAME]?: string;\n [UI]?: unknown;\n [key: string]: any;\n};\n\ntype CharmsListInput = {\n allCharms: Default;\n};\n\n// Recipe returns only UI, no data outputs (only symbol properties)\ninterface CharmsListOutput {\n [key: string]: unknown;\n}\n\nconst visit = handler<\n Record,\n { charm: any }\n>((_, state) => {\n return navigateTo(state.charm);\n}, { proxy: true });\n\nconst removeCharm = handler<\n Record,\n {\n charm: any;\n allCharms: Cell;\n }\n>((_, state) => {\n const charmName = state.charm[NAME];\n const allCharmsValue = state.allCharms.get();\n const index = allCharmsValue.findIndex((c: any) => c[NAME] === charmName);\n\n if (index !== -1) {\n const charmListCopy = [...allCharmsValue];\n console.log(\"charmListCopy before\", charmListCopy);\n charmListCopy.splice(index, 1);\n console.log(\"charmListCopy after\", charmListCopy);\n state.allCharms.set(charmListCopy);\n }\n});\n\nconst spawnChatList = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(ChatList({\n selectedCharm: { charm: undefined },\n charmsList: [],\n allCharms: state.allCharms, // we should handle empty here\n }));\n});\n\nconst spawnChatbot = handler<\n Record,\n Record\n>((_, state) => {\n return navigateTo(Chatbot({\n messages: [],\n tools: undefined,\n }));\n});\n\nconst spawnChatbotOutliner = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(ChatbotOutliner({\n title: \"Chatbot Outliner\",\n expandChat: false,\n messages: [],\n outline: {\n root: { body: \"\", children: [], attachments: [] },\n },\n allCharms: state.allCharms,\n }));\n});\n\nconst spawnNote = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(Note({\n title: \"New Note\",\n content: \"\",\n allCharms: state.allCharms,\n }));\n});\n\nexport default recipe(\n \"DefaultCharmList\",\n ({ allCharms }) => {\n return {\n [NAME]: str`DefaultCharmList (${allCharms.length})`,\n [UI]: (\n \n ,\n })}\n />\n\n \n {/* Quick Launch Toolbar */}\n \n

Quicklaunch:

\n ,\n })}\n >\n 📂 Chat List\n \n \n 💬 Chatbot\n \n \n 📝 Chatbot Outliner\n \n ,\n })}\n >\n 📄 Note\n \n
\n\n

Charms ({allCharms.length})

\n\n \n \n \n Charm Name\n Actions\n \n \n \n {derive(allCharms, (allCharms) =>\n allCharms.map((charm: any) => (\n \n {charm[NAME] || \"Untitled Charm\"}\n \n \n \n Visit\n \n \n Remove\n \n \n \n \n )))}\n \n \n
\n
\n ),\n };\n },\n);\n" }, { "name": "/chatbot.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n generateObject,\n h,\n handler,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n recipe,\n str,\n Stream,\n UI,\n} from \"commontools\";\n\nconst sendMessage = handler<\n { detail: { message: string } },\n {\n addMessage: Stream;\n }\n>((event, { addMessage }) => {\n addMessage.send({\n role: \"user\",\n content: [{ type: \"text\", text: event.detail.message }],\n });\n});\n\nconst clearChat = handler(\n (\n _: never,\n { messages, pending }: {\n messages: Cell>;\n pending: Cell;\n },\n ) => {\n messages.set([]);\n pending.set(false);\n },\n);\n\ntype ChatInput = {\n messages: Default, []>;\n tools: any;\n theme?: any;\n};\n\ntype ChatOutput = {\n messages: Array;\n pending: boolean | undefined;\n addMessage: Stream;\n cancelGeneration: Stream;\n title?: string;\n};\n\nexport const TitleGenerator = recipe<\n { model?: string; messages: Array }\n>(\"Title Generator\", ({ model, messages }) => {\n const titleMessages = derive(messages, (m) => {\n if (!m || m.length === 0) return \"\";\n\n const messageCount = 2;\n const selectedMessages = m.slice(0, messageCount).filter(Boolean);\n\n if (selectedMessages.length === 0) return \"\";\n\n return selectedMessages.map((msg) => JSON.stringify(msg)).join(\"\\n\");\n });\n\n const { result } = generateObject({\n system:\n \"Generate at most a 3-word title based on the following content, respond with NOTHING but the literal title text.\",\n prompt: titleMessages,\n model,\n schema: {\n type: \"object\",\n properties: {\n title: {\n type: \"string\",\n description: \"The title of the chat\",\n },\n },\n required: [\"title\"],\n },\n });\n\n const title = derive(result, (t) => {\n return t?.title || \"Untitled Chat\";\n });\n\n return title;\n});\n\nexport default recipe(\n \"Chat\",\n ({ messages, tools, theme }) => {\n const model = cell(\"anthropic:claude-sonnet-4-5\");\n\n const { addMessage, cancelGeneration, pending } = llmDialog({\n system: \"You are a helpful assistant with some tools.\",\n messages,\n tools,\n model,\n });\n\n const { result } = fetchData({\n url: \"/api/ai/llm/models\",\n mode: \"json\",\n });\n\n const items = derive(result, (models) => {\n if (!models) return [];\n const items = Object.keys(models as any).map((key) => ({\n label: key,\n value: key,\n }));\n return items;\n });\n\n const title = TitleGenerator({ model, messages });\n\n return {\n [NAME]: title,\n [UI]: (\n \n \n {title}\n \n \n\n \n \n \n\n
\n \n \n
\n
\n ),\n messages,\n pending,\n addMessage,\n cancelGeneration,\n title,\n };\n },\n);\n" }, { "name": "/chatbot-outliner.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n getRecipeEnvironment,\n h,\n handler,\n ID,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n str,\n Stream,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot.tsx\";\n\ntype Charm = any;\n\ntype OutlinerNode = {\n body: Default;\n children: Default;\n attachments: Default[], []>;\n};\n\ntype Outliner = {\n root: OutlinerNode;\n};\n\ntype PageResult = {\n outline: Default<\n Outliner,\n { root: { body: \"\"; children: []; attachments: [] } }\n >;\n};\n\nexport type PageInput = {\n outline: Outliner;\n allCharms: Cell;\n};\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nexport const Page = recipe(\n \"Page\",\n ({ outline, allCharms }) => {\n return {\n [NAME]: \"Page\",\n [UI]: (\n \n ),\n outline,\n };\n },\n);\n\ntype LLMTestInput = {\n title: Default;\n messages: Default, []>;\n expandChat: Default;\n outline: Default<\n Outliner,\n { root: { body: \"Untitled Page\"; children: []; attachments: [] } }\n >;\n allCharms: Cell;\n};\n\ntype LLMTestResult = {\n messages: Default, []>;\n};\n\n// put a node at the end of the outline (by appending to root.children)\nconst appendOutlinerNode = handler<\n {\n /** The text content/title of the outliner node to be appended */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { outline: Cell }\n>(\n (args, state) => {\n try {\n (state.outline.key(\"root\").key(\"children\")).push({\n body: args.body,\n children: [],\n attachments: [],\n });\n\n args.result.set(\n `${state.outline.key(\"root\").key(\"children\").get().length} nodes`,\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport default recipe(\n \"Outliner\",\n ({ title, expandChat, messages, outline, allCharms }) => {\n const tools = {\n appendOutlinerNode: {\n description: \"Add a new outliner node.\",\n inputSchema: {\n type: \"object\",\n properties: {\n body: {\n type: \"string\",\n description: \"The title of the new node.\",\n },\n },\n required: [\"body\"],\n } as JSONSchema,\n handler: appendOutlinerNode({ outline }),\n },\n };\n\n const chat = Chat({ messages, tools });\n const { addMessage, cancelGeneration, pending } = chat;\n\n return {\n [NAME]: title,\n [UI]: (\n \n \n
\n
\n Show Chat\n
\n
\n\n \n \n
\n \n
\n\n \n \n \n \n \n
\n\n {ifElse(\n expandChat,\n chat,\n null,\n )}\n
\n
\n ),\n messages,\n };\n },\n);\n" }, { "name": "/chatbot-note-composed.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n getRecipeEnvironment,\n h,\n handler,\n ID,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n str,\n Stream,\n toSchema,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot.tsx\";\nimport Note from \"./note.tsx\";\nimport Tools, {\n addListItem,\n calculator,\n ListItem,\n readListItems,\n readWebpage,\n searchWeb,\n} from \"./common-tools.tsx\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\n// export type ChatbotNoteInput = {\n// content: Default;\n// allCharms?: Cell;\n// };\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\ntype ChatbotNoteInput = {\n title: Default;\n messages: Default, []>;\n content: Default;\n allCharms: Cell;\n};\n\ntype ChatbotNoteResult = {\n messages: Default, []>;\n mentioned: Default, []>;\n backlinks: Default, []>;\n content: Default;\n note: any;\n chat: any;\n list: Default;\n};\n\nconst newNote = handler<\n {\n /** The text content of the note */\n title: string;\n content?: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const n = Note({\n title: args.title,\n content: args.content || \"\",\n allCharms: state.allCharms,\n });\n\n args.result.set(\n `Created note ${args.title}!`,\n );\n\n state.allCharms.push(n as unknown as MentionableCharm);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\n// put a note at the end of the outline (by appending to root.children)\nconst editNote = handler<\n {\n /** The text content of the note */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { content: Cell }\n>(\n (args, state) => {\n try {\n state.content.set(args.body);\n\n args.result.set(\n `Updated note!`,\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst readNote = handler<\n {\n /** A cell to store the result text */\n result: Cell;\n },\n { content: string }\n>(\n (args, state) => {\n try {\n args.result.set(state.content);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst listMentionable = handler<\n {\n /** A cell to store the result text */\n result: Cell;\n },\n { allCharms: { [NAME]: string }[] }\n>(\n (args, state) => {\n try {\n const namesList = state.allCharms.map((charm) => charm[NAME]);\n args.result.set(JSON.stringify(namesList));\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst readNoteByIndex = handler<\n {\n /** A cell to store the result text */\n index: number;\n result: Cell;\n },\n { allCharms: { [NAME]: string; content?: string }[] }\n>(\n (args, state) => {\n try {\n args.result.set(\n state.allCharms[args.index]?.content || \"No content found\",\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst editNoteByIndex = handler<\n {\n /** The index of the note to edit */\n index: number;\n /** The new text content of the note */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const charms = state.allCharms.get();\n if (args.index < 0 || args.index >= charms.length) {\n args.result.set(`Error: Invalid index ${args.index}`);\n return;\n }\n\n state.allCharms.key(args.index).key(\"content\").set(args.body);\n args.result.set(`Updated note at index ${args.index}!`);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst navigateToNote = handler<\n {\n /** The index of the note to navigate to */\n index: number;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const charms = state.allCharms.get();\n if (args.index < 0 || args.index >= charms.length) {\n args.result.set(`Error: Invalid index ${args.index}`);\n return;\n }\n\n const targetCharm = charms[args.index];\n args.result.set(`Navigating to note: ${targetCharm[NAME]}`);\n\n return navigateTo(state.allCharms.key(args.index));\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport default recipe(\n \"Chatbot + Note\",\n ({ title, messages, content, allCharms }) => {\n const list = cell([]);\n\n const tools = {\n searchWeb: {\n pattern: searchWeb,\n },\n readWebpage: {\n pattern: readWebpage,\n },\n calculator: {\n pattern: calculator,\n },\n addListItem: {\n handler: addListItem({ list }),\n },\n readListItems: {\n handler: readListItems({ list }),\n },\n editActiveNote: {\n description: \"Modify the shared note.\",\n inputSchema: {\n type: \"object\",\n properties: {\n body: {\n type: \"string\",\n description: \"The content of the note.\",\n },\n },\n required: [\"body\"],\n } as JSONSchema,\n handler: editNote({ content }),\n },\n readActiveNote: {\n description: \"Read the currently focused note.\",\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n } as JSONSchema,\n handler: readNote({ content }),\n },\n listNotes: {\n description:\n \"List all mentionable note titles (read the body with readNoteByIndex).\",\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n } as JSONSchema,\n handler: listMentionable({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n readNoteByIndex: {\n description:\n \"Read the body of a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n },\n required: [\"index\"],\n } as JSONSchema,\n handler: readNoteByIndex({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n editNoteByIndex: {\n description:\n \"Edit the body of a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n body: {\n type: \"string\",\n description: \"The new content of the note.\",\n },\n },\n required: [\"index\", \"body\"],\n } as JSONSchema,\n handler: editNoteByIndex({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n navigateToNote: {\n description: \"Navigate to a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n },\n required: [\"index\"],\n } as JSONSchema,\n handler: navigateToNote({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n newNote: {\n description: \"Read the shared note.\",\n inputSchema: {\n type: \"object\",\n properties: {\n title: {\n type: \"string\",\n description: \"The title of the note.\",\n },\n content: {\n type: \"string\",\n description: \"The content of the note.\",\n },\n },\n required: [\"title\"],\n } as JSONSchema,\n handler: newNote({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n };\n\n const chat = Chat({ messages, tools });\n const note = Note({ title, content, allCharms });\n\n return {\n [NAME]: title,\n chat,\n note,\n content,\n messages,\n mentioned: note.mentioned,\n backlinks: note.backlinks,\n list,\n };\n },\n);\n" }, { "name": "/note.tsx", "contents": "/// \nimport {\n Cell,\n cell,\n Default,\n derive,\n h,\n handler,\n lift,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n toSchema,\n UI,\n} from \"commontools\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\ntype Input = {\n title: Default;\n content: Default;\n allCharms: Cell;\n};\n\ntype Output = {\n mentioned: Default, []>;\n content: Default;\n backlinks: Default, []>;\n};\n\nconst updateTitle = handler<\n { detail: { value: string } },\n { title: Cell }\n>(\n (event, state) => {\n state.title.set(event.detail?.value ?? \"\");\n },\n);\n\nconst updateContent = handler<\n { detail: { value: string } },\n { content: Cell }\n>(\n (event, state) => {\n state.content.set(event.detail?.value ?? \"\");\n },\n);\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nconst handleNewBacklink = handler<\n {\n detail: {\n text: string;\n charmId: any;\n charm: Cell;\n navigate: boolean;\n };\n },\n {\n allCharms: Cell;\n }\n>(({ detail }, { allCharms }) => {\n console.log(\"new charm\", detail.text, detail.charmId);\n\n if (detail.navigate) {\n return navigateTo(detail.charm);\n } else {\n allCharms.push(detail.charm as unknown as MentionableCharm);\n }\n});\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\nconst Note = recipe(\n \"Note\",\n ({ title, content, allCharms }) => {\n const mentioned = cell([]);\n\n const computeBacklinks = lift<\n { allCharms: Cell; content: Cell },\n MentionableCharm[]\n >(\n ({ allCharms, content }) => {\n const cs = allCharms.get();\n if (!cs) return [];\n\n const self = cs.find((c) => c.content === content.get());\n\n const results = self\n ? cs.filter((c) =>\n c.mentioned?.some((m) => m.content === self.content) ?? false\n )\n : [];\n\n return results;\n },\n );\n\n const backlinks: OpaqueRef = computeBacklinks({\n allCharms,\n content: content as unknown as Cell, // TODO(bf): this is valid, but types complain\n });\n\n // The only way to serialize a pattern, apparently?\n const pattern = derive(undefined, () => JSON.stringify(Note));\n\n return {\n [NAME]: title,\n [UI]: (\n \n
\n \n
\n\n \n
\n ),\n title,\n content,\n mentioned,\n backlinks,\n };\n },\n);\n\nexport default Note;\n" }, { "name": "/chatbot-list-view.tsx", "contents": "/// \nimport {\n Cell,\n cell,\n Default,\n derive,\n h,\n handler,\n ID,\n ifElse,\n lift,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n toSchema,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot-note-composed.tsx\";\nimport { ListItem } from \"./common-tools.tsx\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\ntype CharmEntry = {\n [ID]: string; // randomId is a string\n local_id: string; // same as ID but easier to access\n charm: any;\n};\n\ntype Input = {\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\n charmsList: Default;\n allCharms: Cell;\n theme?: {\n accentColor: Default;\n fontFace: Default;\n borderRadius: Default;\n };\n};\n\ntype Output = {\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\n};\n\nconst removeChat = handler<\n unknown,\n {\n charmsList: Cell;\n id: string;\n selectedCharm: Cell>;\n }\n>(\n (\n _,\n { charmsList, id, selectedCharm },\n ) => {\n const list = charmsList.get();\n const index = list.findIndex((entry) => entry.local_id === id);\n if (index === -1) return;\n\n const removed = list[index];\n const next = [...list];\n next.splice(index, 1);\n charmsList.set(next);\n\n // If we removed the currently selected charm, choose a new selection.\n const current = selectedCharm.get();\n if (current?.charm === removed.charm) {\n const replacement = next[index] ?? next[index - 1];\n if (replacement) {\n selectedCharm.set({ charm: replacement.charm });\n } else {\n selectedCharm.set({ charm: undefined as unknown as any });\n }\n }\n },\n);\n\n// this will be called whenever charm or selectedCharm changes\n// pass isInitialized to make sure we dont call this each time\n// we change selectedCharm, otherwise creates a loop\nconst storeCharm = lift(\n toSchema<{\n charm: any;\n selectedCharm: Cell>;\n charmsList: Cell;\n allCharms: Cell;\n theme?: {\n accentColor: Default;\n fontFace: Default;\n borderRadius: Default;\n };\n isInitialized: Cell;\n }>(),\n undefined,\n ({ charm, selectedCharm, charmsList, isInitialized, allCharms }) => { // Not including `allCharms` is a compile error...\n if (!isInitialized.get()) {\n console.log(\n \"storeCharm storing charm:\",\n charm,\n );\n selectedCharm.set({ charm });\n\n // create the chat charm with a custom name including a random suffix\n const randomId = Math.random().toString(36).substring(2, 10); // Random 8-char string\n charmsList.push({ [ID]: randomId, local_id: randomId, charm });\n\n isInitialized.set(true);\n return charm;\n } else {\n console.log(\"storeCharm: already initialized\");\n }\n return undefined;\n },\n);\n\nconst populateChatList = lift(\n toSchema<{\n charmsList: CharmEntry[];\n allCharms: Cell;\n selectedCharm: Cell<{ charm: any }>;\n }>(),\n undefined,\n (\n { charmsList, allCharms, selectedCharm },\n ) => {\n if (charmsList.length === 0) {\n const isInitialized = cell(false);\n return storeCharm({\n charm: Chat({\n title: \"New Chat\",\n messages: [],\n content: \"\",\n allCharms,\n }),\n selectedCharm,\n charmsList,\n allCharms,\n isInitialized: isInitialized as unknown as Cell,\n });\n }\n\n return charmsList;\n },\n);\n\nconst createChatRecipe = handler<\n unknown,\n {\n selectedCharm: Cell<{ charm: any }>;\n charmsList: Cell;\n allCharms: Cell;\n }\n>(\n (_, { selectedCharm, charmsList, allCharms }) => {\n const isInitialized = cell(false);\n\n const charm = Chat({\n title: \"New Chat\",\n messages: [],\n content: \"\",\n allCharms,\n });\n // store the charm ref in a cell (pass isInitialized to prevent recursive calls)\n return storeCharm({\n charm,\n selectedCharm,\n charmsList: charmsList as unknown as OpaqueRef,\n allCharms,\n isInitialized: isInitialized as unknown as Cell,\n });\n },\n);\n\nconst selectCharm = handler<\n unknown,\n { selectedCharm: Cell<{ charm: any }>; charm: any }\n>(\n (_, { selectedCharm, charm }) => {\n console.log(\"selectCharm: updating selectedCharm to \", charm);\n selectedCharm.set({ charm });\n return selectedCharm;\n },\n);\n\nconst logCharmsList = lift<\n { charmsList: Cell },\n Cell\n>(\n ({ charmsList }) => {\n console.log(\"logCharmsList: \", charmsList.get());\n return charmsList;\n },\n);\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\nconst combineLists = lift(\n (\n { allCharms, charmsList }: { allCharms: any[]; charmsList: CharmEntry[] },\n ) => {\n return [...charmsList.map((c) => c.charm), ...allCharms];\n },\n);\n\nconst getSelectedCharm = lift<\n { entry: { charm: any | undefined } },\n {\n chat: unknown;\n note: unknown;\n list: ListItem[];\n backlinks: MentionableCharm[];\n mentioned: MentionableCharm[];\n } | undefined\n>(\n ({ entry }) => {\n return entry?.charm;\n },\n);\n\nconst getCharmName = lift(({ charm }: { charm: any }) => {\n return charm?.[NAME] || \"Unknown\";\n});\n\n// create the named cell inside the recipe body, so we do it just once\nexport default recipe(\n \"Launcher\",\n ({ selectedCharm, charmsList, allCharms, theme }) => {\n logCharmsList({ charmsList: charmsList as unknown as Cell });\n\n populateChatList({\n selectedCharm: selectedCharm as unknown as Cell<\n Pick\n >,\n charmsList,\n allCharms,\n });\n\n const combined = combineLists({\n allCharms: allCharms as unknown as any[],\n charmsList,\n });\n\n const selected = getSelectedCharm({ entry: selectedCharm });\n\n const localTheme = theme ?? {\n accentColor: cell(\"#3b82f6\"),\n fontFace: cell(\"system-ui, -apple-system, sans-serif\"),\n borderRadius: cell(\"0.5rem\"),\n };\n\n return {\n [NAME]: \"Launcher\",\n [UI]: (\n \n \n
\n \n
\n \n Create New Chat\n alt+N\n \n
\n
\n\n {/* Keyboard shortcuts */}\n \n
\n \n {/* workaround: this seems to correctly start the sub-recipes on a refresh while directly rendering does not */}\n {/* this should be fixed after the builder-refactor (DX1) */}\n \n \n \n \n \n \n\n \n\n \n \n
\n
\n ),\n selectedCharm,\n charmsList,\n };\n },\n);\n" }, { "name": "/common-tools.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n BuiltInLLMTool,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n h,\n handler,\n ifElse,\n llmDialog,\n NAME,\n recipe,\n Stream,\n UI,\n} from \"commontools\";\n\n///// COMMON TOOLS (get it?) ////\n\n/**\n * Calculate the result of a mathematical expression.\n * Supports +, -, *, /, and parentheses.\n */\ntype CalculatorRequest = {\n /** The mathematical expression to evaluate. */\n expression: string;\n};\n\nexport const calculator = recipe<\n CalculatorRequest,\n string | { error: string }\n>(\"Calculator\", ({ expression }) => {\n return derive(expression, (expr) => {\n const sanitized = expr.replace(/[^0-9+\\-*/().\\s]/g, \"\");\n let result;\n try {\n result = Function(`\"use strict\"; return (${sanitized})`)();\n } catch (error) {\n result = { error: (error as any)?.message || \"\" };\n }\n return result;\n });\n});\n\n/** Add an item to the list. */\ntype AddListItemRequest = {\n /** The item to add to the list. */\n item: string;\n result: Cell;\n};\n\n/** Read all items from the list. */\ntype ReadListItemsRequest = {\n result: Cell;\n};\n\nexport type ListItem = {\n title: string;\n};\n\nexport const addListItem = handler<\n AddListItemRequest,\n { list: Cell }\n>(\n (args, state) => {\n try {\n state.list.push({ title: args.item });\n args.result.set(`${state.list.get().length} items`);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport const readListItems = handler<\n ReadListItemsRequest,\n { list: ListItem[] }\n>(\n (args, state) => {\n try {\n const items = state.list;\n if (items.length === 0) {\n args.result.set(\"The list is empty\");\n } else {\n const itemList = items.map((item, index) =>\n `${index + 1}. ${item.title}`\n ).join(\"\\n\");\n args.result.set(`List items (${items.length} total):\\n${itemList}`);\n }\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\n/** Search the web for information. */\ntype SearchQuery = {\n /** The query to search the web for. */\n query: string;\n};\n\ntype SearchWebResult = {\n results: {\n title: string;\n url: string;\n description: string;\n }[];\n};\n\nexport const searchWeb = recipe<\n SearchQuery,\n SearchWebResult | { error: string }\n>(\"Search Web\", ({ query }) => {\n const { result, error } = fetchData({\n url: \"/api/agent-tools/web-search\",\n mode: \"json\",\n options: {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: {\n query,\n max_results: 5,\n },\n },\n });\n\n // TODO(seefeld): Should we instead return { result, error }? Or allocate a\n // special [ERROR] for errors? Ideally this isn\\'t specific to using recipes as\n // tools but a general pattern.\n return ifElse(error, { error }, result);\n});\n\n/** Read and extract content from a specific webpage URL. */\ntype ReadWebRequest = {\n /** The URL of the webpage to read and extract content from. */\n url: string;\n};\n\ntype ReadWebResult = {\n content: string;\n metadata: {\n title?: string;\n author?: string;\n date?: string;\n word_count: number;\n };\n};\n\nexport const readWebpage = recipe<\n ReadWebRequest,\n ReadWebResult | { error: string }\n>(\"Read Webpage\", ({ url }) => {\n const { result, error } = fetchData({\n url: \"/api/agent-tools/web-read\",\n mode: \"json\",\n options: {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: {\n url,\n max_tokens: 4000,\n include_code: true,\n },\n },\n });\n\n return ifElse(error, { error }, result);\n});\n\ntype ToolsInput = {\n list: ListItem[];\n};\n\nexport default recipe(\"Tools\", ({ list }) => {\n const tools: Record = {\n search_web: {\n pattern: searchWeb,\n },\n read_webpage: {\n pattern: readWebpage,\n },\n calculator: {\n pattern: calculator,\n },\n addListItem: {\n handler: addListItem({ list }),\n },\n };\n\n return { tools, list };\n});\n" } ] } } }, "since": 10 } } }, "of:baedreih3s7r744kith3ntkg6oooklw2sy2vyycy22zlmm4l7rnizislpqa": { "application/json": { "ba4jcayx527rfjibrx52vqus25gkki536ox6xrx5droaurr2b4vvh6rzo": { "is": { "source": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" }, "value": { "$NAME": { "$alias": { "path": [ "argument", "title" ], "schema": { "type": "string", "default": "LLM Test" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "LLM Test" }, "messages": { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMMessage" }, "default": [] }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "messages", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] }, "BuiltInLLMMessage": { "type": "object", "properties": { "role": { "enum": [ "system", "user", "assistant", "tool" ] }, "content": { "$ref": "#/$defs/BuiltInLLMContent" } }, "required": [ "role", "content" ] }, "BuiltInLLMContent": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMContentPart" } } ] }, "BuiltInLLMContentPart": { "anyOf": [ { "$ref": "#/$defs/BuiltInLLMTextPart" }, { "$ref": "#/$defs/BuiltInLLMImagePart" }, { "$ref": "#/$defs/BuiltInLLMToolCallPart" }, { "$ref": "#/$defs/BuiltInLLMToolResultPart" } ] }, "BuiltInLLMToolResultPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-result" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "output": { "anyOf": [ { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "value": { "type": "string" } }, "required": [ "type", "value" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "json" ] }, "value": true }, "required": [ "type", "value" ] } ] } }, "required": [ "type", "toolCallId", "toolName", "output" ] }, "BuiltInLLMToolCallPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-call" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "input": { "$ref": "#/$defs/Record" } }, "required": [ "type", "toolCallId", "toolName", "input" ] }, "Record": { "type": "object", "properties": { }, "additionalProperties": true }, "BuiltInLLMImagePart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "image" ] }, "image": { "anyOf": [ { "type": "string" }, true, true, { "type": "string", "format": "uri" } ] } }, "required": [ "type", "image" ] }, "BuiltInLLMTextPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "text": { "type": "string" } }, "required": [ "type", "text" ] } } }, "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } }, "chat": { "$alias": { "path": [ "internal", "chat" ], "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } }, "note": { "$alias": { "path": [ "internal", "note" ], "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } }, "content": { "$alias": { "path": [ "argument", "content" ], "schema": { "type": "string", "default": "" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "LLM Test" }, "messages": { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMMessage" }, "default": [] }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "messages", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] }, "BuiltInLLMMessage": { "type": "object", "properties": { "role": { "enum": [ "system", "user", "assistant", "tool" ] }, "content": { "$ref": "#/$defs/BuiltInLLMContent" } }, "required": [ "role", "content" ] }, "BuiltInLLMContent": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMContentPart" } } ] }, "BuiltInLLMContentPart": { "anyOf": [ { "$ref": "#/$defs/BuiltInLLMTextPart" }, { "$ref": "#/$defs/BuiltInLLMImagePart" }, { "$ref": "#/$defs/BuiltInLLMToolCallPart" }, { "$ref": "#/$defs/BuiltInLLMToolResultPart" } ] }, "BuiltInLLMToolResultPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-result" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "output": { "anyOf": [ { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "value": { "type": "string" } }, "required": [ "type", "value" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "json" ] }, "value": true }, "required": [ "type", "value" ] } ] } }, "required": [ "type", "toolCallId", "toolName", "output" ] }, "BuiltInLLMToolCallPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-call" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "input": { "$ref": "#/$defs/Record" } }, "required": [ "type", "toolCallId", "toolName", "input" ] }, "Record": { "type": "object", "properties": { }, "additionalProperties": true }, "BuiltInLLMImagePart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "image" ] }, "image": { "anyOf": [ { "type": "string" }, true, true, { "type": "string", "format": "uri" } ] } }, "required": [ "type", "image" ] }, "BuiltInLLMTextPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "text": { "type": "string" } }, "required": [ "type", "text" ] } } }, "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } }, "messages": { "$alias": { "path": [ "argument", "messages" ], "schema": { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMMessage" }, "default": [] }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "LLM Test" }, "messages": { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMMessage" }, "default": [] }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "messages", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] }, "BuiltInLLMMessage": { "type": "object", "properties": { "role": { "enum": [ "system", "user", "assistant", "tool" ] }, "content": { "$ref": "#/$defs/BuiltInLLMContent" } }, "required": [ "role", "content" ] }, "BuiltInLLMContent": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMContentPart" } } ] }, "BuiltInLLMContentPart": { "anyOf": [ { "$ref": "#/$defs/BuiltInLLMTextPart" }, { "$ref": "#/$defs/BuiltInLLMImagePart" }, { "$ref": "#/$defs/BuiltInLLMToolCallPart" }, { "$ref": "#/$defs/BuiltInLLMToolResultPart" } ] }, "BuiltInLLMToolResultPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-result" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "output": { "anyOf": [ { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "value": { "type": "string" } }, "required": [ "type", "value" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "json" ] }, "value": true }, "required": [ "type", "value" ] } ] } }, "required": [ "type", "toolCallId", "toolName", "output" ] }, "BuiltInLLMToolCallPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-call" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "input": { "$ref": "#/$defs/Record" } }, "required": [ "type", "toolCallId", "toolName", "input" ] }, "Record": { "type": "object", "properties": { }, "additionalProperties": true }, "BuiltInLLMImagePart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "image" ] }, "image": { "anyOf": [ { "type": "string" }, true, true, { "type": "string", "format": "uri" } ] } }, "required": [ "type", "image" ] }, "BuiltInLLMTextPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "text": { "type": "string" } }, "required": [ "type", "text" ] } } }, "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } }, "mentioned": { "$alias": { "path": [ "internal", "note", "mentioned" ], "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } }, "backlinks": { "$alias": { "path": [ "internal", "note", "backlinks" ], "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } }, "list": { "$alias": { "path": [ "internal", "list" ], "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } } } }, "since": 17 } } }, "of:baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy": { "application/json": { "ba4jcadiaault4t5qhzfnrgl3xjdom2ugglsj36qdbvnjkd6riv5yikrb": { "is": { "value": { "$TYPE": "ba4jcbnvt4wgnz4kl4oy4me5odwt4bzdxal5yyyisakv52a2ihfryinkw", "resultRef": { "/": { "link@1": { "path": [], "id": "of:baedreih3s7r744kith3ntkg6oooklw2sy2vyycy22zlmm4l7rnizislpqa" } } }, "internal": { "$event": { "$stream": true }, "__#0stream": { "$stream": true }, "__#1stream": { "$stream": true }, "__#2stream": { "$stream": true }, "__#3stream": { "$stream": true }, "note": { "/": { "link@1": { "path": [], "id": "of:baedreifb44fs5axxlfrqgz2hgnaj5hsmone73fwpadd3pyvwcyfdiyvcg4" } } }, "__#4stream": { "$stream": true }, "__#5stream": { "$stream": true }, "list": [], "__#6stream": { "$stream": true }, "__#7stream": { "$stream": true }, "chat": { "/": { "link@1": { "path": [], "id": "of:baedreif3pbfllprvaib562wi254n6pzcge6jed7jmbkxidfgcsntd7ului" } } } }, "spell": { "/": { "link@1": { "id": "of:baedreic6kkn6frrhxluqz63hfv7jf3ta6hppcjz7non2pwj33tdmcoso4u" } } }, "argument": { "title": "New Chat", "messages": [], "content": "[[one (baedreidvk42ywcn6n6ucdpfg2pvi5o6p3njkk6rltyvydkkbjcco5m4wcu)]]\n[[two (baedreibninu5twfm72l6gs5sbaghg6gdtmn2365encfoinebrvnsmavrr4)]]\n[[three (baedreibyolwzasa3njbwrwexvtolf7b7x5wh5lkwkepa5jbc6paghoc5ua)]]\n[[four (baedreigyxxqptxd2vlfwxnhzdwdha32i4ou5onzw6ruunaqudg5u42agva)]]\n", "allCharms": { "$alias": { "cell": { "/": "baedreiahv63wxwgaem4hzjkizl4qncfgvca7pj5cvdon7cukumfon3ioye" }, "path": [] } } } } }, "since": 97 } } }, "of:baedreic6kkn6frrhxluqz63hfv7jf3ta6hppcjz7non2pwj33tdmcoso4u": { "application/json": { "ba4jcaeb5ln6pvlsfyq7eyk2wjvowbzqi6vcz4mas7m2vgjx5kcfvtynl": { "is": { "value": { "id": "ba4jcbnvt4wgnz4kl4oy4me5odwt4bzdxal5yyyisakv52a2ihfryinkw", "program": { "main": "/chatbot-note-composed.tsx", "mainExport": "default", "files": [ { "name": "/default-app.tsx", "contents": "/// \nimport {\n Cell,\n Default,\n derive,\n h,\n handler,\n NAME,\n navigateTo,\n Opaque,\n OpaqueRef,\n recipe,\n str,\n UI,\n} from \"commontools\";\n\n// Import recipes we want to be launchable from the default app.\nimport Chatbot from \"./chatbot.tsx\";\nimport ChatbotOutliner from \"./chatbot-outliner.tsx\";\nimport { type MentionableCharm } from \"./chatbot-note-composed.tsx\";\nimport { default as Note } from \"./note.tsx\";\nimport ChatList from \"./chatbot-list-view.tsx\";\n\nexport type Charm = {\n [NAME]?: string;\n [UI]?: unknown;\n [key: string]: any;\n};\n\ntype CharmsListInput = {\n allCharms: Default;\n};\n\n// Recipe returns only UI, no data outputs (only symbol properties)\ninterface CharmsListOutput {\n [key: string]: unknown;\n}\n\nconst visit = handler<\n Record,\n { charm: any }\n>((_, state) => {\n return navigateTo(state.charm);\n}, { proxy: true });\n\nconst removeCharm = handler<\n Record,\n {\n charm: any;\n allCharms: Cell;\n }\n>((_, state) => {\n const charmName = state.charm[NAME];\n const allCharmsValue = state.allCharms.get();\n const index = allCharmsValue.findIndex((c: any) => c[NAME] === charmName);\n\n if (index !== -1) {\n const charmListCopy = [...allCharmsValue];\n console.log(\"charmListCopy before\", charmListCopy);\n charmListCopy.splice(index, 1);\n console.log(\"charmListCopy after\", charmListCopy);\n state.allCharms.set(charmListCopy);\n }\n});\n\nconst spawnChatList = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(ChatList({\n selectedCharm: { charm: undefined },\n charmsList: [],\n allCharms: state.allCharms, // we should handle empty here\n }));\n});\n\nconst spawnChatbot = handler<\n Record,\n Record\n>((_, state) => {\n return navigateTo(Chatbot({\n messages: [],\n tools: undefined,\n }));\n});\n\nconst spawnChatbotOutliner = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(ChatbotOutliner({\n title: \"Chatbot Outliner\",\n expandChat: false,\n messages: [],\n outline: {\n root: { body: \"\", children: [], attachments: [] },\n },\n allCharms: state.allCharms,\n }));\n});\n\nconst spawnNote = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(Note({\n title: \"New Note\",\n content: \"\",\n allCharms: state.allCharms,\n }));\n});\n\nexport default recipe(\n \"DefaultCharmList\",\n ({ allCharms }) => {\n return {\n [NAME]: str`DefaultCharmList (${allCharms.length})`,\n [UI]: (\n \n ,\n })}\n />\n\n \n {/* Quick Launch Toolbar */}\n \n

Quicklaunch:

\n ,\n })}\n >\n 📂 Chat List\n \n \n 💬 Chatbot\n \n \n 📝 Chatbot Outliner\n \n ,\n })}\n >\n 📄 Note\n \n
\n\n

Charms ({allCharms.length})

\n\n \n \n \n Charm Name\n Actions\n \n \n \n {derive(allCharms, (allCharms) =>\n allCharms.map((charm: any) => (\n \n {charm[NAME] || \"Untitled Charm\"}\n \n \n \n Visit\n \n \n Remove\n \n \n \n \n )))}\n \n \n
\n
\n ),\n };\n },\n);\n" }, { "name": "/chatbot.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n generateObject,\n h,\n handler,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n recipe,\n str,\n Stream,\n UI,\n} from \"commontools\";\n\nconst sendMessage = handler<\n { detail: { message: string } },\n {\n addMessage: Stream;\n }\n>((event, { addMessage }) => {\n addMessage.send({\n role: \"user\",\n content: [{ type: \"text\", text: event.detail.message }],\n });\n});\n\nconst clearChat = handler(\n (\n _: never,\n { messages, pending }: {\n messages: Cell>;\n pending: Cell;\n },\n ) => {\n messages.set([]);\n pending.set(false);\n },\n);\n\ntype ChatInput = {\n messages: Default, []>;\n tools: any;\n theme?: any;\n};\n\ntype ChatOutput = {\n messages: Array;\n pending: boolean | undefined;\n addMessage: Stream;\n cancelGeneration: Stream;\n title?: string;\n};\n\nexport const TitleGenerator = recipe<\n { model?: string; messages: Array }\n>(\"Title Generator\", ({ model, messages }) => {\n const titleMessages = derive(messages, (m) => {\n if (!m || m.length === 0) return \"\";\n\n const messageCount = 2;\n const selectedMessages = m.slice(0, messageCount).filter(Boolean);\n\n if (selectedMessages.length === 0) return \"\";\n\n return selectedMessages.map((msg) => JSON.stringify(msg)).join(\"\\n\");\n });\n\n const { result } = generateObject({\n system:\n \"Generate at most a 3-word title based on the following content, respond with NOTHING but the literal title text.\",\n prompt: titleMessages,\n model,\n schema: {\n type: \"object\",\n properties: {\n title: {\n type: \"string\",\n description: \"The title of the chat\",\n },\n },\n required: [\"title\"],\n },\n });\n\n const title = derive(result, (t) => {\n return t?.title || \"Untitled Chat\";\n });\n\n return title;\n});\n\nexport default recipe(\n \"Chat\",\n ({ messages, tools, theme }) => {\n const model = cell(\"anthropic:claude-sonnet-4-5\");\n\n const { addMessage, cancelGeneration, pending } = llmDialog({\n system: \"You are a helpful assistant with some tools.\",\n messages,\n tools,\n model,\n });\n\n const { result } = fetchData({\n url: \"/api/ai/llm/models\",\n mode: \"json\",\n });\n\n const items = derive(result, (models) => {\n if (!models) return [];\n const items = Object.keys(models as any).map((key) => ({\n label: key,\n value: key,\n }));\n return items;\n });\n\n const title = TitleGenerator({ model, messages });\n\n return {\n [NAME]: title,\n [UI]: (\n \n \n {title}\n \n \n\n \n \n \n\n
\n \n \n
\n
\n ),\n messages,\n pending,\n addMessage,\n cancelGeneration,\n title,\n };\n },\n);\n" }, { "name": "/chatbot-outliner.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n getRecipeEnvironment,\n h,\n handler,\n ID,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n str,\n Stream,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot.tsx\";\n\ntype Charm = any;\n\ntype OutlinerNode = {\n body: Default;\n children: Default;\n attachments: Default[], []>;\n};\n\ntype Outliner = {\n root: OutlinerNode;\n};\n\ntype PageResult = {\n outline: Default<\n Outliner,\n { root: { body: \"\"; children: []; attachments: [] } }\n >;\n};\n\nexport type PageInput = {\n outline: Outliner;\n allCharms: Cell;\n};\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nexport const Page = recipe(\n \"Page\",\n ({ outline, allCharms }) => {\n return {\n [NAME]: \"Page\",\n [UI]: (\n \n ),\n outline,\n };\n },\n);\n\ntype LLMTestInput = {\n title: Default;\n messages: Default, []>;\n expandChat: Default;\n outline: Default<\n Outliner,\n { root: { body: \"Untitled Page\"; children: []; attachments: [] } }\n >;\n allCharms: Cell;\n};\n\ntype LLMTestResult = {\n messages: Default, []>;\n};\n\n// put a node at the end of the outline (by appending to root.children)\nconst appendOutlinerNode = handler<\n {\n /** The text content/title of the outliner node to be appended */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { outline: Cell }\n>(\n (args, state) => {\n try {\n (state.outline.key(\"root\").key(\"children\")).push({\n body: args.body,\n children: [],\n attachments: [],\n });\n\n args.result.set(\n `${state.outline.key(\"root\").key(\"children\").get().length} nodes`,\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport default recipe(\n \"Outliner\",\n ({ title, expandChat, messages, outline, allCharms }) => {\n const tools = {\n appendOutlinerNode: {\n description: \"Add a new outliner node.\",\n inputSchema: {\n type: \"object\",\n properties: {\n body: {\n type: \"string\",\n description: \"The title of the new node.\",\n },\n },\n required: [\"body\"],\n } as JSONSchema,\n handler: appendOutlinerNode({ outline }),\n },\n };\n\n const chat = Chat({ messages, tools });\n const { addMessage, cancelGeneration, pending } = chat;\n\n return {\n [NAME]: title,\n [UI]: (\n \n \n
\n
\n Show Chat\n
\n
\n\n \n \n
\n \n
\n\n \n \n \n \n \n
\n\n {ifElse(\n expandChat,\n chat,\n null,\n )}\n
\n
\n ),\n messages,\n };\n },\n);\n" }, { "name": "/chatbot-note-composed.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n getRecipeEnvironment,\n h,\n handler,\n ID,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n str,\n Stream,\n toSchema,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot.tsx\";\nimport Note from \"./note.tsx\";\nimport Tools, {\n addListItem,\n calculator,\n ListItem,\n readListItems,\n readWebpage,\n searchWeb,\n} from \"./common-tools.tsx\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\n// export type ChatbotNoteInput = {\n// content: Default;\n// allCharms?: Cell;\n// };\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\ntype ChatbotNoteInput = {\n title: Default;\n messages: Default, []>;\n content: Default;\n allCharms: Cell;\n};\n\ntype ChatbotNoteResult = {\n messages: Default, []>;\n mentioned: Default, []>;\n backlinks: Default, []>;\n content: Default;\n note: any;\n chat: any;\n list: Default;\n};\n\nconst newNote = handler<\n {\n /** The text content of the note */\n title: string;\n content?: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const n = Note({\n title: args.title,\n content: args.content || \"\",\n allCharms: state.allCharms,\n });\n\n args.result.set(\n `Created note ${args.title}!`,\n );\n\n state.allCharms.push(n as unknown as MentionableCharm);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\n// put a note at the end of the outline (by appending to root.children)\nconst editNote = handler<\n {\n /** The text content of the note */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { content: Cell }\n>(\n (args, state) => {\n try {\n state.content.set(args.body);\n\n args.result.set(\n `Updated note!`,\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst readNote = handler<\n {\n /** A cell to store the result text */\n result: Cell;\n },\n { content: string }\n>(\n (args, state) => {\n try {\n args.result.set(state.content);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst listMentionable = handler<\n {\n /** A cell to store the result text */\n result: Cell;\n },\n { allCharms: { [NAME]: string }[] }\n>(\n (args, state) => {\n try {\n const namesList = state.allCharms.map((charm) => charm[NAME]);\n args.result.set(JSON.stringify(namesList));\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst readNoteByIndex = handler<\n {\n /** A cell to store the result text */\n index: number;\n result: Cell;\n },\n { allCharms: { [NAME]: string; content?: string }[] }\n>(\n (args, state) => {\n try {\n args.result.set(\n state.allCharms[args.index]?.content || \"No content found\",\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst editNoteByIndex = handler<\n {\n /** The index of the note to edit */\n index: number;\n /** The new text content of the note */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const charms = state.allCharms.get();\n if (args.index < 0 || args.index >= charms.length) {\n args.result.set(`Error: Invalid index ${args.index}`);\n return;\n }\n\n state.allCharms.key(args.index).key(\"content\").set(args.body);\n args.result.set(`Updated note at index ${args.index}!`);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst navigateToNote = handler<\n {\n /** The index of the note to navigate to */\n index: number;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const charms = state.allCharms.get();\n if (args.index < 0 || args.index >= charms.length) {\n args.result.set(`Error: Invalid index ${args.index}`);\n return;\n }\n\n const targetCharm = charms[args.index];\n args.result.set(`Navigating to note: ${targetCharm[NAME]}`);\n\n return navigateTo(state.allCharms.key(args.index));\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport default recipe(\n \"Chatbot + Note\",\n ({ title, messages, content, allCharms }) => {\n const list = cell([]);\n\n const tools = {\n searchWeb: {\n pattern: searchWeb,\n },\n readWebpage: {\n pattern: readWebpage,\n },\n calculator: {\n pattern: calculator,\n },\n addListItem: {\n handler: addListItem({ list }),\n },\n readListItems: {\n handler: readListItems({ list }),\n },\n editActiveNote: {\n description: \"Modify the shared note.\",\n inputSchema: {\n type: \"object\",\n properties: {\n body: {\n type: \"string\",\n description: \"The content of the note.\",\n },\n },\n required: [\"body\"],\n } as JSONSchema,\n handler: editNote({ content }),\n },\n readActiveNote: {\n description: \"Read the currently focused note.\",\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n } as JSONSchema,\n handler: readNote({ content }),\n },\n listNotes: {\n description:\n \"List all mentionable note titles (read the body with readNoteByIndex).\",\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n } as JSONSchema,\n handler: listMentionable({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n readNoteByIndex: {\n description:\n \"Read the body of a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n },\n required: [\"index\"],\n } as JSONSchema,\n handler: readNoteByIndex({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n editNoteByIndex: {\n description:\n \"Edit the body of a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n body: {\n type: \"string\",\n description: \"The new content of the note.\",\n },\n },\n required: [\"index\", \"body\"],\n } as JSONSchema,\n handler: editNoteByIndex({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n navigateToNote: {\n description: \"Navigate to a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n },\n required: [\"index\"],\n } as JSONSchema,\n handler: navigateToNote({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n newNote: {\n description: \"Read the shared note.\",\n inputSchema: {\n type: \"object\",\n properties: {\n title: {\n type: \"string\",\n description: \"The title of the note.\",\n },\n content: {\n type: \"string\",\n description: \"The content of the note.\",\n },\n },\n required: [\"title\"],\n } as JSONSchema,\n handler: newNote({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n };\n\n const chat = Chat({ messages, tools });\n const note = Note({ title, content, allCharms });\n\n return {\n [NAME]: title,\n chat,\n note,\n content,\n messages,\n mentioned: note.mentioned,\n backlinks: note.backlinks,\n list,\n };\n },\n);\n" }, { "name": "/note.tsx", "contents": "/// \nimport {\n Cell,\n cell,\n Default,\n derive,\n h,\n handler,\n lift,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n toSchema,\n UI,\n} from \"commontools\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\ntype Input = {\n title: Default;\n content: Default;\n allCharms: Cell;\n};\n\ntype Output = {\n mentioned: Default, []>;\n content: Default;\n backlinks: Default, []>;\n};\n\nconst updateTitle = handler<\n { detail: { value: string } },\n { title: Cell }\n>(\n (event, state) => {\n state.title.set(event.detail?.value ?? \"\");\n },\n);\n\nconst updateContent = handler<\n { detail: { value: string } },\n { content: Cell }\n>(\n (event, state) => {\n state.content.set(event.detail?.value ?? \"\");\n },\n);\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nconst handleNewBacklink = handler<\n {\n detail: {\n text: string;\n charmId: any;\n charm: Cell;\n navigate: boolean;\n };\n },\n {\n allCharms: Cell;\n }\n>(({ detail }, { allCharms }) => {\n console.log(\"new charm\", detail.text, detail.charmId);\n\n if (detail.navigate) {\n return navigateTo(detail.charm);\n } else {\n allCharms.push(detail.charm as unknown as MentionableCharm);\n }\n});\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\nconst Note = recipe(\n \"Note\",\n ({ title, content, allCharms }) => {\n const mentioned = cell([]);\n\n const computeBacklinks = lift<\n { allCharms: Cell; content: Cell },\n MentionableCharm[]\n >(\n ({ allCharms, content }) => {\n const cs = allCharms.get();\n if (!cs) return [];\n\n const self = cs.find((c) => c.content === content.get());\n\n const results = self\n ? cs.filter((c) =>\n c.mentioned?.some((m) => m.content === self.content) ?? false\n )\n : [];\n\n return results;\n },\n );\n\n const backlinks: OpaqueRef = computeBacklinks({\n allCharms,\n content: content as unknown as Cell, // TODO(bf): this is valid, but types complain\n });\n\n // The only way to serialize a pattern, apparently?\n const pattern = derive(undefined, () => JSON.stringify(Note));\n\n return {\n [NAME]: title,\n [UI]: (\n \n
\n \n
\n\n \n
\n ),\n title,\n content,\n mentioned,\n backlinks,\n };\n },\n);\n\nexport default Note;\n" }, { "name": "/chatbot-list-view.tsx", "contents": "/// \nimport {\n Cell,\n cell,\n Default,\n derive,\n h,\n handler,\n ID,\n ifElse,\n lift,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n toSchema,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot-note-composed.tsx\";\nimport { ListItem } from \"./common-tools.tsx\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\ntype CharmEntry = {\n [ID]: string; // randomId is a string\n local_id: string; // same as ID but easier to access\n charm: any;\n};\n\ntype Input = {\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\n charmsList: Default;\n allCharms: Cell;\n theme?: {\n accentColor: Default;\n fontFace: Default;\n borderRadius: Default;\n };\n};\n\ntype Output = {\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\n};\n\nconst removeChat = handler<\n unknown,\n {\n charmsList: Cell;\n id: string;\n selectedCharm: Cell>;\n }\n>(\n (\n _,\n { charmsList, id, selectedCharm },\n ) => {\n const list = charmsList.get();\n const index = list.findIndex((entry) => entry.local_id === id);\n if (index === -1) return;\n\n const removed = list[index];\n const next = [...list];\n next.splice(index, 1);\n charmsList.set(next);\n\n // If we removed the currently selected charm, choose a new selection.\n const current = selectedCharm.get();\n if (current?.charm === removed.charm) {\n const replacement = next[index] ?? next[index - 1];\n if (replacement) {\n selectedCharm.set({ charm: replacement.charm });\n } else {\n selectedCharm.set({ charm: undefined as unknown as any });\n }\n }\n },\n);\n\n// this will be called whenever charm or selectedCharm changes\n// pass isInitialized to make sure we dont call this each time\n// we change selectedCharm, otherwise creates a loop\nconst storeCharm = lift(\n toSchema<{\n charm: any;\n selectedCharm: Cell>;\n charmsList: Cell;\n allCharms: Cell;\n theme?: {\n accentColor: Default;\n fontFace: Default;\n borderRadius: Default;\n };\n isInitialized: Cell;\n }>(),\n undefined,\n ({ charm, selectedCharm, charmsList, isInitialized, allCharms }) => { // Not including `allCharms` is a compile error...\n if (!isInitialized.get()) {\n console.log(\n \"storeCharm storing charm:\",\n charm,\n );\n selectedCharm.set({ charm });\n\n // create the chat charm with a custom name including a random suffix\n const randomId = Math.random().toString(36).substring(2, 10); // Random 8-char string\n charmsList.push({ [ID]: randomId, local_id: randomId, charm });\n\n isInitialized.set(true);\n return charm;\n } else {\n console.log(\"storeCharm: already initialized\");\n }\n return undefined;\n },\n);\n\nconst populateChatList = lift(\n toSchema<{\n charmsList: CharmEntry[];\n allCharms: Cell;\n selectedCharm: Cell<{ charm: any }>;\n }>(),\n undefined,\n (\n { charmsList, allCharms, selectedCharm },\n ) => {\n if (charmsList.length === 0) {\n const isInitialized = cell(false);\n return storeCharm({\n charm: Chat({\n title: \"New Chat\",\n messages: [],\n content: \"\",\n allCharms,\n }),\n selectedCharm,\n charmsList,\n allCharms,\n isInitialized: isInitialized as unknown as Cell,\n });\n }\n\n return charmsList;\n },\n);\n\nconst createChatRecipe = handler<\n unknown,\n {\n selectedCharm: Cell<{ charm: any }>;\n charmsList: Cell;\n allCharms: Cell;\n }\n>(\n (_, { selectedCharm, charmsList, allCharms }) => {\n const isInitialized = cell(false);\n\n const charm = Chat({\n title: \"New Chat\",\n messages: [],\n content: \"\",\n allCharms,\n });\n // store the charm ref in a cell (pass isInitialized to prevent recursive calls)\n return storeCharm({\n charm,\n selectedCharm,\n charmsList: charmsList as unknown as OpaqueRef,\n allCharms,\n isInitialized: isInitialized as unknown as Cell,\n });\n },\n);\n\nconst selectCharm = handler<\n unknown,\n { selectedCharm: Cell<{ charm: any }>; charm: any }\n>(\n (_, { selectedCharm, charm }) => {\n console.log(\"selectCharm: updating selectedCharm to \", charm);\n selectedCharm.set({ charm });\n return selectedCharm;\n },\n);\n\nconst logCharmsList = lift<\n { charmsList: Cell },\n Cell\n>(\n ({ charmsList }) => {\n console.log(\"logCharmsList: \", charmsList.get());\n return charmsList;\n },\n);\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\nconst combineLists = lift(\n (\n { allCharms, charmsList }: { allCharms: any[]; charmsList: CharmEntry[] },\n ) => {\n return [...charmsList.map((c) => c.charm), ...allCharms];\n },\n);\n\nconst getSelectedCharm = lift<\n { entry: { charm: any | undefined } },\n {\n chat: unknown;\n note: unknown;\n list: ListItem[];\n backlinks: MentionableCharm[];\n mentioned: MentionableCharm[];\n } | undefined\n>(\n ({ entry }) => {\n return entry?.charm;\n },\n);\n\nconst getCharmName = lift(({ charm }: { charm: any }) => {\n return charm?.[NAME] || \"Unknown\";\n});\n\n// create the named cell inside the recipe body, so we do it just once\nexport default recipe(\n \"Launcher\",\n ({ selectedCharm, charmsList, allCharms, theme }) => {\n logCharmsList({ charmsList: charmsList as unknown as Cell });\n\n populateChatList({\n selectedCharm: selectedCharm as unknown as Cell<\n Pick\n >,\n charmsList,\n allCharms,\n });\n\n const combined = combineLists({\n allCharms: allCharms as unknown as any[],\n charmsList,\n });\n\n const selected = getSelectedCharm({ entry: selectedCharm });\n\n const localTheme = theme ?? {\n accentColor: cell(\"#3b82f6\"),\n fontFace: cell(\"system-ui, -apple-system, sans-serif\"),\n borderRadius: cell(\"0.5rem\"),\n };\n\n return {\n [NAME]: \"Launcher\",\n [UI]: (\n \n \n
\n \n
\n \n Create New Chat\n alt+N\n \n
\n
\n\n {/* Keyboard shortcuts */}\n \n
\n \n {/* workaround: this seems to correctly start the sub-recipes on a refresh while directly rendering does not */}\n {/* this should be fixed after the builder-refactor (DX1) */}\n \n \n \n \n \n \n\n \n\n \n \n
\n
\n ),\n selectedCharm,\n charmsList,\n };\n },\n);\n" }, { "name": "/common-tools.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n BuiltInLLMTool,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n h,\n handler,\n ifElse,\n llmDialog,\n NAME,\n recipe,\n Stream,\n UI,\n} from \"commontools\";\n\n///// COMMON TOOLS (get it?) ////\n\n/**\n * Calculate the result of a mathematical expression.\n * Supports +, -, *, /, and parentheses.\n */\ntype CalculatorRequest = {\n /** The mathematical expression to evaluate. */\n expression: string;\n};\n\nexport const calculator = recipe<\n CalculatorRequest,\n string | { error: string }\n>(\"Calculator\", ({ expression }) => {\n return derive(expression, (expr) => {\n const sanitized = expr.replace(/[^0-9+\\-*/().\\s]/g, \"\");\n let result;\n try {\n result = Function(`\"use strict\"; return (${sanitized})`)();\n } catch (error) {\n result = { error: (error as any)?.message || \"\" };\n }\n return result;\n });\n});\n\n/** Add an item to the list. */\ntype AddListItemRequest = {\n /** The item to add to the list. */\n item: string;\n result: Cell;\n};\n\n/** Read all items from the list. */\ntype ReadListItemsRequest = {\n result: Cell;\n};\n\nexport type ListItem = {\n title: string;\n};\n\nexport const addListItem = handler<\n AddListItemRequest,\n { list: Cell }\n>(\n (args, state) => {\n try {\n state.list.push({ title: args.item });\n args.result.set(`${state.list.get().length} items`);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport const readListItems = handler<\n ReadListItemsRequest,\n { list: ListItem[] }\n>(\n (args, state) => {\n try {\n const items = state.list;\n if (items.length === 0) {\n args.result.set(\"The list is empty\");\n } else {\n const itemList = items.map((item, index) =>\n `${index + 1}. ${item.title}`\n ).join(\"\\n\");\n args.result.set(`List items (${items.length} total):\\n${itemList}`);\n }\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\n/** Search the web for information. */\ntype SearchQuery = {\n /** The query to search the web for. */\n query: string;\n};\n\ntype SearchWebResult = {\n results: {\n title: string;\n url: string;\n description: string;\n }[];\n};\n\nexport const searchWeb = recipe<\n SearchQuery,\n SearchWebResult | { error: string }\n>(\"Search Web\", ({ query }) => {\n const { result, error } = fetchData({\n url: \"/api/agent-tools/web-search\",\n mode: \"json\",\n options: {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: {\n query,\n max_results: 5,\n },\n },\n });\n\n // TODO(seefeld): Should we instead return { result, error }? Or allocate a\n // special [ERROR] for errors? Ideally this isn\\'t specific to using recipes as\n // tools but a general pattern.\n return ifElse(error, { error }, result);\n});\n\n/** Read and extract content from a specific webpage URL. */\ntype ReadWebRequest = {\n /** The URL of the webpage to read and extract content from. */\n url: string;\n};\n\ntype ReadWebResult = {\n content: string;\n metadata: {\n title?: string;\n author?: string;\n date?: string;\n word_count: number;\n };\n};\n\nexport const readWebpage = recipe<\n ReadWebRequest,\n ReadWebResult | { error: string }\n>(\"Read Webpage\", ({ url }) => {\n const { result, error } = fetchData({\n url: \"/api/agent-tools/web-read\",\n mode: \"json\",\n options: {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: {\n url,\n max_tokens: 4000,\n include_code: true,\n },\n },\n });\n\n return ifElse(error, { error }, result);\n});\n\ntype ToolsInput = {\n list: ListItem[];\n};\n\nexport default recipe(\"Tools\", ({ list }) => {\n const tools: Record = {\n search_web: {\n pattern: searchWeb,\n },\n read_webpage: {\n pattern: readWebpage,\n },\n calculator: {\n pattern: calculator,\n },\n addListItem: {\n handler: addListItem({ list }),\n },\n };\n\n return { tools, list };\n});\n" } ] } } }, "since": 13 } } }, "of:baedreif3pbfllprvaib562wi254n6pzcge6jed7jmbkxidfgcsntd7ului": { "application/json": { "ba4jcahu4e5elsrgscpbmxivvvrllndjkgnrpccfy437g2d5kbpepgcjv": { "is": { "source": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" }, "value": { "$NAME": { "$alias": { "path": [ "internal", "$NAME" ], "cell": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" } } }, "$UI": { "type": "vnode", "name": "ct-screen", "props": { }, "children": [ { "type": "vnode", "name": "ct-hstack", "props": { "justify": "between", "slot": "header" }, "children": [ { "type": "vnode", "name": "ct-heading", "props": { "level": 4 }, "children": [ { "$alias": { "path": [ "internal", "$NAME" ], "cell": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" } } } ] }, { "type": "vnode", "name": "ct-tools-chip", "props": { "tools": { "$alias": { "path": [ "argument", "tools" ], "schema": { }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "messages": { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMMessage" }, "default": [] }, "tools": true, "theme": true }, "required": [ "messages", "tools" ], "$defs": { "BuiltInLLMMessage": { "type": "object", "properties": { "role": { "enum": [ "system", "user", "assistant", "tool" ] }, "content": { "$ref": "#/$defs/BuiltInLLMContent" } }, "required": [ "role", "content" ] }, "BuiltInLLMContent": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMContentPart" } } ] }, "BuiltInLLMContentPart": { "anyOf": [ { "$ref": "#/$defs/BuiltInLLMTextPart" }, { "$ref": "#/$defs/BuiltInLLMImagePart" }, { "$ref": "#/$defs/BuiltInLLMToolCallPart" }, { "$ref": "#/$defs/BuiltInLLMToolResultPart" } ] }, "BuiltInLLMToolResultPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-result" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "output": { "anyOf": [ { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "value": { "type": "string" } }, "required": [ "type", "value" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "json" ] }, "value": true }, "required": [ "type", "value" ] } ] } }, "required": [ "type", "toolCallId", "toolName", "output" ] }, "BuiltInLLMToolCallPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-call" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "input": { "$ref": "#/$defs/Record" } }, "required": [ "type", "toolCallId", "toolName", "input" ] }, "Record": { "type": "object", "properties": { }, "additionalProperties": true }, "BuiltInLLMImagePart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "image" ] }, "image": { "anyOf": [ { "type": "string" }, true, true, { "type": "string", "format": "uri" } ] } }, "required": [ "type", "image" ] }, "BuiltInLLMTextPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "text": { "type": "string" } }, "required": [ "type", "text" ] } } }, "cell": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" } } } }, "children": [] } ] }, { "type": "vnode", "name": "ct-vscroll", "props": { "flex": true, "showScrollbar": true, "fadeEdges": true, "snapToBottom": true }, "children": [ { "type": "vnode", "name": "ct-chat", "props": { "theme": { "$alias": { "path": [ "argument", "theme" ], "schema": { }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "messages": { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMMessage" }, "default": [] }, "tools": true, "theme": true }, "required": [ "messages", "tools" ], "$defs": { "BuiltInLLMMessage": { "type": "object", "properties": { "role": { "enum": [ "system", "user", "assistant", "tool" ] }, "content": { "$ref": "#/$defs/BuiltInLLMContent" } }, "required": [ "role", "content" ] }, "BuiltInLLMContent": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMContentPart" } } ] }, "BuiltInLLMContentPart": { "anyOf": [ { "$ref": "#/$defs/BuiltInLLMTextPart" }, { "$ref": "#/$defs/BuiltInLLMImagePart" }, { "$ref": "#/$defs/BuiltInLLMToolCallPart" }, { "$ref": "#/$defs/BuiltInLLMToolResultPart" } ] }, "BuiltInLLMToolResultPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-result" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "output": { "anyOf": [ { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "value": { "type": "string" } }, "required": [ "type", "value" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "json" ] }, "value": true }, "required": [ "type", "value" ] } ] } }, "required": [ "type", "toolCallId", "toolName", "output" ] }, "BuiltInLLMToolCallPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-call" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "input": { "$ref": "#/$defs/Record" } }, "required": [ "type", "toolCallId", "toolName", "input" ] }, "Record": { "type": "object", "properties": { }, "additionalProperties": true }, "BuiltInLLMImagePart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "image" ] }, "image": { "anyOf": [ { "type": "string" }, true, true, { "type": "string", "format": "uri" } ] } }, "required": [ "type", "image" ] }, "BuiltInLLMTextPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "text": { "type": "string" } }, "required": [ "type", "text" ] } } }, "cell": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" } } }, "$messages": { "$alias": { "path": [ "argument", "messages" ], "schema": { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMMessage" }, "default": [] }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "messages": { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMMessage" }, "default": [] }, "tools": true, "theme": true }, "required": [ "messages", "tools" ], "$defs": { "BuiltInLLMMessage": { "type": "object", "properties": { "role": { "enum": [ "system", "user", "assistant", "tool" ] }, "content": { "$ref": "#/$defs/BuiltInLLMContent" } }, "required": [ "role", "content" ] }, "BuiltInLLMContent": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMContentPart" } } ] }, "BuiltInLLMContentPart": { "anyOf": [ { "$ref": "#/$defs/BuiltInLLMTextPart" }, { "$ref": "#/$defs/BuiltInLLMImagePart" }, { "$ref": "#/$defs/BuiltInLLMToolCallPart" }, { "$ref": "#/$defs/BuiltInLLMToolResultPart" } ] }, "BuiltInLLMToolResultPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-result" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "output": { "anyOf": [ { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "value": { "type": "string" } }, "required": [ "type", "value" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "json" ] }, "value": true }, "required": [ "type", "value" ] } ] } }, "required": [ "type", "toolCallId", "toolName", "output" ] }, "BuiltInLLMToolCallPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-call" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "input": { "$ref": "#/$defs/Record" } }, "required": [ "type", "toolCallId", "toolName", "input" ] }, "Record": { "type": "object", "properties": { }, "additionalProperties": true }, "BuiltInLLMImagePart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "image" ] }, "image": { "anyOf": [ { "type": "string" }, true, true, { "type": "string", "format": "uri" } ] } }, "required": [ "type", "image" ] }, "BuiltInLLMTextPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "text": { "type": "string" } }, "required": [ "type", "text" ] } } }, "cell": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" } } }, "pending": { "$alias": { "path": [ "internal", "__#0", "pending" ], "cell": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" } } }, "tools": { "$alias": { "path": [ "argument", "tools" ], "schema": { }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "messages": { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMMessage" }, "default": [] }, "tools": true, "theme": true }, "required": [ "messages", "tools" ], "$defs": { "BuiltInLLMMessage": { "type": "object", "properties": { "role": { "enum": [ "system", "user", "assistant", "tool" ] }, "content": { "$ref": "#/$defs/BuiltInLLMContent" } }, "required": [ "role", "content" ] }, "BuiltInLLMContent": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMContentPart" } } ] }, "BuiltInLLMContentPart": { "anyOf": [ { "$ref": "#/$defs/BuiltInLLMTextPart" }, { "$ref": "#/$defs/BuiltInLLMImagePart" }, { "$ref": "#/$defs/BuiltInLLMToolCallPart" }, { "$ref": "#/$defs/BuiltInLLMToolResultPart" } ] }, "BuiltInLLMToolResultPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-result" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "output": { "anyOf": [ { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "value": { "type": "string" } }, "required": [ "type", "value" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "json" ] }, "value": true }, "required": [ "type", "value" ] } ] } }, "required": [ "type", "toolCallId", "toolName", "output" ] }, "BuiltInLLMToolCallPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-call" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "input": { "$ref": "#/$defs/Record" } }, "required": [ "type", "toolCallId", "toolName", "input" ] }, "Record": { "type": "object", "properties": { }, "additionalProperties": true }, "BuiltInLLMImagePart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "image" ] }, "image": { "anyOf": [ { "type": "string" }, true, true, { "type": "string", "format": "uri" } ] } }, "required": [ "type", "image" ] }, "BuiltInLLMTextPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "text": { "type": "string" } }, "required": [ "type", "text" ] } } }, "cell": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" } } } }, "children": [] } ] }, { "type": "vnode", "name": "div", "props": { "slot": "footer" }, "children": [ { "type": "vnode", "name": "ct-prompt-input", "props": { "placeholder": "Ask the LLM a question...", "pending": { "$alias": { "path": [ "internal", "__#0", "pending" ], "cell": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" } } }, "onct-send": { "$alias": { "path": [ "internal", "$event" ], "schema": { "type": "object", "properties": { "detail": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } }, "required": [ "detail" ] }, "rootSchema": { "type": "object", "properties": { "detail": { "type": "object", "properties": { "message": { "type": "string" } }, "required": [ "message" ] } }, "required": [ "detail" ] }, "cell": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" } } }, "onct-stop": { "$alias": { "path": [ "internal", "__#0", "cancelGeneration" ], "cell": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" } } } }, "children": [] }, { "type": "vnode", "name": "ct-select", "props": { "items": { "$alias": { "path": [ "internal", "__#1" ], "cell": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" } } }, "$value": { "$alias": { "path": [ "internal", "model" ], "cell": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" } } } }, "children": [] } ] } ] }, "messages": { "$alias": { "path": [ "argument", "messages" ], "schema": { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMMessage" }, "default": [] }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "messages": { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMMessage" }, "default": [] }, "tools": true, "theme": true }, "required": [ "messages", "tools" ], "$defs": { "BuiltInLLMMessage": { "type": "object", "properties": { "role": { "enum": [ "system", "user", "assistant", "tool" ] }, "content": { "$ref": "#/$defs/BuiltInLLMContent" } }, "required": [ "role", "content" ] }, "BuiltInLLMContent": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMContentPart" } } ] }, "BuiltInLLMContentPart": { "anyOf": [ { "$ref": "#/$defs/BuiltInLLMTextPart" }, { "$ref": "#/$defs/BuiltInLLMImagePart" }, { "$ref": "#/$defs/BuiltInLLMToolCallPart" }, { "$ref": "#/$defs/BuiltInLLMToolResultPart" } ] }, "BuiltInLLMToolResultPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-result" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "output": { "anyOf": [ { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "value": { "type": "string" } }, "required": [ "type", "value" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "json" ] }, "value": true }, "required": [ "type", "value" ] } ] } }, "required": [ "type", "toolCallId", "toolName", "output" ] }, "BuiltInLLMToolCallPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-call" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "input": { "$ref": "#/$defs/Record" } }, "required": [ "type", "toolCallId", "toolName", "input" ] }, "Record": { "type": "object", "properties": { }, "additionalProperties": true }, "BuiltInLLMImagePart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "image" ] }, "image": { "anyOf": [ { "type": "string" }, true, true, { "type": "string", "format": "uri" } ] } }, "required": [ "type", "image" ] }, "BuiltInLLMTextPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "text": { "type": "string" } }, "required": [ "type", "text" ] } } }, "cell": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" } } }, "pending": { "$alias": { "path": [ "internal", "__#0", "pending" ], "cell": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" } } }, "addMessage": { "$alias": { "path": [ "internal", "__#0", "addMessage" ], "cell": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" } } }, "cancelGeneration": { "$alias": { "path": [ "internal", "__#0", "cancelGeneration" ], "cell": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" } } }, "title": { "$alias": { "path": [ "internal", "$NAME" ], "cell": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" } } } } }, "since": 17 } } }, "of:baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4": { "application/json": { "ba4jcbopet2kuqdpa2on7b5gs4gcqdfpbefvjfqjhk7iuxnpayzhswhos": { "is": { "value": { "$TYPE": "ba4jcbuywva6ktbchwywdnu2riv7cuywz3g7zpg4a4oqnju6wfmx33nmj", "resultRef": { "/": { "link@1": { "path": [], "id": "of:baedreif3pbfllprvaib562wi254n6pzcge6jed7jmbkxidfgcsntd7ului" } } }, "internal": { "model": "anthropic:claude-sonnet-4-5", "__#0": { "/": { "link@1": { "path": [], "id": "of:baedreidzxh4cwepeapuwyxfx6srdrhiiboxp4q6uik5c3o74hl52u2bste", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, "$event": { "$stream": true }, "value": { "pending": { "/": { "link@1": { "path": [], "id": "of:baedreicq254thfkongrxdlbw3mvjmwul2g3lfdqrsr3tkbcmcd3647lnxa", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, "result": { "/": { "link@1": { "path": [], "id": "of:baedreiaxqjmo567ty7ihojha3iezfvupu5ts4la3xgwpfg53aoqwpyuofi", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, "error": { "/": { "link@1": { "path": [], "id": "of:baedreib2dnfzhck5bn2oxdzgzduyhf72x7t4mniq27jypacvynbfbbprxu", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } } }, "$NAME": { "/": { "link@1": { "path": [], "id": "of:baedreia4yc7gahp4obzf3uhvaiyewc5svvao6aouafqyd6xya7vd3mwgze" } } }, "__#1": [ { "label": "anthropic:claude-opus-4-1", "value": "anthropic:claude-opus-4-1" }, { "label": "anthropic:claude-opus-4-1-thinking", "value": "anthropic:claude-opus-4-1-thinking" }, { "label": "anthropic:claude-sonnet-4-0", "value": "anthropic:claude-sonnet-4-0" }, { "label": "anthropic:claude-sonnet-4-0-thinking", "value": "anthropic:claude-sonnet-4-0-thinking" }, { "label": "anthropic:claude-sonnet-4-5", "value": "anthropic:claude-sonnet-4-5" }, { "label": "anthropic:claude-sonnet-4-5-thinking", "value": "anthropic:claude-sonnet-4-5-thinking" }, { "label": "groq:moonshotai/kimi-k2-instruct", "value": "groq:moonshotai/kimi-k2-instruct" }, { "label": "groq:openai/gpt-oss-120b", "value": "groq:openai/gpt-oss-120b" } ] }, "spell": { "/": { "link@1": { "id": "of:baedreidot3olwjidm4vssvompzauvu2xq3xhzkx2xeksl6rxadoxpwefke" } } }, "argument": { "messages": { "$alias": { "path": [ "argument", "messages" ], "schema": { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMMessage" }, "default": [] }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "LLM Test" }, "messages": { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMMessage" }, "default": [] }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "messages", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] }, "BuiltInLLMMessage": { "type": "object", "properties": { "role": { "enum": [ "system", "user", "assistant", "tool" ] }, "content": { "$ref": "#/$defs/BuiltInLLMContent" } }, "required": [ "role", "content" ] }, "BuiltInLLMContent": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMContentPart" } } ] }, "BuiltInLLMContentPart": { "anyOf": [ { "$ref": "#/$defs/BuiltInLLMTextPart" }, { "$ref": "#/$defs/BuiltInLLMImagePart" }, { "$ref": "#/$defs/BuiltInLLMToolCallPart" }, { "$ref": "#/$defs/BuiltInLLMToolResultPart" } ] }, "BuiltInLLMToolResultPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-result" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "output": { "anyOf": [ { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "value": { "type": "string" } }, "required": [ "type", "value" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "json" ] }, "value": true }, "required": [ "type", "value" ] } ] } }, "required": [ "type", "toolCallId", "toolName", "output" ] }, "BuiltInLLMToolCallPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-call" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "input": { "$ref": "#/$defs/Record" } }, "required": [ "type", "toolCallId", "toolName", "input" ] }, "Record": { "type": "object", "properties": { }, "additionalProperties": true }, "BuiltInLLMImagePart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "image" ] }, "image": { "anyOf": [ { "type": "string" }, true, true, { "type": "string", "format": "uri" } ] } }, "required": [ "type", "image" ] }, "BuiltInLLMTextPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "text": { "type": "string" } }, "required": [ "type", "text" ] } } }, "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } }, "tools": { "searchWeb": { "pattern": { "argumentSchema": { "type": "object", "properties": { "query": { "type": "string", "description": "The query to search the web for." } }, "required": [ "query" ], "description": "Search the web for information." }, "resultSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "anyOf": [ { "$ref": "#/$defs/SearchWebResult" }, { "type": "object", "properties": { "error": { "type": "string" } }, "required": [ "error" ] } ], "$defs": { "SearchWebResult": { "type": "object", "properties": { "results": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string" }, "url": { "type": "string" }, "description": { "type": "string" } }, "required": [ "title", "url", "description" ] } } }, "required": [ "results" ] } } }, "initial": { "internal": { "0": { "result": { } } } }, "result": { "$alias": { "path": [ "internal", "__#0" ] } }, "nodes": [ { "module": { "type": "ref", "implementation": "fetchData" }, "inputs": { "url": "/api/agent-tools/web-search", "mode": "json", "options": { "method": "POST", "headers": { "Content-Type": "application/json" }, "body": { "query": { "$alias": { "path": [ "argument", "query" ], "schema": { "type": "string", "description": "The query to search the web for." }, "rootSchema": { "type": "object", "properties": { "query": { "type": "string", "description": "The query to search the web for." } }, "required": [ "query" ], "description": "Search the web for information." } } }, "max_results": 5 } } }, "outputs": { "$alias": { "path": [ "internal", "0" ] } } }, { "module": { "type": "ref", "implementation": "ifElse" }, "inputs": [ { "$alias": { "path": [ "internal", "0", "error" ] } }, { "error": { "$alias": { "path": [ "internal", "0", "error" ] } } }, { "$alias": { "path": [ "internal", "0", "result" ] } } ], "outputs": { "$alias": { "path": [ "internal", "__#0" ] } } } ] } }, "readWebpage": { "pattern": { "argumentSchema": { "type": "object", "properties": { "url": { "type": "string", "description": "The URL of the webpage to read and extract content from." } }, "required": [ "url" ], "description": "Read and extract content from a specific webpage URL." }, "resultSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "anyOf": [ { "$ref": "#/$defs/ReadWebResult" }, { "type": "object", "properties": { "error": { "type": "string" } }, "required": [ "error" ] } ], "$defs": { "ReadWebResult": { "type": "object", "properties": { "content": { "type": "string" }, "metadata": { "type": "object", "properties": { "title": { "type": "string" }, "author": { "type": "string" }, "date": { "type": "string" }, "word_count": { "type": "number" } }, "required": [ "word_count" ] } }, "required": [ "content", "metadata" ] } } }, "initial": { "internal": { "0": { "result": { } } } }, "result": { "$alias": { "path": [ "internal", "__#0" ] } }, "nodes": [ { "module": { "type": "ref", "implementation": "fetchData" }, "inputs": { "url": "/api/agent-tools/web-read", "mode": "json", "options": { "method": "POST", "headers": { "Content-Type": "application/json" }, "body": { "url": { "$alias": { "path": [ "argument", "url" ], "schema": { "type": "string", "description": "The URL of the webpage to read and extract content from." }, "rootSchema": { "type": "object", "properties": { "url": { "type": "string", "description": "The URL of the webpage to read and extract content from." } }, "required": [ "url" ], "description": "Read and extract content from a specific webpage URL." } } }, "max_tokens": 4000, "include_code": true } } }, "outputs": { "$alias": { "path": [ "internal", "0" ] } } }, { "module": { "type": "ref", "implementation": "ifElse" }, "inputs": [ { "$alias": { "path": [ "internal", "0", "error" ] } }, { "error": { "$alias": { "path": [ "internal", "0", "error" ] } } }, { "$alias": { "path": [ "internal", "0", "result" ] } } ], "outputs": { "$alias": { "path": [ "internal", "__#0" ] } } } ] } }, "calculator": { "pattern": { "argumentSchema": { "type": "object", "properties": { "expression": { "type": "string", "description": "The mathematical expression to evaluate." } }, "required": [ "expression" ], "description": "Calculate the result of a mathematical expression.\nSupports +, -, *, /, and parentheses." }, "resultSchema": { "anyOf": [ { "type": "string" }, { "type": "object", "properties": { "error": { "type": "string" } }, "required": [ "error" ] } ] }, "initial": { }, "result": { "$alias": { "path": [ "internal", "__#0" ] } }, "nodes": [ { "module": { "type": "javascript", "implementation": "(expr) => {\n const sanitized = expr.replace(/[^0-9+\\-*/().\\s]/g, \"\");\n let result;\n try {\n result = Function(`\"use strict\"; return (${sanitized})`)();\n }\n catch (error) {\n result = { error: error?.message || \"\" };\n }\n return result;\n }", "argumentSchema": { "type": "string" }, "resultSchema": true }, "inputs": { "$alias": { "path": [ "argument", "expression" ], "schema": { "type": "string", "description": "The mathematical expression to evaluate." }, "rootSchema": { "type": "object", "properties": { "expression": { "type": "string", "description": "The mathematical expression to evaluate." } }, "required": [ "expression" ], "description": "Calculate the result of a mathematical expression.\nSupports +, -, *, /, and parentheses." } } }, "outputs": { "$alias": { "path": [ "internal", "__#0" ] } } } ] } }, "addListItem": { "handler": { "$alias": { "path": [ "internal", "__#5stream" ], "schema": { "type": "object", "properties": { "item": { "type": "string", "description": "The item to add to the list." }, "result": { "type": "string" } }, "required": [ "item", "result" ], "description": "Add an item to the list." }, "rootSchema": { "type": "object", "properties": { "item": { "type": "string", "description": "The item to add to the list." }, "result": { "type": "string" } }, "required": [ "item", "result" ], "description": "Add an item to the list." }, "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } } }, "readListItems": { "handler": { "$alias": { "path": [ "internal", "__#6stream" ], "schema": { "type": "object", "properties": { "result": { "type": "string" } }, "required": [ "result" ], "description": "Read all items from the list." }, "rootSchema": { "type": "object", "properties": { "result": { "type": "string" } }, "required": [ "result" ], "description": "Read all items from the list." }, "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } } }, "editActiveNote": { "description": "Modify the shared note.", "inputSchema": { "type": "object", "properties": { "body": { "type": "string", "description": "The content of the note." } }, "required": [ "body" ] }, "handler": { "$alias": { "path": [ "internal", "__#7stream" ], "schema": { "type": "object", "properties": { "body": { "type": "string", "description": "The text content of the note" }, "result": { "type": "string", "description": "A cell to store the result message indicating success or error" } }, "required": [ "body", "result" ] }, "rootSchema": { "type": "object", "properties": { "body": { "type": "string", "description": "The text content of the note" }, "result": { "type": "string", "description": "A cell to store the result message indicating success or error" } }, "required": [ "body", "result" ] }, "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } } }, "readActiveNote": { "description": "Read the currently focused note.", "inputSchema": { "type": "object", "properties": { }, "required": [] }, "handler": { "$alias": { "path": [ "internal", "$event" ], "schema": { "type": "object", "properties": { "result": { "type": "string", "description": "A cell to store the result text" } }, "required": [ "result" ] }, "rootSchema": { "type": "object", "properties": { "result": { "type": "string", "description": "A cell to store the result text" } }, "required": [ "result" ] }, "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } } }, "listNotes": { "description": "List all mentionable note titles (read the body with readNoteByIndex).", "inputSchema": { "type": "object", "properties": { }, "required": [] }, "handler": { "$alias": { "path": [ "internal", "__#4stream" ], "schema": { "type": "object", "properties": { "result": { "type": "string", "description": "A cell to store the result text" } }, "required": [ "result" ] }, "rootSchema": { "type": "object", "properties": { "result": { "type": "string", "description": "A cell to store the result text" } }, "required": [ "result" ] }, "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } } }, "readNoteByIndex": { "description": "Read the body of a note by its index in the listNotes() list.", "inputSchema": { "type": "object", "properties": { "index": { "type": "number", "description": "The index of the note in the notes list." } }, "required": [ "index" ] }, "handler": { "$alias": { "path": [ "internal", "__#0stream" ], "schema": { "type": "object", "properties": { "index": { "type": "number", "description": "A cell to store the result text" }, "result": { "type": "string" } }, "required": [ "index", "result" ] }, "rootSchema": { "type": "object", "properties": { "index": { "type": "number", "description": "A cell to store the result text" }, "result": { "type": "string" } }, "required": [ "index", "result" ] }, "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } } }, "editNoteByIndex": { "description": "Edit the body of a note by its index in the listNotes() list.", "inputSchema": { "type": "object", "properties": { "index": { "type": "number", "description": "The index of the note in the notes list." }, "body": { "type": "string", "description": "The new content of the note." } }, "required": [ "index", "body" ] }, "handler": { "$alias": { "path": [ "internal", "__#1stream" ], "schema": { "type": "object", "properties": { "index": { "type": "number", "description": "The index of the note to edit" }, "body": { "type": "string", "description": "The new text content of the note" }, "result": { "type": "string", "description": "A cell to store the result message indicating success or error" } }, "required": [ "index", "body", "result" ] }, "rootSchema": { "type": "object", "properties": { "index": { "type": "number", "description": "The index of the note to edit" }, "body": { "type": "string", "description": "The new text content of the note" }, "result": { "type": "string", "description": "A cell to store the result message indicating success or error" } }, "required": [ "index", "body", "result" ] }, "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } } }, "navigateToNote": { "description": "Navigate to a note by its index in the listNotes() list.", "inputSchema": { "type": "object", "properties": { "index": { "type": "number", "description": "The index of the note in the notes list." } }, "required": [ "index" ] }, "handler": { "$alias": { "path": [ "internal", "__#2stream" ], "schema": { "type": "object", "properties": { "index": { "type": "number", "description": "The index of the note to navigate to" }, "result": { "type": "string", "description": "A cell to store the result message indicating success or error" } }, "required": [ "index", "result" ] }, "rootSchema": { "type": "object", "properties": { "index": { "type": "number", "description": "The index of the note to navigate to" }, "result": { "type": "string", "description": "A cell to store the result message indicating success or error" } }, "required": [ "index", "result" ] }, "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } } }, "newNote": { "description": "Read the shared note.", "inputSchema": { "type": "object", "properties": { "title": { "type": "string", "description": "The title of the note." }, "content": { "type": "string", "description": "The content of the note." } }, "required": [ "title" ] }, "handler": { "$alias": { "path": [ "internal", "__#3stream" ], "schema": { "type": "object", "properties": { "title": { "type": "string", "description": "The text content of the note" }, "content": { "type": "string" }, "result": { "type": "string", "description": "A cell to store the result message indicating success or error" } }, "required": [ "title", "result" ] }, "rootSchema": { "type": "object", "properties": { "title": { "type": "string", "description": "The text content of the note" }, "content": { "type": "string" }, "result": { "type": "string", "description": "A cell to store the result message indicating success or error" } }, "required": [ "title", "result" ] }, "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } } } } } } }, "since": 47 } } }, "of:baedreidot3olwjidm4vssvompzauvu2xq3xhzkx2xeksl6rxadoxpwefke": { "application/json": { "ba4jcakrm6sm2abu3u4fyt5gbhlreazwuszq5crmwtj3zszw7hbdsice7": { "is": { "value": { "id": "ba4jcbuywva6ktbchwywdnu2riv7cuywz3g7zpg4a4oqnju6wfmx33nmj", "program": { "main": "/chatbot.tsx", "mainExport": "default", "files": [ { "name": "/default-app.tsx", "contents": "/// \nimport {\n Cell,\n Default,\n derive,\n h,\n handler,\n NAME,\n navigateTo,\n Opaque,\n OpaqueRef,\n recipe,\n str,\n UI,\n} from \"commontools\";\n\n// Import recipes we want to be launchable from the default app.\nimport Chatbot from \"./chatbot.tsx\";\nimport ChatbotOutliner from \"./chatbot-outliner.tsx\";\nimport { type MentionableCharm } from \"./chatbot-note-composed.tsx\";\nimport { default as Note } from \"./note.tsx\";\nimport ChatList from \"./chatbot-list-view.tsx\";\n\nexport type Charm = {\n [NAME]?: string;\n [UI]?: unknown;\n [key: string]: any;\n};\n\ntype CharmsListInput = {\n allCharms: Default;\n};\n\n// Recipe returns only UI, no data outputs (only symbol properties)\ninterface CharmsListOutput {\n [key: string]: unknown;\n}\n\nconst visit = handler<\n Record,\n { charm: any }\n>((_, state) => {\n return navigateTo(state.charm);\n}, { proxy: true });\n\nconst removeCharm = handler<\n Record,\n {\n charm: any;\n allCharms: Cell;\n }\n>((_, state) => {\n const charmName = state.charm[NAME];\n const allCharmsValue = state.allCharms.get();\n const index = allCharmsValue.findIndex((c: any) => c[NAME] === charmName);\n\n if (index !== -1) {\n const charmListCopy = [...allCharmsValue];\n console.log(\"charmListCopy before\", charmListCopy);\n charmListCopy.splice(index, 1);\n console.log(\"charmListCopy after\", charmListCopy);\n state.allCharms.set(charmListCopy);\n }\n});\n\nconst spawnChatList = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(ChatList({\n selectedCharm: { charm: undefined },\n charmsList: [],\n allCharms: state.allCharms, // we should handle empty here\n }));\n});\n\nconst spawnChatbot = handler<\n Record,\n Record\n>((_, state) => {\n return navigateTo(Chatbot({\n messages: [],\n tools: undefined,\n }));\n});\n\nconst spawnChatbotOutliner = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(ChatbotOutliner({\n title: \"Chatbot Outliner\",\n expandChat: false,\n messages: [],\n outline: {\n root: { body: \"\", children: [], attachments: [] },\n },\n allCharms: state.allCharms,\n }));\n});\n\nconst spawnNote = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(Note({\n title: \"New Note\",\n content: \"\",\n allCharms: state.allCharms,\n }));\n});\n\nexport default recipe(\n \"DefaultCharmList\",\n ({ allCharms }) => {\n return {\n [NAME]: str`DefaultCharmList (${allCharms.length})`,\n [UI]: (\n \n ,\n })}\n />\n\n \n {/* Quick Launch Toolbar */}\n \n

Quicklaunch:

\n ,\n })}\n >\n 📂 Chat List\n \n \n 💬 Chatbot\n \n \n 📝 Chatbot Outliner\n \n ,\n })}\n >\n 📄 Note\n \n
\n\n

Charms ({allCharms.length})

\n\n \n \n \n Charm Name\n Actions\n \n \n \n {derive(allCharms, (allCharms) =>\n allCharms.map((charm: any) => (\n \n {charm[NAME] || \"Untitled Charm\"}\n \n \n \n Visit\n \n \n Remove\n \n \n \n \n )))}\n \n \n
\n
\n ),\n };\n },\n);\n" }, { "name": "/chatbot.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n generateObject,\n h,\n handler,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n recipe,\n str,\n Stream,\n UI,\n} from \"commontools\";\n\nconst sendMessage = handler<\n { detail: { message: string } },\n {\n addMessage: Stream;\n }\n>((event, { addMessage }) => {\n addMessage.send({\n role: \"user\",\n content: [{ type: \"text\", text: event.detail.message }],\n });\n});\n\nconst clearChat = handler(\n (\n _: never,\n { messages, pending }: {\n messages: Cell>;\n pending: Cell;\n },\n ) => {\n messages.set([]);\n pending.set(false);\n },\n);\n\ntype ChatInput = {\n messages: Default, []>;\n tools: any;\n theme?: any;\n};\n\ntype ChatOutput = {\n messages: Array;\n pending: boolean | undefined;\n addMessage: Stream;\n cancelGeneration: Stream;\n title?: string;\n};\n\nexport const TitleGenerator = recipe<\n { model?: string; messages: Array }\n>(\"Title Generator\", ({ model, messages }) => {\n const titleMessages = derive(messages, (m) => {\n if (!m || m.length === 0) return \"\";\n\n const messageCount = 2;\n const selectedMessages = m.slice(0, messageCount).filter(Boolean);\n\n if (selectedMessages.length === 0) return \"\";\n\n return selectedMessages.map((msg) => JSON.stringify(msg)).join(\"\\n\");\n });\n\n const { result } = generateObject({\n system:\n \"Generate at most a 3-word title based on the following content, respond with NOTHING but the literal title text.\",\n prompt: titleMessages,\n model,\n schema: {\n type: \"object\",\n properties: {\n title: {\n type: \"string\",\n description: \"The title of the chat\",\n },\n },\n required: [\"title\"],\n },\n });\n\n const title = derive(result, (t) => {\n return t?.title || \"Untitled Chat\";\n });\n\n return title;\n});\n\nexport default recipe(\n \"Chat\",\n ({ messages, tools, theme }) => {\n const model = cell(\"anthropic:claude-sonnet-4-5\");\n\n const { addMessage, cancelGeneration, pending } = llmDialog({\n system: \"You are a helpful assistant with some tools.\",\n messages,\n tools,\n model,\n });\n\n const { result } = fetchData({\n url: \"/api/ai/llm/models\",\n mode: \"json\",\n });\n\n const items = derive(result, (models) => {\n if (!models) return [];\n const items = Object.keys(models as any).map((key) => ({\n label: key,\n value: key,\n }));\n return items;\n });\n\n const title = TitleGenerator({ model, messages });\n\n return {\n [NAME]: title,\n [UI]: (\n \n \n {title}\n \n \n\n \n \n \n\n
\n \n \n
\n
\n ),\n messages,\n pending,\n addMessage,\n cancelGeneration,\n title,\n };\n },\n);\n" }, { "name": "/chatbot-outliner.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n getRecipeEnvironment,\n h,\n handler,\n ID,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n str,\n Stream,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot.tsx\";\n\ntype Charm = any;\n\ntype OutlinerNode = {\n body: Default;\n children: Default;\n attachments: Default[], []>;\n};\n\ntype Outliner = {\n root: OutlinerNode;\n};\n\ntype PageResult = {\n outline: Default<\n Outliner,\n { root: { body: \"\"; children: []; attachments: [] } }\n >;\n};\n\nexport type PageInput = {\n outline: Outliner;\n allCharms: Cell;\n};\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nexport const Page = recipe(\n \"Page\",\n ({ outline, allCharms }) => {\n return {\n [NAME]: \"Page\",\n [UI]: (\n \n ),\n outline,\n };\n },\n);\n\ntype LLMTestInput = {\n title: Default;\n messages: Default, []>;\n expandChat: Default;\n outline: Default<\n Outliner,\n { root: { body: \"Untitled Page\"; children: []; attachments: [] } }\n >;\n allCharms: Cell;\n};\n\ntype LLMTestResult = {\n messages: Default, []>;\n};\n\n// put a node at the end of the outline (by appending to root.children)\nconst appendOutlinerNode = handler<\n {\n /** The text content/title of the outliner node to be appended */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { outline: Cell }\n>(\n (args, state) => {\n try {\n (state.outline.key(\"root\").key(\"children\")).push({\n body: args.body,\n children: [],\n attachments: [],\n });\n\n args.result.set(\n `${state.outline.key(\"root\").key(\"children\").get().length} nodes`,\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport default recipe(\n \"Outliner\",\n ({ title, expandChat, messages, outline, allCharms }) => {\n const tools = {\n appendOutlinerNode: {\n description: \"Add a new outliner node.\",\n inputSchema: {\n type: \"object\",\n properties: {\n body: {\n type: \"string\",\n description: \"The title of the new node.\",\n },\n },\n required: [\"body\"],\n } as JSONSchema,\n handler: appendOutlinerNode({ outline }),\n },\n };\n\n const chat = Chat({ messages, tools });\n const { addMessage, cancelGeneration, pending } = chat;\n\n return {\n [NAME]: title,\n [UI]: (\n \n \n
\n
\n Show Chat\n
\n
\n\n \n \n
\n \n
\n\n \n \n \n \n \n
\n\n {ifElse(\n expandChat,\n chat,\n null,\n )}\n
\n
\n ),\n messages,\n };\n },\n);\n" }, { "name": "/chatbot-note-composed.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n getRecipeEnvironment,\n h,\n handler,\n ID,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n str,\n Stream,\n toSchema,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot.tsx\";\nimport Note from \"./note.tsx\";\nimport Tools, {\n addListItem,\n calculator,\n ListItem,\n readListItems,\n readWebpage,\n searchWeb,\n} from \"./common-tools.tsx\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\n// export type ChatbotNoteInput = {\n// content: Default;\n// allCharms?: Cell;\n// };\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\ntype ChatbotNoteInput = {\n title: Default;\n messages: Default, []>;\n content: Default;\n allCharms: Cell;\n};\n\ntype ChatbotNoteResult = {\n messages: Default, []>;\n mentioned: Default, []>;\n backlinks: Default, []>;\n content: Default;\n note: any;\n chat: any;\n list: Default;\n};\n\nconst newNote = handler<\n {\n /** The text content of the note */\n title: string;\n content?: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const n = Note({\n title: args.title,\n content: args.content || \"\",\n allCharms: state.allCharms,\n });\n\n args.result.set(\n `Created note ${args.title}!`,\n );\n\n state.allCharms.push(n as unknown as MentionableCharm);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\n// put a note at the end of the outline (by appending to root.children)\nconst editNote = handler<\n {\n /** The text content of the note */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { content: Cell }\n>(\n (args, state) => {\n try {\n state.content.set(args.body);\n\n args.result.set(\n `Updated note!`,\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst readNote = handler<\n {\n /** A cell to store the result text */\n result: Cell;\n },\n { content: string }\n>(\n (args, state) => {\n try {\n args.result.set(state.content);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst listMentionable = handler<\n {\n /** A cell to store the result text */\n result: Cell;\n },\n { allCharms: { [NAME]: string }[] }\n>(\n (args, state) => {\n try {\n const namesList = state.allCharms.map((charm) => charm[NAME]);\n args.result.set(JSON.stringify(namesList));\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst readNoteByIndex = handler<\n {\n /** A cell to store the result text */\n index: number;\n result: Cell;\n },\n { allCharms: { [NAME]: string; content?: string }[] }\n>(\n (args, state) => {\n try {\n args.result.set(\n state.allCharms[args.index]?.content || \"No content found\",\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst editNoteByIndex = handler<\n {\n /** The index of the note to edit */\n index: number;\n /** The new text content of the note */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const charms = state.allCharms.get();\n if (args.index < 0 || args.index >= charms.length) {\n args.result.set(`Error: Invalid index ${args.index}`);\n return;\n }\n\n state.allCharms.key(args.index).key(\"content\").set(args.body);\n args.result.set(`Updated note at index ${args.index}!`);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst navigateToNote = handler<\n {\n /** The index of the note to navigate to */\n index: number;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const charms = state.allCharms.get();\n if (args.index < 0 || args.index >= charms.length) {\n args.result.set(`Error: Invalid index ${args.index}`);\n return;\n }\n\n const targetCharm = charms[args.index];\n args.result.set(`Navigating to note: ${targetCharm[NAME]}`);\n\n return navigateTo(state.allCharms.key(args.index));\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport default recipe(\n \"Chatbot + Note\",\n ({ title, messages, content, allCharms }) => {\n const list = cell([]);\n\n const tools = {\n searchWeb: {\n pattern: searchWeb,\n },\n readWebpage: {\n pattern: readWebpage,\n },\n calculator: {\n pattern: calculator,\n },\n addListItem: {\n handler: addListItem({ list }),\n },\n readListItems: {\n handler: readListItems({ list }),\n },\n editActiveNote: {\n description: \"Modify the shared note.\",\n inputSchema: {\n type: \"object\",\n properties: {\n body: {\n type: \"string\",\n description: \"The content of the note.\",\n },\n },\n required: [\"body\"],\n } as JSONSchema,\n handler: editNote({ content }),\n },\n readActiveNote: {\n description: \"Read the currently focused note.\",\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n } as JSONSchema,\n handler: readNote({ content }),\n },\n listNotes: {\n description:\n \"List all mentionable note titles (read the body with readNoteByIndex).\",\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n } as JSONSchema,\n handler: listMentionable({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n readNoteByIndex: {\n description:\n \"Read the body of a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n },\n required: [\"index\"],\n } as JSONSchema,\n handler: readNoteByIndex({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n editNoteByIndex: {\n description:\n \"Edit the body of a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n body: {\n type: \"string\",\n description: \"The new content of the note.\",\n },\n },\n required: [\"index\", \"body\"],\n } as JSONSchema,\n handler: editNoteByIndex({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n navigateToNote: {\n description: \"Navigate to a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n },\n required: [\"index\"],\n } as JSONSchema,\n handler: navigateToNote({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n newNote: {\n description: \"Read the shared note.\",\n inputSchema: {\n type: \"object\",\n properties: {\n title: {\n type: \"string\",\n description: \"The title of the note.\",\n },\n content: {\n type: \"string\",\n description: \"The content of the note.\",\n },\n },\n required: [\"title\"],\n } as JSONSchema,\n handler: newNote({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n };\n\n const chat = Chat({ messages, tools });\n const note = Note({ title, content, allCharms });\n\n return {\n [NAME]: title,\n chat,\n note,\n content,\n messages,\n mentioned: note.mentioned,\n backlinks: note.backlinks,\n list,\n };\n },\n);\n" }, { "name": "/note.tsx", "contents": "/// \nimport {\n Cell,\n cell,\n Default,\n derive,\n h,\n handler,\n lift,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n toSchema,\n UI,\n} from \"commontools\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\ntype Input = {\n title: Default;\n content: Default;\n allCharms: Cell;\n};\n\ntype Output = {\n mentioned: Default, []>;\n content: Default;\n backlinks: Default, []>;\n};\n\nconst updateTitle = handler<\n { detail: { value: string } },\n { title: Cell }\n>(\n (event, state) => {\n state.title.set(event.detail?.value ?? \"\");\n },\n);\n\nconst updateContent = handler<\n { detail: { value: string } },\n { content: Cell }\n>(\n (event, state) => {\n state.content.set(event.detail?.value ?? \"\");\n },\n);\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nconst handleNewBacklink = handler<\n {\n detail: {\n text: string;\n charmId: any;\n charm: Cell;\n navigate: boolean;\n };\n },\n {\n allCharms: Cell;\n }\n>(({ detail }, { allCharms }) => {\n console.log(\"new charm\", detail.text, detail.charmId);\n\n if (detail.navigate) {\n return navigateTo(detail.charm);\n } else {\n allCharms.push(detail.charm as unknown as MentionableCharm);\n }\n});\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\nconst Note = recipe(\n \"Note\",\n ({ title, content, allCharms }) => {\n const mentioned = cell([]);\n\n const computeBacklinks = lift<\n { allCharms: Cell; content: Cell },\n MentionableCharm[]\n >(\n ({ allCharms, content }) => {\n const cs = allCharms.get();\n if (!cs) return [];\n\n const self = cs.find((c) => c.content === content.get());\n\n const results = self\n ? cs.filter((c) =>\n c.mentioned?.some((m) => m.content === self.content) ?? false\n )\n : [];\n\n return results;\n },\n );\n\n const backlinks: OpaqueRef = computeBacklinks({\n allCharms,\n content: content as unknown as Cell, // TODO(bf): this is valid, but types complain\n });\n\n // The only way to serialize a pattern, apparently?\n const pattern = derive(undefined, () => JSON.stringify(Note));\n\n return {\n [NAME]: title,\n [UI]: (\n \n
\n \n
\n\n \n
\n ),\n title,\n content,\n mentioned,\n backlinks,\n };\n },\n);\n\nexport default Note;\n" }, { "name": "/chatbot-list-view.tsx", "contents": "/// \nimport {\n Cell,\n cell,\n Default,\n derive,\n h,\n handler,\n ID,\n ifElse,\n lift,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n toSchema,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot-note-composed.tsx\";\nimport { ListItem } from \"./common-tools.tsx\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\ntype CharmEntry = {\n [ID]: string; // randomId is a string\n local_id: string; // same as ID but easier to access\n charm: any;\n};\n\ntype Input = {\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\n charmsList: Default;\n allCharms: Cell;\n theme?: {\n accentColor: Default;\n fontFace: Default;\n borderRadius: Default;\n };\n};\n\ntype Output = {\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\n};\n\nconst removeChat = handler<\n unknown,\n {\n charmsList: Cell;\n id: string;\n selectedCharm: Cell>;\n }\n>(\n (\n _,\n { charmsList, id, selectedCharm },\n ) => {\n const list = charmsList.get();\n const index = list.findIndex((entry) => entry.local_id === id);\n if (index === -1) return;\n\n const removed = list[index];\n const next = [...list];\n next.splice(index, 1);\n charmsList.set(next);\n\n // If we removed the currently selected charm, choose a new selection.\n const current = selectedCharm.get();\n if (current?.charm === removed.charm) {\n const replacement = next[index] ?? next[index - 1];\n if (replacement) {\n selectedCharm.set({ charm: replacement.charm });\n } else {\n selectedCharm.set({ charm: undefined as unknown as any });\n }\n }\n },\n);\n\n// this will be called whenever charm or selectedCharm changes\n// pass isInitialized to make sure we dont call this each time\n// we change selectedCharm, otherwise creates a loop\nconst storeCharm = lift(\n toSchema<{\n charm: any;\n selectedCharm: Cell>;\n charmsList: Cell;\n allCharms: Cell;\n theme?: {\n accentColor: Default;\n fontFace: Default;\n borderRadius: Default;\n };\n isInitialized: Cell;\n }>(),\n undefined,\n ({ charm, selectedCharm, charmsList, isInitialized, allCharms }) => { // Not including `allCharms` is a compile error...\n if (!isInitialized.get()) {\n console.log(\n \"storeCharm storing charm:\",\n charm,\n );\n selectedCharm.set({ charm });\n\n // create the chat charm with a custom name including a random suffix\n const randomId = Math.random().toString(36).substring(2, 10); // Random 8-char string\n charmsList.push({ [ID]: randomId, local_id: randomId, charm });\n\n isInitialized.set(true);\n return charm;\n } else {\n console.log(\"storeCharm: already initialized\");\n }\n return undefined;\n },\n);\n\nconst populateChatList = lift(\n toSchema<{\n charmsList: CharmEntry[];\n allCharms: Cell;\n selectedCharm: Cell<{ charm: any }>;\n }>(),\n undefined,\n (\n { charmsList, allCharms, selectedCharm },\n ) => {\n if (charmsList.length === 0) {\n const isInitialized = cell(false);\n return storeCharm({\n charm: Chat({\n title: \"New Chat\",\n messages: [],\n content: \"\",\n allCharms,\n }),\n selectedCharm,\n charmsList,\n allCharms,\n isInitialized: isInitialized as unknown as Cell,\n });\n }\n\n return charmsList;\n },\n);\n\nconst createChatRecipe = handler<\n unknown,\n {\n selectedCharm: Cell<{ charm: any }>;\n charmsList: Cell;\n allCharms: Cell;\n }\n>(\n (_, { selectedCharm, charmsList, allCharms }) => {\n const isInitialized = cell(false);\n\n const charm = Chat({\n title: \"New Chat\",\n messages: [],\n content: \"\",\n allCharms,\n });\n // store the charm ref in a cell (pass isInitialized to prevent recursive calls)\n return storeCharm({\n charm,\n selectedCharm,\n charmsList: charmsList as unknown as OpaqueRef,\n allCharms,\n isInitialized: isInitialized as unknown as Cell,\n });\n },\n);\n\nconst selectCharm = handler<\n unknown,\n { selectedCharm: Cell<{ charm: any }>; charm: any }\n>(\n (_, { selectedCharm, charm }) => {\n console.log(\"selectCharm: updating selectedCharm to \", charm);\n selectedCharm.set({ charm });\n return selectedCharm;\n },\n);\n\nconst logCharmsList = lift<\n { charmsList: Cell },\n Cell\n>(\n ({ charmsList }) => {\n console.log(\"logCharmsList: \", charmsList.get());\n return charmsList;\n },\n);\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\nconst combineLists = lift(\n (\n { allCharms, charmsList }: { allCharms: any[]; charmsList: CharmEntry[] },\n ) => {\n return [...charmsList.map((c) => c.charm), ...allCharms];\n },\n);\n\nconst getSelectedCharm = lift<\n { entry: { charm: any | undefined } },\n {\n chat: unknown;\n note: unknown;\n list: ListItem[];\n backlinks: MentionableCharm[];\n mentioned: MentionableCharm[];\n } | undefined\n>(\n ({ entry }) => {\n return entry?.charm;\n },\n);\n\nconst getCharmName = lift(({ charm }: { charm: any }) => {\n return charm?.[NAME] || \"Unknown\";\n});\n\n// create the named cell inside the recipe body, so we do it just once\nexport default recipe(\n \"Launcher\",\n ({ selectedCharm, charmsList, allCharms, theme }) => {\n logCharmsList({ charmsList: charmsList as unknown as Cell });\n\n populateChatList({\n selectedCharm: selectedCharm as unknown as Cell<\n Pick\n >,\n charmsList,\n allCharms,\n });\n\n const combined = combineLists({\n allCharms: allCharms as unknown as any[],\n charmsList,\n });\n\n const selected = getSelectedCharm({ entry: selectedCharm });\n\n const localTheme = theme ?? {\n accentColor: cell(\"#3b82f6\"),\n fontFace: cell(\"system-ui, -apple-system, sans-serif\"),\n borderRadius: cell(\"0.5rem\"),\n };\n\n return {\n [NAME]: \"Launcher\",\n [UI]: (\n \n \n
\n \n
\n \n Create New Chat\n alt+N\n \n
\n
\n\n {/* Keyboard shortcuts */}\n \n
\n \n {/* workaround: this seems to correctly start the sub-recipes on a refresh while directly rendering does not */}\n {/* this should be fixed after the builder-refactor (DX1) */}\n \n \n \n \n \n \n\n \n\n \n \n
\n
\n ),\n selectedCharm,\n charmsList,\n };\n },\n);\n" }, { "name": "/common-tools.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n BuiltInLLMTool,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n h,\n handler,\n ifElse,\n llmDialog,\n NAME,\n recipe,\n Stream,\n UI,\n} from \"commontools\";\n\n///// COMMON TOOLS (get it?) ////\n\n/**\n * Calculate the result of a mathematical expression.\n * Supports +, -, *, /, and parentheses.\n */\ntype CalculatorRequest = {\n /** The mathematical expression to evaluate. */\n expression: string;\n};\n\nexport const calculator = recipe<\n CalculatorRequest,\n string | { error: string }\n>(\"Calculator\", ({ expression }) => {\n return derive(expression, (expr) => {\n const sanitized = expr.replace(/[^0-9+\\-*/().\\s]/g, \"\");\n let result;\n try {\n result = Function(`\"use strict\"; return (${sanitized})`)();\n } catch (error) {\n result = { error: (error as any)?.message || \"\" };\n }\n return result;\n });\n});\n\n/** Add an item to the list. */\ntype AddListItemRequest = {\n /** The item to add to the list. */\n item: string;\n result: Cell;\n};\n\n/** Read all items from the list. */\ntype ReadListItemsRequest = {\n result: Cell;\n};\n\nexport type ListItem = {\n title: string;\n};\n\nexport const addListItem = handler<\n AddListItemRequest,\n { list: Cell }\n>(\n (args, state) => {\n try {\n state.list.push({ title: args.item });\n args.result.set(`${state.list.get().length} items`);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport const readListItems = handler<\n ReadListItemsRequest,\n { list: ListItem[] }\n>(\n (args, state) => {\n try {\n const items = state.list;\n if (items.length === 0) {\n args.result.set(\"The list is empty\");\n } else {\n const itemList = items.map((item, index) =>\n `${index + 1}. ${item.title}`\n ).join(\"\\n\");\n args.result.set(`List items (${items.length} total):\\n${itemList}`);\n }\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\n/** Search the web for information. */\ntype SearchQuery = {\n /** The query to search the web for. */\n query: string;\n};\n\ntype SearchWebResult = {\n results: {\n title: string;\n url: string;\n description: string;\n }[];\n};\n\nexport const searchWeb = recipe<\n SearchQuery,\n SearchWebResult | { error: string }\n>(\"Search Web\", ({ query }) => {\n const { result, error } = fetchData({\n url: \"/api/agent-tools/web-search\",\n mode: \"json\",\n options: {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: {\n query,\n max_results: 5,\n },\n },\n });\n\n // TODO(seefeld): Should we instead return { result, error }? Or allocate a\n // special [ERROR] for errors? Ideally this isn\\'t specific to using recipes as\n // tools but a general pattern.\n return ifElse(error, { error }, result);\n});\n\n/** Read and extract content from a specific webpage URL. */\ntype ReadWebRequest = {\n /** The URL of the webpage to read and extract content from. */\n url: string;\n};\n\ntype ReadWebResult = {\n content: string;\n metadata: {\n title?: string;\n author?: string;\n date?: string;\n word_count: number;\n };\n};\n\nexport const readWebpage = recipe<\n ReadWebRequest,\n ReadWebResult | { error: string }\n>(\"Read Webpage\", ({ url }) => {\n const { result, error } = fetchData({\n url: \"/api/agent-tools/web-read\",\n mode: \"json\",\n options: {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: {\n url,\n max_tokens: 4000,\n include_code: true,\n },\n },\n });\n\n return ifElse(error, { error }, result);\n});\n\ntype ToolsInput = {\n list: ListItem[];\n};\n\nexport default recipe(\"Tools\", ({ list }) => {\n const tools: Record = {\n search_web: {\n pattern: searchWeb,\n },\n read_webpage: {\n pattern: readWebpage,\n },\n calculator: {\n pattern: calculator,\n },\n addListItem: {\n handler: addListItem({ list }),\n },\n };\n\n return { tools, list };\n});\n" } ] } } }, "since": 14 } } }, "of:baedreia4yc7gahp4obzf3uhvaiyewc5svvao6aouafqyd6xya7vd3mwgze": { "application/json": { "ba4jcazx4oqg7tjxexorpqe2slrokeawnpgbtpg2bvhqlamgaryhvkr4z": { "is": { "source": { "/": "baedreidblgfriwnkzwfhl6v4vloiksavnq5j4h2blyo5zxxymuvjyhj46i" }, "value": { "$alias": { "path": [ "internal", "__#0" ], "cell": { "/": "baedreidblgfriwnkzwfhl6v4vloiksavnq5j4h2blyo5zxxymuvjyhj46i" } } } }, "since": 17 } } }, "of:baedreidblgfriwnkzwfhl6v4vloiksavnq5j4h2blyo5zxxymuvjyhj46i": { "application/json": { "ba4jcb27nrmt74cbdpsa3guijjp6zsjlb623qpjspnc2ip2l6yl7yivzb": { "is": { "value": { "$TYPE": "ba4jcbklrlmvvqij7jre5nn3wuqrv6e3mshfd3njnmqinnne7acgspuza", "resultRef": { "/": { "link@1": { "path": [], "id": "of:baedreia4yc7gahp4obzf3uhvaiyewc5svvao6aouafqyd6xya7vd3mwgze" } } }, "internal": { "defaultValue": { "pending": { "/": { "link@1": { "path": [], "id": "of:baedreicyeijol47rmmtf2wwwnldnuxam4xzg56dtvtu3bmqqsvi23f4sli", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, "result": { "/": { "link@1": { "path": [], "id": "of:baedreift2vpfjfllcs3gxcubgbqjnjgursxrz4qmw25fypdfsi7mmj3f2a", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, "partial": { "/": { "link@1": { "path": [], "id": "of:baedreibkfir4uivemhvtym5ppj2gbpelqfktc76uipqqci4j2a6ii23q4m", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, "requestHash": { "/": { "link@1": { "path": [], "id": "of:baedreibbqfoogsx5axelgu3eahsrrbvmhvkczdyftaruhbdjfdisf3jysm", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } } }, "prompt": "", "__#0": "Untitled Chat" }, "spell": { "/": { "link@1": { "id": "of:baedreiaje4ypvndxx4yy4g4n5tsngfy3s3h6dg7xttput4fc4vvxvpcvry" } } }, "argument": { "model": { "$alias": { "path": [ "internal", "model" ], "cell": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" } } }, "messages": { "$alias": { "path": [ "argument", "messages" ], "schema": { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMMessage" }, "default": [] }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "messages": { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMMessage" }, "default": [] }, "tools": true, "theme": true }, "required": [ "messages", "tools" ], "$defs": { "BuiltInLLMMessage": { "type": "object", "properties": { "role": { "enum": [ "system", "user", "assistant", "tool" ] }, "content": { "$ref": "#/$defs/BuiltInLLMContent" } }, "required": [ "role", "content" ] }, "BuiltInLLMContent": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMContentPart" } } ] }, "BuiltInLLMContentPart": { "anyOf": [ { "$ref": "#/$defs/BuiltInLLMTextPart" }, { "$ref": "#/$defs/BuiltInLLMImagePart" }, { "$ref": "#/$defs/BuiltInLLMToolCallPart" }, { "$ref": "#/$defs/BuiltInLLMToolResultPart" } ] }, "BuiltInLLMToolResultPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-result" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "output": { "anyOf": [ { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "value": { "type": "string" } }, "required": [ "type", "value" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "json" ] }, "value": true }, "required": [ "type", "value" ] } ] } }, "required": [ "type", "toolCallId", "toolName", "output" ] }, "BuiltInLLMToolCallPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-call" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "input": { "$ref": "#/$defs/Record" } }, "required": [ "type", "toolCallId", "toolName", "input" ] }, "Record": { "type": "object", "properties": { }, "additionalProperties": true }, "BuiltInLLMImagePart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "image" ] }, "image": { "anyOf": [ { "type": "string" }, true, true, { "type": "string", "format": "uri" } ] } }, "required": [ "type", "image" ] }, "BuiltInLLMTextPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "text": { "type": "string" } }, "required": [ "type", "text" ] } } }, "cell": { "/": "baedreiatmrbqzixxw7op7kvfxx4me7lqhkqd7za5quc5orxqhysscak7x4" } } } } } }, "since": 33 } } }, "of:baedreiaje4ypvndxx4yy4g4n5tsngfy3s3h6dg7xttput4fc4vvxvpcvry": { "application/json": { "ba4jcaxcxm7vsvl4gm42bwuxsugksnp2ogbvwb7gnvhlcj5n2346rkv5w": { "is": { "value": { "id": "ba4jcbklrlmvvqij7jre5nn3wuqrv6e3mshfd3njnmqinnne7acgspuza", "program": { "main": "/chatbot.tsx", "mainExport": "TitleGenerator", "files": [ { "name": "/default-app.tsx", "contents": "/// \nimport {\n Cell,\n Default,\n derive,\n h,\n handler,\n NAME,\n navigateTo,\n Opaque,\n OpaqueRef,\n recipe,\n str,\n UI,\n} from \"commontools\";\n\n// Import recipes we want to be launchable from the default app.\nimport Chatbot from \"./chatbot.tsx\";\nimport ChatbotOutliner from \"./chatbot-outliner.tsx\";\nimport { type MentionableCharm } from \"./chatbot-note-composed.tsx\";\nimport { default as Note } from \"./note.tsx\";\nimport ChatList from \"./chatbot-list-view.tsx\";\n\nexport type Charm = {\n [NAME]?: string;\n [UI]?: unknown;\n [key: string]: any;\n};\n\ntype CharmsListInput = {\n allCharms: Default;\n};\n\n// Recipe returns only UI, no data outputs (only symbol properties)\ninterface CharmsListOutput {\n [key: string]: unknown;\n}\n\nconst visit = handler<\n Record,\n { charm: any }\n>((_, state) => {\n return navigateTo(state.charm);\n}, { proxy: true });\n\nconst removeCharm = handler<\n Record,\n {\n charm: any;\n allCharms: Cell;\n }\n>((_, state) => {\n const charmName = state.charm[NAME];\n const allCharmsValue = state.allCharms.get();\n const index = allCharmsValue.findIndex((c: any) => c[NAME] === charmName);\n\n if (index !== -1) {\n const charmListCopy = [...allCharmsValue];\n console.log(\"charmListCopy before\", charmListCopy);\n charmListCopy.splice(index, 1);\n console.log(\"charmListCopy after\", charmListCopy);\n state.allCharms.set(charmListCopy);\n }\n});\n\nconst spawnChatList = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(ChatList({\n selectedCharm: { charm: undefined },\n charmsList: [],\n allCharms: state.allCharms, // we should handle empty here\n }));\n});\n\nconst spawnChatbot = handler<\n Record,\n Record\n>((_, state) => {\n return navigateTo(Chatbot({\n messages: [],\n tools: undefined,\n }));\n});\n\nconst spawnChatbotOutliner = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(ChatbotOutliner({\n title: \"Chatbot Outliner\",\n expandChat: false,\n messages: [],\n outline: {\n root: { body: \"\", children: [], attachments: [] },\n },\n allCharms: state.allCharms,\n }));\n});\n\nconst spawnNote = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(Note({\n title: \"New Note\",\n content: \"\",\n allCharms: state.allCharms,\n }));\n});\n\nexport default recipe(\n \"DefaultCharmList\",\n ({ allCharms }) => {\n return {\n [NAME]: str`DefaultCharmList (${allCharms.length})`,\n [UI]: (\n \n ,\n })}\n />\n\n \n {/* Quick Launch Toolbar */}\n \n

Quicklaunch:

\n ,\n })}\n >\n 📂 Chat List\n \n \n 💬 Chatbot\n \n \n 📝 Chatbot Outliner\n \n ,\n })}\n >\n 📄 Note\n \n
\n\n

Charms ({allCharms.length})

\n\n \n \n \n Charm Name\n Actions\n \n \n \n {derive(allCharms, (allCharms) =>\n allCharms.map((charm: any) => (\n \n {charm[NAME] || \"Untitled Charm\"}\n \n \n \n Visit\n \n \n Remove\n \n \n \n \n )))}\n \n \n
\n
\n ),\n };\n },\n);\n" }, { "name": "/chatbot.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n generateObject,\n h,\n handler,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n recipe,\n str,\n Stream,\n UI,\n} from \"commontools\";\n\nconst sendMessage = handler<\n { detail: { message: string } },\n {\n addMessage: Stream;\n }\n>((event, { addMessage }) => {\n addMessage.send({\n role: \"user\",\n content: [{ type: \"text\", text: event.detail.message }],\n });\n});\n\nconst clearChat = handler(\n (\n _: never,\n { messages, pending }: {\n messages: Cell>;\n pending: Cell;\n },\n ) => {\n messages.set([]);\n pending.set(false);\n },\n);\n\ntype ChatInput = {\n messages: Default, []>;\n tools: any;\n theme?: any;\n};\n\ntype ChatOutput = {\n messages: Array;\n pending: boolean | undefined;\n addMessage: Stream;\n cancelGeneration: Stream;\n title?: string;\n};\n\nexport const TitleGenerator = recipe<\n { model?: string; messages: Array }\n>(\"Title Generator\", ({ model, messages }) => {\n const titleMessages = derive(messages, (m) => {\n if (!m || m.length === 0) return \"\";\n\n const messageCount = 2;\n const selectedMessages = m.slice(0, messageCount).filter(Boolean);\n\n if (selectedMessages.length === 0) return \"\";\n\n return selectedMessages.map((msg) => JSON.stringify(msg)).join(\"\\n\");\n });\n\n const { result } = generateObject({\n system:\n \"Generate at most a 3-word title based on the following content, respond with NOTHING but the literal title text.\",\n prompt: titleMessages,\n model,\n schema: {\n type: \"object\",\n properties: {\n title: {\n type: \"string\",\n description: \"The title of the chat\",\n },\n },\n required: [\"title\"],\n },\n });\n\n const title = derive(result, (t) => {\n return t?.title || \"Untitled Chat\";\n });\n\n return title;\n});\n\nexport default recipe(\n \"Chat\",\n ({ messages, tools, theme }) => {\n const model = cell(\"anthropic:claude-sonnet-4-5\");\n\n const { addMessage, cancelGeneration, pending } = llmDialog({\n system: \"You are a helpful assistant with some tools.\",\n messages,\n tools,\n model,\n });\n\n const { result } = fetchData({\n url: \"/api/ai/llm/models\",\n mode: \"json\",\n });\n\n const items = derive(result, (models) => {\n if (!models) return [];\n const items = Object.keys(models as any).map((key) => ({\n label: key,\n value: key,\n }));\n return items;\n });\n\n const title = TitleGenerator({ model, messages });\n\n return {\n [NAME]: title,\n [UI]: (\n \n \n {title}\n \n \n\n \n \n \n\n
\n \n \n
\n
\n ),\n messages,\n pending,\n addMessage,\n cancelGeneration,\n title,\n };\n },\n);\n" }, { "name": "/chatbot-outliner.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n getRecipeEnvironment,\n h,\n handler,\n ID,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n str,\n Stream,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot.tsx\";\n\ntype Charm = any;\n\ntype OutlinerNode = {\n body: Default;\n children: Default;\n attachments: Default[], []>;\n};\n\ntype Outliner = {\n root: OutlinerNode;\n};\n\ntype PageResult = {\n outline: Default<\n Outliner,\n { root: { body: \"\"; children: []; attachments: [] } }\n >;\n};\n\nexport type PageInput = {\n outline: Outliner;\n allCharms: Cell;\n};\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nexport const Page = recipe(\n \"Page\",\n ({ outline, allCharms }) => {\n return {\n [NAME]: \"Page\",\n [UI]: (\n \n ),\n outline,\n };\n },\n);\n\ntype LLMTestInput = {\n title: Default;\n messages: Default, []>;\n expandChat: Default;\n outline: Default<\n Outliner,\n { root: { body: \"Untitled Page\"; children: []; attachments: [] } }\n >;\n allCharms: Cell;\n};\n\ntype LLMTestResult = {\n messages: Default, []>;\n};\n\n// put a node at the end of the outline (by appending to root.children)\nconst appendOutlinerNode = handler<\n {\n /** The text content/title of the outliner node to be appended */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { outline: Cell }\n>(\n (args, state) => {\n try {\n (state.outline.key(\"root\").key(\"children\")).push({\n body: args.body,\n children: [],\n attachments: [],\n });\n\n args.result.set(\n `${state.outline.key(\"root\").key(\"children\").get().length} nodes`,\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport default recipe(\n \"Outliner\",\n ({ title, expandChat, messages, outline, allCharms }) => {\n const tools = {\n appendOutlinerNode: {\n description: \"Add a new outliner node.\",\n inputSchema: {\n type: \"object\",\n properties: {\n body: {\n type: \"string\",\n description: \"The title of the new node.\",\n },\n },\n required: [\"body\"],\n } as JSONSchema,\n handler: appendOutlinerNode({ outline }),\n },\n };\n\n const chat = Chat({ messages, tools });\n const { addMessage, cancelGeneration, pending } = chat;\n\n return {\n [NAME]: title,\n [UI]: (\n \n \n
\n
\n Show Chat\n
\n
\n\n \n \n
\n \n
\n\n \n \n \n \n \n
\n\n {ifElse(\n expandChat,\n chat,\n null,\n )}\n
\n
\n ),\n messages,\n };\n },\n);\n" }, { "name": "/chatbot-note-composed.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n getRecipeEnvironment,\n h,\n handler,\n ID,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n str,\n Stream,\n toSchema,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot.tsx\";\nimport Note from \"./note.tsx\";\nimport Tools, {\n addListItem,\n calculator,\n ListItem,\n readListItems,\n readWebpage,\n searchWeb,\n} from \"./common-tools.tsx\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\n// export type ChatbotNoteInput = {\n// content: Default;\n// allCharms?: Cell;\n// };\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\ntype ChatbotNoteInput = {\n title: Default;\n messages: Default, []>;\n content: Default;\n allCharms: Cell;\n};\n\ntype ChatbotNoteResult = {\n messages: Default, []>;\n mentioned: Default, []>;\n backlinks: Default, []>;\n content: Default;\n note: any;\n chat: any;\n list: Default;\n};\n\nconst newNote = handler<\n {\n /** The text content of the note */\n title: string;\n content?: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const n = Note({\n title: args.title,\n content: args.content || \"\",\n allCharms: state.allCharms,\n });\n\n args.result.set(\n `Created note ${args.title}!`,\n );\n\n state.allCharms.push(n as unknown as MentionableCharm);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\n// put a note at the end of the outline (by appending to root.children)\nconst editNote = handler<\n {\n /** The text content of the note */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { content: Cell }\n>(\n (args, state) => {\n try {\n state.content.set(args.body);\n\n args.result.set(\n `Updated note!`,\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst readNote = handler<\n {\n /** A cell to store the result text */\n result: Cell;\n },\n { content: string }\n>(\n (args, state) => {\n try {\n args.result.set(state.content);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst listMentionable = handler<\n {\n /** A cell to store the result text */\n result: Cell;\n },\n { allCharms: { [NAME]: string }[] }\n>(\n (args, state) => {\n try {\n const namesList = state.allCharms.map((charm) => charm[NAME]);\n args.result.set(JSON.stringify(namesList));\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst readNoteByIndex = handler<\n {\n /** A cell to store the result text */\n index: number;\n result: Cell;\n },\n { allCharms: { [NAME]: string; content?: string }[] }\n>(\n (args, state) => {\n try {\n args.result.set(\n state.allCharms[args.index]?.content || \"No content found\",\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst editNoteByIndex = handler<\n {\n /** The index of the note to edit */\n index: number;\n /** The new text content of the note */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const charms = state.allCharms.get();\n if (args.index < 0 || args.index >= charms.length) {\n args.result.set(`Error: Invalid index ${args.index}`);\n return;\n }\n\n state.allCharms.key(args.index).key(\"content\").set(args.body);\n args.result.set(`Updated note at index ${args.index}!`);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst navigateToNote = handler<\n {\n /** The index of the note to navigate to */\n index: number;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const charms = state.allCharms.get();\n if (args.index < 0 || args.index >= charms.length) {\n args.result.set(`Error: Invalid index ${args.index}`);\n return;\n }\n\n const targetCharm = charms[args.index];\n args.result.set(`Navigating to note: ${targetCharm[NAME]}`);\n\n return navigateTo(state.allCharms.key(args.index));\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport default recipe(\n \"Chatbot + Note\",\n ({ title, messages, content, allCharms }) => {\n const list = cell([]);\n\n const tools = {\n searchWeb: {\n pattern: searchWeb,\n },\n readWebpage: {\n pattern: readWebpage,\n },\n calculator: {\n pattern: calculator,\n },\n addListItem: {\n handler: addListItem({ list }),\n },\n readListItems: {\n handler: readListItems({ list }),\n },\n editActiveNote: {\n description: \"Modify the shared note.\",\n inputSchema: {\n type: \"object\",\n properties: {\n body: {\n type: \"string\",\n description: \"The content of the note.\",\n },\n },\n required: [\"body\"],\n } as JSONSchema,\n handler: editNote({ content }),\n },\n readActiveNote: {\n description: \"Read the currently focused note.\",\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n } as JSONSchema,\n handler: readNote({ content }),\n },\n listNotes: {\n description:\n \"List all mentionable note titles (read the body with readNoteByIndex).\",\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n } as JSONSchema,\n handler: listMentionable({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n readNoteByIndex: {\n description:\n \"Read the body of a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n },\n required: [\"index\"],\n } as JSONSchema,\n handler: readNoteByIndex({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n editNoteByIndex: {\n description:\n \"Edit the body of a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n body: {\n type: \"string\",\n description: \"The new content of the note.\",\n },\n },\n required: [\"index\", \"body\"],\n } as JSONSchema,\n handler: editNoteByIndex({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n navigateToNote: {\n description: \"Navigate to a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n },\n required: [\"index\"],\n } as JSONSchema,\n handler: navigateToNote({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n newNote: {\n description: \"Read the shared note.\",\n inputSchema: {\n type: \"object\",\n properties: {\n title: {\n type: \"string\",\n description: \"The title of the note.\",\n },\n content: {\n type: \"string\",\n description: \"The content of the note.\",\n },\n },\n required: [\"title\"],\n } as JSONSchema,\n handler: newNote({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n };\n\n const chat = Chat({ messages, tools });\n const note = Note({ title, content, allCharms });\n\n return {\n [NAME]: title,\n chat,\n note,\n content,\n messages,\n mentioned: note.mentioned,\n backlinks: note.backlinks,\n list,\n };\n },\n);\n" }, { "name": "/note.tsx", "contents": "/// \nimport {\n Cell,\n cell,\n Default,\n derive,\n h,\n handler,\n lift,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n toSchema,\n UI,\n} from \"commontools\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\ntype Input = {\n title: Default;\n content: Default;\n allCharms: Cell;\n};\n\ntype Output = {\n mentioned: Default, []>;\n content: Default;\n backlinks: Default, []>;\n};\n\nconst updateTitle = handler<\n { detail: { value: string } },\n { title: Cell }\n>(\n (event, state) => {\n state.title.set(event.detail?.value ?? \"\");\n },\n);\n\nconst updateContent = handler<\n { detail: { value: string } },\n { content: Cell }\n>(\n (event, state) => {\n state.content.set(event.detail?.value ?? \"\");\n },\n);\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nconst handleNewBacklink = handler<\n {\n detail: {\n text: string;\n charmId: any;\n charm: Cell;\n navigate: boolean;\n };\n },\n {\n allCharms: Cell;\n }\n>(({ detail }, { allCharms }) => {\n console.log(\"new charm\", detail.text, detail.charmId);\n\n if (detail.navigate) {\n return navigateTo(detail.charm);\n } else {\n allCharms.push(detail.charm as unknown as MentionableCharm);\n }\n});\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\nconst Note = recipe(\n \"Note\",\n ({ title, content, allCharms }) => {\n const mentioned = cell([]);\n\n const computeBacklinks = lift<\n { allCharms: Cell; content: Cell },\n MentionableCharm[]\n >(\n ({ allCharms, content }) => {\n const cs = allCharms.get();\n if (!cs) return [];\n\n const self = cs.find((c) => c.content === content.get());\n\n const results = self\n ? cs.filter((c) =>\n c.mentioned?.some((m) => m.content === self.content) ?? false\n )\n : [];\n\n return results;\n },\n );\n\n const backlinks: OpaqueRef = computeBacklinks({\n allCharms,\n content: content as unknown as Cell, // TODO(bf): this is valid, but types complain\n });\n\n // The only way to serialize a pattern, apparently?\n const pattern = derive(undefined, () => JSON.stringify(Note));\n\n return {\n [NAME]: title,\n [UI]: (\n \n
\n \n
\n\n \n
\n ),\n title,\n content,\n mentioned,\n backlinks,\n };\n },\n);\n\nexport default Note;\n" }, { "name": "/chatbot-list-view.tsx", "contents": "/// \nimport {\n Cell,\n cell,\n Default,\n derive,\n h,\n handler,\n ID,\n ifElse,\n lift,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n toSchema,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot-note-composed.tsx\";\nimport { ListItem } from \"./common-tools.tsx\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\ntype CharmEntry = {\n [ID]: string; // randomId is a string\n local_id: string; // same as ID but easier to access\n charm: any;\n};\n\ntype Input = {\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\n charmsList: Default;\n allCharms: Cell;\n theme?: {\n accentColor: Default;\n fontFace: Default;\n borderRadius: Default;\n };\n};\n\ntype Output = {\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\n};\n\nconst removeChat = handler<\n unknown,\n {\n charmsList: Cell;\n id: string;\n selectedCharm: Cell>;\n }\n>(\n (\n _,\n { charmsList, id, selectedCharm },\n ) => {\n const list = charmsList.get();\n const index = list.findIndex((entry) => entry.local_id === id);\n if (index === -1) return;\n\n const removed = list[index];\n const next = [...list];\n next.splice(index, 1);\n charmsList.set(next);\n\n // If we removed the currently selected charm, choose a new selection.\n const current = selectedCharm.get();\n if (current?.charm === removed.charm) {\n const replacement = next[index] ?? next[index - 1];\n if (replacement) {\n selectedCharm.set({ charm: replacement.charm });\n } else {\n selectedCharm.set({ charm: undefined as unknown as any });\n }\n }\n },\n);\n\n// this will be called whenever charm or selectedCharm changes\n// pass isInitialized to make sure we dont call this each time\n// we change selectedCharm, otherwise creates a loop\nconst storeCharm = lift(\n toSchema<{\n charm: any;\n selectedCharm: Cell>;\n charmsList: Cell;\n allCharms: Cell;\n theme?: {\n accentColor: Default;\n fontFace: Default;\n borderRadius: Default;\n };\n isInitialized: Cell;\n }>(),\n undefined,\n ({ charm, selectedCharm, charmsList, isInitialized, allCharms }) => { // Not including `allCharms` is a compile error...\n if (!isInitialized.get()) {\n console.log(\n \"storeCharm storing charm:\",\n charm,\n );\n selectedCharm.set({ charm });\n\n // create the chat charm with a custom name including a random suffix\n const randomId = Math.random().toString(36).substring(2, 10); // Random 8-char string\n charmsList.push({ [ID]: randomId, local_id: randomId, charm });\n\n isInitialized.set(true);\n return charm;\n } else {\n console.log(\"storeCharm: already initialized\");\n }\n return undefined;\n },\n);\n\nconst populateChatList = lift(\n toSchema<{\n charmsList: CharmEntry[];\n allCharms: Cell;\n selectedCharm: Cell<{ charm: any }>;\n }>(),\n undefined,\n (\n { charmsList, allCharms, selectedCharm },\n ) => {\n if (charmsList.length === 0) {\n const isInitialized = cell(false);\n return storeCharm({\n charm: Chat({\n title: \"New Chat\",\n messages: [],\n content: \"\",\n allCharms,\n }),\n selectedCharm,\n charmsList,\n allCharms,\n isInitialized: isInitialized as unknown as Cell,\n });\n }\n\n return charmsList;\n },\n);\n\nconst createChatRecipe = handler<\n unknown,\n {\n selectedCharm: Cell<{ charm: any }>;\n charmsList: Cell;\n allCharms: Cell;\n }\n>(\n (_, { selectedCharm, charmsList, allCharms }) => {\n const isInitialized = cell(false);\n\n const charm = Chat({\n title: \"New Chat\",\n messages: [],\n content: \"\",\n allCharms,\n });\n // store the charm ref in a cell (pass isInitialized to prevent recursive calls)\n return storeCharm({\n charm,\n selectedCharm,\n charmsList: charmsList as unknown as OpaqueRef,\n allCharms,\n isInitialized: isInitialized as unknown as Cell,\n });\n },\n);\n\nconst selectCharm = handler<\n unknown,\n { selectedCharm: Cell<{ charm: any }>; charm: any }\n>(\n (_, { selectedCharm, charm }) => {\n console.log(\"selectCharm: updating selectedCharm to \", charm);\n selectedCharm.set({ charm });\n return selectedCharm;\n },\n);\n\nconst logCharmsList = lift<\n { charmsList: Cell },\n Cell\n>(\n ({ charmsList }) => {\n console.log(\"logCharmsList: \", charmsList.get());\n return charmsList;\n },\n);\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\nconst combineLists = lift(\n (\n { allCharms, charmsList }: { allCharms: any[]; charmsList: CharmEntry[] },\n ) => {\n return [...charmsList.map((c) => c.charm), ...allCharms];\n },\n);\n\nconst getSelectedCharm = lift<\n { entry: { charm: any | undefined } },\n {\n chat: unknown;\n note: unknown;\n list: ListItem[];\n backlinks: MentionableCharm[];\n mentioned: MentionableCharm[];\n } | undefined\n>(\n ({ entry }) => {\n return entry?.charm;\n },\n);\n\nconst getCharmName = lift(({ charm }: { charm: any }) => {\n return charm?.[NAME] || \"Unknown\";\n});\n\n// create the named cell inside the recipe body, so we do it just once\nexport default recipe(\n \"Launcher\",\n ({ selectedCharm, charmsList, allCharms, theme }) => {\n logCharmsList({ charmsList: charmsList as unknown as Cell });\n\n populateChatList({\n selectedCharm: selectedCharm as unknown as Cell<\n Pick\n >,\n charmsList,\n allCharms,\n });\n\n const combined = combineLists({\n allCharms: allCharms as unknown as any[],\n charmsList,\n });\n\n const selected = getSelectedCharm({ entry: selectedCharm });\n\n const localTheme = theme ?? {\n accentColor: cell(\"#3b82f6\"),\n fontFace: cell(\"system-ui, -apple-system, sans-serif\"),\n borderRadius: cell(\"0.5rem\"),\n };\n\n return {\n [NAME]: \"Launcher\",\n [UI]: (\n \n \n
\n \n
\n \n Create New Chat\n alt+N\n \n
\n
\n\n {/* Keyboard shortcuts */}\n \n
\n \n {/* workaround: this seems to correctly start the sub-recipes on a refresh while directly rendering does not */}\n {/* this should be fixed after the builder-refactor (DX1) */}\n \n \n \n \n \n \n\n \n\n \n \n
\n
\n ),\n selectedCharm,\n charmsList,\n };\n },\n);\n" }, { "name": "/common-tools.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n BuiltInLLMTool,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n h,\n handler,\n ifElse,\n llmDialog,\n NAME,\n recipe,\n Stream,\n UI,\n} from \"commontools\";\n\n///// COMMON TOOLS (get it?) ////\n\n/**\n * Calculate the result of a mathematical expression.\n * Supports +, -, *, /, and parentheses.\n */\ntype CalculatorRequest = {\n /** The mathematical expression to evaluate. */\n expression: string;\n};\n\nexport const calculator = recipe<\n CalculatorRequest,\n string | { error: string }\n>(\"Calculator\", ({ expression }) => {\n return derive(expression, (expr) => {\n const sanitized = expr.replace(/[^0-9+\\-*/().\\s]/g, \"\");\n let result;\n try {\n result = Function(`\"use strict\"; return (${sanitized})`)();\n } catch (error) {\n result = { error: (error as any)?.message || \"\" };\n }\n return result;\n });\n});\n\n/** Add an item to the list. */\ntype AddListItemRequest = {\n /** The item to add to the list. */\n item: string;\n result: Cell;\n};\n\n/** Read all items from the list. */\ntype ReadListItemsRequest = {\n result: Cell;\n};\n\nexport type ListItem = {\n title: string;\n};\n\nexport const addListItem = handler<\n AddListItemRequest,\n { list: Cell }\n>(\n (args, state) => {\n try {\n state.list.push({ title: args.item });\n args.result.set(`${state.list.get().length} items`);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport const readListItems = handler<\n ReadListItemsRequest,\n { list: ListItem[] }\n>(\n (args, state) => {\n try {\n const items = state.list;\n if (items.length === 0) {\n args.result.set(\"The list is empty\");\n } else {\n const itemList = items.map((item, index) =>\n `${index + 1}. ${item.title}`\n ).join(\"\\n\");\n args.result.set(`List items (${items.length} total):\\n${itemList}`);\n }\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\n/** Search the web for information. */\ntype SearchQuery = {\n /** The query to search the web for. */\n query: string;\n};\n\ntype SearchWebResult = {\n results: {\n title: string;\n url: string;\n description: string;\n }[];\n};\n\nexport const searchWeb = recipe<\n SearchQuery,\n SearchWebResult | { error: string }\n>(\"Search Web\", ({ query }) => {\n const { result, error } = fetchData({\n url: \"/api/agent-tools/web-search\",\n mode: \"json\",\n options: {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: {\n query,\n max_results: 5,\n },\n },\n });\n\n // TODO(seefeld): Should we instead return { result, error }? Or allocate a\n // special [ERROR] for errors? Ideally this isn\\'t specific to using recipes as\n // tools but a general pattern.\n return ifElse(error, { error }, result);\n});\n\n/** Read and extract content from a specific webpage URL. */\ntype ReadWebRequest = {\n /** The URL of the webpage to read and extract content from. */\n url: string;\n};\n\ntype ReadWebResult = {\n content: string;\n metadata: {\n title?: string;\n author?: string;\n date?: string;\n word_count: number;\n };\n};\n\nexport const readWebpage = recipe<\n ReadWebRequest,\n ReadWebResult | { error: string }\n>(\"Read Webpage\", ({ url }) => {\n const { result, error } = fetchData({\n url: \"/api/agent-tools/web-read\",\n mode: \"json\",\n options: {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: {\n url,\n max_tokens: 4000,\n include_code: true,\n },\n },\n });\n\n return ifElse(error, { error }, result);\n});\n\ntype ToolsInput = {\n list: ListItem[];\n};\n\nexport default recipe(\"Tools\", ({ list }) => {\n const tools: Record = {\n search_web: {\n pattern: searchWeb,\n },\n read_webpage: {\n pattern: readWebpage,\n },\n calculator: {\n pattern: calculator,\n },\n addListItem: {\n handler: addListItem({ list }),\n },\n };\n\n return { tools, list };\n});\n" } ] } } }, "since": 15 } } }, "of:baedreidzxh4cwepeapuwyxfx6srdrhiiboxp4q6uik5c3o74hl52u2bste": { "application/json": { "ba4jcbkigoxcw6x5c32jytayhimbheppwtygaezruxkthhtwrq4c7ac3p": { "is": { "value": { "addMessage": { "$stream": true }, "cancelGeneration": { "$stream": true } } }, "since": 25 } } }, "of:baedreifb44fs5axxlfrqgz2hgnaj5hsmone73fwpadd3pyvwcyfdiyvcg4": { "application/json": { "ba4jcb242ye6ek3y6ndaxxfgap5auqj2bijfs3epyipzsan6rgtepzfyr": { "is": { "source": { "/": "baedreib6f5iposybjjprscmvwvlafrojazfjfhqo57wxb5hsiggwkeixsy" }, "value": { "$NAME": { "$alias": { "path": [ "argument", "title" ], "schema": { "type": "string", "default": "Untitled Note" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreib6f5iposybjjprscmvwvlafrojazfjfhqo57wxb5hsiggwkeixsy" } } }, "$UI": { "type": "vnode", "name": "ct-screen", "props": { }, "children": [ { "type": "vnode", "name": "div", "props": { "slot": "header" }, "children": [ { "type": "vnode", "name": "ct-input", "props": { "$value": { "$alias": { "path": [ "argument", "title" ], "schema": { "type": "string", "default": "Untitled Note" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreib6f5iposybjjprscmvwvlafrojazfjfhqo57wxb5hsiggwkeixsy" } } }, "placeholder": "Enter title..." }, "children": [] } ] }, { "type": "vnode", "name": "ct-code-editor", "props": { "$value": { "$alias": { "path": [ "argument", "content" ], "schema": { "type": "string", "default": "" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreib6f5iposybjjprscmvwvlafrojazfjfhqo57wxb5hsiggwkeixsy" } } }, "$mentionable": { "$alias": { "path": [ "argument", "allCharms" ], "schema": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreib6f5iposybjjprscmvwvlafrojazfjfhqo57wxb5hsiggwkeixsy" } } }, "$mentioned": { "$alias": { "path": [ "internal", "mentioned" ], "cell": { "/": "baedreib6f5iposybjjprscmvwvlafrojazfjfhqo57wxb5hsiggwkeixsy" } } }, "$pattern": { "$alias": { "path": [ "internal", "__#0" ], "cell": { "/": "baedreib6f5iposybjjprscmvwvlafrojazfjfhqo57wxb5hsiggwkeixsy" } } }, "onbacklink-click": { "$alias": { "path": [ "internal", "__#1stream" ], "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "charm": { "$ref": "#/$defs/MentionableCharm" } }, "required": [ "charm" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "charm": { "$ref": "#/$defs/MentionableCharm" } }, "required": [ "charm" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreib6f5iposybjjprscmvwvlafrojazfjfhqo57wxb5hsiggwkeixsy" } } }, "onbacklink-create": { "$alias": { "path": [ "internal", "$event" ], "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "text": { "type": "string" }, "charmId": true, "charm": { "$ref": "#/$defs/MentionableCharm" }, "navigate": { "type": "boolean" } }, "required": [ "text", "charmId", "charm", "navigate" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "text": { "type": "string" }, "charmId": true, "charm": { "$ref": "#/$defs/MentionableCharm" }, "navigate": { "type": "boolean" } }, "required": [ "text", "charmId", "charm", "navigate" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreib6f5iposybjjprscmvwvlafrojazfjfhqo57wxb5hsiggwkeixsy" } } }, "language": "text/markdown", "theme": "light", "wordWrap": true, "tabIndent": true, "lineNumbers": true }, "children": [] } ] }, "title": { "$alias": { "path": [ "argument", "title" ], "schema": { "type": "string", "default": "Untitled Note" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreib6f5iposybjjprscmvwvlafrojazfjfhqo57wxb5hsiggwkeixsy" } } }, "content": { "$alias": { "path": [ "argument", "content" ], "schema": { "type": "string", "default": "" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreib6f5iposybjjprscmvwvlafrojazfjfhqo57wxb5hsiggwkeixsy" } } }, "mentioned": { "$alias": { "path": [ "internal", "mentioned" ], "cell": { "/": "baedreib6f5iposybjjprscmvwvlafrojazfjfhqo57wxb5hsiggwkeixsy" } } }, "backlinks": { "$alias": { "path": [ "internal", "backlinks" ], "cell": { "/": "baedreib6f5iposybjjprscmvwvlafrojazfjfhqo57wxb5hsiggwkeixsy" } } } } }, "since": 17 } } }, "of:baedreib6f5iposybjjprscmvwvlafrojazfjfhqo57wxb5hsiggwkeixsy": { "application/json": { "ba4jcasxg4r5gk2ruedrjkl3pjp2pq35htaa3ccpyryv5yuidgpnczayd": { "is": { "value": { "$TYPE": "ba4jcbyaoz42hjqx5jmqxkxncz55lqhkwys6xzdcdjfgknlvbnmhr4uay", "resultRef": { "/": { "link@1": { "path": [], "id": "of:baedreifb44fs5axxlfrqgz2hgnaj5hsmone73fwpadd3pyvwcyfdiyvcg4" } } }, "internal": { "$event": { "$stream": true }, "mentioned": [ { "/": { "link@1": { "path": [ "2" ], "id": "of:baedreiahv63wxwgaem4hzjkizl4qncfgvca7pj5cvdon7cukumfon3ioye", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, { "/": { "link@1": { "path": [ "3" ], "id": "of:baedreiahv63wxwgaem4hzjkizl4qncfgvca7pj5cvdon7cukumfon3ioye", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, { "/": { "link@1": { "path": [ "4" ], "id": "of:baedreiahv63wxwgaem4hzjkizl4qncfgvca7pj5cvdon7cukumfon3ioye", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } }, { "/": { "link@1": { "path": [ "5" ], "id": "of:baedreiahv63wxwgaem4hzjkizl4qncfgvca7pj5cvdon7cukumfon3ioye", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } } ], "__#1stream": { "$stream": true }, "backlinks": [], "__#0": "{\"argumentSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"resultSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"default\":[]},\"content\":{\"type\":\"string\",\"default\":\"\"},\"backlinks\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"default\":[]}},\"required\":[\"mentioned\",\"content\",\"backlinks\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"initial\":{\"internal\":{\"$event\":{\"$stream\":true},\"mentioned\":[],\"__#1stream\":{\"$stream\":true}}},\"result\":{\"$NAME\":{\"$alias\":{\"path\":[\"argument\",\"title\"],\"schema\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"$UI\":{\"type\":\"vnode\",\"name\":\"ct-screen\",\"props\":{},\"children\":[{\"type\":\"vnode\",\"name\":\"div\",\"props\":{\"slot\":\"header\"},\"children\":[{\"type\":\"vnode\",\"name\":\"ct-input\",\"props\":{\"$value\":{\"$alias\":{\"path\":[\"argument\",\"title\"],\"schema\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"placeholder\":\"Enter title...\"},\"children\":[]}]},{\"type\":\"vnode\",\"name\":\"ct-code-editor\",\"props\":{\"$value\":{\"$alias\":{\"path\":[\"argument\",\"content\"],\"schema\":{\"type\":\"string\",\"default\":\"\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"$mentionable\":{\"$alias\":{\"path\":[\"argument\",\"allCharms\"],\"schema\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"$mentioned\":{\"$alias\":{\"path\":[\"internal\",\"mentioned\"]}},\"$pattern\":{\"$alias\":{\"path\":[\"internal\",\"__#0\"]}},\"onbacklink-click\":{\"$alias\":{\"path\":[\"internal\",\"__#1stream\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"onbacklink-create\":{\"$alias\":{\"path\":[\"internal\",\"$event\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"language\":\"text/markdown\",\"theme\":\"light\",\"wordWrap\":true,\"tabIndent\":true,\"lineNumbers\":true},\"children\":[]}]},\"title\":{\"$alias\":{\"path\":[\"argument\",\"title\"],\"schema\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"content\":{\"$alias\":{\"path\":[\"argument\",\"content\"],\"schema\":{\"type\":\"string\",\"default\":\"\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"mentioned\":{\"$alias\":{\"path\":[\"internal\",\"mentioned\"]}},\"backlinks\":{\"$alias\":{\"path\":[\"internal\",\"backlinks\"]}}},\"nodes\":[{\"module\":{\"type\":\"javascript\",\"implementation\":\"({ allCharms, content }) => {\\n const cs = allCharms.get();\\n if (!cs)\\n return [];\\n const self = cs.find((c) => c.content === content.get());\\n const results = self\\n ? cs.filter((c) => c.mentioned?.some((m) => m.content === self.content) ?? false)\\n : [];\\n return results;\\n }\",\"argumentSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"asCell\":true},\"content\":{\"type\":\"string\",\"asCell\":true}},\"required\":[\"allCharms\",\"content\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"resultSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"$ref\":\"#/$defs/AnonymousType_1\",\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}},\"inputs\":{\"allCharms\":{\"$alias\":{\"path\":[\"argument\",\"allCharms\"],\"schema\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"content\":{\"$alias\":{\"path\":[\"argument\",\"content\"],\"schema\":{\"type\":\"string\",\"default\":\"\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"outputs\":{\"$alias\":{\"path\":[\"internal\",\"backlinks\"]}}},{\"module\":{\"type\":\"javascript\",\"implementation\":\"({ detail }, { allCharms }) => {\\n console.log(\\\"new charm\\\", detail.text, detail.charmId);\\n if (detail.navigate) {\\n return (0, commontools_5.navigateTo)(detail.charm);\\n }\\n else {\\n allCharms.push(detail.charm);\\n }\\n }\",\"wrapper\":\"handler\",\"argumentSchema\":{\"type\":\"object\",\"properties\":{\"$event\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\",\"asCell\":true},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"]},\"$ctx\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"asCell\":true}},\"required\":[\"allCharms\"]}},\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]},\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}}}}},\"inputs\":{\"$ctx\":{\"allCharms\":{\"$alias\":{\"path\":[\"argument\",\"allCharms\"],\"schema\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"$event\":{\"$alias\":{\"path\":[\"internal\",\"$event\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"outputs\":{}},{\"module\":{\"type\":\"javascript\",\"implementation\":\"() => JSON.stringify(Note)\",\"argumentSchema\":true,\"resultSchema\":{\"type\":\"string\"}},\"outputs\":{\"$alias\":{\"path\":[\"internal\",\"__#0\"]}}},{\"module\":{\"type\":\"javascript\",\"implementation\":\"({ detail }, _) => {\\n return (0, commontools_5.navigateTo)(detail.charm);\\n }\",\"wrapper\":\"handler\",\"argumentSchema\":{\"type\":\"object\",\"properties\":{\"$event\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\",\"asCell\":true}},\"required\":[\"charm\"]}},\"required\":[\"detail\"]},\"$ctx\":{\"type\":\"object\",\"properties\":{},\"additionalProperties\":false}},\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}},\"inputs\":{\"$ctx\":{},\"$event\":{\"$alias\":{\"path\":[\"internal\",\"__#1stream\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"outputs\":{}}],\"program\":{\"main\":\"/note.tsx\",\"mainExport\":\"default\",\"files\":[{\"name\":\"/default-app.tsx\",\"contents\":\"/// \\nimport {\\n Cell,\\n Default,\\n derive,\\n h,\\n handler,\\n NAME,\\n navigateTo,\\n Opaque,\\n OpaqueRef,\\n recipe,\\n str,\\n UI,\\n} from \\\"commontools\\\";\\n\\n// Import recipes we want to be launchable from the default app.\\nimport Chatbot from \\\"./chatbot.tsx\\\";\\nimport ChatbotOutliner from \\\"./chatbot-outliner.tsx\\\";\\nimport { type MentionableCharm } from \\\"./chatbot-note-composed.tsx\\\";\\nimport { default as Note } from \\\"./note.tsx\\\";\\nimport ChatList from \\\"./chatbot-list-view.tsx\\\";\\n\\nexport type Charm = {\\n [NAME]?: string;\\n [UI]?: unknown;\\n [key: string]: any;\\n};\\n\\ntype CharmsListInput = {\\n allCharms: Default;\\n};\\n\\n// Recipe returns only UI, no data outputs (only symbol properties)\\ninterface CharmsListOutput {\\n [key: string]: unknown;\\n}\\n\\nconst visit = handler<\\n Record,\\n { charm: any }\\n>((_, state) => {\\n return navigateTo(state.charm);\\n}, { proxy: true });\\n\\nconst removeCharm = handler<\\n Record,\\n {\\n charm: any;\\n allCharms: Cell;\\n }\\n>((_, state) => {\\n const charmName = state.charm[NAME];\\n const allCharmsValue = state.allCharms.get();\\n const index = allCharmsValue.findIndex((c: any) => c[NAME] === charmName);\\n\\n if (index !== -1) {\\n const charmListCopy = [...allCharmsValue];\\n console.log(\\\"charmListCopy before\\\", charmListCopy);\\n charmListCopy.splice(index, 1);\\n console.log(\\\"charmListCopy after\\\", charmListCopy);\\n state.allCharms.set(charmListCopy);\\n }\\n});\\n\\nconst spawnChatList = handler<\\n Record,\\n { allCharms: Cell }\\n>((_, state) => {\\n return navigateTo(ChatList({\\n selectedCharm: { charm: undefined },\\n charmsList: [],\\n allCharms: state.allCharms, // we should handle empty here\\n }));\\n});\\n\\nconst spawnChatbot = handler<\\n Record,\\n Record\\n>((_, state) => {\\n return navigateTo(Chatbot({\\n messages: [],\\n tools: undefined,\\n }));\\n});\\n\\nconst spawnChatbotOutliner = handler<\\n Record,\\n { allCharms: Cell }\\n>((_, state) => {\\n return navigateTo(ChatbotOutliner({\\n title: \\\"Chatbot Outliner\\\",\\n expandChat: false,\\n messages: [],\\n outline: {\\n root: { body: \\\"\\\", children: [], attachments: [] },\\n },\\n allCharms: state.allCharms,\\n }));\\n});\\n\\nconst spawnNote = handler<\\n Record,\\n { allCharms: Cell }\\n>((_, state) => {\\n return navigateTo(Note({\\n title: \\\"New Note\\\",\\n content: \\\"\\\",\\n allCharms: state.allCharms,\\n }));\\n});\\n\\nexport default recipe(\\n \\\"DefaultCharmList\\\",\\n ({ allCharms }) => {\\n return {\\n [NAME]: str`DefaultCharmList (${allCharms.length})`,\\n [UI]: (\\n \\n ,\\n })}\\n />\\n\\n \\n {/* Quick Launch Toolbar */}\\n \\n

Quicklaunch:

\\n ,\\n })}\\n >\\n 📂 Chat List\\n \\n \\n 💬 Chatbot\\n \\n \\n 📝 Chatbot Outliner\\n \\n ,\\n })}\\n >\\n 📄 Note\\n \\n
\\n\\n

Charms ({allCharms.length})

\\n\\n \\n \\n \\n Charm Name\\n Actions\\n \\n \\n \\n {derive(allCharms, (allCharms) =>\\n allCharms.map((charm: any) => (\\n \\n {charm[NAME] || \\\"Untitled Charm\\\"}\\n \\n \\n \\n Visit\\n \\n \\n Remove\\n \\n \\n \\n \\n )))}\\n \\n \\n
\\n
\\n ),\\n };\\n },\\n);\\n\"},{\"name\":\"/chatbot.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n generateObject,\\n h,\\n handler,\\n ifElse,\\n JSONSchema,\\n lift,\\n llm,\\n llmDialog,\\n NAME,\\n recipe,\\n str,\\n Stream,\\n UI,\\n} from \\\"commontools\\\";\\n\\nconst sendMessage = handler<\\n { detail: { message: string } },\\n {\\n addMessage: Stream;\\n }\\n>((event, { addMessage }) => {\\n addMessage.send({\\n role: \\\"user\\\",\\n content: [{ type: \\\"text\\\", text: event.detail.message }],\\n });\\n});\\n\\nconst clearChat = handler(\\n (\\n _: never,\\n { messages, pending }: {\\n messages: Cell>;\\n pending: Cell;\\n },\\n ) => {\\n messages.set([]);\\n pending.set(false);\\n },\\n);\\n\\ntype ChatInput = {\\n messages: Default, []>;\\n tools: any;\\n theme?: any;\\n};\\n\\ntype ChatOutput = {\\n messages: Array;\\n pending: boolean | undefined;\\n addMessage: Stream;\\n cancelGeneration: Stream;\\n title?: string;\\n};\\n\\nexport const TitleGenerator = recipe<\\n { model?: string; messages: Array }\\n>(\\\"Title Generator\\\", ({ model, messages }) => {\\n const titleMessages = derive(messages, (m) => {\\n if (!m || m.length === 0) return \\\"\\\";\\n\\n const messageCount = 2;\\n const selectedMessages = m.slice(0, messageCount).filter(Boolean);\\n\\n if (selectedMessages.length === 0) return \\\"\\\";\\n\\n return selectedMessages.map((msg) => JSON.stringify(msg)).join(\\\"\\\\n\\\");\\n });\\n\\n const { result } = generateObject({\\n system:\\n \\\"Generate at most a 3-word title based on the following content, respond with NOTHING but the literal title text.\\\",\\n prompt: titleMessages,\\n model,\\n schema: {\\n type: \\\"object\\\",\\n properties: {\\n title: {\\n type: \\\"string\\\",\\n description: \\\"The title of the chat\\\",\\n },\\n },\\n required: [\\\"title\\\"],\\n },\\n });\\n\\n const title = derive(result, (t) => {\\n return t?.title || \\\"Untitled Chat\\\";\\n });\\n\\n return title;\\n});\\n\\nexport default recipe(\\n \\\"Chat\\\",\\n ({ messages, tools, theme }) => {\\n const model = cell(\\\"anthropic:claude-sonnet-4-5\\\");\\n\\n const { addMessage, cancelGeneration, pending } = llmDialog({\\n system: \\\"You are a helpful assistant with some tools.\\\",\\n messages,\\n tools,\\n model,\\n });\\n\\n const { result } = fetchData({\\n url: \\\"/api/ai/llm/models\\\",\\n mode: \\\"json\\\",\\n });\\n\\n const items = derive(result, (models) => {\\n if (!models) return [];\\n const items = Object.keys(models as any).map((key) => ({\\n label: key,\\n value: key,\\n }));\\n return items;\\n });\\n\\n const title = TitleGenerator({ model, messages });\\n\\n return {\\n [NAME]: title,\\n [UI]: (\\n \\n \\n {title}\\n \\n \\n\\n \\n \\n \\n\\n
\\n \\n \\n
\\n
\\n ),\\n messages,\\n pending,\\n addMessage,\\n cancelGeneration,\\n title,\\n };\\n },\\n);\\n\"},{\"name\":\"/chatbot-outliner.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n getRecipeEnvironment,\\n h,\\n handler,\\n ID,\\n ifElse,\\n JSONSchema,\\n lift,\\n llm,\\n llmDialog,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n str,\\n Stream,\\n UI,\\n} from \\\"commontools\\\";\\n\\nimport Chat from \\\"./chatbot.tsx\\\";\\n\\ntype Charm = any;\\n\\ntype OutlinerNode = {\\n body: Default;\\n children: Default;\\n attachments: Default[], []>;\\n};\\n\\ntype Outliner = {\\n root: OutlinerNode;\\n};\\n\\ntype PageResult = {\\n outline: Default<\\n Outliner,\\n { root: { body: \\\"\\\"; children: []; attachments: [] } }\\n >;\\n};\\n\\nexport type PageInput = {\\n outline: Outliner;\\n allCharms: Cell;\\n};\\n\\nconst handleCharmLinkClick = handler<\\n {\\n detail: {\\n charm: Cell;\\n };\\n },\\n Record\\n>(({ detail }, _) => {\\n return navigateTo(detail.charm);\\n});\\n\\nexport const Page = recipe(\\n \\\"Page\\\",\\n ({ outline, allCharms }) => {\\n return {\\n [NAME]: \\\"Page\\\",\\n [UI]: (\\n \\n ),\\n outline,\\n };\\n },\\n);\\n\\ntype LLMTestInput = {\\n title: Default;\\n messages: Default, []>;\\n expandChat: Default;\\n outline: Default<\\n Outliner,\\n { root: { body: \\\"Untitled Page\\\"; children: []; attachments: [] } }\\n >;\\n allCharms: Cell;\\n};\\n\\ntype LLMTestResult = {\\n messages: Default, []>;\\n};\\n\\n// put a node at the end of the outline (by appending to root.children)\\nconst appendOutlinerNode = handler<\\n {\\n /** The text content/title of the outliner node to be appended */\\n body: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { outline: Cell }\\n>(\\n (args, state) => {\\n try {\\n (state.outline.key(\\\"root\\\").key(\\\"children\\\")).push({\\n body: args.body,\\n children: [],\\n attachments: [],\\n });\\n\\n args.result.set(\\n `${state.outline.key(\\\"root\\\").key(\\\"children\\\").get().length} nodes`,\\n );\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nexport default recipe(\\n \\\"Outliner\\\",\\n ({ title, expandChat, messages, outline, allCharms }) => {\\n const tools = {\\n appendOutlinerNode: {\\n description: \\\"Add a new outliner node.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n body: {\\n type: \\\"string\\\",\\n description: \\\"The title of the new node.\\\",\\n },\\n },\\n required: [\\\"body\\\"],\\n } as JSONSchema,\\n handler: appendOutlinerNode({ outline }),\\n },\\n };\\n\\n const chat = Chat({ messages, tools });\\n const { addMessage, cancelGeneration, pending } = chat;\\n\\n return {\\n [NAME]: title,\\n [UI]: (\\n \\n \\n
\\n
\\n Show Chat\\n
\\n
\\n\\n \\n \\n
\\n \\n
\\n\\n \\n \\n \\n \\n \\n
\\n\\n {ifElse(\\n expandChat,\\n chat,\\n null,\\n )}\\n
\\n
\\n ),\\n messages,\\n };\\n },\\n);\\n\"},{\"name\":\"/chatbot-note-composed.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n getRecipeEnvironment,\\n h,\\n handler,\\n ID,\\n ifElse,\\n JSONSchema,\\n lift,\\n llm,\\n llmDialog,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n str,\\n Stream,\\n toSchema,\\n UI,\\n} from \\\"commontools\\\";\\n\\nimport Chat from \\\"./chatbot.tsx\\\";\\nimport Note from \\\"./note.tsx\\\";\\nimport Tools, {\\n addListItem,\\n calculator,\\n ListItem,\\n readListItems,\\n readWebpage,\\n searchWeb,\\n} from \\\"./common-tools.tsx\\\";\\n\\nexport type MentionableCharm = {\\n [NAME]: string;\\n content?: string;\\n mentioned?: MentionableCharm[];\\n};\\n\\n// export type ChatbotNoteInput = {\\n// content: Default;\\n// allCharms?: Cell;\\n// };\\n\\nconst handleCharmLinkClick = handler<\\n {\\n detail: {\\n charm: Cell;\\n };\\n },\\n Record\\n>(({ detail }, _) => {\\n return navigateTo(detail.charm);\\n});\\n\\nconst handleCharmLinkClicked = handler(\\n (_: any, { charm }: { charm: Cell }) => {\\n return navigateTo(charm);\\n },\\n);\\n\\ntype ChatbotNoteInput = {\\n title: Default;\\n messages: Default, []>;\\n content: Default;\\n allCharms: Cell;\\n};\\n\\ntype ChatbotNoteResult = {\\n messages: Default, []>;\\n mentioned: Default, []>;\\n backlinks: Default, []>;\\n content: Default;\\n note: any;\\n chat: any;\\n list: Default;\\n};\\n\\nconst newNote = handler<\\n {\\n /** The text content of the note */\\n title: string;\\n content?: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { allCharms: Cell }\\n>(\\n (args, state) => {\\n try {\\n const n = Note({\\n title: args.title,\\n content: args.content || \\\"\\\",\\n allCharms: state.allCharms,\\n });\\n\\n args.result.set(\\n `Created note ${args.title}!`,\\n );\\n\\n state.allCharms.push(n as unknown as MentionableCharm);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\n// put a note at the end of the outline (by appending to root.children)\\nconst editNote = handler<\\n {\\n /** The text content of the note */\\n body: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { content: Cell }\\n>(\\n (args, state) => {\\n try {\\n state.content.set(args.body);\\n\\n args.result.set(\\n `Updated note!`,\\n );\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst readNote = handler<\\n {\\n /** A cell to store the result text */\\n result: Cell;\\n },\\n { content: string }\\n>(\\n (args, state) => {\\n try {\\n args.result.set(state.content);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst listMentionable = handler<\\n {\\n /** A cell to store the result text */\\n result: Cell;\\n },\\n { allCharms: { [NAME]: string }[] }\\n>(\\n (args, state) => {\\n try {\\n const namesList = state.allCharms.map((charm) => charm[NAME]);\\n args.result.set(JSON.stringify(namesList));\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst readNoteByIndex = handler<\\n {\\n /** A cell to store the result text */\\n index: number;\\n result: Cell;\\n },\\n { allCharms: { [NAME]: string; content?: string }[] }\\n>(\\n (args, state) => {\\n try {\\n args.result.set(\\n state.allCharms[args.index]?.content || \\\"No content found\\\",\\n );\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst editNoteByIndex = handler<\\n {\\n /** The index of the note to edit */\\n index: number;\\n /** The new text content of the note */\\n body: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { allCharms: Cell }\\n>(\\n (args, state) => {\\n try {\\n const charms = state.allCharms.get();\\n if (args.index < 0 || args.index >= charms.length) {\\n args.result.set(`Error: Invalid index ${args.index}`);\\n return;\\n }\\n\\n state.allCharms.key(args.index).key(\\\"content\\\").set(args.body);\\n args.result.set(`Updated note at index ${args.index}!`);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst navigateToNote = handler<\\n {\\n /** The index of the note to navigate to */\\n index: number;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { allCharms: Cell }\\n>(\\n (args, state) => {\\n try {\\n const charms = state.allCharms.get();\\n if (args.index < 0 || args.index >= charms.length) {\\n args.result.set(`Error: Invalid index ${args.index}`);\\n return;\\n }\\n\\n const targetCharm = charms[args.index];\\n args.result.set(`Navigating to note: ${targetCharm[NAME]}`);\\n\\n return navigateTo(state.allCharms.key(args.index));\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nexport default recipe(\\n \\\"Chatbot + Note\\\",\\n ({ title, messages, content, allCharms }) => {\\n const list = cell([]);\\n\\n const tools = {\\n searchWeb: {\\n pattern: searchWeb,\\n },\\n readWebpage: {\\n pattern: readWebpage,\\n },\\n calculator: {\\n pattern: calculator,\\n },\\n addListItem: {\\n handler: addListItem({ list }),\\n },\\n readListItems: {\\n handler: readListItems({ list }),\\n },\\n editActiveNote: {\\n description: \\\"Modify the shared note.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n body: {\\n type: \\\"string\\\",\\n description: \\\"The content of the note.\\\",\\n },\\n },\\n required: [\\\"body\\\"],\\n } as JSONSchema,\\n handler: editNote({ content }),\\n },\\n readActiveNote: {\\n description: \\\"Read the currently focused note.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {},\\n required: [],\\n } as JSONSchema,\\n handler: readNote({ content }),\\n },\\n listNotes: {\\n description:\\n \\\"List all mentionable note titles (read the body with readNoteByIndex).\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {},\\n required: [],\\n } as JSONSchema,\\n handler: listMentionable({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n readNoteByIndex: {\\n description:\\n \\\"Read the body of a note by its index in the listNotes() list.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n index: {\\n type: \\\"number\\\",\\n description: \\\"The index of the note in the notes list.\\\",\\n },\\n },\\n required: [\\\"index\\\"],\\n } as JSONSchema,\\n handler: readNoteByIndex({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n editNoteByIndex: {\\n description:\\n \\\"Edit the body of a note by its index in the listNotes() list.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n index: {\\n type: \\\"number\\\",\\n description: \\\"The index of the note in the notes list.\\\",\\n },\\n body: {\\n type: \\\"string\\\",\\n description: \\\"The new content of the note.\\\",\\n },\\n },\\n required: [\\\"index\\\", \\\"body\\\"],\\n } as JSONSchema,\\n handler: editNoteByIndex({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n navigateToNote: {\\n description: \\\"Navigate to a note by its index in the listNotes() list.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n index: {\\n type: \\\"number\\\",\\n description: \\\"The index of the note in the notes list.\\\",\\n },\\n },\\n required: [\\\"index\\\"],\\n } as JSONSchema,\\n handler: navigateToNote({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n newNote: {\\n description: \\\"Read the shared note.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n title: {\\n type: \\\"string\\\",\\n description: \\\"The title of the note.\\\",\\n },\\n content: {\\n type: \\\"string\\\",\\n description: \\\"The content of the note.\\\",\\n },\\n },\\n required: [\\\"title\\\"],\\n } as JSONSchema,\\n handler: newNote({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n };\\n\\n const chat = Chat({ messages, tools });\\n const note = Note({ title, content, allCharms });\\n\\n return {\\n [NAME]: title,\\n chat,\\n note,\\n content,\\n messages,\\n mentioned: note.mentioned,\\n backlinks: note.backlinks,\\n list,\\n };\\n },\\n);\\n\"},{\"name\":\"/note.tsx\",\"contents\":\"/// \\nimport {\\n Cell,\\n cell,\\n Default,\\n derive,\\n h,\\n handler,\\n lift,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n toSchema,\\n UI,\\n} from \\\"commontools\\\";\\n\\nexport type MentionableCharm = {\\n [NAME]: string;\\n content?: string;\\n mentioned?: MentionableCharm[];\\n};\\n\\ntype Input = {\\n title: Default;\\n content: Default;\\n allCharms: Cell;\\n};\\n\\ntype Output = {\\n mentioned: Default, []>;\\n content: Default;\\n backlinks: Default, []>;\\n};\\n\\nconst updateTitle = handler<\\n { detail: { value: string } },\\n { title: Cell }\\n>(\\n (event, state) => {\\n state.title.set(event.detail?.value ?? \\\"\\\");\\n },\\n);\\n\\nconst updateContent = handler<\\n { detail: { value: string } },\\n { content: Cell }\\n>(\\n (event, state) => {\\n state.content.set(event.detail?.value ?? \\\"\\\");\\n },\\n);\\n\\nconst handleCharmLinkClick = handler<\\n {\\n detail: {\\n charm: Cell;\\n };\\n },\\n Record\\n>(({ detail }, _) => {\\n return navigateTo(detail.charm);\\n});\\n\\nconst handleNewBacklink = handler<\\n {\\n detail: {\\n text: string;\\n charmId: any;\\n charm: Cell;\\n navigate: boolean;\\n };\\n },\\n {\\n allCharms: Cell;\\n }\\n>(({ detail }, { allCharms }) => {\\n console.log(\\\"new charm\\\", detail.text, detail.charmId);\\n\\n if (detail.navigate) {\\n return navigateTo(detail.charm);\\n } else {\\n allCharms.push(detail.charm as unknown as MentionableCharm);\\n }\\n});\\n\\nconst handleCharmLinkClicked = handler(\\n (_: any, { charm }: { charm: Cell }) => {\\n return navigateTo(charm);\\n },\\n);\\n\\nconst Note = recipe(\\n \\\"Note\\\",\\n ({ title, content, allCharms }) => {\\n const mentioned = cell([]);\\n\\n const computeBacklinks = lift<\\n { allCharms: Cell; content: Cell },\\n MentionableCharm[]\\n >(\\n ({ allCharms, content }) => {\\n const cs = allCharms.get();\\n if (!cs) return [];\\n\\n const self = cs.find((c) => c.content === content.get());\\n\\n const results = self\\n ? cs.filter((c) =>\\n c.mentioned?.some((m) => m.content === self.content) ?? false\\n )\\n : [];\\n\\n return results;\\n },\\n );\\n\\n const backlinks: OpaqueRef = computeBacklinks({\\n allCharms,\\n content: content as unknown as Cell, // TODO(bf): this is valid, but types complain\\n });\\n\\n // The only way to serialize a pattern, apparently?\\n const pattern = derive(undefined, () => JSON.stringify(Note));\\n\\n return {\\n [NAME]: title,\\n [UI]: (\\n \\n
\\n \\n
\\n\\n \\n
\\n ),\\n title,\\n content,\\n mentioned,\\n backlinks,\\n };\\n },\\n);\\n\\nexport default Note;\\n\"},{\"name\":\"/chatbot-list-view.tsx\",\"contents\":\"/// \\nimport {\\n Cell,\\n cell,\\n Default,\\n derive,\\n h,\\n handler,\\n ID,\\n ifElse,\\n lift,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n toSchema,\\n UI,\\n} from \\\"commontools\\\";\\n\\nimport Chat from \\\"./chatbot-note-composed.tsx\\\";\\nimport { ListItem } from \\\"./common-tools.tsx\\\";\\n\\nexport type MentionableCharm = {\\n [NAME]: string;\\n content?: string;\\n mentioned?: MentionableCharm[];\\n};\\n\\ntype CharmEntry = {\\n [ID]: string; // randomId is a string\\n local_id: string; // same as ID but easier to access\\n charm: any;\\n};\\n\\ntype Input = {\\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\\n charmsList: Default;\\n allCharms: Cell;\\n theme?: {\\n accentColor: Default;\\n fontFace: Default;\\n borderRadius: Default;\\n };\\n};\\n\\ntype Output = {\\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\\n};\\n\\nconst removeChat = handler<\\n unknown,\\n {\\n charmsList: Cell;\\n id: string;\\n selectedCharm: Cell>;\\n }\\n>(\\n (\\n _,\\n { charmsList, id, selectedCharm },\\n ) => {\\n const list = charmsList.get();\\n const index = list.findIndex((entry) => entry.local_id === id);\\n if (index === -1) return;\\n\\n const removed = list[index];\\n const next = [...list];\\n next.splice(index, 1);\\n charmsList.set(next);\\n\\n // If we removed the currently selected charm, choose a new selection.\\n const current = selectedCharm.get();\\n if (current?.charm === removed.charm) {\\n const replacement = next[index] ?? next[index - 1];\\n if (replacement) {\\n selectedCharm.set({ charm: replacement.charm });\\n } else {\\n selectedCharm.set({ charm: undefined as unknown as any });\\n }\\n }\\n },\\n);\\n\\n// this will be called whenever charm or selectedCharm changes\\n// pass isInitialized to make sure we dont call this each time\\n// we change selectedCharm, otherwise creates a loop\\nconst storeCharm = lift(\\n toSchema<{\\n charm: any;\\n selectedCharm: Cell>;\\n charmsList: Cell;\\n allCharms: Cell;\\n theme?: {\\n accentColor: Default;\\n fontFace: Default;\\n borderRadius: Default;\\n };\\n isInitialized: Cell;\\n }>(),\\n undefined,\\n ({ charm, selectedCharm, charmsList, isInitialized, allCharms }) => { // Not including `allCharms` is a compile error...\\n if (!isInitialized.get()) {\\n console.log(\\n \\\"storeCharm storing charm:\\\",\\n charm,\\n );\\n selectedCharm.set({ charm });\\n\\n // create the chat charm with a custom name including a random suffix\\n const randomId = Math.random().toString(36).substring(2, 10); // Random 8-char string\\n charmsList.push({ [ID]: randomId, local_id: randomId, charm });\\n\\n isInitialized.set(true);\\n return charm;\\n } else {\\n console.log(\\\"storeCharm: already initialized\\\");\\n }\\n return undefined;\\n },\\n);\\n\\nconst populateChatList = lift(\\n toSchema<{\\n charmsList: CharmEntry[];\\n allCharms: Cell;\\n selectedCharm: Cell<{ charm: any }>;\\n }>(),\\n undefined,\\n (\\n { charmsList, allCharms, selectedCharm },\\n ) => {\\n if (charmsList.length === 0) {\\n const isInitialized = cell(false);\\n return storeCharm({\\n charm: Chat({\\n title: \\\"New Chat\\\",\\n messages: [],\\n content: \\\"\\\",\\n allCharms,\\n }),\\n selectedCharm,\\n charmsList,\\n allCharms,\\n isInitialized: isInitialized as unknown as Cell,\\n });\\n }\\n\\n return charmsList;\\n },\\n);\\n\\nconst createChatRecipe = handler<\\n unknown,\\n {\\n selectedCharm: Cell<{ charm: any }>;\\n charmsList: Cell;\\n allCharms: Cell;\\n }\\n>(\\n (_, { selectedCharm, charmsList, allCharms }) => {\\n const isInitialized = cell(false);\\n\\n const charm = Chat({\\n title: \\\"New Chat\\\",\\n messages: [],\\n content: \\\"\\\",\\n allCharms,\\n });\\n // store the charm ref in a cell (pass isInitialized to prevent recursive calls)\\n return storeCharm({\\n charm,\\n selectedCharm,\\n charmsList: charmsList as unknown as OpaqueRef,\\n allCharms,\\n isInitialized: isInitialized as unknown as Cell,\\n });\\n },\\n);\\n\\nconst selectCharm = handler<\\n unknown,\\n { selectedCharm: Cell<{ charm: any }>; charm: any }\\n>(\\n (_, { selectedCharm, charm }) => {\\n console.log(\\\"selectCharm: updating selectedCharm to \\\", charm);\\n selectedCharm.set({ charm });\\n return selectedCharm;\\n },\\n);\\n\\nconst logCharmsList = lift<\\n { charmsList: Cell },\\n Cell\\n>(\\n ({ charmsList }) => {\\n console.log(\\\"logCharmsList: \\\", charmsList.get());\\n return charmsList;\\n },\\n);\\n\\nconst handleCharmLinkClicked = handler(\\n (_: any, { charm }: { charm: Cell }) => {\\n return navigateTo(charm);\\n },\\n);\\n\\nconst combineLists = lift(\\n (\\n { allCharms, charmsList }: { allCharms: any[]; charmsList: CharmEntry[] },\\n ) => {\\n return [...charmsList.map((c) => c.charm), ...allCharms];\\n },\\n);\\n\\nconst getSelectedCharm = lift<\\n { entry: { charm: any | undefined } },\\n {\\n chat: unknown;\\n note: unknown;\\n list: ListItem[];\\n backlinks: MentionableCharm[];\\n mentioned: MentionableCharm[];\\n } | undefined\\n>(\\n ({ entry }) => {\\n return entry?.charm;\\n },\\n);\\n\\nconst getCharmName = lift(({ charm }: { charm: any }) => {\\n return charm?.[NAME] || \\\"Unknown\\\";\\n});\\n\\n// create the named cell inside the recipe body, so we do it just once\\nexport default recipe(\\n \\\"Launcher\\\",\\n ({ selectedCharm, charmsList, allCharms, theme }) => {\\n logCharmsList({ charmsList: charmsList as unknown as Cell });\\n\\n populateChatList({\\n selectedCharm: selectedCharm as unknown as Cell<\\n Pick\\n >,\\n charmsList,\\n allCharms,\\n });\\n\\n const combined = combineLists({\\n allCharms: allCharms as unknown as any[],\\n charmsList,\\n });\\n\\n const selected = getSelectedCharm({ entry: selectedCharm });\\n\\n const localTheme = theme ?? {\\n accentColor: cell(\\\"#3b82f6\\\"),\\n fontFace: cell(\\\"system-ui, -apple-system, sans-serif\\\"),\\n borderRadius: cell(\\\"0.5rem\\\"),\\n };\\n\\n return {\\n [NAME]: \\\"Launcher\\\",\\n [UI]: (\\n \\n \\n
\\n \\n
\\n \\n Create New Chat\\n alt+N\\n \\n
\\n
\\n\\n {/* Keyboard shortcuts */}\\n \\n
\\n \\n {/* workaround: this seems to correctly start the sub-recipes on a refresh while directly rendering does not */}\\n {/* this should be fixed after the builder-refactor (DX1) */}\\n \\n \\n \\n \\n \\n \\n\\n \\n\\n \\n \\n
\\n
\\n ),\\n selectedCharm,\\n charmsList,\\n };\\n },\\n);\\n\"},{\"name\":\"/common-tools.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n BuiltInLLMTool,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n h,\\n handler,\\n ifElse,\\n llmDialog,\\n NAME,\\n recipe,\\n Stream,\\n UI,\\n} from \\\"commontools\\\";\\n\\n///// COMMON TOOLS (get it?) ////\\n\\n/**\\n * Calculate the result of a mathematical expression.\\n * Supports +, -, *, /, and parentheses.\\n */\\ntype CalculatorRequest = {\\n /** The mathematical expression to evaluate. */\\n expression: string;\\n};\\n\\nexport const calculator = recipe<\\n CalculatorRequest,\\n string | { error: string }\\n>(\\\"Calculator\\\", ({ expression }) => {\\n return derive(expression, (expr) => {\\n const sanitized = expr.replace(/[^0-9+\\\\-*/().\\\\s]/g, \\\"\\\");\\n let result;\\n try {\\n result = Function(`\\\"use strict\\\"; return (${sanitized})`)();\\n } catch (error) {\\n result = { error: (error as any)?.message || \\\"\\\" };\\n }\\n return result;\\n });\\n});\\n\\n/** Add an item to the list. */\\ntype AddListItemRequest = {\\n /** The item to add to the list. */\\n item: string;\\n result: Cell;\\n};\\n\\n/** Read all items from the list. */\\ntype ReadListItemsRequest = {\\n result: Cell;\\n};\\n\\nexport type ListItem = {\\n title: string;\\n};\\n\\nexport const addListItem = handler<\\n AddListItemRequest,\\n { list: Cell }\\n>(\\n (args, state) => {\\n try {\\n state.list.push({ title: args.item });\\n args.result.set(`${state.list.get().length} items`);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nexport const readListItems = handler<\\n ReadListItemsRequest,\\n { list: ListItem[] }\\n>(\\n (args, state) => {\\n try {\\n const items = state.list;\\n if (items.length === 0) {\\n args.result.set(\\\"The list is empty\\\");\\n } else {\\n const itemList = items.map((item, index) =>\\n `${index + 1}. ${item.title}`\\n ).join(\\\"\\\\n\\\");\\n args.result.set(`List items (${items.length} total):\\\\n${itemList}`);\\n }\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\n/** Search the web for information. */\\ntype SearchQuery = {\\n /** The query to search the web for. */\\n query: string;\\n};\\n\\ntype SearchWebResult = {\\n results: {\\n title: string;\\n url: string;\\n description: string;\\n }[];\\n};\\n\\nexport const searchWeb = recipe<\\n SearchQuery,\\n SearchWebResult | { error: string }\\n>(\\\"Search Web\\\", ({ query }) => {\\n const { result, error } = fetchData({\\n url: \\\"/api/agent-tools/web-search\\\",\\n mode: \\\"json\\\",\\n options: {\\n method: \\\"POST\\\",\\n headers: {\\n \\\"Content-Type\\\": \\\"application/json\\\",\\n },\\n body: {\\n query,\\n max_results: 5,\\n },\\n },\\n });\\n\\n // TODO(seefeld): Should we instead return { result, error }? Or allocate a\\n // special [ERROR] for errors? Ideally this isn\\'t specific to using recipes as\\n // tools but a general pattern.\\n return ifElse(error, { error }, result);\\n});\\n\\n/** Read and extract content from a specific webpage URL. */\\ntype ReadWebRequest = {\\n /** The URL of the webpage to read and extract content from. */\\n url: string;\\n};\\n\\ntype ReadWebResult = {\\n content: string;\\n metadata: {\\n title?: string;\\n author?: string;\\n date?: string;\\n word_count: number;\\n };\\n};\\n\\nexport const readWebpage = recipe<\\n ReadWebRequest,\\n ReadWebResult | { error: string }\\n>(\\\"Read Webpage\\\", ({ url }) => {\\n const { result, error } = fetchData({\\n url: \\\"/api/agent-tools/web-read\\\",\\n mode: \\\"json\\\",\\n options: {\\n method: \\\"POST\\\",\\n headers: {\\n \\\"Content-Type\\\": \\\"application/json\\\",\\n },\\n body: {\\n url,\\n max_tokens: 4000,\\n include_code: true,\\n },\\n },\\n });\\n\\n return ifElse(error, { error }, result);\\n});\\n\\ntype ToolsInput = {\\n list: ListItem[];\\n};\\n\\nexport default recipe(\\\"Tools\\\", ({ list }) => {\\n const tools: Record = {\\n search_web: {\\n pattern: searchWeb,\\n },\\n read_webpage: {\\n pattern: readWebpage,\\n },\\n calculator: {\\n pattern: calculator,\\n },\\n addListItem: {\\n handler: addListItem({ list }),\\n },\\n };\\n\\n return { tools, list };\\n});\\n\"}]}}" }, "spell": { "/": { "link@1": { "id": "of:baedreibk3pk3njig5krex3aaqtcmphgmhhgh2knafrdu33f4qg4lazp2ny" } } }, "argument": { "title": { "$alias": { "path": [ "argument", "title" ], "schema": { "type": "string", "default": "LLM Test" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "LLM Test" }, "messages": { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMMessage" }, "default": [] }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "messages", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] }, "BuiltInLLMMessage": { "type": "object", "properties": { "role": { "enum": [ "system", "user", "assistant", "tool" ] }, "content": { "$ref": "#/$defs/BuiltInLLMContent" } }, "required": [ "role", "content" ] }, "BuiltInLLMContent": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMContentPart" } } ] }, "BuiltInLLMContentPart": { "anyOf": [ { "$ref": "#/$defs/BuiltInLLMTextPart" }, { "$ref": "#/$defs/BuiltInLLMImagePart" }, { "$ref": "#/$defs/BuiltInLLMToolCallPart" }, { "$ref": "#/$defs/BuiltInLLMToolResultPart" } ] }, "BuiltInLLMToolResultPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-result" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "output": { "anyOf": [ { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "value": { "type": "string" } }, "required": [ "type", "value" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "json" ] }, "value": true }, "required": [ "type", "value" ] } ] } }, "required": [ "type", "toolCallId", "toolName", "output" ] }, "BuiltInLLMToolCallPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-call" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "input": { "$ref": "#/$defs/Record" } }, "required": [ "type", "toolCallId", "toolName", "input" ] }, "Record": { "type": "object", "properties": { }, "additionalProperties": true }, "BuiltInLLMImagePart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "image" ] }, "image": { "anyOf": [ { "type": "string" }, true, true, { "type": "string", "format": "uri" } ] } }, "required": [ "type", "image" ] }, "BuiltInLLMTextPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "text": { "type": "string" } }, "required": [ "type", "text" ] } } }, "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } }, "content": { "$alias": { "path": [ "argument", "content" ], "schema": { "type": "string", "default": "" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "LLM Test" }, "messages": { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMMessage" }, "default": [] }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "messages", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] }, "BuiltInLLMMessage": { "type": "object", "properties": { "role": { "enum": [ "system", "user", "assistant", "tool" ] }, "content": { "$ref": "#/$defs/BuiltInLLMContent" } }, "required": [ "role", "content" ] }, "BuiltInLLMContent": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMContentPart" } } ] }, "BuiltInLLMContentPart": { "anyOf": [ { "$ref": "#/$defs/BuiltInLLMTextPart" }, { "$ref": "#/$defs/BuiltInLLMImagePart" }, { "$ref": "#/$defs/BuiltInLLMToolCallPart" }, { "$ref": "#/$defs/BuiltInLLMToolResultPart" } ] }, "BuiltInLLMToolResultPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-result" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "output": { "anyOf": [ { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "value": { "type": "string" } }, "required": [ "type", "value" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "json" ] }, "value": true }, "required": [ "type", "value" ] } ] } }, "required": [ "type", "toolCallId", "toolName", "output" ] }, "BuiltInLLMToolCallPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-call" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "input": { "$ref": "#/$defs/Record" } }, "required": [ "type", "toolCallId", "toolName", "input" ] }, "Record": { "type": "object", "properties": { }, "additionalProperties": true }, "BuiltInLLMImagePart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "image" ] }, "image": { "anyOf": [ { "type": "string" }, true, true, { "type": "string", "format": "uri" } ] } }, "required": [ "type", "image" ] }, "BuiltInLLMTextPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "text": { "type": "string" } }, "required": [ "type", "text" ] } } }, "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } }, "allCharms": { "$alias": { "path": [ "argument", "allCharms" ], "schema": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "LLM Test" }, "messages": { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMMessage" }, "default": [] }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "messages", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] }, "BuiltInLLMMessage": { "type": "object", "properties": { "role": { "enum": [ "system", "user", "assistant", "tool" ] }, "content": { "$ref": "#/$defs/BuiltInLLMContent" } }, "required": [ "role", "content" ] }, "BuiltInLLMContent": { "anyOf": [ { "type": "string" }, { "type": "array", "items": { "$ref": "#/$defs/BuiltInLLMContentPart" } } ] }, "BuiltInLLMContentPart": { "anyOf": [ { "$ref": "#/$defs/BuiltInLLMTextPart" }, { "$ref": "#/$defs/BuiltInLLMImagePart" }, { "$ref": "#/$defs/BuiltInLLMToolCallPart" }, { "$ref": "#/$defs/BuiltInLLMToolResultPart" } ] }, "BuiltInLLMToolResultPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-result" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "output": { "anyOf": [ { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "value": { "type": "string" } }, "required": [ "type", "value" ] }, { "type": "object", "properties": { "type": { "type": "string", "enum": [ "json" ] }, "value": true }, "required": [ "type", "value" ] } ] } }, "required": [ "type", "toolCallId", "toolName", "output" ] }, "BuiltInLLMToolCallPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "tool-call" ] }, "toolCallId": { "type": "string" }, "toolName": { "type": "string" }, "input": { "$ref": "#/$defs/Record" } }, "required": [ "type", "toolCallId", "toolName", "input" ] }, "Record": { "type": "object", "properties": { }, "additionalProperties": true }, "BuiltInLLMImagePart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "image" ] }, "image": { "anyOf": [ { "type": "string" }, true, true, { "type": "string", "format": "uri" } ] } }, "required": [ "type", "image" ] }, "BuiltInLLMTextPart": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "text" ] }, "text": { "type": "string" } }, "required": [ "type", "text" ] } } }, "cell": { "/": "baedreidjhhm2kswzohmsb2hkzbjadbqrrxuvg22ogbqu4h363eym6bacyy" } } } } } }, "since": 98 } } }, "of:baedreibk3pk3njig5krex3aaqtcmphgmhhgh2knafrdu33f4qg4lazp2ny": { "application/json": { "ba4jcapnnsiuxtkbeqlhfkxlwg7u67ih5uimrpib5ew22euo45hevs63b": { "is": { "value": { "id": "ba4jcbyaoz42hjqx5jmqxkxncz55lqhkwys6xzdcdjfgknlvbnmhr4uay", "program": { "main": "/note.tsx", "mainExport": "default", "files": [ { "name": "/default-app.tsx", "contents": "/// \nimport {\n Cell,\n Default,\n derive,\n h,\n handler,\n NAME,\n navigateTo,\n Opaque,\n OpaqueRef,\n recipe,\n str,\n UI,\n} from \"commontools\";\n\n// Import recipes we want to be launchable from the default app.\nimport Chatbot from \"./chatbot.tsx\";\nimport ChatbotOutliner from \"./chatbot-outliner.tsx\";\nimport { type MentionableCharm } from \"./chatbot-note-composed.tsx\";\nimport { default as Note } from \"./note.tsx\";\nimport ChatList from \"./chatbot-list-view.tsx\";\n\nexport type Charm = {\n [NAME]?: string;\n [UI]?: unknown;\n [key: string]: any;\n};\n\ntype CharmsListInput = {\n allCharms: Default;\n};\n\n// Recipe returns only UI, no data outputs (only symbol properties)\ninterface CharmsListOutput {\n [key: string]: unknown;\n}\n\nconst visit = handler<\n Record,\n { charm: any }\n>((_, state) => {\n return navigateTo(state.charm);\n}, { proxy: true });\n\nconst removeCharm = handler<\n Record,\n {\n charm: any;\n allCharms: Cell;\n }\n>((_, state) => {\n const charmName = state.charm[NAME];\n const allCharmsValue = state.allCharms.get();\n const index = allCharmsValue.findIndex((c: any) => c[NAME] === charmName);\n\n if (index !== -1) {\n const charmListCopy = [...allCharmsValue];\n console.log(\"charmListCopy before\", charmListCopy);\n charmListCopy.splice(index, 1);\n console.log(\"charmListCopy after\", charmListCopy);\n state.allCharms.set(charmListCopy);\n }\n});\n\nconst spawnChatList = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(ChatList({\n selectedCharm: { charm: undefined },\n charmsList: [],\n allCharms: state.allCharms, // we should handle empty here\n }));\n});\n\nconst spawnChatbot = handler<\n Record,\n Record\n>((_, state) => {\n return navigateTo(Chatbot({\n messages: [],\n tools: undefined,\n }));\n});\n\nconst spawnChatbotOutliner = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(ChatbotOutliner({\n title: \"Chatbot Outliner\",\n expandChat: false,\n messages: [],\n outline: {\n root: { body: \"\", children: [], attachments: [] },\n },\n allCharms: state.allCharms,\n }));\n});\n\nconst spawnNote = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(Note({\n title: \"New Note\",\n content: \"\",\n allCharms: state.allCharms,\n }));\n});\n\nexport default recipe(\n \"DefaultCharmList\",\n ({ allCharms }) => {\n return {\n [NAME]: str`DefaultCharmList (${allCharms.length})`,\n [UI]: (\n \n ,\n })}\n />\n\n \n {/* Quick Launch Toolbar */}\n \n

Quicklaunch:

\n ,\n })}\n >\n 📂 Chat List\n \n \n 💬 Chatbot\n \n \n 📝 Chatbot Outliner\n \n ,\n })}\n >\n 📄 Note\n \n
\n\n

Charms ({allCharms.length})

\n\n \n \n \n Charm Name\n Actions\n \n \n \n {derive(allCharms, (allCharms) =>\n allCharms.map((charm: any) => (\n \n {charm[NAME] || \"Untitled Charm\"}\n \n \n \n Visit\n \n \n Remove\n \n \n \n \n )))}\n \n \n
\n
\n ),\n };\n },\n);\n" }, { "name": "/chatbot.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n generateObject,\n h,\n handler,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n recipe,\n str,\n Stream,\n UI,\n} from \"commontools\";\n\nconst sendMessage = handler<\n { detail: { message: string } },\n {\n addMessage: Stream;\n }\n>((event, { addMessage }) => {\n addMessage.send({\n role: \"user\",\n content: [{ type: \"text\", text: event.detail.message }],\n });\n});\n\nconst clearChat = handler(\n (\n _: never,\n { messages, pending }: {\n messages: Cell>;\n pending: Cell;\n },\n ) => {\n messages.set([]);\n pending.set(false);\n },\n);\n\ntype ChatInput = {\n messages: Default, []>;\n tools: any;\n theme?: any;\n};\n\ntype ChatOutput = {\n messages: Array;\n pending: boolean | undefined;\n addMessage: Stream;\n cancelGeneration: Stream;\n title?: string;\n};\n\nexport const TitleGenerator = recipe<\n { model?: string; messages: Array }\n>(\"Title Generator\", ({ model, messages }) => {\n const titleMessages = derive(messages, (m) => {\n if (!m || m.length === 0) return \"\";\n\n const messageCount = 2;\n const selectedMessages = m.slice(0, messageCount).filter(Boolean);\n\n if (selectedMessages.length === 0) return \"\";\n\n return selectedMessages.map((msg) => JSON.stringify(msg)).join(\"\\n\");\n });\n\n const { result } = generateObject({\n system:\n \"Generate at most a 3-word title based on the following content, respond with NOTHING but the literal title text.\",\n prompt: titleMessages,\n model,\n schema: {\n type: \"object\",\n properties: {\n title: {\n type: \"string\",\n description: \"The title of the chat\",\n },\n },\n required: [\"title\"],\n },\n });\n\n const title = derive(result, (t) => {\n return t?.title || \"Untitled Chat\";\n });\n\n return title;\n});\n\nexport default recipe(\n \"Chat\",\n ({ messages, tools, theme }) => {\n const model = cell(\"anthropic:claude-sonnet-4-5\");\n\n const { addMessage, cancelGeneration, pending } = llmDialog({\n system: \"You are a helpful assistant with some tools.\",\n messages,\n tools,\n model,\n });\n\n const { result } = fetchData({\n url: \"/api/ai/llm/models\",\n mode: \"json\",\n });\n\n const items = derive(result, (models) => {\n if (!models) return [];\n const items = Object.keys(models as any).map((key) => ({\n label: key,\n value: key,\n }));\n return items;\n });\n\n const title = TitleGenerator({ model, messages });\n\n return {\n [NAME]: title,\n [UI]: (\n \n \n {title}\n \n \n\n \n \n \n\n
\n \n \n
\n
\n ),\n messages,\n pending,\n addMessage,\n cancelGeneration,\n title,\n };\n },\n);\n" }, { "name": "/chatbot-outliner.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n getRecipeEnvironment,\n h,\n handler,\n ID,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n str,\n Stream,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot.tsx\";\n\ntype Charm = any;\n\ntype OutlinerNode = {\n body: Default;\n children: Default;\n attachments: Default[], []>;\n};\n\ntype Outliner = {\n root: OutlinerNode;\n};\n\ntype PageResult = {\n outline: Default<\n Outliner,\n { root: { body: \"\"; children: []; attachments: [] } }\n >;\n};\n\nexport type PageInput = {\n outline: Outliner;\n allCharms: Cell;\n};\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nexport const Page = recipe(\n \"Page\",\n ({ outline, allCharms }) => {\n return {\n [NAME]: \"Page\",\n [UI]: (\n \n ),\n outline,\n };\n },\n);\n\ntype LLMTestInput = {\n title: Default;\n messages: Default, []>;\n expandChat: Default;\n outline: Default<\n Outliner,\n { root: { body: \"Untitled Page\"; children: []; attachments: [] } }\n >;\n allCharms: Cell;\n};\n\ntype LLMTestResult = {\n messages: Default, []>;\n};\n\n// put a node at the end of the outline (by appending to root.children)\nconst appendOutlinerNode = handler<\n {\n /** The text content/title of the outliner node to be appended */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { outline: Cell }\n>(\n (args, state) => {\n try {\n (state.outline.key(\"root\").key(\"children\")).push({\n body: args.body,\n children: [],\n attachments: [],\n });\n\n args.result.set(\n `${state.outline.key(\"root\").key(\"children\").get().length} nodes`,\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport default recipe(\n \"Outliner\",\n ({ title, expandChat, messages, outline, allCharms }) => {\n const tools = {\n appendOutlinerNode: {\n description: \"Add a new outliner node.\",\n inputSchema: {\n type: \"object\",\n properties: {\n body: {\n type: \"string\",\n description: \"The title of the new node.\",\n },\n },\n required: [\"body\"],\n } as JSONSchema,\n handler: appendOutlinerNode({ outline }),\n },\n };\n\n const chat = Chat({ messages, tools });\n const { addMessage, cancelGeneration, pending } = chat;\n\n return {\n [NAME]: title,\n [UI]: (\n \n \n
\n
\n Show Chat\n
\n
\n\n \n \n
\n \n
\n\n \n \n \n \n \n
\n\n {ifElse(\n expandChat,\n chat,\n null,\n )}\n
\n
\n ),\n messages,\n };\n },\n);\n" }, { "name": "/chatbot-note-composed.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n getRecipeEnvironment,\n h,\n handler,\n ID,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n str,\n Stream,\n toSchema,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot.tsx\";\nimport Note from \"./note.tsx\";\nimport Tools, {\n addListItem,\n calculator,\n ListItem,\n readListItems,\n readWebpage,\n searchWeb,\n} from \"./common-tools.tsx\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\n// export type ChatbotNoteInput = {\n// content: Default;\n// allCharms?: Cell;\n// };\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\ntype ChatbotNoteInput = {\n title: Default;\n messages: Default, []>;\n content: Default;\n allCharms: Cell;\n};\n\ntype ChatbotNoteResult = {\n messages: Default, []>;\n mentioned: Default, []>;\n backlinks: Default, []>;\n content: Default;\n note: any;\n chat: any;\n list: Default;\n};\n\nconst newNote = handler<\n {\n /** The text content of the note */\n title: string;\n content?: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const n = Note({\n title: args.title,\n content: args.content || \"\",\n allCharms: state.allCharms,\n });\n\n args.result.set(\n `Created note ${args.title}!`,\n );\n\n state.allCharms.push(n as unknown as MentionableCharm);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\n// put a note at the end of the outline (by appending to root.children)\nconst editNote = handler<\n {\n /** The text content of the note */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { content: Cell }\n>(\n (args, state) => {\n try {\n state.content.set(args.body);\n\n args.result.set(\n `Updated note!`,\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst readNote = handler<\n {\n /** A cell to store the result text */\n result: Cell;\n },\n { content: string }\n>(\n (args, state) => {\n try {\n args.result.set(state.content);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst listMentionable = handler<\n {\n /** A cell to store the result text */\n result: Cell;\n },\n { allCharms: { [NAME]: string }[] }\n>(\n (args, state) => {\n try {\n const namesList = state.allCharms.map((charm) => charm[NAME]);\n args.result.set(JSON.stringify(namesList));\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst readNoteByIndex = handler<\n {\n /** A cell to store the result text */\n index: number;\n result: Cell;\n },\n { allCharms: { [NAME]: string; content?: string }[] }\n>(\n (args, state) => {\n try {\n args.result.set(\n state.allCharms[args.index]?.content || \"No content found\",\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst editNoteByIndex = handler<\n {\n /** The index of the note to edit */\n index: number;\n /** The new text content of the note */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const charms = state.allCharms.get();\n if (args.index < 0 || args.index >= charms.length) {\n args.result.set(`Error: Invalid index ${args.index}`);\n return;\n }\n\n state.allCharms.key(args.index).key(\"content\").set(args.body);\n args.result.set(`Updated note at index ${args.index}!`);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst navigateToNote = handler<\n {\n /** The index of the note to navigate to */\n index: number;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const charms = state.allCharms.get();\n if (args.index < 0 || args.index >= charms.length) {\n args.result.set(`Error: Invalid index ${args.index}`);\n return;\n }\n\n const targetCharm = charms[args.index];\n args.result.set(`Navigating to note: ${targetCharm[NAME]}`);\n\n return navigateTo(state.allCharms.key(args.index));\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport default recipe(\n \"Chatbot + Note\",\n ({ title, messages, content, allCharms }) => {\n const list = cell([]);\n\n const tools = {\n searchWeb: {\n pattern: searchWeb,\n },\n readWebpage: {\n pattern: readWebpage,\n },\n calculator: {\n pattern: calculator,\n },\n addListItem: {\n handler: addListItem({ list }),\n },\n readListItems: {\n handler: readListItems({ list }),\n },\n editActiveNote: {\n description: \"Modify the shared note.\",\n inputSchema: {\n type: \"object\",\n properties: {\n body: {\n type: \"string\",\n description: \"The content of the note.\",\n },\n },\n required: [\"body\"],\n } as JSONSchema,\n handler: editNote({ content }),\n },\n readActiveNote: {\n description: \"Read the currently focused note.\",\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n } as JSONSchema,\n handler: readNote({ content }),\n },\n listNotes: {\n description:\n \"List all mentionable note titles (read the body with readNoteByIndex).\",\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n } as JSONSchema,\n handler: listMentionable({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n readNoteByIndex: {\n description:\n \"Read the body of a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n },\n required: [\"index\"],\n } as JSONSchema,\n handler: readNoteByIndex({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n editNoteByIndex: {\n description:\n \"Edit the body of a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n body: {\n type: \"string\",\n description: \"The new content of the note.\",\n },\n },\n required: [\"index\", \"body\"],\n } as JSONSchema,\n handler: editNoteByIndex({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n navigateToNote: {\n description: \"Navigate to a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n },\n required: [\"index\"],\n } as JSONSchema,\n handler: navigateToNote({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n newNote: {\n description: \"Read the shared note.\",\n inputSchema: {\n type: \"object\",\n properties: {\n title: {\n type: \"string\",\n description: \"The title of the note.\",\n },\n content: {\n type: \"string\",\n description: \"The content of the note.\",\n },\n },\n required: [\"title\"],\n } as JSONSchema,\n handler: newNote({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n };\n\n const chat = Chat({ messages, tools });\n const note = Note({ title, content, allCharms });\n\n return {\n [NAME]: title,\n chat,\n note,\n content,\n messages,\n mentioned: note.mentioned,\n backlinks: note.backlinks,\n list,\n };\n },\n);\n" }, { "name": "/note.tsx", "contents": "/// \nimport {\n Cell,\n cell,\n Default,\n derive,\n h,\n handler,\n lift,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n toSchema,\n UI,\n} from \"commontools\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\ntype Input = {\n title: Default;\n content: Default;\n allCharms: Cell;\n};\n\ntype Output = {\n mentioned: Default, []>;\n content: Default;\n backlinks: Default, []>;\n};\n\nconst updateTitle = handler<\n { detail: { value: string } },\n { title: Cell }\n>(\n (event, state) => {\n state.title.set(event.detail?.value ?? \"\");\n },\n);\n\nconst updateContent = handler<\n { detail: { value: string } },\n { content: Cell }\n>(\n (event, state) => {\n state.content.set(event.detail?.value ?? \"\");\n },\n);\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nconst handleNewBacklink = handler<\n {\n detail: {\n text: string;\n charmId: any;\n charm: Cell;\n navigate: boolean;\n };\n },\n {\n allCharms: Cell;\n }\n>(({ detail }, { allCharms }) => {\n console.log(\"new charm\", detail.text, detail.charmId);\n\n if (detail.navigate) {\n return navigateTo(detail.charm);\n } else {\n allCharms.push(detail.charm as unknown as MentionableCharm);\n }\n});\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\nconst Note = recipe(\n \"Note\",\n ({ title, content, allCharms }) => {\n const mentioned = cell([]);\n\n const computeBacklinks = lift<\n { allCharms: Cell; content: Cell },\n MentionableCharm[]\n >(\n ({ allCharms, content }) => {\n const cs = allCharms.get();\n if (!cs) return [];\n\n const self = cs.find((c) => c.content === content.get());\n\n const results = self\n ? cs.filter((c) =>\n c.mentioned?.some((m) => m.content === self.content) ?? false\n )\n : [];\n\n return results;\n },\n );\n\n const backlinks: OpaqueRef = computeBacklinks({\n allCharms,\n content: content as unknown as Cell, // TODO(bf): this is valid, but types complain\n });\n\n // The only way to serialize a pattern, apparently?\n const pattern = derive(undefined, () => JSON.stringify(Note));\n\n return {\n [NAME]: title,\n [UI]: (\n \n
\n \n
\n\n \n
\n ),\n title,\n content,\n mentioned,\n backlinks,\n };\n },\n);\n\nexport default Note;\n" }, { "name": "/chatbot-list-view.tsx", "contents": "/// \nimport {\n Cell,\n cell,\n Default,\n derive,\n h,\n handler,\n ID,\n ifElse,\n lift,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n toSchema,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot-note-composed.tsx\";\nimport { ListItem } from \"./common-tools.tsx\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\ntype CharmEntry = {\n [ID]: string; // randomId is a string\n local_id: string; // same as ID but easier to access\n charm: any;\n};\n\ntype Input = {\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\n charmsList: Default;\n allCharms: Cell;\n theme?: {\n accentColor: Default;\n fontFace: Default;\n borderRadius: Default;\n };\n};\n\ntype Output = {\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\n};\n\nconst removeChat = handler<\n unknown,\n {\n charmsList: Cell;\n id: string;\n selectedCharm: Cell>;\n }\n>(\n (\n _,\n { charmsList, id, selectedCharm },\n ) => {\n const list = charmsList.get();\n const index = list.findIndex((entry) => entry.local_id === id);\n if (index === -1) return;\n\n const removed = list[index];\n const next = [...list];\n next.splice(index, 1);\n charmsList.set(next);\n\n // If we removed the currently selected charm, choose a new selection.\n const current = selectedCharm.get();\n if (current?.charm === removed.charm) {\n const replacement = next[index] ?? next[index - 1];\n if (replacement) {\n selectedCharm.set({ charm: replacement.charm });\n } else {\n selectedCharm.set({ charm: undefined as unknown as any });\n }\n }\n },\n);\n\n// this will be called whenever charm or selectedCharm changes\n// pass isInitialized to make sure we dont call this each time\n// we change selectedCharm, otherwise creates a loop\nconst storeCharm = lift(\n toSchema<{\n charm: any;\n selectedCharm: Cell>;\n charmsList: Cell;\n allCharms: Cell;\n theme?: {\n accentColor: Default;\n fontFace: Default;\n borderRadius: Default;\n };\n isInitialized: Cell;\n }>(),\n undefined,\n ({ charm, selectedCharm, charmsList, isInitialized, allCharms }) => { // Not including `allCharms` is a compile error...\n if (!isInitialized.get()) {\n console.log(\n \"storeCharm storing charm:\",\n charm,\n );\n selectedCharm.set({ charm });\n\n // create the chat charm with a custom name including a random suffix\n const randomId = Math.random().toString(36).substring(2, 10); // Random 8-char string\n charmsList.push({ [ID]: randomId, local_id: randomId, charm });\n\n isInitialized.set(true);\n return charm;\n } else {\n console.log(\"storeCharm: already initialized\");\n }\n return undefined;\n },\n);\n\nconst populateChatList = lift(\n toSchema<{\n charmsList: CharmEntry[];\n allCharms: Cell;\n selectedCharm: Cell<{ charm: any }>;\n }>(),\n undefined,\n (\n { charmsList, allCharms, selectedCharm },\n ) => {\n if (charmsList.length === 0) {\n const isInitialized = cell(false);\n return storeCharm({\n charm: Chat({\n title: \"New Chat\",\n messages: [],\n content: \"\",\n allCharms,\n }),\n selectedCharm,\n charmsList,\n allCharms,\n isInitialized: isInitialized as unknown as Cell,\n });\n }\n\n return charmsList;\n },\n);\n\nconst createChatRecipe = handler<\n unknown,\n {\n selectedCharm: Cell<{ charm: any }>;\n charmsList: Cell;\n allCharms: Cell;\n }\n>(\n (_, { selectedCharm, charmsList, allCharms }) => {\n const isInitialized = cell(false);\n\n const charm = Chat({\n title: \"New Chat\",\n messages: [],\n content: \"\",\n allCharms,\n });\n // store the charm ref in a cell (pass isInitialized to prevent recursive calls)\n return storeCharm({\n charm,\n selectedCharm,\n charmsList: charmsList as unknown as OpaqueRef,\n allCharms,\n isInitialized: isInitialized as unknown as Cell,\n });\n },\n);\n\nconst selectCharm = handler<\n unknown,\n { selectedCharm: Cell<{ charm: any }>; charm: any }\n>(\n (_, { selectedCharm, charm }) => {\n console.log(\"selectCharm: updating selectedCharm to \", charm);\n selectedCharm.set({ charm });\n return selectedCharm;\n },\n);\n\nconst logCharmsList = lift<\n { charmsList: Cell },\n Cell\n>(\n ({ charmsList }) => {\n console.log(\"logCharmsList: \", charmsList.get());\n return charmsList;\n },\n);\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\nconst combineLists = lift(\n (\n { allCharms, charmsList }: { allCharms: any[]; charmsList: CharmEntry[] },\n ) => {\n return [...charmsList.map((c) => c.charm), ...allCharms];\n },\n);\n\nconst getSelectedCharm = lift<\n { entry: { charm: any | undefined } },\n {\n chat: unknown;\n note: unknown;\n list: ListItem[];\n backlinks: MentionableCharm[];\n mentioned: MentionableCharm[];\n } | undefined\n>(\n ({ entry }) => {\n return entry?.charm;\n },\n);\n\nconst getCharmName = lift(({ charm }: { charm: any }) => {\n return charm?.[NAME] || \"Unknown\";\n});\n\n// create the named cell inside the recipe body, so we do it just once\nexport default recipe(\n \"Launcher\",\n ({ selectedCharm, charmsList, allCharms, theme }) => {\n logCharmsList({ charmsList: charmsList as unknown as Cell });\n\n populateChatList({\n selectedCharm: selectedCharm as unknown as Cell<\n Pick\n >,\n charmsList,\n allCharms,\n });\n\n const combined = combineLists({\n allCharms: allCharms as unknown as any[],\n charmsList,\n });\n\n const selected = getSelectedCharm({ entry: selectedCharm });\n\n const localTheme = theme ?? {\n accentColor: cell(\"#3b82f6\"),\n fontFace: cell(\"system-ui, -apple-system, sans-serif\"),\n borderRadius: cell(\"0.5rem\"),\n };\n\n return {\n [NAME]: \"Launcher\",\n [UI]: (\n \n \n
\n \n
\n \n Create New Chat\n alt+N\n \n
\n
\n\n {/* Keyboard shortcuts */}\n \n
\n \n {/* workaround: this seems to correctly start the sub-recipes on a refresh while directly rendering does not */}\n {/* this should be fixed after the builder-refactor (DX1) */}\n \n \n \n \n \n \n\n \n\n \n \n
\n
\n ),\n selectedCharm,\n charmsList,\n };\n },\n);\n" }, { "name": "/common-tools.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n BuiltInLLMTool,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n h,\n handler,\n ifElse,\n llmDialog,\n NAME,\n recipe,\n Stream,\n UI,\n} from \"commontools\";\n\n///// COMMON TOOLS (get it?) ////\n\n/**\n * Calculate the result of a mathematical expression.\n * Supports +, -, *, /, and parentheses.\n */\ntype CalculatorRequest = {\n /** The mathematical expression to evaluate. */\n expression: string;\n};\n\nexport const calculator = recipe<\n CalculatorRequest,\n string | { error: string }\n>(\"Calculator\", ({ expression }) => {\n return derive(expression, (expr) => {\n const sanitized = expr.replace(/[^0-9+\\-*/().\\s]/g, \"\");\n let result;\n try {\n result = Function(`\"use strict\"; return (${sanitized})`)();\n } catch (error) {\n result = { error: (error as any)?.message || \"\" };\n }\n return result;\n });\n});\n\n/** Add an item to the list. */\ntype AddListItemRequest = {\n /** The item to add to the list. */\n item: string;\n result: Cell;\n};\n\n/** Read all items from the list. */\ntype ReadListItemsRequest = {\n result: Cell;\n};\n\nexport type ListItem = {\n title: string;\n};\n\nexport const addListItem = handler<\n AddListItemRequest,\n { list: Cell }\n>(\n (args, state) => {\n try {\n state.list.push({ title: args.item });\n args.result.set(`${state.list.get().length} items`);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport const readListItems = handler<\n ReadListItemsRequest,\n { list: ListItem[] }\n>(\n (args, state) => {\n try {\n const items = state.list;\n if (items.length === 0) {\n args.result.set(\"The list is empty\");\n } else {\n const itemList = items.map((item, index) =>\n `${index + 1}. ${item.title}`\n ).join(\"\\n\");\n args.result.set(`List items (${items.length} total):\\n${itemList}`);\n }\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\n/** Search the web for information. */\ntype SearchQuery = {\n /** The query to search the web for. */\n query: string;\n};\n\ntype SearchWebResult = {\n results: {\n title: string;\n url: string;\n description: string;\n }[];\n};\n\nexport const searchWeb = recipe<\n SearchQuery,\n SearchWebResult | { error: string }\n>(\"Search Web\", ({ query }) => {\n const { result, error } = fetchData({\n url: \"/api/agent-tools/web-search\",\n mode: \"json\",\n options: {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: {\n query,\n max_results: 5,\n },\n },\n });\n\n // TODO(seefeld): Should we instead return { result, error }? Or allocate a\n // special [ERROR] for errors? Ideally this isn\\'t specific to using recipes as\n // tools but a general pattern.\n return ifElse(error, { error }, result);\n});\n\n/** Read and extract content from a specific webpage URL. */\ntype ReadWebRequest = {\n /** The URL of the webpage to read and extract content from. */\n url: string;\n};\n\ntype ReadWebResult = {\n content: string;\n metadata: {\n title?: string;\n author?: string;\n date?: string;\n word_count: number;\n };\n};\n\nexport const readWebpage = recipe<\n ReadWebRequest,\n ReadWebResult | { error: string }\n>(\"Read Webpage\", ({ url }) => {\n const { result, error } = fetchData({\n url: \"/api/agent-tools/web-read\",\n mode: \"json\",\n options: {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: {\n url,\n max_tokens: 4000,\n include_code: true,\n },\n },\n });\n\n return ifElse(error, { error }, result);\n});\n\ntype ToolsInput = {\n list: ListItem[];\n};\n\nexport default recipe(\"Tools\", ({ list }) => {\n const tools: Record = {\n search_web: {\n pattern: searchWeb,\n },\n read_webpage: {\n pattern: readWebpage,\n },\n calculator: {\n pattern: calculator,\n },\n addListItem: {\n handler: addListItem({ list }),\n },\n };\n\n return { tools, list };\n});\n" } ] } } }, "since": 16 } } }, "of:baedreidvk42ywcn6n6ucdpfg2pvi5o6p3njkk6rltyvydkkbjcco5m4wcu": { "application/json": { "ba4jcbdbucsmohtisjypa6w5tb5i4hp2bpydo2qzmamxvizzpdszwb747": { "is": { "source": { "/": "baedreigwd7ieoltwk6heontrraaco3ggcmbaoddoev55wx3hbpdz5hhwdu" }, "value": { "$NAME": { "$alias": { "path": [ "argument", "title" ], "schema": { "type": "string", "default": "Untitled Note" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreigwd7ieoltwk6heontrraaco3ggcmbaoddoev55wx3hbpdz5hhwdu" } } }, "$UI": { "type": "vnode", "name": "ct-screen", "props": { }, "children": [ { "type": "vnode", "name": "div", "props": { "slot": "header" }, "children": [ { "type": "vnode", "name": "ct-input", "props": { "$value": { "$alias": { "path": [ "argument", "title" ], "schema": { "type": "string", "default": "Untitled Note" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreigwd7ieoltwk6heontrraaco3ggcmbaoddoev55wx3hbpdz5hhwdu" } } }, "placeholder": "Enter title..." }, "children": [] } ] }, { "type": "vnode", "name": "ct-code-editor", "props": { "$value": { "$alias": { "path": [ "argument", "content" ], "schema": { "type": "string", "default": "" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreigwd7ieoltwk6heontrraaco3ggcmbaoddoev55wx3hbpdz5hhwdu" } } }, "$mentionable": { "$alias": { "path": [ "argument", "allCharms" ], "schema": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreigwd7ieoltwk6heontrraaco3ggcmbaoddoev55wx3hbpdz5hhwdu" } } }, "$mentioned": { "$alias": { "path": [ "internal", "mentioned" ], "cell": { "/": "baedreigwd7ieoltwk6heontrraaco3ggcmbaoddoev55wx3hbpdz5hhwdu" } } }, "$pattern": { "$alias": { "path": [ "internal", "__#0" ], "cell": { "/": "baedreigwd7ieoltwk6heontrraaco3ggcmbaoddoev55wx3hbpdz5hhwdu" } } }, "onbacklink-click": { "$alias": { "path": [ "internal", "__#1stream" ], "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "charm": { "$ref": "#/$defs/MentionableCharm" } }, "required": [ "charm" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "charm": { "$ref": "#/$defs/MentionableCharm" } }, "required": [ "charm" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreigwd7ieoltwk6heontrraaco3ggcmbaoddoev55wx3hbpdz5hhwdu" } } }, "onbacklink-create": { "$alias": { "path": [ "internal", "$event" ], "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "text": { "type": "string" }, "charmId": true, "charm": { "$ref": "#/$defs/MentionableCharm" }, "navigate": { "type": "boolean" } }, "required": [ "text", "charmId", "charm", "navigate" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "text": { "type": "string" }, "charmId": true, "charm": { "$ref": "#/$defs/MentionableCharm" }, "navigate": { "type": "boolean" } }, "required": [ "text", "charmId", "charm", "navigate" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreigwd7ieoltwk6heontrraaco3ggcmbaoddoev55wx3hbpdz5hhwdu" } } }, "language": "text/markdown", "theme": "light", "wordWrap": true, "tabIndent": true, "lineNumbers": true }, "children": [] } ] }, "title": { "$alias": { "path": [ "argument", "title" ], "schema": { "type": "string", "default": "Untitled Note" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreigwd7ieoltwk6heontrraaco3ggcmbaoddoev55wx3hbpdz5hhwdu" } } }, "content": { "$alias": { "path": [ "argument", "content" ], "schema": { "type": "string", "default": "" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreigwd7ieoltwk6heontrraaco3ggcmbaoddoev55wx3hbpdz5hhwdu" } } }, "mentioned": { "$alias": { "path": [ "internal", "mentioned" ], "cell": { "/": "baedreigwd7ieoltwk6heontrraaco3ggcmbaoddoev55wx3hbpdz5hhwdu" } } }, "backlinks": { "$alias": { "path": [ "internal", "backlinks" ], "cell": { "/": "baedreigwd7ieoltwk6heontrraaco3ggcmbaoddoev55wx3hbpdz5hhwdu" } } } } }, "since": 51 } } }, "of:baedreigwd7ieoltwk6heontrraaco3ggcmbaoddoev55wx3hbpdz5hhwdu": { "application/json": { "ba4jcb55x44zhwznchg6o623rg6cdd2alclshk3sym42ssju3ffxj5mpk": { "is": { "value": { "$TYPE": "ba4jcb5fkie7blry4u2wchwaog45dpfdwrpmrklu2zlndduvgd7dhc2ks", "resultRef": { "/": { "link@1": { "path": [], "id": "of:baedreidvk42ywcn6n6ucdpfg2pvi5o6p3njkk6rltyvydkkbjcco5m4wcu" } } }, "internal": { "$event": { "$stream": true }, "mentioned": [], "__#1stream": { "$stream": true }, "backlinks": [], "__#0": "{\"argumentSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"resultSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"default\":[]},\"content\":{\"type\":\"string\",\"default\":\"\"},\"backlinks\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"default\":[]}},\"required\":[\"mentioned\",\"content\",\"backlinks\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"initial\":{\"internal\":{\"$event\":{\"$stream\":true},\"mentioned\":[],\"__#1stream\":{\"$stream\":true}}},\"result\":{\"$NAME\":{\"$alias\":{\"path\":[\"argument\",\"title\"],\"schema\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"$UI\":{\"type\":\"vnode\",\"name\":\"ct-screen\",\"props\":{},\"children\":[{\"type\":\"vnode\",\"name\":\"div\",\"props\":{\"slot\":\"header\"},\"children\":[{\"type\":\"vnode\",\"name\":\"ct-input\",\"props\":{\"$value\":{\"$alias\":{\"path\":[\"argument\",\"title\"],\"schema\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"placeholder\":\"Enter title...\"},\"children\":[]}]},{\"type\":\"vnode\",\"name\":\"ct-code-editor\",\"props\":{\"$value\":{\"$alias\":{\"path\":[\"argument\",\"content\"],\"schema\":{\"type\":\"string\",\"default\":\"\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"$mentionable\":{\"$alias\":{\"path\":[\"argument\",\"allCharms\"],\"schema\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"$mentioned\":{\"$alias\":{\"path\":[\"internal\",\"mentioned\"]}},\"$pattern\":{\"$alias\":{\"path\":[\"internal\",\"__#0\"]}},\"onbacklink-click\":{\"$alias\":{\"path\":[\"internal\",\"__#1stream\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"onbacklink-create\":{\"$alias\":{\"path\":[\"internal\",\"$event\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"language\":\"text/markdown\",\"theme\":\"light\",\"wordWrap\":true,\"tabIndent\":true,\"lineNumbers\":true},\"children\":[]}]},\"title\":{\"$alias\":{\"path\":[\"argument\",\"title\"],\"schema\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"content\":{\"$alias\":{\"path\":[\"argument\",\"content\"],\"schema\":{\"type\":\"string\",\"default\":\"\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"mentioned\":{\"$alias\":{\"path\":[\"internal\",\"mentioned\"]}},\"backlinks\":{\"$alias\":{\"path\":[\"internal\",\"backlinks\"]}}},\"nodes\":[{\"module\":{\"type\":\"javascript\",\"implementation\":\"({ allCharms, content }) => {\\n const cs = allCharms.get();\\n if (!cs)\\n return [];\\n const self = cs.find((c) => c.content === content.get());\\n const results = self\\n ? cs.filter((c) => c.mentioned?.some((m) => m.content === self.content) ?? false)\\n : [];\\n return results;\\n }\",\"argumentSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"asCell\":true},\"content\":{\"type\":\"string\",\"asCell\":true}},\"required\":[\"allCharms\",\"content\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"resultSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"$ref\":\"#/$defs/AnonymousType_1\",\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}},\"inputs\":{\"allCharms\":{\"$alias\":{\"path\":[\"argument\",\"allCharms\"],\"schema\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"content\":{\"$alias\":{\"path\":[\"argument\",\"content\"],\"schema\":{\"type\":\"string\",\"default\":\"\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"outputs\":{\"$alias\":{\"path\":[\"internal\",\"backlinks\"]}}},{\"module\":{\"type\":\"javascript\",\"implementation\":\"({ detail }, { allCharms }) => {\\n console.log(\\\"new charm\\\", detail.text, detail.charmId);\\n if (detail.navigate) {\\n return (0, commontools_5.navigateTo)(detail.charm);\\n }\\n else {\\n allCharms.push(detail.charm);\\n }\\n }\",\"wrapper\":\"handler\",\"argumentSchema\":{\"type\":\"object\",\"properties\":{\"$event\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\",\"asCell\":true},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"]},\"$ctx\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"asCell\":true}},\"required\":[\"allCharms\"]}},\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]},\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}}}}},\"inputs\":{\"$ctx\":{\"allCharms\":{\"$alias\":{\"path\":[\"argument\",\"allCharms\"],\"schema\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"$event\":{\"$alias\":{\"path\":[\"internal\",\"$event\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"outputs\":{}},{\"module\":{\"type\":\"javascript\",\"implementation\":\"() => JSON.stringify(Note)\",\"argumentSchema\":true,\"resultSchema\":{\"type\":\"string\"}},\"outputs\":{\"$alias\":{\"path\":[\"internal\",\"__#0\"]}}},{\"module\":{\"type\":\"javascript\",\"implementation\":\"({ detail }, _) => {\\n return (0, commontools_5.navigateTo)(detail.charm);\\n }\",\"wrapper\":\"handler\",\"argumentSchema\":{\"type\":\"object\",\"properties\":{\"$event\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\",\"asCell\":true}},\"required\":[\"charm\"]}},\"required\":[\"detail\"]},\"$ctx\":{\"type\":\"object\",\"properties\":{},\"additionalProperties\":false}},\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}},\"inputs\":{\"$ctx\":{},\"$event\":{\"$alias\":{\"path\":[\"internal\",\"__#1stream\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"outputs\":{}}],\"program\":{\"main\":\"/note.tsx\",\"mainExport\":\"default\",\"files\":[{\"name\":\"/default-app.tsx\",\"contents\":\"/// \\nimport {\\n Cell,\\n Default,\\n derive,\\n h,\\n handler,\\n NAME,\\n navigateTo,\\n Opaque,\\n OpaqueRef,\\n recipe,\\n str,\\n UI,\\n} from \\\"commontools\\\";\\n\\n// Import recipes we want to be launchable from the default app.\\nimport Chatbot from \\\"./chatbot.tsx\\\";\\nimport ChatbotOutliner from \\\"./chatbot-outliner.tsx\\\";\\nimport { type MentionableCharm } from \\\"./chatbot-note-composed.tsx\\\";\\nimport { default as Note } from \\\"./note.tsx\\\";\\nimport ChatList from \\\"./chatbot-list-view.tsx\\\";\\n\\nexport type Charm = {\\n [NAME]?: string;\\n [UI]?: unknown;\\n [key: string]: any;\\n};\\n\\ntype CharmsListInput = {\\n allCharms: Default;\\n};\\n\\n// Recipe returns only UI, no data outputs (only symbol properties)\\ninterface CharmsListOutput {\\n [key: string]: unknown;\\n}\\n\\nconst visit = handler<\\n Record,\\n { charm: any }\\n>((_, state) => {\\n return navigateTo(state.charm);\\n}, { proxy: true });\\n\\nconst removeCharm = handler<\\n Record,\\n {\\n charm: any;\\n allCharms: Cell;\\n }\\n>((_, state) => {\\n const charmName = state.charm[NAME];\\n const allCharmsValue = state.allCharms.get();\\n const index = allCharmsValue.findIndex((c: any) => c[NAME] === charmName);\\n\\n if (index !== -1) {\\n const charmListCopy = [...allCharmsValue];\\n console.log(\\\"charmListCopy before\\\", charmListCopy);\\n charmListCopy.splice(index, 1);\\n console.log(\\\"charmListCopy after\\\", charmListCopy);\\n state.allCharms.set(charmListCopy);\\n }\\n});\\n\\nconst spawnChatList = handler<\\n Record,\\n { allCharms: Cell }\\n>((_, state) => {\\n return navigateTo(ChatList({\\n selectedCharm: { charm: undefined },\\n charmsList: [],\\n allCharms: state.allCharms, // we should handle empty here\\n }));\\n});\\n\\nconst spawnChatbot = handler<\\n Record,\\n Record\\n>((_, state) => {\\n return navigateTo(Chatbot({\\n messages: [],\\n tools: undefined,\\n }));\\n});\\n\\nconst spawnChatbotOutliner = handler<\\n Record,\\n { allCharms: Cell }\\n>((_, state) => {\\n return navigateTo(ChatbotOutliner({\\n title: \\\"Chatbot Outliner\\\",\\n expandChat: false,\\n messages: [],\\n outline: {\\n root: { body: \\\"\\\", children: [], attachments: [] },\\n },\\n allCharms: state.allCharms,\\n }));\\n});\\n\\nconst spawnNote = handler<\\n Record,\\n { allCharms: Cell }\\n>((_, state) => {\\n return navigateTo(Note({\\n title: \\\"New Note\\\",\\n content: \\\"\\\",\\n allCharms: state.allCharms,\\n }));\\n});\\n\\nexport default recipe(\\n \\\"DefaultCharmList\\\",\\n ({ allCharms }) => {\\n return {\\n [NAME]: str`DefaultCharmList (${allCharms.length})`,\\n [UI]: (\\n \\n ,\\n })}\\n />\\n\\n \\n {/* Quick Launch Toolbar */}\\n \\n

Quicklaunch:

\\n ,\\n })}\\n >\\n 📂 Chat List\\n \\n \\n 💬 Chatbot\\n \\n \\n 📝 Chatbot Outliner\\n \\n ,\\n })}\\n >\\n 📄 Note\\n \\n
\\n\\n

Charms ({allCharms.length})

\\n\\n \\n \\n \\n Charm Name\\n Actions\\n \\n \\n \\n {derive(allCharms, (allCharms) =>\\n allCharms.map((charm: any) => (\\n \\n {charm[NAME] || \\\"Untitled Charm\\\"}\\n \\n \\n \\n Visit\\n \\n \\n Remove\\n \\n \\n \\n \\n )))}\\n \\n \\n
\\n
\\n ),\\n };\\n },\\n);\\n\"},{\"name\":\"/chatbot.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n generateObject,\\n h,\\n handler,\\n ifElse,\\n JSONSchema,\\n lift,\\n llm,\\n llmDialog,\\n NAME,\\n recipe,\\n str,\\n Stream,\\n UI,\\n} from \\\"commontools\\\";\\n\\nconst sendMessage = handler<\\n { detail: { message: string } },\\n {\\n addMessage: Stream;\\n }\\n>((event, { addMessage }) => {\\n addMessage.send({\\n role: \\\"user\\\",\\n content: [{ type: \\\"text\\\", text: event.detail.message }],\\n });\\n});\\n\\nconst clearChat = handler(\\n (\\n _: never,\\n { messages, pending }: {\\n messages: Cell>;\\n pending: Cell;\\n },\\n ) => {\\n messages.set([]);\\n pending.set(false);\\n },\\n);\\n\\ntype ChatInput = {\\n messages: Default, []>;\\n tools: any;\\n theme?: any;\\n};\\n\\ntype ChatOutput = {\\n messages: Array;\\n pending: boolean | undefined;\\n addMessage: Stream;\\n cancelGeneration: Stream;\\n title?: string;\\n};\\n\\nexport const TitleGenerator = recipe<\\n { model?: string; messages: Array }\\n>(\\\"Title Generator\\\", ({ model, messages }) => {\\n const titleMessages = derive(messages, (m) => {\\n if (!m || m.length === 0) return \\\"\\\";\\n\\n const messageCount = 2;\\n const selectedMessages = m.slice(0, messageCount).filter(Boolean);\\n\\n if (selectedMessages.length === 0) return \\\"\\\";\\n\\n return selectedMessages.map((msg) => JSON.stringify(msg)).join(\\\"\\\\n\\\");\\n });\\n\\n const { result } = generateObject({\\n system:\\n \\\"Generate at most a 3-word title based on the following content, respond with NOTHING but the literal title text.\\\",\\n prompt: titleMessages,\\n model,\\n schema: {\\n type: \\\"object\\\",\\n properties: {\\n title: {\\n type: \\\"string\\\",\\n description: \\\"The title of the chat\\\",\\n },\\n },\\n required: [\\\"title\\\"],\\n },\\n });\\n\\n const title = derive(result, (t) => {\\n return t?.title || \\\"Untitled Chat\\\";\\n });\\n\\n return title;\\n});\\n\\nexport default recipe(\\n \\\"Chat\\\",\\n ({ messages, tools, theme }) => {\\n const model = cell(\\\"anthropic:claude-sonnet-4-5\\\");\\n\\n const { addMessage, cancelGeneration, pending } = llmDialog({\\n system: \\\"You are a helpful assistant with some tools.\\\",\\n messages,\\n tools,\\n model,\\n });\\n\\n const { result } = fetchData({\\n url: \\\"/api/ai/llm/models\\\",\\n mode: \\\"json\\\",\\n });\\n\\n const items = derive(result, (models) => {\\n if (!models) return [];\\n const items = Object.keys(models as any).map((key) => ({\\n label: key,\\n value: key,\\n }));\\n return items;\\n });\\n\\n const title = TitleGenerator({ model, messages });\\n\\n return {\\n [NAME]: title,\\n [UI]: (\\n \\n \\n {title}\\n \\n \\n\\n \\n \\n \\n\\n
\\n \\n \\n
\\n
\\n ),\\n messages,\\n pending,\\n addMessage,\\n cancelGeneration,\\n title,\\n };\\n },\\n);\\n\"},{\"name\":\"/chatbot-outliner.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n getRecipeEnvironment,\\n h,\\n handler,\\n ID,\\n ifElse,\\n JSONSchema,\\n lift,\\n llm,\\n llmDialog,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n str,\\n Stream,\\n UI,\\n} from \\\"commontools\\\";\\n\\nimport Chat from \\\"./chatbot.tsx\\\";\\n\\ntype Charm = any;\\n\\ntype OutlinerNode = {\\n body: Default;\\n children: Default;\\n attachments: Default[], []>;\\n};\\n\\ntype Outliner = {\\n root: OutlinerNode;\\n};\\n\\ntype PageResult = {\\n outline: Default<\\n Outliner,\\n { root: { body: \\\"\\\"; children: []; attachments: [] } }\\n >;\\n};\\n\\nexport type PageInput = {\\n outline: Outliner;\\n allCharms: Cell;\\n};\\n\\nconst handleCharmLinkClick = handler<\\n {\\n detail: {\\n charm: Cell;\\n };\\n },\\n Record\\n>(({ detail }, _) => {\\n return navigateTo(detail.charm);\\n});\\n\\nexport const Page = recipe(\\n \\\"Page\\\",\\n ({ outline, allCharms }) => {\\n return {\\n [NAME]: \\\"Page\\\",\\n [UI]: (\\n \\n ),\\n outline,\\n };\\n },\\n);\\n\\ntype LLMTestInput = {\\n title: Default;\\n messages: Default, []>;\\n expandChat: Default;\\n outline: Default<\\n Outliner,\\n { root: { body: \\\"Untitled Page\\\"; children: []; attachments: [] } }\\n >;\\n allCharms: Cell;\\n};\\n\\ntype LLMTestResult = {\\n messages: Default, []>;\\n};\\n\\n// put a node at the end of the outline (by appending to root.children)\\nconst appendOutlinerNode = handler<\\n {\\n /** The text content/title of the outliner node to be appended */\\n body: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { outline: Cell }\\n>(\\n (args, state) => {\\n try {\\n (state.outline.key(\\\"root\\\").key(\\\"children\\\")).push({\\n body: args.body,\\n children: [],\\n attachments: [],\\n });\\n\\n args.result.set(\\n `${state.outline.key(\\\"root\\\").key(\\\"children\\\").get().length} nodes`,\\n );\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nexport default recipe(\\n \\\"Outliner\\\",\\n ({ title, expandChat, messages, outline, allCharms }) => {\\n const tools = {\\n appendOutlinerNode: {\\n description: \\\"Add a new outliner node.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n body: {\\n type: \\\"string\\\",\\n description: \\\"The title of the new node.\\\",\\n },\\n },\\n required: [\\\"body\\\"],\\n } as JSONSchema,\\n handler: appendOutlinerNode({ outline }),\\n },\\n };\\n\\n const chat = Chat({ messages, tools });\\n const { addMessage, cancelGeneration, pending } = chat;\\n\\n return {\\n [NAME]: title,\\n [UI]: (\\n \\n \\n
\\n
\\n Show Chat\\n
\\n
\\n\\n \\n \\n
\\n \\n
\\n\\n \\n \\n \\n \\n \\n
\\n\\n {ifElse(\\n expandChat,\\n chat,\\n null,\\n )}\\n
\\n
\\n ),\\n messages,\\n };\\n },\\n);\\n\"},{\"name\":\"/chatbot-note-composed.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n getRecipeEnvironment,\\n h,\\n handler,\\n ID,\\n ifElse,\\n JSONSchema,\\n lift,\\n llm,\\n llmDialog,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n str,\\n Stream,\\n toSchema,\\n UI,\\n} from \\\"commontools\\\";\\n\\nimport Chat from \\\"./chatbot.tsx\\\";\\nimport Note from \\\"./note.tsx\\\";\\nimport Tools, {\\n addListItem,\\n calculator,\\n ListItem,\\n readListItems,\\n readWebpage,\\n searchWeb,\\n} from \\\"./common-tools.tsx\\\";\\n\\nexport type MentionableCharm = {\\n [NAME]: string;\\n content?: string;\\n mentioned?: MentionableCharm[];\\n};\\n\\n// export type ChatbotNoteInput = {\\n// content: Default;\\n// allCharms?: Cell;\\n// };\\n\\nconst handleCharmLinkClick = handler<\\n {\\n detail: {\\n charm: Cell;\\n };\\n },\\n Record\\n>(({ detail }, _) => {\\n return navigateTo(detail.charm);\\n});\\n\\nconst handleCharmLinkClicked = handler(\\n (_: any, { charm }: { charm: Cell }) => {\\n return navigateTo(charm);\\n },\\n);\\n\\ntype ChatbotNoteInput = {\\n title: Default;\\n messages: Default, []>;\\n content: Default;\\n allCharms: Cell;\\n};\\n\\ntype ChatbotNoteResult = {\\n messages: Default, []>;\\n mentioned: Default, []>;\\n backlinks: Default, []>;\\n content: Default;\\n note: any;\\n chat: any;\\n list: Default;\\n};\\n\\nconst newNote = handler<\\n {\\n /** The text content of the note */\\n title: string;\\n content?: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { allCharms: Cell }\\n>(\\n (args, state) => {\\n try {\\n const n = Note({\\n title: args.title,\\n content: args.content || \\\"\\\",\\n allCharms: state.allCharms,\\n });\\n\\n args.result.set(\\n `Created note ${args.title}!`,\\n );\\n\\n state.allCharms.push(n as unknown as MentionableCharm);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\n// put a note at the end of the outline (by appending to root.children)\\nconst editNote = handler<\\n {\\n /** The text content of the note */\\n body: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { content: Cell }\\n>(\\n (args, state) => {\\n try {\\n state.content.set(args.body);\\n\\n args.result.set(\\n `Updated note!`,\\n );\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst readNote = handler<\\n {\\n /** A cell to store the result text */\\n result: Cell;\\n },\\n { content: string }\\n>(\\n (args, state) => {\\n try {\\n args.result.set(state.content);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst listMentionable = handler<\\n {\\n /** A cell to store the result text */\\n result: Cell;\\n },\\n { allCharms: { [NAME]: string }[] }\\n>(\\n (args, state) => {\\n try {\\n const namesList = state.allCharms.map((charm) => charm[NAME]);\\n args.result.set(JSON.stringify(namesList));\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst readNoteByIndex = handler<\\n {\\n /** A cell to store the result text */\\n index: number;\\n result: Cell;\\n },\\n { allCharms: { [NAME]: string; content?: string }[] }\\n>(\\n (args, state) => {\\n try {\\n args.result.set(\\n state.allCharms[args.index]?.content || \\\"No content found\\\",\\n );\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst editNoteByIndex = handler<\\n {\\n /** The index of the note to edit */\\n index: number;\\n /** The new text content of the note */\\n body: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { allCharms: Cell }\\n>(\\n (args, state) => {\\n try {\\n const charms = state.allCharms.get();\\n if (args.index < 0 || args.index >= charms.length) {\\n args.result.set(`Error: Invalid index ${args.index}`);\\n return;\\n }\\n\\n state.allCharms.key(args.index).key(\\\"content\\\").set(args.body);\\n args.result.set(`Updated note at index ${args.index}!`);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst navigateToNote = handler<\\n {\\n /** The index of the note to navigate to */\\n index: number;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { allCharms: Cell }\\n>(\\n (args, state) => {\\n try {\\n const charms = state.allCharms.get();\\n if (args.index < 0 || args.index >= charms.length) {\\n args.result.set(`Error: Invalid index ${args.index}`);\\n return;\\n }\\n\\n const targetCharm = charms[args.index];\\n args.result.set(`Navigating to note: ${targetCharm[NAME]}`);\\n\\n return navigateTo(state.allCharms.key(args.index));\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nexport default recipe(\\n \\\"Chatbot + Note\\\",\\n ({ title, messages, content, allCharms }) => {\\n const list = cell([]);\\n\\n const tools = {\\n searchWeb: {\\n pattern: searchWeb,\\n },\\n readWebpage: {\\n pattern: readWebpage,\\n },\\n calculator: {\\n pattern: calculator,\\n },\\n addListItem: {\\n handler: addListItem({ list }),\\n },\\n readListItems: {\\n handler: readListItems({ list }),\\n },\\n editActiveNote: {\\n description: \\\"Modify the shared note.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n body: {\\n type: \\\"string\\\",\\n description: \\\"The content of the note.\\\",\\n },\\n },\\n required: [\\\"body\\\"],\\n } as JSONSchema,\\n handler: editNote({ content }),\\n },\\n readActiveNote: {\\n description: \\\"Read the currently focused note.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {},\\n required: [],\\n } as JSONSchema,\\n handler: readNote({ content }),\\n },\\n listNotes: {\\n description:\\n \\\"List all mentionable note titles (read the body with readNoteByIndex).\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {},\\n required: [],\\n } as JSONSchema,\\n handler: listMentionable({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n readNoteByIndex: {\\n description:\\n \\\"Read the body of a note by its index in the listNotes() list.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n index: {\\n type: \\\"number\\\",\\n description: \\\"The index of the note in the notes list.\\\",\\n },\\n },\\n required: [\\\"index\\\"],\\n } as JSONSchema,\\n handler: readNoteByIndex({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n editNoteByIndex: {\\n description:\\n \\\"Edit the body of a note by its index in the listNotes() list.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n index: {\\n type: \\\"number\\\",\\n description: \\\"The index of the note in the notes list.\\\",\\n },\\n body: {\\n type: \\\"string\\\",\\n description: \\\"The new content of the note.\\\",\\n },\\n },\\n required: [\\\"index\\\", \\\"body\\\"],\\n } as JSONSchema,\\n handler: editNoteByIndex({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n navigateToNote: {\\n description: \\\"Navigate to a note by its index in the listNotes() list.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n index: {\\n type: \\\"number\\\",\\n description: \\\"The index of the note in the notes list.\\\",\\n },\\n },\\n required: [\\\"index\\\"],\\n } as JSONSchema,\\n handler: navigateToNote({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n newNote: {\\n description: \\\"Read the shared note.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n title: {\\n type: \\\"string\\\",\\n description: \\\"The title of the note.\\\",\\n },\\n content: {\\n type: \\\"string\\\",\\n description: \\\"The content of the note.\\\",\\n },\\n },\\n required: [\\\"title\\\"],\\n } as JSONSchema,\\n handler: newNote({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n };\\n\\n const chat = Chat({ messages, tools });\\n const note = Note({ title, content, allCharms });\\n\\n return {\\n [NAME]: title,\\n chat,\\n note,\\n content,\\n messages,\\n mentioned: note.mentioned,\\n backlinks: note.backlinks,\\n list,\\n };\\n },\\n);\\n\"},{\"name\":\"/note.tsx\",\"contents\":\"/// \\nimport {\\n Cell,\\n cell,\\n Default,\\n derive,\\n h,\\n handler,\\n lift,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n toSchema,\\n UI,\\n} from \\\"commontools\\\";\\n\\nexport type MentionableCharm = {\\n [NAME]: string;\\n content?: string;\\n mentioned?: MentionableCharm[];\\n};\\n\\ntype Input = {\\n title: Default;\\n content: Default;\\n allCharms: Cell;\\n};\\n\\ntype Output = {\\n mentioned: Default, []>;\\n content: Default;\\n backlinks: Default, []>;\\n};\\n\\nconst updateTitle = handler<\\n { detail: { value: string } },\\n { title: Cell }\\n>(\\n (event, state) => {\\n state.title.set(event.detail?.value ?? \\\"\\\");\\n },\\n);\\n\\nconst updateContent = handler<\\n { detail: { value: string } },\\n { content: Cell }\\n>(\\n (event, state) => {\\n state.content.set(event.detail?.value ?? \\\"\\\");\\n },\\n);\\n\\nconst handleCharmLinkClick = handler<\\n {\\n detail: {\\n charm: Cell;\\n };\\n },\\n Record\\n>(({ detail }, _) => {\\n return navigateTo(detail.charm);\\n});\\n\\nconst handleNewBacklink = handler<\\n {\\n detail: {\\n text: string;\\n charmId: any;\\n charm: Cell;\\n navigate: boolean;\\n };\\n },\\n {\\n allCharms: Cell;\\n }\\n>(({ detail }, { allCharms }) => {\\n console.log(\\\"new charm\\\", detail.text, detail.charmId);\\n\\n if (detail.navigate) {\\n return navigateTo(detail.charm);\\n } else {\\n allCharms.push(detail.charm as unknown as MentionableCharm);\\n }\\n});\\n\\nconst handleCharmLinkClicked = handler(\\n (_: any, { charm }: { charm: Cell }) => {\\n return navigateTo(charm);\\n },\\n);\\n\\nconst Note = recipe(\\n \\\"Note\\\",\\n ({ title, content, allCharms }) => {\\n const mentioned = cell([]);\\n\\n const computeBacklinks = lift<\\n { allCharms: Cell; content: Cell },\\n MentionableCharm[]\\n >(\\n ({ allCharms, content }) => {\\n const cs = allCharms.get();\\n if (!cs) return [];\\n\\n const self = cs.find((c) => c.content === content.get());\\n\\n const results = self\\n ? cs.filter((c) =>\\n c.mentioned?.some((m) => m.content === self.content) ?? false\\n )\\n : [];\\n\\n return results;\\n },\\n );\\n\\n const backlinks: OpaqueRef = computeBacklinks({\\n allCharms,\\n content: content as unknown as Cell, // TODO(bf): this is valid, but types complain\\n });\\n\\n // The only way to serialize a pattern, apparently?\\n const pattern = derive(undefined, () => JSON.stringify(Note));\\n\\n return {\\n [NAME]: title,\\n [UI]: (\\n \\n
\\n \\n
\\n\\n \\n
\\n ),\\n title,\\n content,\\n mentioned,\\n backlinks,\\n };\\n },\\n);\\n\\nexport default Note;\\n\"},{\"name\":\"/chatbot-list-view.tsx\",\"contents\":\"/// \\nimport {\\n Cell,\\n cell,\\n Default,\\n derive,\\n h,\\n handler,\\n ID,\\n ifElse,\\n lift,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n toSchema,\\n UI,\\n} from \\\"commontools\\\";\\n\\nimport Chat from \\\"./chatbot-note-composed.tsx\\\";\\nimport { ListItem } from \\\"./common-tools.tsx\\\";\\n\\nexport type MentionableCharm = {\\n [NAME]: string;\\n content?: string;\\n mentioned?: MentionableCharm[];\\n};\\n\\ntype CharmEntry = {\\n [ID]: string; // randomId is a string\\n local_id: string; // same as ID but easier to access\\n charm: any;\\n};\\n\\ntype Input = {\\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\\n charmsList: Default;\\n allCharms: Cell;\\n theme?: {\\n accentColor: Default;\\n fontFace: Default;\\n borderRadius: Default;\\n };\\n};\\n\\ntype Output = {\\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\\n};\\n\\nconst removeChat = handler<\\n unknown,\\n {\\n charmsList: Cell;\\n id: string;\\n selectedCharm: Cell>;\\n }\\n>(\\n (\\n _,\\n { charmsList, id, selectedCharm },\\n ) => {\\n const list = charmsList.get();\\n const index = list.findIndex((entry) => entry.local_id === id);\\n if (index === -1) return;\\n\\n const removed = list[index];\\n const next = [...list];\\n next.splice(index, 1);\\n charmsList.set(next);\\n\\n // If we removed the currently selected charm, choose a new selection.\\n const current = selectedCharm.get();\\n if (current?.charm === removed.charm) {\\n const replacement = next[index] ?? next[index - 1];\\n if (replacement) {\\n selectedCharm.set({ charm: replacement.charm });\\n } else {\\n selectedCharm.set({ charm: undefined as unknown as any });\\n }\\n }\\n },\\n);\\n\\n// this will be called whenever charm or selectedCharm changes\\n// pass isInitialized to make sure we dont call this each time\\n// we change selectedCharm, otherwise creates a loop\\nconst storeCharm = lift(\\n toSchema<{\\n charm: any;\\n selectedCharm: Cell>;\\n charmsList: Cell;\\n allCharms: Cell;\\n theme?: {\\n accentColor: Default;\\n fontFace: Default;\\n borderRadius: Default;\\n };\\n isInitialized: Cell;\\n }>(),\\n undefined,\\n ({ charm, selectedCharm, charmsList, isInitialized, allCharms }) => { // Not including `allCharms` is a compile error...\\n if (!isInitialized.get()) {\\n console.log(\\n \\\"storeCharm storing charm:\\\",\\n charm,\\n );\\n selectedCharm.set({ charm });\\n\\n // create the chat charm with a custom name including a random suffix\\n const randomId = Math.random().toString(36).substring(2, 10); // Random 8-char string\\n charmsList.push({ [ID]: randomId, local_id: randomId, charm });\\n\\n isInitialized.set(true);\\n return charm;\\n } else {\\n console.log(\\\"storeCharm: already initialized\\\");\\n }\\n return undefined;\\n },\\n);\\n\\nconst populateChatList = lift(\\n toSchema<{\\n charmsList: CharmEntry[];\\n allCharms: Cell;\\n selectedCharm: Cell<{ charm: any }>;\\n }>(),\\n undefined,\\n (\\n { charmsList, allCharms, selectedCharm },\\n ) => {\\n if (charmsList.length === 0) {\\n const isInitialized = cell(false);\\n return storeCharm({\\n charm: Chat({\\n title: \\\"New Chat\\\",\\n messages: [],\\n content: \\\"\\\",\\n allCharms,\\n }),\\n selectedCharm,\\n charmsList,\\n allCharms,\\n isInitialized: isInitialized as unknown as Cell,\\n });\\n }\\n\\n return charmsList;\\n },\\n);\\n\\nconst createChatRecipe = handler<\\n unknown,\\n {\\n selectedCharm: Cell<{ charm: any }>;\\n charmsList: Cell;\\n allCharms: Cell;\\n }\\n>(\\n (_, { selectedCharm, charmsList, allCharms }) => {\\n const isInitialized = cell(false);\\n\\n const charm = Chat({\\n title: \\\"New Chat\\\",\\n messages: [],\\n content: \\\"\\\",\\n allCharms,\\n });\\n // store the charm ref in a cell (pass isInitialized to prevent recursive calls)\\n return storeCharm({\\n charm,\\n selectedCharm,\\n charmsList: charmsList as unknown as OpaqueRef,\\n allCharms,\\n isInitialized: isInitialized as unknown as Cell,\\n });\\n },\\n);\\n\\nconst selectCharm = handler<\\n unknown,\\n { selectedCharm: Cell<{ charm: any }>; charm: any }\\n>(\\n (_, { selectedCharm, charm }) => {\\n console.log(\\\"selectCharm: updating selectedCharm to \\\", charm);\\n selectedCharm.set({ charm });\\n return selectedCharm;\\n },\\n);\\n\\nconst logCharmsList = lift<\\n { charmsList: Cell },\\n Cell\\n>(\\n ({ charmsList }) => {\\n console.log(\\\"logCharmsList: \\\", charmsList.get());\\n return charmsList;\\n },\\n);\\n\\nconst handleCharmLinkClicked = handler(\\n (_: any, { charm }: { charm: Cell }) => {\\n return navigateTo(charm);\\n },\\n);\\n\\nconst combineLists = lift(\\n (\\n { allCharms, charmsList }: { allCharms: any[]; charmsList: CharmEntry[] },\\n ) => {\\n return [...charmsList.map((c) => c.charm), ...allCharms];\\n },\\n);\\n\\nconst getSelectedCharm = lift<\\n { entry: { charm: any | undefined } },\\n {\\n chat: unknown;\\n note: unknown;\\n list: ListItem[];\\n backlinks: MentionableCharm[];\\n mentioned: MentionableCharm[];\\n } | undefined\\n>(\\n ({ entry }) => {\\n return entry?.charm;\\n },\\n);\\n\\nconst getCharmName = lift(({ charm }: { charm: any }) => {\\n return charm?.[NAME] || \\\"Unknown\\\";\\n});\\n\\n// create the named cell inside the recipe body, so we do it just once\\nexport default recipe(\\n \\\"Launcher\\\",\\n ({ selectedCharm, charmsList, allCharms, theme }) => {\\n logCharmsList({ charmsList: charmsList as unknown as Cell });\\n\\n populateChatList({\\n selectedCharm: selectedCharm as unknown as Cell<\\n Pick\\n >,\\n charmsList,\\n allCharms,\\n });\\n\\n const combined = combineLists({\\n allCharms: allCharms as unknown as any[],\\n charmsList,\\n });\\n\\n const selected = getSelectedCharm({ entry: selectedCharm });\\n\\n const localTheme = theme ?? {\\n accentColor: cell(\\\"#3b82f6\\\"),\\n fontFace: cell(\\\"system-ui, -apple-system, sans-serif\\\"),\\n borderRadius: cell(\\\"0.5rem\\\"),\\n };\\n\\n return {\\n [NAME]: \\\"Launcher\\\",\\n [UI]: (\\n \\n \\n
\\n \\n
\\n \\n Create New Chat\\n alt+N\\n \\n
\\n
\\n\\n {/* Keyboard shortcuts */}\\n \\n
\\n \\n {/* workaround: this seems to correctly start the sub-recipes on a refresh while directly rendering does not */}\\n {/* this should be fixed after the builder-refactor (DX1) */}\\n \\n \\n \\n \\n \\n \\n\\n \\n\\n \\n \\n
\\n
\\n ),\\n selectedCharm,\\n charmsList,\\n };\\n },\\n);\\n\"},{\"name\":\"/common-tools.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n BuiltInLLMTool,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n h,\\n handler,\\n ifElse,\\n llmDialog,\\n NAME,\\n recipe,\\n Stream,\\n UI,\\n} from \\\"commontools\\\";\\n\\n///// COMMON TOOLS (get it?) ////\\n\\n/**\\n * Calculate the result of a mathematical expression.\\n * Supports +, -, *, /, and parentheses.\\n */\\ntype CalculatorRequest = {\\n /** The mathematical expression to evaluate. */\\n expression: string;\\n};\\n\\nexport const calculator = recipe<\\n CalculatorRequest,\\n string | { error: string }\\n>(\\\"Calculator\\\", ({ expression }) => {\\n return derive(expression, (expr) => {\\n const sanitized = expr.replace(/[^0-9+\\\\-*/().\\\\s]/g, \\\"\\\");\\n let result;\\n try {\\n result = Function(`\\\"use strict\\\"; return (${sanitized})`)();\\n } catch (error) {\\n result = { error: (error as any)?.message || \\\"\\\" };\\n }\\n return result;\\n });\\n});\\n\\n/** Add an item to the list. */\\ntype AddListItemRequest = {\\n /** The item to add to the list. */\\n item: string;\\n result: Cell;\\n};\\n\\n/** Read all items from the list. */\\ntype ReadListItemsRequest = {\\n result: Cell;\\n};\\n\\nexport type ListItem = {\\n title: string;\\n};\\n\\nexport const addListItem = handler<\\n AddListItemRequest,\\n { list: Cell }\\n>(\\n (args, state) => {\\n try {\\n state.list.push({ title: args.item });\\n args.result.set(`${state.list.get().length} items`);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nexport const readListItems = handler<\\n ReadListItemsRequest,\\n { list: ListItem[] }\\n>(\\n (args, state) => {\\n try {\\n const items = state.list;\\n if (items.length === 0) {\\n args.result.set(\\\"The list is empty\\\");\\n } else {\\n const itemList = items.map((item, index) =>\\n `${index + 1}. ${item.title}`\\n ).join(\\\"\\\\n\\\");\\n args.result.set(`List items (${items.length} total):\\\\n${itemList}`);\\n }\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\n/** Search the web for information. */\\ntype SearchQuery = {\\n /** The query to search the web for. */\\n query: string;\\n};\\n\\ntype SearchWebResult = {\\n results: {\\n title: string;\\n url: string;\\n description: string;\\n }[];\\n};\\n\\nexport const searchWeb = recipe<\\n SearchQuery,\\n SearchWebResult | { error: string }\\n>(\\\"Search Web\\\", ({ query }) => {\\n const { result, error } = fetchData({\\n url: \\\"/api/agent-tools/web-search\\\",\\n mode: \\\"json\\\",\\n options: {\\n method: \\\"POST\\\",\\n headers: {\\n \\\"Content-Type\\\": \\\"application/json\\\",\\n },\\n body: {\\n query,\\n max_results: 5,\\n },\\n },\\n });\\n\\n // TODO(seefeld): Should we instead return { result, error }? Or allocate a\\n // special [ERROR] for errors? Ideally this isn\\'t specific to using recipes as\\n // tools but a general pattern.\\n return ifElse(error, { error }, result);\\n});\\n\\n/** Read and extract content from a specific webpage URL. */\\ntype ReadWebRequest = {\\n /** The URL of the webpage to read and extract content from. */\\n url: string;\\n};\\n\\ntype ReadWebResult = {\\n content: string;\\n metadata: {\\n title?: string;\\n author?: string;\\n date?: string;\\n word_count: number;\\n };\\n};\\n\\nexport const readWebpage = recipe<\\n ReadWebRequest,\\n ReadWebResult | { error: string }\\n>(\\\"Read Webpage\\\", ({ url }) => {\\n const { result, error } = fetchData({\\n url: \\\"/api/agent-tools/web-read\\\",\\n mode: \\\"json\\\",\\n options: {\\n method: \\\"POST\\\",\\n headers: {\\n \\\"Content-Type\\\": \\\"application/json\\\",\\n },\\n body: {\\n url,\\n max_tokens: 4000,\\n include_code: true,\\n },\\n },\\n });\\n\\n return ifElse(error, { error }, result);\\n});\\n\\ntype ToolsInput = {\\n list: ListItem[];\\n};\\n\\nexport default recipe(\\\"Tools\\\", ({ list }) => {\\n const tools: Record = {\\n search_web: {\\n pattern: searchWeb,\\n },\\n read_webpage: {\\n pattern: readWebpage,\\n },\\n calculator: {\\n pattern: calculator,\\n },\\n addListItem: {\\n handler: addListItem({ list }),\\n },\\n };\\n\\n return { tools, list };\\n});\\n\"}]}}" }, "spell": { "/": { "link@1": { "id": "of:baedreic5vwrifhgsveszaoiglpnwpg6muauspvb7lkbehia7oltjqtmeby" } } }, "argument": { "title": "one", "content": "", "allCharms": { "/": { "link@1": { "path": [], "id": "of:baedreiahv63wxwgaem4hzjkizl4qncfgvca7pj5cvdon7cukumfon3ioye", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } } } } }, "since": 54 } } }, "of:baedreic5vwrifhgsveszaoiglpnwpg6muauspvb7lkbehia7oltjqtmeby": { "application/json": { "ba4jcbinzthh537agprtjwhbekqi7rf4saaocet6ifik2kne4rr7vwuht": { "is": { "value": { "id": "ba4jcb5fkie7blry4u2wchwaog45dpfdwrpmrklu2zlndduvgd7dhc2ks", "program": { "main": "/note.tsx", "mainExport": "default", "files": [ { "name": "/default-app.tsx", "contents": "/// \nimport {\n Cell,\n Default,\n derive,\n h,\n handler,\n NAME,\n navigateTo,\n Opaque,\n OpaqueRef,\n recipe,\n str,\n UI,\n} from \"commontools\";\n\n// Import recipes we want to be launchable from the default app.\nimport Chatbot from \"./chatbot.tsx\";\nimport ChatbotOutliner from \"./chatbot-outliner.tsx\";\nimport { type MentionableCharm } from \"./chatbot-note-composed.tsx\";\nimport { default as Note } from \"./note.tsx\";\nimport ChatList from \"./chatbot-list-view.tsx\";\n\nexport type Charm = {\n [NAME]?: string;\n [UI]?: unknown;\n [key: string]: any;\n};\n\ntype CharmsListInput = {\n allCharms: Default;\n};\n\n// Recipe returns only UI, no data outputs (only symbol properties)\ninterface CharmsListOutput {\n [key: string]: unknown;\n}\n\nconst visit = handler<\n Record,\n { charm: any }\n>((_, state) => {\n return navigateTo(state.charm);\n}, { proxy: true });\n\nconst removeCharm = handler<\n Record,\n {\n charm: any;\n allCharms: Cell;\n }\n>((_, state) => {\n const charmName = state.charm[NAME];\n const allCharmsValue = state.allCharms.get();\n const index = allCharmsValue.findIndex((c: any) => c[NAME] === charmName);\n\n if (index !== -1) {\n const charmListCopy = [...allCharmsValue];\n console.log(\"charmListCopy before\", charmListCopy);\n charmListCopy.splice(index, 1);\n console.log(\"charmListCopy after\", charmListCopy);\n state.allCharms.set(charmListCopy);\n }\n});\n\nconst spawnChatList = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(ChatList({\n selectedCharm: { charm: undefined },\n charmsList: [],\n allCharms: state.allCharms, // we should handle empty here\n }));\n});\n\nconst spawnChatbot = handler<\n Record,\n Record\n>((_, state) => {\n return navigateTo(Chatbot({\n messages: [],\n tools: undefined,\n }));\n});\n\nconst spawnChatbotOutliner = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(ChatbotOutliner({\n title: \"Chatbot Outliner\",\n expandChat: false,\n messages: [],\n outline: {\n root: { body: \"\", children: [], attachments: [] },\n },\n allCharms: state.allCharms,\n }));\n});\n\nconst spawnNote = handler<\n Record,\n { allCharms: Cell }\n>((_, state) => {\n return navigateTo(Note({\n title: \"New Note\",\n content: \"\",\n allCharms: state.allCharms,\n }));\n});\n\nexport default recipe(\n \"DefaultCharmList\",\n ({ allCharms }) => {\n return {\n [NAME]: str`DefaultCharmList (${allCharms.length})`,\n [UI]: (\n \n ,\n })}\n />\n\n \n {/* Quick Launch Toolbar */}\n \n

Quicklaunch:

\n ,\n })}\n >\n 📂 Chat List\n \n \n 💬 Chatbot\n \n \n 📝 Chatbot Outliner\n \n ,\n })}\n >\n 📄 Note\n \n
\n\n

Charms ({allCharms.length})

\n\n \n \n \n Charm Name\n Actions\n \n \n \n {derive(allCharms, (allCharms) =>\n allCharms.map((charm: any) => (\n \n {charm[NAME] || \"Untitled Charm\"}\n \n \n \n Visit\n \n \n Remove\n \n \n \n \n )))}\n \n \n
\n
\n ),\n };\n },\n);\n" }, { "name": "/chatbot.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n generateObject,\n h,\n handler,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n recipe,\n str,\n Stream,\n UI,\n} from \"commontools\";\n\nconst sendMessage = handler<\n { detail: { message: string } },\n {\n addMessage: Stream;\n }\n>((event, { addMessage }) => {\n addMessage.send({\n role: \"user\",\n content: [{ type: \"text\", text: event.detail.message }],\n });\n});\n\nconst clearChat = handler(\n (\n _: never,\n { messages, pending }: {\n messages: Cell>;\n pending: Cell;\n },\n ) => {\n messages.set([]);\n pending.set(false);\n },\n);\n\ntype ChatInput = {\n messages: Default, []>;\n tools: any;\n theme?: any;\n};\n\ntype ChatOutput = {\n messages: Array;\n pending: boolean | undefined;\n addMessage: Stream;\n cancelGeneration: Stream;\n title?: string;\n};\n\nexport const TitleGenerator = recipe<\n { model?: string; messages: Array }\n>(\"Title Generator\", ({ model, messages }) => {\n const titleMessages = derive(messages, (m) => {\n if (!m || m.length === 0) return \"\";\n\n const messageCount = 2;\n const selectedMessages = m.slice(0, messageCount).filter(Boolean);\n\n if (selectedMessages.length === 0) return \"\";\n\n return selectedMessages.map((msg) => JSON.stringify(msg)).join(\"\\n\");\n });\n\n const { result } = generateObject({\n system:\n \"Generate at most a 3-word title based on the following content, respond with NOTHING but the literal title text.\",\n prompt: titleMessages,\n model,\n schema: {\n type: \"object\",\n properties: {\n title: {\n type: \"string\",\n description: \"The title of the chat\",\n },\n },\n required: [\"title\"],\n },\n });\n\n const title = derive(result, (t) => {\n return t?.title || \"Untitled Chat\";\n });\n\n return title;\n});\n\nexport default recipe(\n \"Chat\",\n ({ messages, tools, theme }) => {\n const model = cell(\"anthropic:claude-sonnet-4-5\");\n\n const { addMessage, cancelGeneration, pending } = llmDialog({\n system: \"You are a helpful assistant with some tools.\",\n messages,\n tools,\n model,\n });\n\n const { result } = fetchData({\n url: \"/api/ai/llm/models\",\n mode: \"json\",\n });\n\n const items = derive(result, (models) => {\n if (!models) return [];\n const items = Object.keys(models as any).map((key) => ({\n label: key,\n value: key,\n }));\n return items;\n });\n\n const title = TitleGenerator({ model, messages });\n\n return {\n [NAME]: title,\n [UI]: (\n \n \n {title}\n \n \n\n \n \n \n\n
\n \n \n
\n
\n ),\n messages,\n pending,\n addMessage,\n cancelGeneration,\n title,\n };\n },\n);\n" }, { "name": "/chatbot-outliner.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n getRecipeEnvironment,\n h,\n handler,\n ID,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n str,\n Stream,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot.tsx\";\n\ntype Charm = any;\n\ntype OutlinerNode = {\n body: Default;\n children: Default;\n attachments: Default[], []>;\n};\n\ntype Outliner = {\n root: OutlinerNode;\n};\n\ntype PageResult = {\n outline: Default<\n Outliner,\n { root: { body: \"\"; children: []; attachments: [] } }\n >;\n};\n\nexport type PageInput = {\n outline: Outliner;\n allCharms: Cell;\n};\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nexport const Page = recipe(\n \"Page\",\n ({ outline, allCharms }) => {\n return {\n [NAME]: \"Page\",\n [UI]: (\n \n ),\n outline,\n };\n },\n);\n\ntype LLMTestInput = {\n title: Default;\n messages: Default, []>;\n expandChat: Default;\n outline: Default<\n Outliner,\n { root: { body: \"Untitled Page\"; children: []; attachments: [] } }\n >;\n allCharms: Cell;\n};\n\ntype LLMTestResult = {\n messages: Default, []>;\n};\n\n// put a node at the end of the outline (by appending to root.children)\nconst appendOutlinerNode = handler<\n {\n /** The text content/title of the outliner node to be appended */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { outline: Cell }\n>(\n (args, state) => {\n try {\n (state.outline.key(\"root\").key(\"children\")).push({\n body: args.body,\n children: [],\n attachments: [],\n });\n\n args.result.set(\n `${state.outline.key(\"root\").key(\"children\").get().length} nodes`,\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport default recipe(\n \"Outliner\",\n ({ title, expandChat, messages, outline, allCharms }) => {\n const tools = {\n appendOutlinerNode: {\n description: \"Add a new outliner node.\",\n inputSchema: {\n type: \"object\",\n properties: {\n body: {\n type: \"string\",\n description: \"The title of the new node.\",\n },\n },\n required: [\"body\"],\n } as JSONSchema,\n handler: appendOutlinerNode({ outline }),\n },\n };\n\n const chat = Chat({ messages, tools });\n const { addMessage, cancelGeneration, pending } = chat;\n\n return {\n [NAME]: title,\n [UI]: (\n \n \n
\n
\n Show Chat\n
\n
\n\n \n \n
\n \n
\n\n \n \n \n \n \n
\n\n {ifElse(\n expandChat,\n chat,\n null,\n )}\n
\n
\n ),\n messages,\n };\n },\n);\n" }, { "name": "/chatbot-note-composed.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n getRecipeEnvironment,\n h,\n handler,\n ID,\n ifElse,\n JSONSchema,\n lift,\n llm,\n llmDialog,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n str,\n Stream,\n toSchema,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot.tsx\";\nimport Note from \"./note.tsx\";\nimport Tools, {\n addListItem,\n calculator,\n ListItem,\n readListItems,\n readWebpage,\n searchWeb,\n} from \"./common-tools.tsx\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\n// export type ChatbotNoteInput = {\n// content: Default;\n// allCharms?: Cell;\n// };\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\ntype ChatbotNoteInput = {\n title: Default;\n messages: Default, []>;\n content: Default;\n allCharms: Cell;\n};\n\ntype ChatbotNoteResult = {\n messages: Default, []>;\n mentioned: Default, []>;\n backlinks: Default, []>;\n content: Default;\n note: any;\n chat: any;\n list: Default;\n};\n\nconst newNote = handler<\n {\n /** The text content of the note */\n title: string;\n content?: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const n = Note({\n title: args.title,\n content: args.content || \"\",\n allCharms: state.allCharms,\n });\n\n args.result.set(\n `Created note ${args.title}!`,\n );\n\n state.allCharms.push(n as unknown as MentionableCharm);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\n// put a note at the end of the outline (by appending to root.children)\nconst editNote = handler<\n {\n /** The text content of the note */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { content: Cell }\n>(\n (args, state) => {\n try {\n state.content.set(args.body);\n\n args.result.set(\n `Updated note!`,\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst readNote = handler<\n {\n /** A cell to store the result text */\n result: Cell;\n },\n { content: string }\n>(\n (args, state) => {\n try {\n args.result.set(state.content);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst listMentionable = handler<\n {\n /** A cell to store the result text */\n result: Cell;\n },\n { allCharms: { [NAME]: string }[] }\n>(\n (args, state) => {\n try {\n const namesList = state.allCharms.map((charm) => charm[NAME]);\n args.result.set(JSON.stringify(namesList));\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst readNoteByIndex = handler<\n {\n /** A cell to store the result text */\n index: number;\n result: Cell;\n },\n { allCharms: { [NAME]: string; content?: string }[] }\n>(\n (args, state) => {\n try {\n args.result.set(\n state.allCharms[args.index]?.content || \"No content found\",\n );\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst editNoteByIndex = handler<\n {\n /** The index of the note to edit */\n index: number;\n /** The new text content of the note */\n body: string;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const charms = state.allCharms.get();\n if (args.index < 0 || args.index >= charms.length) {\n args.result.set(`Error: Invalid index ${args.index}`);\n return;\n }\n\n state.allCharms.key(args.index).key(\"content\").set(args.body);\n args.result.set(`Updated note at index ${args.index}!`);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nconst navigateToNote = handler<\n {\n /** The index of the note to navigate to */\n index: number;\n /** A cell to store the result message indicating success or error */\n result: Cell;\n },\n { allCharms: Cell }\n>(\n (args, state) => {\n try {\n const charms = state.allCharms.get();\n if (args.index < 0 || args.index >= charms.length) {\n args.result.set(`Error: Invalid index ${args.index}`);\n return;\n }\n\n const targetCharm = charms[args.index];\n args.result.set(`Navigating to note: ${targetCharm[NAME]}`);\n\n return navigateTo(state.allCharms.key(args.index));\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport default recipe(\n \"Chatbot + Note\",\n ({ title, messages, content, allCharms }) => {\n const list = cell([]);\n\n const tools = {\n searchWeb: {\n pattern: searchWeb,\n },\n readWebpage: {\n pattern: readWebpage,\n },\n calculator: {\n pattern: calculator,\n },\n addListItem: {\n handler: addListItem({ list }),\n },\n readListItems: {\n handler: readListItems({ list }),\n },\n editActiveNote: {\n description: \"Modify the shared note.\",\n inputSchema: {\n type: \"object\",\n properties: {\n body: {\n type: \"string\",\n description: \"The content of the note.\",\n },\n },\n required: [\"body\"],\n } as JSONSchema,\n handler: editNote({ content }),\n },\n readActiveNote: {\n description: \"Read the currently focused note.\",\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n } as JSONSchema,\n handler: readNote({ content }),\n },\n listNotes: {\n description:\n \"List all mentionable note titles (read the body with readNoteByIndex).\",\n inputSchema: {\n type: \"object\",\n properties: {},\n required: [],\n } as JSONSchema,\n handler: listMentionable({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n readNoteByIndex: {\n description:\n \"Read the body of a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n },\n required: [\"index\"],\n } as JSONSchema,\n handler: readNoteByIndex({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n editNoteByIndex: {\n description:\n \"Edit the body of a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n body: {\n type: \"string\",\n description: \"The new content of the note.\",\n },\n },\n required: [\"index\", \"body\"],\n } as JSONSchema,\n handler: editNoteByIndex({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n navigateToNote: {\n description: \"Navigate to a note by its index in the listNotes() list.\",\n inputSchema: {\n type: \"object\",\n properties: {\n index: {\n type: \"number\",\n description: \"The index of the note in the notes list.\",\n },\n },\n required: [\"index\"],\n } as JSONSchema,\n handler: navigateToNote({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n newNote: {\n description: \"Read the shared note.\",\n inputSchema: {\n type: \"object\",\n properties: {\n title: {\n type: \"string\",\n description: \"The title of the note.\",\n },\n content: {\n type: \"string\",\n description: \"The content of the note.\",\n },\n },\n required: [\"title\"],\n } as JSONSchema,\n handler: newNote({\n allCharms: allCharms as unknown as OpaqueRef,\n }),\n },\n };\n\n const chat = Chat({ messages, tools });\n const note = Note({ title, content, allCharms });\n\n return {\n [NAME]: title,\n chat,\n note,\n content,\n messages,\n mentioned: note.mentioned,\n backlinks: note.backlinks,\n list,\n };\n },\n);\n" }, { "name": "/note.tsx", "contents": "/// \nimport {\n Cell,\n cell,\n Default,\n derive,\n h,\n handler,\n lift,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n toSchema,\n UI,\n} from \"commontools\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\ntype Input = {\n title: Default;\n content: Default;\n allCharms: Cell;\n};\n\ntype Output = {\n mentioned: Default, []>;\n content: Default;\n backlinks: Default, []>;\n};\n\nconst updateTitle = handler<\n { detail: { value: string } },\n { title: Cell }\n>(\n (event, state) => {\n state.title.set(event.detail?.value ?? \"\");\n },\n);\n\nconst updateContent = handler<\n { detail: { value: string } },\n { content: Cell }\n>(\n (event, state) => {\n state.content.set(event.detail?.value ?? \"\");\n },\n);\n\nconst handleCharmLinkClick = handler<\n {\n detail: {\n charm: Cell;\n };\n },\n Record\n>(({ detail }, _) => {\n return navigateTo(detail.charm);\n});\n\nconst handleNewBacklink = handler<\n {\n detail: {\n text: string;\n charmId: any;\n charm: Cell;\n navigate: boolean;\n };\n },\n {\n allCharms: Cell;\n }\n>(({ detail }, { allCharms }) => {\n console.log(\"new charm\", detail.text, detail.charmId);\n\n if (detail.navigate) {\n return navigateTo(detail.charm);\n } else {\n allCharms.push(detail.charm as unknown as MentionableCharm);\n }\n});\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\nconst Note = recipe(\n \"Note\",\n ({ title, content, allCharms }) => {\n const mentioned = cell([]);\n\n const computeBacklinks = lift<\n { allCharms: Cell; content: Cell },\n MentionableCharm[]\n >(\n ({ allCharms, content }) => {\n const cs = allCharms.get();\n if (!cs) return [];\n\n const self = cs.find((c) => c.content === content.get());\n\n const results = self\n ? cs.filter((c) =>\n c.mentioned?.some((m) => m.content === self.content) ?? false\n )\n : [];\n\n return results;\n },\n );\n\n const backlinks: OpaqueRef = computeBacklinks({\n allCharms,\n content: content as unknown as Cell, // TODO(bf): this is valid, but types complain\n });\n\n // The only way to serialize a pattern, apparently?\n const pattern = derive(undefined, () => JSON.stringify(Note));\n\n return {\n [NAME]: title,\n [UI]: (\n \n
\n \n
\n\n \n
\n ),\n title,\n content,\n mentioned,\n backlinks,\n };\n },\n);\n\nexport default Note;\n" }, { "name": "/chatbot-list-view.tsx", "contents": "/// \nimport {\n Cell,\n cell,\n Default,\n derive,\n h,\n handler,\n ID,\n ifElse,\n lift,\n NAME,\n navigateTo,\n OpaqueRef,\n recipe,\n toSchema,\n UI,\n} from \"commontools\";\n\nimport Chat from \"./chatbot-note-composed.tsx\";\nimport { ListItem } from \"./common-tools.tsx\";\n\nexport type MentionableCharm = {\n [NAME]: string;\n content?: string;\n mentioned?: MentionableCharm[];\n};\n\ntype CharmEntry = {\n [ID]: string; // randomId is a string\n local_id: string; // same as ID but easier to access\n charm: any;\n};\n\ntype Input = {\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\n charmsList: Default;\n allCharms: Cell;\n theme?: {\n accentColor: Default;\n fontFace: Default;\n borderRadius: Default;\n };\n};\n\ntype Output = {\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\n};\n\nconst removeChat = handler<\n unknown,\n {\n charmsList: Cell;\n id: string;\n selectedCharm: Cell>;\n }\n>(\n (\n _,\n { charmsList, id, selectedCharm },\n ) => {\n const list = charmsList.get();\n const index = list.findIndex((entry) => entry.local_id === id);\n if (index === -1) return;\n\n const removed = list[index];\n const next = [...list];\n next.splice(index, 1);\n charmsList.set(next);\n\n // If we removed the currently selected charm, choose a new selection.\n const current = selectedCharm.get();\n if (current?.charm === removed.charm) {\n const replacement = next[index] ?? next[index - 1];\n if (replacement) {\n selectedCharm.set({ charm: replacement.charm });\n } else {\n selectedCharm.set({ charm: undefined as unknown as any });\n }\n }\n },\n);\n\n// this will be called whenever charm or selectedCharm changes\n// pass isInitialized to make sure we dont call this each time\n// we change selectedCharm, otherwise creates a loop\nconst storeCharm = lift(\n toSchema<{\n charm: any;\n selectedCharm: Cell>;\n charmsList: Cell;\n allCharms: Cell;\n theme?: {\n accentColor: Default;\n fontFace: Default;\n borderRadius: Default;\n };\n isInitialized: Cell;\n }>(),\n undefined,\n ({ charm, selectedCharm, charmsList, isInitialized, allCharms }) => { // Not including `allCharms` is a compile error...\n if (!isInitialized.get()) {\n console.log(\n \"storeCharm storing charm:\",\n charm,\n );\n selectedCharm.set({ charm });\n\n // create the chat charm with a custom name including a random suffix\n const randomId = Math.random().toString(36).substring(2, 10); // Random 8-char string\n charmsList.push({ [ID]: randomId, local_id: randomId, charm });\n\n isInitialized.set(true);\n return charm;\n } else {\n console.log(\"storeCharm: already initialized\");\n }\n return undefined;\n },\n);\n\nconst populateChatList = lift(\n toSchema<{\n charmsList: CharmEntry[];\n allCharms: Cell;\n selectedCharm: Cell<{ charm: any }>;\n }>(),\n undefined,\n (\n { charmsList, allCharms, selectedCharm },\n ) => {\n if (charmsList.length === 0) {\n const isInitialized = cell(false);\n return storeCharm({\n charm: Chat({\n title: \"New Chat\",\n messages: [],\n content: \"\",\n allCharms,\n }),\n selectedCharm,\n charmsList,\n allCharms,\n isInitialized: isInitialized as unknown as Cell,\n });\n }\n\n return charmsList;\n },\n);\n\nconst createChatRecipe = handler<\n unknown,\n {\n selectedCharm: Cell<{ charm: any }>;\n charmsList: Cell;\n allCharms: Cell;\n }\n>(\n (_, { selectedCharm, charmsList, allCharms }) => {\n const isInitialized = cell(false);\n\n const charm = Chat({\n title: \"New Chat\",\n messages: [],\n content: \"\",\n allCharms,\n });\n // store the charm ref in a cell (pass isInitialized to prevent recursive calls)\n return storeCharm({\n charm,\n selectedCharm,\n charmsList: charmsList as unknown as OpaqueRef,\n allCharms,\n isInitialized: isInitialized as unknown as Cell,\n });\n },\n);\n\nconst selectCharm = handler<\n unknown,\n { selectedCharm: Cell<{ charm: any }>; charm: any }\n>(\n (_, { selectedCharm, charm }) => {\n console.log(\"selectCharm: updating selectedCharm to \", charm);\n selectedCharm.set({ charm });\n return selectedCharm;\n },\n);\n\nconst logCharmsList = lift<\n { charmsList: Cell },\n Cell\n>(\n ({ charmsList }) => {\n console.log(\"logCharmsList: \", charmsList.get());\n return charmsList;\n },\n);\n\nconst handleCharmLinkClicked = handler(\n (_: any, { charm }: { charm: Cell }) => {\n return navigateTo(charm);\n },\n);\n\nconst combineLists = lift(\n (\n { allCharms, charmsList }: { allCharms: any[]; charmsList: CharmEntry[] },\n ) => {\n return [...charmsList.map((c) => c.charm), ...allCharms];\n },\n);\n\nconst getSelectedCharm = lift<\n { entry: { charm: any | undefined } },\n {\n chat: unknown;\n note: unknown;\n list: ListItem[];\n backlinks: MentionableCharm[];\n mentioned: MentionableCharm[];\n } | undefined\n>(\n ({ entry }) => {\n return entry?.charm;\n },\n);\n\nconst getCharmName = lift(({ charm }: { charm: any }) => {\n return charm?.[NAME] || \"Unknown\";\n});\n\n// create the named cell inside the recipe body, so we do it just once\nexport default recipe(\n \"Launcher\",\n ({ selectedCharm, charmsList, allCharms, theme }) => {\n logCharmsList({ charmsList: charmsList as unknown as Cell });\n\n populateChatList({\n selectedCharm: selectedCharm as unknown as Cell<\n Pick\n >,\n charmsList,\n allCharms,\n });\n\n const combined = combineLists({\n allCharms: allCharms as unknown as any[],\n charmsList,\n });\n\n const selected = getSelectedCharm({ entry: selectedCharm });\n\n const localTheme = theme ?? {\n accentColor: cell(\"#3b82f6\"),\n fontFace: cell(\"system-ui, -apple-system, sans-serif\"),\n borderRadius: cell(\"0.5rem\"),\n };\n\n return {\n [NAME]: \"Launcher\",\n [UI]: (\n \n \n
\n \n
\n \n Create New Chat\n alt+N\n \n
\n
\n\n {/* Keyboard shortcuts */}\n \n
\n \n {/* workaround: this seems to correctly start the sub-recipes on a refresh while directly rendering does not */}\n {/* this should be fixed after the builder-refactor (DX1) */}\n \n \n \n \n \n \n\n \n\n \n \n
\n
\n ),\n selectedCharm,\n charmsList,\n };\n },\n);\n" }, { "name": "/common-tools.tsx", "contents": "/// \nimport {\n BuiltInLLMMessage,\n BuiltInLLMTool,\n Cell,\n cell,\n Default,\n derive,\n fetchData,\n h,\n handler,\n ifElse,\n llmDialog,\n NAME,\n recipe,\n Stream,\n UI,\n} from \"commontools\";\n\n///// COMMON TOOLS (get it?) ////\n\n/**\n * Calculate the result of a mathematical expression.\n * Supports +, -, *, /, and parentheses.\n */\ntype CalculatorRequest = {\n /** The mathematical expression to evaluate. */\n expression: string;\n};\n\nexport const calculator = recipe<\n CalculatorRequest,\n string | { error: string }\n>(\"Calculator\", ({ expression }) => {\n return derive(expression, (expr) => {\n const sanitized = expr.replace(/[^0-9+\\-*/().\\s]/g, \"\");\n let result;\n try {\n result = Function(`\"use strict\"; return (${sanitized})`)();\n } catch (error) {\n result = { error: (error as any)?.message || \"\" };\n }\n return result;\n });\n});\n\n/** Add an item to the list. */\ntype AddListItemRequest = {\n /** The item to add to the list. */\n item: string;\n result: Cell;\n};\n\n/** Read all items from the list. */\ntype ReadListItemsRequest = {\n result: Cell;\n};\n\nexport type ListItem = {\n title: string;\n};\n\nexport const addListItem = handler<\n AddListItemRequest,\n { list: Cell }\n>(\n (args, state) => {\n try {\n state.list.push({ title: args.item });\n args.result.set(`${state.list.get().length} items`);\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\nexport const readListItems = handler<\n ReadListItemsRequest,\n { list: ListItem[] }\n>(\n (args, state) => {\n try {\n const items = state.list;\n if (items.length === 0) {\n args.result.set(\"The list is empty\");\n } else {\n const itemList = items.map((item, index) =>\n `${index + 1}. ${item.title}`\n ).join(\"\\n\");\n args.result.set(`List items (${items.length} total):\\n${itemList}`);\n }\n } catch (error) {\n args.result.set(`Error: ${(error as any)?.message || \"\"}`);\n }\n },\n);\n\n/** Search the web for information. */\ntype SearchQuery = {\n /** The query to search the web for. */\n query: string;\n};\n\ntype SearchWebResult = {\n results: {\n title: string;\n url: string;\n description: string;\n }[];\n};\n\nexport const searchWeb = recipe<\n SearchQuery,\n SearchWebResult | { error: string }\n>(\"Search Web\", ({ query }) => {\n const { result, error } = fetchData({\n url: \"/api/agent-tools/web-search\",\n mode: \"json\",\n options: {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: {\n query,\n max_results: 5,\n },\n },\n });\n\n // TODO(seefeld): Should we instead return { result, error }? Or allocate a\n // special [ERROR] for errors? Ideally this isn\\'t specific to using recipes as\n // tools but a general pattern.\n return ifElse(error, { error }, result);\n});\n\n/** Read and extract content from a specific webpage URL. */\ntype ReadWebRequest = {\n /** The URL of the webpage to read and extract content from. */\n url: string;\n};\n\ntype ReadWebResult = {\n content: string;\n metadata: {\n title?: string;\n author?: string;\n date?: string;\n word_count: number;\n };\n};\n\nexport const readWebpage = recipe<\n ReadWebRequest,\n ReadWebResult | { error: string }\n>(\"Read Webpage\", ({ url }) => {\n const { result, error } = fetchData({\n url: \"/api/agent-tools/web-read\",\n mode: \"json\",\n options: {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: {\n url,\n max_tokens: 4000,\n include_code: true,\n },\n },\n });\n\n return ifElse(error, { error }, result);\n});\n\ntype ToolsInput = {\n list: ListItem[];\n};\n\nexport default recipe(\"Tools\", ({ list }) => {\n const tools: Record = {\n search_web: {\n pattern: searchWeb,\n },\n read_webpage: {\n pattern: readWebpage,\n },\n calculator: {\n pattern: calculator,\n },\n addListItem: {\n handler: addListItem({ list }),\n },\n };\n\n return { tools, list };\n});\n" } ] } } }, "since": 50 } } }, "of:baedreibninu5twfm72l6gs5sbaghg6gdtmn2365encfoinebrvnsmavrr4": { "application/json": { "ba4jcbidzvrx2rzbzgbjtwe42vlcommgfygoivqhoh32ifpljzbkmqx2e": { "is": { "source": { "/": "baedreiahgj72ya6x5xlhxqt23iez6etkhhzaioxdd7i5sxwve4cheascve" }, "value": { "$NAME": { "$alias": { "path": [ "argument", "title" ], "schema": { "type": "string", "default": "Untitled Note" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreiahgj72ya6x5xlhxqt23iez6etkhhzaioxdd7i5sxwve4cheascve" } } }, "$UI": { "type": "vnode", "name": "ct-screen", "props": { }, "children": [ { "type": "vnode", "name": "div", "props": { "slot": "header" }, "children": [ { "type": "vnode", "name": "ct-input", "props": { "$value": { "$alias": { "path": [ "argument", "title" ], "schema": { "type": "string", "default": "Untitled Note" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreiahgj72ya6x5xlhxqt23iez6etkhhzaioxdd7i5sxwve4cheascve" } } }, "placeholder": "Enter title..." }, "children": [] } ] }, { "type": "vnode", "name": "ct-code-editor", "props": { "$value": { "$alias": { "path": [ "argument", "content" ], "schema": { "type": "string", "default": "" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreiahgj72ya6x5xlhxqt23iez6etkhhzaioxdd7i5sxwve4cheascve" } } }, "$mentionable": { "$alias": { "path": [ "argument", "allCharms" ], "schema": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreiahgj72ya6x5xlhxqt23iez6etkhhzaioxdd7i5sxwve4cheascve" } } }, "$mentioned": { "$alias": { "path": [ "internal", "mentioned" ], "cell": { "/": "baedreiahgj72ya6x5xlhxqt23iez6etkhhzaioxdd7i5sxwve4cheascve" } } }, "$pattern": { "$alias": { "path": [ "internal", "__#0" ], "cell": { "/": "baedreiahgj72ya6x5xlhxqt23iez6etkhhzaioxdd7i5sxwve4cheascve" } } }, "onbacklink-click": { "$alias": { "path": [ "internal", "__#1stream" ], "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "charm": { "$ref": "#/$defs/MentionableCharm" } }, "required": [ "charm" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "charm": { "$ref": "#/$defs/MentionableCharm" } }, "required": [ "charm" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreiahgj72ya6x5xlhxqt23iez6etkhhzaioxdd7i5sxwve4cheascve" } } }, "onbacklink-create": { "$alias": { "path": [ "internal", "$event" ], "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "text": { "type": "string" }, "charmId": true, "charm": { "$ref": "#/$defs/MentionableCharm" }, "navigate": { "type": "boolean" } }, "required": [ "text", "charmId", "charm", "navigate" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "text": { "type": "string" }, "charmId": true, "charm": { "$ref": "#/$defs/MentionableCharm" }, "navigate": { "type": "boolean" } }, "required": [ "text", "charmId", "charm", "navigate" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreiahgj72ya6x5xlhxqt23iez6etkhhzaioxdd7i5sxwve4cheascve" } } }, "language": "text/markdown", "theme": "light", "wordWrap": true, "tabIndent": true, "lineNumbers": true }, "children": [] } ] }, "title": { "$alias": { "path": [ "argument", "title" ], "schema": { "type": "string", "default": "Untitled Note" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreiahgj72ya6x5xlhxqt23iez6etkhhzaioxdd7i5sxwve4cheascve" } } }, "content": { "$alias": { "path": [ "argument", "content" ], "schema": { "type": "string", "default": "" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreiahgj72ya6x5xlhxqt23iez6etkhhzaioxdd7i5sxwve4cheascve" } } }, "mentioned": { "$alias": { "path": [ "internal", "mentioned" ], "cell": { "/": "baedreiahgj72ya6x5xlhxqt23iez6etkhhzaioxdd7i5sxwve4cheascve" } } }, "backlinks": { "$alias": { "path": [ "internal", "backlinks" ], "cell": { "/": "baedreiahgj72ya6x5xlhxqt23iez6etkhhzaioxdd7i5sxwve4cheascve" } } } } }, "since": 65 } } }, "of:baedreiahgj72ya6x5xlhxqt23iez6etkhhzaioxdd7i5sxwve4cheascve": { "application/json": { "ba4jcbqwrsic7m52iq5dutkxpnglfoqfjqcqqye6eitm4fa7be47dfebi": { "is": { "value": { "$TYPE": "ba4jcb5fkie7blry4u2wchwaog45dpfdwrpmrklu2zlndduvgd7dhc2ks", "resultRef": { "/": { "link@1": { "path": [], "id": "of:baedreibninu5twfm72l6gs5sbaghg6gdtmn2365encfoinebrvnsmavrr4" } } }, "internal": { "$event": { "$stream": true }, "mentioned": [], "__#1stream": { "$stream": true }, "backlinks": [], "__#0": "{\"argumentSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"resultSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"default\":[]},\"content\":{\"type\":\"string\",\"default\":\"\"},\"backlinks\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"default\":[]}},\"required\":[\"mentioned\",\"content\",\"backlinks\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"initial\":{\"internal\":{\"$event\":{\"$stream\":true},\"mentioned\":[],\"__#1stream\":{\"$stream\":true}}},\"result\":{\"$NAME\":{\"$alias\":{\"path\":[\"argument\",\"title\"],\"schema\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"$UI\":{\"type\":\"vnode\",\"name\":\"ct-screen\",\"props\":{},\"children\":[{\"type\":\"vnode\",\"name\":\"div\",\"props\":{\"slot\":\"header\"},\"children\":[{\"type\":\"vnode\",\"name\":\"ct-input\",\"props\":{\"$value\":{\"$alias\":{\"path\":[\"argument\",\"title\"],\"schema\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"placeholder\":\"Enter title...\"},\"children\":[]}]},{\"type\":\"vnode\",\"name\":\"ct-code-editor\",\"props\":{\"$value\":{\"$alias\":{\"path\":[\"argument\",\"content\"],\"schema\":{\"type\":\"string\",\"default\":\"\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"$mentionable\":{\"$alias\":{\"path\":[\"argument\",\"allCharms\"],\"schema\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"$mentioned\":{\"$alias\":{\"path\":[\"internal\",\"mentioned\"]}},\"$pattern\":{\"$alias\":{\"path\":[\"internal\",\"__#0\"]}},\"onbacklink-click\":{\"$alias\":{\"path\":[\"internal\",\"__#1stream\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"onbacklink-create\":{\"$alias\":{\"path\":[\"internal\",\"$event\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"language\":\"text/markdown\",\"theme\":\"light\",\"wordWrap\":true,\"tabIndent\":true,\"lineNumbers\":true},\"children\":[]}]},\"title\":{\"$alias\":{\"path\":[\"argument\",\"title\"],\"schema\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"content\":{\"$alias\":{\"path\":[\"argument\",\"content\"],\"schema\":{\"type\":\"string\",\"default\":\"\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"mentioned\":{\"$alias\":{\"path\":[\"internal\",\"mentioned\"]}},\"backlinks\":{\"$alias\":{\"path\":[\"internal\",\"backlinks\"]}}},\"nodes\":[{\"module\":{\"type\":\"javascript\",\"implementation\":\"({ allCharms, content }) => {\\n const cs = allCharms.get();\\n if (!cs)\\n return [];\\n const self = cs.find((c) => c.content === content.get());\\n const results = self\\n ? cs.filter((c) => c.mentioned?.some((m) => m.content === self.content) ?? false)\\n : [];\\n return results;\\n }\",\"argumentSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"asCell\":true},\"content\":{\"type\":\"string\",\"asCell\":true}},\"required\":[\"allCharms\",\"content\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"resultSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"$ref\":\"#/$defs/AnonymousType_1\",\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}},\"inputs\":{\"allCharms\":{\"$alias\":{\"path\":[\"argument\",\"allCharms\"],\"schema\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"content\":{\"$alias\":{\"path\":[\"argument\",\"content\"],\"schema\":{\"type\":\"string\",\"default\":\"\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"outputs\":{\"$alias\":{\"path\":[\"internal\",\"backlinks\"]}}},{\"module\":{\"type\":\"javascript\",\"implementation\":\"({ detail }, { allCharms }) => {\\n console.log(\\\"new charm\\\", detail.text, detail.charmId);\\n if (detail.navigate) {\\n return (0, commontools_5.navigateTo)(detail.charm);\\n }\\n else {\\n allCharms.push(detail.charm);\\n }\\n }\",\"wrapper\":\"handler\",\"argumentSchema\":{\"type\":\"object\",\"properties\":{\"$event\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\",\"asCell\":true},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"]},\"$ctx\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"asCell\":true}},\"required\":[\"allCharms\"]}},\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]},\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}}}}},\"inputs\":{\"$ctx\":{\"allCharms\":{\"$alias\":{\"path\":[\"argument\",\"allCharms\"],\"schema\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"$event\":{\"$alias\":{\"path\":[\"internal\",\"$event\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"outputs\":{}},{\"module\":{\"type\":\"javascript\",\"implementation\":\"() => JSON.stringify(Note)\",\"argumentSchema\":true,\"resultSchema\":{\"type\":\"string\"}},\"outputs\":{\"$alias\":{\"path\":[\"internal\",\"__#0\"]}}},{\"module\":{\"type\":\"javascript\",\"implementation\":\"({ detail }, _) => {\\n return (0, commontools_5.navigateTo)(detail.charm);\\n }\",\"wrapper\":\"handler\",\"argumentSchema\":{\"type\":\"object\",\"properties\":{\"$event\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\",\"asCell\":true}},\"required\":[\"charm\"]}},\"required\":[\"detail\"]},\"$ctx\":{\"type\":\"object\",\"properties\":{},\"additionalProperties\":false}},\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}},\"inputs\":{\"$ctx\":{},\"$event\":{\"$alias\":{\"path\":[\"internal\",\"__#1stream\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"outputs\":{}}],\"program\":{\"main\":\"/note.tsx\",\"mainExport\":\"default\",\"files\":[{\"name\":\"/default-app.tsx\",\"contents\":\"/// \\nimport {\\n Cell,\\n Default,\\n derive,\\n h,\\n handler,\\n NAME,\\n navigateTo,\\n Opaque,\\n OpaqueRef,\\n recipe,\\n str,\\n UI,\\n} from \\\"commontools\\\";\\n\\n// Import recipes we want to be launchable from the default app.\\nimport Chatbot from \\\"./chatbot.tsx\\\";\\nimport ChatbotOutliner from \\\"./chatbot-outliner.tsx\\\";\\nimport { type MentionableCharm } from \\\"./chatbot-note-composed.tsx\\\";\\nimport { default as Note } from \\\"./note.tsx\\\";\\nimport ChatList from \\\"./chatbot-list-view.tsx\\\";\\n\\nexport type Charm = {\\n [NAME]?: string;\\n [UI]?: unknown;\\n [key: string]: any;\\n};\\n\\ntype CharmsListInput = {\\n allCharms: Default;\\n};\\n\\n// Recipe returns only UI, no data outputs (only symbol properties)\\ninterface CharmsListOutput {\\n [key: string]: unknown;\\n}\\n\\nconst visit = handler<\\n Record,\\n { charm: any }\\n>((_, state) => {\\n return navigateTo(state.charm);\\n}, { proxy: true });\\n\\nconst removeCharm = handler<\\n Record,\\n {\\n charm: any;\\n allCharms: Cell;\\n }\\n>((_, state) => {\\n const charmName = state.charm[NAME];\\n const allCharmsValue = state.allCharms.get();\\n const index = allCharmsValue.findIndex((c: any) => c[NAME] === charmName);\\n\\n if (index !== -1) {\\n const charmListCopy = [...allCharmsValue];\\n console.log(\\\"charmListCopy before\\\", charmListCopy);\\n charmListCopy.splice(index, 1);\\n console.log(\\\"charmListCopy after\\\", charmListCopy);\\n state.allCharms.set(charmListCopy);\\n }\\n});\\n\\nconst spawnChatList = handler<\\n Record,\\n { allCharms: Cell }\\n>((_, state) => {\\n return navigateTo(ChatList({\\n selectedCharm: { charm: undefined },\\n charmsList: [],\\n allCharms: state.allCharms, // we should handle empty here\\n }));\\n});\\n\\nconst spawnChatbot = handler<\\n Record,\\n Record\\n>((_, state) => {\\n return navigateTo(Chatbot({\\n messages: [],\\n tools: undefined,\\n }));\\n});\\n\\nconst spawnChatbotOutliner = handler<\\n Record,\\n { allCharms: Cell }\\n>((_, state) => {\\n return navigateTo(ChatbotOutliner({\\n title: \\\"Chatbot Outliner\\\",\\n expandChat: false,\\n messages: [],\\n outline: {\\n root: { body: \\\"\\\", children: [], attachments: [] },\\n },\\n allCharms: state.allCharms,\\n }));\\n});\\n\\nconst spawnNote = handler<\\n Record,\\n { allCharms: Cell }\\n>((_, state) => {\\n return navigateTo(Note({\\n title: \\\"New Note\\\",\\n content: \\\"\\\",\\n allCharms: state.allCharms,\\n }));\\n});\\n\\nexport default recipe(\\n \\\"DefaultCharmList\\\",\\n ({ allCharms }) => {\\n return {\\n [NAME]: str`DefaultCharmList (${allCharms.length})`,\\n [UI]: (\\n \\n ,\\n })}\\n />\\n\\n \\n {/* Quick Launch Toolbar */}\\n \\n

Quicklaunch:

\\n ,\\n })}\\n >\\n 📂 Chat List\\n \\n \\n 💬 Chatbot\\n \\n \\n 📝 Chatbot Outliner\\n \\n ,\\n })}\\n >\\n 📄 Note\\n \\n
\\n\\n

Charms ({allCharms.length})

\\n\\n \\n \\n \\n Charm Name\\n Actions\\n \\n \\n \\n {derive(allCharms, (allCharms) =>\\n allCharms.map((charm: any) => (\\n \\n {charm[NAME] || \\\"Untitled Charm\\\"}\\n \\n \\n \\n Visit\\n \\n \\n Remove\\n \\n \\n \\n \\n )))}\\n \\n \\n
\\n
\\n ),\\n };\\n },\\n);\\n\"},{\"name\":\"/chatbot.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n generateObject,\\n h,\\n handler,\\n ifElse,\\n JSONSchema,\\n lift,\\n llm,\\n llmDialog,\\n NAME,\\n recipe,\\n str,\\n Stream,\\n UI,\\n} from \\\"commontools\\\";\\n\\nconst sendMessage = handler<\\n { detail: { message: string } },\\n {\\n addMessage: Stream;\\n }\\n>((event, { addMessage }) => {\\n addMessage.send({\\n role: \\\"user\\\",\\n content: [{ type: \\\"text\\\", text: event.detail.message }],\\n });\\n});\\n\\nconst clearChat = handler(\\n (\\n _: never,\\n { messages, pending }: {\\n messages: Cell>;\\n pending: Cell;\\n },\\n ) => {\\n messages.set([]);\\n pending.set(false);\\n },\\n);\\n\\ntype ChatInput = {\\n messages: Default, []>;\\n tools: any;\\n theme?: any;\\n};\\n\\ntype ChatOutput = {\\n messages: Array;\\n pending: boolean | undefined;\\n addMessage: Stream;\\n cancelGeneration: Stream;\\n title?: string;\\n};\\n\\nexport const TitleGenerator = recipe<\\n { model?: string; messages: Array }\\n>(\\\"Title Generator\\\", ({ model, messages }) => {\\n const titleMessages = derive(messages, (m) => {\\n if (!m || m.length === 0) return \\\"\\\";\\n\\n const messageCount = 2;\\n const selectedMessages = m.slice(0, messageCount).filter(Boolean);\\n\\n if (selectedMessages.length === 0) return \\\"\\\";\\n\\n return selectedMessages.map((msg) => JSON.stringify(msg)).join(\\\"\\\\n\\\");\\n });\\n\\n const { result } = generateObject({\\n system:\\n \\\"Generate at most a 3-word title based on the following content, respond with NOTHING but the literal title text.\\\",\\n prompt: titleMessages,\\n model,\\n schema: {\\n type: \\\"object\\\",\\n properties: {\\n title: {\\n type: \\\"string\\\",\\n description: \\\"The title of the chat\\\",\\n },\\n },\\n required: [\\\"title\\\"],\\n },\\n });\\n\\n const title = derive(result, (t) => {\\n return t?.title || \\\"Untitled Chat\\\";\\n });\\n\\n return title;\\n});\\n\\nexport default recipe(\\n \\\"Chat\\\",\\n ({ messages, tools, theme }) => {\\n const model = cell(\\\"anthropic:claude-sonnet-4-5\\\");\\n\\n const { addMessage, cancelGeneration, pending } = llmDialog({\\n system: \\\"You are a helpful assistant with some tools.\\\",\\n messages,\\n tools,\\n model,\\n });\\n\\n const { result } = fetchData({\\n url: \\\"/api/ai/llm/models\\\",\\n mode: \\\"json\\\",\\n });\\n\\n const items = derive(result, (models) => {\\n if (!models) return [];\\n const items = Object.keys(models as any).map((key) => ({\\n label: key,\\n value: key,\\n }));\\n return items;\\n });\\n\\n const title = TitleGenerator({ model, messages });\\n\\n return {\\n [NAME]: title,\\n [UI]: (\\n \\n \\n {title}\\n \\n \\n\\n \\n \\n \\n\\n
\\n \\n \\n
\\n
\\n ),\\n messages,\\n pending,\\n addMessage,\\n cancelGeneration,\\n title,\\n };\\n },\\n);\\n\"},{\"name\":\"/chatbot-outliner.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n getRecipeEnvironment,\\n h,\\n handler,\\n ID,\\n ifElse,\\n JSONSchema,\\n lift,\\n llm,\\n llmDialog,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n str,\\n Stream,\\n UI,\\n} from \\\"commontools\\\";\\n\\nimport Chat from \\\"./chatbot.tsx\\\";\\n\\ntype Charm = any;\\n\\ntype OutlinerNode = {\\n body: Default;\\n children: Default;\\n attachments: Default[], []>;\\n};\\n\\ntype Outliner = {\\n root: OutlinerNode;\\n};\\n\\ntype PageResult = {\\n outline: Default<\\n Outliner,\\n { root: { body: \\\"\\\"; children: []; attachments: [] } }\\n >;\\n};\\n\\nexport type PageInput = {\\n outline: Outliner;\\n allCharms: Cell;\\n};\\n\\nconst handleCharmLinkClick = handler<\\n {\\n detail: {\\n charm: Cell;\\n };\\n },\\n Record\\n>(({ detail }, _) => {\\n return navigateTo(detail.charm);\\n});\\n\\nexport const Page = recipe(\\n \\\"Page\\\",\\n ({ outline, allCharms }) => {\\n return {\\n [NAME]: \\\"Page\\\",\\n [UI]: (\\n \\n ),\\n outline,\\n };\\n },\\n);\\n\\ntype LLMTestInput = {\\n title: Default;\\n messages: Default, []>;\\n expandChat: Default;\\n outline: Default<\\n Outliner,\\n { root: { body: \\\"Untitled Page\\\"; children: []; attachments: [] } }\\n >;\\n allCharms: Cell;\\n};\\n\\ntype LLMTestResult = {\\n messages: Default, []>;\\n};\\n\\n// put a node at the end of the outline (by appending to root.children)\\nconst appendOutlinerNode = handler<\\n {\\n /** The text content/title of the outliner node to be appended */\\n body: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { outline: Cell }\\n>(\\n (args, state) => {\\n try {\\n (state.outline.key(\\\"root\\\").key(\\\"children\\\")).push({\\n body: args.body,\\n children: [],\\n attachments: [],\\n });\\n\\n args.result.set(\\n `${state.outline.key(\\\"root\\\").key(\\\"children\\\").get().length} nodes`,\\n );\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nexport default recipe(\\n \\\"Outliner\\\",\\n ({ title, expandChat, messages, outline, allCharms }) => {\\n const tools = {\\n appendOutlinerNode: {\\n description: \\\"Add a new outliner node.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n body: {\\n type: \\\"string\\\",\\n description: \\\"The title of the new node.\\\",\\n },\\n },\\n required: [\\\"body\\\"],\\n } as JSONSchema,\\n handler: appendOutlinerNode({ outline }),\\n },\\n };\\n\\n const chat = Chat({ messages, tools });\\n const { addMessage, cancelGeneration, pending } = chat;\\n\\n return {\\n [NAME]: title,\\n [UI]: (\\n \\n \\n
\\n
\\n Show Chat\\n
\\n
\\n\\n \\n \\n
\\n \\n
\\n\\n \\n \\n \\n \\n \\n
\\n\\n {ifElse(\\n expandChat,\\n chat,\\n null,\\n )}\\n
\\n
\\n ),\\n messages,\\n };\\n },\\n);\\n\"},{\"name\":\"/chatbot-note-composed.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n getRecipeEnvironment,\\n h,\\n handler,\\n ID,\\n ifElse,\\n JSONSchema,\\n lift,\\n llm,\\n llmDialog,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n str,\\n Stream,\\n toSchema,\\n UI,\\n} from \\\"commontools\\\";\\n\\nimport Chat from \\\"./chatbot.tsx\\\";\\nimport Note from \\\"./note.tsx\\\";\\nimport Tools, {\\n addListItem,\\n calculator,\\n ListItem,\\n readListItems,\\n readWebpage,\\n searchWeb,\\n} from \\\"./common-tools.tsx\\\";\\n\\nexport type MentionableCharm = {\\n [NAME]: string;\\n content?: string;\\n mentioned?: MentionableCharm[];\\n};\\n\\n// export type ChatbotNoteInput = {\\n// content: Default;\\n// allCharms?: Cell;\\n// };\\n\\nconst handleCharmLinkClick = handler<\\n {\\n detail: {\\n charm: Cell;\\n };\\n },\\n Record\\n>(({ detail }, _) => {\\n return navigateTo(detail.charm);\\n});\\n\\nconst handleCharmLinkClicked = handler(\\n (_: any, { charm }: { charm: Cell }) => {\\n return navigateTo(charm);\\n },\\n);\\n\\ntype ChatbotNoteInput = {\\n title: Default;\\n messages: Default, []>;\\n content: Default;\\n allCharms: Cell;\\n};\\n\\ntype ChatbotNoteResult = {\\n messages: Default, []>;\\n mentioned: Default, []>;\\n backlinks: Default, []>;\\n content: Default;\\n note: any;\\n chat: any;\\n list: Default;\\n};\\n\\nconst newNote = handler<\\n {\\n /** The text content of the note */\\n title: string;\\n content?: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { allCharms: Cell }\\n>(\\n (args, state) => {\\n try {\\n const n = Note({\\n title: args.title,\\n content: args.content || \\\"\\\",\\n allCharms: state.allCharms,\\n });\\n\\n args.result.set(\\n `Created note ${args.title}!`,\\n );\\n\\n state.allCharms.push(n as unknown as MentionableCharm);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\n// put a note at the end of the outline (by appending to root.children)\\nconst editNote = handler<\\n {\\n /** The text content of the note */\\n body: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { content: Cell }\\n>(\\n (args, state) => {\\n try {\\n state.content.set(args.body);\\n\\n args.result.set(\\n `Updated note!`,\\n );\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst readNote = handler<\\n {\\n /** A cell to store the result text */\\n result: Cell;\\n },\\n { content: string }\\n>(\\n (args, state) => {\\n try {\\n args.result.set(state.content);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst listMentionable = handler<\\n {\\n /** A cell to store the result text */\\n result: Cell;\\n },\\n { allCharms: { [NAME]: string }[] }\\n>(\\n (args, state) => {\\n try {\\n const namesList = state.allCharms.map((charm) => charm[NAME]);\\n args.result.set(JSON.stringify(namesList));\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst readNoteByIndex = handler<\\n {\\n /** A cell to store the result text */\\n index: number;\\n result: Cell;\\n },\\n { allCharms: { [NAME]: string; content?: string }[] }\\n>(\\n (args, state) => {\\n try {\\n args.result.set(\\n state.allCharms[args.index]?.content || \\\"No content found\\\",\\n );\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst editNoteByIndex = handler<\\n {\\n /** The index of the note to edit */\\n index: number;\\n /** The new text content of the note */\\n body: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { allCharms: Cell }\\n>(\\n (args, state) => {\\n try {\\n const charms = state.allCharms.get();\\n if (args.index < 0 || args.index >= charms.length) {\\n args.result.set(`Error: Invalid index ${args.index}`);\\n return;\\n }\\n\\n state.allCharms.key(args.index).key(\\\"content\\\").set(args.body);\\n args.result.set(`Updated note at index ${args.index}!`);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst navigateToNote = handler<\\n {\\n /** The index of the note to navigate to */\\n index: number;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { allCharms: Cell }\\n>(\\n (args, state) => {\\n try {\\n const charms = state.allCharms.get();\\n if (args.index < 0 || args.index >= charms.length) {\\n args.result.set(`Error: Invalid index ${args.index}`);\\n return;\\n }\\n\\n const targetCharm = charms[args.index];\\n args.result.set(`Navigating to note: ${targetCharm[NAME]}`);\\n\\n return navigateTo(state.allCharms.key(args.index));\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nexport default recipe(\\n \\\"Chatbot + Note\\\",\\n ({ title, messages, content, allCharms }) => {\\n const list = cell([]);\\n\\n const tools = {\\n searchWeb: {\\n pattern: searchWeb,\\n },\\n readWebpage: {\\n pattern: readWebpage,\\n },\\n calculator: {\\n pattern: calculator,\\n },\\n addListItem: {\\n handler: addListItem({ list }),\\n },\\n readListItems: {\\n handler: readListItems({ list }),\\n },\\n editActiveNote: {\\n description: \\\"Modify the shared note.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n body: {\\n type: \\\"string\\\",\\n description: \\\"The content of the note.\\\",\\n },\\n },\\n required: [\\\"body\\\"],\\n } as JSONSchema,\\n handler: editNote({ content }),\\n },\\n readActiveNote: {\\n description: \\\"Read the currently focused note.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {},\\n required: [],\\n } as JSONSchema,\\n handler: readNote({ content }),\\n },\\n listNotes: {\\n description:\\n \\\"List all mentionable note titles (read the body with readNoteByIndex).\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {},\\n required: [],\\n } as JSONSchema,\\n handler: listMentionable({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n readNoteByIndex: {\\n description:\\n \\\"Read the body of a note by its index in the listNotes() list.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n index: {\\n type: \\\"number\\\",\\n description: \\\"The index of the note in the notes list.\\\",\\n },\\n },\\n required: [\\\"index\\\"],\\n } as JSONSchema,\\n handler: readNoteByIndex({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n editNoteByIndex: {\\n description:\\n \\\"Edit the body of a note by its index in the listNotes() list.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n index: {\\n type: \\\"number\\\",\\n description: \\\"The index of the note in the notes list.\\\",\\n },\\n body: {\\n type: \\\"string\\\",\\n description: \\\"The new content of the note.\\\",\\n },\\n },\\n required: [\\\"index\\\", \\\"body\\\"],\\n } as JSONSchema,\\n handler: editNoteByIndex({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n navigateToNote: {\\n description: \\\"Navigate to a note by its index in the listNotes() list.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n index: {\\n type: \\\"number\\\",\\n description: \\\"The index of the note in the notes list.\\\",\\n },\\n },\\n required: [\\\"index\\\"],\\n } as JSONSchema,\\n handler: navigateToNote({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n newNote: {\\n description: \\\"Read the shared note.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n title: {\\n type: \\\"string\\\",\\n description: \\\"The title of the note.\\\",\\n },\\n content: {\\n type: \\\"string\\\",\\n description: \\\"The content of the note.\\\",\\n },\\n },\\n required: [\\\"title\\\"],\\n } as JSONSchema,\\n handler: newNote({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n };\\n\\n const chat = Chat({ messages, tools });\\n const note = Note({ title, content, allCharms });\\n\\n return {\\n [NAME]: title,\\n chat,\\n note,\\n content,\\n messages,\\n mentioned: note.mentioned,\\n backlinks: note.backlinks,\\n list,\\n };\\n },\\n);\\n\"},{\"name\":\"/note.tsx\",\"contents\":\"/// \\nimport {\\n Cell,\\n cell,\\n Default,\\n derive,\\n h,\\n handler,\\n lift,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n toSchema,\\n UI,\\n} from \\\"commontools\\\";\\n\\nexport type MentionableCharm = {\\n [NAME]: string;\\n content?: string;\\n mentioned?: MentionableCharm[];\\n};\\n\\ntype Input = {\\n title: Default;\\n content: Default;\\n allCharms: Cell;\\n};\\n\\ntype Output = {\\n mentioned: Default, []>;\\n content: Default;\\n backlinks: Default, []>;\\n};\\n\\nconst updateTitle = handler<\\n { detail: { value: string } },\\n { title: Cell }\\n>(\\n (event, state) => {\\n state.title.set(event.detail?.value ?? \\\"\\\");\\n },\\n);\\n\\nconst updateContent = handler<\\n { detail: { value: string } },\\n { content: Cell }\\n>(\\n (event, state) => {\\n state.content.set(event.detail?.value ?? \\\"\\\");\\n },\\n);\\n\\nconst handleCharmLinkClick = handler<\\n {\\n detail: {\\n charm: Cell;\\n };\\n },\\n Record\\n>(({ detail }, _) => {\\n return navigateTo(detail.charm);\\n});\\n\\nconst handleNewBacklink = handler<\\n {\\n detail: {\\n text: string;\\n charmId: any;\\n charm: Cell;\\n navigate: boolean;\\n };\\n },\\n {\\n allCharms: Cell;\\n }\\n>(({ detail }, { allCharms }) => {\\n console.log(\\\"new charm\\\", detail.text, detail.charmId);\\n\\n if (detail.navigate) {\\n return navigateTo(detail.charm);\\n } else {\\n allCharms.push(detail.charm as unknown as MentionableCharm);\\n }\\n});\\n\\nconst handleCharmLinkClicked = handler(\\n (_: any, { charm }: { charm: Cell }) => {\\n return navigateTo(charm);\\n },\\n);\\n\\nconst Note = recipe(\\n \\\"Note\\\",\\n ({ title, content, allCharms }) => {\\n const mentioned = cell([]);\\n\\n const computeBacklinks = lift<\\n { allCharms: Cell; content: Cell },\\n MentionableCharm[]\\n >(\\n ({ allCharms, content }) => {\\n const cs = allCharms.get();\\n if (!cs) return [];\\n\\n const self = cs.find((c) => c.content === content.get());\\n\\n const results = self\\n ? cs.filter((c) =>\\n c.mentioned?.some((m) => m.content === self.content) ?? false\\n )\\n : [];\\n\\n return results;\\n },\\n );\\n\\n const backlinks: OpaqueRef = computeBacklinks({\\n allCharms,\\n content: content as unknown as Cell, // TODO(bf): this is valid, but types complain\\n });\\n\\n // The only way to serialize a pattern, apparently?\\n const pattern = derive(undefined, () => JSON.stringify(Note));\\n\\n return {\\n [NAME]: title,\\n [UI]: (\\n \\n
\\n \\n
\\n\\n \\n
\\n ),\\n title,\\n content,\\n mentioned,\\n backlinks,\\n };\\n },\\n);\\n\\nexport default Note;\\n\"},{\"name\":\"/chatbot-list-view.tsx\",\"contents\":\"/// \\nimport {\\n Cell,\\n cell,\\n Default,\\n derive,\\n h,\\n handler,\\n ID,\\n ifElse,\\n lift,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n toSchema,\\n UI,\\n} from \\\"commontools\\\";\\n\\nimport Chat from \\\"./chatbot-note-composed.tsx\\\";\\nimport { ListItem } from \\\"./common-tools.tsx\\\";\\n\\nexport type MentionableCharm = {\\n [NAME]: string;\\n content?: string;\\n mentioned?: MentionableCharm[];\\n};\\n\\ntype CharmEntry = {\\n [ID]: string; // randomId is a string\\n local_id: string; // same as ID but easier to access\\n charm: any;\\n};\\n\\ntype Input = {\\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\\n charmsList: Default;\\n allCharms: Cell;\\n theme?: {\\n accentColor: Default;\\n fontFace: Default;\\n borderRadius: Default;\\n };\\n};\\n\\ntype Output = {\\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\\n};\\n\\nconst removeChat = handler<\\n unknown,\\n {\\n charmsList: Cell;\\n id: string;\\n selectedCharm: Cell>;\\n }\\n>(\\n (\\n _,\\n { charmsList, id, selectedCharm },\\n ) => {\\n const list = charmsList.get();\\n const index = list.findIndex((entry) => entry.local_id === id);\\n if (index === -1) return;\\n\\n const removed = list[index];\\n const next = [...list];\\n next.splice(index, 1);\\n charmsList.set(next);\\n\\n // If we removed the currently selected charm, choose a new selection.\\n const current = selectedCharm.get();\\n if (current?.charm === removed.charm) {\\n const replacement = next[index] ?? next[index - 1];\\n if (replacement) {\\n selectedCharm.set({ charm: replacement.charm });\\n } else {\\n selectedCharm.set({ charm: undefined as unknown as any });\\n }\\n }\\n },\\n);\\n\\n// this will be called whenever charm or selectedCharm changes\\n// pass isInitialized to make sure we dont call this each time\\n// we change selectedCharm, otherwise creates a loop\\nconst storeCharm = lift(\\n toSchema<{\\n charm: any;\\n selectedCharm: Cell>;\\n charmsList: Cell;\\n allCharms: Cell;\\n theme?: {\\n accentColor: Default;\\n fontFace: Default;\\n borderRadius: Default;\\n };\\n isInitialized: Cell;\\n }>(),\\n undefined,\\n ({ charm, selectedCharm, charmsList, isInitialized, allCharms }) => { // Not including `allCharms` is a compile error...\\n if (!isInitialized.get()) {\\n console.log(\\n \\\"storeCharm storing charm:\\\",\\n charm,\\n );\\n selectedCharm.set({ charm });\\n\\n // create the chat charm with a custom name including a random suffix\\n const randomId = Math.random().toString(36).substring(2, 10); // Random 8-char string\\n charmsList.push({ [ID]: randomId, local_id: randomId, charm });\\n\\n isInitialized.set(true);\\n return charm;\\n } else {\\n console.log(\\\"storeCharm: already initialized\\\");\\n }\\n return undefined;\\n },\\n);\\n\\nconst populateChatList = lift(\\n toSchema<{\\n charmsList: CharmEntry[];\\n allCharms: Cell;\\n selectedCharm: Cell<{ charm: any }>;\\n }>(),\\n undefined,\\n (\\n { charmsList, allCharms, selectedCharm },\\n ) => {\\n if (charmsList.length === 0) {\\n const isInitialized = cell(false);\\n return storeCharm({\\n charm: Chat({\\n title: \\\"New Chat\\\",\\n messages: [],\\n content: \\\"\\\",\\n allCharms,\\n }),\\n selectedCharm,\\n charmsList,\\n allCharms,\\n isInitialized: isInitialized as unknown as Cell,\\n });\\n }\\n\\n return charmsList;\\n },\\n);\\n\\nconst createChatRecipe = handler<\\n unknown,\\n {\\n selectedCharm: Cell<{ charm: any }>;\\n charmsList: Cell;\\n allCharms: Cell;\\n }\\n>(\\n (_, { selectedCharm, charmsList, allCharms }) => {\\n const isInitialized = cell(false);\\n\\n const charm = Chat({\\n title: \\\"New Chat\\\",\\n messages: [],\\n content: \\\"\\\",\\n allCharms,\\n });\\n // store the charm ref in a cell (pass isInitialized to prevent recursive calls)\\n return storeCharm({\\n charm,\\n selectedCharm,\\n charmsList: charmsList as unknown as OpaqueRef,\\n allCharms,\\n isInitialized: isInitialized as unknown as Cell,\\n });\\n },\\n);\\n\\nconst selectCharm = handler<\\n unknown,\\n { selectedCharm: Cell<{ charm: any }>; charm: any }\\n>(\\n (_, { selectedCharm, charm }) => {\\n console.log(\\\"selectCharm: updating selectedCharm to \\\", charm);\\n selectedCharm.set({ charm });\\n return selectedCharm;\\n },\\n);\\n\\nconst logCharmsList = lift<\\n { charmsList: Cell },\\n Cell\\n>(\\n ({ charmsList }) => {\\n console.log(\\\"logCharmsList: \\\", charmsList.get());\\n return charmsList;\\n },\\n);\\n\\nconst handleCharmLinkClicked = handler(\\n (_: any, { charm }: { charm: Cell }) => {\\n return navigateTo(charm);\\n },\\n);\\n\\nconst combineLists = lift(\\n (\\n { allCharms, charmsList }: { allCharms: any[]; charmsList: CharmEntry[] },\\n ) => {\\n return [...charmsList.map((c) => c.charm), ...allCharms];\\n },\\n);\\n\\nconst getSelectedCharm = lift<\\n { entry: { charm: any | undefined } },\\n {\\n chat: unknown;\\n note: unknown;\\n list: ListItem[];\\n backlinks: MentionableCharm[];\\n mentioned: MentionableCharm[];\\n } | undefined\\n>(\\n ({ entry }) => {\\n return entry?.charm;\\n },\\n);\\n\\nconst getCharmName = lift(({ charm }: { charm: any }) => {\\n return charm?.[NAME] || \\\"Unknown\\\";\\n});\\n\\n// create the named cell inside the recipe body, so we do it just once\\nexport default recipe(\\n \\\"Launcher\\\",\\n ({ selectedCharm, charmsList, allCharms, theme }) => {\\n logCharmsList({ charmsList: charmsList as unknown as Cell });\\n\\n populateChatList({\\n selectedCharm: selectedCharm as unknown as Cell<\\n Pick\\n >,\\n charmsList,\\n allCharms,\\n });\\n\\n const combined = combineLists({\\n allCharms: allCharms as unknown as any[],\\n charmsList,\\n });\\n\\n const selected = getSelectedCharm({ entry: selectedCharm });\\n\\n const localTheme = theme ?? {\\n accentColor: cell(\\\"#3b82f6\\\"),\\n fontFace: cell(\\\"system-ui, -apple-system, sans-serif\\\"),\\n borderRadius: cell(\\\"0.5rem\\\"),\\n };\\n\\n return {\\n [NAME]: \\\"Launcher\\\",\\n [UI]: (\\n \\n \\n
\\n \\n
\\n \\n Create New Chat\\n alt+N\\n \\n
\\n
\\n\\n {/* Keyboard shortcuts */}\\n \\n
\\n \\n {/* workaround: this seems to correctly start the sub-recipes on a refresh while directly rendering does not */}\\n {/* this should be fixed after the builder-refactor (DX1) */}\\n \\n \\n \\n \\n \\n \\n\\n \\n\\n \\n \\n
\\n
\\n ),\\n selectedCharm,\\n charmsList,\\n };\\n },\\n);\\n\"},{\"name\":\"/common-tools.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n BuiltInLLMTool,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n h,\\n handler,\\n ifElse,\\n llmDialog,\\n NAME,\\n recipe,\\n Stream,\\n UI,\\n} from \\\"commontools\\\";\\n\\n///// COMMON TOOLS (get it?) ////\\n\\n/**\\n * Calculate the result of a mathematical expression.\\n * Supports +, -, *, /, and parentheses.\\n */\\ntype CalculatorRequest = {\\n /** The mathematical expression to evaluate. */\\n expression: string;\\n};\\n\\nexport const calculator = recipe<\\n CalculatorRequest,\\n string | { error: string }\\n>(\\\"Calculator\\\", ({ expression }) => {\\n return derive(expression, (expr) => {\\n const sanitized = expr.replace(/[^0-9+\\\\-*/().\\\\s]/g, \\\"\\\");\\n let result;\\n try {\\n result = Function(`\\\"use strict\\\"; return (${sanitized})`)();\\n } catch (error) {\\n result = { error: (error as any)?.message || \\\"\\\" };\\n }\\n return result;\\n });\\n});\\n\\n/** Add an item to the list. */\\ntype AddListItemRequest = {\\n /** The item to add to the list. */\\n item: string;\\n result: Cell;\\n};\\n\\n/** Read all items from the list. */\\ntype ReadListItemsRequest = {\\n result: Cell;\\n};\\n\\nexport type ListItem = {\\n title: string;\\n};\\n\\nexport const addListItem = handler<\\n AddListItemRequest,\\n { list: Cell }\\n>(\\n (args, state) => {\\n try {\\n state.list.push({ title: args.item });\\n args.result.set(`${state.list.get().length} items`);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nexport const readListItems = handler<\\n ReadListItemsRequest,\\n { list: ListItem[] }\\n>(\\n (args, state) => {\\n try {\\n const items = state.list;\\n if (items.length === 0) {\\n args.result.set(\\\"The list is empty\\\");\\n } else {\\n const itemList = items.map((item, index) =>\\n `${index + 1}. ${item.title}`\\n ).join(\\\"\\\\n\\\");\\n args.result.set(`List items (${items.length} total):\\\\n${itemList}`);\\n }\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\n/** Search the web for information. */\\ntype SearchQuery = {\\n /** The query to search the web for. */\\n query: string;\\n};\\n\\ntype SearchWebResult = {\\n results: {\\n title: string;\\n url: string;\\n description: string;\\n }[];\\n};\\n\\nexport const searchWeb = recipe<\\n SearchQuery,\\n SearchWebResult | { error: string }\\n>(\\\"Search Web\\\", ({ query }) => {\\n const { result, error } = fetchData({\\n url: \\\"/api/agent-tools/web-search\\\",\\n mode: \\\"json\\\",\\n options: {\\n method: \\\"POST\\\",\\n headers: {\\n \\\"Content-Type\\\": \\\"application/json\\\",\\n },\\n body: {\\n query,\\n max_results: 5,\\n },\\n },\\n });\\n\\n // TODO(seefeld): Should we instead return { result, error }? Or allocate a\\n // special [ERROR] for errors? Ideally this isn\\'t specific to using recipes as\\n // tools but a general pattern.\\n return ifElse(error, { error }, result);\\n});\\n\\n/** Read and extract content from a specific webpage URL. */\\ntype ReadWebRequest = {\\n /** The URL of the webpage to read and extract content from. */\\n url: string;\\n};\\n\\ntype ReadWebResult = {\\n content: string;\\n metadata: {\\n title?: string;\\n author?: string;\\n date?: string;\\n word_count: number;\\n };\\n};\\n\\nexport const readWebpage = recipe<\\n ReadWebRequest,\\n ReadWebResult | { error: string }\\n>(\\\"Read Webpage\\\", ({ url }) => {\\n const { result, error } = fetchData({\\n url: \\\"/api/agent-tools/web-read\\\",\\n mode: \\\"json\\\",\\n options: {\\n method: \\\"POST\\\",\\n headers: {\\n \\\"Content-Type\\\": \\\"application/json\\\",\\n },\\n body: {\\n url,\\n max_tokens: 4000,\\n include_code: true,\\n },\\n },\\n });\\n\\n return ifElse(error, { error }, result);\\n});\\n\\ntype ToolsInput = {\\n list: ListItem[];\\n};\\n\\nexport default recipe(\\\"Tools\\\", ({ list }) => {\\n const tools: Record = {\\n search_web: {\\n pattern: searchWeb,\\n },\\n read_webpage: {\\n pattern: readWebpage,\\n },\\n calculator: {\\n pattern: calculator,\\n },\\n addListItem: {\\n handler: addListItem({ list }),\\n },\\n };\\n\\n return { tools, list };\\n});\\n\"}]}}" }, "spell": { "/": { "link@1": { "id": "of:baedreic5vwrifhgsveszaoiglpnwpg6muauspvb7lkbehia7oltjqtmeby" } } }, "argument": { "title": "two", "content": "", "allCharms": { "/": { "link@1": { "path": [], "id": "of:baedreiahv63wxwgaem4hzjkizl4qncfgvca7pj5cvdon7cukumfon3ioye", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } } } } }, "since": 68 } } }, "of:baedreibyolwzasa3njbwrwexvtolf7b7x5wh5lkwkepa5jbc6paghoc5ua": { "application/json": { "ba4jcb2fusnk5k3fqwratg45ikswtstfp6rriopkqfvtozfxfjs6qnbkj": { "is": { "source": { "/": "baedreie554qgkdxesjzgkmhtmqlengrcyrlacfwjypvsguhxnm6ks6jbba" }, "value": { "$NAME": { "$alias": { "path": [ "argument", "title" ], "schema": { "type": "string", "default": "Untitled Note" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreie554qgkdxesjzgkmhtmqlengrcyrlacfwjypvsguhxnm6ks6jbba" } } }, "$UI": { "type": "vnode", "name": "ct-screen", "props": { }, "children": [ { "type": "vnode", "name": "div", "props": { "slot": "header" }, "children": [ { "type": "vnode", "name": "ct-input", "props": { "$value": { "$alias": { "path": [ "argument", "title" ], "schema": { "type": "string", "default": "Untitled Note" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreie554qgkdxesjzgkmhtmqlengrcyrlacfwjypvsguhxnm6ks6jbba" } } }, "placeholder": "Enter title..." }, "children": [] } ] }, { "type": "vnode", "name": "ct-code-editor", "props": { "$value": { "$alias": { "path": [ "argument", "content" ], "schema": { "type": "string", "default": "" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreie554qgkdxesjzgkmhtmqlengrcyrlacfwjypvsguhxnm6ks6jbba" } } }, "$mentionable": { "$alias": { "path": [ "argument", "allCharms" ], "schema": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreie554qgkdxesjzgkmhtmqlengrcyrlacfwjypvsguhxnm6ks6jbba" } } }, "$mentioned": { "$alias": { "path": [ "internal", "mentioned" ], "cell": { "/": "baedreie554qgkdxesjzgkmhtmqlengrcyrlacfwjypvsguhxnm6ks6jbba" } } }, "$pattern": { "$alias": { "path": [ "internal", "__#0" ], "cell": { "/": "baedreie554qgkdxesjzgkmhtmqlengrcyrlacfwjypvsguhxnm6ks6jbba" } } }, "onbacklink-click": { "$alias": { "path": [ "internal", "__#1stream" ], "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "charm": { "$ref": "#/$defs/MentionableCharm" } }, "required": [ "charm" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "charm": { "$ref": "#/$defs/MentionableCharm" } }, "required": [ "charm" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreie554qgkdxesjzgkmhtmqlengrcyrlacfwjypvsguhxnm6ks6jbba" } } }, "onbacklink-create": { "$alias": { "path": [ "internal", "$event" ], "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "text": { "type": "string" }, "charmId": true, "charm": { "$ref": "#/$defs/MentionableCharm" }, "navigate": { "type": "boolean" } }, "required": [ "text", "charmId", "charm", "navigate" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "text": { "type": "string" }, "charmId": true, "charm": { "$ref": "#/$defs/MentionableCharm" }, "navigate": { "type": "boolean" } }, "required": [ "text", "charmId", "charm", "navigate" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreie554qgkdxesjzgkmhtmqlengrcyrlacfwjypvsguhxnm6ks6jbba" } } }, "language": "text/markdown", "theme": "light", "wordWrap": true, "tabIndent": true, "lineNumbers": true }, "children": [] } ] }, "title": { "$alias": { "path": [ "argument", "title" ], "schema": { "type": "string", "default": "Untitled Note" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreie554qgkdxesjzgkmhtmqlengrcyrlacfwjypvsguhxnm6ks6jbba" } } }, "content": { "$alias": { "path": [ "argument", "content" ], "schema": { "type": "string", "default": "" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreie554qgkdxesjzgkmhtmqlengrcyrlacfwjypvsguhxnm6ks6jbba" } } }, "mentioned": { "$alias": { "path": [ "internal", "mentioned" ], "cell": { "/": "baedreie554qgkdxesjzgkmhtmqlengrcyrlacfwjypvsguhxnm6ks6jbba" } } }, "backlinks": { "$alias": { "path": [ "internal", "backlinks" ], "cell": { "/": "baedreie554qgkdxesjzgkmhtmqlengrcyrlacfwjypvsguhxnm6ks6jbba" } } } } }, "since": 77 } } }, "of:baedreie554qgkdxesjzgkmhtmqlengrcyrlacfwjypvsguhxnm6ks6jbba": { "application/json": { "ba4jcaolgecob2y7rq4tl7ktp43oky2ghk2jujoxqwznbaxgekqs3msks": { "is": { "value": { "$TYPE": "ba4jcb5fkie7blry4u2wchwaog45dpfdwrpmrklu2zlndduvgd7dhc2ks", "resultRef": { "/": { "link@1": { "path": [], "id": "of:baedreibyolwzasa3njbwrwexvtolf7b7x5wh5lkwkepa5jbc6paghoc5ua" } } }, "internal": { "$event": { "$stream": true }, "mentioned": [], "__#1stream": { "$stream": true }, "backlinks": [], "__#0": "{\"argumentSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"resultSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"default\":[]},\"content\":{\"type\":\"string\",\"default\":\"\"},\"backlinks\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"default\":[]}},\"required\":[\"mentioned\",\"content\",\"backlinks\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"initial\":{\"internal\":{\"$event\":{\"$stream\":true},\"mentioned\":[],\"__#1stream\":{\"$stream\":true}}},\"result\":{\"$NAME\":{\"$alias\":{\"path\":[\"argument\",\"title\"],\"schema\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"$UI\":{\"type\":\"vnode\",\"name\":\"ct-screen\",\"props\":{},\"children\":[{\"type\":\"vnode\",\"name\":\"div\",\"props\":{\"slot\":\"header\"},\"children\":[{\"type\":\"vnode\",\"name\":\"ct-input\",\"props\":{\"$value\":{\"$alias\":{\"path\":[\"argument\",\"title\"],\"schema\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"placeholder\":\"Enter title...\"},\"children\":[]}]},{\"type\":\"vnode\",\"name\":\"ct-code-editor\",\"props\":{\"$value\":{\"$alias\":{\"path\":[\"argument\",\"content\"],\"schema\":{\"type\":\"string\",\"default\":\"\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"$mentionable\":{\"$alias\":{\"path\":[\"argument\",\"allCharms\"],\"schema\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"$mentioned\":{\"$alias\":{\"path\":[\"internal\",\"mentioned\"]}},\"$pattern\":{\"$alias\":{\"path\":[\"internal\",\"__#0\"]}},\"onbacklink-click\":{\"$alias\":{\"path\":[\"internal\",\"__#1stream\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"onbacklink-create\":{\"$alias\":{\"path\":[\"internal\",\"$event\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"language\":\"text/markdown\",\"theme\":\"light\",\"wordWrap\":true,\"tabIndent\":true,\"lineNumbers\":true},\"children\":[]}]},\"title\":{\"$alias\":{\"path\":[\"argument\",\"title\"],\"schema\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"content\":{\"$alias\":{\"path\":[\"argument\",\"content\"],\"schema\":{\"type\":\"string\",\"default\":\"\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"mentioned\":{\"$alias\":{\"path\":[\"internal\",\"mentioned\"]}},\"backlinks\":{\"$alias\":{\"path\":[\"internal\",\"backlinks\"]}}},\"nodes\":[{\"module\":{\"type\":\"javascript\",\"implementation\":\"({ allCharms, content }) => {\\n const cs = allCharms.get();\\n if (!cs)\\n return [];\\n const self = cs.find((c) => c.content === content.get());\\n const results = self\\n ? cs.filter((c) => c.mentioned?.some((m) => m.content === self.content) ?? false)\\n : [];\\n return results;\\n }\",\"argumentSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"asCell\":true},\"content\":{\"type\":\"string\",\"asCell\":true}},\"required\":[\"allCharms\",\"content\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"resultSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"$ref\":\"#/$defs/AnonymousType_1\",\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}},\"inputs\":{\"allCharms\":{\"$alias\":{\"path\":[\"argument\",\"allCharms\"],\"schema\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"content\":{\"$alias\":{\"path\":[\"argument\",\"content\"],\"schema\":{\"type\":\"string\",\"default\":\"\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"outputs\":{\"$alias\":{\"path\":[\"internal\",\"backlinks\"]}}},{\"module\":{\"type\":\"javascript\",\"implementation\":\"({ detail }, { allCharms }) => {\\n console.log(\\\"new charm\\\", detail.text, detail.charmId);\\n if (detail.navigate) {\\n return (0, commontools_5.navigateTo)(detail.charm);\\n }\\n else {\\n allCharms.push(detail.charm);\\n }\\n }\",\"wrapper\":\"handler\",\"argumentSchema\":{\"type\":\"object\",\"properties\":{\"$event\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\",\"asCell\":true},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"]},\"$ctx\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"asCell\":true}},\"required\":[\"allCharms\"]}},\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]},\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}}}}},\"inputs\":{\"$ctx\":{\"allCharms\":{\"$alias\":{\"path\":[\"argument\",\"allCharms\"],\"schema\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"$event\":{\"$alias\":{\"path\":[\"internal\",\"$event\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"outputs\":{}},{\"module\":{\"type\":\"javascript\",\"implementation\":\"() => JSON.stringify(Note)\",\"argumentSchema\":true,\"resultSchema\":{\"type\":\"string\"}},\"outputs\":{\"$alias\":{\"path\":[\"internal\",\"__#0\"]}}},{\"module\":{\"type\":\"javascript\",\"implementation\":\"({ detail }, _) => {\\n return (0, commontools_5.navigateTo)(detail.charm);\\n }\",\"wrapper\":\"handler\",\"argumentSchema\":{\"type\":\"object\",\"properties\":{\"$event\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\",\"asCell\":true}},\"required\":[\"charm\"]}},\"required\":[\"detail\"]},\"$ctx\":{\"type\":\"object\",\"properties\":{},\"additionalProperties\":false}},\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}},\"inputs\":{\"$ctx\":{},\"$event\":{\"$alias\":{\"path\":[\"internal\",\"__#1stream\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"outputs\":{}}],\"program\":{\"main\":\"/note.tsx\",\"mainExport\":\"default\",\"files\":[{\"name\":\"/default-app.tsx\",\"contents\":\"/// \\nimport {\\n Cell,\\n Default,\\n derive,\\n h,\\n handler,\\n NAME,\\n navigateTo,\\n Opaque,\\n OpaqueRef,\\n recipe,\\n str,\\n UI,\\n} from \\\"commontools\\\";\\n\\n// Import recipes we want to be launchable from the default app.\\nimport Chatbot from \\\"./chatbot.tsx\\\";\\nimport ChatbotOutliner from \\\"./chatbot-outliner.tsx\\\";\\nimport { type MentionableCharm } from \\\"./chatbot-note-composed.tsx\\\";\\nimport { default as Note } from \\\"./note.tsx\\\";\\nimport ChatList from \\\"./chatbot-list-view.tsx\\\";\\n\\nexport type Charm = {\\n [NAME]?: string;\\n [UI]?: unknown;\\n [key: string]: any;\\n};\\n\\ntype CharmsListInput = {\\n allCharms: Default;\\n};\\n\\n// Recipe returns only UI, no data outputs (only symbol properties)\\ninterface CharmsListOutput {\\n [key: string]: unknown;\\n}\\n\\nconst visit = handler<\\n Record,\\n { charm: any }\\n>((_, state) => {\\n return navigateTo(state.charm);\\n}, { proxy: true });\\n\\nconst removeCharm = handler<\\n Record,\\n {\\n charm: any;\\n allCharms: Cell;\\n }\\n>((_, state) => {\\n const charmName = state.charm[NAME];\\n const allCharmsValue = state.allCharms.get();\\n const index = allCharmsValue.findIndex((c: any) => c[NAME] === charmName);\\n\\n if (index !== -1) {\\n const charmListCopy = [...allCharmsValue];\\n console.log(\\\"charmListCopy before\\\", charmListCopy);\\n charmListCopy.splice(index, 1);\\n console.log(\\\"charmListCopy after\\\", charmListCopy);\\n state.allCharms.set(charmListCopy);\\n }\\n});\\n\\nconst spawnChatList = handler<\\n Record,\\n { allCharms: Cell }\\n>((_, state) => {\\n return navigateTo(ChatList({\\n selectedCharm: { charm: undefined },\\n charmsList: [],\\n allCharms: state.allCharms, // we should handle empty here\\n }));\\n});\\n\\nconst spawnChatbot = handler<\\n Record,\\n Record\\n>((_, state) => {\\n return navigateTo(Chatbot({\\n messages: [],\\n tools: undefined,\\n }));\\n});\\n\\nconst spawnChatbotOutliner = handler<\\n Record,\\n { allCharms: Cell }\\n>((_, state) => {\\n return navigateTo(ChatbotOutliner({\\n title: \\\"Chatbot Outliner\\\",\\n expandChat: false,\\n messages: [],\\n outline: {\\n root: { body: \\\"\\\", children: [], attachments: [] },\\n },\\n allCharms: state.allCharms,\\n }));\\n});\\n\\nconst spawnNote = handler<\\n Record,\\n { allCharms: Cell }\\n>((_, state) => {\\n return navigateTo(Note({\\n title: \\\"New Note\\\",\\n content: \\\"\\\",\\n allCharms: state.allCharms,\\n }));\\n});\\n\\nexport default recipe(\\n \\\"DefaultCharmList\\\",\\n ({ allCharms }) => {\\n return {\\n [NAME]: str`DefaultCharmList (${allCharms.length})`,\\n [UI]: (\\n \\n ,\\n })}\\n />\\n\\n \\n {/* Quick Launch Toolbar */}\\n \\n

Quicklaunch:

\\n ,\\n })}\\n >\\n 📂 Chat List\\n \\n \\n 💬 Chatbot\\n \\n \\n 📝 Chatbot Outliner\\n \\n ,\\n })}\\n >\\n 📄 Note\\n \\n
\\n\\n

Charms ({allCharms.length})

\\n\\n \\n \\n \\n Charm Name\\n Actions\\n \\n \\n \\n {derive(allCharms, (allCharms) =>\\n allCharms.map((charm: any) => (\\n \\n {charm[NAME] || \\\"Untitled Charm\\\"}\\n \\n \\n \\n Visit\\n \\n \\n Remove\\n \\n \\n \\n \\n )))}\\n \\n \\n
\\n
\\n ),\\n };\\n },\\n);\\n\"},{\"name\":\"/chatbot.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n generateObject,\\n h,\\n handler,\\n ifElse,\\n JSONSchema,\\n lift,\\n llm,\\n llmDialog,\\n NAME,\\n recipe,\\n str,\\n Stream,\\n UI,\\n} from \\\"commontools\\\";\\n\\nconst sendMessage = handler<\\n { detail: { message: string } },\\n {\\n addMessage: Stream;\\n }\\n>((event, { addMessage }) => {\\n addMessage.send({\\n role: \\\"user\\\",\\n content: [{ type: \\\"text\\\", text: event.detail.message }],\\n });\\n});\\n\\nconst clearChat = handler(\\n (\\n _: never,\\n { messages, pending }: {\\n messages: Cell>;\\n pending: Cell;\\n },\\n ) => {\\n messages.set([]);\\n pending.set(false);\\n },\\n);\\n\\ntype ChatInput = {\\n messages: Default, []>;\\n tools: any;\\n theme?: any;\\n};\\n\\ntype ChatOutput = {\\n messages: Array;\\n pending: boolean | undefined;\\n addMessage: Stream;\\n cancelGeneration: Stream;\\n title?: string;\\n};\\n\\nexport const TitleGenerator = recipe<\\n { model?: string; messages: Array }\\n>(\\\"Title Generator\\\", ({ model, messages }) => {\\n const titleMessages = derive(messages, (m) => {\\n if (!m || m.length === 0) return \\\"\\\";\\n\\n const messageCount = 2;\\n const selectedMessages = m.slice(0, messageCount).filter(Boolean);\\n\\n if (selectedMessages.length === 0) return \\\"\\\";\\n\\n return selectedMessages.map((msg) => JSON.stringify(msg)).join(\\\"\\\\n\\\");\\n });\\n\\n const { result } = generateObject({\\n system:\\n \\\"Generate at most a 3-word title based on the following content, respond with NOTHING but the literal title text.\\\",\\n prompt: titleMessages,\\n model,\\n schema: {\\n type: \\\"object\\\",\\n properties: {\\n title: {\\n type: \\\"string\\\",\\n description: \\\"The title of the chat\\\",\\n },\\n },\\n required: [\\\"title\\\"],\\n },\\n });\\n\\n const title = derive(result, (t) => {\\n return t?.title || \\\"Untitled Chat\\\";\\n });\\n\\n return title;\\n});\\n\\nexport default recipe(\\n \\\"Chat\\\",\\n ({ messages, tools, theme }) => {\\n const model = cell(\\\"anthropic:claude-sonnet-4-5\\\");\\n\\n const { addMessage, cancelGeneration, pending } = llmDialog({\\n system: \\\"You are a helpful assistant with some tools.\\\",\\n messages,\\n tools,\\n model,\\n });\\n\\n const { result } = fetchData({\\n url: \\\"/api/ai/llm/models\\\",\\n mode: \\\"json\\\",\\n });\\n\\n const items = derive(result, (models) => {\\n if (!models) return [];\\n const items = Object.keys(models as any).map((key) => ({\\n label: key,\\n value: key,\\n }));\\n return items;\\n });\\n\\n const title = TitleGenerator({ model, messages });\\n\\n return {\\n [NAME]: title,\\n [UI]: (\\n \\n \\n {title}\\n \\n \\n\\n \\n \\n \\n\\n
\\n \\n \\n
\\n
\\n ),\\n messages,\\n pending,\\n addMessage,\\n cancelGeneration,\\n title,\\n };\\n },\\n);\\n\"},{\"name\":\"/chatbot-outliner.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n getRecipeEnvironment,\\n h,\\n handler,\\n ID,\\n ifElse,\\n JSONSchema,\\n lift,\\n llm,\\n llmDialog,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n str,\\n Stream,\\n UI,\\n} from \\\"commontools\\\";\\n\\nimport Chat from \\\"./chatbot.tsx\\\";\\n\\ntype Charm = any;\\n\\ntype OutlinerNode = {\\n body: Default;\\n children: Default;\\n attachments: Default[], []>;\\n};\\n\\ntype Outliner = {\\n root: OutlinerNode;\\n};\\n\\ntype PageResult = {\\n outline: Default<\\n Outliner,\\n { root: { body: \\\"\\\"; children: []; attachments: [] } }\\n >;\\n};\\n\\nexport type PageInput = {\\n outline: Outliner;\\n allCharms: Cell;\\n};\\n\\nconst handleCharmLinkClick = handler<\\n {\\n detail: {\\n charm: Cell;\\n };\\n },\\n Record\\n>(({ detail }, _) => {\\n return navigateTo(detail.charm);\\n});\\n\\nexport const Page = recipe(\\n \\\"Page\\\",\\n ({ outline, allCharms }) => {\\n return {\\n [NAME]: \\\"Page\\\",\\n [UI]: (\\n \\n ),\\n outline,\\n };\\n },\\n);\\n\\ntype LLMTestInput = {\\n title: Default;\\n messages: Default, []>;\\n expandChat: Default;\\n outline: Default<\\n Outliner,\\n { root: { body: \\\"Untitled Page\\\"; children: []; attachments: [] } }\\n >;\\n allCharms: Cell;\\n};\\n\\ntype LLMTestResult = {\\n messages: Default, []>;\\n};\\n\\n// put a node at the end of the outline (by appending to root.children)\\nconst appendOutlinerNode = handler<\\n {\\n /** The text content/title of the outliner node to be appended */\\n body: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { outline: Cell }\\n>(\\n (args, state) => {\\n try {\\n (state.outline.key(\\\"root\\\").key(\\\"children\\\")).push({\\n body: args.body,\\n children: [],\\n attachments: [],\\n });\\n\\n args.result.set(\\n `${state.outline.key(\\\"root\\\").key(\\\"children\\\").get().length} nodes`,\\n );\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nexport default recipe(\\n \\\"Outliner\\\",\\n ({ title, expandChat, messages, outline, allCharms }) => {\\n const tools = {\\n appendOutlinerNode: {\\n description: \\\"Add a new outliner node.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n body: {\\n type: \\\"string\\\",\\n description: \\\"The title of the new node.\\\",\\n },\\n },\\n required: [\\\"body\\\"],\\n } as JSONSchema,\\n handler: appendOutlinerNode({ outline }),\\n },\\n };\\n\\n const chat = Chat({ messages, tools });\\n const { addMessage, cancelGeneration, pending } = chat;\\n\\n return {\\n [NAME]: title,\\n [UI]: (\\n \\n \\n
\\n
\\n Show Chat\\n
\\n
\\n\\n \\n \\n
\\n \\n
\\n\\n \\n \\n \\n \\n \\n
\\n\\n {ifElse(\\n expandChat,\\n chat,\\n null,\\n )}\\n
\\n
\\n ),\\n messages,\\n };\\n },\\n);\\n\"},{\"name\":\"/chatbot-note-composed.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n getRecipeEnvironment,\\n h,\\n handler,\\n ID,\\n ifElse,\\n JSONSchema,\\n lift,\\n llm,\\n llmDialog,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n str,\\n Stream,\\n toSchema,\\n UI,\\n} from \\\"commontools\\\";\\n\\nimport Chat from \\\"./chatbot.tsx\\\";\\nimport Note from \\\"./note.tsx\\\";\\nimport Tools, {\\n addListItem,\\n calculator,\\n ListItem,\\n readListItems,\\n readWebpage,\\n searchWeb,\\n} from \\\"./common-tools.tsx\\\";\\n\\nexport type MentionableCharm = {\\n [NAME]: string;\\n content?: string;\\n mentioned?: MentionableCharm[];\\n};\\n\\n// export type ChatbotNoteInput = {\\n// content: Default;\\n// allCharms?: Cell;\\n// };\\n\\nconst handleCharmLinkClick = handler<\\n {\\n detail: {\\n charm: Cell;\\n };\\n },\\n Record\\n>(({ detail }, _) => {\\n return navigateTo(detail.charm);\\n});\\n\\nconst handleCharmLinkClicked = handler(\\n (_: any, { charm }: { charm: Cell }) => {\\n return navigateTo(charm);\\n },\\n);\\n\\ntype ChatbotNoteInput = {\\n title: Default;\\n messages: Default, []>;\\n content: Default;\\n allCharms: Cell;\\n};\\n\\ntype ChatbotNoteResult = {\\n messages: Default, []>;\\n mentioned: Default, []>;\\n backlinks: Default, []>;\\n content: Default;\\n note: any;\\n chat: any;\\n list: Default;\\n};\\n\\nconst newNote = handler<\\n {\\n /** The text content of the note */\\n title: string;\\n content?: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { allCharms: Cell }\\n>(\\n (args, state) => {\\n try {\\n const n = Note({\\n title: args.title,\\n content: args.content || \\\"\\\",\\n allCharms: state.allCharms,\\n });\\n\\n args.result.set(\\n `Created note ${args.title}!`,\\n );\\n\\n state.allCharms.push(n as unknown as MentionableCharm);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\n// put a note at the end of the outline (by appending to root.children)\\nconst editNote = handler<\\n {\\n /** The text content of the note */\\n body: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { content: Cell }\\n>(\\n (args, state) => {\\n try {\\n state.content.set(args.body);\\n\\n args.result.set(\\n `Updated note!`,\\n );\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst readNote = handler<\\n {\\n /** A cell to store the result text */\\n result: Cell;\\n },\\n { content: string }\\n>(\\n (args, state) => {\\n try {\\n args.result.set(state.content);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst listMentionable = handler<\\n {\\n /** A cell to store the result text */\\n result: Cell;\\n },\\n { allCharms: { [NAME]: string }[] }\\n>(\\n (args, state) => {\\n try {\\n const namesList = state.allCharms.map((charm) => charm[NAME]);\\n args.result.set(JSON.stringify(namesList));\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst readNoteByIndex = handler<\\n {\\n /** A cell to store the result text */\\n index: number;\\n result: Cell;\\n },\\n { allCharms: { [NAME]: string; content?: string }[] }\\n>(\\n (args, state) => {\\n try {\\n args.result.set(\\n state.allCharms[args.index]?.content || \\\"No content found\\\",\\n );\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst editNoteByIndex = handler<\\n {\\n /** The index of the note to edit */\\n index: number;\\n /** The new text content of the note */\\n body: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { allCharms: Cell }\\n>(\\n (args, state) => {\\n try {\\n const charms = state.allCharms.get();\\n if (args.index < 0 || args.index >= charms.length) {\\n args.result.set(`Error: Invalid index ${args.index}`);\\n return;\\n }\\n\\n state.allCharms.key(args.index).key(\\\"content\\\").set(args.body);\\n args.result.set(`Updated note at index ${args.index}!`);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst navigateToNote = handler<\\n {\\n /** The index of the note to navigate to */\\n index: number;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { allCharms: Cell }\\n>(\\n (args, state) => {\\n try {\\n const charms = state.allCharms.get();\\n if (args.index < 0 || args.index >= charms.length) {\\n args.result.set(`Error: Invalid index ${args.index}`);\\n return;\\n }\\n\\n const targetCharm = charms[args.index];\\n args.result.set(`Navigating to note: ${targetCharm[NAME]}`);\\n\\n return navigateTo(state.allCharms.key(args.index));\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nexport default recipe(\\n \\\"Chatbot + Note\\\",\\n ({ title, messages, content, allCharms }) => {\\n const list = cell([]);\\n\\n const tools = {\\n searchWeb: {\\n pattern: searchWeb,\\n },\\n readWebpage: {\\n pattern: readWebpage,\\n },\\n calculator: {\\n pattern: calculator,\\n },\\n addListItem: {\\n handler: addListItem({ list }),\\n },\\n readListItems: {\\n handler: readListItems({ list }),\\n },\\n editActiveNote: {\\n description: \\\"Modify the shared note.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n body: {\\n type: \\\"string\\\",\\n description: \\\"The content of the note.\\\",\\n },\\n },\\n required: [\\\"body\\\"],\\n } as JSONSchema,\\n handler: editNote({ content }),\\n },\\n readActiveNote: {\\n description: \\\"Read the currently focused note.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {},\\n required: [],\\n } as JSONSchema,\\n handler: readNote({ content }),\\n },\\n listNotes: {\\n description:\\n \\\"List all mentionable note titles (read the body with readNoteByIndex).\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {},\\n required: [],\\n } as JSONSchema,\\n handler: listMentionable({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n readNoteByIndex: {\\n description:\\n \\\"Read the body of a note by its index in the listNotes() list.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n index: {\\n type: \\\"number\\\",\\n description: \\\"The index of the note in the notes list.\\\",\\n },\\n },\\n required: [\\\"index\\\"],\\n } as JSONSchema,\\n handler: readNoteByIndex({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n editNoteByIndex: {\\n description:\\n \\\"Edit the body of a note by its index in the listNotes() list.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n index: {\\n type: \\\"number\\\",\\n description: \\\"The index of the note in the notes list.\\\",\\n },\\n body: {\\n type: \\\"string\\\",\\n description: \\\"The new content of the note.\\\",\\n },\\n },\\n required: [\\\"index\\\", \\\"body\\\"],\\n } as JSONSchema,\\n handler: editNoteByIndex({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n navigateToNote: {\\n description: \\\"Navigate to a note by its index in the listNotes() list.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n index: {\\n type: \\\"number\\\",\\n description: \\\"The index of the note in the notes list.\\\",\\n },\\n },\\n required: [\\\"index\\\"],\\n } as JSONSchema,\\n handler: navigateToNote({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n newNote: {\\n description: \\\"Read the shared note.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n title: {\\n type: \\\"string\\\",\\n description: \\\"The title of the note.\\\",\\n },\\n content: {\\n type: \\\"string\\\",\\n description: \\\"The content of the note.\\\",\\n },\\n },\\n required: [\\\"title\\\"],\\n } as JSONSchema,\\n handler: newNote({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n };\\n\\n const chat = Chat({ messages, tools });\\n const note = Note({ title, content, allCharms });\\n\\n return {\\n [NAME]: title,\\n chat,\\n note,\\n content,\\n messages,\\n mentioned: note.mentioned,\\n backlinks: note.backlinks,\\n list,\\n };\\n },\\n);\\n\"},{\"name\":\"/note.tsx\",\"contents\":\"/// \\nimport {\\n Cell,\\n cell,\\n Default,\\n derive,\\n h,\\n handler,\\n lift,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n toSchema,\\n UI,\\n} from \\\"commontools\\\";\\n\\nexport type MentionableCharm = {\\n [NAME]: string;\\n content?: string;\\n mentioned?: MentionableCharm[];\\n};\\n\\ntype Input = {\\n title: Default;\\n content: Default;\\n allCharms: Cell;\\n};\\n\\ntype Output = {\\n mentioned: Default, []>;\\n content: Default;\\n backlinks: Default, []>;\\n};\\n\\nconst updateTitle = handler<\\n { detail: { value: string } },\\n { title: Cell }\\n>(\\n (event, state) => {\\n state.title.set(event.detail?.value ?? \\\"\\\");\\n },\\n);\\n\\nconst updateContent = handler<\\n { detail: { value: string } },\\n { content: Cell }\\n>(\\n (event, state) => {\\n state.content.set(event.detail?.value ?? \\\"\\\");\\n },\\n);\\n\\nconst handleCharmLinkClick = handler<\\n {\\n detail: {\\n charm: Cell;\\n };\\n },\\n Record\\n>(({ detail }, _) => {\\n return navigateTo(detail.charm);\\n});\\n\\nconst handleNewBacklink = handler<\\n {\\n detail: {\\n text: string;\\n charmId: any;\\n charm: Cell;\\n navigate: boolean;\\n };\\n },\\n {\\n allCharms: Cell;\\n }\\n>(({ detail }, { allCharms }) => {\\n console.log(\\\"new charm\\\", detail.text, detail.charmId);\\n\\n if (detail.navigate) {\\n return navigateTo(detail.charm);\\n } else {\\n allCharms.push(detail.charm as unknown as MentionableCharm);\\n }\\n});\\n\\nconst handleCharmLinkClicked = handler(\\n (_: any, { charm }: { charm: Cell }) => {\\n return navigateTo(charm);\\n },\\n);\\n\\nconst Note = recipe(\\n \\\"Note\\\",\\n ({ title, content, allCharms }) => {\\n const mentioned = cell([]);\\n\\n const computeBacklinks = lift<\\n { allCharms: Cell; content: Cell },\\n MentionableCharm[]\\n >(\\n ({ allCharms, content }) => {\\n const cs = allCharms.get();\\n if (!cs) return [];\\n\\n const self = cs.find((c) => c.content === content.get());\\n\\n const results = self\\n ? cs.filter((c) =>\\n c.mentioned?.some((m) => m.content === self.content) ?? false\\n )\\n : [];\\n\\n return results;\\n },\\n );\\n\\n const backlinks: OpaqueRef = computeBacklinks({\\n allCharms,\\n content: content as unknown as Cell, // TODO(bf): this is valid, but types complain\\n });\\n\\n // The only way to serialize a pattern, apparently?\\n const pattern = derive(undefined, () => JSON.stringify(Note));\\n\\n return {\\n [NAME]: title,\\n [UI]: (\\n \\n
\\n \\n
\\n\\n \\n
\\n ),\\n title,\\n content,\\n mentioned,\\n backlinks,\\n };\\n },\\n);\\n\\nexport default Note;\\n\"},{\"name\":\"/chatbot-list-view.tsx\",\"contents\":\"/// \\nimport {\\n Cell,\\n cell,\\n Default,\\n derive,\\n h,\\n handler,\\n ID,\\n ifElse,\\n lift,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n toSchema,\\n UI,\\n} from \\\"commontools\\\";\\n\\nimport Chat from \\\"./chatbot-note-composed.tsx\\\";\\nimport { ListItem } from \\\"./common-tools.tsx\\\";\\n\\nexport type MentionableCharm = {\\n [NAME]: string;\\n content?: string;\\n mentioned?: MentionableCharm[];\\n};\\n\\ntype CharmEntry = {\\n [ID]: string; // randomId is a string\\n local_id: string; // same as ID but easier to access\\n charm: any;\\n};\\n\\ntype Input = {\\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\\n charmsList: Default;\\n allCharms: Cell;\\n theme?: {\\n accentColor: Default;\\n fontFace: Default;\\n borderRadius: Default;\\n };\\n};\\n\\ntype Output = {\\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\\n};\\n\\nconst removeChat = handler<\\n unknown,\\n {\\n charmsList: Cell;\\n id: string;\\n selectedCharm: Cell>;\\n }\\n>(\\n (\\n _,\\n { charmsList, id, selectedCharm },\\n ) => {\\n const list = charmsList.get();\\n const index = list.findIndex((entry) => entry.local_id === id);\\n if (index === -1) return;\\n\\n const removed = list[index];\\n const next = [...list];\\n next.splice(index, 1);\\n charmsList.set(next);\\n\\n // If we removed the currently selected charm, choose a new selection.\\n const current = selectedCharm.get();\\n if (current?.charm === removed.charm) {\\n const replacement = next[index] ?? next[index - 1];\\n if (replacement) {\\n selectedCharm.set({ charm: replacement.charm });\\n } else {\\n selectedCharm.set({ charm: undefined as unknown as any });\\n }\\n }\\n },\\n);\\n\\n// this will be called whenever charm or selectedCharm changes\\n// pass isInitialized to make sure we dont call this each time\\n// we change selectedCharm, otherwise creates a loop\\nconst storeCharm = lift(\\n toSchema<{\\n charm: any;\\n selectedCharm: Cell>;\\n charmsList: Cell;\\n allCharms: Cell;\\n theme?: {\\n accentColor: Default;\\n fontFace: Default;\\n borderRadius: Default;\\n };\\n isInitialized: Cell;\\n }>(),\\n undefined,\\n ({ charm, selectedCharm, charmsList, isInitialized, allCharms }) => { // Not including `allCharms` is a compile error...\\n if (!isInitialized.get()) {\\n console.log(\\n \\\"storeCharm storing charm:\\\",\\n charm,\\n );\\n selectedCharm.set({ charm });\\n\\n // create the chat charm with a custom name including a random suffix\\n const randomId = Math.random().toString(36).substring(2, 10); // Random 8-char string\\n charmsList.push({ [ID]: randomId, local_id: randomId, charm });\\n\\n isInitialized.set(true);\\n return charm;\\n } else {\\n console.log(\\\"storeCharm: already initialized\\\");\\n }\\n return undefined;\\n },\\n);\\n\\nconst populateChatList = lift(\\n toSchema<{\\n charmsList: CharmEntry[];\\n allCharms: Cell;\\n selectedCharm: Cell<{ charm: any }>;\\n }>(),\\n undefined,\\n (\\n { charmsList, allCharms, selectedCharm },\\n ) => {\\n if (charmsList.length === 0) {\\n const isInitialized = cell(false);\\n return storeCharm({\\n charm: Chat({\\n title: \\\"New Chat\\\",\\n messages: [],\\n content: \\\"\\\",\\n allCharms,\\n }),\\n selectedCharm,\\n charmsList,\\n allCharms,\\n isInitialized: isInitialized as unknown as Cell,\\n });\\n }\\n\\n return charmsList;\\n },\\n);\\n\\nconst createChatRecipe = handler<\\n unknown,\\n {\\n selectedCharm: Cell<{ charm: any }>;\\n charmsList: Cell;\\n allCharms: Cell;\\n }\\n>(\\n (_, { selectedCharm, charmsList, allCharms }) => {\\n const isInitialized = cell(false);\\n\\n const charm = Chat({\\n title: \\\"New Chat\\\",\\n messages: [],\\n content: \\\"\\\",\\n allCharms,\\n });\\n // store the charm ref in a cell (pass isInitialized to prevent recursive calls)\\n return storeCharm({\\n charm,\\n selectedCharm,\\n charmsList: charmsList as unknown as OpaqueRef,\\n allCharms,\\n isInitialized: isInitialized as unknown as Cell,\\n });\\n },\\n);\\n\\nconst selectCharm = handler<\\n unknown,\\n { selectedCharm: Cell<{ charm: any }>; charm: any }\\n>(\\n (_, { selectedCharm, charm }) => {\\n console.log(\\\"selectCharm: updating selectedCharm to \\\", charm);\\n selectedCharm.set({ charm });\\n return selectedCharm;\\n },\\n);\\n\\nconst logCharmsList = lift<\\n { charmsList: Cell },\\n Cell\\n>(\\n ({ charmsList }) => {\\n console.log(\\\"logCharmsList: \\\", charmsList.get());\\n return charmsList;\\n },\\n);\\n\\nconst handleCharmLinkClicked = handler(\\n (_: any, { charm }: { charm: Cell }) => {\\n return navigateTo(charm);\\n },\\n);\\n\\nconst combineLists = lift(\\n (\\n { allCharms, charmsList }: { allCharms: any[]; charmsList: CharmEntry[] },\\n ) => {\\n return [...charmsList.map((c) => c.charm), ...allCharms];\\n },\\n);\\n\\nconst getSelectedCharm = lift<\\n { entry: { charm: any | undefined } },\\n {\\n chat: unknown;\\n note: unknown;\\n list: ListItem[];\\n backlinks: MentionableCharm[];\\n mentioned: MentionableCharm[];\\n } | undefined\\n>(\\n ({ entry }) => {\\n return entry?.charm;\\n },\\n);\\n\\nconst getCharmName = lift(({ charm }: { charm: any }) => {\\n return charm?.[NAME] || \\\"Unknown\\\";\\n});\\n\\n// create the named cell inside the recipe body, so we do it just once\\nexport default recipe(\\n \\\"Launcher\\\",\\n ({ selectedCharm, charmsList, allCharms, theme }) => {\\n logCharmsList({ charmsList: charmsList as unknown as Cell });\\n\\n populateChatList({\\n selectedCharm: selectedCharm as unknown as Cell<\\n Pick\\n >,\\n charmsList,\\n allCharms,\\n });\\n\\n const combined = combineLists({\\n allCharms: allCharms as unknown as any[],\\n charmsList,\\n });\\n\\n const selected = getSelectedCharm({ entry: selectedCharm });\\n\\n const localTheme = theme ?? {\\n accentColor: cell(\\\"#3b82f6\\\"),\\n fontFace: cell(\\\"system-ui, -apple-system, sans-serif\\\"),\\n borderRadius: cell(\\\"0.5rem\\\"),\\n };\\n\\n return {\\n [NAME]: \\\"Launcher\\\",\\n [UI]: (\\n \\n \\n
\\n \\n
\\n \\n Create New Chat\\n alt+N\\n \\n
\\n
\\n\\n {/* Keyboard shortcuts */}\\n \\n
\\n \\n {/* workaround: this seems to correctly start the sub-recipes on a refresh while directly rendering does not */}\\n {/* this should be fixed after the builder-refactor (DX1) */}\\n \\n \\n \\n \\n \\n \\n\\n \\n\\n \\n \\n
\\n
\\n ),\\n selectedCharm,\\n charmsList,\\n };\\n },\\n);\\n\"},{\"name\":\"/common-tools.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n BuiltInLLMTool,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n h,\\n handler,\\n ifElse,\\n llmDialog,\\n NAME,\\n recipe,\\n Stream,\\n UI,\\n} from \\\"commontools\\\";\\n\\n///// COMMON TOOLS (get it?) ////\\n\\n/**\\n * Calculate the result of a mathematical expression.\\n * Supports +, -, *, /, and parentheses.\\n */\\ntype CalculatorRequest = {\\n /** The mathematical expression to evaluate. */\\n expression: string;\\n};\\n\\nexport const calculator = recipe<\\n CalculatorRequest,\\n string | { error: string }\\n>(\\\"Calculator\\\", ({ expression }) => {\\n return derive(expression, (expr) => {\\n const sanitized = expr.replace(/[^0-9+\\\\-*/().\\\\s]/g, \\\"\\\");\\n let result;\\n try {\\n result = Function(`\\\"use strict\\\"; return (${sanitized})`)();\\n } catch (error) {\\n result = { error: (error as any)?.message || \\\"\\\" };\\n }\\n return result;\\n });\\n});\\n\\n/** Add an item to the list. */\\ntype AddListItemRequest = {\\n /** The item to add to the list. */\\n item: string;\\n result: Cell;\\n};\\n\\n/** Read all items from the list. */\\ntype ReadListItemsRequest = {\\n result: Cell;\\n};\\n\\nexport type ListItem = {\\n title: string;\\n};\\n\\nexport const addListItem = handler<\\n AddListItemRequest,\\n { list: Cell }\\n>(\\n (args, state) => {\\n try {\\n state.list.push({ title: args.item });\\n args.result.set(`${state.list.get().length} items`);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nexport const readListItems = handler<\\n ReadListItemsRequest,\\n { list: ListItem[] }\\n>(\\n (args, state) => {\\n try {\\n const items = state.list;\\n if (items.length === 0) {\\n args.result.set(\\\"The list is empty\\\");\\n } else {\\n const itemList = items.map((item, index) =>\\n `${index + 1}. ${item.title}`\\n ).join(\\\"\\\\n\\\");\\n args.result.set(`List items (${items.length} total):\\\\n${itemList}`);\\n }\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\n/** Search the web for information. */\\ntype SearchQuery = {\\n /** The query to search the web for. */\\n query: string;\\n};\\n\\ntype SearchWebResult = {\\n results: {\\n title: string;\\n url: string;\\n description: string;\\n }[];\\n};\\n\\nexport const searchWeb = recipe<\\n SearchQuery,\\n SearchWebResult | { error: string }\\n>(\\\"Search Web\\\", ({ query }) => {\\n const { result, error } = fetchData({\\n url: \\\"/api/agent-tools/web-search\\\",\\n mode: \\\"json\\\",\\n options: {\\n method: \\\"POST\\\",\\n headers: {\\n \\\"Content-Type\\\": \\\"application/json\\\",\\n },\\n body: {\\n query,\\n max_results: 5,\\n },\\n },\\n });\\n\\n // TODO(seefeld): Should we instead return { result, error }? Or allocate a\\n // special [ERROR] for errors? Ideally this isn\\'t specific to using recipes as\\n // tools but a general pattern.\\n return ifElse(error, { error }, result);\\n});\\n\\n/** Read and extract content from a specific webpage URL. */\\ntype ReadWebRequest = {\\n /** The URL of the webpage to read and extract content from. */\\n url: string;\\n};\\n\\ntype ReadWebResult = {\\n content: string;\\n metadata: {\\n title?: string;\\n author?: string;\\n date?: string;\\n word_count: number;\\n };\\n};\\n\\nexport const readWebpage = recipe<\\n ReadWebRequest,\\n ReadWebResult | { error: string }\\n>(\\\"Read Webpage\\\", ({ url }) => {\\n const { result, error } = fetchData({\\n url: \\\"/api/agent-tools/web-read\\\",\\n mode: \\\"json\\\",\\n options: {\\n method: \\\"POST\\\",\\n headers: {\\n \\\"Content-Type\\\": \\\"application/json\\\",\\n },\\n body: {\\n url,\\n max_tokens: 4000,\\n include_code: true,\\n },\\n },\\n });\\n\\n return ifElse(error, { error }, result);\\n});\\n\\ntype ToolsInput = {\\n list: ListItem[];\\n};\\n\\nexport default recipe(\\\"Tools\\\", ({ list }) => {\\n const tools: Record = {\\n search_web: {\\n pattern: searchWeb,\\n },\\n read_webpage: {\\n pattern: readWebpage,\\n },\\n calculator: {\\n pattern: calculator,\\n },\\n addListItem: {\\n handler: addListItem({ list }),\\n },\\n };\\n\\n return { tools, list };\\n});\\n\"}]}}" }, "spell": { "/": { "link@1": { "id": "of:baedreic5vwrifhgsveszaoiglpnwpg6muauspvb7lkbehia7oltjqtmeby" } } }, "argument": { "title": "three", "content": "", "allCharms": { "/": { "link@1": { "path": [], "id": "of:baedreiahv63wxwgaem4hzjkizl4qncfgvca7pj5cvdon7cukumfon3ioye", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } } } } }, "since": 80 } } }, "of:baedreigyxxqptxd2vlfwxnhzdwdha32i4ou5onzw6ruunaqudg5u42agva": { "application/json": { "ba4jcbj4fpxavqadaypagztshpzemfcoxxrragkuy2fdyg7jr6cjvygif": { "is": { "source": { "/": "baedreigf4ywexq2vyxxqtvergkpckhbbk56nenomjh7mw7um3cl33jrjgy" }, "value": { "$NAME": { "$alias": { "path": [ "argument", "title" ], "schema": { "type": "string", "default": "Untitled Note" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreigf4ywexq2vyxxqtvergkpckhbbk56nenomjh7mw7um3cl33jrjgy" } } }, "$UI": { "type": "vnode", "name": "ct-screen", "props": { }, "children": [ { "type": "vnode", "name": "div", "props": { "slot": "header" }, "children": [ { "type": "vnode", "name": "ct-input", "props": { "$value": { "$alias": { "path": [ "argument", "title" ], "schema": { "type": "string", "default": "Untitled Note" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreigf4ywexq2vyxxqtvergkpckhbbk56nenomjh7mw7um3cl33jrjgy" } } }, "placeholder": "Enter title..." }, "children": [] } ] }, { "type": "vnode", "name": "ct-code-editor", "props": { "$value": { "$alias": { "path": [ "argument", "content" ], "schema": { "type": "string", "default": "" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreigf4ywexq2vyxxqtvergkpckhbbk56nenomjh7mw7um3cl33jrjgy" } } }, "$mentionable": { "$alias": { "path": [ "argument", "allCharms" ], "schema": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreigf4ywexq2vyxxqtvergkpckhbbk56nenomjh7mw7um3cl33jrjgy" } } }, "$mentioned": { "$alias": { "path": [ "internal", "mentioned" ], "cell": { "/": "baedreigf4ywexq2vyxxqtvergkpckhbbk56nenomjh7mw7um3cl33jrjgy" } } }, "$pattern": { "$alias": { "path": [ "internal", "__#0" ], "cell": { "/": "baedreigf4ywexq2vyxxqtvergkpckhbbk56nenomjh7mw7um3cl33jrjgy" } } }, "onbacklink-click": { "$alias": { "path": [ "internal", "__#1stream" ], "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "charm": { "$ref": "#/$defs/MentionableCharm" } }, "required": [ "charm" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "charm": { "$ref": "#/$defs/MentionableCharm" } }, "required": [ "charm" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreigf4ywexq2vyxxqtvergkpckhbbk56nenomjh7mw7um3cl33jrjgy" } } }, "onbacklink-create": { "$alias": { "path": [ "internal", "$event" ], "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "text": { "type": "string" }, "charmId": true, "charm": { "$ref": "#/$defs/MentionableCharm" }, "navigate": { "type": "boolean" } }, "required": [ "text", "charmId", "charm", "navigate" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "detail": { "type": "object", "properties": { "text": { "type": "string" }, "charmId": true, "charm": { "$ref": "#/$defs/MentionableCharm" }, "navigate": { "type": "boolean" } }, "required": [ "text", "charmId", "charm", "navigate" ] } }, "required": [ "detail" ], "$defs": { "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreigf4ywexq2vyxxqtvergkpckhbbk56nenomjh7mw7um3cl33jrjgy" } } }, "language": "text/markdown", "theme": "light", "wordWrap": true, "tabIndent": true, "lineNumbers": true }, "children": [] } ] }, "title": { "$alias": { "path": [ "argument", "title" ], "schema": { "type": "string", "default": "Untitled Note" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreigf4ywexq2vyxxqtvergkpckhbbk56nenomjh7mw7um3cl33jrjgy" } } }, "content": { "$alias": { "path": [ "argument", "content" ], "schema": { "type": "string", "default": "" }, "rootSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "title": { "type": "string", "default": "Untitled Note" }, "content": { "type": "string", "default": "" }, "allCharms": { "$ref": "#/$defs/AnonymousType_1" } }, "required": [ "title", "content", "allCharms" ], "$defs": { "AnonymousType_1": { "type": "array", "items": { "$ref": "#/$defs/MentionableCharm" } }, "MentionableCharm": { "type": "object", "properties": { "content": { "type": "string" }, "mentioned": { "$ref": "#/$defs/AnonymousType_1" }, "$NAME": { "type": "string" } }, "required": [ "$NAME" ] } } }, "cell": { "/": "baedreigf4ywexq2vyxxqtvergkpckhbbk56nenomjh7mw7um3cl33jrjgy" } } }, "mentioned": { "$alias": { "path": [ "internal", "mentioned" ], "cell": { "/": "baedreigf4ywexq2vyxxqtvergkpckhbbk56nenomjh7mw7um3cl33jrjgy" } } }, "backlinks": { "$alias": { "path": [ "internal", "backlinks" ], "cell": { "/": "baedreigf4ywexq2vyxxqtvergkpckhbbk56nenomjh7mw7um3cl33jrjgy" } } } } }, "since": 89 } } }, "of:baedreigf4ywexq2vyxxqtvergkpckhbbk56nenomjh7mw7um3cl33jrjgy": { "application/json": { "ba4jca6yirnjjouffvrjcnrkt2ypndq47jg32czkao5ylpolz4ee6r3id": { "is": { "value": { "$TYPE": "ba4jcb5fkie7blry4u2wchwaog45dpfdwrpmrklu2zlndduvgd7dhc2ks", "resultRef": { "/": { "link@1": { "path": [], "id": "of:baedreigyxxqptxd2vlfwxnhzdwdha32i4ou5onzw6ruunaqudg5u42agva" } } }, "internal": { "$event": { "$stream": true }, "mentioned": [], "__#1stream": { "$stream": true }, "backlinks": [], "__#0": "{\"argumentSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"resultSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"default\":[]},\"content\":{\"type\":\"string\",\"default\":\"\"},\"backlinks\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"default\":[]}},\"required\":[\"mentioned\",\"content\",\"backlinks\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"initial\":{\"internal\":{\"$event\":{\"$stream\":true},\"mentioned\":[],\"__#1stream\":{\"$stream\":true}}},\"result\":{\"$NAME\":{\"$alias\":{\"path\":[\"argument\",\"title\"],\"schema\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"$UI\":{\"type\":\"vnode\",\"name\":\"ct-screen\",\"props\":{},\"children\":[{\"type\":\"vnode\",\"name\":\"div\",\"props\":{\"slot\":\"header\"},\"children\":[{\"type\":\"vnode\",\"name\":\"ct-input\",\"props\":{\"$value\":{\"$alias\":{\"path\":[\"argument\",\"title\"],\"schema\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"placeholder\":\"Enter title...\"},\"children\":[]}]},{\"type\":\"vnode\",\"name\":\"ct-code-editor\",\"props\":{\"$value\":{\"$alias\":{\"path\":[\"argument\",\"content\"],\"schema\":{\"type\":\"string\",\"default\":\"\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"$mentionable\":{\"$alias\":{\"path\":[\"argument\",\"allCharms\"],\"schema\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"$mentioned\":{\"$alias\":{\"path\":[\"internal\",\"mentioned\"]}},\"$pattern\":{\"$alias\":{\"path\":[\"internal\",\"__#0\"]}},\"onbacklink-click\":{\"$alias\":{\"path\":[\"internal\",\"__#1stream\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"onbacklink-create\":{\"$alias\":{\"path\":[\"internal\",\"$event\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"language\":\"text/markdown\",\"theme\":\"light\",\"wordWrap\":true,\"tabIndent\":true,\"lineNumbers\":true},\"children\":[]}]},\"title\":{\"$alias\":{\"path\":[\"argument\",\"title\"],\"schema\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"content\":{\"$alias\":{\"path\":[\"argument\",\"content\"],\"schema\":{\"type\":\"string\",\"default\":\"\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"mentioned\":{\"$alias\":{\"path\":[\"internal\",\"mentioned\"]}},\"backlinks\":{\"$alias\":{\"path\":[\"internal\",\"backlinks\"]}}},\"nodes\":[{\"module\":{\"type\":\"javascript\",\"implementation\":\"({ allCharms, content }) => {\\n const cs = allCharms.get();\\n if (!cs)\\n return [];\\n const self = cs.find((c) => c.content === content.get());\\n const results = self\\n ? cs.filter((c) => c.mentioned?.some((m) => m.content === self.content) ?? false)\\n : [];\\n return results;\\n }\",\"argumentSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"asCell\":true},\"content\":{\"type\":\"string\",\"asCell\":true}},\"required\":[\"allCharms\",\"content\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"resultSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"$ref\":\"#/$defs/AnonymousType_1\",\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}},\"inputs\":{\"allCharms\":{\"$alias\":{\"path\":[\"argument\",\"allCharms\"],\"schema\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}},\"content\":{\"$alias\":{\"path\":[\"argument\",\"content\"],\"schema\":{\"type\":\"string\",\"default\":\"\"},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"outputs\":{\"$alias\":{\"path\":[\"internal\",\"backlinks\"]}}},{\"module\":{\"type\":\"javascript\",\"implementation\":\"({ detail }, { allCharms }) => {\\n console.log(\\\"new charm\\\", detail.text, detail.charmId);\\n if (detail.navigate) {\\n return (0, commontools_5.navigateTo)(detail.charm);\\n }\\n else {\\n allCharms.push(detail.charm);\\n }\\n }\",\"wrapper\":\"handler\",\"argumentSchema\":{\"type\":\"object\",\"properties\":{\"$event\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\",\"asCell\":true},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"]},\"$ctx\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\",\"asCell\":true}},\"required\":[\"allCharms\"]}},\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]},\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}}}}},\"inputs\":{\"$ctx\":{\"allCharms\":{\"$alias\":{\"path\":[\"argument\",\"allCharms\"],\"schema\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\",\"default\":\"Untitled Note\"},\"content\":{\"type\":\"string\",\"default\":\"\"},\"allCharms\":{\"$ref\":\"#/$defs/AnonymousType_1\"}},\"required\":[\"title\",\"content\",\"allCharms\"],\"$defs\":{\"AnonymousType_1\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"$ref\":\"#/$defs/AnonymousType_1\"},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"$event\":{\"$alias\":{\"path\":[\"internal\",\"$event\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"text\":{\"type\":\"string\"},\"charmId\":true,\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"},\"navigate\":{\"type\":\"boolean\"}},\"required\":[\"text\",\"charmId\",\"charm\",\"navigate\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"outputs\":{}},{\"module\":{\"type\":\"javascript\",\"implementation\":\"() => JSON.stringify(Note)\",\"argumentSchema\":true,\"resultSchema\":{\"type\":\"string\"}},\"outputs\":{\"$alias\":{\"path\":[\"internal\",\"__#0\"]}}},{\"module\":{\"type\":\"javascript\",\"implementation\":\"({ detail }, _) => {\\n return (0, commontools_5.navigateTo)(detail.charm);\\n }\",\"wrapper\":\"handler\",\"argumentSchema\":{\"type\":\"object\",\"properties\":{\"$event\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\",\"asCell\":true}},\"required\":[\"charm\"]}},\"required\":[\"detail\"]},\"$ctx\":{\"type\":\"object\",\"properties\":{},\"additionalProperties\":false}},\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}},\"inputs\":{\"$ctx\":{},\"$event\":{\"$alias\":{\"path\":[\"internal\",\"__#1stream\"],\"schema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}},\"rootSchema\":{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"detail\":{\"type\":\"object\",\"properties\":{\"charm\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"required\":[\"charm\"]}},\"required\":[\"detail\"],\"$defs\":{\"MentionableCharm\":{\"type\":\"object\",\"properties\":{\"content\":{\"type\":\"string\"},\"mentioned\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/$defs/MentionableCharm\"}},\"$NAME\":{\"type\":\"string\"}},\"required\":[\"$NAME\"]}}}}}},\"outputs\":{}}],\"program\":{\"main\":\"/note.tsx\",\"mainExport\":\"default\",\"files\":[{\"name\":\"/default-app.tsx\",\"contents\":\"/// \\nimport {\\n Cell,\\n Default,\\n derive,\\n h,\\n handler,\\n NAME,\\n navigateTo,\\n Opaque,\\n OpaqueRef,\\n recipe,\\n str,\\n UI,\\n} from \\\"commontools\\\";\\n\\n// Import recipes we want to be launchable from the default app.\\nimport Chatbot from \\\"./chatbot.tsx\\\";\\nimport ChatbotOutliner from \\\"./chatbot-outliner.tsx\\\";\\nimport { type MentionableCharm } from \\\"./chatbot-note-composed.tsx\\\";\\nimport { default as Note } from \\\"./note.tsx\\\";\\nimport ChatList from \\\"./chatbot-list-view.tsx\\\";\\n\\nexport type Charm = {\\n [NAME]?: string;\\n [UI]?: unknown;\\n [key: string]: any;\\n};\\n\\ntype CharmsListInput = {\\n allCharms: Default;\\n};\\n\\n// Recipe returns only UI, no data outputs (only symbol properties)\\ninterface CharmsListOutput {\\n [key: string]: unknown;\\n}\\n\\nconst visit = handler<\\n Record,\\n { charm: any }\\n>((_, state) => {\\n return navigateTo(state.charm);\\n}, { proxy: true });\\n\\nconst removeCharm = handler<\\n Record,\\n {\\n charm: any;\\n allCharms: Cell;\\n }\\n>((_, state) => {\\n const charmName = state.charm[NAME];\\n const allCharmsValue = state.allCharms.get();\\n const index = allCharmsValue.findIndex((c: any) => c[NAME] === charmName);\\n\\n if (index !== -1) {\\n const charmListCopy = [...allCharmsValue];\\n console.log(\\\"charmListCopy before\\\", charmListCopy);\\n charmListCopy.splice(index, 1);\\n console.log(\\\"charmListCopy after\\\", charmListCopy);\\n state.allCharms.set(charmListCopy);\\n }\\n});\\n\\nconst spawnChatList = handler<\\n Record,\\n { allCharms: Cell }\\n>((_, state) => {\\n return navigateTo(ChatList({\\n selectedCharm: { charm: undefined },\\n charmsList: [],\\n allCharms: state.allCharms, // we should handle empty here\\n }));\\n});\\n\\nconst spawnChatbot = handler<\\n Record,\\n Record\\n>((_, state) => {\\n return navigateTo(Chatbot({\\n messages: [],\\n tools: undefined,\\n }));\\n});\\n\\nconst spawnChatbotOutliner = handler<\\n Record,\\n { allCharms: Cell }\\n>((_, state) => {\\n return navigateTo(ChatbotOutliner({\\n title: \\\"Chatbot Outliner\\\",\\n expandChat: false,\\n messages: [],\\n outline: {\\n root: { body: \\\"\\\", children: [], attachments: [] },\\n },\\n allCharms: state.allCharms,\\n }));\\n});\\n\\nconst spawnNote = handler<\\n Record,\\n { allCharms: Cell }\\n>((_, state) => {\\n return navigateTo(Note({\\n title: \\\"New Note\\\",\\n content: \\\"\\\",\\n allCharms: state.allCharms,\\n }));\\n});\\n\\nexport default recipe(\\n \\\"DefaultCharmList\\\",\\n ({ allCharms }) => {\\n return {\\n [NAME]: str`DefaultCharmList (${allCharms.length})`,\\n [UI]: (\\n \\n ,\\n })}\\n />\\n\\n \\n {/* Quick Launch Toolbar */}\\n \\n

Quicklaunch:

\\n ,\\n })}\\n >\\n 📂 Chat List\\n \\n \\n 💬 Chatbot\\n \\n \\n 📝 Chatbot Outliner\\n \\n ,\\n })}\\n >\\n 📄 Note\\n \\n
\\n\\n

Charms ({allCharms.length})

\\n\\n \\n \\n \\n Charm Name\\n Actions\\n \\n \\n \\n {derive(allCharms, (allCharms) =>\\n allCharms.map((charm: any) => (\\n \\n {charm[NAME] || \\\"Untitled Charm\\\"}\\n \\n \\n \\n Visit\\n \\n \\n Remove\\n \\n \\n \\n \\n )))}\\n \\n \\n
\\n
\\n ),\\n };\\n },\\n);\\n\"},{\"name\":\"/chatbot.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n generateObject,\\n h,\\n handler,\\n ifElse,\\n JSONSchema,\\n lift,\\n llm,\\n llmDialog,\\n NAME,\\n recipe,\\n str,\\n Stream,\\n UI,\\n} from \\\"commontools\\\";\\n\\nconst sendMessage = handler<\\n { detail: { message: string } },\\n {\\n addMessage: Stream;\\n }\\n>((event, { addMessage }) => {\\n addMessage.send({\\n role: \\\"user\\\",\\n content: [{ type: \\\"text\\\", text: event.detail.message }],\\n });\\n});\\n\\nconst clearChat = handler(\\n (\\n _: never,\\n { messages, pending }: {\\n messages: Cell>;\\n pending: Cell;\\n },\\n ) => {\\n messages.set([]);\\n pending.set(false);\\n },\\n);\\n\\ntype ChatInput = {\\n messages: Default, []>;\\n tools: any;\\n theme?: any;\\n};\\n\\ntype ChatOutput = {\\n messages: Array;\\n pending: boolean | undefined;\\n addMessage: Stream;\\n cancelGeneration: Stream;\\n title?: string;\\n};\\n\\nexport const TitleGenerator = recipe<\\n { model?: string; messages: Array }\\n>(\\\"Title Generator\\\", ({ model, messages }) => {\\n const titleMessages = derive(messages, (m) => {\\n if (!m || m.length === 0) return \\\"\\\";\\n\\n const messageCount = 2;\\n const selectedMessages = m.slice(0, messageCount).filter(Boolean);\\n\\n if (selectedMessages.length === 0) return \\\"\\\";\\n\\n return selectedMessages.map((msg) => JSON.stringify(msg)).join(\\\"\\\\n\\\");\\n });\\n\\n const { result } = generateObject({\\n system:\\n \\\"Generate at most a 3-word title based on the following content, respond with NOTHING but the literal title text.\\\",\\n prompt: titleMessages,\\n model,\\n schema: {\\n type: \\\"object\\\",\\n properties: {\\n title: {\\n type: \\\"string\\\",\\n description: \\\"The title of the chat\\\",\\n },\\n },\\n required: [\\\"title\\\"],\\n },\\n });\\n\\n const title = derive(result, (t) => {\\n return t?.title || \\\"Untitled Chat\\\";\\n });\\n\\n return title;\\n});\\n\\nexport default recipe(\\n \\\"Chat\\\",\\n ({ messages, tools, theme }) => {\\n const model = cell(\\\"anthropic:claude-sonnet-4-5\\\");\\n\\n const { addMessage, cancelGeneration, pending } = llmDialog({\\n system: \\\"You are a helpful assistant with some tools.\\\",\\n messages,\\n tools,\\n model,\\n });\\n\\n const { result } = fetchData({\\n url: \\\"/api/ai/llm/models\\\",\\n mode: \\\"json\\\",\\n });\\n\\n const items = derive(result, (models) => {\\n if (!models) return [];\\n const items = Object.keys(models as any).map((key) => ({\\n label: key,\\n value: key,\\n }));\\n return items;\\n });\\n\\n const title = TitleGenerator({ model, messages });\\n\\n return {\\n [NAME]: title,\\n [UI]: (\\n \\n \\n {title}\\n \\n \\n\\n \\n \\n \\n\\n
\\n \\n \\n
\\n
\\n ),\\n messages,\\n pending,\\n addMessage,\\n cancelGeneration,\\n title,\\n };\\n },\\n);\\n\"},{\"name\":\"/chatbot-outliner.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n getRecipeEnvironment,\\n h,\\n handler,\\n ID,\\n ifElse,\\n JSONSchema,\\n lift,\\n llm,\\n llmDialog,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n str,\\n Stream,\\n UI,\\n} from \\\"commontools\\\";\\n\\nimport Chat from \\\"./chatbot.tsx\\\";\\n\\ntype Charm = any;\\n\\ntype OutlinerNode = {\\n body: Default;\\n children: Default;\\n attachments: Default[], []>;\\n};\\n\\ntype Outliner = {\\n root: OutlinerNode;\\n};\\n\\ntype PageResult = {\\n outline: Default<\\n Outliner,\\n { root: { body: \\\"\\\"; children: []; attachments: [] } }\\n >;\\n};\\n\\nexport type PageInput = {\\n outline: Outliner;\\n allCharms: Cell;\\n};\\n\\nconst handleCharmLinkClick = handler<\\n {\\n detail: {\\n charm: Cell;\\n };\\n },\\n Record\\n>(({ detail }, _) => {\\n return navigateTo(detail.charm);\\n});\\n\\nexport const Page = recipe(\\n \\\"Page\\\",\\n ({ outline, allCharms }) => {\\n return {\\n [NAME]: \\\"Page\\\",\\n [UI]: (\\n \\n ),\\n outline,\\n };\\n },\\n);\\n\\ntype LLMTestInput = {\\n title: Default;\\n messages: Default, []>;\\n expandChat: Default;\\n outline: Default<\\n Outliner,\\n { root: { body: \\\"Untitled Page\\\"; children: []; attachments: [] } }\\n >;\\n allCharms: Cell;\\n};\\n\\ntype LLMTestResult = {\\n messages: Default, []>;\\n};\\n\\n// put a node at the end of the outline (by appending to root.children)\\nconst appendOutlinerNode = handler<\\n {\\n /** The text content/title of the outliner node to be appended */\\n body: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { outline: Cell }\\n>(\\n (args, state) => {\\n try {\\n (state.outline.key(\\\"root\\\").key(\\\"children\\\")).push({\\n body: args.body,\\n children: [],\\n attachments: [],\\n });\\n\\n args.result.set(\\n `${state.outline.key(\\\"root\\\").key(\\\"children\\\").get().length} nodes`,\\n );\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nexport default recipe(\\n \\\"Outliner\\\",\\n ({ title, expandChat, messages, outline, allCharms }) => {\\n const tools = {\\n appendOutlinerNode: {\\n description: \\\"Add a new outliner node.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n body: {\\n type: \\\"string\\\",\\n description: \\\"The title of the new node.\\\",\\n },\\n },\\n required: [\\\"body\\\"],\\n } as JSONSchema,\\n handler: appendOutlinerNode({ outline }),\\n },\\n };\\n\\n const chat = Chat({ messages, tools });\\n const { addMessage, cancelGeneration, pending } = chat;\\n\\n return {\\n [NAME]: title,\\n [UI]: (\\n \\n \\n
\\n
\\n Show Chat\\n
\\n
\\n\\n \\n \\n
\\n \\n
\\n\\n \\n \\n \\n \\n \\n
\\n\\n {ifElse(\\n expandChat,\\n chat,\\n null,\\n )}\\n
\\n
\\n ),\\n messages,\\n };\\n },\\n);\\n\"},{\"name\":\"/chatbot-note-composed.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n getRecipeEnvironment,\\n h,\\n handler,\\n ID,\\n ifElse,\\n JSONSchema,\\n lift,\\n llm,\\n llmDialog,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n str,\\n Stream,\\n toSchema,\\n UI,\\n} from \\\"commontools\\\";\\n\\nimport Chat from \\\"./chatbot.tsx\\\";\\nimport Note from \\\"./note.tsx\\\";\\nimport Tools, {\\n addListItem,\\n calculator,\\n ListItem,\\n readListItems,\\n readWebpage,\\n searchWeb,\\n} from \\\"./common-tools.tsx\\\";\\n\\nexport type MentionableCharm = {\\n [NAME]: string;\\n content?: string;\\n mentioned?: MentionableCharm[];\\n};\\n\\n// export type ChatbotNoteInput = {\\n// content: Default;\\n// allCharms?: Cell;\\n// };\\n\\nconst handleCharmLinkClick = handler<\\n {\\n detail: {\\n charm: Cell;\\n };\\n },\\n Record\\n>(({ detail }, _) => {\\n return navigateTo(detail.charm);\\n});\\n\\nconst handleCharmLinkClicked = handler(\\n (_: any, { charm }: { charm: Cell }) => {\\n return navigateTo(charm);\\n },\\n);\\n\\ntype ChatbotNoteInput = {\\n title: Default;\\n messages: Default, []>;\\n content: Default;\\n allCharms: Cell;\\n};\\n\\ntype ChatbotNoteResult = {\\n messages: Default, []>;\\n mentioned: Default, []>;\\n backlinks: Default, []>;\\n content: Default;\\n note: any;\\n chat: any;\\n list: Default;\\n};\\n\\nconst newNote = handler<\\n {\\n /** The text content of the note */\\n title: string;\\n content?: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { allCharms: Cell }\\n>(\\n (args, state) => {\\n try {\\n const n = Note({\\n title: args.title,\\n content: args.content || \\\"\\\",\\n allCharms: state.allCharms,\\n });\\n\\n args.result.set(\\n `Created note ${args.title}!`,\\n );\\n\\n state.allCharms.push(n as unknown as MentionableCharm);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\n// put a note at the end of the outline (by appending to root.children)\\nconst editNote = handler<\\n {\\n /** The text content of the note */\\n body: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { content: Cell }\\n>(\\n (args, state) => {\\n try {\\n state.content.set(args.body);\\n\\n args.result.set(\\n `Updated note!`,\\n );\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst readNote = handler<\\n {\\n /** A cell to store the result text */\\n result: Cell;\\n },\\n { content: string }\\n>(\\n (args, state) => {\\n try {\\n args.result.set(state.content);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst listMentionable = handler<\\n {\\n /** A cell to store the result text */\\n result: Cell;\\n },\\n { allCharms: { [NAME]: string }[] }\\n>(\\n (args, state) => {\\n try {\\n const namesList = state.allCharms.map((charm) => charm[NAME]);\\n args.result.set(JSON.stringify(namesList));\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst readNoteByIndex = handler<\\n {\\n /** A cell to store the result text */\\n index: number;\\n result: Cell;\\n },\\n { allCharms: { [NAME]: string; content?: string }[] }\\n>(\\n (args, state) => {\\n try {\\n args.result.set(\\n state.allCharms[args.index]?.content || \\\"No content found\\\",\\n );\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst editNoteByIndex = handler<\\n {\\n /** The index of the note to edit */\\n index: number;\\n /** The new text content of the note */\\n body: string;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { allCharms: Cell }\\n>(\\n (args, state) => {\\n try {\\n const charms = state.allCharms.get();\\n if (args.index < 0 || args.index >= charms.length) {\\n args.result.set(`Error: Invalid index ${args.index}`);\\n return;\\n }\\n\\n state.allCharms.key(args.index).key(\\\"content\\\").set(args.body);\\n args.result.set(`Updated note at index ${args.index}!`);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nconst navigateToNote = handler<\\n {\\n /** The index of the note to navigate to */\\n index: number;\\n /** A cell to store the result message indicating success or error */\\n result: Cell;\\n },\\n { allCharms: Cell }\\n>(\\n (args, state) => {\\n try {\\n const charms = state.allCharms.get();\\n if (args.index < 0 || args.index >= charms.length) {\\n args.result.set(`Error: Invalid index ${args.index}`);\\n return;\\n }\\n\\n const targetCharm = charms[args.index];\\n args.result.set(`Navigating to note: ${targetCharm[NAME]}`);\\n\\n return navigateTo(state.allCharms.key(args.index));\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nexport default recipe(\\n \\\"Chatbot + Note\\\",\\n ({ title, messages, content, allCharms }) => {\\n const list = cell([]);\\n\\n const tools = {\\n searchWeb: {\\n pattern: searchWeb,\\n },\\n readWebpage: {\\n pattern: readWebpage,\\n },\\n calculator: {\\n pattern: calculator,\\n },\\n addListItem: {\\n handler: addListItem({ list }),\\n },\\n readListItems: {\\n handler: readListItems({ list }),\\n },\\n editActiveNote: {\\n description: \\\"Modify the shared note.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n body: {\\n type: \\\"string\\\",\\n description: \\\"The content of the note.\\\",\\n },\\n },\\n required: [\\\"body\\\"],\\n } as JSONSchema,\\n handler: editNote({ content }),\\n },\\n readActiveNote: {\\n description: \\\"Read the currently focused note.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {},\\n required: [],\\n } as JSONSchema,\\n handler: readNote({ content }),\\n },\\n listNotes: {\\n description:\\n \\\"List all mentionable note titles (read the body with readNoteByIndex).\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {},\\n required: [],\\n } as JSONSchema,\\n handler: listMentionable({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n readNoteByIndex: {\\n description:\\n \\\"Read the body of a note by its index in the listNotes() list.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n index: {\\n type: \\\"number\\\",\\n description: \\\"The index of the note in the notes list.\\\",\\n },\\n },\\n required: [\\\"index\\\"],\\n } as JSONSchema,\\n handler: readNoteByIndex({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n editNoteByIndex: {\\n description:\\n \\\"Edit the body of a note by its index in the listNotes() list.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n index: {\\n type: \\\"number\\\",\\n description: \\\"The index of the note in the notes list.\\\",\\n },\\n body: {\\n type: \\\"string\\\",\\n description: \\\"The new content of the note.\\\",\\n },\\n },\\n required: [\\\"index\\\", \\\"body\\\"],\\n } as JSONSchema,\\n handler: editNoteByIndex({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n navigateToNote: {\\n description: \\\"Navigate to a note by its index in the listNotes() list.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n index: {\\n type: \\\"number\\\",\\n description: \\\"The index of the note in the notes list.\\\",\\n },\\n },\\n required: [\\\"index\\\"],\\n } as JSONSchema,\\n handler: navigateToNote({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n newNote: {\\n description: \\\"Read the shared note.\\\",\\n inputSchema: {\\n type: \\\"object\\\",\\n properties: {\\n title: {\\n type: \\\"string\\\",\\n description: \\\"The title of the note.\\\",\\n },\\n content: {\\n type: \\\"string\\\",\\n description: \\\"The content of the note.\\\",\\n },\\n },\\n required: [\\\"title\\\"],\\n } as JSONSchema,\\n handler: newNote({\\n allCharms: allCharms as unknown as OpaqueRef,\\n }),\\n },\\n };\\n\\n const chat = Chat({ messages, tools });\\n const note = Note({ title, content, allCharms });\\n\\n return {\\n [NAME]: title,\\n chat,\\n note,\\n content,\\n messages,\\n mentioned: note.mentioned,\\n backlinks: note.backlinks,\\n list,\\n };\\n },\\n);\\n\"},{\"name\":\"/note.tsx\",\"contents\":\"/// \\nimport {\\n Cell,\\n cell,\\n Default,\\n derive,\\n h,\\n handler,\\n lift,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n toSchema,\\n UI,\\n} from \\\"commontools\\\";\\n\\nexport type MentionableCharm = {\\n [NAME]: string;\\n content?: string;\\n mentioned?: MentionableCharm[];\\n};\\n\\ntype Input = {\\n title: Default;\\n content: Default;\\n allCharms: Cell;\\n};\\n\\ntype Output = {\\n mentioned: Default, []>;\\n content: Default;\\n backlinks: Default, []>;\\n};\\n\\nconst updateTitle = handler<\\n { detail: { value: string } },\\n { title: Cell }\\n>(\\n (event, state) => {\\n state.title.set(event.detail?.value ?? \\\"\\\");\\n },\\n);\\n\\nconst updateContent = handler<\\n { detail: { value: string } },\\n { content: Cell }\\n>(\\n (event, state) => {\\n state.content.set(event.detail?.value ?? \\\"\\\");\\n },\\n);\\n\\nconst handleCharmLinkClick = handler<\\n {\\n detail: {\\n charm: Cell;\\n };\\n },\\n Record\\n>(({ detail }, _) => {\\n return navigateTo(detail.charm);\\n});\\n\\nconst handleNewBacklink = handler<\\n {\\n detail: {\\n text: string;\\n charmId: any;\\n charm: Cell;\\n navigate: boolean;\\n };\\n },\\n {\\n allCharms: Cell;\\n }\\n>(({ detail }, { allCharms }) => {\\n console.log(\\\"new charm\\\", detail.text, detail.charmId);\\n\\n if (detail.navigate) {\\n return navigateTo(detail.charm);\\n } else {\\n allCharms.push(detail.charm as unknown as MentionableCharm);\\n }\\n});\\n\\nconst handleCharmLinkClicked = handler(\\n (_: any, { charm }: { charm: Cell }) => {\\n return navigateTo(charm);\\n },\\n);\\n\\nconst Note = recipe(\\n \\\"Note\\\",\\n ({ title, content, allCharms }) => {\\n const mentioned = cell([]);\\n\\n const computeBacklinks = lift<\\n { allCharms: Cell; content: Cell },\\n MentionableCharm[]\\n >(\\n ({ allCharms, content }) => {\\n const cs = allCharms.get();\\n if (!cs) return [];\\n\\n const self = cs.find((c) => c.content === content.get());\\n\\n const results = self\\n ? cs.filter((c) =>\\n c.mentioned?.some((m) => m.content === self.content) ?? false\\n )\\n : [];\\n\\n return results;\\n },\\n );\\n\\n const backlinks: OpaqueRef = computeBacklinks({\\n allCharms,\\n content: content as unknown as Cell, // TODO(bf): this is valid, but types complain\\n });\\n\\n // The only way to serialize a pattern, apparently?\\n const pattern = derive(undefined, () => JSON.stringify(Note));\\n\\n return {\\n [NAME]: title,\\n [UI]: (\\n \\n
\\n \\n
\\n\\n \\n
\\n ),\\n title,\\n content,\\n mentioned,\\n backlinks,\\n };\\n },\\n);\\n\\nexport default Note;\\n\"},{\"name\":\"/chatbot-list-view.tsx\",\"contents\":\"/// \\nimport {\\n Cell,\\n cell,\\n Default,\\n derive,\\n h,\\n handler,\\n ID,\\n ifElse,\\n lift,\\n NAME,\\n navigateTo,\\n OpaqueRef,\\n recipe,\\n toSchema,\\n UI,\\n} from \\\"commontools\\\";\\n\\nimport Chat from \\\"./chatbot-note-composed.tsx\\\";\\nimport { ListItem } from \\\"./common-tools.tsx\\\";\\n\\nexport type MentionableCharm = {\\n [NAME]: string;\\n content?: string;\\n mentioned?: MentionableCharm[];\\n};\\n\\ntype CharmEntry = {\\n [ID]: string; // randomId is a string\\n local_id: string; // same as ID but easier to access\\n charm: any;\\n};\\n\\ntype Input = {\\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\\n charmsList: Default;\\n allCharms: Cell;\\n theme?: {\\n accentColor: Default;\\n fontFace: Default;\\n borderRadius: Default;\\n };\\n};\\n\\ntype Output = {\\n selectedCharm: Default<{ charm: any }, { charm: undefined }>;\\n};\\n\\nconst removeChat = handler<\\n unknown,\\n {\\n charmsList: Cell;\\n id: string;\\n selectedCharm: Cell>;\\n }\\n>(\\n (\\n _,\\n { charmsList, id, selectedCharm },\\n ) => {\\n const list = charmsList.get();\\n const index = list.findIndex((entry) => entry.local_id === id);\\n if (index === -1) return;\\n\\n const removed = list[index];\\n const next = [...list];\\n next.splice(index, 1);\\n charmsList.set(next);\\n\\n // If we removed the currently selected charm, choose a new selection.\\n const current = selectedCharm.get();\\n if (current?.charm === removed.charm) {\\n const replacement = next[index] ?? next[index - 1];\\n if (replacement) {\\n selectedCharm.set({ charm: replacement.charm });\\n } else {\\n selectedCharm.set({ charm: undefined as unknown as any });\\n }\\n }\\n },\\n);\\n\\n// this will be called whenever charm or selectedCharm changes\\n// pass isInitialized to make sure we dont call this each time\\n// we change selectedCharm, otherwise creates a loop\\nconst storeCharm = lift(\\n toSchema<{\\n charm: any;\\n selectedCharm: Cell>;\\n charmsList: Cell;\\n allCharms: Cell;\\n theme?: {\\n accentColor: Default;\\n fontFace: Default;\\n borderRadius: Default;\\n };\\n isInitialized: Cell;\\n }>(),\\n undefined,\\n ({ charm, selectedCharm, charmsList, isInitialized, allCharms }) => { // Not including `allCharms` is a compile error...\\n if (!isInitialized.get()) {\\n console.log(\\n \\\"storeCharm storing charm:\\\",\\n charm,\\n );\\n selectedCharm.set({ charm });\\n\\n // create the chat charm with a custom name including a random suffix\\n const randomId = Math.random().toString(36).substring(2, 10); // Random 8-char string\\n charmsList.push({ [ID]: randomId, local_id: randomId, charm });\\n\\n isInitialized.set(true);\\n return charm;\\n } else {\\n console.log(\\\"storeCharm: already initialized\\\");\\n }\\n return undefined;\\n },\\n);\\n\\nconst populateChatList = lift(\\n toSchema<{\\n charmsList: CharmEntry[];\\n allCharms: Cell;\\n selectedCharm: Cell<{ charm: any }>;\\n }>(),\\n undefined,\\n (\\n { charmsList, allCharms, selectedCharm },\\n ) => {\\n if (charmsList.length === 0) {\\n const isInitialized = cell(false);\\n return storeCharm({\\n charm: Chat({\\n title: \\\"New Chat\\\",\\n messages: [],\\n content: \\\"\\\",\\n allCharms,\\n }),\\n selectedCharm,\\n charmsList,\\n allCharms,\\n isInitialized: isInitialized as unknown as Cell,\\n });\\n }\\n\\n return charmsList;\\n },\\n);\\n\\nconst createChatRecipe = handler<\\n unknown,\\n {\\n selectedCharm: Cell<{ charm: any }>;\\n charmsList: Cell;\\n allCharms: Cell;\\n }\\n>(\\n (_, { selectedCharm, charmsList, allCharms }) => {\\n const isInitialized = cell(false);\\n\\n const charm = Chat({\\n title: \\\"New Chat\\\",\\n messages: [],\\n content: \\\"\\\",\\n allCharms,\\n });\\n // store the charm ref in a cell (pass isInitialized to prevent recursive calls)\\n return storeCharm({\\n charm,\\n selectedCharm,\\n charmsList: charmsList as unknown as OpaqueRef,\\n allCharms,\\n isInitialized: isInitialized as unknown as Cell,\\n });\\n },\\n);\\n\\nconst selectCharm = handler<\\n unknown,\\n { selectedCharm: Cell<{ charm: any }>; charm: any }\\n>(\\n (_, { selectedCharm, charm }) => {\\n console.log(\\\"selectCharm: updating selectedCharm to \\\", charm);\\n selectedCharm.set({ charm });\\n return selectedCharm;\\n },\\n);\\n\\nconst logCharmsList = lift<\\n { charmsList: Cell },\\n Cell\\n>(\\n ({ charmsList }) => {\\n console.log(\\\"logCharmsList: \\\", charmsList.get());\\n return charmsList;\\n },\\n);\\n\\nconst handleCharmLinkClicked = handler(\\n (_: any, { charm }: { charm: Cell }) => {\\n return navigateTo(charm);\\n },\\n);\\n\\nconst combineLists = lift(\\n (\\n { allCharms, charmsList }: { allCharms: any[]; charmsList: CharmEntry[] },\\n ) => {\\n return [...charmsList.map((c) => c.charm), ...allCharms];\\n },\\n);\\n\\nconst getSelectedCharm = lift<\\n { entry: { charm: any | undefined } },\\n {\\n chat: unknown;\\n note: unknown;\\n list: ListItem[];\\n backlinks: MentionableCharm[];\\n mentioned: MentionableCharm[];\\n } | undefined\\n>(\\n ({ entry }) => {\\n return entry?.charm;\\n },\\n);\\n\\nconst getCharmName = lift(({ charm }: { charm: any }) => {\\n return charm?.[NAME] || \\\"Unknown\\\";\\n});\\n\\n// create the named cell inside the recipe body, so we do it just once\\nexport default recipe(\\n \\\"Launcher\\\",\\n ({ selectedCharm, charmsList, allCharms, theme }) => {\\n logCharmsList({ charmsList: charmsList as unknown as Cell });\\n\\n populateChatList({\\n selectedCharm: selectedCharm as unknown as Cell<\\n Pick\\n >,\\n charmsList,\\n allCharms,\\n });\\n\\n const combined = combineLists({\\n allCharms: allCharms as unknown as any[],\\n charmsList,\\n });\\n\\n const selected = getSelectedCharm({ entry: selectedCharm });\\n\\n const localTheme = theme ?? {\\n accentColor: cell(\\\"#3b82f6\\\"),\\n fontFace: cell(\\\"system-ui, -apple-system, sans-serif\\\"),\\n borderRadius: cell(\\\"0.5rem\\\"),\\n };\\n\\n return {\\n [NAME]: \\\"Launcher\\\",\\n [UI]: (\\n \\n \\n
\\n \\n
\\n \\n Create New Chat\\n alt+N\\n \\n
\\n
\\n\\n {/* Keyboard shortcuts */}\\n \\n
\\n \\n {/* workaround: this seems to correctly start the sub-recipes on a refresh while directly rendering does not */}\\n {/* this should be fixed after the builder-refactor (DX1) */}\\n \\n \\n \\n \\n \\n \\n\\n \\n\\n \\n \\n
\\n
\\n ),\\n selectedCharm,\\n charmsList,\\n };\\n },\\n);\\n\"},{\"name\":\"/common-tools.tsx\",\"contents\":\"/// \\nimport {\\n BuiltInLLMMessage,\\n BuiltInLLMTool,\\n Cell,\\n cell,\\n Default,\\n derive,\\n fetchData,\\n h,\\n handler,\\n ifElse,\\n llmDialog,\\n NAME,\\n recipe,\\n Stream,\\n UI,\\n} from \\\"commontools\\\";\\n\\n///// COMMON TOOLS (get it?) ////\\n\\n/**\\n * Calculate the result of a mathematical expression.\\n * Supports +, -, *, /, and parentheses.\\n */\\ntype CalculatorRequest = {\\n /** The mathematical expression to evaluate. */\\n expression: string;\\n};\\n\\nexport const calculator = recipe<\\n CalculatorRequest,\\n string | { error: string }\\n>(\\\"Calculator\\\", ({ expression }) => {\\n return derive(expression, (expr) => {\\n const sanitized = expr.replace(/[^0-9+\\\\-*/().\\\\s]/g, \\\"\\\");\\n let result;\\n try {\\n result = Function(`\\\"use strict\\\"; return (${sanitized})`)();\\n } catch (error) {\\n result = { error: (error as any)?.message || \\\"\\\" };\\n }\\n return result;\\n });\\n});\\n\\n/** Add an item to the list. */\\ntype AddListItemRequest = {\\n /** The item to add to the list. */\\n item: string;\\n result: Cell;\\n};\\n\\n/** Read all items from the list. */\\ntype ReadListItemsRequest = {\\n result: Cell;\\n};\\n\\nexport type ListItem = {\\n title: string;\\n};\\n\\nexport const addListItem = handler<\\n AddListItemRequest,\\n { list: Cell }\\n>(\\n (args, state) => {\\n try {\\n state.list.push({ title: args.item });\\n args.result.set(`${state.list.get().length} items`);\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\nexport const readListItems = handler<\\n ReadListItemsRequest,\\n { list: ListItem[] }\\n>(\\n (args, state) => {\\n try {\\n const items = state.list;\\n if (items.length === 0) {\\n args.result.set(\\\"The list is empty\\\");\\n } else {\\n const itemList = items.map((item, index) =>\\n `${index + 1}. ${item.title}`\\n ).join(\\\"\\\\n\\\");\\n args.result.set(`List items (${items.length} total):\\\\n${itemList}`);\\n }\\n } catch (error) {\\n args.result.set(`Error: ${(error as any)?.message || \\\"\\\"}`);\\n }\\n },\\n);\\n\\n/** Search the web for information. */\\ntype SearchQuery = {\\n /** The query to search the web for. */\\n query: string;\\n};\\n\\ntype SearchWebResult = {\\n results: {\\n title: string;\\n url: string;\\n description: string;\\n }[];\\n};\\n\\nexport const searchWeb = recipe<\\n SearchQuery,\\n SearchWebResult | { error: string }\\n>(\\\"Search Web\\\", ({ query }) => {\\n const { result, error } = fetchData({\\n url: \\\"/api/agent-tools/web-search\\\",\\n mode: \\\"json\\\",\\n options: {\\n method: \\\"POST\\\",\\n headers: {\\n \\\"Content-Type\\\": \\\"application/json\\\",\\n },\\n body: {\\n query,\\n max_results: 5,\\n },\\n },\\n });\\n\\n // TODO(seefeld): Should we instead return { result, error }? Or allocate a\\n // special [ERROR] for errors? Ideally this isn\\'t specific to using recipes as\\n // tools but a general pattern.\\n return ifElse(error, { error }, result);\\n});\\n\\n/** Read and extract content from a specific webpage URL. */\\ntype ReadWebRequest = {\\n /** The URL of the webpage to read and extract content from. */\\n url: string;\\n};\\n\\ntype ReadWebResult = {\\n content: string;\\n metadata: {\\n title?: string;\\n author?: string;\\n date?: string;\\n word_count: number;\\n };\\n};\\n\\nexport const readWebpage = recipe<\\n ReadWebRequest,\\n ReadWebResult | { error: string }\\n>(\\\"Read Webpage\\\", ({ url }) => {\\n const { result, error } = fetchData({\\n url: \\\"/api/agent-tools/web-read\\\",\\n mode: \\\"json\\\",\\n options: {\\n method: \\\"POST\\\",\\n headers: {\\n \\\"Content-Type\\\": \\\"application/json\\\",\\n },\\n body: {\\n url,\\n max_tokens: 4000,\\n include_code: true,\\n },\\n },\\n });\\n\\n return ifElse(error, { error }, result);\\n});\\n\\ntype ToolsInput = {\\n list: ListItem[];\\n};\\n\\nexport default recipe(\\\"Tools\\\", ({ list }) => {\\n const tools: Record = {\\n search_web: {\\n pattern: searchWeb,\\n },\\n read_webpage: {\\n pattern: readWebpage,\\n },\\n calculator: {\\n pattern: calculator,\\n },\\n addListItem: {\\n handler: addListItem({ list }),\\n },\\n };\\n\\n return { tools, list };\\n});\\n\"}]}}" }, "spell": { "/": { "link@1": { "id": "of:baedreic5vwrifhgsveszaoiglpnwpg6muauspvb7lkbehia7oltjqtmeby" } } }, "argument": { "title": "four", "content": "", "allCharms": { "/": { "link@1": { "path": [], "id": "of:baedreiahv63wxwgaem4hzjkizl4qncfgvca7pj5cvdon7cukumfon3ioye", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } } } } }, "since": 92 } } }, "of:baedreicv3mllykrlg2ahbgffulevsda4qxjipyuntyfs7fdi4nzrxfiw6u": { "application/json": { "ba4jcbnnc4j37pfffwrsiel2ernmweiy7vi5ywfw2ht2togtmaeormugw": { "is": { "value": [ { "/": { "link@1": { "path": [], "id": "of:baedreidrrfrxknbyztmwaxzgzdbwlxjopw3qt23yvofd4jppiawcqysvja", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } } ], "source": { "/": "baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u" } }, "since": 37 } } }, "of:baedreidrrfrxknbyztmwaxzgzdbwlxjopw3qt23yvofd4jppiawcqysvja": { "application/json": { "ba4jcbkx5kt7bl7l74qtnaq7pe4a5n3yx7pjsybhx7scd5od2pofeihr6": { "is": { "source": { "/": "baedreibairjnl4kc3ttiik7et6vfykfw4rx23wrbgkofxln3qmhedkrlpy" }, "value": { "type": "vnode", "name": "ct-list-item", "props": { "onct-activate": { "$alias": { "path": [ "internal", "__#1stream" ], "schema": true, "rootSchema": true, "cell": { "/": "baedreibairjnl4kc3ttiik7et6vfykfw4rx23wrbgkofxln3qmhedkrlpy" } } } }, "children": [ { "type": "vnode", "name": "span", "props": { }, "children": [ { "$alias": { "path": [ "internal", "__#0" ], "cell": { "/": "baedreibairjnl4kc3ttiik7et6vfykfw4rx23wrbgkofxln3qmhedkrlpy" } } } ] }, { "type": "vnode", "name": "span", "props": { "slot": "meta" }, "children": [ { "$alias": { "path": [ "argument", "element", "local_id" ], "cell": { "/": "baedreibairjnl4kc3ttiik7et6vfykfw4rx23wrbgkofxln3qmhedkrlpy" } } } ] }, { "type": "vnode", "name": "ct-button", "props": { "slot": "actions", "size": "sm", "title": "Delete Chat", "variant": "destructive", "onClick": { "$alias": { "path": [ "internal", "$event" ], "schema": true, "rootSchema": true, "cell": { "/": "baedreibairjnl4kc3ttiik7et6vfykfw4rx23wrbgkofxln3qmhedkrlpy" } } } }, "children": [ "🗑️" ] } ] } }, "since": 37 } } }, "of:baedreibairjnl4kc3ttiik7et6vfykfw4rx23wrbgkofxln3qmhedkrlpy": { "application/json": { "ba4jcbcf7xnq7nyft6davnjwqzbfuxxyefdp7pnu2mtl4glc2wriu2vum": { "is": { "value": { "$TYPE": "ba4jcavuvtwicvswvypo2ldhglfd5vjhzkuhruzji3qmeyfo5nxyg2vhq", "resultRef": { "/": { "link@1": { "path": [], "id": "of:baedreidrrfrxknbyztmwaxzgzdbwlxjopw3qt23yvofd4jppiawcqysvja" } } }, "internal": { "$event": { "$stream": true }, "__#1stream": { "$stream": true }, "__#0": "New Chat" }, "spell": { "/": { "link@1": { "id": "of:baedreihuml7pvojy7ojbgjoubftlytaqi4dpmjnk6swchdosfe2tnenjxe" } } }, "argument": { "element": { "/": { "link@1": { "path": [ "argument", "charmsList", "0" ], "id": "of:baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF", "overwrite": "redirect" } } }, "index": 0, "array": { "/": { "link@1": { "path": [ "argument", "charmsList" ], "id": "of:baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF", "overwrite": "redirect" } } } } }, "source": { "/": "baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u" } }, "since": 39 } } }, "of:baedreiboekykwgdbufsup3shixvj6g2lbzlxy666g5lbhvdivuj7x375ae": { "application/json": { "ba4jcbjzcujw6isggsyq4qtum3cvznqqc52eaa3dtirk7ggr4vvvpnkae": { "is": { "value": { "local_id": "wtt20c2l", "charm": { "/": { "link@1": { "path": [], "id": "of:baedreih3s7r744kith3ntkg6oooklw2sy2vyycy22zlmm4l7rnizislpqa", "space": "did:key:z6MkkGMscCkDFETV5efoTSEybcVfo8muPQUp7qMa3mUGC4mF" } } } } }, "since": 24 } } }, "of:baedreihsyzn7myhp646sdiyb4ixi76jihj27hsgg3mcmlea6hqz72zaexe": { "application/json": { "ba4jca2ab4tt43k4icq3gfv6gq7t547cs3jezxo6nwrtfnov62wah7xzi": { "is": { "value": { "/": { "link@1": { "path": [ "1" ], "id": "data:application/json,%7B%22value%22%3A%5B%7B%22%24alias%22%3A%7B%22path%22%3A%5B%22internal%22%2C%22list%22%5D%2C%22cell%22%3A%7B%22%2F%22%3A%22baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u%22%7D%7D%7D%2C%7B%22type%22%3A%22vnode%22%2C%22name%22%3A%22common-fragment%22%2C%22props%22%3A%7B%7D%2C%22children%22%3A%5B%7B%22type%22%3A%22vnode%22%2C%22name%22%3A%22div%22%2C%22props%22%3A%7B%7D%2C%22children%22%3A%5B%7B%22type%22%3A%22vnode%22%2C%22name%22%3A%22ct-heading%22%2C%22props%22%3A%7B%22level%22%3A4%7D%2C%22children%22%3A%5B%22Backlinks%22%5D%7D%2C%7B%22type%22%3A%22vnode%22%2C%22name%22%3A%22ct-vstack%22%2C%22props%22%3A%7B%7D%2C%22children%22%3A%5B%7B%22%24alias%22%3A%7B%22path%22%3A%5B%22internal%22%2C%22__%230%22%5D%2C%22cell%22%3A%7B%22%2F%22%3A%22baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u%22%7D%7D%7D%5D%7D%5D%7D%2C%7B%22type%22%3A%22vnode%22%2C%22name%22%3A%22ct-ct-collapsible%22%2C%22props%22%3A%7B%7D%2C%22children%22%3A%5B%7B%22type%22%3A%22vnode%22%2C%22name%22%3A%22ct-heading%22%2C%22props%22%3A%7B%22slot%22%3A%22trigger%22%2C%22level%22%3A5%2C%22no-margin%22%3Atrue%7D%2C%22children%22%3A%5B%22List%22%5D%7D%2C%7B%22type%22%3A%22vnode%22%2C%22name%22%3A%22ct-list%22%2C%22props%22%3A%7B%22%24value%22%3A%7B%22%24alias%22%3A%7B%22path%22%3A%5B%22internal%22%2C%22list%22%2C%22list%22%5D%2C%22cell%22%3A%7B%22%2F%22%3A%22baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u%22%7D%7D%7D%7D%2C%22children%22%3A%5B%5D%7D%5D%7D%2C%7B%22type%22%3A%22vnode%22%2C%22name%22%3A%22ct-collapsible%22%2C%22props%22%3A%7B%7D%2C%22children%22%3A%5B%7B%22type%22%3A%22vnode%22%2C%22name%22%3A%22ct-heading%22%2C%22props%22%3A%7B%22slot%22%3A%22trigger%22%2C%22level%22%3A5%2C%22no-margin%22%3Atrue%7D%2C%22children%22%3A%5B%22Mentioned%20Charms%22%5D%7D%2C%7B%22type%22%3A%22vnode%22%2C%22name%22%3A%22ct-vstack%22%2C%22props%22%3A%7B%7D%2C%22children%22%3A%5B%7B%22%24alias%22%3A%7B%22path%22%3A%5B%22internal%22%2C%22__%231%22%5D%2C%22cell%22%3A%7B%22%2F%22%3A%22baedreibyee7wugohld5chzqxgckibuluga64i6zswmx7zqz67v2xp3mk3u%22%7D%7D%7D%5D%7D%5D%7D%5D%7D%2Cnull%5D%7D" } } } }, "since": 38 } } } }