@vellumai/assistant 0.8.9-staging.3 → 0.8.9-staging.5

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 (91) hide show
  1. package/openapi.yaml +16 -115
  2. package/package.json +1 -1
  3. package/src/__tests__/anthropic-provider.test.ts +23 -8
  4. package/src/__tests__/context-window-manager-compact-retry.test.ts +120 -14
  5. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +73 -4
  6. package/src/__tests__/credential-security-invariants.test.ts +1 -0
  7. package/src/__tests__/gateway-only-guard.test.ts +5 -0
  8. package/src/__tests__/llm-resolver.test.ts +73 -0
  9. package/src/__tests__/plugin-external-api.test.ts +68 -0
  10. package/src/__tests__/published-app-updater.test.ts +138 -0
  11. package/src/api/responses/memory-v3-selection-log.ts +19 -10
  12. package/src/cli/commands/__tests__/memory-v3.test.ts +191 -210
  13. package/src/cli/commands/memory-v3.ts +57 -199
  14. package/src/config/call-site-defaults.ts +0 -1
  15. package/src/config/llm-resolver.ts +39 -7
  16. package/src/config/schemas/__tests__/memory-v3.test.ts +25 -9
  17. package/src/config/schemas/call-site-catalog.ts +0 -7
  18. package/src/config/schemas/llm.ts +17 -1
  19. package/src/config/schemas/memory-v3.ts +58 -8
  20. package/src/config/seed-inference-profiles.ts +18 -0
  21. package/src/daemon/conversation-agent-loop.ts +9 -17
  22. package/src/daemon/external-plugins-bootstrap.ts +8 -3
  23. package/src/daemon/tool-side-effects.ts +15 -0
  24. package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -97
  25. package/src/memory/v2/__tests__/page-store.test.ts +22 -0
  26. package/src/memory/v2/consolidation-job.ts +2 -72
  27. package/src/memory/v2/types.ts +5 -0
  28. package/src/plugins/defaults/compaction/window-manager.ts +56 -0
  29. package/src/plugins/defaults/memory-v3-shadow/__tests__/capabilities.test.ts +19 -66
  30. package/src/plugins/defaults/memory-v3-shadow/__tests__/dense.test.ts +181 -0
  31. package/src/plugins/defaults/memory-v3-shadow/__tests__/edge.test.ts +247 -0
  32. package/src/plugins/defaults/memory-v3-shadow/__tests__/live-integration.test.ts +139 -129
  33. package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +332 -164
  34. package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +516 -293
  35. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +306 -0
  36. package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +51 -21
  37. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +402 -0
  38. package/src/plugins/defaults/memory-v3-shadow/__tests__/section-needle.test.ts +135 -0
  39. package/src/plugins/defaults/memory-v3-shadow/__tests__/sections.test.ts +125 -0
  40. package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +66 -11
  41. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +446 -0
  42. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +271 -110
  43. package/src/plugins/defaults/memory-v3-shadow/__tests__/types.test.ts +0 -22
  44. package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +26 -62
  45. package/src/plugins/defaults/memory-v3-shadow/dense.ts +97 -0
  46. package/src/plugins/defaults/memory-v3-shadow/edge.ts +252 -0
  47. package/src/plugins/defaults/memory-v3-shadow/injector.ts +3 -2
  48. package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +415 -181
  49. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +196 -56
  50. package/src/plugins/defaults/memory-v3-shadow/page-content.ts +39 -2
  51. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +204 -0
  52. package/src/plugins/defaults/memory-v3-shadow/render-injection.ts +15 -7
  53. package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +236 -0
  54. package/src/plugins/defaults/memory-v3-shadow/section-needle.ts +200 -0
  55. package/src/plugins/defaults/memory-v3-shadow/sections.ts +115 -0
  56. package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +75 -3
  57. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +111 -78
  58. package/src/plugins/defaults/memory-v3-shadow/types.ts +52 -19
  59. package/src/plugins/defaults/memory-v3-shadow/working-set.ts +4 -1
  60. package/src/plugins/external-api.ts +114 -0
  61. package/src/providers/anthropic/client.ts +9 -10
  62. package/src/providers/inference/kimi-cjk-token-ids.ts +493 -0
  63. package/src/providers/inference/logit-bias.ts +55 -0
  64. package/src/providers/openai/chat-completions-provider.ts +19 -1
  65. package/src/providers/retry.ts +22 -0
  66. package/src/providers/types.ts +6 -0
  67. package/src/runtime/routes/app-management-routes.ts +3 -0
  68. package/src/runtime/routes/memory-v3-routes.ts +64 -314
  69. package/src/services/published-app-updater.ts +30 -8
  70. package/src/tools/skills/load.ts +1 -1
  71. package/src/plugins/defaults/memory-v3-shadow/__tests__/assign.test.ts +0 -242
  72. package/src/plugins/defaults/memory-v3-shadow/__tests__/core.test.ts +0 -39
  73. package/src/plugins/defaults/memory-v3-shadow/__tests__/health.test.ts +0 -219
  74. package/src/plugins/defaults/memory-v3-shadow/__tests__/needle.test.ts +0 -107
  75. package/src/plugins/defaults/memory-v3-shadow/__tests__/provider-blocks.test.ts +0 -13
  76. package/src/plugins/defaults/memory-v3-shadow/__tests__/reconcile.test.ts +0 -274
  77. package/src/plugins/defaults/memory-v3-shadow/__tests__/router.test.ts +0 -337
  78. package/src/plugins/defaults/memory-v3-shadow/__tests__/selector.test.ts +0 -470
  79. package/src/plugins/defaults/memory-v3-shadow/__tests__/snapshot.test.ts +0 -168
  80. package/src/plugins/defaults/memory-v3-shadow/__tests__/tree.test.ts +0 -192
  81. package/src/plugins/defaults/memory-v3-shadow/assign.ts +0 -272
  82. package/src/plugins/defaults/memory-v3-shadow/core.ts +0 -26
  83. package/src/plugins/defaults/memory-v3-shadow/health.ts +0 -0
  84. package/src/plugins/defaults/memory-v3-shadow/needle.ts +0 -115
  85. package/src/plugins/defaults/memory-v3-shadow/provider-blocks.ts +0 -26
  86. package/src/plugins/defaults/memory-v3-shadow/reconcile.ts +0 -527
  87. package/src/plugins/defaults/memory-v3-shadow/router.ts +0 -190
  88. package/src/plugins/defaults/memory-v3-shadow/selector.ts +0 -226
  89. package/src/plugins/defaults/memory-v3-shadow/snapshot.ts +0 -209
  90. package/src/plugins/defaults/memory-v3-shadow/tree.ts +0 -174
  91. package/src/util/map-limit.ts +0 -27
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Tests for the `globalThis.__vellumPluginRuntime` bridge.
3
+ *
4
+ * The bridge exists so workspace-local plugins (`<workspaceDir>/plugins/*`)
5
+ * can register with the daemon's bundled module instances even when the
6
+ * daemon is a `bun --compile` binary. Absolute-path imports against a
7
+ * compiled binary load fresh disk copies into a disjoint module graph; the
8
+ * bridge sidesteps that by attaching a stable handle to globalThis.
9
+ */
10
+
11
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
12
+
13
+ import {
14
+ getPluginRuntime,
15
+ installPluginRuntime,
16
+ uninstallPluginRuntimeForTests,
17
+ } from "../plugins/external-api.js";
18
+ import { registerPlugin } from "../plugins/registry.js";
19
+ import { assistantEventHub } from "../runtime/assistant-event-hub.js";
20
+ import { getSecureKeyAsync } from "../security/secure-keys.js";
21
+
22
+ describe("plugin external-api bridge", () => {
23
+ beforeEach(() => {
24
+ uninstallPluginRuntimeForTests();
25
+ });
26
+
27
+ afterEach(() => {
28
+ uninstallPluginRuntimeForTests();
29
+ });
30
+
31
+ test("installs a runtime handle on globalThis", () => {
32
+ expect(getPluginRuntime()).toBeUndefined();
33
+ installPluginRuntime();
34
+ const runtime = getPluginRuntime();
35
+ expect(runtime).toBeDefined();
36
+ expect(runtime?.version).toBe(1);
37
+ });
38
+
39
+ test("exposes the canonical registerPlugin / hub / secrets references", () => {
40
+ installPluginRuntime();
41
+ const runtime = getPluginRuntime();
42
+ expect(runtime?.registerPlugin).toBe(registerPlugin);
43
+ expect(runtime?.assistantEventHub).toBe(assistantEventHub);
44
+ expect(runtime?.getSecureKeyAsync).toBe(getSecureKeyAsync);
45
+ });
46
+
47
+ test("plugins can read the runtime via the documented globalThis key", () => {
48
+ installPluginRuntime();
49
+ // Mirror the access pattern documented for plugin authors.
50
+ const runtime = (
51
+ globalThis as { __vellumPluginRuntime?: { version: number } }
52
+ ).__vellumPluginRuntime;
53
+ expect(runtime).toBeDefined();
54
+ expect(runtime?.version).toBe(1);
55
+ });
56
+
57
+ test("install is idempotent — repeat calls preserve the same handle", () => {
58
+ installPluginRuntime();
59
+ const first = getPluginRuntime();
60
+ installPluginRuntime();
61
+ installPluginRuntime();
62
+ expect(getPluginRuntime()).toBe(first);
63
+ });
64
+
65
+ test("getPluginRuntime returns undefined when the bridge is not installed", () => {
66
+ expect(getPluginRuntime()).toBeUndefined();
67
+ });
68
+ });
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Tests that the auto-redeploy path deploys the app's *effective* HTML
3
+ * (dist/index.html for multifile apps) rather than the empty `htmlDefinition`.
4
+ */
5
+
6
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
7
+
8
+ import type { AppDefinition } from "../memory/app-store.js";
9
+
10
+ // ── Mocks ───────────────────────────────────────────────────────────────
11
+
12
+ let mockApp: AppDefinition | null = null;
13
+ let mockIsMultifile = false;
14
+ let mockEffectiveHtml = "";
15
+ // A directory that does not exist on disk, so the multifile dist-existence
16
+ // guard reads `false` from the real fs without mocking node:fs (which would
17
+ // leak across test files).
18
+ let mockAppDir = "/tmp/__vellum_test_nonexistent__/app-1";
19
+
20
+ mock.module("../memory/app-store.js", () => ({
21
+ getApp: () => mockApp,
22
+ getAppDirPath: () => mockAppDir,
23
+ isMultifileApp: () => mockIsMultifile,
24
+ resolveEffectiveAppHtml: () => mockEffectiveHtml,
25
+ }));
26
+
27
+ let mockPublishedPage: {
28
+ id: string;
29
+ projectSlug?: string;
30
+ htmlHash: string;
31
+ } | null = null;
32
+ const updatePublishedPageSpy = mock(() => {});
33
+
34
+ mock.module("../memory/published-pages-store.js", () => ({
35
+ getActivePublishedPageByAppId: () => mockPublishedPage,
36
+ updatePublishedPage: updatePublishedPageSpy,
37
+ }));
38
+
39
+ const deploySpy = mock(async (_args: { html: string; name: string }) => ({
40
+ deploymentId: "dep-1",
41
+ url: "https://example.vercel.app",
42
+ }));
43
+
44
+ mock.module("../services/vercel-deploy.js", () => ({
45
+ deployHtmlToVercel: deploySpy,
46
+ }));
47
+
48
+ // credentialBroker.serverUse invokes execute(token) and reports success.
49
+ mock.module("../tools/credentials/broker.js", () => ({
50
+ credentialBroker: {
51
+ serverUse: async ({
52
+ execute,
53
+ }: {
54
+ execute: (token: string) => Promise<unknown>;
55
+ }) => {
56
+ await execute("test-token");
57
+ return { success: true };
58
+ },
59
+ },
60
+ }));
61
+
62
+ const { updatePublishedAppDeployment } =
63
+ await import("../services/published-app-updater.js");
64
+
65
+ function makeApp(overrides: Partial<AppDefinition> = {}): AppDefinition {
66
+ return {
67
+ id: "app-1",
68
+ name: "App",
69
+ schemaJson: "{}",
70
+ htmlDefinition: "",
71
+ createdAt: 1,
72
+ updatedAt: 2,
73
+ ...overrides,
74
+ };
75
+ }
76
+
77
+ // ── Tests ───────────────────────────────────────────────────────────────
78
+
79
+ describe("updatePublishedAppDeployment", () => {
80
+ beforeEach(() => {
81
+ mockApp = makeApp();
82
+ mockIsMultifile = false;
83
+ mockEffectiveHtml = "";
84
+ mockPublishedPage = { id: "pp-1", projectSlug: "slug", htmlHash: "old" };
85
+ mockAppDir = "/tmp/__vellum_test_nonexistent__/app-1";
86
+ deploySpy.mockClear();
87
+ updatePublishedPageSpy.mockClear();
88
+ });
89
+
90
+ test("deploys the resolved effective HTML, not the empty htmlDefinition", async () => {
91
+ // htmlDefinition is "" (as it is for every multifile app); the real
92
+ // content comes from resolveEffectiveAppHtml. isMultifile=false here keeps
93
+ // the dist guard out of the way so the assertion targets the html source.
94
+ mockApp = makeApp({ htmlDefinition: "" });
95
+ mockEffectiveHtml = "<html><body>real app</body></html>";
96
+
97
+ await updatePublishedAppDeployment("app-1");
98
+
99
+ expect(deploySpy).toHaveBeenCalledTimes(1);
100
+ expect(deploySpy.mock.calls[0][0].html).toBe(
101
+ "<html><body>real app</body></html>",
102
+ );
103
+ });
104
+
105
+ test("skips deploy when a multifile app has no compiled output", async () => {
106
+ mockIsMultifile = true;
107
+ mockApp = makeApp({ formatVersion: 2 });
108
+ mockEffectiveHtml = "<p>App compilation failed.</p>";
109
+ // mockAppDir does not exist → dist/index.html is absent.
110
+
111
+ await updatePublishedAppDeployment("app-1");
112
+
113
+ expect(deploySpy).not.toHaveBeenCalled();
114
+ });
115
+
116
+ test("skips deploy when content hash is unchanged", async () => {
117
+ const html = "<html>same</html>";
118
+ mockEffectiveHtml = html;
119
+ const { createHash } = await import("node:crypto");
120
+ mockPublishedPage = {
121
+ id: "pp-1",
122
+ htmlHash: createHash("sha256").update(html).digest("hex"),
123
+ };
124
+
125
+ await updatePublishedAppDeployment("app-1");
126
+
127
+ expect(deploySpy).not.toHaveBeenCalled();
128
+ });
129
+
130
+ test("skips deploy when the app has no active published page", async () => {
131
+ mockPublishedPage = null;
132
+ mockEffectiveHtml = "<html>x</html>";
133
+
134
+ await updatePublishedAppDeployment("app-1");
135
+
136
+ expect(deploySpy).not.toHaveBeenCalled();
137
+ });
138
+ });
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Wire contract for the memory v3 selection set surfaced in the inspector's
3
3
  * Memory tab. Mirrors the return value of `getMemoryV3SelectionForInspector`
