Add extensions option to createAgentSession SDK

- Accept ExtensionFactory[] for inline extensions (merged with discovery)
- Mark preloadedExtensions as @internal (CLI implementation detail)
- Update sdk.md with inline extension example
- Update CHANGELOG
This commit is contained in:
Mario Zechner 2026-01-05 03:38:56 +01:00
parent 8da793b1ba
commit 79cb8f0906
6 changed files with 138 additions and 24 deletions

View file

@ -29,9 +29,11 @@ import { AuthStorage } from "./auth-storage.js";
import { createEventBus, type EventBus } from "./event-bus.js";
import {
discoverAndLoadExtensions,
type ExtensionFactory,
ExtensionRunner,
type LoadExtensionsResult,
type LoadedExtension,
loadExtensionFromFactory,
type ToolDefinition,
wrapRegisteredTools,
wrapToolsWithExtensions,
@ -99,9 +101,14 @@ export interface CreateAgentSessionOptions {
tools?: Tool[];
/** Custom tools to register (in addition to built-in tools). */
customTools?: ToolDefinition[];
/** Inline extensions (merged with discovery). */
extensions?: ExtensionFactory[];
/** Additional extension paths to load (merged with discovery). */
additionalExtensionPaths?: string[];
/** Pre-loaded extensions (skips loading, used when extensions were loaded early for CLI flags). */
/**
* Pre-loaded extensions (skips file discovery).
* @internal Used by CLI when extensions are loaded early to parse custom flags.
*/
preloadedExtensions?: LoadedExtension[];
/** Shared event bus for tool/extension communication. Default: creates new bus. */
@ -447,6 +454,42 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
}
}
// Load inline extensions from factories
if (options.extensions && options.extensions.length > 0) {
// Create shared UI context holder that will be set later
const uiHolder: { ui: any; hasUI: boolean } = {
ui: {
select: async () => undefined,
confirm: async () => false,
input: async () => undefined,
notify: () => {},
setStatus: () => {},
setWidget: () => {},
setTitle: () => {},
custom: async () => undefined as never,
setEditorText: () => {},
getEditorText: () => "",
editor: async () => undefined,
get theme() {
return {} as any;
},
},
hasUI: false,
};
for (let i = 0; i < options.extensions.length; i++) {
const factory = options.extensions[i];
const loaded = loadExtensionFromFactory(factory, cwd, eventBus, uiHolder, `<inline-${i}>`);
extensionsResult.extensions.push(loaded);
}
// Extend setUIContext to update inline extensions too
const originalSetUIContext = extensionsResult.setUIContext;
extensionsResult.setUIContext = (uiContext, hasUI) => {
originalSetUIContext(uiContext, hasUI);
uiHolder.ui = uiContext;
uiHolder.hasUI = hasUI;
};
}
// Create extension runner if we have extensions
let extensionRunner: ExtensionRunner | undefined;
if (extensionsResult.extensions.length > 0) {