mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-14 02:42:24 +03:00
Injeta a tag de usuário obrigatória nas requisições de inferência do provider Nous, com teste próprio ampliado. Validado no worktree combinado. Obrigado!
This commit is contained in:
1
changelog.d/fixes/11861-nous-tags-user-injection.md
Normal file
1
changelog.d/fixes/11861-nous-tags-user-injection.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(provider/nous):** inject required user= tag into Nous Research inference requests to resolve upstream 400 "missing tags" error ([#11861](https://github.com/diegosouzapw/OmniRoute/issues/11861)) — thanks @Karan825
|
||||
@@ -639,8 +639,7 @@ export class DefaultExecutor extends BaseExecutor {
|
||||
|
||||
const record = body as Record<string, unknown>;
|
||||
const rf = record.response_format as
|
||||
| { type?: string; json_schema?: { schema?: unknown } }
|
||||
| undefined;
|
||||
{ type?: string; json_schema?: { schema?: unknown } } | undefined;
|
||||
if (!rf) return body;
|
||||
|
||||
// openai-compatible-* providers accept json_object natively — only the
|
||||
@@ -748,6 +747,38 @@ export class DefaultExecutor extends BaseExecutor {
|
||||
delete withoutClientMetadata.client_metadata;
|
||||
withDefaults = withoutClientMetadata;
|
||||
}
|
||||
// Nous Research inference gateway (portal.nousresearch.com) requires a top-level
|
||||
// `tags` array containing at least a `user=` item on raw API-key requests (#11861).
|
||||
// Without `tags`, upstream returns 400 "missing tags".
|
||||
// Without `user=...`, upstream returns 400 "missing user tag".
|
||||
if (
|
||||
this.provider === "nous-research" &&
|
||||
withDefaults &&
|
||||
typeof withDefaults === "object" &&
|
||||
!Array.isArray(withDefaults)
|
||||
) {
|
||||
const record = withDefaults as Record<string, unknown>;
|
||||
const extraBody = record.extra_body as Record<string, unknown> | undefined;
|
||||
|
||||
const rawTags = Array.isArray(record.tags)
|
||||
? (record.tags as unknown[])
|
||||
: Array.isArray(extraBody?.tags)
|
||||
? (extraBody.tags as unknown[])
|
||||
: [];
|
||||
|
||||
const stringTags = rawTags.filter(
|
||||
(t): t is string => typeof t === "string" && t.trim().length > 0
|
||||
);
|
||||
|
||||
const hasUserTag = stringTags.some((t) => t.startsWith("user="));
|
||||
if (!hasUserTag) {
|
||||
const username =
|
||||
typeof record.user === "string" && record.user.trim() ? record.user.trim() : "omniroute";
|
||||
record.tags = [...stringTags, `user=${username}`];
|
||||
} else {
|
||||
record.tags = stringTags;
|
||||
}
|
||||
}
|
||||
|
||||
// 9router#1649: Mistral's API returns 422 (extra_forbidden) when an
|
||||
// assistant message carries a `reasoning_content` field (replayed thinking
|
||||
|
||||
@@ -631,6 +631,7 @@ export async function validateNousResearchProvider({ apiKey, providerSpecificDat
|
||||
model: modelId,
|
||||
messages: [{ role: "user", content: "test" }],
|
||||
max_tokens: 1,
|
||||
tags: ["user=omniroute"],
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@@ -29,8 +29,62 @@ test("nous-research DefaultExecutor.buildUrl() targets the correct inference end
|
||||
|
||||
const url = executor.buildUrl("Hermes-4-70B", false, 0, null);
|
||||
|
||||
assert.equal(
|
||||
url,
|
||||
"https://inference-api.nousresearch.com/v1/chat/completions"
|
||||
);
|
||||
assert.equal(url, "https://inference-api.nousresearch.com/v1/chat/completions");
|
||||
});
|
||||
|
||||
test("nous-research DefaultExecutor.transformRequest injects user=omniroute tag when tags is absent (#11861)", () => {
|
||||
const executor = new DefaultExecutor("nous-research");
|
||||
const transformed = executor.transformRequest(
|
||||
"Hermes-4-70B",
|
||||
{ model: "Hermes-4-70B", messages: [{ role: "user", content: "hello" }] },
|
||||
false,
|
||||
null
|
||||
) as Record<string, unknown>;
|
||||
|
||||
assert.ok(Array.isArray(transformed.tags), "Expected tags array on nous-research body");
|
||||
assert.deepEqual(transformed.tags, ["user=omniroute"]);
|
||||
});
|
||||
|
||||
test("nous-research DefaultExecutor.transformRequest respects client-sent user in tags (#11861)", () => {
|
||||
const executor = new DefaultExecutor("nous-research");
|
||||
const transformed = executor.transformRequest(
|
||||
"Hermes-4-70B",
|
||||
{ model: "Hermes-4-70B", user: "dev-user", messages: [{ role: "user", content: "hello" }] },
|
||||
false,
|
||||
null
|
||||
) as Record<string, unknown>;
|
||||
|
||||
assert.deepEqual(transformed.tags, ["user=dev-user"]);
|
||||
});
|
||||
|
||||
test("nous-research DefaultExecutor.transformRequest preserves existing tags and appends user tag (#11861)", () => {
|
||||
const executor = new DefaultExecutor("nous-research");
|
||||
const transformed = executor.transformRequest(
|
||||
"Hermes-4-70B",
|
||||
{
|
||||
model: "Hermes-4-70B",
|
||||
tags: ["client=agent"],
|
||||
messages: [{ role: "user", content: "hello" }],
|
||||
},
|
||||
false,
|
||||
null
|
||||
) as Record<string, unknown>;
|
||||
|
||||
assert.deepEqual(transformed.tags, ["client=agent", "user=omniroute"]);
|
||||
});
|
||||
|
||||
test("nous-research DefaultExecutor.transformRequest does not duplicate user tag if already present (#11861)", () => {
|
||||
const executor = new DefaultExecutor("nous-research");
|
||||
const transformed = executor.transformRequest(
|
||||
"Hermes-4-70B",
|
||||
{
|
||||
model: "Hermes-4-70B",
|
||||
tags: ["user=custom-tag"],
|
||||
messages: [{ role: "user", content: "hello" }],
|
||||
},
|
||||
false,
|
||||
null
|
||||
) as Record<string, unknown>;
|
||||
|
||||
assert.deepEqual(transformed.tags, ["user=custom-tag"]);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user