@vellumai/assistant 0.11.1 → 0.11.2-staging.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/Dockerfile +1 -3
- package/README.md +1 -1
- package/eslint.config.mjs +28 -8
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/stripe-currency.test.ts +37 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/stripe-currency.ts +55 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/stripe-currency.test.ts +37 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/stripe-currency.ts +55 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/stripe-currency.test.ts +37 -0
- package/node_modules/@vellumai/service-contracts/src/stripe-currency.ts +55 -0
- package/node_modules/@vellumai/slack-text/src/index.test.ts +48 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +25 -6
- package/openapi.yaml +292 -5
- package/package.json +1 -1
- package/src/__tests__/agent-loop-resume-interrupted.test.ts +223 -0
- package/src/__tests__/byok-default-profile-ensure.test.ts +43 -0
- package/src/__tests__/cli-logger-boundary-guard.test.ts +87 -0
- package/src/__tests__/compaction-events.test.ts +139 -2
- package/src/__tests__/config-loader-backfill.test.ts +35 -3
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +30 -0
- package/src/__tests__/conversation-agent-loop.test.ts +180 -7
- package/src/__tests__/conversation-error.test.ts +211 -4
- package/src/__tests__/conversation-options-turn-scoped-transport.test.ts +64 -0
- package/src/__tests__/conversation-queue.test.ts +126 -0
- package/src/__tests__/conversation-retry-route.test.ts +46 -7
- package/src/__tests__/conversation-slash.test.ts +4 -2
- package/src/__tests__/conversation-summarize-route.test.ts +7 -1
- package/src/__tests__/conversation-summarize-up-to.test.ts +71 -5
- package/src/__tests__/document-create-dedupe.test.ts +2 -1
- package/src/__tests__/document-find-replace.test.ts +2 -1
- package/src/__tests__/document-tool-security.test.ts +2 -1
- package/src/__tests__/document-update-default-surface.test.ts +2 -1
- package/src/__tests__/document-workspace-file.test.ts +467 -0
- package/src/__tests__/emit-signal-routing-intent.test.ts +290 -49
- package/src/__tests__/guardian-card-withdrawal.test.ts +91 -3
- package/src/__tests__/http-user-message-parity.test.ts +66 -0
- package/src/__tests__/list-messages-attachments.test.ts +87 -0
- package/src/__tests__/list-messages-provider-error.test.ts +143 -0
- package/src/__tests__/list-messages-system-card.test.ts +100 -0
- package/src/__tests__/llm-resolver.test.ts +19 -9
- package/src/__tests__/managed-profile-guard.test.ts +23 -0
- package/src/__tests__/notification-platform-adapter.test.ts +130 -2
- package/src/__tests__/notification-telegram-adapter.test.ts +6 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +45 -0
- package/src/__tests__/plugin-api-model-profiles.test.ts +10 -1
- package/src/__tests__/plugin-import-boundary-guard.test.ts +3 -0
- package/src/__tests__/provider-error-scenarios.test.ts +140 -0
- package/src/__tests__/provider-send-message-override-profile.test.ts +95 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +66 -3
- package/src/__tests__/scripted-turn-metadata-persistence.test.ts +209 -0
- package/src/__tests__/skills.test.ts +27 -0
- package/src/__tests__/slack-channels-routes.test.ts +0 -2
- package/src/__tests__/slack-share-routes.test.ts +0 -3
- package/src/__tests__/slack-users-routes.test.ts +0 -2
- package/src/__tests__/subagent-tools.test.ts +11 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +58 -0
- package/src/__tests__/tool-result-spool.test.ts +5 -4
- package/src/__tests__/turn-boundary-resolution.test.ts +53 -0
- package/src/__tests__/turn-events-store.test.ts +26 -0
- package/src/__tests__/ui-visual-surface.test.ts +695 -0
- package/src/__tests__/unified-turn-context-visible-app.test.ts +99 -0
- package/src/__tests__/visible-app-context.test.ts +189 -0
- package/src/__tests__/workspace-git-service.test.ts +173 -33
- package/src/__tests__/workspace-migration-137-repair-retired-fireworks-minimax-model-id.test.ts +157 -0
- package/src/__tests__/workspace-migration-138-backfill-home-feed-titles.test.ts +373 -0
- package/src/__tests__/workspace-migration-139-clear-renamed-cost-profile-label.test.ts +137 -0
- package/src/agent/loop.ts +36 -7
- package/src/api/events/context-window-usage.ts +31 -0
- package/src/api/events/notification-intent.ts +8 -0
- package/src/api/events/ui-surface-pending.ts +35 -0
- package/src/api/index.ts +14 -0
- package/src/api/responses/conversation-message.ts +25 -4
- package/src/api/surfaces.ts +90 -1
- package/src/approvals/guardian-card-withdrawal.ts +66 -31
- package/src/approvals/guardian-decision-primitive.ts +4 -0
- package/src/calls/__tests__/call-setup-router.test.ts +156 -26
- package/src/calls/__tests__/voice-session-bridge.test.ts +201 -12
- package/src/calls/call-setup-router.ts +80 -36
- package/src/calls/voice-session-bridge.ts +173 -26
- package/src/cli/commands/inference.help.ts +3 -3
- package/src/cli/commands/notifications.help.ts +3 -2
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +42 -128
- package/src/cli/commands/platform/__tests__/credits.test.ts +9 -78
- package/src/cli/commands/platform/__tests__/helpers.ts +90 -0
- package/src/cli/commands/platform/__tests__/invoices.test.ts +238 -0
- package/src/cli/commands/platform/__tests__/plans.test.ts +9 -88
- package/src/cli/commands/platform/__tests__/status.test.ts +12 -87
- package/src/cli/commands/platform/__tests__/subscription.test.ts +9 -86
- package/src/cli/commands/platform/index.help.ts +92 -0
- package/src/cli/commands/platform/index.ts +7 -0
- package/src/cli/commands/platform/invoices.ts +132 -0
- package/src/cli/commands/usage.help.ts +1 -1
- package/src/cli/lib/list-installed-plugins.ts +2 -1
- package/src/config/__tests__/default-profile-catalog.test.ts +7 -10
- package/src/config/__tests__/deployment-context-defaults.test.ts +27 -5
- package/src/config/assistant-feature-flags.ts +7 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +3 -2
- package/src/config/bundled-skills/subagent/SKILL.md +3 -1
- package/src/config/bundled-skills/subagent/TOOLS.json +3 -3
- package/src/config/bundled-skills/visualize/SKILL.md +163 -0
- package/src/config/call-site-defaults.ts +3 -2
- package/src/config/default-profile-catalog.ts +75 -70
- package/src/config/default-profile-names.ts +13 -28
- package/src/config/env-registry.ts +1 -0
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/llm-resolver.ts +21 -5
- package/src/config/loader.ts +18 -11
- package/src/config/schemas/llm.ts +1 -9
- package/src/config/schemas/memory-retrospective.ts +9 -0
- package/src/config/schemas/monitoring.ts +28 -2
- package/src/config/schemas/workspace-git.ts +15 -0
- package/src/config/seed-inference-profiles.ts +19 -5
- package/src/context/post-turn-tool-result-truncation.ts +2 -2
- package/src/conversations/__tests__/message-consolidation.test.ts +54 -0
- package/src/conversations/message-consolidation.ts +17 -15
- package/src/daemon/__tests__/turn-tail-assistant-reply-notify.test.ts +182 -0
- package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +181 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +90 -7
- package/src/daemon/conversation-agent-loop.ts +107 -22
- package/src/daemon/conversation-error.ts +169 -48
- package/src/daemon/conversation-messaging.ts +87 -4
- package/src/daemon/conversation-process.ts +57 -45
- package/src/daemon/conversation-runtime-assembly.ts +57 -0
- package/src/daemon/conversation-store.ts +36 -1
- package/src/daemon/conversation-surfaces.ts +68 -6
- package/src/daemon/conversation-turn-finalize.ts +76 -18
- package/src/daemon/conversation.ts +122 -27
- package/src/daemon/lifecycle.ts +9 -0
- package/src/daemon/message-types/conversations.ts +8 -0
- package/src/daemon/message-types/surfaces.ts +3 -0
- package/src/documents/document-store.ts +247 -10
- package/src/home/__tests__/feed-types.test.ts +43 -8
- package/src/home/__tests__/feed-writer.test.ts +59 -0
- package/src/home/feed-types.ts +34 -7
- package/src/home/feed-writer.ts +15 -6
- package/src/live-voice/__tests__/activity-label.test.ts +95 -0
- package/src/live-voice/__tests__/live-activity-reporter.test.ts +86 -5
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +310 -25
- package/src/live-voice/__tests__/live-voice-events.test.ts +4 -4
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +8 -4
- package/src/live-voice/__tests__/live-voice-vad.test.ts +9 -1
- package/src/live-voice/activity-label.ts +169 -0
- package/src/live-voice/live-activity-reporter.ts +35 -6
- package/src/live-voice/live-voice-session.ts +282 -41
- package/src/live-voice/protocol.ts +35 -0
- package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +84 -2
- package/src/messaging/providers/slack/adapter.ts +86 -19
- package/src/messaging/providers/slack/api.test.ts +85 -1
- package/src/messaging/providers/slack/api.ts +121 -288
- package/src/messaging/providers/slack/client.ts +20 -251
- package/src/messaging/providers/slack/send.test.ts +4 -9
- package/src/messaging/providers/slack/send.ts +1 -1
- package/src/messaging/providers/slack/types.ts +5 -0
- package/src/messaging/providers/slack/web-api-transport.test.ts +181 -0
- package/src/messaging/providers/slack/web-api-transport.ts +367 -0
- package/src/messaging/providers/slack/withdraw.ts +6 -14
- package/src/messaging/providers/telegram-bot/send.test.ts +31 -1
- package/src/messaging/providers/telegram-bot/send.ts +23 -2
- package/src/messaging/providers/telegram-bot/withdraw.test.ts +152 -0
- package/src/messaging/providers/telegram-bot/withdraw.ts +166 -0
- package/src/monitoring/__tests__/db-integrity-sample.test.ts +18 -4
- package/src/monitoring/__tests__/file-descriptors.test.ts +144 -0
- package/src/monitoring/file-descriptors.ts +262 -0
- package/src/monitoring/process-memory.ts +4 -11
- package/src/monitoring/resource-sampler.ts +5 -0
- package/src/monitoring/worker.ts +12 -0
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +740 -0
- package/src/notifications/__tests__/broadcaster.test.ts +347 -7
- package/src/notifications/__tests__/copy-composer.test.ts +53 -3
- package/src/notifications/__tests__/decision-engine.test.ts +349 -29
- package/src/notifications/__tests__/deterministic-checks.test.ts +21 -0
- package/src/notifications/__tests__/edit-notification.test.ts +330 -0
- package/src/notifications/__tests__/guardian-delivery-recorder.test.ts +71 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +170 -12
- package/src/notifications/adapters/macos.ts +3 -0
- package/src/notifications/adapters/platform.ts +90 -14
- package/src/notifications/adapters/telegram.ts +6 -4
- package/src/notifications/assistant-reply-producer.ts +219 -0
- package/src/notifications/broadcaster.ts +523 -317
- package/src/notifications/copy-composer.ts +27 -6
- package/src/notifications/decision-engine.ts +154 -77
- package/src/notifications/deterministic-checks.ts +6 -7
- package/src/notifications/edit-notification.ts +8 -4
- package/src/notifications/emit-signal.ts +49 -16
- package/src/notifications/guardian-delivery-recorder.ts +8 -2
- package/src/notifications/home-feed-side-effect.ts +43 -6
- package/src/notifications/notification-utils.ts +39 -4
- package/src/notifications/signal.ts +10 -0
- package/src/notifications/types.ts +17 -0
- package/src/persistence/bookmark-crud.ts +18 -9
- package/src/persistence/conversation-attention-store.ts +26 -0
- package/src/persistence/conversation-crud.ts +79 -32
- package/src/persistence/conversation-queries.ts +30 -15
- package/src/persistence/conversation-title-service.ts +5 -170
- package/src/persistence/conversation-types.ts +192 -1
- package/src/persistence/db-init.ts +14 -1
- package/src/persistence/db-maintenance.ts +5 -4
- package/src/persistence/embeddings/__tests__/plugin-index-qdrant-init.test.ts +219 -0
- package/src/persistence/embeddings/__tests__/plugin-index.test.ts +22 -0
- package/src/persistence/embeddings/__tests__/worker-script-version.test.ts +76 -0
- package/src/persistence/embeddings/embedding-local.ts +2 -1
- package/src/persistence/embeddings/embedding-runtime-manager.ts +29 -5
- package/src/persistence/embeddings/plugin-index.ts +84 -12
- package/src/persistence/migrations/360-add-document-workspace-path.test.ts +110 -0
- package/src/persistence/migrations/360-add-document-workspace-path.ts +39 -0
- package/src/persistence/planner-statistics.ts +14 -0
- package/src/persistence/schema/documents.ts +26 -11
- package/src/persistence/steps.ts +2 -0
- package/src/platform/client.test.ts +172 -2
- package/src/platform/client.ts +178 -55
- package/src/plugin-api/conversation-turn.ts +13 -0
- package/src/plugin-api/model-profiles.test.ts +6 -2
- package/src/plugins/defaults/memory/__tests__/bookmark-crud.test.ts +34 -0
- package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +22 -0
- package/src/plugins/defaults/memory/__tests__/jobs-store-enqueue-gate.test.ts +11 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +199 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-enqueue.test.ts +98 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +105 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +24 -2
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-wake-chain.test.ts +524 -0
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +1 -1
- package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +9 -4
- package/src/plugins/defaults/memory/host-utils.ts +5 -0
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +105 -1
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +64 -5
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +36 -1
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +12 -3
- package/src/plugins/defaults/memory/src/__tests__/memory-v2-simulate-route.test.ts +1 -0
- package/src/plugins/defaults/memory/substrate/__tests__/skill-store.test.ts +195 -1
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +1 -1
- package/src/plugins/defaults/memory/substrate/skill-store.ts +167 -29
- package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +131 -0
- package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +1 -0
- package/src/plugins/defaults/memory/v2/activation-log-store.ts +4 -0
- package/src/plugins/defaults/memory/v2/injection.ts +48 -3
- package/src/plugins/defaults/memory/v2/rerank-local.ts +6 -2
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +1 -1
- package/src/plugins/defaults/platform-hosted/routes/reengage.ts +1 -1
- package/src/plugins/defaults/turn-context/injectors.ts +1 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +26 -0
- package/src/plugins/types.ts +17 -0
- package/src/prompts/templates/system-sections.ts +2 -2
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +43 -2
- package/src/providers/__tests__/vellum-mismatch-routing.test.ts +8 -0
- package/src/providers/call-site-routing.ts +77 -14
- package/src/providers/connection-resolution.ts +42 -2
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +127 -1
- package/src/providers/inference/adapter-factory.ts +70 -12
- package/src/providers/model-catalog.ts +0 -11
- package/src/providers/model-intents.ts +11 -0
- package/src/providers/registry.ts +8 -0
- package/src/providers/retry.ts +85 -17
- package/src/providers/types.ts +8 -1
- package/src/runtime/__tests__/agent-wake.test.ts +181 -0
- package/src/runtime/agent-wake.ts +132 -9
- package/src/runtime/channel-approval-types.ts +25 -0
- package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +2 -2
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +11 -0
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +121 -9
- package/src/runtime/routes/__tests__/platform-invoice-routes.test.ts +392 -0
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +7 -0
- package/src/runtime/routes/__tests__/workspace-commit-routes.test.ts +63 -0
- package/src/runtime/routes/consolidation-routes.ts +1 -1
- package/src/runtime/routes/conversation-management-routes.ts +18 -6
- package/src/runtime/routes/conversation-query-routes.ts +14 -23
- package/src/runtime/routes/conversation-routes.ts +113 -8
- package/src/runtime/routes/credential-routes.ts +1 -5
- package/src/runtime/routes/documents-routes.ts +207 -12
- package/src/runtime/routes/identity-routes.ts +3 -93
- package/src/runtime/routes/inbound-stages/admission-policy.test.ts +31 -1
- package/src/runtime/routes/inbound-stages/admission-policy.ts +18 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +52 -3
- package/src/runtime/routes/notification-routes.ts +4 -1
- package/src/runtime/routes/platform-routes.ts +238 -3
- package/src/runtime/routes/playground/guard.ts +1 -2
- package/src/runtime/routes/slack-channel-routes.ts +2 -4
- package/src/runtime/routes/workspace-commit-routes.ts +49 -2
- package/src/runtime/routes/workspace-routes.ts +11 -12
- package/src/runtime/routes/workspace-utils.ts +49 -2
- package/src/runtime/services/conversation-serializer.ts +2 -4
- package/src/subagent/__tests__/consult-context-gating.test.ts +98 -0
- package/src/subagent/__tests__/consult-context-skills.test.ts +82 -0
- package/src/subagent/__tests__/consult-context.test.ts +84 -0
- package/src/subagent/__tests__/consult-prompt.test.ts +36 -0
- package/src/subagent/consult-context.ts +410 -0
- package/src/subagent/consult-prompt.ts +38 -5
- package/src/subagent/manager.ts +9 -4
- package/src/subagent/types.ts +8 -0
- package/src/telemetry/telemetry-event-sources.ts +7 -0
- package/src/telemetry/telemetry-wire-source.json +1 -1
- package/src/telemetry/telemetry-wire.generated.ts +1 -0
- package/src/telemetry/turn-events-store.ts +30 -1
- package/src/telemetry/types.ts +24 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
- package/src/tools/browser/pinned-tabs.ts +3 -1
- package/src/tools/subagent/spawn.ts +23 -1
- package/src/tools/terminal/safe-env.ts +1 -0
- package/src/tools/ui-surface/definitions.ts +39 -1
- package/src/tools/ui-surface/surface-shape-docs.ts +38 -4
- package/src/tools/ui-surface/visual-validation.ts +787 -0
- package/src/tools/workflows/run-workflow.test.ts +1 -0
- package/src/util/__tests__/short-title.test.ts +229 -0
- package/src/util/__tests__/worker-compute.test.ts +65 -0
- package/src/util/cgroup-cpu.ts +93 -0
- package/src/util/errors.ts +27 -0
- package/src/util/process-tree.ts +19 -0
- package/src/util/short-title.ts +189 -0
- package/src/util/worker-compute.ts +83 -0
- package/src/workspace/byok-default-profile-ensure.ts +25 -15
- package/src/workspace/git-service.ts +79 -30
- package/src/workspace/migrations/137-repair-retired-fireworks-minimax-model-id.ts +131 -0
- package/src/workspace/migrations/138-backfill-home-feed-titles.ts +179 -0
- package/src/workspace/migrations/139-clear-renamed-cost-profile-label.ts +92 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/plugins/defaults/memory/substrate/constants.ts +0 -8
package/openapi.yaml
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
openapi: 3.1.0
|
|
4
4
|
info:
|
|
5
5
|
title: Vellum Assistant API
|
|
6
|
-
version: 0.11.
|
|
6
|
+
version: 0.11.2
|
|
7
7
|
description: Auto-generated OpenAPI specification for the Vellum Assistant runtime HTTP server.
|
|
8
8
|
servers:
|
|
9
9
|
- url: http://127.0.0.1:7821
|
|
@@ -699,6 +699,52 @@ paths:
|
|
|
699
699
|
required:
|
|
700
700
|
- ok
|
|
701
701
|
additionalProperties: false
|
|
702
|
+
/v1/admin/workspace-compact-history:
|
|
703
|
+
post:
|
|
704
|
+
operationId: admin_workspacecompacthistory_post
|
|
705
|
+
summary: Compact workspace git history
|
|
706
|
+
description:
|
|
707
|
+
Squash workspace git history older than the retention window into a single base commit and prune reclaimed
|
|
708
|
+
objects. By default acts only when an oversized blob is reclaimable; with force, the squash runs
|
|
709
|
+
unconditionally.
|
|
710
|
+
tags:
|
|
711
|
+
- admin
|
|
712
|
+
requestBody:
|
|
713
|
+
required: true
|
|
714
|
+
content:
|
|
715
|
+
application/json:
|
|
716
|
+
schema:
|
|
717
|
+
type: object
|
|
718
|
+
properties:
|
|
719
|
+
force:
|
|
720
|
+
description: Squash aged history even when no oversized blob is reclaimable
|
|
721
|
+
type: boolean
|
|
722
|
+
retentionDays:
|
|
723
|
+
description: Retention window override in days (default 7)
|
|
724
|
+
type: integer
|
|
725
|
+
exclusiveMinimum: 0
|
|
726
|
+
maximum: 9007199254740991
|
|
727
|
+
responses:
|
|
728
|
+
"200":
|
|
729
|
+
description: Successful response
|
|
730
|
+
content:
|
|
731
|
+
application/json:
|
|
732
|
+
schema:
|
|
733
|
+
type: object
|
|
734
|
+
properties:
|
|
735
|
+
rewrote:
|
|
736
|
+
type: boolean
|
|
737
|
+
squashedCommits:
|
|
738
|
+
type: number
|
|
739
|
+
keptCommits:
|
|
740
|
+
type: number
|
|
741
|
+
retryAfterMs:
|
|
742
|
+
type: number
|
|
743
|
+
required:
|
|
744
|
+
- rewrote
|
|
745
|
+
- squashedCommits
|
|
746
|
+
- keptCommits
|
|
747
|
+
additionalProperties: false
|
|
702
748
|
/v1/apps:
|
|
703
749
|
get:
|
|
704
750
|
operationId: apps_get
|
|
@@ -10665,6 +10711,11 @@ paths:
|
|
|
10665
10711
|
type: number
|
|
10666
10712
|
updatedAt:
|
|
10667
10713
|
type: number
|
|
10714
|
+
workspacePath:
|
|
10715
|
+
anyOf:
|
|
10716
|
+
- type: string
|
|
10717
|
+
- type: "null"
|
|
10718
|
+
description: Workspace-relative file this document is bound to, or null
|
|
10668
10719
|
required:
|
|
10669
10720
|
- success
|
|
10670
10721
|
- surfaceId
|
|
@@ -10674,6 +10725,7 @@ paths:
|
|
|
10674
10725
|
- wordCount
|
|
10675
10726
|
- createdAt
|
|
10676
10727
|
- updatedAt
|
|
10728
|
+
- workspacePath
|
|
10677
10729
|
additionalProperties: false
|
|
10678
10730
|
/v1/documents/{id}/comments:
|
|
10679
10731
|
get:
|
|
@@ -11091,6 +11143,74 @@ paths:
|
|
|
11091
11143
|
schema:
|
|
11092
11144
|
type: string
|
|
11093
11145
|
format: binary
|
|
11146
|
+
/v1/documents/for-workspace-file:
|
|
11147
|
+
post:
|
|
11148
|
+
operationId: documents_forworkspacefile_post
|
|
11149
|
+
summary: Get or create the document for a workspace markdown file
|
|
11150
|
+
description:
|
|
11151
|
+
"Return the document bound to a workspace markdown file, creating it on first open. The file is the source
|
|
11152
|
+
of truth at open time: stored content that has drifted from the file is refreshed from disk before the document
|
|
11153
|
+
is returned."
|
|
11154
|
+
tags:
|
|
11155
|
+
- documents
|
|
11156
|
+
requestBody:
|
|
11157
|
+
required: true
|
|
11158
|
+
content:
|
|
11159
|
+
application/json:
|
|
11160
|
+
schema:
|
|
11161
|
+
type: object
|
|
11162
|
+
properties:
|
|
11163
|
+
path:
|
|
11164
|
+
type: string
|
|
11165
|
+
description: Workspace-relative path to a .md/.markdown file
|
|
11166
|
+
conversationId:
|
|
11167
|
+
type: string
|
|
11168
|
+
description: Conversation the document is opened from
|
|
11169
|
+
required:
|
|
11170
|
+
- path
|
|
11171
|
+
- conversationId
|
|
11172
|
+
responses:
|
|
11173
|
+
"200":
|
|
11174
|
+
description: Successful response
|
|
11175
|
+
content:
|
|
11176
|
+
application/json:
|
|
11177
|
+
schema:
|
|
11178
|
+
type: object
|
|
11179
|
+
properties:
|
|
11180
|
+
success:
|
|
11181
|
+
type: boolean
|
|
11182
|
+
surfaceId:
|
|
11183
|
+
type: string
|
|
11184
|
+
conversationId:
|
|
11185
|
+
type: string
|
|
11186
|
+
title:
|
|
11187
|
+
type: string
|
|
11188
|
+
content:
|
|
11189
|
+
type: string
|
|
11190
|
+
wordCount:
|
|
11191
|
+
type: number
|
|
11192
|
+
createdAt:
|
|
11193
|
+
type: number
|
|
11194
|
+
updatedAt:
|
|
11195
|
+
type: number
|
|
11196
|
+
workspacePath:
|
|
11197
|
+
anyOf:
|
|
11198
|
+
- type: string
|
|
11199
|
+
- type: "null"
|
|
11200
|
+
description: Workspace-relative file this document is bound to, or null
|
|
11201
|
+
required:
|
|
11202
|
+
- success
|
|
11203
|
+
- surfaceId
|
|
11204
|
+
- conversationId
|
|
11205
|
+
- title
|
|
11206
|
+
- content
|
|
11207
|
+
- wordCount
|
|
11208
|
+
- createdAt
|
|
11209
|
+
- updatedAt
|
|
11210
|
+
- workspacePath
|
|
11211
|
+
additionalProperties: false
|
|
11212
|
+
"422":
|
|
11213
|
+
description: Path is not a markdown file
|
|
11094
11214
|
/v1/domain/register:
|
|
11095
11215
|
post:
|
|
11096
11216
|
operationId: domain_register_post
|
|
@@ -14633,8 +14753,9 @@ paths:
|
|
|
14633
14753
|
summary: Create a provider connection
|
|
14634
14754
|
description:
|
|
14635
14755
|
Create a new named provider connection. When auth is omitted it is derived from the provider (keyless
|
|
14636
|
-
providers get none, vellum gets platform, everything else needs credential for api_key auth).
|
|
14637
|
-
|
|
14756
|
+
providers get none, vellum gets platform, everything else needs credential for api_key auth). An explicit auth
|
|
14757
|
+
object must agree with the provider; platform auth belongs to vellum and only to vellum. Fails with 409 if a
|
|
14758
|
+
connection with this name already exists.
|
|
14638
14759
|
tags:
|
|
14639
14760
|
- inference
|
|
14640
14761
|
requestBody:
|
|
@@ -14743,8 +14864,9 @@ paths:
|
|
|
14743
14864
|
summary: Update a provider connection
|
|
14744
14865
|
description:
|
|
14745
14866
|
Update an existing connection. Cannot rename or change the provider. Omitting auth keeps the stored auth;
|
|
14746
|
-
passing credential alone rotates the key via provider-derived api_key auth.
|
|
14747
|
-
|
|
14867
|
+
passing credential alone rotates the key via provider-derived api_key auth. An explicit auth object must agree
|
|
14868
|
+
with the connection's provider; platform auth belongs to vellum and only to vellum. For the Vellum-managed
|
|
14869
|
+
connection (vellum) the auth is locked to platform; label remains editable.
|
|
14748
14870
|
tags:
|
|
14749
14871
|
- inference
|
|
14750
14872
|
parameters:
|
|
@@ -19543,6 +19665,14 @@ paths:
|
|
|
19543
19665
|
additionalProperties: false
|
|
19544
19666
|
systemCard:
|
|
19545
19667
|
type: boolean
|
|
19668
|
+
providerError:
|
|
19669
|
+
type: object
|
|
19670
|
+
properties:
|
|
19671
|
+
code:
|
|
19672
|
+
type: string
|
|
19673
|
+
category:
|
|
19674
|
+
type: string
|
|
19675
|
+
additionalProperties: false
|
|
19546
19676
|
slackMessage:
|
|
19547
19677
|
type: object
|
|
19548
19678
|
properties:
|
|
@@ -19709,6 +19839,13 @@ paths:
|
|
|
19709
19839
|
Client OS surface ("web" | "ios" | "macos" | "android"), reported separately from `interface`. Drives the
|
|
19710
19840
|
per-turn `client_os` context only; does not affect transport/host-proxy capabilities.
|
|
19711
19841
|
type: string
|
|
19842
|
+
visibleAppId:
|
|
19843
|
+
description:
|
|
19844
|
+
'Id of the app the client currently has open on screen (app viewer or the app-editing split). Drives the
|
|
19845
|
+
per-turn `visible_app:` context line so the assistant can resolve "the app" to what the user is
|
|
19846
|
+
looking at. View state only: it never affects transport, routing, or tool gating, and is omitted
|
|
19847
|
+
whenever no app is in view.'
|
|
19848
|
+
type: string
|
|
19712
19849
|
clientMessageId:
|
|
19713
19850
|
type: string
|
|
19714
19851
|
description:
|
|
@@ -19752,6 +19889,16 @@ paths:
|
|
|
19752
19889
|
snapshots, emits no echo, and does not supersede pending interactions. Honored on the standard send
|
|
19753
19890
|
path only — slash-command content bypasses it."
|
|
19754
19891
|
type: boolean
|
|
19892
|
+
scripted:
|
|
19893
|
+
description:
|
|
19894
|
+
"When true, this turn was auto-sent on the user's behalf rather than typed by them: onboarding research
|
|
19895
|
+
prompts, the personality rewrite message, research corrections, hidden kickoff greetings, the legacy
|
|
19896
|
+
pre-chat bootstrap. Stamped onto the persisted message and forwarded to turn telemetry, where
|
|
19897
|
+
activation metrics exclude it. Send false for a genuine typed message; OMIT the field only if the
|
|
19898
|
+
client genuinely cannot tell, since absent means UNKNOWN and a wrong false is trusted downstream.
|
|
19899
|
+
Independent of `hidden`: a turn can be visible and scripted (the research prompt) or hidden and
|
|
19900
|
+
scripted (the kickoff greeting)."
|
|
19901
|
+
type: boolean
|
|
19755
19902
|
onboarding:
|
|
19756
19903
|
type: object
|
|
19757
19904
|
properties:
|
|
@@ -21372,6 +21519,7 @@ paths:
|
|
|
21372
21519
|
minLength: 1
|
|
21373
21520
|
description: Feed item id (notif:<uuid>) or bare uuid
|
|
21374
21521
|
title:
|
|
21522
|
+
description: New title. An empty value is ignored, never cleared.
|
|
21375
21523
|
type: string
|
|
21376
21524
|
body:
|
|
21377
21525
|
type: string
|
|
@@ -22765,6 +22913,145 @@ paths:
|
|
|
22765
22913
|
- disconnected
|
|
22766
22914
|
- previousBaseUrl
|
|
22767
22915
|
additionalProperties: false
|
|
22916
|
+
/v1/platform/invoices:
|
|
22917
|
+
get:
|
|
22918
|
+
operationId: platform_invoices_get
|
|
22919
|
+
summary: List one page of the organization's Stripe invoices
|
|
22920
|
+
description:
|
|
22921
|
+
Fetches one page of the org's Stripe invoice history (newest first) from the platform billing invoices
|
|
22922
|
+
endpoint. Amounts are in the currency's minor units. When has_more is true, pass the last invoice's id as
|
|
22923
|
+
starting_after to fetch the next page.
|
|
22924
|
+
tags:
|
|
22925
|
+
- platform
|
|
22926
|
+
parameters:
|
|
22927
|
+
- name: starting_after
|
|
22928
|
+
in: query
|
|
22929
|
+
required: false
|
|
22930
|
+
schema:
|
|
22931
|
+
type: string
|
|
22932
|
+
description: "Cursor: return invoices older than the invoice with this id (from the previous page's last entry)."
|
|
22933
|
+
responses:
|
|
22934
|
+
"200":
|
|
22935
|
+
description: Successful response
|
|
22936
|
+
content:
|
|
22937
|
+
application/json:
|
|
22938
|
+
schema:
|
|
22939
|
+
type: object
|
|
22940
|
+
properties:
|
|
22941
|
+
invoices:
|
|
22942
|
+
type: array
|
|
22943
|
+
items:
|
|
22944
|
+
type: object
|
|
22945
|
+
properties:
|
|
22946
|
+
id:
|
|
22947
|
+
type: string
|
|
22948
|
+
number:
|
|
22949
|
+
anyOf:
|
|
22950
|
+
- type: string
|
|
22951
|
+
- type: "null"
|
|
22952
|
+
status:
|
|
22953
|
+
anyOf:
|
|
22954
|
+
- type: string
|
|
22955
|
+
- type: "null"
|
|
22956
|
+
currency:
|
|
22957
|
+
type: string
|
|
22958
|
+
amount_due:
|
|
22959
|
+
type: number
|
|
22960
|
+
amount_paid:
|
|
22961
|
+
type: number
|
|
22962
|
+
amount_remaining:
|
|
22963
|
+
type: number
|
|
22964
|
+
created:
|
|
22965
|
+
type: number
|
|
22966
|
+
hosted_invoice_url:
|
|
22967
|
+
anyOf:
|
|
22968
|
+
- type: string
|
|
22969
|
+
- type: "null"
|
|
22970
|
+
invoice_pdf:
|
|
22971
|
+
anyOf:
|
|
22972
|
+
- type: string
|
|
22973
|
+
- type: "null"
|
|
22974
|
+
required:
|
|
22975
|
+
- id
|
|
22976
|
+
- number
|
|
22977
|
+
- status
|
|
22978
|
+
- currency
|
|
22979
|
+
- amount_due
|
|
22980
|
+
- amount_paid
|
|
22981
|
+
- amount_remaining
|
|
22982
|
+
- created
|
|
22983
|
+
- hosted_invoice_url
|
|
22984
|
+
- invoice_pdf
|
|
22985
|
+
additionalProperties: false
|
|
22986
|
+
has_more:
|
|
22987
|
+
type: boolean
|
|
22988
|
+
required:
|
|
22989
|
+
- invoices
|
|
22990
|
+
- has_more
|
|
22991
|
+
additionalProperties: false
|
|
22992
|
+
/v1/platform/invoices/{id}:
|
|
22993
|
+
get:
|
|
22994
|
+
operationId: platform_invoices_by_id_get
|
|
22995
|
+
summary: Get a single Stripe invoice by ID
|
|
22996
|
+
description:
|
|
22997
|
+
Pages through the org's invoice list from the platform and returns the invoice matching the given Stripe
|
|
22998
|
+
invoice ID (e.g. in_xxx). 404 if no such invoice.
|
|
22999
|
+
tags:
|
|
23000
|
+
- platform
|
|
23001
|
+
parameters:
|
|
23002
|
+
- name: id
|
|
23003
|
+
in: path
|
|
23004
|
+
required: true
|
|
23005
|
+
schema:
|
|
23006
|
+
type: string
|
|
23007
|
+
responses:
|
|
23008
|
+
"200":
|
|
23009
|
+
description: Successful response
|
|
23010
|
+
content:
|
|
23011
|
+
application/json:
|
|
23012
|
+
schema:
|
|
23013
|
+
type: object
|
|
23014
|
+
properties:
|
|
23015
|
+
id:
|
|
23016
|
+
type: string
|
|
23017
|
+
number:
|
|
23018
|
+
anyOf:
|
|
23019
|
+
- type: string
|
|
23020
|
+
- type: "null"
|
|
23021
|
+
status:
|
|
23022
|
+
anyOf:
|
|
23023
|
+
- type: string
|
|
23024
|
+
- type: "null"
|
|
23025
|
+
currency:
|
|
23026
|
+
type: string
|
|
23027
|
+
amount_due:
|
|
23028
|
+
type: number
|
|
23029
|
+
amount_paid:
|
|
23030
|
+
type: number
|
|
23031
|
+
amount_remaining:
|
|
23032
|
+
type: number
|
|
23033
|
+
created:
|
|
23034
|
+
type: number
|
|
23035
|
+
hosted_invoice_url:
|
|
23036
|
+
anyOf:
|
|
23037
|
+
- type: string
|
|
23038
|
+
- type: "null"
|
|
23039
|
+
invoice_pdf:
|
|
23040
|
+
anyOf:
|
|
23041
|
+
- type: string
|
|
23042
|
+
- type: "null"
|
|
23043
|
+
required:
|
|
23044
|
+
- id
|
|
23045
|
+
- number
|
|
23046
|
+
- status
|
|
23047
|
+
- currency
|
|
23048
|
+
- amount_due
|
|
23049
|
+
- amount_paid
|
|
23050
|
+
- amount_remaining
|
|
23051
|
+
- created
|
|
23052
|
+
- hosted_invoice_url
|
|
23053
|
+
- invoice_pdf
|
|
23054
|
+
additionalProperties: false
|
|
22768
23055
|
/v1/platform/plans:
|
|
22769
23056
|
get:
|
|
22770
23057
|
operationId: platform_plans_get
|
package/package.json
CHANGED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cover for the loop's interrupted-call recovery.
|
|
3
|
+
*
|
|
4
|
+
* The reported failure: the model runs several tools, the next call streams for
|
|
5
|
+
* a while and then dies (the upstream killed a generation that blew its decode
|
|
6
|
+
* deadline), and the loop surfaces the error and ends the turn — leaving the
|
|
7
|
+
* task half-done until the user types "continue". These tests assert the loop
|
|
8
|
+
* now carries on by itself, and that it still stops when carrying on would be
|
|
9
|
+
* pointless.
|
|
10
|
+
*
|
|
11
|
+
* The recovery is built into {@link AgentLoop}, not contributed by a plugin, so
|
|
12
|
+
* these run it as the loop's own behavior. The default plugin stack is
|
|
13
|
+
* registered because the loop fires hook chains during a turn regardless.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { beforeEach, describe, expect, test } from "bun:test";
|
|
17
|
+
|
|
18
|
+
import type { AgentEvent } from "../agent/loop.js";
|
|
19
|
+
import { AgentLoop } from "../agent/loop.js";
|
|
20
|
+
import type { LLMCallSite } from "../config/schemas/llm.js";
|
|
21
|
+
import { resetPluginRegistryAndRegisterDefaults } from "../plugins/defaults/index.js";
|
|
22
|
+
import type {
|
|
23
|
+
Message,
|
|
24
|
+
Provider,
|
|
25
|
+
ProviderResponse,
|
|
26
|
+
SendMessageOptions,
|
|
27
|
+
ToolDefinition,
|
|
28
|
+
} from "../providers/types.js";
|
|
29
|
+
import { ProviderError } from "../util/errors.js";
|
|
30
|
+
|
|
31
|
+
const tools: ToolDefinition[] = [
|
|
32
|
+
{
|
|
33
|
+
name: "read_file",
|
|
34
|
+
description: "Read a file",
|
|
35
|
+
input_schema: { type: "object", properties: { path: { type: "string" } } },
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const userMessage: Message = {
|
|
40
|
+
role: "user",
|
|
41
|
+
content: [{ type: "text", text: "finish the course page" }],
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/** The rejection from the reported turn, thrown from inside a live stream. */
|
|
45
|
+
function midStreamRejection(): ProviderError {
|
|
46
|
+
return new ProviderError(
|
|
47
|
+
"OpenAI-compatible API error (unknown status): litellm.MidStreamFallbackError: " +
|
|
48
|
+
"litellm.APIConnectionError: OpenAIException - Decode wall clock timeout after 600s",
|
|
49
|
+
"openai-compatible",
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** A scripted turn: return a response, or stream `thinking` and then throw. */
|
|
54
|
+
type Turn =
|
|
55
|
+
| { kind: "reply"; response: ProviderResponse }
|
|
56
|
+
| { kind: "interrupt"; thinking: string }
|
|
57
|
+
| { kind: "refuse" };
|
|
58
|
+
|
|
59
|
+
function scriptedProvider(turns: Turn[]): {
|
|
60
|
+
provider: Provider;
|
|
61
|
+
callCount: () => number;
|
|
62
|
+
} {
|
|
63
|
+
let index = 0;
|
|
64
|
+
const provider: Provider = {
|
|
65
|
+
name: "openai-compatible",
|
|
66
|
+
async sendMessage(
|
|
67
|
+
_messages: Message[],
|
|
68
|
+
options?: SendMessageOptions,
|
|
69
|
+
): Promise<ProviderResponse> {
|
|
70
|
+
const turn = turns[Math.min(index, turns.length - 1)]!;
|
|
71
|
+
index++;
|
|
72
|
+
if (turn.kind === "refuse") {
|
|
73
|
+
// Rejected before generating: nothing ever streams.
|
|
74
|
+
throw midStreamRejection();
|
|
75
|
+
}
|
|
76
|
+
if (turn.kind === "interrupt") {
|
|
77
|
+
options?.onEvent?.({ type: "thinking_delta", thinking: turn.thinking });
|
|
78
|
+
throw midStreamRejection();
|
|
79
|
+
}
|
|
80
|
+
for (const block of turn.response.content) {
|
|
81
|
+
if (block.type === "text") {
|
|
82
|
+
options?.onEvent?.({ type: "text_delta", text: block.text });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return turn.response;
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
return { provider, callCount: () => index };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function reply(text: string): Turn {
|
|
92
|
+
return {
|
|
93
|
+
kind: "reply",
|
|
94
|
+
response: {
|
|
95
|
+
content: [{ type: "text", text }],
|
|
96
|
+
model: "glm-5.2",
|
|
97
|
+
usage: { inputTokens: 10, outputTokens: 5 },
|
|
98
|
+
stopReason: "end_turn",
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function callsTool(id: string): Turn {
|
|
104
|
+
return {
|
|
105
|
+
kind: "reply",
|
|
106
|
+
response: {
|
|
107
|
+
content: [
|
|
108
|
+
{ type: "tool_use", id, name: "read_file", input: { path: "app.js" } },
|
|
109
|
+
],
|
|
110
|
+
model: "glm-5.2",
|
|
111
|
+
usage: { inputTokens: 10, outputTokens: 5 },
|
|
112
|
+
stopReason: "tool_use",
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function runLoop(provider: Provider, callSite: LLMCallSite = "mainAgent") {
|
|
118
|
+
const events: AgentEvent[] = [];
|
|
119
|
+
const loop = new AgentLoop({
|
|
120
|
+
provider,
|
|
121
|
+
systemPrompt: "system",
|
|
122
|
+
conversationId: "conv-resume-e2e",
|
|
123
|
+
tools,
|
|
124
|
+
toolExecutor: async () => ({ content: "file data", isError: false }),
|
|
125
|
+
});
|
|
126
|
+
return loop
|
|
127
|
+
.run({
|
|
128
|
+
requestId: "req-resume-e2e",
|
|
129
|
+
messages: [userMessage],
|
|
130
|
+
callSite,
|
|
131
|
+
onEvent: (event) => {
|
|
132
|
+
events.push(event);
|
|
133
|
+
},
|
|
134
|
+
trust: { sourceChannel: "vellum", trustClass: "unknown" },
|
|
135
|
+
})
|
|
136
|
+
.then((result) => ({ ...result, events }));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function assistantTextOf(history: Message[]): string {
|
|
140
|
+
return history
|
|
141
|
+
.filter((message) => message.role === "assistant")
|
|
142
|
+
.flatMap((message) => message.content)
|
|
143
|
+
.map((block) => (block.type === "text" ? block.text : ""))
|
|
144
|
+
.join("");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
describe("AgentLoop — a call interrupted mid-generation", () => {
|
|
148
|
+
beforeEach(() => {
|
|
149
|
+
resetPluginRegistryAndRegisterDefaults();
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test("carries on instead of ending the turn", async () => {
|
|
153
|
+
const { provider, callCount } = scriptedProvider([
|
|
154
|
+
callsTool("call-1"),
|
|
155
|
+
{ kind: "interrupt", thinking: "Now I need to understand the layout" },
|
|
156
|
+
reply("Done — the page is wired up."),
|
|
157
|
+
]);
|
|
158
|
+
|
|
159
|
+
const { history, events } = await runLoop(provider);
|
|
160
|
+
|
|
161
|
+
// The turn finished on its own: tool call, interrupted call, resumed call.
|
|
162
|
+
expect(callCount()).toBe(3);
|
|
163
|
+
expect(assistantTextOf(history)).toContain("Done — the page is wired up.");
|
|
164
|
+
expect(events.filter((event) => event.type === "error")).toHaveLength(0);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test("keeps the tool work the interrupted turn had already done", async () => {
|
|
168
|
+
const { provider } = scriptedProvider([
|
|
169
|
+
callsTool("call-1"),
|
|
170
|
+
{ kind: "interrupt", thinking: "reading the file" },
|
|
171
|
+
reply("Summary of the file."),
|
|
172
|
+
]);
|
|
173
|
+
|
|
174
|
+
const { history } = await runLoop(provider);
|
|
175
|
+
|
|
176
|
+
// The resumed call re-sends the same history, so the completed tool call
|
|
177
|
+
// and its result are still there rather than being replayed or dropped.
|
|
178
|
+
const toolUses = history
|
|
179
|
+
.flatMap((message) => message.content)
|
|
180
|
+
.filter((block) => block.type === "tool_use");
|
|
181
|
+
const toolResults = history
|
|
182
|
+
.flatMap((message) => message.content)
|
|
183
|
+
.filter((block) => block.type === "tool_result");
|
|
184
|
+
expect(toolUses).toHaveLength(1);
|
|
185
|
+
expect(toolResults).toHaveLength(1);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
test("surfaces the error when the resumed call is interrupted too", async () => {
|
|
189
|
+
const { provider, callCount } = scriptedProvider([
|
|
190
|
+
{ kind: "interrupt", thinking: "starting" },
|
|
191
|
+
]);
|
|
192
|
+
|
|
193
|
+
const { events } = await runLoop(provider);
|
|
194
|
+
|
|
195
|
+
// One resume, then the error stands rather than looping.
|
|
196
|
+
expect(callCount()).toBe(2);
|
|
197
|
+
expect(events.filter((event) => event.type === "error")).toHaveLength(1);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test("does not resume a background call site", async () => {
|
|
201
|
+
// A compaction, subagent, or other background call answers to a caller
|
|
202
|
+
// that owns its own failure handling; nobody is sitting there to type
|
|
203
|
+
// "continue" at it.
|
|
204
|
+
const { provider, callCount } = scriptedProvider([
|
|
205
|
+
{ kind: "interrupt", thinking: "summarizing" },
|
|
206
|
+
]);
|
|
207
|
+
|
|
208
|
+
await runLoop(provider, "compactionAgent");
|
|
209
|
+
|
|
210
|
+
expect(callCount()).toBe(1);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test("does not resume a request the provider refused outright", async () => {
|
|
214
|
+
// Nothing streamed, so re-sending the identical request would fail the same
|
|
215
|
+
// way; the error surfaces on the first rejection.
|
|
216
|
+
const { provider, callCount } = scriptedProvider([{ kind: "refuse" }]);
|
|
217
|
+
|
|
218
|
+
const { events } = await runLoop(provider);
|
|
219
|
+
|
|
220
|
+
expect(callCount()).toBe(1);
|
|
221
|
+
expect(events.filter((event) => event.type === "error")).toHaveLength(1);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
@@ -1092,4 +1092,47 @@ describe("ensureByokDefaultProfiles", () => {
|
|
|
1092
1092
|
|
|
1093
1093
|
expect(readFileSync(configPath(), "utf-8")).toBe(before);
|
|
1094
1094
|
});
|
|
1095
|
+
|
|
1096
|
+
// The hatch wrote each copy's model by resolving the cost profile's intent
|
|
1097
|
+
// at hatch time. These are the ids that resolved per provider, pinned as
|
|
1098
|
+
// literals rather than derived from the template: a test that materializes
|
|
1099
|
+
// the template agrees with itself no matter which intent the template names,
|
|
1100
|
+
// and so cannot catch a template whose model comparison has drifted off what
|
|
1101
|
+
// is on disk.
|
|
1102
|
+
test.each([
|
|
1103
|
+
["openrouter", "anthropic/claude-haiku-4.5"],
|
|
1104
|
+
["gemini", "gemini-3.1-flash-lite"],
|
|
1105
|
+
["openai", "gpt-5.6-luna"],
|
|
1106
|
+
] as const)(
|
|
1107
|
+
"an unedited %s cost copy still converts",
|
|
1108
|
+
(provider, hatchModel) => {
|
|
1109
|
+
writeConfig({
|
|
1110
|
+
llm: {
|
|
1111
|
+
defaultProvider: { provider },
|
|
1112
|
+
activeProfile: "custom-cost-optimized",
|
|
1113
|
+
profiles: {
|
|
1114
|
+
"custom-cost-optimized": {
|
|
1115
|
+
...(hatchBody("cost-optimized", provider) as Record<
|
|
1116
|
+
string,
|
|
1117
|
+
unknown
|
|
1118
|
+
>),
|
|
1119
|
+
model: hatchModel,
|
|
1120
|
+
},
|
|
1121
|
+
"custom-balanced": hatchBody("balanced", provider),
|
|
1122
|
+
"custom-quality-optimized": hatchBody(
|
|
1123
|
+
"quality-optimized",
|
|
1124
|
+
provider,
|
|
1125
|
+
),
|
|
1126
|
+
},
|
|
1127
|
+
},
|
|
1128
|
+
});
|
|
1129
|
+
|
|
1130
|
+
ensureByokDefaultProfiles(workspaceDir);
|
|
1131
|
+
|
|
1132
|
+
expect(profiles()["custom-cost-optimized"]).toBeUndefined();
|
|
1133
|
+
expect(profiles()["cost-optimized"]).toBeUndefined();
|
|
1134
|
+
expect(llm().activeProfile).toBe("cost-optimized");
|
|
1135
|
+
expectSecondRunNoop();
|
|
1136
|
+
},
|
|
1137
|
+
);
|
|
1095
1138
|
});
|