Skip to content

Commit d936c51

Browse files
committed
Add Smol agent implem
1 parent 21649b2 commit d936c51

File tree

4 files changed

+54
-51
lines changed

4 files changed

+54
-51
lines changed

packages/mcp-client/cli.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,9 @@ import { homedir } from "node:os";
55
import { Agent } from "./src";
66
import type { StdioServerParameters } from "@modelcontextprotocol/sdk/client/stdio.js";
77

8-
async function* boboGenerator(message: string) {
9-
for (let i = 0; i < 6; i++) {
10-
yield "bobo ";
11-
await new Promise((resolve) => setTimeout(resolve, 400));
12-
}
13-
}
14-
158
const ANSI = {
169
BLUE: "\x1b[34m",
10+
GREEN: "\x1b[32m",
1711
RED: "\x1b[31m",
1812
RESET: "\x1b[0m",
1913
};
@@ -64,8 +58,18 @@ async function main() {
6458

6559
while (true) {
6660
const input = await rl.question("> ");
67-
for await (const bobo of boboGenerator(input)) {
68-
console.log(bobo);
61+
for await (const response of agent.processSingleTurn(input)) {
62+
if ("choices" in response) {
63+
stdout.write(response.choices[0].message.content ?? "");
64+
stdout.write("\n\n");
65+
} else {
66+
/// Tool call info
67+
stdout.write(ANSI.GREEN);
68+
stdout.write(`Tool[${response.name}] ${response.tool_call_id}\n`);
69+
stdout.write(response.content);
70+
stdout.write(ANSI.RESET);
71+
stdout.write("\n\n");
72+
}
6973
}
7074
}
7175
}

packages/mcp-client/src/Agent.ts

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { InferenceProvider } from "@huggingface/inference";
2+
import type { ChatCompletionInputMessageTool } from "./McpClient";
23
import { McpClient } from "./McpClient";
3-
import type { ChatCompletionInputMessage } from "@huggingface/tasks";
4+
import type { ChatCompletionInputMessage, ChatCompletionOutput } from "@huggingface/tasks";
45
import type { StdioServerParameters } from "@modelcontextprotocol/sdk/client/stdio";
56

67
const DEFAULT_SYSTEM_PROMPT = `
@@ -40,18 +41,14 @@ export class Agent extends McpClient {
4041
return this.addMcpServers(this.servers);
4142
}
4243

43-
async processUserMessage(query: string) {
44+
async *processSingleTurn(input: string): AsyncGenerator<ChatCompletionOutput | ChatCompletionInputMessageTool> {
4445
this.messages.push({
4546
role: "user",
46-
content: query,
47+
content: input,
4748
});
4849

49-
const stream = await this.client.chatCompletionStream({
50-
provider: this.provider,
51-
model: this.model,
52-
messages,
53-
tools: this.availableTools,
54-
tool_choice: "auto",
55-
});
50+
while (this.messages.at(-1)?.role !== "assistant") {
51+
yield* this.processSingleTurnWithTools(this.messages);
52+
}
5653
}
5754
}

packages/mcp-client/src/McpClient.ts

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,17 @@ import { debug } from "./utils";
1313

1414
type ToolName = string;
1515

16+
export interface ChatCompletionInputMessageTool extends ChatCompletionInputMessage {
17+
role: "tool";
18+
tool_call_id: string;
19+
content: string;
20+
name?: string;
21+
}
22+
1623
export class McpClient {
17-
private client: InferenceClient;
18-
private provider: string;
19-
private model: string;
24+
protected client: InferenceClient;
25+
protected provider: string;
26+
protected model: string;
2027
private clients: Map<ToolName, Client> = new Map();
2128
public readonly availableTools: ChatCompletionInputTool[] = [];
2229

@@ -62,13 +69,10 @@ export class McpClient {
6269
);
6370
}
6471

65-
async processQuery(query: string): Promise<ChatCompletionOutput> {
66-
const messages: ChatCompletionInputMessage[] = [
67-
{
68-
role: "user",
69-
content: query,
70-
},
71-
];
72+
async *processSingleTurnWithTools(
73+
messages: ChatCompletionInputMessage[]
74+
): AsyncGenerator<ChatCompletionOutput | ChatCompletionInputMessageTool> {
75+
debug("start of single turn");
7276

7377
const response = await this.client.chatCompletion({
7478
provider: this.provider,
@@ -80,43 +84,41 @@ export class McpClient {
8084

8185
const toolCalls = response.choices[0].message.tool_calls;
8286
if (!toolCalls || toolCalls.length === 0) {
83-
return response;
87+
messages.push({
88+
role: response.choices[0].message.role,
89+
content: response.choices[0].message.content,
90+
});
91+
return yield response;
8492
}
8593
for (const toolCall of toolCalls) {
8694
const toolName = toolCall.function.name;
8795
const toolArgs = JSON.parse(toolCall.function.arguments);
8896

97+
const message: ChatCompletionInputMessageTool = {
98+
role: "tool",
99+
tool_call_id: toolCall.id,
100+
content: "",
101+
name: toolName,
102+
};
89103
/// Get the appropriate session for this tool
90104
const client = this.clients.get(toolName);
91105
if (client) {
92106
const result = await client.callTool({ name: toolName, arguments: toolArgs });
93-
messages.push({
94-
tool_call_id: toolCall.id,
95-
role: "tool",
96-
name: toolName,
97-
content: (result.content as Array<{ text: string }>)[0].text,
98-
});
107+
message.content = (result.content as Array<{ text: string }>)[0].text;
99108
} else {
100-
messages.push({
101-
tool_call_id: toolCall.id,
102-
role: "tool",
103-
name: toolName,
104-
content: `Error: No session found for tool: ${toolName}`,
105-
});
109+
message.content = `Error: No session found for tool: ${toolName}`;
106110
}
111+
messages.push(message);
112+
yield message;
107113
}
108-
109-
const enrichedResponse = await this.client.chatCompletion({
110-
provider: this.provider,
111-
model: this.model,
112-
messages,
113-
});
114-
115-
return enrichedResponse;
116114
}
117115

118116
async cleanup(): Promise<void> {
119117
const clients = new Set(this.clients.values());
120118
await Promise.all([...clients].map((client) => client.close()));
121119
}
120+
121+
async [Symbol.dispose](): Promise<void> {
122+
return this.cleanup();
123+
}
122124
}

packages/mcp-client/src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export function debug(...args: unknown[]): void {
22
if (process.env.DEBUG) {
3-
console.log(args);
3+
console.debug(args);
44
}
55
}

0 commit comments

Comments
 (0)