@useago/sdk 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,18 @@
1
+ /**
2
+ * A minimal observable store: a single value plus synchronous subscriptions.
3
+ *
4
+ * ```ts
5
+ * const store = createStore({ count: 0 });
6
+ * const unsubscribe = store.subscribe((state) => save(state));
7
+ * store.set({ count: 1 }); // listeners fire synchronously
8
+ * ```
9
+ */
10
+ export interface Store<T> {
11
+ /** Current state. */
12
+ get(): T;
13
+ /** Replace the state and notify subscribers synchronously. */
14
+ set(next: T): void;
15
+ /** Register a listener; returns a function that removes it. */
16
+ subscribe(listener: (state: T) => void): () => void;
17
+ }
18
+ export declare function createStore<T>(initial: T): Store<T>;
@@ -0,0 +1,18 @@
1
+ import { type ShallowRef } from "vue";
2
+ import type { Store } from "../../state/createStore";
3
+ /**
4
+ * Read a framework-agnostic AGO store (`createStore`) as a reactive Vue ref.
5
+ *
6
+ * The ref's `.value` updates on every `store.set(...)`. Mutate through the store,
7
+ * not the ref. A `shallowRef` is used because the store replaces its value
8
+ * wholesale, so deep reactivity would be wasted work.
9
+ *
10
+ * ```ts
11
+ * const cart = createStore({ items: [] as string[] });
12
+ *
13
+ * // in setup():
14
+ * const state = useAgoStore(cart);
15
+ * // template: {{ state.items.length }}
16
+ * ```
17
+ */
18
+ export declare function useAgoStore<T>(store: Store<T>): ShallowRef<T>;
@@ -6,5 +6,6 @@ export { useMessages } from "./composables/useMessages";
6
6
  export { useConversation } from "./composables/useConversation";
7
7
  export { useAgoFunction, useAgoNavigation } from "./composables/useAgoFunction";
8
8
  export { useAgoEvents } from "./composables/useAgoEvents";
9
+ export { useAgoStore } from "./composables/useAgoStore";
9
10
  export { AGO_CLIENT_KEY } from "./symbols";
10
11
  export type { AgoConfig, AgoMessage, Conversation, AgoAgent, AgoSource, ToolCallData, } from "../client/types";
package/dist/vue.cjs CHANGED
@@ -298,12 +298,37 @@ function useAgoEvents(event, handler) {
298
298
  });
299
299
  }
300
300
  //#endregion
301
+ //#region src/vue/composables/useAgoStore.ts
302
+ /**
303
+ * Read a framework-agnostic AGO store (`createStore`) as a reactive Vue ref.
304
+ *
305
+ * The ref's `.value` updates on every `store.set(...)`. Mutate through the store,
306
+ * not the ref. A `shallowRef` is used because the store replaces its value
307
+ * wholesale, so deep reactivity would be wasted work.
308
+ *
309
+ * ```ts
310
+ * const cart = createStore({ items: [] as string[] });
311
+ *
312
+ * // in setup():
313
+ * const state = useAgoStore(cart);
314
+ * // template: {{ state.items.length }}
315
+ * ```
316
+ */
317
+ function useAgoStore(store) {
318
+ const state = (0, vue.shallowRef)(store.get());
319
+ (0, vue.onScopeDispose)(store.subscribe((next) => {
320
+ state.value = next;
321
+ }));
322
+ return state;
323
+ }
324
+ //#endregion
301
325
  exports.AGO_CLIENT_KEY = AGO_CLIENT_KEY;
302
326
  exports.AgoPlugin = AgoPlugin;
303
327
  exports.useAgo = useAgo;
304
328
  exports.useAgoEvents = useAgoEvents;
305
329
  exports.useAgoFunction = useAgoFunction;
306
330
  exports.useAgoNavigation = useAgoNavigation;
331
+ exports.useAgoStore = useAgoStore;
307
332
  exports.useChat = useChat;
308
333
  exports.useConversation = useConversation;
309
334
  exports.useMessages = useMessages;
