feat: added toolChoice support and optimized TUI

- Added ToolChoice type and toolChoice parameter support across all AI providers (OpenAI, Azure OpenAI, Anthropic, Google) enabling fine-grained control over tool/function selection during LLM calls.
- Added toolChoice override capability to Agent.prompt() method and session prompt options allowing callers to control tool selection behavior per request.
- Added provider-specific tool choice mapping functions (mapAnthropicToolChoice, mapGoogleToolChoice, mapOpenAiToolChoice) to normalize tool choice formats across different LLM APIs.
- Removed kernel heartbeat/ping mechanism from PythonKernel, simplifying health monitoring by relying on direct isAlive() checks instead of periodic HTTP requests.
This commit is contained in:
can1357
2026-01-28 02:39:28 +01:00
parent 6b96418f87
commit cc91f80e99
21 changed files with 392 additions and 167 deletions
@@ -302,51 +302,6 @@ describe("PythonKernel (external gateway)", () => {
});
});
it("marks kernel dead after repeated ping failures", async () => {
const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {
if (url.endsWith("/api/kernels") && init?.method === "POST") {
return new Response(JSON.stringify({ id: "kernel-2" }), { status: 201 });
}
if (url.includes("/api/kernels/kernel-2") && !init?.method) {
throw new Error("ping failed");
}
return new Response("", { status: 200 });
});
globalThis.fetch = fetchMock as unknown as typeof fetch;
let initSeen = false;
let preludeSeen = false;
const kernelPromise = PythonKernel.start({ cwd: "/" });
await Bun.sleep(10);
const ws = FakeWebSocket.lastInstance;
if (!ws) throw new Error("WebSocket not initialized");
ws.setSendHandler(data => {
const msg = typeof data === "string" ? (JSON.parse(data) as JupyterMessage) : decodeMessage(data);
const code = String(msg.content.code ?? "");
if (!initSeen) {
initSeen = true;
sendOkExecution(ws, msg.header.msg_id);
return;
}
if (!preludeSeen) {
expect(code).toBe(PYTHON_PRELUDE);
preludeSeen = true;
}
sendOkExecution(ws, msg.header.msg_id);
});
const kernel = await kernelPromise;
const firstPing = await kernel.ping(1);
const secondPing = await kernel.ping(1);
expect(firstPing).toBe(false);
expect(secondPing).toBe(false);
expect(kernel.isAlive()).toBe(false);
await kernel.shutdown();
});
it("initializes the IPython prelude", async () => {
const fetchMock = vi.fn(async (url: string, init?: RequestInit) => {
if (url.endsWith("/api/kernels") && init?.method === "POST") {