@vellumai/assistant 0.8.11 → 0.8.12-staging.2
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/ARCHITECTURE.md +15 -17
- package/README.md +0 -6
- package/bun.lock +6 -122
- package/node_modules/@vellumai/gateway-client/bun.lock +1 -0
- package/node_modules/@vellumai/gateway-client/package.json +3 -1
- package/node_modules/@vellumai/gateway-client/src/__tests__/gateway-client.test.ts +1 -1
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +87 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +3 -5
- package/openapi.yaml +633 -4
- package/package.json +1 -3
- package/src/__tests__/adaptive-thinking-repair.test.ts +185 -0
- package/src/__tests__/agent-loop-compaction-events.test.ts +7 -6
- package/src/__tests__/anthropic-provider.test.ts +129 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +4 -1
- package/src/__tests__/btw-routes.test.ts +7 -34
- package/src/__tests__/checker.test.ts +6 -12
- package/src/__tests__/config-loader-backfill.test.ts +4 -2
- package/src/__tests__/config-loader-quarantine-notice.test.ts +167 -0
- package/src/__tests__/config-watcher.test.ts +2 -2
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
- package/src/__tests__/conversation-error.test.ts +2 -6
- package/src/__tests__/conversation-history-web-search.test.ts +8 -0
- package/src/__tests__/conversation-title-service.test.ts +2 -1
- package/src/__tests__/credential-security-invariants.test.ts +1 -1
- package/src/__tests__/disk-pressure-tools.test.ts +1 -1
- package/src/__tests__/exploration-drift-hook.test.ts +692 -0
- package/src/__tests__/filing-service.test.ts +8 -3
- package/src/__tests__/guardian-action-store.test.ts +0 -167
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -1
- package/src/__tests__/heartbeat-service.test.ts +5 -2
- package/src/__tests__/identity-intro-cache.test.ts +12 -5
- package/src/__tests__/identity-routes.test.ts +16 -57
- package/src/__tests__/injector-chain.test.ts +8 -3
- package/src/__tests__/injector-config-quarantine-notice.test.ts +115 -0
- package/src/__tests__/llm-catalog-parity.test.ts +16 -0
- package/src/__tests__/llm-usage-store.test.ts +11 -0
- package/src/__tests__/log-export-workspace.test.ts +468 -3
- package/src/__tests__/memory-v2-static-injector.test.ts +22 -0
- package/src/__tests__/model-intents.test.ts +1 -1
- package/src/__tests__/oauth-cli.test.ts +19 -8
- package/src/__tests__/openai-provider.test.ts +34 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +0 -1
- package/src/__tests__/recurrence-engine.test.ts +45 -0
- package/src/__tests__/schedule-routes.test.ts +34 -0
- package/src/__tests__/scheduler-disk-pressure.test.ts +1 -1
- package/src/__tests__/script-proxy-conversation-manager.test.ts +10 -5
- package/src/__tests__/secret-fixtures.ts +20 -0
- package/src/__tests__/skill-tool-factory.test.ts +49 -0
- package/src/__tests__/subagent-role-registry.test.ts +24 -1
- package/src/__tests__/subagent-tools.test.ts +1 -0
- package/src/__tests__/system-prompt.test.ts +109 -11
- package/src/__tests__/tool-approval-handler.test.ts +85 -0
- package/src/__tests__/tool-audit-listener.test.ts +86 -0
- package/src/__tests__/tool-error-hook.test.ts +1 -0
- package/src/__tests__/tool-result-spool.test.ts +337 -0
- package/src/__tests__/tool-result-truncate-hook.test.ts +1 -0
- package/src/__tests__/validate-input.test.ts +95 -1
- package/src/__tests__/workspace-migration-098-remove-stale-updates-bulletin-file.test.ts +65 -0
- package/src/__tests__/workspace-migration-099-disable-cache-one-shot-callsites.test.ts +139 -0
- package/src/__tests__/workspace-migration-100-upgrade-quality-profile-to-fable-5.test.ts +174 -0
- package/src/__tests__/workspace-migration-101-upgrade-balanced-economy-to-minimax-m3.test.ts +162 -0
- package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +45 -95
- package/src/acp/__tests__/agent-process.test.ts +315 -2
- package/src/acp/__tests__/prepare-agent-env.test.ts +79 -5
- package/src/acp/agent-process.ts +163 -34
- package/src/acp/prepare-agent-env.ts +55 -15
- package/src/agent/loop.ts +81 -24
- package/src/api/events/usage-progress.ts +28 -0
- package/src/api/index.ts +6 -0
- package/src/background-wake/wake-intent-hooks.test.ts +2 -0
- package/src/bundler/app-bundler.ts +25 -42
- package/src/bundler/app-compiler.ts +8 -0
- package/src/calls/call-controller.ts +1 -1
- package/src/cli/commands/plugins.ts +248 -15
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +318 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +16 -9
- package/src/cli/lib/__tests__/plugin-artifact.test.ts +183 -0
- package/src/cli/lib/__tests__/plugin-details.test.ts +158 -0
- package/src/cli/lib/__tests__/plugin-fingerprint.test.ts +245 -0
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +307 -0
- package/src/cli/lib/inspect-plugin.ts +252 -0
- package/src/cli/lib/install-from-github.ts +214 -21
- package/src/cli/lib/list-installed-plugins.ts +17 -6
- package/src/cli/lib/plugin-artifact.ts +103 -0
- package/src/cli/lib/plugin-details.ts +18 -1
- package/src/cli/lib/plugin-fingerprint.ts +197 -0
- package/src/cli/lib/upgrade-plugin.ts +225 -0
- package/src/config/bundled-skills/subagent/SKILL.md +2 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +8 -2
- package/src/config/call-site-defaults.ts +13 -2
- package/src/config/feature-flag-registry.json +8 -16
- package/src/config/loader.ts +52 -59
- package/src/config/schema.ts +0 -2
- package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +10 -0
- package/src/config/schemas/llm.ts +10 -0
- package/src/config/schemas/memory-v2.ts +13 -0
- package/src/config/schemas/memory-v3.ts +92 -0
- package/src/config/seed-inference-profiles.ts +4 -8
- package/src/context/post-turn-tool-result-truncation.ts +32 -18
- package/src/context/tool-result-spool.ts +104 -0
- package/src/credential-execution/feature-gates.ts +0 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +41 -16
- package/src/daemon/conversation-error.ts +6 -15
- package/src/daemon/conversation.ts +9 -0
- package/src/daemon/disk-pressure-policy.ts +0 -1
- package/src/daemon/lifecycle.ts +1 -20
- package/src/daemon/message-types/conversations.ts +2 -15
- package/src/daemon/trust-context.ts +1 -1
- package/src/events/tool-audit-listener.ts +40 -9
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -1
- package/src/home/__tests__/home-content-refresh.test.ts +114 -0
- package/src/home/__tests__/suggested-prompts.test.ts +86 -5
- package/src/home/home-content-refresh.ts +43 -31
- package/src/home/home-greeting-cache.ts +8 -1
- package/src/home/home-greeting.ts +13 -9
- package/src/home/suggested-prompts.ts +77 -24
- package/src/ipc/routes/trust-rules.test.ts +66 -72
- package/src/media/image-credentials.ts +2 -2
- package/src/memory/__tests__/compaction-log-store-clickhouse.test.ts +432 -0
- package/src/memory/{compaction-log-writer-clickhouse.ts → compaction-log-store-clickhouse.ts} +264 -55
- package/src/memory/conversation-attention-store.ts +1 -0
- package/src/memory/conversation-bootstrap.ts +18 -9
- package/src/memory/conversation-crud.ts +12 -2
- package/src/memory/conversation-title-service.ts +53 -9
- package/src/memory/delivery-channels.ts +0 -69
- package/src/memory/graph/extraction-job.ts +0 -15
- package/src/memory/guardian-action-store.ts +1 -376
- package/src/memory/llm-usage-store.ts +5 -1
- package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +2 -2
- package/src/memory/v2/__tests__/consolidation-job.test.ts +183 -2
- package/src/memory/v2/__tests__/injection.test.ts +70 -0
- package/src/memory/v2/__tests__/static-context.test.ts +12 -0
- package/src/memory/v2/consolidation-job.ts +93 -9
- package/src/memory/v2/injection.ts +53 -0
- package/src/memory/v2/prompts/consolidation.ts +1 -0
- package/src/memory/v2/static-context.ts +13 -1
- package/src/memory/v2/sweep-job.ts +1 -1
- package/src/memory/v2/types.ts +5 -0
- package/src/plugin-api/types.ts +7 -0
- package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +300 -0
- package/src/plugins/defaults/exploration-drift/package.json +15 -0
- package/src/plugins/defaults/index.ts +25 -0
- package/src/plugins/defaults/memory-retrieval/injectors.ts +132 -4
- package/src/plugins/defaults/memory-v3-shadow/__tests__/card.test.ts +92 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/carry-integration.test.ts +2 -1
- package/src/plugins/defaults/memory-v3-shadow/__tests__/fresh-set.test.ts +52 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +1 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/live-integration.test.ts +2 -1
- package/src/plugins/defaults/memory-v3-shadow/__tests__/orchestrate.test.ts +136 -5
- package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +17 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/selection-log-store.test.ts +6 -0
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-integration.test.ts +5 -1
- package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +68 -4
- package/src/plugins/defaults/memory-v3-shadow/card.ts +49 -5
- package/src/plugins/defaults/memory-v3-shadow/fresh-set.ts +59 -0
- package/src/plugins/defaults/memory-v3-shadow/injector.ts +4 -2
- package/src/plugins/defaults/memory-v3-shadow/learned-edges.test.ts +169 -0
- package/src/plugins/defaults/memory-v3-shadow/learned-edges.ts +178 -0
- package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +115 -26
- package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +13 -9
- package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +144 -22
- package/src/plugins/defaults/memory-v3-shadow/types.ts +24 -6
- package/src/plugins/defaults/title-generate/hooks/stop.ts +13 -0
- package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +16 -0
- package/src/prompts/cache-boundary.ts +17 -0
- package/src/prompts/sections.ts +50 -17
- package/src/prompts/system-prompt.ts +12 -4
- package/src/prompts/templates/system-sections.ts +22 -0
- package/src/providers/__tests__/unparseable-tool-args.test.ts +53 -0
- package/src/providers/anthropic/client.ts +74 -28
- package/src/providers/gemini/client.ts +5 -1
- package/src/providers/minimax/client.ts +9 -0
- package/src/providers/model-catalog.ts +28 -0
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/chat-completions-provider.ts +4 -2
- package/src/providers/openai/responses-provider.ts +7 -2
- package/src/providers/retry.ts +8 -0
- package/src/providers/types.ts +11 -0
- package/src/providers/unparseable-tool-args.ts +56 -0
- package/src/runtime/AGENTS.md +6 -0
- package/src/runtime/__tests__/agent-wake.test.ts +2 -2
- package/src/runtime/agent-wake.ts +5 -5
- package/src/runtime/background-job-runner.ts +2 -2
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +150 -3
- package/src/runtime/migrations/vbundle-import-analyzer.ts +29 -6
- package/src/runtime/migrations/vbundle-import-policy.ts +23 -0
- package/src/runtime/migrations/vbundle-importer.ts +9 -4
- package/src/runtime/migrations/vbundle-streaming-importer.ts +8 -3
- package/src/runtime/pre-first-message-gate.ts +1 -1
- package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +241 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +132 -0
- package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +97 -185
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +17 -0
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +348 -0
- package/src/runtime/routes/__tests__/task-routes.test.ts +3 -3
- package/src/runtime/routes/btw-routes.ts +0 -14
- package/src/runtime/routes/conversation-compaction-routes.ts +86 -19
- package/src/runtime/routes/conversation-list-routes.ts +77 -5
- package/src/runtime/routes/conversation-management-routes.ts +54 -0
- package/src/runtime/routes/conversation-query-routes.ts +79 -4
- package/src/runtime/routes/gateway-log-routes.ts +14 -64
- package/src/runtime/routes/home-feed-routes.ts +10 -0
- package/src/runtime/routes/identity-intro-cache.ts +1 -1
- package/src/runtime/routes/identity-routes.ts +76 -20
- package/src/runtime/routes/inbound-message-handler.ts +0 -36
- package/src/runtime/routes/log-export-routes.ts +143 -96
- package/src/runtime/routes/plugins-routes.ts +380 -0
- package/src/runtime/routes/redact-staged-export.ts +259 -0
- package/src/runtime/routes/schedule-routes.ts +19 -2
- package/src/runtime/routes/trust-rules-routes.ts +14 -67
- package/src/schedule/recurrence-engine.ts +34 -0
- package/src/schedule/scheduler.ts +1 -0
- package/src/security/redact-json.ts +61 -0
- package/src/skills/validate-input.ts +41 -1
- package/src/subagent/types.ts +26 -1
- package/src/telemetry/types.ts +15 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +6 -1
- package/src/telemetry/usage-telemetry-reporter.ts +1 -0
- package/src/tools/apps/executors.ts +1 -1
- package/src/tools/skills/skill-tool-factory.ts +19 -8
- package/src/tools/tool-approval-handler.ts +31 -0
- package/src/usage/types.ts +8 -1
- package/src/util/platform.ts +16 -0
- package/src/watcher/engine.ts +1 -0
- package/src/workspace/adaptive-thinking-repair.ts +113 -0
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +70 -67
- package/src/workspace/migrations/098-remove-stale-updates-bulletin-file.ts +31 -0
- package/src/workspace/migrations/099-disable-cache-one-shot-callsites.ts +81 -0
- package/src/workspace/migrations/100-upgrade-quality-profile-to-fable-5.ts +86 -0
- package/src/workspace/migrations/101-upgrade-balanced-economy-to-minimax-m3.ts +70 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +0 -202
- package/src/__tests__/conversation-starters-cadence.test.ts +0 -161
- package/src/__tests__/guardian-action-followup-executor.test.ts +0 -322
- package/src/__tests__/guardian-action-followup-store.test.ts +0 -373
- package/src/__tests__/guardian-action-late-reply.test.ts +0 -1083
- package/src/__tests__/update-bulletin-job.test.ts +0 -292
- package/src/config/schemas/updates.ts +0 -14
- package/src/memory/__tests__/compaction-log-writer-clickhouse.test.ts +0 -227
- package/src/memory/conversation-starters-cadence.ts +0 -78
- package/src/prompts/update-bulletin-job.ts +0 -180
- package/src/runtime/guardian-action-followup-executor.ts +0 -306
|
@@ -1,373 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
|
-
|
|
3
|
-
mock.module("../util/logger.js", () => ({
|
|
4
|
-
getLogger: () =>
|
|
5
|
-
new Proxy({} as Record<string, unknown>, {
|
|
6
|
-
get: () => () => {},
|
|
7
|
-
}),
|
|
8
|
-
}));
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
createCallSession,
|
|
12
|
-
createPendingQuestion,
|
|
13
|
-
} from "../calls/call-store.js";
|
|
14
|
-
import { getDb } from "../memory/db-connection.js";
|
|
15
|
-
import { initializeDb } from "../memory/db-init.js";
|
|
16
|
-
import {
|
|
17
|
-
createGuardianActionRequest,
|
|
18
|
-
expireGuardianActionRequest,
|
|
19
|
-
finalizeFollowup,
|
|
20
|
-
getGuardianActionRequest,
|
|
21
|
-
markTimedOutWithReason,
|
|
22
|
-
progressFollowupState,
|
|
23
|
-
resolveGuardianActionRequest,
|
|
24
|
-
startFollowupFromExpiredRequest,
|
|
25
|
-
} from "../memory/guardian-action-store.js";
|
|
26
|
-
import { conversations } from "../memory/schema.js";
|
|
27
|
-
|
|
28
|
-
initializeDb();
|
|
29
|
-
|
|
30
|
-
function ensureConversation(id: string): void {
|
|
31
|
-
const db = getDb();
|
|
32
|
-
const now = Date.now();
|
|
33
|
-
db.insert(conversations)
|
|
34
|
-
.values({
|
|
35
|
-
id,
|
|
36
|
-
title: `Conversation ${id}`,
|
|
37
|
-
createdAt: now,
|
|
38
|
-
updatedAt: now,
|
|
39
|
-
})
|
|
40
|
-
.run();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function resetTables(): void {
|
|
44
|
-
const db = getDb();
|
|
45
|
-
db.run("DELETE FROM guardian_action_deliveries");
|
|
46
|
-
db.run("DELETE FROM guardian_action_requests");
|
|
47
|
-
db.run("DELETE FROM call_pending_questions");
|
|
48
|
-
db.run("DELETE FROM call_events");
|
|
49
|
-
db.run("DELETE FROM call_sessions");
|
|
50
|
-
db.run("DELETE FROM messages");
|
|
51
|
-
db.run("DELETE FROM conversations");
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function createTestRequest(convId: string) {
|
|
55
|
-
ensureConversation(convId);
|
|
56
|
-
const session = createCallSession({
|
|
57
|
-
conversationId: convId,
|
|
58
|
-
provider: "twilio",
|
|
59
|
-
fromNumber: "+15550001111",
|
|
60
|
-
toNumber: "+15550002222",
|
|
61
|
-
});
|
|
62
|
-
const pq = createPendingQuestion(session.id, "What is the gate code?");
|
|
63
|
-
return createGuardianActionRequest({
|
|
64
|
-
kind: "ask_guardian",
|
|
65
|
-
sourceChannel: "phone",
|
|
66
|
-
sourceConversationId: convId,
|
|
67
|
-
callSessionId: session.id,
|
|
68
|
-
pendingQuestionId: pq.id,
|
|
69
|
-
questionText: pq.questionText,
|
|
70
|
-
expiresAt: Date.now() + 60_000,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
describe("guardian-action-followup-store", () => {
|
|
75
|
-
beforeEach(() => {
|
|
76
|
-
resetTables();
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
// ── markTimedOutWithReason ──────────────────────────────────────────
|
|
80
|
-
|
|
81
|
-
test("markTimedOutWithReason sets expired_reason correctly for call_timeout", () => {
|
|
82
|
-
const request = createTestRequest("conv-followup-1");
|
|
83
|
-
const result = markTimedOutWithReason(request.id, "call_timeout");
|
|
84
|
-
|
|
85
|
-
expect(result).not.toBeNull();
|
|
86
|
-
expect(result!.status).toBe("expired");
|
|
87
|
-
expect(result!.expiredReason).toBe("call_timeout");
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
test("markTimedOutWithReason sets expired_reason correctly for sweep_timeout", () => {
|
|
91
|
-
const request = createTestRequest("conv-followup-2");
|
|
92
|
-
const result = markTimedOutWithReason(request.id, "sweep_timeout");
|
|
93
|
-
|
|
94
|
-
expect(result).not.toBeNull();
|
|
95
|
-
expect(result!.status).toBe("expired");
|
|
96
|
-
expect(result!.expiredReason).toBe("sweep_timeout");
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
test("markTimedOutWithReason returns null for already-expired request", () => {
|
|
100
|
-
const request = createTestRequest("conv-followup-3");
|
|
101
|
-
|
|
102
|
-
// First call succeeds
|
|
103
|
-
const first = markTimedOutWithReason(request.id, "call_timeout");
|
|
104
|
-
expect(first).not.toBeNull();
|
|
105
|
-
|
|
106
|
-
// Second call returns null (already expired)
|
|
107
|
-
const second = markTimedOutWithReason(request.id, "sweep_timeout");
|
|
108
|
-
expect(second).toBeNull();
|
|
109
|
-
|
|
110
|
-
// Verify the original reason is preserved
|
|
111
|
-
const reloaded = getGuardianActionRequest(request.id);
|
|
112
|
-
expect(reloaded!.expiredReason).toBe("call_timeout");
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test("markTimedOutWithReason returns null for answered request", () => {
|
|
116
|
-
const request = createTestRequest("conv-followup-4");
|
|
117
|
-
resolveGuardianActionRequest(request.id, "The code is 1234", "telegram");
|
|
118
|
-
|
|
119
|
-
const result = markTimedOutWithReason(request.id, "call_timeout");
|
|
120
|
-
expect(result).toBeNull();
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
// ── startFollowupFromExpiredRequest ─────────────────────────────────
|
|
124
|
-
|
|
125
|
-
test("startFollowupFromExpiredRequest transitions correctly", () => {
|
|
126
|
-
const request = createTestRequest("conv-followup-5");
|
|
127
|
-
markTimedOutWithReason(request.id, "call_timeout");
|
|
128
|
-
|
|
129
|
-
const result = startFollowupFromExpiredRequest(
|
|
130
|
-
request.id,
|
|
131
|
-
"The code is 5678",
|
|
132
|
-
);
|
|
133
|
-
expect(result).not.toBeNull();
|
|
134
|
-
expect(result!.followupState).toBe("awaiting_guardian_choice");
|
|
135
|
-
expect(result!.lateAnswerText).toBe("The code is 5678");
|
|
136
|
-
expect(result!.lateAnsweredAt).toBeGreaterThan(0);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
test("startFollowupFromExpiredRequest rejects pending request", () => {
|
|
140
|
-
const request = createTestRequest("conv-followup-6");
|
|
141
|
-
|
|
142
|
-
const result = startFollowupFromExpiredRequest(request.id, "Late answer");
|
|
143
|
-
expect(result).toBeNull();
|
|
144
|
-
|
|
145
|
-
// Verify followup_state unchanged
|
|
146
|
-
const reloaded = getGuardianActionRequest(request.id);
|
|
147
|
-
expect(reloaded!.followupState).toBe("none");
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
test("startFollowupFromExpiredRequest rejects answered request", () => {
|
|
151
|
-
const request = createTestRequest("conv-followup-7");
|
|
152
|
-
resolveGuardianActionRequest(request.id, "Original answer", "telegram");
|
|
153
|
-
|
|
154
|
-
const result = startFollowupFromExpiredRequest(request.id, "Late answer");
|
|
155
|
-
expect(result).toBeNull();
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
test("startFollowupFromExpiredRequest rejects already-in-followup request", () => {
|
|
159
|
-
const request = createTestRequest("conv-followup-8");
|
|
160
|
-
markTimedOutWithReason(request.id, "call_timeout");
|
|
161
|
-
startFollowupFromExpiredRequest(request.id, "First late answer");
|
|
162
|
-
|
|
163
|
-
// Second attempt should fail
|
|
164
|
-
const result = startFollowupFromExpiredRequest(
|
|
165
|
-
request.id,
|
|
166
|
-
"Another late answer",
|
|
167
|
-
);
|
|
168
|
-
expect(result).toBeNull();
|
|
169
|
-
|
|
170
|
-
// Verify original late answer preserved
|
|
171
|
-
const reloaded = getGuardianActionRequest(request.id);
|
|
172
|
-
expect(reloaded!.lateAnswerText).toBe("First late answer");
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
// ── progressFollowupState ───────────────────────────────────────────
|
|
176
|
-
|
|
177
|
-
test("progressFollowupState valid transition: awaiting_guardian_choice -> dispatching", () => {
|
|
178
|
-
const request = createTestRequest("conv-followup-9");
|
|
179
|
-
markTimedOutWithReason(request.id, "call_timeout");
|
|
180
|
-
startFollowupFromExpiredRequest(request.id, "Late answer");
|
|
181
|
-
|
|
182
|
-
const result = progressFollowupState(
|
|
183
|
-
request.id,
|
|
184
|
-
"dispatching",
|
|
185
|
-
"call_back",
|
|
186
|
-
);
|
|
187
|
-
expect(result).not.toBeNull();
|
|
188
|
-
expect(result!.followupState).toBe("dispatching");
|
|
189
|
-
expect(result!.followupAction).toBe("call_back");
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
test("progressFollowupState rejects terminal transition: awaiting_guardian_choice -> declined", () => {
|
|
193
|
-
const request = createTestRequest("conv-followup-10");
|
|
194
|
-
markTimedOutWithReason(request.id, "call_timeout");
|
|
195
|
-
startFollowupFromExpiredRequest(request.id, "Late answer");
|
|
196
|
-
|
|
197
|
-
// Terminal transitions must go through finalizeFollowup, not progressFollowupState
|
|
198
|
-
const result = progressFollowupState(request.id, "declined", "decline");
|
|
199
|
-
expect(result).toBeNull();
|
|
200
|
-
|
|
201
|
-
// Verify state unchanged
|
|
202
|
-
const reloaded = getGuardianActionRequest(request.id);
|
|
203
|
-
expect(reloaded!.followupState).toBe("awaiting_guardian_choice");
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
test("progressFollowupState rejects invalid transition: none -> dispatching", () => {
|
|
207
|
-
const request = createTestRequest("conv-followup-11");
|
|
208
|
-
markTimedOutWithReason(request.id, "call_timeout");
|
|
209
|
-
|
|
210
|
-
// followup_state is 'none', cannot jump to 'dispatching'
|
|
211
|
-
const result = progressFollowupState(request.id, "dispatching");
|
|
212
|
-
expect(result).toBeNull();
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
test("progressFollowupState rejects invalid transition: dispatching -> awaiting_guardian_choice", () => {
|
|
216
|
-
const request = createTestRequest("conv-followup-12");
|
|
217
|
-
markTimedOutWithReason(request.id, "call_timeout");
|
|
218
|
-
startFollowupFromExpiredRequest(request.id, "Late answer");
|
|
219
|
-
progressFollowupState(request.id, "dispatching", "call_back");
|
|
220
|
-
|
|
221
|
-
// Cannot go back to awaiting_guardian_choice
|
|
222
|
-
const result = progressFollowupState(
|
|
223
|
-
request.id,
|
|
224
|
-
"awaiting_guardian_choice",
|
|
225
|
-
);
|
|
226
|
-
expect(result).toBeNull();
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
test("progressFollowupState rejects transition from terminal state", () => {
|
|
230
|
-
const request = createTestRequest("conv-followup-13");
|
|
231
|
-
markTimedOutWithReason(request.id, "call_timeout");
|
|
232
|
-
startFollowupFromExpiredRequest(request.id, "Late answer");
|
|
233
|
-
progressFollowupState(request.id, "dispatching", "call_back");
|
|
234
|
-
finalizeFollowup(request.id, "completed");
|
|
235
|
-
|
|
236
|
-
// completed is terminal — progressFollowupState cannot leave it
|
|
237
|
-
const result = progressFollowupState(request.id, "dispatching");
|
|
238
|
-
expect(result).toBeNull();
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
test("progressFollowupState rejects none -> awaiting_guardian_choice even on expired request", () => {
|
|
242
|
-
const request = createTestRequest("conv-followup-13b");
|
|
243
|
-
markTimedOutWithReason(request.id, "call_timeout");
|
|
244
|
-
|
|
245
|
-
// none -> awaiting_guardian_choice must only go through startFollowupFromExpiredRequest
|
|
246
|
-
// (which atomically sets lateAnswerText and lateAnsweredAt)
|
|
247
|
-
const result = progressFollowupState(
|
|
248
|
-
request.id,
|
|
249
|
-
"awaiting_guardian_choice",
|
|
250
|
-
);
|
|
251
|
-
expect(result).toBeNull();
|
|
252
|
-
|
|
253
|
-
// Verify followup_state unchanged
|
|
254
|
-
const reloaded = getGuardianActionRequest(request.id);
|
|
255
|
-
expect(reloaded!.followupState).toBe("none");
|
|
256
|
-
expect(reloaded!.status).toBe("expired");
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
test("progressFollowupState rejects non-expired request", () => {
|
|
260
|
-
const request = createTestRequest("conv-followup-13c");
|
|
261
|
-
|
|
262
|
-
// Request is still 'pending', not 'expired' — follow-up transitions must not apply
|
|
263
|
-
const result = progressFollowupState(
|
|
264
|
-
request.id,
|
|
265
|
-
"awaiting_guardian_choice",
|
|
266
|
-
);
|
|
267
|
-
expect(result).toBeNull();
|
|
268
|
-
|
|
269
|
-
// Verify followup_state unchanged
|
|
270
|
-
const reloaded = getGuardianActionRequest(request.id);
|
|
271
|
-
expect(reloaded!.followupState).toBe("none");
|
|
272
|
-
expect(reloaded!.status).toBe("pending");
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
// ── finalizeFollowup ────────────────────────────────────────────────
|
|
276
|
-
|
|
277
|
-
test("finalizeFollowup sets followup_completed_at for completed", () => {
|
|
278
|
-
const request = createTestRequest("conv-followup-14");
|
|
279
|
-
markTimedOutWithReason(request.id, "call_timeout");
|
|
280
|
-
startFollowupFromExpiredRequest(request.id, "Late answer");
|
|
281
|
-
progressFollowupState(request.id, "dispatching", "call_back");
|
|
282
|
-
|
|
283
|
-
const result = finalizeFollowup(request.id, "completed");
|
|
284
|
-
expect(result).not.toBeNull();
|
|
285
|
-
expect(result!.followupState).toBe("completed");
|
|
286
|
-
expect(result!.followupCompletedAt).toBeGreaterThan(0);
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
test("finalizeFollowup sets followup_completed_at for failed", () => {
|
|
290
|
-
const request = createTestRequest("conv-followup-15");
|
|
291
|
-
markTimedOutWithReason(request.id, "call_timeout");
|
|
292
|
-
startFollowupFromExpiredRequest(request.id, "Late answer");
|
|
293
|
-
progressFollowupState(request.id, "dispatching", "call_back");
|
|
294
|
-
|
|
295
|
-
const result = finalizeFollowup(request.id, "failed");
|
|
296
|
-
expect(result).not.toBeNull();
|
|
297
|
-
expect(result!.followupState).toBe("failed");
|
|
298
|
-
expect(result!.followupCompletedAt).toBeGreaterThan(0);
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
test("finalizeFollowup with declined from awaiting_guardian_choice", () => {
|
|
302
|
-
const request = createTestRequest("conv-followup-16");
|
|
303
|
-
markTimedOutWithReason(request.id, "call_timeout");
|
|
304
|
-
startFollowupFromExpiredRequest(request.id, "Late answer");
|
|
305
|
-
|
|
306
|
-
const result = finalizeFollowup(request.id, "declined");
|
|
307
|
-
expect(result).not.toBeNull();
|
|
308
|
-
expect(result!.followupState).toBe("declined");
|
|
309
|
-
expect(result!.followupCompletedAt).toBeGreaterThan(0);
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
test("finalizeFollowup rejects invalid transition from none", () => {
|
|
313
|
-
const request = createTestRequest("conv-followup-17");
|
|
314
|
-
markTimedOutWithReason(request.id, "call_timeout");
|
|
315
|
-
|
|
316
|
-
// followup_state is 'none', cannot finalize
|
|
317
|
-
const result = finalizeFollowup(request.id, "completed");
|
|
318
|
-
expect(result).toBeNull();
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
test("finalizeFollowup rejects non-expired request", () => {
|
|
322
|
-
const request = createTestRequest("conv-followup-17b");
|
|
323
|
-
|
|
324
|
-
// Request is still 'pending', not 'expired' — finalize must not apply
|
|
325
|
-
const result = finalizeFollowup(request.id, "completed");
|
|
326
|
-
expect(result).toBeNull();
|
|
327
|
-
|
|
328
|
-
// Verify followup_state unchanged
|
|
329
|
-
const reloaded = getGuardianActionRequest(request.id);
|
|
330
|
-
expect(reloaded!.followupState).toBe("none");
|
|
331
|
-
expect(reloaded!.status).toBe("pending");
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
// ── Existing behavior preserved ─────────────────────────────────────
|
|
335
|
-
|
|
336
|
-
test("resolve/expire behavior unchanged: resolveGuardianActionRequest still works", () => {
|
|
337
|
-
const request = createTestRequest("conv-followup-18");
|
|
338
|
-
|
|
339
|
-
const resolved = resolveGuardianActionRequest(
|
|
340
|
-
request.id,
|
|
341
|
-
"Answer here",
|
|
342
|
-
"telegram",
|
|
343
|
-
"user-1",
|
|
344
|
-
);
|
|
345
|
-
expect(resolved).not.toBeNull();
|
|
346
|
-
expect(resolved!.status).toBe("answered");
|
|
347
|
-
expect(resolved!.answerText).toBe("Answer here");
|
|
348
|
-
// Follow-up fields remain at defaults
|
|
349
|
-
expect(resolved!.followupState).toBe("none");
|
|
350
|
-
expect(resolved!.expiredReason).toBeNull();
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
test("expireGuardianActionRequest sets explicit reason", () => {
|
|
354
|
-
const request = createTestRequest("conv-followup-19");
|
|
355
|
-
|
|
356
|
-
expireGuardianActionRequest(request.id, "call_timeout");
|
|
357
|
-
|
|
358
|
-
const reloaded = getGuardianActionRequest(request.id);
|
|
359
|
-
expect(reloaded!.status).toBe("expired");
|
|
360
|
-
expect(reloaded!.expiredReason).toBe("call_timeout");
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
test("new fields default correctly on freshly created request", () => {
|
|
364
|
-
const request = createTestRequest("conv-followup-21");
|
|
365
|
-
|
|
366
|
-
expect(request.expiredReason).toBeNull();
|
|
367
|
-
expect(request.followupState).toBe("none");
|
|
368
|
-
expect(request.lateAnswerText).toBeNull();
|
|
369
|
-
expect(request.lateAnsweredAt).toBeNull();
|
|
370
|
-
expect(request.followupAction).toBeNull();
|
|
371
|
-
expect(request.followupCompletedAt).toBeNull();
|
|
372
|
-
});
|
|
373
|
-
});
|