@vellumai/assistant 0.12.5 → 0.12.6-dev.202609292116.41f7caa
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/.env.example +2 -0
- package/ARCHITECTURE.md +26 -3
- package/docs/automatic-done.md +32 -0
- package/docs/desktop-browser-cli.md +3 -2
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/mcp-oauth.test.ts +53 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/mcp-oauth.ts +60 -0
- package/node_modules/@vellumai/environments/src/shell.test.ts +13 -1
- package/node_modules/@vellumai/environments/src/shell.ts +22 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/mcp-oauth.test.ts +53 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/mcp-oauth.ts +60 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/status-contracts.test.ts +39 -0
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +25 -0
- package/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/service-contracts/src/__tests__/mcp-oauth.test.ts +53 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/mcp-oauth.ts +60 -0
- package/openapi.yaml +270 -10
- package/package.json +1 -1
- package/src/__tests__/agent-loop.test.ts +76 -0
- package/src/__tests__/anthropic-provider.test.ts +2 -0
- package/src/__tests__/byok-default-profile-ensure.test.ts +7 -0
- package/src/__tests__/config-get-vision-flag.test.ts +1 -1
- package/src/__tests__/config-loader-validation-reset-notice.test.ts +2 -2
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +160 -154
- package/src/__tests__/conversation-evictor.test.ts +54 -0
- package/src/__tests__/conversation-pairing.test.ts +112 -0
- package/src/__tests__/document-append-idempotency.test.ts +13 -0
- package/src/__tests__/document-create-dedupe.test.ts +13 -0
- package/src/__tests__/document-find-replace.test.ts +13 -0
- package/src/__tests__/document-revision-history.test.ts +390 -0
- package/src/__tests__/document-revision.test.ts +425 -0
- package/src/__tests__/document-tool-security.test.ts +13 -0
- package/src/__tests__/document-update-default-surface.test.ts +13 -0
- package/src/__tests__/emit-signal-routing-intent.test.ts +270 -0
- package/src/__tests__/gateway-flag-listener.test.ts +59 -6
- package/src/__tests__/headless-browser-navigate.test.ts +20 -30
- package/src/__tests__/host-cu-proxy.test.ts +79 -0
- package/src/__tests__/host-cu-routes-targeted.test.ts +14 -5
- package/src/__tests__/host-shell-tool.test.ts +6 -2
- package/src/__tests__/identity-routes.test.ts +4 -3
- package/src/__tests__/list-messages-client-message-id.test.ts +43 -0
- package/src/__tests__/llm-catalog-parity.test.ts +4 -4
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/notification-platform-adapter.test.ts +83 -1
- package/src/__tests__/oauth2-gateway-transport.test.ts +2 -0
- package/src/__tests__/openai-provider.test.ts +38 -11
- package/src/__tests__/pricing.test.ts +11 -0
- package/src/__tests__/public-ingress-urls.test.ts +26 -0
- package/src/__tests__/retry-thinking-tool-choice.test.ts +47 -0
- package/src/__tests__/skill-execute-input.test.ts +11 -0
- package/src/__tests__/tool-approval-handler.test.ts +4 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +26 -0
- package/src/__tests__/usage-attribution.test.ts +31 -0
- package/src/__tests__/workspace-migration-133-collapse-provider-connections.test.ts +3 -3
- package/src/__tests__/workspace-migration-160-repair-retired-fireworks-model-ids.test.ts +262 -0
- package/src/__tests__/workspace-migration-161-repair-retired-fireworks-glm-5p2-model-id.test.ts +233 -0
- package/src/acp/agent-process.ts +6 -1
- package/src/acp/client-handler.ts +6 -1
- package/src/agent/loop-unparseable-tool-retry.test.ts +333 -0
- package/src/agent/loop.ts +161 -17
- package/src/api/events/document-editor-show.ts +5 -0
- package/src/api/events/document-editor-update.ts +10 -0
- package/src/api/events/tool-result.ts +1 -0
- package/src/calls/__tests__/call-controller.test.ts +273 -1
- package/src/calls/__tests__/media-stream-server-integration.test.ts +40 -0
- package/src/calls/__tests__/media-stream-stt-session.test.ts +33 -0
- package/src/calls/__tests__/voice-session-bridge.test.ts +54 -0
- package/src/calls/call-constants.ts +10 -0
- package/src/calls/call-controller.ts +359 -25
- package/src/calls/channel-admission-reader.ts +15 -9
- package/src/calls/media-stream-server.ts +18 -0
- package/src/calls/media-stream-stt-session.ts +30 -9
- package/src/calls/twilio-provider.ts +14 -31
- package/src/calls/voice-session-bridge.ts +18 -1
- package/src/cli/commands/browser.ts +1 -2
- package/src/cli/lib/__tests__/plugin-artifact.test.ts +23 -0
- package/src/cli/lib/__tests__/plugin-catalog-visibility.test.ts +2 -0
- package/src/cli/lib/__tests__/plugin-details.test.ts +16 -0
- package/src/cli/lib/bundled-marketplace.json +54 -2
- package/src/cli/lib/inspect-plugin.ts +15 -15
- package/src/cli/lib/list-installed-plugins.ts +29 -28
- package/src/cli/lib/plugin-artifact.ts +74 -63
- package/src/cli/lib/plugin-catalog-visibility.ts +1 -0
- package/src/cli/lib/plugin-details.ts +27 -42
- package/src/cli/lib/plugin-marketplace.ts +6 -8
- package/src/cli/lib/plugin-surfaces.ts +8 -7
- package/src/cli.ts +1 -3
- package/src/config/__tests__/chat-settings.test.ts +121 -0
- package/src/config/assistant-feature-flags.ts +28 -23
- package/src/config/bundled-skills/computer-use/SKILL.md +20 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +11 -11
- package/src/config/chat-settings.ts +100 -0
- package/src/config/default-profile-catalog.ts +1 -1
- package/src/config/feature-flag-cache.ts +7 -25
- package/src/config/feature-flag-registry.json +9 -9
- package/src/config/loader.ts +5 -1
- package/src/config/profile-text-generation.ts +25 -21
- package/src/config/schemas/conversations.ts +14 -0
- package/src/config/schemas/llm.ts +1 -0
- package/src/config/schemas/notifications.ts +8 -1
- package/src/contacts/gateway-channel-read.ts +1 -1
- package/src/conversations/__tests__/auto-archive-activity.test.ts +136 -0
- package/src/conversations/__tests__/auto-archive.test.ts +304 -0
- package/src/conversations/auto-archive-activity.ts +61 -0
- package/src/conversations/auto-archive.ts +201 -0
- package/src/daemon/computer-use-observation.test.ts +81 -0
- package/src/daemon/computer-use-observation.ts +23 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +18 -2
- package/src/daemon/conversation-agent-loop.ts +14 -6
- package/src/daemon/conversation-evictor.ts +50 -16
- package/src/daemon/conversation-messaging.ts +4 -0
- package/src/daemon/conversation-process.ts +15 -0
- package/src/daemon/conversation-queue-manager.ts +2 -0
- package/src/daemon/conversation.ts +2 -0
- package/src/daemon/doordash-steps.ts +1 -3
- package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +43 -1
- package/src/daemon/handlers/__tests__/config-channels.test.ts +1 -1
- package/src/daemon/handlers/config-a2a.ts +75 -2
- package/src/daemon/handlers/shared.ts +13 -2
- package/src/daemon/host-cu-proxy.ts +34 -3
- package/src/daemon/lifecycle.ts +15 -2
- package/src/daemon/process-message.ts +5 -0
- package/src/daemon/shutdown-handlers.ts +3 -0
- package/src/daemon/turn-finalization.ts +4 -0
- package/src/desktop/desktop-browser-endpoint.ts +11 -2
- package/src/desktop/desktop-chrome-policy.test.ts +1 -0
- package/src/desktop/desktop-chrome-policy.ts +7 -1
- package/src/desktop/desktop-computer-use.test.ts +14 -4
- package/src/desktop/desktop-session-manager.ts +5 -3
- package/src/documents/document-revisions-store.ts +153 -0
- package/src/documents/document-store.ts +471 -133
- package/src/followups/followup-store.ts +0 -4
- package/src/i18n/__tests__/i18n.test.ts +25 -0
- package/src/i18n/assistant-text.ts +18 -0
- package/src/i18n/index.ts +1 -0
- package/src/i18n/messages.ts +11 -0
- package/src/inbound/__tests__/oauth-callback-url.test.ts +25 -2
- package/src/inbound/oauth-callback-url.ts +30 -1
- package/src/inbound/public-ingress-urls.ts +12 -2
- package/src/ipc/gateway-client.test.ts +40 -0
- package/src/ipc/gateway-client.ts +12 -29
- package/src/ipc/gateway-flag-listener.ts +7 -10
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +71 -0
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +83 -0
- package/src/live-voice/__tests__/protocol.test.ts +77 -0
- package/src/live-voice/__tests__/share-targets.test.ts +163 -0
- package/src/live-voice/live-voice-session.ts +23 -6
- package/src/live-voice/protocol.ts +22 -0
- package/src/live-voice/share-targets.ts +225 -0
- package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +144 -3
- package/src/mcp/__tests__/mcp-oauth-provider.test.ts +2 -0
- package/src/mcp/client.ts +1 -19
- package/src/mcp/mcp-oauth-provider.ts +66 -49
- package/src/media/openrouter-image-service.ts +39 -22
- package/src/monitoring/__tests__/oom-inheritance-sweep.test.ts +86 -0
- package/src/monitoring/__tests__/oom-kill-reporter.test.ts +374 -0
- package/src/monitoring/control.ts +2 -1
- package/src/monitoring/oom-inheritance-sweep.ts +96 -0
- package/src/monitoring/oom-kill-reporter.ts +469 -0
- package/src/monitoring/resource-sampler.ts +30 -0
- package/src/notifications/README.md +53 -4
- package/src/notifications/__tests__/assistant-initiated-thread.test.ts +254 -0
- package/src/notifications/__tests__/broadcaster.test.ts +558 -6
- package/src/notifications/__tests__/completion-policy.test.ts +37 -0
- package/src/notifications/__tests__/from-me-alert-integration.test.ts +192 -0
- package/src/notifications/adapters/platform.ts +14 -0
- package/src/notifications/assistant-initiated-thread.ts +101 -0
- package/src/notifications/broadcaster.ts +94 -16
- package/src/notifications/chat-reply-policy.ts +11 -0
- package/src/notifications/completion-policy.ts +12 -2
- package/src/notifications/conversation-pairing.ts +15 -70
- package/src/notifications/emit-signal.ts +34 -3
- package/src/notifications/types.ts +2 -0
- package/src/oauth/connect-orchestrator.ts +1 -2
- package/src/persistence/__tests__/conversation-auto-archive.test.ts +330 -0
- package/src/persistence/conversation-auto-archive.ts +170 -0
- package/src/persistence/conversation-crud.ts +2 -1
- package/src/persistence/conversation-queries.ts +15 -8
- package/src/persistence/embeddings/embed.test.ts +96 -0
- package/src/persistence/embeddings/embed.ts +20 -2
- package/src/persistence/embeddings/embedding-gemini.test.ts +39 -3
- package/src/persistence/embeddings/embedding-gemini.ts +39 -1
- package/src/persistence/embeddings/embedding-local.ts +6 -0
- package/src/persistence/embeddings/qdrant-manager.ts +5 -0
- package/src/persistence/job-utils.ts +10 -0
- package/src/persistence/migrations/384-add-document-revision.test.ts +83 -0
- package/src/persistence/migrations/384-add-document-revision.ts +21 -0
- package/src/persistence/migrations/385-create-document-revisions.test.ts +67 -0
- package/src/persistence/migrations/385-create-document-revisions.ts +28 -0
- package/src/persistence/migrations/386-conversations-last-reopened-at.ts +10 -0
- package/src/persistence/migrations/__tests__/386-conversations-last-reopened-at.test.ts +32 -0
- package/src/persistence/schema/conversations.ts +1 -0
- package/src/persistence/schema/documents.ts +20 -0
- package/src/persistence/steps.ts +6 -0
- package/src/platform/managed-speech.ts +42 -46
- package/src/plugin-api/vision-support.test.ts +21 -21
- package/src/plugins/defaults/empty-response/hooks/post-model-call.ts +11 -6
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +1 -1
- package/src/providers/__tests__/search-provider-catalog.test.ts +8 -0
- package/src/providers/__tests__/unparseable-tool-args.test.ts +25 -0
- package/src/providers/anthropic/client.ts +1 -1
- package/src/providers/fireworks/client.test.ts +168 -0
- package/src/providers/fireworks/client.ts +24 -0
- package/src/providers/inference/adapter-factory.ts +6 -0
- package/src/providers/ionet/client.test.ts +143 -0
- package/src/providers/ionet/client.ts +37 -0
- package/src/providers/model-catalog.ts +141 -84
- package/src/providers/model-intents.ts +4 -4
- package/src/providers/openai/chat-completions-provider.ts +33 -2
- package/src/providers/retry.ts +56 -4
- package/src/providers/search-provider-catalog.ts +10 -0
- package/src/providers/types.ts +10 -2
- package/src/providers/unparseable-tool-args.ts +29 -5
- package/src/providers/usage-tracking.ts +5 -3
- package/src/runtime/assistant-event-hub.ts +23 -0
- package/src/runtime/auth/__tests__/guard-tests.test.ts +0 -7
- package/src/runtime/auth/__tests__/route-policy.test.ts +1 -1
- package/src/runtime/channel-reply-delivery.ts +2 -0
- package/src/runtime/channel-retry-sweep.ts +1 -2
- package/src/runtime/http-types.ts +3 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +35 -10
- package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +48 -0
- package/src/runtime/migrations/vbundle-builder.ts +19 -3
- package/src/runtime/migrations/vbundle-streaming-importer.ts +14 -19
- package/src/runtime/migrations/vbundle-streaming-validator.ts +14 -7
- package/src/runtime/migrations/vbundle-validator.ts +54 -1
- package/src/runtime/pending-interactions.ts +20 -2
- package/src/runtime/routes/__tests__/contact-routes.test.ts +5 -3
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +36 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +375 -2
- package/src/runtime/routes/__tests__/inference-send-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +12 -0
- package/src/runtime/routes/contact-routes.ts +2 -2
- package/src/runtime/routes/conversation-list-routes.ts +10 -2
- package/src/runtime/routes/conversation-query-routes.ts +48 -10
- package/src/runtime/routes/conversation-routes.ts +7 -0
- package/src/runtime/routes/documents-routes.ts +185 -47
- package/src/runtime/routes/events-routes.ts +1 -3
- package/src/runtime/routes/host-app-control-routes.ts +1 -0
- package/src/runtime/routes/host-bash-routes.ts +1 -0
- package/src/runtime/routes/host-browser-routes.ts +15 -0
- package/src/runtime/routes/host-cu-routes.ts +4 -1
- package/src/runtime/routes/host-file-routes.ts +1 -0
- package/src/runtime/routes/host-proxy-result-binding.test.ts +83 -0
- package/src/runtime/routes/host-proxy-result-binding.ts +25 -0
- package/src/runtime/routes/host-transfer-routes.ts +1 -0
- package/src/runtime/routes/identity-routes.ts +3 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -0
- package/src/runtime/routes/integrations/a2a.ts +4 -1
- package/src/runtime/routes/migration-routes.ts +3 -1
- package/src/runtime/routes/notification-routes.ts +1 -2
- package/src/runtime/routes/ui-snapshot-routes.test.ts +1 -0
- package/src/runtime/routes/user-route-dispatcher.ts +5 -1
- package/src/runtime/verification-templates.ts +1 -2
- package/src/sequence/analytics.ts +0 -4
- package/src/sequence/engine.ts +1 -11
- package/src/sequence/guardrails.ts +1 -6
- package/src/sequence/importer.ts +0 -8
- package/src/sequence/store.ts +0 -10
- package/src/signals/user-message.ts +0 -6
- package/src/skills/catalog-install.ts +52 -23
- package/src/tools/browser/browser-execution.ts +20 -23
- package/src/tools/browser/cdp-client/cdp-inspect/ws-transport.ts +1 -3
- package/src/tools/document/document-tool.ts +13 -11
- package/src/tools/executor.ts +1 -2
- package/src/tools/host-terminal/host-shell.ts +4 -2
- package/src/tools/network/__tests__/web-search.test.ts +105 -0
- package/src/tools/network/web-fetch.ts +2 -4
- package/src/tools/network/web-search.ts +239 -12
- package/src/tools/shared/filesystem/format-diff.ts +1 -2
- package/src/tools/shared/shell-output.test.ts +42 -0
- package/src/tools/shared/shell-output.ts +27 -4
- package/src/tools/skills/execute.ts +10 -7
- package/src/tools/terminal/shell.ts +3 -3
- package/src/tools/tool-approval-handler.ts +9 -1
- package/src/tools/ui-surface/visual-validation.ts +1 -2
- package/src/usage/attribution.ts +18 -1
- package/src/util/__tests__/oom-priority.test.ts +55 -0
- package/src/util/__tests__/worker-memory.test.ts +16 -0
- package/src/util/debounce.ts +0 -4
- package/src/util/oom-priority.ts +79 -0
- package/src/util/platform.ts +0 -2
- package/src/util/plugin-manifest.ts +5 -7
- package/src/util/pricing.ts +25 -0
- package/src/util/worker-memory.ts +9 -3
- package/src/util/worker-process.ts +8 -0
- package/src/workspace/byok-default-profile-ensure.ts +11 -0
- package/src/workspace/hatched-date.ts +11 -4
- package/src/workspace/migrations/160-repair-retired-fireworks-model-ids.ts +209 -0
- package/src/workspace/migrations/161-repair-retired-fireworks-glm-5p2-model-id.ts +197 -0
- package/src/workspace/migrations/registry.ts +4 -0
|
@@ -148,7 +148,7 @@ mock.module(
|
|
|
148
148
|
// agent loop's compaction path consumes, mirroring the real manager's
|
|
149
149
|
// `overflowStepToResult` so the loop sees the rung's reduced history, injection
|
|
150
150
|
// mode, terminal auto-compress flag, and exhaustion.
|
|
151
|
-
function makeOverflowLadderStub(): {
|
|
151
|
+
function makeOverflowLadderStub(stubOpts: { maxInputTokens?: number } = {}): {
|
|
152
152
|
resetOverflowRecovery: () => void;
|
|
153
153
|
reduceOverflowOneRung: (
|
|
154
154
|
msgs: Message[],
|
|
@@ -161,6 +161,7 @@ function makeOverflowLadderStub(): {
|
|
|
161
161
|
signal?: AbortSignal,
|
|
162
162
|
) => Promise<unknown>;
|
|
163
163
|
} {
|
|
164
|
+
const maxInputTokens = stubOpts.maxInputTokens ?? 200_000;
|
|
164
165
|
let state: unknown;
|
|
165
166
|
const reduceOverflowOneRung = async (msgs: Message[], opts: unknown) => {
|
|
166
167
|
if (!state) {
|
|
@@ -178,7 +179,26 @@ function makeOverflowLadderStub(): {
|
|
|
178
179
|
},
|
|
179
180
|
reduceOverflowOneRung,
|
|
180
181
|
recoverContextOverflow: async (msgs: Message[], opts: unknown) => {
|
|
181
|
-
const
|
|
182
|
+
const options = opts as {
|
|
183
|
+
actualTokens: number | null;
|
|
184
|
+
isInteractive: boolean;
|
|
185
|
+
};
|
|
186
|
+
// Mirror ContextWindowManager.deriveOverflowTurnTarget: compute the
|
|
187
|
+
// estimation-error-corrected target and include it in the opts the
|
|
188
|
+
// mock reducer receives, so tests can assert on targetTokens.
|
|
189
|
+
const estimatedInputTokens = estimatePromptTokens(msgs);
|
|
190
|
+
const preflightBudget = Math.floor(maxInputTokens * 0.95);
|
|
191
|
+
const { targetTokens } = computeCorrectedOverflowTarget({
|
|
192
|
+
preflightBudget,
|
|
193
|
+
actualTokens: options.actualTokens,
|
|
194
|
+
estimatedTokens: estimatedInputTokens,
|
|
195
|
+
});
|
|
196
|
+
const enrichedOpts = {
|
|
197
|
+
...options,
|
|
198
|
+
targetTokens,
|
|
199
|
+
estimatedInputTokens,
|
|
200
|
+
};
|
|
201
|
+
const step = (await reduceOverflowOneRung(msgs, enrichedOpts)) as {
|
|
182
202
|
messages: Message[];
|
|
183
203
|
estimatedTokens?: number;
|
|
184
204
|
state: {
|
|
@@ -460,9 +480,11 @@ mock.module("../memory/archive-store.js", () => ({
|
|
|
460
480
|
// ── Imports (after mocks) ────────────────────────────────────────────
|
|
461
481
|
|
|
462
482
|
import { AgentLoop } from "../agent/loop.js";
|
|
483
|
+
import { estimatePromptTokens } from "../context/token-estimator.js";
|
|
463
484
|
import type { Conversation } from "../daemon/conversation.js";
|
|
464
485
|
import { runAgentLoopImpl } from "../daemon/conversation-agent-loop.js";
|
|
465
486
|
import type { QueueDrainReason } from "../daemon/conversation-queue-manager.js";
|
|
487
|
+
import { computeCorrectedOverflowTarget } from "../plugins/defaults/compaction/corrected-target.js";
|
|
466
488
|
import { asConversation } from "./helpers/mock-conversation.js";
|
|
467
489
|
import {
|
|
468
490
|
createMockProvider,
|
|
@@ -748,96 +770,83 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
748
770
|
});
|
|
749
771
|
|
|
750
772
|
// ── Test 1 ────────────────────────────────────────────────────────
|
|
751
|
-
//
|
|
752
|
-
// before hitting context_too_large
|
|
753
|
-
//
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
// Expected behavior (PR 2 fix): After progress + context_too_large,
|
|
758
|
-
// the system should still attempt compaction before surfacing error.
|
|
759
|
-
test.todo(
|
|
760
|
-
"context too large after progress triggers compaction retry instead of immediate failure",
|
|
761
|
-
async () => {
|
|
762
|
-
const events: AssistantEvent[] = [];
|
|
763
|
-
let reducerCalled = false;
|
|
773
|
+
// Verifies overflow recovery fires even when the agent made tool-use progress
|
|
774
|
+
// before hitting context_too_large. The convergence path must not skip
|
|
775
|
+
// compaction just because messages were appended earlier in the turn.
|
|
776
|
+
test("context too large after progress triggers compaction retry instead of immediate failure", async () => {
|
|
777
|
+
const events: AssistantEvent[] = [];
|
|
778
|
+
let reducerCalled = false;
|
|
764
779
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
780
|
+
mockReducerStepFn = (msgs: Message[]) => {
|
|
781
|
+
reducerCalled = true;
|
|
782
|
+
return {
|
|
783
|
+
messages: msgs,
|
|
784
|
+
tier: "forced_compaction",
|
|
785
|
+
state: {
|
|
786
|
+
appliedTiers: ["forced_compaction"],
|
|
787
|
+
injectionMode: "full",
|
|
788
|
+
exhausted: false,
|
|
789
|
+
},
|
|
790
|
+
estimatedTokens: 50_000,
|
|
791
|
+
compactionResult: {
|
|
792
|
+
compacted: true,
|
|
768
793
|
messages: msgs,
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
previousEstimatedInputTokens: 190_000,
|
|
782
|
-
estimatedInputTokens: 50_000,
|
|
783
|
-
maxInputTokens: 200_000,
|
|
784
|
-
thresholdTokens: 160_000,
|
|
785
|
-
compactedMessages: 10,
|
|
786
|
-
summaryCalls: 1,
|
|
787
|
-
summaryInputTokens: 500,
|
|
788
|
-
summaryOutputTokens: 200,
|
|
789
|
-
summaryModel: "mock-model",
|
|
790
|
-
},
|
|
791
|
-
};
|
|
794
|
+
compactedPersistedMessages: 5,
|
|
795
|
+
summaryText: "Summary",
|
|
796
|
+
previousEstimatedInputTokens: 190_000,
|
|
797
|
+
estimatedInputTokens: 50_000,
|
|
798
|
+
maxInputTokens: 200_000,
|
|
799
|
+
thresholdTokens: 160_000,
|
|
800
|
+
compactedMessages: 10,
|
|
801
|
+
summaryCalls: 1,
|
|
802
|
+
summaryInputTokens: 500,
|
|
803
|
+
summaryOutputTokens: 200,
|
|
804
|
+
summaryModel: "mock-model",
|
|
805
|
+
},
|
|
792
806
|
};
|
|
807
|
+
};
|
|
793
808
|
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
809
|
+
// Run 1 makes progress (a tool turn) then the following provider call
|
|
810
|
+
// rejects with a context_too_large error; after the convergence reducer
|
|
811
|
+
// compacts, the rerun recovers with plain text.
|
|
812
|
+
const { provider } = createMockProvider([
|
|
813
|
+
toolUseResponse("tu-progress", "bash", { command: "ls" }),
|
|
814
|
+
new Error("prompt is too long: 242201 tokens > 200000 maximum"),
|
|
815
|
+
textResponse("recovered after compaction"),
|
|
816
|
+
]);
|
|
802
817
|
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
},
|
|
818
|
+
const ctx = makeCtx({
|
|
819
|
+
loopProvider: provider,
|
|
820
|
+
loopTools: [
|
|
821
|
+
{
|
|
822
|
+
name: "bash",
|
|
823
|
+
description: "Run a shell command",
|
|
824
|
+
input_schema: {
|
|
825
|
+
type: "object",
|
|
826
|
+
properties: { command: { type: "string" } },
|
|
813
827
|
},
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
}
|
|
828
|
+
},
|
|
829
|
+
],
|
|
830
|
+
toolExecutor: async () => ({
|
|
831
|
+
content: "file1.ts\nfile2.ts",
|
|
832
|
+
isError: false,
|
|
833
|
+
}),
|
|
834
|
+
contextWindowManager: {
|
|
835
|
+
updateConfig: () => {},
|
|
836
|
+
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
837
|
+
maybeCompact: async () => ({ compacted: false }),
|
|
838
|
+
} as unknown as Conversation["contextWindowManager"],
|
|
839
|
+
});
|
|
825
840
|
|
|
826
|
-
|
|
841
|
+
await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
|
|
827
842
|
|
|
828
|
-
|
|
829
|
-
// context_too_large. The error is surfaced immediately.
|
|
830
|
-
// After PR 2 fix, the reducer SHOULD be called to attempt compaction.
|
|
831
|
-
expect(reducerCalled).toBe(true);
|
|
843
|
+
expect(reducerCalled).toBe(true);
|
|
832
844
|
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
expect(conversationError).toBeUndefined();
|
|
839
|
-
},
|
|
840
|
-
);
|
|
845
|
+
const conversationError = events.find(
|
|
846
|
+
(e) => e.type === "conversation_error",
|
|
847
|
+
);
|
|
848
|
+
expect(conversationError).toBeUndefined();
|
|
849
|
+
});
|
|
841
850
|
|
|
842
851
|
// ── Test 2 ────────────────────────────────────────────────────────
|
|
843
852
|
// When estimation says we're within budget but the provider rejects, the
|
|
@@ -922,88 +931,85 @@ describe("session-agent-loop overflow recovery (JARVIS-110)", () => {
|
|
|
922
931
|
// of 242k (1.31x the estimate of 185k), the target is adjusted downward
|
|
923
932
|
// based on the observed mismatch (190k / 1.31 ≈ 145k) so the reducer
|
|
924
933
|
// converges toward the real ceiling rather than the optimistic estimate.
|
|
925
|
-
test
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
const events: AssistantEvent[] = [];
|
|
929
|
-
let capturedTargetTokens: number | undefined;
|
|
934
|
+
test("forced compaction targets a lower budget when estimation has been inaccurate", async () => {
|
|
935
|
+
const events: AssistantEvent[] = [];
|
|
936
|
+
let capturedTargetTokens: number | undefined;
|
|
930
937
|
|
|
931
|
-
|
|
932
|
-
|
|
938
|
+
// Estimator says 185k (below 190k budget = 200k * 0.95)
|
|
939
|
+
mockEstimateTokens = 185_000;
|
|
933
940
|
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
941
|
+
// Reducer captures the targetTokens from the config
|
|
942
|
+
mockReducerStepFn = (msgs: Message[], cfg: unknown) => {
|
|
943
|
+
capturedTargetTokens = (cfg as { targetTokens: number }).targetTokens;
|
|
944
|
+
return {
|
|
945
|
+
messages: msgs,
|
|
946
|
+
tier: "forced_compaction",
|
|
947
|
+
state: {
|
|
948
|
+
appliedTiers: ["forced_compaction"],
|
|
949
|
+
injectionMode: "full",
|
|
950
|
+
exhausted: false,
|
|
951
|
+
},
|
|
952
|
+
estimatedTokens: 100_000,
|
|
953
|
+
compactionResult: {
|
|
954
|
+
compacted: true,
|
|
938
955
|
messages: msgs,
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
previousEstimatedInputTokens: 185_000,
|
|
952
|
-
estimatedInputTokens: 100_000,
|
|
953
|
-
maxInputTokens: 200_000,
|
|
954
|
-
thresholdTokens: 160_000,
|
|
955
|
-
compactedMessages: 20,
|
|
956
|
-
summaryCalls: 1,
|
|
957
|
-
summaryInputTokens: 800,
|
|
958
|
-
summaryOutputTokens: 300,
|
|
959
|
-
summaryModel: "mock-model",
|
|
960
|
-
},
|
|
961
|
-
};
|
|
956
|
+
compactedPersistedMessages: 10,
|
|
957
|
+
summaryText: "Summary",
|
|
958
|
+
previousEstimatedInputTokens: 185_000,
|
|
959
|
+
estimatedInputTokens: 100_000,
|
|
960
|
+
maxInputTokens: 200_000,
|
|
961
|
+
thresholdTokens: 160_000,
|
|
962
|
+
compactedMessages: 20,
|
|
963
|
+
summaryCalls: 1,
|
|
964
|
+
summaryInputTokens: 800,
|
|
965
|
+
summaryOutputTokens: 300,
|
|
966
|
+
summaryModel: "mock-model",
|
|
967
|
+
},
|
|
962
968
|
};
|
|
969
|
+
};
|
|
963
970
|
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
+
// The provider rejects the first call with a context_too_large error
|
|
972
|
+
// (actual tokens 242201, far above the 185k estimate); after forced
|
|
973
|
+
// compaction re-targets a lower budget, the rerun recovers with text.
|
|
974
|
+
const { provider, calls } = createMockProvider([
|
|
975
|
+
new Error("prompt is too long: 242201 tokens > 200000 maximum"),
|
|
976
|
+
textResponse("recovered"),
|
|
977
|
+
]);
|
|
971
978
|
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
979
|
+
const ctx = makeCtx({
|
|
980
|
+
loopProvider: provider,
|
|
981
|
+
contextWindowManager: {
|
|
982
|
+
updateConfig: () => {},
|
|
983
|
+
shouldCompact: () => ({ needed: false, estimatedTokens: 0 }),
|
|
984
|
+
maybeCompact: async () => ({ compacted: false }),
|
|
985
|
+
} as unknown as Conversation["contextWindowManager"],
|
|
986
|
+
});
|
|
980
987
|
|
|
981
|
-
|
|
988
|
+
await runAgentLoopImpl(ctx, "hello", "msg-1", (msg) => events.push(msg));
|
|
982
989
|
|
|
983
|
-
|
|
984
|
-
|
|
990
|
+
// The reducer should have been called with a corrected target
|
|
991
|
+
expect(capturedTargetTokens).toBeDefined();
|
|
985
992
|
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
993
|
+
// preflightBudget = 200_000 * 0.95 = 190_000
|
|
994
|
+
// estimationErrorRatio = 242201 / 185000 ≈ 1.309
|
|
995
|
+
// correctedTarget = floor(190000 / 1.309) ≈ 145_130
|
|
996
|
+
// The corrected target must be LESS than the uncorrected preflightBudget
|
|
997
|
+
const preflightBudget = 190_000;
|
|
998
|
+
expect(capturedTargetTokens!).toBeLessThan(preflightBudget);
|
|
992
999
|
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
1000
|
+
// Verify the approximate corrected value (190000 / (242201/185000))
|
|
1001
|
+
const expectedCorrectedTarget = Math.floor(
|
|
1002
|
+
preflightBudget / (242201 / 185_000),
|
|
1003
|
+
);
|
|
1004
|
+
expect(capturedTargetTokens!).toBe(expectedCorrectedTarget);
|
|
998
1005
|
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
);
|
|
1006
|
+
// Should recover without conversation_error
|
|
1007
|
+
const conversationError = events.find(
|
|
1008
|
+
(e) => e.type === "conversation_error",
|
|
1009
|
+
);
|
|
1010
|
+
expect(conversationError).toBeUndefined();
|
|
1011
|
+
expect(calls.length).toBe(2);
|
|
1012
|
+
});
|
|
1007
1013
|
|
|
1008
1014
|
// ── Test 4 ────────────────────────────────────────────────────────
|
|
1009
1015
|
// A realistic 75+ message conversation with many tool calls where
|
|
@@ -12,6 +12,7 @@ mock.module("../subagent/index.js", () => ({
|
|
|
12
12
|
|
|
13
13
|
import {
|
|
14
14
|
ConversationEvictor,
|
|
15
|
+
defaultMemoryThresholdBytes,
|
|
15
16
|
type EvictableConversation,
|
|
16
17
|
} from "../daemon/conversation-evictor.js";
|
|
17
18
|
|
|
@@ -268,6 +269,46 @@ describe("ConversationEvictor", () => {
|
|
|
268
269
|
expect(resident.disposed).toBe(false);
|
|
269
270
|
expect(idle.disposed).toBe(true);
|
|
270
271
|
});
|
|
272
|
+
|
|
273
|
+
test("evicts a bounded batch per sweep, least recently used first", () => {
|
|
274
|
+
for (let i = 0; i < 15; i++) {
|
|
275
|
+
sessions.set(`conv-${i}`, createMockSession());
|
|
276
|
+
}
|
|
277
|
+
evictor = new ConversationEvictor(sessions, {
|
|
278
|
+
ttlMs: Number.MAX_SAFE_INTEGER,
|
|
279
|
+
maxConversations: Number.MAX_SAFE_INTEGER,
|
|
280
|
+
memoryThresholdBytes: 0,
|
|
281
|
+
});
|
|
282
|
+
for (let i = 0; i < 15; i++) {
|
|
283
|
+
evictor.touch(`conv-${i}`);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
expect(evictor.sweep().memoryEvicted).toBe(10);
|
|
287
|
+
expect(sessions.has("conv-0")).toBe(false);
|
|
288
|
+
expect(sessions.has("conv-10")).toBe(true);
|
|
289
|
+
expect(evictor.sweep().memoryEvicted).toBe(5);
|
|
290
|
+
expect(sessions.size).toBe(0);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
test("derives the threshold from the container limit at first sweep, not construction", () => {
|
|
294
|
+
const previous = process.env.VELLUM_MEMORY_LIMIT;
|
|
295
|
+
sessions.set("idle", createMockSession());
|
|
296
|
+
evictor = new ConversationEvictor(sessions, {
|
|
297
|
+
ttlMs: Number.MAX_SAFE_INTEGER,
|
|
298
|
+
maxConversations: Number.MAX_SAFE_INTEGER,
|
|
299
|
+
});
|
|
300
|
+
// Half of 1 MiB is far below any live RSS, so the phase must fire.
|
|
301
|
+
process.env.VELLUM_MEMORY_LIMIT = "1Mi";
|
|
302
|
+
try {
|
|
303
|
+
expect(evictor.sweep().memoryEvicted).toBe(1);
|
|
304
|
+
} finally {
|
|
305
|
+
if (previous === undefined) {
|
|
306
|
+
delete process.env.VELLUM_MEMORY_LIMIT;
|
|
307
|
+
} else {
|
|
308
|
+
process.env.VELLUM_MEMORY_LIMIT = previous;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
});
|
|
271
312
|
});
|
|
272
313
|
|
|
273
314
|
describe("onEvict", () => {
|
|
@@ -326,3 +367,16 @@ describe("ConversationEvictor", () => {
|
|
|
326
367
|
});
|
|
327
368
|
});
|
|
328
369
|
});
|
|
370
|
+
|
|
371
|
+
describe("defaultMemoryThresholdBytes", () => {
|
|
372
|
+
const GIB = 1024 * 1024 * 1024;
|
|
373
|
+
|
|
374
|
+
test("is half the container limit", () => {
|
|
375
|
+
expect(defaultMemoryThresholdBytes(3 * GIB)).toBe(1.5 * GIB);
|
|
376
|
+
expect(defaultMemoryThresholdBytes(8 * GIB)).toBe(4 * GIB);
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
test("falls back to 3 GiB without a limit", () => {
|
|
380
|
+
expect(defaultMemoryThresholdBytes(null)).toBe(3 * GIB);
|
|
381
|
+
});
|
|
382
|
+
});
|
|
@@ -116,6 +116,7 @@ mock.module("../config/assistant-initiated-threads-gate.js", () => ({
|
|
|
116
116
|
isAssistantInitiatedThreadsEnabled: () => assistantInitiatedThreadsEnabled,
|
|
117
117
|
}));
|
|
118
118
|
|
|
119
|
+
import { resolveAssistantInitiatedThread } from "../notifications/assistant-initiated-thread.js";
|
|
119
120
|
import { pairDeliveryWithConversation } from "../notifications/conversation-pairing.js";
|
|
120
121
|
import type { NotificationSignal } from "../notifications/signal.js";
|
|
121
122
|
import type {
|
|
@@ -1478,6 +1479,117 @@ describe("pairDeliveryWithConversation", () => {
|
|
|
1478
1479
|
...overrides,
|
|
1479
1480
|
});
|
|
1480
1481
|
|
|
1482
|
+
test("a prepared resolution is reused even if the source changes before pairing", async () => {
|
|
1483
|
+
assistantInitiatedThreadsEnabled = true;
|
|
1484
|
+
const signal = share({
|
|
1485
|
+
conversationMetadata: { groupId: "group-123" },
|
|
1486
|
+
});
|
|
1487
|
+
const original = structuredClone(signal);
|
|
1488
|
+
const assistantInitiatedThread = resolveAssistantInitiatedThread(signal);
|
|
1489
|
+
getConversationMock.mockClear();
|
|
1490
|
+
mockExistingConversations[signal.sourceContextId] = {
|
|
1491
|
+
id: signal.sourceContextId,
|
|
1492
|
+
source: "user",
|
|
1493
|
+
title: null,
|
|
1494
|
+
conversationType: "standard",
|
|
1495
|
+
};
|
|
1496
|
+
|
|
1497
|
+
const result = await pairDeliveryWithConversation(
|
|
1498
|
+
signal,
|
|
1499
|
+
"vellum",
|
|
1500
|
+
makeCopy(),
|
|
1501
|
+
{ assistantInitiatedThread },
|
|
1502
|
+
);
|
|
1503
|
+
|
|
1504
|
+
expect(result.createdNewConversation).toBe(true);
|
|
1505
|
+
expect(result.messageId).toBe("msg-001");
|
|
1506
|
+
expect(createConversationMock).toHaveBeenCalledWith(
|
|
1507
|
+
expect.objectContaining({
|
|
1508
|
+
source: "assistant_initiated",
|
|
1509
|
+
groupId: "group-123",
|
|
1510
|
+
}),
|
|
1511
|
+
);
|
|
1512
|
+
expect(getConversationMock).not.toHaveBeenCalled();
|
|
1513
|
+
expect(signal).toEqual(original);
|
|
1514
|
+
});
|
|
1515
|
+
|
|
1516
|
+
test("an ineligible prepared resolution retains passive pairing when the flag changes", async () => {
|
|
1517
|
+
const signal = share();
|
|
1518
|
+
const assistantInitiatedThread = resolveAssistantInitiatedThread(signal);
|
|
1519
|
+
assistantInitiatedThreadsEnabled = true;
|
|
1520
|
+
mockExistingConversations[signal.sourceContextId] = {
|
|
1521
|
+
id: signal.sourceContextId,
|
|
1522
|
+
source: "heartbeat",
|
|
1523
|
+
title: null,
|
|
1524
|
+
conversationType: "background",
|
|
1525
|
+
};
|
|
1526
|
+
|
|
1527
|
+
const result = await pairDeliveryWithConversation(
|
|
1528
|
+
signal,
|
|
1529
|
+
"vellum",
|
|
1530
|
+
makeCopy(),
|
|
1531
|
+
{ assistantInitiatedThread },
|
|
1532
|
+
);
|
|
1533
|
+
|
|
1534
|
+
expect(result.createdNewConversation).toBe(false);
|
|
1535
|
+
expect(result.conversationId).toBe(signal.sourceContextId);
|
|
1536
|
+
expect(createConversationMock).not.toHaveBeenCalled();
|
|
1537
|
+
expect(addMessageMock).toHaveBeenCalledTimes(1);
|
|
1538
|
+
});
|
|
1539
|
+
|
|
1540
|
+
test.each(["slack", "telegram", "discord"] as const)(
|
|
1541
|
+
"%s retains the producer metadata despite a prepared vellum resolution",
|
|
1542
|
+
async (channel) => {
|
|
1543
|
+
assistantInitiatedThreadsEnabled = true;
|
|
1544
|
+
const signal = share({
|
|
1545
|
+
conversationMetadata: { groupId: "group-123" },
|
|
1546
|
+
});
|
|
1547
|
+
const original = structuredClone(signal);
|
|
1548
|
+
const assistantInitiatedThread =
|
|
1549
|
+
resolveAssistantInitiatedThread(signal);
|
|
1550
|
+
getConversationMock.mockClear();
|
|
1551
|
+
|
|
1552
|
+
const result = await pairDeliveryWithConversation(
|
|
1553
|
+
signal,
|
|
1554
|
+
channel,
|
|
1555
|
+
makeCopy(),
|
|
1556
|
+
{ assistantInitiatedThread },
|
|
1557
|
+
);
|
|
1558
|
+
|
|
1559
|
+
expect(result.createdNewConversation).toBe(true);
|
|
1560
|
+
expect(result.strategy).toBe("continue_existing_conversation");
|
|
1561
|
+
expect(createConversationMock).toHaveBeenCalledWith(
|
|
1562
|
+
expect.objectContaining({
|
|
1563
|
+
conversationType: "background",
|
|
1564
|
+
source: "notification",
|
|
1565
|
+
groupId: "group-123",
|
|
1566
|
+
}),
|
|
1567
|
+
);
|
|
1568
|
+
expect(addMessageMock).not.toHaveBeenCalled();
|
|
1569
|
+
expect(getConversationMock).not.toHaveBeenCalled();
|
|
1570
|
+
expect(signal).toEqual(original);
|
|
1571
|
+
},
|
|
1572
|
+
);
|
|
1573
|
+
|
|
1574
|
+
test("platform delivery does not pair a prepared vellum resolution", async () => {
|
|
1575
|
+
assistantInitiatedThreadsEnabled = true;
|
|
1576
|
+
const signal = share();
|
|
1577
|
+
const assistantInitiatedThread = resolveAssistantInitiatedThread(signal);
|
|
1578
|
+
|
|
1579
|
+
const result = await pairDeliveryWithConversation(
|
|
1580
|
+
signal,
|
|
1581
|
+
"platform",
|
|
1582
|
+
makeCopy(),
|
|
1583
|
+
{ assistantInitiatedThread },
|
|
1584
|
+
);
|
|
1585
|
+
|
|
1586
|
+
expect(result.strategy).toBe("push_only");
|
|
1587
|
+
expect(result.createdNewConversation).toBe(false);
|
|
1588
|
+
expect(result.conversationId).toBeNull();
|
|
1589
|
+
expect(createConversationMock).not.toHaveBeenCalled();
|
|
1590
|
+
expect(addMessageMock).not.toHaveBeenCalled();
|
|
1591
|
+
});
|
|
1592
|
+
|
|
1481
1593
|
test("flag on: a share from a background run materializes a section thread", async () => {
|
|
1482
1594
|
assistantInitiatedThreadsEnabled = true;
|
|
1483
1595
|
mockExistingConversations["conv-heartbeat"] = {
|
|
@@ -35,6 +35,7 @@ function bootstrapDocumentTables(): void {
|
|
|
35
35
|
const raw = getSqlite();
|
|
36
36
|
raw.exec(/*sql*/ `
|
|
37
37
|
DROP TABLE IF EXISTS document_conversations;
|
|
38
|
+
DROP TABLE IF EXISTS document_revisions;
|
|
38
39
|
DROP TABLE IF EXISTS documents;
|
|
39
40
|
DROP TABLE IF EXISTS conversations;
|
|
40
41
|
|
|
@@ -51,9 +52,21 @@ function bootstrapDocumentTables(): void {
|
|
|
51
52
|
word_count INTEGER NOT NULL DEFAULT 0,
|
|
52
53
|
created_at INTEGER NOT NULL,
|
|
53
54
|
updated_at INTEGER NOT NULL,
|
|
55
|
+
revision INTEGER NOT NULL DEFAULT 0,
|
|
54
56
|
workspace_path TEXT
|
|
55
57
|
);
|
|
56
58
|
|
|
59
|
+
CREATE TABLE document_revisions (
|
|
60
|
+
surface_id TEXT NOT NULL REFERENCES documents(surface_id) ON DELETE CASCADE,
|
|
61
|
+
revision INTEGER NOT NULL,
|
|
62
|
+
title TEXT NOT NULL,
|
|
63
|
+
content TEXT NOT NULL,
|
|
64
|
+
word_count INTEGER NOT NULL DEFAULT 0,
|
|
65
|
+
author TEXT NOT NULL,
|
|
66
|
+
created_at INTEGER NOT NULL,
|
|
67
|
+
PRIMARY KEY (surface_id, revision)
|
|
68
|
+
);
|
|
69
|
+
|
|
57
70
|
CREATE TABLE document_conversations (
|
|
58
71
|
surface_id TEXT NOT NULL,
|
|
59
72
|
conversation_id TEXT NOT NULL,
|
|
@@ -29,6 +29,7 @@ function bootstrapDocumentTables(): void {
|
|
|
29
29
|
const raw = getSqlite();
|
|
30
30
|
raw.exec(/*sql*/ `
|
|
31
31
|
DROP TABLE IF EXISTS document_conversations;
|
|
32
|
+
DROP TABLE IF EXISTS document_revisions;
|
|
32
33
|
DROP TABLE IF EXISTS documents;
|
|
33
34
|
DROP TABLE IF EXISTS conversations;
|
|
34
35
|
|
|
@@ -45,9 +46,21 @@ function bootstrapDocumentTables(): void {
|
|
|
45
46
|
word_count INTEGER NOT NULL DEFAULT 0,
|
|
46
47
|
created_at INTEGER NOT NULL,
|
|
47
48
|
updated_at INTEGER NOT NULL,
|
|
49
|
+
revision INTEGER NOT NULL DEFAULT 0,
|
|
48
50
|
workspace_path TEXT
|
|
49
51
|
);
|
|
50
52
|
|
|
53
|
+
CREATE TABLE document_revisions (
|
|
54
|
+
surface_id TEXT NOT NULL REFERENCES documents(surface_id) ON DELETE CASCADE,
|
|
55
|
+
revision INTEGER NOT NULL,
|
|
56
|
+
title TEXT NOT NULL,
|
|
57
|
+
content TEXT NOT NULL,
|
|
58
|
+
word_count INTEGER NOT NULL DEFAULT 0,
|
|
59
|
+
author TEXT NOT NULL,
|
|
60
|
+
created_at INTEGER NOT NULL,
|
|
61
|
+
PRIMARY KEY (surface_id, revision)
|
|
62
|
+
);
|
|
63
|
+
|
|
51
64
|
CREATE TABLE document_conversations (
|
|
52
65
|
surface_id TEXT NOT NULL,
|
|
53
66
|
conversation_id TEXT NOT NULL,
|
|
@@ -28,6 +28,7 @@ function bootstrapDocumentTables(): void {
|
|
|
28
28
|
const raw = getSqlite();
|
|
29
29
|
raw.exec(/*sql*/ `
|
|
30
30
|
DROP TABLE IF EXISTS document_conversations;
|
|
31
|
+
DROP TABLE IF EXISTS document_revisions;
|
|
31
32
|
DROP TABLE IF EXISTS documents;
|
|
32
33
|
DROP TABLE IF EXISTS conversations;
|
|
33
34
|
|
|
@@ -44,9 +45,21 @@ function bootstrapDocumentTables(): void {
|
|
|
44
45
|
word_count INTEGER NOT NULL DEFAULT 0,
|
|
45
46
|
created_at INTEGER NOT NULL,
|
|
46
47
|
updated_at INTEGER NOT NULL,
|
|
48
|
+
revision INTEGER NOT NULL DEFAULT 0,
|
|
47
49
|
workspace_path TEXT
|
|
48
50
|
);
|
|
49
51
|
|
|
52
|
+
CREATE TABLE document_revisions (
|
|
53
|
+
surface_id TEXT NOT NULL REFERENCES documents(surface_id) ON DELETE CASCADE,
|
|
54
|
+
revision INTEGER NOT NULL,
|
|
55
|
+
title TEXT NOT NULL,
|
|
56
|
+
content TEXT NOT NULL,
|
|
57
|
+
word_count INTEGER NOT NULL DEFAULT 0,
|
|
58
|
+
author TEXT NOT NULL,
|
|
59
|
+
created_at INTEGER NOT NULL,
|
|
60
|
+
PRIMARY KEY (surface_id, revision)
|
|
61
|
+
);
|
|
62
|
+
|
|
50
63
|
CREATE TABLE document_conversations (
|
|
51
64
|
surface_id TEXT NOT NULL,
|
|
52
65
|
conversation_id TEXT NOT NULL,
|