@supyagent/sdk 0.1.14 → 0.1.15
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 +75 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -1
- package/dist/index.d.ts +34 -1
- package/dist/index.js +74 -2
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +13 -0
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +13 -0
- package/dist/react.js.map +1 -1
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
|
+
createBashTool: () => createBashTool,
|
|
23
24
|
supyagent: () => supyagent
|
|
24
25
|
});
|
|
25
26
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -120,8 +121,8 @@ function convertTools(tools, baseUrl, apiKey) {
|
|
|
120
121
|
const metadata = t.metadata;
|
|
121
122
|
result[name] = (0, import_ai.tool)({
|
|
122
123
|
description,
|
|
123
|
-
|
|
124
|
-
execute: createExecutor(metadata, baseUrl, apiKey)
|
|
124
|
+
inputSchema: (0, import_ai.jsonSchema)(parameters),
|
|
125
|
+
execute: async (args) => createExecutor(metadata, baseUrl, apiKey)(args)
|
|
125
126
|
});
|
|
126
127
|
}
|
|
127
128
|
return result;
|
|
@@ -193,8 +194,80 @@ function resolveCacheTTL(cache) {
|
|
|
193
194
|
if (typeof cache === "number") return cache;
|
|
194
195
|
return 0;
|
|
195
196
|
}
|
|
197
|
+
|
|
198
|
+
// src/tools/bash.ts
|
|
199
|
+
var import_ai2 = require("ai");
|
|
200
|
+
var import_node_child_process = require("child_process");
|
|
201
|
+
var MAX_OUTPUT = 3e4;
|
|
202
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
203
|
+
function createBashTool(options) {
|
|
204
|
+
const cwd = options?.cwd ?? process.cwd();
|
|
205
|
+
const timeout = Math.min(options?.timeout ?? DEFAULT_TIMEOUT, 6e5);
|
|
206
|
+
const maxOutput = options?.maxOutput ?? MAX_OUTPUT;
|
|
207
|
+
const schema = {
|
|
208
|
+
type: "object",
|
|
209
|
+
properties: {
|
|
210
|
+
command: {
|
|
211
|
+
type: "string",
|
|
212
|
+
description: "The bash command to execute"
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
required: ["command"]
|
|
216
|
+
};
|
|
217
|
+
return (0, import_ai2.tool)({
|
|
218
|
+
description: "Execute a bash command on the server. Use this for running shell commands, scripts, package managers, git operations, file manipulation, and system tasks. Returns stdout, stderr, and exit code.",
|
|
219
|
+
inputSchema: (0, import_ai2.jsonSchema)(schema),
|
|
220
|
+
execute: async (args) => {
|
|
221
|
+
const { command } = args;
|
|
222
|
+
const start = Date.now();
|
|
223
|
+
return new Promise((resolve) => {
|
|
224
|
+
const child = (0, import_node_child_process.exec)(
|
|
225
|
+
command,
|
|
226
|
+
{
|
|
227
|
+
cwd,
|
|
228
|
+
timeout,
|
|
229
|
+
shell: "/bin/bash",
|
|
230
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
231
|
+
// 10MB buffer
|
|
232
|
+
env: { ...process.env, TERM: "dumb" }
|
|
233
|
+
},
|
|
234
|
+
(error, stdout, stderr) => {
|
|
235
|
+
const durationMs = Date.now() - start;
|
|
236
|
+
const timedOut = error?.killed === true;
|
|
237
|
+
const exitCode = timedOut ? 124 : typeof error?.code === "number" ? error.code : error ? 1 : 0;
|
|
238
|
+
resolve({
|
|
239
|
+
stdout: truncate(stdout, maxOutput),
|
|
240
|
+
stderr: truncate(stderr, maxOutput),
|
|
241
|
+
exitCode,
|
|
242
|
+
durationMs,
|
|
243
|
+
...timedOut ? { timedOut: true } : {}
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
);
|
|
247
|
+
child.on("error", () => {
|
|
248
|
+
resolve({
|
|
249
|
+
stdout: "",
|
|
250
|
+
stderr: "Failed to start process",
|
|
251
|
+
exitCode: 127,
|
|
252
|
+
durationMs: Date.now() - start
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
function truncate(str, max) {
|
|
260
|
+
if (str.length <= max) return str;
|
|
261
|
+
const half = Math.floor(max / 2) - 50;
|
|
262
|
+
return str.slice(0, half) + `
|
|
263
|
+
|
|
264
|
+
... (${str.length - max} characters truncated) ...
|
|
265
|
+
|
|
266
|
+
` + str.slice(-half);
|
|
267
|
+
}
|
|
196
268
|
// Annotate the CommonJS export names for ESM import in node:
|
|
197
269
|
0 && (module.exports = {
|
|
270
|
+
createBashTool,
|
|
198
271
|
supyagent
|
|
199
272
|
});
|
|
200
273
|
//# sourceMappingURL=index.cjs.map
|
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 // 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":[]}
|
|
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","../src/tools/bash.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\";\nexport { createBashTool } from \"./tools/bash.js\";\nexport type { BashToolOptions, BashToolResult } from \"./tools/bash.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 inputSchema: jsonSchema(parameters as Parameters<typeof jsonSchema>[0]),\n execute: async (args) => createExecutor(metadata, baseUrl, apiKey)(args as Record<string, unknown>),\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","import { tool, jsonSchema } from \"ai\";\nimport { exec, type ExecException } from \"node:child_process\";\n\nconst MAX_OUTPUT = 30_000;\nconst DEFAULT_TIMEOUT = 30_000; // 30 seconds\n\nexport interface BashToolOptions {\n /** Working directory for commands. Defaults to `process.cwd()`. */\n cwd?: string;\n /** Command timeout in milliseconds. Defaults to 30000 (30s). Max 600000 (10m). */\n timeout?: number;\n /** Maximum output length in characters. Defaults to 30000. */\n maxOutput?: number;\n}\n\nexport interface BashToolResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n durationMs: number;\n timedOut?: boolean;\n}\n\n/**\n * Create a bash tool that executes shell commands on the server.\n *\n * @example\n * ```ts\n * import { supyagent, createBashTool } from '@supyagent/sdk';\n *\n * const client = supyagent({ apiKey: process.env.SUPYAGENT_API_KEY! });\n * const supyagentTools = await client.tools({ cache: 300 });\n *\n * const tools = {\n * ...supyagentTools,\n * bash: createBashTool({ cwd: '/path/to/project' }),\n * };\n * ```\n */\nexport function createBashTool(options?: BashToolOptions) {\n const cwd = options?.cwd ?? process.cwd();\n const timeout = Math.min(options?.timeout ?? DEFAULT_TIMEOUT, 600_000);\n const maxOutput = options?.maxOutput ?? MAX_OUTPUT;\n\n const schema = {\n type: \"object\" as const,\n properties: {\n command: {\n type: \"string\",\n description: \"The bash command to execute\",\n },\n },\n required: [\"command\"],\n };\n\n return tool({\n description:\n \"Execute a bash command on the server. Use this for running shell commands, scripts, package managers, git operations, file manipulation, and system tasks. Returns stdout, stderr, and exit code.\",\n inputSchema: jsonSchema(schema as Parameters<typeof jsonSchema>[0]),\n execute: async (args): Promise<BashToolResult> => {\n const { command } = args as { command: string };\n const start = Date.now();\n\n return new Promise<BashToolResult>((resolve) => {\n const child = exec(\n command,\n {\n cwd,\n timeout,\n shell: \"/bin/bash\",\n maxBuffer: 10 * 1024 * 1024, // 10MB buffer\n env: { ...process.env, TERM: \"dumb\" },\n },\n (error: ExecException | null, stdout: string, stderr: string) => {\n const durationMs = Date.now() - start;\n const timedOut = error?.killed === true;\n const exitCode = timedOut\n ? 124\n : typeof error?.code === \"number\"\n ? error.code\n : error\n ? 1\n : 0;\n\n resolve({\n stdout: truncate(stdout, maxOutput),\n stderr: truncate(stderr, maxOutput),\n exitCode,\n durationMs,\n ...(timedOut ? { timedOut: true } : {}),\n });\n }\n );\n\n // Ensure the child process is killed on timeout\n child.on(\"error\", () => {\n resolve({\n stdout: \"\",\n stderr: \"Failed to start process\",\n exitCode: 127,\n durationMs: Date.now() - start,\n });\n });\n });\n },\n });\n}\n\nfunction truncate(str: string, max: number): string {\n if (str.length <= max) return str;\n const half = Math.floor(max / 2) - 50;\n return (\n str.slice(0, half) +\n `\\n\\n... (${str.length - max} characters truncated) ...\\n\\n` +\n str.slice(-half)\n );\n}\n"],"mappings":"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","names":["import_ai"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -63,4 +63,37 @@ interface SupyagentClient {
|
|
|
63
63
|
*/
|
|
64
64
|
declare function supyagent(options: SupyagentOptions): SupyagentClient;
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
interface BashToolOptions {
|
|
67
|
+
/** Working directory for commands. Defaults to `process.cwd()`. */
|
|
68
|
+
cwd?: string;
|
|
69
|
+
/** Command timeout in milliseconds. Defaults to 30000 (30s). Max 600000 (10m). */
|
|
70
|
+
timeout?: number;
|
|
71
|
+
/** Maximum output length in characters. Defaults to 30000. */
|
|
72
|
+
maxOutput?: number;
|
|
73
|
+
}
|
|
74
|
+
interface BashToolResult {
|
|
75
|
+
stdout: string;
|
|
76
|
+
stderr: string;
|
|
77
|
+
exitCode: number;
|
|
78
|
+
durationMs: number;
|
|
79
|
+
timedOut?: boolean;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Create a bash tool that executes shell commands on the server.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```ts
|
|
86
|
+
* import { supyagent, createBashTool } from '@supyagent/sdk';
|
|
87
|
+
*
|
|
88
|
+
* const client = supyagent({ apiKey: process.env.SUPYAGENT_API_KEY! });
|
|
89
|
+
* const supyagentTools = await client.tools({ cache: 300 });
|
|
90
|
+
*
|
|
91
|
+
* const tools = {
|
|
92
|
+
* ...supyagentTools,
|
|
93
|
+
* bash: createBashTool({ cwd: '/path/to/project' }),
|
|
94
|
+
* };
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
declare function createBashTool(options?: BashToolOptions): ai.Tool<unknown, BashToolResult>;
|
|
98
|
+
|
|
99
|
+
export { type BashToolOptions, type BashToolResult, type OpenAITool, type SupyagentClient, type SupyagentOptions, type ToolFilterOptions, type ToolMetadata, type ToolsResponse, createBashTool, supyagent };
|
package/dist/index.d.ts
CHANGED
|
@@ -63,4 +63,37 @@ interface SupyagentClient {
|
|
|
63
63
|
*/
|
|
64
64
|
declare function supyagent(options: SupyagentOptions): SupyagentClient;
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
interface BashToolOptions {
|
|
67
|
+
/** Working directory for commands. Defaults to `process.cwd()`. */
|
|
68
|
+
cwd?: string;
|
|
69
|
+
/** Command timeout in milliseconds. Defaults to 30000 (30s). Max 600000 (10m). */
|
|
70
|
+
timeout?: number;
|
|
71
|
+
/** Maximum output length in characters. Defaults to 30000. */
|
|
72
|
+
maxOutput?: number;
|
|
73
|
+
}
|
|
74
|
+
interface BashToolResult {
|
|
75
|
+
stdout: string;
|
|
76
|
+
stderr: string;
|
|
77
|
+
exitCode: number;
|
|
78
|
+
durationMs: number;
|
|
79
|
+
timedOut?: boolean;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Create a bash tool that executes shell commands on the server.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```ts
|
|
86
|
+
* import { supyagent, createBashTool } from '@supyagent/sdk';
|
|
87
|
+
*
|
|
88
|
+
* const client = supyagent({ apiKey: process.env.SUPYAGENT_API_KEY! });
|
|
89
|
+
* const supyagentTools = await client.tools({ cache: 300 });
|
|
90
|
+
*
|
|
91
|
+
* const tools = {
|
|
92
|
+
* ...supyagentTools,
|
|
93
|
+
* bash: createBashTool({ cwd: '/path/to/project' }),
|
|
94
|
+
* };
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
declare function createBashTool(options?: BashToolOptions): ai.Tool<unknown, BashToolResult>;
|
|
98
|
+
|
|
99
|
+
export { type BashToolOptions, type BashToolResult, type OpenAITool, type SupyagentClient, type SupyagentOptions, type ToolFilterOptions, type ToolMetadata, type ToolsResponse, createBashTool, supyagent };
|
package/dist/index.js
CHANGED
|
@@ -94,8 +94,8 @@ function convertTools(tools, baseUrl, apiKey) {
|
|
|
94
94
|
const metadata = t.metadata;
|
|
95
95
|
result[name] = tool({
|
|
96
96
|
description,
|
|
97
|
-
|
|
98
|
-
execute: createExecutor(metadata, baseUrl, apiKey)
|
|
97
|
+
inputSchema: jsonSchema(parameters),
|
|
98
|
+
execute: async (args) => createExecutor(metadata, baseUrl, apiKey)(args)
|
|
99
99
|
});
|
|
100
100
|
}
|
|
101
101
|
return result;
|
|
@@ -167,7 +167,79 @@ function resolveCacheTTL(cache) {
|
|
|
167
167
|
if (typeof cache === "number") return cache;
|
|
168
168
|
return 0;
|
|
169
169
|
}
|
|
170
|
+
|
|
171
|
+
// src/tools/bash.ts
|
|
172
|
+
import { tool as tool2, jsonSchema as jsonSchema2 } from "ai";
|
|
173
|
+
import { exec } from "child_process";
|
|
174
|
+
var MAX_OUTPUT = 3e4;
|
|
175
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
176
|
+
function createBashTool(options) {
|
|
177
|
+
const cwd = options?.cwd ?? process.cwd();
|
|
178
|
+
const timeout = Math.min(options?.timeout ?? DEFAULT_TIMEOUT, 6e5);
|
|
179
|
+
const maxOutput = options?.maxOutput ?? MAX_OUTPUT;
|
|
180
|
+
const schema = {
|
|
181
|
+
type: "object",
|
|
182
|
+
properties: {
|
|
183
|
+
command: {
|
|
184
|
+
type: "string",
|
|
185
|
+
description: "The bash command to execute"
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
required: ["command"]
|
|
189
|
+
};
|
|
190
|
+
return tool2({
|
|
191
|
+
description: "Execute a bash command on the server. Use this for running shell commands, scripts, package managers, git operations, file manipulation, and system tasks. Returns stdout, stderr, and exit code.",
|
|
192
|
+
inputSchema: jsonSchema2(schema),
|
|
193
|
+
execute: async (args) => {
|
|
194
|
+
const { command } = args;
|
|
195
|
+
const start = Date.now();
|
|
196
|
+
return new Promise((resolve) => {
|
|
197
|
+
const child = exec(
|
|
198
|
+
command,
|
|
199
|
+
{
|
|
200
|
+
cwd,
|
|
201
|
+
timeout,
|
|
202
|
+
shell: "/bin/bash",
|
|
203
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
204
|
+
// 10MB buffer
|
|
205
|
+
env: { ...process.env, TERM: "dumb" }
|
|
206
|
+
},
|
|
207
|
+
(error, stdout, stderr) => {
|
|
208
|
+
const durationMs = Date.now() - start;
|
|
209
|
+
const timedOut = error?.killed === true;
|
|
210
|
+
const exitCode = timedOut ? 124 : typeof error?.code === "number" ? error.code : error ? 1 : 0;
|
|
211
|
+
resolve({
|
|
212
|
+
stdout: truncate(stdout, maxOutput),
|
|
213
|
+
stderr: truncate(stderr, maxOutput),
|
|
214
|
+
exitCode,
|
|
215
|
+
durationMs,
|
|
216
|
+
...timedOut ? { timedOut: true } : {}
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
);
|
|
220
|
+
child.on("error", () => {
|
|
221
|
+
resolve({
|
|
222
|
+
stdout: "",
|
|
223
|
+
stderr: "Failed to start process",
|
|
224
|
+
exitCode: 127,
|
|
225
|
+
durationMs: Date.now() - start
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
function truncate(str, max) {
|
|
233
|
+
if (str.length <= max) return str;
|
|
234
|
+
const half = Math.floor(max / 2) - 50;
|
|
235
|
+
return str.slice(0, half) + `
|
|
236
|
+
|
|
237
|
+
... (${str.length - max} characters truncated) ...
|
|
238
|
+
|
|
239
|
+
` + str.slice(-half);
|
|
240
|
+
}
|
|
170
241
|
export {
|
|
242
|
+
createBashTool,
|
|
171
243
|
supyagent
|
|
172
244
|
};
|
|
173
245
|
//# sourceMappingURL=index.js.map
|
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 // 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":[]}
|
|
1
|
+
{"version":3,"sources":["../src/core/cache.ts","../src/core/tool-converter.ts","../src/core/http-executor.ts","../src/core/client.ts","../src/tools/bash.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 inputSchema: jsonSchema(parameters as Parameters<typeof jsonSchema>[0]),\n execute: async (args) => createExecutor(metadata, baseUrl, apiKey)(args as Record<string, unknown>),\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","import { tool, jsonSchema } from \"ai\";\nimport { exec, type ExecException } from \"node:child_process\";\n\nconst MAX_OUTPUT = 30_000;\nconst DEFAULT_TIMEOUT = 30_000; // 30 seconds\n\nexport interface BashToolOptions {\n /** Working directory for commands. Defaults to `process.cwd()`. */\n cwd?: string;\n /** Command timeout in milliseconds. Defaults to 30000 (30s). Max 600000 (10m). */\n timeout?: number;\n /** Maximum output length in characters. Defaults to 30000. */\n maxOutput?: number;\n}\n\nexport interface BashToolResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n durationMs: number;\n timedOut?: boolean;\n}\n\n/**\n * Create a bash tool that executes shell commands on the server.\n *\n * @example\n * ```ts\n * import { supyagent, createBashTool } from '@supyagent/sdk';\n *\n * const client = supyagent({ apiKey: process.env.SUPYAGENT_API_KEY! });\n * const supyagentTools = await client.tools({ cache: 300 });\n *\n * const tools = {\n * ...supyagentTools,\n * bash: createBashTool({ cwd: '/path/to/project' }),\n * };\n * ```\n */\nexport function createBashTool(options?: BashToolOptions) {\n const cwd = options?.cwd ?? process.cwd();\n const timeout = Math.min(options?.timeout ?? DEFAULT_TIMEOUT, 600_000);\n const maxOutput = options?.maxOutput ?? MAX_OUTPUT;\n\n const schema = {\n type: \"object\" as const,\n properties: {\n command: {\n type: \"string\",\n description: \"The bash command to execute\",\n },\n },\n required: [\"command\"],\n };\n\n return tool({\n description:\n \"Execute a bash command on the server. Use this for running shell commands, scripts, package managers, git operations, file manipulation, and system tasks. Returns stdout, stderr, and exit code.\",\n inputSchema: jsonSchema(schema as Parameters<typeof jsonSchema>[0]),\n execute: async (args): Promise<BashToolResult> => {\n const { command } = args as { command: string };\n const start = Date.now();\n\n return new Promise<BashToolResult>((resolve) => {\n const child = exec(\n command,\n {\n cwd,\n timeout,\n shell: \"/bin/bash\",\n maxBuffer: 10 * 1024 * 1024, // 10MB buffer\n env: { ...process.env, TERM: \"dumb\" },\n },\n (error: ExecException | null, stdout: string, stderr: string) => {\n const durationMs = Date.now() - start;\n const timedOut = error?.killed === true;\n const exitCode = timedOut\n ? 124\n : typeof error?.code === \"number\"\n ? error.code\n : error\n ? 1\n : 0;\n\n resolve({\n stdout: truncate(stdout, maxOutput),\n stderr: truncate(stderr, maxOutput),\n exitCode,\n durationMs,\n ...(timedOut ? { timedOut: true } : {}),\n });\n }\n );\n\n // Ensure the child process is killed on timeout\n child.on(\"error\", () => {\n resolve({\n stdout: \"\",\n stderr: \"Failed to start process\",\n exitCode: 127,\n durationMs: Date.now() - start,\n });\n });\n });\n },\n });\n}\n\nfunction truncate(str: string, max: number): string {\n if (str.length <= max) return str;\n const half = Math.floor(max / 2) - 50;\n return (\n str.slice(0, half) +\n `\\n\\n... (${str.length - max} characters truncated) ...\\n\\n` +\n str.slice(-half)\n );\n}\n"],"mappings":"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","names":["tool","jsonSchema"]}
|
package/dist/react.cjs
CHANGED
|
@@ -196,6 +196,9 @@ function getFormatterType(toolName) {
|
|
|
196
196
|
return "twilio";
|
|
197
197
|
case "linkedin":
|
|
198
198
|
return "linkedin";
|
|
199
|
+
case "bash":
|
|
200
|
+
case "shell":
|
|
201
|
+
return "bash";
|
|
199
202
|
default:
|
|
200
203
|
return "generic";
|
|
201
204
|
}
|
|
@@ -605,6 +608,15 @@ function getLinkedinSummary(data) {
|
|
|
605
608
|
}
|
|
606
609
|
return { text: "LinkedIn result" };
|
|
607
610
|
}
|
|
611
|
+
function getBashSummary(data) {
|
|
612
|
+
if (typeof data !== "object" || data === null) return { text: "Command executed" };
|
|
613
|
+
const d = data;
|
|
614
|
+
const exitCode = d.exitCode ?? d.exit_code ?? 0;
|
|
615
|
+
const timedOut = d.timedOut ?? d.timed_out;
|
|
616
|
+
if (timedOut) return { text: "Command timed out", badge: { text: "timeout", variant: "warning" } };
|
|
617
|
+
if (exitCode === 0) return { text: "Command succeeded", badge: { text: "exit 0", variant: "success" } };
|
|
618
|
+
return { text: `Command failed`, badge: { text: `exit ${exitCode}`, variant: "error" } };
|
|
619
|
+
}
|
|
608
620
|
function getGenericSummary(_data, toolName) {
|
|
609
621
|
return { text: humanizeToolName(toolName) };
|
|
610
622
|
}
|
|
@@ -635,6 +647,7 @@ var SUMMARY_MAP = {
|
|
|
635
647
|
calendly: getCalendlySummary,
|
|
636
648
|
twilio: getTwilioSummary,
|
|
637
649
|
linkedin: getLinkedinSummary,
|
|
650
|
+
bash: getBashSummary,
|
|
638
651
|
generic: getGenericSummary
|
|
639
652
|
};
|
|
640
653
|
function getSummary(formatterType, data, toolName) {
|