@radaros/core 0.3.5 → 0.3.6
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.d.ts +1407 -0
- package/dist/index.js +5269 -0
- package/package.json +6 -2
- package/src/a2a/a2a-remote-agent.ts +0 -270
- package/src/a2a/types.ts +0 -142
- package/src/agent/agent.ts +0 -417
- package/src/agent/llm-loop.ts +0 -290
- package/src/agent/run-context.ts +0 -35
- package/src/agent/types.ts +0 -89
- package/src/events/event-bus.ts +0 -45
- package/src/events/types.ts +0 -16
- package/src/guardrails/types.ts +0 -5
- package/src/hooks/types.ts +0 -6
- package/src/index.ts +0 -157
- package/src/knowledge/knowledge-base.ts +0 -146
- package/src/logger/logger.ts +0 -249
- package/src/mcp/mcp-client.ts +0 -264
- package/src/memory/memory.ts +0 -87
- package/src/memory/types.ts +0 -13
- package/src/memory/user-memory.ts +0 -211
- package/src/models/provider.ts +0 -22
- package/src/models/providers/anthropic.ts +0 -360
- package/src/models/providers/google.ts +0 -386
- package/src/models/providers/ollama.ts +0 -211
- package/src/models/providers/openai.ts +0 -345
- package/src/models/providers/vertex.ts +0 -427
- package/src/models/registry.ts +0 -107
- package/src/models/types.ts +0 -124
- package/src/session/session-manager.ts +0 -75
- package/src/session/types.ts +0 -10
- package/src/storage/driver.ts +0 -10
- package/src/storage/in-memory.ts +0 -44
- package/src/storage/mongodb.ts +0 -70
- package/src/storage/postgres.ts +0 -81
- package/src/storage/sqlite.ts +0 -81
- package/src/team/modes.ts +0 -1
- package/src/team/team.ts +0 -323
- package/src/team/types.ts +0 -26
- package/src/toolkits/base.ts +0 -15
- package/src/toolkits/duckduckgo.ts +0 -256
- package/src/toolkits/gmail.ts +0 -226
- package/src/toolkits/hackernews.ts +0 -121
- package/src/toolkits/websearch.ts +0 -158
- package/src/toolkits/whatsapp.ts +0 -209
- package/src/tools/define-tool.ts +0 -22
- package/src/tools/tool-executor.ts +0 -221
- package/src/tools/types.ts +0 -36
- package/src/utils/retry.ts +0 -56
- package/src/vector/base.ts +0 -44
- package/src/vector/embeddings/google.ts +0 -64
- package/src/vector/embeddings/openai.ts +0 -66
- package/src/vector/in-memory.ts +0 -115
- package/src/vector/mongodb.ts +0 -241
- package/src/vector/pgvector.ts +0 -169
- package/src/vector/qdrant.ts +0 -203
- package/src/vector/types.ts +0 -55
- package/src/workflow/step-runner.ts +0 -303
- package/src/workflow/types.ts +0 -55
- package/src/workflow/workflow.ts +0 -68
- package/tsconfig.json +0 -8
package/src/logger/logger.ts
DELETED
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
export type LogLevel = "debug" | "info" | "warn" | "error" | "silent";
|
|
2
|
-
|
|
3
|
-
const LEVEL_ORDER: Record<LogLevel, number> = {
|
|
4
|
-
debug: 0,
|
|
5
|
-
info: 1,
|
|
6
|
-
warn: 2,
|
|
7
|
-
error: 3,
|
|
8
|
-
silent: 4,
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const C = {
|
|
12
|
-
reset: "\x1b[0m",
|
|
13
|
-
bold: "\x1b[1m",
|
|
14
|
-
dim: "\x1b[2m",
|
|
15
|
-
italic: "\x1b[3m",
|
|
16
|
-
|
|
17
|
-
black: "\x1b[30m",
|
|
18
|
-
red: "\x1b[31m",
|
|
19
|
-
green: "\x1b[32m",
|
|
20
|
-
yellow: "\x1b[33m",
|
|
21
|
-
blue: "\x1b[34m",
|
|
22
|
-
magenta: "\x1b[35m",
|
|
23
|
-
cyan: "\x1b[36m",
|
|
24
|
-
white: "\x1b[37m",
|
|
25
|
-
|
|
26
|
-
bgBlack: "\x1b[40m",
|
|
27
|
-
bgRed: "\x1b[41m",
|
|
28
|
-
bgGreen: "\x1b[42m",
|
|
29
|
-
bgYellow: "\x1b[43m",
|
|
30
|
-
bgBlue: "\x1b[44m",
|
|
31
|
-
bgMagenta: "\x1b[45m",
|
|
32
|
-
bgCyan: "\x1b[46m",
|
|
33
|
-
|
|
34
|
-
gray: "\x1b[90m",
|
|
35
|
-
brightGreen: "\x1b[92m",
|
|
36
|
-
brightYellow: "\x1b[93m",
|
|
37
|
-
brightBlue: "\x1b[94m",
|
|
38
|
-
brightMagenta: "\x1b[95m",
|
|
39
|
-
brightCyan: "\x1b[96m",
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
function noColor(str: string): string {
|
|
43
|
-
return str.replace(/\x1b\[[0-9;]*m/g, "");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface LoggerConfig {
|
|
47
|
-
level?: LogLevel;
|
|
48
|
-
color?: boolean;
|
|
49
|
-
prefix?: string;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export class Logger {
|
|
53
|
-
private level: LogLevel;
|
|
54
|
-
private color: boolean;
|
|
55
|
-
private prefix: string;
|
|
56
|
-
|
|
57
|
-
constructor(config: LoggerConfig = {}) {
|
|
58
|
-
this.level = config.level ?? "info";
|
|
59
|
-
this.color = config.color ?? process.stdout.isTTY !== false;
|
|
60
|
-
this.prefix = config.prefix ?? "radaros";
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
private c(code: string, text: string): string {
|
|
64
|
-
return this.color ? `${code}${text}${C.reset}` : text;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
private shouldLog(level: LogLevel): boolean {
|
|
68
|
-
return LEVEL_ORDER[level] >= LEVEL_ORDER[this.level];
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
private tag(level: LogLevel): string {
|
|
72
|
-
switch (level) {
|
|
73
|
-
case "debug":
|
|
74
|
-
return this.c(C.gray, "DBG");
|
|
75
|
-
case "info":
|
|
76
|
-
return this.c(C.brightCyan, "INF");
|
|
77
|
-
case "warn":
|
|
78
|
-
return this.c(C.brightYellow, "WRN");
|
|
79
|
-
case "error":
|
|
80
|
-
return this.c(C.red, "ERR");
|
|
81
|
-
default:
|
|
82
|
-
return "";
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
private timestamp(): string {
|
|
87
|
-
const now = new Date();
|
|
88
|
-
const ts = now.toISOString().slice(11, 23);
|
|
89
|
-
return this.c(C.dim, ts);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
private log(level: LogLevel, msg: string, data?: Record<string, unknown>): void {
|
|
93
|
-
if (!this.shouldLog(level)) return;
|
|
94
|
-
const parts = [
|
|
95
|
-
this.timestamp(),
|
|
96
|
-
this.tag(level),
|
|
97
|
-
this.c(C.dim, `[${this.prefix}]`),
|
|
98
|
-
msg,
|
|
99
|
-
];
|
|
100
|
-
if (data && Object.keys(data).length > 0) {
|
|
101
|
-
const formatted = Object.entries(data)
|
|
102
|
-
.map(([k, v]) => `${this.c(C.dim, k + "=")}${this.formatValue(v)}`)
|
|
103
|
-
.join(" ");
|
|
104
|
-
parts.push(formatted);
|
|
105
|
-
}
|
|
106
|
-
console.log(parts.join(" "));
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
private formatValue(v: unknown): string {
|
|
110
|
-
if (typeof v === "number") return this.c(C.brightGreen, String(v));
|
|
111
|
-
if (typeof v === "string") return this.c(C.yellow, `"${v}"`);
|
|
112
|
-
if (typeof v === "boolean") return this.c(C.magenta, String(v));
|
|
113
|
-
return String(v);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
debug(msg: string, data?: Record<string, unknown>) {
|
|
117
|
-
this.log("debug", msg, data);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
info(msg: string, data?: Record<string, unknown>) {
|
|
121
|
-
this.log("info", msg, data);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
warn(msg: string, data?: Record<string, unknown>) {
|
|
125
|
-
this.log("warn", msg, data);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
error(msg: string, data?: Record<string, unknown>) {
|
|
129
|
-
this.log("error", msg, data);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// ── Formatted agent output helpers ────────────────────────────────────
|
|
133
|
-
|
|
134
|
-
private readonly boxWidth = 80;
|
|
135
|
-
|
|
136
|
-
private pipe(): string {
|
|
137
|
-
return this.c(C.brightCyan, "│");
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
private printBoxLine(label: string, value: string, labelColor = C.dim, valueColor = C.white): void {
|
|
141
|
-
const lines = value.split("\n");
|
|
142
|
-
const prefix = `${this.pipe()} ${this.c(labelColor, label)}`;
|
|
143
|
-
console.log(`${prefix}${this.c(valueColor, lines[0])}`);
|
|
144
|
-
const pad = " ".repeat(noColor(label).length);
|
|
145
|
-
for (let i = 1; i < lines.length; i++) {
|
|
146
|
-
console.log(`${this.pipe()} ${pad}${this.c(valueColor, lines[i])}`);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
agentStart(agentName: string, input: string): void {
|
|
151
|
-
if (!this.shouldLog("info")) return;
|
|
152
|
-
const title = ` Agent: ${agentName} `;
|
|
153
|
-
const lineLen = Math.max(0, this.boxWidth - title.length - 2);
|
|
154
|
-
console.log("");
|
|
155
|
-
console.log(
|
|
156
|
-
this.c(C.bold + C.brightCyan, "┌─") +
|
|
157
|
-
this.c(C.bold + C.brightCyan, title) +
|
|
158
|
-
this.c(C.dim, "─".repeat(lineLen))
|
|
159
|
-
);
|
|
160
|
-
this.printBoxLine("Input: ", input);
|
|
161
|
-
console.log(this.pipe());
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
toolCall(toolName: string, args: Record<string, unknown>): void {
|
|
165
|
-
if (!this.shouldLog("debug")) return;
|
|
166
|
-
const argsStr = JSON.stringify(args, null, 2);
|
|
167
|
-
console.log(
|
|
168
|
-
`${this.pipe()} ${this.c(C.brightMagenta, "⚡")} ${this.c(C.magenta, toolName)}`
|
|
169
|
-
);
|
|
170
|
-
if (argsStr !== "{}" && argsStr !== "[]") {
|
|
171
|
-
const truncated = argsStr.length > 200 ? argsStr.slice(0, 200) + "…" : argsStr;
|
|
172
|
-
for (const line of truncated.split("\n")) {
|
|
173
|
-
console.log(`${this.pipe()} ${this.c(C.dim, line)}`);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
toolResult(toolName: string, result: string): void {
|
|
179
|
-
if (!this.shouldLog("debug")) return;
|
|
180
|
-
const truncated = result.length > 300 ? result.slice(0, 300) + "…" : result;
|
|
181
|
-
console.log(
|
|
182
|
-
`${this.pipe()} ${this.c(C.green, "✓")} ${this.c(C.dim, toolName + " →")}`
|
|
183
|
-
);
|
|
184
|
-
for (const line of truncated.split("\n")) {
|
|
185
|
-
console.log(`${this.pipe()} ${this.c(C.gray, line)}`);
|
|
186
|
-
}
|
|
187
|
-
console.log(this.pipe());
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
thinking(content: string): void {
|
|
191
|
-
if (!this.shouldLog("info")) return;
|
|
192
|
-
const truncated = content.length > 500 ? content.slice(0, 500) + "…" : content;
|
|
193
|
-
const label = this.c(C.dim + C.italic, "Thinking: ");
|
|
194
|
-
const lines = truncated.split("\n");
|
|
195
|
-
console.log(`${this.pipe()} ${label}${this.c(C.dim + C.italic, lines[0])}`);
|
|
196
|
-
const pad = " ".repeat(10);
|
|
197
|
-
for (let i = 1; i < lines.length; i++) {
|
|
198
|
-
console.log(`${this.pipe()} ${pad}${this.c(C.dim + C.italic, lines[i])}`);
|
|
199
|
-
}
|
|
200
|
-
console.log(this.pipe());
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
agentEnd(
|
|
204
|
-
agentName: string,
|
|
205
|
-
output: string,
|
|
206
|
-
usage: { promptTokens: number; completionTokens: number; totalTokens: number; reasoningTokens?: number },
|
|
207
|
-
durationMs: number
|
|
208
|
-
): void {
|
|
209
|
-
if (!this.shouldLog("info")) return;
|
|
210
|
-
|
|
211
|
-
console.log(this.pipe());
|
|
212
|
-
this.printBoxLine("Output: ", output);
|
|
213
|
-
console.log(this.pipe());
|
|
214
|
-
|
|
215
|
-
let tokensLine =
|
|
216
|
-
this.c(C.dim, "Tokens: ") +
|
|
217
|
-
this.c(C.brightGreen, `↑ ${usage.promptTokens}`) +
|
|
218
|
-
this.c(C.dim, " ") +
|
|
219
|
-
this.c(C.brightGreen, `↓ ${usage.completionTokens}`) +
|
|
220
|
-
this.c(C.dim, " ") +
|
|
221
|
-
this.c(C.bold + C.brightGreen, `Σ ${usage.totalTokens}`);
|
|
222
|
-
|
|
223
|
-
if (usage.reasoningTokens) {
|
|
224
|
-
tokensLine += this.c(C.dim, " ") + this.c(C.brightMagenta, `🧠 ${usage.reasoningTokens}`);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const duration =
|
|
228
|
-
this.c(C.dim, "Duration: ") +
|
|
229
|
-
this.c(C.yellow, this.formatDuration(durationMs));
|
|
230
|
-
|
|
231
|
-
console.log(`${this.pipe()} ${tokensLine}`);
|
|
232
|
-
console.log(`${this.pipe()} ${duration}`);
|
|
233
|
-
console.log(
|
|
234
|
-
this.c(C.bold + C.brightCyan, "└") +
|
|
235
|
-
this.c(C.dim, "─".repeat(this.boxWidth - 1))
|
|
236
|
-
);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
separator(): void {
|
|
240
|
-
if (!this.shouldLog("info")) return;
|
|
241
|
-
console.log(this.c(C.dim, "─".repeat(this.boxWidth)));
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
private formatDuration(ms: number): string {
|
|
245
|
-
if (ms < 1000) return `${ms}ms`;
|
|
246
|
-
const secs = (ms / 1000).toFixed(1);
|
|
247
|
-
return `${secs}s`;
|
|
248
|
-
}
|
|
249
|
-
}
|
package/src/mcp/mcp-client.ts
DELETED
|
@@ -1,264 +0,0 @@
|
|
|
1
|
-
import type { ToolDef, ToolResult } from "../tools/types.js";
|
|
2
|
-
import type { RunContext } from "../agent/run-context.js";
|
|
3
|
-
|
|
4
|
-
export interface MCPToolProviderConfig {
|
|
5
|
-
name: string;
|
|
6
|
-
transport: "stdio" | "http";
|
|
7
|
-
/** For stdio transport: command to spawn */
|
|
8
|
-
command?: string;
|
|
9
|
-
/** For stdio transport: args for the command */
|
|
10
|
-
args?: string[];
|
|
11
|
-
/** For stdio transport: environment variables */
|
|
12
|
-
env?: Record<string, string>;
|
|
13
|
-
/** For http transport: server URL */
|
|
14
|
-
url?: string;
|
|
15
|
-
/** For http transport: custom headers */
|
|
16
|
-
headers?: Record<string, string>;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Connects to an MCP (Model Context Protocol) server and exposes its tools
|
|
21
|
-
* as native RadarOS ToolDef[] that any Agent can use.
|
|
22
|
-
*
|
|
23
|
-
* Supports stdio and HTTP (Streamable HTTP) transports.
|
|
24
|
-
* Requires: npm install @modelcontextprotocol/sdk
|
|
25
|
-
*/
|
|
26
|
-
export class MCPToolProvider {
|
|
27
|
-
readonly name: string;
|
|
28
|
-
private config: MCPToolProviderConfig;
|
|
29
|
-
private client: any = null;
|
|
30
|
-
private transportInstance: any = null;
|
|
31
|
-
private tools: ToolDef[] = [];
|
|
32
|
-
private connected = false;
|
|
33
|
-
|
|
34
|
-
constructor(config: MCPToolProviderConfig) {
|
|
35
|
-
this.name = config.name;
|
|
36
|
-
this.config = config;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async connect(): Promise<void> {
|
|
40
|
-
if (this.connected) return;
|
|
41
|
-
|
|
42
|
-
let ClientClass: any;
|
|
43
|
-
try {
|
|
44
|
-
const mod = await import("@modelcontextprotocol/sdk/client/index.js");
|
|
45
|
-
ClientClass = mod.Client;
|
|
46
|
-
} catch {
|
|
47
|
-
throw new Error(
|
|
48
|
-
"@modelcontextprotocol/sdk is required for MCPToolProvider. Install it: npm install @modelcontextprotocol/sdk"
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
this.client = new ClientClass(
|
|
53
|
-
{ name: `radaros-${this.name}`, version: "1.0.0" },
|
|
54
|
-
{ capabilities: {} }
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
if (this.config.transport === "stdio") {
|
|
58
|
-
if (!this.config.command) {
|
|
59
|
-
throw new Error("MCPToolProvider: 'command' is required for stdio transport");
|
|
60
|
-
}
|
|
61
|
-
const { StdioClientTransport } = await import(
|
|
62
|
-
"@modelcontextprotocol/sdk/client/stdio.js"
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
this.transportInstance = new StdioClientTransport({
|
|
66
|
-
command: this.config.command,
|
|
67
|
-
args: this.config.args ?? [],
|
|
68
|
-
env: { ...process.env, ...(this.config.env ?? {}) } as Record<string, string>,
|
|
69
|
-
});
|
|
70
|
-
} else if (this.config.transport === "http") {
|
|
71
|
-
if (!this.config.url) {
|
|
72
|
-
throw new Error("MCPToolProvider: 'url' is required for http transport");
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
let TransportClass: any;
|
|
76
|
-
try {
|
|
77
|
-
const mod = await import(
|
|
78
|
-
"@modelcontextprotocol/sdk/client/streamableHttp.js"
|
|
79
|
-
);
|
|
80
|
-
TransportClass = mod.StreamableHTTPClientTransport;
|
|
81
|
-
} catch {
|
|
82
|
-
const mod = await import("@modelcontextprotocol/sdk/client/sse.js");
|
|
83
|
-
TransportClass = mod.SSEClientTransport;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
this.transportInstance = new TransportClass(
|
|
87
|
-
new URL(this.config.url),
|
|
88
|
-
{ requestInit: { headers: this.config.headers ?? {} } }
|
|
89
|
-
);
|
|
90
|
-
} else {
|
|
91
|
-
throw new Error(`MCPToolProvider: unsupported transport '${this.config.transport}'`);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
await this.client.connect(this.transportInstance);
|
|
95
|
-
this.connected = true;
|
|
96
|
-
await this.discoverTools();
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
private async discoverTools(): Promise<void> {
|
|
100
|
-
const { z } = await import("zod");
|
|
101
|
-
const result = await this.client.listTools();
|
|
102
|
-
const mcpTools: any[] = result.tools ?? [];
|
|
103
|
-
|
|
104
|
-
this.tools = mcpTools.map((mcpTool: any) => {
|
|
105
|
-
const toolName = mcpTool.name;
|
|
106
|
-
const description = mcpTool.description ?? "";
|
|
107
|
-
const inputSchema = mcpTool.inputSchema ?? { type: "object", properties: {} };
|
|
108
|
-
|
|
109
|
-
const parameters = this.jsonSchemaToZod(inputSchema, z);
|
|
110
|
-
|
|
111
|
-
const execute = async (
|
|
112
|
-
args: Record<string, unknown>,
|
|
113
|
-
_ctx: RunContext
|
|
114
|
-
): Promise<string | ToolResult> => {
|
|
115
|
-
const callResult = await this.client.callTool({
|
|
116
|
-
name: toolName,
|
|
117
|
-
arguments: args,
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
const contents: any[] = callResult.content ?? [];
|
|
121
|
-
const textParts = contents
|
|
122
|
-
.filter((c: any) => c.type === "text")
|
|
123
|
-
.map((c: any) => c.text);
|
|
124
|
-
|
|
125
|
-
const text = textParts.join("\n") || JSON.stringify(callResult);
|
|
126
|
-
|
|
127
|
-
const artifacts = contents
|
|
128
|
-
.filter((c: any) => c.type !== "text")
|
|
129
|
-
.map((c: any) => ({
|
|
130
|
-
type: c.type,
|
|
131
|
-
data: c.data ?? c.blob ?? c.text,
|
|
132
|
-
mimeType: c.mimeType,
|
|
133
|
-
}));
|
|
134
|
-
|
|
135
|
-
if (artifacts.length > 0) {
|
|
136
|
-
return { content: text, artifacts };
|
|
137
|
-
}
|
|
138
|
-
return text;
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
return {
|
|
142
|
-
name: `${this.name}__${toolName}`,
|
|
143
|
-
description: `[${this.name}] ${description}`,
|
|
144
|
-
parameters,
|
|
145
|
-
execute,
|
|
146
|
-
rawJsonSchema: inputSchema,
|
|
147
|
-
} satisfies ToolDef;
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
private jsonSchemaToZod(schema: any, z: any): any {
|
|
152
|
-
if (!schema || !schema.properties) {
|
|
153
|
-
return z.object({}).passthrough();
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const shape: Record<string, any> = {};
|
|
157
|
-
const required: string[] = schema.required ?? [];
|
|
158
|
-
|
|
159
|
-
for (const [key, prop] of Object.entries(schema.properties) as [string, any][]) {
|
|
160
|
-
let field: any;
|
|
161
|
-
|
|
162
|
-
switch (prop.type) {
|
|
163
|
-
case "string":
|
|
164
|
-
field = z.string();
|
|
165
|
-
if (prop.enum) field = z.enum(prop.enum);
|
|
166
|
-
break;
|
|
167
|
-
case "number":
|
|
168
|
-
case "integer":
|
|
169
|
-
field = z.number();
|
|
170
|
-
break;
|
|
171
|
-
case "boolean":
|
|
172
|
-
field = z.boolean();
|
|
173
|
-
break;
|
|
174
|
-
case "array":
|
|
175
|
-
field = z.array(z.any());
|
|
176
|
-
break;
|
|
177
|
-
case "object":
|
|
178
|
-
field = z.record(z.any());
|
|
179
|
-
break;
|
|
180
|
-
default:
|
|
181
|
-
field = z.any();
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
if (prop.description) {
|
|
185
|
-
field = field.describe(prop.description);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (!required.includes(key)) {
|
|
189
|
-
field = field.optional();
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
shape[key] = field;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return z.object(shape);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Returns tools from this MCP server as RadarOS ToolDef[].
|
|
200
|
-
* Optionally filter by tool names to reduce token usage.
|
|
201
|
-
*
|
|
202
|
-
* @param filter - Tool names to include (without the server name prefix).
|
|
203
|
-
* If omitted, returns all tools.
|
|
204
|
-
*
|
|
205
|
-
* @example
|
|
206
|
-
* // All tools
|
|
207
|
-
* await mcp.getTools()
|
|
208
|
-
*
|
|
209
|
-
* // Only specific tools (pass the original MCP tool names, not prefixed)
|
|
210
|
-
* await mcp.getTools({ include: ["get_latest_release", "search_repositories"] })
|
|
211
|
-
*
|
|
212
|
-
* // Exclude specific tools
|
|
213
|
-
* await mcp.getTools({ exclude: ["push_files", "create_repository"] })
|
|
214
|
-
*/
|
|
215
|
-
async getTools(filter?: {
|
|
216
|
-
include?: string[];
|
|
217
|
-
exclude?: string[];
|
|
218
|
-
}): Promise<ToolDef[]> {
|
|
219
|
-
if (!this.connected) {
|
|
220
|
-
await this.connect();
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
if (!filter) {
|
|
224
|
-
return [...this.tools];
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const prefix = `${this.name}__`;
|
|
228
|
-
|
|
229
|
-
return this.tools.filter((tool) => {
|
|
230
|
-
const shortName = tool.name.startsWith(prefix)
|
|
231
|
-
? tool.name.slice(prefix.length)
|
|
232
|
-
: tool.name;
|
|
233
|
-
|
|
234
|
-
if (filter.include) {
|
|
235
|
-
return filter.include.includes(shortName);
|
|
236
|
-
}
|
|
237
|
-
if (filter.exclude) {
|
|
238
|
-
return !filter.exclude.includes(shortName);
|
|
239
|
-
}
|
|
240
|
-
return true;
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/** Refresh the tool list from the MCP server. */
|
|
245
|
-
async refresh(): Promise<void> {
|
|
246
|
-
if (!this.connected) {
|
|
247
|
-
throw new Error("MCPToolProvider: not connected. Call connect() first.");
|
|
248
|
-
}
|
|
249
|
-
await this.discoverTools();
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/** Disconnect from the MCP server. */
|
|
253
|
-
async close(): Promise<void> {
|
|
254
|
-
if (this.client && this.connected) {
|
|
255
|
-
try {
|
|
256
|
-
await this.client.close();
|
|
257
|
-
} catch {
|
|
258
|
-
// ignore close errors
|
|
259
|
-
}
|
|
260
|
-
this.connected = false;
|
|
261
|
-
this.tools = [];
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
package/src/memory/memory.ts
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { InMemoryStorage } from "../storage/in-memory.js";
|
|
2
|
-
import type { StorageDriver } from "../storage/driver.js";
|
|
3
|
-
import { getTextContent, type ChatMessage } from "../models/types.js";
|
|
4
|
-
import type { MemoryConfig, MemoryEntry } from "./types.js";
|
|
5
|
-
|
|
6
|
-
const SHORT_TERM_NS = "memory:short";
|
|
7
|
-
const LONG_TERM_NS = "memory:long";
|
|
8
|
-
|
|
9
|
-
export class Memory {
|
|
10
|
-
private storage: StorageDriver;
|
|
11
|
-
private maxShortTermMessages: number;
|
|
12
|
-
private enableLongTerm: boolean;
|
|
13
|
-
|
|
14
|
-
constructor(config?: MemoryConfig) {
|
|
15
|
-
this.storage = config?.storage ?? new InMemoryStorage();
|
|
16
|
-
this.maxShortTermMessages = config?.maxShortTermMessages ?? 50;
|
|
17
|
-
this.enableLongTerm = config?.enableLongTerm ?? false;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async addMessages(
|
|
21
|
-
sessionId: string,
|
|
22
|
-
messages: ChatMessage[]
|
|
23
|
-
): Promise<void> {
|
|
24
|
-
const existing =
|
|
25
|
-
(await this.storage.get<ChatMessage[]>(SHORT_TERM_NS, sessionId)) ?? [];
|
|
26
|
-
const updated = [...existing, ...messages];
|
|
27
|
-
|
|
28
|
-
if (updated.length > this.maxShortTermMessages) {
|
|
29
|
-
const overflow = updated.splice(
|
|
30
|
-
0,
|
|
31
|
-
updated.length - this.maxShortTermMessages
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
if (this.enableLongTerm && overflow.length > 0) {
|
|
35
|
-
await this.summarizeAndStore(sessionId, overflow);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
await this.storage.set(SHORT_TERM_NS, sessionId, updated);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
async getMessages(sessionId: string): Promise<ChatMessage[]> {
|
|
43
|
-
return (
|
|
44
|
-
(await this.storage.get<ChatMessage[]>(SHORT_TERM_NS, sessionId)) ?? []
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async getSummaries(sessionId: string): Promise<string[]> {
|
|
49
|
-
if (!this.enableLongTerm) return [];
|
|
50
|
-
|
|
51
|
-
const entries = await this.storage.list<MemoryEntry>(
|
|
52
|
-
LONG_TERM_NS,
|
|
53
|
-
sessionId
|
|
54
|
-
);
|
|
55
|
-
return entries.map((e) => e.value.summary);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async getContextString(sessionId: string): Promise<string> {
|
|
59
|
-
const summaries = await this.getSummaries(sessionId);
|
|
60
|
-
if (summaries.length === 0) return "";
|
|
61
|
-
return `Previous context:\n${summaries.join("\n")}`;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
private async summarizeAndStore(
|
|
65
|
-
sessionId: string,
|
|
66
|
-
messages: ChatMessage[]
|
|
67
|
-
): Promise<void> {
|
|
68
|
-
const textParts = messages
|
|
69
|
-
.filter((m) => m.content)
|
|
70
|
-
.map((m) => `${m.role}: ${getTextContent(m.content)}`);
|
|
71
|
-
|
|
72
|
-
if (textParts.length === 0) return;
|
|
73
|
-
|
|
74
|
-
const summary = textParts.join(" | ").slice(0, 500);
|
|
75
|
-
const entry: MemoryEntry = {
|
|
76
|
-
key: `${sessionId}:${Date.now()}`,
|
|
77
|
-
summary,
|
|
78
|
-
createdAt: new Date(),
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
await this.storage.set(LONG_TERM_NS, entry.key, entry);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async clear(sessionId: string): Promise<void> {
|
|
85
|
-
await this.storage.delete(SHORT_TERM_NS, sessionId);
|
|
86
|
-
}
|
|
87
|
-
}
|
package/src/memory/types.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { StorageDriver } from "../storage/driver.js";
|
|
2
|
-
|
|
3
|
-
export interface MemoryConfig {
|
|
4
|
-
storage?: StorageDriver;
|
|
5
|
-
maxShortTermMessages?: number;
|
|
6
|
-
enableLongTerm?: boolean;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface MemoryEntry {
|
|
10
|
-
key: string;
|
|
11
|
-
summary: string;
|
|
12
|
-
createdAt: Date;
|
|
13
|
-
}
|