@vellumai/assistant 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +54 -54
- package/docs/architecture/integrations.md +62 -67
- package/docs/credential-execution-service.md +3 -3
- package/package.json +1 -1
- package/src/__tests__/agent-loop.test.ts +111 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +3 -4
- package/src/__tests__/app-builder-tool-scripts.test.ts +13 -151
- package/src/__tests__/app-dir-path-guard.test.ts +78 -0
- package/src/__tests__/app-executors.test.ts +1 -291
- package/src/__tests__/app-git-history.test.ts +4 -4
- package/src/__tests__/app-routes-csp.test.ts +1 -0
- package/src/__tests__/app-store-dir-names.test.ts +426 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +7 -9
- package/src/__tests__/attachments-store.test.ts +169 -21
- package/src/__tests__/attachments.test.ts +115 -1
- package/src/__tests__/btw-routes.test.ts +1 -0
- package/src/__tests__/canonical-guardian-store.test.ts +38 -0
- package/src/__tests__/channel-reply-delivery.test.ts +55 -0
- package/src/__tests__/checker.test.ts +54 -0
- package/src/__tests__/claude-code-skill-regression.test.ts +2 -0
- package/src/__tests__/claude-code-tool-profiles.test.ts +2 -0
- package/src/__tests__/compaction.benchmark.test.ts +2 -1
- package/src/__tests__/config-schema-cmd.test.ts +68 -21
- package/src/__tests__/config-schema.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +149 -5
- package/src/__tests__/conversation-agent-loop.test.ts +290 -2
- package/src/__tests__/conversation-attachments.test.ts +17 -19
- package/src/__tests__/conversation-disk-view-integration.test.ts +277 -0
- package/src/__tests__/conversation-disk-view.test.ts +810 -0
- package/src/__tests__/conversation-error.test.ts +1 -1
- package/src/__tests__/conversation-fork-crud.test.ts +551 -0
- package/src/__tests__/conversation-fork-route.test.ts +386 -0
- package/src/__tests__/conversation-history-web-search.test.ts +1 -1
- package/src/__tests__/conversation-key-store-disk-view.test.ts +130 -0
- package/src/__tests__/conversation-media-retry.test.ts +8 -2
- package/src/__tests__/conversation-queue.test.ts +36 -1
- package/src/__tests__/conversation-routes-disk-view.test.ts +439 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +2 -2
- package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -7
- package/src/__tests__/conversation-runtime-assembly.test.ts +17 -2
- package/src/__tests__/conversation-skill-tools.test.ts +4 -9
- package/src/__tests__/conversation-slash-commands.test.ts +149 -0
- package/src/__tests__/conversation-store.test.ts +24 -21
- package/src/__tests__/conversation-surfaces-state-update.test.ts +246 -0
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -0
- package/src/__tests__/conversation-title-service.test.ts +137 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +25 -315
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +1 -0
- package/src/__tests__/conversation-tool-setup-side-effect-flag.test.ts +1 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +44 -2
- package/src/__tests__/conversation-workspace-injection.test.ts +11 -0
- package/src/__tests__/credential-execution-feature-gates.test.ts +3 -3
- package/src/__tests__/credential-security-invariants.test.ts +3 -0
- package/src/__tests__/credential-vault-unit.test.ts +5 -10
- package/src/__tests__/cu-unified-flow.test.ts +1 -0
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +241 -0
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +214 -0
- package/src/__tests__/diagnostics-export.test.ts +70 -1
- package/src/__tests__/filesystem-tools.test.ts +4 -2
- package/src/__tests__/first-greeting.test.ts +80 -0
- package/src/__tests__/gateway-only-guard.test.ts +1 -0
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +3 -7
- package/src/__tests__/history-repair.test.ts +103 -10
- package/src/__tests__/http-conversation-lineage.test.ts +251 -0
- package/src/__tests__/image-source-path-reinject.test.ts +136 -0
- package/src/__tests__/llm-context-normalization.test.ts +1116 -0
- package/src/__tests__/llm-context-route-provider.test.ts +217 -0
- package/src/__tests__/llm-request-log-turn-query.test.ts +270 -0
- package/src/__tests__/media-generate-image.test.ts +47 -94
- package/src/__tests__/memory-lifecycle-e2e.test.ts +3 -1
- package/src/__tests__/memory-recall-quality.test.ts +5 -5
- package/src/__tests__/migration-cross-version-compatibility.test.ts +4 -1
- package/src/__tests__/migration-export-http.test.ts +3 -1
- package/src/__tests__/migration-import-commit-http.test.ts +18 -4
- package/src/__tests__/migration-import-preflight-http.test.ts +1 -3
- package/src/__tests__/mime-builder.test.ts +3 -2
- package/src/__tests__/non-member-access-request.test.ts +12 -1
- package/src/__tests__/notification-decision-identity.test.ts +52 -0
- package/src/__tests__/oauth-apps-routes.test.ts +103 -0
- package/src/__tests__/oauth-store.test.ts +115 -0
- package/src/__tests__/provider-error-scenarios.test.ts +1 -3
- package/src/__tests__/provider-failover-actual-provider.test.ts +66 -0
- package/src/__tests__/recording-handler.test.ts +17 -0
- package/src/__tests__/registry.test.ts +3 -8
- package/src/__tests__/relay-server.test.ts +1 -1
- package/src/__tests__/runtime-attachment-metadata.test.ts +7 -3
- package/src/__tests__/schema-transforms.test.ts +165 -5
- package/src/__tests__/server-history-render.test.ts +2 -2
- package/src/__tests__/skill-feature-flags-integration.test.ts +18 -17
- package/src/__tests__/skill-feature-flags.test.ts +13 -13
- package/src/__tests__/skill-load-feature-flag.test.ts +4 -4
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
- package/src/__tests__/slack-inbound-verification.test.ts +2 -2
- package/src/__tests__/starter-task-flow.test.ts +1 -0
- package/src/__tests__/suggestion-routes.test.ts +443 -0
- package/src/__tests__/swarm-conversation-integration.test.ts +1 -0
- package/src/__tests__/swarm-recursion.test.ts +1 -0
- package/src/__tests__/swarm-tool.test.ts +1 -0
- package/src/__tests__/system-prompt.test.ts +8 -0
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +32 -5
- package/src/__tests__/top-level-renderer.test.ts +22 -0
- package/src/__tests__/turn-boundary-resolution.test.ts +243 -0
- package/src/__tests__/web-fetch.test.ts +6 -2
- package/src/__tests__/workspace-migration-006-services-config.test.ts +335 -0
- package/src/__tests__/workspace-migration-007-web-search-provider-rename.test.ts +312 -0
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +278 -0
- package/src/__tests__/workspace-migration-010-app-dir-rename.test.ts +275 -0
- package/src/__tests__/workspace-migration-012-rename-conversation-disk-view-dirs.test.ts +77 -0
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +401 -0
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +328 -0
- package/src/__tests__/workspace-migration-seed-device-id.test.ts +6 -10
- package/src/agent/attachments.ts +27 -1
- package/src/agent/loop.ts +29 -1
- package/src/avatar/traits-png-sync.ts +80 -25
- package/src/bundler/app-bundler.ts +4 -4
- package/src/calls/call-domain.ts +1 -0
- package/src/calls/voice-session-bridge.ts +1 -0
- package/src/cli/commands/auth.ts +92 -0
- package/src/cli/commands/avatar.ts +7 -6
- package/src/cli/commands/config.ts +2 -0
- package/src/cli/commands/oauth/providers.ts +29 -0
- package/src/cli/program.ts +12 -0
- package/src/cli.ts +15 -48
- package/src/config/bundled-skills/app-builder/SKILL.md +103 -28
- package/src/config/bundled-skills/app-builder/TOOLS.json +5 -199
- package/src/config/bundled-skills/app-builder/tools/{app-query.ts → app-refresh.ts} +2 -2
- package/src/config/bundled-skills/contacts/tools/google-contacts.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +6 -9
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +4 -6
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +4 -6
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +2 -3
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +1 -1
- package/src/config/bundled-skills/image-studio/SKILL.md +2 -2
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -2
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +45 -72
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -3
- package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
- package/src/config/bundled-skills/slack/tools/shared.ts +19 -4
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +2 -3
- package/src/config/bundled-skills/transcribe/SKILL.md +1 -1
- package/src/config/bundled-skills/transcribe/TOOLS.json +2 -6
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +19 -83
- package/src/config/bundled-tool-registry.ts +2 -14
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/loader.ts +64 -0
- package/src/config/raw-config-utils.ts +30 -0
- package/src/config/schema-utils.ts +28 -7
- package/src/config/schema.ts +8 -0
- package/src/config/schemas/elevenlabs.ts +18 -0
- package/src/config/schemas/memory-lifecycle.ts +4 -2
- package/src/config/schemas/memory-storage.ts +1 -1
- package/src/config/schemas/services.ts +8 -6
- package/src/contacts/contact-store.ts +13 -6
- package/src/contacts/contacts-write.ts +0 -1
- package/src/context/window-manager.ts +13 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +46 -42
- package/src/daemon/conversation-agent-loop.ts +56 -19
- package/src/daemon/conversation-attachments.ts +18 -36
- package/src/daemon/conversation-error.ts +2 -1
- package/src/daemon/conversation-history.ts +18 -4
- package/src/daemon/conversation-lifecycle.ts +39 -15
- package/src/daemon/conversation-messaging.ts +70 -26
- package/src/daemon/conversation-process.ts +58 -34
- package/src/daemon/conversation-runtime-assembly.ts +21 -38
- package/src/daemon/conversation-slash.ts +121 -256
- package/src/daemon/conversation-surfaces.ts +143 -20
- package/src/daemon/conversation-tool-setup.ts +0 -6
- package/src/daemon/conversation-workspace.ts +21 -1
- package/src/daemon/conversation.ts +51 -29
- package/src/daemon/first-greeting.ts +35 -0
- package/src/daemon/handlers/config-embeddings.ts +148 -0
- package/src/daemon/handlers/config-model.ts +71 -26
- package/src/daemon/handlers/conversations.ts +0 -23
- package/src/daemon/handlers/recording.ts +26 -21
- package/src/daemon/history-repair.ts +28 -8
- package/src/daemon/host-cu-proxy.ts +2 -2
- package/src/daemon/lifecycle.ts +106 -64
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/conversations.ts +19 -0
- package/src/daemon/message-types/messages.ts +1 -0
- package/src/daemon/message-types/shared.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/message-types/upgrades.ts +23 -0
- package/src/daemon/server.ts +83 -12
- package/src/daemon/shutdown-handlers.ts +8 -5
- package/src/daemon/startup-error.ts +9 -0
- package/src/daemon/tool-side-effects.ts +11 -28
- package/src/events/tool-permission-telemetry-listener.ts +1 -3
- package/src/instrument.ts +0 -4
- package/src/media/app-icon-generator.ts +2 -2
- package/src/memory/app-git-service.ts +28 -16
- package/src/memory/app-store.ts +230 -41
- package/src/memory/attachments-store.ts +558 -130
- package/src/memory/conversation-attention-store.ts +70 -0
- package/src/memory/conversation-crud.ts +442 -3
- package/src/memory/conversation-directories.ts +125 -0
- package/src/memory/conversation-disk-view.ts +390 -0
- package/src/memory/conversation-key-store.ts +17 -5
- package/src/memory/conversation-queries.ts +5 -1
- package/src/memory/conversation-title-service.ts +21 -49
- package/src/memory/db-init.ts +28 -0
- package/src/memory/embedding-backend.ts +42 -53
- package/src/memory/embedding-gemini.test.ts +4 -4
- package/src/memory/embedding-local.ts +1 -3
- package/src/memory/embedding-ollama.ts +1 -3
- package/src/memory/embedding-openai.ts +1 -3
- package/src/memory/indexer.ts +9 -7
- package/src/memory/items-extractor.ts +42 -13
- package/src/memory/job-handlers/conversation-starters.ts +6 -1
- package/src/memory/job-handlers/embedding.test.ts +1 -4
- package/src/memory/llm-request-log-store.ts +100 -1
- package/src/memory/migrations/102-alter-table-columns.ts +5 -0
- package/src/memory/migrations/146-schedule-oneshot-routing.ts +3 -3
- package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +66 -70
- package/src/memory/migrations/148-drop-reminders-table.ts +5 -9
- package/src/memory/migrations/160-drop-loopback-port-column.ts +1 -3
- package/src/memory/migrations/174-rename-thread-starters-table.ts +0 -7
- package/src/memory/migrations/178-oauth-providers-managed-service-config-key.ts +15 -0
- package/src/memory/migrations/179-llm-request-log-message-id.ts +16 -0
- package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +66 -0
- package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +46 -0
- package/src/memory/migrations/182-oauth-providers-display-metadata.ts +20 -0
- package/src/memory/migrations/183-add-conversation-fork-lineage.ts +22 -0
- package/src/memory/migrations/184-llm-request-log-provider.ts +12 -0
- package/src/memory/migrations/index.ts +7 -0
- package/src/memory/migrations/registry.ts +13 -0
- package/src/memory/retriever.test.ts +601 -2
- package/src/memory/retriever.ts +85 -9
- package/src/memory/schema/conversations.ts +6 -0
- package/src/memory/schema/infrastructure.ts +13 -7
- package/src/memory/schema/oauth.ts +6 -0
- package/src/messaging/providers/gmail/mime-builder.ts +3 -1
- package/src/notifications/copy-composer.ts +26 -0
- package/src/notifications/decision-engine.ts +14 -1
- package/src/notifications/emit-signal.ts +1 -1
- package/src/notifications/signal.ts +36 -0
- package/src/oauth/byo-connection.test.ts +1 -45
- package/src/oauth/byo-connection.ts +2 -8
- package/src/oauth/connect-orchestrator.ts +15 -11
- package/src/oauth/connection-resolver.test.ts +191 -0
- package/src/oauth/connection-resolver.ts +66 -38
- package/src/oauth/connection.ts +0 -1
- package/src/oauth/oauth-store.ts +97 -47
- package/src/oauth/platform-connection.test.ts +0 -1
- package/src/oauth/platform-connection.ts +11 -3
- package/src/oauth/seed-providers.ts +78 -3
- package/src/oauth/token-persistence.ts +16 -10
- package/src/permissions/checker.ts +62 -19
- package/src/prompts/system-prompt.ts +2 -0
- package/src/prompts/templates/BOOTSTRAP.md +2 -0
- package/src/providers/anthropic/client.ts +8 -1
- package/src/providers/failover.ts +4 -1
- package/src/providers/gemini/client.ts +50 -0
- package/src/providers/model-catalog.ts +92 -0
- package/src/providers/model-intents.ts +29 -20
- package/src/providers/openai/client.ts +49 -0
- package/src/providers/types.ts +2 -0
- package/src/runtime/access-request-helper.ts +16 -7
- package/src/runtime/auth/credential-service.ts +3 -1
- package/src/runtime/auth/route-policy.ts +14 -1
- package/src/runtime/btw-sidechain.ts +101 -0
- package/src/runtime/channel-reply-delivery.ts +17 -1
- package/src/runtime/http-router.ts +3 -1
- package/src/runtime/http-server.ts +196 -141
- package/src/runtime/http-types.ts +1 -0
- package/src/runtime/migrations/vbundle-builder.ts +5 -1
- package/src/runtime/routes/access-request-decision.ts +41 -0
- package/src/runtime/routes/app-management-routes.ts +6 -3
- package/src/runtime/routes/app-routes.ts +7 -3
- package/src/runtime/routes/approval-routes.ts +1 -0
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +34 -2
- package/src/runtime/routes/attachment-routes.ts +45 -15
- package/src/runtime/routes/btw-routes.ts +21 -61
- package/src/runtime/routes/conversation-management-routes.ts +68 -0
- package/src/runtime/routes/conversation-query-routes.ts +180 -10
- package/src/runtime/routes/conversation-routes.ts +222 -28
- package/src/runtime/routes/conversation-starter-routes.ts +9 -11
- package/src/runtime/routes/diagnostics-routes.ts +1 -0
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -2
- package/src/runtime/routes/llm-context-normalization.ts +1199 -0
- package/src/runtime/routes/log-export-routes.ts +3 -0
- package/src/runtime/routes/memory-item-routes.test.ts +34 -0
- package/src/runtime/routes/memory-item-routes.ts +4 -0
- package/src/runtime/routes/migration-routes.ts +4 -1
- package/src/runtime/routes/oauth-apps.ts +291 -0
- package/src/runtime/routes/secret-routes.ts +28 -1
- package/src/runtime/routes/settings-routes.ts +14 -0
- package/src/runtime/routes/trace-event-routes.ts +4 -1
- package/src/schedule/schedule-store.ts +9 -21
- package/src/security/secure-keys.ts +21 -0
- package/src/signals/bash.ts +1 -1
- package/src/swarm/backend-claude-code.ts +3 -6
- package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
- package/src/telemetry/usage-telemetry-reporter.ts +3 -1
- package/src/tools/AGENTS.md +6 -10
- package/src/tools/apps/executors.ts +17 -232
- package/src/tools/claude-code/claude-code.ts +2 -3
- package/src/tools/credentials/vault.ts +7 -12
- package/src/tools/host-filesystem/read.ts +13 -10
- package/src/tools/network/__tests__/web-search.test.ts +4 -2
- package/src/tools/schedule/list.ts +2 -7
- package/src/tools/schema-transforms.ts +5 -0
- package/src/tools/shared/filesystem/format-diff.ts +4 -21
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/tool-manifest.ts +0 -6
- package/src/tools/ui-surface/definitions.ts +2 -2
- package/src/util/device-id.ts +28 -5
- package/src/util/platform.ts +6 -0
- package/src/util/pricing.ts +1 -0
- package/src/util/retry.ts +1 -3
- package/src/workspace/migrations/002-backfill-installation-id.ts +23 -12
- package/src/workspace/migrations/003-seed-device-id.ts +3 -4
- package/src/workspace/migrations/006-services-config.ts +5 -0
- package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +12 -0
- package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +10 -0
- package/src/workspace/migrations/010-app-dir-rename.ts +223 -0
- package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +64 -0
- package/src/workspace/migrations/013-repair-conversation-disk-view.ts +11 -0
- package/src/workspace/migrations/rebuild-conversation-disk-view.ts +186 -0
- package/src/workspace/migrations/registry.ts +10 -0
- package/src/workspace/top-level-renderer.ts +12 -0
- package/src/__tests__/asset-materialize-tool.test.ts +0 -523
- package/src/__tests__/asset-search-tool.test.ts +0 -536
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +0 -56
- package/src/__tests__/media-reuse-story.e2e.test.ts +0 -762
- package/src/__tests__/media-visibility-policy.test.ts +0 -190
- package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +0 -14
- package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +0 -13
- package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +0 -21
- package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +0 -14
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +0 -13
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +0 -23
- package/src/daemon/media-visibility-policy.ts +0 -59
- package/src/tools/assets/materialize.ts +0 -248
- package/src/tools/assets/search.ts +0 -400
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
import type { z } from "zod";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Unwrap a Zod schema to reach its inner object shape, handling:
|
|
5
|
+
* - default/optional/nullable wrappers (innerType)
|
|
6
|
+
* - pipe/transform wrappers (in — the input side)
|
|
7
|
+
*/
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
|
+
function unwrapToShape(schema: any): any {
|
|
10
|
+
let current = schema;
|
|
11
|
+
while (current && !current.shape) {
|
|
12
|
+
const def = current._zod?.def;
|
|
13
|
+
if (!def) break;
|
|
14
|
+
// Pipe/transform: follow the input side to get the pre-transform schema
|
|
15
|
+
if (def.type === "pipe" && def.in) {
|
|
16
|
+
current = def.in;
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
// Default/optional/nullable: follow innerType
|
|
20
|
+
if (def.innerType) {
|
|
21
|
+
current = def.innerType;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
return current;
|
|
27
|
+
}
|
|
28
|
+
|
|
3
29
|
/**
|
|
4
30
|
* Navigate a Zod schema by dotted path, unwrapping wrapper types
|
|
5
|
-
* (default, optional, nullable) to reach inner object shapes.
|
|
31
|
+
* (default, optional, nullable, pipe/transform) to reach inner object shapes.
|
|
6
32
|
* Returns the Zod schema at the given path, or null if the path is invalid.
|
|
7
33
|
*/
|
|
8
34
|
export function getSchemaAtPath(
|
|
@@ -13,12 +39,7 @@ export function getSchemaAtPath(
|
|
|
13
39
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
40
|
let current: any = schema;
|
|
15
41
|
for (const key of keys) {
|
|
16
|
-
|
|
17
|
-
while (current && !current.shape) {
|
|
18
|
-
const inner = current._zod?.def?.innerType;
|
|
19
|
-
if (!inner) break;
|
|
20
|
-
current = inner;
|
|
21
|
-
}
|
|
42
|
+
current = unwrapToShape(current);
|
|
22
43
|
if (!current || !current.shape) return null;
|
|
23
44
|
current = current.shape[key];
|
|
24
45
|
if (!current) return null;
|
package/src/config/schema.ts
CHANGED
|
@@ -38,6 +38,7 @@ export type { ElevenLabsConfig } from "./schemas/elevenlabs.js";
|
|
|
38
38
|
export {
|
|
39
39
|
DEFAULT_ELEVENLABS_VOICE_ID,
|
|
40
40
|
ElevenLabsConfigSchema,
|
|
41
|
+
VALID_CONVERSATION_TIMEOUTS,
|
|
41
42
|
} from "./schemas/elevenlabs.js";
|
|
42
43
|
export type { HeartbeatConfig } from "./schemas/heartbeat.js";
|
|
43
44
|
export { HeartbeatConfigSchema } from "./schemas/heartbeat.js";
|
|
@@ -321,6 +322,13 @@ export const AssistantConfigSchema = z
|
|
|
321
322
|
.boolean()
|
|
322
323
|
.default(true)
|
|
323
324
|
.describe("Whether to send diagnostic/crash reports"),
|
|
325
|
+
maxStepsPerSession: z
|
|
326
|
+
.number({ error: "maxStepsPerSession must be a number" })
|
|
327
|
+
.int("maxStepsPerSession must be an integer")
|
|
328
|
+
.min(1, "maxStepsPerSession must be >= 1")
|
|
329
|
+
.max(200, "maxStepsPerSession must be <= 200")
|
|
330
|
+
.default(50)
|
|
331
|
+
.describe("Maximum number of computer-use steps per session"),
|
|
324
332
|
})
|
|
325
333
|
.superRefine((config, ctx) => {
|
|
326
334
|
if (
|
|
@@ -5,6 +5,9 @@ import { z } from "zod";
|
|
|
5
5
|
// Mirrored in: clients/macos/.../OpenAIVoiceService.swift (defaultVoiceId)
|
|
6
6
|
export const DEFAULT_ELEVENLABS_VOICE_ID = "ZF6FPAbjXT4488VcRRnw";
|
|
7
7
|
|
|
8
|
+
/** Valid conversation timeout values (seconds). Shared with voice-config-update tool. */
|
|
9
|
+
export const VALID_CONVERSATION_TIMEOUTS = [5, 10, 15, 30, 60] as const;
|
|
10
|
+
|
|
8
11
|
export const ElevenLabsConfigSchema = z
|
|
9
12
|
.object({
|
|
10
13
|
voiceId: z
|
|
@@ -42,6 +45,21 @@ export const ElevenLabsConfigSchema = z
|
|
|
42
45
|
.describe(
|
|
43
46
|
"How closely the output matches the original voice — higher values increase similarity",
|
|
44
47
|
),
|
|
48
|
+
conversationTimeoutSeconds: z
|
|
49
|
+
.number({
|
|
50
|
+
error: "elevenlabs.conversationTimeoutSeconds must be a number",
|
|
51
|
+
})
|
|
52
|
+
.refine(
|
|
53
|
+
(v) =>
|
|
54
|
+
VALID_CONVERSATION_TIMEOUTS.includes(
|
|
55
|
+
v as (typeof VALID_CONVERSATION_TIMEOUTS)[number],
|
|
56
|
+
),
|
|
57
|
+
{
|
|
58
|
+
message: `elevenlabs.conversationTimeoutSeconds must be one of: ${VALID_CONVERSATION_TIMEOUTS.join(", ")}`,
|
|
59
|
+
},
|
|
60
|
+
)
|
|
61
|
+
.default(30)
|
|
62
|
+
.describe("Seconds of silence before voice conversation auto-ends"),
|
|
45
63
|
})
|
|
46
64
|
.describe("ElevenLabs text-to-speech configuration");
|
|
47
65
|
|
|
@@ -68,8 +68,10 @@ export const MemoryCleanupConfigSchema = z
|
|
|
68
68
|
.nonnegative(
|
|
69
69
|
"memory.cleanup.conversationRetentionDays must be non-negative",
|
|
70
70
|
)
|
|
71
|
-
.default(
|
|
72
|
-
.describe(
|
|
71
|
+
.default(0)
|
|
72
|
+
.describe(
|
|
73
|
+
"Number of days to retain conversation data before cleanup (0 disables pruning)",
|
|
74
|
+
),
|
|
73
75
|
})
|
|
74
76
|
.describe("Automatic memory cleanup and garbage collection settings");
|
|
75
77
|
|
|
@@ -20,15 +20,18 @@ export const VALID_WEB_SEARCH_PROVIDERS = [
|
|
|
20
20
|
"inference-provider-native",
|
|
21
21
|
] as const;
|
|
22
22
|
|
|
23
|
-
export const
|
|
23
|
+
export const BaseServiceSchema = z.object({
|
|
24
24
|
mode: ServiceModeSchema.default("your-own"),
|
|
25
|
+
});
|
|
26
|
+
export type BaseService = z.infer<typeof BaseServiceSchema>;
|
|
27
|
+
|
|
28
|
+
export const InferenceServiceSchema = BaseServiceSchema.extend({
|
|
25
29
|
provider: z.enum(VALID_INFERENCE_PROVIDERS).default("anthropic"),
|
|
26
30
|
model: z.string().default("claude-opus-4-6"),
|
|
27
31
|
});
|
|
28
32
|
export type InferenceService = z.infer<typeof InferenceServiceSchema>;
|
|
29
33
|
|
|
30
|
-
export const ImageGenerationServiceSchema =
|
|
31
|
-
mode: ServiceModeSchema.default("your-own"),
|
|
34
|
+
export const ImageGenerationServiceSchema = BaseServiceSchema.extend({
|
|
32
35
|
provider: z.enum(VALID_IMAGE_GEN_PROVIDERS).default("gemini"),
|
|
33
36
|
model: z.string().default("gemini-3.1-flash-image-preview"),
|
|
34
37
|
});
|
|
@@ -36,15 +39,14 @@ export type ImageGenerationService = z.infer<
|
|
|
36
39
|
typeof ImageGenerationServiceSchema
|
|
37
40
|
>;
|
|
38
41
|
|
|
39
|
-
export const WebSearchServiceSchema =
|
|
40
|
-
mode: ServiceModeSchema.default("your-own"),
|
|
42
|
+
export const WebSearchServiceSchema = BaseServiceSchema.extend({
|
|
41
43
|
provider: z
|
|
42
44
|
.enum(VALID_WEB_SEARCH_PROVIDERS)
|
|
43
45
|
.default("inference-provider-native"),
|
|
44
46
|
});
|
|
45
47
|
export type WebSearchService = z.infer<typeof WebSearchServiceSchema>;
|
|
46
48
|
|
|
47
|
-
export const GoogleOAuthServiceSchema =
|
|
49
|
+
export const GoogleOAuthServiceSchema = BaseServiceSchema.extend({
|
|
48
50
|
mode: ServiceModeSchema.default("managed"),
|
|
49
51
|
});
|
|
50
52
|
export type GoogleOAuthService = z.infer<typeof GoogleOAuthServiceSchema>;
|
|
@@ -295,21 +295,28 @@ function syncChannels(
|
|
|
295
295
|
.get();
|
|
296
296
|
|
|
297
297
|
if (existing) {
|
|
298
|
+
// Preserve guardian blocks: if the channel is blocked, do not overwrite
|
|
299
|
+
// its status/policy — mirrors the guard in the cross-contact reassignment
|
|
300
|
+
// path so a blocked channel cannot be unblocked via a same-contact sync.
|
|
301
|
+
const isBlocked = existing.status === "blocked";
|
|
302
|
+
|
|
298
303
|
const updateSet: Record<string, unknown> = {};
|
|
299
304
|
if (ch.isPrimary !== undefined) updateSet.isPrimary = ch.isPrimary;
|
|
300
305
|
if (ch.externalUserId !== undefined)
|
|
301
306
|
updateSet.externalUserId = ch.externalUserId;
|
|
302
307
|
if (ch.externalChatId !== undefined)
|
|
303
308
|
updateSet.externalChatId = ch.externalChatId;
|
|
304
|
-
if (
|
|
305
|
-
|
|
309
|
+
if (!isBlocked) {
|
|
310
|
+
if (ch.status !== undefined) updateSet.status = ch.status;
|
|
311
|
+
if (ch.policy !== undefined) updateSet.policy = ch.policy;
|
|
312
|
+
if (ch.revokedReason !== undefined)
|
|
313
|
+
updateSet.revokedReason = ch.revokedReason;
|
|
314
|
+
if (ch.blockedReason !== undefined)
|
|
315
|
+
updateSet.blockedReason = ch.blockedReason;
|
|
316
|
+
}
|
|
306
317
|
if (ch.verifiedAt !== undefined) updateSet.verifiedAt = ch.verifiedAt;
|
|
307
318
|
if (ch.verifiedVia !== undefined) updateSet.verifiedVia = ch.verifiedVia;
|
|
308
319
|
if (ch.inviteId !== undefined) updateSet.inviteId = ch.inviteId;
|
|
309
|
-
if (ch.revokedReason !== undefined)
|
|
310
|
-
updateSet.revokedReason = ch.revokedReason;
|
|
311
|
-
if (ch.blockedReason !== undefined)
|
|
312
|
-
updateSet.blockedReason = ch.blockedReason;
|
|
313
320
|
|
|
314
321
|
if (Object.keys(updateSet).length > 0) {
|
|
315
322
|
updateSet.updatedAt = now;
|
|
@@ -681,13 +681,24 @@ function countPersistedMessages(messages: Message[]): number {
|
|
|
681
681
|
}).length;
|
|
682
682
|
}
|
|
683
683
|
|
|
684
|
-
|
|
684
|
+
function isSystemNoticeBlock(block: ContentBlock): boolean {
|
|
685
|
+
if (block.type !== "text") return false;
|
|
686
|
+
const text = (block as { text?: string }).text ?? "";
|
|
687
|
+
return (
|
|
688
|
+
text.startsWith("<system_notice>") && text.endsWith("</system_notice>")
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/** A user message that contains ONLY tool_result blocks (no text or other content).
|
|
693
|
+
* System notice text blocks (retry nudges, progress checks) do not count as user content. */
|
|
685
694
|
function isToolResultOnly(message: Message): boolean {
|
|
686
695
|
return (
|
|
687
696
|
message.content.length > 0 &&
|
|
688
697
|
message.content.every(
|
|
689
698
|
(block) =>
|
|
690
|
-
block.type === "tool_result" ||
|
|
699
|
+
block.type === "tool_result" ||
|
|
700
|
+
block.type === "web_search_tool_result" ||
|
|
701
|
+
isSystemNoticeBlock(block),
|
|
691
702
|
)
|
|
692
703
|
);
|
|
693
704
|
}
|
|
@@ -15,11 +15,16 @@ import type {
|
|
|
15
15
|
} from "../channels/types.js";
|
|
16
16
|
import {
|
|
17
17
|
addMessage,
|
|
18
|
+
getConversation,
|
|
18
19
|
getMessageById,
|
|
19
20
|
provenanceFromTrustContext,
|
|
20
21
|
updateMessageContent,
|
|
21
22
|
} from "../memory/conversation-crud.js";
|
|
22
|
-
import {
|
|
23
|
+
import { syncMessageToDisk } from "../memory/conversation-disk-view.js";
|
|
24
|
+
import {
|
|
25
|
+
backfillMessageIdOnLogs,
|
|
26
|
+
recordRequestLog,
|
|
27
|
+
} from "../memory/llm-request-log-store.js";
|
|
23
28
|
import type { ContentBlock, ImageContent } from "../providers/types.js";
|
|
24
29
|
import type { DirectiveRequest } from "./assistant-attachments.js";
|
|
25
30
|
import {
|
|
@@ -48,6 +53,8 @@ export interface EventHandlerState {
|
|
|
48
53
|
llmCallStartedEmitted: boolean;
|
|
49
54
|
pendingDirectiveDisplayBuffer: string;
|
|
50
55
|
firstAssistantText: string;
|
|
56
|
+
/** Most recent resolved provider for the current exchange's usage accounting. */
|
|
57
|
+
exchangeProviderName: string | undefined;
|
|
51
58
|
exchangeInputTokens: number;
|
|
52
59
|
exchangeCacheCreationInputTokens: number;
|
|
53
60
|
exchangeCacheReadInputTokens: number;
|
|
@@ -114,6 +121,7 @@ export function createEventHandlerState(): EventHandlerState {
|
|
|
114
121
|
llmCallStartedEmitted: false,
|
|
115
122
|
pendingDirectiveDisplayBuffer: "",
|
|
116
123
|
firstAssistantText: "",
|
|
124
|
+
exchangeProviderName: undefined,
|
|
117
125
|
exchangeInputTokens: 0,
|
|
118
126
|
exchangeCacheCreationInputTokens: 0,
|
|
119
127
|
exchangeCacheReadInputTokens: 0,
|
|
@@ -168,28 +176,10 @@ export function emitLlmCallStartedIfNeeded(
|
|
|
168
176
|
}
|
|
169
177
|
|
|
170
178
|
// ── Client Payload Size Caps ─────────────────────────────────────────
|
|
171
|
-
// The client truncates tool results anyway (20 000 chars in ChatViewModel),
|
|
172
|
-
// but the full string can be megabytes (file_read, bash output). Capping
|
|
173
|
-
// here avoids sending oversized payloads which get decoded on the
|
|
174
|
-
// client's main thread.
|
|
175
|
-
|
|
176
|
-
const TOOL_RESULT_MAX_CHARS = 20_000;
|
|
177
|
-
const TOOL_RESULT_TRUNCATION_SUFFIX = "...[truncated]";
|
|
178
|
-
|
|
179
179
|
// tool_input_delta streams accumulated JSON as tools run. For non-app
|
|
180
180
|
// tools the client discards it (extractCodePreview only handles app tools),
|
|
181
|
-
// so we
|
|
182
|
-
const
|
|
183
|
-
const APP_TOOL_NAMES = new Set(["app_create", "app_update"]);
|
|
184
|
-
|
|
185
|
-
function truncateForClient(
|
|
186
|
-
value: string,
|
|
187
|
-
maxChars: number,
|
|
188
|
-
suffix: string,
|
|
189
|
-
): string {
|
|
190
|
-
if (value.length <= maxChars) return value;
|
|
191
|
-
return value.slice(0, maxChars - suffix.length) + suffix;
|
|
192
|
-
}
|
|
181
|
+
// so we skip forwarding entirely to avoid transport/decode overhead.
|
|
182
|
+
const APP_TOOL_NAMES = new Set(["app_create"]);
|
|
193
183
|
|
|
194
184
|
// ── Friendly Tool Names ──────────────────────────────────────────────
|
|
195
185
|
|
|
@@ -207,11 +197,9 @@ const TOOL_FRIENDLY_NAMES: Record<string, string> = {
|
|
|
207
197
|
browser_scroll: "browser",
|
|
208
198
|
browser_wait: "browser",
|
|
209
199
|
app_create: "app",
|
|
210
|
-
|
|
200
|
+
app_refresh: "app refresh",
|
|
211
201
|
skill_load: "skill",
|
|
212
202
|
skill_execute: "skill",
|
|
213
|
-
app_file_edit: "app file",
|
|
214
|
-
app_file_write: "app file",
|
|
215
203
|
};
|
|
216
204
|
|
|
217
205
|
function friendlyToolName(name: string): string {
|
|
@@ -409,19 +397,14 @@ export function handleInputJsonDelta(
|
|
|
409
397
|
deps: EventHandlerDeps,
|
|
410
398
|
event: Extract<AgentEvent, { type: "input_json_delta" }>,
|
|
411
399
|
): void {
|
|
412
|
-
//
|
|
413
|
-
// app_create/app_update code previews
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
: truncateForClient(
|
|
417
|
-
event.accumulatedJson,
|
|
418
|
-
TOOL_INPUT_DELTA_MAX_CHARS,
|
|
419
|
-
TOOL_RESULT_TRUNCATION_SUFFIX,
|
|
420
|
-
);
|
|
400
|
+
// Only forward input deltas for app tools — the client only uses this
|
|
401
|
+
// stream for app_create/app_update code previews. Non-app tools would
|
|
402
|
+
// send large cumulative JSON on every delta with no benefit.
|
|
403
|
+
if (!APP_TOOL_NAMES.has(event.toolName)) return;
|
|
421
404
|
deps.onEvent({
|
|
422
405
|
type: "tool_input_delta",
|
|
423
406
|
toolName: event.toolName,
|
|
424
|
-
content,
|
|
407
|
+
content: event.accumulatedJson,
|
|
425
408
|
conversationId: deps.ctx.conversationId,
|
|
426
409
|
toolUseId: event.toolUseId,
|
|
427
410
|
});
|
|
@@ -438,11 +421,7 @@ export function handleToolResult(
|
|
|
438
421
|
deps.onEvent({
|
|
439
422
|
type: "tool_result",
|
|
440
423
|
toolName: "",
|
|
441
|
-
result:
|
|
442
|
-
event.content,
|
|
443
|
-
TOOL_RESULT_MAX_CHARS,
|
|
444
|
-
TOOL_RESULT_TRUNCATION_SUFFIX,
|
|
445
|
-
),
|
|
424
|
+
result: event.content,
|
|
446
425
|
isError: event.isError,
|
|
447
426
|
diff: event.diff,
|
|
448
427
|
status: event.status,
|
|
@@ -664,12 +643,21 @@ export async function handleMessageComplete(
|
|
|
664
643
|
assistantMessageInterface:
|
|
665
644
|
deps.turnInterfaceContext.assistantMessageInterface,
|
|
666
645
|
};
|
|
667
|
-
await addMessage(
|
|
646
|
+
const toolResultMsg = await addMessage(
|
|
668
647
|
deps.ctx.conversationId,
|
|
669
648
|
"user",
|
|
670
649
|
JSON.stringify(toolResultBlocks),
|
|
671
650
|
toolResultMetadata,
|
|
672
651
|
);
|
|
652
|
+
// Sync tool-result user message to disk view
|
|
653
|
+
const convForToolResult = getConversation(deps.ctx.conversationId);
|
|
654
|
+
if (convForToolResult) {
|
|
655
|
+
syncMessageToDisk(
|
|
656
|
+
deps.ctx.conversationId,
|
|
657
|
+
toolResultMsg.id,
|
|
658
|
+
convForToolResult.createdAt,
|
|
659
|
+
);
|
|
660
|
+
}
|
|
673
661
|
for (const id of state.pendingToolResults.keys()) {
|
|
674
662
|
state.persistedToolUseIds.add(id);
|
|
675
663
|
}
|
|
@@ -734,6 +722,18 @@ export async function handleMessageComplete(
|
|
|
734
722
|
);
|
|
735
723
|
state.lastAssistantMessageId = assistantMsg.id;
|
|
736
724
|
|
|
725
|
+
// Backfill message_id on all LLM request logs from this turn.
|
|
726
|
+
// The agent loop is single-threaded per conversation, so all rows with
|
|
727
|
+
// message_id IS NULL belong to the current turn.
|
|
728
|
+
try {
|
|
729
|
+
backfillMessageIdOnLogs(deps.ctx.conversationId, assistantMsg.id);
|
|
730
|
+
} catch (err) {
|
|
731
|
+
deps.rlog.warn(
|
|
732
|
+
{ err },
|
|
733
|
+
"Failed to backfill message_id on LLM request logs (non-fatal)",
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
737
|
deps.ctx.currentTurnSurfaces = [];
|
|
738
738
|
|
|
739
739
|
// Emit trace event
|
|
@@ -761,6 +761,8 @@ export function handleUsage(
|
|
|
761
761
|
deps: EventHandlerDeps,
|
|
762
762
|
event: Extract<AgentEvent, { type: "usage" }>,
|
|
763
763
|
): void {
|
|
764
|
+
const providerName = event.actualProvider ?? deps.ctx.provider.name;
|
|
765
|
+
state.exchangeProviderName = providerName;
|
|
764
766
|
state.exchangeInputTokens += event.inputTokens;
|
|
765
767
|
state.exchangeCacheCreationInputTokens += event.cacheCreationInputTokens ?? 0;
|
|
766
768
|
state.exchangeCacheReadInputTokens += event.cacheReadInputTokens ?? 0;
|
|
@@ -776,6 +778,8 @@ export function handleUsage(
|
|
|
776
778
|
deps.ctx.conversationId,
|
|
777
779
|
JSON.stringify(event.rawRequest),
|
|
778
780
|
JSON.stringify(event.rawResponse),
|
|
781
|
+
undefined,
|
|
782
|
+
providerName,
|
|
779
783
|
);
|
|
780
784
|
} catch (err) {
|
|
781
785
|
deps.rlog.warn({ err }, "Failed to persist LLM request log (non-fatal)");
|
|
@@ -786,12 +790,12 @@ export function handleUsage(
|
|
|
786
790
|
|
|
787
791
|
deps.ctx.traceEmitter.emit(
|
|
788
792
|
"llm_call_finished",
|
|
789
|
-
`LLM call to ${
|
|
793
|
+
`LLM call to ${providerName} finished`,
|
|
790
794
|
{
|
|
791
795
|
requestId: deps.reqId,
|
|
792
796
|
status: "success",
|
|
793
797
|
attributes: {
|
|
794
|
-
provider:
|
|
798
|
+
provider: providerName,
|
|
795
799
|
model: event.model,
|
|
796
800
|
inputTokens: event.inputTokens,
|
|
797
801
|
outputTokens: event.outputTokens,
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
setSentryConversationContext,
|
|
33
33
|
} from "../instrument.js";
|
|
34
34
|
import { commitAppTurnChanges } from "../memory/app-git-service.js";
|
|
35
|
-
import { getApp, listAppFiles } from "../memory/app-store.js";
|
|
35
|
+
import { getApp, listAppFiles, resolveAppDir } from "../memory/app-store.js";
|
|
36
36
|
import {
|
|
37
37
|
addMessage,
|
|
38
38
|
deleteMessageById,
|
|
@@ -43,6 +43,10 @@ import {
|
|
|
43
43
|
updateConversationContextWindow,
|
|
44
44
|
updateConversationTitle,
|
|
45
45
|
} from "../memory/conversation-crud.js";
|
|
46
|
+
import {
|
|
47
|
+
rebuildConversationDiskViewFromDbState,
|
|
48
|
+
syncMessageToDisk,
|
|
49
|
+
} from "../memory/conversation-disk-view.js";
|
|
46
50
|
import {
|
|
47
51
|
isReplaceableTitle,
|
|
48
52
|
queueGenerateConversationTitle,
|
|
@@ -77,7 +81,6 @@ import {
|
|
|
77
81
|
} from "./conversation-agent-loop-handlers.js";
|
|
78
82
|
import {
|
|
79
83
|
approveHostAttachmentRead,
|
|
80
|
-
formatAttachmentWarnings,
|
|
81
84
|
resolveAssistantAttachments,
|
|
82
85
|
} from "./conversation-attachments.js";
|
|
83
86
|
import {
|
|
@@ -173,11 +176,9 @@ const TOOL_FRIENDLY_LABEL: Record<string, string> = {
|
|
|
173
176
|
browser_scroll: "Browser",
|
|
174
177
|
browser_wait: "Browser",
|
|
175
178
|
app_create: "Create App",
|
|
176
|
-
|
|
179
|
+
app_refresh: "Refresh App",
|
|
177
180
|
skill_load: "Load Skill",
|
|
178
181
|
skill_execute: "Run Skill Tool",
|
|
179
|
-
app_file_edit: "Edit App File",
|
|
180
|
-
app_file_write: "Write App File",
|
|
181
182
|
};
|
|
182
183
|
|
|
183
184
|
type GitServiceInitializer = {
|
|
@@ -604,6 +605,7 @@ export async function runAgentLoopImpl(
|
|
|
604
605
|
if (app) {
|
|
605
606
|
activeSurface.appId = app.id;
|
|
606
607
|
activeSurface.appName = app.name;
|
|
608
|
+
activeSurface.appDirName = resolveAppDir(app.id).dirName;
|
|
607
609
|
activeSurface.appSchemaJson = app.schemaJson;
|
|
608
610
|
activeSurface.appFiles = listAppFiles(app.id);
|
|
609
611
|
if (app.pages && Object.keys(app.pages).length > 0) {
|
|
@@ -801,7 +803,16 @@ export async function runAgentLoopImpl(
|
|
|
801
803
|
mode: currentInjectionMode,
|
|
802
804
|
});
|
|
803
805
|
|
|
804
|
-
|
|
806
|
+
// Re-estimate with injections included — step.estimatedTokens was
|
|
807
|
+
// computed on bare history (ctx.messages) and doesn't account for
|
|
808
|
+
// tokens added by runtime injections.
|
|
809
|
+
const postInjectionTokens = estimatePromptTokens(
|
|
810
|
+
runMessages,
|
|
811
|
+
ctx.systemPrompt,
|
|
812
|
+
{ providerName: ctx.provider.name, toolTokenBudget },
|
|
813
|
+
);
|
|
814
|
+
|
|
815
|
+
if (postInjectionTokens <= preflightBudget) break;
|
|
805
816
|
}
|
|
806
817
|
}
|
|
807
818
|
|
|
@@ -1173,6 +1184,7 @@ export async function runAgentLoopImpl(
|
|
|
1173
1184
|
preRepairMessages = runMessages;
|
|
1174
1185
|
preRunHistoryLength = runMessages.length;
|
|
1175
1186
|
state.contextTooLargeDetected = false;
|
|
1187
|
+
yieldedForBudget = false;
|
|
1176
1188
|
|
|
1177
1189
|
updatedHistory = await ctx.agentLoop.run(
|
|
1178
1190
|
runMessages,
|
|
@@ -1195,6 +1207,15 @@ export async function runAgentLoopImpl(
|
|
|
1195
1207
|
"Post-convergence rerun still yielded at checkpoint — continuing reduction",
|
|
1196
1208
|
);
|
|
1197
1209
|
state.contextTooLargeDetected = true;
|
|
1210
|
+
|
|
1211
|
+
// Fold rerun progress into ctx.messages so the next reducer
|
|
1212
|
+
// tier operates on up-to-date history instead of stale
|
|
1213
|
+
// pre-rerun messages.
|
|
1214
|
+
if (updatedHistory.length > preRunHistoryLength) {
|
|
1215
|
+
ctx.messages = stripInjectedContext(updatedHistory);
|
|
1216
|
+
preRepairMessages = updatedHistory;
|
|
1217
|
+
preRunHistoryLength = updatedHistory.length;
|
|
1218
|
+
}
|
|
1198
1219
|
}
|
|
1199
1220
|
}
|
|
1200
1221
|
|
|
@@ -1514,16 +1535,29 @@ export async function runAgentLoopImpl(
|
|
|
1514
1535
|
state.exchangeCacheCreationInputTokens,
|
|
1515
1536
|
state.exchangeCacheReadInputTokens,
|
|
1516
1537
|
collapseRawResponses(state.exchangeRawResponses),
|
|
1538
|
+
state.exchangeProviderName,
|
|
1517
1539
|
);
|
|
1518
1540
|
|
|
1519
1541
|
void getHookManager().trigger("post-message", {
|
|
1520
1542
|
conversationId: ctx.conversationId,
|
|
1521
1543
|
});
|
|
1522
1544
|
|
|
1545
|
+
const syncLastAssistantMessageToDisk = (): void => {
|
|
1546
|
+
if (!state.lastAssistantMessageId) return;
|
|
1547
|
+
const convForDisk = getConversation(ctx.conversationId);
|
|
1548
|
+
if (!convForDisk) return;
|
|
1549
|
+
syncMessageToDisk(
|
|
1550
|
+
ctx.conversationId,
|
|
1551
|
+
state.lastAssistantMessageId,
|
|
1552
|
+
convForDisk.createdAt,
|
|
1553
|
+
);
|
|
1554
|
+
};
|
|
1555
|
+
|
|
1523
1556
|
// Fast-path: when the user cancelled, skip expensive post-loop work
|
|
1524
1557
|
// (attachment resolution) and emit the cancellation event immediately
|
|
1525
1558
|
// so the client can re-enable the UI without delay.
|
|
1526
1559
|
if (abortController.signal.aborted) {
|
|
1560
|
+
syncLastAssistantMessageToDisk();
|
|
1527
1561
|
ctx.emitActivityState("idle", "generation_cancelled", "global", reqId);
|
|
1528
1562
|
ctx.traceEmitter.emit(
|
|
1529
1563
|
"generation_cancelled",
|
|
@@ -1559,17 +1593,7 @@ export async function runAgentLoopImpl(
|
|
|
1559
1593
|
|
|
1560
1594
|
ctx.lastAssistantAttachments = assistantAttachments;
|
|
1561
1595
|
ctx.lastAttachmentWarnings = attachmentResult.directiveWarnings;
|
|
1562
|
-
|
|
1563
|
-
const warningText = formatAttachmentWarnings(
|
|
1564
|
-
attachmentResult.directiveWarnings,
|
|
1565
|
-
);
|
|
1566
|
-
if (warningText) {
|
|
1567
|
-
onEvent({
|
|
1568
|
-
type: "assistant_text_delta",
|
|
1569
|
-
text: warningText,
|
|
1570
|
-
conversationId: ctx.conversationId,
|
|
1571
|
-
});
|
|
1572
|
-
}
|
|
1596
|
+
syncLastAssistantMessageToDisk();
|
|
1573
1597
|
|
|
1574
1598
|
// Re-check: the user may have cancelled during attachment resolution
|
|
1575
1599
|
if (abortController.signal.aborted) {
|
|
@@ -1604,6 +1628,9 @@ export async function runAgentLoopImpl(
|
|
|
1604
1628
|
...(emittedAttachments.length > 0
|
|
1605
1629
|
? { attachments: emittedAttachments }
|
|
1606
1630
|
: {}),
|
|
1631
|
+
...(ctx.lastAttachmentWarnings.length > 0
|
|
1632
|
+
? { attachmentWarnings: ctx.lastAttachmentWarnings }
|
|
1633
|
+
: {}),
|
|
1607
1634
|
...(state.lastAssistantMessageId
|
|
1608
1635
|
? { messageId: state.lastAssistantMessageId }
|
|
1609
1636
|
: {}),
|
|
@@ -1624,6 +1651,9 @@ export async function runAgentLoopImpl(
|
|
|
1624
1651
|
...(emittedAttachments.length > 0
|
|
1625
1652
|
? { attachments: emittedAttachments }
|
|
1626
1653
|
: {}),
|
|
1654
|
+
...(ctx.lastAttachmentWarnings.length > 0
|
|
1655
|
+
? { attachmentWarnings: ctx.lastAttachmentWarnings }
|
|
1656
|
+
: {}),
|
|
1627
1657
|
...(state.lastAssistantMessageId
|
|
1628
1658
|
? { messageId: state.lastAssistantMessageId }
|
|
1629
1659
|
: {}),
|
|
@@ -1739,7 +1769,13 @@ export async function runAgentLoopImpl(
|
|
|
1739
1769
|
ctx.commandIntent = undefined;
|
|
1740
1770
|
|
|
1741
1771
|
if (userMessageId) {
|
|
1742
|
-
consolidateAssistantMessages(
|
|
1772
|
+
const didMutateHistory = consolidateAssistantMessages(
|
|
1773
|
+
ctx.conversationId,
|
|
1774
|
+
userMessageId,
|
|
1775
|
+
);
|
|
1776
|
+
if (didMutateHistory) {
|
|
1777
|
+
rebuildConversationDiskViewFromDbState(ctx.conversationId);
|
|
1778
|
+
}
|
|
1743
1779
|
}
|
|
1744
1780
|
|
|
1745
1781
|
ctx.drainQueue(yieldedForHandoff ? "checkpoint_handoff" : "loop_complete");
|
|
@@ -1766,11 +1802,12 @@ function emitUsage(
|
|
|
1766
1802
|
cacheCreationInputTokens = 0,
|
|
1767
1803
|
cacheReadInputTokens = 0,
|
|
1768
1804
|
rawResponse?: unknown,
|
|
1805
|
+
providerName?: string,
|
|
1769
1806
|
): void {
|
|
1770
1807
|
recordUsage(
|
|
1771
1808
|
{
|
|
1772
1809
|
conversationId: ctx.conversationId,
|
|
1773
|
-
providerName: ctx.provider.name,
|
|
1810
|
+
providerName: providerName ?? ctx.provider.name,
|
|
1774
1811
|
usageStats: ctx.usageStats,
|
|
1775
1812
|
},
|
|
1776
1813
|
inputTokens,
|