@supyagent/sdk 0.1.13 → 0.1.14
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.
- package/dist/index.cjs +16 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -68,6 +68,22 @@ function createExecutor(metadata, baseUrl, apiKey) {
|
|
|
68
68
|
delete remainingArgs[paramName];
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
+
if ("id" in remainingArgs && resolvedPath.includes("{")) {
|
|
72
|
+
const unresolved = resolvedPath.match(/\{(\w+)\}/g);
|
|
73
|
+
if (unresolved) {
|
|
74
|
+
for (const param of unresolved) {
|
|
75
|
+
const paramName = param.slice(1, -1);
|
|
76
|
+
if (paramName.toLowerCase().endsWith("id")) {
|
|
77
|
+
resolvedPath = resolvedPath.replace(
|
|
78
|
+
param,
|
|
79
|
+
encodeURIComponent(String(remainingArgs.id))
|
|
80
|
+
);
|
|
81
|
+
delete remainingArgs.id;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
71
87
|
}
|
|
72
88
|
let url = `${baseUrl}${resolvedPath}`;
|
|
73
89
|
const fetchOptions = {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/core/cache.ts","../src/core/tool-converter.ts","../src/core/http-executor.ts","../src/core/client.ts"],"sourcesContent":["export { supyagent } from \"./core/client.js\";\nexport type {\n SupyagentOptions,\n SupyagentClient,\n ToolFilterOptions,\n ToolMetadata,\n OpenAITool,\n ToolsResponse,\n} from \"./core/types.js\";\n","interface CacheEntry<T> {\n data: T;\n expiresAt: number;\n}\n\nexport class TTLCache<T> {\n private store = new Map<string, CacheEntry<T>>();\n\n get(key: string): T | undefined {\n const entry = this.store.get(key);\n if (!entry) return undefined;\n if (Date.now() > entry.expiresAt) {\n this.store.delete(key);\n return undefined;\n }\n return entry.data;\n }\n\n set(key: string, data: T, ttlSeconds: number): void {\n this.store.set(key, {\n data,\n expiresAt: Date.now() + ttlSeconds * 1000,\n });\n }\n\n clear(): void {\n this.store.clear();\n }\n}\n","import { tool, jsonSchema } from \"ai\";\nimport type { OpenAITool } from \"./types.js\";\nimport { createExecutor } from \"./http-executor.js\";\n\n/**\n * Converts an array of OpenAI-format tools from the supyagent API\n * into a Record of AI SDK tool() instances ready for streamText/generateText.\n */\nexport function convertTools(\n tools: OpenAITool[],\n baseUrl: string,\n apiKey: string\n): Record<string, import(\"ai\").Tool> {\n const result: Record<string, import(\"ai\").Tool> = {};\n\n for (const t of tools) {\n const { name, description, parameters } = t.function;\n const metadata = t.metadata;\n\n result[name] = tool({\n description,\n parameters: jsonSchema(parameters as Parameters<typeof jsonSchema>[0]),\n execute: createExecutor(metadata, baseUrl, apiKey),\n });\n }\n\n return result;\n}\n\n/**\n * Filter tools by provider, service, or tool name.\n */\nexport function filterTools(\n tools: OpenAITool[],\n options: { only?: string[]; except?: string[] }\n): OpenAITool[] {\n let filtered = tools;\n\n if (options.only && options.only.length > 0) {\n const onlySet = new Set(options.only.map((s) => s.toLowerCase()));\n filtered = filtered.filter((t) => {\n const name = t.function.name.toLowerCase();\n const provider = t.metadata.provider.toLowerCase();\n const service = t.metadata.service.toLowerCase();\n return onlySet.has(name) || onlySet.has(provider) || onlySet.has(service);\n });\n }\n\n if (options.except && options.except.length > 0) {\n const exceptSet = new Set(options.except.map((s) => s.toLowerCase()));\n filtered = filtered.filter((t) => {\n const name = t.function.name.toLowerCase();\n const provider = t.metadata.provider.toLowerCase();\n const service = t.metadata.service.toLowerCase();\n return (\n !exceptSet.has(name) &&\n !exceptSet.has(provider) &&\n !exceptSet.has(service)\n );\n });\n }\n\n return filtered;\n}\n","import type { ToolMetadata } from \"./types.js\";\n\n/**\n * Creates an execute function for a tool that calls the supyagent API.\n *\n * Handles:\n * - Path parameter substitution (e.g., {messageId} in /api/v1/gmail/messages/{messageId})\n * - GET/DELETE: remaining args → query string\n * - POST/PUT/PATCH: merge bodyDefaults + remaining args → JSON body\n */\nexport function createExecutor(\n metadata: ToolMetadata,\n baseUrl: string,\n apiKey: string\n): (args: Record<string, unknown>) => Promise<unknown> {\n return async (args: Record<string, unknown>) => {\n const { method, path, bodyDefaults } = metadata;\n\n // Extract path parameters and substitute into the path\n const remainingArgs = { ...args };\n let resolvedPath = path;\n\n const pathParams = path.match(/\\{(\\w+)\\}/g);\n if (pathParams) {\n for (const param of pathParams) {\n const paramName = param.slice(1, -1);\n if (paramName in remainingArgs) {\n resolvedPath = resolvedPath.replace(\n param,\n encodeURIComponent(String(remainingArgs[paramName]))\n );\n delete remainingArgs[paramName];\n }\n }\n }\n\n let url = `${baseUrl}${resolvedPath}`;\n\n const fetchOptions: RequestInit = {\n method,\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n };\n\n if (method === \"GET\" || method === \"DELETE\") {\n // Remaining args go as query parameters\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(remainingArgs)) {\n if (value !== undefined && value !== null) {\n params.set(key, String(value));\n }\n }\n const qs = params.toString();\n if (qs) url += `?${qs}`;\n } else {\n // POST/PUT/PATCH: merge bodyDefaults with remaining args\n const body = { ...bodyDefaults, ...remainingArgs };\n fetchOptions.body = JSON.stringify(body);\n }\n\n const response = await fetch(url, fetchOptions);\n const data = await response.json();\n return data;\n };\n}\n","import type {\n SupyagentOptions,\n SupyagentClient,\n ToolFilterOptions,\n ToolsResponse,\n} from \"./types.js\";\nimport { TTLCache } from \"./cache.js\";\nimport { convertTools, filterTools } from \"./tool-converter.js\";\n\nconst DEFAULT_BASE_URL = \"https://app.supyagent.com\";\nconst CACHE_KEY = \"tools\";\n\n/**\n * Create a supyagent client for fetching and converting tools.\n *\n * @example\n * ```ts\n * import { supyagent } from '@supyagent/sdk';\n *\n * const client = supyagent({ apiKey: process.env.SUPYAGENT_API_KEY! });\n * const tools = await client.tools({ cache: 300 });\n * ```\n */\nexport function supyagent(options: SupyagentOptions): SupyagentClient {\n const { apiKey, baseUrl = DEFAULT_BASE_URL } = options;\n const cache = new TTLCache<ToolsResponse>();\n\n return {\n async tools(filterOptions?: ToolFilterOptions) {\n const cacheTTL = resolveCacheTTL(filterOptions?.cache);\n\n // Check cache\n let response = cacheTTL > 0 ? cache.get(CACHE_KEY) : undefined;\n\n if (!response) {\n // Fetch from API\n const res = await fetch(`${baseUrl}/api/v1/tools`, {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n });\n\n if (!res.ok) {\n const error = await res.text();\n throw new Error(\n `Supyagent API error (${res.status}): ${error}`\n );\n }\n\n const json = await res.json();\n // API wraps response in { ok, data: { tools, base_url, total } }\n response = (json.data ?? json) as ToolsResponse;\n\n // Store in cache if TTL > 0\n if (cacheTTL > 0) {\n cache.set(CACHE_KEY, response, cacheTTL);\n }\n }\n\n // Use API-reported base_url for tool execution\n const toolBaseUrl = response.base_url || baseUrl;\n\n // Guard against non-array tools (e.g., API returns empty or unexpected shape)\n const toolsArray = Array.isArray(response.tools) ? response.tools : [];\n\n // Filter\n const filtered = filterTools(toolsArray, {\n only: filterOptions?.only,\n except: filterOptions?.except,\n });\n\n // Convert to AI SDK tools\n return convertTools(filtered, toolBaseUrl, apiKey);\n },\n };\n}\n\nfunction resolveCacheTTL(cache?: boolean | number): number {\n if (cache === true) return 60;\n if (typeof cache === \"number\") return cache;\n return 0;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/core/cache.ts","../src/core/tool-converter.ts","../src/core/http-executor.ts","../src/core/client.ts"],"sourcesContent":["export { supyagent } from \"./core/client.js\";\nexport type {\n SupyagentOptions,\n SupyagentClient,\n ToolFilterOptions,\n ToolMetadata,\n OpenAITool,\n ToolsResponse,\n} from \"./core/types.js\";\n","interface CacheEntry<T> {\n data: T;\n expiresAt: number;\n}\n\nexport class TTLCache<T> {\n private store = new Map<string, CacheEntry<T>>();\n\n get(key: string): T | undefined {\n const entry = this.store.get(key);\n if (!entry) return undefined;\n if (Date.now() > entry.expiresAt) {\n this.store.delete(key);\n return undefined;\n }\n return entry.data;\n }\n\n set(key: string, data: T, ttlSeconds: number): void {\n this.store.set(key, {\n data,\n expiresAt: Date.now() + ttlSeconds * 1000,\n });\n }\n\n clear(): void {\n this.store.clear();\n }\n}\n","import { tool, jsonSchema } from \"ai\";\nimport type { OpenAITool } from \"./types.js\";\nimport { createExecutor } from \"./http-executor.js\";\n\n/**\n * Converts an array of OpenAI-format tools from the supyagent API\n * into a Record of AI SDK tool() instances ready for streamText/generateText.\n */\nexport function convertTools(\n tools: OpenAITool[],\n baseUrl: string,\n apiKey: string\n): Record<string, import(\"ai\").Tool> {\n const result: Record<string, import(\"ai\").Tool> = {};\n\n for (const t of tools) {\n const { name, description, parameters } = t.function;\n const metadata = t.metadata;\n\n result[name] = tool({\n description,\n parameters: jsonSchema(parameters as Parameters<typeof jsonSchema>[0]),\n execute: createExecutor(metadata, baseUrl, apiKey),\n });\n }\n\n return result;\n}\n\n/**\n * Filter tools by provider, service, or tool name.\n */\nexport function filterTools(\n tools: OpenAITool[],\n options: { only?: string[]; except?: string[] }\n): OpenAITool[] {\n let filtered = tools;\n\n if (options.only && options.only.length > 0) {\n const onlySet = new Set(options.only.map((s) => s.toLowerCase()));\n filtered = filtered.filter((t) => {\n const name = t.function.name.toLowerCase();\n const provider = t.metadata.provider.toLowerCase();\n const service = t.metadata.service.toLowerCase();\n return onlySet.has(name) || onlySet.has(provider) || onlySet.has(service);\n });\n }\n\n if (options.except && options.except.length > 0) {\n const exceptSet = new Set(options.except.map((s) => s.toLowerCase()));\n filtered = filtered.filter((t) => {\n const name = t.function.name.toLowerCase();\n const provider = t.metadata.provider.toLowerCase();\n const service = t.metadata.service.toLowerCase();\n return (\n !exceptSet.has(name) &&\n !exceptSet.has(provider) &&\n !exceptSet.has(service)\n );\n });\n }\n\n return filtered;\n}\n","import type { ToolMetadata } from \"./types.js\";\n\n/**\n * Creates an execute function for a tool that calls the supyagent API.\n *\n * Handles:\n * - Path parameter substitution (e.g., {messageId} in /api/v1/gmail/messages/{messageId})\n * - GET/DELETE: remaining args → query string\n * - POST/PUT/PATCH: merge bodyDefaults + remaining args → JSON body\n */\nexport function createExecutor(\n metadata: ToolMetadata,\n baseUrl: string,\n apiKey: string\n): (args: Record<string, unknown>) => Promise<unknown> {\n return async (args: Record<string, unknown>) => {\n const { method, path, bodyDefaults } = metadata;\n\n // Extract path parameters and substitute into the path\n const remainingArgs = { ...args };\n let resolvedPath = path;\n\n const pathParams = path.match(/\\{(\\w+)\\}/g);\n if (pathParams) {\n for (const param of pathParams) {\n const paramName = param.slice(1, -1);\n if (paramName in remainingArgs) {\n resolvedPath = resolvedPath.replace(\n param,\n encodeURIComponent(String(remainingArgs[paramName]))\n );\n delete remainingArgs[paramName];\n }\n }\n\n // Fallback: LLMs often send { id } instead of { messageId }, { eventId }, etc.\n // because list responses return objects with an `id` field.\n // For any unresolved {fooId} param, try `id` from the args (once only).\n if (\"id\" in remainingArgs && resolvedPath.includes(\"{\")) {\n const unresolved = resolvedPath.match(/\\{(\\w+)\\}/g);\n if (unresolved) {\n for (const param of unresolved) {\n const paramName = param.slice(1, -1);\n if (paramName.toLowerCase().endsWith(\"id\")) {\n resolvedPath = resolvedPath.replace(\n param,\n encodeURIComponent(String(remainingArgs.id))\n );\n delete remainingArgs.id;\n break; // consume `id` only once\n }\n }\n }\n }\n }\n\n let url = `${baseUrl}${resolvedPath}`;\n\n const fetchOptions: RequestInit = {\n method,\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n };\n\n if (method === \"GET\" || method === \"DELETE\") {\n // Remaining args go as query parameters\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(remainingArgs)) {\n if (value !== undefined && value !== null) {\n params.set(key, String(value));\n }\n }\n const qs = params.toString();\n if (qs) url += `?${qs}`;\n } else {\n // POST/PUT/PATCH: merge bodyDefaults with remaining args\n const body = { ...bodyDefaults, ...remainingArgs };\n fetchOptions.body = JSON.stringify(body);\n }\n\n const response = await fetch(url, fetchOptions);\n const data = await response.json();\n return data;\n };\n}\n","import type {\n SupyagentOptions,\n SupyagentClient,\n ToolFilterOptions,\n ToolsResponse,\n} from \"./types.js\";\nimport { TTLCache } from \"./cache.js\";\nimport { convertTools, filterTools } from \"./tool-converter.js\";\n\nconst DEFAULT_BASE_URL = \"https://app.supyagent.com\";\nconst CACHE_KEY = \"tools\";\n\n/**\n * Create a supyagent client for fetching and converting tools.\n *\n * @example\n * ```ts\n * import { supyagent } from '@supyagent/sdk';\n *\n * const client = supyagent({ apiKey: process.env.SUPYAGENT_API_KEY! });\n * const tools = await client.tools({ cache: 300 });\n * ```\n */\nexport function supyagent(options: SupyagentOptions): SupyagentClient {\n const { apiKey, baseUrl = DEFAULT_BASE_URL } = options;\n const cache = new TTLCache<ToolsResponse>();\n\n return {\n async tools(filterOptions?: ToolFilterOptions) {\n const cacheTTL = resolveCacheTTL(filterOptions?.cache);\n\n // Check cache\n let response = cacheTTL > 0 ? cache.get(CACHE_KEY) : undefined;\n\n if (!response) {\n // Fetch from API\n const res = await fetch(`${baseUrl}/api/v1/tools`, {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n });\n\n if (!res.ok) {\n const error = await res.text();\n throw new Error(\n `Supyagent API error (${res.status}): ${error}`\n );\n }\n\n const json = await res.json();\n // API wraps response in { ok, data: { tools, base_url, total } }\n response = (json.data ?? json) as ToolsResponse;\n\n // Store in cache if TTL > 0\n if (cacheTTL > 0) {\n cache.set(CACHE_KEY, response, cacheTTL);\n }\n }\n\n // Use API-reported base_url for tool execution\n const toolBaseUrl = response.base_url || baseUrl;\n\n // Guard against non-array tools (e.g., API returns empty or unexpected shape)\n const toolsArray = Array.isArray(response.tools) ? response.tools : [];\n\n // Filter\n const filtered = filterTools(toolsArray, {\n only: filterOptions?.only,\n except: filterOptions?.except,\n });\n\n // Convert to AI SDK tools\n return convertTools(filtered, toolBaseUrl, apiKey);\n },\n };\n}\n\nfunction resolveCacheTTL(cache?: boolean | number): number {\n if (cache === true) return 60;\n if (typeof cache === \"number\") return cache;\n return 0;\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -42,6 +42,22 @@ function createExecutor(metadata, baseUrl, apiKey) {
|
|
|
42
42
|
delete remainingArgs[paramName];
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
+
if ("id" in remainingArgs && resolvedPath.includes("{")) {
|
|
46
|
+
const unresolved = resolvedPath.match(/\{(\w+)\}/g);
|
|
47
|
+
if (unresolved) {
|
|
48
|
+
for (const param of unresolved) {
|
|
49
|
+
const paramName = param.slice(1, -1);
|
|
50
|
+
if (paramName.toLowerCase().endsWith("id")) {
|
|
51
|
+
resolvedPath = resolvedPath.replace(
|
|
52
|
+
param,
|
|
53
|
+
encodeURIComponent(String(remainingArgs.id))
|
|
54
|
+
);
|
|
55
|
+
delete remainingArgs.id;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
45
61
|
}
|
|
46
62
|
let url = `${baseUrl}${resolvedPath}`;
|
|
47
63
|
const fetchOptions = {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/cache.ts","../src/core/tool-converter.ts","../src/core/http-executor.ts","../src/core/client.ts"],"sourcesContent":["interface CacheEntry<T> {\n data: T;\n expiresAt: number;\n}\n\nexport class TTLCache<T> {\n private store = new Map<string, CacheEntry<T>>();\n\n get(key: string): T | undefined {\n const entry = this.store.get(key);\n if (!entry) return undefined;\n if (Date.now() > entry.expiresAt) {\n this.store.delete(key);\n return undefined;\n }\n return entry.data;\n }\n\n set(key: string, data: T, ttlSeconds: number): void {\n this.store.set(key, {\n data,\n expiresAt: Date.now() + ttlSeconds * 1000,\n });\n }\n\n clear(): void {\n this.store.clear();\n }\n}\n","import { tool, jsonSchema } from \"ai\";\nimport type { OpenAITool } from \"./types.js\";\nimport { createExecutor } from \"./http-executor.js\";\n\n/**\n * Converts an array of OpenAI-format tools from the supyagent API\n * into a Record of AI SDK tool() instances ready for streamText/generateText.\n */\nexport function convertTools(\n tools: OpenAITool[],\n baseUrl: string,\n apiKey: string\n): Record<string, import(\"ai\").Tool> {\n const result: Record<string, import(\"ai\").Tool> = {};\n\n for (const t of tools) {\n const { name, description, parameters } = t.function;\n const metadata = t.metadata;\n\n result[name] = tool({\n description,\n parameters: jsonSchema(parameters as Parameters<typeof jsonSchema>[0]),\n execute: createExecutor(metadata, baseUrl, apiKey),\n });\n }\n\n return result;\n}\n\n/**\n * Filter tools by provider, service, or tool name.\n */\nexport function filterTools(\n tools: OpenAITool[],\n options: { only?: string[]; except?: string[] }\n): OpenAITool[] {\n let filtered = tools;\n\n if (options.only && options.only.length > 0) {\n const onlySet = new Set(options.only.map((s) => s.toLowerCase()));\n filtered = filtered.filter((t) => {\n const name = t.function.name.toLowerCase();\n const provider = t.metadata.provider.toLowerCase();\n const service = t.metadata.service.toLowerCase();\n return onlySet.has(name) || onlySet.has(provider) || onlySet.has(service);\n });\n }\n\n if (options.except && options.except.length > 0) {\n const exceptSet = new Set(options.except.map((s) => s.toLowerCase()));\n filtered = filtered.filter((t) => {\n const name = t.function.name.toLowerCase();\n const provider = t.metadata.provider.toLowerCase();\n const service = t.metadata.service.toLowerCase();\n return (\n !exceptSet.has(name) &&\n !exceptSet.has(provider) &&\n !exceptSet.has(service)\n );\n });\n }\n\n return filtered;\n}\n","import type { ToolMetadata } from \"./types.js\";\n\n/**\n * Creates an execute function for a tool that calls the supyagent API.\n *\n * Handles:\n * - Path parameter substitution (e.g., {messageId} in /api/v1/gmail/messages/{messageId})\n * - GET/DELETE: remaining args → query string\n * - POST/PUT/PATCH: merge bodyDefaults + remaining args → JSON body\n */\nexport function createExecutor(\n metadata: ToolMetadata,\n baseUrl: string,\n apiKey: string\n): (args: Record<string, unknown>) => Promise<unknown> {\n return async (args: Record<string, unknown>) => {\n const { method, path, bodyDefaults } = metadata;\n\n // Extract path parameters and substitute into the path\n const remainingArgs = { ...args };\n let resolvedPath = path;\n\n const pathParams = path.match(/\\{(\\w+)\\}/g);\n if (pathParams) {\n for (const param of pathParams) {\n const paramName = param.slice(1, -1);\n if (paramName in remainingArgs) {\n resolvedPath = resolvedPath.replace(\n param,\n encodeURIComponent(String(remainingArgs[paramName]))\n );\n delete remainingArgs[paramName];\n }\n }\n }\n\n let url = `${baseUrl}${resolvedPath}`;\n\n const fetchOptions: RequestInit = {\n method,\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n };\n\n if (method === \"GET\" || method === \"DELETE\") {\n // Remaining args go as query parameters\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(remainingArgs)) {\n if (value !== undefined && value !== null) {\n params.set(key, String(value));\n }\n }\n const qs = params.toString();\n if (qs) url += `?${qs}`;\n } else {\n // POST/PUT/PATCH: merge bodyDefaults with remaining args\n const body = { ...bodyDefaults, ...remainingArgs };\n fetchOptions.body = JSON.stringify(body);\n }\n\n const response = await fetch(url, fetchOptions);\n const data = await response.json();\n return data;\n };\n}\n","import type {\n SupyagentOptions,\n SupyagentClient,\n ToolFilterOptions,\n ToolsResponse,\n} from \"./types.js\";\nimport { TTLCache } from \"./cache.js\";\nimport { convertTools, filterTools } from \"./tool-converter.js\";\n\nconst DEFAULT_BASE_URL = \"https://app.supyagent.com\";\nconst CACHE_KEY = \"tools\";\n\n/**\n * Create a supyagent client for fetching and converting tools.\n *\n * @example\n * ```ts\n * import { supyagent } from '@supyagent/sdk';\n *\n * const client = supyagent({ apiKey: process.env.SUPYAGENT_API_KEY! });\n * const tools = await client.tools({ cache: 300 });\n * ```\n */\nexport function supyagent(options: SupyagentOptions): SupyagentClient {\n const { apiKey, baseUrl = DEFAULT_BASE_URL } = options;\n const cache = new TTLCache<ToolsResponse>();\n\n return {\n async tools(filterOptions?: ToolFilterOptions) {\n const cacheTTL = resolveCacheTTL(filterOptions?.cache);\n\n // Check cache\n let response = cacheTTL > 0 ? cache.get(CACHE_KEY) : undefined;\n\n if (!response) {\n // Fetch from API\n const res = await fetch(`${baseUrl}/api/v1/tools`, {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n });\n\n if (!res.ok) {\n const error = await res.text();\n throw new Error(\n `Supyagent API error (${res.status}): ${error}`\n );\n }\n\n const json = await res.json();\n // API wraps response in { ok, data: { tools, base_url, total } }\n response = (json.data ?? json) as ToolsResponse;\n\n // Store in cache if TTL > 0\n if (cacheTTL > 0) {\n cache.set(CACHE_KEY, response, cacheTTL);\n }\n }\n\n // Use API-reported base_url for tool execution\n const toolBaseUrl = response.base_url || baseUrl;\n\n // Guard against non-array tools (e.g., API returns empty or unexpected shape)\n const toolsArray = Array.isArray(response.tools) ? response.tools : [];\n\n // Filter\n const filtered = filterTools(toolsArray, {\n only: filterOptions?.only,\n except: filterOptions?.except,\n });\n\n // Convert to AI SDK tools\n return convertTools(filtered, toolBaseUrl, apiKey);\n },\n };\n}\n\nfunction resolveCacheTTL(cache?: boolean | number): number {\n if (cache === true) return 60;\n if (typeof cache === \"number\") return cache;\n return 0;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/core/cache.ts","../src/core/tool-converter.ts","../src/core/http-executor.ts","../src/core/client.ts"],"sourcesContent":["interface CacheEntry<T> {\n data: T;\n expiresAt: number;\n}\n\nexport class TTLCache<T> {\n private store = new Map<string, CacheEntry<T>>();\n\n get(key: string): T | undefined {\n const entry = this.store.get(key);\n if (!entry) return undefined;\n if (Date.now() > entry.expiresAt) {\n this.store.delete(key);\n return undefined;\n }\n return entry.data;\n }\n\n set(key: string, data: T, ttlSeconds: number): void {\n this.store.set(key, {\n data,\n expiresAt: Date.now() + ttlSeconds * 1000,\n });\n }\n\n clear(): void {\n this.store.clear();\n }\n}\n","import { tool, jsonSchema } from \"ai\";\nimport type { OpenAITool } from \"./types.js\";\nimport { createExecutor } from \"./http-executor.js\";\n\n/**\n * Converts an array of OpenAI-format tools from the supyagent API\n * into a Record of AI SDK tool() instances ready for streamText/generateText.\n */\nexport function convertTools(\n tools: OpenAITool[],\n baseUrl: string,\n apiKey: string\n): Record<string, import(\"ai\").Tool> {\n const result: Record<string, import(\"ai\").Tool> = {};\n\n for (const t of tools) {\n const { name, description, parameters } = t.function;\n const metadata = t.metadata;\n\n result[name] = tool({\n description,\n parameters: jsonSchema(parameters as Parameters<typeof jsonSchema>[0]),\n execute: createExecutor(metadata, baseUrl, apiKey),\n });\n }\n\n return result;\n}\n\n/**\n * Filter tools by provider, service, or tool name.\n */\nexport function filterTools(\n tools: OpenAITool[],\n options: { only?: string[]; except?: string[] }\n): OpenAITool[] {\n let filtered = tools;\n\n if (options.only && options.only.length > 0) {\n const onlySet = new Set(options.only.map((s) => s.toLowerCase()));\n filtered = filtered.filter((t) => {\n const name = t.function.name.toLowerCase();\n const provider = t.metadata.provider.toLowerCase();\n const service = t.metadata.service.toLowerCase();\n return onlySet.has(name) || onlySet.has(provider) || onlySet.has(service);\n });\n }\n\n if (options.except && options.except.length > 0) {\n const exceptSet = new Set(options.except.map((s) => s.toLowerCase()));\n filtered = filtered.filter((t) => {\n const name = t.function.name.toLowerCase();\n const provider = t.metadata.provider.toLowerCase();\n const service = t.metadata.service.toLowerCase();\n return (\n !exceptSet.has(name) &&\n !exceptSet.has(provider) &&\n !exceptSet.has(service)\n );\n });\n }\n\n return filtered;\n}\n","import type { ToolMetadata } from \"./types.js\";\n\n/**\n * Creates an execute function for a tool that calls the supyagent API.\n *\n * Handles:\n * - Path parameter substitution (e.g., {messageId} in /api/v1/gmail/messages/{messageId})\n * - GET/DELETE: remaining args → query string\n * - POST/PUT/PATCH: merge bodyDefaults + remaining args → JSON body\n */\nexport function createExecutor(\n metadata: ToolMetadata,\n baseUrl: string,\n apiKey: string\n): (args: Record<string, unknown>) => Promise<unknown> {\n return async (args: Record<string, unknown>) => {\n const { method, path, bodyDefaults } = metadata;\n\n // Extract path parameters and substitute into the path\n const remainingArgs = { ...args };\n let resolvedPath = path;\n\n const pathParams = path.match(/\\{(\\w+)\\}/g);\n if (pathParams) {\n for (const param of pathParams) {\n const paramName = param.slice(1, -1);\n if (paramName in remainingArgs) {\n resolvedPath = resolvedPath.replace(\n param,\n encodeURIComponent(String(remainingArgs[paramName]))\n );\n delete remainingArgs[paramName];\n }\n }\n\n // Fallback: LLMs often send { id } instead of { messageId }, { eventId }, etc.\n // because list responses return objects with an `id` field.\n // For any unresolved {fooId} param, try `id` from the args (once only).\n if (\"id\" in remainingArgs && resolvedPath.includes(\"{\")) {\n const unresolved = resolvedPath.match(/\\{(\\w+)\\}/g);\n if (unresolved) {\n for (const param of unresolved) {\n const paramName = param.slice(1, -1);\n if (paramName.toLowerCase().endsWith(\"id\")) {\n resolvedPath = resolvedPath.replace(\n param,\n encodeURIComponent(String(remainingArgs.id))\n );\n delete remainingArgs.id;\n break; // consume `id` only once\n }\n }\n }\n }\n }\n\n let url = `${baseUrl}${resolvedPath}`;\n\n const fetchOptions: RequestInit = {\n method,\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n };\n\n if (method === \"GET\" || method === \"DELETE\") {\n // Remaining args go as query parameters\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(remainingArgs)) {\n if (value !== undefined && value !== null) {\n params.set(key, String(value));\n }\n }\n const qs = params.toString();\n if (qs) url += `?${qs}`;\n } else {\n // POST/PUT/PATCH: merge bodyDefaults with remaining args\n const body = { ...bodyDefaults, ...remainingArgs };\n fetchOptions.body = JSON.stringify(body);\n }\n\n const response = await fetch(url, fetchOptions);\n const data = await response.json();\n return data;\n };\n}\n","import type {\n SupyagentOptions,\n SupyagentClient,\n ToolFilterOptions,\n ToolsResponse,\n} from \"./types.js\";\nimport { TTLCache } from \"./cache.js\";\nimport { convertTools, filterTools } from \"./tool-converter.js\";\n\nconst DEFAULT_BASE_URL = \"https://app.supyagent.com\";\nconst CACHE_KEY = \"tools\";\n\n/**\n * Create a supyagent client for fetching and converting tools.\n *\n * @example\n * ```ts\n * import { supyagent } from '@supyagent/sdk';\n *\n * const client = supyagent({ apiKey: process.env.SUPYAGENT_API_KEY! });\n * const tools = await client.tools({ cache: 300 });\n * ```\n */\nexport function supyagent(options: SupyagentOptions): SupyagentClient {\n const { apiKey, baseUrl = DEFAULT_BASE_URL } = options;\n const cache = new TTLCache<ToolsResponse>();\n\n return {\n async tools(filterOptions?: ToolFilterOptions) {\n const cacheTTL = resolveCacheTTL(filterOptions?.cache);\n\n // Check cache\n let response = cacheTTL > 0 ? cache.get(CACHE_KEY) : undefined;\n\n if (!response) {\n // Fetch from API\n const res = await fetch(`${baseUrl}/api/v1/tools`, {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n },\n });\n\n if (!res.ok) {\n const error = await res.text();\n throw new Error(\n `Supyagent API error (${res.status}): ${error}`\n );\n }\n\n const json = await res.json();\n // API wraps response in { ok, data: { tools, base_url, total } }\n response = (json.data ?? json) as ToolsResponse;\n\n // Store in cache if TTL > 0\n if (cacheTTL > 0) {\n cache.set(CACHE_KEY, response, cacheTTL);\n }\n }\n\n // Use API-reported base_url for tool execution\n const toolBaseUrl = response.base_url || baseUrl;\n\n // Guard against non-array tools (e.g., API returns empty or unexpected shape)\n const toolsArray = Array.isArray(response.tools) ? response.tools : [];\n\n // Filter\n const filtered = filterTools(toolsArray, {\n only: filterOptions?.only,\n except: filterOptions?.except,\n });\n\n // Convert to AI SDK tools\n return convertTools(filtered, toolBaseUrl, apiKey);\n },\n };\n}\n\nfunction resolveCacheTTL(cache?: boolean | number): number {\n if (cache === true) return 60;\n if (typeof cache === \"number\") return cache;\n return 0;\n}\n"],"mappings":"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","names":[]}
|