fix(extensions): preserve service-tier host compatibility
This commit is contained in:
@@ -72,6 +72,10 @@ export type ExtensionErrorListener = (error: ExtensionError) => void;
|
||||
export const EXTENSION_HANDLER_TIMEOUT_MS = 30_000;
|
||||
let extensionHandlerTimeoutMs = EXTENSION_HANDLER_TIMEOUT_MS;
|
||||
|
||||
function throwUnsupportedServiceTierAction(): never {
|
||||
throw new Error("This extension host does not support service-tier actions");
|
||||
}
|
||||
|
||||
export function testSetExtensionHandlerTimeoutMs(timeoutMs: number): void {
|
||||
extensionHandlerTimeoutMs = timeoutMs;
|
||||
}
|
||||
@@ -298,8 +302,8 @@ export class ExtensionRunner {
|
||||
this.runtime.setModel = actions.setModel;
|
||||
this.runtime.getThinkingLevel = actions.getThinkingLevel;
|
||||
this.runtime.setThinkingLevel = actions.setThinkingLevel;
|
||||
this.runtime.getServiceTiers = actions.getServiceTiers;
|
||||
this.runtime.setServiceTier = actions.setServiceTier;
|
||||
this.runtime.getServiceTiers = actions.getServiceTiers ?? throwUnsupportedServiceTierAction;
|
||||
this.runtime.setServiceTier = actions.setServiceTier ?? throwUnsupportedServiceTierAction;
|
||||
this.runtime.getSessionName = actions.getSessionName;
|
||||
this.runtime.setSessionName = actions.setSessionName;
|
||||
|
||||
|
||||
@@ -1455,8 +1455,8 @@ export interface ExtensionActions {
|
||||
setModel: SetModelHandler;
|
||||
getThinkingLevel: GetThinkingLevelHandler;
|
||||
setThinkingLevel: SetThinkingLevelHandler;
|
||||
getServiceTiers: GetServiceTiersHandler;
|
||||
setServiceTier: SetServiceTierHandler;
|
||||
getServiceTiers?: GetServiceTiersHandler;
|
||||
setServiceTier?: SetServiceTierHandler;
|
||||
getSessionName: () => string | undefined;
|
||||
setSessionName: (name: string) => Promise<void>;
|
||||
}
|
||||
@@ -1488,8 +1488,11 @@ export interface ExtensionCommandContextActions {
|
||||
reload: () => Promise<void>;
|
||||
}
|
||||
|
||||
/** Full runtime = state + actions. */
|
||||
export interface ExtensionRuntime extends ExtensionRuntimeState, ExtensionActions {}
|
||||
/** Full runtime = state + actions, including host-compatible service-tier fallbacks. */
|
||||
export interface ExtensionRuntime extends ExtensionRuntimeState, ExtensionActions {
|
||||
getServiceTiers: GetServiceTiersHandler;
|
||||
setServiceTier: SetServiceTierHandler;
|
||||
}
|
||||
|
||||
/** Loaded extension with all registered items. */
|
||||
export interface Extension {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Tests for ExtensionRunner - conflict detection, error handling, tool wrapping.
|
||||
*/
|
||||
|
||||
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "bun:test";
|
||||
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, expectTypeOf, it, vi } from "bun:test";
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import type { AgentMessage, AgentTool } from "@oh-my-pi/pi-agent-core";
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
ExtensionRunner,
|
||||
testSetExtensionHandlerTimeoutMs,
|
||||
} from "@oh-my-pi/pi-coding-agent/extensibility/extensions/runner";
|
||||
import type { ExtensionError } from "@oh-my-pi/pi-coding-agent/extensibility/extensions/types";
|
||||
import type { ExtensionError, ExtensionServiceTier } from "@oh-my-pi/pi-coding-agent/extensibility/extensions/types";
|
||||
import { ExtensionToolWrapper } from "@oh-my-pi/pi-coding-agent/extensibility/extensions/wrapper";
|
||||
import { Type } from "@oh-my-pi/pi-coding-agent/extensibility/typebox";
|
||||
import { AuthStorage } from "@oh-my-pi/pi-coding-agent/session/auth-storage";
|
||||
@@ -529,8 +529,6 @@ describe("ExtensionRunner", () => {
|
||||
setModel: async () => false,
|
||||
getThinkingLevel: () => undefined,
|
||||
setThinkingLevel: () => {},
|
||||
getServiceTiers: () => ({}),
|
||||
setServiceTier: () => {},
|
||||
getSessionName: () => undefined,
|
||||
setSessionName: async () => {},
|
||||
},
|
||||
@@ -1208,8 +1206,6 @@ describe("ExtensionRunner", () => {
|
||||
setModel: async () => false,
|
||||
getThinkingLevel: () => undefined,
|
||||
setThinkingLevel: () => {},
|
||||
getServiceTiers: () => ({}),
|
||||
setServiceTier: () => {},
|
||||
getSessionName: () => undefined,
|
||||
setSessionName: async () => {},
|
||||
},
|
||||
@@ -1237,6 +1233,14 @@ describe("ExtensionRunner", () => {
|
||||
});
|
||||
|
||||
describe("service tier API", () => {
|
||||
it("restricts tiers to values supported by each provider family", () => {
|
||||
expectTypeOf<"scale">().toExtend<ExtensionServiceTier<"openai">>();
|
||||
expectTypeOf<"flex">().toExtend<ExtensionServiceTier<"google">>();
|
||||
expectTypeOf<"priority">().toExtend<ExtensionServiceTier<"anthropic">>();
|
||||
expectTypeOf<"scale">().not.toExtend<ExtensionServiceTier<"google">>();
|
||||
expectTypeOf<"flex">().not.toExtend<ExtensionServiceTier<"anthropic">>();
|
||||
});
|
||||
|
||||
it("returns a detached snapshot, forwards valid changes, and rejects invalid family tiers", async () => {
|
||||
const extCode = `
|
||||
export default function(pi) {
|
||||
@@ -1246,8 +1250,13 @@ describe("ExtensionRunner", () => {
|
||||
pi.appendEntry("service-tier-snapshot", tiers);
|
||||
pi.setServiceTier("google", "flex");
|
||||
pi.setServiceTier("openai", undefined);
|
||||
});
|
||||
pi.on("session_start", () => {
|
||||
pi.setServiceTier("anthropic", "scale");
|
||||
});
|
||||
pi.on("session_start", () => {
|
||||
pi.setServiceTier("bogus", "priority");
|
||||
});
|
||||
}
|
||||
`;
|
||||
const explicitExtensionPath = path.join(tempDir.path(), "service-tiers.ts");
|
||||
@@ -1309,8 +1318,9 @@ describe("ExtensionRunner", () => {
|
||||
["google", "flex"],
|
||||
["openai", undefined],
|
||||
]);
|
||||
expect(errors).toHaveLength(1);
|
||||
expect(errors).toHaveLength(2);
|
||||
expect(errors[0]).toContain('Invalid service tier "scale" for family "anthropic"');
|
||||
expect(errors[1]).toContain('Invalid service tier "priority" for family "bogus"');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1350,8 +1360,6 @@ describe("ExtensionRunner", () => {
|
||||
setModel: async () => false,
|
||||
getThinkingLevel: () => undefined,
|
||||
setThinkingLevel: () => {},
|
||||
getServiceTiers: () => ({}),
|
||||
setServiceTier: () => {},
|
||||
getSessionName: () => sessionManager.getSessionName(),
|
||||
setSessionName: async name => {
|
||||
await sessionManager.setSessionName(name);
|
||||
@@ -1410,8 +1418,6 @@ describe("ExtensionRunner", () => {
|
||||
setModel: async () => false,
|
||||
getThinkingLevel: () => undefined,
|
||||
setThinkingLevel: () => {},
|
||||
getServiceTiers: () => ({}),
|
||||
setServiceTier: () => {},
|
||||
getSessionName: () => undefined,
|
||||
setSessionName: async () => {},
|
||||
},
|
||||
@@ -2079,8 +2085,6 @@ describe("ExtensionRunner", () => {
|
||||
setModel: async () => false,
|
||||
getThinkingLevel: () => undefined,
|
||||
setThinkingLevel: () => {},
|
||||
getServiceTiers: () => ({}),
|
||||
setServiceTier: () => {},
|
||||
getSessionName: () => sessionManager.getSessionName(),
|
||||
setSessionName: async () => {},
|
||||
},
|
||||
|
||||
@@ -60,8 +60,6 @@ const initializeRunnerForTest = (runner: ExtensionRunner | undefined): void => {
|
||||
setModel: async () => false,
|
||||
getThinkingLevel: () => undefined,
|
||||
setThinkingLevel: () => {},
|
||||
getServiceTiers: () => ({}),
|
||||
setServiceTier: () => {},
|
||||
getSessionName: () => undefined,
|
||||
setSessionName: async () => {},
|
||||
},
|
||||
@@ -529,8 +527,6 @@ describe("createAgentSession credential_disabled subscription", () => {
|
||||
setModel: async () => false,
|
||||
getThinkingLevel: () => undefined,
|
||||
setThinkingLevel: () => {},
|
||||
getServiceTiers: () => ({}),
|
||||
setServiceTier: () => {},
|
||||
getSessionName: () => undefined,
|
||||
setSessionName: async () => {},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user