@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.
Files changed (22) hide show
  1. package/openapi.yaml +16 -0
  2. package/package.json +1 -1
  3. package/src/__tests__/conversation-agent-loop.test.ts +75 -1
  4. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +10 -0
  5. package/src/__tests__/conversation-surfaces-history-restored-completion.test.ts +969 -0
  6. package/src/__tests__/conversation-surfaces-persisted-info.test.ts +312 -0
  7. package/src/__tests__/surface-completion-compaction-boundary.test.ts +124 -0
  8. package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +298 -0
  9. package/src/config/bundled-skills/media-processing/SKILL.md +1 -1
  10. package/src/config/bundled-skills/media-processing/TOOLS.json +1 -1
  11. package/src/config/bundled-skills/media-processing/__tests__/media-analysis-default-model.test.ts +177 -0
  12. package/src/config/bundled-skills/media-processing/services/gemini-map.ts +4 -3
  13. package/src/config/bundled-skills/media-processing/services/gemini-video.ts +2 -1
  14. package/src/config/bundled-skills/media-processing/services/media-analysis-model.ts +12 -0
  15. package/src/daemon/conversation-agent-loop-handlers.ts +12 -0
  16. package/src/daemon/conversation-agent-loop.ts +8 -1
  17. package/src/daemon/conversation-surface-state.ts +9 -0
  18. package/src/daemon/conversation-surfaces.ts +337 -96
  19. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +48 -0
  20. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +16 -1
  21. package/src/runtime/routes/conversation-query-routes.ts +33 -0
  22. 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellumai/assistant",
3
- "version": "0.11.1-dev.202608041641.cd84db1",
3
+ "version": "0.11.1-dev.202608041735.8f969f7",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
@@ -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