mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-05-28 19:05:31 +02:00
feat: enhance streaming response handling with new renderer. Process fullStream instead of textStream only
This commit is contained in:
parent
62caa0c8b6
commit
d30d551d16
1 changed files with 91 additions and 47 deletions
|
|
@ -10,8 +10,9 @@ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"
|
||||||
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
||||||
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
||||||
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
||||||
|
import { StreamRenderer } from "../lib/stream-renderer.js";
|
||||||
|
|
||||||
const model = openai("gpt-4.1");
|
const model = openai("gpt-5");
|
||||||
const rl = readline.createInterface({ input, output });
|
const rl = readline.createInterface({ input, output });
|
||||||
|
|
||||||
// Base directory for file operations - dynamically use user's home directory
|
// Base directory for file operations - dynamically use user's home directory
|
||||||
|
|
@ -54,21 +55,11 @@ export async function startCopilot() {
|
||||||
messages.push({ role: "user", content: userInput });
|
messages.push({ role: "user", content: userInput });
|
||||||
|
|
||||||
// Stream AI response
|
// Stream AI response
|
||||||
process.stdout.write("\nCopilot: ");
|
|
||||||
|
|
||||||
let currentStep = 0;
|
|
||||||
const result = streamText({
|
const result = streamText({
|
||||||
model: model,
|
model: model,
|
||||||
messages: messages,
|
messages: messages,
|
||||||
system: `You are an intelligent workflow assistant helping users manage their workflows in ${BASE_DIR}.
|
system: `You are an intelligent workflow assistant helping users manage their workflows in ${BASE_DIR}.
|
||||||
|
|
||||||
REASONING & THINKING:
|
|
||||||
- Before taking action, think through what the user is asking for and put out a text with your reasoning process and the steps you will take to complete the task.
|
|
||||||
- Break down complex tasks into clear steps
|
|
||||||
- Explore existing files/structure before creating new ones
|
|
||||||
- Explain your reasoning as you work through tasks
|
|
||||||
- Be proactive in understanding context
|
|
||||||
|
|
||||||
WORKFLOW KNOWLEDGE:
|
WORKFLOW KNOWLEDGE:
|
||||||
- Workflows are JSON files that orchestrate multiple agents
|
- Workflows are JSON files that orchestrate multiple agents
|
||||||
- Agents are JSON files defining AI assistants with specific tools and instructions
|
- Agents are JSON files defining AI assistants with specific tools and instructions
|
||||||
|
|
@ -217,11 +208,11 @@ DELETION RULES:
|
||||||
5. Only delete/modify what the user confirms
|
5. Only delete/modify what the user confirms
|
||||||
|
|
||||||
COMMUNICATION STYLE:
|
COMMUNICATION STYLE:
|
||||||
- Start by thinking through the request
|
- Break down complex tasks into clear steps
|
||||||
- Explain what you're exploring and why
|
- Explore existing files/structure before creating new ones
|
||||||
- Show your reasoning process
|
- Explain your reasoning as you work through tasks
|
||||||
|
- Be proactive in understanding context
|
||||||
- Confirm what you've done and suggest next steps
|
- Confirm what you've done and suggest next steps
|
||||||
- Be conversational but informative
|
|
||||||
- Always ask for confirmation before destructive operations!!
|
- Always ask for confirmation before destructive operations!!
|
||||||
|
|
||||||
Always use relative paths (no ${BASE_DIR} prefix) when calling tools.`,
|
Always use relative paths (no ${BASE_DIR} prefix) when calling tools.`,
|
||||||
|
|
@ -599,42 +590,95 @@ Always use relative paths (no ${BASE_DIR} prefix) when calling tools.`,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
stopWhen: stepCountIs(20),
|
||||||
stopWhen: stepCountIs(15),
|
|
||||||
|
|
||||||
onStepFinish: async ({ toolResults }) => {
|
|
||||||
currentStep++;
|
|
||||||
|
|
||||||
// Show results with clear formatting
|
|
||||||
if (toolResults && toolResults.length > 0) {
|
|
||||||
console.log(`\n[Step ${currentStep}]`);
|
|
||||||
for (const result of toolResults) {
|
|
||||||
const res = result as any;
|
|
||||||
console.log(`🔧 Tool: ${res.toolName}`);
|
|
||||||
|
|
||||||
if (res.result && typeof res.result === 'object') {
|
|
||||||
const resultData = res.result as any;
|
|
||||||
if (resultData.success) {
|
|
||||||
console.log(`✅ ${resultData.message || 'Success'}`);
|
|
||||||
if (resultData.description) console.log(` → ${resultData.description}`);
|
|
||||||
if (resultData.reason) console.log(` → ${resultData.reason}`);
|
|
||||||
} else {
|
|
||||||
console.log(`❌ ${resultData.message || 'Failed'}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Stream and collect response
|
// Initialize renderer with workflow-style output
|
||||||
|
const renderer = new StreamRenderer({
|
||||||
|
showHeaders: false,
|
||||||
|
dimReasoning: true,
|
||||||
|
jsonIndent: 2,
|
||||||
|
truncateJsonAt: 500,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Stream and collect response using fullStream
|
||||||
let assistantResponse = "";
|
let assistantResponse = "";
|
||||||
for await (const textPart of result.textStream) {
|
const { fullStream } = result;
|
||||||
process.stdout.write(textPart);
|
|
||||||
assistantResponse += textPart;
|
for await (const event of fullStream) {
|
||||||
|
switch (event.type) {
|
||||||
|
case "reasoning-start":
|
||||||
|
renderer.render({
|
||||||
|
type: "stream-event",
|
||||||
|
stepId: "copilot",
|
||||||
|
event: { type: "reasoning-start" }
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "reasoning-delta":
|
||||||
|
renderer.render({
|
||||||
|
type: "stream-event",
|
||||||
|
stepId: "copilot",
|
||||||
|
event: { type: "reasoning-delta", delta: event.text }
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "reasoning-end":
|
||||||
|
renderer.render({
|
||||||
|
type: "stream-event",
|
||||||
|
stepId: "copilot",
|
||||||
|
event: { type: "reasoning-end" }
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "text-start":
|
||||||
|
renderer.render({
|
||||||
|
type: "stream-event",
|
||||||
|
stepId: "copilot",
|
||||||
|
event: { type: "text-start" }
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "text-delta":
|
||||||
|
renderer.render({
|
||||||
|
type: "stream-event",
|
||||||
|
stepId: "copilot",
|
||||||
|
event: { type: "text-delta", delta: event.text }
|
||||||
|
});
|
||||||
|
assistantResponse += event.text;
|
||||||
|
break;
|
||||||
|
case "text-end":
|
||||||
|
renderer.render({
|
||||||
|
type: "stream-event",
|
||||||
|
stepId: "copilot",
|
||||||
|
event: { type: "text-end" }
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "tool-call":
|
||||||
|
renderer.render({
|
||||||
|
type: "stream-event",
|
||||||
|
stepId: "copilot",
|
||||||
|
event: {
|
||||||
|
type: "tool-call",
|
||||||
|
toolCallId: event.toolCallId,
|
||||||
|
toolName: event.toolName,
|
||||||
|
input: 'args' in event ? event.args : event.input
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "tool-result":
|
||||||
|
// Tool results are not directly rendered in copilot mode
|
||||||
|
break;
|
||||||
|
case "finish":
|
||||||
|
renderer.render({
|
||||||
|
type: "stream-event",
|
||||||
|
stepId: "copilot",
|
||||||
|
event: {
|
||||||
|
type: "usage",
|
||||||
|
usage: event.totalUsage
|
||||||
|
}
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
console.log("\n");
|
|
||||||
|
console.log();
|
||||||
|
|
||||||
// Add assistant response to history
|
// Add assistant response to history
|
||||||
messages.push({ role: "assistant", content: assistantResponse });
|
messages.push({ role: "assistant", content: assistantResponse });
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue