Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion open-sse/executors/adapta-web.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { BaseExecutor, type ExecuteInput } from "./base.ts";
import { prepareToolMessages, buildToolAwareResult } from "../translator/webTools.ts";

const ADAPTA_APP_URL = "https://agent.adapta.one";
const ADAPTA_CLERK_URL = "https://clerk.agent.adapta.one";
Expand Down Expand Up @@ -352,6 +353,7 @@ export class AdaptaWebExecutor extends BaseExecutor {
async execute({ model, body, stream, credentials, signal, log }: ExecuteInput) {
const bodyObj = (body ?? {}) as Record<string, unknown>;
const messages = (Array.isArray(bodyObj.messages) ? bodyObj.messages : []) as OpenAIMessage[];
const { hasTools, requestedTools, effectiveMessages } = prepareToolMessages(bodyObj, messages);

// 1. Extract and validate credentials
const rawKey = String((credentials as Record<string, unknown>)?.apiKey ?? "");
Expand Down Expand Up @@ -385,7 +387,7 @@ export class AdaptaWebExecutor extends BaseExecutor {

// 2. Build Adapta request body
const aiModelId = MODEL_ID_MAP[model] ?? DEFAULT_AI_MODEL_ID;
const adaptaMessages = buildAdaptaMessages(messages);
const adaptaMessages = buildAdaptaMessages(effectiveMessages);

if (adaptaMessages.length === 0) {
return {
Expand Down Expand Up @@ -488,6 +490,35 @@ export class AdaptaWebExecutor extends BaseExecutor {
reader.releaseLock();
}

if (hasTools) {
const { content, toolCalls, finishReason } = buildToolAwareResult(fullText, requestedTools, "adp");
if (toolCalls) {
return {
response: new Response(
JSON.stringify({
id: `chatcmpl-adp-${Date.now()}`, object: "chat.completion",
created: Math.floor(Date.now() / 1000), model,
choices: [{ index: 0, message: { role: "assistant", content: null, tool_calls: toolCalls }, finish_reason: finishReason }],
}),
{ status: 200, headers: { "Content-Type": "application/json" } }
),
url: ADAPTA_STREAM_URL, headers, transformedBody: requestPayload,
};
}
return {
response: new Response(
JSON.stringify({
id: `chatcmpl-adp-${Date.now()}`, object: "chat.completion",
created: Math.floor(Date.now() / 1000), model,
choices: [{ index: 0, message: { role: "assistant", content }, finish_reason: "stop" }],
usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
}),
{ status: 200, headers: { "Content-Type": "application/json" } }
),
url: ADAPTA_STREAM_URL, headers, transformedBody: requestPayload,
};
}

return {
response: new Response(
JSON.stringify({
Expand Down
28 changes: 26 additions & 2 deletions open-sse/executors/blackbox-web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
} from "./base.ts";
import { FETCH_TIMEOUT_MS } from "../config/constants.ts";
import { normalizeSessionCookieHeader } from "@/lib/providers/webCookieAuth";
import { prepareToolMessages, buildToolAwareResult } from "../translator/webTools.ts";

const BLACKBOX_CHAT_API = "https://app.blackbox.ai/api/chat";
const BLACKBOX_DEFAULT_COOKIE = "next-auth.session-token";
Expand Down Expand Up @@ -302,7 +303,8 @@ export class BlackboxWebExecutor extends BaseExecutor {
log,
upstreamExtraHeaders,
}: ExecuteInput) {
const messages = (body as Record<string, unknown>).messages as
const bodyObj = (body || {}) as Record<string, unknown>;
const messages = bodyObj.messages as
| Array<Record<string, unknown>>
| undefined;
if (!messages || !Array.isArray(messages) || messages.length === 0) {
Expand All @@ -323,8 +325,9 @@ export class BlackboxWebExecutor extends BaseExecutor {
};
}

const { hasTools, requestedTools, effectiveMessages } = prepareToolMessages(bodyObj, messages as Array<{ role: string; content: unknown }>);
const chatId = crypto.randomUUID().slice(0, 7);
const parsedMessages = parseOpenAIMessages(messages, chatId);
const parsedMessages = parseOpenAIMessages(effectiveMessages, chatId);
if (parsedMessages.length === 0) {
const errorResponse = new Response(
JSON.stringify({
Expand Down Expand Up @@ -645,6 +648,27 @@ export class BlackboxWebExecutor extends BaseExecutor {
const id = `chatcmpl-blackbox-${crypto.randomUUID().slice(0, 12)}`;
const created = Math.floor(Date.now() / 1000);

if (hasTools) {
const { content, toolCalls, finishReason } = buildToolAwareResult(responseText, requestedTools, "bbx");
if (toolCalls) {
const toolResponse = new Response(
JSON.stringify({
id, object: "chat.completion", created, model,
choices: [{ index: 0, message: { role: "assistant", content: null, tool_calls: toolCalls }, finish_reason: finishReason }],
}),
{ status: 200, headers: { "Content-Type": "application/json" } }
);
return { response: toolResponse, url: BLACKBOX_CHAT_API, headers, transformedBody };
}
const finalResponse = stream
? new Response(buildStreamingResponse(content, model, id, created), {
status: 200,
headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", "X-Accel-Buffering": "no" },
})
: buildNonStreamingResponse(content, model, id, created);
return { response: finalResponse, url: BLACKBOX_CHAT_API, headers, transformedBody };
}

const finalResponse = stream
? new Response(buildStreamingResponse(responseText, model, id, created), {
status: 200,
Expand Down
35 changes: 28 additions & 7 deletions open-sse/executors/duckduckgo-web.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { BaseExecutor, type ExecuteInput } from "./base.ts";
import { FETCH_TIMEOUT_MS } from "../config/constants.ts";
import { prepareToolMessages, buildToolAwareResult } from "../translator/webTools.ts";

export const DUCKDUCKGO_BASE = "https://duckduckgo.com";
const STATUS_URL = `${DUCKDUCKGO_BASE}/duckchat/v1/status`;
Expand Down Expand Up @@ -64,7 +65,16 @@ export class DuckDuckGoWebExecutor extends BaseExecutor {
}

async execute(input: ExecuteInput) {
const { model, messages, stream, signal, upstreamHeaders } = input;
const { model, body, stream, signal } = input;
const bodyObj = (body || {}) as Record<string, unknown>;
const messages = (bodyObj.messages as Array<{ role: string; content: string }>) || [];

if (signal?.aborted) {
return new Response(
JSON.stringify({ error: { message: "Request cancelled" } }),
{ status: 499, headers: { "Content-Type": "application/json" } }
);
}

if (!messages || messages.length === 0) {
return new Response(
Expand All @@ -73,6 +83,8 @@ export class DuckDuckGoWebExecutor extends BaseExecutor {
);
}

const { hasTools, requestedTools, effectiveMessages } = prepareToolMessages(bodyObj, messages);

// Acquire session from pool for fingerprint rotation
const pool = this.getPool();
let session;
Expand Down Expand Up @@ -117,7 +129,7 @@ export class DuckDuckGoWebExecutor extends BaseExecutor {
},
body: JSON.stringify({
model,
messages,
messages: effectiveMessages,
stream: stream !== false,
}),
signal: mergedSignal,
Expand Down Expand Up @@ -145,13 +157,13 @@ export class DuckDuckGoWebExecutor extends BaseExecutor {
},
body: JSON.stringify({
model,
messages,
messages: effectiveMessages,
stream: stream !== false,
}),
signal: mergedSignal,
});

return this.processResponse(retryResponse, stream !== false);
return this.processResponse(retryResponse, stream !== false, hasTools, requestedTools);
}
return new Response(
JSON.stringify({ error: { message: "Service unavailable" } }),
Expand All @@ -167,7 +179,7 @@ export class DuckDuckGoWebExecutor extends BaseExecutor {
);
}

const result = this.processResponse(chatResponse, stream !== false);
const result = this.processResponse(chatResponse, stream !== false, hasTools, requestedTools);

// Report pool status based on response
if (pool && session) {
Expand Down Expand Up @@ -222,7 +234,7 @@ export class DuckDuckGoWebExecutor extends BaseExecutor {
}
}

private async processResponse(response: Response, streaming: boolean): Promise<Response> {
private async processResponse(response: Response, streaming: boolean, hasTools?: boolean, requestedTools?: unknown): Promise<Response> {
if (!response.ok) {
const body = await response.text();
return new Response(body, {
Expand All @@ -231,7 +243,7 @@ export class DuckDuckGoWebExecutor extends BaseExecutor {
});
}

if (streaming) {
if (streaming && !hasTools) {
const reader = response.body?.getReader();
if (!reader) {
return new Response(
Expand Down Expand Up @@ -304,6 +316,15 @@ export class DuckDuckGoWebExecutor extends BaseExecutor {
}
}

if (hasTools) {
const { content, toolCalls, finishReason } = buildToolAwareResult(fullContent, requestedTools, "ddg");
const message: Record<string, unknown> = { role: "assistant", content };
if (toolCalls) { message.tool_calls = toolCalls; message.content = null; }
return new Response(JSON.stringify({ choices: [{ index: 0, message, finish_reason: finishReason }] }), {
headers: { "Content-Type": "application/json" },
});
}

const openaiResponse = {
choices: [
{
Expand Down
23 changes: 22 additions & 1 deletion open-sse/executors/inner-ai.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createHash } from "node:crypto";
import { BaseExecutor, type ExecuteInput } from "./base.ts";
import { prepareToolMessages, buildToolAwareResult } from "../translator/webTools.ts";
import { sanitizeErrorMessage } from "../utils/error.ts";

const INNER_AI_CHAT_URL = "https://chatapi.innerai.com/chat";
Expand Down Expand Up @@ -599,7 +600,8 @@ export class InnerAiExecutor extends BaseExecutor {

// Build message content from OpenAI messages array
const rawMessages = Array.isArray(bodyObj.messages) ? bodyObj.messages : [];
const messages = rawMessages as Array<Record<string, unknown>>;
const { hasTools, requestedTools, effectiveMessages } = prepareToolMessages(bodyObj, rawMessages);
const messages = effectiveMessages as Array<Record<string, unknown>>;
const messageContent = buildMessageContent(messages);
if (!messageContent.trim()) {
return makeErrorResult(400, "No message content to send", body);
Expand Down Expand Up @@ -693,6 +695,25 @@ export class InnerAiExecutor extends BaseExecutor {
throw err;
}
const completionId = `chatcmpl-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;

if (hasTools) {
const { content: cleaned, toolCalls, finishReason } = buildToolAwareResult(content, requestedTools, "inner");
if (toolCalls) {
return {
response: new Response(
JSON.stringify({
id: completionId, object: "chat.completion",
created: Math.floor(Date.now() / 1000), model: resolvedModel,
choices: [{ index: 0, message: { role: "assistant", content: null, tool_calls: toolCalls }, finish_reason: finishReason }],
}),
{ status: 200, headers: { "Content-Type": "application/json" } }
),
url: INNER_AI_CHAT_URL, headers: reqHeaders, transformedBody: innerAiBody,
};
}
content = cleaned;
}

return {
response: new Response(
JSON.stringify({
Expand Down
44 changes: 35 additions & 9 deletions open-sse/executors/muse-spark-web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from "./base.ts";
import { FETCH_TIMEOUT_MS } from "../config/constants.ts";
import { getRotatingApiKey } from "../services/apiKeyRotator.ts";
import { prepareToolMessages, buildToolAwareResult } from "../translator/webTools.ts";
import {
normalizeSessionCookieHeader,
normalizeSessionCookieHeaders,
Expand Down Expand Up @@ -1144,18 +1145,20 @@ function rememberAssistantTurn(
});
}

function buildSuccessResult(
async function buildSuccessResult(
parsed: ParsedMetaAiResponse,
stream: boolean,
model: string,
headers: Record<string, string>,
transformedBody: unknown
): MuseSparkExecuteResult {
transformedBody: unknown,
hasTools?: boolean,
requestedTools?: unknown
): Promise<MuseSparkExecuteResult> {
const id = `chatcmpl-meta-${crypto.randomUUID().slice(0, 12)}`;
const created = Math.floor(Date.now() / 1000);
const deltas = parsed.deltas.length > 0 ? parsed.deltas : [parsed.content];
const reasoningDeltas = parsed.reasoningDeltas;
const response = stream
let response = stream
? new Response(buildStreamingResponse(deltas, reasoningDeltas, model, id, created), {
status: 200,
headers: {
Expand All @@ -1166,6 +1169,24 @@ function buildSuccessResult(
})
: buildNonStreamingResponse(parsed.content, parsed.reasoningContent, model, id, created);

if (hasTools && !stream) {
const bodyText = await (response as Response).text();
try {
const json = JSON.parse(bodyText);
const rawContent = json?.choices?.[0]?.message?.content || "";
const { content, toolCalls, finishReason } = buildToolAwareResult(rawContent, requestedTools, "muse");
if (toolCalls) {
json.choices[0].message = { role: "assistant", content: null, tool_calls: toolCalls };
json.choices[0].finish_reason = finishReason;
} else {
json.choices[0].message.content = content;
}
response = new Response(JSON.stringify(json), {
status: 200, headers: { "Content-Type": "application/json" },
});
} catch { /* keep original response */ }
}

return resultWithResponse(response, headers, transformedBody);
}

Expand All @@ -1183,12 +1204,14 @@ export class MuseSparkWebExecutor extends BaseExecutor {
log,
upstreamExtraHeaders,
}: ExecuteInput) {
const messages = getOpenAiMessages(body);
if (!messages) {
const bodyObj = (body || {}) as Record<string, unknown>;
const rawMessages = getOpenAiMessages(body);
if (!rawMessages) {
return errorResult(400, "Missing or empty messages array", "invalid_request", {}, body);
}

const parsedHistory = parseOpenAIMessages(messages);
const { hasTools, requestedTools, effectiveMessages } = prepareToolMessages(bodyObj, rawMessages as Array<{ role: string; content: unknown }>);
const parsedHistory = parseOpenAIMessages(effectiveMessages);
if (!parsedHistory.foldedPrompt) {
return errorResult(400, "Empty query after processing messages", "invalid_request", {}, body);
}
Expand Down Expand Up @@ -1222,7 +1245,10 @@ export class MuseSparkWebExecutor extends BaseExecutor {
const combinedSignal = signal ? mergeAbortSignals(signal, timeoutSignal) : timeoutSignal;

const fetchResult = await postMetaAiRequest(headers, transformedBody, combinedSignal, log);
if (!fetchResult.ok) return fetchResult.result;
if (!fetchResult.ok) {
const err = fetchResult as { ok: false; result: MuseSparkExecuteResult };
return err.result;
}

const upstreamResponse = fetchResult.response;
if (!upstreamResponse.ok) {
Expand Down Expand Up @@ -1252,6 +1278,6 @@ export class MuseSparkWebExecutor extends BaseExecutor {
}

rememberAssistantTurn(parsed, credentials, model, parsedHistory, conversationContext);
return buildSuccessResult(parsed, stream, model, headers, transformedBody);
return buildSuccessResult(parsed, stream, model, headers, transformedBody, hasTools, requestedTools);
}
}
Loading