chore(vendor): import pi 1.3.0

Imported as a linear vendor commit so forge rebases do not replay the upstream root tree.

git-subtree-dir: third_party/pi

git-subtree-split: 71023aec1546d6d677a65669c5665c0927ce0dd0
This commit is contained in:
2026-10-15 17:58:48 -04:00
parent 719370c8f7
commit 6081e3e325
1743 changed files with 205460 additions and 131705 deletions

View File

@@ -13,16 +13,18 @@ import type {
FauxProviderRegistration,
FauxResponseStep,
Model,
ToolResultMessage,
} from "@earendil-works/pi-ai/compat";
import { registerFauxProvider, streamSimple } from "@earendil-works/pi-ai/compat";
import { AgentSession, type AgentSessionEvent } from "../../src/core/agent-session.ts";
import { AuthStorage } from "../../src/core/auth-storage.ts";
import type { ExtensionRunner } from "../../src/core/extensions/index.ts";
import type { ExtensionRunner, ExtensionUIContext } from "../../src/core/extensions/index.ts";
import { convertToLlm } from "../../src/core/messages.ts";
import { SessionManager } from "../../src/core/session-manager.ts";
import type { Settings } from "../../src/core/settings-manager.ts";
import { SettingsManager } from "../../src/core/settings-manager.ts";
import type { InlineExtension, ResourceLoader } from "../../src/index.ts";
import { theme } from "../../src/modes/interactive/theme/theme.ts";
import {
type CreateTestExtensionsResultInput,
createTestExtensionsResult,
@@ -60,10 +62,55 @@ export function getAssistantTexts(harness: Harness): string[] {
.map((message) => getMessageText(message));
}
/** The latest result of `toolName` in the session transcript. */
export function getToolResult(harness: Harness, toolName: string): ToolResultMessage {
const result = harness.session.messages.findLast(
(message): message is ToolResultMessage => message.role === "toolResult" && message.toolName === toolName,
);
if (!result) throw new Error(`No ${toolName} tool result`);
return result;
}
/** An extension UI context that does nothing, with `overrides` applied. */
export function createTestUiContext(overrides: Partial<ExtensionUIContext> = {}): ExtensionUIContext {
return {
select: async () => undefined,
confirm: async () => false,
input: async () => undefined,
notify: () => {},
onTerminalInput: () => () => {},
setStatus: () => {},
setWorkingMessage: () => {},
setWorkingVisible: () => {},
setWorkingIndicator: () => {},
setHiddenThinkingLabel: () => {},
setWidget: () => {},
setFooter: () => {},
setHeader: () => {},
setTitle: () => {},
custom: async <T>() => undefined as T,
pasteToEditor: () => {},
setEditorText: () => {},
getEditorText: () => "",
editor: async () => undefined,
addAutocompleteProvider: () => {},
setEditorComponent: () => {},
getEditorComponent: () => undefined,
get theme() {
return theme;
},
getAllThemes: () => [],
getTheme: () => undefined,
setTheme: () => ({ success: false, error: "Theme switching not available in tests" }),
getToolsExpanded: () => false,
setToolsExpanded: () => {},
...overrides,
};
}
export interface HarnessOptions {
models?: FauxModelDefinition[];
settings?: Partial<Settings>;
systemPrompt?: string;
tools?: AgentTool[];
initialActiveToolNames?: string[];
allowedToolNames?: string[];
@@ -72,6 +119,8 @@ export interface HarnessOptions {
extensionFactories?: Array<InlineExtension | CreateTestExtensionsResultInput>;
withConfiguredAuth?: boolean;
modelsJson?: Record<string, unknown>;
/** Session to continue, for example to test a resume. Default: a new in-memory session. */
sessionManager?: SessionManager;
}
export interface Harness {
@@ -109,7 +158,7 @@ export async function createHarness(options: HarnessOptions = {}): Promise<Harne
const withConfiguredAuth = options.withConfiguredAuth ?? true;
const extensionRunnerRef: { current?: ExtensionRunner } = {};
const sessionManager = SessionManager.inMemory();
const sessionManager = options.sessionManager ?? SessionManager.inMemory();
const settingsManager = SettingsManager.inMemory(options.settings);
const authStorage = AuthStorage.inMemory();
@@ -132,6 +181,7 @@ export async function createHarness(options: HarnessOptions = {}): Promise<Harne
api: registeredModel.api,
reasoning: registeredModel.reasoning,
input: registeredModel.input,
inputLimits: registeredModel.inputLimits,
cost: registeredModel.cost,
contextWindow: registeredModel.contextWindow,
maxTokens: registeredModel.maxTokens,
@@ -145,7 +195,7 @@ export async function createHarness(options: HarnessOptions = {}): Promise<Harne
streamFn: streamSimple,
initialState: {
model,
systemPrompt: options.systemPrompt ?? "You are a test assistant.",
systemPrompt: "",
tools: [],
},
convertToLlm,
@@ -188,6 +238,7 @@ export async function createHarness(options: HarnessOptions = {}): Promise<Harne
resourceLoader,
baseToolsOverride: toolMap,
initialActiveToolNames: options.initialActiveToolNames,
usesDefaultTools: options.initialActiveToolNames === undefined,
allowedToolNames: options.allowedToolNames,
excludedToolNames: options.excludedToolNames,
extensionRunnerRef,