@vellumai/assistant 0.4.49 → 0.4.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +24 -33
- package/README.md +3 -3
- package/docs/architecture/integrations.md +2 -2
- package/docs/architecture/keychain-broker.md +6 -6
- package/docs/architecture/memory.md +180 -119
- package/knip.json +32 -0
- package/package.json +3 -2
- package/src/__tests__/agent-loop.test.ts +3 -1
- package/src/__tests__/anthropic-provider.test.ts +114 -23
- package/src/__tests__/approval-cascade.test.ts +1 -15
- package/src/__tests__/approval-routes-http.test.ts +2 -0
- package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
- package/src/__tests__/btw-routes.test.ts +61 -5
- package/src/__tests__/canonical-guardian-store.test.ts +95 -0
- package/src/__tests__/checker.test.ts +13 -0
- package/src/__tests__/config-schema.test.ts +1 -68
- package/src/__tests__/config-watcher.test.ts +8 -0
- package/src/__tests__/context-memory-e2e.test.ts +11 -100
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +8 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/credential-security-e2e.test.ts +1 -0
- package/src/__tests__/credential-security-invariants.test.ts +8 -7
- package/src/__tests__/credential-vault-unit.test.ts +23 -18
- package/src/__tests__/credential-vault.test.ts +30 -18
- package/src/__tests__/credentials-cli.test.ts +257 -82
- package/src/__tests__/cu-unified-flow.test.ts +532 -0
- package/src/__tests__/date-context.test.ts +93 -77
- package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
- package/src/__tests__/guardian-routing-invariants.test.ts +93 -0
- package/src/__tests__/history-repair.test.ts +245 -0
- package/src/__tests__/host-cu-proxy.test.ts +165 -3
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +36 -7
- package/src/__tests__/integration-status.test.ts +31 -30
- package/src/__tests__/invite-redemption-service.test.ts +166 -13
- package/src/__tests__/invite-routes-http.test.ts +166 -5
- package/src/__tests__/keychain-broker-client.test.ts +4 -4
- package/src/__tests__/list-messages-attachments.test.ts +193 -0
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
- package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
- package/src/__tests__/memory-recall-quality.test.ts +244 -407
- package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
- package/src/__tests__/memory-regressions.test.ts +477 -2841
- package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
- package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
- package/src/__tests__/mime-builder.test.ts +28 -0
- package/src/__tests__/native-web-search.test.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +824 -31
- package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
- package/src/__tests__/oauth-store.test.ts +363 -17
- package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
- package/src/__tests__/registry.test.ts +0 -1
- package/src/__tests__/relay-server.test.ts +55 -1
- package/src/__tests__/schedule-tools.test.ts +32 -0
- package/src/__tests__/script-proxy-certs.test.ts +1 -1
- package/src/__tests__/secret-onetime-send.test.ts +1 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +183 -0
- package/src/__tests__/secure-keys.test.ts +78 -18
- package/src/__tests__/send-endpoint-busy.test.ts +3 -0
- package/src/__tests__/server-history-render.test.ts +2 -2
- package/src/__tests__/session-abort-tool-results.test.ts +1 -14
- package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
- package/src/__tests__/session-agent-loop.test.ts +19 -15
- package/src/__tests__/session-confirmation-signals.test.ts +1 -15
- package/src/__tests__/session-error.test.ts +124 -2
- package/src/__tests__/session-history-web-search.test.ts +918 -0
- package/src/__tests__/session-pre-run-repair.test.ts +1 -14
- package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
- package/src/__tests__/session-queue.test.ts +37 -27
- package/src/__tests__/session-runtime-assembly.test.ts +54 -0
- package/src/__tests__/session-slash-known.test.ts +1 -15
- package/src/__tests__/session-slash-queue.test.ts +1 -15
- package/src/__tests__/session-slash-unknown.test.ts +1 -15
- package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
- package/src/__tests__/session-workspace-injection.test.ts +3 -37
- package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
- package/src/__tests__/skills-install-extract.test.ts +93 -0
- package/src/__tests__/skills.test.ts +2 -2
- package/src/__tests__/skillssh-registry.test.ts +451 -0
- package/src/__tests__/slack-channel-config.test.ts +10 -8
- package/src/__tests__/trust-store.test.ts +15 -0
- package/src/__tests__/twilio-config.test.ts +11 -10
- package/src/__tests__/twilio-provider.test.ts +9 -4
- package/src/__tests__/voice-invite-redemption.test.ts +85 -5
- package/src/agent/ax-tree-compaction.test.ts +51 -0
- package/src/agent/loop.ts +39 -12
- package/src/approvals/AGENTS.md +1 -1
- package/src/approvals/guardian-request-resolvers.ts +14 -2
- package/src/bundler/compiler-tools.ts +66 -2
- package/src/calls/call-domain.ts +134 -3
- package/src/calls/call-store.ts +6 -0
- package/src/calls/relay-server.ts +44 -6
- package/src/calls/relay-setup-router.ts +17 -1
- package/src/calls/twilio-config.ts +5 -4
- package/src/calls/twilio-provider.ts +14 -9
- package/src/calls/twilio-rest.ts +10 -7
- package/src/calls/types.ts +3 -1
- package/src/cli/commands/config.ts +14 -9
- package/src/cli/commands/contacts.ts +3 -0
- package/src/cli/commands/credentials.ts +170 -174
- package/src/cli/commands/doctor.ts +11 -8
- package/src/cli/commands/keys.ts +9 -9
- package/src/cli/commands/mcp.ts +46 -59
- package/src/cli/commands/memory.ts +16 -165
- package/src/cli/commands/oauth/apps.ts +68 -10
- package/src/cli/commands/oauth/connections.ts +475 -105
- package/src/cli/commands/oauth/index.ts +3 -3
- package/src/cli/commands/oauth/providers.ts +18 -4
- package/src/cli/commands/sessions.ts +5 -2
- package/src/cli/commands/skills.ts +173 -1
- package/src/cli/http-client.ts +0 -20
- package/src/cli/main-screen.tsx +2 -2
- package/src/cli/program.ts +5 -6
- package/src/cli.ts +20 -22
- package/src/config/__tests__/feature-flag-registry-bundled.test.ts +39 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +1 -1
- package/src/config/bundled-skills/computer-use/tools/computer-use-observe.ts +12 -0
- package/src/config/bundled-skills/contacts/SKILL.md +35 -11
- package/src/config/bundled-skills/contacts/tools/google-contacts.ts +1 -1
- package/src/config/bundled-skills/gmail/SKILL.md +1 -1
- package/src/config/bundled-skills/gmail/TOOLS.json +52 -0
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +13 -3
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +9 -2
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +9 -2
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +5 -1
- package/src/config/bundled-skills/google-calendar/TOOLS.json +20 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +8 -2
- package/src/config/bundled-skills/messaging/SKILL.md +1 -1
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/shared.ts +7 -5
- package/src/config/bundled-skills/slack/tools/shared.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +1 -1
- package/src/config/bundled-tool-registry.ts +2 -5
- package/src/config/loader.ts +6 -42
- package/src/config/schema.ts +1 -12
- package/src/config/schemas/memory-lifecycle.ts +0 -9
- package/src/config/schemas/memory-processing.ts +0 -180
- package/src/config/schemas/memory-retrieval.ts +32 -104
- package/src/config/schemas/memory.ts +0 -10
- package/src/config/types.ts +0 -4
- package/src/contacts/contact-store.ts +39 -2
- package/src/contacts/contacts-write.ts +9 -0
- package/src/context/window-manager.ts +4 -1
- package/src/daemon/config-watcher.ts +55 -2
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/date-context.ts +114 -31
- package/src/daemon/handlers/config-ingress.ts +2 -2
- package/src/daemon/handlers/config-slack-channel.ts +59 -39
- package/src/daemon/handlers/config-telegram.ts +23 -14
- package/src/daemon/handlers/session-history.ts +1 -358
- package/src/daemon/handlers/sessions.ts +18 -13
- package/src/daemon/handlers/shared.ts +3 -17
- package/src/daemon/handlers/skills.ts +20 -1
- package/src/daemon/history-repair.ts +72 -8
- package/src/daemon/host-cu-proxy.ts +55 -26
- package/src/daemon/lifecycle.ts +39 -4
- package/src/daemon/mcp-reload-service.ts +2 -2
- package/src/daemon/message-types/computer-use.ts +1 -12
- package/src/daemon/message-types/memory.ts +4 -16
- package/src/daemon/message-types/messages.ts +1 -0
- package/src/daemon/message-types/sessions.ts +4 -42
- package/src/daemon/server.ts +6 -1
- package/src/daemon/session-agent-loop-handlers.ts +38 -0
- package/src/daemon/session-agent-loop.ts +334 -48
- package/src/daemon/session-error.ts +89 -6
- package/src/daemon/session-history.ts +17 -7
- package/src/daemon/session-media-retry.ts +6 -2
- package/src/daemon/session-memory.ts +69 -149
- package/src/daemon/session-process.ts +10 -1
- package/src/daemon/session-runtime-assembly.ts +49 -19
- package/src/daemon/session-slash.ts +3 -5
- package/src/daemon/session-surfaces.ts +4 -1
- package/src/daemon/session-tool-setup.ts +7 -1
- package/src/daemon/session.ts +12 -2
- package/src/email/providers/index.ts +2 -2
- package/src/instrument.ts +61 -1
- package/src/media/avatar-router.ts +1 -1
- package/src/memory/admin.ts +2 -191
- package/src/memory/canonical-guardian-store.ts +38 -2
- package/src/memory/conversation-crud.ts +0 -33
- package/src/memory/conversation-queries.ts +25 -83
- package/src/memory/db-init.ts +32 -0
- package/src/memory/embedding-backend.ts +84 -8
- package/src/memory/embedding-types.ts +9 -1
- package/src/memory/indexer.ts +7 -46
- package/src/memory/invite-store.ts +19 -0
- package/src/memory/items-extractor.ts +274 -76
- package/src/memory/job-handlers/backfill.ts +2 -127
- package/src/memory/job-handlers/cleanup.ts +2 -16
- package/src/memory/job-handlers/extraction.ts +2 -138
- package/src/memory/job-handlers/index-maintenance.ts +1 -6
- package/src/memory/job-handlers/summarization.ts +3 -148
- package/src/memory/job-utils.ts +21 -59
- package/src/memory/jobs-store.ts +1 -159
- package/src/memory/jobs-worker.ts +9 -52
- package/src/memory/migrations/104-core-indexes.ts +3 -3
- package/src/memory/migrations/149-oauth-tables.ts +2 -0
- package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
- package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
- package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
- package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
- package/src/memory/migrations/154-drop-fts.ts +20 -0
- package/src/memory/migrations/155-drop-conflicts.ts +7 -0
- package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
- package/src/memory/migrations/157-invite-contact-id.ts +104 -0
- package/src/memory/migrations/index.ts +8 -0
- package/src/memory/migrations/registry.ts +6 -0
- package/src/memory/qdrant-client.ts +148 -51
- package/src/memory/raw-query.ts +1 -1
- package/src/memory/retriever.test.ts +294 -273
- package/src/memory/retriever.ts +421 -645
- package/src/memory/schema/calls.ts +2 -0
- package/src/memory/schema/contacts.ts +1 -0
- package/src/memory/schema/memory-core.ts +3 -48
- package/src/memory/schema/oauth.ts +2 -0
- package/src/memory/search/formatting.ts +263 -176
- package/src/memory/search/lexical.ts +1 -254
- package/src/memory/search/ranking.ts +0 -455
- package/src/memory/search/semantic.ts +100 -14
- package/src/memory/search/staleness.ts +47 -0
- package/src/memory/search/tier-classifier.ts +21 -0
- package/src/memory/search/types.ts +15 -77
- package/src/memory/task-memory-cleanup.ts +4 -6
- package/src/messaging/provider.ts +1 -1
- package/src/messaging/providers/gmail/adapter.ts +1 -1
- package/src/messaging/providers/gmail/mime-builder.ts +17 -7
- package/src/messaging/providers/telegram-bot/adapter.ts +17 -8
- package/src/messaging/providers/whatsapp/adapter.ts +13 -9
- package/src/messaging/registry.ts +9 -5
- package/src/oauth/byo-connection.test.ts +40 -25
- package/src/oauth/connect-orchestrator.ts +4 -10
- package/src/oauth/connection-resolver.ts +20 -6
- package/src/oauth/manual-token-connection.ts +5 -5
- package/src/oauth/oauth-store.ts +183 -31
- package/src/oauth/platform-connection.test.ts +1 -1
- package/src/oauth/provider-behaviors.ts +503 -4
- package/src/oauth/seed-providers.ts +214 -8
- package/src/oauth/token-persistence.ts +31 -16
- package/src/permissions/defaults.ts +1 -0
- package/src/permissions/trust-store.ts +23 -1
- package/src/playbooks/playbook-compiler.ts +1 -1
- package/src/prompts/system-prompt.ts +18 -2
- package/src/providers/anthropic/client.ts +56 -126
- package/src/providers/types.ts +7 -1
- package/src/runtime/AGENTS.md +9 -0
- package/src/runtime/auth/route-policy.ts +6 -3
- package/src/runtime/channel-readiness-service.ts +48 -40
- package/src/runtime/guardian-reply-router.ts +24 -22
- package/src/runtime/http-server.ts +2 -2
- package/src/runtime/http-types.ts +2 -0
- package/src/runtime/invite-redemption-service.ts +72 -12
- package/src/runtime/invite-service.ts +43 -0
- package/src/runtime/middleware/twilio-validation.ts +1 -1
- package/src/runtime/pending-interactions.ts +2 -2
- package/src/runtime/routes/brain-graph-routes.ts +10 -90
- package/src/runtime/routes/btw-routes.ts +10 -5
- package/src/runtime/routes/conversation-routes.ts +56 -11
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
- package/src/runtime/routes/integrations/slack/channel.ts +2 -2
- package/src/runtime/routes/integrations/telegram.ts +2 -2
- package/src/runtime/routes/integrations/twilio.ts +17 -17
- package/src/runtime/routes/invite-routes.ts +29 -4
- package/src/runtime/routes/memory-item-routes.test.ts +754 -0
- package/src/runtime/routes/memory-item-routes.ts +503 -0
- package/src/runtime/routes/secret-routes.ts +17 -0
- package/src/runtime/routes/session-management-routes.ts +3 -3
- package/src/runtime/routes/settings-routes.ts +3 -3
- package/src/runtime/routes/trust-rules-routes.ts +14 -0
- package/src/runtime/routes/workspace-routes.ts +9 -4
- package/src/runtime/routes/workspace-utils.ts +8 -2
- package/src/schedule/integration-status.ts +26 -19
- package/src/security/keychain-broker-client.ts +17 -4
- package/src/security/oauth2.ts +6 -7
- package/src/security/secure-keys.ts +44 -19
- package/src/security/token-manager.ts +46 -39
- package/src/services/vercel-deploy.ts +0 -24
- package/src/signals/confirm.ts +78 -0
- package/src/signals/mcp-reload.ts +18 -0
- package/src/skills/catalog-install.ts +74 -18
- package/src/skills/skillssh-registry.ts +503 -0
- package/src/tools/assets/search.ts +5 -1
- package/src/tools/computer-use/definitions.ts +0 -10
- package/src/tools/computer-use/registry.ts +1 -1
- package/src/tools/credentials/vault.ts +22 -7
- package/src/tools/memory/definitions.ts +4 -13
- package/src/tools/memory/handlers.test.ts +83 -103
- package/src/tools/memory/handlers.ts +50 -85
- package/src/tools/network/script-proxy/session-manager.ts +8 -8
- package/src/tools/schedule/create.ts +10 -3
- package/src/tools/schedule/update.ts +8 -1
- package/src/tools/skills/load.ts +25 -2
- package/src/watcher/provider-types.ts +1 -1
- package/src/watcher/providers/github.ts +1 -1
- package/src/watcher/providers/gmail.ts +3 -3
- package/src/watcher/providers/google-calendar.ts +3 -3
- package/src/watcher/providers/linear.ts +1 -1
- package/src/__tests__/clarification-resolver.test.ts +0 -193
- package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
- package/src/__tests__/conflict-policy.test.ts +0 -269
- package/src/__tests__/conflict-store.test.ts +0 -372
- package/src/__tests__/contradiction-checker.test.ts +0 -361
- package/src/__tests__/entity-extractor.test.ts +0 -211
- package/src/__tests__/entity-search.test.ts +0 -1117
- package/src/__tests__/profile-compiler.test.ts +0 -392
- package/src/__tests__/session-conflict-gate.test.ts +0 -1228
- package/src/__tests__/session-profile-injection.test.ts +0 -557
- package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
- package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
- package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
- package/src/daemon/session-conflict-gate.ts +0 -167
- package/src/daemon/session-dynamic-profile.ts +0 -77
- package/src/memory/clarification-resolver.ts +0 -417
- package/src/memory/conflict-intent.ts +0 -205
- package/src/memory/conflict-policy.ts +0 -127
- package/src/memory/conflict-store.ts +0 -410
- package/src/memory/contradiction-checker.ts +0 -508
- package/src/memory/entity-extractor.ts +0 -535
- package/src/memory/format-recall.ts +0 -47
- package/src/memory/fts-reconciler.ts +0 -165
- package/src/memory/job-handlers/conflict.ts +0 -200
- package/src/memory/profile-compiler.ts +0 -195
- package/src/memory/recall-cache.ts +0 -117
- package/src/memory/search/entity.ts +0 -535
- package/src/memory/search/query-expansion.test.ts +0 -70
- package/src/memory/search/query-expansion.ts +0 -118
- package/src/runtime/routes/mcp-routes.ts +0 -20
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
AgentEvent,
|
|
14
14
|
AgentLoop,
|
|
15
15
|
CheckpointDecision,
|
|
16
|
+
CheckpointInfo,
|
|
16
17
|
} from "../agent/loop.js";
|
|
17
18
|
import { createAssistantMessage } from "../agent/message-types.js";
|
|
18
19
|
import type {
|
|
@@ -26,6 +27,10 @@ import { estimatePromptTokens } from "../context/token-estimator.js";
|
|
|
26
27
|
import type { ContextWindowManager } from "../context/window-manager.js";
|
|
27
28
|
import type { ToolProfiler } from "../events/tool-profiling-listener.js";
|
|
28
29
|
import { getHookManager } from "../hooks/manager.js";
|
|
30
|
+
import {
|
|
31
|
+
clearSentrySessionContext,
|
|
32
|
+
setSentrySessionContext,
|
|
33
|
+
} from "../instrument.js";
|
|
29
34
|
import { commitAppTurnChanges } from "../memory/app-git-service.js";
|
|
30
35
|
import { getApp, listAppFiles } from "../memory/app-store.js";
|
|
31
36
|
import {
|
|
@@ -68,7 +73,7 @@ import {
|
|
|
68
73
|
} from "./context-overflow-reducer.js";
|
|
69
74
|
import {
|
|
70
75
|
buildTemporalContext,
|
|
71
|
-
|
|
76
|
+
extractUserTimeZoneFromRecall,
|
|
72
77
|
} from "./date-context.js";
|
|
73
78
|
import { deepRepairHistory, repairHistory } from "./history-repair.js";
|
|
74
79
|
import type {
|
|
@@ -88,8 +93,6 @@ import {
|
|
|
88
93
|
formatAttachmentWarnings,
|
|
89
94
|
resolveAssistantAttachments,
|
|
90
95
|
} from "./session-attachments.js";
|
|
91
|
-
import type { ConflictGate } from "./session-conflict-gate.js";
|
|
92
|
-
import { stripDynamicProfileMessages } from "./session-dynamic-profile.js";
|
|
93
96
|
import {
|
|
94
97
|
buildSessionErrorMessage,
|
|
95
98
|
classifySessionError,
|
|
@@ -122,6 +125,40 @@ import type { TraceEmitter } from "./trace-emitter.js";
|
|
|
122
125
|
|
|
123
126
|
const log = getLogger("session-agent-loop");
|
|
124
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Parse the actual token count reported by the provider in a context-too-large
|
|
130
|
+
* error message. Providers typically include the prompt size, e.g.:
|
|
131
|
+
* "prompt is too long: 242201 tokens > 200000 maximum"
|
|
132
|
+
* "too many input tokens: 242201 > 200000"
|
|
133
|
+
*
|
|
134
|
+
* Returns the actual token count or null if it cannot be parsed.
|
|
135
|
+
*/
|
|
136
|
+
function parseActualTokensFromError(
|
|
137
|
+
errorMessage: string | null,
|
|
138
|
+
): number | null {
|
|
139
|
+
if (!errorMessage) return null;
|
|
140
|
+
|
|
141
|
+
// Match patterns like "242201 tokens > 200000" or "242201 > 200000 maximum"
|
|
142
|
+
const match = errorMessage.match(
|
|
143
|
+
/(\d[\d,]*)\s*tokens?\s*[>≥]|:\s*(\d[\d,]*)\s*[>≥]/i,
|
|
144
|
+
);
|
|
145
|
+
if (match) {
|
|
146
|
+
const raw = (match[1] || match[2]).replace(/,/g, "");
|
|
147
|
+
const parsed = parseInt(raw, 10);
|
|
148
|
+
if (!isNaN(parsed) && parsed > 0) return parsed;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Fallback: match "too many input tokens: N > M"
|
|
152
|
+
const fallback = errorMessage.match(/(\d[\d,]*)\s*[>≥]\s*\d/);
|
|
153
|
+
if (fallback) {
|
|
154
|
+
const raw = fallback[1].replace(/,/g, "");
|
|
155
|
+
const parsed = parseInt(raw, 10);
|
|
156
|
+
if (!isNaN(parsed) && parsed > 0) return parsed;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
|
|
125
162
|
/** Title-cased friendly labels for tool names, used in confirmation chips. */
|
|
126
163
|
const TOOL_FRIENDLY_LABEL: Record<string, string> = {
|
|
127
164
|
bash: "Run Command",
|
|
@@ -165,7 +202,6 @@ export interface AgentLoopSessionContext {
|
|
|
165
202
|
contextCompactedMessageCount: number;
|
|
166
203
|
contextCompactedAt: number | null;
|
|
167
204
|
|
|
168
|
-
readonly conflictGate: ConflictGate;
|
|
169
205
|
readonly memoryPolicy: { scopeId: string; includeDefaultFallback: boolean };
|
|
170
206
|
|
|
171
207
|
currentActiveSurfaceId?: string;
|
|
@@ -231,6 +267,7 @@ export interface AgentLoopSessionContext {
|
|
|
231
267
|
| "tool_result_received"
|
|
232
268
|
| "confirmation_requested"
|
|
233
269
|
| "confirmation_resolved"
|
|
270
|
+
| "context_compacting"
|
|
234
271
|
| "message_complete"
|
|
235
272
|
| "generation_cancelled"
|
|
236
273
|
| "error_terminal",
|
|
@@ -350,6 +387,18 @@ export async function runAgentLoopImpl(
|
|
|
350
387
|
ctx.profiler.startRequest();
|
|
351
388
|
let turnStarted = false;
|
|
352
389
|
|
|
390
|
+
// Populate Sentry scope with session-specific tags so any exception
|
|
391
|
+
// captured during this turn (e.g. inside agent/loop.ts) can be
|
|
392
|
+
// filtered by conversation, assistant, or user in the dashboard.
|
|
393
|
+
setSentrySessionContext({
|
|
394
|
+
assistantId: ctx.assistantId ?? DAEMON_INTERNAL_ASSISTANT_ID,
|
|
395
|
+
conversationId: ctx.conversationId,
|
|
396
|
+
messageCount: ctx.messages.length,
|
|
397
|
+
userIdentifier:
|
|
398
|
+
ctx.trustContext?.guardianPrincipalId ??
|
|
399
|
+
ctx.trustContext?.requesterExternalUserId,
|
|
400
|
+
});
|
|
401
|
+
|
|
353
402
|
try {
|
|
354
403
|
// Auto-complete stale interactive surfaces from previous turns.
|
|
355
404
|
// Only dismiss when the user sends a new message (not a surface action
|
|
@@ -432,10 +481,9 @@ export async function runAgentLoopImpl(
|
|
|
432
481
|
if (compactCheck.needed) {
|
|
433
482
|
ctx.emitActivityState(
|
|
434
483
|
"thinking",
|
|
435
|
-
"
|
|
484
|
+
"context_compacting",
|
|
436
485
|
"assistant_turn",
|
|
437
486
|
reqId,
|
|
438
|
-
"Compacting context",
|
|
439
487
|
);
|
|
440
488
|
}
|
|
441
489
|
const compacted = await ctx.contextWindowManager.maybeCompact(
|
|
@@ -528,12 +576,9 @@ export async function runAgentLoopImpl(
|
|
|
528
576
|
messages: ctx.messages,
|
|
529
577
|
systemPrompt: ctx.systemPrompt,
|
|
530
578
|
provider: ctx.provider,
|
|
531
|
-
conflictGate: ctx.conflictGate,
|
|
532
579
|
scopeId: ctx.memoryPolicy.scopeId,
|
|
533
580
|
includeDefaultFallback: ctx.memoryPolicy.includeDefaultFallback,
|
|
534
581
|
trustClass: resolveTrustClass(ctx.trustContext),
|
|
535
|
-
isInteractive:
|
|
536
|
-
options?.isInteractive ?? (!ctx.hasNoClient && !ctx.headlessLock),
|
|
537
582
|
},
|
|
538
583
|
content,
|
|
539
584
|
userMessageId,
|
|
@@ -541,7 +586,7 @@ export async function runAgentLoopImpl(
|
|
|
541
586
|
onEvent,
|
|
542
587
|
);
|
|
543
588
|
|
|
544
|
-
const { recall
|
|
589
|
+
const { recall } = memoryResult;
|
|
545
590
|
runMessages = memoryResult.runMessages;
|
|
546
591
|
|
|
547
592
|
// Build active surface context
|
|
@@ -574,16 +619,16 @@ export async function runAgentLoopImpl(
|
|
|
574
619
|
|
|
575
620
|
// Compute fresh temporal context each turn for date grounding.
|
|
576
621
|
// Absolute "now" is always anchored to assistant host clock, while local
|
|
577
|
-
// date semantics prefer configured user timezone, then
|
|
622
|
+
// date semantics prefer configured user timezone, then recalled memory.
|
|
578
623
|
const hostTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
579
|
-
const userTimeZone = extractUserTimeZoneFromDynamicProfile(
|
|
580
|
-
dynamicProfile.text,
|
|
581
|
-
);
|
|
582
624
|
const configuredUserTimeZone = getConfig().ui.userTimezone ?? null;
|
|
625
|
+
const recalledUserTimeZone = extractUserTimeZoneFromRecall(
|
|
626
|
+
recall.injectedText,
|
|
627
|
+
);
|
|
583
628
|
const temporalContext = buildTemporalContext({
|
|
584
629
|
hostTimeZone,
|
|
585
630
|
configuredUserTimeZone,
|
|
586
|
-
userTimeZone,
|
|
631
|
+
userTimeZone: recalledUserTimeZone,
|
|
587
632
|
});
|
|
588
633
|
|
|
589
634
|
// Use the channel/interface context captured at the top of this function
|
|
@@ -656,7 +701,12 @@ export async function runAgentLoopImpl(
|
|
|
656
701
|
const config = getConfig();
|
|
657
702
|
const overflowRecovery = config.contextWindow.overflowRecovery;
|
|
658
703
|
const providerMaxTokens = config.contextWindow.maxInputTokens;
|
|
659
|
-
|
|
704
|
+
// Widen safety margin for large conversations where estimation error
|
|
705
|
+
// compounds across many messages with tool results.
|
|
706
|
+
const baseSafetyMargin = overflowRecovery.safetyMarginRatio;
|
|
707
|
+
const messageCount = ctx.messages.length;
|
|
708
|
+
const safetyMargin =
|
|
709
|
+
messageCount > 50 ? Math.max(baseSafetyMargin, 0.15) : baseSafetyMargin;
|
|
660
710
|
const preflightBudget = Math.floor(providerMaxTokens * (1 - safetyMargin));
|
|
661
711
|
let reducerState: ReducerState | undefined;
|
|
662
712
|
|
|
@@ -686,10 +736,9 @@ export async function runAgentLoopImpl(
|
|
|
686
736
|
preflightAttempts++;
|
|
687
737
|
ctx.emitActivityState(
|
|
688
738
|
"thinking",
|
|
689
|
-
"
|
|
739
|
+
"context_compacting",
|
|
690
740
|
"assistant_turn",
|
|
691
741
|
reqId,
|
|
692
|
-
"Compacting context",
|
|
693
742
|
);
|
|
694
743
|
const step = await reduceContextOverflow(
|
|
695
744
|
ctx.messages,
|
|
@@ -790,7 +839,9 @@ export async function runAgentLoopImpl(
|
|
|
790
839
|
const eventHandler = (event: AgentEvent) =>
|
|
791
840
|
dispatchAgentEvent(state, deps, event);
|
|
792
841
|
|
|
793
|
-
|
|
842
|
+
let yieldedForBudget = false;
|
|
843
|
+
|
|
844
|
+
const onCheckpoint = (checkpoint: CheckpointInfo): CheckpointDecision => {
|
|
794
845
|
const turnTools = state.currentTurnToolNames;
|
|
795
846
|
state.currentTurnToolNames = [];
|
|
796
847
|
|
|
@@ -803,6 +854,27 @@ export async function runAgentLoopImpl(
|
|
|
803
854
|
return "yield";
|
|
804
855
|
}
|
|
805
856
|
}
|
|
857
|
+
|
|
858
|
+
// Mid-loop token budget check: estimate current context size and
|
|
859
|
+
// yield if we're approaching the preflight budget. This lets the
|
|
860
|
+
// session-agent-loop run compaction before the provider rejects.
|
|
861
|
+
if (overflowRecovery.enabled) {
|
|
862
|
+
const midLoopThreshold = preflightBudget * 0.85;
|
|
863
|
+
const estimated = estimatePromptTokens(
|
|
864
|
+
checkpoint.history,
|
|
865
|
+
ctx.systemPrompt,
|
|
866
|
+
{ providerName: ctx.provider.name },
|
|
867
|
+
);
|
|
868
|
+
if (estimated > midLoopThreshold) {
|
|
869
|
+
rlog.warn(
|
|
870
|
+
{ phase: "mid-loop", estimated, threshold: midLoopThreshold },
|
|
871
|
+
"Token estimate approaching budget — yielding for compaction",
|
|
872
|
+
);
|
|
873
|
+
yieldedForBudget = true;
|
|
874
|
+
return "yield";
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
|
|
806
878
|
return "continue";
|
|
807
879
|
};
|
|
808
880
|
|
|
@@ -818,6 +890,109 @@ export async function runAgentLoopImpl(
|
|
|
818
890
|
onCheckpoint,
|
|
819
891
|
);
|
|
820
892
|
|
|
893
|
+
// ── Proactive mid-loop compaction ───────────────────────────────
|
|
894
|
+
// When the agent loop yielded because the token budget check in
|
|
895
|
+
// onCheckpoint detected approaching limits, run compaction on the
|
|
896
|
+
// accumulated history and re-enter the agent loop. This is distinct
|
|
897
|
+
// from the reactive convergence loop below that fires after a
|
|
898
|
+
// provider rejection — here we compact *before* hitting the limit.
|
|
899
|
+
let midLoopCompactAttempts = 0;
|
|
900
|
+
while (
|
|
901
|
+
yieldedForBudget &&
|
|
902
|
+
midLoopCompactAttempts < overflowRecovery.maxAttempts &&
|
|
903
|
+
!state.contextTooLargeDetected &&
|
|
904
|
+
!abortController.signal.aborted
|
|
905
|
+
) {
|
|
906
|
+
midLoopCompactAttempts++;
|
|
907
|
+
yieldedForBudget = false;
|
|
908
|
+
|
|
909
|
+
rlog.info(
|
|
910
|
+
{ phase: "mid-loop-compact" },
|
|
911
|
+
"Running compaction after checkpoint yield",
|
|
912
|
+
);
|
|
913
|
+
|
|
914
|
+
// Strip injected context from updated history before compacting,
|
|
915
|
+
// so we compact the "raw" persistent messages.
|
|
916
|
+
const rawHistory = stripInjectedContext(updatedHistory, {
|
|
917
|
+
stripRecall: (msgs) =>
|
|
918
|
+
stripMemoryRecallMessages(
|
|
919
|
+
msgs,
|
|
920
|
+
recall.injectedText,
|
|
921
|
+
"separate_context_message",
|
|
922
|
+
),
|
|
923
|
+
});
|
|
924
|
+
ctx.messages = rawHistory;
|
|
925
|
+
|
|
926
|
+
ctx.emitActivityState(
|
|
927
|
+
"thinking",
|
|
928
|
+
"context_compacting",
|
|
929
|
+
"assistant_turn",
|
|
930
|
+
reqId,
|
|
931
|
+
"Compacting context",
|
|
932
|
+
);
|
|
933
|
+
const midLoopCompact = await ctx.contextWindowManager.maybeCompact(
|
|
934
|
+
ctx.messages,
|
|
935
|
+
abortController.signal,
|
|
936
|
+
{
|
|
937
|
+
lastCompactedAt: ctx.contextCompactedAt ?? undefined,
|
|
938
|
+
force: true,
|
|
939
|
+
targetInputTokensOverride: preflightBudget,
|
|
940
|
+
},
|
|
941
|
+
);
|
|
942
|
+
if (midLoopCompact.compacted) {
|
|
943
|
+
ctx.messages = midLoopCompact.messages;
|
|
944
|
+
ctx.contextCompactedMessageCount +=
|
|
945
|
+
midLoopCompact.compactedPersistedMessages;
|
|
946
|
+
ctx.contextCompactedAt = Date.now();
|
|
947
|
+
updateConversationContextWindow(
|
|
948
|
+
ctx.conversationId,
|
|
949
|
+
midLoopCompact.summaryText,
|
|
950
|
+
ctx.contextCompactedMessageCount,
|
|
951
|
+
);
|
|
952
|
+
onEvent({
|
|
953
|
+
type: "context_compacted",
|
|
954
|
+
previousEstimatedInputTokens:
|
|
955
|
+
midLoopCompact.previousEstimatedInputTokens,
|
|
956
|
+
estimatedInputTokens: midLoopCompact.estimatedInputTokens,
|
|
957
|
+
maxInputTokens: midLoopCompact.maxInputTokens,
|
|
958
|
+
thresholdTokens: midLoopCompact.thresholdTokens,
|
|
959
|
+
compactedMessages: midLoopCompact.compactedMessages,
|
|
960
|
+
summaryCalls: midLoopCompact.summaryCalls,
|
|
961
|
+
summaryInputTokens: midLoopCompact.summaryInputTokens,
|
|
962
|
+
summaryOutputTokens: midLoopCompact.summaryOutputTokens,
|
|
963
|
+
summaryModel: midLoopCompact.summaryModel,
|
|
964
|
+
});
|
|
965
|
+
emitUsage(
|
|
966
|
+
ctx,
|
|
967
|
+
midLoopCompact.summaryInputTokens,
|
|
968
|
+
midLoopCompact.summaryOutputTokens,
|
|
969
|
+
midLoopCompact.summaryModel,
|
|
970
|
+
onEvent,
|
|
971
|
+
"context_compactor",
|
|
972
|
+
reqId,
|
|
973
|
+
midLoopCompact.summaryCacheCreationInputTokens ?? 0,
|
|
974
|
+
midLoopCompact.summaryCacheReadInputTokens ?? 0,
|
|
975
|
+
collapseRawResponses(midLoopCompact.summaryRawResponses),
|
|
976
|
+
);
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
// Re-inject runtime context and re-enter the agent loop
|
|
980
|
+
runMessages = applyRuntimeInjections(ctx.messages, {
|
|
981
|
+
...injectionOpts,
|
|
982
|
+
mode: currentInjectionMode,
|
|
983
|
+
});
|
|
984
|
+
preRepairMessages = runMessages;
|
|
985
|
+
preRunHistoryLength = runMessages.length;
|
|
986
|
+
|
|
987
|
+
updatedHistory = await ctx.agentLoop.run(
|
|
988
|
+
runMessages,
|
|
989
|
+
eventHandler,
|
|
990
|
+
abortController.signal,
|
|
991
|
+
reqId,
|
|
992
|
+
onCheckpoint,
|
|
993
|
+
);
|
|
994
|
+
}
|
|
995
|
+
|
|
821
996
|
// One-shot ordering error retry
|
|
822
997
|
if (
|
|
823
998
|
state.orderingErrorDetected &&
|
|
@@ -855,14 +1030,58 @@ export async function runAgentLoopImpl(
|
|
|
855
1030
|
// reducer tiers (forced compaction, tool-result truncation, media
|
|
856
1031
|
// stubbing, injection downgrade) with optional approval gating for
|
|
857
1032
|
// interactive latest-turn compression.
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
)
|
|
1033
|
+
//
|
|
1034
|
+
// When progress was made (agent added messages before hitting the
|
|
1035
|
+
// limit), incorporate those new messages into ctx.messages so the
|
|
1036
|
+
// convergence loop operates on the full (larger) history.
|
|
1037
|
+
if (state.contextTooLargeDetected) {
|
|
1038
|
+
if (updatedHistory.length > preRunHistoryLength) {
|
|
1039
|
+
ctx.messages = stripInjectedContext(updatedHistory, {
|
|
1040
|
+
stripRecall: (msgs) =>
|
|
1041
|
+
stripMemoryRecallMessages(
|
|
1042
|
+
msgs,
|
|
1043
|
+
recall.injectedText,
|
|
1044
|
+
"separate_context_message",
|
|
1045
|
+
),
|
|
1046
|
+
});
|
|
1047
|
+
preRepairMessages = updatedHistory;
|
|
1048
|
+
}
|
|
862
1049
|
if (!reducerState) {
|
|
863
1050
|
reducerState = createInitialReducerState();
|
|
864
1051
|
}
|
|
865
1052
|
|
|
1053
|
+
// When the provider reveals the actual token count in its error
|
|
1054
|
+
// message (e.g. "242201 tokens > 200000"), use it to correct the
|
|
1055
|
+
// compaction target. The estimator may significantly underestimate
|
|
1056
|
+
// (e.g. estimated 185k but actual was 242k), so using the
|
|
1057
|
+
// uncorrected preflightBudget would still be too high.
|
|
1058
|
+
const actualTokens = parseActualTokensFromError(
|
|
1059
|
+
state.contextTooLargeErrorMessage,
|
|
1060
|
+
);
|
|
1061
|
+
const estimatedTokensAtOverflow = estimatePromptTokens(
|
|
1062
|
+
ctx.messages,
|
|
1063
|
+
ctx.systemPrompt,
|
|
1064
|
+
{ providerName: ctx.provider.name },
|
|
1065
|
+
);
|
|
1066
|
+
let correctedTarget = preflightBudget;
|
|
1067
|
+
if (actualTokens && estimatedTokensAtOverflow > 0) {
|
|
1068
|
+
const estimationErrorRatio = actualTokens / estimatedTokensAtOverflow;
|
|
1069
|
+
if (estimationErrorRatio > 1.0) {
|
|
1070
|
+
correctedTarget = Math.floor(preflightBudget / estimationErrorRatio);
|
|
1071
|
+
rlog.warn(
|
|
1072
|
+
{
|
|
1073
|
+
phase: "convergence",
|
|
1074
|
+
actualTokens,
|
|
1075
|
+
estimatedTokens: estimatedTokensAtOverflow,
|
|
1076
|
+
estimationErrorRatio: estimationErrorRatio.toFixed(2),
|
|
1077
|
+
preflightBudget,
|
|
1078
|
+
correctedTarget,
|
|
1079
|
+
},
|
|
1080
|
+
"Adjusting compaction target based on observed estimation error",
|
|
1081
|
+
);
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
|
|
866
1085
|
let convergenceAttempts = 0;
|
|
867
1086
|
const maxAttempts = overflowRecovery.maxAttempts;
|
|
868
1087
|
|
|
@@ -883,10 +1102,9 @@ export async function runAgentLoopImpl(
|
|
|
883
1102
|
|
|
884
1103
|
ctx.emitActivityState(
|
|
885
1104
|
"thinking",
|
|
886
|
-
"
|
|
1105
|
+
"context_compacting",
|
|
887
1106
|
"assistant_turn",
|
|
888
1107
|
reqId,
|
|
889
|
-
"Compacting context",
|
|
890
1108
|
);
|
|
891
1109
|
const step = await reduceContextOverflow(
|
|
892
1110
|
ctx.messages,
|
|
@@ -894,7 +1112,7 @@ export async function runAgentLoopImpl(
|
|
|
894
1112
|
providerName: ctx.provider.name,
|
|
895
1113
|
systemPrompt: ctx.systemPrompt,
|
|
896
1114
|
contextWindow: config.contextWindow,
|
|
897
|
-
targetTokens:
|
|
1115
|
+
targetTokens: correctedTarget,
|
|
898
1116
|
},
|
|
899
1117
|
reducerState,
|
|
900
1118
|
(msgs, signal, opts) =>
|
|
@@ -906,6 +1124,12 @@ export async function runAgentLoopImpl(
|
|
|
906
1124
|
ctx.messages = step.messages;
|
|
907
1125
|
currentInjectionMode = step.state.injectionMode;
|
|
908
1126
|
|
|
1127
|
+
// If the reducer is now exhausted without compacting, break out
|
|
1128
|
+
// so the overflow policy path can attempt emergency compaction.
|
|
1129
|
+
if (reducerState.exhausted && !step.compactionResult?.compacted) {
|
|
1130
|
+
break;
|
|
1131
|
+
}
|
|
1132
|
+
|
|
909
1133
|
if (step.compactionResult?.compacted) {
|
|
910
1134
|
ctx.contextCompactedMessageCount +=
|
|
911
1135
|
step.compactionResult.compactedPersistedMessages;
|
|
@@ -959,6 +1183,75 @@ export async function runAgentLoopImpl(
|
|
|
959
1183
|
);
|
|
960
1184
|
}
|
|
961
1185
|
|
|
1186
|
+
// When all reducer tiers are exhausted but the context is still too
|
|
1187
|
+
// large, attempt one last emergency compaction before consulting the
|
|
1188
|
+
// overflow policy. This covers the case where progress was made
|
|
1189
|
+
// (messages grew) and the normal tiers couldn't compact enough.
|
|
1190
|
+
if (state.contextTooLargeDetected && reducerState.exhausted) {
|
|
1191
|
+
const emergencyCompact = await ctx.contextWindowManager.maybeCompact(
|
|
1192
|
+
ctx.messages,
|
|
1193
|
+
abortController.signal,
|
|
1194
|
+
{
|
|
1195
|
+
lastCompactedAt: ctx.contextCompactedAt ?? undefined,
|
|
1196
|
+
force: true,
|
|
1197
|
+
minKeepRecentUserTurns: 0,
|
|
1198
|
+
targetInputTokensOverride: correctedTarget,
|
|
1199
|
+
},
|
|
1200
|
+
);
|
|
1201
|
+
if (emergencyCompact.compacted) {
|
|
1202
|
+
ctx.messages = emergencyCompact.messages;
|
|
1203
|
+
ctx.contextCompactedMessageCount +=
|
|
1204
|
+
emergencyCompact.compactedPersistedMessages;
|
|
1205
|
+
ctx.contextCompactedAt = Date.now();
|
|
1206
|
+
updateConversationContextWindow(
|
|
1207
|
+
ctx.conversationId,
|
|
1208
|
+
emergencyCompact.summaryText,
|
|
1209
|
+
ctx.contextCompactedMessageCount,
|
|
1210
|
+
);
|
|
1211
|
+
onEvent({
|
|
1212
|
+
type: "context_compacted",
|
|
1213
|
+
previousEstimatedInputTokens:
|
|
1214
|
+
emergencyCompact.previousEstimatedInputTokens,
|
|
1215
|
+
estimatedInputTokens: emergencyCompact.estimatedInputTokens,
|
|
1216
|
+
maxInputTokens: emergencyCompact.maxInputTokens,
|
|
1217
|
+
thresholdTokens: emergencyCompact.thresholdTokens,
|
|
1218
|
+
compactedMessages: emergencyCompact.compactedMessages,
|
|
1219
|
+
summaryCalls: emergencyCompact.summaryCalls,
|
|
1220
|
+
summaryInputTokens: emergencyCompact.summaryInputTokens,
|
|
1221
|
+
summaryOutputTokens: emergencyCompact.summaryOutputTokens,
|
|
1222
|
+
summaryModel: emergencyCompact.summaryModel,
|
|
1223
|
+
});
|
|
1224
|
+
emitUsage(
|
|
1225
|
+
ctx,
|
|
1226
|
+
emergencyCompact.summaryInputTokens,
|
|
1227
|
+
emergencyCompact.summaryOutputTokens,
|
|
1228
|
+
emergencyCompact.summaryModel,
|
|
1229
|
+
onEvent,
|
|
1230
|
+
"context_compactor",
|
|
1231
|
+
reqId,
|
|
1232
|
+
emergencyCompact.summaryCacheCreationInputTokens ?? 0,
|
|
1233
|
+
emergencyCompact.summaryCacheReadInputTokens ?? 0,
|
|
1234
|
+
collapseRawResponses(emergencyCompact.summaryRawResponses),
|
|
1235
|
+
);
|
|
1236
|
+
|
|
1237
|
+
runMessages = applyRuntimeInjections(ctx.messages, {
|
|
1238
|
+
...injectionOpts,
|
|
1239
|
+
mode: currentInjectionMode,
|
|
1240
|
+
});
|
|
1241
|
+
preRepairMessages = runMessages;
|
|
1242
|
+
preRunHistoryLength = runMessages.length;
|
|
1243
|
+
state.contextTooLargeDetected = false;
|
|
1244
|
+
|
|
1245
|
+
updatedHistory = await ctx.agentLoop.run(
|
|
1246
|
+
runMessages,
|
|
1247
|
+
eventHandler,
|
|
1248
|
+
abortController.signal,
|
|
1249
|
+
reqId,
|
|
1250
|
+
onCheckpoint,
|
|
1251
|
+
);
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
|
|
962
1255
|
// All reducer tiers exhausted but provider still rejects —
|
|
963
1256
|
// consult the overflow policy for latest-turn compression.
|
|
964
1257
|
if (state.contextTooLargeDetected) {
|
|
@@ -982,7 +1275,7 @@ export async function runAgentLoopImpl(
|
|
|
982
1275
|
lastCompactedAt: ctx.contextCompactedAt ?? undefined,
|
|
983
1276
|
force: true,
|
|
984
1277
|
minKeepRecentUserTurns: 0,
|
|
985
|
-
targetInputTokensOverride:
|
|
1278
|
+
targetInputTokensOverride: correctedTarget,
|
|
986
1279
|
},
|
|
987
1280
|
);
|
|
988
1281
|
if (emergencyCompact.compacted) {
|
|
@@ -1075,10 +1368,9 @@ export async function runAgentLoopImpl(
|
|
|
1075
1368
|
// Non-interactive — auto-compress without asking
|
|
1076
1369
|
ctx.emitActivityState(
|
|
1077
1370
|
"thinking",
|
|
1078
|
-
"
|
|
1371
|
+
"context_compacting",
|
|
1079
1372
|
"assistant_turn",
|
|
1080
1373
|
reqId,
|
|
1081
|
-
"Compacting context",
|
|
1082
1374
|
);
|
|
1083
1375
|
const emergencyCompact = await ctx.contextWindowManager.maybeCompact(
|
|
1084
1376
|
ctx.messages,
|
|
@@ -1087,7 +1379,7 @@ export async function runAgentLoopImpl(
|
|
|
1087
1379
|
lastCompactedAt: ctx.contextCompactedAt ?? undefined,
|
|
1088
1380
|
force: true,
|
|
1089
1381
|
minKeepRecentUserTurns: 0,
|
|
1090
|
-
targetInputTokensOverride:
|
|
1382
|
+
targetInputTokensOverride: correctedTarget,
|
|
1091
1383
|
},
|
|
1092
1384
|
);
|
|
1093
1385
|
if (emergencyCompact.compacted) {
|
|
@@ -1154,19 +1446,6 @@ export async function runAgentLoopImpl(
|
|
|
1154
1446
|
);
|
|
1155
1447
|
onEvent(buildSessionErrorMessage(ctx.conversationId, classified));
|
|
1156
1448
|
}
|
|
1157
|
-
} else if (state.contextTooLargeDetected) {
|
|
1158
|
-
// Progress was made (updatedHistory grew), so the retry path above was
|
|
1159
|
-
// skipped. Surface the error so clients are not left with a silent failure.
|
|
1160
|
-
rlog.warn(
|
|
1161
|
-
{ phase: "post_run" },
|
|
1162
|
-
"Context too large after progress — surfacing error without retry",
|
|
1163
|
-
);
|
|
1164
|
-
const classified = classifySessionError(
|
|
1165
|
-
new Error("context_length_exceeded"),
|
|
1166
|
-
{ phase: "agent_loop" },
|
|
1167
|
-
);
|
|
1168
|
-
onEvent(buildSessionErrorMessage(ctx.conversationId, classified));
|
|
1169
|
-
state.providerErrorUserMessage = classified.userMessage;
|
|
1170
1449
|
}
|
|
1171
1450
|
|
|
1172
1451
|
if (state.deferredOrderingError) {
|
|
@@ -1280,10 +1559,8 @@ export async function runAgentLoopImpl(
|
|
|
1280
1559
|
stripMemoryRecallMessages(
|
|
1281
1560
|
msgs,
|
|
1282
1561
|
recall.injectedText,
|
|
1283
|
-
|
|
1562
|
+
"separate_context_message",
|
|
1284
1563
|
),
|
|
1285
|
-
stripDynamicProfile: (msgs) =>
|
|
1286
|
-
stripDynamicProfileMessages(msgs, dynamicProfile.text),
|
|
1287
1564
|
});
|
|
1288
1565
|
|
|
1289
1566
|
emitUsage(
|
|
@@ -1451,12 +1728,17 @@ export async function runAgentLoopImpl(
|
|
|
1451
1728
|
const message = err instanceof Error ? err.message : String(err);
|
|
1452
1729
|
const errorClass = err instanceof Error ? err.constructor.name : "Error";
|
|
1453
1730
|
rlog.error({ err }, "Session processing error");
|
|
1731
|
+
const classified = classifySessionError(err, errorCtx);
|
|
1454
1732
|
ctx.traceEmitter.emit("request_error", truncate(message, 200, ""), {
|
|
1455
1733
|
requestId: reqId,
|
|
1456
1734
|
status: "error",
|
|
1457
|
-
attributes: {
|
|
1735
|
+
attributes: {
|
|
1736
|
+
errorClass,
|
|
1737
|
+
message: truncate(message, 500, ""),
|
|
1738
|
+
errorCategory: classified.errorCategory,
|
|
1739
|
+
errorCode: classified.code,
|
|
1740
|
+
},
|
|
1458
1741
|
});
|
|
1459
|
-
const classified = classifySessionError(err, errorCtx);
|
|
1460
1742
|
onEvent({ type: "error", message: classified.userMessage });
|
|
1461
1743
|
onEvent(buildSessionErrorMessage(ctx.conversationId, classified));
|
|
1462
1744
|
void getHookManager().trigger("on-error", {
|
|
@@ -1515,6 +1797,10 @@ export async function runAgentLoopImpl(
|
|
|
1515
1797
|
}
|
|
1516
1798
|
|
|
1517
1799
|
ctx.drainQueue(yieldedForHandoff ? "checkpoint_handoff" : "loop_complete");
|
|
1800
|
+
|
|
1801
|
+
// Clear session tags so they don't leak into unrelated error captures
|
|
1802
|
+
// (e.g. unhandledRejection from a different async chain).
|
|
1803
|
+
clearSentrySessionContext();
|
|
1518
1804
|
}
|
|
1519
1805
|
}
|
|
1520
1806
|
|