package/dist/vue.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"vue.cjs","names":[],"sources":["../src/vue/symbols.ts","../src/vue/plugin.ts","../src/vue/composables/useAgo.ts","../src/vue/composables/useMessages.ts","../src/vue/composables/useConversation.ts","../src/vue/composables/useChat.ts","../src/vue/composables/useAgoFunction.ts","../src/vue/composables/useAgoEvents.ts"],"sourcesContent":["import type { InjectionKey } from \"vue\";\nimport type { AgoClient } from \"../client/AgoClient\";\n\nexport const AGO_CLIENT_KEY: InjectionKey<AgoClient> = Symbol(\"ago-client\");\n","import type { App } from \"vue\";\nimport { AgoClient } from \"../client/AgoClient\";\nimport type { AgoConfig } from \"../client/types\";\nimport { AGO_CLIENT_KEY } from \"./symbols\";\n\nexport interface AgoPluginOptions extends AgoConfig {}\n\n/**\n * Vue plugin that provides an AgoClient to the entire app via inject/provide.\n *\n * ```ts\n * import { AgoPlugin } from \"@useago/sdk/vue\";\n *\n * app.use(AgoPlugin, { baseUrl: \"https://YOUR-DOMAIN.useago.com\" });\n * ```\n */\nexport const AgoPlugin = {\n install(app: App, options: AgoPluginOptions) {\n const client = new AgoClient(options);\n app.provide(AGO_CLIENT_KEY, client);\n },\n};\n","import { inject } from \"vue\";\nimport { AgoClient } from \"../../client/AgoClient\";\nimport type { AgoConfig } from \"../../client/types\";\nimport { AGO_CLIENT_KEY } from \"../symbols\";\n\n/**\n * Get or create an AgoClient.\n *\n * - Without args: returns the client from `AgoPlugin` (throws if none).\n * - With config: creates a new client instance.\n *\n * ```ts\n * // From plugin\n * const client = useAgo();\n *\n * // Standalone\n * const client = useAgo({ baseUrl: \"https://YOUR-DOMAIN.useago.com\" });\n * ```\n */\nexport function useAgo(config?: AgoConfig): AgoClient {\n if (config) {\n return new AgoClient(config);\n }\n\n const client = inject(AGO_CLIENT_KEY);\n if (!client) {\n throw new Error(\n \"useAgo(): no AgoClient found. Either pass config or install AgoPlugin.\"\n );\n }\n return client;\n}\n","import { ref, onMounted, onUnmounted } from \"vue\";\nimport type { AgoClient } from \"../../client/AgoClient\";\nimport type { AgoMessage } from \"../../client/types\";\nimport { useAgo } from \"./useAgo\";\n\nexport interface UseMessagesOptions {\n client?: AgoClient;\n conversationId?: string;\n}\n\n/**\n * Composable to manage messages in a conversation.\n *\n * ```ts\n * const { messages, sendMessage, isLoading } = useMessages();\n * ```\n */\nexport function useMessages(options: UseMessagesOptions = {}) {\n const client = options.client ?? useAgo();\n\n const messages = ref<AgoMessage[]>([]);\n const conversationId = ref<string | undefined>(options.conversationId);\n const isLoading = ref(false);\n const error = ref<Error | null>(null);\n\n const handleStart = (data: { conversationId: string; messageId: string }) => {\n if (!conversationId.value) {\n conversationId.value = data.conversationId;\n }\n };\n\n const handleChunk = (data: { content: string; messageId: string }) => {\n const idx = messages.value.findIndex((m: AgoMessage) => m.id === data.messageId);\n if (idx >= 0) {\n messages.value[idx] = {\n ...messages.value[idx],\n content: messages.value[idx].content + data.content,\n };\n }\n };\n\n const handleComplete = (message: AgoMessage) => {\n const idx = messages.value.findIndex((m: AgoMessage) => m.id === message.id);\n if (idx >= 0) {\n messages.value[idx] = message;\n } else {\n messages.value.push(message);\n }\n isLoading.value = false;\n };\n\n const handleError = (data: { error: string }) => {\n error.value = new Error(data.error);\n isLoading.value = false;\n };\n\n onMounted(() => {\n client.on(\"message:start\", handleStart);\n client.on(\"message:chunk\", handleChunk);\n client.on(\"message:complete\", handleComplete);\n client.on(\"message:error\", handleError);\n });\n\n onUnmounted(() => {\n client.off(\"message:start\", handleStart);\n client.off(\"message:chunk\", handleChunk);\n client.off(\"message:complete\", handleComplete);\n client.off(\"message:error\", handleError);\n });\n\n async function sendMessage(content: string, files?: File[]): Promise<AgoMessage | null> {\n isLoading.value = true;\n error.value = null;\n\n // Optimistic user message\n const userMsg: AgoMessage = {\n id: `temp-${Date.now()}`,\n conversationId: conversationId.value || \"\",\n content,\n role: \"user\",\n status: \"DONE\",\n createdAt: new Date(),\n };\n const assistantMsg: AgoMessage = {\n id: `temp-assistant-${Date.now()}`,\n conversationId: conversationId.value || \"\",\n content: \"\",\n role: \"assistant\",\n status: \"IN_PROGRESS\",\n createdAt: new Date(),\n };\n messages.value.push(userMsg, assistantMsg);\n\n try {\n const response = await client.sendMessage(content, {\n conversationId: conversationId.value,\n files,\n });\n if (response.conversationId && !conversationId.value) {\n conversationId.value = response.conversationId;\n }\n // Replace temp messages\n messages.value = messages.value.filter((m: AgoMessage) => !m.id.startsWith(\"temp-\"));\n const updatedUser = { ...userMsg, id: userMsg.id.replace(\"temp-\", \"user-\"), conversationId: response.conversationId };\n if (!messages.value.some((m: AgoMessage) => m.id === response.id)) {\n messages.value.push(updatedUser, response);\n } else {\n messages.value.push(updatedUser);\n }\n return response;\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(\"Failed to send\");\n isLoading.value = false;\n messages.value = messages.value.filter((m: AgoMessage) => !m.id.startsWith(\"temp-\"));\n return null;\n }\n }\n\n function clearMessages() {\n messages.value = [];\n conversationId.value = undefined;\n error.value = null;\n }\n\n return { messages, isLoading, error, conversationId, sendMessage, clearMessages };\n}\n","import { ref, onMounted } from \"vue\";\nimport type { AgoClient } from \"../../client/AgoClient\";\nimport type { Conversation } from \"../../client/types\";\nimport { useAgo } from \"./useAgo\";\n\nexport interface UseConversationOptions {\n client?: AgoClient;\n autoLoad?: boolean;\n}\n\n/**\n * Composable to manage conversations.\n *\n * ```ts\n * const { conversations, selectConversation } = useConversation();\n * ```\n */\nexport function useConversation(options: UseConversationOptions = {}) {\n const client = options.client ?? useAgo();\n const autoLoad = options.autoLoad ?? true;\n\n const conversations = ref<Conversation[]>([]);\n const currentConversation = ref<Conversation | null>(null);\n const isLoading = ref(false);\n const error = ref<Error | null>(null);\n\n async function refreshConversations() {\n isLoading.value = true;\n error.value = null;\n try {\n conversations.value = await client.getConversations();\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(\"Failed to load conversations\");\n } finally {\n isLoading.value = false;\n }\n }\n\n async function selectConversation(id: string) {\n isLoading.value = true;\n error.value = null;\n try {\n currentConversation.value = await client.getConversation(id);\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(\"Failed to load conversation\");\n } finally {\n isLoading.value = false;\n }\n }\n\n function startNewConversation() {\n currentConversation.value = null;\n }\n\n onMounted(() => {\n if (autoLoad) refreshConversations();\n });\n\n return {\n conversations,\n currentConversation,\n isLoading,\n error,\n selectConversation,\n startNewConversation,\n refreshConversations,\n };\n}\n","import { computed } from \"vue\";\nimport type { AgoClient } from \"../../client/AgoClient\";\nimport { useMessages } from \"./useMessages\";\nimport { useConversation } from \"./useConversation\";\n\nexport interface UseChatOptions {\n client?: AgoClient;\n conversationId?: string;\n autoLoad?: boolean;\n}\n\n/**\n * All-in-one composable combining messages + conversations.\n *\n * ```ts\n * const { messages, sendMessage, conversations, selectConversation } = useChat();\n * ```\n */\nexport function useChat(options: UseChatOptions = {}) {\n const msgResult = useMessages({\n client: options.client,\n conversationId: options.conversationId,\n });\n\n const convResult = useConversation({\n client: options.client,\n autoLoad: options.autoLoad,\n });\n\n const error = computed(\n () => msgResult.error.value || convResult.error.value\n );\n\n return {\n // Messages\n messages: msgResult.messages,\n isLoading: msgResult.isLoading,\n error,\n sendMessage: msgResult.sendMessage,\n clearMessages: msgResult.clearMessages,\n conversationId: msgResult.conversationId,\n // Conversations\n conversations: convResult.conversations,\n currentConversation: convResult.currentConversation,\n isConversationsLoading: convResult.isLoading,\n selectConversation: convResult.selectConversation,\n startNewConversation: convResult.startNewConversation,\n refreshConversations: convResult.refreshConversations,\n };\n}\n","import { onMounted, onUnmounted } from \"vue\";\nimport type { ClientFunctionHandler, ClientFunctionSchema } from \"../../functions/types\";\nimport { useAgo } from \"./useAgo\";\n\n/**\n * Register a client-side function with auto-cleanup on unmount.\n *\n * ```ts\n * useAgoFunction(\"showToast\", {\n * description: \"Show a toast\",\n * parameters: { type: \"object\", properties: { message: { type: \"string\" } } },\n * handler: async (args) => { toast(args.message); return { shown: true }; },\n * });\n * ```\n */\nexport function useAgoFunction(\n name: string,\n options: {\n description: string;\n parameters: ClientFunctionSchema[\"parameters\"];\n handler: ClientFunctionHandler;\n }\n): void {\n const client = useAgo();\n\n onMounted(() => {\n client.registerFunction(name, options.handler, {\n description: options.description,\n parameters: options.parameters,\n });\n });\n\n onUnmounted(() => {\n client.unregisterFunction(name);\n });\n}\n\nexport interface AgoRoute {\n name: string;\n path: string;\n description: string;\n}\n\n/**\n * Register navigation routes with auto-cleanup on unmount.\n * Works with vue-router's `useRouter().push`.\n *\n * ```ts\n * const router = useRouter();\n * useAgoNavigation((path) => router.push(path), [\n * { name: \"dashboard\", path: \"/dashboard\", description: \"Main dashboard\" },\n * ]);\n * ```\n */\nexport function useAgoNavigation(\n navigate: (path: string) => void,\n routes: AgoRoute[]\n): void {\n const client = useAgo();\n\n onMounted(() => {\n client.registerNavigationFunction(navigate, routes);\n });\n\n onUnmounted(() => {\n client.unregisterFunction(\"navigateToPage\");\n });\n}\n","import { onMounted, onUnmounted } from \"vue\";\nimport type { AgoClientEvents, AgoEventName } from \"../../client/types\";\nimport { useAgo } from \"./useAgo\";\n\n/**\n * Subscribe to AGO client events with auto-cleanup on unmount.\n *\n * ```ts\n * useAgoEvents(\"message:complete\", (msg) => {\n * console.log(\"Got message:\", msg.content);\n * });\n * ```\n */\nexport function useAgoEvents<K extends AgoEventName>(\n event: K,\n handler: (data: AgoClientEvents[K]) => void\n): void {\n const client = useAgo();\n\n onMounted(() => {\n client.on(event, handler);\n });\n\n onUnmounted(() => {\n client.off(event, handler);\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"vue.cjs","names":[],"sources":["../src/vue/symbols.ts","../src/vue/plugin.ts","../src/vue/composables/useAgo.ts","../src/vue/composables/useMessages.ts","../src/vue/composables/useConversation.ts","../src/vue/composables/useChat.ts","../src/vue/composables/useAgoFunction.ts","../src/vue/composables/useAgoEvents.ts","../src/vue/composables/useAgoStore.ts"],"sourcesContent":["import type { InjectionKey } from \"vue\";\nimport type { AgoClient } from \"../client/AgoClient\";\n\nexport const AGO_CLIENT_KEY: InjectionKey<AgoClient> = Symbol(\"ago-client\");\n","import type { App } from \"vue\";\nimport { AgoClient } from \"../client/AgoClient\";\nimport type { AgoConfig } from \"../client/types\";\nimport { AGO_CLIENT_KEY } from \"./symbols\";\n\nexport interface AgoPluginOptions extends AgoConfig {}\n\n/**\n * Vue plugin that provides an AgoClient to the entire app via inject/provide.\n *\n * ```ts\n * import { AgoPlugin } from \"@useago/sdk/vue\";\n *\n * app.use(AgoPlugin, { baseUrl: \"https://YOUR-DOMAIN.useago.com\" });\n * ```\n */\nexport const AgoPlugin = {\n install(app: App, options: AgoPluginOptions) {\n const client = new AgoClient(options);\n app.provide(AGO_CLIENT_KEY, client);\n },\n};\n","import { inject } from \"vue\";\nimport { AgoClient } from \"../../client/AgoClient\";\nimport type { AgoConfig } from \"../../client/types\";\nimport { AGO_CLIENT_KEY } from \"../symbols\";\n\n/**\n * Get or create an AgoClient.\n *\n * - Without args: returns the client from `AgoPlugin` (throws if none).\n * - With config: creates a new client instance.\n *\n * ```ts\n * // From plugin\n * const client = useAgo();\n *\n * // Standalone\n * const client = useAgo({ baseUrl: \"https://YOUR-DOMAIN.useago.com\" });\n * ```\n */\nexport function useAgo(config?: AgoConfig): AgoClient {\n if (config) {\n return new AgoClient(config);\n }\n\n const client = inject(AGO_CLIENT_KEY);\n if (!client) {\n throw new Error(\n \"useAgo(): no AgoClient found. Either pass config or install AgoPlugin.\"\n );\n }\n return client;\n}\n","import { ref, onMounted, onUnmounted } from \"vue\";\nimport type { AgoClient } from \"../../client/AgoClient\";\nimport type { AgoMessage } from \"../../client/types\";\nimport { useAgo } from \"./useAgo\";\n\nexport interface UseMessagesOptions {\n client?: AgoClient;\n conversationId?: string;\n}\n\n/**\n * Composable to manage messages in a conversation.\n *\n * ```ts\n * const { messages, sendMessage, isLoading } = useMessages();\n * ```\n */\nexport function useMessages(options: UseMessagesOptions = {}) {\n const client = options.client ?? useAgo();\n\n const messages = ref<AgoMessage[]>([]);\n const conversationId = ref<string | undefined>(options.conversationId);\n const isLoading = ref(false);\n const error = ref<Error | null>(null);\n\n const handleStart = (data: { conversationId: string; messageId: string }) => {\n if (!conversationId.value) {\n conversationId.value = data.conversationId;\n }\n };\n\n const handleChunk = (data: { content: string; messageId: string }) => {\n const idx = messages.value.findIndex((m: AgoMessage) => m.id === data.messageId);\n if (idx >= 0) {\n messages.value[idx] = {\n ...messages.value[idx],\n content: messages.value[idx].content + data.content,\n };\n }\n };\n\n const handleComplete = (message: AgoMessage) => {\n const idx = messages.value.findIndex((m: AgoMessage) => m.id === message.id);\n if (idx >= 0) {\n messages.value[idx] = message;\n } else {\n messages.value.push(message);\n }\n isLoading.value = false;\n };\n\n const handleError = (data: { error: string }) => {\n error.value = new Error(data.error);\n isLoading.value = false;\n };\n\n onMounted(() => {\n client.on(\"message:start\", handleStart);\n client.on(\"message:chunk\", handleChunk);\n client.on(\"message:complete\", handleComplete);\n client.on(\"message:error\", handleError);\n });\n\n onUnmounted(() => {\n client.off(\"message:start\", handleStart);\n client.off(\"message:chunk\", handleChunk);\n client.off(\"message:complete\", handleComplete);\n client.off(\"message:error\", handleError);\n });\n\n async function sendMessage(content: string, files?: File[]): Promise<AgoMessage | null> {\n isLoading.value = true;\n error.value = null;\n\n // Optimistic user message\n const userMsg: AgoMessage = {\n id: `temp-${Date.now()}`,\n conversationId: conversationId.value || \"\",\n content,\n role: \"user\",\n status: \"DONE\",\n createdAt: new Date(),\n };\n const assistantMsg: AgoMessage = {\n id: `temp-assistant-${Date.now()}`,\n conversationId: conversationId.value || \"\",\n content: \"\",\n role: \"assistant\",\n status: \"IN_PROGRESS\",\n createdAt: new Date(),\n };\n messages.value.push(userMsg, assistantMsg);\n\n try {\n const response = await client.sendMessage(content, {\n conversationId: conversationId.value,\n files,\n });\n if (response.conversationId && !conversationId.value) {\n conversationId.value = response.conversationId;\n }\n // Replace temp messages\n messages.value = messages.value.filter((m: AgoMessage) => !m.id.startsWith(\"temp-\"));\n const updatedUser = { ...userMsg, id: userMsg.id.replace(\"temp-\", \"user-\"), conversationId: response.conversationId };\n if (!messages.value.some((m: AgoMessage) => m.id === response.id)) {\n messages.value.push(updatedUser, response);\n } else {\n messages.value.push(updatedUser);\n }\n return response;\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(\"Failed to send\");\n isLoading.value = false;\n messages.value = messages.value.filter((m: AgoMessage) => !m.id.startsWith(\"temp-\"));\n return null;\n }\n }\n\n function clearMessages() {\n messages.value = [];\n conversationId.value = undefined;\n error.value = null;\n }\n\n return { messages, isLoading, error, conversationId, sendMessage, clearMessages };\n}\n","import { ref, onMounted } from \"vue\";\nimport type { AgoClient } from \"../../client/AgoClient\";\nimport type { Conversation } from \"../../client/types\";\nimport { useAgo } from \"./useAgo\";\n\nexport interface UseConversationOptions {\n client?: AgoClient;\n autoLoad?: boolean;\n}\n\n/**\n * Composable to manage conversations.\n *\n * ```ts\n * const { conversations, selectConversation } = useConversation();\n * ```\n */\nexport function useConversation(options: UseConversationOptions = {}) {\n const client = options.client ?? useAgo();\n const autoLoad = options.autoLoad ?? true;\n\n const conversations = ref<Conversation[]>([]);\n const currentConversation = ref<Conversation | null>(null);\n const isLoading = ref(false);\n const error = ref<Error | null>(null);\n\n async function refreshConversations() {\n isLoading.value = true;\n error.value = null;\n try {\n conversations.value = await client.getConversations();\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(\"Failed to load conversations\");\n } finally {\n isLoading.value = false;\n }\n }\n\n async function selectConversation(id: string) {\n isLoading.value = true;\n error.value = null;\n try {\n currentConversation.value = await client.getConversation(id);\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(\"Failed to load conversation\");\n } finally {\n isLoading.value = false;\n }\n }\n\n function startNewConversation() {\n currentConversation.value = null;\n }\n\n onMounted(() => {\n if (autoLoad) refreshConversations();\n });\n\n return {\n conversations,\n currentConversation,\n isLoading,\n error,\n selectConversation,\n startNewConversation,\n refreshConversations,\n };\n}\n","import { computed } from \"vue\";\nimport type { AgoClient } from \"../../client/AgoClient\";\nimport { useMessages } from \"./useMessages\";\nimport { useConversation } from \"./useConversation\";\n\nexport interface UseChatOptions {\n client?: AgoClient;\n conversationId?: string;\n autoLoad?: boolean;\n}\n\n/**\n * All-in-one composable combining messages + conversations.\n *\n * ```ts\n * const { messages, sendMessage, conversations, selectConversation } = useChat();\n * ```\n */\nexport function useChat(options: UseChatOptions = {}) {\n const msgResult = useMessages({\n client: options.client,\n conversationId: options.conversationId,\n });\n\n const convResult = useConversation({\n client: options.client,\n autoLoad: options.autoLoad,\n });\n\n const error = computed(\n () => msgResult.error.value || convResult.error.value\n );\n\n return {\n // Messages\n messages: msgResult.messages,\n isLoading: msgResult.isLoading,\n error,\n sendMessage: msgResult.sendMessage,\n clearMessages: msgResult.clearMessages,\n conversationId: msgResult.conversationId,\n // Conversations\n conversations: convResult.conversations,\n currentConversation: convResult.currentConversation,\n isConversationsLoading: convResult.isLoading,\n selectConversation: convResult.selectConversation,\n startNewConversation: convResult.startNewConversation,\n refreshConversations: convResult.refreshConversations,\n };\n}\n","import { onMounted, onUnmounted } from \"vue\";\nimport type { ClientFunctionHandler, ClientFunctionSchema } from \"../../functions/types\";\nimport { useAgo } from \"./useAgo\";\n\n/**\n * Register a client-side function with auto-cleanup on unmount.\n *\n * ```ts\n * useAgoFunction(\"showToast\", {\n * description: \"Show a toast\",\n * parameters: { type: \"object\", properties: { message: { type: \"string\" } } },\n * handler: async (args) => { toast(args.message); return { shown: true }; },\n * });\n * ```\n */\nexport function useAgoFunction(\n name: string,\n options: {\n description: string;\n parameters: ClientFunctionSchema[\"parameters\"];\n handler: ClientFunctionHandler;\n }\n): void {\n const client = useAgo();\n\n onMounted(() => {\n client.registerFunction(name, options.handler, {\n description: options.description,\n parameters: options.parameters,\n });\n });\n\n onUnmounted(() => {\n client.unregisterFunction(name);\n });\n}\n\nexport interface AgoRoute {\n name: string;\n path: string;\n description: string;\n}\n\n/**\n * Register navigation routes with auto-cleanup on unmount.\n * Works with vue-router's `useRouter().push`.\n *\n * ```ts\n * const router = useRouter();\n * useAgoNavigation((path) => router.push(path), [\n * { name: \"dashboard\", path: \"/dashboard\", description: \"Main dashboard\" },\n * ]);\n * ```\n */\nexport function useAgoNavigation(\n navigate: (path: string) => void,\n routes: AgoRoute[]\n): void {\n const client = useAgo();\n\n onMounted(() => {\n client.registerNavigationFunction(navigate, routes);\n });\n\n onUnmounted(() => {\n client.unregisterFunction(\"navigateToPage\");\n });\n}\n","import { onMounted, onUnmounted } from \"vue\";\nimport type { AgoClientEvents, AgoEventName } from \"../../client/types\";\nimport { useAgo } from \"./useAgo\";\n\n/**\n * Subscribe to AGO client events with auto-cleanup on unmount.\n *\n * ```ts\n * useAgoEvents(\"message:complete\", (msg) => {\n * console.log(\"Got message:\", msg.content);\n * });\n * ```\n */\nexport function useAgoEvents<K extends AgoEventName>(\n event: K,\n handler: (data: AgoClientEvents[K]) => void\n): void {\n const client = useAgo();\n\n onMounted(() => {\n client.on(event, handler);\n });\n\n onUnmounted(() => {\n client.off(event, handler);\n });\n}\n","import { shallowRef, onScopeDispose, type ShallowRef } from \"vue\";\nimport type { Store } from \"../../state/createStore\";\n\n/**\n * Read a framework-agnostic AGO store (`createStore`) as a reactive Vue ref.\n *\n * The ref's `.value` updates on every `store.set(...)`. Mutate through the store,\n * not the ref. A `shallowRef` is used because the store replaces its value\n * wholesale, so deep reactivity would be wasted work.\n *\n * ```ts\n * const cart = createStore({ items: [] as string[] });\n *\n * // in setup():\n * const state = useAgoStore(cart);\n * // template: {{ state.items.length }}\n * ```\n */\nexport function useAgoStore<T>(store: Store<T>): ShallowRef<T> {\n const state = shallowRef(store.get()) as ShallowRef<T>;\n // Subscribe during setup so no updates are missed before mount; clean up when\n // the surrounding effect scope (the component) is disposed.\n const unsubscribe = store.subscribe((next) => {\n state.value = next;\n });\n onScopeDispose(unsubscribe);\n return state;\n}\n"],"mappings":"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"}
package/dist/vue.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as AgoClient } from "./AgoClient-CNT-8sh_.js";
2
- import { computed, inject, onMounted, onUnmounted, ref } from "vue";
2
+ import { computed, inject, onMounted, onScopeDispose, onUnmounted, ref, shallowRef } from "vue";
3
3
  //#region src/vue/symbols.ts
