From 6f83da2cf6d0f1f82d4d85e345ebe606402c7335 Mon Sep 17 00:00:00 2001 From: Mike Thicke Date: Fri, 9 May 2025 12:11:14 -0400 Subject: [PATCH] Sources list --- package-lock.json | 24 ++++++++++++------------ src/components/ChatInterface.tsx | 8 +++++++- src/components/SourceList.tsx | 17 +++++++++++++++++ src/services/model-service.ts | 19 ++++++++++++++++--- 4 files changed, 52 insertions(+), 16 deletions(-) create mode 100644 src/components/SourceList.tsx diff --git a/package-lock.json b/package-lock.json index 3a305b9..157e7b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1728,9 +1728,9 @@ } }, "node_modules/fdir": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", - "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", "dev": true, "license": "MIT", "peerDependencies": { @@ -2667,13 +2667,13 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", - "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", + "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", "dev": true, "license": "MIT", "dependencies": { - "fdir": "^6.4.3", + "fdir": "^6.4.4", "picomatch": "^4.0.2" }, "engines": { @@ -2775,18 +2775,18 @@ "license": "ISC" }, "node_modules/vite": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.1.tgz", - "integrity": "sha512-kkzzkqtMESYklo96HKKPE5KKLkC1amlsqt+RjFMlX2AvbRB/0wghap19NdBxxwGZ+h/C6DLCrcEphPIItlGrRQ==", + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", - "fdir": "^6.4.3", + "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", - "tinyglobby": "^0.2.12" + "tinyglobby": "^0.2.13" }, "bin": { "vite": "bin/vite.js" diff --git a/src/components/ChatInterface.tsx b/src/components/ChatInterface.tsx index 5e0e362..5a8d4fa 100644 --- a/src/components/ChatInterface.tsx +++ b/src/components/ChatInterface.tsx @@ -8,11 +8,13 @@ import { ContextNote, ChatRequest, generateChatTitle, + Source, } from "@/services/model-service"; import { PluginContext, ChangeCallbackContext, AppContext } from "@/CoiChatApp"; import { ChatHistory } from "@/components/ChatHistory"; import { UserInput } from "@/components/UserInput"; import { LinkedNotes } from "@/components/LinkedNotes"; +import { SourceList } from "@/components/SourceList"; export interface ChatInterfaceProps { initialMessages: CoreMessage[]; @@ -50,6 +52,8 @@ export const ChatInterface = ({ const [messages, setMessages] = createSignal(initialMessages); const [linkedNotes, setLinkedNotes] = createSignal(initialLinkedNotes); + const [sources, setSources] = createSignal([]); + const app = useContext(AppContext); const handleLinkNote = (file: TFile) => { @@ -102,7 +106,7 @@ export const ChatInterface = ({ const responseStream = await generateChatResponse(request, registry); let accumulatedContent = ""; - for await (const chunk of responseStream) { + for await (const chunk of responseStream.textStream) { accumulatedContent += chunk; const responseMessage: CoreMessage = { role: "assistant", @@ -114,6 +118,7 @@ export const ChatInterface = ({ return updatedMessages; }); } + setSources(await responseStream.sources); const newTitle = await generateChatTitle(model().id, messages(), registry); if (onChange) { onChange(messages(), newTitle, linkedNotes()); @@ -123,6 +128,7 @@ export const ChatInterface = ({ return (
+ {sources().length > 0 && } {linkedNotes().length > 0 && ( { + return ( +
+
    + {sources.map((source) => ( +
  1. + + {source.title ?? source.url} + +
  2. + ))} +
+
+ ); +}; diff --git a/src/services/model-service.ts b/src/services/model-service.ts index 4a22c6f..2dada85 100644 --- a/src/services/model-service.ts +++ b/src/services/model-service.ts @@ -1,4 +1,11 @@ -import { streamText, generateText, GenerateTextResult, CoreMessage } from "ai"; +import { + streamText, + generateText, + GenerateTextResult, + CoreMessage, + StreamTextResult, + ToolSet, +} from "ai"; import { ModelRegistry, ModelId } from "./model-registry"; export interface ContextNote { @@ -16,6 +23,12 @@ export interface ChatRequest { contextNotes?: ContextNote[]; } +export interface Source { + id: string; + url: string; + title?: string; +} + /** * Generates a chat response based on the provided request. * @@ -27,7 +40,7 @@ export interface ChatRequest { export async function generateChatResponse( request: ChatRequest, registry: ModelRegistry, -): Promise> { +): Promise> { const model = registry.getLanguageModel(request.modelId); // Prepare context from linked notes if any @@ -55,7 +68,7 @@ export async function generateChatResponse( }; const result = streamText(config); - return result.textStream; + return result; } export async function generateChatTitle(