@vellumai/assistant 0.4.29 → 0.4.31
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 +39 -37
- package/Dockerfile +14 -8
- package/README.md +7 -8
- package/docs/architecture/memory.md +28 -29
- package/docs/runbook-trusted-contacts.md +76 -43
- package/package.json +1 -1
- package/scripts/ipc/check-swift-decoder-drift.ts +2 -3
- package/scripts/test.sh +1 -1
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +4 -37
- package/src/__tests__/actor-token-service.test.ts +4 -3
- package/src/__tests__/app-executors.test.ts +7 -17
- package/src/__tests__/assistant-feature-flags-integration.test.ts +18 -10
- package/src/__tests__/browser-skill-endstate.test.ts +10 -1
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +1 -0
- package/src/__tests__/channel-approval-routes.test.ts +44 -44
- package/src/__tests__/channel-approval.test.ts +8 -0
- package/src/__tests__/channel-approvals.test.ts +39 -1
- package/src/__tests__/channel-guardian.test.ts +15 -5
- package/src/__tests__/channel-reply-delivery.test.ts +31 -0
- package/src/__tests__/config-schema.test.ts +0 -9
- package/src/__tests__/conflict-policy.test.ts +76 -0
- package/src/__tests__/conflict-store.test.ts +14 -20
- package/src/__tests__/contacts-tools.test.ts +8 -61
- package/src/__tests__/contradiction-checker.test.ts +5 -1
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +9 -0
- package/src/__tests__/gateway-only-guard.test.ts +1 -0
- package/src/__tests__/gemini-image-service.test.ts +2 -2
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +5 -3
- package/src/__tests__/guardian-grant-minting.test.ts +6 -6
- package/src/__tests__/guardian-routing-invariants.test.ts +40 -15
- package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +4 -6
- package/src/__tests__/inbound-invite-redemption.test.ts +1 -1
- package/src/__tests__/integrations-cli.test.ts +3 -27
- package/src/__tests__/intent-routing.test.ts +3 -0
- package/src/__tests__/invite-redemption-service.test.ts +1 -1
- package/src/__tests__/{ingress-routes-http.test.ts → invite-routes-http.test.ts} +40 -320
- package/src/__tests__/ipc-snapshot.test.ts +4 -31
- package/src/__tests__/memory-lifecycle-e2e.test.ts +11 -10
- package/src/__tests__/nl-approval-parser.test.ts +305 -0
- package/src/__tests__/oauth-provider-profiles.test.ts +34 -0
- package/src/__tests__/provider-error-scenarios.test.ts +68 -0
- package/src/__tests__/registry.test.ts +0 -10
- package/src/__tests__/relay-server.test.ts +1 -1
- package/src/__tests__/retry-after-extraction.test.ts +111 -0
- package/src/__tests__/script-proxy-profile-template-fallback.test.ts +127 -0
- package/src/__tests__/script-proxy-session-runtime.test.ts +6 -1
- package/src/__tests__/session-agent-loop.test.ts +0 -2
- package/src/__tests__/session-conflict-gate.test.ts +243 -388
- package/src/__tests__/session-media-retry.test.ts +147 -0
- package/src/__tests__/session-profile-injection.test.ts +0 -2
- package/src/__tests__/session-runtime-assembly.test.ts +2 -3
- package/src/__tests__/session-skill-tools.test.ts +0 -49
- package/src/__tests__/session-workspace-cache-state.test.ts +0 -1
- package/src/__tests__/session-workspace-injection.test.ts +0 -1
- package/src/__tests__/session-workspace-tool-tracking.test.ts +0 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +9 -5
- package/src/__tests__/skill-feature-flags.test.ts +18 -12
- package/src/__tests__/skill-load-feature-flag.test.ts +4 -3
- package/src/__tests__/slack-block-formatting.test.ts +100 -0
- package/src/__tests__/slack-inbound-verification.test.ts +346 -0
- package/src/__tests__/slack-reaction-approvals.test.ts +77 -0
- package/src/__tests__/slack-skill.test.ts +3 -2
- package/src/__tests__/starter-task-flow.test.ts +0 -1
- package/src/__tests__/tool-grant-request-escalation.test.ts +2 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +2 -1
- package/src/__tests__/trusted-contact-verification.test.ts +3 -1
- package/src/__tests__/voice-invite-redemption.test.ts +1 -1
- package/src/amazon/client.ts +7 -24
- package/src/approvals/guardian-decision-primitive.ts +11 -7
- package/src/approvals/guardian-request-resolvers.ts +5 -3
- package/src/calls/relay-server.ts +44 -11
- package/src/channels/config.ts +1 -1
- package/src/cli/integrations.ts +10 -66
- package/src/config/bundled-skills/app-builder/SKILL.md +193 -1500
- package/src/config/bundled-skills/app-builder/TOOLS.json +70 -18
- package/src/config/bundled-skills/browser/TOOLS.json +59 -2
- package/src/config/bundled-skills/chatgpt-import/TOOLS.json +4 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +50 -2
- package/src/config/bundled-skills/contacts/SKILL.md +49 -53
- package/src/config/bundled-skills/contacts/TOOLS.json +26 -22
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +40 -62
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +17 -43
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +18 -57
- package/src/config/bundled-skills/document/TOOLS.json +8 -0
- package/src/config/bundled-skills/email-setup/SKILL.md +10 -7
- package/src/config/bundled-skills/followups/TOOLS.json +12 -0
- package/src/config/bundled-skills/google-calendar/TOOLS.json +124 -26
- package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +54 -21
- package/src/config/bundled-skills/image-studio/TOOLS.json +12 -2
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +14 -8
- package/src/config/bundled-skills/knowledge-graph/TOOLS.json +13 -3
- package/src/config/bundled-skills/media-processing/SKILL.md +1 -1
- package/src/config/bundled-skills/media-processing/TOOLS.json +28 -0
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +26 -6
- package/src/config/bundled-skills/messaging/TOOLS.json +228 -182
- package/src/config/bundled-skills/notifications/SKILL.md +3 -2
- package/src/config/bundled-skills/notifications/TOOLS.json +7 -13
- package/src/config/bundled-skills/phone-calls/TOOLS.json +13 -1
- package/src/config/bundled-skills/playbooks/TOOLS.json +16 -0
- package/src/config/bundled-skills/reminder/TOOLS.json +15 -2
- package/src/config/bundled-skills/schedule/SKILL.md +33 -15
- package/src/config/bundled-skills/schedule/TOOLS.json +17 -1
- package/src/config/bundled-skills/slack/SKILL.md +30 -1
- package/src/config/bundled-skills/slack/TOOLS.json +89 -2
- package/src/config/bundled-skills/slack/tools/slack-channel-permissions.ts +146 -0
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +120 -0
- package/src/config/bundled-skills/slack-app-setup/SKILL.md +200 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +22 -2
- package/src/config/bundled-skills/tasks/TOOLS.json +86 -14
- package/src/config/bundled-skills/transcribe/TOOLS.json +4 -0
- package/src/config/bundled-skills/watcher/TOOLS.json +20 -0
- package/src/config/bundled-tool-registry.ts +2 -5
- package/src/config/channel-permission-profiles.ts +155 -0
- package/src/config/env.ts +4 -1
- package/src/config/memory-schema.ts +0 -10
- package/src/config/system-prompt.ts +6 -0
- package/src/contacts/contact-store.ts +221 -56
- package/src/contacts/contacts-write.ts +14 -3
- package/src/contacts/types.ts +35 -4
- package/src/daemon/assistant-attachments.ts +23 -3
- package/src/daemon/guardian-verification-intent.ts +7 -4
- package/src/daemon/handlers/apps.ts +1 -2
- package/src/daemon/handlers/config-heartbeat.ts +1 -2
- package/src/daemon/handlers/config-inbox.ts +16 -134
- package/src/daemon/handlers/contacts.ts +2 -2
- package/src/daemon/handlers/guardian-actions.ts +21 -88
- package/src/daemon/handlers/sessions.ts +2 -2
- package/src/daemon/ipc-contract/apps.ts +0 -1
- package/src/daemon/ipc-contract/contacts.ts +2 -2
- package/src/daemon/ipc-contract/inbox.ts +7 -66
- package/src/daemon/ipc-contract/sessions.ts +1 -0
- package/src/daemon/ipc-contract/surfaces.ts +0 -1
- package/src/daemon/ipc-contract-inventory.json +2 -4
- package/src/daemon/lifecycle.ts +14 -2
- package/src/daemon/session-agent-loop-handlers.ts +9 -0
- package/src/daemon/session-agent-loop.ts +2 -45
- package/src/daemon/session-attachments.ts +5 -1
- package/src/daemon/session-conflict-gate.ts +21 -82
- package/src/daemon/session-error.ts +18 -0
- package/src/daemon/session-lifecycle.ts +4 -5
- package/src/daemon/session-media-retry.ts +15 -1
- package/src/daemon/session-memory.ts +7 -52
- package/src/daemon/session-process.ts +3 -1
- package/src/daemon/session-runtime-assembly.ts +18 -35
- package/src/daemon/session-surfaces.ts +0 -1
- package/src/daemon/session-tool-setup.ts +7 -4
- package/src/events/domain-events.ts +2 -1
- package/src/heartbeat/heartbeat-service.ts +5 -1
- package/src/home-base/prebuilt/seed.ts +0 -1
- package/src/influencer/client.ts +7 -24
- package/src/media/gemini-image-service.ts +48 -3
- package/src/memory/app-store.ts +0 -4
- package/src/memory/conflict-intent.ts +3 -6
- package/src/memory/conflict-policy.ts +34 -0
- package/src/memory/conflict-store.ts +10 -18
- package/src/memory/contradiction-checker.ts +2 -2
- package/src/memory/conversation-attention-store.ts +3 -1
- package/src/memory/db-init.ts +8 -0
- package/src/memory/job-handlers/conflict.ts +0 -7
- package/src/memory/migrations/133-assistant-contact-metadata.ts +21 -0
- package/src/memory/migrations/134-contacts-notes-column.ts +51 -0
- package/src/memory/migrations/135-backfill-contact-interaction-stats.ts +31 -0
- package/src/memory/migrations/index.ts +3 -0
- package/src/memory/schema.ts +12 -17
- package/src/memory/slack-thread-store.ts +187 -0
- package/src/messaging/index.ts +0 -1
- package/src/messaging/providers/slack/client.ts +84 -26
- package/src/messaging/providers/slack/types.ts +4 -0
- package/src/messaging/types.ts +0 -38
- package/src/notifications/adapters/slack.ts +90 -0
- package/src/notifications/destination-resolver.ts +42 -1
- package/src/notifications/emit-signal.ts +17 -1
- package/src/oauth/provider-profiles.ts +22 -0
- package/src/providers/anthropic/client.ts +3 -0
- package/src/providers/openai/client.ts +3 -0
- package/src/providers/retry.ts +9 -1
- package/src/runtime/actor-trust-resolver.ts +8 -0
- package/src/runtime/auth/require-bound-guardian.ts +44 -0
- package/src/runtime/auth/route-policy.ts +4 -8
- package/src/runtime/channel-approval-types.ts +18 -0
- package/src/runtime/channel-approvals.ts +8 -0
- package/src/runtime/channel-invite-transport.ts +1 -1
- package/src/runtime/channel-reply-delivery.ts +62 -3
- package/src/runtime/gateway-client.ts +36 -2
- package/src/runtime/gateway-internal-client.ts +86 -0
- package/src/runtime/guardian-action-service.ts +128 -0
- package/src/runtime/guardian-outbound-actions.ts +3 -3
- package/src/runtime/guardian-reply-router.ts +4 -4
- package/src/runtime/guardian-verification-templates.ts +16 -1
- package/src/runtime/http-server.ts +29 -46
- package/src/runtime/invite-redemption-service.ts +1 -1
- package/src/runtime/{ingress-service.ts → invite-service.ts} +5 -157
- package/src/runtime/nl-approval-parser.ts +138 -0
- package/src/runtime/routes/approval-routes.ts +1 -40
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +6 -3
- package/src/runtime/routes/channel-route-shared.ts +35 -1
- package/src/runtime/routes/contact-routes.ts +494 -47
- package/src/runtime/routes/conversation-routes.ts +2 -1
- package/src/runtime/routes/global-search-routes.ts +2 -2
- package/src/runtime/routes/guardian-action-routes.ts +19 -111
- package/src/runtime/routes/guardian-approval-interception.ts +78 -1
- package/src/runtime/routes/guardian-bootstrap-routes.ts +6 -1
- package/src/runtime/routes/inbound-message-handler.ts +40 -12
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +227 -1
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +108 -0
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +2 -1
- package/src/runtime/routes/{ingress-routes.ts → invite-routes.ts} +10 -110
- package/src/runtime/routes/migration-routes.ts +17 -17
- package/src/runtime/slack-block-formatting.ts +176 -0
- package/src/schedule/scheduler.ts +11 -2
- package/src/tools/apps/executors.ts +16 -15
- package/src/tools/calls/call-end.ts +1 -1
- package/src/tools/computer-use/definitions.ts +16 -0
- package/src/tools/credentials/vault.ts +86 -2
- package/src/tools/network/script-proxy/session-manager.ts +28 -3
- package/src/tools/permission-checker.ts +18 -0
- package/src/tools/terminal/shell.ts +15 -5
- package/src/tools/tool-approval-handler.ts +48 -4
- package/src/tools/types.ts +38 -1
- package/src/util/errors.ts +5 -1
- package/src/util/retry.ts +21 -0
- package/src/watcher/providers/slack.ts +33 -3
- package/src/workspace/git-service.ts +6 -4
- package/src/__tests__/get-weather.test.ts +0 -393
- package/src/__tests__/weather-skill-regression.test.ts +0 -276
- package/src/autonomy/autonomy-resolver.ts +0 -62
- package/src/autonomy/autonomy-store.ts +0 -138
- package/src/autonomy/disposition-mapper.ts +0 -31
- package/src/autonomy/index.ts +0 -11
- package/src/autonomy/types.ts +0 -43
- package/src/config/bundled-skills/weather/SKILL.md +0 -38
- package/src/config/bundled-skills/weather/TOOLS.json +0 -32
- package/src/config/bundled-skills/weather/icon.svg +0 -24
- package/src/config/bundled-skills/weather/tools/get-weather.ts +0 -12
- package/src/messaging/triage-engine.ts +0 -344
- package/src/tools/weather/service.ts +0 -712
- /package/src/memory/{ingress-invite-store.ts → invite-store.ts} +0 -0
package/ARCHITECTURE.md
CHANGED
|
@@ -433,31 +433,33 @@ External users who are not the guardian can gain access to the assistant through
|
|
|
433
433
|
|
|
434
434
|
**Notification signals:** The flow emits signals at each lifecycle transition via `emitNotificationSignal()`:
|
|
435
435
|
|
|
436
|
-
- `ingress.access_request` —
|
|
436
|
+
- `ingress.access_request` — unknown contact denied, guardian notified
|
|
437
437
|
- `ingress.trusted_contact.guardian_decision` — guardian approved or denied
|
|
438
438
|
- `ingress.trusted_contact.verification_sent` — code created and delivered
|
|
439
|
-
- `ingress.trusted_contact.activated` — requester verified,
|
|
439
|
+
- `ingress.trusted_contact.activated` — requester verified, contact active
|
|
440
440
|
- `ingress.trusted_contact.denied` — guardian explicitly denied
|
|
441
441
|
|
|
442
442
|
**HTTP API (for management):**
|
|
443
443
|
|
|
444
|
-
| Endpoint
|
|
445
|
-
|
|
|
446
|
-
| `/v1/
|
|
447
|
-
| `/v1/
|
|
448
|
-
| `/v1/
|
|
449
|
-
| `/v1/
|
|
444
|
+
| Endpoint | Method | Description |
|
|
445
|
+
| --------------------------- | ------ | ---------------------------------------------------------------- |
|
|
446
|
+
| `/v1/contacts` | GET | List contacts (filterable by role, search by query/channel/etc.) |
|
|
447
|
+
| `/v1/contacts` | POST | Create or update a contact |
|
|
448
|
+
| `/v1/contacts/:id` | GET | Get a contact by ID |
|
|
449
|
+
| `/v1/contacts/merge` | POST | Merge two contacts |
|
|
450
|
+
| `/v1/contacts/channels/:id` | PATCH | Update a contact channel's status/policy |
|
|
450
451
|
|
|
451
452
|
**Key source files:**
|
|
452
453
|
|
|
453
454
|
| File | Purpose |
|
|
454
455
|
| ------------------------------------------------------ | ----------------------------------------------------------------------------- |
|
|
455
|
-
| `src/runtime/routes/inbound-message-handler.ts` | Ingress ACL,
|
|
456
|
+
| `src/runtime/routes/inbound-message-handler.ts` | Ingress ACL, unknown-contact rejection, verification code interception |
|
|
456
457
|
| `src/runtime/routes/access-request-decision.ts` | Guardian decision → verification session creation |
|
|
457
458
|
| `src/runtime/routes/guardian-approval-interception.ts` | Routes guardian decisions (button + conversational) to access request handler |
|
|
458
459
|
| `src/runtime/channel-guardian-service.ts` | Verification challenge lifecycle, identity binding, rate limiting |
|
|
459
|
-
| `src/runtime/routes/
|
|
460
|
-
| `src/runtime/
|
|
460
|
+
| `src/runtime/routes/contact-routes.ts` | HTTP API handlers for contact and channel management |
|
|
461
|
+
| `src/runtime/routes/invite-routes.ts` | HTTP API handlers for invite management |
|
|
462
|
+
| `src/runtime/invite-service.ts` | Business logic for invite operations |
|
|
461
463
|
| `src/contacts/contact-store.ts` | Contact read queries — lookup, search, list, and channel operations |
|
|
462
464
|
| `src/memory/channel-guardian-store.ts` | Approval request and verification challenge persistence |
|
|
463
465
|
| `src/config/bundled-skills/contacts/SKILL.md` | Unified skill for contact management, access control, and invite links |
|
|
@@ -482,7 +484,7 @@ A complementary access-granting flow where the guardian proactively creates a sh
|
|
|
482
484
|
├─────────────────────────────────────────────────────────────┤
|
|
483
485
|
│ Core Redemption Engine (invite-redemption-service.ts) │
|
|
484
486
|
│ Channel-agnostic token validation, expiry, use-count, │
|
|
485
|
-
│ channel-match enforcement,
|
|
487
|
+
│ channel-match enforcement, contact activation/reactivation │
|
|
486
488
|
│ Returns: InviteRedemptionOutcome (discriminated union) │
|
|
487
489
|
│ Reply templates: invite-redemption-templates.ts │
|
|
488
490
|
└─────────────────────────────────────────────────────────────┘
|
|
@@ -496,12 +498,12 @@ A complementary access-granting flow where the guardian proactively creates a sh
|
|
|
496
498
|
4. Guardian shares the link with the invitee out-of-band.
|
|
497
499
|
5. Invitee clicks the link, opening Telegram which sends `/start iv_<token>` to the bot.
|
|
498
500
|
6. The gateway forwards the message to `/channels/inbound`. The inbound handler calls `getTransport('telegram').extractInboundToken()` to parse the `iv_` token.
|
|
499
|
-
7. The token is redeemed via `invite-redemption-service.ts`, which validates,
|
|
501
|
+
7. The token is redeemed via `invite-redemption-service.ts`, which validates, activates the contact, and returns a `redeemed` outcome.
|
|
500
502
|
8. A deterministic welcome message is delivered to the invitee (bypasses the LLM pipeline).
|
|
501
503
|
|
|
502
504
|
**Token prefix convention:** The `iv_` prefix distinguishes invite tokens from `gv_` (guardian verification) tokens. Both use the same Telegram `/start` deep-link mechanism but are routed to different handlers.
|
|
503
505
|
|
|
504
|
-
**Inbound intercept points:** Invite token extraction runs early in the inbound handler, before ACL denial, so valid invites short-circuit the
|
|
506
|
+
**Inbound intercept points:** Invite token extraction runs early in the inbound handler, before ACL denial, so valid invites short-circuit the contact check. Two intercept branches handle: (a) unknown contacts — the invite creates their first contact record; (b) inactive contacts (revoked/pending) — the invite reactivates them.
|
|
505
507
|
|
|
506
508
|
**Channel adapter status:**
|
|
507
509
|
|
|
@@ -518,8 +520,8 @@ Voice invites use a short numeric code (4-10 digits, default 6) instead of a URL
|
|
|
518
520
|
|
|
519
521
|
**Creation flow:**
|
|
520
522
|
|
|
521
|
-
1. Guardian creates a voice invite via `POST /v1/
|
|
522
|
-
2. `
|
|
523
|
+
1. Guardian creates a voice invite via `POST /v1/contacts/invites` with `sourceChannel: "voice"` and `expectedExternalUserId` (E.164 phone).
|
|
524
|
+
2. `invite-service.ts` generates a cryptographically random numeric code (`generateVoiceCode`), hashes it with SHA-256 (`hashVoiceCode`), and stores only the hash.
|
|
523
525
|
3. The one-time plaintext `voiceCode` is returned in the creation response. The raw token is NOT returned for voice invites — redemption uses the identity-bound code flow exclusively.
|
|
524
526
|
4. Guardian communicates the code to the invitee out-of-band.
|
|
525
527
|
|
|
@@ -528,7 +530,7 @@ Voice invites use a short numeric code (4-10 digits, default 6) instead of a URL
|
|
|
528
530
|
1. Unknown caller dials in. `relay-server.ts` resolves trust via `resolveActorTrust`. Caller is `unknown`, no pending guardian challenge.
|
|
529
531
|
2. The relay checks `findActiveVoiceInvites` for invites bound to the caller's phone number.
|
|
530
532
|
3. If active, non-expired invites exist, the relay enters the `invite_redemption_pending` state (reuses the `verification_pending` connection state) and prompts the caller with personalized copy: `Welcome <friend-name>. Please enter the 6-digit code that <guardian-name> provided you to verify your identity.`
|
|
531
|
-
4. `redeemVoiceInviteCode` validates: identity match, code hash match, expiry, use count. On success,
|
|
533
|
+
4. `redeemVoiceInviteCode` validates: identity match, code hash match, expiry, use count. On success, the contact is activated and the call transitions to the normal call flow.
|
|
532
534
|
5. On invalid/expired code, the caller hears deterministic failure copy: `Sorry, the code you provided is incorrect or has since expired. Please ask <guardian-name> for a new code. Goodbye.` and the call ends immediately.
|
|
533
535
|
|
|
534
536
|
**Security invariants:**
|
|
@@ -536,24 +538,24 @@ Voice invites use a short numeric code (4-10 digits, default 6) instead of a URL
|
|
|
536
538
|
- The plaintext voice code is returned exactly once at creation time and never stored.
|
|
537
539
|
- Voice invites are identity-bound: `expectedExternalUserId` must match the caller's E.164 number. An attacker with the code but the wrong phone number cannot redeem.
|
|
538
540
|
- Failure responses are intentionally generic (`invalid_or_expired`) to prevent oracle attacks.
|
|
539
|
-
- Blocked
|
|
541
|
+
- Blocked contacts cannot bypass the guardian's explicit block via invite redemption.
|
|
540
542
|
|
|
541
543
|
**Key source files:**
|
|
542
544
|
|
|
543
|
-
| File | Purpose
|
|
544
|
-
| --------------------------------------------------- |
|
|
545
|
-
| `src/runtime/invite-redemption-service.ts` | Core redemption engine — token validation, voice code redemption,
|
|
546
|
-
| `src/runtime/invite-redemption-templates.ts` | Deterministic reply templates for each redemption outcome
|
|
547
|
-
| `src/runtime/channel-invite-transport.ts` | Transport adapter registry with `buildShareableInvite` / `extractInboundToken` interface
|
|
548
|
-
| `src/runtime/channel-invite-transports/telegram.ts` | Telegram adapter — `t.me/<bot>?start=iv_<token>` deep links, `/start iv_<token>` extraction
|
|
549
|
-
| `src/runtime/channel-invite-transports/voice.ts` | Voice transport adapter — code-based redemption metadata
|
|
550
|
-
| `src/daemon/guardian-invite-intent.ts` | Intent detection — routes create/list/revoke requests into the contacts skill
|
|
551
|
-
| `src/runtime/
|
|
552
|
-
| `src/runtime/routes/
|
|
553
|
-
| `src/runtime/routes/inbound-message-handler.ts` | Invite token intercept in the inbound flow (
|
|
554
|
-
| `src/calls/relay-server.ts` | Voice relay state machine — `invite_redemption_pending` subflow (always-on canonical behavior)
|
|
555
|
-
| `src/util/voice-code.ts` | Cryptographic voice code generation and SHA-256 hashing
|
|
556
|
-
| `src/memory/
|
|
545
|
+
| File | Purpose |
|
|
546
|
+
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
547
|
+
| `src/runtime/invite-redemption-service.ts` | Core redemption engine — token validation, voice code redemption, contact activation, discriminated-union outcomes |
|
|
548
|
+
| `src/runtime/invite-redemption-templates.ts` | Deterministic reply templates for each redemption outcome |
|
|
549
|
+
| `src/runtime/channel-invite-transport.ts` | Transport adapter registry with `buildShareableInvite` / `extractInboundToken` interface |
|
|
550
|
+
| `src/runtime/channel-invite-transports/telegram.ts` | Telegram adapter — `t.me/<bot>?start=iv_<token>` deep links, `/start iv_<token>` extraction |
|
|
551
|
+
| `src/runtime/channel-invite-transports/voice.ts` | Voice transport adapter — code-based redemption metadata |
|
|
552
|
+
| `src/daemon/guardian-invite-intent.ts` | Intent detection — routes create/list/revoke requests into the contacts skill |
|
|
553
|
+
| `src/runtime/invite-service.ts` | Shared business logic for invite operations (used by both HTTP routes and IPC) |
|
|
554
|
+
| `src/runtime/routes/invite-routes.ts` | HTTP API handlers for invite management including voice invite creation and redemption |
|
|
555
|
+
| `src/runtime/routes/inbound-message-handler.ts` | Invite token intercept in the inbound flow (unknown-contact and inactive-contact branches) |
|
|
556
|
+
| `src/calls/relay-server.ts` | Voice relay state machine — `invite_redemption_pending` subflow (always-on canonical behavior) |
|
|
557
|
+
| `src/util/voice-code.ts` | Cryptographic voice code generation and SHA-256 hashing |
|
|
558
|
+
| `src/memory/invite-store.ts` | Invite persistence including `findActiveVoiceInvites` for identity-bound lookup |
|
|
557
559
|
|
|
558
560
|
### Voice Inbound Security Model (Canonical)
|
|
559
561
|
|
|
@@ -595,7 +597,7 @@ When no invite exists and no pending guardian challenge is active, the relay ent
|
|
|
595
597
|
2. On name capture, `notifyGuardianOfAccessRequest` creates a canonical guardian request (`kind: 'access_request'`) and notifies the guardian via the notification pipeline.
|
|
596
598
|
3. The relay transitions to `awaiting_guardian_decision` and plays hold music/messaging while polling the canonical request status.
|
|
597
599
|
4. The guardian approves or denies via any channel (Telegram, SMS, desktop). All decisions route through `applyCanonicalGuardianDecision`, which dispatches to the `access_request` resolver in `guardian-request-resolvers.ts`.
|
|
598
|
-
5. On approval: the resolver directly activates the caller as a trusted contact (
|
|
600
|
+
5. On approval: the resolver directly activates the caller as a trusted contact (sets channel `status: 'active'`, `policy: 'allow'`), the poll detects the approved status, the relay transitions to the normal call flow with the caller's guardian context updated.
|
|
599
601
|
6. On denial or timeout: the caller hears a denial message and the call ends.
|
|
600
602
|
|
|
601
603
|
**Path 3: Inbound guardian verification (pending challenge)**
|
|
@@ -888,7 +890,7 @@ graph LR
|
|
|
888
890
|
C12["tool_permission_simulate<br/>toolName, input, workingDir?,<br/>isInteractive?, forcePromptSideEffects?,<br/>executionTarget?"]
|
|
889
891
|
C13["conversation_search<br/>query, limit?,<br/>maxMessagesPerConversation?"]
|
|
890
892
|
C14["ingress_invite<br/>create / list / revoke / redeem"]
|
|
891
|
-
C15["
|
|
893
|
+
C15["contacts<br/>list / get / update_channel"]
|
|
892
894
|
end
|
|
893
895
|
|
|
894
896
|
SOCKET["Unix Socket<br/>~/.vellum/vellum.sock<br/>───────────────<br/>Newline-delimited JSON<br/>Max 96MB per message<br/>Ping/pong every 30s<br/>Auto-reconnect<br/>1s → 30s backoff"]
|
|
@@ -920,7 +922,7 @@ graph LR
|
|
|
920
922
|
S22["tool_permission_simulate_response<br/>decision, riskLevel, reason?,<br/>promptPayload?, matchedRuleId?"]
|
|
921
923
|
S23["conversation_search_response<br/>query, results[]: conversationId,<br/>title, updatedAt, matchingMessages[]"]
|
|
922
924
|
S24["ingress_invite_response<br/>invite / invites"]
|
|
923
|
-
S25["
|
|
925
|
+
S25["contacts_response<br/>contact / contacts"]
|
|
924
926
|
end
|
|
925
927
|
|
|
926
928
|
C0 --> SOCKET
|
|
@@ -2204,8 +2206,8 @@ Connected channels are resolved at signal emission time: vellum is always includ
|
|
|
2204
2206
|
| Guardian bindings | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; revoked bindings retained |
|
|
2205
2207
|
| Guardian verification challenges | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; consumed/expired challenges retained |
|
|
2206
2208
|
| Guardian approval requests | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; decision outcome retained |
|
|
2207
|
-
|
|
|
2208
|
-
|
|
|
2209
|
+
| Contact invites | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; token hash stored, raw token never persisted |
|
|
2210
|
+
| Contacts & channels | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; revoked/blocked contacts retained |
|
|
2209
2211
|
| Notification events | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; deduplicated by dedupeKey |
|
|
2210
2212
|
| Notification decisions | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; FK to notification_events |
|
|
2211
2213
|
| Notification deliveries | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; FK to notification_decisions |
|
package/Dockerfile
CHANGED
|
@@ -16,16 +16,21 @@ RUN apt-get update && apt-get install -y \
|
|
|
16
16
|
RUN curl -fsSL https://bun.sh/install | bash
|
|
17
17
|
ENV PATH="/root/.bun/bin:${PATH}"
|
|
18
18
|
|
|
19
|
-
#
|
|
20
|
-
COPY package.json bun.lock ./
|
|
19
|
+
# Install assistant and CLI dependencies first for cache reuse
|
|
20
|
+
COPY assistant/package.json assistant/bun.lock ./assistant/
|
|
21
|
+
RUN cd /app/assistant && bun install --frozen-lockfile
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
RUN bun install --frozen-lockfile
|
|
23
|
+
COPY cli/package.json cli/bun.lock ./cli/
|
|
24
|
+
RUN cd /app/cli && bun install --frozen-lockfile
|
|
25
|
+
|
|
26
|
+
# Copy source
|
|
27
|
+
COPY assistant ./assistant
|
|
28
|
+
COPY cli ./cli
|
|
24
29
|
|
|
25
30
|
# Final stage
|
|
26
31
|
FROM debian:trixie@sha256:3615a749858a1cba49b408fb49c37093db813321355a9ab7c1f9f4836341e9db AS runner
|
|
27
32
|
|
|
28
|
-
WORKDIR /app
|
|
33
|
+
WORKDIR /app/assistant
|
|
29
34
|
|
|
30
35
|
# Install runtime dependencies for Playwright and tree-sitter
|
|
31
36
|
RUN apt-get update && apt-get install -y \
|
|
@@ -47,6 +52,10 @@ RUN apt-get update && apt-get install -y \
|
|
|
47
52
|
COPY --from=builder /root/.bun/bin/bun /usr/local/bin/bun
|
|
48
53
|
RUN ln -sf /usr/local/bin/bun /usr/local/bin/bunx
|
|
49
54
|
|
|
55
|
+
# Install a vellum CLI launcher backed by the bundled local cli package
|
|
56
|
+
RUN printf '#!/usr/bin/env sh\nexec bun run /app/cli/src/index.ts "$@"\n' > /usr/local/bin/vellum && \
|
|
57
|
+
chmod +x /usr/local/bin/vellum
|
|
58
|
+
|
|
50
59
|
# Create non-root user that also has sudo access so it can like install stuff
|
|
51
60
|
RUN groupadd --system --gid 1001 assistant && \
|
|
52
61
|
useradd --system --uid 1001 --gid assistant --create-home --shell /bin/bash assistant && \
|
|
@@ -95,8 +104,5 @@ ENV IS_CONTAINERIZED=true
|
|
|
95
104
|
# Copy from builder
|
|
96
105
|
COPY --from=builder /app /app
|
|
97
106
|
|
|
98
|
-
# Copy source
|
|
99
|
-
COPY . .
|
|
100
|
-
|
|
101
107
|
# Run the daemon + http server
|
|
102
108
|
CMD ["bun", "run", "src/daemon/main.ts"]
|
package/README.md
CHANGED
|
@@ -337,7 +337,7 @@ Guardian verification and ingress contact management are complementary but indep
|
|
|
337
337
|
| `src/runtime/trust-context-resolver.ts` | Actor role classification: guardian / non-guardian / unverified_channel |
|
|
338
338
|
| `src/runtime/routes/inbound-message-handler.ts` | Ingress ACL enforcement, verification-code intercept, escalation creation |
|
|
339
339
|
| `src/contacts/contact-store.ts` | Contact + channel CRUD: `findContactChannel`, `upsertContact`, `updateChannelStatus`, `searchContacts` |
|
|
340
|
-
| `src/memory/
|
|
340
|
+
| `src/memory/invite-store.ts` | Invite lifecycle: `createInvite`, `redeemInvite` (atomically creates member record) |
|
|
341
341
|
| `src/memory/channel-guardian-store.ts` | Persistence for guardian bindings, verification challenges, and approval requests |
|
|
342
342
|
| `src/runtime/guardian-outbound-actions.ts` | Shared business logic for outbound verification (start/resend/cancel) |
|
|
343
343
|
| `src/runtime/routes/integration-routes.ts` | HTTP route handlers for outbound guardian verification endpoints |
|
|
@@ -432,7 +432,7 @@ Redemption auto-creates a **member** record with an access policy:
|
|
|
432
432
|
- **`deny`** — Messages are rejected with a refusal notice.
|
|
433
433
|
- **`escalate`** — Messages are held for guardian (owner) approval before processing.
|
|
434
434
|
|
|
435
|
-
Non-members (senders with no invite redemption) are denied by default.
|
|
435
|
+
Non-members (senders with no invite redemption) are denied by default. Contacts can be listed, updated, revoked, or blocked via the HTTP API (`/v1/contacts` and `/v1/contacts/channels`).
|
|
436
436
|
|
|
437
437
|
### Escalation Flow
|
|
438
438
|
|
|
@@ -447,15 +447,14 @@ If no guardian binding exists, escalation fails closed — the message is denied
|
|
|
447
447
|
| Message Type | Actions | Description |
|
|
448
448
|
| ---------------- | ---------------------------- | ------------------------------------------------------------------------ |
|
|
449
449
|
| `ingress_invite` | create, list, revoke, redeem | Manage invite tokens (SHA-256 hashed, raw token returned once on create) |
|
|
450
|
-
| `ingress_member` | list, upsert, revoke, block | Manage member records and access policies |
|
|
451
450
|
|
|
452
451
|
### Key Modules
|
|
453
452
|
|
|
454
453
|
| File | Purpose |
|
|
455
454
|
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
456
|
-
| `src/memory/
|
|
455
|
+
| `src/memory/invite-store.ts` | CRUD for invite tokens with SHA-256 hashing and expiry |
|
|
457
456
|
| `src/contacts/contact-store.ts` | Contact + channel CRUD with policy enforcement |
|
|
458
|
-
| `src/daemon/handlers/config-inbox.ts` | IPC handlers for
|
|
457
|
+
| `src/daemon/handlers/config-inbox.ts` | IPC handlers for invite contract |
|
|
459
458
|
| `src/daemon/ipc-contract/inbox.ts` | TypeScript type definitions for ingress IPC messages |
|
|
460
459
|
| `src/runtime/routes/channel-routes.ts` | ACL enforcement point — member lookup, policy check, escalation creation |
|
|
461
460
|
| `src/runtime/invite-redemption-service.ts` | Core redemption engine — token validation, member creation, discriminated-union outcomes |
|
|
@@ -463,7 +462,7 @@ If no guardian binding exists, escalation fails closed — the message is denied
|
|
|
463
462
|
| `src/runtime/channel-invite-transport.ts` | Transport adapter registry — `buildShareableInvite` / `extractInboundToken` per channel |
|
|
464
463
|
| `src/runtime/channel-invite-transports/telegram.ts` | Telegram adapter — builds `t.me/<bot>?start=iv_<token>` deep links, extracts `iv_` tokens from `/start` commands |
|
|
465
464
|
| `src/daemon/guardian-invite-intent.ts` | Intent detection — routes guardian invite management requests into the `contacts` skill |
|
|
466
|
-
| `src/runtime/
|
|
465
|
+
| `src/runtime/invite-service.ts` | Shared business logic for invite and contact operations (HTTP + IPC) |
|
|
467
466
|
|
|
468
467
|
## Database
|
|
469
468
|
|
|
@@ -482,7 +481,7 @@ bun run db:push # Apply migrations
|
|
|
482
481
|
|
|
483
482
|
```bash
|
|
484
483
|
# Build production image
|
|
485
|
-
docker build -t vellum-assistant:local
|
|
484
|
+
docker build -f assistant/Dockerfile -t vellum-assistant:local .
|
|
486
485
|
|
|
487
486
|
# Run
|
|
488
487
|
docker run --rm -p 3001:3001 \
|
|
@@ -490,7 +489,7 @@ docker run --rm -p 3001:3001 \
|
|
|
490
489
|
vellum-assistant:local
|
|
491
490
|
```
|
|
492
491
|
|
|
493
|
-
The image
|
|
492
|
+
The image exposes port `3001` and bundles the `vellum` CLI binary.
|
|
494
493
|
|
|
495
494
|
## Troubleshooting
|
|
496
495
|
|
|
@@ -41,7 +41,7 @@ graph TB
|
|
|
41
41
|
|
|
42
42
|
subgraph "Read Path (Memory Recall)"
|
|
43
43
|
QUERY["Recall Query Builder<br/>User request + compacted context summary"]
|
|
44
|
-
CONFLICT_GATE["Soft Conflict Gate<br/>dismiss non-actionable conflicts (kind + statement policy)<br/>
|
|
44
|
+
CONFLICT_GATE["Soft Conflict Gate<br/>dismiss non-actionable conflicts (kind + statement + provenance policy)<br/>attempt internal resolution from user turn<br/>relevance-based; never produces user-facing prompts"]
|
|
45
45
|
PROFILE_BUILD["Dynamic Profile Compiler<br/>active trusted profile memories<br/>user_confirmed > user_reported > assistant_inferred"]
|
|
46
46
|
PROFILE_INJECT["Inject profile context block<br/>into runtime user tail<br/>(strict token cap)"]
|
|
47
47
|
BUDGET["Dynamic Recall Budget<br/>computeRecallBudget()<br/>from prompt headroom"]
|
|
@@ -158,28 +158,26 @@ The key distinction: normal compaction is a cost-optimized background process th
|
|
|
158
158
|
|
|
159
159
|
### Memory Retrieval Config Knobs (Defaults)
|
|
160
160
|
|
|
161
|
-
| Config key | Default | Purpose
|
|
162
|
-
| --------------------------------------------------------- | ----------------------------------------------------------------: |
|
|
163
|
-
| `memory.retrieval.dynamicBudget.enabled` | `true` | Toggle per-turn recall budget calculation from live prompt headroom.
|
|
164
|
-
| `memory.retrieval.dynamicBudget.minInjectTokens` | `1200` | Lower clamp for computed recall injection budget.
|
|
165
|
-
| `memory.retrieval.dynamicBudget.maxInjectTokens` | `10000` | Upper clamp for computed recall injection budget.
|
|
166
|
-
| `memory.retrieval.dynamicBudget.targetHeadroomTokens` | `10000` | Reserved headroom to keep free for response generation/tool traces.
|
|
167
|
-
| `memory.entity.extractRelations.enabled` | `true` | Enable relation edge extraction and persistence in `memory_entity_relations`.
|
|
168
|
-
| `memory.entity.extractRelations.backfillBatchSize` | `200` | Batch size for checkpointed `backfill_entity_relations` jobs.
|
|
169
|
-
| `memory.entity.relationRetrieval.enabled` | `true` | Enable one-hop relation expansion from matched seed entities at recall time.
|
|
170
|
-
| `memory.entity.relationRetrieval.maxSeedEntities` | `8` | Maximum matched seed entities from the query.
|
|
171
|
-
| `memory.entity.relationRetrieval.maxNeighborEntities` | `20` | Maximum unique neighbor entities expanded from relation edges.
|
|
172
|
-
| `memory.entity.relationRetrieval.maxEdges` | `40` | Maximum relation edges traversed during expansion.
|
|
173
|
-
| `memory.entity.relationRetrieval.neighborScoreMultiplier` | `0.7` | Downweight multiplier for relation-expanded candidates vs direct entity hits.
|
|
174
|
-
| `memory.conflicts.enabled` | `true` | Enable soft conflict gate for unresolved `memory_item_conflicts`.
|
|
175
|
-
| `memory.conflicts.
|
|
176
|
-
| `memory.conflicts.
|
|
177
|
-
| `memory.conflicts.
|
|
178
|
-
| `memory.conflicts.
|
|
179
|
-
| `memory.
|
|
180
|
-
| `memory.
|
|
181
|
-
| `memory.profile.enabled` | `true` | Enable dynamic profile compilation from active trusted profile/preference/constraint/instruction memories. |
|
|
182
|
-
| `memory.profile.maxInjectTokens` | `800` | Hard token cap enforced by `ProfileCompiler` when generating the runtime profile block. |
|
|
161
|
+
| Config key | Default | Purpose |
|
|
162
|
+
| --------------------------------------------------------- | ----------------------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------ |
|
|
163
|
+
| `memory.retrieval.dynamicBudget.enabled` | `true` | Toggle per-turn recall budget calculation from live prompt headroom. |
|
|
164
|
+
| `memory.retrieval.dynamicBudget.minInjectTokens` | `1200` | Lower clamp for computed recall injection budget. |
|
|
165
|
+
| `memory.retrieval.dynamicBudget.maxInjectTokens` | `10000` | Upper clamp for computed recall injection budget. |
|
|
166
|
+
| `memory.retrieval.dynamicBudget.targetHeadroomTokens` | `10000` | Reserved headroom to keep free for response generation/tool traces. |
|
|
167
|
+
| `memory.entity.extractRelations.enabled` | `true` | Enable relation edge extraction and persistence in `memory_entity_relations`. |
|
|
168
|
+
| `memory.entity.extractRelations.backfillBatchSize` | `200` | Batch size for checkpointed `backfill_entity_relations` jobs. |
|
|
169
|
+
| `memory.entity.relationRetrieval.enabled` | `true` | Enable one-hop relation expansion from matched seed entities at recall time. |
|
|
170
|
+
| `memory.entity.relationRetrieval.maxSeedEntities` | `8` | Maximum matched seed entities from the query. |
|
|
171
|
+
| `memory.entity.relationRetrieval.maxNeighborEntities` | `20` | Maximum unique neighbor entities expanded from relation edges. |
|
|
172
|
+
| `memory.entity.relationRetrieval.maxEdges` | `40` | Maximum relation edges traversed during expansion. |
|
|
173
|
+
| `memory.entity.relationRetrieval.neighborScoreMultiplier` | `0.7` | Downweight multiplier for relation-expanded candidates vs direct entity hits. |
|
|
174
|
+
| `memory.conflicts.enabled` | `true` | Enable soft conflict gate for unresolved `memory_item_conflicts`. |
|
|
175
|
+
| `memory.conflicts.resolverLlmTimeoutMs` | `12000` | Timeout bound for clarification resolver LLM fallback. |
|
|
176
|
+
| `memory.conflicts.relevanceThreshold` | `0.3` | Similarity threshold for deciding whether a pending conflict is relevant to the current request. |
|
|
177
|
+
| `memory.conflicts.gateMode` | `'soft'` | Conflict gate strategy. Currently only `'soft'` is supported (resolves conflicts internally without user prompts). |
|
|
178
|
+
| `memory.conflicts.conflictableKinds` | `['preference', 'profile', 'constraint', 'instruction', 'style']` | Memory item kinds eligible for conflict detection. Items with kinds outside this list are auto-dismissed. |
|
|
179
|
+
| `memory.profile.enabled` | `true` | Enable dynamic profile compilation from active trusted profile/preference/constraint/instruction memories. |
|
|
180
|
+
| `memory.profile.maxInjectTokens` | `800` | Hard token cap enforced by `ProfileCompiler` when generating the runtime profile block. |
|
|
183
181
|
|
|
184
182
|
### Memory Recall Debugging Playbook
|
|
185
183
|
|
|
@@ -211,7 +209,7 @@ The key distinction: normal compaction is a cost-optimized background process th
|
|
|
211
209
|
stateDiagram-v2
|
|
212
210
|
[*] --> ActiveItems : extract_items/check_contradictions
|
|
213
211
|
ActiveItems --> PendingConflict : ambiguous_contradiction\n(candidate -> pending_clarification)
|
|
214
|
-
PendingConflict --> PendingConflict :
|
|
212
|
+
PendingConflict --> PendingConflict : internal evaluation\n(relevance check, no user prompt)
|
|
215
213
|
PendingConflict --> Dismissed : non-actionable\n(kind policy + transient statement filter)
|
|
216
214
|
PendingConflict --> ResolvedKeepExisting : clarification resolver\n+ applyConflictResolution
|
|
217
215
|
PendingConflict --> ResolvedKeepCandidate : clarification resolver\n+ applyConflictResolution
|
|
@@ -224,6 +222,10 @@ stateDiagram-v2
|
|
|
224
222
|
SupersededItems --> CleanupItems : cleanup_stale_superseded_items
|
|
225
223
|
```
|
|
226
224
|
|
|
225
|
+
### Internal-Only Conflict Handling
|
|
226
|
+
|
|
227
|
+
Memory conflict resolution is entirely internal and non-interruptive. The conflict gate evaluates pending conflicts on each turn, dismisses non-actionable ones (based on kind policy, statement eligibility, coherence, and provenance), and attempts resolution when user input looks like a natural clarification. At no point does the conflict system produce user-facing clarification prompts, inject conflict instructions into the assistant's response, or block the user's request. The user is never aware that a conflict exists; the runtime response path always continues answering the user's actual request. This invariant is enforced across the conflict gate (`session-conflict-gate.ts`), session memory (`session-memory.ts`), session agent loop (`session-agent-loop.ts`), and runtime assembly (`session-runtime-assembly.ts`).
|
|
228
|
+
|
|
227
229
|
Runtime profile flow (per turn):
|
|
228
230
|
|
|
229
231
|
1. `ProfileCompiler` builds a trusted profile block from active `profile` / `preference` / `constraint` / `instruction` items under strict token cap.
|
|
@@ -238,7 +240,7 @@ Two trust gates enforce trust-class-based access control over the memory pipelin
|
|
|
238
240
|
|
|
239
241
|
- **Write gate** (`indexer.ts`): The `extract_items` and `resolve_conflicts` jobs only run for messages from trusted actors (guardian or undefined provenance). Messages from untrusted actors (`trusted_contact`, `unknown`) are still segmented and embedded — so they appear in conversation context — but no profile extraction or conflict resolution is triggered. This prevents untrusted channels from injecting or mutating long-term memory items.
|
|
240
242
|
|
|
241
|
-
- **Read gate** (`session-memory.ts`): When the current session's actor is untrusted, the memory recall pipeline returns a no-op context — no recall injection, no dynamic profile, no conflict
|
|
243
|
+
- **Read gate** (`session-memory.ts`): When the current session's actor is untrusted, the memory recall pipeline returns a no-op context — no recall injection, no dynamic profile, no conflict resolution. This ensures untrusted actors cannot surface or exploit previously extracted memory.
|
|
242
244
|
|
|
243
245
|
Trust policy is **cross-channel and trust-class-based**: decisions use `trustContext.trustClass`, not the channel string. Desktop/IPC sessions default to `trustClass: 'guardian'`. External channels (Telegram, SMS, WhatsApp, voice) provide explicit trust context via the resolver. Messages without provenance metadata are treated as trusted (guardian); all new messages carry provenance.
|
|
244
246
|
|
|
@@ -381,7 +383,7 @@ graph TB
|
|
|
381
383
|
- **Prepend, not append**: The workspace block is prepended to the user message content so that Anthropic cache breakpoints continue to land on the trailing user text block, preserving prompt cache efficiency.
|
|
382
384
|
- **Runtime-only**: The injected `<workspace_top_level>` block is stripped from `this.messages` after the agent loop completes. It never persists in conversation history or the database.
|
|
383
385
|
- **Dirty-refresh**: The scanner runs once on the first turn, then only re-runs after a successful mutation tool (`file_edit`, `file_write`, `bash`). Failed tool results do not trigger a refresh.
|
|
384
|
-
- **Injection ordering**: Workspace context is injected after other runtime injections (
|
|
386
|
+
- **Injection ordering**: Workspace context is injected after other runtime injections (active surface, etc.) via `applyRuntimeInjections`, but because it is **prepended** to content blocks, it appears first in the final message.
|
|
385
387
|
|
|
386
388
|
### Cache compatibility
|
|
387
389
|
|
|
@@ -506,7 +508,6 @@ graph TB
|
|
|
506
508
|
10. **Provider-aware commit message generation (optional)**: When `workspaceGit.commitMessageLLM.enabled` is `true`, turn-boundary commits attempt to generate a descriptive commit message using the configured LLM provider before falling back to deterministic messages. The feature ships disabled by default and is designed to never degrade turn completion guarantees.
|
|
507
509
|
|
|
508
510
|
**Commit message LLM fallback chain**: The generator runs a sequence of pre-flight checks before calling the LLM. Each check that fails produces a machine-readable `llmFallbackReason` in the structured log output and immediately returns a deterministic message. The checks, in order:
|
|
509
|
-
|
|
510
511
|
1. `disabled` — `commitMessageLLM.enabled` is `false` or `useConfiguredProvider` is `false`
|
|
511
512
|
2. `missing_provider_api_key` — the configured provider's API key is not set in `config.apiKeys` (skipped for keyless providers like Ollama that run without an API key)
|
|
512
513
|
3. `breaker_open` — the generator's internal circuit breaker is open after consecutive LLM failures (exponential backoff)
|
|
@@ -516,11 +517,9 @@ graph TB
|
|
|
516
517
|
7. `timeout` — the LLM call exceeded `timeoutMs` (AbortController fires)
|
|
517
518
|
8. `provider_error` — the provider threw an exception during the LLM call
|
|
518
519
|
9. `invalid_output` — the LLM returned empty text, the literal string "FALLBACK", or total output > 500 chars
|
|
519
|
-
|
|
520
520
|
- **Subject line capping**: If the LLM subject line exceeds 72 chars it is deterministically truncated to 72 chars. This is NOT treated as a failure (no breaker penalty, no deterministic fallback).
|
|
521
521
|
|
|
522
522
|
**Fast model resolution**: The LLM call uses a small/fast model to minimize latency and cost. The model is resolved **before** any provider call as a pre-flight check:
|
|
523
|
-
|
|
524
523
|
- If `commitMessageLLM.providerFastModelOverrides[provider]` is set, that model is used.
|
|
525
524
|
- Otherwise, a built-in default is used: `anthropic` -> `claude-haiku-4-5-20251001`, `openai` -> `gpt-4o-mini`, `gemini` -> `gemini-2.0-flash`.
|
|
526
525
|
- If the configured provider has no override and no built-in default (e.g., `ollama`, `fireworks`, `openrouter`), the generator returns a deterministic fallback with reason `missing_fast_model` and the provider is never called. To enable LLM commit messages for such providers, set `providerFastModelOverrides[provider]` to the desired model.
|