diff --git a/CHANGELOG.md b/CHANGELOG.md index b1e9abf..1397e23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## Unreleased +### Fixes + +- Offer catalog models that carry a named profile. Muse 1.3.0 tags every live `providerCatalog` row with the catalog's profile, so the model menu showed only the current model and no catalog choice could be selected. Profiled rows are now advertised and selectable, and the profile travels with the selection through `session/setModel`. +- Default to `muse-spark-1.3` when neither the session nor Muse settings name a model. Muse's own catalog default can be a `-contributor` variant, whose content may be used for product improvement, so the adapter keeps an explicit non-contributor default rather than following it. + ## [0.6.1](https://github.com/bex-co/muse-code-acp/compare/v0.6.0...v0.6.1) (2026-09-16) ### Fixes diff --git a/docs/capability-audit.md b/docs/capability-audit.md index 7461785..a6cca6d 100644 --- a/docs/capability-audit.md +++ b/docs/capability-audit.md @@ -18,7 +18,7 @@ The table records the m6 audit snapshot; subsequent owner evidence can supersede | list, close | Native discovery with pagination; close releases the host and retains history | `session-discovery-live.test.ts`; native deletion is absent, future w1/012 | | fork | Native full or completed-turn boundary fork, gated by SDK host support; separate owner/MCP inventory | `session-fork-live.test.ts`; no extra roots or silent recreation | | model/provider | Adapter settings overlay plus explicit public setter; provider-qualified IDs; idle replacement | w2/m5 shipped; actual model requests verified on both hosts even when resume metadata already agrees | -| named model profiles | Identity retained; selection unavailable because effective routing is unverified | w2/m5 explicit failure; rerun with a real public profile catalog before enabling | +| named model profiles | Catalog rows keep their profile identity and are selectable; setModel carries the profile | Muse 1.3.0-R3401.1: every live providerCatalog row carries the catalog profile; selecting one served that model | | effort | Requested preference; 1.1.1 omits main effort, 1.2.1 maps none→minimal and ultra→max | w2/m5 provider matrix; no per-model restrictions inferred; future w1/010 | | client gateway and recommendations | Negotiated adapter-owned isolated settings/keys and advisory choice provenance | w2/m5; no automatic selection, account/tier/quota claim or endpoint fallback | | mode / native approval policy | Adapter automatic once choices are independent of native policy; dangerous modes guarded | w2/m4 tool effects; m6 policy menu/rejection share version decisions; 1.1.1 offers native onRequest only | diff --git a/docs/sdk-migration.md b/docs/sdk-migration.md index fab8e1d..600763f 100644 --- a/docs/sdk-migration.md +++ b/docs/sdk-migration.md @@ -116,8 +116,10 @@ including a reused multi-turn session. Failed admission starts no turn and does not persist the selection as successfully applied. Config options represent requested settings; negotiated `muse/sessionState` reports native observations separately. The overlay remains until its retained host closes; user settings stay intact. -Named profile identity is preserved in discovery, but effective routing is unverified; -named-profile selections are unavailable with an actionable explanation. +Named profile identity is preserved in discovery and in the selection sent through +`session/setModel`. `model/list` reports the profile per catalog, and on Muse +1.3.0 every live provider-catalog row carries it, so profiled rows are offered and +selectable like any other choice. Form elicitation supports single selections, bounded multiple selections, and free text up to 500 characters. Invalid responses fail the turn and cancel the diff --git a/src/config-options.ts b/src/config-options.ts index c8079d2..918c584 100644 --- a/src/config-options.ts +++ b/src/config-options.ts @@ -24,7 +24,7 @@ export function isReasoningEffort(value: unknown): value is MuseReasoningEffort return typeof value === "string" && (EFFORT_LEVELS as readonly string[]).includes(value); } -const DEFAULT_MODEL = "muse-spark-1.2"; +const DEFAULT_MODEL = "muse-spark-1.3"; const DEFAULT_EFFORT = "high"; export interface SessionConfig { @@ -55,7 +55,7 @@ export function buildConfigOptions( const discovered: readonly DiscoveredModel[] = backend === "sdk" ? discovery?.status === "available" - ? discovery.models.filter((model) => model.profileId == null) + ? discovery.models : [] : KNOWN_MODELS.map((id) => ({ id, name: id })); const current = discovered.filter( @@ -174,11 +174,6 @@ export function selectModel( ); if (matches.length === 1) { const model = matches[0]; - if (model.profileId != null) - throw RequestError.invalidParams( - undefined, - "Named model profile routing is unverified on supported Muse hosts; choose a provider model without a named profile", - ); return { ...config, model: model.id, providerId: model.providerId, profileId: model.profileId }; } if ( diff --git a/src/muse-sdk-host.ts b/src/muse-sdk-host.ts index 00c538a..7a9097b 100644 --- a/src/muse-sdk-host.ts +++ b/src/muse-sdk-host.ts @@ -301,10 +301,6 @@ export class MuseSdkHost { private async open(preparing: () => void): Promise { const options = this.options; - if (options.profileId != null) - throw new Error( - "Named model profile routing is unverified on supported Muse hosts; choose a provider model without a named profile. No turn was started", - ); // Only probed when the host check runs: spawning the real binary for a // version string is exactly what `checkHost: false` exists to avoid. const hostVersion = diff --git a/src/tests/config-options.test.ts b/src/tests/config-options.test.ts index 05abc63..90e881e 100644 --- a/src/tests/config-options.test.ts +++ b/src/tests/config-options.test.ts @@ -55,7 +55,7 @@ describe("defaultSessionConfig", () => { defaultSessionConfig({ model: "muse-spark-1.2-contributor", reasoningEffort: "ultra" }), ).toEqual({ model: "muse-spark-1.2-contributor", reasoningEffort: "ultra" }); expect(defaultSessionConfig({ reasoningEffort: "bogus" })).toEqual({ - model: "muse-spark-1.2", + model: "muse-spark-1.3", reasoningEffort: "high", }); }); diff --git a/src/tests/model-identity.test.ts b/src/tests/model-identity.test.ts index ad1ca2b..3c7f65a 100644 --- a/src/tests/model-identity.test.ts +++ b/src/tests/model-identity.test.ts @@ -99,13 +99,19 @@ it("recommendations retain explicit values and use only advertised choices", asy ).toMatchObject({ source: "retainedSelection", applied: false }); }); -it("does not advertise unverified named-profile routing or lose its identity", () => { +it("advertises and selects catalog models that carry a named profile", () => { + // Muse 1.3.0 provider catalogs tag every row with the account's catalog + // profile, so filtering profiled rows left only the synthetic current model. const profiled = { id: "named", name: "Named", providerId: "meta", profileId: "team" }; const catalog = { status: "available" as const, source: "providerCatalog", models: [profiled] }; const value = modelChoice(profiled); - const options = buildConfigOptions(config, "sdk", catalog); - expect(JSON.stringify(options)).not.toContain(value); - expect(() => selectModel(config, value, catalog)).toThrow( - /Named model profile routing is unverified/, - ); + const option = buildConfigOptions(config, "sdk", catalog).find((o) => o.id === "model")!; + if (option.type !== "select") throw Error("wrong type"); + expect(option.options.map((o) => ("value" in o ? o.value : undefined))).toContain(value); + expect(selectModel(config, value, catalog)).toMatchObject({ + model: "named", + providerId: "meta", + profileId: "team", + }); + expect(selectModel(config, "named", catalog)).toMatchObject({ profileId: "team" }); });