Compare commits

..

15 Commits

Author SHA1 Message Date
backryun
695fa96233 sync feat/conductor-voice onto release/v3.8.50 (post RF3) — resolve env/runtimeEnv/i18n/localDb [merge-prs-8222] 2026-08-12 01:58:35 -03:00
diegosouzapw
4b2bd2e37f feat(dashboard): Faro chat with push-to-talk voice on the Conductor panel 2026-07-22 21:11:47 -03:00
diegosouzapw
9813f35ff0 chore(env): CONDUCTOR_SPOKESPERSON_URL declared in schema, .env.example and ENVIRONMENT.md 2026-07-22 21:04:23 -03:00
diegosouzapw
54c69cf48d feat(dashboard): /api/conductor/ask — server-side proxy to Faro (spokesperson) with whitelisted {text,pending} 2026-07-22 21:04:18 -03:00
diegosouzapw
12b957a2df feat(dashboard): Conductor panel — fleet live view, task detail and cancel over /api/conductor proxy 2026-07-22 20:55:19 -03:00
diegosouzapw
5d3c988715 feat(dashboard): /api/conductor proxy routes (fleet, task detail, cancel) behind management auth 2026-07-22 20:44:03 -03:00
diegosouzapw
af97f7fc31 feat(dashboard): server-side hub proxy for the Conductor panel (whitelisted shapes, fail-open) 2026-07-22 20:41:46 -03:00
diegosouzapw
4d6c855258 feat(a2a): agent card announces Conductor fleet skills 2026-07-22 08:36:51 -03:00
diegosouzapw
7b951761fc feat(a2a): fleet skills derived from the Conductor hub for the agent card 2026-07-22 08:35:16 -03:00
diegosouzapw
b97318d73b docs(reference): document CONDUCTOR_HUB_URL/TOKEN in ENVIRONMENT.md (env-doc-sync gate) 2026-07-22 01:06:22 -03:00
diegosouzapw
a75295f359 fix(a2a): conductor bridge parses the hub's real SSE wire format (id/type in frame, data={ts,payload}) 2026-07-22 00:25:35 -03:00
diegosouzapw
00e15af622 feat(a2a): start conductor bridge at boot behind CONDUCTOR_HUB_URL 2026-07-22 00:23:28 -03:00
diegosouzapw
5eb10e896d feat(a2a): conductor bridge connection loop with persisted cursor and backoff 2026-07-22 00:21:10 -03:00
diegosouzapw
33baf62b58 feat(a2a): incremental SSE parser for conductor bridge 2026-07-22 00:21:10 -03:00
diegosouzapw
d42a58141b feat(a2a): conductor bridge core — event mapping with canceled->cancelled 2026-07-22 00:20:29 -03:00
54 changed files with 60 additions and 1630 deletions

View File

@@ -1,11 +0,0 @@
- **feat(plugins):** add onStreamComplete built-in event exposing streaming usage and timing (#9571)
Adds a new `onStreamComplete` plugin event that fires after an SSE stream is fully
consumed, carrying usage token counts and timing metrics (latency, TTFT). Built-in
events now include `onStreamComplete` as a fire-and-forget lifecycle hook.
Payload: `status`, `usage` (prompt_tokens, completion_tokens, reasoning_tokens,
cache_read_input_tokens, cache_creation_input_tokens), `timing` (latencyMs, ttft),
`model`, `provider`, `errorCode`.
Non-breaking — existing `onResponse` hooks with `{ streamed: true }` remain unchanged.

View File

@@ -1 +0,0 @@
- feat(a2a): inbound delegation to the OmniConductor fleet — `POST /api/a2a/tasks` translates an external A2A task into the hub's `POST /v1/tasks` (fleet skills only, repo required, `CONDUCTOR_ORCHESTRATOR_TOKEN` with hub-token fallback); states flow back through the SSE→A2A mirror

View File

@@ -178,9 +178,6 @@ The JSON-RPC endpoint `/a2a` is the canonical A2A entry point. The REST endpoint
| `/api/a2a/tasks/[id]` | GET | Get task by ID | management |
| `/api/a2a/tasks/[id]/cancel` | POST | Cancel running task | management |
| `/.well-known/agent.json` | GET | Agent Card (A2A discovery) | (public, cached 3600s) |
| `/api/a2a/tasks` | POST | Inbound delegation to the OmniConductor fleet (Conductor PRD RF5) | Bearer vs `OMNIROUTE_API_KEY` + `a2aEnabled` |
**Inbound Conductor delegation (`POST /api/a2a/tasks`):** external A2A agents delegate coding work to the OmniConductor fleet through OmniRoute. Body: `{ skill: "conductor" | "conductor-cli-<profile>", messages: [{role, content}], metadata: { conductor: { repo: { url, base_ref? }, mode?, cli?, model? } } }` — only Conductor fleet skills (the ones announced on the Agent Card) are delegable; `metadata.conductor.repo.url` is required (the fleet works on git repos). The route translates to the hub's `POST /v1/tasks` using the server-side `CONDUCTOR_ORCHESTRATOR_TOKEN` (fallback `CONDUCTOR_HUB_TOKEN`) and returns `201 { conductor_task_id, state: "submitted" }`; task states flow back through the SSE→A2A mirror (RF1) and are visible via `GET /api/a2a/tasks?skill=conductor`.
---

View File

@@ -233,32 +233,6 @@ import { hyperagentProvider } from "./registry/hyperagent/index.ts";
import { muse_codeProvider } from "./registry/muse-code/index.ts";
import { naga_acProvider } from "./registry/naga-ac/index.ts";
import { chatanywhereProvider } from "./registry/chatanywhere/index.ts";
import { zyloApiProvider } from "./registry/zylo-api/index.ts";
import { poolsideProvider } from "./registry/poolside/index.ts";
import { fastrouterProvider } from "./registry/fastrouter/index.ts";
import { anyapiProvider } from "./registry/anyapi/index.ts";
import { electronhubProvider } from "./registry/electronhub/index.ts";
import { llmgatewayProvider } from "./registry/llmgateway/index.ts";
import { llmKiwiProvider } from "./registry/llm-kiwi/index.ts";
import { literouterProvider } from "./registry/literouter/index.ts";
import { mnnAiProvider } from "./registry/mnn-ai/index.ts";
import { meganovaAiProvider } from "./registry/meganova-ai/index.ts";
import { mixlayerProvider } from "./registry/mixlayer/index.ts";
import { spekaProvider } from "./registry/speka/index.ts";
import { tokenreplyProvider } from "./registry/tokenreply/index.ts";
import { yoloAutoProvider } from "./registry/yolo-auto/index.ts";
import { dxntProvider } from "./registry/dxnt/index.ts";
import { cloudcodeOneProvider } from "./registry/cloudcode-one/index.ts";
import { ofoxaiProvider } from "./registry/ofoxai/index.ts";
import { zerolimitaiProvider } from "./registry/zerolimitai/index.ts";
import { helyxaiProvider } from "./registry/helyxai/index.ts";
import { aurikoProvider } from "./registry/auriko/index.ts";
import { poixeAiProvider } from "./registry/poixe-ai/index.ts";
import { nagaAiProvider } from "./registry/naga-ai/index.ts";
import { chatOripeProvider } from "./registry/chat-oripe/index.ts";
import { freeinferenceProvider } from "./registry/freeinference/index.ts";
import { freeAiProvider } from "./registry/free-ai/index.ts";
export const REGISTRY: Record<string, RegistryEntry> = {
aimlapi: aimlapiProvider,
@@ -491,33 +465,7 @@ export const REGISTRY: Record<string, RegistryEntry> = {
promptql: promptqlProvider,
hyperagent: hyperagentProvider,
"muse-code": muse_codeProvider,
"zylo-api": zyloApiProvider,
unorouter: unorouterProvider,
"naga-ac": naga_acProvider,
chatanywhere: chatanywhereProvider,
poolside: poolsideProvider,
fastrouter: fastrouterProvider,
anyapi: anyapiProvider,
electronhub: electronhubProvider,
llmgateway: llmgatewayProvider,
"llm-kiwi": llmKiwiProvider,
literouter: literouterProvider,
"mnn-ai": mnnAiProvider,
"meganova-ai": meganovaAiProvider,
mixlayer: mixlayerProvider,
speka: spekaProvider,
tokenreply: tokenreplyProvider,
"yolo-auto": yoloAutoProvider,
dxnt: dxntProvider,
"cloudcode-one": cloudcodeOneProvider,
ofoxai: ofoxaiProvider,
zerolimitai: zerolimitaiProvider,
helyxai: helyxaiProvider,
auriko: aurikoProvider,
"poixe-ai": poixeAiProvider,
"naga-ai": nagaAiProvider,
"chat-oripe": chatOripeProvider,
freeinference: freeinferenceProvider,
"free-ai": freeAiProvider,
};

View File

@@ -1,11 +0,0 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
export const aurikoProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
id: "auriko",
alias: "auriko",
baseUrl: "https://api.auriko.ai/v1/chat/completions",
modelsUrl: "https://api.auriko.ai/v1/models",
models: [],
passthroughModels: true,
});

View File

@@ -1,12 +0,0 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
// The upstream brand and hostname are ambiguous, so avoid unverified quota claims.
export const chatOripeProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
id: "chat-oripe",
alias: "chat-oripe",
baseUrl: "https://api.oriper.com/v1/chat/completions",
modelsUrl: "https://api.oriper.com/v1/models",
models: [],
passthroughModels: true,
});

View File

