diff --git a/scripts/smoke-provider-runtime.mjs b/scripts/smoke-provider-runtime.mjs
index 47c12c6..7cafc1d 100644
--- a/scripts/smoke-provider-runtime.mjs
+++ b/scripts/smoke-provider-runtime.mjs
@@ -1,7 +1,7 @@
/**
- * OFFLINE native Pi Google initialization gate (no generation or provider calls).
- * Unlike /api/models, this traverses Pi's lazy adapter and constructs GoogleGenAI.
- * The real onPayload hook throws a unique sentinel BEFORE generateContentStream.
+ * OFFLINE native Pi Google/Bedrock initialization gate (no generation or provider calls).
+ * Unlike /api/models, this traverses Pi's lazy adapters and constructs real SDK clients.
+ * The real onPayload hook throws a unique sentinel BEFORE SDK request dispatch.
* All file modules must resolve inside the payload, including nested dependencies.
*
* node scripts/smoke-provider-runtime.mjs [--standalone
] [--runtime ]
@@ -81,17 +81,22 @@ async function probe(standalone) {
const entry = pathToFileURL(path.join(root, "node_modules/@earendil-works/pi-ai/dist/index.js"));
const { createModels } = await import(entry.href);
const models = createModels();
- for (const [name, factory] of [["google", "googleProvider"], ["opencode", "opencodeProvider"], ["opencode-go", "opencodeGoProvider"]]) {
+ for (const [name, factory, api, label] of [
+ ["google", "googleProvider", "google-generative-ai", "Google"],
+ ["opencode", "opencodeProvider", "google-generative-ai", "Google"],
+ ["opencode-go", "opencodeGoProvider", "google-generative-ai", "Google"],
+ ["amazon-bedrock", "amazonBedrockProvider", "bedrock-converse-stream", "Bedrock"],
+ ]) {
const provider = (await import(new URL(`providers/${name}.js`, entry).href))[factory]();
models.setProvider(provider);
- const model = provider.getModels().find((candidate) => candidate.api === "google-generative-ai");
- assert.ok(model, `${name}: missing Google-backed catalog model`);
+ const model = provider.getModels().find((candidate) => candidate.api === api);
+ assert.ok(model, `${name}: missing ${api} catalog model`);
const sentinel = `LH_OFFLINE_ON_PAYLOAD_${randomUUID()}`;
let reached = 0;
const result = await models.streamSimple(model, { messages: [{ role: "user", content: "Offline initialization only", timestamp: 0 }] }, {
apiKey: "dummy-offline-provider-gate-not-a-key",
onPayload(payload, selected) {
- assert.equal(selected.api, "google-generative-ai");
+ assert.equal(selected.api, api);
assert.ok(payload && typeof payload === "object");
reached++;
throw new Error(sentinel);
@@ -101,7 +106,7 @@ async function probe(standalone) {
assert.equal(result.stopReason, "error");
assert.equal(result.errorMessage, sentinel, `${name}: unexpected initialization error`);
noNetwork();
- console.log(`[smoke-provider-runtime] ${name}: native lazy Google adapter reached onPayload; generation stopped`);
+ console.log(`[smoke-provider-runtime] ${name}: native lazy ${label} adapter reached onPayload; generation stopped`);
}
// Exercise the public lazy OAuth surface offline. toAuth evaluates the
// real flow module and its imports but neither logs in nor refreshes.
diff --git a/src/agent/custom-providers.ts b/src/agent/custom-providers.ts
index 3966ea1..5c82773 100644
--- a/src/agent/custom-providers.ts
+++ b/src/agent/custom-providers.ts
@@ -8,7 +8,7 @@ import { openAICodexResponsesApi } from "@earendil-works/pi-ai/api/openai-codex-
import { azureOpenAIResponsesApi } from "@earendil-works/pi-ai/api/azure-openai-responses.lazy";
import { googleGenerativeAIApi } from "@earendil-works/pi-ai/api/google-generative-ai.lazy";
import { googleVertexApi } from "@earendil-works/pi-ai/api/google-vertex.lazy";
-import { bedrockConverseStreamApi } from "@earendil-works/pi-ai/api/bedrock-converse-stream.lazy";
+import { lazyApi } from "@earendil-works/pi-ai/api/lazy";
import { mistralConversationsApi } from "@earendil-works/pi-ai/api/mistral-conversations.lazy";
import { piMessagesApi } from "@earendil-works/pi-ai/api/pi-messages.lazy";
import { resolveCustomValue, type CustomProviderConfig } from "../core/custom-providers.ts";
@@ -21,7 +21,10 @@ const apis: Record = {
"azure-openai-responses": azureOpenAIResponsesApi(),
"google-generative-ai": googleGenerativeAIApi(),
"google-vertex": googleVertexApi(),
- "bedrock-converse-stream": bedrockConverseStreamApi(),
+ // Pi's Bedrock wrapper intentionally hides its Node-only import from
+ // bundlers. Give this server's standalone tracer a literal public import;
+ // Pi still owns both lazy forwarding and the unchanged native transport.
+ "bedrock-converse-stream": lazyApi(() => import("@earendil-works/pi-ai/api/bedrock-converse-stream")),
"mistral-conversations": mistralConversationsApi(),
"pi-messages": piMessagesApi(),
};
diff --git a/tests/provider-runtime-payload.test.ts b/tests/provider-runtime-payload.test.ts
index dec3213..85c9b8b 100644
--- a/tests/provider-runtime-payload.test.ts
+++ b/tests/provider-runtime-payload.test.ts
@@ -1,4 +1,4 @@
-/** Real installed Pi/Google SDK only; no provider stubs, keys, or generation. */
+/** Real installed Pi/Google/Bedrock SDKs only; no provider stubs, keys, or generation. */
import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import * as fs from "node:fs";
@@ -12,11 +12,12 @@ const checkout = fileURLToPath(new URL("..", import.meta.url));
const run = (payload: string) => spawnSync(process.execPath, [script, "--standalone", payload], { encoding: "utf8", timeout: 40_000 });
describe("offline native Pi Google initialization gate", () => {
- it("reaches the sentinel for direct Google and Google-backed OpenCode adapters using the real SDK", () => {
+ it("reaches the sentinel for Google, Google-backed OpenCode and Bedrock adapters using the real SDKs", () => {
// This is an unbundled positive control, NOT proof of standalone completeness.
const result = run(checkout);
assert.equal(result.status, 0, String(result.stderr));
for (const provider of ["google", "opencode", "opencode-go"]) assert.ok(String(result.stdout).includes(`${provider}: native lazy Google adapter reached onPayload`));
+ assert.ok(String(result.stdout).includes("amazon-bedrock: native lazy Bedrock adapter reached onPayload"));
assert.match(String(result.stdout), /zero network attempts/);
});
it("rejects a missing Pi entry instead of treating any error as success", () => {