mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-04-25 00:16:29 +02:00
move rb widget apis to /api/widget/v1
This commit is contained in:
parent
7f571092a2
commit
573188afb0
10 changed files with 106 additions and 83 deletions
|
|
@ -15,7 +15,7 @@ import crypto from 'crypto';
|
|||
import { SignJWT } from "jose";
|
||||
import { Claims, getSession } from "@auth0/nextjs-auth0";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { baseWorkflow } from "./lib/utils";
|
||||
import { baseWorkflow, callClientToolWebhook, getAgenticApiResponse } from "./lib/utils";
|
||||
|
||||
const crawler = new FirecrawlApp({ apiKey: process.env.FIRECRAWL_API_KEY || '' });
|
||||
|
||||
|
|
@ -466,25 +466,8 @@ export async function getAssistantResponse(
|
|||
}> {
|
||||
await projectAuthCheck(projectId);
|
||||
|
||||
// call agentic api
|
||||
const response = await fetch(process.env.AGENTIC_API_URL + '/chat', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(request),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
console.error('Failed to call agentic api', response);
|
||||
throw new Error(`Failed to call agentic api: ${response.statusText}`);
|
||||
}
|
||||
const responseJson = await response.json();
|
||||
const result: z.infer<typeof AgenticAPIChatResponse> = responseJson;
|
||||
return {
|
||||
messages: convertFromAgenticAPIChatMessages(result.messages),
|
||||
state: result.state,
|
||||
rawAPIResponse: result,
|
||||
};
|
||||
const response = await getAgenticApiResponse(request);
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function getCopilotResponse(
|
||||
|
|
@ -916,61 +899,6 @@ export async function executeClientTool(
|
|||
): Promise<unknown> {
|
||||
await projectAuthCheck(projectId);
|
||||
|
||||
const project = await projectsCollection.findOne({
|
||||
"_id": projectId,
|
||||
});
|
||||
if (!project) {
|
||||
throw new Error('Project not found');
|
||||
}
|
||||
|
||||
if (!project.webhookUrl) {
|
||||
throw new Error('Webhook URL not found');
|
||||
}
|
||||
|
||||
// prepare request body
|
||||
const content = JSON.stringify({
|
||||
toolCall,
|
||||
} as z.infer<typeof ClientToolCallRequestBody>);
|
||||
const requestId = crypto.randomUUID();
|
||||
const bodyHash = crypto
|
||||
.createHash('sha256')
|
||||
.update(content, 'utf8')
|
||||
.digest('hex');
|
||||
|
||||
// sign request
|
||||
const jwt = await new SignJWT({
|
||||
requestId,
|
||||
projectId,
|
||||
bodyHash,
|
||||
} as z.infer<typeof ClientToolCallJwt>)
|
||||
.setProtectedHeader({
|
||||
alg: 'HS256',
|
||||
typ: 'JWT',
|
||||
})
|
||||
.setIssuer('rowboat')
|
||||
.setAudience(project.webhookUrl)
|
||||
.setSubject(`tool-call-${toolCall.id}`)
|
||||
.setJti(requestId)
|
||||
.setIssuedAt()
|
||||
.setExpirationTime("5 minutes")
|
||||
.sign(new TextEncoder().encode(project.secret));
|
||||
|
||||
// make request
|
||||
const request: z.infer<typeof ClientToolCallRequest> = {
|
||||
requestId,
|
||||
content,
|
||||
};
|
||||
const response = await fetch(project.webhookUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-signature-jwt': jwt,
|
||||
},
|
||||
body: JSON.stringify(request),
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to call webhook: ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
const responseBody = await response.json();
|
||||
return responseBody;
|
||||
const result = await callClientToolWebhook(toolCall, projectId);
|
||||
return result;
|
||||
}
|
||||
|
|
@ -4,8 +4,8 @@ import { agentWorkflowsCollection, db, projectsCollection } from "@/app/lib/mong
|
|||
import { z } from "zod";
|
||||
import { ObjectId, WithId } from "mongodb";
|
||||
import { authCheck } from "../../../utils";
|
||||
import { AgenticAPIChatRequest, convertToAgenticAPIChatMessages, convertToCoreMessages, convertWorkflowToAgenticAPI } from "@/app/lib/types";
|
||||
import { executeClientTool, getAssistantResponse } from "@/app/actions";
|
||||
import { AgenticAPIChatRequest, convertToAgenticAPIChatMessages, convertWorkflowToAgenticAPI } from "@/app/lib/types";
|
||||
import { callClientToolWebhook, getAgenticApiResponse } from "@/app/lib/utils";
|
||||
|
||||
const chatsCollection = db.collection<z.infer<typeof apiV1.Chat>>("chats");
|
||||
const chatMessagesCollection = db.collection<z.infer<typeof apiV1.ChatMessage>>("chatMessages");
|
||||
|
|
@ -91,7 +91,7 @@ export async function POST(
|
|||
startAgent,
|
||||
};
|
||||
console.log("turn: sending agentic request", JSON.stringify(request, null, 2));
|
||||
const response = await getAssistantResponse(session.projectId, request);
|
||||
const response = await getAgenticApiResponse(request);
|
||||
state = response.state;
|
||||
if (response.messages.length === 0) {
|
||||
throw new Error("No messages returned from assistant");
|
||||
|
|
@ -111,7 +111,7 @@ export async function POST(
|
|||
const toolCallResults = await Promise.all(lastMessage.tool_calls.map(async toolCall => {
|
||||
console.log('executing tool call', toolCall);
|
||||
try {
|
||||
return await executeClientTool(toolCall, session.projectId);
|
||||
return await callClientToolWebhook(toolCall, session.projectId);
|
||||
} catch (error) {
|
||||
console.error(`Error executing tool call ${toolCall.id}:`, error);
|
||||
return { error: "Tool execution failed" };
|
||||
|
|
@ -1,5 +1,9 @@
|
|||
import { Workflow } from "@/app/lib/types";
|
||||
import { AgenticAPIChatRequest, AgenticAPIChatResponse, ClientToolCallJwt, ClientToolCallRequest, ClientToolCallRequestBody, convertFromAgenticAPIChatMessages, Workflow } from "@/app/lib/types";
|
||||
import { z } from "zod";
|
||||
import { projectsCollection } from "./mongodb";
|
||||
import { apiV1 } from "rowboat-shared";
|
||||
import { SignJWT } from "jose";
|
||||
import crypto from "crypto";
|
||||
|
||||
export const baseWorkflow: z.infer<typeof Workflow> = {
|
||||
projectId: "",
|
||||
|
|
@ -100,4 +104,95 @@ You are an helpful customer support assistant
|
|||
},
|
||||
],
|
||||
tools: [],
|
||||
};
|
||||
};
|
||||
|
||||
export async function callClientToolWebhook(
|
||||
toolCall: z.infer<typeof apiV1.AssistantMessageWithToolCalls>['tool_calls'][number],
|
||||
projectId: string,
|
||||
): Promise<unknown> {
|
||||
const project = await projectsCollection.findOne({
|
||||
"_id": projectId,
|
||||
});
|
||||
if (!project) {
|
||||
throw new Error('Project not found');
|
||||
}
|
||||
|
||||
if (!project.webhookUrl) {
|
||||
throw new Error('Webhook URL not found');
|
||||
}
|
||||
|
||||
// prepare request body
|
||||
const content = JSON.stringify({
|
||||
toolCall,
|
||||
} as z.infer<typeof ClientToolCallRequestBody>);
|
||||
const requestId = crypto.randomUUID();
|
||||
const bodyHash = crypto
|
||||
.createHash('sha256')
|
||||
.update(content, 'utf8')
|
||||
.digest('hex');
|
||||
|
||||
// sign request
|
||||
const jwt = await new SignJWT({
|
||||
requestId,
|
||||
projectId,
|
||||
bodyHash,
|
||||
} as z.infer<typeof ClientToolCallJwt>)
|
||||
.setProtectedHeader({
|
||||
alg: 'HS256',
|
||||
typ: 'JWT',
|
||||
})
|
||||
.setIssuer('rowboat')
|
||||
.setAudience(project.webhookUrl)
|
||||
.setSubject(`tool-call-${toolCall.id}`)
|
||||
.setJti(requestId)
|
||||
.setIssuedAt()
|
||||
.setExpirationTime("5 minutes")
|
||||
.sign(new TextEncoder().encode(project.secret));
|
||||
|
||||
// make request
|
||||
const request: z.infer<typeof ClientToolCallRequest> = {
|
||||
requestId,
|
||||
content,
|
||||
};
|
||||
const response = await fetch(project.webhookUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-signature-jwt': jwt,
|
||||
},
|
||||
body: JSON.stringify(request),
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to call webhook: ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
const responseBody = await response.json();
|
||||
return responseBody;
|
||||
}
|
||||
|
||||
export async function getAgenticApiResponse(
|
||||
request: z.infer<typeof AgenticAPIChatRequest>,
|
||||
): Promise<{
|
||||
messages: z.infer<typeof apiV1.ChatMessage>[],
|
||||
state: unknown,
|
||||
rawAPIResponse: unknown,
|
||||
}> {
|
||||
// call agentic api
|
||||
const response = await fetch(process.env.AGENTIC_API_URL + '/chat', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(request),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
if (!response.ok) {
|
||||
console.error('Failed to call agentic api', response);
|
||||
throw new Error(`Failed to call agentic api: ${response.statusText}`);
|
||||
}
|
||||
const responseJson = await response.json();
|
||||
const result: z.infer<typeof AgenticAPIChatResponse> = responseJson;
|
||||
return {
|
||||
messages: convertFromAgenticAPIChatMessages(result.messages),
|
||||
state: result.state,
|
||||
rawAPIResponse: result,
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue