mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-19 12:04:08 +00:00
fix(coding-agent): make models.json model fields optional with defaults
Model definitions now only require 'id'. All other fields have sensible
defaults for local models (Ollama, LM Studio, etc.):
- name: defaults to id
- reasoning: defaults to false
- input: defaults to ["text"]
- cost: defaults to {input: 0, output: 0, cacheRead: 0, cacheWrite: 0}
- contextWindow: defaults to 128000
- maxTokens: defaults to 16384
Existing configs that specify all fields continue to work unchanged.
Fixes #1146
This commit is contained in:
parent
3830d74d22
commit
c8b8f043a7
2 changed files with 26 additions and 20 deletions
|
|
@ -12,6 +12,7 @@
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fixed `pi update` not updating npm/git packages when called without arguments ([#1151](https://github.com/badlogic/pi-mono/issues/1151))
|
- Fixed `pi update` not updating npm/git packages when called without arguments ([#1151](https://github.com/badlogic/pi-mono/issues/1151))
|
||||||
|
- Fixed `models.json` validation requiring fields documented as optional. Model definitions now only require `id`; all other fields (`name`, `reasoning`, `input`, `cost`, `contextWindow`, `maxTokens`) have sensible defaults. ([#1146](https://github.com/badlogic/pi-mono/issues/1146))
|
||||||
|
|
||||||
## [0.50.9] - 2026-02-01
|
## [0.50.9] - 2026-02-01
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,20 +60,23 @@ const OpenAIResponsesCompatSchema = Type.Object({
|
||||||
const OpenAICompatSchema = Type.Union([OpenAICompletionsCompatSchema, OpenAIResponsesCompatSchema]);
|
const OpenAICompatSchema = Type.Union([OpenAICompletionsCompatSchema, OpenAIResponsesCompatSchema]);
|
||||||
|
|
||||||
// Schema for custom model definition
|
// Schema for custom model definition
|
||||||
|
// Most fields are optional with sensible defaults for local models (Ollama, LM Studio, etc.)
|
||||||
const ModelDefinitionSchema = Type.Object({
|
const ModelDefinitionSchema = Type.Object({
|
||||||
id: Type.String({ minLength: 1 }),
|
id: Type.String({ minLength: 1 }),
|
||||||
name: Type.String({ minLength: 1 }),
|
name: Type.Optional(Type.String({ minLength: 1 })),
|
||||||
api: Type.Optional(Type.String({ minLength: 1 })),
|
api: Type.Optional(Type.String({ minLength: 1 })),
|
||||||
reasoning: Type.Boolean(),
|
reasoning: Type.Optional(Type.Boolean()),
|
||||||
input: Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image")])),
|
input: Type.Optional(Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image")]))),
|
||||||
cost: Type.Object({
|
cost: Type.Optional(
|
||||||
|
Type.Object({
|
||||||
input: Type.Number(),
|
input: Type.Number(),
|
||||||
output: Type.Number(),
|
output: Type.Number(),
|
||||||
cacheRead: Type.Number(),
|
cacheRead: Type.Number(),
|
||||||
cacheWrite: Type.Number(),
|
cacheWrite: Type.Number(),
|
||||||
}),
|
}),
|
||||||
contextWindow: Type.Number(),
|
),
|
||||||
maxTokens: Type.Number(),
|
contextWindow: Type.Optional(Type.Number()),
|
||||||
|
maxTokens: Type.Optional(Type.Number()),
|
||||||
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
||||||
compat: Type.Optional(OpenAICompatSchema),
|
compat: Type.Optional(OpenAICompatSchema),
|
||||||
});
|
});
|
||||||
|
|
@ -352,10 +355,10 @@ export class ModelRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!modelDef.id) throw new Error(`Provider ${providerName}: model missing "id"`);
|
if (!modelDef.id) throw new Error(`Provider ${providerName}: model missing "id"`);
|
||||||
if (!modelDef.name) throw new Error(`Provider ${providerName}: model missing "name"`);
|
// Validate contextWindow/maxTokens only if provided (they have defaults)
|
||||||
if (modelDef.contextWindow <= 0)
|
if (modelDef.contextWindow !== undefined && modelDef.contextWindow <= 0)
|
||||||
throw new Error(`Provider ${providerName}, model ${modelDef.id}: invalid contextWindow`);
|
throw new Error(`Provider ${providerName}, model ${modelDef.id}: invalid contextWindow`);
|
||||||
if (modelDef.maxTokens <= 0)
|
if (modelDef.maxTokens !== undefined && modelDef.maxTokens <= 0)
|
||||||
throw new Error(`Provider ${providerName}, model ${modelDef.id}: invalid maxTokens`);
|
throw new Error(`Provider ${providerName}, model ${modelDef.id}: invalid maxTokens`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -392,17 +395,19 @@ export class ModelRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
// baseUrl is validated to exist for providers with models
|
// baseUrl is validated to exist for providers with models
|
||||||
|
// Apply defaults for optional fields
|
||||||
|
const defaultCost = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
||||||
models.push({
|
models.push({
|
||||||
id: modelDef.id,
|
id: modelDef.id,
|
||||||
name: modelDef.name,
|
name: modelDef.name ?? modelDef.id,
|
||||||
api: api as Api,
|
api: api as Api,
|
||||||
provider: providerName,
|
provider: providerName,
|
||||||
baseUrl: providerConfig.baseUrl!,
|
baseUrl: providerConfig.baseUrl!,
|
||||||
reasoning: modelDef.reasoning,
|
reasoning: modelDef.reasoning ?? false,
|
||||||
input: modelDef.input as ("text" | "image")[],
|
input: (modelDef.input ?? ["text"]) as ("text" | "image")[],
|
||||||
cost: modelDef.cost,
|
cost: modelDef.cost ?? defaultCost,
|
||||||
contextWindow: modelDef.contextWindow,
|
contextWindow: modelDef.contextWindow ?? 128000,
|
||||||
maxTokens: modelDef.maxTokens,
|
maxTokens: modelDef.maxTokens ?? 16384,
|
||||||
headers,
|
headers,
|
||||||
compat: modelDef.compat,
|
compat: modelDef.compat,
|
||||||
} as Model<Api>);
|
} as Model<Api>);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue