Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/fix-default-model-tier.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@perstack/runtime": patch
"@perstack/installer": patch
"perstack": patch
---

Fix: Preserve `defaultModelTier` when resolving experts from API

The `toRuntimeExpert` function in both runtime and installer packages was dropping the `defaultModelTier` field when converting API response experts to runtime Expert objects. This caused all API-fetched experts to ignore their configured model tier and fall back to the provider's highest-tier model (e.g., claude-opus-4-6 instead of claude-haiku-4-5 for `defaultModelTier: "low"`).

Also fixed `configExpertToExpert` in the installer package which had the same omission when converting TOML config experts.
62 changes: 31 additions & 31 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/installer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@perstack/api-client": "^0.0.57",
"@perstack/api-client": "^0.0.58",
"@perstack/core": "workspace:*",
"@perstack/perstack-toml": "workspace:*",
"@perstack/skill-manager": "workspace:*"
Expand Down
4 changes: 4 additions & 0 deletions packages/installer/src/expert-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
defaultPerstackApiBaseUrl,
type Expert,
expertSchema,
type ModelTier,
type PerstackConfig,
PerstackError,
type RuntimeVersion,
Expand Down Expand Up @@ -47,6 +48,7 @@ export type PublishedExpertData = {
>
delegates?: string[]
tags?: string[]
defaultModelTier?: ModelTier
}

export function toRuntimeExpert(key: string, expert: PublishedExpertData): Expert {
Expand Down Expand Up @@ -117,6 +119,7 @@ export function toRuntimeExpert(key: string, expert: PublishedExpertData): Exper
skills,
delegates: expert.delegates ?? [],
tags: expert.tags ?? [],
defaultModelTier: expert.defaultModelTier,
}
}

Expand All @@ -136,6 +139,7 @@ export function configExpertToExpert(
providerTools: configExpert.providerTools,
providerSkills: configExpert.providerSkills,
providerToolOptions: configExpert.providerToolOptions,
defaultModelTier: configExpert.defaultModelTier,
})
}

Expand Down
2 changes: 1 addition & 1 deletion packages/runtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"@ai-sdk/openai": "^3.0.29",
"@modelcontextprotocol/sdk": "^1.26.0",
"@paralleldrive/cuid2": "^3.3.0",
"@perstack/api-client": "^0.0.57",
"@perstack/api-client": "^0.0.58",
"@perstack/base": "0.0.78",
"@perstack/core": "0.0.64",
"ai": "^6.0.86",
Expand Down
9 changes: 9 additions & 0 deletions packages/runtime/src/helpers/resolve-expert.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ mock.module("@perstack/api-client", () => ({
skills: {},
delegates: [],
tags: [],
defaultModelTier: "low",
},
},
},
Expand Down Expand Up @@ -136,6 +137,14 @@ describe("@perstack/runtime: resolveExpertToRun", () => {
expect(result.key).toBe("published-expert")
})

it("preserves defaultModelTier from API response", async () => {
const experts: Record<string, Expert> = {}
await resolveExpertToRun("remote-expert", experts, {
perstackApiBaseUrl: "https://api.test.com",
})
expect(experts["@remote-expert/delegate"].defaultModelTier).toBe("low")
})

it("resolves delegate from already-populated experts without API call", async () => {
const experts: Record<string, Expert> = {}
await resolveExpertToRun("remote-expert", experts, {
Expand Down
10 changes: 9 additions & 1 deletion packages/runtime/src/helpers/resolve-expert.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { createApiClient } from "@perstack/api-client"
import { type Expert, PerstackError, type RuntimeVersion, type Skill } from "@perstack/core"
import {
type Expert,
type ModelTier,
PerstackError,
type RuntimeVersion,
type Skill,
} from "@perstack/core"

export async function resolveExpertToRun(
expertKey: string,
Expand Down Expand Up @@ -73,6 +79,7 @@ function toRuntimeExpert(
>
delegates?: string[]
tags?: string[]
defaultModelTier?: ModelTier
},
): Expert {
const skills: Record<string, Skill> = Object.fromEntries(
Expand Down Expand Up @@ -142,5 +149,6 @@ function toRuntimeExpert(
skills,
delegates: expert.delegates ?? [],
tags: expert.tags ?? [],
defaultModelTier: expert.defaultModelTier,
}
}
2 changes: 1 addition & 1 deletion packages/studio/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@perstack/api-client": "^0.0.57",
"@perstack/api-client": "^0.0.58",
"@perstack/core": "workspace:*",
"@perstack/installer": "workspace:*",
"@perstack/perstack-toml": "workspace:*"
Expand Down