feat: register claude-code provider
This commit is contained in:
@@ -12,6 +12,8 @@ import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
|
|||||||
import { type ModelRole } from "../../config.ts";
|
import { type ModelRole } from "../../config.ts";
|
||||||
import { DEFAULT_THINKING_ORDER } from "../core/settings.ts";
|
import { DEFAULT_THINKING_ORDER } from "../core/settings.ts";
|
||||||
import packageMetadata from "../../package.json" with { type: "json" };
|
import packageMetadata from "../../package.json" with { type: "json" };
|
||||||
|
import { createClaudeCodeProvider } from "./claude-code/provider.ts";
|
||||||
|
import { streamClaudeCode } from "./claude-code/stream.ts";
|
||||||
|
|
||||||
/** App identity is immutable and shared by Models and every native Agent.
|
/** App identity is immutable and shared by Models and every native Agent.
|
||||||
* Agent's default Pi attribution otherwise overrides the Models identity. */
|
* Agent's default Pi attribution otherwise overrides the Models identity. */
|
||||||
@@ -57,6 +59,7 @@ export function piModels() {
|
|||||||
if (!collection) {
|
if (!collection) {
|
||||||
collection = createModels({ identity: APP_IDENTITY });
|
collection = createModels({ identity: APP_IDENTITY });
|
||||||
for (const provider of builtinProviders()) collection.setProvider(provider);
|
for (const provider of builtinProviders()) collection.setProvider(provider);
|
||||||
|
collection.setProvider(createClaudeCodeProvider(streamClaudeCode));
|
||||||
}
|
}
|
||||||
return collection;
|
return collection;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import type {
|
|||||||
} from "../core/contracts/models.ts";
|
} from "../core/contracts/models.ts";
|
||||||
import type { EffectiveModelSpec, EffectiveSlot } from "../core/settings-resolution.ts";
|
import type { EffectiveModelSpec, EffectiveSlot } from "../core/settings-resolution.ts";
|
||||||
import { AUTH_PROVIDER_KEYS } from "../core/auth-keys.ts";
|
import { AUTH_PROVIDER_KEYS } from "../core/auth-keys.ts";
|
||||||
|
import { CLAUDE_CODE_PROVIDER } from "../agent/claude-code/constants.ts";
|
||||||
import { BACKGROUND_MODEL_ROLES, MODEL_SLOTS, type BackgroundModelRole, type ModelSlotName, type ModelsSettings } from "../core/settings.ts";
|
import { BACKGROUND_MODEL_ROLES, MODEL_SLOTS, type BackgroundModelRole, type ModelSlotName, type ModelsSettings } from "../core/settings.ts";
|
||||||
|
|
||||||
/** The picker's client-safe model entry (contract: core/contracts/models.ts). */
|
/** The picker's client-safe model entry (contract: core/contracts/models.ts). */
|
||||||
@@ -130,9 +131,10 @@ export function catalogProviders(): CatalogProvider[] {
|
|||||||
|
|
||||||
/** The providers whose key is present — the picker federates exactly
|
/** The providers whose key is present — the picker federates exactly
|
||||||
* these (a keyless provider's models are unreachable by design; the
|
* these (a keyless provider's models are unreachable by design; the
|
||||||
* Keys page is the discovery surface, same discipline as search). */
|
* Keys page is the discovery surface, same discipline as search), plus
|
||||||
|
* claude-code, which runs on the local CLI's subscription and takes no key. */
|
||||||
function keyedProviderIds(): Set<string> {
|
function keyedProviderIds(): Set<string> {
|
||||||
return new Set(catalogProviders().filter((p) => p.keyPresent).map((p) => p.id));
|
return new Set([...catalogProviders().filter((p) => p.keyPresent).map((p) => p.id), CLAUDE_CODE_PROVIDER]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Project one catalog model to the client DTO. */
|
/** Project one catalog model to the client DTO. */
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { describe, it } from "node:test";
|
import { describe, it } from "node:test";
|
||||||
import assert from "node:assert/strict";
|
import assert from "node:assert/strict";
|
||||||
import {
|
import {
|
||||||
|
catalogContextLimits,
|
||||||
catalogDefaultsFor,
|
catalogDefaultsFor,
|
||||||
catalogProviders,
|
catalogProviders,
|
||||||
catalogRolePins,
|
catalogRolePins,
|
||||||
@@ -22,6 +23,7 @@ import { BACKGROUND_MODEL_ROLES } from "../src/core/settings.ts";
|
|||||||
import { resolveSettings } from "../src/core/settings-resolution.ts";
|
import { resolveSettings } from "../src/core/settings-resolution.ts";
|
||||||
import { readSettings } from "../src/store/settings.ts";
|
import { readSettings } from "../src/store/settings.ts";
|
||||||
import { effectiveSettings } from "../src/server/stores.ts";
|
import { effectiveSettings } from "../src/server/stores.ts";
|
||||||
|
import { providerKeyPresent } from "../src/server/keys.ts";
|
||||||
|
|
||||||
// The model-control wave (2026-09-12): pi-ai owns the registry — these pins
|
// The model-control wave (2026-09-12): pi-ai owns the registry — these pins
|
||||||
// hold our projection + validation honest against the shipped catalog, and
|
// hold our projection + validation honest against the shipped catalog, and
|
||||||
@@ -326,4 +328,26 @@ describe("pi thinking truth (pinned against pi-ai upgrades)", () => {
|
|||||||
const { piEngineFor } = await import("../src/agent/models.ts");
|
const { piEngineFor } = await import("../src/agent/models.ts");
|
||||||
assert.throws(() => piEngineFor("prober"), /no configured model for role "prober"/);
|
assert.throws(() => piEngineFor("prober"), /no configured model for role "prober"/);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe("the claude-code provider (subscription CLI, no key)", () => {
|
||||||
|
it("modelCatalog() lists claude-code opus/sonnet/haiku with no keys saved", () => {
|
||||||
|
const ids = modelCatalog()
|
||||||
|
.models.filter((m) => m.provider === "claude-code")
|
||||||
|
.map((m) => m.id);
|
||||||
|
assert.deepEqual(ids, ["haiku", "opus", "sonnet"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("catalogContextLimits() has claude-code:opus", () => {
|
||||||
|
assert.ok((catalogContextLimits().get("claude-code:opus") ?? 0) > 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('piEngineForSpec({ provider: "claude-code", id: "sonnet" }) resolves', () => {
|
||||||
|
const engine = piEngineForSpec({ provider: "claude-code", id: "sonnet" });
|
||||||
|
assert.equal(engine.model.provider, "claude-code");
|
||||||
|
assert.equal(engine.model.id, "sonnet");
|
||||||
|
});
|
||||||
|
|
||||||
|
it('providerKeyPresent("claude-code") is true', () => {
|
||||||
|
assert.equal(providerKeyPresent("claude-code"), true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user