@omercnet/paseo-omp 0.3.0-next.103.1 → 0.3.0-next.104.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/server/provider/catalog.ts +39 -10
- package/server/provider/omp-rpc.ts +50 -17
- package/server/provider/session.ts +104 -46
package/package.json
CHANGED
|
@@ -48,6 +48,27 @@ const THINKING_OPTIONS: readonly ProviderThinkingOption[] = [
|
|
|
48
48
|
{ id: "xhigh", label: "XHigh", description: "Extra-high reasoning" },
|
|
49
49
|
{ id: "max", label: "Max", description: "Maximum reasoning" },
|
|
50
50
|
];
|
|
51
|
+
export const OMP_MAX_CATALOG_MODELS = 256;
|
|
52
|
+
|
|
53
|
+
export function selectOmpModels(
|
|
54
|
+
models: readonly OmpModel[],
|
|
55
|
+
activeModel: OmpModel | null | undefined,
|
|
56
|
+
): OmpModel[] {
|
|
57
|
+
if (models.length <= OMP_MAX_CATALOG_MODELS) return [...models];
|
|
58
|
+
const selected = models.slice(0, OMP_MAX_CATALOG_MODELS);
|
|
59
|
+
if (!activeModel) return selected;
|
|
60
|
+
const active = models.find(
|
|
61
|
+
(model) => model.provider === activeModel.provider && model.id === activeModel.id,
|
|
62
|
+
);
|
|
63
|
+
if (
|
|
64
|
+
!active ||
|
|
65
|
+
selected.some((model) => model.provider === active.provider && model.id === active.id)
|
|
66
|
+
) {
|
|
67
|
+
return selected;
|
|
68
|
+
}
|
|
69
|
+
selected[OMP_MAX_CATALOG_MODELS - 1] = active;
|
|
70
|
+
return selected;
|
|
71
|
+
}
|
|
51
72
|
|
|
52
73
|
export function nativeOmpModelId(model: OmpModel): string {
|
|
53
74
|
if (model.provider.includes("/")) {
|
|
@@ -60,14 +81,9 @@ export function ompModelId(model: OmpModel): string {
|
|
|
60
81
|
const nativeIdentity = `${Buffer.byteLength(model.provider, "utf8")}:${model.provider}${Buffer.byteLength(model.id, "utf8")}:${model.id}`;
|
|
61
82
|
return `omp:model:${createHash("sha256").update(nativeIdentity).digest("hex")}`;
|
|
62
83
|
}
|
|
63
|
-
|
|
64
|
-
export function mapOmpModels(
|
|
65
|
-
models: readonly OmpModel[],
|
|
66
|
-
serializer = new OmpPublicDataSerializer(),
|
|
67
|
-
): ProviderModel[] {
|
|
84
|
+
export function validateOmpModelIdentities(models: readonly OmpModel[]): void {
|
|
68
85
|
const seenIds = new Map<string, string>();
|
|
69
|
-
|
|
70
|
-
const thinkingOptions = thinkingForModel(model);
|
|
86
|
+
for (const model of models) {
|
|
71
87
|
const id = ompModelId(model);
|
|
72
88
|
const nativeIdentity = nativeOmpModelId(model);
|
|
73
89
|
const existing = seenIds.get(id);
|
|
@@ -76,6 +92,17 @@ export function mapOmpModels(
|
|
|
76
92
|
}
|
|
77
93
|
if (existing !== undefined) throw new Error("OMP reported a duplicate model identity");
|
|
78
94
|
seenIds.set(id, nativeIdentity);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function mapOmpModels(
|
|
99
|
+
models: readonly OmpModel[],
|
|
100
|
+
serializer = new OmpPublicDataSerializer(),
|
|
101
|
+
): ProviderModel[] {
|
|
102
|
+
validateOmpModelIdentities(models);
|
|
103
|
+
return models.map((model) => {
|
|
104
|
+
const thinkingOptions = thinkingForModel(model);
|
|
105
|
+
const id = ompModelId(model);
|
|
79
106
|
const provider = serializer.text(model.provider, 256);
|
|
80
107
|
const modelId = serializer.text(model.id, 256);
|
|
81
108
|
const name = model.name ? serializer.text(model.name, 256) : modelId;
|
|
@@ -143,14 +170,16 @@ export async function discoverOmpCatalog(
|
|
|
143
170
|
? [...configuredValues, ...(session.inheritedRedactionValues ?? [])]
|
|
144
171
|
: configuredValues,
|
|
145
172
|
);
|
|
146
|
-
|
|
173
|
+
validateOmpModelIdentities(nativeModels);
|
|
174
|
+
const selectedNativeModels = selectOmpModels(nativeModels, state.model);
|
|
175
|
+
const models = mapOmpModels(selectedNativeModels, serializer);
|
|
147
176
|
if (models.length === 0) throw new Error("OMP reported no available models");
|
|
148
177
|
const defaultModel = state.model ? ompModelId(state.model) : models[0]?.id;
|
|
149
178
|
const currentModel = state.model
|
|
150
|
-
?
|
|
179
|
+
? selectedNativeModels.find(
|
|
151
180
|
(model) => model.provider === state.model?.provider && model.id === state.model.id,
|
|
152
181
|
)
|
|
153
|
-
:
|
|
182
|
+
: selectedNativeModels[0];
|
|
154
183
|
if (state.model && !currentModel) throw new Error("OMP reported an unadvertised active model");
|
|
155
184
|
const thinkingOptions = thinkingForModel(currentModel);
|
|
156
185
|
const defaultThinkingOption = thinkingOptions.some(
|
|
@@ -70,6 +70,7 @@ const MAX_OPTIONAL_METADATA_NODES = 4_096;
|
|
|
70
70
|
const MAX_TASK_CORRELATION_BYTES = 256 * 1024;
|
|
71
71
|
const MAX_TASK_CORRELATION_ITEMS = 1_024;
|
|
72
72
|
const MAX_TASK_CORRELATION_NODES = 4_096;
|
|
73
|
+
const MAX_MODEL_CATALOG_ITEMS = 4_096;
|
|
73
74
|
// Tool-intensive OMP turns legitimately exceed 64 blocks; transport byte/node budgets remain the
|
|
74
75
|
// primary resource bounds.
|
|
75
76
|
export const OMP_MAX_CONTENT_PARTS = 4_096;
|
|
@@ -115,6 +116,17 @@ function boundedString(maxBytes: number, minBytes = 0) {
|
|
|
115
116
|
return bytes >= minBytes && bytes <= maxBytes;
|
|
116
117
|
});
|
|
117
118
|
}
|
|
119
|
+
function boundedOptionalStringArray(maxItems: number, maxBytes: number) {
|
|
120
|
+
return z.unknown().transform((value): string[] | undefined => {
|
|
121
|
+
if (!Array.isArray(value)) return undefined;
|
|
122
|
+
return value
|
|
123
|
+
.filter(
|
|
124
|
+
(item): item is string =>
|
|
125
|
+
typeof item === "string" && item.length > 0 && utf8Bytes(item) <= maxBytes,
|
|
126
|
+
)
|
|
127
|
+
.slice(0, maxItems);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
118
130
|
|
|
119
131
|
const IDENTIFIER = boundedString(MAX_ID_LENGTH, 1);
|
|
120
132
|
const NAME = boundedString(MAX_NAME_LENGTH, 1);
|
|
@@ -191,6 +203,7 @@ function sanitizeLiveDisplayFrame(value: unknown): unknown {
|
|
|
191
203
|
return changed ? { ...frame, messages } : value;
|
|
192
204
|
}
|
|
193
205
|
const OmpThinkingLevelSchema = z.enum(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
|
|
206
|
+
const OmpCurrentThinkingLevelSchema = boundedString(32).optional().catch(undefined);
|
|
194
207
|
|
|
195
208
|
function isBoundedJson(
|
|
196
209
|
value: unknown,
|
|
@@ -546,19 +559,33 @@ const OmpAvailableCommandSchema = z.object({
|
|
|
546
559
|
.optional(),
|
|
547
560
|
source: boundedString(64).optional(),
|
|
548
561
|
});
|
|
562
|
+
const OmpThinkingMetadataSchema = z
|
|
563
|
+
.unknown()
|
|
564
|
+
.transform((value): { efforts?: string[]; defaultLevel?: string } | undefined => {
|
|
565
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
|
|
566
|
+
const record = value as Record<string, unknown>;
|
|
567
|
+
const efforts = boundedOptionalStringArray(16, 32).parse(record.efforts);
|
|
568
|
+
const defaultLevel = boundedString(32).optional().catch(undefined).parse(record.defaultLevel);
|
|
569
|
+
return {
|
|
570
|
+
...(efforts !== undefined ? { efforts } : {}),
|
|
571
|
+
...(defaultLevel !== undefined ? { defaultLevel } : {}),
|
|
572
|
+
};
|
|
573
|
+
});
|
|
549
574
|
const OmpModelSchema = z.object({
|
|
550
575
|
provider: OMP_PROVIDER_NAME,
|
|
551
576
|
id: NAME,
|
|
552
|
-
name: boundedString(MAX_NAME_LENGTH).optional(),
|
|
553
|
-
reasoning: z.boolean().optional(),
|
|
554
|
-
thinking:
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
.
|
|
560
|
-
|
|
561
|
-
|
|
577
|
+
name: boundedString(MAX_NAME_LENGTH).optional().catch(undefined),
|
|
578
|
+
reasoning: z.boolean().optional().catch(undefined),
|
|
579
|
+
thinking: OmpThinkingMetadataSchema.optional(),
|
|
580
|
+
input: boundedOptionalStringArray(16, MAX_NAME_LENGTH).optional(),
|
|
581
|
+
contextWindow: z
|
|
582
|
+
.number()
|
|
583
|
+
.int()
|
|
584
|
+
.nonnegative()
|
|
585
|
+
.max(100_000_000)
|
|
586
|
+
.nullable()
|
|
587
|
+
.optional()
|
|
588
|
+
.catch(undefined),
|
|
562
589
|
});
|
|
563
590
|
const TokenCountSchema = z.number().int().nonnegative().max(MAX_TOKEN_COUNT);
|
|
564
591
|
const OptionalTokenCountSchema = TokenCountSchema.nullable().optional();
|
|
@@ -610,13 +637,13 @@ const OmpCompactionResultSchema = z.object({
|
|
|
610
637
|
});
|
|
611
638
|
const OmpSessionStateSchema = z.object({
|
|
612
639
|
model: OmpModelSchema.nullable().optional(),
|
|
613
|
-
thinkingLevel:
|
|
640
|
+
thinkingLevel: OmpCurrentThinkingLevelSchema,
|
|
614
641
|
isStreaming: z.boolean(),
|
|
615
642
|
isCompacting: z.boolean(),
|
|
616
643
|
sessionId: IDENTIFIER,
|
|
617
644
|
autoCompactionEnabled: z.boolean().optional(),
|
|
618
|
-
contextUsage: OmpContextUsageSchema.nullable().optional(),
|
|
619
|
-
sessionFile: boundedString(MAX_PATH_LENGTH).optional(),
|
|
645
|
+
contextUsage: OmpContextUsageSchema.nullable().optional().catch(undefined),
|
|
646
|
+
sessionFile: boundedString(MAX_PATH_LENGTH).optional().catch(undefined),
|
|
620
647
|
});
|
|
621
648
|
const OmpReadyFrameSchema = z.object({
|
|
622
649
|
type: z.literal("ready"),
|
|
@@ -1217,7 +1244,7 @@ function runtimeFrameCollectionLimit(frame: Record<string, unknown>): number {
|
|
|
1217
1244
|
return 1_024;
|
|
1218
1245
|
}
|
|
1219
1246
|
const OmpModelsResultSchema = z.object({
|
|
1220
|
-
models: z.array(OmpModelSchema).min(1).max(
|
|
1247
|
+
models: z.array(OmpModelSchema).min(1).max(MAX_MODEL_CATALOG_ITEMS),
|
|
1221
1248
|
});
|
|
1222
1249
|
const OmpPromptAckSchema = z.object({ agentInvoked: z.boolean().optional() }).optional();
|
|
1223
1250
|
const OmpAvailableCommandsResultSchema = z.object({
|
|
@@ -2480,13 +2507,19 @@ class OmpRpcProcess {
|
|
|
2480
2507
|
: response.data.data;
|
|
2481
2508
|
const boundedFrame =
|
|
2482
2509
|
responseData === response.data.data ? frame : { ...frame, data: responseData };
|
|
2483
|
-
const responseItemLimit = isBranchHistory
|
|
2510
|
+
const responseItemLimit = isBranchHistory
|
|
2511
|
+
? 1_024
|
|
2512
|
+
: isHistory
|
|
2513
|
+
? 100_000
|
|
2514
|
+
: pending.command === "get_available_models"
|
|
2515
|
+
? MAX_MODEL_CATALOG_ITEMS
|
|
2516
|
+
: MAX_ARRAY_ITEMS;
|
|
2484
2517
|
const responseByteLimit =
|
|
2485
2518
|
isBranchHistory || isHistory
|
|
2486
2519
|
? Math.min(MAX_REASSEMBLED_FRAME_BYTES, this.reassembledFrameLimit)
|
|
2487
2520
|
: 2 * 1024 * 1024;
|
|
2488
|
-
//
|
|
2489
|
-
// node
|
|
2521
|
+
// Model catalogs are truncated before publication, while the transport still enforces
|
|
2522
|
+
// aggregate byte and node budgets over the complete response.
|
|
2490
2523
|
const responseNodeLimit = isBranchHistory
|
|
2491
2524
|
? 4_096
|
|
2492
2525
|
: isHistory
|
|
@@ -11,7 +11,15 @@ import type {
|
|
|
11
11
|
ProviderUsage,
|
|
12
12
|
} from "@getpaseo/plugin/server/provider";
|
|
13
13
|
import { getForgeDefinitionOrNeutral } from "@getpaseo/protocol/forge-manifest";
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
mapOmpModels,
|
|
16
|
+
nativeOmpModelId,
|
|
17
|
+
OMP_MODES,
|
|
18
|
+
ompModelId,
|
|
19
|
+
selectOmpModels,
|
|
20
|
+
thinkingForModel,
|
|
21
|
+
validateOmpModelIdentities,
|
|
22
|
+
} from "./catalog";
|
|
15
23
|
import {
|
|
16
24
|
normalizeOmpSessionConfig,
|
|
17
25
|
type OmpRecoveryOptions,
|
|
@@ -939,6 +947,8 @@ export class OmpProviderSession {
|
|
|
939
947
|
private readonly pendingToolPermissions = new Map<string, PendingToolPermission>();
|
|
940
948
|
private readonly inFlightToolPermissions = new Map<string, PendingToolPermission>();
|
|
941
949
|
private readonly resolvedToolApprovalIds = new BoundedStringSet(MAX_TRACKED_ENTRY_IDS);
|
|
950
|
+
private unsupportedThinkingNoticePending = false;
|
|
951
|
+
private unsupportedThinkingNoticePublished = false;
|
|
942
952
|
|
|
943
953
|
private constructor(
|
|
944
954
|
id: string,
|
|
@@ -1057,10 +1067,9 @@ export class OmpProviderSession {
|
|
|
1057
1067
|
}
|
|
1058
1068
|
const startOptions: OmpStartOptions = {
|
|
1059
1069
|
...normalizedConfig,
|
|
1060
|
-
//
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
: {}),
|
|
1070
|
+
// Thinking is authorized only after this runtime reports its exact model catalog.
|
|
1071
|
+
thinkingOption: undefined,
|
|
1072
|
+
...(resumeSessionId ? { systemPrompt: undefined, resumeSessionId } : {}),
|
|
1064
1073
|
signal,
|
|
1065
1074
|
environment,
|
|
1066
1075
|
};
|
|
@@ -1096,6 +1105,7 @@ export class OmpProviderSession {
|
|
|
1096
1105
|
() => ({ available: false, commands: [] }),
|
|
1097
1106
|
),
|
|
1098
1107
|
]);
|
|
1108
|
+
validateOmpModelIdentities(nativeModels);
|
|
1099
1109
|
if (effectiveConfig.persist && !native.canReplayHistory) {
|
|
1100
1110
|
throw new OmpPublicError("OMP session persistence requires negotiated RPC protocol v2");
|
|
1101
1111
|
}
|
|
@@ -1109,12 +1119,10 @@ export class OmpProviderSession {
|
|
|
1109
1119
|
if (resumeSessionId && initialState.sessionId !== resumeSessionId) {
|
|
1110
1120
|
throw new OmpPublicError("OMP resumed a different native session");
|
|
1111
1121
|
}
|
|
1112
|
-
const models = mapOmpModels(nativeModels, new OmpPublicDataSerializer(outputRedactionValues));
|
|
1113
|
-
const nativeModelsByPublicId = new Map(
|
|
1114
|
-
nativeModels.map((model) => [ompModelId(model), model] as const),
|
|
1115
|
-
);
|
|
1116
1122
|
if (!resumeSessionId && input.config.model) {
|
|
1117
|
-
const selected =
|
|
1123
|
+
const selected = selectOmpModels(nativeModels, state.model).find(
|
|
1124
|
+
(model) => ompModelId(model) === input.config.model,
|
|
1125
|
+
);
|
|
1118
1126
|
if (!selected) {
|
|
1119
1127
|
throw new OmpPublicError("OMP model is not advertised by the configured session runtime");
|
|
1120
1128
|
}
|
|
@@ -1123,9 +1131,29 @@ export class OmpProviderSession {
|
|
|
1123
1131
|
state = await native.getState();
|
|
1124
1132
|
}
|
|
1125
1133
|
}
|
|
1134
|
+
let currentModel = state.model
|
|
1135
|
+
? nativeModels.find(
|
|
1136
|
+
(model) => model.provider === state.model?.provider && model.id === state.model.id,
|
|
1137
|
+
)
|
|
1138
|
+
: undefined;
|
|
1139
|
+
if (state.model && !currentModel) {
|
|
1140
|
+
throw new OmpPublicError("OMP runtime selected an unadvertised model");
|
|
1141
|
+
}
|
|
1142
|
+
if (!resumeSessionId && input.config.thinkingOption !== undefined) {
|
|
1143
|
+
if (
|
|
1144
|
+
!thinkingForModel(currentModel).some(
|
|
1145
|
+
(option) => option.id === input.config.thinkingOption,
|
|
1146
|
+
)
|
|
1147
|
+
) {
|
|
1148
|
+
throw new OmpPublicError("OMP thinking level is unavailable for the selected model");
|
|
1149
|
+
}
|
|
1150
|
+
if (state.thinkingLevel !== input.config.thinkingOption) {
|
|
1151
|
+
await native.setThinkingLevel(input.config.thinkingOption);
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1126
1154
|
const reconciledConfigRevision = bootstrapConfigRevision;
|
|
1127
1155
|
state = await native.getState();
|
|
1128
|
-
|
|
1156
|
+
currentModel = state.model
|
|
1129
1157
|
? nativeModels.find(
|
|
1130
1158
|
(model) => model.provider === state.model?.provider && model.id === state.model.id,
|
|
1131
1159
|
)
|
|
@@ -1133,21 +1161,21 @@ export class OmpProviderSession {
|
|
|
1133
1161
|
if (state.model && !currentModel) {
|
|
1134
1162
|
throw new OmpPublicError("OMP runtime selected an unadvertised model");
|
|
1135
1163
|
}
|
|
1164
|
+
const selectedNativeModels = selectOmpModels(nativeModels, state.model);
|
|
1165
|
+
const models = mapOmpModels(
|
|
1166
|
+
selectedNativeModels,
|
|
1167
|
+
new OmpPublicDataSerializer(outputRedactionValues),
|
|
1168
|
+
);
|
|
1169
|
+
const nativeModelsByPublicId = new Map(
|
|
1170
|
+
nativeModels.map((model) => [ompModelId(model), model] as const),
|
|
1171
|
+
);
|
|
1136
1172
|
const thinkingOptions = thinkingForModel(currentModel);
|
|
1137
|
-
const
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
throw new OmpPublicError("OMP thinking level is unavailable for the selected model");
|
|
1144
|
-
}
|
|
1145
|
-
if (
|
|
1146
|
-
committedThinkingLevel &&
|
|
1147
|
-
!thinkingOptions.some((option) => option.id === committedThinkingLevel)
|
|
1148
|
-
) {
|
|
1149
|
-
throw new OmpPublicError("OMP runtime selected an unsupported thinking level");
|
|
1150
|
-
}
|
|
1173
|
+
const applicableLevel = applicableThinkingLevel(currentModel, state.thinkingLevel);
|
|
1174
|
+
const committedThinkingLevel = thinkingOptions.some((option) => option.id === applicableLevel)
|
|
1175
|
+
? applicableLevel
|
|
1176
|
+
: undefined;
|
|
1177
|
+
const unsupportedThinkingLevel =
|
|
1178
|
+
applicableLevel !== undefined && committedThinkingLevel === undefined;
|
|
1151
1179
|
const configState: ProviderConfigState = {
|
|
1152
1180
|
...(state.model ? { model: ompModelId(state.model) } : {}),
|
|
1153
1181
|
mode: normalizedConfig.mode ?? "full",
|
|
@@ -1210,6 +1238,7 @@ export class OmpProviderSession {
|
|
|
1210
1238
|
retireRewindSession,
|
|
1211
1239
|
scheduler,
|
|
1212
1240
|
);
|
|
1241
|
+
session.unsupportedThinkingNoticePending = unsupportedThinkingLevel;
|
|
1213
1242
|
|
|
1214
1243
|
if (bootstrapConfigRevision !== reconciledConfigRevision) {
|
|
1215
1244
|
session.configRefreshDirty = true;
|
|
@@ -1268,6 +1297,7 @@ export class OmpProviderSession {
|
|
|
1268
1297
|
: {}),
|
|
1269
1298
|
...(this.config.title ? { title: this.dataFilter.text(this.config.title, 256) } : {}),
|
|
1270
1299
|
});
|
|
1300
|
+
this.publishUnsupportedThinkingNotice();
|
|
1271
1301
|
this.emit({ type: "session.config", sessionId: this.id, config: this.configState });
|
|
1272
1302
|
if (this.replayHistoryOnOpen) await this.replayHistory(true);
|
|
1273
1303
|
this.publishCommands(this.commandCatalog);
|
|
@@ -1275,6 +1305,22 @@ export class OmpProviderSession {
|
|
|
1275
1305
|
this.readyPublished = true;
|
|
1276
1306
|
if (this.configRefreshDirty) this.scheduleCommittedConfigRefresh();
|
|
1277
1307
|
}
|
|
1308
|
+
private publishUnsupportedThinkingNotice(): void {
|
|
1309
|
+
if (!this.unsupportedThinkingNoticePending || this.unsupportedThinkingNoticePublished) return;
|
|
1310
|
+
this.unsupportedThinkingNoticePending = false;
|
|
1311
|
+
this.unsupportedThinkingNoticePublished = true;
|
|
1312
|
+
this.emit({
|
|
1313
|
+
type: "session.notice",
|
|
1314
|
+
sessionId: this.id,
|
|
1315
|
+
notice: {
|
|
1316
|
+
id: "omp:unsupported-thinking-level",
|
|
1317
|
+
severity: "warning",
|
|
1318
|
+
title: "OMP thinking level unavailable",
|
|
1319
|
+
description:
|
|
1320
|
+
"OMP reported a thinking level that the active model does not advertise. Paseo omitted it from the session configuration.",
|
|
1321
|
+
},
|
|
1322
|
+
});
|
|
1323
|
+
}
|
|
1278
1324
|
|
|
1279
1325
|
private usageFrom(
|
|
1280
1326
|
state: OmpSessionState | undefined,
|
|
@@ -1685,6 +1731,17 @@ export class OmpProviderSession {
|
|
|
1685
1731
|
if (this.activeTurn || beforeState.isStreaming || beforeState.isCompacting) {
|
|
1686
1732
|
throw new OmpPublicError("Cannot rewind the OMP conversation while a turn is active");
|
|
1687
1733
|
}
|
|
1734
|
+
const beforeAdvertisedModel = beforeState.model
|
|
1735
|
+
? this.nativeModelsByPublicId.get(ompModelId(beforeState.model))
|
|
1736
|
+
: undefined;
|
|
1737
|
+
if (beforeState.model && !beforeAdvertisedModel) {
|
|
1738
|
+
throw new OmpPublicError("OMP runtime selected an unadvertised model");
|
|
1739
|
+
}
|
|
1740
|
+
const restorableThinkingLevel = thinkingForModel(beforeAdvertisedModel).some(
|
|
1741
|
+
(option) => option.id === beforeState.thinkingLevel,
|
|
1742
|
+
)
|
|
1743
|
+
? beforeState.thinkingLevel
|
|
1744
|
+
: undefined;
|
|
1688
1745
|
branchMutationPossible = true;
|
|
1689
1746
|
let result: OmpBranchResult;
|
|
1690
1747
|
try {
|
|
@@ -1727,13 +1784,10 @@ export class OmpProviderSession {
|
|
|
1727
1784
|
}
|
|
1728
1785
|
await runtime.setModel(beforeState.model.provider, beforeState.model.id);
|
|
1729
1786
|
}
|
|
1730
|
-
if (thinkingChanged) {
|
|
1731
|
-
|
|
1732
|
-
throw new OmpPublicError("OMP changed thinking level while rewinding the conversation");
|
|
1733
|
-
}
|
|
1734
|
-
await runtime.setThinkingLevel(beforeState.thinkingLevel);
|
|
1787
|
+
if (thinkingChanged && restorableThinkingLevel) {
|
|
1788
|
+
await runtime.setThinkingLevel(restorableThinkingLevel);
|
|
1735
1789
|
}
|
|
1736
|
-
if (modelChanged || thinkingChanged) {
|
|
1790
|
+
if (modelChanged || (thinkingChanged && restorableThinkingLevel)) {
|
|
1737
1791
|
state = await runtime.getState();
|
|
1738
1792
|
this.requireCurrentRuntime(runtime, generation);
|
|
1739
1793
|
}
|
|
@@ -1741,7 +1795,7 @@ export class OmpProviderSession {
|
|
|
1741
1795
|
state.sessionId !== this.nativeSessionId ||
|
|
1742
1796
|
state.model?.provider !== beforeState.model?.provider ||
|
|
1743
1797
|
state.model?.id !== beforeState.model?.id ||
|
|
1744
|
-
state.thinkingLevel !==
|
|
1798
|
+
(restorableThinkingLevel !== undefined && state.thinkingLevel !== restorableThinkingLevel)
|
|
1745
1799
|
) {
|
|
1746
1800
|
throw new OmpPublicError("OMP did not preserve session configuration while rewinding");
|
|
1747
1801
|
}
|
|
@@ -2341,7 +2395,10 @@ export class OmpProviderSession {
|
|
|
2341
2395
|
const targetModel = targetModelId
|
|
2342
2396
|
? this.nativeModelsByPublicId.get(targetModelId)
|
|
2343
2397
|
: undefined;
|
|
2344
|
-
|
|
2398
|
+
const targetModelPublished = this.configState.models.some(
|
|
2399
|
+
(model) => model.id === targetModelId,
|
|
2400
|
+
);
|
|
2401
|
+
if (input.changes.model !== undefined && (!targetModel || !targetModelPublished)) {
|
|
2345
2402
|
throw new OmpPublicError("OMP model selection is unavailable");
|
|
2346
2403
|
}
|
|
2347
2404
|
if (
|
|
@@ -2588,13 +2645,18 @@ export class OmpProviderSession {
|
|
|
2588
2645
|
throw new OmpCatalogEscape("OMP runtime selected an unadvertised model");
|
|
2589
2646
|
}
|
|
2590
2647
|
const thinkingOptions = thinkingForModel(advertisedModel);
|
|
2591
|
-
const
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
) {
|
|
2596
|
-
|
|
2648
|
+
const applicableLevel = applicableThinkingLevel(advertisedModel, state.thinkingLevel);
|
|
2649
|
+
const committedThinkingLevel = thinkingOptions.some((option) => option.id === applicableLevel)
|
|
2650
|
+
? applicableLevel
|
|
2651
|
+
: undefined;
|
|
2652
|
+
if (applicableLevel !== undefined && committedThinkingLevel === undefined) {
|
|
2653
|
+
this.unsupportedThinkingNoticePending = true;
|
|
2654
|
+
this.publishUnsupportedThinkingNotice();
|
|
2597
2655
|
}
|
|
2656
|
+
const models = mapOmpModels(
|
|
2657
|
+
selectOmpModels([...this.nativeModelsByPublicId.values()], state.model),
|
|
2658
|
+
this.dataFilter,
|
|
2659
|
+
);
|
|
2598
2660
|
this.configRefreshAttempts = 0;
|
|
2599
2661
|
this.cancelConfigRefreshRetry();
|
|
2600
2662
|
const nextConfig: ProviderConfigState = {
|
|
@@ -2603,12 +2665,15 @@ export class OmpProviderSession {
|
|
|
2603
2665
|
...(committedThinkingLevel
|
|
2604
2666
|
? { thinkingOption: committedThinkingLevel }
|
|
2605
2667
|
: { thinkingOption: undefined }),
|
|
2668
|
+
models,
|
|
2606
2669
|
thinkingOptions,
|
|
2607
2670
|
};
|
|
2608
2671
|
const changed =
|
|
2609
2672
|
force ||
|
|
2610
2673
|
nextConfig.model !== this.configState.model ||
|
|
2611
2674
|
nextConfig.thinkingOption !== this.configState.thinkingOption ||
|
|
2675
|
+
nextConfig.models.some((model, index) => model.id !== this.configState.models[index]?.id) ||
|
|
2676
|
+
this.configState.models.length !== nextConfig.models.length ||
|
|
2612
2677
|
nextConfig.thinkingOptions.length !== this.configState.thinkingOptions.length ||
|
|
2613
2678
|
nextConfig.thinkingOptions.some(
|
|
2614
2679
|
(option, index) =>
|
|
@@ -2929,13 +2994,6 @@ export class OmpProviderSession {
|
|
|
2929
2994
|
if (state.model && !advertisedModel) {
|
|
2930
2995
|
throw new Error("OMP recovered with an unadvertised model");
|
|
2931
2996
|
}
|
|
2932
|
-
const recoveredThinkingLevel = applicableThinkingLevel(advertisedModel, state.thinkingLevel);
|
|
2933
|
-
if (
|
|
2934
|
-
recoveredThinkingLevel &&
|
|
2935
|
-
!thinkingForModel(advertisedModel).some((option) => option.id === recoveredThinkingLevel)
|
|
2936
|
-
) {
|
|
2937
|
-
throw new Error("OMP recovered with an unsupported thinking level");
|
|
2938
|
-
}
|
|
2939
2997
|
if (this.closed) throw new Error("OMP session closed while runtime recovery was pending");
|
|
2940
2998
|
if (!this.hostTools.isBoundTo(recovered)) {
|
|
2941
2999
|
throw new Error("OMP host tool bridge detached during recovery");
|