@@ -1,12 +1,17 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
// International endpoint; audited free access is limited to non-commercial use.
export const chatanywhereProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
// ChatAnywhere (api.chatanywhere.tech) — OpenAI-compatible gateway from the
// chatanywhere/GPT_API_free project (~38.7k GitHub stars). Requires GitHub-account-
// gated API key. Free tier is for personal non-commercial use only.
export const chatanywhereProvider: RegistryEntry = {
id: "chatanywhere",
alias: "chatanywhere",
baseUrl: "https://api.chatanywhere.org/v1/chat/completions",
modelsUrl: "https://api.chatanywhere.org/v1/models",
models: [],
alias: "chtany",
format: "openai",
executor: "default",
baseUrl: "https://api.chatanywhere.tech/v1/chat/completions",
modelsUrl: "https://api.chatanywhere.tech/v1/models",
authType: "apikey",
authHeader: "bearer",
passthroughModels: true,
});
models: [],
};

View File

@@ -1,20 +0,0 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
/**
* CloudCode.ONE - OpenAI-compatible API with published free model aliases.
*
* The Anthropic-compatible endpoint is documented separately; this registry
* covers the OpenAI-compatible API surface audited for this migration.
*/
export const cloudcodeOneProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
id: "cloudcode-one",
alias: "cloudcode-one",
baseUrl: "https://api.cloudcode.one/v1/chat/completions",
modelsUrl: "https://api.cloudcode.one/v1/models",
models: [
{ id: "glm-4.7-flash", name: "GLM 4.7 Flash" },
{ id: "glm-4.6v-flash", name: "GLM 4.6V Flash" },
],
passthroughModels: true,
});

View File

@@ -1,5 +1,5 @@
import type { RegistryEntry } from "../../shared.ts";
import { CONOL_FALLBACK_MODELS } from "../../../../services/conolModels.ts";
import { CONOL_FALLBACK_MODELS } from "../../../services/conolModels.ts";
export const conol_webProvider: RegistryEntry = {
id: "conol-web",

View File

@@ -1,17 +0,0 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
/**
* DXNT - OpenAI-compatible API with a free account quota.
*
* Models are discovered from the provider's authenticated catalog rather than
* copied into a static list, so account-specific availability remains intact.
*/
export const dxntProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
id: "dxnt",
alias: "dxnt",
baseUrl: "https://www.dxnt.com/v1/chat/completions",
modelsUrl: "https://www.dxnt.com/v1/models",
models: [],
passthroughModels: true,
});

View File

@@ -1,11 +0,0 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
export const freeAiProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
id: "free-ai",
alias: "free-ai",
baseUrl: "https://api.free.ai/v1/chat/",
modelsUrl: "https://api.free.ai/v1/models",
models: [],
passthroughModels: true,
});

View File

@@ -1,11 +0,0 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
export const freeinferenceProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
id: "freeinference",
alias: "freeinference",
baseUrl: "https://freeinference.org/v1/chat/completions",
modelsUrl: "https://freeinference.org/v1/models",
models: [],
passthroughModels: true,
});

View File

@@ -1,11 +0,0 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
export const helyxaiProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
id: "helyxai",
alias: "helyxai",
baseUrl: "https://helyxai.space/v1/chat/completions",
modelsUrl: "https://helyxai.space/v1/models",
models: [],
passthroughModels: true,
});

View File

@@ -1,11 +0,0 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
export const literouterProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
id: "literouter",
alias: "literouter",
baseUrl: "https://api.literouter.com/v1/chat/completions",
modelsUrl: "https://api.literouter.com/v1/models",
models: [],
passthroughModels: true,
});

View File

@@ -1,11 +0,0 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
export const meganovaAiProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
id: "meganova-ai",
alias: "meganova-ai",
baseUrl: "https://api.meganova.ai/v1/chat/completions",
modelsUrl: "https://api.meganova.ai/v1/models",
models: [],
passthroughModels: true,
});

View File

@@ -1,11 +0,0 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
export const mixlayerProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
id: "mixlayer",
alias: "mixlayer",
baseUrl: "https://models.mixlayer.ai/v1/chat/completions",
modelsUrl: "https://models.mixlayer.ai/v1/models",
models: [{ id: "qwen/qwen3.5-4b-free", name: "Qwen 3.5 4B (free)" }],
passthroughModels: true,
});

View File

@@ -1,11 +0,0 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
export const mnnAiProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
id: "mnn-ai",
alias: "mnn-ai",
baseUrl: "https://api.mnnai.ru/v1/chat/completions",
modelsUrl: "https://api.mnnai.ru/v1/models",
models: [],
passthroughModels: true,
});

View File

@@ -1,12 +0,0 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
// Free access terms may permit data collection or training use; discover models dynamically.
export const nagaAiProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
id: "naga-ai",
alias: "naga-ai",
baseUrl: "https://api.naga.ac/v1/chat/completions",
modelsUrl: "https://api.naga.ac/v1/models",
models: [],
passthroughModels: true,
});

View File

@@ -1,11 +0,0 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
export const ofoxaiProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
id: "ofoxai",
alias: "ofoxai",
baseUrl: "https://api.ofox.ai/v1/chat/completions",
modelsUrl: "https://api.ofox.ai/v1/models",
models: [],
passthroughModels: true,
});

View File

@@ -1,11 +0,0 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
export const poixeAiProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
id: "poixe-ai",
alias: "poixe-ai",
baseUrl: "https://api.poixe.com/v1/chat/completions",
modelsUrl: "https://api.poixe.com/v1/models",
models: [],
passthroughModels: true,
});

View File

@@ -1,11 +0,0 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
export const spekaProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
id: "speka",
alias: "speka",
baseUrl: "https://speka.me/v1/chat/completions",
modelsUrl: "https://speka.me/v1/models",
models: [],
passthroughModels: true,
});

View File

@@ -1,11 +0,0 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
export const tokenreplyProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
id: "tokenreply",
alias: "tokenreply",
baseUrl: "https://api.tokenreply.com/v1/chat/completions",
modelsUrl: "https://api.tokenreply.com/v1/models",
models: [],
passthroughModels: true,
});

View File

@@ -1,11 +1,14 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
export const unorouterProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
export const unorouterProvider: RegistryEntry = {
id: "unorouter",
alias: "unorouter",
baseUrl: "https://api.unorouter.com/v1/chat/completions",
modelsUrl: "https://api.unorouter.com/v1/models",
models: [],
format: "openai",
executor: "default",
baseUrl: "https://api.unorouter.ai/v1/chat/completions",
authType: "apikey",
authHeader: "bearer",
defaultContextLength: 128000,
models: [{ id: "auto", name: "Auto (Best Available)" }],
passthroughModels: true,
});
};

View File

@@ -1,17 +0,0 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
/**
* Yolo-Auto - OpenAI-compatible API with a request-limited free tier.
*
* The catalog is kept intentionally small: the documented free-tier model is
* seeded while passthrough discovery allows the service to publish updates.
*/
export const yoloAutoProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
id: "yolo-auto",
alias: "yolo-auto",
baseUrl: "https://yolo-auto.com/v1/chat/completions",
modelsUrl: "https://yolo-auto.com/v1/models",
models: [{ id: "qwen3.6-35b-a3b", name: "Qwen 3.6 35B A3B" }],
passthroughModels: true,
});

View File

@@ -1,11 +0,0 @@
import type { RegistryEntry } from "../../shared.ts";
import { buildOpenAiCompatibleRegistryEntry } from "../../shared.ts";
export const zerolimitaiProvider: RegistryEntry = buildOpenAiCompatibleRegistryEntry({
id: "zerolimitai",
alias: "zerolimitai",
baseUrl: "https://www.zerolimitai.com/api/v1/chat/completions",
modelsUrl: "https://www.zerolimitai.com/api/v1/models",
models: [],
passthroughModels: true,
});

View File

@@ -1,5 +1,3 @@
import { randomUUID } from "node:crypto";
import { BaseExecutor, type ExecuteInput } from "./base.ts";
import { makeExecutorErrorResult as makeErrorResult } from "../utils/error.ts";
import { initTinyCmsWasm, generateSecurePayload } from "./tinycmsSigner.ts";
@@ -30,9 +28,9 @@ async function fetchChallenge(uuid: string): Promise<any> {
const res = await fetch(CHALLENGE_URL, {
method: "GET",
headers: {
uuid: uuid,
"uuid": uuid,
"x-origin": "https://gov.freegpt.win",
Accept: "application/json",
"Accept": "application/json",
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36",
},
});
@@ -69,10 +67,10 @@ export class TinyCmsExecutor extends BaseExecutor {
const challengeObj = await fetchChallenge(uuid);
const timestamp = Date.now().toString();
// The nonce is signed into the anti-replay payload below, so it must come from a CSPRNG.
// `randomUUID` from node:crypto is always available on the supported runtimes — the old
// non-cryptographic fallback produced a predictable nonce with no way to notice.
const nonceJs = randomUUID();
const nonceJs =
typeof crypto !== "undefined" && crypto.randomUUID
? crypto.randomUUID()
: `${Date.now()}-${Math.random().toString(16).slice(2)}`;
const securePayload = generateSecurePayload(
uuid,
@@ -123,7 +121,12 @@ export class TinyCmsExecutor extends BaseExecutor {
body: response.body,
};
} catch (err: any) {
return makeErrorResult(500, `TinyCMS Error: ${err.message}`, body, CHAT_URL);
return makeErrorResult(
500,
`TinyCMS Error: ${err.message}`,
body,
CHAT_URL
);
}
}
}

View File

