Files
smartagent/ts/smartagent.tools.http.ts

206 lines
6.3 KiB
TypeScript
Raw Normal View History

2025-12-02 10:59:09 +00:00
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;
}
}