@aerostack/sdk-openai 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -0
- package/dist/commonjs/__tests__/converter.test.d.ts +2 -0
- package/dist/commonjs/__tests__/converter.test.d.ts.map +1 -0
- package/dist/commonjs/__tests__/converter.test.js +149 -0
- package/dist/commonjs/__tests__/converter.test.js.map +1 -0
- package/dist/commonjs/__tests__/executor.test.d.ts +2 -0
- package/dist/commonjs/__tests__/executor.test.d.ts.map +1 -0
- package/dist/commonjs/__tests__/executor.test.js +141 -0
- package/dist/commonjs/__tests__/executor.test.js.map +1 -0
- package/dist/commonjs/converter.d.ts +35 -0
- package/dist/commonjs/converter.d.ts.map +1 -0
- package/dist/commonjs/converter.js +89 -0
- package/dist/commonjs/converter.js.map +1 -0
- package/dist/commonjs/executor.d.ts +40 -0
- package/dist/commonjs/executor.d.ts.map +1 -0
- package/dist/commonjs/executor.js +84 -0
- package/dist/commonjs/executor.js.map +1 -0
- package/dist/commonjs/index.d.ts +88 -0
- package/dist/commonjs/index.d.ts.map +1 -0
- package/dist/commonjs/index.js +132 -0
- package/dist/commonjs/index.js.map +1 -0
- package/dist/commonjs/package.json +3 -0
- package/dist/esm/__tests__/converter.test.d.ts +2 -0
- package/dist/esm/__tests__/converter.test.d.ts.map +1 -0
- package/dist/esm/__tests__/converter.test.js +147 -0
- package/dist/esm/__tests__/converter.test.js.map +1 -0
- package/dist/esm/__tests__/executor.test.d.ts +2 -0
- package/dist/esm/__tests__/executor.test.d.ts.map +1 -0
- package/dist/esm/__tests__/executor.test.js +139 -0
- package/dist/esm/__tests__/executor.test.js.map +1 -0
- package/dist/esm/converter.d.ts +35 -0
- package/dist/esm/converter.d.ts.map +1 -0
- package/dist/esm/converter.js +82 -0
- package/dist/esm/converter.js.map +1 -0
- package/dist/esm/executor.d.ts +40 -0
- package/dist/esm/executor.d.ts.map +1 -0
- package/dist/esm/executor.js +79 -0
- package/dist/esm/executor.js.map +1 -0
- package/dist/esm/index.d.ts +88 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +120 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/package.json +65 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executeToolCall = executeToolCall;
|
|
4
|
+
exports.executeToolCalls = executeToolCalls;
|
|
5
|
+
exports.formatToolResult = formatToolResult;
|
|
6
|
+
const core_1 = require("@aerostack/core");
|
|
7
|
+
/**
|
|
8
|
+
* Execute a single OpenAI tool call against the Aerostack workspace.
|
|
9
|
+
*
|
|
10
|
+
* Returns a ChatCompletionToolMessageParam ready to append to messages.
|
|
11
|
+
* Errors from the workspace are returned as tool error messages (not thrown),
|
|
12
|
+
* because OpenAI expects a tool message back even when tools fail.
|
|
13
|
+
*
|
|
14
|
+
* @param nameMap - Optional reverse map from sanitized→original tool names
|
|
15
|
+
*/
|
|
16
|
+
async function executeToolCall(client, toolCall, nameMap) {
|
|
17
|
+
const originalName = nameMap?.get(toolCall.function.name) ?? toolCall.function.name;
|
|
18
|
+
let args;
|
|
19
|
+
try {
|
|
20
|
+
args = JSON.parse(toolCall.function.arguments || '{}');
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return {
|
|
24
|
+
role: 'tool',
|
|
25
|
+
tool_call_id: toolCall.id,
|
|
26
|
+
content: `Error: Failed to parse tool arguments as JSON`,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const result = await client.callTool(originalName, args);
|
|
31
|
+
return {
|
|
32
|
+
role: 'tool',
|
|
33
|
+
tool_call_id: toolCall.id,
|
|
34
|
+
content: formatToolResult(result),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
const message = err instanceof core_1.AerostackError
|
|
39
|
+
? `Error (${err.rpcCode}): ${err.message}`
|
|
40
|
+
: err instanceof Error
|
|
41
|
+
? `Error: ${err.message}`
|
|
42
|
+
: 'Error: Unknown error executing tool';
|
|
43
|
+
return {
|
|
44
|
+
role: 'tool',
|
|
45
|
+
tool_call_id: toolCall.id,
|
|
46
|
+
content: message,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Execute multiple tool calls in parallel.
|
|
52
|
+
*
|
|
53
|
+
* Returns an array of ChatCompletionToolMessageParam in the same order as input.
|
|
54
|
+
*/
|
|
55
|
+
async function executeToolCalls(client, toolCalls, nameMap) {
|
|
56
|
+
return Promise.all(toolCalls.map(tc => executeToolCall(client, tc, nameMap)));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Flatten McpToolResult content array into a single string for OpenAI.
|
|
60
|
+
*
|
|
61
|
+
* McpToolResult.content is an array of content blocks (text, base64 data, etc.).
|
|
62
|
+
* OpenAI tool messages expect a single string. We concatenate text blocks and
|
|
63
|
+
* JSON-serialize any non-text content.
|
|
64
|
+
*/
|
|
65
|
+
function formatToolResult(result) {
|
|
66
|
+
if (!result.content || result.content.length === 0) {
|
|
67
|
+
return result.isError ? 'Error: Tool returned no content' : 'Success (no output)';
|
|
68
|
+
}
|
|
69
|
+
const parts = [];
|
|
70
|
+
for (const block of result.content) {
|
|
71
|
+
if (block.text) {
|
|
72
|
+
parts.push(block.text);
|
|
73
|
+
}
|
|
74
|
+
else if (block.data) {
|
|
75
|
+
parts.push(`[${block.mimeType ?? 'binary'} data: ${block.data.length} chars base64]`);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
parts.push(JSON.stringify(block));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const text = parts.join('\n');
|
|
82
|
+
return result.isError ? `Error: ${text}` : text;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @aerostack/sdk-openai — Use Aerostack workspace tools as OpenAI function-calling tools.
|
|
3
|
+
*
|
|
4
|
+
* @example Standalone functions
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { getTools, handleToolCall, handleToolCalls } from '@aerostack/sdk-openai';
|
|
7
|
+
* import OpenAI from 'openai';
|
|
8
|
+
*
|
|
9
|
+
* const openai = new OpenAI();
|
|
10
|
+
* const config = { workspace: 'my-workspace', token: 'mwt_...' };
|
|
11
|
+
*
|
|
12
|
+
* const tools = await getTools(config);
|
|
13
|
+
* const response = await openai.chat.completions.create({
|
|
14
|
+
* model: 'gpt-4o',
|
|
15
|
+
* messages: [{ role: 'user', content: 'Create a GitHub issue for the login bug' }],
|
|
16
|
+
* tools,
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* const toolCalls = response.choices[0]?.message.tool_calls;
|
|
20
|
+
* if (toolCalls) {
|
|
21
|
+
* const results = await handleToolCalls(toolCalls, config);
|
|
22
|
+
* // results are ChatCompletionToolMessageParam[] — append to messages and continue
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @example Factory pattern
|
|
27
|
+
* ```ts
|
|
28
|
+
* const client = createAerostackOpenAI({ workspace: 'my-workspace', token: 'mwt_...' });
|
|
29
|
+
* const tools = await client.tools();
|
|
30
|
+
* const results = await client.handleToolCalls(toolCalls);
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
import type { ChatCompletionTool, ChatCompletionMessageToolCall, ChatCompletionToolMessageParam } from 'openai/resources/chat/completions';
|
|
34
|
+
import { WorkspaceClient } from '@aerostack/core';
|
|
35
|
+
import type { McpTool } from '@aerostack/core';
|
|
36
|
+
import type { WorkspaceConfig } from './executor.js';
|
|
37
|
+
export type { WorkspaceConfig } from './executor.js';
|
|
38
|
+
export { convertTools, convertTool, sanitizeToolName, isValidOpenAIName } from './converter.js';
|
|
39
|
+
export { formatToolResult } from './executor.js';
|
|
40
|
+
/** Result from getTools — includes both the OpenAI tools and the name map for execution. */
|
|
41
|
+
export interface ToolSet {
|
|
42
|
+
/** OpenAI-formatted tools, ready for chat.completions.create({ tools }) */
|
|
43
|
+
tools: ChatCompletionTool[];
|
|
44
|
+
/** Reverse map from sanitized names to original MCP tool names (used internally by handleToolCall) */
|
|
45
|
+
nameMap: Map<string, string>;
|
|
46
|
+
/** Raw MCP tools from the workspace */
|
|
47
|
+
raw: McpTool[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Fetch tools from an Aerostack workspace and convert to OpenAI format.
|
|
51
|
+
*
|
|
52
|
+
* Returns a ToolSet containing the formatted tools, a name map for execution,
|
|
53
|
+
* and the raw MCP tools for inspection.
|
|
54
|
+
*/
|
|
55
|
+
export declare function getTools(config: WorkspaceConfig): Promise<ToolSet>;
|
|
56
|
+
/**
|
|
57
|
+
* Execute a single OpenAI tool call against the workspace.
|
|
58
|
+
*
|
|
59
|
+
* @param toolCall - A tool call from response.choices[0].message.tool_calls
|
|
60
|
+
* @param config - Workspace connection config
|
|
61
|
+
* @param nameMap - Optional name map from getTools() (pass if tools were renamed)
|
|
62
|
+
*/
|
|
63
|
+
export declare function handleToolCall(toolCall: ChatCompletionMessageToolCall, config: WorkspaceConfig, nameMap?: Map<string, string>): Promise<ChatCompletionToolMessageParam>;
|
|
64
|
+
/**
|
|
65
|
+
* Execute multiple OpenAI tool calls in parallel against the workspace.
|
|
66
|
+
*
|
|
67
|
+
* Returns ChatCompletionToolMessageParam[] in the same order as input —
|
|
68
|
+
* ready to append to your messages array.
|
|
69
|
+
*/
|
|
70
|
+
export declare function handleToolCalls(toolCalls: ChatCompletionMessageToolCall[], config: WorkspaceConfig, nameMap?: Map<string, string>): Promise<ChatCompletionToolMessageParam[]>;
|
|
71
|
+
export interface AerostackOpenAIClient {
|
|
72
|
+
/** Fetch and convert workspace tools to OpenAI format. */
|
|
73
|
+
tools(): Promise<ToolSet>;
|
|
74
|
+
/** Execute a single tool call. */
|
|
75
|
+
handleToolCall(toolCall: ChatCompletionMessageToolCall): Promise<ChatCompletionToolMessageParam>;
|
|
76
|
+
/** Execute multiple tool calls in parallel. */
|
|
77
|
+
handleToolCalls(toolCalls: ChatCompletionMessageToolCall[]): Promise<ChatCompletionToolMessageParam[]>;
|
|
78
|
+
/** Access the underlying WorkspaceClient for advanced use. */
|
|
79
|
+
readonly workspaceClient: WorkspaceClient;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Create a reusable Aerostack OpenAI client.
|
|
83
|
+
*
|
|
84
|
+
* Reuses a single WorkspaceClient instance and caches the name map
|
|
85
|
+
* after the first tools() call for consistent tool name resolution.
|
|
86
|
+
*/
|
|
87
|
+
export declare function createAerostackOpenAI(config: WorkspaceConfig): AerostackOpenAIClient;
|
|
88
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,6BAA6B,EAAE,8BAA8B,EAAE,MAAM,mCAAmC,CAAC;AAC3I,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGrD,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAChG,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,4FAA4F;AAC5F,MAAM,WAAW,OAAO;IACpB,2EAA2E;IAC3E,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,sGAAsG;IACtG,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,uCAAuC;IACvC,GAAG,EAAE,OAAO,EAAE,CAAC;CAClB;AAcD;;;;;GAKG;AACH,wBAAsB,QAAQ,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,CAMxE;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAChC,QAAQ,EAAE,6BAA6B,EACvC,MAAM,EAAE,eAAe,EACvB,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,OAAO,CAAC,8BAA8B,CAAC,CAGzC;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACjC,SAAS,EAAE,6BAA6B,EAAE,EAC1C,MAAM,EAAE,eAAe,EACvB,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,OAAO,CAAC,8BAA8B,EAAE,CAAC,CAG3C;AAMD,MAAM,WAAW,qBAAqB;IAClC,0DAA0D;IAC1D,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1B,kCAAkC;IAClC,cAAc,CAAC,QAAQ,EAAE,6BAA6B,GAAG,OAAO,CAAC,8BAA8B,CAAC,CAAC;IACjG,+CAA+C;IAC/C,eAAe,CAAC,SAAS,EAAE,6BAA6B,EAAE,GAAG,OAAO,CAAC,8BAA8B,EAAE,CAAC,CAAC;IACvG,8DAA8D;IAC9D,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;CAC7C;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,eAAe,GAAG,qBAAqB,CAoCpF"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @aerostack/sdk-openai — Use Aerostack workspace tools as OpenAI function-calling tools.
|
|
4
|
+
*
|
|
5
|
+
* @example Standalone functions
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { getTools, handleToolCall, handleToolCalls } from '@aerostack/sdk-openai';
|
|
8
|
+
* import OpenAI from 'openai';
|
|
9
|
+
*
|
|
10
|
+
* const openai = new OpenAI();
|
|
11
|
+
* const config = { workspace: 'my-workspace', token: 'mwt_...' };
|
|
12
|
+
*
|
|
13
|
+
* const tools = await getTools(config);
|
|
14
|
+
* const response = await openai.chat.completions.create({
|
|
15
|
+
* model: 'gpt-4o',
|
|
16
|
+
* messages: [{ role: 'user', content: 'Create a GitHub issue for the login bug' }],
|
|
17
|
+
* tools,
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* const toolCalls = response.choices[0]?.message.tool_calls;
|
|
21
|
+
* if (toolCalls) {
|
|
22
|
+
* const results = await handleToolCalls(toolCalls, config);
|
|
23
|
+
* // results are ChatCompletionToolMessageParam[] — append to messages and continue
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @example Factory pattern
|
|
28
|
+
* ```ts
|
|
29
|
+
* const client = createAerostackOpenAI({ workspace: 'my-workspace', token: 'mwt_...' });
|
|
30
|
+
* const tools = await client.tools();
|
|
31
|
+
* const results = await client.handleToolCalls(toolCalls);
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
+
exports.formatToolResult = exports.isValidOpenAIName = exports.sanitizeToolName = exports.convertTool = exports.convertTools = void 0;
|
|
36
|
+
exports.getTools = getTools;
|
|
37
|
+
exports.handleToolCall = handleToolCall;
|
|
38
|
+
exports.handleToolCalls = handleToolCalls;
|
|
39
|
+
exports.createAerostackOpenAI = createAerostackOpenAI;
|
|
40
|
+
const core_1 = require("@aerostack/core");
|
|
41
|
+
const converter_js_1 = require("./converter.js");
|
|
42
|
+
const executor_js_1 = require("./executor.js");
|
|
43
|
+
var converter_js_2 = require("./converter.js");
|
|
44
|
+
Object.defineProperty(exports, "convertTools", { enumerable: true, get: function () { return converter_js_2.convertTools; } });
|
|
45
|
+
Object.defineProperty(exports, "convertTool", { enumerable: true, get: function () { return converter_js_2.convertTool; } });
|
|
46
|
+
Object.defineProperty(exports, "sanitizeToolName", { enumerable: true, get: function () { return converter_js_2.sanitizeToolName; } });
|
|
47
|
+
Object.defineProperty(exports, "isValidOpenAIName", { enumerable: true, get: function () { return converter_js_2.isValidOpenAIName; } });
|
|
48
|
+
var executor_js_2 = require("./executor.js");
|
|
49
|
+
Object.defineProperty(exports, "formatToolResult", { enumerable: true, get: function () { return executor_js_2.formatToolResult; } });
|
|
50
|
+
function createWorkspaceClient(config) {
|
|
51
|
+
return new core_1.WorkspaceClient({
|
|
52
|
+
slug: config.workspace,
|
|
53
|
+
token: config.token,
|
|
54
|
+
baseUrl: config.baseUrl,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// Standalone functions
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
/**
|
|
61
|
+
* Fetch tools from an Aerostack workspace and convert to OpenAI format.
|
|
62
|
+
*
|
|
63
|
+
* Returns a ToolSet containing the formatted tools, a name map for execution,
|
|
64
|
+
* and the raw MCP tools for inspection.
|
|
65
|
+
*/
|
|
66
|
+
async function getTools(config) {
|
|
67
|
+
const client = createWorkspaceClient(config);
|
|
68
|
+
const raw = await client.listTools();
|
|
69
|
+
const tools = (0, converter_js_1.convertTools)(raw);
|
|
70
|
+
const nameMap = (0, converter_js_1.buildNameMap)(raw);
|
|
71
|
+
return { tools, nameMap, raw };
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Execute a single OpenAI tool call against the workspace.
|
|
75
|
+
*
|
|
76
|
+
* @param toolCall - A tool call from response.choices[0].message.tool_calls
|
|
77
|
+
* @param config - Workspace connection config
|
|
78
|
+
* @param nameMap - Optional name map from getTools() (pass if tools were renamed)
|
|
79
|
+
*/
|
|
80
|
+
async function handleToolCall(toolCall, config, nameMap) {
|
|
81
|
+
const client = createWorkspaceClient(config);
|
|
82
|
+
return (0, executor_js_1.executeToolCall)(client, toolCall, nameMap);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Execute multiple OpenAI tool calls in parallel against the workspace.
|
|
86
|
+
*
|
|
87
|
+
* Returns ChatCompletionToolMessageParam[] in the same order as input —
|
|
88
|
+
* ready to append to your messages array.
|
|
89
|
+
*/
|
|
90
|
+
async function handleToolCalls(toolCalls, config, nameMap) {
|
|
91
|
+
const client = createWorkspaceClient(config);
|
|
92
|
+
return (0, executor_js_1.executeToolCalls)(client, toolCalls, nameMap);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Create a reusable Aerostack OpenAI client.
|
|
96
|
+
*
|
|
97
|
+
* Reuses a single WorkspaceClient instance and caches the name map
|
|
98
|
+
* after the first tools() call for consistent tool name resolution.
|
|
99
|
+
*/
|
|
100
|
+
function createAerostackOpenAI(config) {
|
|
101
|
+
const wsClient = createWorkspaceClient(config);
|
|
102
|
+
let cachedNameMap;
|
|
103
|
+
/** Ensure name map is populated — fetches tools on first call. */
|
|
104
|
+
async function ensureNameMap() {
|
|
105
|
+
if (!cachedNameMap) {
|
|
106
|
+
const raw = await wsClient.listTools();
|
|
107
|
+
cachedNameMap = (0, converter_js_1.buildNameMap)(raw);
|
|
108
|
+
}
|
|
109
|
+
return cachedNameMap;
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
async tools() {
|
|
113
|
+
const raw = await wsClient.listTools();
|
|
114
|
+
const tools = (0, converter_js_1.convertTools)(raw);
|
|
115
|
+
const nameMap = (0, converter_js_1.buildNameMap)(raw);
|
|
116
|
+
cachedNameMap = nameMap;
|
|
117
|
+
return { tools, nameMap, raw };
|
|
118
|
+
},
|
|
119
|
+
async handleToolCall(toolCall) {
|
|
120
|
+
const nameMap = await ensureNameMap();
|
|
121
|
+
return (0, executor_js_1.executeToolCall)(wsClient, toolCall, nameMap);
|
|
122
|
+
},
|
|
123
|
+
async handleToolCalls(toolCalls) {
|
|
124
|
+
const nameMap = await ensureNameMap();
|
|
125
|
+
return (0, executor_js_1.executeToolCalls)(wsClient, toolCalls, nameMap);
|
|
126
|
+
},
|
|
127
|
+
get workspaceClient() {
|
|
128
|
+
return wsClient;
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"converter.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/converter.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { convertTool, convertTools, sanitizeToolName, buildNameMap, isValidOpenAIName } from '../converter.js';
|
|
3
|
+
describe('convertTool', () => {
|
|
4
|
+
it('converts a standard MCP tool to OpenAI format', () => {
|
|
5
|
+
const mcpTool = {
|
|
6
|
+
name: 'github__create_issue',
|
|
7
|
+
description: 'Create a GitHub issue',
|
|
8
|
+
inputSchema: {
|
|
9
|
+
type: 'object',
|
|
10
|
+
properties: {
|
|
11
|
+
title: { type: 'string' },
|
|
12
|
+
body: { type: 'string' },
|
|
13
|
+
},
|
|
14
|
+
required: ['title'],
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
const result = convertTool(mcpTool);
|
|
18
|
+
expect(result).toEqual({
|
|
19
|
+
type: 'function',
|
|
20
|
+
function: {
|
|
21
|
+
name: 'github__create_issue',
|
|
22
|
+
description: 'Create a GitHub issue',
|
|
23
|
+
parameters: {
|
|
24
|
+
type: 'object',
|
|
25
|
+
properties: {
|
|
26
|
+
title: { type: 'string' },
|
|
27
|
+
body: { type: 'string' },
|
|
28
|
+
},
|
|
29
|
+
required: ['title'],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
it('handles undefined inputSchema with empty object schema', () => {
|
|
35
|
+
const mcpTool = {
|
|
36
|
+
name: 'slack__ping',
|
|
37
|
+
description: 'Ping Slack',
|
|
38
|
+
};
|
|
39
|
+
const result = convertTool(mcpTool);
|
|
40
|
+
expect(result.function.parameters).toEqual({
|
|
41
|
+
type: 'object',
|
|
42
|
+
properties: {},
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
it('handles undefined description', () => {
|
|
46
|
+
const mcpTool = {
|
|
47
|
+
name: 'my_tool',
|
|
48
|
+
inputSchema: { type: 'object', properties: {} },
|
|
49
|
+
};
|
|
50
|
+
const result = convertTool(mcpTool);
|
|
51
|
+
expect(result.function.description).toBeUndefined();
|
|
52
|
+
expect(result.function.name).toBe('my_tool');
|
|
53
|
+
});
|
|
54
|
+
it('handles tool with empty description', () => {
|
|
55
|
+
const mcpTool = {
|
|
56
|
+
name: 'my_tool',
|
|
57
|
+
description: '',
|
|
58
|
+
inputSchema: { type: 'object', properties: {} },
|
|
59
|
+
};
|
|
60
|
+
const result = convertTool(mcpTool);
|
|
61
|
+
// Empty string is falsy, so description should be omitted
|
|
62
|
+
expect(result.function).not.toHaveProperty('description');
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
describe('convertTools', () => {
|
|
66
|
+
it('converts an array of tools', () => {
|
|
67
|
+
const tools = [
|
|
68
|
+
{ name: 'tool_a', description: 'A' },
|
|
69
|
+
{ name: 'tool_b', description: 'B' },
|
|
70
|
+
];
|
|
71
|
+
const result = convertTools(tools);
|
|
72
|
+
expect(result).toHaveLength(2);
|
|
73
|
+
expect(result[0].function.name).toBe('tool_a');
|
|
74
|
+
expect(result[1].function.name).toBe('tool_b');
|
|
75
|
+
});
|
|
76
|
+
it('handles empty array', () => {
|
|
77
|
+
expect(convertTools([])).toEqual([]);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe('sanitizeToolName', () => {
|
|
81
|
+
it('passes through valid names unchanged', () => {
|
|
82
|
+
expect(sanitizeToolName('github__create_issue')).toBe('github__create_issue');
|
|
83
|
+
expect(sanitizeToolName('my-tool-123')).toBe('my-tool-123');
|
|
84
|
+
});
|
|
85
|
+
it('replaces invalid characters with underscores', () => {
|
|
86
|
+
expect(sanitizeToolName('my.tool.name')).toBe('my_tool_name');
|
|
87
|
+
expect(sanitizeToolName('tool with spaces')).toBe('tool_with_spaces');
|
|
88
|
+
});
|
|
89
|
+
it('throws on empty name', () => {
|
|
90
|
+
expect(() => sanitizeToolName('')).toThrow(/empty/i);
|
|
91
|
+
});
|
|
92
|
+
it('truncates names over 64 characters', () => {
|
|
93
|
+
const longName = 'a'.repeat(100);
|
|
94
|
+
const result = sanitizeToolName(longName);
|
|
95
|
+
expect(result.length).toBeLessThanOrEqual(64);
|
|
96
|
+
});
|
|
97
|
+
it('produces different truncated names for different long inputs', () => {
|
|
98
|
+
const name1 = 'server_one__' + 'a'.repeat(100);
|
|
99
|
+
const name2 = 'server_two__' + 'b'.repeat(100);
|
|
100
|
+
const result1 = sanitizeToolName(name1);
|
|
101
|
+
const result2 = sanitizeToolName(name2);
|
|
102
|
+
expect(result1).not.toBe(result2);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
describe('buildNameMap', () => {
|
|
106
|
+
it('maps sanitized names back to originals', () => {
|
|
107
|
+
const tools = [
|
|
108
|
+
{ name: 'github__create_issue' },
|
|
109
|
+
{ name: 'slack.post.message' },
|
|
110
|
+
];
|
|
111
|
+
const map = buildNameMap(tools);
|
|
112
|
+
expect(map.get('github__create_issue')).toBe('github__create_issue');
|
|
113
|
+
expect(map.get('slack_post_message')).toBe('slack.post.message');
|
|
114
|
+
});
|
|
115
|
+
it('throws on name collision', () => {
|
|
116
|
+
const tools = [
|
|
117
|
+
{ name: 'server.create' },
|
|
118
|
+
{ name: 'server_create' },
|
|
119
|
+
];
|
|
120
|
+
expect(() => buildNameMap(tools)).toThrow(/collision/i);
|
|
121
|
+
});
|
|
122
|
+
it('allows duplicate identical names', () => {
|
|
123
|
+
const tools = [
|
|
124
|
+
{ name: 'my_tool' },
|
|
125
|
+
{ name: 'my_tool' },
|
|
126
|
+
];
|
|
127
|
+
expect(() => buildNameMap(tools)).not.toThrow();
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
describe('isValidOpenAIName', () => {
|
|
131
|
+
it('accepts valid names', () => {
|
|
132
|
+
expect(isValidOpenAIName('my_tool')).toBe(true);
|
|
133
|
+
expect(isValidOpenAIName('github__create_issue')).toBe(true);
|
|
134
|
+
expect(isValidOpenAIName('a-b-c')).toBe(true);
|
|
135
|
+
});
|
|
136
|
+
it('rejects names with invalid characters', () => {
|
|
137
|
+
expect(isValidOpenAIName('my.tool')).toBe(false);
|
|
138
|
+
expect(isValidOpenAIName('tool name')).toBe(false);
|
|
139
|
+
});
|
|
140
|
+
it('rejects names over 64 characters', () => {
|
|
141
|
+
expect(isValidOpenAIName('a'.repeat(65))).toBe(false);
|
|
142
|
+
});
|
|
143
|
+
it('rejects empty string', () => {
|
|
144
|
+
expect(isValidOpenAIName('')).toBe(false);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
//# sourceMappingURL=converter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"converter.test.js","sourceRoot":"","sources":["../../../src/__tests__/converter.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/executor.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { executeToolCall, executeToolCalls, formatToolResult } from '../executor.js';
|
|
3
|
+
import { AerostackError } from '@aerostack/core';
|
|
4
|
+
function mockClient(callToolResult, shouldThrow = false) {
|
|
5
|
+
return {
|
|
6
|
+
callTool: shouldThrow
|
|
7
|
+
? vi.fn().mockRejectedValue(callToolResult)
|
|
8
|
+
: vi.fn().mockResolvedValue(callToolResult),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function makeToolCall(overrides = {}) {
|
|
12
|
+
return {
|
|
13
|
+
id: 'call_abc123',
|
|
14
|
+
type: 'function',
|
|
15
|
+
function: {
|
|
16
|
+
name: 'github__create_issue',
|
|
17
|
+
arguments: JSON.stringify({ title: 'Bug fix' }),
|
|
18
|
+
},
|
|
19
|
+
...overrides,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
describe('executeToolCall', () => {
|
|
23
|
+
it('executes a tool call and returns a tool message', async () => {
|
|
24
|
+
const client = mockClient({
|
|
25
|
+
content: [{ type: 'text', text: 'Issue #42 created' }],
|
|
26
|
+
});
|
|
27
|
+
const result = await executeToolCall(client, makeToolCall());
|
|
28
|
+
expect(result).toEqual({
|
|
29
|
+
role: 'tool',
|
|
30
|
+
tool_call_id: 'call_abc123',
|
|
31
|
+
content: 'Issue #42 created',
|
|
32
|
+
});
|
|
33
|
+
expect(client.callTool).toHaveBeenCalledWith('github__create_issue', { title: 'Bug fix' });
|
|
34
|
+
});
|
|
35
|
+
it('uses nameMap to resolve sanitized names', async () => {
|
|
36
|
+
const client = mockClient({
|
|
37
|
+
content: [{ type: 'text', text: 'done' }],
|
|
38
|
+
});
|
|
39
|
+
const nameMap = new Map([['slack_post_message', 'slack.post.message']]);
|
|
40
|
+
const tc = makeToolCall({
|
|
41
|
+
function: { name: 'slack_post_message', arguments: '{}' },
|
|
42
|
+
});
|
|
43
|
+
await executeToolCall(client, tc, nameMap);
|
|
44
|
+
expect(client.callTool).toHaveBeenCalledWith('slack.post.message', {});
|
|
45
|
+
});
|
|
46
|
+
it('returns error message when AerostackError is thrown', async () => {
|
|
47
|
+
const err = new AerostackError('MCP server down', 503, -32603, 'req-123');
|
|
48
|
+
const client = mockClient(err, true);
|
|
49
|
+
const result = await executeToolCall(client, makeToolCall());
|
|
50
|
+
expect(result.role).toBe('tool');
|
|
51
|
+
expect(result.content).toContain('Error (-32603)');
|
|
52
|
+
expect(result.content).toContain('MCP server down');
|
|
53
|
+
});
|
|
54
|
+
it('returns error message for generic errors', async () => {
|
|
55
|
+
const err = new Error('Network timeout');
|
|
56
|
+
const client = mockClient(err, true);
|
|
57
|
+
const result = await executeToolCall(client, makeToolCall());
|
|
58
|
+
expect(result.content).toBe('Error: Network timeout');
|
|
59
|
+
});
|
|
60
|
+
it('returns error for malformed JSON arguments', async () => {
|
|
61
|
+
const client = mockClient({});
|
|
62
|
+
const tc = makeToolCall({
|
|
63
|
+
function: { name: 'test', arguments: 'not json{' },
|
|
64
|
+
});
|
|
65
|
+
const result = await executeToolCall(client, tc);
|
|
66
|
+
expect(result.content).toContain('Failed to parse tool arguments');
|
|
67
|
+
});
|
|
68
|
+
it('handles empty arguments string', async () => {
|
|
69
|
+
const client = mockClient({
|
|
70
|
+
content: [{ type: 'text', text: 'ok' }],
|
|
71
|
+
});
|
|
72
|
+
const tc = makeToolCall({
|
|
73
|
+
function: { name: 'test', arguments: '' },
|
|
74
|
+
});
|
|
75
|
+
await executeToolCall(client, tc);
|
|
76
|
+
expect(client.callTool).toHaveBeenCalledWith('test', {});
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
describe('executeToolCalls', () => {
|
|
80
|
+
it('executes multiple tool calls in parallel', async () => {
|
|
81
|
+
const client = mockClient({
|
|
82
|
+
content: [{ type: 'text', text: 'done' }],
|
|
83
|
+
});
|
|
84
|
+
const toolCalls = [
|
|
85
|
+
makeToolCall({ id: 'call_1' }),
|
|
86
|
+
makeToolCall({ id: 'call_2' }),
|
|
87
|
+
];
|
|
88
|
+
const results = await executeToolCalls(client, toolCalls);
|
|
89
|
+
expect(results).toHaveLength(2);
|
|
90
|
+
expect(results[0].tool_call_id).toBe('call_1');
|
|
91
|
+
expect(results[1].tool_call_id).toBe('call_2');
|
|
92
|
+
});
|
|
93
|
+
it('handles empty array', async () => {
|
|
94
|
+
const client = mockClient({});
|
|
95
|
+
const results = await executeToolCalls(client, []);
|
|
96
|
+
expect(results).toEqual([]);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
describe('formatToolResult', () => {
|
|
100
|
+
it('formats single text content', () => {
|
|
101
|
+
const result = formatToolResult({
|
|
102
|
+
content: [{ type: 'text', text: 'Hello world' }],
|
|
103
|
+
});
|
|
104
|
+
expect(result).toBe('Hello world');
|
|
105
|
+
});
|
|
106
|
+
it('concatenates multiple text blocks', () => {
|
|
107
|
+
const result = formatToolResult({
|
|
108
|
+
content: [
|
|
109
|
+
{ type: 'text', text: 'Line 1' },
|
|
110
|
+
{ type: 'text', text: 'Line 2' },
|
|
111
|
+
],
|
|
112
|
+
});
|
|
113
|
+
expect(result).toBe('Line 1\nLine 2');
|
|
114
|
+
});
|
|
115
|
+
it('handles binary data blocks', () => {
|
|
116
|
+
const result = formatToolResult({
|
|
117
|
+
content: [{ type: 'image', data: 'base64data...', mimeType: 'image/png' }],
|
|
118
|
+
});
|
|
119
|
+
expect(result).toContain('image/png');
|
|
120
|
+
expect(result).toContain('base64');
|
|
121
|
+
});
|
|
122
|
+
it('prefixes error results', () => {
|
|
123
|
+
const result = formatToolResult({
|
|
124
|
+
content: [{ type: 'text', text: 'Something failed' }],
|
|
125
|
+
isError: true,
|
|
126
|
+
});
|
|
127
|
+
expect(result).toBe('Error: Something failed');
|
|
128
|
+
});
|
|
129
|
+
it('handles empty content array', () => {
|
|
130
|
+
expect(formatToolResult({ content: [] })).toBe('Success (no output)');
|
|
131
|
+
});
|
|
132
|
+
it('handles undefined content', () => {
|
|
133
|
+
expect(formatToolResult({})).toBe('Success (no output)');
|
|
134
|
+
});
|
|
135
|
+
it('handles empty content with isError', () => {
|
|
136
|
+
expect(formatToolResult({ content: [], isError: true })).toBe('Error: Tool returned no content');
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
//# sourceMappingURL=executor.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.test.js","sourceRoot":"","sources":["../../../src/__tests__/executor.test.ts"],"names":[],"mappings":"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"}
|