Prompt is too long
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { streamText, tool } from 'ai';
|
||||
import { createOpenAI } from '@ai-sdk/openai';
|
||||
import { z } from 'zod';
|
||||
import { stepCountIs, streamText, tool } from "ai";
|
||||
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
listTerminals,
|
||||
createTerminal,
|
||||
@@ -8,16 +8,8 @@ import {
|
||||
sendText,
|
||||
renameTerminal,
|
||||
killTerminal,
|
||||
} from '../daemon/terminal-manager.js';
|
||||
|
||||
let openaiClient: ReturnType<typeof createOpenAI> | null = null;
|
||||
|
||||
/**
|
||||
* Initialize OpenAI client with API key
|
||||
*/
|
||||
export function initializeOpenAI(apiKey: string): void {
|
||||
openaiClient = createOpenAI({ apiKey });
|
||||
}
|
||||
} from "../daemon/terminal-manager.js";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/**
|
||||
* Terminal tools using Vercel AI SDK tool() function
|
||||
@@ -25,8 +17,8 @@ export function initializeOpenAI(apiKey: string): void {
|
||||
*/
|
||||
export const terminalTools = {
|
||||
list_terminals: tool({
|
||||
description: 'List all available terminals in the voice-dev session',
|
||||
parameters: z.object({}),
|
||||
description: "List all available terminals in the voice-dev session",
|
||||
inputSchema: z.object({}),
|
||||
execute: async () => {
|
||||
const terminals = await listTerminals();
|
||||
return { terminals };
|
||||
@@ -34,24 +26,38 @@ export const terminalTools = {
|
||||
}),
|
||||
|
||||
create_terminal: tool({
|
||||
description: 'Create a new terminal with specified name and working directory',
|
||||
parameters: z.object({
|
||||
name: z.string().describe('Unique name for the terminal'),
|
||||
workingDirectory: z.string().describe('Working directory path'),
|
||||
initialCommand: z.string().optional().describe('Optional command to run on creation'),
|
||||
description:
|
||||
"Create a new terminal with specified name and working directory",
|
||||
inputSchema: z.object({
|
||||
name: z.string().describe("Unique name for the terminal"),
|
||||
workingDirectory: z.string().describe("Working directory path"),
|
||||
initialCommand: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Optional command to run on creation"),
|
||||
}),
|
||||
execute: async ({ name, workingDirectory, initialCommand }) => {
|
||||
const terminal = await createTerminal({ name, workingDirectory, initialCommand });
|
||||
const terminal = await createTerminal({
|
||||
name,
|
||||
workingDirectory,
|
||||
initialCommand,
|
||||
});
|
||||
return { terminal };
|
||||
},
|
||||
}),
|
||||
|
||||
capture_terminal: tool({
|
||||
description: 'Capture and return the output from a terminal',
|
||||
parameters: z.object({
|
||||
terminalId: z.string().describe('Terminal ID (e.g., @123)'),
|
||||
lines: z.number().optional().describe('Number of lines to capture (default: 200)'),
|
||||
wait: z.number().optional().describe('Milliseconds to wait before capture'),
|
||||
description: "Capture and return the output from a terminal",
|
||||
inputSchema: z.object({
|
||||
terminalId: z.string().describe("Terminal ID (e.g., @123)"),
|
||||
lines: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Number of lines to capture (default: 200)"),
|
||||
wait: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Milliseconds to wait before capture"),
|
||||
}),
|
||||
execute: async ({ terminalId, lines, wait }) => {
|
||||
const output = await captureTerminal(terminalId, lines, wait);
|
||||
@@ -60,30 +66,38 @@ export const terminalTools = {
|
||||
}),
|
||||
|
||||
send_text: tool({
|
||||
description: 'Send text or commands to a terminal',
|
||||
parameters: z.object({
|
||||
terminalId: z.string().describe('Terminal ID (e.g., @123)'),
|
||||
text: z.string().describe('Text to send to the terminal'),
|
||||
pressEnter: z.boolean().optional().describe('Whether to press Enter after text'),
|
||||
description: "Send text or commands to a terminal",
|
||||
inputSchema: z.object({
|
||||
terminalId: z.string().describe("Terminal ID (e.g., @123)"),
|
||||
text: z.string().describe("Text to send to the terminal"),
|
||||
pressEnter: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Whether to press Enter after text"),
|
||||
return_output: z
|
||||
.object({
|
||||
lines: z.number().optional(),
|
||||
wait: z.number().optional(),
|
||||
})
|
||||
.optional()
|
||||
.describe('Capture output after sending'),
|
||||
.describe("Capture output after sending"),
|
||||
}),
|
||||
execute: async ({ terminalId, text, pressEnter, return_output }) => {
|
||||
const output = await sendText(terminalId, text, pressEnter, return_output);
|
||||
const output = await sendText(
|
||||
terminalId,
|
||||
text,
|
||||
pressEnter,
|
||||
return_output
|
||||
);
|
||||
return { output };
|
||||
},
|
||||
}),
|
||||
|
||||
rename_terminal: tool({
|
||||
description: 'Rename an existing terminal',
|
||||
parameters: z.object({
|
||||
terminalId: z.string().describe('Terminal ID to rename'),
|
||||
newName: z.string().describe('New unique name for the terminal'),
|
||||
description: "Rename an existing terminal",
|
||||
inputSchema: z.object({
|
||||
terminalId: z.string().describe("Terminal ID to rename"),
|
||||
newName: z.string().describe("New unique name for the terminal"),
|
||||
}),
|
||||
execute: async ({ terminalId, newName }) => {
|
||||
await renameTerminal(terminalId, newName);
|
||||
@@ -92,9 +106,9 @@ export const terminalTools = {
|
||||
}),
|
||||
|
||||
kill_terminal: tool({
|
||||
description: 'Close and destroy a terminal',
|
||||
parameters: z.object({
|
||||
terminalId: z.string().describe('Terminal ID to kill'),
|
||||
description: "Close and destroy a terminal",
|
||||
inputSchema: z.object({
|
||||
terminalId: z.string().describe("Terminal ID to kill"),
|
||||
}),
|
||||
execute: async ({ terminalId }) => {
|
||||
await killTerminal(terminalId);
|
||||
@@ -107,7 +121,7 @@ export const terminalTools = {
|
||||
* Message interface for conversation
|
||||
*/
|
||||
export interface Message {
|
||||
role: 'system' | 'user' | 'assistant';
|
||||
role: "system" | "user" | "assistant";
|
||||
content: string;
|
||||
}
|
||||
|
||||
@@ -126,21 +140,23 @@ export interface StreamLLMParams {
|
||||
* Stream LLM response with automatic tool execution
|
||||
*/
|
||||
export async function streamLLM(params: StreamLLMParams): Promise<string> {
|
||||
if (!openaiClient) {
|
||||
throw new Error('OpenAI client not initialized. Call initializeOpenAI() first.');
|
||||
}
|
||||
invariant(process.env.OPENROUTER_API_KEY, "OPENROUTER_API_KEY is required");
|
||||
|
||||
const openrouter = createOpenRouter({
|
||||
apiKey: process.env.OPENROUTER_API_KEY,
|
||||
});
|
||||
|
||||
const result = await streamText({
|
||||
model: openaiClient('gpt-4o') as any, // Type assertion to work around AI SDK version conflicts
|
||||
model: openrouter("anthropic/claude-haiku-4.5"),
|
||||
messages: params.messages,
|
||||
tools: terminalTools,
|
||||
maxSteps: 5, // Allow up to 5 tool executions per turn
|
||||
stopWhen: stepCountIs(10),
|
||||
onStepFinish: async (event) => {
|
||||
// Called after each step (tool call or text generation)
|
||||
if (event.toolCalls && event.toolCalls.length > 0) {
|
||||
for (const toolCall of event.toolCalls) {
|
||||
if (params.onToolCall) {
|
||||
params.onToolCall(toolCall.toolName, toolCall.args);
|
||||
params.onToolCall(toolCall.toolName, toolCall.input);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,14 +164,14 @@ export async function streamLLM(params: StreamLLMParams): Promise<string> {
|
||||
if (event.toolResults && event.toolResults.length > 0) {
|
||||
for (const toolResult of event.toolResults) {
|
||||
if (params.onToolResult) {
|
||||
params.onToolResult(toolResult.toolName, toolResult.result);
|
||||
params.onToolResult(toolResult.toolName, toolResult.output);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
let fullText = '';
|
||||
let fullText = "";
|
||||
|
||||
// Stream text chunks to the caller
|
||||
for await (const chunk of result.textStream) {
|
||||
|
||||
@@ -59,15 +59,8 @@ export async function processUserMessage(params: {
|
||||
});
|
||||
conversation.lastActivity = new Date();
|
||||
|
||||
// Broadcast user message to WebSocket clients
|
||||
if (params.wsServer) {
|
||||
params.wsServer.broadcastActivityLog({
|
||||
id: uuidv4(),
|
||||
timestamp: new Date(),
|
||||
type: 'transcript',
|
||||
content: params.message,
|
||||
});
|
||||
}
|
||||
// Note: User message is already broadcast by the caller (e.g., after STT in index.ts)
|
||||
// No need to broadcast again here to avoid duplication
|
||||
|
||||
let assistantResponse = '';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user