mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-25 16:42:16 +03:00
feat(volcengine): switch Agent Plan discovery to ListAgentPlanLatestModel
This commit is contained in:
committed by
Markus Hartung
parent
34150506f2
commit
07a378c86c
@@ -7,13 +7,16 @@
|
||||
* top-level Ark actions, authenticated by the same console cookie + csrf
|
||||
* token already captured during plan binding (see volcenginePlanBinding.ts).
|
||||
*
|
||||
* - Agent Plan: `GetAgentPlanModelMappingMeta` → Result.Data[]
|
||||
* filter: platform-enabled LLMs plus API-verified canonical registry IDs
|
||||
* id : RespModelID (already version-suffixed, matches chat endpoint)
|
||||
* - Agent Plan: `ListAgentPlanLatestModel` → Result.Data[]
|
||||
* id : ModelId (version-suffixed, matches chat endpoint)
|
||||
* - Coding Plan: `ListArkCodeLatestModel` → Result.Data[]
|
||||
* id : ModelId (version-suffixed)
|
||||
*
|
||||
* The console API returns only id/name/version/description — NOT capabilities
|
||||
* Both APIs return the same response shape (ModelId / OutputName / Enabled /
|
||||
* Description / EnabledThinking). We keep ALL entries — the chat endpoint
|
||||
* accepts every listed ModelId, and `Enabled` only reflects console visibility.
|
||||
*
|
||||
* The console API returns only id/name/description — NOT capabilities
|
||||
* (contextLength, toolCalling, vision, reasoning). We enrich each discovered
|
||||
* model from a static family→capability map keyed by the OutputName/ModelName
|
||||
* prefix, falling back to conservative defaults so new families stay usable
|
||||
@@ -23,8 +26,6 @@
|
||||
* persist it via replaceSyncedAvailableModelsForConnection.
|
||||
*/
|
||||
|
||||
import { VOLCENGINE_AGENT_PLAN_MODELS } from "@omniroute/open-sse/config/providers/registry/volcengine/agent-plan/index.ts";
|
||||
|
||||
import type { SyncedAvailableModelInput } from "@/lib/db/models/synced";
|
||||
|
||||
type JsonRecord = Record<string, unknown>;
|
||||
@@ -128,8 +129,8 @@ const PLAN_DISCOVERY_CONFIG: Record<
|
||||
}
|
||||
> = {
|
||||
agent: {
|
||||
action: "GetAgentPlanModelMappingMeta",
|
||||
payload: { Edition: "agent_plan_personal" },
|
||||
action: "ListAgentPlanLatestModel",
|
||||
payload: {},
|
||||
referer: AGENT_PLAN_REFERER,
|
||||
requiresAccountId: false,
|
||||
},
|
||||
@@ -301,48 +302,20 @@ export function enrichModel(model: DiscoveredVolcModel): SyncedAvailableModelInp
|
||||
};
|
||||
}
|
||||
|
||||
const AGENT_PLAN_API_VERIFIED_IDS = new Set(VOLCENGINE_AGENT_PLAN_MODELS.map((model) => model.id));
|
||||
|
||||
/**
|
||||
* Parse Agent Plan `GetAgentPlanModelMappingMeta` Result.Data[].
|
||||
* Parse `ListAgentPlanLatestModel` / `ListArkCodeLatestModel` Result.Data[].
|
||||
*
|
||||
* `PlatformAllowStatus` controls console platform visibility/mapping; it is
|
||||
* NOT an API availability flag. Some canonical Agent Plan chat models (for
|
||||
* example kimi-k3) are returned with `PlatformAllowStatus=false`, `Type` and
|
||||
* display metadata unset, while `/api/plan/v3/chat/completions` accepts them.
|
||||
* Keep those only when they are in the API-verified canonical registry. This
|
||||
* avoids admitting the same response's media models, auto-router, and legacy
|
||||
* aliases while still allowing newly platform-enabled LLMs to be discovered.
|
||||
* Both console APIs return the same response shape: each entry has
|
||||
* `ModelId` (the version-suffixed ID accepted by the chat endpoint),
|
||||
* `OutputName` / `ModelName` (the canonical family name used for capability
|
||||
* enrichment), `Enabled` (console visibility — not API availability), and
|
||||
* optional `Description` / `EnabledThinking`.
|
||||
*
|
||||
* We keep ALL entries with a non-empty `ModelId`. The chat endpoint accepts
|
||||
* every listed model; `Enabled` only controls whether the model appears in
|
||||
* the console's model picker, so filtering on it would hide callable models.
|
||||
*/
|
||||
export function parseAgentPlanModels(json: JsonRecord): DiscoveredVolcModel[] {
|
||||
const data = record(json.Result).Data;
|
||||
const arr = Array.isArray(data) ? data : [];
|
||||
const out: DiscoveredVolcModel[] = [];
|
||||
for (const raw of arr) {
|
||||
const item = record(raw);
|
||||
const platformEnabledLlm =
|
||||
item.PlatformAllowStatus === true && stringField(item.Type) === "llm";
|
||||
const id = stringField(item.RespModelID);
|
||||
if (!id || (!platformEnabledLlm && !AGENT_PLAN_API_VERIFIED_IDS.has(id))) continue;
|
||||
const name = stringField(item.RespModelName) || id;
|
||||
out.push({
|
||||
id,
|
||||
name,
|
||||
...(stringField(item.RespModelVersion)
|
||||
? { description: `v${stringField(item.RespModelVersion)}` }
|
||||
: {}),
|
||||
});
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse Coding Plan `ListArkCodeLatestModel` Result.Data[].
|
||||
* The API exposes every catalog entry regardless of subscription state; we
|
||||
* keep ALL of them (the chat endpoint accepts them, Enabled only reflects
|
||||
* console visibility) but surface Enabled through the description.
|
||||
*/
|
||||
function parseCodingPlanModels(json: JsonRecord): DiscoveredVolcModel[] {
|
||||
export function parseLatestModelList(json: JsonRecord): DiscoveredVolcModel[] {
|
||||
const data = record(json.Result).Data;
|
||||
const arr = Array.isArray(data) ? data : [];
|
||||
const out: DiscoveredVolcModel[] = [];
|
||||
@@ -412,8 +385,7 @@ export async function fetchVolcPlanModels(
|
||||
);
|
||||
}
|
||||
|
||||
const discovered =
|
||||
kind === "agent" ? parseAgentPlanModels(result.json) : parseCodingPlanModels(result.json);
|
||||
const discovered = parseLatestModelList(result.json);
|
||||
if (discovered.length === 0) {
|
||||
throw new Error(`Volcano ${kind} plan returned no usable models`);
|
||||
}
|
||||
|
||||
@@ -1,27 +1,39 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
import { enrichModel, parseAgentPlanModels } from "@/lib/providers/volcenginePlanModelDiscovery";
|
||||
import { enrichModel, parseLatestModelList } from "@/lib/providers/volcenginePlanModelDiscovery";
|
||||
|
||||
test("Agent Plan discovery keeps canonical API-callable models hidden by the console", () => {
|
||||
const models = parseAgentPlanModels({
|
||||
test("Agent Plan discovery keeps all ListAgentPlanLatestModel entries", () => {
|
||||
// `ListAgentPlanLatestModel` returns the same shape as Coding Plan's
|
||||
// `ListArkCodeLatestModel`: ModelId / OutputName / Enabled / Description.
|
||||
// We keep ALL entries — `Enabled` only reflects console visibility, not
|
||||
// API availability. Previously disabled-but-callable models like
|
||||
// kimi-k3 must be retained.
|
||||
const models = parseLatestModelList({
|
||||
Result: {
|
||||
Data: [
|
||||
{
|
||||
RespModelID: "doubao-seed-evolving",
|
||||
RespModelName: "doubao-seed-evolving",
|
||||
PlatformAllowStatus: true,
|
||||
Type: "llm",
|
||||
ModelId: "doubao-seed-evolving-latest-version",
|
||||
OutputName: "doubao-seed-evolving",
|
||||
Enabled: false,
|
||||
EnabledThinking: true,
|
||||
},
|
||||
{
|
||||
RespModelID: "kimi-k3",
|
||||
PlatformAllowStatus: false,
|
||||
Type: null,
|
||||
ModelId: "kimi-k3-260701",
|
||||
OutputName: "kimi-k3",
|
||||
Enabled: false,
|
||||
EnabledThinking: true,
|
||||
},
|
||||
{
|
||||
RespModelID: "minimax-m3",
|
||||
PlatformAllowStatus: false,
|
||||
Type: null,
|
||||
ModelId: "auto",
|
||||
OutputName: "auto",
|
||||
Enabled: true,
|
||||
},
|
||||
{
|
||||
ModelId: "minimax-m3-modelhub",
|
||||
OutputName: "minimax-m3",
|
||||
Enabled: false,
|
||||
EnabledThinking: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -29,49 +41,29 @@ test("Agent Plan discovery keeps canonical API-callable models hidden by the con
|
||||
|
||||
assert.deepEqual(
|
||||
models.map((model) => model.id),
|
||||
["doubao-seed-evolving", "kimi-k3", "minimax-m3"]
|
||||
["doubao-seed-evolving-latest-version", "kimi-k3-260701", "auto", "minimax-m3-modelhub"]
|
||||
);
|
||||
// OutputName is used as the canonical family name for enrichment.
|
||||
assert.equal(models[1].name, "kimi-k3");
|
||||
assert.equal(models[1].enabledThinking, true);
|
||||
});
|
||||
|
||||
test("Agent Plan discovery excludes disabled aliases, auto-routing, and non-chat models", () => {
|
||||
const models = parseAgentPlanModels({
|
||||
Result: {
|
||||
Data: [
|
||||
{
|
||||
RespModelID: "future-platform-model",
|
||||
PlatformAllowStatus: true,
|
||||
Type: "llm",
|
||||
},
|
||||
{
|
||||
RespModelID: "glm-5.2",
|
||||
PlatformAllowStatus: false,
|
||||
Type: null,
|
||||
},
|
||||
{
|
||||
RespModelID: "auto",
|
||||
PlatformAllowStatus: false,
|
||||
Type: null,
|
||||
},
|
||||
{
|
||||
RespModelID: "doubao-seed-tts-2.0",
|
||||
PlatformAllowStatus: true,
|
||||
Type: "audio",
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepEqual(
|
||||
models.map((model) => model.id),
|
||||
["future-platform-model"]
|
||||
);
|
||||
});
|
||||
|
||||
test("Agent Plan canonical Kimi K3 receives registry-equivalent capabilities", () => {
|
||||
const kimi = enrichModel({ id: "kimi-k3", name: "kimi-k3" });
|
||||
test("enrichment maps context/vision/tools from the OutputName family", () => {
|
||||
const kimi = enrichModel({ id: "kimi-k3-260701", name: "kimi-k3" });
|
||||
|
||||
assert.equal(kimi.inputTokenLimit, 1048576);
|
||||
assert.equal(kimi.supportsVision, true);
|
||||
assert.equal(kimi.supportsTools, true);
|
||||
assert.equal(kimi.supportsThinking, true);
|
||||
|
||||
const glm = enrichModel({ id: "glm-5-3-260801", name: "glm-5.3" });
|
||||
assert.equal(glm.inputTokenLimit, 1048576);
|
||||
assert.equal(glm.supportsVision, false);
|
||||
|
||||
const doubao = enrichModel({
|
||||
id: "doubao-seed-evolving-latest-version",
|
||||
name: "doubao-seed-evolving",
|
||||
});
|
||||
assert.equal(doubao.inputTokenLimit, 1048576);
|
||||
assert.equal(doubao.supportsVision, true);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user