Revert "fix(dashboard): lazy-init useMobileKeyboard so remount has no stale render"

This reverts commit 3f5d01f4d4.
This commit is contained in:
gsxdsm
2026-05-06 21:40:55 -07:00
parent 3f5d01f4d4
commit 8ec6c1086f
5 changed files with 60 additions and 181 deletions

View File

@@ -993,36 +993,6 @@ describe("createFnAgent", () => {
}));
});
it("continues session creation when setting thinking level hits reasoning conflict", async () => {
const { piLog } = await import("../logger.js");
const warnSpy = vi.spyOn(piLog, "warn").mockImplementation(() => {});
const setThinkingLevel = vi.fn(() => {
throw new Error("400 cannot specify both 'thinking' and 'reasoning_effort'");
});
createAgentSessionMock.mockResolvedValueOnce({
session: {
prompt: vi.fn(),
subscribe: vi.fn(),
dispose: vi.fn(),
setThinkingLevel,
},
});
const { createFnAgent } = await import("../pi.js");
await expect(createFnAgent({
cwd: "/tmp",
systemPrompt: "test",
tools: "readonly",
defaultThinkingLevel: "high",
})).resolves.toBeTruthy();
expect(setThinkingLevel).toHaveBeenCalledWith("high");
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("Disabling explicit thinking level"));
warnSpy.mockRestore();
});
describe("skill selection", () => {
beforeEach(() => {
// Reset modules to ensure fresh imports for each test

View File

@@ -662,53 +662,11 @@ describe("session failure diagnostics", () => {
await expect((session as any).promptWithFallback("Run task")).resolves.toBeUndefined();
expect(warnSpy).toHaveBeenCalledWith(
expect.stringContaining("Failed to dispose session during swap: dispose failed"),
expect.stringContaining("Failed to dispose session during model fallback swap: dispose failed"),
);
warnSpy.mockRestore();
});
it("retries prompt on thinking/reasoning conflict without switching fallback models", async () => {
const createAgentSessionMock = vi.mocked(createAgentSession);
const firstSession = {
model: { provider: "test", id: "primary-model" },
prompt: vi.fn().mockRejectedValue(new Error("400 cannot specify both 'thinking' and 'reasoning_effort'")),
subscribe: vi.fn(),
dispose: vi.fn(),
setThinkingLevel: vi.fn(),
sessionFile: undefined,
} as unknown as AgentSession;
const retrySession = {
model: { provider: "test", id: "primary-model" },
prompt: vi.fn().mockResolvedValue(undefined),
subscribe: vi.fn(),
dispose: vi.fn(),
setThinkingLevel: vi.fn(),
sessionFile: undefined,
} as unknown as AgentSession;
createAgentSessionMock.mockReset();
createAgentSessionMock
.mockResolvedValueOnce({ session: firstSession } as any)
.mockResolvedValueOnce({ session: retrySession } as any);
const { session } = await createFnAgent({
cwd: "/test/project",
systemPrompt: "Test thinking compatibility",
defaultProvider: "test",
defaultModelId: "primary-model",
fallbackProvider: "test",
fallbackModelId: "fallback-model",
defaultThinkingLevel: "high",
});
await expect((session as any).promptWithFallback("Run review")).resolves.toBeUndefined();
expect(createAgentSessionMock).toHaveBeenCalledTimes(2);
expect((retrySession.setThinkingLevel as any).mock.calls.length).toBe(0);
});
});
describe("piLog structured diagnostics", () => {

View File

@@ -130,10 +130,6 @@ function clearSessionStateError(session: AgentSession): void {
}
}
function isThinkingReasoningConflictError(message: string): boolean {
return /cannot specify both\s+['"]?thinking['"]?\s+and\s+['"]?reasoning_effort['"]?/i.test(message);
}
async function promptSessionAndCheck(session: AgentSession, prompt: string, options?: unknown): Promise<void> {
clearSessionStateError(session);
if (options === undefined) {
@@ -1287,83 +1283,21 @@ export async function createFnAgent(options: AgentOptions): Promise<AgentResult>
piLog.log("Fallback session created successfully");
}
let activeSession = sessionResult.session;
installToolResultContentGuard(activeSession as AgentToolHookSession);
installMessageContentGuard(activeSession as AgentToolHookSession, sessionManager as unknown as SessionManagerLike);
(activeSession as any).__fusionMemoryAppendAvailable = options.customTools?.some((tool) => tool.name === FN_MEMORY_APPEND_TOOL_NAME) === true;
const promptableSession = activeSession as PromptableSession;
let thinkingCompatibilityDisabled = false;
const applyThinkingLevelIfSupported = (targetSession: AgentSession, sourceModel: string): void => {
if (!options.defaultThinkingLevel || thinkingCompatibilityDisabled) {
return;
}
try {
(targetSession as PromptableSession).setThinkingLevel(options.defaultThinkingLevel as any);
} catch (err: unknown) {
const message = err instanceof Error ? err.message : String(err);
if (!isThinkingReasoningConflictError(message)) {
throw err;
}
thinkingCompatibilityDisabled = true;
piLog.warn(`Disabling explicit thinking level for model ${sourceModel}: ${message}`);
}
};
const wireFallbackHooks = (targetSession: PromptableSession): void => {
installToolResultContentGuard(targetSession as unknown as AgentToolHookSession);
installMessageContentGuard(
targetSession as unknown as AgentToolHookSession,
sessionManager as unknown as SessionManagerLike,
);
(targetSession as any).__fusionMemoryAppendAvailable = options.customTools?.some((tool) => tool.name === FN_MEMORY_APPEND_TOOL_NAME) === true;
targetSession.subscribe((event) => {
if (event.type === "message_update") {
const msgEvent = event.assistantMessageEvent;
if (msgEvent.type === "text_delta") {
options.onText?.(msgEvent.delta);
} else if (msgEvent.type === "thinking_delta") {
options.onThinking?.(msgEvent.delta);
}
}
if (event.type === "tool_execution_start") {
options.onToolStart?.(event.toolName, event.args as Record<string, unknown> | undefined);
}
if (event.type === "tool_execution_end") {
options.onToolEnd?.(event.toolName, event.isError, event.result);
}
});
};
const swapPromptSession = async (modelToUse: typeof selectedModel): Promise<PromptableSession> => {
if (!modelToUse) {
throw new Error("Cannot swap session without a resolved model");
}
try {
activeSession.dispose();
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
piLog.warn(`Failed to dispose session during swap: ${msg}`);
}
const next = (await createSessionWithModel(modelToUse)).session as PromptableSession;
wireFallbackHooks(next);
applyThinkingLevelIfSupported(next, `${modelToUse.provider}/${modelToUse.id}`);
Object.setPrototypeOf(promptableSession, Object.getPrototypeOf(next));
Object.assign(promptableSession, next);
promptableSession.promptWithFallback = next.promptWithFallback ?? promptableSession.promptWithFallback;
activeSession = next;
return next;
};
const { session } = sessionResult;
installToolResultContentGuard(session as AgentToolHookSession);
installMessageContentGuard(session as AgentToolHookSession, sessionManager as unknown as SessionManagerLike);
(session as any).__fusionMemoryAppendAvailable = options.customTools?.some((tool) => tool.name === FN_MEMORY_APPEND_TOOL_NAME) === true;
const promptableSession = session as PromptableSession;
promptableSession.promptWithFallback = async (prompt: string, promptOptions?: unknown) => {
try {
await promptSessionAndCheck(activeSession, prompt, promptOptions);
await promptSessionAndCheck(session, prompt, promptOptions);
return;
} catch (err: any) {
const errorMessage = err?.message || "";
if (isContextLimitError(errorMessage)) {
// Context limit error — attempt auto-compaction and retry once
const promptMemoryRetry = await retryWithCompactedPromptMemory(activeSession, prompt, promptOptions);
const promptMemoryRetry = await retryWithCompactedPromptMemory(session, prompt, promptOptions);
if (promptMemoryRetry.recovered) {
return;
}
@@ -1375,12 +1309,12 @@ export async function createFnAgent(options: AgentOptions): Promise<AgentResult>
}
piLog.warn("promptWithFallback: context limit error — attempting auto-compaction");
await flushMemoryBeforeSessionCompaction(activeSession);
const compactResult = await compactSessionContext(activeSession);
await flushMemoryBeforeSessionCompaction(session);
const compactResult = await compactSessionContext(session);
if (compactResult) {
piLog.log(`promptWithFallback: compaction succeeded (${compactResult.tokensBefore} tokens) — retrying prompt`);
try {
await promptSessionAndCheck(activeSession, prompt, promptOptions);
await promptSessionAndCheck(session, prompt, promptOptions);
return;
} catch (retryErr: any) {
const retryErrorMessage = retryErr?.message || "";
@@ -1394,21 +1328,52 @@ export async function createFnAgent(options: AgentOptions): Promise<AgentResult>
}
}
if (!usingFallback && options.defaultThinkingLevel && !thinkingCompatibilityDisabled && isThinkingReasoningConflictError(errorMessage)) {
thinkingCompatibilityDisabled = true;
piLog.warn(`Prompt failed with thinking/reasoning conflict; retrying without explicit thinking level: ${errorMessage}`);
const recoveredSession = await swapPromptSession(selectedModel);
await promptSessionAndCheck(recoveredSession, prompt, promptOptions);
return;
}
if (!fallbackModel || usingFallback || !isRetryableModelSelectionError(errorMessage)) {
throw err;
}
usingFallback = true;
const fallbackSession = await swapPromptSession(fallbackModel);
try {
session.dispose();
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
piLog.warn(`Failed to dispose session during model fallback swap: ${msg}`);
}
const fallbackSessionResult = await createSessionWithModel(fallbackModel);
await emitFallbackUsed("prompt-time");
const fallbackSession = fallbackSessionResult.session as PromptableSession;
installToolResultContentGuard(fallbackSession as unknown as AgentToolHookSession);
installMessageContentGuard(
fallbackSession as unknown as AgentToolHookSession,
sessionManager as unknown as SessionManagerLike,
);
(fallbackSession as any).__fusionMemoryAppendAvailable = options.customTools?.some((tool) => tool.name === FN_MEMORY_APPEND_TOOL_NAME) === true;
if (options.defaultThinkingLevel) {
fallbackSession.setThinkingLevel(options.defaultThinkingLevel as any);
}
fallbackSession.subscribe((event) => {
if (event.type === "message_update") {
const msgEvent = event.assistantMessageEvent;
if (msgEvent.type === "text_delta") {
options.onText?.(msgEvent.delta);
} else if (msgEvent.type === "thinking_delta") {
options.onThinking?.(msgEvent.delta);
}
}
if (event.type === "tool_execution_start") {
options.onToolStart?.(event.toolName, event.args as Record<string, unknown> | undefined);
}
if (event.type === "tool_execution_end") {
options.onToolEnd?.(event.toolName, event.isError, event.result);
}
});
Object.setPrototypeOf(promptableSession, Object.getPrototypeOf(fallbackSession));
Object.assign(promptableSession, fallbackSession);
promptableSession.promptWithFallback = fallbackSession.promptWithFallback ?? promptableSession.promptWithFallback;
// Retry with fallback model, also with auto-compaction support
try {
@@ -1451,11 +1416,10 @@ export async function createFnAgent(options: AgentOptions): Promise<AgentResult>
}
};
// Apply thinking level if specified (with compatibility fallback).
applyThinkingLevelIfSupported(
promptableSession,
selectedModel ? `${selectedModel.provider}/${selectedModel.id}` : describeModel(promptableSession),
);
// Apply thinking level if specified
if (options.defaultThinkingLevel) {
promptableSession.setThinkingLevel(options.defaultThinkingLevel as any);
}
// Wire up event listeners
promptableSession.subscribe((event) => {