206 lines
6.3 KiB
TypeScript
206 lines
6.3 KiB
TypeScript
import * as plugins from './plugins.js';
|
|
import * as interfaces from './smartagent.interfaces.js';
|
|
import { BaseToolWrapper } from './smartagent.tools.base.js';
|
|
|
|
/**
|
|
* HTTP tool for making web requests
|
|
* Wraps @push.rocks/smartrequest
|
|
*/
|
|
export class HttpTool extends BaseToolWrapper {
|
|
public name = 'http';
|
|
public description = 'Make HTTP requests to web APIs and services';
|
|
|
|
public actions: interfaces.IToolAction[] = [
|
|
{
|
|
name: 'get',
|
|
description: 'Make a GET request',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
url: { type: 'string', description: 'URL to request' },
|
|
headers: { type: 'object', description: 'Request headers (key-value pairs)' },
|
|
query: { type: 'object', description: 'Query parameters (key-value pairs)' },
|
|
timeout: { type: 'number', description: 'Timeout in milliseconds' },
|
|
},
|
|
required: ['url'],
|
|
},
|
|
},
|
|
{
|
|
name: 'post',
|
|
description: 'Make a POST request with JSON body',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
url: { type: 'string', description: 'URL to request' },
|
|
body: { type: 'object', description: 'JSON body to send' },
|
|
headers: { type: 'object', description: 'Request headers (key-value pairs)' },
|
|
query: { type: 'object', description: 'Query parameters (key-value pairs)' },
|
|
timeout: { type: 'number', description: 'Timeout in milliseconds' },
|
|
},
|
|
required: ['url'],
|
|
},
|
|
},
|
|
{
|
|
name: 'put',
|
|
description: 'Make a PUT request with JSON body',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
url: { type: 'string', description: 'URL to request' },
|
|
body: { type: 'object', description: 'JSON body to send' },
|
|
headers: { type: 'object', description: 'Request headers (key-value pairs)' },
|
|
timeout: { type: 'number', description: 'Timeout in milliseconds' },
|
|
},
|
|
required: ['url', 'body'],
|
|
},
|
|
},
|
|
{
|
|
name: 'patch',
|
|
description: 'Make a PATCH request with JSON body',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
url: { type: 'string', description: 'URL to request' },
|
|
body: { type: 'object', description: 'JSON body to send' },
|
|
headers: { type: 'object', description: 'Request headers (key-value pairs)' },
|
|
timeout: { type: 'number', description: 'Timeout in milliseconds' },
|
|
},
|
|
required: ['url', 'body'],
|
|
},
|
|
},
|
|
{
|
|
name: 'delete',
|
|
description: 'Make a DELETE request',
|
|
parameters: {
|
|
type: 'object',
|
|
properties: {
|
|
url: { type: 'string', description: 'URL to request' },
|
|
headers: { type: 'object', description: 'Request headers (key-value pairs)' },
|
|
timeout: { type: 'number', description: 'Timeout in milliseconds' },
|
|
},
|
|
required: ['url'],
|
|
},
|
|
},
|
|
];
|
|
|
|
public async initialize(): Promise<void> {
|
|
// SmartRequest is stateless, no initialization needed
|
|
this.isInitialized = true;
|
|
}
|
|
|
|
public async cleanup(): Promise<void> {
|
|
this.isInitialized = false;
|
|
}
|
|
|
|
public async execute(
|
|
action: string,
|
|
params: Record<string, unknown>
|
|
): Promise<interfaces.IToolExecutionResult> {
|
|
this.validateAction(action);
|
|
this.ensureInitialized();
|
|
|
|
try {
|
|
let request = plugins.smartrequest.SmartRequest.create().url(params.url as string);
|
|
|
|
// Add headers
|
|
if (params.headers && typeof params.headers === 'object') {
|
|
for (const [key, value] of Object.entries(params.headers as Record<string, string>)) {
|
|
request = request.header(key, value);
|
|
}
|
|
}
|
|
|
|
// Add query parameters
|
|
if (params.query && typeof params.query === 'object') {
|
|
request = request.query(params.query as Record<string, string>);
|
|
}
|
|
|
|
// Add timeout
|
|
if (params.timeout) {
|
|
request = request.timeout(params.timeout as number);
|
|
}
|
|
|
|
// Add JSON body for POST, PUT, PATCH
|
|
if (params.body && ['post', 'put', 'patch'].includes(action)) {
|
|
request = request.json(params.body);
|
|
}
|
|
|
|
// Execute the request
|
|
let response;
|
|
switch (action) {
|
|
case 'get':
|
|
response = await request.get();
|
|
break;
|
|
case 'post':
|
|
response = await request.post();
|
|
break;
|
|
case 'put':
|
|
response = await request.put();
|
|
break;
|
|
case 'patch':
|
|
response = await request.patch();
|
|
break;
|
|
case 'delete':
|
|
response = await request.delete();
|
|
break;
|
|
default:
|
|
return { success: false, error: `Unknown action: ${action}` };
|
|
}
|
|
|
|
// Parse response body
|
|
let body: unknown;
|
|
const contentType = response.headers?.['content-type'] || '';
|
|
|
|
try {
|
|
if (contentType.includes('application/json')) {
|
|
body = await response.json();
|
|
} else {
|
|
body = await response.text();
|
|
}
|
|
} catch {
|
|
body = null;
|
|
}
|
|
|
|
return {
|
|
success: response.ok,
|
|
result: {
|
|
url: params.url,
|
|
method: action.toUpperCase(),
|
|
status: response.status,
|
|
statusText: response.statusText,
|
|
ok: response.ok,
|
|
headers: response.headers,
|
|
body,
|
|
},
|
|
};
|
|
} catch (error) {
|
|
return {
|
|
success: false,
|
|
error: error instanceof Error ? error.message : String(error),
|
|
};
|
|
}
|
|
}
|
|
|
|
public getCallSummary(action: string, params: Record<string, unknown>): string {
|
|
const method = action.toUpperCase();
|
|
let summary = `${method} request to "${params.url}"`;
|
|
|
|
if (params.query && Object.keys(params.query as object).length > 0) {
|
|
const queryStr = JSON.stringify(params.query);
|
|
summary += ` with query: ${queryStr.length > 50 ? queryStr.substring(0, 50) + '...' : queryStr}`;
|
|
}
|
|
|
|
if (params.body) {
|
|
const bodyStr = JSON.stringify(params.body);
|
|
const preview = bodyStr.length > 100 ? bodyStr.substring(0, 100) + '...' : bodyStr;
|
|
summary += ` with body: ${preview}`;
|
|
}
|
|
|
|
if (params.headers && Object.keys(params.headers as object).length > 0) {
|
|
const headerKeys = Object.keys(params.headers as object).join(', ');
|
|
summary += ` with headers: [${headerKeys}]`;
|
|
}
|
|
|
|
return summary;
|
|
}
|
|
}
|