@vellumai/assistant 0.5.16 → 0.6.0
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 +1 -1
- package/Dockerfile +0 -3
- package/knip.json +2 -1
- package/openapi.yaml +660 -80
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +68 -0
- package/src/__tests__/agent-loop.test.ts +0 -32
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
- package/src/__tests__/anthropic-provider.test.ts +57 -3
- package/src/__tests__/app-compiler.test.ts +120 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +2 -2
- package/src/__tests__/call-conversation-messages.test.ts +2 -6
- package/src/__tests__/call-domain.test.ts +2 -6
- package/src/__tests__/call-pointer-messages.test.ts +2 -14
- package/src/__tests__/call-recovery.test.ts +2 -6
- package/src/__tests__/call-routes-http.test.ts +2 -6
- package/src/__tests__/call-store.test.ts +2 -6
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +2 -6
- package/src/__tests__/canonical-guardian-store.test.ts +2 -6
- package/src/__tests__/channel-delivery-store.test.ts +2 -6
- package/src/__tests__/channel-retry-sweep.test.ts +2 -6
- package/src/__tests__/checker.test.ts +25 -3
- package/src/__tests__/clawhub.test.ts +54 -24
- package/src/__tests__/cli-command-risk-guard.test.ts +14 -0
- package/src/__tests__/cli-memory.test.ts +74 -69
- package/src/__tests__/config-schema.test.ts +1 -1
- package/src/__tests__/config-set-platform-guard.test.ts +302 -0
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -6
- package/src/__tests__/contacts-tools.test.ts +31 -0
- package/src/__tests__/context-overflow-reducer.test.ts +86 -0
- package/src/__tests__/context-token-estimator.test.ts +175 -10
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +9 -0
- package/src/__tests__/conversation-agent-loop.test.ts +9 -0
- package/src/__tests__/conversation-attachments.test.ts +2 -6
- package/src/__tests__/conversation-attention-store.test.ts +2 -6
- package/src/__tests__/conversation-clear-safety.test.ts +2 -6
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +4 -10
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -6
- package/src/__tests__/conversation-disk-view.test.ts +2 -6
- package/src/__tests__/conversation-error.test.ts +33 -2
- package/src/__tests__/conversation-fork-crud.test.ts +2 -6
- package/src/__tests__/conversation-history-web-search.test.ts +5 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +5 -1
- package/src/__tests__/conversation-media-retry.test.ts +91 -0
- package/src/__tests__/conversation-starter-routes.test.ts +20 -11
- package/src/__tests__/conversation-store.test.ts +2 -6
- package/src/__tests__/conversation-usage.test.ts +2 -6
- package/src/__tests__/conversation-wipe.test.ts +11 -408
- package/src/__tests__/credential-execution-feature-gates.test.ts +3 -3
- package/src/__tests__/credential-execution-shell-lockdown.test.ts +2 -2
- package/src/__tests__/credential-security-e2e.test.ts +2 -0
- package/src/__tests__/followup-tools.test.ts +2 -6
- package/src/__tests__/graph-extraction-event-date.test.ts +186 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -6
- package/src/__tests__/guardian-action-followup-executor.test.ts +2 -6
- package/src/__tests__/guardian-action-followup-store.test.ts +2 -6
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +2 -6
- package/src/__tests__/guardian-action-late-reply.test.ts +2 -6
- package/src/__tests__/guardian-action-store.test.ts +2 -6
- package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -6
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +8 -8
- package/src/__tests__/guardian-dispatch.test.ts +2 -6
- package/src/__tests__/guardian-grant-minting.test.ts +2 -14
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -6
- package/src/__tests__/guardian-routing-invariants.test.ts +192 -6
- package/src/__tests__/guardian-routing-state.test.ts +2 -6
- package/src/__tests__/guardian-verification-voice-binding.test.ts +2 -6
- package/src/__tests__/inbound-invite-redemption.test.ts +2 -6
- package/src/__tests__/injection-block.test.ts +154 -0
- package/src/__tests__/install-meta.test.ts +506 -0
- package/src/__tests__/install-skill-routing.test.ts +292 -0
- package/src/__tests__/invite-redemption-service.test.ts +2 -6
- package/src/__tests__/invite-routes-http.test.ts +2 -6
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +2 -14
- package/src/__tests__/list-messages-attachments.test.ts +2 -6
- package/src/__tests__/llm-context-route-provider.test.ts +2 -6
- package/src/__tests__/llm-request-log-turn-query.test.ts +2 -6
- package/src/__tests__/llm-usage-store.test.ts +2 -6
- package/src/__tests__/log-export-workspace.test.ts +2 -6
- package/src/__tests__/managed-store.test.ts +38 -11
- package/src/__tests__/memory-jobs-worker-backoff.test.ts +2 -8
- package/src/__tests__/memory-recall-log-store.test.ts +2 -6
- package/src/__tests__/memory-upsert-concurrency.test.ts +4 -112
- package/src/__tests__/non-member-access-request.test.ts +2 -6
- package/src/__tests__/notification-guardian-path.test.ts +2 -6
- package/src/__tests__/oauth-cli.test.ts +364 -2
- package/src/__tests__/oauth2-gateway-transport.test.ts +18 -3
- package/src/__tests__/outlook-attachments.test.ts +301 -0
- package/src/__tests__/outlook-automation-tools.test.ts +425 -0
- package/src/__tests__/outlook-categories.test.ts +212 -0
- package/src/__tests__/outlook-client-automation.test.ts +246 -0
- package/src/__tests__/outlook-compose-tools.test.ts +325 -0
- package/src/__tests__/outlook-declutter-tools.test.ts +585 -0
- package/src/__tests__/outlook-email-watcher.test.ts +322 -0
- package/src/__tests__/outlook-follow-up.test.ts +196 -0
- package/src/__tests__/outlook-messaging-provider.test.ts +498 -3
- package/src/__tests__/outlook-trash.test.ts +77 -0
- package/src/__tests__/outlook-unsubscribe.test.ts +250 -0
- package/src/__tests__/platform-callback-registration.test.ts +4 -4
- package/src/__tests__/playbook-execution.test.ts +76 -80
- package/src/__tests__/playbook-tools.test.ts +5 -7
- package/src/__tests__/provider-error-scenarios.test.ts +21 -0
- package/src/__tests__/rebuild-index-graph-nodes.test.ts +273 -0
- package/src/__tests__/registry.test.ts +2 -2
- package/src/__tests__/require-fresh-approval.test.ts +64 -2
- package/src/__tests__/runtime-events-sse-parity.test.ts +2 -6
- package/src/__tests__/runtime-events-sse.test.ts +2 -6
- package/src/__tests__/schedule-store.test.ts +2 -6
- package/src/__tests__/schedule-tools.test.ts +2 -6
- package/src/__tests__/scheduler-recurrence.test.ts +1 -5
- package/src/__tests__/scoped-approval-grants.test.ts +2 -6
- package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -6
- package/src/__tests__/search-skills-unified.test.ts +421 -0
- package/src/__tests__/secret-onetime-send.test.ts +2 -0
- package/src/__tests__/send-endpoint-busy.test.ts +2 -6
- package/src/__tests__/sequence-store.test.ts +2 -6
- package/src/__tests__/server-history-render.test.ts +2 -6
- package/src/__tests__/skill-feature-flags-integration.test.ts +38 -31
- package/src/__tests__/skill-feature-flags.test.ts +6 -6
- package/src/__tests__/skill-load-feature-flag.test.ts +11 -11
- package/src/__tests__/skill-memory.test.ts +140 -98
- package/src/__tests__/skills-uninstall.test.ts +2 -2
- package/src/__tests__/skills.test.ts +1 -1
- package/src/__tests__/slack-inbound-verification.test.ts +2 -6
- package/src/__tests__/task-compiler.test.ts +2 -6
- package/src/__tests__/task-management-tools.test.ts +2 -6
- package/src/__tests__/task-memory-cleanup.test.ts +173 -229
- package/src/__tests__/task-runner.test.ts +2 -6
- package/src/__tests__/task-scheduler.test.ts +2 -6
- package/src/__tests__/test-preload.ts +3 -0
- package/src/__tests__/tool-approval-handler.test.ts +2 -6
- package/src/__tests__/tool-grant-request-escalation.test.ts +2 -6
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +276 -0
- package/src/__tests__/trust-store.test.ts +1 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +2 -6
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -6
- package/src/__tests__/trusted-contact-multichannel.test.ts +2 -6
- package/src/__tests__/trusted-contact-verification.test.ts +2 -6
- package/src/__tests__/turn-boundary-resolution.test.ts +2 -6
- package/src/__tests__/usage-cache-backfill-migration.test.ts +1 -6
- package/src/__tests__/usage-routes.test.ts +2 -6
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
- package/src/__tests__/voice-invite-redemption.test.ts +2 -6
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -6
- package/src/__tests__/voice-session-bridge.test.ts +2 -6
- package/src/__tests__/volume-security-guard.test.ts +2 -0
- package/src/__tests__/workspace-lifecycle.test.ts +29 -1
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -6
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +2 -6
- package/src/__tests__/workspace-migration-026-backfill-install-meta.test.ts +558 -0
- package/src/__tests__/workspace-policy.test.ts +1 -1
- package/src/agent/attachments.ts +7 -2
- package/src/agent/image-optimize.ts +165 -0
- package/src/agent/loop.ts +1 -15
- package/src/bundler/app-compiler.ts +179 -2
- package/src/bundler/package-resolver.ts +3 -5
- package/src/cli/__tests__/notifications.test.ts +1 -2
- package/src/cli/cli-memory.ts +67 -64
- package/src/cli/commands/avatar.ts +3 -3
- package/src/cli/commands/config.ts +26 -13
- package/src/cli/commands/doctor.ts +2 -2
- package/src/cli/commands/memory.ts +41 -55
- package/src/cli/commands/oauth/__tests__/connect.test.ts +2 -2
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +2 -2
- package/src/cli/commands/oauth/__tests__/mode.test.ts +8 -1
- package/src/cli/commands/oauth/__tests__/status.test.ts +2 -2
- package/src/cli/commands/oauth/connect.ts +11 -6
- package/src/cli/commands/oauth/mode.ts +7 -0
- package/src/cli/commands/oauth/shared.ts +39 -3
- package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +5 -5
- package/src/cli/commands/platform/index.ts +16 -16
- package/src/cli/commands/skills.ts +88 -16
- package/src/cli/commands/trust.ts +2 -2
- package/src/cli/lib/daemon-credential-client.ts +2 -3
- package/src/config/bundled-skills/acp/TOOLS.json +1 -1
- package/src/config/bundled-skills/contacts/SKILL.md +0 -1
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -8
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -4
- package/src/config/bundled-skills/gmail/SKILL.md +2 -10
- package/src/config/bundled-skills/google-calendar/SKILL.md +1 -9
- package/src/config/bundled-skills/messaging/SKILL.md +10 -18
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +40 -33
- package/src/config/bundled-skills/outlook/SKILL.md +189 -0
- package/src/config/bundled-skills/outlook/TOOLS.json +530 -0
- package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +85 -0
- package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +77 -0
- package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +84 -0
- package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +94 -0
- package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +49 -0
- package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +237 -0
- package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +161 -0
- package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +32 -0
- package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +272 -0
- package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +29 -0
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +129 -0
- package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +87 -0
- package/src/config/bundled-skills/outlook/tools/shared.ts +20 -0
- package/src/config/bundled-skills/outlook-calendar/SKILL.md +51 -0
- package/src/config/bundled-skills/outlook-calendar/TOOLS.json +221 -0
- package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +252 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +53 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +74 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +18 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +46 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +36 -0
- package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +17 -0
- package/src/config/bundled-skills/outlook-calendar/types.ts +120 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +47 -40
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +16 -29
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +16 -18
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +39 -47
- package/src/config/bundled-skills/slack/SKILL.md +1 -7
- package/src/config/bundled-tool-registry.ts +56 -4
- package/src/config/env-registry.ts +15 -8
- package/src/config/feature-flag-registry.json +21 -124
- package/src/config/schemas/platform.ts +8 -0
- package/src/config/schemas/timeouts.ts +1 -1
- package/src/config/skills.ts +18 -7
- package/src/context/token-estimator.ts +25 -18
- package/src/context/window-manager.ts +6 -2
- package/src/credential-execution/process-manager.ts +3 -1
- package/src/daemon/context-overflow-reducer.ts +46 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +123 -82
- package/src/daemon/conversation-agent-loop.ts +96 -61
- package/src/daemon/conversation-error.ts +31 -8
- package/src/daemon/conversation-lifecycle.ts +33 -0
- package/src/daemon/conversation-media-retry.ts +85 -7
- package/src/daemon/conversation-notifiers.ts +4 -1
- package/src/daemon/conversation-runtime-assembly.ts +5 -0
- package/src/daemon/conversation.ts +41 -2
- package/src/daemon/daemon-control.ts +8 -2
- package/src/daemon/handlers/shared.ts +22 -12
- package/src/daemon/handlers/skills.ts +416 -202
- package/src/daemon/lifecycle.ts +40 -1
- package/src/daemon/main.ts +5 -1
- package/src/daemon/message-types/conversations.ts +4 -1
- package/src/daemon/message-types/messages.ts +3 -1
- package/src/daemon/message-types/skills.ts +97 -36
- package/src/daemon/providers-setup.ts +5 -0
- package/src/daemon/server.ts +11 -2
- package/src/daemon/tool-side-effects.ts +27 -5
- package/src/heartbeat/heartbeat-service.ts +1 -0
- package/src/hooks/cli.ts +2 -2
- package/src/hooks/runner.ts +15 -38
- package/src/inbound/platform-callback-registration.ts +14 -14
- package/src/memory/admin.ts +11 -45
- package/src/memory/conversation-bootstrap.ts +2 -0
- package/src/memory/conversation-crud.ts +242 -348
- package/src/memory/conversation-group-migration.ts +157 -0
- package/src/memory/conversation-queries.ts +4 -2
- package/src/memory/db-init.ts +30 -3
- package/src/memory/embed.ts +73 -0
- package/src/memory/embedding-backend.ts +8 -14
- package/src/memory/embedding-runtime-manager.ts +12 -114
- package/src/memory/fingerprint.ts +2 -2
- package/src/memory/graph/bootstrap.ts +512 -0
- package/src/memory/graph/capability-seed.ts +297 -0
- package/src/memory/graph/consolidation.ts +691 -0
- package/src/memory/graph/conversation-graph-memory.ts +630 -0
- package/src/memory/graph/decay.test.ts +208 -0
- package/src/memory/graph/decay.ts +195 -0
- package/src/memory/graph/extraction-job.ts +69 -0
- package/src/memory/graph/extraction.test.ts +936 -0
- package/src/memory/graph/extraction.ts +1254 -0
- package/src/memory/graph/graph-search.ts +266 -0
- package/src/memory/graph/image-ref-utils.ts +29 -0
- package/src/memory/graph/injection.test.ts +513 -0
- package/src/memory/graph/injection.ts +439 -0
- package/src/memory/graph/inspect.ts +534 -0
- package/src/memory/graph/narrative.ts +267 -0
- package/src/memory/graph/pattern-scan.ts +269 -0
- package/src/memory/graph/retriever.ts +1008 -0
- package/src/memory/graph/scoring.test.ts +548 -0
- package/src/memory/graph/scoring.ts +232 -0
- package/src/memory/graph/serendipity.ts +65 -0
- package/src/memory/graph/store.test.ts +1050 -0
- package/src/memory/graph/store.ts +699 -0
- package/src/memory/graph/tool-handlers.ts +426 -0
- package/src/memory/graph/tools.ts +141 -0
- package/src/memory/graph/triggers.test.ts +487 -0
- package/src/memory/graph/triggers.ts +223 -0
- package/src/memory/graph/types.ts +271 -0
- package/src/memory/group-crud.ts +191 -0
- package/src/memory/indexer.ts +37 -19
- package/src/memory/job-handlers/cleanup.ts +0 -53
- package/src/memory/job-handlers/conversation-starters.ts +91 -53
- package/src/memory/job-handlers/embedding.ts +5 -31
- package/src/memory/job-handlers/index-maintenance.ts +23 -11
- package/src/memory/job-handlers/summarization.ts +32 -17
- package/src/memory/job-utils.ts +1 -1
- package/src/memory/jobs-store.ts +50 -70
- package/src/memory/jobs-worker.ts +147 -112
- package/src/memory/message-content.ts +1 -0
- package/src/memory/migrations/202-memory-graph-tables.ts +130 -0
- package/src/memory/migrations/203-drop-memory-items-tables.ts +23 -0
- package/src/memory/migrations/204-rename-memory-graph-type-values.ts +46 -0
- package/src/memory/migrations/205-memory-graph-image-refs.ts +11 -0
- package/src/memory/migrations/index.ts +4 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/qdrant-client.ts +44 -17
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/memory-graph.ts +139 -0
- package/src/memory/search/semantic.ts +47 -91
- package/src/memory/task-memory-cleanup.ts +28 -50
- package/src/messaging/providers/outlook/adapter.ts +8 -1
- package/src/messaging/providers/outlook/client.ts +299 -0
- package/src/messaging/providers/outlook/types.ts +118 -0
- package/src/notifications/adapters/macos.ts +1 -0
- package/src/notifications/copy-composer.ts +9 -0
- package/src/notifications/signal.ts +16 -0
- package/src/oauth/seed-providers.ts +2 -1
- package/src/permissions/checker.ts +24 -3
- package/src/permissions/defaults.ts +4 -4
- package/src/permissions/workspace-policy.ts +1 -1
- package/src/playbooks/playbook-compiler.ts +19 -18
- package/src/playbooks/types.ts +4 -3
- package/src/prompts/system-prompt.ts +3 -29
- package/src/providers/anthropic/client.ts +47 -19
- package/src/providers/gemini/client.ts +1 -1
- package/src/providers/openai/client.ts +1 -1
- package/src/providers/registry.ts +1 -1
- package/src/providers/retry.ts +19 -3
- package/src/runtime/actor-trust-resolver.ts +5 -1
- package/src/runtime/auth/route-policy.ts +7 -0
- package/src/runtime/guardian-reply-router.ts +5 -1
- package/src/runtime/http-server.ts +23 -3
- package/src/runtime/middleware/auth.ts +20 -0
- package/src/runtime/routes/attachment-routes.test.ts +106 -0
- package/src/runtime/routes/attachment-routes.ts +106 -16
- package/src/runtime/routes/brain-graph-routes.ts +21 -22
- package/src/runtime/routes/btw-routes.ts +8 -0
- package/src/runtime/routes/conversation-management-routes.ts +2 -0
- package/src/runtime/routes/conversation-starter-routes.ts +2 -2
- package/src/runtime/routes/debug-routes.ts +1 -1
- package/src/runtime/routes/global-search-routes.ts +21 -19
- package/src/runtime/routes/group-routes.ts +207 -0
- package/src/runtime/routes/guardian-action-routes.ts +21 -10
- package/src/runtime/routes/guardian-bootstrap-routes.ts +23 -19
- package/src/runtime/routes/inbound-message-handler.ts +19 -0
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +292 -0
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +207 -0
- package/src/runtime/routes/memory-item-routes.test.ts +2 -14
- package/src/runtime/routes/memory-item-routes.ts +341 -388
- package/src/runtime/routes/schedule-routes.ts +2 -0
- package/src/runtime/routes/skills-routes.ts +103 -37
- package/src/runtime/routes/work-items-routes.test.ts +2 -6
- package/src/schedule/scheduler.ts +8 -1
- package/src/security/oauth2.ts +1 -1
- package/src/security/secure-keys.ts +4 -8
- package/src/shared/provider-env-vars.ts +19 -0
- package/src/skills/catalog-cache.ts +5 -0
- package/src/skills/catalog-install.ts +15 -14
- package/src/skills/clawhub.ts +134 -154
- package/src/skills/install-meta.ts +208 -0
- package/src/skills/managed-store.ts +27 -16
- package/src/skills/skill-memory.ts +152 -77
- package/src/skills/skillssh-registry.ts +19 -17
- package/src/tasks/task-runner.ts +3 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +3 -5
- package/src/tools/browser/runtime-check.ts +3 -1
- package/src/tools/memory/register.ts +63 -46
- package/src/tools/permission-checker.ts +7 -1
- package/src/tools/shared/filesystem/image-read.ts +22 -85
- package/src/tools/terminal/safe-env.ts +1 -0
- package/src/tools/tool-manifest.ts +3 -3
- package/src/util/browser.ts +25 -10
- package/src/util/bun-runtime.ts +172 -0
- package/src/watcher/providers/outlook-calendar.ts +343 -0
- package/src/watcher/providers/outlook.ts +198 -0
- package/src/workspace/migrations/025-remove-oauth-app-setup-skills.ts +76 -0
- package/src/workspace/migrations/026-backfill-install-meta.ts +325 -0
- package/src/workspace/migrations/027-remove-orphaned-optimized-images-cache.ts +42 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/__tests__/context-memory-e2e.test.ts +0 -415
- package/src/__tests__/journal-context.test.ts +0 -268
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -297
- package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -459
- package/src/__tests__/memory-query-builder.test.ts +0 -59
- package/src/__tests__/memory-recall-quality.test.ts +0 -1046
- package/src/__tests__/memory-regressions.experimental.test.ts +0 -629
- package/src/__tests__/memory-regressions.test.ts +0 -3696
- package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -295
- package/src/daemon/conversation-memory.ts +0 -207
- package/src/memory/conversation-starters-cadence.ts +0 -74
- package/src/memory/items-extractor.ts +0 -860
- package/src/memory/job-handlers/batch-extraction.ts +0 -753
- package/src/memory/job-handlers/extraction.ts +0 -40
- package/src/memory/job-handlers/journal-carry-forward.test.ts +0 -355
- package/src/memory/job-handlers/journal-carry-forward.ts +0 -255
- package/src/memory/journal-memory.ts +0 -224
- package/src/memory/query-builder.ts +0 -47
- package/src/memory/query-expansion.ts +0 -83
- package/src/memory/retriever.test.ts +0 -1592
- package/src/memory/retriever.ts +0 -1331
- package/src/memory/search/formatting.test.ts +0 -140
- package/src/memory/search/formatting.ts +0 -262
- package/src/memory/search/mmr.ts +0 -139
- package/src/memory/search/ranking.ts +0 -15
- package/src/memory/search/staleness.ts +0 -40
- package/src/memory/search/tier-classifier.ts +0 -18
- package/src/memory/search/types.ts +0 -121
- package/src/prompts/journal-context.ts +0 -154
- package/src/tools/memory/definitions.ts +0 -69
- package/src/tools/memory/handlers.test.ts +0 -562
- package/src/tools/memory/handlers.ts +0 -434
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Memory Graph — Narrative arc refinement
|
|
3
|
+
//
|
|
4
|
+
// Re-evaluates narrativeRole assignments with hindsight. Details that seemed
|
|
5
|
+
// minor at creation time can be elevated to "turning-point" or "thesis"
|
|
6
|
+
// once later events reveal their importance.
|
|
7
|
+
//
|
|
8
|
+
// Runs monthly or on demand. One LLM call over narrative-tagged nodes +
|
|
9
|
+
// high-significance nodes to re-evaluate arc assignments.
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
import type { AssistantConfig } from "../../config/types.js";
|
|
13
|
+
import {
|
|
14
|
+
extractToolUse,
|
|
15
|
+
getConfiguredProvider,
|
|
16
|
+
userMessage,
|
|
17
|
+
} from "../../providers/provider-send-message.js";
|
|
18
|
+
import { BackendUnavailableError } from "../../util/errors.js";
|
|
19
|
+
import { getLogger } from "../../util/logger.js";
|
|
20
|
+
import { queryNodes, updateNode } from "./store.js";
|
|
21
|
+
import type { MemoryNode } from "./types.js";
|
|
22
|
+
|
|
23
|
+
const log = getLogger("graph-narrative");
|
|
24
|
+
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Narrative refinement prompt
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
function buildNarrativePrompt(
|
|
30
|
+
nodes: Array<{
|
|
31
|
+
id: string;
|
|
32
|
+
type: string;
|
|
33
|
+
content: string;
|
|
34
|
+
significance: number;
|
|
35
|
+
narrativeRole: string | null;
|
|
36
|
+
partOfStory: string | null;
|
|
37
|
+
created: number;
|
|
38
|
+
}>,
|
|
39
|
+
): string {
|
|
40
|
+
const nodeList = nodes
|
|
41
|
+
.map((n) => {
|
|
42
|
+
const age = Math.floor((Date.now() - n.created) / (1000 * 60 * 60 * 24));
|
|
43
|
+
const role = n.narrativeRole ? ` role="${n.narrativeRole}"` : "";
|
|
44
|
+
const story = n.partOfStory ? ` story="${n.partOfStory}"` : "";
|
|
45
|
+
return ` [${n.id}] type=${n.type} sig=${n.significance.toFixed(2)} age=${age}d${role}${story}\n ${n.content}`;
|
|
46
|
+
})
|
|
47
|
+
.join("\n\n");
|
|
48
|
+
|
|
49
|
+
return `You are reviewing the narrative structure of an AI assistant's memory graph. These are the high-significance memories and memories that already have narrative roles assigned.
|
|
50
|
+
|
|
51
|
+
## Your Tasks
|
|
52
|
+
|
|
53
|
+
1. **Identify story arcs**: Group related memories into named narrative arcs. An arc is a coherent thread that spans multiple memories — like "the personality drift crisis" or "building the voice pipeline" or "the substrate problem."
|
|
54
|
+
|
|
55
|
+
2. **Assign narrative roles**: For each memory in a story arc, assign one of:
|
|
56
|
+
- "inciting-incident": the event that kicked off the arc
|
|
57
|
+
- "turning-point": a moment where the arc changed direction
|
|
58
|
+
- "foreshadowing": something that hinted at what was to come (only visible in hindsight)
|
|
59
|
+
- "thesis": a conclusion or insight that the arc was building toward
|
|
60
|
+
- "resolution": the arc reached a conclusion or resting point
|
|
61
|
+
- null: remove a role that was incorrectly assigned
|
|
62
|
+
|
|
63
|
+
3. **Re-evaluate with hindsight**: Some memories tagged as ordinary at the time may have turned out to be pivotal. Conversely, some "turning-points" may have been premature. Update based on everything you can see now.
|
|
64
|
+
|
|
65
|
+
## Constraints
|
|
66
|
+
|
|
67
|
+
- Only assign narrative roles to memories that genuinely participate in a story arc
|
|
68
|
+
- Not every memory needs a role — most don't
|
|
69
|
+
- Story arc names should be short and descriptive (3-5 words)
|
|
70
|
+
- Don't create new arcs with fewer than 3 nodes
|
|
71
|
+
|
|
72
|
+
## Memories
|
|
73
|
+
|
|
74
|
+
${nodeList}
|
|
75
|
+
|
|
76
|
+
Use the refine_narratives tool to output your changes.`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const NARRATIVE_TOOL_SCHEMA = {
|
|
80
|
+
name: "refine_narratives",
|
|
81
|
+
description: "Output narrative role and story arc updates",
|
|
82
|
+
input_schema: {
|
|
83
|
+
type: "object" as const,
|
|
84
|
+
properties: {
|
|
85
|
+
updates: {
|
|
86
|
+
type: "array" as const,
|
|
87
|
+
items: {
|
|
88
|
+
type: "object" as const,
|
|
89
|
+
properties: {
|
|
90
|
+
id: { type: "string" as const },
|
|
91
|
+
narrativeRole: {
|
|
92
|
+
type: ["string", "null"] as unknown as "string",
|
|
93
|
+
description:
|
|
94
|
+
"inciting-incident, turning-point, foreshadowing, thesis, resolution, or null to remove",
|
|
95
|
+
},
|
|
96
|
+
partOfStory: {
|
|
97
|
+
type: ["string", "null"] as unknown as "string",
|
|
98
|
+
description:
|
|
99
|
+
"Short name for the narrative arc, or null to remove",
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
required: ["id"] as const,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
arcs_summary: {
|
|
106
|
+
type: "array" as const,
|
|
107
|
+
description: "Summary of identified story arcs",
|
|
108
|
+
items: {
|
|
109
|
+
type: "object" as const,
|
|
110
|
+
properties: {
|
|
111
|
+
name: { type: "string" as const },
|
|
112
|
+
description: { type: "string" as const },
|
|
113
|
+
node_count: { type: "number" as const },
|
|
114
|
+
},
|
|
115
|
+
required: ["name", "description", "node_count"] as const,
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
required: ["updates", "arcs_summary"] as const,
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
// Run narrative refinement
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
export interface NarrativeResult {
|
|
128
|
+
nodesUpdated: number;
|
|
129
|
+
arcsIdentified: number;
|
|
130
|
+
latencyMs: number;
|
|
131
|
+
arcs: Array<{ name: string; description: string; nodeCount: number }>;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export async function runNarrativeRefinement(
|
|
135
|
+
scopeId: string = "default",
|
|
136
|
+
_config: AssistantConfig,
|
|
137
|
+
): Promise<NarrativeResult> {
|
|
138
|
+
const start = Date.now();
|
|
139
|
+
const result: NarrativeResult = {
|
|
140
|
+
nodesUpdated: 0,
|
|
141
|
+
arcsIdentified: 0,
|
|
142
|
+
latencyMs: 0,
|
|
143
|
+
arcs: [],
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// Collect: all nodes with existing narrative roles + top significance nodes
|
|
147
|
+
const allNodes = queryNodes({
|
|
148
|
+
scopeId,
|
|
149
|
+
fidelityNot: ["gone"],
|
|
150
|
+
limit: 10000,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const narrativeNodes = allNodes.filter(
|
|
154
|
+
(n) => n.narrativeRole || n.partOfStory || n.significance >= 0.7,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
if (narrativeNodes.length < 5) {
|
|
158
|
+
log.info("Too few narrative-eligible nodes for refinement");
|
|
159
|
+
result.latencyMs = Date.now() - start;
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Cap at 150 to fit in context
|
|
164
|
+
const candidates = narrativeNodes
|
|
165
|
+
.sort((a, b) => b.significance - a.significance)
|
|
166
|
+
.slice(0, 150);
|
|
167
|
+
|
|
168
|
+
const provider = await getConfiguredProvider();
|
|
169
|
+
if (!provider) {
|
|
170
|
+
throw new BackendUnavailableError(
|
|
171
|
+
"Provider unavailable for narrative refinement",
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const candidateIds = new Set(candidates.map((n) => n.id));
|
|
176
|
+
|
|
177
|
+
const systemPrompt = buildNarrativePrompt(
|
|
178
|
+
candidates.map((n) => ({
|
|
179
|
+
id: n.id,
|
|
180
|
+
type: n.type,
|
|
181
|
+
content: n.content,
|
|
182
|
+
significance: n.significance,
|
|
183
|
+
narrativeRole: n.narrativeRole,
|
|
184
|
+
partOfStory: n.partOfStory,
|
|
185
|
+
created: n.created,
|
|
186
|
+
})),
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
const response = await provider.sendMessage(
|
|
190
|
+
[
|
|
191
|
+
userMessage(
|
|
192
|
+
"Review and refine the narrative structure of these memories. Identify story arcs and assign roles with the benefit of hindsight.",
|
|
193
|
+
),
|
|
194
|
+
],
|
|
195
|
+
[NARRATIVE_TOOL_SCHEMA],
|
|
196
|
+
systemPrompt,
|
|
197
|
+
{
|
|
198
|
+
config: {
|
|
199
|
+
modelIntent: "quality-optimized" as const,
|
|
200
|
+
tool_choice: { type: "tool" as const, name: "refine_narratives" },
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
const toolBlock = extractToolUse(response);
|
|
206
|
+
if (!toolBlock) {
|
|
207
|
+
log.warn("No tool_use block in narrative refinement response");
|
|
208
|
+
result.latencyMs = Date.now() - start;
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const input = toolBlock.input as {
|
|
213
|
+
updates?: Array<{
|
|
214
|
+
id: string;
|
|
215
|
+
narrativeRole?: string | null;
|
|
216
|
+
partOfStory?: string | null;
|
|
217
|
+
}>;
|
|
218
|
+
arcs_summary?: Array<{
|
|
219
|
+
name: string;
|
|
220
|
+
description: string;
|
|
221
|
+
node_count: number;
|
|
222
|
+
}>;
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// Apply updates
|
|
226
|
+
for (const update of input.updates ?? []) {
|
|
227
|
+
if (!candidateIds.has(update.id)) continue;
|
|
228
|
+
|
|
229
|
+
const changes: Partial<MemoryNode> = { lastConsolidated: Date.now() };
|
|
230
|
+
let hasChange = false;
|
|
231
|
+
|
|
232
|
+
if (update.narrativeRole !== undefined) {
|
|
233
|
+
changes.narrativeRole = update.narrativeRole;
|
|
234
|
+
hasChange = true;
|
|
235
|
+
}
|
|
236
|
+
if (update.partOfStory !== undefined) {
|
|
237
|
+
changes.partOfStory = update.partOfStory;
|
|
238
|
+
hasChange = true;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (hasChange) {
|
|
242
|
+
updateNode(update.id, changes);
|
|
243
|
+
result.nodesUpdated++;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Record arc summaries
|
|
248
|
+
result.arcs = (input.arcs_summary ?? []).map((a) => ({
|
|
249
|
+
name: a.name,
|
|
250
|
+
description: a.description,
|
|
251
|
+
nodeCount: a.node_count,
|
|
252
|
+
}));
|
|
253
|
+
result.arcsIdentified = result.arcs.length;
|
|
254
|
+
|
|
255
|
+
result.latencyMs = Date.now() - start;
|
|
256
|
+
|
|
257
|
+
log.info(
|
|
258
|
+
{
|
|
259
|
+
nodesUpdated: result.nodesUpdated,
|
|
260
|
+
arcsIdentified: result.arcsIdentified,
|
|
261
|
+
latencyMs: result.latencyMs,
|
|
262
|
+
},
|
|
263
|
+
"Narrative refinement complete",
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
return result;
|
|
267
|
+
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Memory Graph — Pattern detection
|
|
3
|
+
//
|
|
4
|
+
// Scans nodes for recurring themes and creates meta-nodes that capture
|
|
5
|
+
// patterns the assistant has noticed. E.g., 5 separate mentions of being
|
|
6
|
+
// tired → meta-node "User has been consistently tired over the past week."
|
|
7
|
+
//
|
|
8
|
+
// Also detects behavioral patterns in the assistant's own actions.
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
import type { AssistantConfig } from "../../config/types.js";
|
|
12
|
+
import {
|
|
13
|
+
extractToolUse,
|
|
14
|
+
getConfiguredProvider,
|
|
15
|
+
userMessage,
|
|
16
|
+
} from "../../providers/provider-send-message.js";
|
|
17
|
+
import { BackendUnavailableError } from "../../util/errors.js";
|
|
18
|
+
import { getLogger } from "../../util/logger.js";
|
|
19
|
+
import { createEdge, createNode, queryNodes } from "./store.js";
|
|
20
|
+
|
|
21
|
+
const log = getLogger("graph-pattern-scan");
|
|
22
|
+
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Pattern scan prompt
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
function buildPatternScanPrompt(
|
|
28
|
+
nodes: Array<{ id: string; type: string; content: string; created: number }>,
|
|
29
|
+
): string {
|
|
30
|
+
const nodeList = nodes
|
|
31
|
+
.map((n) => {
|
|
32
|
+
const age = Math.floor((Date.now() - n.created) / (1000 * 60 * 60 * 24));
|
|
33
|
+
return ` [${n.id}] type=${n.type} age=${age}d\n ${n.content}`;
|
|
34
|
+
})
|
|
35
|
+
.join("\n\n");
|
|
36
|
+
|
|
37
|
+
return `You are analyzing a random sample of an AI assistant's memory graph for recurring patterns, themes, and meta-observations.
|
|
38
|
+
|
|
39
|
+
## Your Tasks
|
|
40
|
+
|
|
41
|
+
1. **Detect recurring themes**: Look for topics, emotions, or situations that appear across 3+ nodes. Create a meta-node that captures the pattern itself — not just a summary, but an observation about the pattern.
|
|
42
|
+
- Example: "I notice that user mentions being tired in at least 5 separate conversations over the past two weeks. This isn't isolated — it's a pattern worth monitoring."
|
|
43
|
+
- Example: "There's a recurring theme of user starting ambitious projects late at night. Three separate memories mention work sessions starting after midnight."
|
|
44
|
+
|
|
45
|
+
2. **Detect behavioral patterns**: Look for patterns in the assistant's own behavior across memories.
|
|
46
|
+
- Example: "I tend to over-commit to solving problems in the moment rather than flagging them for later."
|
|
47
|
+
|
|
48
|
+
3. **Avoid trivial patterns**: Don't create meta-nodes for things that are obvious from single memories. The pattern must emerge from MULTIPLE memories taken together.
|
|
49
|
+
|
|
50
|
+
## Constraints
|
|
51
|
+
|
|
52
|
+
- Write meta-node content in first person
|
|
53
|
+
- Type should be "behavioral" (for assistant patterns) or "narrative" (for observed user/relationship patterns)
|
|
54
|
+
- Set significance based on how actionable or important the pattern is
|
|
55
|
+
- Create "part-of" edges from source nodes to the new pattern node
|
|
56
|
+
- Only create patterns you're genuinely confident about — 3+ supporting nodes minimum
|
|
57
|
+
|
|
58
|
+
## Memory Sample
|
|
59
|
+
|
|
60
|
+
${nodeList}
|
|
61
|
+
|
|
62
|
+
Use the detect_patterns tool to output any patterns found.`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const PATTERN_TOOL_SCHEMA = {
|
|
66
|
+
name: "detect_patterns",
|
|
67
|
+
description: "Output detected patterns from the memory sample",
|
|
68
|
+
input_schema: {
|
|
69
|
+
type: "object" as const,
|
|
70
|
+
properties: {
|
|
71
|
+
patterns: {
|
|
72
|
+
type: "array" as const,
|
|
73
|
+
items: {
|
|
74
|
+
type: "object" as const,
|
|
75
|
+
properties: {
|
|
76
|
+
content: {
|
|
77
|
+
type: "string" as const,
|
|
78
|
+
description: "First-person prose describing the pattern",
|
|
79
|
+
},
|
|
80
|
+
type: {
|
|
81
|
+
type: "string" as const,
|
|
82
|
+
enum: ["behavioral", "narrative"],
|
|
83
|
+
},
|
|
84
|
+
significance: { type: "number" as const },
|
|
85
|
+
source_node_ids: {
|
|
86
|
+
type: "array" as const,
|
|
87
|
+
items: { type: "string" as const },
|
|
88
|
+
description:
|
|
89
|
+
"IDs of nodes that support this pattern (3+ required)",
|
|
90
|
+
},
|
|
91
|
+
partOfStory: {
|
|
92
|
+
type: "string" as const,
|
|
93
|
+
description: "Optional narrative arc name",
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
required: [
|
|
97
|
+
"content",
|
|
98
|
+
"type",
|
|
99
|
+
"significance",
|
|
100
|
+
"source_node_ids",
|
|
101
|
+
] as const,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
required: ["patterns"] as const,
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
// Run pattern scan
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
|
|
113
|
+
export interface PatternScanResult {
|
|
114
|
+
patternsDetected: number;
|
|
115
|
+
edgesCreated: number;
|
|
116
|
+
latencyMs: number;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export async function runPatternScan(
|
|
120
|
+
scopeId: string = "default",
|
|
121
|
+
_config: AssistantConfig,
|
|
122
|
+
): Promise<PatternScanResult> {
|
|
123
|
+
const start = Date.now();
|
|
124
|
+
const result: PatternScanResult = {
|
|
125
|
+
patternsDetected: 0,
|
|
126
|
+
edgesCreated: 0,
|
|
127
|
+
latencyMs: 0,
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// Sample: take all nodes (for a graph of ~1000, this is manageable)
|
|
131
|
+
// For larger graphs, we'd sample more selectively
|
|
132
|
+
const allNodes = queryNodes({
|
|
133
|
+
scopeId,
|
|
134
|
+
fidelityNot: ["gone"],
|
|
135
|
+
limit: 200,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
if (allNodes.length < 10) {
|
|
139
|
+
log.info("Too few nodes for pattern scan");
|
|
140
|
+
result.latencyMs = Date.now() - start;
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const provider = await getConfiguredProvider();
|
|
145
|
+
if (!provider) {
|
|
146
|
+
throw new BackendUnavailableError("Provider unavailable for pattern scan");
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const systemPrompt = buildPatternScanPrompt(
|
|
150
|
+
allNodes.map((n) => ({
|
|
151
|
+
id: n.id,
|
|
152
|
+
type: n.type,
|
|
153
|
+
content: n.content,
|
|
154
|
+
created: n.created,
|
|
155
|
+
})),
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
const response = await provider.sendMessage(
|
|
159
|
+
[
|
|
160
|
+
userMessage(
|
|
161
|
+
"Analyze this memory sample for recurring patterns. Only report patterns you're confident about.",
|
|
162
|
+
),
|
|
163
|
+
],
|
|
164
|
+
[PATTERN_TOOL_SCHEMA],
|
|
165
|
+
systemPrompt,
|
|
166
|
+
{
|
|
167
|
+
config: {
|
|
168
|
+
modelIntent: "quality-optimized" as const,
|
|
169
|
+
tool_choice: { type: "tool" as const, name: "detect_patterns" },
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
const toolBlock = extractToolUse(response);
|
|
175
|
+
if (!toolBlock) {
|
|
176
|
+
log.warn("No tool_use block in pattern scan response");
|
|
177
|
+
result.latencyMs = Date.now() - start;
|
|
178
|
+
return result;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const input = toolBlock.input as {
|
|
182
|
+
patterns?: Array<{
|
|
183
|
+
content: string;
|
|
184
|
+
type: string;
|
|
185
|
+
significance: number;
|
|
186
|
+
source_node_ids: string[];
|
|
187
|
+
partOfStory?: string;
|
|
188
|
+
}>;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const existingIds = new Set(allNodes.map((n) => n.id));
|
|
192
|
+
const now = Date.now();
|
|
193
|
+
|
|
194
|
+
for (const pattern of input.patterns ?? []) {
|
|
195
|
+
// Validate: at least 3 source nodes that actually exist
|
|
196
|
+
const validSources = pattern.source_node_ids.filter((id) =>
|
|
197
|
+
existingIds.has(id),
|
|
198
|
+
);
|
|
199
|
+
if (validSources.length < 3) continue;
|
|
200
|
+
|
|
201
|
+
const type =
|
|
202
|
+
pattern.type === "behavioral"
|
|
203
|
+
? ("behavioral" as const)
|
|
204
|
+
: ("narrative" as const);
|
|
205
|
+
const sig = Math.max(0.3, Math.min(0.8, pattern.significance));
|
|
206
|
+
|
|
207
|
+
const newNode = createNode({
|
|
208
|
+
content: pattern.content,
|
|
209
|
+
type,
|
|
210
|
+
created: now,
|
|
211
|
+
lastAccessed: now,
|
|
212
|
+
lastConsolidated: now,
|
|
213
|
+
eventDate: null,
|
|
214
|
+
emotionalCharge: {
|
|
215
|
+
valence: 0,
|
|
216
|
+
intensity: 0.3,
|
|
217
|
+
decayCurve: "linear",
|
|
218
|
+
decayRate: 0.05,
|
|
219
|
+
originalIntensity: 0.3,
|
|
220
|
+
},
|
|
221
|
+
fidelity: "clear",
|
|
222
|
+
confidence: 0.7,
|
|
223
|
+
significance: sig,
|
|
224
|
+
stability: 14,
|
|
225
|
+
reinforcementCount: 0,
|
|
226
|
+
lastReinforced: now,
|
|
227
|
+
sourceConversations: [],
|
|
228
|
+
sourceType: "observed",
|
|
229
|
+
narrativeRole: null,
|
|
230
|
+
partOfStory: pattern.partOfStory ?? null,
|
|
231
|
+
imageRefs: null,
|
|
232
|
+
scopeId,
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
result.patternsDetected++;
|
|
236
|
+
|
|
237
|
+
// Create part-of edges from source nodes to pattern node
|
|
238
|
+
for (const sourceId of validSources) {
|
|
239
|
+
try {
|
|
240
|
+
createEdge({
|
|
241
|
+
sourceNodeId: sourceId,
|
|
242
|
+
targetNodeId: newNode.id,
|
|
243
|
+
relationship: "part-of",
|
|
244
|
+
weight: 0.7,
|
|
245
|
+
created: now,
|
|
246
|
+
});
|
|
247
|
+
result.edgesCreated++;
|
|
248
|
+
} catch {
|
|
249
|
+
log.warn(
|
|
250
|
+
{ sourceId, patternId: newNode.id },
|
|
251
|
+
"Failed to create pattern edge",
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
result.latencyMs = Date.now() - start;
|
|
258
|
+
|
|
259
|
+
log.info(
|
|
260
|
+
{
|
|
261
|
+
patternsDetected: result.patternsDetected,
|
|
262
|
+
edgesCreated: result.edgesCreated,
|
|
263
|
+
latencyMs: result.latencyMs,
|
|
264
|
+
},
|
|
265
|
+
"Pattern scan complete",
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
return result;
|
|
269
|
+
}
|