@vellumai/assistant 0.11.1-dev.202608041641.cd84db1 → 0.11.1-dev.202608041735.8f969f7
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 +16 -0
- package/package.json +1 -1
- package/src/__tests__/conversation-agent-loop.test.ts +75 -1
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +10 -0
- package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +969 -0
- package/src/__tests__/conversation-surfaces-persisted-info.test.ts +312 -0
- package/src/__tests__/surface-completion-compaction-boundary.test.ts +124 -0
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +298 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +1 -1
- package/src/config/bundled-skills/media-processing/TOOLS.json +1 -1
- package/src/config/bundled-skills/media-processing/__tests__/media-analysis-default-model.test.ts +177 -0
- package/src/config/bundled-skills/media-processing/services/gemini-map.ts +4 -3
- package/src/config/bundled-skills/media-processing/services/gemini-video.ts +2 -1
- package/src/config/bundled-skills/media-processing/services/media-analysis-model.ts +12 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +12 -0
- package/src/daemon/conversation-agent-loop.ts +8 -1
- package/src/daemon/conversation-surface-state.ts +9 -0
- package/src/daemon/conversation-surfaces.ts +337 -96
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +48 -0
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +16 -1
- package/src/runtime/routes/conversation-query-routes.ts +33 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +10 -0
package/openapi.yaml
CHANGED
|
@@ -4737,6 +4737,8 @@ paths:
|
|
|
4737
4737
|
type: string
|
|
4738
4738
|
defaultProfile:
|
|
4739
4739
|
type: string
|
|
4740
|
+
shippedDefaultProfile:
|
|
4741
|
+
type: string
|
|
4740
4742
|
required:
|
|
4741
4743
|
- id
|
|
4742
4744
|
- displayName
|
|
@@ -33305,6 +33307,14 @@ components:
|
|
|
33305
33307
|
anyOf:
|
|
33306
33308
|
- $ref: "#/components/schemas/CallSiteOverrideDraft"
|
|
33307
33309
|
- type: "null"
|
|
33310
|
+
defaultProfileOverrides:
|
|
33311
|
+
type: object
|
|
33312
|
+
propertyNames:
|
|
33313
|
+
type: string
|
|
33314
|
+
additionalProperties:
|
|
33315
|
+
anyOf:
|
|
33316
|
+
- type: string
|
|
33317
|
+
- type: "null"
|
|
33308
33318
|
profileSession:
|
|
33309
33319
|
anyOf:
|
|
33310
33320
|
- type: object
|
|
@@ -34132,6 +34142,12 @@ components:
|
|
|
34132
34142
|
type: string
|
|
34133
34143
|
additionalProperties: false
|
|
34134
34144
|
- type: "null"
|
|
34145
|
+
defaultProfileOverrides:
|
|
34146
|
+
type: object
|
|
34147
|
+
propertyNames:
|
|
34148
|
+
type: string
|
|
34149
|
+
additionalProperties:
|
|
34150
|
+
type: string
|
|
34135
34151
|
profileSession:
|
|
34136
34152
|
type: object
|
|
34137
34153
|
properties:
|
package/package.json
CHANGED
|
@@ -318,6 +318,8 @@ const deleteMessageByIdMock = mock(() => ({
|
|
|
318
318
|
deletedSummaryIds: [],
|
|
319
319
|
}));
|
|
320
320
|
const reserveMessageMock = mock(async () => ({ id: "msg-reserve" }));
|
|
321
|
+
/** Persisted rows the loop reads back. Empty unless a test seeds one. */
|
|
322
|
+
let mockStoredMessages: unknown[] = [];
|
|
321
323
|
const updateMessageContentMock = mock(() => {});
|
|
322
324
|
const finalizeMessageContentMock = mock(() => {});
|
|
323
325
|
const addMessageMock = mock(() => ({ id: "mock-msg-id" }));
|
|
@@ -328,7 +330,7 @@ mock.module("../persistence/conversation-crud.js", () => ({
|
|
|
328
330
|
updateConversationUsage: () => {},
|
|
329
331
|
updateMessageMetadata: updateMessageMetadataMock,
|
|
330
332
|
setConversationHistoryStrippedAt: setConversationHistoryStrippedAtMock,
|
|
331
|
-
getMessages: () =>
|
|
333
|
+
getMessages: () => mockStoredMessages,
|
|
332
334
|
getConversation: () => mockConversationRow,
|
|
333
335
|
provenanceFromTrustContext: () => ({
|
|
334
336
|
source: "user",
|
|
@@ -931,7 +933,9 @@ beforeEach(() => {
|
|
|
931
933
|
getSlackCompactionWatermarkForPrefixMock.mockClear();
|
|
932
934
|
deleteMessageByIdMock.mockClear();
|
|
933
935
|
reserveMessageMock.mockClear();
|
|
936
|
+
mockStoredMessages = [];
|
|
934
937
|
updateMessageContentMock.mockClear();
|
|
938
|
+
updateMessageContentMock.mockImplementation(() => {});
|
|
935
939
|
finalizeMessageContentMock.mockClear();
|
|
936
940
|
rmSync(inflightDir(), { recursive: true, force: true });
|
|
937
941
|
addMessageMock.mockClear();
|
|
@@ -1971,6 +1975,76 @@ describe("session-agent-loop", () => {
|
|
|
1971
1975
|
expect(ctx.pendingSurfaceActions.has("stale-form-1")).toBe(false);
|
|
1972
1976
|
});
|
|
1973
1977
|
|
|
1978
|
+
test("withholds the dismissal event and keeps the surface pending when its persisted write fails", async () => {
|
|
1979
|
+
const events: AssistantEvent[] = [];
|
|
1980
|
+
|
|
1981
|
+
const ctx = makeCtx();
|
|
1982
|
+
ctx.pendingSurfaceActions.set("stale-table-2", { surfaceType: "table" });
|
|
1983
|
+
mockStoredMessages = [
|
|
1984
|
+
{
|
|
1985
|
+
id: "msg-with-stale-surface",
|
|
1986
|
+
conversationId: "conv-1",
|
|
1987
|
+
role: "assistant",
|
|
1988
|
+
content: [{ type: "ui_surface", surfaceId: "stale-table-2" }],
|
|
1989
|
+
createdAt: 0,
|
|
1990
|
+
metadata: null,
|
|
1991
|
+
},
|
|
1992
|
+
];
|
|
1993
|
+
updateMessageContentMock.mockImplementationOnce(() => {
|
|
1994
|
+
throw new Error("database is locked");
|
|
1995
|
+
});
|
|
1996
|
+
|
|
1997
|
+
await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg), {
|
|
1998
|
+
isUserMessage: true,
|
|
1999
|
+
});
|
|
2000
|
+
|
|
2001
|
+
// Announcing a dismissal the DB still holds as pending leaves the client
|
|
2002
|
+
// showing a card the next history reseed reverts.
|
|
2003
|
+
expect(
|
|
2004
|
+
events.filter((e) => e.type === "ui_surface_complete"),
|
|
2005
|
+
).toHaveLength(0);
|
|
2006
|
+
// The card stays live on the client, so the daemon must keep treating it
|
|
2007
|
+
// as pending; the sweep retries on the next user message.
|
|
2008
|
+
expect(ctx.pendingSurfaceActions.has("stale-table-2")).toBe(true);
|
|
2009
|
+
});
|
|
2010
|
+
|
|
2011
|
+
test("dismisses the remaining surfaces when one write fails", async () => {
|
|
2012
|
+
const events: AssistantEvent[] = [];
|
|
2013
|
+
|
|
2014
|
+
const ctx = makeCtx();
|
|
2015
|
+
ctx.pendingSurfaceActions.set("stale-table-3", { surfaceType: "table" });
|
|
2016
|
+
ctx.pendingSurfaceActions.set("stale-form-3", { surfaceType: "form" });
|
|
2017
|
+
mockStoredMessages = [
|
|
2018
|
+
{
|
|
2019
|
+
id: "msg-with-stale-surfaces",
|
|
2020
|
+
conversationId: "conv-1",
|
|
2021
|
+
role: "assistant",
|
|
2022
|
+
content: [
|
|
2023
|
+
{ type: "ui_surface", surfaceId: "stale-table-3" },
|
|
2024
|
+
{ type: "ui_surface", surfaceId: "stale-form-3" },
|
|
2025
|
+
],
|
|
2026
|
+
createdAt: 0,
|
|
2027
|
+
metadata: null,
|
|
2028
|
+
},
|
|
2029
|
+
];
|
|
2030
|
+
updateMessageContentMock.mockImplementationOnce(() => {
|
|
2031
|
+
throw new Error("database is locked");
|
|
2032
|
+
});
|
|
2033
|
+
|
|
2034
|
+
await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg), {
|
|
2035
|
+
isUserMessage: true,
|
|
2036
|
+
});
|
|
2037
|
+
|
|
2038
|
+
// Retaining the failed entry must not stall the sweep: deleting the
|
|
2039
|
+
// current key while iterating the map leaves later keys reachable.
|
|
2040
|
+
const completed = events
|
|
2041
|
+
.filter((e) => e.type === "ui_surface_complete")
|
|
2042
|
+
.map((e) => (e as { surfaceId: string }).surfaceId);
|
|
2043
|
+
expect(completed).toEqual(["stale-form-3"]);
|
|
2044
|
+
expect(ctx.pendingSurfaceActions.has("stale-table-3")).toBe(true);
|
|
2045
|
+
expect(ctx.pendingSurfaceActions.has("stale-form-3")).toBe(false);
|
|
2046
|
+
});
|
|
2047
|
+
|
|
1974
2048
|
test("does not auto-complete surfaces when request is a surface action", async () => {
|
|
1975
2049
|
const events: AssistantEvent[] = [];
|
|
1976
2050
|
|
|
@@ -9,6 +9,16 @@ mock.module("../runtime/assistant-event-hub.js", () => ({
|
|
|
9
9
|
broadcastMessage: (msg: AssistantEvent) => broadcastedMessages.push(msg),
|
|
10
10
|
}));
|
|
11
11
|
|
|
12
|
+
// These surfaces are shown live and asserted through their client messages, so
|
|
13
|
+
// history holds nothing. Stand in an empty store: the completion path reads
|
|
14
|
+
// persisted `ui_surface` blocks, and this file's DB carries no schema, so the
|
|
15
|
+
// real read would throw and be indistinguishable from a persistence failure.
|
|
16
|
+
const realCrud = await import("../persistence/conversation-crud.js");
|
|
17
|
+
mock.module("../persistence/conversation-crud.js", () => ({
|
|
18
|
+
...realCrud,
|
|
19
|
+
getMessages: () => [],
|
|
20
|
+
}));
|
|
21
|
+
|
|
12
22
|
const { createSurfaceMutex, handleSurfaceAction, surfaceProxyResolver } =
|
|
13
23
|
await import("../daemon/conversation-surfaces.js");
|
|
14
24
|
|