@vellumai/assistant 0.4.49 β 0.4.50
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 +24 -33
- package/README.md +3 -3
- package/docs/architecture/memory.md +180 -119
- package/package.json +2 -2
- package/src/__tests__/agent-loop.test.ts +3 -1
- package/src/__tests__/anthropic-provider.test.ts +114 -23
- package/src/__tests__/approval-cascade.test.ts +1 -15
- package/src/__tests__/approval-routes-http.test.ts +2 -0
- package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
- package/src/__tests__/canonical-guardian-store.test.ts +95 -0
- package/src/__tests__/checker.test.ts +13 -0
- package/src/__tests__/config-schema.test.ts +1 -68
- package/src/__tests__/context-memory-e2e.test.ts +11 -100
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +8 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/credential-security-e2e.test.ts +1 -0
- package/src/__tests__/credential-vault-unit.test.ts +4 -0
- package/src/__tests__/credential-vault.test.ts +13 -1
- package/src/__tests__/cu-unified-flow.test.ts +532 -0
- package/src/__tests__/date-context.test.ts +93 -77
- package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
- package/src/__tests__/guardian-routing-invariants.test.ts +93 -0
- package/src/__tests__/history-repair.test.ts +245 -0
- package/src/__tests__/host-cu-proxy.test.ts +165 -3
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/invite-redemption-service.test.ts +65 -1
- package/src/__tests__/keychain-broker-client.test.ts +4 -4
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
- package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
- package/src/__tests__/memory-recall-quality.test.ts +244 -407
- package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
- package/src/__tests__/memory-regressions.test.ts +477 -2841
- package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
- package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
- package/src/__tests__/mime-builder.test.ts +28 -0
- package/src/__tests__/native-web-search.test.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +572 -5
- package/src/__tests__/oauth-store.test.ts +120 -6
- package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
- package/src/__tests__/registry.test.ts +0 -1
- package/src/__tests__/relay-server.test.ts +46 -1
- package/src/__tests__/schedule-tools.test.ts +32 -0
- package/src/__tests__/script-proxy-certs.test.ts +1 -1
- package/src/__tests__/secret-onetime-send.test.ts +1 -0
- package/src/__tests__/secure-keys.test.ts +7 -2
- package/src/__tests__/send-endpoint-busy.test.ts +3 -0
- package/src/__tests__/session-abort-tool-results.test.ts +1 -14
- package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
- package/src/__tests__/session-agent-loop.test.ts +19 -15
- package/src/__tests__/session-confirmation-signals.test.ts +1 -15
- package/src/__tests__/session-error.test.ts +124 -2
- package/src/__tests__/session-history-web-search.test.ts +918 -0
- package/src/__tests__/session-pre-run-repair.test.ts +1 -14
- package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
- package/src/__tests__/session-queue.test.ts +37 -27
- package/src/__tests__/session-runtime-assembly.test.ts +54 -0
- package/src/__tests__/session-slash-known.test.ts +1 -15
- package/src/__tests__/session-slash-queue.test.ts +1 -15
- package/src/__tests__/session-slash-unknown.test.ts +1 -15
- package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
- package/src/__tests__/session-workspace-injection.test.ts +3 -37
- package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
- package/src/__tests__/skills-install-extract.test.ts +93 -0
- package/src/__tests__/skillssh-registry.test.ts +451 -0
- package/src/__tests__/trust-store.test.ts +15 -0
- package/src/__tests__/voice-invite-redemption.test.ts +32 -1
- package/src/agent/ax-tree-compaction.test.ts +51 -0
- package/src/agent/loop.ts +39 -12
- package/src/approvals/AGENTS.md +1 -1
- package/src/approvals/guardian-request-resolvers.ts +14 -2
- package/src/bundler/compiler-tools.ts +66 -2
- package/src/calls/call-domain.ts +132 -0
- package/src/calls/call-store.ts +6 -0
- package/src/calls/relay-server.ts +43 -5
- package/src/calls/relay-setup-router.ts +17 -1
- package/src/calls/twilio-config.ts +1 -1
- package/src/calls/types.ts +3 -1
- package/src/cli/commands/doctor.ts +4 -3
- package/src/cli/commands/mcp.ts +46 -59
- package/src/cli/commands/memory.ts +16 -165
- package/src/cli/commands/oauth/apps.ts +31 -2
- package/src/cli/commands/oauth/connections.ts +431 -97
- package/src/cli/commands/oauth/providers.ts +15 -1
- package/src/cli/commands/sessions.ts +5 -2
- package/src/cli/commands/skills.ts +173 -1
- package/src/cli/http-client.ts +0 -20
- package/src/cli/main-screen.tsx +2 -2
- package/src/cli/program.ts +5 -6
- package/src/cli.ts +4 -10
- package/src/config/bundled-skills/computer-use/TOOLS.json +1 -1
- package/src/config/bundled-skills/computer-use/tools/computer-use-observe.ts +12 -0
- package/src/config/bundled-tool-registry.ts +2 -5
- package/src/config/schema.ts +1 -12
- package/src/config/schemas/memory-lifecycle.ts +0 -9
- package/src/config/schemas/memory-processing.ts +0 -180
- package/src/config/schemas/memory-retrieval.ts +32 -104
- package/src/config/schemas/memory.ts +0 -10
- package/src/config/types.ts +0 -4
- package/src/context/window-manager.ts +4 -1
- package/src/daemon/config-watcher.ts +61 -3
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/date-context.ts +114 -31
- package/src/daemon/handlers/sessions.ts +18 -13
- package/src/daemon/handlers/skills.ts +20 -1
- package/src/daemon/history-repair.ts +72 -8
- package/src/daemon/host-cu-proxy.ts +55 -26
- package/src/daemon/lifecycle.ts +31 -3
- package/src/daemon/mcp-reload-service.ts +2 -2
- package/src/daemon/message-types/computer-use.ts +1 -12
- package/src/daemon/message-types/memory.ts +4 -16
- package/src/daemon/message-types/messages.ts +1 -0
- package/src/daemon/message-types/sessions.ts +4 -0
- package/src/daemon/server.ts +12 -1
- package/src/daemon/session-agent-loop-handlers.ts +38 -0
- package/src/daemon/session-agent-loop.ts +334 -48
- package/src/daemon/session-error.ts +89 -6
- package/src/daemon/session-history.ts +17 -7
- package/src/daemon/session-media-retry.ts +6 -2
- package/src/daemon/session-memory.ts +69 -149
- package/src/daemon/session-process.ts +10 -1
- package/src/daemon/session-runtime-assembly.ts +49 -19
- package/src/daemon/session-surfaces.ts +4 -1
- package/src/daemon/session-tool-setup.ts +7 -1
- package/src/daemon/session.ts +12 -2
- package/src/instrument.ts +61 -1
- package/src/memory/admin.ts +2 -191
- package/src/memory/canonical-guardian-store.ts +38 -2
- package/src/memory/conversation-crud.ts +0 -33
- package/src/memory/conversation-queries.ts +22 -3
- package/src/memory/db-init.ts +28 -0
- package/src/memory/embedding-backend.ts +84 -8
- package/src/memory/embedding-types.ts +9 -1
- package/src/memory/indexer.ts +7 -46
- package/src/memory/items-extractor.ts +274 -76
- package/src/memory/job-handlers/backfill.ts +2 -127
- package/src/memory/job-handlers/cleanup.ts +2 -16
- package/src/memory/job-handlers/extraction.ts +2 -138
- package/src/memory/job-handlers/index-maintenance.ts +1 -6
- package/src/memory/job-handlers/summarization.ts +3 -148
- package/src/memory/job-utils.ts +21 -59
- package/src/memory/jobs-store.ts +1 -159
- package/src/memory/jobs-worker.ts +9 -52
- package/src/memory/migrations/104-core-indexes.ts +3 -3
- package/src/memory/migrations/149-oauth-tables.ts +2 -0
- package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
- package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
- package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
- package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
- package/src/memory/migrations/154-drop-fts.ts +20 -0
- package/src/memory/migrations/155-drop-conflicts.ts +7 -0
- package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
- package/src/memory/migrations/index.ts +7 -0
- package/src/memory/qdrant-client.ts +148 -51
- package/src/memory/raw-query.ts +1 -1
- package/src/memory/retriever.test.ts +294 -273
- package/src/memory/retriever.ts +421 -645
- package/src/memory/schema/calls.ts +2 -0
- package/src/memory/schema/memory-core.ts +3 -48
- package/src/memory/schema/oauth.ts +2 -0
- package/src/memory/search/formatting.ts +263 -176
- package/src/memory/search/lexical.ts +1 -254
- package/src/memory/search/ranking.ts +0 -455
- package/src/memory/search/semantic.ts +100 -14
- package/src/memory/search/staleness.ts +47 -0
- package/src/memory/search/tier-classifier.ts +21 -0
- package/src/memory/search/types.ts +15 -77
- package/src/memory/task-memory-cleanup.ts +4 -6
- package/src/messaging/providers/gmail/mime-builder.ts +17 -7
- package/src/oauth/byo-connection.test.ts +8 -1
- package/src/oauth/oauth-store.ts +113 -27
- package/src/oauth/seed-providers.ts +6 -0
- package/src/oauth/token-persistence.ts +11 -3
- package/src/permissions/defaults.ts +1 -0
- package/src/permissions/trust-store.ts +23 -1
- package/src/playbooks/playbook-compiler.ts +1 -1
- package/src/prompts/system-prompt.ts +18 -2
- package/src/providers/anthropic/client.ts +56 -126
- package/src/providers/types.ts +7 -1
- package/src/runtime/AGENTS.md +9 -0
- package/src/runtime/auth/route-policy.ts +6 -3
- package/src/runtime/guardian-reply-router.ts +24 -22
- package/src/runtime/http-server.ts +2 -2
- package/src/runtime/invite-redemption-service.ts +19 -1
- package/src/runtime/invite-service.ts +25 -0
- package/src/runtime/pending-interactions.ts +2 -2
- package/src/runtime/routes/brain-graph-routes.ts +10 -90
- package/src/runtime/routes/conversation-routes.ts +9 -1
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
- package/src/runtime/routes/memory-item-routes.test.ts +754 -0
- package/src/runtime/routes/memory-item-routes.ts +503 -0
- package/src/runtime/routes/session-management-routes.ts +3 -3
- package/src/runtime/routes/settings-routes.ts +2 -2
- package/src/runtime/routes/trust-rules-routes.ts +14 -0
- package/src/runtime/routes/workspace-routes.ts +2 -1
- package/src/security/keychain-broker-client.ts +17 -4
- package/src/security/secure-keys.ts +25 -3
- package/src/security/token-manager.ts +36 -36
- package/src/skills/catalog-install.ts +74 -18
- package/src/skills/skillssh-registry.ts +503 -0
- package/src/tools/assets/search.ts +5 -1
- package/src/tools/computer-use/definitions.ts +0 -10
- package/src/tools/computer-use/registry.ts +1 -1
- package/src/tools/credentials/vault.ts +1 -3
- package/src/tools/memory/definitions.ts +4 -13
- package/src/tools/memory/handlers.test.ts +83 -103
- package/src/tools/memory/handlers.ts +50 -85
- package/src/tools/schedule/create.ts +8 -1
- package/src/tools/schedule/update.ts +8 -1
- package/src/tools/skills/load.ts +25 -2
- package/src/__tests__/clarification-resolver.test.ts +0 -193
- package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
- package/src/__tests__/conflict-policy.test.ts +0 -269
- package/src/__tests__/conflict-store.test.ts +0 -372
- package/src/__tests__/contradiction-checker.test.ts +0 -361
- package/src/__tests__/entity-extractor.test.ts +0 -211
- package/src/__tests__/entity-search.test.ts +0 -1117
- package/src/__tests__/profile-compiler.test.ts +0 -392
- package/src/__tests__/session-conflict-gate.test.ts +0 -1228
- package/src/__tests__/session-profile-injection.test.ts +0 -557
- package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
- package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
- package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
- package/src/daemon/session-conflict-gate.ts +0 -167
- package/src/daemon/session-dynamic-profile.ts +0 -77
- package/src/memory/clarification-resolver.ts +0 -417
- package/src/memory/conflict-intent.ts +0 -205
- package/src/memory/conflict-policy.ts +0 -127
- package/src/memory/conflict-store.ts +0 -410
- package/src/memory/contradiction-checker.ts +0 -508
- package/src/memory/entity-extractor.ts +0 -535
- package/src/memory/format-recall.ts +0 -47
- package/src/memory/fts-reconciler.ts +0 -165
- package/src/memory/job-handlers/conflict.ts +0 -200
- package/src/memory/profile-compiler.ts +0 -195
- package/src/memory/recall-cache.ts +0 -117
- package/src/memory/search/entity.ts +0 -535
- package/src/memory/search/query-expansion.test.ts +0 -70
- package/src/memory/search/query-expansion.ts +0 -118
- package/src/runtime/routes/mcp-routes.ts +0 -20
|
@@ -1,557 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
|
-
|
|
3
|
-
import type { AgentEvent } from "../agent/loop.js";
|
|
4
|
-
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
5
|
-
import type { Message, ProviderResponse } from "../providers/types.js";
|
|
6
|
-
|
|
7
|
-
let runCalls: Message[][] = [];
|
|
8
|
-
let profileCompilerCalls = 0;
|
|
9
|
-
let profileCompilerArgs: Array<Record<string, unknown>> = [];
|
|
10
|
-
let recallArgs: Array<Record<string, unknown>> = [];
|
|
11
|
-
let profileEnabled = true;
|
|
12
|
-
let memoryEnabled = true;
|
|
13
|
-
let profileText =
|
|
14
|
-
"<dynamic-user-profile>\n- timezone: America/Los_Angeles\n</dynamic-user-profile>";
|
|
15
|
-
|
|
16
|
-
const persistedMessages: Array<{
|
|
17
|
-
id: string;
|
|
18
|
-
role: string;
|
|
19
|
-
content: string;
|
|
20
|
-
createdAt: number;
|
|
21
|
-
}> = [];
|
|
22
|
-
|
|
23
|
-
mock.module("../util/logger.js", () => ({
|
|
24
|
-
getLogger: () =>
|
|
25
|
-
new Proxy({} as Record<string, unknown>, { get: () => () => {} }),
|
|
26
|
-
}));
|
|
27
|
-
|
|
28
|
-
mock.module("../util/platform.js", () => ({
|
|
29
|
-
getDataDir: () => "/tmp",
|
|
30
|
-
}));
|
|
31
|
-
|
|
32
|
-
mock.module("../memory/guardian-action-store.js", () => ({
|
|
33
|
-
getPendingDeliveryByConversation: () => null,
|
|
34
|
-
getGuardianActionRequest: () => null,
|
|
35
|
-
resolveGuardianActionRequest: () => {},
|
|
36
|
-
}));
|
|
37
|
-
|
|
38
|
-
mock.module("../providers/registry.js", () => ({
|
|
39
|
-
getProvider: () => ({ name: "mock-provider" }),
|
|
40
|
-
initializeProviders: () => {},
|
|
41
|
-
}));
|
|
42
|
-
|
|
43
|
-
mock.module("../config/loader.js", () => ({
|
|
44
|
-
getConfig: () => ({
|
|
45
|
-
ui: {},
|
|
46
|
-
|
|
47
|
-
provider: "mock-provider",
|
|
48
|
-
maxTokens: 4096,
|
|
49
|
-
thinking: false,
|
|
50
|
-
contextWindow: {
|
|
51
|
-
enabled: true,
|
|
52
|
-
maxInputTokens: 100000,
|
|
53
|
-
targetBudgetRatio: 0.30,
|
|
54
|
-
compactThreshold: 0.8, summaryBudgetRatio: 0.05,
|
|
55
|
-
overflowRecovery: {
|
|
56
|
-
enabled: true,
|
|
57
|
-
safetyMarginRatio: 0.05,
|
|
58
|
-
maxAttempts: 3,
|
|
59
|
-
interactiveLatestTurnCompression: "summarize",
|
|
60
|
-
nonInteractiveLatestTurnCompression: "truncate",
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
rateLimit: { maxRequestsPerMinute: 0, maxTokensPerSession: 0 },
|
|
64
|
-
apiKeys: {},
|
|
65
|
-
daemon: {
|
|
66
|
-
startupSocketWaitMs: 5000,
|
|
67
|
-
stopTimeoutMs: 5000,
|
|
68
|
-
sigkillGracePeriodMs: 2000,
|
|
69
|
-
titleGenerationMaxTokens: 30,
|
|
70
|
-
standaloneRecording: true,
|
|
71
|
-
},
|
|
72
|
-
memory: {
|
|
73
|
-
enabled: memoryEnabled,
|
|
74
|
-
retrieval: {
|
|
75
|
-
injectionStrategy: "prepend_user_block",
|
|
76
|
-
dynamicBudget: {
|
|
77
|
-
enabled: false,
|
|
78
|
-
minInjectTokens: 1200,
|
|
79
|
-
maxInjectTokens: 10000,
|
|
80
|
-
targetHeadroomTokens: 10000,
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
conflicts: {
|
|
84
|
-
enabled: false,
|
|
85
|
-
gateMode: "soft",
|
|
86
|
-
resolverLlmTimeoutMs: 250,
|
|
87
|
-
relevanceThreshold: 0.2,
|
|
88
|
-
},
|
|
89
|
-
profile: {
|
|
90
|
-
enabled: profileEnabled,
|
|
91
|
-
maxInjectTokens: 300,
|
|
92
|
-
},
|
|
93
|
-
},
|
|
94
|
-
}),
|
|
95
|
-
loadRawConfig: () => ({}),
|
|
96
|
-
saveRawConfig: () => {},
|
|
97
|
-
invalidateConfigCache: () => {},
|
|
98
|
-
}));
|
|
99
|
-
|
|
100
|
-
mock.module("../prompts/system-prompt.js", () => ({
|
|
101
|
-
buildSystemPrompt: () => "system prompt",
|
|
102
|
-
}));
|
|
103
|
-
|
|
104
|
-
mock.module("../config/skills.js", () => ({
|
|
105
|
-
loadSkillCatalog: () => [],
|
|
106
|
-
loadSkillBySelector: () => ({ skill: null }),
|
|
107
|
-
ensureSkillIcon: async () => null,
|
|
108
|
-
}));
|
|
109
|
-
|
|
110
|
-
mock.module("../config/skill-state.js", () => ({
|
|
111
|
-
resolveSkillStates: () => [],
|
|
112
|
-
}));
|
|
113
|
-
|
|
114
|
-
mock.module("../skills/slash-commands.js", () => ({
|
|
115
|
-
buildInvocableSlashCatalog: () => new Map(),
|
|
116
|
-
resolveSlashSkillCommand: () => ({ kind: "not_slash" }),
|
|
117
|
-
rewriteKnownSlashCommandPrompt: () => "",
|
|
118
|
-
parseSlashCandidate: () => ({ kind: "not_slash" }),
|
|
119
|
-
}));
|
|
120
|
-
|
|
121
|
-
mock.module("../permissions/trust-store.js", () => ({
|
|
122
|
-
addRule: () => {},
|
|
123
|
-
findHighestPriorityRule: () => null,
|
|
124
|
-
clearCache: () => {},
|
|
125
|
-
}));
|
|
126
|
-
|
|
127
|
-
mock.module("../security/secret-allowlist.js", () => ({
|
|
128
|
-
resetAllowlist: () => {},
|
|
129
|
-
}));
|
|
130
|
-
|
|
131
|
-
mock.module("../memory/conversation-crud.js", () => ({
|
|
132
|
-
getConversationThreadType: () => "default",
|
|
133
|
-
setConversationOriginChannelIfUnset: () => {},
|
|
134
|
-
provenanceFromTrustContext: () => ({
|
|
135
|
-
source: "user",
|
|
136
|
-
trustContext: undefined,
|
|
137
|
-
}),
|
|
138
|
-
getConversationOriginInterface: () => null,
|
|
139
|
-
getConversationOriginChannel: () => null,
|
|
140
|
-
getMessages: () => persistedMessages,
|
|
141
|
-
getConversation: () => ({
|
|
142
|
-
id: "conv-1",
|
|
143
|
-
contextSummary: null,
|
|
144
|
-
contextCompactedMessageCount: 0,
|
|
145
|
-
contextCompactedAt: null,
|
|
146
|
-
totalInputTokens: 0,
|
|
147
|
-
totalOutputTokens: 0,
|
|
148
|
-
totalEstimatedCost: 0,
|
|
149
|
-
}),
|
|
150
|
-
addMessage: (_conversationId: string, role: string, content: string) => {
|
|
151
|
-
const row = {
|
|
152
|
-
id: `msg-${persistedMessages.length + 1}`,
|
|
153
|
-
role,
|
|
154
|
-
content,
|
|
155
|
-
createdAt: Date.now(),
|
|
156
|
-
};
|
|
157
|
-
persistedMessages.push(row);
|
|
158
|
-
return { id: row.id };
|
|
159
|
-
},
|
|
160
|
-
updateConversationUsage: () => {},
|
|
161
|
-
updateConversationTitle: () => {},
|
|
162
|
-
updateConversationContextWindow: () => {},
|
|
163
|
-
deleteMessageById: () => ({ segmentIds: [], orphanedItemIds: [] }),
|
|
164
|
-
deleteLastExchange: () => 0,
|
|
165
|
-
}));
|
|
166
|
-
|
|
167
|
-
mock.module("../memory/conversation-queries.js", () => ({
|
|
168
|
-
isLastUserMessageToolResult: () => false,
|
|
169
|
-
}));
|
|
170
|
-
|
|
171
|
-
mock.module("../memory/attachments-store.js", () => ({
|
|
172
|
-
uploadAttachment: () => ({ id: "att-1" }),
|
|
173
|
-
linkAttachmentToMessage: () => {},
|
|
174
|
-
}));
|
|
175
|
-
|
|
176
|
-
mock.module("../memory/retriever.js", () => ({
|
|
177
|
-
buildMemoryRecall: async (
|
|
178
|
-
_query: string,
|
|
179
|
-
_convId: string,
|
|
180
|
-
_config: unknown,
|
|
181
|
-
options?: Record<string, unknown>,
|
|
182
|
-
) => {
|
|
183
|
-
if (options) recallArgs.push(options);
|
|
184
|
-
return {
|
|
185
|
-
enabled: true,
|
|
186
|
-
degraded: false,
|
|
187
|
-
reason: null,
|
|
188
|
-
provider: "mock",
|
|
189
|
-
model: "mock",
|
|
190
|
-
injectedText: "",
|
|
191
|
-
lexicalHits: 0,
|
|
192
|
-
semanticHits: 0,
|
|
193
|
-
recencyHits: 0,
|
|
194
|
-
entityHits: 0,
|
|
195
|
-
relationSeedEntityCount: 0,
|
|
196
|
-
relationTraversedEdgeCount: 0,
|
|
197
|
-
relationNeighborEntityCount: 0,
|
|
198
|
-
relationExpandedItemCount: 0,
|
|
199
|
-
earlyTerminated: false,
|
|
200
|
-
mergedCount: 0,
|
|
201
|
-
selectedCount: 0,
|
|
202
|
-
rerankApplied: false,
|
|
203
|
-
injectedTokens: 0,
|
|
204
|
-
latencyMs: 0,
|
|
205
|
-
topCandidates: [],
|
|
206
|
-
};
|
|
207
|
-
},
|
|
208
|
-
injectMemoryRecallIntoUserMessage: (msg: Message) => msg,
|
|
209
|
-
injectMemoryRecallAsSeparateMessage: (msgs: Message[]) => msgs,
|
|
210
|
-
stripMemoryRecallMessages: (msgs: Message[]) => msgs,
|
|
211
|
-
}));
|
|
212
|
-
|
|
213
|
-
mock.module("../context/window-manager.js", () => ({
|
|
214
|
-
ContextWindowManager: class {
|
|
215
|
-
constructor() {}
|
|
216
|
-
shouldCompact() {
|
|
217
|
-
return { needed: false, estimatedTokens: 0 };
|
|
218
|
-
}
|
|
219
|
-
async maybeCompact() {
|
|
220
|
-
return { compacted: false };
|
|
221
|
-
}
|
|
222
|
-
},
|
|
223
|
-
createContextSummaryMessage: () => ({
|
|
224
|
-
role: "user",
|
|
225
|
-
content: [{ type: "text", text: "summary" }],
|
|
226
|
-
}),
|
|
227
|
-
getSummaryFromContextMessage: () => null,
|
|
228
|
-
}));
|
|
229
|
-
|
|
230
|
-
mock.module("../memory/conflict-store.js", () => ({
|
|
231
|
-
listPendingConflictDetails: () => [],
|
|
232
|
-
applyConflictResolution: () => true,
|
|
233
|
-
}));
|
|
234
|
-
|
|
235
|
-
mock.module("../memory/clarification-resolver.js", () => ({
|
|
236
|
-
resolveConflictClarification: async () => ({
|
|
237
|
-
resolution: "still_unclear",
|
|
238
|
-
strategy: "heuristic",
|
|
239
|
-
resolvedStatement: null,
|
|
240
|
-
explanation: "Need user clarification.",
|
|
241
|
-
}),
|
|
242
|
-
}));
|
|
243
|
-
|
|
244
|
-
mock.module("../memory/admin.js", () => ({
|
|
245
|
-
getMemoryConflictAndCleanupStats: () => ({
|
|
246
|
-
conflicts: { pending: 0, resolved: 0, oldestPendingAgeMs: null },
|
|
247
|
-
cleanup: {
|
|
248
|
-
resolvedBacklog: 0,
|
|
249
|
-
supersededBacklog: 0,
|
|
250
|
-
resolvedCompleted24h: 0,
|
|
251
|
-
supersededCompleted24h: 0,
|
|
252
|
-
},
|
|
253
|
-
}),
|
|
254
|
-
}));
|
|
255
|
-
|
|
256
|
-
mock.module("../memory/profile-compiler.js", () => ({
|
|
257
|
-
compileDynamicProfile: (options?: Record<string, unknown>) => {
|
|
258
|
-
profileCompilerCalls += 1;
|
|
259
|
-
if (options) profileCompilerArgs.push(options);
|
|
260
|
-
return {
|
|
261
|
-
text: profileText,
|
|
262
|
-
sourceCount: 2,
|
|
263
|
-
selectedCount: 1,
|
|
264
|
-
budgetTokens: 300,
|
|
265
|
-
tokenEstimate: 28,
|
|
266
|
-
};
|
|
267
|
-
},
|
|
268
|
-
}));
|
|
269
|
-
|
|
270
|
-
mock.module("../memory/llm-usage-store.js", () => ({
|
|
271
|
-
recordUsageEvent: () => ({ id: "usage-1", createdAt: Date.now() }),
|
|
272
|
-
}));
|
|
273
|
-
|
|
274
|
-
mock.module("../agent/loop.js", () => ({
|
|
275
|
-
AgentLoop: class {
|
|
276
|
-
constructor() {}
|
|
277
|
-
async run(
|
|
278
|
-
messages: Message[],
|
|
279
|
-
onEvent: (event: AgentEvent) => void,
|
|
280
|
-
): Promise<Message[]> {
|
|
281
|
-
runCalls.push(messages);
|
|
282
|
-
const assistantMessage: Message = {
|
|
283
|
-
role: "assistant",
|
|
284
|
-
content: [{ type: "text", text: "normal assistant answer" }],
|
|
285
|
-
};
|
|
286
|
-
onEvent({
|
|
287
|
-
type: "usage",
|
|
288
|
-
inputTokens: 10,
|
|
289
|
-
outputTokens: 5,
|
|
290
|
-
model: "mock",
|
|
291
|
-
providerDurationMs: 10,
|
|
292
|
-
});
|
|
293
|
-
onEvent({ type: "message_complete", message: assistantMessage });
|
|
294
|
-
return [...messages, assistantMessage];
|
|
295
|
-
}
|
|
296
|
-
},
|
|
297
|
-
}));
|
|
298
|
-
mock.module("../memory/canonical-guardian-store.js", () => ({
|
|
299
|
-
listPendingCanonicalGuardianRequestsByDestinationConversation: () => [],
|
|
300
|
-
listCanonicalGuardianRequests: () => [],
|
|
301
|
-
listPendingRequestsByConversationScope: () => [],
|
|
302
|
-
createCanonicalGuardianRequest: () => ({
|
|
303
|
-
id: "mock-cg-id",
|
|
304
|
-
code: "MOCK",
|
|
305
|
-
status: "pending",
|
|
306
|
-
}),
|
|
307
|
-
getCanonicalGuardianRequest: () => null,
|
|
308
|
-
getCanonicalGuardianRequestByCode: () => null,
|
|
309
|
-
updateCanonicalGuardianRequest: () => {},
|
|
310
|
-
resolveCanonicalGuardianRequest: () => {},
|
|
311
|
-
createCanonicalGuardianDelivery: () => ({ id: "mock-cgd-id" }),
|
|
312
|
-
listCanonicalGuardianDeliveries: () => [],
|
|
313
|
-
listPendingCanonicalGuardianRequestsByDestinationChat: () => [],
|
|
314
|
-
updateCanonicalGuardianDelivery: () => {},
|
|
315
|
-
generateCanonicalRequestCode: () => "MOCK-CODE",
|
|
316
|
-
}));
|
|
317
|
-
|
|
318
|
-
import type { SessionMemoryPolicy } from "../daemon/session.js";
|
|
319
|
-
import { DEFAULT_MEMORY_POLICY, Session } from "../daemon/session.js";
|
|
320
|
-
import {
|
|
321
|
-
injectDynamicProfileIntoUserMessage,
|
|
322
|
-
stripDynamicProfileMessages,
|
|
323
|
-
} from "../daemon/session-dynamic-profile.js";
|
|
324
|
-
|
|
325
|
-
function makeSession(memoryPolicy?: SessionMemoryPolicy): Session {
|
|
326
|
-
const provider = {
|
|
327
|
-
name: "mock",
|
|
328
|
-
async sendMessage(): Promise<ProviderResponse> {
|
|
329
|
-
return {
|
|
330
|
-
content: [],
|
|
331
|
-
model: "mock",
|
|
332
|
-
usage: { inputTokens: 0, outputTokens: 0 },
|
|
333
|
-
stopReason: "end_turn",
|
|
334
|
-
};
|
|
335
|
-
},
|
|
336
|
-
};
|
|
337
|
-
const session = new Session(
|
|
338
|
-
"conv-1",
|
|
339
|
-
provider,
|
|
340
|
-
"system prompt",
|
|
341
|
-
4096,
|
|
342
|
-
() => {},
|
|
343
|
-
"/tmp",
|
|
344
|
-
undefined,
|
|
345
|
-
memoryPolicy,
|
|
346
|
-
);
|
|
347
|
-
session.setTrustContext({ trustClass: "guardian", sourceChannel: "vellum" });
|
|
348
|
-
return session;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
function messageText(message: Message): string {
|
|
352
|
-
return message.content
|
|
353
|
-
.filter((block) => block.type === "text")
|
|
354
|
-
.map((block) => (block as { type: "text"; text: string }).text)
|
|
355
|
-
.join("\n");
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
describe("Session dynamic profile injection", () => {
|
|
359
|
-
beforeEach(() => {
|
|
360
|
-
runCalls = [];
|
|
361
|
-
persistedMessages.length = 0;
|
|
362
|
-
profileCompilerCalls = 0;
|
|
363
|
-
profileCompilerArgs = [];
|
|
364
|
-
recallArgs = [];
|
|
365
|
-
profileEnabled = true;
|
|
366
|
-
memoryEnabled = true;
|
|
367
|
-
profileText =
|
|
368
|
-
"<dynamic-user-profile>\n- timezone: America/Los_Angeles\n</dynamic-user-profile>";
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
test("injects profile context for runtime and strips it from persisted history", async () => {
|
|
372
|
-
const session = makeSession();
|
|
373
|
-
await session.loadFromDb();
|
|
374
|
-
|
|
375
|
-
const events: ServerMessage[] = [];
|
|
376
|
-
await session.processMessage("What should I do next?", [], (event) =>
|
|
377
|
-
events.push(event),
|
|
378
|
-
);
|
|
379
|
-
|
|
380
|
-
expect(runCalls).toHaveLength(1);
|
|
381
|
-
const runtimeUser = runCalls[0][runCalls[0].length - 1];
|
|
382
|
-
expect(runtimeUser.role).toBe("user");
|
|
383
|
-
const runtimeText = messageText(runtimeUser);
|
|
384
|
-
expect(runtimeText).toContain("<dynamic-profile-context>");
|
|
385
|
-
expect(runtimeText).toContain("<dynamic-user-profile>");
|
|
386
|
-
expect(runtimeText).toContain("</dynamic-profile-context>");
|
|
387
|
-
|
|
388
|
-
const persistedUser = session
|
|
389
|
-
.getMessages()
|
|
390
|
-
.find((message) => message.role === "user");
|
|
391
|
-
expect(persistedUser).toBeDefined();
|
|
392
|
-
if (persistedUser) {
|
|
393
|
-
const persistedText = messageText(persistedUser);
|
|
394
|
-
expect(persistedText).not.toContain("<dynamic-profile-context>");
|
|
395
|
-
expect(persistedText).not.toContain("<dynamic-user-profile>");
|
|
396
|
-
expect(persistedText).not.toContain("</dynamic-profile-context>");
|
|
397
|
-
// No empty text blocks should remain after stripping
|
|
398
|
-
const emptyBlocks = persistedUser.content.filter(
|
|
399
|
-
(b) => b.type === "text" && (b as { text: string }).text === "",
|
|
400
|
-
);
|
|
401
|
-
expect(emptyBlocks).toHaveLength(0);
|
|
402
|
-
}
|
|
403
|
-
expect(profileCompilerCalls).toBe(1);
|
|
404
|
-
expect(events.some((event) => event.type === "message_complete")).toBe(
|
|
405
|
-
true,
|
|
406
|
-
);
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
test("strip removes empty text blocks left by dedicated injection block", () => {
|
|
410
|
-
const profile = "timezone: US/Pacific";
|
|
411
|
-
const userMsg: Message = {
|
|
412
|
-
role: "user",
|
|
413
|
-
content: [{ type: "text", text: "hello" }],
|
|
414
|
-
};
|
|
415
|
-
const injected = injectDynamicProfileIntoUserMessage(userMsg, profile);
|
|
416
|
-
// The injected message has 2 content blocks: original + profile
|
|
417
|
-
expect(injected.content).toHaveLength(2);
|
|
418
|
-
const stripped = stripDynamicProfileMessages([injected], profile);
|
|
419
|
-
// After stripping, the dedicated profile block should be removed entirely
|
|
420
|
-
expect(stripped[0].content).toHaveLength(1);
|
|
421
|
-
expect(
|
|
422
|
-
stripped[0].content.every((b) => {
|
|
423
|
-
return b.type !== "text" || (b as { text: string }).text.length > 0;
|
|
424
|
-
}),
|
|
425
|
-
).toBe(true);
|
|
426
|
-
});
|
|
427
|
-
|
|
428
|
-
test("strip only targets the last user message, not earlier ones", () => {
|
|
429
|
-
const profile = "timezone: US/Pacific";
|
|
430
|
-
const profileMarker = "<dynamic-profile-context>";
|
|
431
|
-
const earlyUser: Message = {
|
|
432
|
-
role: "user",
|
|
433
|
-
content: [
|
|
434
|
-
{
|
|
435
|
-
type: "text",
|
|
436
|
-
text: `I pasted: ${profileMarker}\ntimezone: US/Pacific\n</dynamic-profile-context>`,
|
|
437
|
-
},
|
|
438
|
-
],
|
|
439
|
-
};
|
|
440
|
-
const assistant: Message = {
|
|
441
|
-
role: "assistant",
|
|
442
|
-
content: [{ type: "text", text: "ok" }],
|
|
443
|
-
};
|
|
444
|
-
const latestUser: Message = {
|
|
445
|
-
role: "user",
|
|
446
|
-
content: [{ type: "text", text: "follow up" }],
|
|
447
|
-
};
|
|
448
|
-
const injected = injectDynamicProfileIntoUserMessage(latestUser, profile);
|
|
449
|
-
const msgs = [earlyUser, assistant, injected];
|
|
450
|
-
const stripped = stripDynamicProfileMessages(msgs, profile);
|
|
451
|
-
// Earlier user message should be untouched
|
|
452
|
-
expect(messageText(stripped[0])).toContain(profileMarker);
|
|
453
|
-
// Latest user message should have profile removed
|
|
454
|
-
expect(messageText(stripped[2])).not.toContain(profileMarker);
|
|
455
|
-
});
|
|
456
|
-
|
|
457
|
-
test("strip finds injected message even when tool_result user messages follow it", () => {
|
|
458
|
-
const profile = "timezone: US/Pacific";
|
|
459
|
-
const profileMarker = "<dynamic-profile-context>";
|
|
460
|
-
const injectedUser = injectDynamicProfileIntoUserMessage(
|
|
461
|
-
{ role: "user", content: [{ type: "text", text: "hello" }] },
|
|
462
|
-
profile,
|
|
463
|
-
);
|
|
464
|
-
const assistantMsg: Message = {
|
|
465
|
-
role: "assistant",
|
|
466
|
-
content: [{ type: "text", text: "calling tool" }],
|
|
467
|
-
};
|
|
468
|
-
// Simulate tool_result user message appended by agent loop
|
|
469
|
-
const toolResultUser: Message = {
|
|
470
|
-
role: "user",
|
|
471
|
-
content: [
|
|
472
|
-
{ type: "tool_result", tool_use_id: "tu-1", content: "result" },
|
|
473
|
-
],
|
|
474
|
-
};
|
|
475
|
-
const msgs = [injectedUser, assistantMsg, toolResultUser];
|
|
476
|
-
const stripped = stripDynamicProfileMessages(msgs, profile);
|
|
477
|
-
// The injected profile should be stripped from the first user message
|
|
478
|
-
expect(messageText(stripped[0])).not.toContain(profileMarker);
|
|
479
|
-
// tool_result message should be untouched
|
|
480
|
-
expect(stripped[2]).toBe(toolResultUser);
|
|
481
|
-
});
|
|
482
|
-
|
|
483
|
-
test("skips profile compilation/injection when memory.profile.enabled is false", async () => {
|
|
484
|
-
profileEnabled = false;
|
|
485
|
-
const session = makeSession();
|
|
486
|
-
await session.loadFromDb();
|
|
487
|
-
|
|
488
|
-
await session.processMessage("Explain rebase strategy", [], () => {});
|
|
489
|
-
|
|
490
|
-
expect(runCalls).toHaveLength(1);
|
|
491
|
-
const runtimeUser = runCalls[0][runCalls[0].length - 1];
|
|
492
|
-
const runtimeText = messageText(runtimeUser);
|
|
493
|
-
expect(runtimeText).not.toContain("<dynamic-profile-context>");
|
|
494
|
-
expect(profileCompilerCalls).toBe(0);
|
|
495
|
-
});
|
|
496
|
-
|
|
497
|
-
test("skips profile injection when top-level memory.enabled is false", async () => {
|
|
498
|
-
memoryEnabled = false;
|
|
499
|
-
const session = makeSession();
|
|
500
|
-
await session.loadFromDb();
|
|
501
|
-
|
|
502
|
-
await session.processMessage("What is my timezone?", [], () => {});
|
|
503
|
-
|
|
504
|
-
expect(runCalls).toHaveLength(1);
|
|
505
|
-
const runtimeUser = runCalls[0][runCalls[0].length - 1];
|
|
506
|
-
const runtimeText = messageText(runtimeUser);
|
|
507
|
-
expect(runtimeText).not.toContain("<dynamic-profile-context>");
|
|
508
|
-
expect(profileCompilerCalls).toBe(0);
|
|
509
|
-
});
|
|
510
|
-
|
|
511
|
-
test("private thread session uses private scope + default fallback in profile compile and recall", async () => {
|
|
512
|
-
const privatePolicy: SessionMemoryPolicy = {
|
|
513
|
-
scopeId: "private-thread-abc",
|
|
514
|
-
includeDefaultFallback: true,
|
|
515
|
-
strictSideEffects: false,
|
|
516
|
-
};
|
|
517
|
-
const session = makeSession(privatePolicy);
|
|
518
|
-
await session.loadFromDb();
|
|
519
|
-
|
|
520
|
-
await session.processMessage("What do I prefer?", [], () => {});
|
|
521
|
-
|
|
522
|
-
// Profile compiler should receive the private scope with fallback enabled
|
|
523
|
-
expect(profileCompilerCalls).toBe(1);
|
|
524
|
-
expect(profileCompilerArgs).toHaveLength(1);
|
|
525
|
-
expect(profileCompilerArgs[0].scopeId).toBe("private-thread-abc");
|
|
526
|
-
expect(profileCompilerArgs[0].includeDefaultFallback).toBe(true);
|
|
527
|
-
|
|
528
|
-
// Memory recall should receive scopeId and a scopePolicyOverride for the private scope
|
|
529
|
-
expect(recallArgs).toHaveLength(1);
|
|
530
|
-
expect(recallArgs[0].scopeId).toBe("private-thread-abc");
|
|
531
|
-
expect(recallArgs[0].scopePolicyOverride).toEqual({
|
|
532
|
-
scopeId: "private-thread-abc",
|
|
533
|
-
fallbackToDefault: true,
|
|
534
|
-
});
|
|
535
|
-
});
|
|
536
|
-
|
|
537
|
-
test("standard thread uses default scope without fallback in profile compile and no scope override in recall", async () => {
|
|
538
|
-
// Default policy: scopeId='default', includeDefaultFallback=false
|
|
539
|
-
const session = makeSession(DEFAULT_MEMORY_POLICY);
|
|
540
|
-
await session.loadFromDb();
|
|
541
|
-
|
|
542
|
-
await session.processMessage("Tell me about TypeScript", [], () => {});
|
|
543
|
-
|
|
544
|
-
// Profile compiler should receive default scope without fallback
|
|
545
|
-
expect(profileCompilerCalls).toBe(1);
|
|
546
|
-
expect(profileCompilerArgs).toHaveLength(1);
|
|
547
|
-
expect(profileCompilerArgs[0].scopeId).toBe("default");
|
|
548
|
-
expect(profileCompilerArgs[0].includeDefaultFallback).toBe(false);
|
|
549
|
-
|
|
550
|
-
// Memory recall should forward scopeId='default' so buildScopeFilter
|
|
551
|
-
// properly filters to the default scope, and should NOT have a
|
|
552
|
-
// scopePolicyOverride (default scope relies on the global config policy)
|
|
553
|
-
expect(recallArgs).toHaveLength(1);
|
|
554
|
-
expect(recallArgs[0].scopeId).toBe("default");
|
|
555
|
-
expect(recallArgs[0].scopePolicyOverride).toBeUndefined();
|
|
556
|
-
});
|
|
557
|
-
});
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: knowledge-graph
|
|
3
|
-
description: Query the entity knowledge graph to explore relationships between people, projects, tools, and other entities tracked in memory
|
|
4
|
-
compatibility: "Designed for Vellum personal assistants"
|
|
5
|
-
metadata:
|
|
6
|
-
emoji: "πΈοΈ"
|
|
7
|
-
vellum:
|
|
8
|
-
display-name: "Knowledge Graph"
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
# Knowledge Graph
|
|
12
|
-
|
|
13
|
-
Query the entity knowledge graph to explore relationships between people, projects, tools, and other entities tracked in memory.
|
|
14
|
-
|
|
15
|
-
## When to use
|
|
16
|
-
|
|
17
|
-
- When the user asks about relationships between entities ("what tools does project X use?", "who works on project Y?")
|
|
18
|
-
- When the user wants to explore connected entities across the knowledge graph
|
|
19
|
-
- When automatic memory recall doesn't surface the right relationship-based information
|
|
20
|
-
|
|
21
|
-
## Capabilities
|
|
22
|
-
|
|
23
|
-
- **Neighbors**: Find entities directly connected to seed entities (optionally filtered by relation and entity type)
|
|
24
|
-
- **Typed traversal**: Multi-step traversal with type constraints at each step (e.g., "me -> works_on -> projects -> uses -> tools")
|
|
25
|
-
- **Intersection**: Find entities reachable from ALL given seeds (e.g., "projects both Alice and Bob work on")
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 1,
|
|
3
|
-
"tools": [
|
|
4
|
-
{
|
|
5
|
-
"name": "knowledge_graph_query",
|
|
6
|
-
"description": "Query the entity knowledge graph to find related entities and their associated memory items. Supports three query types: 'neighbors' (direct connections), 'typed_traversal' (multi-step with type filters), and 'intersection' (entities reachable from ALL seeds).",
|
|
7
|
-
"category": "memory",
|
|
8
|
-
"risk": "low",
|
|
9
|
-
"input_schema": {
|
|
10
|
-
"type": "object",
|
|
11
|
-
"properties": {
|
|
12
|
-
"query_type": {
|
|
13
|
-
"type": "string",
|
|
14
|
-
"enum": ["neighbors", "typed_traversal", "intersection"],
|
|
15
|
-
"description": "Type of graph query to execute"
|
|
16
|
-
},
|
|
17
|
-
"seeds": {
|
|
18
|
-
"type": "array",
|
|
19
|
-
"items": {
|
|
20
|
-
"type": "string"
|
|
21
|
-
},
|
|
22
|
-
"description": "Entity names or aliases to use as starting points"
|
|
23
|
-
},
|
|
24
|
-
"steps": {
|
|
25
|
-
"type": "array",
|
|
26
|
-
"items": {
|
|
27
|
-
"type": "object",
|
|
28
|
-
"properties": {
|
|
29
|
-
"relation_types": {
|
|
30
|
-
"type": "array",
|
|
31
|
-
"items": {
|
|
32
|
-
"type": "string"
|
|
33
|
-
},
|
|
34
|
-
"description": "Relation types to follow (e.g., 'uses', 'works_on', 'depends_on')"
|
|
35
|
-
},
|
|
36
|
-
"entity_types": {
|
|
37
|
-
"type": "array",
|
|
38
|
-
"items": {
|
|
39
|
-
"type": "string"
|
|
40
|
-
},
|
|
41
|
-
"description": "Entity types to include (e.g., 'person', 'project', 'tool')"
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
"description": "Traversal steps for typed_traversal and intersection queries. Each step defines type filters for one hop."
|
|
46
|
-
},
|
|
47
|
-
"max_results": {
|
|
48
|
-
"type": "number",
|
|
49
|
-
"description": "Maximum number of entities to return (default: 20)"
|
|
50
|
-
},
|
|
51
|
-
"include_items": {
|
|
52
|
-
"type": "boolean",
|
|
53
|
-
"description": "Include associated memory items for each found entity (default: true)"
|
|
54
|
-
},
|
|
55
|
-
"reason": {
|
|
56
|
-
"type": "string",
|
|
57
|
-
"description": "Brief non-technical explanation of why this tool is being called"
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
"required": ["query_type", "seeds"]
|
|
61
|
-
},
|
|
62
|
-
"executor": "tools/graph-query.ts",
|
|
63
|
-
"execution_target": "host"
|
|
64
|
-
}
|
|
65
|
-
]
|
|
66
|
-
}
|