4
4
  var AGO_CLIENT_KEY = Symbol("ago-client");
5
5
  //#endregion
@@ -296,6 +296,30 @@ function useAgoEvents(event, handler) {
296
296
  });
297
297
  }
298
298
  //#endregion
299
- export { AGO_CLIENT_KEY, AgoPlugin, useAgo, useAgoEvents, useAgoFunction, useAgoNavigation, useChat, useConversation, useMessages };
299
+ //#region src/vue/composables/useAgoStore.ts
300
+ /**
301
+ * Read a framework-agnostic AGO store (`createStore`) as a reactive Vue ref.
302
+ *
303
+ * The ref's `.value` updates on every `store.set(...)`. Mutate through the store,
304
+ * not the ref. A `shallowRef` is used because the store replaces its value
305
+ * wholesale, so deep reactivity would be wasted work.
306
+ *
307
+ * ```ts
308
+ * const cart = createStore({ items: [] as string[] });
309
+ *
310
+ * // in setup():
311
+ * const state = useAgoStore(cart);
312
+ * // template: {{ state.items.length }}
313
+ * ```
314
+ */
315
+ function useAgoStore(store) {
316
+ const state = shallowRef(store.get());
317
+ onScopeDispose(store.subscribe((next) => {
318
+ state.value = next;
319
+ }));
320
+ return state;
321
+ }
322
+ //#endregion
323
+ export { AGO_CLIENT_KEY, AgoPlugin, useAgo, useAgoEvents, useAgoFunction, useAgoNavigation, useAgoStore, useChat, useConversation, useMessages };
300
324
 
