mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-08 00:02:20 +03:00
Validated in local merge-train (devbox-vm-06-dev002) @ combined-tip (FAST gates: typecheck/complexity/cognitive/changelog/vitest — only pre-existing audit.test.ts flake). Evidence: /home/diegosouzapw/dev/proxys/OmniRoute/.claude/worktrees/merge-train-20260805-222248-suite.log
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import type { RegistryEntry } from "../../shared.ts";
|
||||
import { normalizeBaseUrl } from "../../../../utils/urlSanitize.ts";
|
||||
|
||||
// Poe (creator.poe.com) — OpenAI-compatible chat/responses gateway. #8082: the
|
||||
// built-in `poe` provider (NAMED_OPENAI_STYLE_PROVIDERS, passthroughModels:true)
|
||||
@@ -7,19 +8,86 @@ import type { RegistryEntry } from "../../shared.ts";
|
||||
// for provider" even though credentials/inference worked fine. This base URL is
|
||||
// the single source of truth other Poe code paths should read from (see
|
||||
// src/lib/providers/validation/audioMiscProviders.ts::validatePoeProvider).
|
||||
//
|
||||
// #8969: canonical `poe` is the API-key provider (DefaultExecutor → api.poe.com).
|
||||
// The web-cookie GraphQL transport lives only on `poe-web` / PoeWebExecutor —
|
||||
// never alias `poe` to that executor (it posts to /api/gql_POST and returns 405).
|
||||
export const POE_DEFAULT_BASE_URL = "https://api.poe.com/v1";
|
||||
|
||||
export const POE_CHAT_COMPLETIONS_URL = `${POE_DEFAULT_BASE_URL}/chat/completions`;
|
||||
export const POE_RESPONSES_URL = `${POE_DEFAULT_BASE_URL}/responses`;
|
||||
export const POE_MESSAGES_URL = `${POE_DEFAULT_BASE_URL}/messages`;
|
||||
|
||||
/** Official Claude model ids are the only ones Poe accepts on /v1/messages. */
|
||||
export function isPoeMessagesEligibleModel(model: string | null | undefined): boolean {
|
||||
if (typeof model !== "string" || !model) return false;
|
||||
return /(?:^|[\/._-])claude(?:[\/._-]|$)/i.test(model);
|
||||
}
|
||||
|
||||
export type PoeUpstreamProtocol = "chat" | "responses" | "messages";
|
||||
|
||||
/**
|
||||
* Normalize an operator-supplied or registry Poe base URL onto one of the three
|
||||
* documented API surfaces. Accepts bare host, `/v1`, full chat/completions URL,
|
||||
* and trailing-slash variants.
|
||||
*/
|
||||
export function resolvePoeUpstreamUrl(opts: {
|
||||
protocol: PoeUpstreamProtocol;
|
||||
configuredBaseUrl?: string | null;
|
||||
responsesBaseUrl?: string | null;
|
||||
messagesUrl?: string | null;
|
||||
defaultChatUrl?: string | null;
|
||||
}): string {
|
||||
const defaultChat = opts.defaultChatUrl || POE_CHAT_COMPLETIONS_URL;
|
||||
const defaultResponses = opts.responsesBaseUrl || POE_RESPONSES_URL;
|
||||
const defaultMessages = opts.messagesUrl || POE_MESSAGES_URL;
|
||||
|
||||
if (opts.protocol === "responses" && !opts.configuredBaseUrl) {
|
||||
return defaultResponses;
|
||||
}
|
||||
if (opts.protocol === "messages" && !opts.configuredBaseUrl) {
|
||||
return defaultMessages;
|
||||
}
|
||||
if (opts.protocol === "chat" && !opts.configuredBaseUrl) {
|
||||
return defaultChat;
|
||||
}
|
||||
|
||||
const raw = normalizeBaseUrl(opts.configuredBaseUrl || defaultChat);
|
||||
// Strip any known protocol suffix so we can re-append the requested one.
|
||||
const root = raw
|
||||
.replace(/\/chat\/completions\/?$/i, "")
|
||||
.replace(/\/responses\/?$/i, "")
|
||||
.replace(/\/messages\/?$/i, "")
|
||||
.replace(/\/$/, "");
|
||||
|
||||
const withV1 = /\/v1$/i.test(root) ? root : `${root}/v1`;
|
||||
|
||||
if (opts.protocol === "responses") return `${withV1}/responses`;
|
||||
if (opts.protocol === "messages") return `${withV1}/messages`;
|
||||
return `${withV1}/chat/completions`;
|
||||
}
|
||||
|
||||
export const poeProvider: RegistryEntry = {
|
||||
id: "poe",
|
||||
alias: "poe",
|
||||
format: "openai",
|
||||
executor: "default",
|
||||
baseUrl: `${POE_DEFAULT_BASE_URL}/chat/completions`,
|
||||
baseUrl: POE_CHAT_COMPLETIONS_URL,
|
||||
responsesBaseUrl: POE_RESPONSES_URL,
|
||||
// Anthropic-compatible Messages API — official Claude models only
|
||||
// (https://creator.poe.com/docs/external-applications/anthropic-compatible-api).
|
||||
// Routed via each claude-* model's targetFormat: "claude" below; GPT/Gemini
|
||||
// stay on Chat Completions / Responses.
|
||||
messagesUrl: POE_MESSAGES_URL,
|
||||
authType: "apikey",
|
||||
authHeader: "bearer",
|
||||
models: [
|
||||
{ id: "gpt-5.2", name: "GPT-5.2" },
|
||||
{ id: "claude-opus-4.8", name: "Claude Opus 4.8" },
|
||||
{
|
||||
id: "claude-opus-4.8",
|
||||
name: "Claude Opus 4.8",
|
||||
targetFormat: "claude",
|
||||
},
|
||||
{ id: "gemini-3.0-pro", name: "Gemini 3.0 Pro" },
|
||||
],
|
||||
};
|
||||
|
||||
@@ -40,6 +40,10 @@ import {
|
||||
normalizeOpenAIChatUrl,
|
||||
getOpenRouterConnectionPreset,
|
||||
} from "./default/urlNormalizers.ts";
|
||||
import {
|
||||
isPoeMessagesEligibleModel,
|
||||
resolvePoeUpstreamUrl,
|
||||
} from "../config/providers/registry/poe/index.ts";
|
||||
import { buildMaritalkChatUrl } from "../config/maritalk.ts";
|
||||
import { LOCAL_PROVIDERS } from "@/shared/constants/providers";
|
||||
import { isForbiddenCustomHeaderName } from "@/shared/constants/upstreamHeaders";
|
||||
@@ -285,6 +289,36 @@ export class DefaultExecutor extends BaseExecutor {
|
||||
case "glm-coding-apikey":
|
||||
// #7364: format override extracted to zaiFormatOverride.ts (file-size ratchet).
|
||||
return resolveZaiUrl(credentials, (fallback) => this.resolveBaseUrl(credentials, fallback));
|
||||
case "poe": {
|
||||
// #8969: Poe API-key surfaces — Chat Completions, Responses, and
|
||||
// Claude-only Messages. Prefer the responses marker from
|
||||
// resolveExecutionCredentials (incoming /v1/responses), then the
|
||||
// registry Claude targetFormat → messagesUrl, else chat/completions.
|
||||
// GPT models must never hit /v1/messages (Poe rejects non-Claude there).
|
||||
const psd = credentials?.providerSpecificData;
|
||||
const manualBaseUrl =
|
||||
typeof psd?.baseUrl === "string" && psd.baseUrl.trim() ? psd.baseUrl.trim() : null;
|
||||
const forceResponses = psd?._omnirouteForceResponsesUpstream === true;
|
||||
const modelTarget = getModelTargetFormat("poe", model);
|
||||
const connectionTarget =
|
||||
typeof psd?.targetFormat === "string" ? (psd.targetFormat as string) : null;
|
||||
const effectiveTarget = modelTarget || connectionTarget;
|
||||
|
||||
let protocol: "chat" | "responses" | "messages" = "chat";
|
||||
if (forceResponses || effectiveTarget === "openai-responses") {
|
||||
protocol = "responses";
|
||||
} else if (effectiveTarget === "claude" && isPoeMessagesEligibleModel(model)) {
|
||||
protocol = "messages";
|
||||
}
|
||||
|
||||
return resolvePoeUpstreamUrl({
|
||||
protocol,
|
||||
configuredBaseUrl: manualBaseUrl,
|
||||
responsesBaseUrl: this.config.responsesBaseUrl,
|
||||
messagesUrl: this.config.messagesUrl,
|
||||
defaultChatUrl: this.config.baseUrl,
|
||||
});
|
||||
}
|
||||
case "claude":
|
||||
case "glm":
|
||||
case "glmt":
|
||||
|
||||
@@ -152,7 +152,9 @@ const executors = {
|
||||
"yuanbao-web": new YuanbaoWebExecutor(),
|
||||
ybw: new YuanbaoWebExecutor(), // Alias
|
||||
"poe-web": new PoeWebExecutor(),
|
||||
poe: new PoeWebExecutor(), // Alias
|
||||
// #8969: do NOT alias canonical `poe` (API-key / api.poe.com) to PoeWebExecutor.
|
||||
// Registry declares executor:"default"; the hard-coded map previously won and
|
||||
// routed API-key traffic to GraphQL /api/gql_POST → HTTP 405.
|
||||
"venice-web": new VeniceWebExecutor(),
|
||||
ven: new VeniceWebExecutor(), // Alias
|
||||
"notion-web": new NotionWebExecutor(),
|
||||
|
||||
@@ -118,6 +118,18 @@ export function resolveExecutionCredentials(opts: {
|
||||
providerSpecificData._omnirouteForceResponsesUpstream = true;
|
||||
}
|
||||
|
||||
// #8969: Poe's native /v1/responses surface — DefaultExecutor.buildUrl("poe")
|
||||
// reads this marker so Responses requests do not land on chat/completions.
|
||||
if (targetFormat === FORMATS.OPENAI_RESPONSES && provider === "poe") {
|
||||
providerSpecificData._omnirouteForceResponsesUpstream = true;
|
||||
}
|
||||
|
||||
// #8969: Claude-tagged Poe models speak Anthropic Messages wire format. Keep
|
||||
// DefaultExecutor from injecting OpenAI stream_options onto that body.
|
||||
if (targetFormat === FORMATS.CLAUDE && provider === "poe") {
|
||||
providerSpecificData.disableStreamOptions = true;
|
||||
}
|
||||
|
||||
// #7364: "zai"/"glm-coding-apikey" default to the Anthropic Messages wire format
|
||||
// (registry format:"claude"), but a per-model targetFormat override (custom-model
|
||||
// dropdown, #2905) can resolve targetFormat to "openai" — e.g. for a vision model
|
||||
|
||||
@@ -105,6 +105,28 @@ test("AgentRouter threads the resolved Responses protocol only into execution cr
|
||||
assert.deepEqual(credentials.providerSpecificData, { apiKeyHealth: {} });
|
||||
});
|
||||
|
||||
test("#8969: poe + responses target sets the responses-upstream marker (no apiType)", () => {
|
||||
const out = resolveExecutionCredentials({
|
||||
...base,
|
||||
provider: "poe",
|
||||
targetFormat: RESPONSES,
|
||||
}) as Record<string, unknown>;
|
||||
const psd = out.providerSpecificData as Record<string, unknown>;
|
||||
assert.equal(psd.apiType, undefined);
|
||||
assert.equal(psd._omnirouteForceResponsesUpstream, true);
|
||||
});
|
||||
|
||||
test("#8969: poe + claude target disables OpenAI stream_options injection", () => {
|
||||
const out = resolveExecutionCredentials({
|
||||
...base,
|
||||
provider: "poe",
|
||||
targetFormat: "claude",
|
||||
}) as Record<string, unknown>;
|
||||
const psd = out.providerSpecificData as Record<string, unknown>;
|
||||
assert.equal(psd.disableStreamOptions, true);
|
||||
assert.equal(psd._omnirouteForceResponsesUpstream, undefined);
|
||||
});
|
||||
|
||||
test("ccSessionId is threaded into providerSpecificData when present", () => {
|
||||
const out = resolveExecutionCredentials({
|
||||
...base,
|
||||
|
||||
356
tests/unit/poe-api-executor-regression.test.ts
Normal file
356
tests/unit/poe-api-executor-regression.test.ts
Normal file
@@ -0,0 +1,356 @@
|
||||
/**
|
||||
* #8969: Canonical `poe` API-key provider must use DefaultExecutor → api.poe.com,
|
||||
* not the web-cookie PoeWebExecutor GraphQL path (which returns HTTP 405).
|
||||
*
|
||||
* Locks:
|
||||
* - getExecutor("poe") is DefaultExecutor; getExecutor("poe-web") stays PoeWebExecutor
|
||||
* - Chat Completions / Responses / Messages URL selection + auth headers
|
||||
* - GPT models never hit Poe's Claude-only Messages endpoint
|
||||
* - Operator baseUrl shapes (bare host, /v1/, trailing slash) normalize correctly
|
||||
* - Upstream 405 is preserved (not swallowed)
|
||||
*/
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-poe-api-8969-"));
|
||||
process.env.DATA_DIR = TEST_DATA_DIR;
|
||||
|
||||
const { getExecutor, hasSpecializedExecutor } = await import("../../open-sse/executors/index.ts");
|
||||
const { DefaultExecutor } = await import("../../open-sse/executors/default.ts");
|
||||
const { PoeWebExecutor } = await import("../../open-sse/executors/poe-web.ts");
|
||||
const { getRegistryEntry } = await import("../../open-sse/config/providerRegistry.ts");
|
||||
const { resolveExecutionCredentials } = await import(
|
||||
"../../open-sse/handlers/chatCore/executionCredentials.ts"
|
||||
);
|
||||
const { POE_DEFAULT_BASE_URL, resolvePoeUpstreamUrl } = await import(
|
||||
"../../open-sse/config/providers/registry/poe/index.ts"
|
||||
);
|
||||
const core = await import("../../src/lib/db/core.ts");
|
||||
|
||||
test.after(() => {
|
||||
try {
|
||||
core.resetDbInstance();
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
const CHAT_URL = "https://api.poe.com/v1/chat/completions";
|
||||
const RESPONSES_URL = "https://api.poe.com/v1/responses";
|
||||
const MESSAGES_URL = "https://api.poe.com/v1/messages";
|
||||
|
||||
function headerRecord(headers: Record<string, string>): Record<string, string> {
|
||||
const out: Record<string, string> = {};
|
||||
for (const [k, v] of Object.entries(headers)) out[k.toLowerCase()] = v;
|
||||
return out;
|
||||
}
|
||||
|
||||
test("#8969: getExecutor(poe) selects DefaultExecutor, not PoeWebExecutor", () => {
|
||||
assert.equal(hasSpecializedExecutor("poe"), false);
|
||||
const executor = getExecutor("poe");
|
||||
assert.ok(executor instanceof DefaultExecutor);
|
||||
assert.equal(executor instanceof PoeWebExecutor, false);
|
||||
assert.equal(executor.provider, "poe");
|
||||
});
|
||||
|
||||
test("#8969: getExecutor(poe-web) still selects PoeWebExecutor", () => {
|
||||
assert.equal(hasSpecializedExecutor("poe-web"), true);
|
||||
assert.ok(getExecutor("poe-web") instanceof PoeWebExecutor);
|
||||
});
|
||||
|
||||
test("#8969: registry declares API-key executor + all three Poe protocol URLs", () => {
|
||||
const entry = getRegistryEntry("poe");
|
||||
assert.ok(entry);
|
||||
assert.equal(entry.executor, "default");
|
||||
assert.equal(entry.authType, "apikey");
|
||||
assert.equal(entry.authHeader, "bearer");
|
||||
assert.equal(entry.baseUrl, CHAT_URL);
|
||||
assert.equal(entry.responsesBaseUrl, RESPONSES_URL);
|
||||
assert.equal(entry.messagesUrl, MESSAGES_URL);
|
||||
assert.equal(POE_DEFAULT_BASE_URL, "https://api.poe.com/v1");
|
||||
|
||||
const claude = entry.models?.find((m) => m.id === "claude-opus-4.8");
|
||||
assert.ok(claude, "catalog must include a Claude model");
|
||||
assert.equal(claude.targetFormat, "claude");
|
||||
|
||||
const gpt = entry.models?.find((m) => m.id === "gpt-5.2");
|
||||
assert.ok(gpt, "catalog must include a GPT model");
|
||||
assert.notEqual(gpt.targetFormat, "claude");
|
||||
});
|
||||
|
||||
test("#8969: buildUrl routes chat / responses / messages correctly", () => {
|
||||
const executor = getExecutor("poe") as DefaultExecutor;
|
||||
const creds = { apiKey: "poe-test-key", providerSpecificData: {} };
|
||||
|
||||
assert.equal(executor.buildUrl("gemma-4-31b", false, 0, creds), CHAT_URL);
|
||||
assert.equal(executor.buildUrl("gemma-4-31b", true, 0, creds), CHAT_URL);
|
||||
assert.equal(executor.buildUrl("gpt-5.2", false, 0, creds), CHAT_URL);
|
||||
|
||||
assert.equal(
|
||||
executor.buildUrl("gpt-5.2", false, 0, {
|
||||
...creds,
|
||||
providerSpecificData: { _omnirouteForceResponsesUpstream: true },
|
||||
}),
|
||||
RESPONSES_URL
|
||||
);
|
||||
assert.equal(
|
||||
executor.buildUrl("claude-opus-4.8", true, 0, {
|
||||
...creds,
|
||||
providerSpecificData: { _omnirouteForceResponsesUpstream: true },
|
||||
}),
|
||||
RESPONSES_URL
|
||||
);
|
||||
|
||||
assert.equal(executor.buildUrl("claude-opus-4.8", false, 0, creds), MESSAGES_URL);
|
||||
assert.equal(executor.buildUrl("claude-opus-4.8", true, 0, creds), MESSAGES_URL);
|
||||
|
||||
// GPT must never land on Poe's Claude-only Messages endpoint — even if an
|
||||
// operator incorrectly stamps targetFormat=claude on the connection.
|
||||
assert.equal(
|
||||
executor.buildUrl("gpt-5.2", false, 0, {
|
||||
...creds,
|
||||
providerSpecificData: { targetFormat: "claude" },
|
||||
}),
|
||||
CHAT_URL
|
||||
);
|
||||
assert.notEqual(
|
||||
executor.buildUrl("gpt-5.2", false, 0, {
|
||||
...creds,
|
||||
providerSpecificData: { targetFormat: "claude" },
|
||||
}),
|
||||
MESSAGES_URL
|
||||
);
|
||||
});
|
||||
|
||||
test("#8969: resolvePoeUpstreamUrl normalizes registry-default / bare-host /v1/ / trailing-slash bases", () => {
|
||||
const cases: Array<{ base: string | null | undefined; protocol: "chat" | "responses" | "messages"; expected: string }> =
|
||||
[
|
||||
{ base: undefined, protocol: "chat", expected: CHAT_URL },
|
||||
{ base: null, protocol: "chat", expected: CHAT_URL },
|
||||
{ base: "https://api.poe.com", protocol: "chat", expected: CHAT_URL },
|
||||
{ base: "https://api.poe.com/", protocol: "chat", expected: CHAT_URL },
|
||||
{ base: "https://api.poe.com/v1", protocol: "chat", expected: CHAT_URL },
|
||||
{ base: "https://api.poe.com/v1/", protocol: "chat", expected: CHAT_URL },
|
||||
{
|
||||
base: "https://api.poe.com/v1/chat/completions",
|
||||
protocol: "chat",
|
||||
expected: CHAT_URL,
|
||||
},
|
||||
{
|
||||
base: "https://api.poe.com/v1/chat/completions/",
|
||||
protocol: "chat",
|
||||
expected: CHAT_URL,
|
||||
},
|
||||
{ base: "https://api.poe.com/v1", protocol: "responses", expected: RESPONSES_URL },
|
||||
{ base: "https://api.poe.com/", protocol: "messages", expected: MESSAGES_URL },
|
||||
{
|
||||
base: "https://custom.example/v1/chat/completions",
|
||||
protocol: "responses",
|
||||
expected: "https://custom.example/v1/responses",
|
||||
},
|
||||
{
|
||||
base: "https://custom.example/v1",
|
||||
protocol: "messages",
|
||||
expected: "https://custom.example/v1/messages",
|
||||
},
|
||||
];
|
||||
|
||||
for (const { base, protocol, expected } of cases) {
|
||||
assert.equal(
|
||||
resolvePoeUpstreamUrl({
|
||||
protocol,
|
||||
configuredBaseUrl: base,
|
||||
responsesBaseUrl: RESPONSES_URL,
|
||||
messagesUrl: MESSAGES_URL,
|
||||
defaultChatUrl: CHAT_URL,
|
||||
}),
|
||||
expected,
|
||||
`base=${String(base)} protocol=${protocol}`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test("#8969: buildHeaders uses Bearer auth and never sends Cookie", () => {
|
||||
const executor = getExecutor("poe") as DefaultExecutor;
|
||||
for (const stream of [false, true]) {
|
||||
const headers = headerRecord(
|
||||
executor.buildHeaders({ apiKey: "poe-test-key", providerSpecificData: {} }, stream)
|
||||
);
|
||||
assert.equal(headers.authorization, "Bearer poe-test-key");
|
||||
assert.equal(headers.cookie, undefined);
|
||||
assert.equal(headers.accept, stream ? "text/event-stream" : "application/json");
|
||||
}
|
||||
});
|
||||
|
||||
test("#8969: resolveExecutionCredentials forces responses upstream for poe", () => {
|
||||
const out = resolveExecutionCredentials({
|
||||
credentials: { providerSpecificData: {} },
|
||||
nativeCodexPassthrough: false,
|
||||
endpointPath: "/v1/responses",
|
||||
targetFormat: "openai-responses",
|
||||
provider: "poe",
|
||||
ccSessionId: null,
|
||||
}) as { providerSpecificData: Record<string, unknown> };
|
||||
assert.equal(out.providerSpecificData._omnirouteForceResponsesUpstream, true);
|
||||
});
|
||||
|
||||
test("#8969: mocked execute posts Chat Completions with Bearer, no Cookie, stripped model", async () => {
|
||||
const executor = getExecutor("poe") as DefaultExecutor;
|
||||
const originalFetch = globalThis.fetch;
|
||||
const seen: Array<{
|
||||
url: string;
|
||||
method: string;
|
||||
authorization: string | null;
|
||||
cookie: string | null;
|
||||
body: Record<string, unknown>;
|
||||
}> = [];
|
||||
|
||||
globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
const headers = new Headers(init?.headers);
|
||||
const rawBody = typeof init?.body === "string" ? init.body : "{}";
|
||||
seen.push({
|
||||
url: String(input),
|
||||
method: (init?.method || "GET").toUpperCase(),
|
||||
authorization: headers.get("authorization"),
|
||||
cookie: headers.get("cookie"),
|
||||
body: JSON.parse(rawBody) as Record<string, unknown>,
|
||||
});
|
||||
return Response.json({
|
||||
id: "chatcmpl-test",
|
||||
object: "chat.completion",
|
||||
choices: [{ index: 0, message: { role: "assistant", content: "OK" }, finish_reason: "stop" }],
|
||||
});
|
||||
}) as typeof fetch;
|
||||
|
||||
try {
|
||||
for (const stream of [false, true]) {
|
||||
seen.length = 0;
|
||||
const result = await executor.execute({
|
||||
model: "gemma-4-31b",
|
||||
body: {
|
||||
model: "gemma-4-31b",
|
||||
messages: [{ role: "user", content: "Reply with OK only." }],
|
||||
max_tokens: 64,
|
||||
stream,
|
||||
},
|
||||
stream,
|
||||
credentials: { apiKey: "poe-test-key", providerSpecificData: {} },
|
||||
signal: null,
|
||||
});
|
||||
|
||||
assert.equal(seen.length, 1, `expected one upstream call (stream=${stream})`);
|
||||
assert.equal(seen[0].method, "POST");
|
||||
assert.equal(seen[0].url, CHAT_URL);
|
||||
assert.equal(seen[0].authorization, "Bearer poe-test-key");
|
||||
assert.equal(seen[0].cookie, null);
|
||||
assert.equal(seen[0].body.model, "gemma-4-31b");
|
||||
assert.equal(seen[0].url.includes("poe.com/api/gql"), false);
|
||||
assert.ok(result.response instanceof Response);
|
||||
assert.equal(result.response.status, 200);
|
||||
}
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
});
|
||||
|
||||
test("#8969: mocked execute routes Responses + Messages fixtures to the right URLs", async () => {
|
||||
const executor = getExecutor("poe") as DefaultExecutor;
|
||||
const originalFetch = globalThis.fetch;
|
||||
let lastUrl = "";
|
||||
|
||||
globalThis.fetch = (async (input: RequestInfo | URL) => {
|
||||
lastUrl = String(input);
|
||||
return Response.json({ id: "ok", object: "response", output: [] });
|
||||
}) as typeof fetch;
|
||||
|
||||
try {
|
||||
await executor.execute({
|
||||
model: "gpt-5.2",
|
||||
body: { model: "gpt-5.2", input: "hi", stream: false },
|
||||
stream: false,
|
||||
credentials: {
|
||||
apiKey: "poe-test-key",
|
||||
providerSpecificData: { _omnirouteForceResponsesUpstream: true },
|
||||
},
|
||||
signal: null,
|
||||
});
|
||||
assert.equal(lastUrl, RESPONSES_URL);
|
||||
|
||||
await executor.execute({
|
||||
model: "claude-opus-4.8",
|
||||
body: {
|
||||
model: "claude-opus-4.8",
|
||||
input: "hi",
|
||||
stream: true,
|
||||
},
|
||||
stream: true,
|
||||
credentials: {
|
||||
apiKey: "poe-test-key",
|
||||
providerSpecificData: { _omnirouteForceResponsesUpstream: true },
|
||||
},
|
||||
signal: null,
|
||||
});
|
||||
assert.equal(lastUrl, RESPONSES_URL);
|
||||
|
||||
globalThis.fetch = (async (input: RequestInfo | URL) => {
|
||||
lastUrl = String(input);
|
||||
return Response.json({
|
||||
id: "msg_ok",
|
||||
type: "message",
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text: "OK" }],
|
||||
});
|
||||
}) as typeof fetch;
|
||||
|
||||
await executor.execute({
|
||||
model: "claude-opus-4.8",
|
||||
body: {
|
||||
model: "claude-opus-4.8",
|
||||
messages: [{ role: "user", content: "hi" }],
|
||||
max_tokens: 16,
|
||||
stream: false,
|
||||
},
|
||||
stream: false,
|
||||
credentials: { apiKey: "poe-test-key", providerSpecificData: {} },
|
||||
signal: null,
|
||||
});
|
||||
assert.equal(lastUrl, MESSAGES_URL);
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
});
|
||||
|
||||
test("#8969: mocked upstream 405 is preserved (not swallowed)", async () => {
|
||||
const executor = getExecutor("poe") as DefaultExecutor;
|
||||
const originalFetch = globalThis.fetch;
|
||||
|
||||
globalThis.fetch = (async () => {
|
||||
return new Response(JSON.stringify({ detail: "Method Not Allowed" }), {
|
||||
status: 405,
|
||||
headers: { "content-type": "application/json" },
|
||||
});
|
||||
}) as typeof fetch;
|
||||
|
||||
try {
|
||||
const result = await executor.execute({
|
||||
model: "gemma-4-31b",
|
||||
body: {
|
||||
model: "gemma-4-31b",
|
||||
messages: [{ role: "user", content: "hi" }],
|
||||
stream: false,
|
||||
},
|
||||
stream: false,
|
||||
credentials: { apiKey: "poe-test-key", providerSpecificData: {} },
|
||||
signal: null,
|
||||
});
|
||||
assert.equal(result.response.status, 405);
|
||||
const text = await result.response.text();
|
||||
assert.match(text, /Method Not Allowed/);
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
});
|
||||
@@ -119,9 +119,11 @@ test("HuggingChat executor is registered", () => {
|
||||
|
||||
test("Poe Web executor is registered", () => {
|
||||
assert.ok(hasSpecializedExecutor("poe-web"));
|
||||
assert.ok(hasSpecializedExecutor("poe"));
|
||||
const executor = getExecutor("poe-web");
|
||||
assert.ok(executor instanceof PoeWebExecutor);
|
||||
// #8969: canonical API-key `poe` must not route through PoeWebExecutor.
|
||||
assert.equal(hasSpecializedExecutor("poe"), false);
|
||||
assert.ok(!(getExecutor("poe") instanceof PoeWebExecutor));
|
||||
});
|
||||
|
||||
test("Venice Web executor is registered", () => {
|
||||
|
||||
Reference in New Issue
Block a user