import { type BuiltInLLMMessage, computed, type Default, handler, llmDialog, NAME, pattern, patternTool, str, type Stream, toSchema, UI, type VNode, Writable, } from "commonfabric"; import { readWebpage, searchWeb } from "./system/common-fabric.tsx"; type ResearchResult = { summary: string; findings: { title: string; source: string; content: string; }[]; sources: string[]; confidence: "high" | "medium" | "low"; }; const triggerGeneration = handler< unknown, { addMessage: Stream; situation: string; result: any | null; } >((_, { addMessage, situation, result }) => { if (!result) { addMessage.send({ role: "user", content: [{ type: "text" as const, text: situation }], }); } }); const sendMessage = handler< { detail: { text: string; attachments?: Array } }, { addMessage: Stream } >((event, { addMessage }) => { addMessage.send({ role: "user", content: [{ type: "text" as const, text: event.detail.text }], }); }); const showRefineInput = handler }>( (_, { showRefine }) => { showRefine.set(true); }, ); export default pattern< { situation: | string | Default<"What are the latest developments in AI agents?">; messages?: Writable | Default<[]>>; context?: { [id: string]: any }; }, { result: any; [UI]: VNode } >(({ situation, messages, context }) => { const systemPrompt = computed( () => `You are a deep research agent. Given a question, use the available tools to: 1. Search the web for relevant information 2. Read promising web pages to gather detailed content 3. Synthesize your findings into a comprehensive answer Your textual responses are invisible to the user, they can only see the presented result. Be thorough - search for multiple aspects of the question and read several sources before forming your answer. When done, call presentResult with your structured findings.`, ); const { addMessage, pending, result: dialogResult, } = llmDialog({ system: systemPrompt, messages, tools: { searchWeb: patternTool(searchWeb), readWebpage: patternTool(readWebpage), }, context: computed(() => context ?? {}), resultSchema: toSchema(), }); const result = computed(() => dialogResult as ResearchResult | undefined); const showRefine = new Writable(false); return { [NAME]: str`Research: ${situation}`, result, [UI]: (

{computed(() => (result?.summary ? "Summary" : ""))}

{computed(() => result?.summary ?? "")}

{computed(() => result?.confidence ? `Confidence: ${result.confidence}` : "" )}

{computed(() => (result?.findings?.length ? "Findings" : ""))}

{computed(() => result?.findings?.map((f: any) => `${f.title}\n${f.content}\n(${f.source})` ).join("\n\n") ?? "" )}

{computed(() => (result?.sources?.length ? "Sources" : ""))}

{computed(() => result?.sources?.join("\n") ?? "")}

(showRefine.get() ? "" : "display:none"))} oncf-send={sendMessage({ addMessage })} />
), }; });