@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.
- package/openapi.yaml +16 -115
- package/package.json +1 -1
- package/src/__tests__/anthropic-provider.test.ts +23 -8
- package/src/__tests__/context-window-manager-compact-retry.test.ts +120 -14
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +73 -4
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/gateway-only-guard.test.ts +5 -0
- package/src/__tests__/llm-resolver.test.ts +73 -0
- package/src/__tests__/plugin-external-api.test.ts +68 -0
- package/src/__tests__/published-app-updater.test.ts +138 -0
- package/src/api/responses/memory-v3-selection-log.ts +19 -10
- package/src/cli/commands/__tests__/memory-v3.test.ts +191 -210
- package/src/cli/commands/memory-v3.ts +57 -199
- package/src/config/call-site-defaults.ts +0 -1
- package/src/config/llm-resolver.ts +39 -7
- package/src/config/schemas/__tests__/memory-v3.test.ts +25 -9
- package/src/config/schemas/call-site-catalog.ts +0 -7
- package/src/config/schemas/llm.ts +17 -1
- package/src/config/schemas/memory-v3.ts +58 -8
- package/src/config/seed-inference-profiles.ts +18 -0
- package/src/daemon/conversation-agent-loop.ts +9 -17
- package/src/daemon/external-plugins-bootstrap.ts +8 -3
- package/src/daemon/tool-side-effects.ts +15 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +4 -97
- package/src/memory/v2/__tests__/page-store.test.ts +22 -0
- package/src/memory/v2/consolidation-job.ts +2 -72
- package/src/memory/v2/types.ts +5 -0
- package/src/plugins/defaults/compaction/window-manager.ts +56 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/capabilities.test.ts +19 -66
- package/src/plugins/defaults/memory-v3-shadow/__tests__/dense.test.ts +181 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/edge.test.ts +247 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/live-integration.test.ts +139 -129
- package/src/plugins/defaults/memory-v3-shadow/__tests__/maintain-job.test.ts +332 -164
- package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +516 -293
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +306 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/render-injection.test.ts +51 -21
- package/src/plugins/defaults/memory-v3-shadow/__tests__/section-dense-store.test.ts +402 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/section-needle.test.ts +135 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/sections.test.ts +125 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +66 -11
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +446 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +271 -110
- package/src/plugins/defaults/memory-v3-shadow/__tests__/types.test.ts +0 -22
- package/src/plugins/defaults/memory-v3-shadow/capabilities.ts +26 -62
- package/src/plugins/defaults/memory-v3-shadow/dense.ts +97 -0
- package/src/plugins/defaults/memory-v3-shadow/edge.ts +252 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +3 -2
- package/src/plugins/defaults/memory-v3-shadow/maintain-job.ts +415 -181
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +196 -56
- package/src/plugins/defaults/memory-v3-shadow/page-content.ts +39 -2
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +204 -0
- package/src/plugins/defaults/memory-v3-shadow/render-injection.ts +15 -7
- package/src/plugins/defaults/memory-v3-shadow/section-dense-store.ts +236 -0
- package/src/plugins/defaults/memory-v3-shadow/section-needle.ts +200 -0
- package/src/plugins/defaults/memory-v3-shadow/sections.ts +115 -0
- package/src/plugins/defaults/memory-v3-shadow/selection-log-store.ts +75 -3
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +111 -78
- package/src/plugins/defaults/memory-v3-shadow/types.ts +52 -19
- package/src/plugins/defaults/memory-v3-shadow/working-set.ts +4 -1
- package/src/plugins/external-api.ts +114 -0
- package/src/providers/anthropic/client.ts +9 -10
- package/src/providers/inference/kimi-cjk-token-ids.ts +493 -0
- package/src/providers/inference/logit-bias.ts +55 -0
- package/src/providers/openai/chat-completions-provider.ts +19 -1
- package/src/providers/retry.ts +22 -0
- package/src/providers/types.ts +6 -0
- package/src/runtime/routes/app-management-routes.ts +3 -0
- package/src/runtime/routes/memory-v3-routes.ts +64 -314
- package/src/services/published-app-updater.ts +30 -8
- package/src/tools/skills/load.ts +1 -1
- package/src/plugins/defaults/memory-v3-shadow/__tests__/assign.test.ts +0 -242
- package/src/plugins/defaults/memory-v3-shadow/__tests__/core.test.ts +0 -39
- package/src/plugins/defaults/memory-v3-shadow/__tests__/health.test.ts +0 -219
- package/src/plugins/defaults/memory-v3-shadow/__tests__/needle.test.ts +0 -107
- package/src/plugins/defaults/memory-v3-shadow/__tests__/provider-blocks.test.ts +0 -13
- package/src/plugins/defaults/memory-v3-shadow/__tests__/reconcile.test.ts +0 -274
- package/src/plugins/defaults/memory-v3-shadow/__tests__/router.test.ts +0 -337
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selector.test.ts +0 -470
- package/src/plugins/defaults/memory-v3-shadow/__tests__/snapshot.test.ts +0 -168
- package/src/plugins/defaults/memory-v3-shadow/__tests__/tree.test.ts +0 -192
- package/src/plugins/defaults/memory-v3-shadow/assign.ts +0 -272
- package/src/plugins/defaults/memory-v3-shadow/core.ts +0 -26
- package/src/plugins/defaults/memory-v3-shadow/health.ts +0 -0
- package/src/plugins/defaults/memory-v3-shadow/needle.ts +0 -115
- package/src/plugins/defaults/memory-v3-shadow/provider-blocks.ts +0 -26
- package/src/plugins/defaults/memory-v3-shadow/reconcile.ts +0 -527
- package/src/plugins/defaults/memory-v3-shadow/router.ts +0 -190
- package/src/plugins/defaults/memory-v3-shadow/selector.ts +0 -226
- package/src/plugins/defaults/memory-v3-shadow/snapshot.ts +0 -209
- package/src/plugins/defaults/memory-v3-shadow/tree.ts +0 -174
- 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
|
|
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`
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
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 `
|
|
26
|
-
* schema stays a permissive string so a new lane label
|
|
27
|
-
* on the FE. `pinned` marks a slug carried
|
|
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
|
|
40
|
-
*
|
|
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(),
|