4
- * in `assistant/src/memory/v3/selection-log-store.ts`.
4
+ * in `assistant/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts`.
5
5
  *
6
6
  * Canonical wire-contract source. Assistant code imports the types directly
7
7
  * from this file via relative paths; external consumers (web client, gateway,
@@ -12,19 +12,27 @@
12
12
  * `live` / `shadow` reflect the CURRENT `memory-v3-live` / `memory-v3-shadow`
13
13
  * flag state, not the per-turn history (the selection rows don't record which
14
14
  * mode was active when they were written). When `live` is true the rendered
15
- * `injectedText` block was actually injected into the turn; when only `shadow`
16
- * is true it is the block that WOULD have been injected. For stable-flag
17
- * shadow validation these coincide; recording per-turn `injected` is a
18
- * documented follow-up.
15
+ * `injectedText` reflects the live selection; when only `shadow` is true it is
16
+ * the block that WOULD have been injected.
17
+ *
18
+ * `injectedText` is APPROXIMATE, not a verbatim record. It is re-rendered from
19
+ * the persisted selection rows, which store slug/source/pinned but NOT the
20
+ * matched-section identity. A page that live injection sent as a single matched
21
+ * section is re-rendered here as its FULL page (the section ordinal isn't
22
+ * persisted), so the text can differ from what was actually sent to the model.
23
+ * The selected slug set is exact — only the rendered text is full-page
24
+ * approximate. Persisting the per-turn injected section is a documented
25
+ * follow-up.
19
26
  */
20
27
 
21
28
  import { z } from "zod";
22
29
 
23
30
  /**
24
31
  * One selected page in the v3 set. `source` is the lane that surfaced it —
25
- * the daemon emits `l1+l2`, `core+l2`, `needle`, or `carry-forward` — but the
26
- * schema stays a permissive string so a new lane label doesn't break parsing
27
- * on the FE. `pinned` marks a slug carried forward across turns.
32
+ * the daemon emits `needle`, `dense`, `edge`, or `carry-forward` — but the
33
+ * schema stays a permissive string so a new lane label (or a historical
34
+ * pre-lane row) doesn't break parsing on the FE. `pinned` marks a slug carried
35
+ * forward across turns.
28
36
  */
29
37
  export const MemoryV3SelectionRowSchema = z.object({
30
38
  slug: z.string(),
@@ -36,8 +44,9 @@ export type MemoryV3SelectionRow = z.infer<typeof MemoryV3SelectionRowSchema>;
36
44
 
37
45
  /**
38
46
  * Memory v3 selection log shape. `injectedText` is the rendered
39
- * `<memory>…</memory>` block for the selection (actual when `live`, would-be
40
- * when `shadow`-only).
47
+ * `<memory>…</memory>` block for the selection — APPROXIMATE: re-rendered from
48
+ * the persisted rows, with full pages where live injection used a matched
49
+ * section (the section identity isn't persisted). See the file header.
41
50
  */
42
51
  export const MemoryV3SelectionLogSchema = z.object({
43
52
  turn: z.number(),