301
325
  //# sourceMappingURL=vue.js.map
package/dist/vue.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"vue.js","names":[],"sources":["../src/vue/symbols.ts","../src/vue/plugin.ts","../src/vue/composables/useAgo.ts","../src/vue/composables/useMessages.ts","../src/vue/composables/useConversation.ts","../src/vue/composables/useChat.ts","../src/vue/composables/useAgoFunction.ts","../src/vue/composables/useAgoEvents.ts"],"sourcesContent":["import type { InjectionKey } from \"vue\";\nimport type { AgoClient } from \"../client/AgoClient\";\n\nexport const AGO_CLIENT_KEY: InjectionKey<AgoClient> = Symbol(\"ago-client\");\n","import type { App } from \"vue\";\nimport { AgoClient } from \"../client/AgoClient\";\nimport type { AgoConfig } from \"../client/types\";\nimport { AGO_CLIENT_KEY } from \"./symbols\";\n\nexport interface AgoPluginOptions extends AgoConfig {}\n\n/**\n * Vue plugin that provides an AgoClient to the entire app via inject/provide.\n *\n * ```ts\n * import { AgoPlugin } from \"@useago/sdk/vue\";\n *\n * app.use(AgoPlugin, { baseUrl: \"https://YOUR-DOMAIN.useago.com\" });\n * ```\n */\nexport const AgoPlugin = {\n install(app: App, options: AgoPluginOptions) {\n const client = new AgoClient(options);\n app.provide(AGO_CLIENT_KEY, client);\n },\n};\n","import { inject } from \"vue\";\nimport { AgoClient } from \"../../client/AgoClient\";\nimport type { AgoConfig } from \"../../client/types\";\nimport { AGO_CLIENT_KEY } from \"../symbols\";\n\n/**\n * Get or create an AgoClient.\n *\n * - Without args: returns the client from `AgoPlugin` (throws if none).\n * - With config: creates a new client instance.\n *\n * ```ts\n * // From plugin\n * const client = useAgo();\n *\n * // Standalone\n * const client = useAgo({ baseUrl: \"https://YOUR-DOMAIN.useago.com\" });\n * ```\n */\nexport function useAgo(config?: AgoConfig): AgoClient {\n if (config) {\n return new AgoClient(config);\n }\n\n const client = inject(AGO_CLIENT_KEY);\n if (!client) {\n throw new Error(\n \"useAgo(): no AgoClient found. Either pass config or install AgoPlugin.\"\n );\n }\n return client;\n}\n","import { ref, onMounted, onUnmounted } from \"vue\";\nimport type { AgoClient } from \"../../client/AgoClient\";\nimport type { AgoMessage } from \"../../client/types\";\nimport { useAgo } from \"./useAgo\";\n\nexport interface UseMessagesOptions {\n client?: AgoClient;\n conversationId?: string;\n}\n\n/**\n * Composable to manage messages in a conversation.\n *\n * ```ts\n * const { messages, sendMessage, isLoading } = useMessages();\n * ```\n */\nexport function useMessages(options: UseMessagesOptions = {}) {\n const client = options.client ?? useAgo();\n\n const messages = ref<AgoMessage[]>([]);\n const conversationId = ref<string | undefined>(options.conversationId);\n const isLoading = ref(false);\n const error = ref<Error | null>(null);\n\n const handleStart = (data: { conversationId: string; messageId: string }) => {\n if (!conversationId.value) {\n conversationId.value = data.conversationId;\n }\n };\n\n const handleChunk = (data: { content: string; messageId: string }) => {\n const idx = messages.value.findIndex((m: AgoMessage) => m.id === data.messageId);\n if (idx >= 0) {\n messages.value[idx] = {\n ...messages.value[idx],\n content: messages.value[idx].content + data.content,\n };\n }\n };\n\n const handleComplete = (message: AgoMessage) => {\n const idx = messages.value.findIndex((m: AgoMessage) => m.id === message.id);\n if (idx >= 0) {\n messages.value[idx] = message;\n } else {\n messages.value.push(message);\n }\n isLoading.value = false;\n };\n\n const handleError = (data: { error: string }) => {\n error.value = new Error(data.error);\n isLoading.value = false;\n };\n\n onMounted(() => {\n client.on(\"message:start\", handleStart);\n client.on(\"message:chunk\", handleChunk);\n client.on(\"message:complete\", handleComplete);\n client.on(\"message:error\", handleError);\n });\n\n onUnmounted(() => {\n client.off(\"message:start\", handleStart);\n client.off(\"message:chunk\", handleChunk);\n client.off(\"message:complete\", handleComplete);\n client.off(\"message:error\", handleError);\n });\n\n async function sendMessage(content: string, files?: File[]): Promise<AgoMessage | null> {\n isLoading.value = true;\n error.value = null;\n\n // Optimistic user message\n const userMsg: AgoMessage = {\n id: `temp-${Date.now()}`,\n conversationId: conversationId.value || \"\",\n content,\n role: \"user\",\n status: \"DONE\",\n createdAt: new Date(),\n };\n const assistantMsg: AgoMessage = {\n id: `temp-assistant-${Date.now()}`,\n conversationId: conversationId.value || \"\",\n content: \"\",\n role: \"assistant\",\n status: \"IN_PROGRESS\",\n createdAt: new Date(),\n };\n messages.value.push(userMsg, assistantMsg);\n\n try {\n const response = await client.sendMessage(content, {\n conversationId: conversationId.value,\n files,\n });\n if (response.conversationId && !conversationId.value) {\n conversationId.value = response.conversationId;\n }\n // Replace temp messages\n messages.value = messages.value.filter((m: AgoMessage) => !m.id.startsWith(\"temp-\"));\n const updatedUser = { ...userMsg, id: userMsg.id.replace(\"temp-\", \"user-\"), conversationId: response.conversationId };\n if (!messages.value.some((m: AgoMessage) => m.id === response.id)) {\n messages.value.push(updatedUser, response);\n } else {\n messages.value.push(updatedUser);\n }\n return response;\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(\"Failed to send\");\n isLoading.value = false;\n messages.value = messages.value.filter((m: AgoMessage) => !m.id.startsWith(\"temp-\"));\n return null;\n }\n }\n\n function clearMessages() {\n messages.value = [];\n conversationId.value = undefined;\n error.value = null;\n }\n\n return { messages, isLoading, error, conversationId, sendMessage, clearMessages };\n}\n","import { ref, onMounted } from \"vue\";\nimport type { AgoClient } from \"../../client/AgoClient\";\nimport type { Conversation } from \"../../client/types\";\nimport { useAgo } from \"./useAgo\";\n\nexport interface UseConversationOptions {\n client?: AgoClient;\n autoLoad?: boolean;\n}\n\n/**\n * Composable to manage conversations.\n *\n * ```ts\n * const { conversations, selectConversation } = useConversation();\n * ```\n */\nexport function useConversation(options: UseConversationOptions = {}) {\n const client = options.client ?? useAgo();\n const autoLoad = options.autoLoad ?? true;\n\n const conversations = ref<Conversation[]>([]);\n const currentConversation = ref<Conversation | null>(null);\n const isLoading = ref(false);\n const error = ref<Error | null>(null);\n\n async function refreshConversations() {\n isLoading.value = true;\n error.value = null;\n try {\n conversations.value = await client.getConversations();\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(\"Failed to load conversations\");\n } finally {\n isLoading.value = false;\n }\n }\n\n async function selectConversation(id: string) {\n isLoading.value = true;\n error.value = null;\n try {\n currentConversation.value = await client.getConversation(id);\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(\"Failed to load conversation\");\n } finally {\n isLoading.value = false;\n }\n }\n\n function startNewConversation() {\n currentConversation.value = null;\n }\n\n onMounted(() => {\n if (autoLoad) refreshConversations();\n });\n\n return {\n conversations,\n currentConversation,\n isLoading,\n error,\n selectConversation,\n startNewConversation,\n refreshConversations,\n };\n}\n","import { computed } from \"vue\";\nimport type { AgoClient } from \"../../client/AgoClient\";\nimport { useMessages } from \"./useMessages\";\nimport { useConversation } from \"./useConversation\";\n\nexport interface UseChatOptions {\n client?: AgoClient;\n conversationId?: string;\n autoLoad?: boolean;\n}\n\n/**\n * All-in-one composable combining messages + conversations.\n *\n * ```ts\n * const { messages, sendMessage, conversations, selectConversation } = useChat();\n * ```\n */\nexport function useChat(options: UseChatOptions = {}) {\n const msgResult = useMessages({\n client: options.client,\n conversationId: options.conversationId,\n });\n\n const convResult = useConversation({\n client: options.client,\n autoLoad: options.autoLoad,\n });\n\n const error = computed(\n () => msgResult.error.value || convResult.error.value\n );\n\n return {\n // Messages\n messages: msgResult.messages,\n isLoading: msgResult.isLoading,\n error,\n sendMessage: msgResult.sendMessage,\n clearMessages: msgResult.clearMessages,\n conversationId: msgResult.conversationId,\n // Conversations\n conversations: convResult.conversations,\n currentConversation: convResult.currentConversation,\n isConversationsLoading: convResult.isLoading,\n selectConversation: convResult.selectConversation,\n startNewConversation: convResult.startNewConversation,\n refreshConversations: convResult.refreshConversations,\n };\n}\n","import { onMounted, onUnmounted } from \"vue\";\nimport type { ClientFunctionHandler, ClientFunctionSchema } from \"../../functions/types\";\nimport { useAgo } from \"./useAgo\";\n\n/**\n * Register a client-side function with auto-cleanup on unmount.\n *\n * ```ts\n * useAgoFunction(\"showToast\", {\n * description: \"Show a toast\",\n * parameters: { type: \"object\", properties: { message: { type: \"string\" } } },\n * handler: async (args) => { toast(args.message); return { shown: true }; },\n * });\n * ```\n */\nexport function useAgoFunction(\n name: string,\n options: {\n description: string;\n parameters: ClientFunctionSchema[\"parameters\"];\n handler: ClientFunctionHandler;\n }\n): void {\n const client = useAgo();\n\n onMounted(() => {\n client.registerFunction(name, options.handler, {\n description: options.description,\n parameters: options.parameters,\n });\n });\n\n onUnmounted(() => {\n client.unregisterFunction(name);\n });\n}\n\nexport interface AgoRoute {\n name: string;\n path: string;\n description: string;\n}\n\n/**\n * Register navigation routes with auto-cleanup on unmount.\n * Works with vue-router's `useRouter().push`.\n *\n * ```ts\n * const router = useRouter();\n * useAgoNavigation((path) => router.push(path), [\n * { name: \"dashboard\", path: \"/dashboard\", description: \"Main dashboard\" },\n * ]);\n * ```\n */\nexport function useAgoNavigation(\n navigate: (path: string) => void,\n routes: AgoRoute[]\n): void {\n const client = useAgo();\n\n onMounted(() => {\n client.registerNavigationFunction(navigate, routes);\n });\n\n onUnmounted(() => {\n client.unregisterFunction(\"navigateToPage\");\n });\n}\n","import { onMounted, onUnmounted } from \"vue\";\nimport type { AgoClientEvents, AgoEventName } from \"../../client/types\";\nimport { useAgo } from \"./useAgo\";\n\n/**\n * Subscribe to AGO client events with auto-cleanup on unmount.\n *\n * ```ts\n * useAgoEvents(\"message:complete\", (msg) => {\n * console.log(\"Got message:\", msg.content);\n * });\n * ```\n */\nexport function useAgoEvents<K extends AgoEventName>(\n event: K,\n handler: (data: AgoClientEvents[K]) => void\n): void {\n const client = useAgo();\n\n onMounted(() => {\n client.on(event, handler);\n });\n\n onUnmounted(() => {\n client.off(event, handler);\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"vue.js","names":[],"sources":["../src/vue/symbols.ts","../src/vue/plugin.ts","../src/vue/composables/useAgo.ts","../src/vue/composables/useMessages.ts","../src/vue/composables/useConversation.ts","../src/vue/composables/useChat.ts","../src/vue/composables/useAgoFunction.ts","../src/vue/composables/useAgoEvents.ts","../src/vue/composables/useAgoStore.ts"],"sourcesContent":["import type { InjectionKey } from \"vue\";\nimport type { AgoClient } from \"../client/AgoClient\";\n\nexport const AGO_CLIENT_KEY: InjectionKey<AgoClient> = Symbol(\"ago-client\");\n","import type { App } from \"vue\";\nimport { AgoClient } from \"../client/AgoClient\";\nimport type { AgoConfig } from \"../client/types\";\nimport { AGO_CLIENT_KEY } from \"./symbols\";\n\nexport interface AgoPluginOptions extends AgoConfig {}\n\n/**\n * Vue plugin that provides an AgoClient to the entire app via inject/provide.\n *\n * ```ts\n * import { AgoPlugin } from \"@useago/sdk/vue\";\n *\n * app.use(AgoPlugin, { baseUrl: \"https://YOUR-DOMAIN.useago.com\" });\n * ```\n */\nexport const AgoPlugin = {\n install(app: App, options: AgoPluginOptions) {\n const client = new AgoClient(options);\n app.provide(AGO_CLIENT_KEY, client);\n },\n};\n","import { inject } from \"vue\";\nimport { AgoClient } from \"../../client/AgoClient\";\nimport type { AgoConfig } from \"../../client/types\";\nimport { AGO_CLIENT_KEY } from \"../symbols\";\n\n/**\n * Get or create an AgoClient.\n *\n * - Without args: returns the client from `AgoPlugin` (throws if none).\n * - With config: creates a new client instance.\n *\n * ```ts\n * // From plugin\n * const client = useAgo();\n *\n * // Standalone\n * const client = useAgo({ baseUrl: \"https://YOUR-DOMAIN.useago.com\" });\n * ```\n */\nexport function useAgo(config?: AgoConfig): AgoClient {\n if (config) {\n return new AgoClient(config);\n }\n\n const client = inject(AGO_CLIENT_KEY);\n if (!client) {\n throw new Error(\n \"useAgo(): no AgoClient found. Either pass config or install AgoPlugin.\"\n );\n }\n return client;\n}\n","import { ref, onMounted, onUnmounted } from \"vue\";\nimport type { AgoClient } from \"../../client/AgoClient\";\nimport type { AgoMessage } from \"../../client/types\";\nimport { useAgo } from \"./useAgo\";\n\nexport interface UseMessagesOptions {\n client?: AgoClient;\n conversationId?: string;\n}\n\n/**\n * Composable to manage messages in a conversation.\n *\n * ```ts\n * const { messages, sendMessage, isLoading } = useMessages();\n * ```\n */\nexport function useMessages(options: UseMessagesOptions = {}) {\n const client = options.client ?? useAgo();\n\n const messages = ref<AgoMessage[]>([]);\n const conversationId = ref<string | undefined>(options.conversationId);\n const isLoading = ref(false);\n const error = ref<Error | null>(null);\n\n const handleStart = (data: { conversationId: string; messageId: string }) => {\n if (!conversationId.value) {\n conversationId.value = data.conversationId;\n }\n };\n\n const handleChunk = (data: { content: string; messageId: string }) => {\n const idx = messages.value.findIndex((m: AgoMessage) => m.id === data.messageId);\n if (idx >= 0) {\n messages.value[idx] = {\n ...messages.value[idx],\n content: messages.value[idx].content + data.content,\n };\n }\n };\n\n const handleComplete = (message: AgoMessage) => {\n const idx = messages.value.findIndex((m: AgoMessage) => m.id === message.id);\n if (idx >= 0) {\n messages.value[idx] = message;\n } else {\n messages.value.push(message);\n }\n isLoading.value = false;\n };\n\n const handleError = (data: { error: string }) => {\n error.value = new Error(data.error);\n isLoading.value = false;\n };\n\n onMounted(() => {\n client.on(\"message:start\", handleStart);\n client.on(\"message:chunk\", handleChunk);\n client.on(\"message:complete\", handleComplete);\n client.on(\"message:error\", handleError);\n });\n\n onUnmounted(() => {\n client.off(\"message:start\", handleStart);\n client.off(\"message:chunk\", handleChunk);\n client.off(\"message:complete\", handleComplete);\n client.off(\"message:error\", handleError);\n });\n\n async function sendMessage(content: string, files?: File[]): Promise<AgoMessage | null> {\n isLoading.value = true;\n error.value = null;\n\n // Optimistic user message\n const userMsg: AgoMessage = {\n id: `temp-${Date.now()}`,\n conversationId: conversationId.value || \"\",\n content,\n role: \"user\",\n status: \"DONE\",\n createdAt: new Date(),\n };\n const assistantMsg: AgoMessage = {\n id: `temp-assistant-${Date.now()}`,\n conversationId: conversationId.value || \"\",\n content: \"\",\n role: \"assistant\",\n status: \"IN_PROGRESS\",\n createdAt: new Date(),\n };\n messages.value.push(userMsg, assistantMsg);\n\n try {\n const response = await client.sendMessage(content, {\n conversationId: conversationId.value,\n files,\n });\n if (response.conversationId && !conversationId.value) {\n conversationId.value = response.conversationId;\n }\n // Replace temp messages\n messages.value = messages.value.filter((m: AgoMessage) => !m.id.startsWith(\"temp-\"));\n const updatedUser = { ...userMsg, id: userMsg.id.replace(\"temp-\", \"user-\"), conversationId: response.conversationId };\n if (!messages.value.some((m: AgoMessage) => m.id === response.id)) {\n messages.value.push(updatedUser, response);\n } else {\n messages.value.push(updatedUser);\n }\n return response;\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(\"Failed to send\");\n isLoading.value = false;\n messages.value = messages.value.filter((m: AgoMessage) => !m.id.startsWith(\"temp-\"));\n return null;\n }\n }\n\n function clearMessages() {\n messages.value = [];\n conversationId.value = undefined;\n error.value = null;\n }\n\n return { messages, isLoading, error, conversationId, sendMessage, clearMessages };\n}\n","import { ref, onMounted } from \"vue\";\nimport type { AgoClient } from \"../../client/AgoClient\";\nimport type { Conversation } from \"../../client/types\";\nimport { useAgo } from \"./useAgo\";\n\nexport interface UseConversationOptions {\n client?: AgoClient;\n autoLoad?: boolean;\n}\n\n/**\n * Composable to manage conversations.\n *\n * ```ts\n * const { conversations, selectConversation } = useConversation();\n * ```\n */\nexport function useConversation(options: UseConversationOptions = {}) {\n const client = options.client ?? useAgo();\n const autoLoad = options.autoLoad ?? true;\n\n const conversations = ref<Conversation[]>([]);\n const currentConversation = ref<Conversation | null>(null);\n const isLoading = ref(false);\n const error = ref<Error | null>(null);\n\n async function refreshConversations() {\n isLoading.value = true;\n error.value = null;\n try {\n conversations.value = await client.getConversations();\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(\"Failed to load conversations\");\n } finally {\n isLoading.value = false;\n }\n }\n\n async function selectConversation(id: string) {\n isLoading.value = true;\n error.value = null;\n try {\n currentConversation.value = await client.getConversation(id);\n } catch (err) {\n error.value = err instanceof Error ? err : new Error(\"Failed to load conversation\");\n } finally {\n isLoading.value = false;\n }\n }\n\n function startNewConversation() {\n currentConversation.value = null;\n }\n\n onMounted(() => {\n if (autoLoad) refreshConversations();\n });\n\n return {\n conversations,\n currentConversation,\n isLoading,\n error,\n selectConversation,\n startNewConversation,\n refreshConversations,\n };\n}\n","import { computed } from \"vue\";\nimport type { AgoClient } from \"../../client/AgoClient\";\nimport { useMessages } from \"./useMessages\";\nimport { useConversation } from \"./useConversation\";\n\nexport interface UseChatOptions {\n client?: AgoClient;\n conversationId?: string;\n autoLoad?: boolean;\n}\n\n/**\n * All-in-one composable combining messages + conversations.\n *\n * ```ts\n * const { messages, sendMessage, conversations, selectConversation } = useChat();\n * ```\n */\nexport function useChat(options: UseChatOptions = {}) {\n const msgResult = useMessages({\n client: options.client,\n conversationId: options.conversationId,\n });\n\n const convResult = useConversation({\n client: options.client,\n autoLoad: options.autoLoad,\n });\n\n const error = computed(\n () => msgResult.error.value || convResult.error.value\n );\n\n return {\n // Messages\n messages: msgResult.messages,\n isLoading: msgResult.isLoading,\n error,\n sendMessage: msgResult.sendMessage,\n clearMessages: msgResult.clearMessages,\n conversationId: msgResult.conversationId,\n // Conversations\n conversations: convResult.conversations,\n currentConversation: convResult.currentConversation,\n isConversationsLoading: convResult.isLoading,\n selectConversation: convResult.selectConversation,\n startNewConversation: convResult.startNewConversation,\n refreshConversations: convResult.refreshConversations,\n };\n}\n","import { onMounted, onUnmounted } from \"vue\";\nimport type { ClientFunctionHandler, ClientFunctionSchema } from \"../../functions/types\";\nimport { useAgo } from \"./useAgo\";\n\n/**\n * Register a client-side function with auto-cleanup on unmount.\n *\n * ```ts\n * useAgoFunction(\"showToast\", {\n * description: \"Show a toast\",\n * parameters: { type: \"object\", properties: { message: { type: \"string\" } } },\n * handler: async (args) => { toast(args.message); return { shown: true }; },\n * });\n * ```\n */\nexport function useAgoFunction(\n name: string,\n options: {\n description: string;\n parameters: ClientFunctionSchema[\"parameters\"];\n handler: ClientFunctionHandler;\n }\n): void {\n const client = useAgo();\n\n onMounted(() => {\n client.registerFunction(name, options.handler, {\n description: options.description,\n parameters: options.parameters,\n });\n });\n\n onUnmounted(() => {\n client.unregisterFunction(name);\n });\n}\n\nexport interface AgoRoute {\n name: string;\n path: string;\n description: string;\n}\n\n/**\n * Register navigation routes with auto-cleanup on unmount.\n * Works with vue-router's `useRouter().push`.\n *\n * ```ts\n * const router = useRouter();\n * useAgoNavigation((path) => router.push(path), [\n * { name: \"dashboard\", path: \"/dashboard\", description: \"Main dashboard\" },\n * ]);\n * ```\n */\nexport function useAgoNavigation(\n navigate: (path: string) => void,\n routes: AgoRoute[]\n): void {\n const client = useAgo();\n\n onMounted(() => {\n client.registerNavigationFunction(navigate, routes);\n });\n\n onUnmounted(() => {\n client.unregisterFunction(\"navigateToPage\");\n });\n}\n","import { onMounted, onUnmounted } from \"vue\";\nimport type { AgoClientEvents, AgoEventName } from \"../../client/types\";\nimport { useAgo } from \"./useAgo\";\n\n/**\n * Subscribe to AGO client events with auto-cleanup on unmount.\n *\n * ```ts\n * useAgoEvents(\"message:complete\", (msg) => {\n * console.log(\"Got message:\", msg.content);\n * });\n * ```\n */\nexport function useAgoEvents<K extends AgoEventName>(\n event: K,\n handler: (data: AgoClientEvents[K]) => void\n): void {\n const client = useAgo();\n\n onMounted(() => {\n client.on(event, handler);\n });\n\n onUnmounted(() => {\n client.off(event, handler);\n });\n}\n","import { shallowRef, onScopeDispose, type ShallowRef } from \"vue\";\nimport type { Store } from \"../../state/createStore\";\n\n/**\n * Read a framework-agnostic AGO store (`createStore`) as a reactive Vue ref.\n *\n * The ref's `.value` updates on every `store.set(...)`. Mutate through the store,\n * not the ref. A `shallowRef` is used because the store replaces its value\n * wholesale, so deep reactivity would be wasted work.\n *\n * ```ts\n * const cart = createStore({ items: [] as string[] });\n *\n * // in setup():\n * const state = useAgoStore(cart);\n * // template: {{ state.items.length }}\n * ```\n */\nexport function useAgoStore<T>(store: Store<T>): ShallowRef<T> {\n const state = shallowRef(store.get()) as ShallowRef<T>;\n // Subscribe during setup so no updates are missed before mount; clean up when\n // the surrounding effect scope (the component) is disposed.\n const unsubscribe = store.subscribe((next) => {\n state.value = next;\n });\n onScopeDispose(unsubscribe);\n return state;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useago/sdk",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "JavaScript SDK for AGO Chat integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",