Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@copass/mastra

Package Overview
Dependencies
Maintainers
1
Versions
29
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@copass/mastra - npm Package Compare versions

Comparing version
0.5.10
to
0.5.11
+6
-1
dist/index.cjs

@@ -58,3 +58,8 @@ "use strict";

subgraph: item.subgraph ?? null,
matched_query_nodes: item.matched_query_nodes ?? null
matched_query_nodes: item.matched_query_nodes ?? null,
// Inline source-file paths so the agent can `read` directly
// without a follow-up `get_origin` call. Empty array when
// the backend couldn't enrich (legacy sandbox / no file
// markers in source chunks).
file_paths: item.file_paths ?? []
})),

@@ -61,0 +66,0 @@ next_steps: response.next_steps

+1
-1

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/index.ts","../src/tools.ts","../src/window-tracker.ts"],"sourcesContent":["export { copassTools } from './tools.js';\nexport type { CopassToolsOptions } from './tools.js';\nexport { createWindowTracker } from './window-tracker.js';\nexport type {\n WindowTracker,\n WindowTrackerOptions,\n StepFinishLike,\n} from './window-tracker.js';\n","import { createTool } from '@mastra/core/tools';\nimport { z } from 'zod';\nimport {\n DISCOVER_DESCRIPTION,\n DISCOVER_QUERY_PARAM,\n GET_ORIGIN_DESCRIPTION,\n INTERPRET_DESCRIPTION,\n INTERPRET_ITEMS_PARAM,\n INTERPRET_QUERY_PARAM,\n ORIGIN_CANONICAL_IDS_PARAM,\n ORIGIN_LIMIT_PARAM,\n SEARCH_DESCRIPTION,\n SEARCH_QUERY_PARAM,\n} from '@copass/config';\nimport type {\n CopassClient,\n OriginEntry,\n OriginFile,\n SearchPreset,\n WindowLike,\n} from '@copass/core';\n\nexport interface CopassToolsOptions {\n /** An authenticated `@copass/core` client. */\n client: CopassClient;\n /** Sandbox all retrieval runs against. */\n sandbox_id: string;\n /** Optional project scoping for retrieval calls. */\n project_id?: string;\n /**\n * Optional conversation window — a {@link WindowLike} (typically a\n * `ContextWindow` from `client.contextWindow.create()`). When provided,\n * every retrieval call is automatically window-aware.\n */\n window?: WindowLike;\n /**\n * Preset for `discover`, `interpret`, and `search`. Defaults to\n * `\"copass/copass_1.0\"`. Under `\"copass/copass_2.0\"` discover items\n * carry `subgraph` (pre-rendered ASCII tree) and `matched_query_nodes`\n * fields. Append `\":thinking\"` (e.g. `\"copass/copass_2.0:thinking\"`)\n * to enable task decomposition before retrieval on `search`.\n */\n preset?: SearchPreset;\n}\n\n/**\n * Return Copass retrieval as a set of Mastra tool objects (built with\n * `createTool` from `@mastra/core/tools`).\n *\n * Agent-framework-neutral shape: the LLM picks `discover` (menu of\n * relevant items) or `search` (synthesized answer). `interpret` stays\n * registered for back-compat but is legacy — prefer `search` for drill-in.\n *\n * @example\n * ```ts\n * import { Agent } from '@mastra/core/agent';\n * import { anthropic } from '@ai-sdk/anthropic';\n * import { copassTools } from '@copass/mastra';\n *\n * const window = await copass.contextWindow.create({ sandbox_id });\n * const tools = copassTools({ client: copass, sandbox_id, window });\n *\n * const agent = new Agent({\n * name: 'support-bot',\n * instructions: 'Answer questions using the knowledge graph.',\n * model: anthropic('claude-opus-4-7'),\n * tools,\n * });\n *\n * const response = await agent.generate('why is checkout flaky?');\n * ```\n */\nexport function copassTools(options: CopassToolsOptions) {\n const { client, sandbox_id, project_id, window, preset = 'copass/copass_1.0' } = options;\n\n const discover = createTool({\n id: 'discover',\n description: DISCOVER_DESCRIPTION,\n inputSchema: z.object({\n query: z.string().describe(DISCOVER_QUERY_PARAM),\n }),\n execute: async ({ query }) => {\n const response = await client.retrieval.discover(sandbox_id, {\n query,\n project_id,\n window,\n preset,\n });\n return {\n header: response.header,\n // Project the v2 fields (`subgraph` + `matched_query_nodes`)\n // alongside the v1 fields. Populated only under\n // `copass/copass_2.0` (or its `copass/2.0` alias); `null` under\n // v1 — agents can ignore them when not present.\n items: response.items.map((item) => ({\n score: item.score,\n summary: item.summary,\n canonical_ids: item.canonical_ids,\n subgraph: item.subgraph ?? null,\n matched_query_nodes: item.matched_query_nodes ?? null,\n })),\n next_steps: response.next_steps,\n };\n },\n });\n\n const interpret = createTool({\n id: 'interpret',\n description: INTERPRET_DESCRIPTION,\n inputSchema: z.object({\n query: z.string().describe(INTERPRET_QUERY_PARAM),\n items: z.array(z.array(z.string())).min(1).describe(INTERPRET_ITEMS_PARAM),\n }),\n execute: async ({ query, items }) => {\n const response = await client.retrieval.interpret(sandbox_id, {\n query,\n items,\n project_id,\n window,\n preset,\n });\n return { brief: response.brief };\n },\n });\n\n const search = createTool({\n id: 'search',\n description: SEARCH_DESCRIPTION,\n inputSchema: z.object({\n query: z.string().describe(SEARCH_QUERY_PARAM),\n }),\n execute: async ({ query }) => {\n const response = await client.retrieval.search(sandbox_id, {\n query,\n project_id,\n window,\n preset,\n });\n return { answer: response.answer };\n },\n });\n\n const get_origin = createTool({\n id: 'get_origin',\n description: GET_ORIGIN_DESCRIPTION,\n inputSchema: z.object({\n canonical_ids: z\n .array(z.string())\n .min(1)\n .max(100)\n .describe(ORIGIN_CANONICAL_IDS_PARAM),\n limit_per_canonical: z\n .number()\n .int()\n .min(1)\n .max(50)\n .optional()\n .describe(ORIGIN_LIMIT_PARAM),\n }),\n execute: async ({ canonical_ids, limit_per_canonical }) => {\n const response = await client.retrieval.getOrigin(sandbox_id, {\n canonical_ids,\n ...(limit_per_canonical !== undefined ? { limit_per_canonical } : {}),\n });\n return {\n sandbox_id: response.sandbox_id,\n origins: response.origins.map((entry: OriginEntry) => ({\n canonical_id: entry.canonical_id,\n files: entry.files.map((f: OriginFile) => ({\n file_path: f.file_path,\n extraction_count: f.extraction_count,\n })),\n })),\n };\n },\n });\n\n return { discover, interpret, search, get_origin };\n}\n","import type { ChatMessage, ChatRole, ContextWindow } from '@copass/core';\n\n/**\n * Minimal shape of a step finish event — Mastra's `Agent.generate()` /\n * `.stream()` accept an `onStepFinish` callback that is structurally\n * compatible with this type. Typed structurally so the adapter doesn't lock\n * to a specific `@mastra/core` major version.\n */\nexport interface StepFinishLike {\n response?: {\n messages?: Array<{\n role?: string;\n content?: unknown;\n }>;\n };\n}\n\nexport interface WindowTrackerOptions {\n /** The Context Window to mirror messages into. */\n window: ContextWindow;\n /**\n * Include `tool` messages (results returned by a tool call) as turns.\n * Default: false — tool results are usually retrieval noise.\n */\n includeToolMessages?: boolean;\n}\n\nexport interface WindowTracker {\n /**\n * Pass to Mastra's `agent.generate()` / `agent.stream()` as `onStepFinish`.\n * Each step's assistant + tool output messages land in the window,\n * de-duplicated against what's already there.\n */\n onStepFinish: (step: StepFinishLike) => Promise<void>;\n /**\n * Record the user's turn before you call `agent.generate()`. Step callbacks\n * only surface messages *generated* during a step, so the user's initial\n * input has to be captured explicitly. Safe to call repeatedly — the tracker\n * de-duplicates.\n */\n recordUserTurn: (content: string) => Promise<void>;\n}\n\n/**\n * Build a window tracker for Mastra agent loops.\n *\n * @example\n * ```ts\n * import { copassTools, createWindowTracker } from '@copass/mastra';\n *\n * const tools = copassTools({ client, sandbox_id, window });\n * const tracker = createWindowTracker({ window });\n *\n * const agent = new Agent({ name: 'support', model, tools });\n *\n * await tracker.recordUserTurn(userMessage);\n * const response = await agent.generate(userMessage, {\n * onStepFinish: tracker.onStepFinish,\n * maxSteps: 5,\n * });\n * ```\n */\nexport function createWindowTracker(options: WindowTrackerOptions): WindowTracker {\n const { window, includeToolMessages = false } = options;\n const seen = new Set<string>();\n for (const turn of window.getTurns()) {\n seen.add(hashTurn(turn));\n }\n\n async function addIfNew(turn: ChatMessage): Promise<void> {\n if (!turn.content.trim()) return;\n const key = hashTurn(turn);\n if (seen.has(key)) return;\n seen.add(key);\n try {\n await window.addTurn(turn);\n } catch {\n /* best-effort */\n }\n }\n\n return {\n async onStepFinish(step) {\n const messages = step.response?.messages ?? [];\n for (const msg of messages) {\n const role = roleFromRole(msg.role, includeToolMessages);\n if (!role) continue;\n await addIfNew({ role, content: contentToString(msg.content) });\n }\n },\n recordUserTurn(content) {\n return addIfNew({ role: 'user', content });\n },\n };\n}\n\nfunction roleFromRole(role: string | undefined, includeToolMessages: boolean): ChatRole | null {\n switch (role) {\n case 'user':\n return 'user';\n case 'assistant':\n return 'assistant';\n case 'system':\n return 'system';\n case 'tool':\n return includeToolMessages ? 'system' : null;\n default:\n return null;\n }\n}\n\nfunction contentToString(content: unknown): string {\n if (typeof content === 'string') return content;\n if (!Array.isArray(content)) return String(content ?? '');\n return content\n .map((part) => {\n if (typeof part === 'string') return part;\n if (part && typeof part === 'object') {\n const rec = part as Record<string, unknown>;\n if (typeof rec.text === 'string') return rec.text;\n }\n return '';\n })\n .filter(Boolean)\n .join('\\n');\n}\n\nfunction hashTurn(turn: ChatMessage): string {\n return `${turn.role}:${turn.content.slice(0, 500)}`;\n}\n"],"mappings":"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","names":[]}
{"version":3,"sources":["../src/index.ts","../src/tools.ts","../src/window-tracker.ts"],"sourcesContent":["export { copassTools } from './tools.js';\nexport type { CopassToolsOptions } from './tools.js';\nexport { createWindowTracker } from './window-tracker.js';\nexport type {\n WindowTracker,\n WindowTrackerOptions,\n StepFinishLike,\n} from './window-tracker.js';\n","import { createTool } from '@mastra/core/tools';\nimport { z } from 'zod';\nimport {\n DISCOVER_DESCRIPTION,\n DISCOVER_QUERY_PARAM,\n GET_ORIGIN_DESCRIPTION,\n INTERPRET_DESCRIPTION,\n INTERPRET_ITEMS_PARAM,\n INTERPRET_QUERY_PARAM,\n ORIGIN_CANONICAL_IDS_PARAM,\n ORIGIN_LIMIT_PARAM,\n SEARCH_DESCRIPTION,\n SEARCH_QUERY_PARAM,\n} from '@copass/config';\nimport type {\n CopassClient,\n OriginEntry,\n OriginFile,\n SearchPreset,\n WindowLike,\n} from '@copass/core';\n\nexport interface CopassToolsOptions {\n /** An authenticated `@copass/core` client. */\n client: CopassClient;\n /** Sandbox all retrieval runs against. */\n sandbox_id: string;\n /** Optional project scoping for retrieval calls. */\n project_id?: string;\n /**\n * Optional conversation window — a {@link WindowLike} (typically a\n * `ContextWindow` from `client.contextWindow.create()`). When provided,\n * every retrieval call is automatically window-aware.\n */\n window?: WindowLike;\n /**\n * Preset for `discover`, `interpret`, and `search`. Defaults to\n * `\"copass/copass_1.0\"`. Under `\"copass/copass_2.0\"` discover items\n * carry `subgraph` (pre-rendered ASCII tree) and `matched_query_nodes`\n * fields. Append `\":thinking\"` (e.g. `\"copass/copass_2.0:thinking\"`)\n * to enable task decomposition before retrieval on `search`.\n */\n preset?: SearchPreset;\n}\n\n/**\n * Return Copass retrieval as a set of Mastra tool objects (built with\n * `createTool` from `@mastra/core/tools`).\n *\n * Agent-framework-neutral shape: the LLM picks `discover` (menu of\n * relevant items) or `search` (synthesized answer). `interpret` stays\n * registered for back-compat but is legacy — prefer `search` for drill-in.\n *\n * @example\n * ```ts\n * import { Agent } from '@mastra/core/agent';\n * import { anthropic } from '@ai-sdk/anthropic';\n * import { copassTools } from '@copass/mastra';\n *\n * const window = await copass.contextWindow.create({ sandbox_id });\n * const tools = copassTools({ client: copass, sandbox_id, window });\n *\n * const agent = new Agent({\n * name: 'support-bot',\n * instructions: 'Answer questions using the knowledge graph.',\n * model: anthropic('claude-opus-4-7'),\n * tools,\n * });\n *\n * const response = await agent.generate('why is checkout flaky?');\n * ```\n */\nexport function copassTools(options: CopassToolsOptions) {\n const { client, sandbox_id, project_id, window, preset = 'copass/copass_1.0' } = options;\n\n const discover = createTool({\n id: 'discover',\n description: DISCOVER_DESCRIPTION,\n inputSchema: z.object({\n query: z.string().describe(DISCOVER_QUERY_PARAM),\n }),\n execute: async ({ query }) => {\n const response = await client.retrieval.discover(sandbox_id, {\n query,\n project_id,\n window,\n preset,\n });\n return {\n header: response.header,\n // Project the v2 fields (`subgraph` + `matched_query_nodes`)\n // alongside the v1 fields. Populated only under\n // `copass/copass_2.0` (or its `copass/2.0` alias); `null` under\n // v1 — agents can ignore them when not present.\n items: response.items.map((item) => ({\n score: item.score,\n summary: item.summary,\n canonical_ids: item.canonical_ids,\n subgraph: item.subgraph ?? null,\n matched_query_nodes: item.matched_query_nodes ?? null,\n // Inline source-file paths so the agent can `read` directly\n // without a follow-up `get_origin` call. Empty array when\n // the backend couldn't enrich (legacy sandbox / no file\n // markers in source chunks).\n file_paths: item.file_paths ?? [],\n })),\n next_steps: response.next_steps,\n };\n },\n });\n\n const interpret = createTool({\n id: 'interpret',\n description: INTERPRET_DESCRIPTION,\n inputSchema: z.object({\n query: z.string().describe(INTERPRET_QUERY_PARAM),\n items: z.array(z.array(z.string())).min(1).describe(INTERPRET_ITEMS_PARAM),\n }),\n execute: async ({ query, items }) => {\n const response = await client.retrieval.interpret(sandbox_id, {\n query,\n items,\n project_id,\n window,\n preset,\n });\n return { brief: response.brief };\n },\n });\n\n const search = createTool({\n id: 'search',\n description: SEARCH_DESCRIPTION,\n inputSchema: z.object({\n query: z.string().describe(SEARCH_QUERY_PARAM),\n }),\n execute: async ({ query }) => {\n const response = await client.retrieval.search(sandbox_id, {\n query,\n project_id,\n window,\n preset,\n });\n return { answer: response.answer };\n },\n });\n\n const get_origin = createTool({\n id: 'get_origin',\n description: GET_ORIGIN_DESCRIPTION,\n inputSchema: z.object({\n canonical_ids: z\n .array(z.string())\n .min(1)\n .max(100)\n .describe(ORIGIN_CANONICAL_IDS_PARAM),\n limit_per_canonical: z\n .number()\n .int()\n .min(1)\n .max(50)\n .optional()\n .describe(ORIGIN_LIMIT_PARAM),\n }),\n execute: async ({ canonical_ids, limit_per_canonical }) => {\n const response = await client.retrieval.getOrigin(sandbox_id, {\n canonical_ids,\n ...(limit_per_canonical !== undefined ? { limit_per_canonical } : {}),\n });\n return {\n sandbox_id: response.sandbox_id,\n origins: response.origins.map((entry: OriginEntry) => ({\n canonical_id: entry.canonical_id,\n files: entry.files.map((f: OriginFile) => ({\n file_path: f.file_path,\n extraction_count: f.extraction_count,\n })),\n })),\n };\n },\n });\n\n return { discover, interpret, search, get_origin };\n}\n","import type { ChatMessage, ChatRole, ContextWindow } from '@copass/core';\n\n/**\n * Minimal shape of a step finish event — Mastra's `Agent.generate()` /\n * `.stream()` accept an `onStepFinish` callback that is structurally\n * compatible with this type. Typed structurally so the adapter doesn't lock\n * to a specific `@mastra/core` major version.\n */\nexport interface StepFinishLike {\n response?: {\n messages?: Array<{\n role?: string;\n content?: unknown;\n }>;\n };\n}\n\nexport interface WindowTrackerOptions {\n /** The Context Window to mirror messages into. */\n window: ContextWindow;\n /**\n * Include `tool` messages (results returned by a tool call) as turns.\n * Default: false — tool results are usually retrieval noise.\n */\n includeToolMessages?: boolean;\n}\n\nexport interface WindowTracker {\n /**\n * Pass to Mastra's `agent.generate()` / `agent.stream()` as `onStepFinish`.\n * Each step's assistant + tool output messages land in the window,\n * de-duplicated against what's already there.\n */\n onStepFinish: (step: StepFinishLike) => Promise<void>;\n /**\n * Record the user's turn before you call `agent.generate()`. Step callbacks\n * only surface messages *generated* during a step, so the user's initial\n * input has to be captured explicitly. Safe to call repeatedly — the tracker\n * de-duplicates.\n */\n recordUserTurn: (content: string) => Promise<void>;\n}\n\n/**\n * Build a window tracker for Mastra agent loops.\n *\n * @example\n * ```ts\n * import { copassTools, createWindowTracker } from '@copass/mastra';\n *\n * const tools = copassTools({ client, sandbox_id, window });\n * const tracker = createWindowTracker({ window });\n *\n * const agent = new Agent({ name: 'support', model, tools });\n *\n * await tracker.recordUserTurn(userMessage);\n * const response = await agent.generate(userMessage, {\n * onStepFinish: tracker.onStepFinish,\n * maxSteps: 5,\n * });\n * ```\n */\nexport function createWindowTracker(options: WindowTrackerOptions): WindowTracker {\n const { window, includeToolMessages = false } = options;\n const seen = new Set<string>();\n for (const turn of window.getTurns()) {\n seen.add(hashTurn(turn));\n }\n\n async function addIfNew(turn: ChatMessage): Promise<void> {\n if (!turn.content.trim()) return;\n const key = hashTurn(turn);\n if (seen.has(key)) return;\n seen.add(key);\n try {\n await window.addTurn(turn);\n } catch {\n /* best-effort */\n }\n }\n\n return {\n async onStepFinish(step) {\n const messages = step.response?.messages ?? [];\n for (const msg of messages) {\n const role = roleFromRole(msg.role, includeToolMessages);\n if (!role) continue;\n await addIfNew({ role, content: contentToString(msg.content) });\n }\n },\n recordUserTurn(content) {\n return addIfNew({ role: 'user', content });\n },\n };\n}\n\nfunction roleFromRole(role: string | undefined, includeToolMessages: boolean): ChatRole | null {\n switch (role) {\n case 'user':\n return 'user';\n case 'assistant':\n return 'assistant';\n case 'system':\n return 'system';\n case 'tool':\n return includeToolMessages ? 'system' : null;\n default:\n return null;\n }\n}\n\nfunction contentToString(content: unknown): string {\n if (typeof content === 'string') return content;\n if (!Array.isArray(content)) return String(content ?? '');\n return content\n .map((part) => {\n if (typeof part === 'string') return part;\n if (part && typeof part === 'object') {\n const rec = part as Record<string, unknown>;\n if (typeof rec.text === 'string') return rec.text;\n }\n return '';\n })\n .filter(Boolean)\n .join('\\n');\n}\n\nfunction hashTurn(turn: ChatMessage): string {\n return `${turn.role}:${turn.content.slice(0, 500)}`;\n}\n"],"mappings":"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","names":[]}

@@ -42,3 +42,8 @@ // src/tools.ts

subgraph: item.subgraph ?? null,
matched_query_nodes: item.matched_query_nodes ?? null
matched_query_nodes: item.matched_query_nodes ?? null,
// Inline source-file paths so the agent can `read` directly
// without a follow-up `get_origin` call. Empty array when
// the backend couldn't enrich (legacy sandbox / no file
// markers in source chunks).
file_paths: item.file_paths ?? []
})),

@@ -45,0 +50,0 @@ next_steps: response.next_steps

@@ -1,1 +0,1 @@

{"version":3,"sources":["../src/tools.ts","../src/window-tracker.ts"],"sourcesContent":["import { createTool } from '@mastra/core/tools';\nimport { z } from 'zod';\nimport {\n DISCOVER_DESCRIPTION,\n DISCOVER_QUERY_PARAM,\n GET_ORIGIN_DESCRIPTION,\n INTERPRET_DESCRIPTION,\n INTERPRET_ITEMS_PARAM,\n INTERPRET_QUERY_PARAM,\n ORIGIN_CANONICAL_IDS_PARAM,\n ORIGIN_LIMIT_PARAM,\n SEARCH_DESCRIPTION,\n SEARCH_QUERY_PARAM,\n} from '@copass/config';\nimport type {\n CopassClient,\n OriginEntry,\n OriginFile,\n SearchPreset,\n WindowLike,\n} from '@copass/core';\n\nexport interface CopassToolsOptions {\n /** An authenticated `@copass/core` client. */\n client: CopassClient;\n /** Sandbox all retrieval runs against. */\n sandbox_id: string;\n /** Optional project scoping for retrieval calls. */\n project_id?: string;\n /**\n * Optional conversation window — a {@link WindowLike} (typically a\n * `ContextWindow` from `client.contextWindow.create()`). When provided,\n * every retrieval call is automatically window-aware.\n */\n window?: WindowLike;\n /**\n * Preset for `discover`, `interpret`, and `search`. Defaults to\n * `\"copass/copass_1.0\"`. Under `\"copass/copass_2.0\"` discover items\n * carry `subgraph` (pre-rendered ASCII tree) and `matched_query_nodes`\n * fields. Append `\":thinking\"` (e.g. `\"copass/copass_2.0:thinking\"`)\n * to enable task decomposition before retrieval on `search`.\n */\n preset?: SearchPreset;\n}\n\n/**\n * Return Copass retrieval as a set of Mastra tool objects (built with\n * `createTool` from `@mastra/core/tools`).\n *\n * Agent-framework-neutral shape: the LLM picks `discover` (menu of\n * relevant items) or `search` (synthesized answer). `interpret` stays\n * registered for back-compat but is legacy — prefer `search` for drill-in.\n *\n * @example\n * ```ts\n * import { Agent } from '@mastra/core/agent';\n * import { anthropic } from '@ai-sdk/anthropic';\n * import { copassTools } from '@copass/mastra';\n *\n * const window = await copass.contextWindow.create({ sandbox_id });\n * const tools = copassTools({ client: copass, sandbox_id, window });\n *\n * const agent = new Agent({\n * name: 'support-bot',\n * instructions: 'Answer questions using the knowledge graph.',\n * model: anthropic('claude-opus-4-7'),\n * tools,\n * });\n *\n * const response = await agent.generate('why is checkout flaky?');\n * ```\n */\nexport function copassTools(options: CopassToolsOptions) {\n const { client, sandbox_id, project_id, window, preset = 'copass/copass_1.0' } = options;\n\n const discover = createTool({\n id: 'discover',\n description: DISCOVER_DESCRIPTION,\n inputSchema: z.object({\n query: z.string().describe(DISCOVER_QUERY_PARAM),\n }),\n execute: async ({ query }) => {\n const response = await client.retrieval.discover(sandbox_id, {\n query,\n project_id,\n window,\n preset,\n });\n return {\n header: response.header,\n // Project the v2 fields (`subgraph` + `matched_query_nodes`)\n // alongside the v1 fields. Populated only under\n // `copass/copass_2.0` (or its `copass/2.0` alias); `null` under\n // v1 — agents can ignore them when not present.\n items: response.items.map((item) => ({\n score: item.score,\n summary: item.summary,\n canonical_ids: item.canonical_ids,\n subgraph: item.subgraph ?? null,\n matched_query_nodes: item.matched_query_nodes ?? null,\n })),\n next_steps: response.next_steps,\n };\n },\n });\n\n const interpret = createTool({\n id: 'interpret',\n description: INTERPRET_DESCRIPTION,\n inputSchema: z.object({\n query: z.string().describe(INTERPRET_QUERY_PARAM),\n items: z.array(z.array(z.string())).min(1).describe(INTERPRET_ITEMS_PARAM),\n }),\n execute: async ({ query, items }) => {\n const response = await client.retrieval.interpret(sandbox_id, {\n query,\n items,\n project_id,\n window,\n preset,\n });\n return { brief: response.brief };\n },\n });\n\n const search = createTool({\n id: 'search',\n description: SEARCH_DESCRIPTION,\n inputSchema: z.object({\n query: z.string().describe(SEARCH_QUERY_PARAM),\n }),\n execute: async ({ query }) => {\n const response = await client.retrieval.search(sandbox_id, {\n query,\n project_id,\n window,\n preset,\n });\n return { answer: response.answer };\n },\n });\n\n const get_origin = createTool({\n id: 'get_origin',\n description: GET_ORIGIN_DESCRIPTION,\n inputSchema: z.object({\n canonical_ids: z\n .array(z.string())\n .min(1)\n .max(100)\n .describe(ORIGIN_CANONICAL_IDS_PARAM),\n limit_per_canonical: z\n .number()\n .int()\n .min(1)\n .max(50)\n .optional()\n .describe(ORIGIN_LIMIT_PARAM),\n }),\n execute: async ({ canonical_ids, limit_per_canonical }) => {\n const response = await client.retrieval.getOrigin(sandbox_id, {\n canonical_ids,\n ...(limit_per_canonical !== undefined ? { limit_per_canonical } : {}),\n });\n return {\n sandbox_id: response.sandbox_id,\n origins: response.origins.map((entry: OriginEntry) => ({\n canonical_id: entry.canonical_id,\n files: entry.files.map((f: OriginFile) => ({\n file_path: f.file_path,\n extraction_count: f.extraction_count,\n })),\n })),\n };\n },\n });\n\n return { discover, interpret, search, get_origin };\n}\n","import type { ChatMessage, ChatRole, ContextWindow } from '@copass/core';\n\n/**\n * Minimal shape of a step finish event — Mastra's `Agent.generate()` /\n * `.stream()` accept an `onStepFinish` callback that is structurally\n * compatible with this type. Typed structurally so the adapter doesn't lock\n * to a specific `@mastra/core` major version.\n */\nexport interface StepFinishLike {\n response?: {\n messages?: Array<{\n role?: string;\n content?: unknown;\n }>;\n };\n}\n\nexport interface WindowTrackerOptions {\n /** The Context Window to mirror messages into. */\n window: ContextWindow;\n /**\n * Include `tool` messages (results returned by a tool call) as turns.\n * Default: false — tool results are usually retrieval noise.\n */\n includeToolMessages?: boolean;\n}\n\nexport interface WindowTracker {\n /**\n * Pass to Mastra's `agent.generate()` / `agent.stream()` as `onStepFinish`.\n * Each step's assistant + tool output messages land in the window,\n * de-duplicated against what's already there.\n */\n onStepFinish: (step: StepFinishLike) => Promise<void>;\n /**\n * Record the user's turn before you call `agent.generate()`. Step callbacks\n * only surface messages *generated* during a step, so the user's initial\n * input has to be captured explicitly. Safe to call repeatedly — the tracker\n * de-duplicates.\n */\n recordUserTurn: (content: string) => Promise<void>;\n}\n\n/**\n * Build a window tracker for Mastra agent loops.\n *\n * @example\n * ```ts\n * import { copassTools, createWindowTracker } from '@copass/mastra';\n *\n * const tools = copassTools({ client, sandbox_id, window });\n * const tracker = createWindowTracker({ window });\n *\n * const agent = new Agent({ name: 'support', model, tools });\n *\n * await tracker.recordUserTurn(userMessage);\n * const response = await agent.generate(userMessage, {\n * onStepFinish: tracker.onStepFinish,\n * maxSteps: 5,\n * });\n * ```\n */\nexport function createWindowTracker(options: WindowTrackerOptions): WindowTracker {\n const { window, includeToolMessages = false } = options;\n const seen = new Set<string>();\n for (const turn of window.getTurns()) {\n seen.add(hashTurn(turn));\n }\n\n async function addIfNew(turn: ChatMessage): Promise<void> {\n if (!turn.content.trim()) return;\n const key = hashTurn(turn);\n if (seen.has(key)) return;\n seen.add(key);\n try {\n await window.addTurn(turn);\n } catch {\n /* best-effort */\n }\n }\n\n return {\n async onStepFinish(step) {\n const messages = step.response?.messages ?? [];\n for (const msg of messages) {\n const role = roleFromRole(msg.role, includeToolMessages);\n if (!role) continue;\n await addIfNew({ role, content: contentToString(msg.content) });\n }\n },\n recordUserTurn(content) {\n return addIfNew({ role: 'user', content });\n },\n };\n}\n\nfunction roleFromRole(role: string | undefined, includeToolMessages: boolean): ChatRole | null {\n switch (role) {\n case 'user':\n return 'user';\n case 'assistant':\n return 'assistant';\n case 'system':\n return 'system';\n case 'tool':\n return includeToolMessages ? 'system' : null;\n default:\n return null;\n }\n}\n\nfunction contentToString(content: unknown): string {\n if (typeof content === 'string') return content;\n if (!Array.isArray(content)) return String(content ?? '');\n return content\n .map((part) => {\n if (typeof part === 'string') return part;\n if (part && typeof part === 'object') {\n const rec = part as Record<string, unknown>;\n if (typeof rec.text === 'string') return rec.text;\n }\n return '';\n })\n .filter(Boolean)\n .join('\\n');\n}\n\nfunction hashTurn(turn: ChatMessage): string {\n return `${turn.role}:${turn.content.slice(0, 500)}`;\n}\n"],"mappings":";AAAA,SAAS,kBAAkB;AAC3B,SAAS,SAAS;AAClB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AA2DA,SAAS,YAAY,SAA6B;AACvD,QAAM,EAAE,QAAQ,YAAY,YAAY,QAAQ,SAAS,oBAAoB,IAAI;AAEjF,QAAM,WAAW,WAAW;AAAA,IAC1B,IAAI;AAAA,IACJ,aAAa;AAAA,IACb,aAAa,EAAE,OAAO;AAAA,MACpB,OAAO,EAAE,OAAO,EAAE,SAAS,oBAAoB;AAAA,IACjD,CAAC;AAAA,IACD,SAAS,OAAO,EAAE,MAAM,MAAM;AAC5B,YAAM,WAAW,MAAM,OAAO,UAAU,SAAS,YAAY;AAAA,QAC3D;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AACD,aAAO;AAAA,QACL,QAAQ,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,QAKjB,OAAO,SAAS,MAAM,IAAI,CAAC,UAAU;AAAA,UACnC,OAAO,KAAK;AAAA,UACZ,SAAS,KAAK;AAAA,UACd,eAAe,KAAK;AAAA,UACpB,UAAU,KAAK,YAAY;AAAA,UAC3B,qBAAqB,KAAK,uBAAuB;AAAA,QACnD,EAAE;AAAA,QACF,YAAY,SAAS;AAAA,MACvB;AAAA,IACF;AAAA,EACF,CAAC;AAED,QAAM,YAAY,WAAW;AAAA,IAC3B,IAAI;AAAA,IACJ,aAAa;AAAA,IACb,aAAa,EAAE,OAAO;AAAA,MACpB,OAAO,EAAE,OAAO,EAAE,SAAS,qBAAqB;AAAA,MAChD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS,qBAAqB;AAAA,IAC3E,CAAC;AAAA,IACD,SAAS,OAAO,EAAE,OAAO,MAAM,MAAM;AACnC,YAAM,WAAW,MAAM,OAAO,UAAU,UAAU,YAAY;AAAA,QAC5D;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AACD,aAAO,EAAE,OAAO,SAAS,MAAM;AAAA,IACjC;AAAA,EACF,CAAC;AAED,QAAM,SAAS,WAAW;AAAA,IACxB,IAAI;AAAA,IACJ,aAAa;AAAA,IACb,aAAa,EAAE,OAAO;AAAA,MACpB,OAAO,EAAE,OAAO,EAAE,SAAS,kBAAkB;AAAA,IAC/C,CAAC;AAAA,IACD,SAAS,OAAO,EAAE,MAAM,MAAM;AAC5B,YAAM,WAAW,MAAM,OAAO,UAAU,OAAO,YAAY;AAAA,QACzD;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AACD,aAAO,EAAE,QAAQ,SAAS,OAAO;AAAA,IACnC;AAAA,EACF,CAAC;AAED,QAAM,aAAa,WAAW;AAAA,IAC5B,IAAI;AAAA,IACJ,aAAa;AAAA,IACb,aAAa,EAAE,OAAO;AAAA,MACpB,eAAe,EACZ,MAAM,EAAE,OAAO,CAAC,EAChB,IAAI,CAAC,EACL,IAAI,GAAG,EACP,SAAS,0BAA0B;AAAA,MACtC,qBAAqB,EAClB,OAAO,EACP,IAAI,EACJ,IAAI,CAAC,EACL,IAAI,EAAE,EACN,SAAS,EACT,SAAS,kBAAkB;AAAA,IAChC,CAAC;AAAA,IACD,SAAS,OAAO,EAAE,eAAe,oBAAoB,MAAM;AACzD,YAAM,WAAW,MAAM,OAAO,UAAU,UAAU,YAAY;AAAA,QAC5D;AAAA,QACA,GAAI,wBAAwB,SAAY,EAAE,oBAAoB,IAAI,CAAC;AAAA,MACrE,CAAC;AACD,aAAO;AAAA,QACL,YAAY,SAAS;AAAA,QACrB,SAAS,SAAS,QAAQ,IAAI,CAAC,WAAwB;AAAA,UACrD,cAAc,MAAM;AAAA,UACpB,OAAO,MAAM,MAAM,IAAI,CAAC,OAAmB;AAAA,YACzC,WAAW,EAAE;AAAA,YACb,kBAAkB,EAAE;AAAA,UACtB,EAAE;AAAA,QACJ,EAAE;AAAA,MACJ;AAAA,IACF;AAAA,EACF,CAAC;AAED,SAAO,EAAE,UAAU,WAAW,QAAQ,WAAW;AACnD;;;ACpHO,SAAS,oBAAoB,SAA8C;AAChF,QAAM,EAAE,QAAQ,sBAAsB,MAAM,IAAI;AAChD,QAAM,OAAO,oBAAI,IAAY;AAC7B,aAAW,QAAQ,OAAO,SAAS,GAAG;AACpC,SAAK,IAAI,SAAS,IAAI,CAAC;AAAA,EACzB;AAEA,iBAAe,SAAS,MAAkC;AACxD,QAAI,CAAC,KAAK,QAAQ,KAAK,EAAG;AAC1B,UAAM,MAAM,SAAS,IAAI;AACzB,QAAI,KAAK,IAAI,GAAG,EAAG;AACnB,SAAK,IAAI,GAAG;AACZ,QAAI;AACF,YAAM,OAAO,QAAQ,IAAI;AAAA,IAC3B,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,aAAa,MAAM;AACvB,YAAM,WAAW,KAAK,UAAU,YAAY,CAAC;AAC7C,iBAAW,OAAO,UAAU;AAC1B,cAAM,OAAO,aAAa,IAAI,MAAM,mBAAmB;AACvD,YAAI,CAAC,KAAM;AACX,cAAM,SAAS,EAAE,MAAM,SAAS,gBAAgB,IAAI,OAAO,EAAE,CAAC;AAAA,MAChE;AAAA,IACF;AAAA,IACA,eAAe,SAAS;AACtB,aAAO,SAAS,EAAE,MAAM,QAAQ,QAAQ,CAAC;AAAA,IAC3C;AAAA,EACF;AACF;AAEA,SAAS,aAAa,MAA0B,qBAA+C;AAC7F,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,sBAAsB,WAAW;AAAA,IAC1C;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,gBAAgB,SAA0B;AACjD,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,MAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,QAAO,OAAO,WAAW,EAAE;AACxD,SAAO,QACJ,IAAI,CAAC,SAAS;AACb,QAAI,OAAO,SAAS,SAAU,QAAO;AACrC,QAAI,QAAQ,OAAO,SAAS,UAAU;AACpC,YAAM,MAAM;AACZ,UAAI,OAAO,IAAI,SAAS,SAAU,QAAO,IAAI;AAAA,IAC/C;AACA,WAAO;AAAA,EACT,CAAC,EACA,OAAO,OAAO,EACd,KAAK,IAAI;AACd;AAEA,SAAS,SAAS,MAA2B;AAC3C,SAAO,GAAG,KAAK,IAAI,IAAI,KAAK,QAAQ,MAAM,GAAG,GAAG,CAAC;AACnD;","names":[]}
{"version":3,"sources":["../src/tools.ts","../src/window-tracker.ts"],"sourcesContent":["import { createTool } from '@mastra/core/tools';\nimport { z } from 'zod';\nimport {\n DISCOVER_DESCRIPTION,\n DISCOVER_QUERY_PARAM,\n GET_ORIGIN_DESCRIPTION,\n INTERPRET_DESCRIPTION,\n INTERPRET_ITEMS_PARAM,\n INTERPRET_QUERY_PARAM,\n ORIGIN_CANONICAL_IDS_PARAM,\n ORIGIN_LIMIT_PARAM,\n SEARCH_DESCRIPTION,\n SEARCH_QUERY_PARAM,\n} from '@copass/config';\nimport type {\n CopassClient,\n OriginEntry,\n OriginFile,\n SearchPreset,\n WindowLike,\n} from '@copass/core';\n\nexport interface CopassToolsOptions {\n /** An authenticated `@copass/core` client. */\n client: CopassClient;\n /** Sandbox all retrieval runs against. */\n sandbox_id: string;\n /** Optional project scoping for retrieval calls. */\n project_id?: string;\n /**\n * Optional conversation window — a {@link WindowLike} (typically a\n * `ContextWindow` from `client.contextWindow.create()`). When provided,\n * every retrieval call is automatically window-aware.\n */\n window?: WindowLike;\n /**\n * Preset for `discover`, `interpret`, and `search`. Defaults to\n * `\"copass/copass_1.0\"`. Under `\"copass/copass_2.0\"` discover items\n * carry `subgraph` (pre-rendered ASCII tree) and `matched_query_nodes`\n * fields. Append `\":thinking\"` (e.g. `\"copass/copass_2.0:thinking\"`)\n * to enable task decomposition before retrieval on `search`.\n */\n preset?: SearchPreset;\n}\n\n/**\n * Return Copass retrieval as a set of Mastra tool objects (built with\n * `createTool` from `@mastra/core/tools`).\n *\n * Agent-framework-neutral shape: the LLM picks `discover` (menu of\n * relevant items) or `search` (synthesized answer). `interpret` stays\n * registered for back-compat but is legacy — prefer `search` for drill-in.\n *\n * @example\n * ```ts\n * import { Agent } from '@mastra/core/agent';\n * import { anthropic } from '@ai-sdk/anthropic';\n * import { copassTools } from '@copass/mastra';\n *\n * const window = await copass.contextWindow.create({ sandbox_id });\n * const tools = copassTools({ client: copass, sandbox_id, window });\n *\n * const agent = new Agent({\n * name: 'support-bot',\n * instructions: 'Answer questions using the knowledge graph.',\n * model: anthropic('claude-opus-4-7'),\n * tools,\n * });\n *\n * const response = await agent.generate('why is checkout flaky?');\n * ```\n */\nexport function copassTools(options: CopassToolsOptions) {\n const { client, sandbox_id, project_id, window, preset = 'copass/copass_1.0' } = options;\n\n const discover = createTool({\n id: 'discover',\n description: DISCOVER_DESCRIPTION,\n inputSchema: z.object({\n query: z.string().describe(DISCOVER_QUERY_PARAM),\n }),\n execute: async ({ query }) => {\n const response = await client.retrieval.discover(sandbox_id, {\n query,\n project_id,\n window,\n preset,\n });\n return {\n header: response.header,\n // Project the v2 fields (`subgraph` + `matched_query_nodes`)\n // alongside the v1 fields. Populated only under\n // `copass/copass_2.0` (or its `copass/2.0` alias); `null` under\n // v1 — agents can ignore them when not present.\n items: response.items.map((item) => ({\n score: item.score,\n summary: item.summary,\n canonical_ids: item.canonical_ids,\n subgraph: item.subgraph ?? null,\n matched_query_nodes: item.matched_query_nodes ?? null,\n // Inline source-file paths so the agent can `read` directly\n // without a follow-up `get_origin` call. Empty array when\n // the backend couldn't enrich (legacy sandbox / no file\n // markers in source chunks).\n file_paths: item.file_paths ?? [],\n })),\n next_steps: response.next_steps,\n };\n },\n });\n\n const interpret = createTool({\n id: 'interpret',\n description: INTERPRET_DESCRIPTION,\n inputSchema: z.object({\n query: z.string().describe(INTERPRET_QUERY_PARAM),\n items: z.array(z.array(z.string())).min(1).describe(INTERPRET_ITEMS_PARAM),\n }),\n execute: async ({ query, items }) => {\n const response = await client.retrieval.interpret(sandbox_id, {\n query,\n items,\n project_id,\n window,\n preset,\n });\n return { brief: response.brief };\n },\n });\n\n const search = createTool({\n id: 'search',\n description: SEARCH_DESCRIPTION,\n inputSchema: z.object({\n query: z.string().describe(SEARCH_QUERY_PARAM),\n }),\n execute: async ({ query }) => {\n const response = await client.retrieval.search(sandbox_id, {\n query,\n project_id,\n window,\n preset,\n });\n return { answer: response.answer };\n },\n });\n\n const get_origin = createTool({\n id: 'get_origin',\n description: GET_ORIGIN_DESCRIPTION,\n inputSchema: z.object({\n canonical_ids: z\n .array(z.string())\n .min(1)\n .max(100)\n .describe(ORIGIN_CANONICAL_IDS_PARAM),\n limit_per_canonical: z\n .number()\n .int()\n .min(1)\n .max(50)\n .optional()\n .describe(ORIGIN_LIMIT_PARAM),\n }),\n execute: async ({ canonical_ids, limit_per_canonical }) => {\n const response = await client.retrieval.getOrigin(sandbox_id, {\n canonical_ids,\n ...(limit_per_canonical !== undefined ? { limit_per_canonical } : {}),\n });\n return {\n sandbox_id: response.sandbox_id,\n origins: response.origins.map((entry: OriginEntry) => ({\n canonical_id: entry.canonical_id,\n files: entry.files.map((f: OriginFile) => ({\n file_path: f.file_path,\n extraction_count: f.extraction_count,\n })),\n })),\n };\n },\n });\n\n return { discover, interpret, search, get_origin };\n}\n","import type { ChatMessage, ChatRole, ContextWindow } from '@copass/core';\n\n/**\n * Minimal shape of a step finish event — Mastra's `Agent.generate()` /\n * `.stream()` accept an `onStepFinish` callback that is structurally\n * compatible with this type. Typed structurally so the adapter doesn't lock\n * to a specific `@mastra/core` major version.\n */\nexport interface StepFinishLike {\n response?: {\n messages?: Array<{\n role?: string;\n content?: unknown;\n }>;\n };\n}\n\nexport interface WindowTrackerOptions {\n /** The Context Window to mirror messages into. */\n window: ContextWindow;\n /**\n * Include `tool` messages (results returned by a tool call) as turns.\n * Default: false — tool results are usually retrieval noise.\n */\n includeToolMessages?: boolean;\n}\n\nexport interface WindowTracker {\n /**\n * Pass to Mastra's `agent.generate()` / `agent.stream()` as `onStepFinish`.\n * Each step's assistant + tool output messages land in the window,\n * de-duplicated against what's already there.\n */\n onStepFinish: (step: StepFinishLike) => Promise<void>;\n /**\n * Record the user's turn before you call `agent.generate()`. Step callbacks\n * only surface messages *generated* during a step, so the user's initial\n * input has to be captured explicitly. Safe to call repeatedly — the tracker\n * de-duplicates.\n */\n recordUserTurn: (content: string) => Promise<void>;\n}\n\n/**\n * Build a window tracker for Mastra agent loops.\n *\n * @example\n * ```ts\n * import { copassTools, createWindowTracker } from '@copass/mastra';\n *\n * const tools = copassTools({ client, sandbox_id, window });\n * const tracker = createWindowTracker({ window });\n *\n * const agent = new Agent({ name: 'support', model, tools });\n *\n * await tracker.recordUserTurn(userMessage);\n * const response = await agent.generate(userMessage, {\n * onStepFinish: tracker.onStepFinish,\n * maxSteps: 5,\n * });\n * ```\n */\nexport function createWindowTracker(options: WindowTrackerOptions): WindowTracker {\n const { window, includeToolMessages = false } = options;\n const seen = new Set<string>();\n for (const turn of window.getTurns()) {\n seen.add(hashTurn(turn));\n }\n\n async function addIfNew(turn: ChatMessage): Promise<void> {\n if (!turn.content.trim()) return;\n const key = hashTurn(turn);\n if (seen.has(key)) return;\n seen.add(key);\n try {\n await window.addTurn(turn);\n } catch {\n /* best-effort */\n }\n }\n\n return {\n async onStepFinish(step) {\n const messages = step.response?.messages ?? [];\n for (const msg of messages) {\n const role = roleFromRole(msg.role, includeToolMessages);\n if (!role) continue;\n await addIfNew({ role, content: contentToString(msg.content) });\n }\n },\n recordUserTurn(content) {\n return addIfNew({ role: 'user', content });\n },\n };\n}\n\nfunction roleFromRole(role: string | undefined, includeToolMessages: boolean): ChatRole | null {\n switch (role) {\n case 'user':\n return 'user';\n case 'assistant':\n return 'assistant';\n case 'system':\n return 'system';\n case 'tool':\n return includeToolMessages ? 'system' : null;\n default:\n return null;\n }\n}\n\nfunction contentToString(content: unknown): string {\n if (typeof content === 'string') return content;\n if (!Array.isArray(content)) return String(content ?? '');\n return content\n .map((part) => {\n if (typeof part === 'string') return part;\n if (part && typeof part === 'object') {\n const rec = part as Record<string, unknown>;\n if (typeof rec.text === 'string') return rec.text;\n }\n return '';\n })\n .filter(Boolean)\n .join('\\n');\n}\n\nfunction hashTurn(turn: ChatMessage): string {\n return `${turn.role}:${turn.content.slice(0, 500)}`;\n}\n"],"mappings":"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","names":[]}
{
"name": "@copass/mastra",
"version": "0.5.10",
"version": "0.5.11",
"description": "Mastra tool adapters for Copass — drop-in discover/interpret/search tools for Mastra agents",

@@ -66,3 +66,3 @@ "publishConfig": {

"devDependencies": {
"@copass/core": "^0.11.1",
"@copass/core": "^0.11.2",
"@mastra/core": "^1.26.0",

@@ -74,3 +74,3 @@ "@types/node": "^25.0.0",

},
"gitHead": "647e1abcdbdc52dae62913df5cf86aeaf68dc2ff"
"gitHead": "527f8b0ee2b7e2b30696923f81e22157bf6af8c9"
}