feat(01-04): add BeforeModelSelectEvent to extension API and wire emission
- Add BeforeModelSelectEvent interface and BeforeModelSelectResult type to types.ts
- Add on('before_model_select') subscription overload to ExtensionAPI interface
- Add emitBeforeModelSelect() method to ExtensionAPI interface and ExtensionRuntimeState
- Implement emitBeforeModelSelect() on ExtensionRunner using invokeHandlers (first-override-wins)
- Bind runner's emitBeforeModelSelect into shared runtime at construction time
- Wire emitBeforeModelSelect delegation through createExtensionAPI in loader.ts
This commit is contained in:
parent
1866ccf781
commit
1cea7fb8bc
3 changed files with 51 additions and 0 deletions
|
|
@ -428,6 +428,8 @@ export function createExtensionRuntime(): ExtensionRuntime {
|
|||
unregisterProvider: (name) => {
|
||||
runtime.pendingProviderRegistrations = runtime.pendingProviderRegistrations.filter((r) => r.name !== name);
|
||||
},
|
||||
// Stub replaced by ExtensionRunner at construction time via bindEmitMethods().
|
||||
emitBeforeModelSelect: async () => undefined,
|
||||
};
|
||||
|
||||
return runtime;
|
||||
|
|
@ -579,6 +581,10 @@ function createExtensionAPI(
|
|||
runtime.unregisterProvider(name);
|
||||
},
|
||||
|
||||
async emitBeforeModelSelect(event: Omit<import("./types.js").BeforeModelSelectEvent, "type">): Promise<import("./types.js").BeforeModelSelectResult | undefined> {
|
||||
return runtime.emitBeforeModelSelect(event);
|
||||
},
|
||||
|
||||
events: eventBus,
|
||||
} as ExtensionAPI;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import type { SessionManager } from "../session-manager.js";
|
|||
import type {
|
||||
BeforeAgentStartEvent,
|
||||
BeforeAgentStartEventResult,
|
||||
BeforeModelSelectEvent,
|
||||
BeforeModelSelectResult,
|
||||
BeforeProviderRequestEvent,
|
||||
CompactOptions,
|
||||
ContextEvent,
|
||||
|
|
@ -230,6 +232,8 @@ export class ExtensionRunner {
|
|||
this.cwd = cwd;
|
||||
this.sessionManager = sessionManager;
|
||||
this.modelRegistry = modelRegistry;
|
||||
// Bind emit methods into the shared runtime so createExtensionAPI can delegate to them.
|
||||
this.runtime.emitBeforeModelSelect = (event) => this.emitBeforeModelSelect(event);
|
||||
}
|
||||
|
||||
bindCore(actions: ExtensionActions, contextActions: ExtensionContextActions): void {
|
||||
|
|
@ -694,6 +698,21 @@ export class ExtensionRunner {
|
|||
return currentPayload;
|
||||
}
|
||||
|
||||
async emitBeforeModelSelect(event: Omit<BeforeModelSelectEvent, "type">): Promise<BeforeModelSelectResult | undefined> {
|
||||
let result: BeforeModelSelectResult | undefined;
|
||||
await this.invokeHandlers("before_model_select", () => ({
|
||||
type: "before_model_select" as const,
|
||||
...event,
|
||||
} satisfies BeforeModelSelectEvent), (handlerResult) => {
|
||||
if (handlerResult) {
|
||||
result = handlerResult as BeforeModelSelectResult;
|
||||
return { done: true }; // first override wins
|
||||
}
|
||||
return { done: false };
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
async emitBeforeAgentStart(
|
||||
prompt: string,
|
||||
images: ImageContent[] | undefined,
|
||||
|
|
|
|||
|
|
@ -603,6 +603,22 @@ export interface ModelSelectEvent {
|
|||
source: ModelSelectSource;
|
||||
}
|
||||
|
||||
/** Fired before model selection runs capability scoring. Extensions can override the selected model. */
|
||||
export interface BeforeModelSelectEvent {
|
||||
type: "before_model_select";
|
||||
unitType: string;
|
||||
unitId: string;
|
||||
classification: { tier: string; reason: string; downgraded: boolean };
|
||||
taskMetadata?: Record<string, unknown>;
|
||||
eligibleModels: string[];
|
||||
phaseConfig?: { primary: string; fallbacks: string[] };
|
||||
}
|
||||
|
||||
/** Result from before_model_select event handler. Return { modelId } to override selection. */
|
||||
export interface BeforeModelSelectResult {
|
||||
modelId: string;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// User Bash Events
|
||||
// ============================================================================
|
||||
|
|
@ -1052,6 +1068,14 @@ export interface ExtensionAPI {
|
|||
on(event: "tool_result", handler: ExtensionHandler<ToolResultEvent, ToolResultEventResult>): void;
|
||||
on(event: "user_bash", handler: ExtensionHandler<UserBashEvent, UserBashEventResult>): void;
|
||||
on(event: "input", handler: ExtensionHandler<InputEvent, InputEventResult>): void;
|
||||
on(event: "before_model_select", handler: ExtensionHandler<BeforeModelSelectEvent, BeforeModelSelectResult>): void;
|
||||
|
||||
// =========================================================================
|
||||
// Event Emission (for host extensions that orchestrate model selection)
|
||||
// =========================================================================
|
||||
|
||||
/** Emit before_model_select event. Returns override model ID or undefined. */
|
||||
emitBeforeModelSelect(event: Omit<BeforeModelSelectEvent, "type">): Promise<BeforeModelSelectResult | undefined>;
|
||||
|
||||
// =========================================================================
|
||||
// Tool Registration
|
||||
|
|
@ -1367,6 +1391,8 @@ export interface ExtensionRuntimeState {
|
|||
*/
|
||||
registerProvider: (name: string, config: ProviderConfig) => void;
|
||||
unregisterProvider: (name: string) => void;
|
||||
/** Emit before_model_select event to all registered handlers. Bound by ExtensionRunner. */
|
||||
emitBeforeModelSelect: (event: Omit<BeforeModelSelectEvent, "type">) => Promise<BeforeModelSelectResult | undefined>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue