feat: use managed model capabilities for reasoning and image input
This commit is contained in:
@@ -98,6 +98,7 @@ import {
|
||||
} from './extension-ui-projector';
|
||||
|
||||
type RuntimeIdKind = 'run' | 'queue';
|
||||
import { buildManagedModelRequest, managedPiThinkingLevel, validateManagedReasoningChoice } from '../../../shared/managed-model-capabilities';
|
||||
|
||||
export interface PiConversationRuntimeOptions {
|
||||
pool: PiWorkerPool;
|
||||
@@ -306,6 +307,9 @@ export function createPiManagedWorkerOpener(
|
||||
let extension;
|
||||
try {
|
||||
extension = await options.extensionHost.registerWorker({
|
||||
...(selection.managedCapability ? { managedModelRequest: buildManagedModelRequest(
|
||||
model.modelId, model.reasoningChoice ?? { mode: 'default' }, selection.managedCapability,
|
||||
) } : {}),
|
||||
conversationId: input.conversation.conversationId,
|
||||
generation: input.generation,
|
||||
projectId: input.conversation.projectId,
|
||||
@@ -796,6 +800,7 @@ export class PiConversationRuntime implements CodingConversationRuntime {
|
||||
}
|
||||
|
||||
this.snapshot(input.conversationId);
|
||||
const managedRequest = await this.prepareManagedRequest(input.conversationId, input.attachments.length > 0);
|
||||
const images = await this.resolveImages(input.attachments);
|
||||
const runId = this.id('run');
|
||||
this.acquireRunBackgroundLease(input.conversationId, runId);
|
||||
@@ -823,7 +828,7 @@ export class PiConversationRuntime implements CodingConversationRuntime {
|
||||
let ticket;
|
||||
try {
|
||||
if (this.extensionHost && generation) {
|
||||
await this.extensionHost.bindRun(input.conversationId, generation, runId);
|
||||
await this.extensionHost.bindRun(input.conversationId, generation, runId, managedRequest);
|
||||
}
|
||||
ticket = this.pool.startTopLevel({
|
||||
conversationId: input.conversationId,
|
||||
@@ -902,10 +907,12 @@ export class PiConversationRuntime implements CodingConversationRuntime {
|
||||
|
||||
async validateModel(model: ProductModelRef): Promise<ProductModelRef> {
|
||||
const selection = await this.resolveModel(model);
|
||||
if (selection.managedCapability) validateManagedReasoningChoice(model.reasoningChoice ?? { mode: 'default' }, selection.managedCapability);
|
||||
return {
|
||||
accountId: selection.accountId,
|
||||
modelId: selection.modelId,
|
||||
thinkingLevel: model.thinkingLevel,
|
||||
...(selection.managedCapability ? { reasoningChoice: model.reasoningChoice ?? { mode: 'default' as const } } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -924,6 +931,7 @@ export class PiConversationRuntime implements CodingConversationRuntime {
|
||||
accountId: selection.accountId,
|
||||
modelId: selection.modelId,
|
||||
thinkingLevel,
|
||||
...(selection.managedCapability ? { reasoningChoice: { mode: 'default' as const } } : {}),
|
||||
},
|
||||
modelResolution: 'resolved',
|
||||
};
|
||||
@@ -981,6 +989,16 @@ export class PiConversationRuntime implements CodingConversationRuntime {
|
||||
true,
|
||||
);
|
||||
}
|
||||
const selection = current.model.accountId === 'niancode-user-models' ? await this.resolveModel(current.model) : undefined;
|
||||
if (selection?.managedCapability) {
|
||||
const choice = input.reasoningChoice ?? (input.thinkingLevel === 'off'
|
||||
? { mode: 'disabled' as const } : { mode: 'enabled' as const, effort: input.thinkingLevel });
|
||||
validateManagedReasoningChoice(choice, selection.managedCapability);
|
||||
await this.pool.request(input.conversationId, { type: 'set_thinking_level', level: managedPiThinkingLevel(choice) });
|
||||
return this.persistEffectiveThinking(input.conversationId, {
|
||||
model: { ...current.model, thinkingLevel: 'off', reasoningChoice: choice }, modelResolution: 'resolved',
|
||||
}, {}, {}, true, true);
|
||||
}
|
||||
const capabilities = await this.pool.request<{ levels?: unknown }>(
|
||||
input.conversationId,
|
||||
{ type: 'get_available_thinking_levels' },
|
||||
@@ -1025,6 +1043,7 @@ export class PiConversationRuntime implements CodingConversationRuntime {
|
||||
async compact(conversationId: string): Promise<void> {
|
||||
await this.waitForProjection(conversationId);
|
||||
this.assertNoUncertainMutation(conversationId);
|
||||
const managedRequest = await this.prepareManagedRequest(conversationId, false);
|
||||
const runId = this.id('run');
|
||||
this.acquireRunBackgroundLease(conversationId, runId);
|
||||
const generation = this.pool.getState(conversationId)?.generation;
|
||||
@@ -1032,7 +1051,7 @@ export class PiConversationRuntime implements CodingConversationRuntime {
|
||||
let ticket;
|
||||
try {
|
||||
if (this.extensionHost && generation) {
|
||||
await this.extensionHost.bindRun(conversationId, generation, runId);
|
||||
await this.extensionHost.bindRun(conversationId, generation, runId, managedRequest);
|
||||
}
|
||||
ticket = this.pool.startTopLevel({
|
||||
conversationId,
|
||||
@@ -1317,6 +1336,7 @@ export class PiConversationRuntime implements CodingConversationRuntime {
|
||||
if (snapshot.run.runId) {
|
||||
this.acquireRunBackgroundLease(input.conversationId, snapshot.run.runId);
|
||||
}
|
||||
await this.prepareManagedRequest(input.conversationId, input.attachments.length > 0);
|
||||
const images = await this.resolveImages(input.attachments);
|
||||
const queuePosition = snapshot.queue.items.length + 1;
|
||||
const queueId = this.id('queue');
|
||||
@@ -1809,6 +1829,17 @@ export class PiConversationRuntime implements CodingConversationRuntime {
|
||||
this.states.set(conversationId, createConversationReducerState(projected));
|
||||
}
|
||||
|
||||
private async prepareManagedRequest(conversationId: string, hasImages: boolean) {
|
||||
const model = this.snapshot(conversationId).conversation.model.model;
|
||||
if (!model || model.accountId !== 'niancode-user-models') return undefined;
|
||||
const selection = await this.resolveModel(model);
|
||||
if (!selection.managedCapability) return undefined;
|
||||
if (hasImages && !selection.input.includes('image')) {
|
||||
throw new CodingRuntimeContractError('CODING_MODEL_UNAVAILABLE', '该模型尚未确认支持图片输入,请选择支持图片的模型', true);
|
||||
}
|
||||
return buildManagedModelRequest(model.modelId, model.reasoningChoice ?? { mode: 'default' }, selection.managedCapability);
|
||||
}
|
||||
|
||||
private async persistEffectiveThinking(
|
||||
conversationId: string,
|
||||
requested: ConversationModelState,
|
||||
@@ -1818,6 +1849,19 @@ export class PiConversationRuntime implements CodingConversationRuntime {
|
||||
forcePersist = false,
|
||||
): Promise<ConversationModelState> {
|
||||
if (!requested.model) return clone(requested);
|
||||
const selection = requested.model.accountId === 'niancode-user-models' ? await this.resolveModel(requested.model) : undefined;
|
||||
if (selection?.managedCapability) {
|
||||
const durable: ConversationModelState = {
|
||||
model: { ...requested.model, thinkingLevel: 'off',
|
||||
reasoningChoice: requested.model.reasoningChoice ?? { mode: 'default' } },
|
||||
modelResolution: 'resolved',
|
||||
};
|
||||
const persisted = await this.registry.setModel(conversationId, durable);
|
||||
this.pool.updateConversationModel(conversationId, persisted);
|
||||
const result = { ...persisted, managedCapability: selection.managedCapability };
|
||||
if (replaceSnapshot) this.replaceModel(conversationId, result);
|
||||
return clone(result);
|
||||
}
|
||||
const effective = effectiveThinkingLevel(stateValue) ?? requested.model.thinkingLevel;
|
||||
const available = availableThinkingLevels(capabilitiesValue);
|
||||
if (!available.includes(effective)) available.push(effective);
|
||||
|
||||
Reference in New Issue
Block a user