Merge branch 'main' into fix/issue-2954-image-maxbytes-config
This commit is contained in:
commit
f212d1bc8c
@ -69,6 +69,7 @@ Status: unreleased.
|
|||||||
- **BREAKING:** Gateway auth mode "none" is removed; gateway now requires token/password (Tailscale Serve identity still allowed).
|
- **BREAKING:** Gateway auth mode "none" is removed; gateway now requires token/password (Tailscale Serve identity still allowed).
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
- Agents: inherit provider baseUrl/api for inline models. (#2740) Thanks @lploc94.
|
||||||
- Memory Search: keep auto provider model defaults and only include remote when configured. (#2576) Thanks @papago2355.
|
- Memory Search: keep auto provider model defaults and only include remote when configured. (#2576) Thanks @papago2355.
|
||||||
- macOS: auto-scroll to bottom when sending a new message while scrolled up. (#2471) Thanks @kennyklee.
|
- macOS: auto-scroll to bottom when sending a new message while scrolled up. (#2471) Thanks @kennyklee.
|
||||||
- Web UI: auto-expand the chat compose textarea while typing (with sensible max height). (#2950) Thanks @shivamraut101.
|
- Web UI: auto-expand the chat compose textarea while typing (with sensible max height). (#2950) Thanks @shivamraut101.
|
||||||
|
|||||||
@ -1,6 +1,12 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
import { buildInlineProviderModels } from "./model.js";
|
vi.mock("@mariozechner/pi-coding-agent", () => ({
|
||||||
|
discoverAuthStorage: vi.fn(() => ({ mocked: true })),
|
||||||
|
discoverModels: vi.fn(() => ({ find: vi.fn(() => null) })),
|
||||||
|
}));
|
||||||
|
|
||||||
|
import type { MoltbotConfig } from "../../config/config.js";
|
||||||
|
import { buildInlineProviderModels, resolveModel } from "./model.js";
|
||||||
|
|
||||||
const makeModel = (id: string) => ({
|
const makeModel = (id: string) => ({
|
||||||
id,
|
id,
|
||||||
@ -15,15 +21,110 @@ const makeModel = (id: string) => ({
|
|||||||
describe("buildInlineProviderModels", () => {
|
describe("buildInlineProviderModels", () => {
|
||||||
it("attaches provider ids to inline models", () => {
|
it("attaches provider ids to inline models", () => {
|
||||||
const providers = {
|
const providers = {
|
||||||
" alpha ": { models: [makeModel("alpha-model")] },
|
" alpha ": { baseUrl: "http://alpha.local", models: [makeModel("alpha-model")] },
|
||||||
beta: { models: [makeModel("beta-model")] },
|
beta: { baseUrl: "http://beta.local", models: [makeModel("beta-model")] },
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = buildInlineProviderModels(providers);
|
const result = buildInlineProviderModels(providers);
|
||||||
|
|
||||||
expect(result).toEqual([
|
expect(result).toEqual([
|
||||||
{ ...makeModel("alpha-model"), provider: "alpha" },
|
{
|
||||||
{ ...makeModel("beta-model"), provider: "beta" },
|
...makeModel("alpha-model"),
|
||||||
|
provider: "alpha",
|
||||||
|
baseUrl: "http://alpha.local",
|
||||||
|
api: undefined,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...makeModel("beta-model"),
|
||||||
|
provider: "beta",
|
||||||
|
baseUrl: "http://beta.local",
|
||||||
|
api: undefined,
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("inherits baseUrl from provider when model does not specify it", () => {
|
||||||
|
const providers = {
|
||||||
|
custom: {
|
||||||
|
baseUrl: "http://localhost:8000",
|
||||||
|
models: [makeModel("custom-model")],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = buildInlineProviderModels(providers);
|
||||||
|
|
||||||
|
expect(result).toHaveLength(1);
|
||||||
|
expect(result[0].baseUrl).toBe("http://localhost:8000");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("inherits api from provider when model does not specify it", () => {
|
||||||
|
const providers = {
|
||||||
|
custom: {
|
||||||
|
baseUrl: "http://localhost:8000",
|
||||||
|
api: "anthropic-messages",
|
||||||
|
models: [makeModel("custom-model")],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = buildInlineProviderModels(providers);
|
||||||
|
|
||||||
|
expect(result).toHaveLength(1);
|
||||||
|
expect(result[0].api).toBe("anthropic-messages");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("model-level api takes precedence over provider-level api", () => {
|
||||||
|
const providers = {
|
||||||
|
custom: {
|
||||||
|
baseUrl: "http://localhost:8000",
|
||||||
|
api: "openai-responses",
|
||||||
|
models: [{ ...makeModel("custom-model"), api: "anthropic-messages" as const }],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = buildInlineProviderModels(providers);
|
||||||
|
|
||||||
|
expect(result).toHaveLength(1);
|
||||||
|
expect(result[0].api).toBe("anthropic-messages");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("inherits both baseUrl and api from provider config", () => {
|
||||||
|
const providers = {
|
||||||
|
custom: {
|
||||||
|
baseUrl: "http://localhost:10000",
|
||||||
|
api: "anthropic-messages",
|
||||||
|
models: [makeModel("claude-opus-4.5")],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = buildInlineProviderModels(providers);
|
||||||
|
|
||||||
|
expect(result).toHaveLength(1);
|
||||||
|
expect(result[0]).toMatchObject({
|
||||||
|
provider: "custom",
|
||||||
|
baseUrl: "http://localhost:10000",
|
||||||
|
api: "anthropic-messages",
|
||||||
|
name: "claude-opus-4.5",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("resolveModel", () => {
|
||||||
|
it("includes provider baseUrl in fallback model", () => {
|
||||||
|
const cfg = {
|
||||||
|
models: {
|
||||||
|
providers: {
|
||||||
|
custom: {
|
||||||
|
baseUrl: "http://localhost:9000",
|
||||||
|
models: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as MoltbotConfig;
|
||||||
|
|
||||||
|
const result = resolveModel("custom", "missing-model", "/tmp/agent", cfg);
|
||||||
|
|
||||||
|
expect(result.model?.baseUrl).toBe("http://localhost:9000");
|
||||||
|
expect(result.model?.provider).toBe("custom");
|
||||||
|
expect(result.model?.id).toBe("missing-model");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -8,15 +8,25 @@ import { DEFAULT_CONTEXT_TOKENS } from "../defaults.js";
|
|||||||
import { normalizeModelCompat } from "../model-compat.js";
|
import { normalizeModelCompat } from "../model-compat.js";
|
||||||
import { normalizeProviderId } from "../model-selection.js";
|
import { normalizeProviderId } from "../model-selection.js";
|
||||||
|
|
||||||
type InlineModelEntry = ModelDefinitionConfig & { provider: string };
|
type InlineModelEntry = ModelDefinitionConfig & { provider: string; baseUrl?: string };
|
||||||
|
type InlineProviderConfig = {
|
||||||
|
baseUrl?: string;
|
||||||
|
api?: ModelDefinitionConfig["api"];
|
||||||
|
models?: ModelDefinitionConfig[];
|
||||||
|
};
|
||||||
|
|
||||||
export function buildInlineProviderModels(
|
export function buildInlineProviderModels(
|
||||||
providers: Record<string, { models?: ModelDefinitionConfig[] }>,
|
providers: Record<string, InlineProviderConfig>,
|
||||||
): InlineModelEntry[] {
|
): InlineModelEntry[] {
|
||||||
return Object.entries(providers).flatMap(([providerId, entry]) => {
|
return Object.entries(providers).flatMap(([providerId, entry]) => {
|
||||||
const trimmed = providerId.trim();
|
const trimmed = providerId.trim();
|
||||||
if (!trimmed) return [];
|
if (!trimmed) return [];
|
||||||
return (entry?.models ?? []).map((model) => ({ ...model, provider: trimmed }));
|
return (entry?.models ?? []).map((model) => ({
|
||||||
|
...model,
|
||||||
|
provider: trimmed,
|
||||||
|
baseUrl: entry?.baseUrl,
|
||||||
|
api: model.api ?? entry?.api,
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,6 +82,7 @@ export function resolveModel(
|
|||||||
name: modelId,
|
name: modelId,
|
||||||
api: providerCfg?.api ?? "openai-responses",
|
api: providerCfg?.api ?? "openai-responses",
|
||||||
provider,
|
provider,
|
||||||
|
baseUrl: providerCfg?.baseUrl,
|
||||||
reasoning: false,
|
reasoning: false,
|
||||||
input: ["text"],
|
input: ["text"],
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user