Merge main into model-registry
This commit is contained in:
@@ -127,6 +127,30 @@ function getAliases(): Record<string, string> {
|
||||
|
||||
type HandlerFn = (...args: unknown[]) => Promise<unknown>;
|
||||
|
||||
let extensionCacheCwd: string | undefined;
|
||||
let extensionCacheGeneration = 0;
|
||||
const extensionCache = new Map<string, ExtensionFactory>();
|
||||
|
||||
interface ExtensionCacheToken {
|
||||
cwd: string;
|
||||
generation: number;
|
||||
}
|
||||
|
||||
export function clearExtensionCache(): void {
|
||||
extensionCache.clear();
|
||||
extensionCacheCwd = undefined;
|
||||
extensionCacheGeneration++;
|
||||
}
|
||||
|
||||
function useExtensionCacheCwd(cwd: string): ExtensionCacheToken {
|
||||
const resolvedCwd = resolvePath(cwd);
|
||||
if (extensionCacheCwd !== undefined && extensionCacheCwd !== resolvedCwd) {
|
||||
clearExtensionCache();
|
||||
}
|
||||
extensionCacheCwd = resolvedCwd;
|
||||
return { cwd: resolvedCwd, generation: extensionCacheGeneration };
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a runtime with throwing stubs for action methods.
|
||||
* Runner.bindCore() replaces these with real implementations.
|
||||
@@ -338,7 +362,22 @@ function createExtensionAPI(
|
||||
return api;
|
||||
}
|
||||
|
||||
async function loadExtensionModule(extensionPath: string) {
|
||||
function isCurrentCacheToken(cacheToken: ExtensionCacheToken | undefined): cacheToken is ExtensionCacheToken {
|
||||
return (
|
||||
cacheToken !== undefined &&
|
||||
extensionCacheCwd === cacheToken.cwd &&
|
||||
extensionCacheGeneration === cacheToken.generation
|
||||
);
|
||||
}
|
||||
|
||||
async function loadExtensionModule(extensionPath: string, cacheToken?: ExtensionCacheToken) {
|
||||
if (isCurrentCacheToken(cacheToken)) {
|
||||
const cachedFactory = extensionCache.get(extensionPath);
|
||||
if (cachedFactory) {
|
||||
return cachedFactory;
|
||||
}
|
||||
}
|
||||
|
||||
const jiti = createJiti(import.meta.url, {
|
||||
moduleCache: false,
|
||||
// In Bun binary: use virtualModules for bundled packages (no filesystem resolution)
|
||||
@@ -349,7 +388,13 @@ async function loadExtensionModule(extensionPath: string) {
|
||||
|
||||
const module = await jiti.import(extensionPath, { default: true });
|
||||
const factory = module as ExtensionFactory;
|
||||
return typeof factory !== "function" ? undefined : factory;
|
||||
if (typeof factory !== "function") {
|
||||
return undefined;
|
||||
}
|
||||
if (isCurrentCacheToken(cacheToken)) {
|
||||
extensionCache.set(extensionPath, factory);
|
||||
}
|
||||
return factory;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -380,11 +425,12 @@ async function loadExtension(
|
||||
cwd: string,
|
||||
eventBus: EventBus,
|
||||
runtime: ExtensionRuntime,
|
||||
cacheToken?: ExtensionCacheToken,
|
||||
): Promise<{ extension: Extension | null; error: string | null }> {
|
||||
const resolvedPath = resolvePath(extensionPath, cwd, { normalizeUnicodeSpaces: true });
|
||||
|
||||
try {
|
||||
const factory = await loadExtensionModule(resolvedPath);
|
||||
const factory = await loadExtensionModule(resolvedPath, cacheToken);
|
||||
if (!factory) {
|
||||
return { extension: null, error: `Extension does not export a valid factory function: ${extensionPath}` };
|
||||
}
|
||||
@@ -420,20 +466,28 @@ export async function loadExtensionFromFactory(
|
||||
/**
|
||||
* Load extensions from paths.
|
||||
*/
|
||||
export async function loadExtensions(
|
||||
async function loadExtensionsInternal(
|
||||
paths: string[],
|
||||
cwd: string,
|
||||
eventBus?: EventBus,
|
||||
runtime?: ExtensionRuntime,
|
||||
useCache = false,
|
||||
): Promise<LoadExtensionsResult> {
|
||||
const extensions: Extension[] = [];
|
||||
const errors: Array<{ path: string; error: string }> = [];
|
||||
const resolvedCwd = resolvePath(cwd);
|
||||
const cacheToken = useCache ? useExtensionCacheCwd(cwd) : undefined;
|
||||
const resolvedCwd = cacheToken?.cwd ?? resolvePath(cwd);
|
||||
const resolvedEventBus = eventBus ?? createEventBus();
|
||||
const resolvedRuntime = runtime ?? createExtensionRuntime();
|
||||
|
||||
for (const extPath of paths) {
|
||||
const { extension, error } = await loadExtension(extPath, resolvedCwd, resolvedEventBus, resolvedRuntime);
|
||||
const { extension, error } = await loadExtension(
|
||||
extPath,
|
||||
resolvedCwd,
|
||||
resolvedEventBus,
|
||||
resolvedRuntime,
|
||||
cacheToken,
|
||||
);
|
||||
|
||||
if (error) {
|
||||
errors.push({ path: extPath, error });
|
||||
@@ -452,6 +506,24 @@ export async function loadExtensions(
|
||||
};
|
||||
}
|
||||
|
||||
export async function loadExtensions(
|
||||
paths: string[],
|
||||
cwd: string,
|
||||
eventBus?: EventBus,
|
||||
runtime?: ExtensionRuntime,
|
||||
): Promise<LoadExtensionsResult> {
|
||||
return loadExtensionsInternal(paths, cwd, eventBus, runtime);
|
||||
}
|
||||
|
||||
export async function loadExtensionsCached(
|
||||
paths: string[],
|
||||
cwd: string,
|
||||
eventBus?: EventBus,
|
||||
runtime?: ExtensionRuntime,
|
||||
): Promise<LoadExtensionsResult> {
|
||||
return loadExtensionsInternal(paths, cwd, eventBus, runtime, true);
|
||||
}
|
||||
|
||||
interface PiManifest {
|
||||
extensions?: string[];
|
||||
themes?: string[];
|
||||
|
||||
@@ -571,6 +571,10 @@ export interface SessionBeforeCompactEvent {
|
||||
preparation: CompactionPreparation;
|
||||
branchEntries: SessionEntry[];
|
||||
customInstructions?: string;
|
||||
/** What triggered the compaction: manual /compact, the context threshold, or context overflow recovery */
|
||||
reason: "manual" | "threshold" | "overflow";
|
||||
/** True when the aborted turn is retried after this compaction (overflow recovery) */
|
||||
willRetry: boolean;
|
||||
signal: AbortSignal;
|
||||
}
|
||||
|
||||
@@ -579,6 +583,10 @@ export interface SessionCompactEvent {
|
||||
type: "session_compact";
|
||||
compactionEntry: CompactionEntry;
|
||||
fromExtension: boolean;
|
||||
/** What triggered the compaction: manual /compact, the context threshold, or context overflow recovery */
|
||||
reason: "manual" | "threshold" | "overflow";
|
||||
/** True when the aborted turn is retried after this compaction (overflow recovery) */
|
||||
willRetry: boolean;
|
||||
}
|
||||
|
||||
/** Fired before an extension runtime is torn down due to quit, reload, or session replacement. */
|
||||
|
||||
Reference in New Issue
Block a user