mirror of
https://github.com/wassname/pi-telegram.git
synced 2026-06-27 16:16:14 +08:00
feat: improve model selection UX and fix queue/status behaviors
- Add search/filtering to the `/model` command with multi-word matching - Finalize partial stream previews (e.g. thinking blocks) on turn abort instead of clearing them - Dynamically format low-cost `$ value` metrics up to 5 decimal places in status outputs - Update queue tests to expect text-turn plans for aborted turns with partial text
This commit is contained in:
@@ -1023,6 +1023,7 @@ export default function (pi: ExtensionAPI) {
|
|||||||
|
|
||||||
async function getModelMenuState(
|
async function getModelMenuState(
|
||||||
chatId: number,
|
chatId: number,
|
||||||
|
args: string | undefined,
|
||||||
ctx: ExtensionContext,
|
ctx: ExtensionContext,
|
||||||
): Promise<TelegramModelMenuState> {
|
): Promise<TelegramModelMenuState> {
|
||||||
const { SettingsManager } = await import("@mariozechner/pi-coding-agent");
|
const { SettingsManager } = await import("@mariozechner/pi-coding-agent");
|
||||||
@@ -1040,6 +1041,7 @@ export default function (pi: ExtensionAPI) {
|
|||||||
availableModels,
|
availableModels,
|
||||||
configuredScopedModelPatterns: configuredScopedModels,
|
configuredScopedModelPatterns: configuredScopedModels,
|
||||||
cliScopedModelPatterns: cliScopedModels ?? undefined,
|
cliScopedModelPatterns: cliScopedModels ?? undefined,
|
||||||
|
filterQuery: args,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1255,6 +1257,7 @@ export default function (pi: ExtensionAPI) {
|
|||||||
async function openModelMenu(
|
async function openModelMenu(
|
||||||
chatId: number,
|
chatId: number,
|
||||||
replyToMessageId: number,
|
replyToMessageId: number,
|
||||||
|
args: string | undefined,
|
||||||
ctx: ExtensionContext,
|
ctx: ExtensionContext,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!ctx.isIdle() && !canOfferInFlightTelegramModelSwitch(ctx)) {
|
if (!ctx.isIdle() && !canOfferInFlightTelegramModelSwitch(ctx)) {
|
||||||
@@ -1265,7 +1268,7 @@ export default function (pi: ExtensionAPI) {
|
|||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const state = await getModelMenuState(chatId, ctx);
|
const state = await getModelMenuState(chatId, args, ctx);
|
||||||
if (state.allModels.length === 0) {
|
if (state.allModels.length === 0) {
|
||||||
await sendTextReply(
|
await sendTextReply(
|
||||||
chatId,
|
chatId,
|
||||||
@@ -1791,8 +1794,8 @@ export default function (pi: ExtensionAPI) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const commandName = parseTelegramCommand(rawText)?.name;
|
const command = parseTelegramCommand(rawText);
|
||||||
const handled = await handleTelegramCommand(commandName, firstMessage, ctx);
|
const handled = await handleTelegramCommand(command?.name, command?.args, firstMessage, ctx);
|
||||||
if (handled) return;
|
if (handled) return;
|
||||||
|
|
||||||
await enqueueTelegramTurn(messages, ctx);
|
await enqueueTelegramTurn(messages, ctx);
|
||||||
|
|||||||
+17
-4
@@ -124,6 +124,7 @@ export interface BuildTelegramModelMenuStateParams {
|
|||||||
availableModels: Model<any>[];
|
availableModels: Model<any>[];
|
||||||
configuredScopedModelPatterns: string[];
|
configuredScopedModelPatterns: string[];
|
||||||
cliScopedModelPatterns?: string[];
|
cliScopedModelPatterns?: string[];
|
||||||
|
filterQuery?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TelegramMenuCallbackAction =
|
export type TelegramMenuCallbackAction =
|
||||||
@@ -416,8 +417,17 @@ export function getModelMenuItems(
|
|||||||
export function buildTelegramModelMenuState(
|
export function buildTelegramModelMenuState(
|
||||||
params: BuildTelegramModelMenuStateParams,
|
params: BuildTelegramModelMenuStateParams,
|
||||||
): TelegramModelMenuState {
|
): TelegramModelMenuState {
|
||||||
|
let filteredAvailableModels = params.availableModels;
|
||||||
|
if (params.filterQuery) {
|
||||||
|
const terms = params.filterQuery.toLowerCase().split(/\s+/).filter(Boolean);
|
||||||
|
filteredAvailableModels = filteredAvailableModels.filter((m) => {
|
||||||
|
const target = `${m.provider}/${m.id}`.toLowerCase();
|
||||||
|
return terms.every((t) => target.includes(t));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const allModels = sortScopedModels(
|
const allModels = sortScopedModels(
|
||||||
params.availableModels.map((model) => ({ model })),
|
filteredAvailableModels.map((model) => ({ model })),
|
||||||
params.activeModel,
|
params.activeModel,
|
||||||
);
|
);
|
||||||
const scopedModels =
|
const scopedModels =
|
||||||
@@ -425,7 +435,7 @@ export function buildTelegramModelMenuState(
|
|||||||
? sortScopedModels(
|
? sortScopedModels(
|
||||||
resolveScopedModelPatterns(
|
resolveScopedModelPatterns(
|
||||||
params.configuredScopedModelPatterns,
|
params.configuredScopedModelPatterns,
|
||||||
params.availableModels,
|
filteredAvailableModels,
|
||||||
),
|
),
|
||||||
params.activeModel,
|
params.activeModel,
|
||||||
)
|
)
|
||||||
@@ -433,17 +443,20 @@ export function buildTelegramModelMenuState(
|
|||||||
let note: string | undefined;
|
let note: string | undefined;
|
||||||
if (
|
if (
|
||||||
params.configuredScopedModelPatterns.length > 0 &&
|
params.configuredScopedModelPatterns.length > 0 &&
|
||||||
scopedModels.length === 0
|
scopedModels.length === 0 &&
|
||||||
|
!params.filterQuery
|
||||||
) {
|
) {
|
||||||
note = params.cliScopedModelPatterns
|
note = params.cliScopedModelPatterns
|
||||||
? "No CLI scoped models matched the current auth configuration. Showing all available models."
|
? "No CLI scoped models matched the current auth configuration. Showing all available models."
|
||||||
: "No scoped models matched the current auth configuration. Showing all available models.";
|
: "No scoped models matched the current auth configuration. Showing all available models.";
|
||||||
|
} else if (params.filterQuery && filteredAvailableModels.length === 0) {
|
||||||
|
note = "No models matched your search query.";
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
chatId: params.chatId,
|
chatId: params.chatId,
|
||||||
messageId: 0,
|
messageId: 0,
|
||||||
page: 0,
|
page: 0,
|
||||||
scope: scopedModels.length > 0 ? "scoped" : "all",
|
scope: (scopedModels.length > 0 && !params.filterQuery) ? "scoped" : "all",
|
||||||
scopedModels,
|
scopedModels,
|
||||||
allModels,
|
allModels,
|
||||||
note,
|
note,
|
||||||
|
|||||||
@@ -367,6 +367,15 @@ export function buildTelegramAgentEndPlan(options: {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (options.stopReason === "aborted") {
|
if (options.stopReason === "aborted") {
|
||||||
|
if (options.hasFinalText) {
|
||||||
|
return {
|
||||||
|
kind: "text",
|
||||||
|
shouldClearPreview: false,
|
||||||
|
shouldDispatchNext,
|
||||||
|
shouldSendErrorMessage: false,
|
||||||
|
shouldSendAttachmentNotice: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
kind: "aborted",
|
kind: "aborted",
|
||||||
shouldClearPreview: true,
|
shouldClearPreview: true,
|
||||||
|
|||||||
+8
-1
@@ -65,12 +65,19 @@ function buildUsageSummary(stats: TelegramUsageStats): string | undefined {
|
|||||||
return tokenParts.length > 0 ? tokenParts.join(" ") : undefined;
|
return tokenParts.length > 0 ? tokenParts.join(" ") : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatCost(cost: number): string {
|
||||||
|
if (cost === 0) return "0.00";
|
||||||
|
if (cost < 0.001) return cost.toFixed(5);
|
||||||
|
if (cost < 0.01) return cost.toFixed(4);
|
||||||
|
return cost.toFixed(3);
|
||||||
|
}
|
||||||
|
|
||||||
function buildCostSummary(
|
function buildCostSummary(
|
||||||
stats: TelegramUsageStats,
|
stats: TelegramUsageStats,
|
||||||
usesSubscription: boolean,
|
usesSubscription: boolean,
|
||||||
): string | undefined {
|
): string | undefined {
|
||||||
if (!stats.totalCost && !usesSubscription) return undefined;
|
if (!stats.totalCost && !usesSubscription) return undefined;
|
||||||
return `$${stats.totalCost.toFixed(3)}${usesSubscription ? " (sub)" : ""}`;
|
return `$${formatCost(stats.totalCost)}${usesSubscription ? " (sub)" : ""}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildContextSummary(
|
function buildContextSummary(
|
||||||
|
|||||||
@@ -526,6 +526,16 @@ test("Agent end plan classifies turn outcomes correctly", () => {
|
|||||||
assert.equal(abortedPlan.kind, "aborted");
|
assert.equal(abortedPlan.kind, "aborted");
|
||||||
assert.equal(abortedPlan.shouldClearPreview, true);
|
assert.equal(abortedPlan.shouldClearPreview, true);
|
||||||
assert.equal(abortedPlan.shouldDispatchNext, false);
|
assert.equal(abortedPlan.shouldDispatchNext, false);
|
||||||
|
const abortedTextPlan = __telegramTestUtils.buildTelegramAgentEndPlan({
|
||||||
|
hasTurn: true,
|
||||||
|
stopReason: "aborted",
|
||||||
|
preserveQueuedTurnsAsHistory: true,
|
||||||
|
hasFinalText: true,
|
||||||
|
hasQueuedAttachments: false,
|
||||||
|
});
|
||||||
|
assert.equal(abortedTextPlan.kind, "text");
|
||||||
|
assert.equal(abortedTextPlan.shouldClearPreview, false);
|
||||||
|
assert.equal(abortedTextPlan.shouldDispatchNext, false);
|
||||||
const errorPlan = __telegramTestUtils.buildTelegramAgentEndPlan({
|
const errorPlan = __telegramTestUtils.buildTelegramAgentEndPlan({
|
||||||
hasTurn: true,
|
hasTurn: true,
|
||||||
stopReason: "error",
|
stopReason: "error",
|
||||||
|
|||||||
Reference in New Issue
Block a user