Compare commits
No commits in common. 'master' and 'install-unocss' have entirely different histories.
master
...
install-un
@ -1,2 +0,0 @@
|
|||||||
.env*
|
|
||||||
.dev.vars*
|
|
@ -1,29 +0,0 @@
|
|||||||
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
|
|
||||||
import { personalAssistantAgent } from "./agents/personalAssistant.js";
|
|
||||||
import { chefAgent } from "./agents/chef.js";
|
|
||||||
import { Agent } from "./types.js";
|
|
||||||
|
|
||||||
// This declaration is primarily for providing type hints in your code
|
|
||||||
interface Env {
|
|
||||||
OPENROUTER_API_KEY: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
const env: Env;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create OpenRouter instance
|
|
||||||
export const openrouter = createOpenRouter({
|
|
||||||
apiKey: import.meta.env.VITE_OPENROUTER_API_KEY || env.OPENROUTER_API_KEY,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Define the agents by ID
|
|
||||||
export const agentsById: Record<string, Agent> = {
|
|
||||||
"personal-assistant": personalAssistantAgent,
|
|
||||||
chef: chefAgent,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper function to get an agent by ID
|
|
||||||
export function getAgentById(agentId: string): Agent | undefined {
|
|
||||||
return agentsById[agentId];
|
|
||||||
}
|
|
@ -1,107 +0,0 @@
|
|||||||
import {
|
|
||||||
streamText,
|
|
||||||
generateText,
|
|
||||||
generateObject,
|
|
||||||
type Message,
|
|
||||||
jsonSchema,
|
|
||||||
} from "ai";
|
|
||||||
import { getAgentById, openrouter } from "./agentRegistry.js";
|
|
||||||
|
|
||||||
// Define the tools with explicit type
|
|
||||||
export interface DelegateParams {
|
|
||||||
agentId?: string;
|
|
||||||
prompt?: string;
|
|
||||||
[key: string]: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EchoParams {
|
|
||||||
message: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ToolFunctions {
|
|
||||||
[key: string]: (params: any) => Promise<string>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tools: ToolFunctions = {
|
|
||||||
delegate: async function ({
|
|
||||||
agentId,
|
|
||||||
prompt,
|
|
||||||
}: DelegateParams): Promise<string> {
|
|
||||||
// Validate required parameters
|
|
||||||
if (!agentId || !prompt) {
|
|
||||||
return "Error: Missing required parameters. Both 'agentId' and 'prompt' are required.";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the target agent
|
|
||||||
const agent = getAgentById(agentId);
|
|
||||||
if (!agent) {
|
|
||||||
return `Error: No such agent: ${agentId}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const conversation: { messages: Array<Omit<Message, "id">> } = {
|
|
||||||
messages: [
|
|
||||||
{ role: "system", content: agent.systemMessage },
|
|
||||||
{ role: "user", content: prompt },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
let isConversationDone = false;
|
|
||||||
while (!isConversationDone) {
|
|
||||||
// Generate a response from the agent using the prompt
|
|
||||||
const result = await generateText({
|
|
||||||
model: openrouter(agent.modelName),
|
|
||||||
messages: conversation.messages,
|
|
||||||
tools: agent.tools,
|
|
||||||
});
|
|
||||||
conversation.messages.push({ role: "assistant", content: result.text });
|
|
||||||
const sentimentIsConversationDone = await generateObject<{
|
|
||||||
isConversationDone: boolean;
|
|
||||||
}>({
|
|
||||||
model: openrouter("mistralai/mistral-nemo"),
|
|
||||||
messages: [
|
|
||||||
{
|
|
||||||
role: "system",
|
|
||||||
content:
|
|
||||||
"You are a tool to determine whether a conversation is done or should continue with another reply.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
role: "user",
|
|
||||||
content: conversation.messages
|
|
||||||
.map((message) => `${message.role}: ${message.content}`)
|
|
||||||
.join("\n"),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
schema: jsonSchema({
|
|
||||||
type: "object",
|
|
||||||
properties: {
|
|
||||||
isConversationDone: {
|
|
||||||
type: "boolean",
|
|
||||||
description:
|
|
||||||
"Whether the conversation is done or should continue and requires a reply.",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
isConversationDone =
|
|
||||||
sentimentIsConversationDone.object.isConversationDone;
|
|
||||||
}
|
|
||||||
|
|
||||||
// const summaryText = await generateSummary();
|
|
||||||
// // Return the agent's response
|
|
||||||
// return summaryText;
|
|
||||||
return conversation.messages
|
|
||||||
.map((message) => `${message.role}: ${message.content}`)
|
|
||||||
.join("\n");
|
|
||||||
} catch (error: unknown) {
|
|
||||||
const errorMessage =
|
|
||||||
error instanceof Error ? error.message : "Unknown error";
|
|
||||||
console.error("Error delegating to agent:", error);
|
|
||||||
return `Error delegating to agent ${agentId}: ${errorMessage}`;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
echo: async function ({ message }: EchoParams): Promise<string> {
|
|
||||||
return message;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default tools;
|
|
@ -1,66 +1,77 @@
|
|||||||
import { streamText, Message, createDataStream } from "ai";
|
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
|
||||||
|
import { streamText } from "ai";
|
||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
import { stream } from "hono/streaming";
|
import { stream } from "hono/streaming";
|
||||||
import { processPendingToolCalls } from "./util.js";
|
import { personalAssistantAgent } from "./agents/assistant.js";
|
||||||
import { agentsById, openrouter } from "./agentRegistry.js";
|
import { chefAgent } from "./agents/chef.js";
|
||||||
|
import { Agent } from "./types.js";
|
||||||
|
|
||||||
|
// This declaration is primarily for providing type hints in your code
|
||||||
|
// and it doesn't directly define the *values* of the environment variables.
|
||||||
|
|
||||||
|
interface Env {
|
||||||
|
OPENROUTER_API_KEY: string;
|
||||||
|
// Add other environment variables here
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
const env: Env;
|
||||||
|
}
|
||||||
|
|
||||||
const app = new Hono();
|
const app = new Hono();
|
||||||
|
|
||||||
app.post("/api/chat/:agent_id", async (c) => {
|
const openrouter = createOpenRouter({
|
||||||
const input: { messages: Message[] } = await c.req.json();
|
apiKey: import.meta.env.VITE_OPENROUTER_API_KEY || env.OPENROUTER_API_KEY,
|
||||||
const agentId = c.req.param("agent_id");
|
});
|
||||||
const agent = agentsById[agentId];
|
const systemMessage = {
|
||||||
if (!agent) {
|
role: "system",
|
||||||
c.status(404);
|
content:
|
||||||
return c.json({ error: `No such agent: ${agentId}` });
|
"You are a wise old man named Dorf that answers questions succintly.",
|
||||||
}
|
};
|
||||||
|
|
||||||
|
app.post("/api/chat", async (c) => {
|
||||||
|
const input = await c.req.json();
|
||||||
|
console.log(input);
|
||||||
|
const result = streamText({
|
||||||
|
model: openrouter("mistral/ministral-8b"),
|
||||||
|
messages: [systemMessage, ...input.messages],
|
||||||
|
tools: {},
|
||||||
|
});
|
||||||
|
|
||||||
const dataStream = createDataStream({
|
// Mark the response as a v1 data stream:
|
||||||
execute: async (dataStreamWriter) => {
|
c.header("X-Vercel-AI-Data-Stream", "v1");
|
||||||
// dataStreamWriter.writeData('initialized call');
|
c.header("Content-Type", "text/plain; charset=utf-8");
|
||||||
|
|
||||||
// Process any pending tool calls in the messages
|
return stream(c, (stream) => stream.pipe(result.toDataStream()));
|
||||||
// This modifies the messages array in place
|
});
|
||||||
await processPendingToolCalls(input.messages, dataStreamWriter);
|
|
||||||
|
|
||||||
const result = streamText({
|
const agentsByName: Record<string, Agent> = {
|
||||||
model: openrouter(agent.modelName),
|
assistant: personalAssistantAgent,
|
||||||
maxSteps: 5,
|
chef: chefAgent,
|
||||||
messages: [
|
};
|
||||||
{ role: "system", content: agent.systemMessage },
|
|
||||||
...Object.values(agentsById).map((agent) => ({
|
|
||||||
role: "system" as const,
|
|
||||||
content: `Agent ${JSON.stringify({
|
|
||||||
id: agent.id,
|
|
||||||
name: agent.name,
|
|
||||||
description: agent.description,
|
|
||||||
skills: agent.skills,
|
|
||||||
})}`,
|
|
||||||
})),
|
|
||||||
...input.messages,
|
|
||||||
],
|
|
||||||
tools: agent.tools,
|
|
||||||
onError: (error) => {
|
|
||||||
console.error("Error in streamText:", error);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
result.mergeIntoDataStream(dataStreamWriter);
|
app.post("/api/chat/:agent_name", async (c) => {
|
||||||
},
|
const input = await c.req.json();
|
||||||
onError: (error) => {
|
const agentName = c.req.param("agent_name");
|
||||||
// Error messages are masked by default for security reasons.
|
const agent = agentsByName[agentName];
|
||||||
// If you want to expose the error message to the client, you can do so here:
|
if (!agent) {
|
||||||
return error instanceof Error ? error.message : String(error);
|
return c.json({ error: `No such agent: ${agentName}` });
|
||||||
},
|
}
|
||||||
|
console.log(input);
|
||||||
|
const result = streamText({
|
||||||
|
model: openrouter(agent.modelName),
|
||||||
|
messages: [
|
||||||
|
{ role: "system", content: agent.systemMessage },
|
||||||
|
...input.messages,
|
||||||
|
],
|
||||||
|
tools: agent.tools,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Mark the response as a v1 data stream:
|
// Mark the response as a v1 data stream:
|
||||||
c.header("X-Vercel-AI-Data-Stream", "v1");
|
c.header("X-Vercel-AI-Data-Stream", "v1");
|
||||||
c.header("Content-Type", "text/plain; charset=utf-8");
|
c.header("Content-Type", "text/plain; charset=utf-8");
|
||||||
|
|
||||||
return stream(c, (stream) =>
|
return stream(c, (stream) => stream.pipe(result.toDataStream()));
|
||||||
stream.pipe(dataStream.pipeThrough(new TextEncoderStream()))
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default app;
|
export default app;
|
||||||
|
Loading…
Reference in New Issue