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:
@@ -15,6 +15,12 @@ import { fileURLToPath } from "node:url"
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const PROJECT_DIR = resolve(__dirname, "..")
|
||||
const EXT_PATH = resolve(PROJECT_DIR, "index.ts")
|
||||
const COMPAT_CALLER_EXT_PATH = resolve(
|
||||
PROJECT_DIR,
|
||||
"tests",
|
||||
"fixtures",
|
||||
"compat-caller-extension.ts",
|
||||
)
|
||||
const TEST_MODEL = "gpt-5.4"
|
||||
const CLAUDE_TEST_MODEL = "claude-sonnet-4-6"
|
||||
|
||||
@@ -486,6 +492,75 @@ async function runRpcExtensionCommands(timeoutMs = 30_000) {
|
||||
}
|
||||
}
|
||||
|
||||
async function runRpcCompatCall(timeoutMs = 30_000) {
|
||||
const child = spawn(
|
||||
PI_BIN,
|
||||
[
|
||||
"--no-extensions",
|
||||
"--mode",
|
||||
"rpc",
|
||||
"-e",
|
||||
EXT_PATH,
|
||||
"-e",
|
||||
COMPAT_CALLER_EXT_PATH,
|
||||
"--provider",
|
||||
"commandcode",
|
||||
"--model",
|
||||
TEST_MODEL,
|
||||
],
|
||||
{
|
||||
cwd: PROJECT_DIR,
|
||||
env,
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
},
|
||||
)
|
||||
|
||||
let buffer = ""
|
||||
let stderr = ""
|
||||
|
||||
const notification = new Promise((resolve, reject) => {
|
||||
const timer = setTimeout(
|
||||
() => reject(new Error(`compat-call timeout. stderr: ${stderr.slice(-500)}`)),
|
||||
timeoutMs,
|
||||
)
|
||||
child.stdout.on("data", (chunk) => {
|
||||
buffer += chunk.toString("utf-8")
|
||||
const lines = buffer.split("\n")
|
||||
buffer = lines.pop() ?? ""
|
||||
for (const line of lines) {
|
||||
if (!line.trim()) continue
|
||||
let event
|
||||
try {
|
||||
event = JSON.parse(line)
|
||||
} catch {
|
||||
continue
|
||||
}
|
||||
if (
|
||||
event.type === "extension_ui_request" &&
|
||||
event.method === "notify" &&
|
||||
typeof event.message === "string" &&
|
||||
event.message.startsWith("compat-call")
|
||||
) {
|
||||
clearTimeout(timer)
|
||||
resolve(event.message)
|
||||
}
|
||||
}
|
||||
})
|
||||
child.stderr.on("data", (chunk) => {
|
||||
stderr += chunk.toString("utf-8")
|
||||
})
|
||||
})
|
||||
|
||||
try {
|
||||
child.stdin.write(
|
||||
`${JSON.stringify({ id: "compat", type: "prompt", message: "/compat-call" })}\n`,
|
||||
)
|
||||
return { message: await notification, stderr }
|
||||
} finally {
|
||||
child.kill()
|
||||
}
|
||||
}
|
||||
|
||||
async function runRpcOverflowRecovery(timeoutMs = 60_000) {
|
||||
const child = spawn(
|
||||
PI_BIN,
|
||||
@@ -797,6 +872,18 @@ try {
|
||||
JSON.stringify(imageContent),
|
||||
)
|
||||
|
||||
console.log("[pi-local] sibling extension streams through the pi-ai compat registry")
|
||||
requestCount = 0
|
||||
const compatCall = await runRpcCompatCall()
|
||||
assert.equal(compatCall.message, "compat-call ok: mock-pi-ok", compatCall.stderr)
|
||||
assert.equal(requestCount, 1)
|
||||
assert.equal(lastRequestBody?.model, TEST_MODEL)
|
||||
assert.ok(
|
||||
typeof lastRequestHeaders.authorization === "string" &&
|
||||
lastRequestHeaders.authorization.startsWith("Bearer "),
|
||||
"compat call should send a bearer Authorization header",
|
||||
)
|
||||
|
||||
console.log("[pi-local] verify overflow normalization and compaction recovery")
|
||||
overflowMode = true
|
||||
overflowRequestCount = 0
|
||||
|
||||
Reference in New Issue
Block a user