@vellumai/assistant 0.11.1-staging.1 → 0.11.1-staging.3
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/openapi.yaml +7 -1
- package/package.json +1 -1
- package/src/__tests__/agent-loop-override-profile.test.ts +21 -14
- package/src/__tests__/config-callsite-patch-merge.test.ts +92 -0
- package/src/__tests__/config-loader-backfill.test.ts +10 -10
- package/src/__tests__/drain-requeue-on-contention.test.ts +124 -0
- package/src/__tests__/managed-profile-guard.test.ts +2 -4
- package/src/__tests__/queued-message-delete-contract.test.ts +339 -0
- package/src/__tests__/worker-entrypoint-guards.test.ts +39 -0
- package/src/api/events/message-requeued.ts +35 -0
- package/src/api/index.ts +6 -0
- package/src/config/__tests__/default-profile-catalog.test.ts +9 -0
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/daemon/conversation-process.ts +77 -12
- package/src/daemon/conversation-queue-manager.ts +19 -0
- package/src/daemon/handlers/conversations.ts +77 -9
- package/src/daemon/shutdown-handlers.ts +20 -7
- package/src/persistence/embeddings/__tests__/embedding-local-lifecycle.test.ts +755 -0
- package/src/persistence/embeddings/embedding-backend.ts +109 -0
- package/src/persistence/embeddings/embedding-local.ts +677 -135
- package/src/persistence/embeddings/embedding-types.ts +19 -0
- package/src/plugin-api/vision-support.test.ts +11 -10
- package/src/plugins/defaults/memory/worker.ts +54 -10
- package/src/providers/__tests__/preflight-resolved-config.test.ts +25 -0
- package/src/providers/__tests__/vellum-mismatch-routing.test.ts +108 -1
- package/src/providers/connection-resolution.ts +61 -1
- package/src/providers/inference/connection-availability.ts +13 -1
- package/src/providers/inference/connections.ts +44 -3
- package/src/providers/routing-identity.ts +2 -1
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +4 -4
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +57 -4
- package/src/runtime/routes/conversation-query-routes.ts +38 -5
- package/src/runtime/routes/inference-provider-connection-routes.ts +27 -3
package/openapi.yaml
CHANGED
|
@@ -20459,7 +20459,9 @@ paths:
|
|
|
20459
20459
|
delete:
|
|
20460
20460
|
operationId: messages_queued_by_id_delete
|
|
20461
20461
|
summary: Delete a queued message
|
|
20462
|
-
description:
|
|
20462
|
+
description:
|
|
20463
|
+
Remove a pending message from the conversation queue before it is processed. Broadcasts
|
|
20464
|
+
`message_queued_deleted` so every client can close out the pending row.
|
|
20463
20465
|
tags:
|
|
20464
20466
|
- messages
|
|
20465
20467
|
parameters:
|
|
@@ -20477,6 +20479,10 @@ paths:
|
|
|
20477
20479
|
responses:
|
|
20478
20480
|
"200":
|
|
20479
20481
|
description: Successful response
|
|
20482
|
+
"403":
|
|
20483
|
+
description: The queued message was enqueued by a different actor principal.
|
|
20484
|
+
"404":
|
|
20485
|
+
description: Conversation or queued message not found.
|
|
20480
20486
|
/v1/messages/queued/{id}/steer:
|
|
20481
20487
|
post:
|
|
20482
20488
|
operationId: messages_queued_by_id_steer_post
|
package/package.json
CHANGED
|
@@ -276,21 +276,28 @@ import { VELLUM_MANAGED_CONNECTION_NAME } from "../providers/vellum-model-routin
|
|
|
276
276
|
// Connection-aware resolver path: satisfy
|
|
277
277
|
// `tryResolveProviderForConnectionName` lookups so resolveDefaultProvider
|
|
278
278
|
// returns a usable provider for any connection name the winning profile
|
|
279
|
-
// references. The managed connection must
|
|
280
|
-
//
|
|
281
|
-
//
|
|
279
|
+
// references. The managed connection must be the platform-auth sentinel row:
|
|
280
|
+
// a managed profile routing through anything else resolves to the platform
|
|
281
|
+
// instead. Other names behave as personal anthropic connections.
|
|
282
282
|
mock.module("../providers/inference/connections.js", () => ({
|
|
283
|
-
getConnection: (_db: unknown, name: string) =>
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
283
|
+
getConnection: (_db: unknown, name: string) =>
|
|
284
|
+
name === VELLUM_MANAGED_CONNECTION_NAME
|
|
285
|
+
? {
|
|
286
|
+
id: 1,
|
|
287
|
+
name,
|
|
288
|
+
provider: "vellum",
|
|
289
|
+
auth: { type: "platform" },
|
|
290
|
+
}
|
|
291
|
+
: {
|
|
292
|
+
id: 1,
|
|
293
|
+
name,
|
|
294
|
+
provider: "anthropic",
|
|
295
|
+
auth_strategy: "user_managed_credential",
|
|
296
|
+
credential_alias: null,
|
|
297
|
+
metadata_json: null,
|
|
298
|
+
created_at: new Date().toISOString(),
|
|
299
|
+
updated_at: new Date().toISOString(),
|
|
300
|
+
},
|
|
294
301
|
}));
|
|
295
302
|
|
|
296
303
|
/**
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pins the `deepMergeOverwrite` behaviour that the Action Overrides editor
|
|
3
|
+
* depends on when it builds an `llm.callSites` patch (LUM-2949).
|
|
4
|
+
*
|
|
5
|
+
* A persisted call-site entry may carry tuning the web editor renders no
|
|
6
|
+
* control for (`effort`, `thinking`, `maxTokens`, ...). The editor decides
|
|
7
|
+
* per entry whether to send the picker triple, send `null`, or omit the key
|
|
8
|
+
* entirely, and each of those choices is only correct because of how this
|
|
9
|
+
* merge treats it. Asserting on the patch body alone would not catch a
|
|
10
|
+
* change here, so the contract is pinned where it lives.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { describe, expect, test } from "bun:test";
|
|
14
|
+
|
|
15
|
+
import { deepMergeOverwrite } from "../config/loader.js";
|
|
16
|
+
|
|
17
|
+
type Raw = Record<string, unknown>;
|
|
18
|
+
|
|
19
|
+
function callSites(entries: Raw): Raw {
|
|
20
|
+
return { llm: { callSites: entries } };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function mergedCallSites(before: Raw, patch: Raw): Raw {
|
|
24
|
+
const raw = callSites(before);
|
|
25
|
+
deepMergeOverwrite(raw, callSites(patch));
|
|
26
|
+
return (raw.llm as Raw).callSites as Raw;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const TUNED = {
|
|
30
|
+
profile: "latency-optimized",
|
|
31
|
+
effort: "low",
|
|
32
|
+
thinking: { enabled: false },
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
describe("llm.callSites patch merge", () => {
|
|
36
|
+
test("an omitted key keeps its persisted value", () => {
|
|
37
|
+
// What the editor sends for an active row: the picker triple only.
|
|
38
|
+
const after = mergedCallSites(
|
|
39
|
+
{ voiceFrontDoor: TUNED },
|
|
40
|
+
{ voiceFrontDoor: { profile: "balanced", provider: null, model: null } },
|
|
41
|
+
);
|
|
42
|
+
expect(after.voiceFrontDoor).toEqual({
|
|
43
|
+
profile: "balanced",
|
|
44
|
+
effort: "low",
|
|
45
|
+
thinking: { enabled: false },
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("a null on an absent key is a no-op, not a write", () => {
|
|
50
|
+
const after = mergedCallSites(
|
|
51
|
+
{ voiceFrontDoor: TUNED },
|
|
52
|
+
{ heartbeatAgent: null },
|
|
53
|
+
);
|
|
54
|
+
expect(after).toEqual({ voiceFrontDoor: TUNED });
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("a null deletes the whole entry, tuning included", () => {
|
|
58
|
+
// Why the editor must not send `null` for a row the user left alone:
|
|
59
|
+
// an entry holding only tuning would be erased.
|
|
60
|
+
const after = mergedCallSites(
|
|
61
|
+
{ tuningOnly: { effort: "low", thinking: { enabled: false } } },
|
|
62
|
+
{ tuningOnly: null },
|
|
63
|
+
);
|
|
64
|
+
expect("tuningOnly" in after).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("omitting a tuning-only entry leaves it untouched", () => {
|
|
68
|
+
const before = {
|
|
69
|
+
tuningOnly: { effort: "low", thinking: { enabled: false } },
|
|
70
|
+
};
|
|
71
|
+
const after = mergedCallSites(before, {
|
|
72
|
+
heartbeatAgent: { profile: "balanced", provider: null, model: null },
|
|
73
|
+
});
|
|
74
|
+
expect(after.tuningOnly).toEqual({
|
|
75
|
+
effort: "low",
|
|
76
|
+
thinking: { enabled: false },
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("an explicit null clears a scalar that is present", () => {
|
|
81
|
+
// The picker triple relies on this to drop a stale provider/model pin.
|
|
82
|
+
const after = mergedCallSites(
|
|
83
|
+
{ pinned: { provider: "anthropic", model: "claude-fable-5" } },
|
|
84
|
+
{ pinned: { profile: "balanced", provider: null, model: null } },
|
|
85
|
+
);
|
|
86
|
+
expect(after.pinned).toEqual({
|
|
87
|
+
profile: "balanced",
|
|
88
|
+
provider: null,
|
|
89
|
+
model: null,
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -650,7 +650,7 @@ describe("loadConfig startup behavior", () => {
|
|
|
650
650
|
expect(raw.llm.profiles).toEqual({});
|
|
651
651
|
// Default content resolves from the code catalog via the effective view.
|
|
652
652
|
const effectiveBalanced = getEffectiveProfile(raw.llm.profiles, "balanced");
|
|
653
|
-
expect(effectiveBalanced?.model).toBe("
|
|
653
|
+
expect(effectiveBalanced?.model).toBe("gpt-5.6-luna");
|
|
654
654
|
expect(effectiveBalanced?.provider).toBe("vellum");
|
|
655
655
|
expect(effectiveBalanced?.provider_connection).toBeUndefined();
|
|
656
656
|
});
|
|
@@ -978,7 +978,7 @@ describe("loadConfig startup behavior", () => {
|
|
|
978
978
|
// Resolution ignores the drifted body: a managed-source entry contributes
|
|
979
979
|
// only label/status/topP, everything else comes from the catalog.
|
|
980
980
|
const effectiveBalanced = getEffectiveProfile(raw.llm.profiles, "balanced");
|
|
981
|
-
expect(effectiveBalanced?.model).toBe("
|
|
981
|
+
expect(effectiveBalanced?.model).toBe("gpt-5.6-luna");
|
|
982
982
|
expect(effectiveBalanced?.provider_connection).toBeUndefined();
|
|
983
983
|
});
|
|
984
984
|
|
|
@@ -1058,7 +1058,7 @@ describe("loadConfig startup behavior", () => {
|
|
|
1058
1058
|
expect(raw.llm.profiles.balanced).toEqual(drifted);
|
|
1059
1059
|
expect(raw.llm.activeProfile).toBe("balanced");
|
|
1060
1060
|
const effectiveBalanced = getEffectiveProfile(raw.llm.profiles, "balanced");
|
|
1061
|
-
expect(effectiveBalanced?.model).toBe("
|
|
1061
|
+
expect(effectiveBalanced?.model).toBe("gpt-5.6-luna");
|
|
1062
1062
|
expect(effectiveBalanced?.maxTokens).toBe(32000);
|
|
1063
1063
|
expect(effectiveBalanced?.provider_connection).toBeUndefined();
|
|
1064
1064
|
// The catalog body carries no topP and the entry has none, so the
|
|
@@ -1090,7 +1090,7 @@ describe("loadConfig startup behavior", () => {
|
|
|
1090
1090
|
expect(raw.llm.profiles.balanced).toEqual(edited);
|
|
1091
1091
|
const effectiveBalanced = getEffectiveProfile(raw.llm.profiles, "balanced");
|
|
1092
1092
|
// Content is served from the catalog...
|
|
1093
|
-
expect(effectiveBalanced?.model).toBe("
|
|
1093
|
+
expect(effectiveBalanced?.model).toBe("gpt-5.6-luna");
|
|
1094
1094
|
// ...with the user's label and status overlaid.
|
|
1095
1095
|
expect(effectiveBalanced?.label).toBe("My Default");
|
|
1096
1096
|
expect(effectiveBalanced?.status).toBe("disabled");
|
|
@@ -1115,7 +1115,7 @@ describe("loadConfig startup behavior", () => {
|
|
|
1115
1115
|
expect(raw.llm.profiles.balanced).toEqual(stub);
|
|
1116
1116
|
const effectiveBalanced = getEffectiveProfile(raw.llm.profiles, "balanced");
|
|
1117
1117
|
expect(effectiveBalanced?.label).toBe("My Default");
|
|
1118
|
-
expect(effectiveBalanced?.model).toBe("
|
|
1118
|
+
expect(effectiveBalanced?.model).toBe("gpt-5.6-luna");
|
|
1119
1119
|
});
|
|
1120
1120
|
|
|
1121
1121
|
test("off-platform boot preserves user-toggled status on a managed stub", () => {
|
|
@@ -1137,7 +1137,7 @@ describe("loadConfig startup behavior", () => {
|
|
|
1137
1137
|
expect(effectiveBalanced?.status).toBe("disabled");
|
|
1138
1138
|
// Content still comes from the catalog — only label/status/topP are
|
|
1139
1139
|
// workspace-owned.
|
|
1140
|
-
expect(effectiveBalanced?.model).toBe("
|
|
1140
|
+
expect(effectiveBalanced?.model).toBe("gpt-5.6-luna");
|
|
1141
1141
|
});
|
|
1142
1142
|
|
|
1143
1143
|
test("boot preserves a user-edited topP override on a managed stub", () => {
|
|
@@ -1161,7 +1161,7 @@ describe("loadConfig startup behavior", () => {
|
|
|
1161
1161
|
expect(effectiveBalanced?.topP).toBe(0.5);
|
|
1162
1162
|
// Content still comes from the catalog — topP is workspace-owned, the
|
|
1163
1163
|
// rest is code-owned.
|
|
1164
|
-
expect(effectiveBalanced?.model).toBe("
|
|
1164
|
+
expect(effectiveBalanced?.model).toBe("gpt-5.6-luna");
|
|
1165
1165
|
});
|
|
1166
1166
|
|
|
1167
1167
|
test("effective balanced profile carries no topP override by default", () => {
|
|
@@ -1216,7 +1216,7 @@ describe("loadConfig startup behavior", () => {
|
|
|
1216
1216
|
expect(raw.llm.profiles.balanced).toBeUndefined();
|
|
1217
1217
|
const effectiveBalanced = getEffectiveProfile(raw.llm.profiles, "balanced");
|
|
1218
1218
|
expect(effectiveBalanced?.label).toBe("Balanced");
|
|
1219
|
-
expect(effectiveBalanced?.model).toBe("
|
|
1219
|
+
expect(effectiveBalanced?.model).toBe("gpt-5.6-luna");
|
|
1220
1220
|
// Status is unset — the default resolves active.
|
|
1221
1221
|
expect("status" in (effectiveBalanced ?? {})).toBe(false);
|
|
1222
1222
|
});
|
|
@@ -1295,7 +1295,7 @@ describe("loadConfig startup behavior", () => {
|
|
|
1295
1295
|
// overlay boot. The overlay-set label is what shows through the
|
|
1296
1296
|
// effective view.
|
|
1297
1297
|
expect(mainAgentConfig.provider).toBe("vellum");
|
|
1298
|
-
expect(mainAgentConfig.model).toBe("
|
|
1298
|
+
expect(mainAgentConfig.model).toBe("gpt-5.6-luna");
|
|
1299
1299
|
|
|
1300
1300
|
const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
1301
1301
|
expect(raw.llm.profiles.balanced).toEqual({
|
|
@@ -1326,7 +1326,7 @@ describe("loadConfig startup behavior", () => {
|
|
|
1326
1326
|
);
|
|
1327
1327
|
expect(effectiveBalanced?.provider).toBe("vellum");
|
|
1328
1328
|
expect(effectiveBalanced?.provider_connection).toBeUndefined();
|
|
1329
|
-
expect(effectiveBalanced?.model).toBe("
|
|
1329
|
+
expect(effectiveBalanced?.model).toBe("gpt-5.6-luna");
|
|
1330
1330
|
expect(effectiveBalanced?.maxTokens).toBe(32000);
|
|
1331
1331
|
expect(effectiveBalanced?.thinking).toEqual({
|
|
1332
1332
|
enabled: true,
|
|
@@ -19,12 +19,17 @@ import {
|
|
|
19
19
|
interface FakeEvent {
|
|
20
20
|
type: string;
|
|
21
21
|
message?: string;
|
|
22
|
+
conversationId?: string;
|
|
23
|
+
requestId?: string;
|
|
24
|
+
position?: number;
|
|
25
|
+
clientMessageId?: string;
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
function makeQueued(
|
|
25
29
|
content: string,
|
|
26
30
|
requestId: string,
|
|
27
31
|
events: FakeEvent[],
|
|
32
|
+
extra?: Partial<QueuedMessage>,
|
|
28
33
|
): QueuedMessage {
|
|
29
34
|
return {
|
|
30
35
|
content,
|
|
@@ -34,6 +39,7 @@ function makeQueued(
|
|
|
34
39
|
events.push(event);
|
|
35
40
|
},
|
|
36
41
|
sentAt: Date.now(),
|
|
42
|
+
...extra,
|
|
37
43
|
} as unknown as QueuedMessage;
|
|
38
44
|
}
|
|
39
45
|
|
|
@@ -200,3 +206,121 @@ describe("drainQueue under processing-lock contention", () => {
|
|
|
200
206
|
).toBe(1);
|
|
201
207
|
});
|
|
202
208
|
});
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* The corrective `message_requeued` event.
|
|
212
|
+
*
|
|
213
|
+
* A drain announces `message_dequeued` before the steps that can send the
|
|
214
|
+
* message back, so a client that cleared its pending indicator on that
|
|
215
|
+
* announcement needs to be told the message is queued again. The rule is
|
|
216
|
+
* announcement-scoped: a requeue that happens before the announcement owes
|
|
217
|
+
* clients nothing, because they never stopped showing the row as queued.
|
|
218
|
+
*/
|
|
219
|
+
describe("message_requeued corrective event", () => {
|
|
220
|
+
test("a busy persist tells the sender its announced message is queued again", async () => {
|
|
221
|
+
const events: FakeEvent[] = [];
|
|
222
|
+
const { conversation, queue } = makeFakeConversation({
|
|
223
|
+
persistError: new Error(CONVERSATION_BUSY_MESSAGE),
|
|
224
|
+
});
|
|
225
|
+
queue.push(
|
|
226
|
+
makeQueued("hello there", "r1", events, {
|
|
227
|
+
clientMessageId: "nonce-1",
|
|
228
|
+
}),
|
|
229
|
+
);
|
|
230
|
+
queue.push(makeQueued("and another", "r2", events));
|
|
231
|
+
|
|
232
|
+
await drainQueue(conversation as never);
|
|
233
|
+
|
|
234
|
+
expect(events.map((event) => event.type)).toEqual([
|
|
235
|
+
"message_dequeued",
|
|
236
|
+
"message_requeued",
|
|
237
|
+
]);
|
|
238
|
+
expect(events[1]).toEqual({
|
|
239
|
+
type: "message_requeued",
|
|
240
|
+
conversationId: "conv-drain-requeue",
|
|
241
|
+
requestId: "r1",
|
|
242
|
+
// Back at the head, so 1 of the 2 visible queued items.
|
|
243
|
+
position: 1,
|
|
244
|
+
clientMessageId: "nonce-1",
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
test("a requeue before the dequeue announcement stays silent", async () => {
|
|
249
|
+
const events: FakeEvent[] = [];
|
|
250
|
+
const { conversation, queue } = makeFakeConversation({ processing: true });
|
|
251
|
+
queue.push(makeQueued("hello there", "r1", events));
|
|
252
|
+
|
|
253
|
+
await drainQueue(conversation as never);
|
|
254
|
+
|
|
255
|
+
// The early lock check requeues before announcing anything, so a
|
|
256
|
+
// corrective event here would contradict what the client is showing.
|
|
257
|
+
expect(events).toEqual([]);
|
|
258
|
+
expect(queue.length).toBe(1);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test("only the batch member whose dequeue was announced is corrected", async () => {
|
|
262
|
+
const headEvents: FakeEvent[] = [];
|
|
263
|
+
const tailEvents: FakeEvent[] = [];
|
|
264
|
+
const { conversation, queue } = makeFakeConversation({
|
|
265
|
+
persistError: new Error(CONVERSATION_BUSY_MESSAGE),
|
|
266
|
+
});
|
|
267
|
+
queue.push(makeQueued("hello there", "r1", headEvents));
|
|
268
|
+
queue.push(makeQueued("and another", "r2", tailEvents));
|
|
269
|
+
|
|
270
|
+
await drainQueue(conversation as never);
|
|
271
|
+
|
|
272
|
+
// The batch drain announces per member as it walks the batch, and the
|
|
273
|
+
// head's busy persist ends the walk before the tail is announced.
|
|
274
|
+
expect(headEvents.map((event) => event.type)).toEqual([
|
|
275
|
+
"message_dequeued",
|
|
276
|
+
"message_requeued",
|
|
277
|
+
]);
|
|
278
|
+
expect(tailEvents).toEqual([]);
|
|
279
|
+
expect(queue.peek(0)?.requestId).toBe("r1");
|
|
280
|
+
expect(queue.peek(1)?.requestId).toBe("r2");
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
test("a hidden send is announced but never corrected", async () => {
|
|
284
|
+
const events: FakeEvent[] = [];
|
|
285
|
+
const { conversation, queue } = makeFakeConversation({
|
|
286
|
+
persistError: new Error(CONVERSATION_BUSY_MESSAGE),
|
|
287
|
+
});
|
|
288
|
+
queue.push(
|
|
289
|
+
makeQueued("wizard closed", "r1", events, {
|
|
290
|
+
metadata: { hidden: true },
|
|
291
|
+
}),
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
await drainQueue(conversation as never);
|
|
295
|
+
|
|
296
|
+
// Hidden sends get no queued ack and render no client row, so there is
|
|
297
|
+
// nothing for a corrective event to restore.
|
|
298
|
+
expect(events.some((event) => event.type === "message_requeued")).toBe(
|
|
299
|
+
false,
|
|
300
|
+
);
|
|
301
|
+
expect(queue.peek(0)?.requestId).toBe("r1");
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
test("a second contention round corrects the message again", async () => {
|
|
305
|
+
const events: FakeEvent[] = [];
|
|
306
|
+
const { conversation, queue } = makeFakeConversation({
|
|
307
|
+
persistErrors: [
|
|
308
|
+
new Error(CONVERSATION_BUSY_MESSAGE),
|
|
309
|
+
new Error(CONVERSATION_BUSY_MESSAGE),
|
|
310
|
+
],
|
|
311
|
+
});
|
|
312
|
+
queue.push(makeQueued("hello there", "r1", events));
|
|
313
|
+
|
|
314
|
+
await drainQueue(conversation as never);
|
|
315
|
+
await drainQueue(conversation as never);
|
|
316
|
+
|
|
317
|
+
// Each round re-announces the dequeue, so each round owes its own
|
|
318
|
+
// correction: the flag settles per announcement, not once per message.
|
|
319
|
+
expect(events.map((event) => event.type)).toEqual([
|
|
320
|
+
"message_dequeued",
|
|
321
|
+
"message_requeued",
|
|
322
|
+
"message_dequeued",
|
|
323
|
+
"message_requeued",
|
|
324
|
+
]);
|
|
325
|
+
});
|
|
326
|
+
});
|
|
@@ -1067,7 +1067,7 @@ describe("code-owned default profiles — wire view and write normalization", ()
|
|
|
1067
1067
|
});
|
|
1068
1068
|
const response = (await getRoute.handler({})) as Record<string, any>;
|
|
1069
1069
|
const wireBalanced = response.llm.profiles.balanced;
|
|
1070
|
-
expect(wireBalanced.model).toBe("
|
|
1070
|
+
expect(wireBalanced.model).toBe("gpt-5.6-luna");
|
|
1071
1071
|
expect(wireBalanced.provider).toBe("vellum");
|
|
1072
1072
|
expect(wireBalanced.provider_connection).toBeUndefined();
|
|
1073
1073
|
expect(wireBalanced.status).toBe("disabled");
|
|
@@ -1314,9 +1314,7 @@ describe("code-owned default profiles — echoes over stale on-disk bodies", ()
|
|
|
1314
1314
|
});
|
|
1315
1315
|
const response = (await getRoute.handler({})) as Record<string, any>;
|
|
1316
1316
|
// The wire view serves catalog content, not the stale body.
|
|
1317
|
-
expect(response.llm.profiles.balanced.model).toBe(
|
|
1318
|
-
"accounts/fireworks/models/glm-5p2",
|
|
1319
|
-
);
|
|
1317
|
+
expect(response.llm.profiles.balanced.model).toBe("gpt-5.6-luna");
|
|
1320
1318
|
const result = await patchRoute.handler({
|
|
1321
1319
|
body: { llm: { profiles: response.llm.profiles } },
|
|
1322
1320
|
});
|