fix(core): register the custom api in the pi-ai compat registry

pi routes the main chat through the registered provider, but sibling
extensions that call streamSimple from @earendil-works/pi-ai/compat with
the active Command Code model resolve model.api through the compat
api-registry, which only knows built-in APIs. On plain pi that failed
with "No API provider registered for api: commandcode-custom".

Register commandcode-custom there and delegate to the transport router.
The registry resolves no credentials for extension providers, so fall
back to the configured Command Code key when the caller passes none.

Closes #68

(cherry picked from commit 7e9659e672771c6a9223b95938e50fb2a051a0a7)
This commit is contained in:
Patrick Wozniak
2026-09-01 23:29:30 +02:00
parent f17cec0eee
commit 0700d9b61d
5 changed files with 156 additions and 3 deletions
+34
View File
@@ -0,0 +1,34 @@
/**
* Test fixture: a sibling extension that streams through the pi-ai compat
* entrypoint with the active session model, the way background-agent
* extensions do. Registers `/compat-call` so the test can drive it over RPC.
*/
import { streamSimple } from "@earendil-works/pi-ai/compat"
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"
export default function (pi: ExtensionAPI) {
pi.registerCommand("compat-call", {
description: "Stream through @earendil-works/pi-ai/compat with the session model",
handler: async (_args, ctx) => {
const model = ctx.model
if (!model) {
ctx.ui.notify("compat-call: no active model", "error")
return
}
try {
const message = await streamSimple(model, {
messages: [{ role: "user", content: "say mock token", timestamp: Date.now() }],
}).result()
const text = message.content
.filter((part): part is { type: "text"; text: string } => part.type === "text")
.map((part) => part.text)
.join("")
ctx.ui.notify(`compat-call ok: ${text}`, "info")
} catch (error) {
const detail = error instanceof Error ? error.message : String(error)
ctx.ui.notify(`compat-call failed: ${detail}`, "error")
}
},
})
}