@@ -251,10 +251,7 @@ import { recordCompressionCacheStats } from "./chatCore/compressionCacheStats.ts
import { writeCavemanOutputAnalytics } from "./chatCore/cavemanOutputAnalytics.ts";
import { scheduleQuotaShareConsumption } from "./chatCore/quotaShareConsumption.ts";
import { emitRequestGamificationEvent } from "./chatCore/gamificationEvent.ts";
import {
runPluginOnResponseHook,
runPluginOnStreamCompleteHook,
} from "./chatCore/pluginOnResponse.ts";
import { runPluginOnResponseHook } from "./chatCore/pluginOnResponse.ts";
import { scheduleStreamingQuotaShareConsumption } from "./chatCore/streamingQuotaShare.ts";
import { recordStreamingUsageStats } from "./chatCore/streamingUsageStats.ts";
import { recordStreamingCost } from "./chatCore/streamingCost.ts";
@@ -4937,17 +4934,6 @@ export async function handleChatCore({
streamUsage,
log,
});
// Plugin onStreamComplete hook — fire-and-forget, fail-open (#9571)
runPluginOnStreamCompleteHook({
status: normalizedStreamStatus,
usage: streamUsage as Record<string, unknown> | undefined,
ttft,
model,
provider,
errorCode: streamErrorCode,
startTime,
});
};
const streamFailureFinalizers = streamFailure.createStreamFailureFinalizers({

View File

@@ -45,57 +45,3 @@ export async function runPluginOnResponseHook(args: {
/* plugin onResponse optional */
}
}
/**
* Payload passed to plugin onStreamComplete hooks after a streaming response is consumed.
* Carries usage token counts, timing metrics (latency, TTFT), model, provider, and error code.
*/
export type PluginOnStreamCompletePayload = {
status: number;
usage?: {
prompt_tokens?: number;
completion_tokens?: number;
reasoning_tokens?: number;
cache_read_input_tokens?: number;
cache_creation_input_tokens?: number;
};
timing?: {
latencyMs: number;
ttft?: number;
};
model?: string;
provider?: string;
errorCode?: string;
};
/**
* Run plugin onStreamComplete hooks — fire-and-forget and fail-open.
* Called inside the onStreamComplete callback (chatCore.ts) where usage and timing data
* converge after an SSE stream is fully consumed.
*/
export async function runPluginOnStreamCompleteHook(args: {
status: number;
usage?: Record<string, unknown>;
ttft?: number;
model: string | null | undefined;
provider: string | null | undefined;
errorCode?: string | null | undefined;
startTime: number;
}): Promise<void> {
try {
const { runOnStreamComplete } = await import("@/lib/plugins/hooks");
runOnStreamComplete({
status: args.status,
usage: args.usage as PluginOnStreamCompletePayload["usage"],
timing: {
latencyMs: Date.now() - args.startTime,
ttft: args.ttft,
},
model: args.model ?? undefined,
provider: args.provider ?? undefined,
errorCode: args.errorCode ?? undefined,
}).catch(() => {});
} catch (_) {
/* plugin onStreamComplete optional */
}
}

View File

@@ -237,16 +237,12 @@ function trustedEnvironmentText(parsed: CodexParsedRequest): string {
}
function decodeXmlText(value: string): string {
// `&amp;` MUST be decoded last: decoding it first turns `&amp;quot;` (the encoding of the
// literal text `&quot;`) into `&quot;`, which the following pass then decodes again into `"`.
// These values feed the workspace-root trust comparison below, so a double-unescape lets an
// encoded path decode into a different path than the one the client actually declared.
return value
.replaceAll("&lt;", "<")
.replaceAll("&gt;", ">")
.replaceAll("&amp;", "&")
.replaceAll("&quot;", '"')
.replaceAll("&#39;", "'")
.replaceAll("&amp;", "&");
.replaceAll("&#39;", "'");
}
function uniqueAbsolutePaths(values: string[], field: string): string[] {

View File

@@ -1,9 +1,5 @@
import { NextResponse } from "next/server";
import { z } from "zod";
import { getTaskManager, type TaskState } from "@/lib/a2a/taskManager";
import { createConductorTask } from "@/lib/conductor/hubProxy";
import { getSettings } from "@/lib/db/settings";
const VALID_TASK_STATES = new Set<TaskState>([
"submitted",
@@ -48,97 +44,3 @@ export async function GET(request: Request) {
return NextResponse.json({ error: message }, { status: 500 });
}
}
// ============ POST — delegação de entrada à frota do Conductor (PRD Conductor RF5) ============
const delegationSchema = z.object({
skill: z.string().default("conductor"),
messages: z.array(z.object({ role: z.string(), content: z.string() })).min(1),
metadata: z
.object({
conductor: z
.object({
repo: z.object({ url: z.string().min(1), base_ref: z.string().optional() }).optional(),
mode: z.string().optional(),
cli: z.string().optional(),
model: z.string().optional(),
})
.optional(),
})
.optional(),
});
/** Mesma semântica de auth do JSON-RPC A2A (src/app/a2a/route.ts): Bearer vs OMNIROUTE_API_KEY; aberto se não configurada. */
function authenticateA2A(request: Request): boolean {
const configuredKey = process.env.OMNIROUTE_API_KEY;
if (!configuredKey) return true;
const token = (request.headers.get("authorization") || "").replace(/^Bearer\s+/i, "");
return token === configuredKey;
}
/**
* Traduz uma task A2A externa em `POST /v1/tasks` do hub do OmniConductor.
* Só skills da frota (`conductor` / `conductor-cli-<profile>` — as anunciadas no
* Agent Card) são delegáveis; os estados voltam pelo espelho SSE→A2A (RF1).
*/
export async function POST(request: Request) {
if (!authenticateA2A(request)) {
return NextResponse.json({ error: "Unauthorized: missing or invalid API key" }, { status: 401 });
}
const settings = await getSettings();
if (settings.a2aEnabled !== true) {
return NextResponse.json(
{ error: "A2A endpoint is disabled. Enable it from the Endpoints page." },
{ status: 503 }
);
}
let raw: unknown;
try {
raw = await request.json();
} catch {
return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 });
}
const parsed = delegationSchema.safeParse(raw);
if (!parsed.success) {
return NextResponse.json({ error: "Invalid A2A task: provide messages[] (and metadata.conductor)" }, { status: 400 });
}
const { skill, messages, metadata } = parsed.data;
if (skill !== "conductor" && !skill.startsWith("conductor-cli-")) {
return NextResponse.json(
{ error: "Only Conductor fleet skills are delegable here (conductor / conductor-cli-<profile>)" },
{ status: 400 }
);
}
const conductor = metadata?.conductor;
if (!conductor?.repo?.url) {
return NextResponse.json(
{ error: "Delegation requires metadata.conductor.repo.url (the fleet works on git repos)" },
{ status: 400 }
);
}
const prompt = [...messages].reverse().find((m) => m.role === "user")?.content ?? messages[messages.length - 1].content;
const created = await createConductorTask({
repoUrl: conductor.repo.url,
baseRef: conductor.repo.base_ref,
prompt,
mode: conductor.mode,
cli: skill.startsWith("conductor-cli-") ? skill.slice("conductor-cli-".length) : conductor.cli,
model: conductor.model,
});
if (!created.ok) {
return NextResponse.json(
{ error: `Conductor hub refused the delegation (HTTP ${created.status})` },
{ status: created.status }
);
}
return NextResponse.json(
{
conductor_task_id: created.task_id,
state: "submitted",
note: "States flow back through the SSE→A2A mirror (GET /api/a2a/tasks, skill=conductor).",
},
{ status: 201 }
);
}

View File

@@ -155,51 +155,6 @@ export async function getConductorTaskDetail(
return null;
}
}
export interface DelegationInput {
repoUrl: string;
prompt: string;
baseRef?: string;
mode?: string;
cli?: string;
model?: string;
}
/**
* Delegates work to the fleet: translates an external A2A task into the hub's
* `POST /v1/tasks` (Conductor PRD RF5). Uses the orchestrator credential when
* set (CONDUCTOR_ORCHESTRATOR_TOKEN), falling back to the hub token. States
* flow back through the RF1 mirror — this call only creates.
*/
export async function createConductorTask(
input: DelegationInput,
opts: HubProxyOptions = {}
): Promise<{ ok: boolean; status: number; task_id?: string }> {
const cfg = hubConfig();
if (!cfg) return { ok: false, status: 503 };
const token = process.env.CONDUCTOR_ORCHESTRATOR_TOKEN?.trim() || cfg.token;
const body: Record<string, unknown> = {
repo: { url: input.repoUrl, base_ref: input.baseRef?.trim() || "main" },
spec: { prompt: input.prompt },
mode: input.mode?.trim() || "solo",
};
const requirements: Record<string, string> = {};
if (input.cli?.trim()) requirements.cli = input.cli.trim();
if (input.model?.trim()) requirements.model = input.model.trim();
if (Object.keys(requirements).length) body.requirements = requirements;
try {
const doFetch = opts.fetchImpl ?? fetch;
const res = await doFetch(`${cfg.url}/v1/tasks`, {
method: "POST",
headers: { authorization: `Bearer ${token}`, "content-type": "application/json" },
body: JSON.stringify(body),
});
if (!res.ok) return { ok: false, status: res.status };
const created = z.object({ id: z.string() }).parse(await res.json());
return { ok: true, status: res.status, task_id: created.id };
} catch {
return { ok: false, status: 503 };
}
}
/** Cancels a task on the hub. Returns the hub's verdict without leaking its body on error. */
export async function cancelConductorTask(

View File

@@ -70,9 +70,9 @@ export const webRuntimeEnvSchema = z.object({
BASE_URL: optionalHttpUrl,
NEXT_PUBLIC_BASE_URL: optionalHttpUrl,
CONDUCTOR_HUB_URL: optionalHttpUrl,
CONDUCTOR_SPOKESPERSON_URL: optionalHttpUrl,
CONDUCTOR_ORCHESTRATOR_TOKEN: optionalTrimmedString,
CONDUCTOR_SPOKESPERSON_URL: optionalHttpUrl,
.8.50
CONDUCTOR_HUB_TOKEN: optionalTrimmedString,
OMNIROUTE_PORT: optionalPortEnv,
API_PORT: optionalPortEnv,

View File

@@ -7,33 +7,6 @@ export const PROVIDER_ENDPOINTS = {
dgrid: "https://api.dgrid.ai/v1/chat/completions",
bai: "https://api.b.ai/v1/chat/completions",
qiniu: "https://api.qnaigc.com/v1/chat/completions",
"zylo-api": "https://api.zyloai.net/v1/chat/completions",
unorouter: "https://api.unorouter.com/v1/chat/completions",
poolside: "https://inference.poolside.ai/v1/chat/completions",
fastrouter: "https://api.fastrouter.ai/api/v1/chat/completions",
anyapi: "https://api.anyapi.ai/v1/chat/completions",
electronhub: "https://api.electronhub.ai/v1/chat/completions",
llmgateway: "https://api.llmgateway.io/v1/chat/completions",
"llm-kiwi": "https://api.llm.kiwi/v1/chat/completions",
literouter: "https://api.literouter.com/v1/chat/completions",
"mnn-ai": "https://api.mnnai.ru/v1/chat/completions",
"meganova-ai": "https://api.meganova.ai/v1/chat/completions",
mixlayer: "https://models.mixlayer.ai/v1/chat/completions",
speka: "https://speka.me/v1/chat/completions",
tokenreply: "https://api.tokenreply.com/v1/chat/completions",
"yolo-auto": "https://yolo-auto.com/v1/chat/completions",
dxnt: "https://www.dxnt.com/v1/chat/completions",
"cloudcode-one": "https://api.cloudcode.one/v1/chat/completions",
ofoxai: "https://api.ofox.ai/v1/chat/completions",
zerolimitai: "https://www.zerolimitai.com/api/v1/chat/completions",
chatanywhere: "https://api.chatanywhere.org/v1/chat/completions",
helyxai: "https://helyxai.space/v1/chat/completions",
auriko: "https://api.auriko.ai/v1/chat/completions",
"poixe-ai": "https://api.poixe.com/v1/chat/completions",
"naga-ai": "https://api.naga.ac/v1/chat/completions",
"chat-oripe": "https://api.oriper.com/v1/chat/completions",
freeinference: "https://freeinference.org/v1/chat/completions",
"free-ai": "https://api.free.ai/v1/chat/",
glm: "https://api.z.ai/api/anthropic/v1/messages",
glmt: "https://api.z.ai/api/anthropic/v1/messages",
"bailian-coding-plan": "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic/v1/messages",

View File

@@ -21,10 +21,7 @@ import { PROVIDER_MODELS as MODELS } from "@omniroute/open-sse/config/providerMo
const PASSTHROUGH_PROVIDERS = new Set(
Object.entries(AI_PROVIDERS)
.filter(([, p]) => (p as any).passthroughModels)
.flatMap(([key, provider]) => {
const alias = (provider as { alias?: unknown }).alias;
return typeof alias === "string" && alias.length > 0 ? [key, alias] : [key];
})
.map(([key]) => key)
);
// Wrap isValidModel with passthrough providers

View File

@@ -96,32 +96,7 @@ export const AGGREGATOR_PROVIDER_IDS = new Set([
"g4f-nvidia",
"naga-ac",
"chatanywhere",
"zylo-api",
"fastrouter",
"anyapi",
"electronhub",
"llmgateway",
"llm-kiwi",
"literouter",
"mnn-ai",
"meganova-ai",
"mixlayer",
"speka",
"tokenreply",
"yolo-auto",
"dxnt",
"cloudcode-one",
"ofoxai",
"zerolimitai",
"helyxai",
"auriko",
"poixe-ai",
"naga-ai",
"chat-oripe",
"freeinference",
"free-ai",
]);;
]);
export const ENTERPRISE_CLOUD_PROVIDER_IDS = new Set([
"azure-openai",

View File

@@ -53,9 +53,6 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
color: "#8B5CF6",
textIcon: "UR",
passthroughModels: true,
hasFree: true,
freeNote:
"Models with the :free suffix do not debit balance; limit is 1 request/minute per free model per user.",
website: "https://unorouter.ai",
apiHint: "Create an API key at https://unorouter.ai, then paste it here as a Bearer token.",
},
@@ -442,37 +439,6 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
apiHint:
"Use https://api.oriper.com/v1 only after confirming the provider's current documentation, terms and key issuance. No quota is guaranteed by this catalog.",
},
freeinference: {
id: "freeinference",
alias: "freeinference",
name: "FreeInference",
icon: "science",
color: "#8B5CF6",
textIcon: "FI",
passthroughModels: true,
website: "https://freeinference.org",
hasFree: true,
freeNote:
"Free research access without a card; non-Harvard applicants require manual approval and no numeric quota is publicly guaranteed.",
apiHint:
"Apply for a FreeInference key, then use https://freeinference.org/v1 as the OpenAI-compatible base URL. Terms allow prompt/response logging and possible publication of anonymized research data; never send sensitive or production data.",
},
"free-ai": {
id: "free-ai",
alias: "free-ai",
name: "Free.ai",
icon: "hub",
color: "#16A34A",
textIcon: "FA",
passthroughModels: true,
website: "https://free.ai",
hasFree: true,
freeNote:
"30,000 tokens/day cover self-hosted models after email verification. Usage beyond the pool can bill at raw cost, and premium external models are paid.",
apiHint:
"Create an sk-free- key, then use the nonstandard but OpenAI-shaped https://api.free.ai/v1/chat/ endpoint. Select a self-hosted zero-price model to stay within the free pool.",
},
dgrid: {
id: "dgrid",
alias: "dgrid",
@@ -1213,7 +1179,6 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
authHint: "Get your Regolo API key from regolo.ai, then paste it here as a Bearer token.",
apiHint:
"OpenAI-compatible endpoint at https://api.regolo.ai/v1 with dynamic model discovery (19 models).",
},
"naga-ac": {
id: "naga-ac",
alias: "naga",
@@ -1230,4 +1195,19 @@ export const APIKEY_PROVIDERS_GATEWAYS = {
authHint:
"Get API key at naga.ac — Google/GitHub/Discord signup available.",
},
chatanywhere: {
id: "chatanywhere",
alias: "chtany",
name: "ChatAnywhere",
icon: "chat",
color: "#10B981",
textIcon: "CA",
website: "https://api.chatanywhere.tech",
hasFree: true,
freeNote:
"Free tier: 5 req/day for GPT-5/4o/4.1, 30/day DeepSeek, 200/day gpt-4o-mini. Personal non-commercial use only — see chatanywhere/GPT_API_free. Requires GitHub-account-gated API key.",
passthroughModels: true,
authHint:
"Get free API key at api.chatanywhere.tech — requires GitHub account signup.",
},
};

View File

@@ -45,21 +45,6 @@ export const APIKEY_PROVIDERS_INFERENCE = {
hasFree: true,
freeNote: "Free plan: 3-day trial with open-source models — no credit card required",
},
poolside: {
id: "poolside",
alias: "poolside",
name: "Poolside",
icon: "memory",
color: "#111827",
textIcon: "PS",
passthroughModels: true,
website: "https://poolside.ai",
hasFree: true,
freeNote:
"Laguna S 2.1 and XS 2.1 are free during Preview; no public numeric quota is published.",
apiHint:
"Create a free developer API key, then use https://inference.poolside.ai/v1 as the OpenAI-compatible base URL.",
},
fireworks: {
id: "fireworks",
alias: "fireworks",

View File

@@ -6,7 +6,9 @@
import { test, after } from "node:test";
import assert from "node:assert/strict";
const { registerHook, unregisterHook } = await import("../../src/lib/plugins/hooks.ts");const { runPluginOnResponseHook, runPluginOnStreamCompleteHook } = await import("../../open-sse/handlers/chatCore/pluginOnResponse.ts");
const { registerHook, unregisterHook } = await import("../../src/lib/plugins/hooks.ts");
const { runPluginOnResponseHook } =
await import("../../open-sse/handlers/chatCore/pluginOnResponse.ts");
async function waitFor(pred: () => boolean, timeoutMs = 2000): Promise<void> {
const deadline = Date.now() + timeoutMs;
@@ -17,7 +19,6 @@ async function waitFor(pred: () => boolean, timeoutMs = 2000): Promise<void> {
after(() => {
unregisterHook("onResponse", "test-onresponse-plugin");
unregisterHook("onStreamComplete", "test-onstreamcomplete-plugin");
});
test("no registered hooks → resolves without throwing (no-op)", async () => {
@@ -142,140 +143,3 @@ test("a throwing hook never rejects the caller (fail-open)", async () => {
);
await new Promise((r) => setTimeout(r, 30));
});
// ── onStreamComplete hook tests (#9571) ──
test("onStreamComplete: no registered hooks resolves without throwing (no-op)", async () => {
const start = Date.now();
await assert.doesNotReject(
runPluginOnStreamCompleteHook({
status: 200,
usage: { prompt_tokens: 10, completion_tokens: 20 },
ttft: 150,
model: "gpt-4",
provider: "openai",
errorCode: undefined,
startTime: start - 500,
})
);
});
test("onStreamComplete: registered hook receives usage + timing payload", async () => {
let captured: Record<string, unknown> | undefined;
registerHook(
"onStreamComplete",
"test-onstreamcomplete-plugin",
async (payload: Record<string, unknown>) => {
captured = payload;
}
);
const startTime = Date.now() - 500;
await runPluginOnStreamCompleteHook({
status: 200,
usage: { prompt_tokens: 42, completion_tokens: 100, reasoning_tokens: 5 },
ttft: 200,
model: "claude-3-opus",
provider: "anthropic",
errorCode: undefined,
startTime,
});
await waitFor(() => captured !== undefined);
assert.ok(captured, "expected onStreamComplete hook to be invoked");
// payload shape: status, usage, timing, model, provider
assert.equal(captured!.status, 200);
assert.ok(captured!.usage, "usage should be present");
assert.equal((captured!.usage as Record<string, number>).prompt_tokens, 42);
assert.equal((captured!.usage as Record<string, number>).completion_tokens, 100);
assert.equal((captured!.usage as Record<string, number>).reasoning_tokens, 5);
assert.ok(captured!.timing, "timing should be present");
const timing = captured!.timing as Record<string, number>;
assert.equal(timing.ttft, 200);
assert.ok(timing.latencyMs > 450, "latencyMs should be near 500");
assert.equal(captured!.model, "claude-3-opus");
assert.equal(captured!.provider, "anthropic");
assert.equal(captured!.errorCode, undefined);
});
test("onStreamComplete: payload includes cache token fields when present", async () => {
let captured: Record<string, unknown> | undefined;
registerHook(
"onStreamComplete",
"test-onstreamcomplete-plugin",
async (payload: Record<string, unknown>) => {
captured = payload;
}
);
await runPluginOnStreamCompleteHook({
status: 200,
usage: {
prompt_tokens: 50,
completion_tokens: 30,
cache_read_input_tokens: 20,
cache_creation_input_tokens: 10,
},
ttft: 100,
model: "gpt-4",
provider: "openai",
errorCode: undefined,
startTime: Date.now(),
});
await waitFor(() => captured !== undefined);
assert.ok(captured);
const usage = captured!.usage as Record<string, number>;
assert.equal(usage.cache_read_input_tokens, 20);
assert.equal(usage.cache_creation_input_tokens, 10);
});
test("onStreamComplete: throwing hook never rejects the caller (fail-open)", async () => {
registerHook("onStreamComplete", "test-onstreamcomplete-plugin", async () => {
throw new Error("stream-complete-boom");
});
await assert.doesNotReject(
runPluginOnStreamCompleteHook({
status: 500,
usage: undefined,
ttft: undefined,
model: "gpt-4",
provider: "openai",
errorCode: "upstream_error",
startTime: Date.now(),
})
);
await new Promise((r) => setTimeout(r, 30));
});
test("onStreamComplete: errorCode is passed through when provided", async () => {
let captured: Record<string, unknown> | undefined;
registerHook(
"onStreamComplete",
"test-onstreamcomplete-plugin",
async (payload: Record<string, unknown>) => {
captured = payload;
}
);
await runPluginOnStreamCompleteHook({
status: 502,
usage: undefined,
ttft: undefined,
model: "grok-3",
provider: "xai",
errorCode: "upstream_timeout",
startTime: Date.now(),
});
await waitFor(() => captured !== undefined);
assert.ok(captured);
assert.equal(captured!.status, 502);
assert.equal(captured!.errorCode, "upstream_timeout");
assert.equal(captured!.model, "grok-3");
assert.equal(captured!.provider, "xai");
});

View File

@@ -1,112 +0,0 @@
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";
import { createServer, type Server } from "node:http";
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-conductor-a2a-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const settings = await import("../../src/lib/db/settings.ts");
const tasksRoute = await import("../../src/app/api/a2a/tasks/route.ts");
const servers: Server[] = [];
async function enableA2A() {
await settings.updateSettings({ a2aEnabled: true });
}
function delegationRequest(body: unknown, bearer?: string) {
return new Request("http://localhost/api/a2a/tasks", {
method: "POST",
headers: {
"content-type": "application/json",
...(bearer ? { authorization: `Bearer ${bearer}` } : {}),
},
body: JSON.stringify(body),
});
}
const VALID_BODY = {
skill: "conductor-cli-claude",
messages: [{ role: "user", content: "adicione um README com a seção Sobre" }],
metadata: { conductor: { repo: { url: "https://git.x/repo", base_ref: "dev" }, mode: "solo", model: "cc/claude-sonnet-5" } },
};
test.beforeEach(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
delete process.env.CONDUCTOR_HUB_URL;
delete process.env.OMNIROUTE_API_KEY;
});
test.after(async () => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
delete process.env.CONDUCTOR_HUB_URL;
delete process.env.OMNIROUTE_API_KEY;
while (servers.length > 0) {
const s = servers.pop();
await new Promise((resolve) => s?.close(resolve));
}
});
test("A2A desabilitado → 503 (mesmo gate do JSON-RPC)", async () => {
const res = await tasksRoute.POST(delegationRequest(VALID_BODY));
assert.equal(res.status, 503);
});
test("com OMNIROUTE_API_KEY configurada, bearer errado → 401 e bearer certo passa", async () => {
await enableA2A();
process.env.OMNIROUTE_API_KEY = "chave-certa";
const denied = await tasksRoute.POST(delegationRequest(VALID_BODY, "chave-errada"));
assert.equal(denied.status, 401);
});
test("delegação válida → 201 com o task_id do hub; requirements derivados da skill do card", async () => {
await enableA2A();
const bodies: unknown[] = [];
await new Promise<void>((resolve) => {
const server = createServer((req, res) => {
let raw = "";
req.on("data", (c) => (raw += c));
req.on("end", () => {
bodies.push(JSON.parse(raw));
res.writeHead(201, { "content-type": "application/json" });
res.end(JSON.stringify({ id: "t_delegada", status: "submitted" }));
});
});
servers.push(server);
server.listen(0, "127.0.0.1", () => {
const addr = server.address();
process.env.CONDUCTOR_HUB_URL = `http://127.0.0.1:${typeof addr === "object" && addr ? addr.port : 0}`;
resolve();
});
});
const res = await tasksRoute.POST(delegationRequest(VALID_BODY));
assert.equal(res.status, 201);
const out = await res.json();
assert.equal(out.conductor_task_id, "t_delegada");
assert.equal(out.state, "submitted");
const sent = bodies[0] as { repo: { url: string; base_ref: string }; spec: { prompt: string }; requirements: { cli: string; model: string } };
assert.equal(sent.repo.url, "https://git.x/repo");
assert.equal(sent.repo.base_ref, "dev");
assert.equal(sent.spec.prompt, "adicione um README com a seção Sobre");
assert.equal(sent.requirements.cli, "claude", "skill conductor-cli-claude vira requirements.cli");
assert.equal(sent.requirements.model, "cc/claude-sonnet-5");
});
test("sem repo na metadata → 400 (delegação exige repo); skill não-conductor → 400", async () => {
await enableA2A();
const noRepo = await tasksRoute.POST(
delegationRequest({ skill: "conductor", messages: [{ role: "user", content: "p" }] })
);
assert.equal(noRepo.status, 400);
const wrongSkill = await tasksRoute.POST(
delegationRequest({ ...VALID_BODY, skill: "smart-routing" })
);
assert.equal(wrongSkill.status, 400);
});

View File

@@ -1,71 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
import { createConductorTask } from "../../src/lib/conductor/hubProxy.ts";
function fakeHub(body: unknown, status = 201) {
const calls: { url: string; method: string; auth: string | null; body: unknown }[] = [];
const impl = (async (url: string | URL | Request, init?: RequestInit) => {
calls.push({
url: String(url),
method: init?.method ?? "GET",
auth: (init?.headers as Record<string, string> | undefined)?.authorization ?? null,
body: JSON.parse(String(init?.body ?? "{}")),
});
return new Response(JSON.stringify(body), { status });
}) as typeof fetch;
return { impl, calls };
}
test.beforeEach(() => {
process.env.CONDUCTOR_HUB_URL = "http://hub.test:7910";
process.env.CONDUCTOR_HUB_TOKEN = "tok-hub";
delete process.env.CONDUCTOR_ORCHESTRATOR_TOKEN;
});
test.after(() => {
delete process.env.CONDUCTOR_HUB_URL;
delete process.env.CONDUCTOR_HUB_TOKEN;
delete process.env.CONDUCTOR_ORCHESTRATOR_TOKEN;
});
test("traduz a delegação A2A no POST /v1/tasks do hub (shape exato do contrato)", async () => {
const { impl, calls } = fakeHub({ id: "t_novo", status: "submitted" });
const r = await createConductorTask(
{ repoUrl: "https://git.x/repo", baseRef: "dev", prompt: "adicione um README", mode: "council-3", cli: "claude", model: "cc/claude-sonnet-5" },
{ fetchImpl: impl }
);
assert.deepEqual(r, { ok: true, status: 201, task_id: "t_novo" });
assert.equal(calls[0].url, "http://hub.test:7910/v1/tasks");
assert.equal(calls[0].method, "POST");
assert.deepEqual(calls[0].body, {
repo: { url: "https://git.x/repo", base_ref: "dev" },
spec: { prompt: "adicione um README" },
mode: "council-3",
requirements: { cli: "claude", model: "cc/claude-sonnet-5" },
});
});
test("defaults: base_ref main, mode solo, sem requirements quando cli/model ausentes", async () => {
const { impl, calls } = fakeHub({ id: "t_d", status: "submitted" });
await createConductorTask({ repoUrl: "https://git.x/r", prompt: "p" }, { fetchImpl: impl });
assert.deepEqual(calls[0].body, { repo: { url: "https://git.x/r", base_ref: "main" }, spec: { prompt: "p" }, mode: "solo" });
});
test("credencial: prefere CONDUCTOR_ORCHESTRATOR_TOKEN; fallback é o token do hub", async () => {
const a = fakeHub({ id: "t_1" });
await createConductorTask({ repoUrl: "https://x/r", prompt: "p" }, { fetchImpl: a.impl });
assert.equal(a.calls[0].auth, "Bearer tok-hub");
process.env.CONDUCTOR_ORCHESTRATOR_TOKEN = "tok-orch";
const b = fakeHub({ id: "t_2" });
await createConductorTask({ repoUrl: "https://x/r", prompt: "p" }, { fetchImpl: b.impl });
assert.equal(b.calls[0].auth, "Bearer tok-orch");
});
test("recusa do hub → {ok:false, status} sem lançar nem vazar corpo; env ausente → 503", async () => {
const { impl } = fakeHub({ error: "segredo do hub" }, 422);
const r = await createConductorTask({ repoUrl: "https://x/r", prompt: "p" }, { fetchImpl: impl });
assert.deepEqual(r, { ok: false, status: 422 });
delete process.env.CONDUCTOR_HUB_URL;
assert.deepEqual(await createConductorTask({ repoUrl: "https://x/r", prompt: "p" }, {}), { ok: false, status: 503 });
});

View File

@@ -1,55 +0,0 @@
import assert from "node:assert/strict";
import test from "node:test";
const { REGISTRY } = await import("../../open-sse/config/providerRegistry.ts");
const { DefaultExecutor, getExecutor } = await import("../../open-sse/executors/index.ts");
const { PROVIDER_ENDPOINTS } = await import("../../src/shared/constants/config.ts");
const { isValidModel } = await import("../../src/shared/constants/models.ts");
const { AGGREGATOR_PROVIDER_IDS } = await import("../../src/shared/constants/providers.ts");
const { APIKEY_PROVIDERS } = await import("../../src/shared/constants/providers/apikey/index.ts");
const providers = [
["zylo-api", "zylo", "https://api.zyloai.net/v1/chat/completions"],
["unorouter", "unorouter", "https://api.unorouter.com/v1/chat/completions"],
["poolside", "poolside", "https://inference.poolside.ai/v1/chat/completions"],
["fastrouter", "fastrouter", "https://api.fastrouter.ai/api/v1/chat/completions"],
["anyapi", "anyapi", "https://api.anyapi.ai/v1/chat/completions"],
["electronhub", "electronhub", "https://api.electronhub.ai/v1/chat/completions"],
["llmgateway", "llmgateway", "https://api.llmgateway.io/v1/chat/completions"],
["llm-kiwi", "llmkiwi", "https://api.llm.kiwi/v1/chat/completions"],
] as const;
for (const [id, alias, endpoint] of providers) {
test(`${id} is wired through registry, metadata, endpoint and default executor`, () => {
const registry = REGISTRY[id];
const metadata = APIKEY_PROVIDERS[id];
assert.ok(registry);
assert.ok(metadata);
assert.equal(registry.id, id);
assert.equal(registry.alias, alias);
assert.equal(registry.baseUrl, endpoint);
assert.equal(PROVIDER_ENDPOINTS[id], endpoint);
assert.equal(metadata.id, id);
assert.equal(metadata.alias, alias);
assert.equal(metadata.hasFree, true);
assert.equal(metadata.passthroughModels, true);
assert.ok(typeof metadata.freeNote === "string" && metadata.freeNote.length > 0);
assert.ok(getExecutor(id) instanceof DefaultExecutor);
assert.equal(isValidModel(id, "future/live-catalog-model"), true);
assert.equal(isValidModel(alias, "future/live-catalog-model"), true);
});
}
test("gateway providers are classified as aggregators while direct Poolside is not", () => {
const gatewayIds = providers.map(([id]) => id).filter((id) => id !== "poolside");
for (const id of gatewayIds) assert.equal(AGGREGATOR_PROVIDER_IDS.has(id), true);
assert.equal(AGGREGATOR_PROVIDER_IDS.has("poolside"), false);
});
test("LLM.Kiwi statically exposes only the confirmed Free plan models", () => {
assert.deepEqual(REGISTRY["llm-kiwi"].models, [
{ id: "auto", name: "Auto" },
{ id: "hrLLM", name: "hrLLM" },
]);
});

View File

@@ -1,51 +0,0 @@
import assert from "node:assert/strict";
import test from "node:test";
import { literouterProvider } from "../../open-sse/config/providers/registry/literouter/index.ts";
import { meganovaAiProvider } from "../../open-sse/config/providers/registry/meganova-ai/index.ts";
import { mnnAiProvider } from "../../open-sse/config/providers/registry/mnn-ai/index.ts";
import type { RegistryEntry } from "../../open-sse/config/providers/shared.ts";
const providers: Array<{
entry: RegistryEntry;
id: string;
chatUrl: string;
modelsUrl: string;
}> = [
{
entry: literouterProvider,
id: "literouter",
chatUrl: "https://api.literouter.com/v1/chat/completions",
modelsUrl: "https://api.literouter.com/v1/models",
},
{
entry: mnnAiProvider,
id: "mnn-ai",
chatUrl: "https://api.mnnai.ru/v1/chat/completions",
modelsUrl: "https://api.mnnai.ru/v1/models",
},
{
entry: meganovaAiProvider,
id: "meganova-ai",
chatUrl: "https://api.meganova.ai/v1/chat/completions",
modelsUrl: "https://api.meganova.ai/v1/models",
},
];
for (const { entry, id, chatUrl, modelsUrl } of providers) {
test(`${id} uses an OpenAI-compatible Bearer registry entry`, () => {
assert.equal(entry.id, id);
assert.equal(entry.alias, id);
assert.equal(entry.format, "openai");
assert.equal(entry.executor, "default");
assert.equal(entry.authType, "apikey");
assert.equal(entry.authHeader, "bearer");
assert.equal(entry.baseUrl, chatUrl);
assert.equal(entry.modelsUrl, modelsUrl);
assert.equal(entry.passthroughModels, true);
});
test(`${id} leaves model discovery to the live upstream catalog`, () => {
assert.deepEqual(entry.models, []);
});
}

View File

@@ -1,60 +0,0 @@
import assert from "node:assert/strict";
import test from "node:test";
import { mixlayerProvider } from "../../open-sse/config/providers/registry/mixlayer/index.ts";
import { spekaProvider } from "../../open-sse/config/providers/registry/speka/index.ts";
import { tokenreplyProvider } from "../../open-sse/config/providers/registry/tokenreply/index.ts";
import type { RegistryEntry } from "../../open-sse/config/providers/shared.ts";
const providers: Array<{
entry: RegistryEntry;
id: string;
chatUrl: string;
modelsUrl: string;
}> = [
{
entry: mixlayerProvider,
id: "mixlayer",
chatUrl: "https://models.mixlayer.ai/v1/chat/completions",
modelsUrl: "https://models.mixlayer.ai/v1/models",
},
{
entry: spekaProvider,
id: "speka",
chatUrl: "https://speka.me/v1/chat/completions",
modelsUrl: "https://speka.me/v1/models",
},
{
entry: tokenreplyProvider,
id: "tokenreply",
chatUrl: "https://api.tokenreply.com/v1/chat/completions",
modelsUrl: "https://api.tokenreply.com/v1/models",
},
];
test("Wave 2-B providers expose OpenAI-compatible Bearer registries", () => {
for (const { entry, id, chatUrl, modelsUrl } of providers) {
assert.equal(entry.id, id);
assert.equal(entry.alias, id);
assert.equal(entry.format, "openai");
assert.equal(entry.executor, "default");
assert.equal(entry.authType, "apikey");
assert.equal(entry.authHeader, "bearer");
assert.equal(entry.baseUrl, chatUrl);
assert.equal(entry.modelsUrl, modelsUrl);
assert.equal(entry.passthroughModels, true);
assert.ok(Array.isArray(entry.models));
}
});
test("Mixlayer seeds only its documented free model", () => {
assert.deepEqual(
mixlayerProvider.models.map((model) => model.id),
["qwen/qwen3.5-4b-free"]
);
});
test("Speka and TokenReply rely on live model catalogs without invented models", () => {
assert.deepEqual(spekaProvider.models, []);
assert.deepEqual(tokenreplyProvider.models, []);
});

View File

@@ -1,58 +0,0 @@
import assert from "node:assert/strict";
import test from "node:test";
import { cloudcodeOneProvider } from "../../open-sse/config/providers/registry/cloudcode-one/index.ts";
import { dxntProvider } from "../../open-sse/config/providers/registry/dxnt/index.ts";
import { yoloAutoProvider } from "../../open-sse/config/providers/registry/yolo-auto/index.ts";
import type { RegistryEntry } from "../../open-sse/config/providers/shared.ts";
const providers: Array<{
entry: RegistryEntry;
id: string;
chatUrl: string;
modelsUrl: string;
modelIds: string[];
}> = [
{
entry: yoloAutoProvider,
id: "yolo-auto",
chatUrl: "https://yolo-auto.com/v1/chat/completions",
modelsUrl: "https://yolo-auto.com/v1/models",
modelIds: ["qwen3.6-35b-a3b"],
},
{
entry: dxntProvider,
id: "dxnt",
chatUrl: "https://www.dxnt.com/v1/chat/completions",
modelsUrl: "https://www.dxnt.com/v1/models",
modelIds: [],
},
{
entry: cloudcodeOneProvider,
id: "cloudcode-one",
chatUrl: "https://api.cloudcode.one/v1/chat/completions",
modelsUrl: "https://api.cloudcode.one/v1/models",
modelIds: ["glm-4.7-flash", "glm-4.6v-flash"],
},
];
for (const { entry, id, chatUrl, modelsUrl, modelIds } of providers) {
test(`${id} uses the standard OpenAI-compatible API-key registry shape`, () => {
assert.equal(entry.id, id);
assert.equal(entry.alias, id);
assert.equal(entry.format, "openai");
assert.equal(entry.executor, "default");
assert.equal(entry.authType, "apikey");
assert.equal(entry.authHeader, "bearer");
assert.equal(entry.baseUrl, chatUrl);
assert.equal(entry.modelsUrl, modelsUrl);
assert.equal(entry.passthroughModels, true);
});
test(`${id} seeds only the audited model identifiers`, () => {
assert.deepEqual(
(entry.models ?? []).map((model) => model.id),
modelIds
);
});
}

View File

@@ -1,60 +0,0 @@
import assert from "node:assert/strict";
import test from "node:test";
const { REGISTRY } = await import("../../open-sse/config/providerRegistry.ts");
const { DefaultExecutor, getExecutor } = await import("../../open-sse/executors/index.ts");
const { PROVIDER_ENDPOINTS } = await import("../../src/shared/constants/config.ts");
const { isValidModel } = await import("../../src/shared/constants/models.ts");
const { AGGREGATOR_PROVIDER_IDS } = await import("../../src/shared/constants/providers.ts");
const { APIKEY_PROVIDERS } = await import("../../src/shared/constants/providers/apikey/index.ts");
const providers = [
["literouter", "https://api.literouter.com/v1/chat/completions", []],
["mnn-ai", "https://api.mnnai.ru/v1/chat/completions", []],
["meganova-ai", "https://api.meganova.ai/v1/chat/completions", []],
["mixlayer", "https://models.mixlayer.ai/v1/chat/completions", ["qwen/qwen3.5-4b-free"]],
["speka", "https://speka.me/v1/chat/completions", []],
["tokenreply", "https://api.tokenreply.com/v1/chat/completions", []],
["yolo-auto", "https://yolo-auto.com/v1/chat/completions", ["qwen3.6-35b-a3b"]],
["dxnt", "https://www.dxnt.com/v1/chat/completions", []],
[
"cloudcode-one",
"https://api.cloudcode.one/v1/chat/completions",
["glm-4.7-flash", "glm-4.6v-flash"],
],
] as const;
for (const [id, endpoint, modelIds] of providers) {
test(`${id} is wired through registry, metadata, endpoint and default executor`, () => {
const registry = REGISTRY[id];
const metadata = APIKEY_PROVIDERS[id];
assert.ok(registry);
assert.ok(metadata);
assert.equal(registry.id, id);
assert.equal(registry.alias, id);
assert.equal(registry.baseUrl, endpoint);
assert.equal(PROVIDER_ENDPOINTS[id], endpoint);
assert.equal(metadata.id, id);
assert.equal(metadata.alias, id);
assert.equal(metadata.hasFree, true);
assert.equal(metadata.passthroughModels, true);
assert.ok(typeof metadata.freeNote === "string" && metadata.freeNote.length > 0);
assert.equal(AGGREGATOR_PROVIDER_IDS.has(id), true);
assert.ok(getExecutor(id) instanceof DefaultExecutor);
assert.equal(isValidModel(id, "future/live-catalog-model"), true);
assert.deepEqual(
registry.models.map((model) => model.id),
modelIds
);
});
}
test("risk-sensitive metadata preserves the audited quota qualifications", () => {
assert.match(APIKEY_PROVIDERS["mnn-ai"].apiHint ?? "", /jurisdiction.*privacy/i);
assert.match(APIKEY_PROVIDERS["meganova-ai"].freeNote ?? "", /per-model quotas/i);
assert.match(APIKEY_PROVIDERS["meganova-ai"].freeNote ?? "", /paid overage/i);
assert.match(APIKEY_PROVIDERS.tokenreply.freeNote ?? "", /no fixed global free quota/i);
assert.match(APIKEY_PROVIDERS["yolo-auto"].freeNote ?? "", /no numeric daily quota/i);
assert.match(APIKEY_PROVIDERS["cloudcode-one"].freeNote ?? "", /credit or a coupon/i);
});

View File

@@ -1,48 +0,0 @@
import assert from "node:assert/strict";
import test from "node:test";
import { chatanywhereProvider } from "../../open-sse/config/providers/registry/chatanywhere/index.ts";
import { ofoxaiProvider } from "../../open-sse/config/providers/registry/ofoxai/index.ts";
import { zerolimitaiProvider } from "../../open-sse/config/providers/registry/zerolimitai/index.ts";
import type { RegistryEntry } from "../../open-sse/config/providers/shared.ts";
const providers: Array<{
entry: RegistryEntry;
id: string;
chatUrl: string;
modelsUrl: string;
}> = [
{
entry: ofoxaiProvider,
id: "ofoxai",
chatUrl: "https://api.ofox.ai/v1/chat/completions",
modelsUrl: "https://api.ofox.ai/v1/models",
},
{
entry: zerolimitaiProvider,
id: "zerolimitai",
chatUrl: "https://www.zerolimitai.com/api/v1/chat/completions",
modelsUrl: "https://www.zerolimitai.com/api/v1/models",
},
{
entry: chatanywhereProvider,
id: "chatanywhere",
chatUrl: "https://api.chatanywhere.org/v1/chat/completions",
modelsUrl: "https://api.chatanywhere.org/v1/models",
},
];
test("Wave 3-A providers expose OpenAI-compatible Bearer registries", () => {
for (const { entry, id, chatUrl, modelsUrl } of providers) {
assert.equal(entry.id, id);
assert.equal(entry.alias, id);
assert.equal(entry.format, "openai");
assert.equal(entry.executor, "default");
assert.equal(entry.authType, "apikey");
assert.equal(entry.authHeader, "bearer");
assert.equal(entry.baseUrl, chatUrl);
assert.equal(entry.modelsUrl, modelsUrl);
assert.equal(entry.passthroughModels, true);
assert.deepEqual(entry.models, []);
}
});

View File

@@ -1,53 +0,0 @@
import assert from "node:assert/strict";
import test from "node:test";
import { aurikoProvider } from "../../open-sse/config/providers/registry/auriko/index.ts";
import { helyxaiProvider } from "../../open-sse/config/providers/registry/helyxai/index.ts";
import { poixeAiProvider } from "../../open-sse/config/providers/registry/poixe-ai/index.ts";
import type { RegistryEntry } from "../../open-sse/config/providers/shared.ts";
const providers: Array<{
entry: RegistryEntry;
id: string;
chatUrl: string;
modelsUrl: string;
}> = [
{
entry: helyxaiProvider,
id: "helyxai",
chatUrl: "https://helyxai.space/v1/chat/completions",
modelsUrl: "https://helyxai.space/v1/models",
},
{
entry: aurikoProvider,
id: "auriko",
chatUrl: "https://api.auriko.ai/v1/chat/completions",
modelsUrl: "https://api.auriko.ai/v1/models",
},
{
entry: poixeAiProvider,
id: "poixe-ai",
chatUrl: "https://api.poixe.com/v1/chat/completions",
modelsUrl: "https://api.poixe.com/v1/models",
},
];
test("Wave 3-B providers expose OpenAI-compatible Bearer registries", () => {
for (const { entry, id, chatUrl, modelsUrl } of providers) {
assert.equal(entry.id, id);
assert.equal(entry.alias, id);
assert.equal(entry.format, "openai");
assert.equal(entry.executor, "default");
assert.equal(entry.authType, "apikey");
assert.equal(entry.authHeader, "bearer");
assert.equal(entry.baseUrl, chatUrl);
assert.equal(entry.modelsUrl, modelsUrl);
assert.equal(entry.passthroughModels, true);
}
});
test("Wave 3-B providers rely on live catalogs without invented models", () => {
for (const { entry } of providers) {
assert.deepEqual(entry.models, []);
}
});

View File

@@ -1,41 +0,0 @@
import assert from "node:assert/strict";
import test from "node:test";
import { chatOripeProvider } from "../../open-sse/config/providers/registry/chat-oripe/index.ts";
import { nagaAiProvider } from "../../open-sse/config/providers/registry/naga-ai/index.ts";
import type { RegistryEntry } from "../../open-sse/config/providers/shared.ts";
const providers: Array<{
entry: RegistryEntry;
id: string;
chatUrl: string;
modelsUrl: string;
}> = [
{
entry: nagaAiProvider,
id: "naga-ai",
chatUrl: "https://api.naga.ac/v1/chat/completions",
modelsUrl: "https://api.naga.ac/v1/models",
},
{
entry: chatOripeProvider,
id: "chat-oripe",
chatUrl: "https://api.oriper.com/v1/chat/completions",
modelsUrl: "https://api.oriper.com/v1/models",
},
];
test("Wave 3-C providers expose OpenAI-compatible Bearer registries", () => {
for (const { entry, id, chatUrl, modelsUrl } of providers) {
assert.equal(entry.id, id);
assert.equal(entry.alias, id);
assert.equal(entry.format, "openai");
assert.equal(entry.executor, "default");
assert.equal(entry.authType, "apikey");
assert.equal(entry.authHeader, "bearer");
assert.equal(entry.baseUrl, chatUrl);
assert.equal(entry.modelsUrl, modelsUrl);
assert.equal(entry.passthroughModels, true);
assert.deepEqual(entry.models, []);
}
});

View File

@@ -1,53 +0,0 @@
import assert from "node:assert/strict";
import test from "node:test";
const { REGISTRY } = await import("../../open-sse/config/providerRegistry.ts");
const { DefaultExecutor, getExecutor } = await import("../../open-sse/executors/index.ts");
const { PROVIDER_ENDPOINTS } = await import("../../src/shared/constants/config.ts");
const { isValidModel } = await import("../../src/shared/constants/models.ts");
const { AGGREGATOR_PROVIDER_IDS } = await import("../../src/shared/constants/providers.ts");
const { APIKEY_PROVIDERS } = await import("../../src/shared/constants/providers/apikey/index.ts");
const providers = [
["ofoxai", "https://api.ofox.ai/v1/chat/completions"],
["zerolimitai", "https://www.zerolimitai.com/api/v1/chat/completions"],
["chatanywhere", "https://api.chatanywhere.org/v1/chat/completions"],
["helyxai", "https://helyxai.space/v1/chat/completions"],
["auriko", "https://api.auriko.ai/v1/chat/completions"],
["poixe-ai", "https://api.poixe.com/v1/chat/completions"],
["naga-ai", "https://api.naga.ac/v1/chat/completions"],
["chat-oripe", "https://api.oriper.com/v1/chat/completions"],
] as const;
for (const [id, endpoint] of providers) {
test(`${id} is wired through registry, metadata, endpoint and default executor`, () => {
const registry = REGISTRY[id];
const metadata = APIKEY_PROVIDERS[id];
assert.ok(registry);
assert.ok(metadata);
assert.equal(registry.id, id);
assert.equal(registry.alias, id);
assert.equal(registry.baseUrl, endpoint);
assert.equal(PROVIDER_ENDPOINTS[id], endpoint);
assert.equal(metadata.id, id);
assert.equal(metadata.alias, id);
assert.equal(metadata.hasFree, true);
assert.equal(metadata.passthroughModels, true);
assert.ok(typeof metadata.freeNote === "string" && metadata.freeNote.length > 0);
assert.equal(AGGREGATOR_PROVIDER_IDS.has(id), true);
assert.ok(getExecutor(id) instanceof DefaultExecutor);
assert.equal(isValidModel(id, "future/live-catalog-model"), true);
assert.deepEqual(registry.models, []);
});
}
test("Wave 3 metadata preserves the audited legal, quota and privacy warnings", () => {
assert.match(APIKEY_PROVIDERS.chatanywhere.freeNote ?? "", /commercial traffic/i);
assert.match(APIKEY_PROVIDERS.zerolimitai.freeNote ?? "", /3 and 7 days/i);
assert.match(APIKEY_PROVIDERS.helyxai.freeNote ?? "", /100,000 tokens\/day/i);
assert.match(APIKEY_PROVIDERS.auriko.freeNote ?? "", /not a free-token pool/i);
assert.match(APIKEY_PROVIDERS["poixe-ai"].freeNote ?? "", /2 RPM\/5 RPD/i);
assert.match(APIKEY_PROVIDERS["naga-ai"].freeNote ?? "", /training/i);
assert.match(APIKEY_PROVIDERS["chat-oripe"].freeNote ?? "", /unconfirmed/i);
});

View File

@@ -1,27 +0,0 @@
import assert from "node:assert/strict";
import test from "node:test";
import { freeinferenceProvider } from "../../open-sse/config/providers/registry/freeinference/index.ts";
import {
DefaultExecutor,
getExecutor,
hasSpecializedExecutor,
} from "../../open-sse/executors/index.ts";
test("FreeInference exposes an OpenAI-compatible Bearer registry", () => {
assert.equal(freeinferenceProvider.id, "freeinference");
assert.equal(freeinferenceProvider.alias, "freeinference");
assert.equal(freeinferenceProvider.format, "openai");
assert.equal(freeinferenceProvider.executor, "default");
assert.equal(freeinferenceProvider.authType, "apikey");
assert.equal(freeinferenceProvider.authHeader, "bearer");
assert.equal(freeinferenceProvider.baseUrl, "https://freeinference.org/v1/chat/completions");
assert.equal(freeinferenceProvider.modelsUrl, "https://freeinference.org/v1/models");
assert.deepEqual(freeinferenceProvider.models, []);
assert.equal(freeinferenceProvider.passthroughModels, true);
});
test("FreeInference uses DefaultExecutor without specialized behavior", () => {
assert.equal(hasSpecializedExecutor("freeinference"), false);
assert.ok(getExecutor("freeinference") instanceof DefaultExecutor);
});

View File

@@ -1,27 +0,0 @@
import assert from "node:assert/strict";
import test from "node:test";
import { freeAiProvider } from "../../open-sse/config/providers/registry/free-ai/index.ts";
import {
DefaultExecutor,
getExecutor,
hasSpecializedExecutor,
} from "../../open-sse/executors/index.ts";
test("Free.ai exposes its exact OpenAI-compatible endpoint and live catalog", () => {
assert.equal(freeAiProvider.id, "free-ai");
assert.equal(freeAiProvider.alias, "free-ai");
assert.equal(freeAiProvider.format, "openai");
assert.equal(freeAiProvider.executor, "default");
assert.equal(freeAiProvider.authType, "apikey");
assert.equal(freeAiProvider.authHeader, "bearer");
assert.equal(freeAiProvider.baseUrl, "https://api.free.ai/v1/chat/");
assert.equal(freeAiProvider.modelsUrl, "https://api.free.ai/v1/models");
assert.deepEqual(freeAiProvider.models, []);
assert.equal(freeAiProvider.passthroughModels, true);
});
test("Free.ai uses DefaultExecutor without a specialized executor", () => {
assert.ok(getExecutor("free-ai") instanceof DefaultExecutor);
assert.equal(hasSpecializedExecutor("free-ai"), false);
});

View File

@@ -1,64 +0,0 @@
import assert from "node:assert/strict";
import test from "node:test";
import { deriveConfigFromRegistryModelsUrl } from "../../src/app/api/providers/[id]/models/discoveryConfig.ts";
const { REGISTRY } = await import("../../open-sse/config/providerRegistry.ts");
const { DefaultExecutor, getExecutor, hasSpecializedExecutor } =
await import("../../open-sse/executors/index.ts");
const { PROVIDER_ENDPOINTS } = await import("../../src/shared/constants/config.ts");
const { isValidModel } = await import("../../src/shared/constants/models.ts");
const { AGGREGATOR_PROVIDER_IDS } = await import("../../src/shared/constants/providers.ts");
const { APIKEY_PROVIDERS } = await import("../../src/shared/constants/providers/apikey/index.ts");
const providers = [
["freeinference", "https://freeinference.org/v1/chat/completions"],
["free-ai", "https://api.free.ai/v1/chat/"],
] as const;
for (const [id, endpoint] of providers) {
test(`${id} is fully wired without a specialized executor`, () => {
const registry = REGISTRY[id];
const metadata = APIKEY_PROVIDERS[id];
assert.ok(registry);
assert.ok(metadata);
assert.equal(registry.id, id);
assert.equal(registry.alias, id);
assert.equal(registry.baseUrl, endpoint);
assert.equal(PROVIDER_ENDPOINTS[id], endpoint);
assert.equal(metadata.id, id);
assert.equal(metadata.alias, id);
assert.equal(metadata.hasFree, true);
assert.equal(metadata.passthroughModels, true);
assert.equal(AGGREGATOR_PROVIDER_IDS.has(id), true);
assert.equal(hasSpecializedExecutor(id), false);
const executor = getExecutor(id);
assert.ok(executor instanceof DefaultExecutor);
assert.equal(executor.buildUrl("live-model", false), endpoint);
assert.equal(isValidModel(id, "future/live-catalog-model"), true);
assert.deepEqual(registry.models, []);
});
}
test("Wave 4 model discovery accepts both public catalog response envelopes", () => {
const freeInferenceDiscovery = deriveConfigFromRegistryModelsUrl("freeinference");
const freeAiDiscovery = deriveConfigFromRegistryModelsUrl("free-ai");
assert.ok(freeInferenceDiscovery);
assert.ok(freeAiDiscovery);
assert.deepEqual(freeInferenceDiscovery.parseResponse({ data: [{ id: "glm-5.1" }] }), [
{ id: "glm-5.1" },
]);
assert.deepEqual(freeAiDiscovery.parseResponse({ models: [{ id: "qwen7b" }] }), [
{ id: "qwen7b" },
]);
});
test("Wave 4 metadata preserves approval, logging and overage warnings", () => {
assert.match(APIKEY_PROVIDERS.freeinference.freeNote ?? "", /manual approval/i);
assert.match(APIKEY_PROVIDERS.freeinference.apiHint ?? "", /logging/i);
assert.match(APIKEY_PROVIDERS["free-ai"].freeNote ?? "", /30,000 tokens\/day/i);
assert.match(APIKEY_PROVIDERS["free-ai"].freeNote ?? "", /premium external models are paid/i);
assert.match(APIKEY_PROVIDERS["free-ai"].apiHint ?? "", /\/v1\/chat\//i);
});

View File

@@ -1,15 +0,0 @@
import assert from "node:assert/strict";
import test from "node:test";
const { isValidModel } = await import("../../src/shared/constants/models.ts");
test("passthrough providers accept live model ids through both provider id and alias", () => {
for (const [id, alias] of [
["zylo-api", "zylo"],
["llm-kiwi", "llmkiwi"],
["freetheai", "fta"],
] as const) {
assert.equal(isValidModel(id, "future/live-catalog-model"), true);
assert.equal(isValidModel(alias, "future/live-catalog-model"), true);
}
});

View File

@@ -1,57 +0,0 @@
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { join } from "node:path";
import test from "node:test";
const REPO_ROOT = join(import.meta.dirname, "..", "..");
/**
* Regression guards for the CodeQL alerts triaged on 2026-08-12.
*
* Both are source-level invariants rather than behavioral round-trips: the functions they
* protect are module-private (`decodeXmlText`) or only reachable through a live upstream
* handshake (`tinycms` nonce), so the guard asserts the property on the source itself.
*/
test("decodeXmlText decodes &amp; last so encoded entities do not double-unescape", () => {
const source = readFileSync(
join(REPO_ROOT, "open-sse/vendor/codex-chatgpt-web/adapters/chatgpt-web/environment.ts"),
"utf8"
);
const body = /function decodeXmlText\(value: string\): string \{([\s\S]*?)\n\}/.exec(source)?.[1];
assert.ok(body, "decodeXmlText not found — update this guard if the helper was renamed");
const order = [...body.matchAll(/replaceAll\("(&[^"]+;)"/g)].map((match) => match[1]);
assert.ok(order.length >= 2, `expected several entity replacements, got ${order.length}`);
assert.equal(
order.at(-1),
"&amp;",
`"&amp;" must be the LAST entity decoded, otherwise "&amp;quot;" decodes to '"' instead ` +
`of the literal "&quot;". Current order: ${order.join(" -> ")}`
);
// Mirror the implementation to document the property the ordering buys us.
const decode = (value: string) =>
order.reduce((acc, entity) => {
const plain = { "&lt;": "<", "&gt;": ">", "&quot;": '"', "&#39;": "'", "&amp;": "&" }[entity];
return plain === undefined ? acc : acc.replaceAll(entity, plain);
}, value);
assert.equal(decode("&amp;quot;"), "&quot;");
assert.equal(decode("&amp;#39;"), "&#39;");
assert.equal(decode("&amp;lt;"), "&lt;");
});
test("tinycms signs its anti-replay nonce with a CSPRNG, never Math.random", () => {
const source = readFileSync(join(REPO_ROOT, "open-sse/executors/tinycms.ts"), "utf8");
assert.match(
source,
/const nonceJs = randomUUID\(\)/,
"the tinycms nonce must come from node:crypto randomUUID"
);
assert.doesNotMatch(
source,
/Math\.random\(\)/,
"Math.random() is not a CSPRNG — the nonce is signed into the anti-replay payload"
);
});