Archived
fix(sessions): keep ignored provider mutations inert
This commit is contained in:
@@ -3,13 +3,19 @@ import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { ModelRuntime } from "@earendil-works/pi-coding-agent";
|
||||
import { InMemoryCredentialStore, type AuthPrompt, type Credential } from "@earendil-works/pi-ai";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OAuthFlowState } from "../../shared/apiTypes.js";
|
||||
import { AuthService, createModelRuntimeForAgentDir, type AuthChange, type AuthServiceLogger } from "./authService.js";
|
||||
import { OAuthLoginFlowService } from "./oauthLoginFlowService.js";
|
||||
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
beforeEach(() => {
|
||||
// Pi 0.81 uses PI_OFFLINE for refreshes after runtime creation. Auth tests
|
||||
// exercise local credential behavior and must never fetch provider catalogs.
|
||||
vi.stubEnv("PI_OFFLINE", "1");
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
vi.unstubAllEnvs();
|
||||
await Promise.all(tempDirs.splice(0).map((dir) => rm(dir, { recursive: true, force: true })));
|
||||
|
||||
@@ -157,6 +157,27 @@ describe("bootstrapAndFreezeGlobalExtensionProviders", () => {
|
||||
expect(JSON.stringify(ignoredMutations)).not.toContain("secret");
|
||||
});
|
||||
|
||||
it("keeps ignored mutations as no-ops when structured logging fails", async () => {
|
||||
const agentDir = await tempDir("pi-web-global-provider-unit-");
|
||||
const runtime = await createTestModelRuntime();
|
||||
const { logger } = capturingLogger();
|
||||
const loggingError = new Error("provider mutation logger failed");
|
||||
const throwingLogger: GlobalProviderBootstrapLogger = {
|
||||
...logger,
|
||||
info(details, message) {
|
||||
if (message === "ignored provider mutation after global bootstrap") throw loggingError;
|
||||
logger.info(details, message);
|
||||
},
|
||||
};
|
||||
|
||||
await bootstrapAndFreezeGlobalExtensionProviders(runtime, agentDir, throwingLogger);
|
||||
|
||||
expect(() => { registerProjectConfigProvider(runtime); }).not.toThrow();
|
||||
expect(() => { runtime.registerNativeProvider(nativeProvider("project-native")); }).not.toThrow();
|
||||
expect(() => { runtime.unregisterProvider("project-only"); }).not.toThrow();
|
||||
expect(runtime.getRegisteredProviderIds()).toEqual([]);
|
||||
});
|
||||
|
||||
it("logs non-fatal Pi bootstrap diagnostics and still freezes the runtime", async () => {
|
||||
const agentDir = await agentDirWithExtension(`
|
||||
export default function (pi) {
|
||||
|
||||
@@ -62,10 +62,14 @@ function freezeProviderMutations(runtime: ModelRuntime, logger: GlobalProviderBo
|
||||
const loggedIds = loggedProviderIds[operation];
|
||||
if (loggedIds.has(providerId)) return;
|
||||
loggedIds.add(providerId);
|
||||
logger.info(
|
||||
{ context: LOG_CONTEXT, operation, providerId },
|
||||
"ignored provider mutation after global bootstrap",
|
||||
);
|
||||
try {
|
||||
logger.info(
|
||||
{ context: LOG_CONTEXT, operation, providerId },
|
||||
"ignored provider mutation after global bootstrap",
|
||||
);
|
||||
} catch {
|
||||
// Logging must not turn an ignored mutation into an extension failure.
|
||||
}
|
||||
};
|
||||
const frozenMethods: ProviderMutationMethods = {
|
||||
registerProvider(providerId) {
|
||||
|
||||
@@ -4,12 +4,22 @@ import { join } from "node:path";
|
||||
import { createAssistantMessageEventStream, InMemoryCredentialStore, type AssistantMessage } from "@earendil-works/pi-ai";
|
||||
import type { StreamFn } from "@earendil-works/pi-agent-core";
|
||||
import { ModelRuntime } from "@earendil-works/pi-coding-agent";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { PiSessionService } from "./piSessionService.js";
|
||||
import { CapturingSessionEventHub, createTestModelRuntime, fakeRuntime, runtimeCreator, seedCredential, sessionGateway, sessionRecord, sessionRef, TEST_MODEL_ID, TEST_MODEL_PROVIDER, testModel, testModelRuntime, type RuntimeCreator } from "./piSessionService.testSupport.js";
|
||||
|
||||
const TEST_AGENT_DIR = "/tmp/pi-web-test-agent";
|
||||
|
||||
beforeEach(() => {
|
||||
// Pi 0.81 uses PI_OFFLINE for refreshes after runtime creation. These tests
|
||||
// exercise local model/auth behavior and must never fetch provider catalogs.
|
||||
vi.stubEnv("PI_OFFLINE", "1");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
describe("PiSessionService prompt, queue, and auth warnings", () => {
|
||||
it("sends prompts to an injected runtime without touching the SDK runtime", async () => {
|
||||
const fake = fakeRuntime("prompt-session");
|
||||
@@ -78,7 +88,7 @@ describe("PiSessionService prompt, queue, and auth warnings", () => {
|
||||
await service.dispose();
|
||||
});
|
||||
|
||||
it("generates a session name for the first prompt via the session's agent.streamFn", async () => {
|
||||
it("generates a session name for the first prompt via the session's agent.streamFunction", async () => {
|
||||
const model = testModel();
|
||||
const streamCalls: unknown[] = [];
|
||||
const streamFn: StreamFn = (streamModel, context, options) => {
|
||||
|
||||
Reference in New Issue
Block a user