@vellumai/assistant 0.4.51 → 0.4.53
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 +2 -2
- package/docs/architecture/keychain-broker.md +19 -6
- package/docs/architecture/memory.md +3 -3
- package/package.json +1 -1
- package/src/__tests__/approval-cascade.test.ts +3 -1
- package/src/__tests__/approval-routes-http.test.ts +0 -1
- package/src/__tests__/asset-materialize-tool.test.ts +0 -1
- package/src/__tests__/asset-search-tool.test.ts +0 -1
- package/src/__tests__/assistant-events-sse-hardening.test.ts +0 -1
- package/src/__tests__/attachments-store.test.ts +0 -1
- package/src/__tests__/avatar-e2e.test.ts +6 -1
- package/src/__tests__/browser-fill-credential.test.ts +3 -0
- package/src/__tests__/btw-routes.test.ts +39 -0
- package/src/__tests__/call-controller.test.ts +0 -1
- package/src/__tests__/call-domain.test.ts +1 -0
- package/src/__tests__/call-routes-http.test.ts +1 -2
- package/src/__tests__/canonical-guardian-store.test.ts +33 -2
- package/src/__tests__/channel-readiness-routes.test.ts +1 -0
- package/src/__tests__/channel-readiness-service.test.ts +1 -0
- package/src/__tests__/claude-code-skill-regression.test.ts +6 -2
- package/src/__tests__/claude-code-tool-profiles.test.ts +7 -2
- package/src/__tests__/config-loader-backfill.test.ts +1 -2
- package/src/__tests__/config-schema.test.ts +6 -37
- package/src/__tests__/conversation-routes-slash-commands.test.ts +0 -1
- package/src/__tests__/credential-broker-server-use.test.ts +16 -16
- package/src/__tests__/credential-security-invariants.test.ts +14 -0
- package/src/__tests__/credential-vault-unit.test.ts +4 -4
- package/src/__tests__/error-handler-friendly-messages.test.ts +4 -5
- package/src/__tests__/gateway-only-enforcement.test.ts +0 -2
- package/src/__tests__/host-shell-tool.test.ts +0 -1
- package/src/__tests__/http-user-message-parity.test.ts +19 -0
- package/src/__tests__/list-messages-attachments.test.ts +0 -1
- package/src/__tests__/log-export-workspace.test.ts +233 -0
- package/src/__tests__/managed-proxy-context.test.ts +1 -1
- package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
- package/src/__tests__/media-generate-image.test.ts +7 -2
- package/src/__tests__/media-reuse-story.e2e.test.ts +1 -1
- package/src/__tests__/memory-regressions.test.ts +0 -1
- package/src/__tests__/migration-cross-version-compatibility.test.ts +0 -1
- package/src/__tests__/migration-export-http.test.ts +0 -1
- package/src/__tests__/migration-import-commit-http.test.ts +0 -1
- package/src/__tests__/migration-import-preflight-http.test.ts +0 -1
- package/src/__tests__/migration-validate-http.test.ts +0 -1
- package/src/__tests__/notification-schedule-dedup.test.ts +237 -0
- package/src/__tests__/oauth-cli.test.ts +1 -10
- package/src/__tests__/oauth-store.test.ts +3 -5
- package/src/__tests__/oauth2-gateway-transport.test.ts +5 -4
- package/src/__tests__/onboarding-starter-tasks.test.ts +1 -1
- package/src/__tests__/onboarding-template-contract.test.ts +1 -2
- package/src/__tests__/pricing.test.ts +0 -11
- package/src/__tests__/provider-commit-message-generator.test.ts +21 -14
- package/src/__tests__/provider-fail-open-selection.test.ts +9 -8
- package/src/__tests__/provider-managed-proxy-integration.test.ts +27 -24
- package/src/__tests__/provider-registry-ollama.test.ts +8 -2
- package/src/__tests__/recording-handler.test.ts +0 -1
- package/src/__tests__/relay-server.test.ts +0 -1
- package/src/__tests__/runtime-attachment-metadata.test.ts +0 -1
- package/src/__tests__/runtime-events-sse-parity.test.ts +0 -1
- package/src/__tests__/runtime-events-sse.test.ts +0 -1
- package/src/__tests__/script-proxy-injection-runtime.test.ts +4 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +0 -1
- package/src/__tests__/secret-scanner-executor.test.ts +0 -1
- package/src/__tests__/send-endpoint-busy.test.ts +0 -1
- package/src/__tests__/session-abort-tool-results.test.ts +3 -1
- package/src/__tests__/session-agent-loop-overflow.test.ts +1012 -838
- package/src/__tests__/session-agent-loop.test.ts +2 -2
- package/src/__tests__/session-confirmation-signals.test.ts +3 -1
- package/src/__tests__/session-error.test.ts +5 -4
- package/src/__tests__/session-history-web-search.test.ts +34 -9
- package/src/__tests__/session-pre-run-repair.test.ts +3 -1
- package/src/__tests__/session-provider-retry-repair.test.ts +31 -26
- package/src/__tests__/session-queue.test.ts +3 -1
- package/src/__tests__/session-runtime-assembly.test.ts +118 -0
- package/src/__tests__/session-slash-known.test.ts +31 -13
- package/src/__tests__/session-slash-queue.test.ts +3 -1
- package/src/__tests__/session-slash-unknown.test.ts +3 -1
- package/src/__tests__/session-workspace-cache-state.test.ts +3 -1
- package/src/__tests__/session-workspace-injection.test.ts +3 -1
- package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -1
- package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -1
- package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -1
- package/src/__tests__/skillssh-registry.test.ts +21 -0
- package/src/__tests__/slack-share-routes.test.ts +1 -1
- package/src/__tests__/swarm-recursion.test.ts +5 -1
- package/src/__tests__/swarm-session-integration.test.ts +25 -14
- package/src/__tests__/swarm-tool.test.ts +5 -2
- package/src/__tests__/telegram-bot-username-resolution.test.ts +2 -4
- package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +1521 -0
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
- package/src/__tests__/tool-executor-shell-integration.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +0 -1
- package/src/__tests__/trust-store.test.ts +5 -1
- package/src/__tests__/twilio-routes.test.ts +2 -2
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -1
- package/src/__tests__/voice-quality.test.ts +2 -1
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
- package/src/__tests__/web-search.test.ts +1 -1
- package/src/agent/loop.ts +17 -1
- package/src/bundler/app-bundler.ts +40 -24
- package/src/calls/call-controller.ts +16 -0
- package/src/calls/relay-server.ts +29 -13
- package/src/calls/voice-control-protocol.ts +1 -0
- package/src/calls/voice-quality.ts +1 -1
- package/src/calls/voice-session-bridge.ts +9 -3
- package/src/channels/types.ts +16 -0
- package/src/cli/commands/bash.ts +173 -0
- package/src/cli/commands/doctor.ts +5 -23
- package/src/cli/commands/oauth/connections.ts +4 -2
- package/src/cli/commands/oauth/providers.ts +1 -13
- package/src/cli/program.ts +2 -0
- package/src/cli/reference.ts +1 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -1
- package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +3 -5
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +2 -3
- package/src/config/bundled-skills/messaging/TOOLS.json +41 -1
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -1
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -1
- package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +2 -1
- package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +2 -1
- package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +2 -1
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +2 -1
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +2 -1
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +2 -1
- package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +2 -1
- package/src/config/bundled-skills/messaging/tools/shared.ts +2 -1
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +1 -1
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +5 -6
- package/src/config/feature-flag-registry.json +8 -0
- package/src/config/loader.ts +7 -135
- package/src/config/schema.ts +0 -6
- package/src/config/schemas/channels.ts +1 -0
- package/src/config/schemas/elevenlabs.ts +2 -2
- package/src/contacts/contact-store.ts +21 -25
- package/src/contacts/contacts-write.ts +6 -6
- package/src/contacts/types.ts +2 -0
- package/src/context/token-estimator.ts +35 -2
- package/src/context/window-manager.ts +16 -2
- package/src/daemon/config-watcher.ts +24 -6
- package/src/daemon/context-overflow-reducer.ts +13 -2
- package/src/daemon/handlers/config-ingress.ts +25 -8
- package/src/daemon/handlers/config-model.ts +21 -15
- package/src/daemon/handlers/config-telegram.ts +18 -6
- package/src/daemon/handlers/dictation.ts +0 -429
- package/src/daemon/handlers/skills.ts +1 -200
- package/src/daemon/lifecycle.ts +8 -5
- package/src/daemon/message-types/contacts.ts +2 -0
- package/src/daemon/message-types/integrations.ts +1 -0
- package/src/daemon/message-types/sessions.ts +2 -0
- package/src/daemon/parse-actual-tokens-from-error.test.ts +75 -0
- package/src/daemon/server.ts +23 -2
- package/src/daemon/session-agent-loop-handlers.ts +1 -1
- package/src/daemon/session-agent-loop.ts +27 -79
- package/src/daemon/session-error.ts +5 -4
- package/src/daemon/session-process.ts +17 -10
- package/src/daemon/session-runtime-assembly.ts +50 -0
- package/src/daemon/session-slash.ts +32 -20
- package/src/daemon/session.ts +1 -0
- package/src/events/domain-events.ts +1 -0
- package/src/media/app-icon-generator.ts +2 -1
- package/src/media/avatar-router.ts +3 -2
- package/src/memory/canonical-guardian-store.ts +25 -3
- package/src/memory/db-init.ts +12 -0
- package/src/memory/embedding-backend.ts +25 -16
- package/src/memory/migrations/158-channel-interaction-columns.ts +18 -0
- package/src/memory/migrations/159-drop-contact-interaction-columns.ts +16 -0
- package/src/memory/migrations/160-drop-loopback-port-column.ts +13 -0
- package/src/memory/migrations/index.ts +3 -0
- package/src/memory/retriever.test.ts +19 -12
- package/src/memory/schema/contacts.ts +2 -2
- package/src/memory/schema/oauth.ts +0 -1
- package/src/oauth/byo-connection.ts +55 -49
- package/src/oauth/connect-orchestrator.ts +5 -3
- package/src/oauth/connect-types.ts +9 -2
- package/src/oauth/manual-token-connection.ts +9 -7
- package/src/oauth/oauth-store.ts +2 -8
- package/src/oauth/provider-behaviors.ts +10 -0
- package/src/oauth/seed-providers.ts +13 -5
- package/src/permissions/checker.ts +20 -1
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +1 -1
- package/src/prompts/system-prompt.ts +2 -11
- package/src/prompts/templates/BOOTSTRAP.md +1 -3
- package/src/providers/anthropic/client.ts +16 -8
- package/src/providers/managed-proxy/constants.ts +1 -1
- package/src/providers/registry.ts +21 -15
- package/src/providers/types.ts +1 -1
- package/src/runtime/auth/route-policy.ts +4 -0
- package/src/runtime/channel-invite-transports/telegram.ts +12 -6
- package/src/runtime/channel-retry-sweep.ts +6 -0
- package/src/runtime/http-types.ts +1 -0
- package/src/runtime/middleware/error-handler.ts +1 -2
- package/src/runtime/routes/app-management-routes.ts +1 -0
- package/src/runtime/routes/btw-routes.ts +20 -1
- package/src/runtime/routes/conversation-routes.ts +32 -13
- package/src/runtime/routes/inbound-message-handler.ts +10 -2
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -0
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +5 -5
- package/src/runtime/routes/integrations/slack/share.ts +5 -5
- package/src/runtime/routes/log-export-routes.ts +122 -10
- package/src/runtime/routes/session-query-routes.ts +3 -3
- package/src/runtime/routes/settings-routes.ts +53 -0
- package/src/runtime/routes/workspace-routes.ts +3 -0
- package/src/runtime/verification-templates.ts +1 -1
- package/src/security/oauth2.ts +4 -4
- package/src/security/secure-keys.ts +24 -3
- package/src/security/token-manager.ts +7 -8
- package/src/signals/bash.ts +157 -0
- package/src/skills/skillssh-registry.ts +6 -1
- package/src/swarm/backend-claude-code.ts +6 -6
- package/src/swarm/worker-backend.ts +1 -1
- package/src/swarm/worker-runner.ts +1 -1
- package/src/telegram/bot-username.ts +11 -0
- package/src/tools/claude-code/claude-code.ts +4 -4
- package/src/tools/credentials/broker.ts +7 -5
- package/src/tools/credentials/vault.ts +3 -2
- package/src/tools/network/__tests__/web-search.test.ts +18 -86
- package/src/tools/network/web-search.ts +9 -15
- package/src/util/platform.ts +7 -1
- package/src/util/pricing.ts +0 -1
- package/src/workspace/provider-commit-message-generator.ts +10 -6
|
@@ -9,12 +9,7 @@ import {
|
|
|
9
9
|
saveRawConfig,
|
|
10
10
|
} from "../../config/loader.js";
|
|
11
11
|
import { resolveSkillStates, skillFlagKey } from "../../config/skill-state.js";
|
|
12
|
-
import {
|
|
13
|
-
ensureSkillIcon,
|
|
14
|
-
loadSkillBySelector,
|
|
15
|
-
loadSkillCatalog,
|
|
16
|
-
type SkillSummary,
|
|
17
|
-
} from "../../config/skills.js";
|
|
12
|
+
import { loadSkillCatalog, type SkillSummary } from "../../config/skills.js";
|
|
18
13
|
import {
|
|
19
14
|
createTimeout,
|
|
20
15
|
extractText,
|
|
@@ -36,20 +31,6 @@ import {
|
|
|
36
31
|
validateManagedSkillId,
|
|
37
32
|
} from "../../skills/managed-store.js";
|
|
38
33
|
import { getWorkspaceSkillsDir } from "../../util/platform.js";
|
|
39
|
-
import type {
|
|
40
|
-
SkillDetailRequest,
|
|
41
|
-
SkillsCheckUpdatesRequest,
|
|
42
|
-
SkillsConfigureRequest,
|
|
43
|
-
SkillsCreateRequest,
|
|
44
|
-
SkillsDisableRequest,
|
|
45
|
-
SkillsDraftRequest,
|
|
46
|
-
SkillsEnableRequest,
|
|
47
|
-
SkillsInspectRequest,
|
|
48
|
-
SkillsInstallRequest,
|
|
49
|
-
SkillsSearchRequest,
|
|
50
|
-
SkillsUninstallRequest,
|
|
51
|
-
SkillsUpdateRequest,
|
|
52
|
-
} from "../message-protocol.js";
|
|
53
34
|
import {
|
|
54
35
|
CONFIG_RELOAD_DEBOUNCE_MS,
|
|
55
36
|
ensureSkillEntry,
|
|
@@ -782,183 +763,3 @@ export async function createSkill(
|
|
|
782
763
|
return { success: false, error: message };
|
|
783
764
|
}
|
|
784
765
|
}
|
|
785
|
-
|
|
786
|
-
// ─── HTTP handlers (thin wrappers) ──────────────────────────────────────────
|
|
787
|
-
|
|
788
|
-
export function handleSkillsList(ctx: HandlerContext): void {
|
|
789
|
-
const skills = listSkills(ctx);
|
|
790
|
-
ctx.send({ type: "skills_list_response", skills });
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
export function handleSkillsEnable(
|
|
794
|
-
msg: SkillsEnableRequest,
|
|
795
|
-
ctx: HandlerContext,
|
|
796
|
-
): void {
|
|
797
|
-
const result = enableSkill(msg.name, ctx);
|
|
798
|
-
ctx.send({
|
|
799
|
-
type: "skills_operation_response",
|
|
800
|
-
operation: "enable",
|
|
801
|
-
...result,
|
|
802
|
-
});
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
export function handleSkillsDisable(
|
|
806
|
-
msg: SkillsDisableRequest,
|
|
807
|
-
ctx: HandlerContext,
|
|
808
|
-
): void {
|
|
809
|
-
const result = disableSkill(msg.name, ctx);
|
|
810
|
-
ctx.send({
|
|
811
|
-
type: "skills_operation_response",
|
|
812
|
-
operation: "disable",
|
|
813
|
-
...result,
|
|
814
|
-
});
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
export function handleSkillsConfigure(
|
|
818
|
-
msg: SkillsConfigureRequest,
|
|
819
|
-
ctx: HandlerContext,
|
|
820
|
-
): void {
|
|
821
|
-
const result = configureSkill(
|
|
822
|
-
msg.name,
|
|
823
|
-
{ env: msg.env, apiKey: msg.apiKey, config: msg.config },
|
|
824
|
-
ctx,
|
|
825
|
-
);
|
|
826
|
-
ctx.send({
|
|
827
|
-
type: "skills_operation_response",
|
|
828
|
-
operation: "configure",
|
|
829
|
-
...result,
|
|
830
|
-
});
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
export async function handleSkillsInstall(
|
|
834
|
-
msg: SkillsInstallRequest,
|
|
835
|
-
ctx: HandlerContext,
|
|
836
|
-
): Promise<void> {
|
|
837
|
-
const result = await installSkill(
|
|
838
|
-
{ slug: msg.slug, version: msg.version },
|
|
839
|
-
ctx,
|
|
840
|
-
);
|
|
841
|
-
ctx.send({
|
|
842
|
-
type: "skills_operation_response",
|
|
843
|
-
operation: "install",
|
|
844
|
-
...result,
|
|
845
|
-
});
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
export async function handleSkillsUninstall(
|
|
849
|
-
msg: SkillsUninstallRequest,
|
|
850
|
-
ctx: HandlerContext,
|
|
851
|
-
): Promise<void> {
|
|
852
|
-
const result = await uninstallSkill(msg.name, ctx);
|
|
853
|
-
ctx.send({
|
|
854
|
-
type: "skills_operation_response",
|
|
855
|
-
operation: "uninstall",
|
|
856
|
-
...result,
|
|
857
|
-
});
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
export async function handleSkillsUpdate(
|
|
861
|
-
msg: SkillsUpdateRequest,
|
|
862
|
-
ctx: HandlerContext,
|
|
863
|
-
): Promise<void> {
|
|
864
|
-
const result = await updateSkill(msg.name, ctx);
|
|
865
|
-
ctx.send({
|
|
866
|
-
type: "skills_operation_response",
|
|
867
|
-
operation: "update",
|
|
868
|
-
...result,
|
|
869
|
-
});
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
export async function handleSkillsCheckUpdates(
|
|
873
|
-
_msg: SkillsCheckUpdatesRequest,
|
|
874
|
-
ctx: HandlerContext,
|
|
875
|
-
): Promise<void> {
|
|
876
|
-
const result = await checkSkillUpdates(ctx);
|
|
877
|
-
ctx.send({
|
|
878
|
-
type: "skills_operation_response",
|
|
879
|
-
operation: "check_updates",
|
|
880
|
-
...result,
|
|
881
|
-
});
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
export async function handleSkillsSearch(
|
|
885
|
-
msg: SkillsSearchRequest,
|
|
886
|
-
ctx: HandlerContext,
|
|
887
|
-
): Promise<void> {
|
|
888
|
-
const result = await searchSkills(msg.query, ctx);
|
|
889
|
-
ctx.send({
|
|
890
|
-
type: "skills_operation_response",
|
|
891
|
-
operation: "search",
|
|
892
|
-
...result,
|
|
893
|
-
});
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
export async function handleSkillsInspect(
|
|
897
|
-
msg: SkillsInspectRequest,
|
|
898
|
-
ctx: HandlerContext,
|
|
899
|
-
): Promise<void> {
|
|
900
|
-
const result = await inspectSkill(msg.slug, ctx);
|
|
901
|
-
ctx.send({
|
|
902
|
-
type: "skills_inspect_response",
|
|
903
|
-
...result,
|
|
904
|
-
});
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
export async function handleSkillDetail(
|
|
908
|
-
msg: SkillDetailRequest,
|
|
909
|
-
ctx: HandlerContext,
|
|
910
|
-
): Promise<void> {
|
|
911
|
-
const result = loadSkillBySelector(msg.skillId);
|
|
912
|
-
if (result.skill) {
|
|
913
|
-
const icon = await ensureSkillIcon(
|
|
914
|
-
result.skill.directoryPath,
|
|
915
|
-
result.skill.displayName,
|
|
916
|
-
result.skill.description,
|
|
917
|
-
);
|
|
918
|
-
ctx.send({
|
|
919
|
-
type: "skill_detail_response",
|
|
920
|
-
skillId: result.skill.id,
|
|
921
|
-
body: result.skill.body,
|
|
922
|
-
...(icon ? { icon } : {}),
|
|
923
|
-
});
|
|
924
|
-
} else {
|
|
925
|
-
ctx.send({
|
|
926
|
-
type: "skill_detail_response",
|
|
927
|
-
skillId: msg.skillId,
|
|
928
|
-
body: "",
|
|
929
|
-
error: result.error ?? "Skill not found",
|
|
930
|
-
});
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
export async function handleSkillsDraft(
|
|
935
|
-
msg: SkillsDraftRequest,
|
|
936
|
-
ctx: HandlerContext,
|
|
937
|
-
): Promise<void> {
|
|
938
|
-
const result = await draftSkill({ sourceText: msg.sourceText }, ctx);
|
|
939
|
-
ctx.send({ type: "skills_draft_response", ...result });
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
export async function handleSkillsCreate(
|
|
943
|
-
msg: SkillsCreateRequest,
|
|
944
|
-
ctx: HandlerContext,
|
|
945
|
-
): Promise<void> {
|
|
946
|
-
const result = await createSkill(
|
|
947
|
-
{
|
|
948
|
-
skillId: msg.skillId,
|
|
949
|
-
name: msg.name,
|
|
950
|
-
description: msg.description,
|
|
951
|
-
emoji: msg.emoji,
|
|
952
|
-
bodyMarkdown: msg.bodyMarkdown,
|
|
953
|
-
userInvocable: msg.userInvocable,
|
|
954
|
-
disableModelInvocation: msg.disableModelInvocation,
|
|
955
|
-
overwrite: msg.overwrite,
|
|
956
|
-
},
|
|
957
|
-
ctx,
|
|
958
|
-
);
|
|
959
|
-
ctx.send({
|
|
960
|
-
type: "skills_operation_response",
|
|
961
|
-
operation: "create",
|
|
962
|
-
...result,
|
|
963
|
-
});
|
|
964
|
-
}
|
package/src/daemon/lifecycle.ts
CHANGED
|
@@ -177,15 +177,17 @@ export async function runDaemon(): Promise<void> {
|
|
|
177
177
|
}
|
|
178
178
|
log.info("Daemon startup: DB initialized");
|
|
179
179
|
|
|
180
|
-
// Expire
|
|
181
|
-
// this process started. Their in-memory pending-interaction
|
|
182
|
-
// references are gone, so they can never be completed.
|
|
183
|
-
//
|
|
180
|
+
// Expire pending interaction-bound canonical guardian requests left over
|
|
181
|
+
// from before this process started. Their in-memory pending-interaction
|
|
182
|
+
// session references are gone, so they can never be completed. Only
|
|
183
|
+
// interaction-bound kinds (tool_approval, pending_question) are expired;
|
|
184
|
+
// persistent kinds (access_request, tool_grant_request) remain valid
|
|
185
|
+
// across restarts.
|
|
184
186
|
const expiredCount = expireAllPendingCanonicalRequests();
|
|
185
187
|
if (expiredCount > 0) {
|
|
186
188
|
log.info(
|
|
187
189
|
{ event: "startup_expired_stale_requests", expiredCount },
|
|
188
|
-
`Expired ${expiredCount} stale
|
|
190
|
+
`Expired ${expiredCount} stale interaction-bound canonical request(s) from previous process`,
|
|
189
191
|
);
|
|
190
192
|
}
|
|
191
193
|
|
|
@@ -421,6 +423,7 @@ export async function runDaemon(): Promise<void> {
|
|
|
421
423
|
scheduleId: schedule.id,
|
|
422
424
|
name: schedule.name,
|
|
423
425
|
},
|
|
426
|
+
dedupeKey: `schedule:complete:${schedule.id}:${Date.now()}`,
|
|
424
427
|
});
|
|
425
428
|
},
|
|
426
429
|
(notification) => {
|
|
@@ -24,6 +24,8 @@ export interface SessionTransportMetadata {
|
|
|
24
24
|
hints?: string[];
|
|
25
25
|
/** Optional concise UX brief for this channel. */
|
|
26
26
|
uxBrief?: string;
|
|
27
|
+
/** Chat type from the gateway (e.g. "private", "group", "supergroup", "channel"). */
|
|
28
|
+
chatType?: string;
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
export interface SessionCreateRequest {
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { parseActualTokensFromError } from "./session-agent-loop.js";
|
|
4
|
+
|
|
5
|
+
describe("parseActualTokensFromError", () => {
|
|
6
|
+
test("returns null for null input", () => {
|
|
7
|
+
expect(parseActualTokensFromError(null)).toBeNull();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
test("returns null for empty string", () => {
|
|
11
|
+
expect(parseActualTokensFromError("")).toBeNull();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test("returns null for unrelated error message", () => {
|
|
15
|
+
expect(
|
|
16
|
+
parseActualTokensFromError("something went wrong"),
|
|
17
|
+
).toBeNull();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("parses Anthropic-style error: prompt is too long: N tokens > M maximum", () => {
|
|
21
|
+
expect(
|
|
22
|
+
parseActualTokensFromError(
|
|
23
|
+
"prompt is too long: 242201 tokens > 200000 maximum",
|
|
24
|
+
),
|
|
25
|
+
).toBe(242201);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("parses wrapped ProviderError from Anthropic", () => {
|
|
29
|
+
expect(
|
|
30
|
+
parseActualTokensFromError(
|
|
31
|
+
"Anthropic API error (400): prompt is too long: 242201 tokens > 200000 maximum",
|
|
32
|
+
),
|
|
33
|
+
).toBe(242201);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("parses OpenAI-style error: too many input tokens: N > M", () => {
|
|
37
|
+
expect(
|
|
38
|
+
parseActualTokensFromError("too many input tokens: 150000 > 128000"),
|
|
39
|
+
).toBe(150000);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("handles comma-separated numbers", () => {
|
|
43
|
+
expect(
|
|
44
|
+
parseActualTokensFromError(
|
|
45
|
+
"prompt is too long: 242,201 tokens > 200,000 maximum",
|
|
46
|
+
),
|
|
47
|
+
).toBe(242201);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("handles comma-separated numbers in fallback path", () => {
|
|
51
|
+
expect(
|
|
52
|
+
parseActualTokensFromError("too many input tokens: 150,000 > 128,000"),
|
|
53
|
+
).toBe(150000);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("parses singular 'token' (without s)", () => {
|
|
57
|
+
expect(
|
|
58
|
+
parseActualTokensFromError("prompt is too long: 1 token > 0 maximum"),
|
|
59
|
+
).toBe(1);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("handles >= comparator", () => {
|
|
63
|
+
expect(
|
|
64
|
+
parseActualTokensFromError(
|
|
65
|
+
"prompt is too long: 242201 tokens ≥ 200000 maximum",
|
|
66
|
+
),
|
|
67
|
+
).toBe(242201);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("returns null when no numeric pattern matches", () => {
|
|
71
|
+
expect(
|
|
72
|
+
parseActualTokensFromError("context window exceeded"),
|
|
73
|
+
).toBeNull();
|
|
74
|
+
});
|
|
75
|
+
});
|
package/src/daemon/server.ts
CHANGED
|
@@ -538,6 +538,22 @@ export class DaemonServer {
|
|
|
538
538
|
);
|
|
539
539
|
newSession.updateClient(sendToClient, true);
|
|
540
540
|
await newSession.loadFromDb();
|
|
541
|
+
// Restore trust/auth context and assistant ID from stored options so
|
|
542
|
+
// that evicted sessions rehydrated by undo/regenerate don't run with
|
|
543
|
+
// unscoped history. Without this, an untrusted actor could operate
|
|
544
|
+
// on the full conversation after eviction.
|
|
545
|
+
if (storedOptions?.assistantId) {
|
|
546
|
+
newSession.setAssistantId(storedOptions.assistantId);
|
|
547
|
+
}
|
|
548
|
+
if (storedOptions?.trustContext) {
|
|
549
|
+
newSession.setTrustContext(storedOptions.trustContext);
|
|
550
|
+
}
|
|
551
|
+
if (storedOptions?.authContext) {
|
|
552
|
+
newSession.setAuthContext(storedOptions.authContext);
|
|
553
|
+
}
|
|
554
|
+
if (storedOptions?.trustContext || storedOptions?.authContext) {
|
|
555
|
+
await newSession.ensureActorScopedHistory();
|
|
556
|
+
}
|
|
541
557
|
this.applyTransportMetadata(newSession, storedOptions);
|
|
542
558
|
this.sessions.set(conversationId, newSession);
|
|
543
559
|
return newSession;
|
|
@@ -639,7 +655,12 @@ export class DaemonServer {
|
|
|
639
655
|
session.setAuthContext(options?.authContext ?? null);
|
|
640
656
|
await session.ensureActorScopedHistory();
|
|
641
657
|
session.setChannelCapabilities(
|
|
642
|
-
resolveChannelCapabilities(
|
|
658
|
+
resolveChannelCapabilities(
|
|
659
|
+
sourceChannel,
|
|
660
|
+
sourceInterface,
|
|
661
|
+
null,
|
|
662
|
+
options?.transport?.chatType,
|
|
663
|
+
),
|
|
643
664
|
);
|
|
644
665
|
// Only create the host bash proxy for desktop client interfaces that can
|
|
645
666
|
// execute commands on the user's machine. Non-desktop sessions (CLI,
|
|
@@ -778,7 +799,7 @@ export class DaemonServer {
|
|
|
778
799
|
sourceInterface,
|
|
779
800
|
);
|
|
780
801
|
|
|
781
|
-
const slashResult = resolveSlash(content);
|
|
802
|
+
const slashResult = await resolveSlash(content);
|
|
782
803
|
|
|
783
804
|
if (slashResult.kind === "unknown") {
|
|
784
805
|
const serverTurnCtx = session.getTurnChannelContext();
|
|
@@ -133,7 +133,7 @@ const log = getLogger("session-agent-loop");
|
|
|
133
133
|
*
|
|
134
134
|
* Returns the actual token count or null if it cannot be parsed.
|
|
135
135
|
*/
|
|
136
|
-
function parseActualTokensFromError(
|
|
136
|
+
export function parseActualTokensFromError(
|
|
137
137
|
errorMessage: string | null,
|
|
138
138
|
): number | null {
|
|
139
139
|
if (!errorMessage) return null;
|
|
@@ -710,10 +710,11 @@ export async function runAgentLoopImpl(
|
|
|
710
710
|
const preflightBudget = Math.floor(providerMaxTokens * (1 - safetyMargin));
|
|
711
711
|
let reducerState: ReducerState | undefined;
|
|
712
712
|
|
|
713
|
+
const toolTokenBudget = ctx.agentLoop.getToolTokenBudget(runMessages);
|
|
713
714
|
const preflightTokens = estimatePromptTokens(
|
|
714
715
|
runMessages,
|
|
715
716
|
ctx.systemPrompt,
|
|
716
|
-
{ providerName: ctx.provider.name },
|
|
717
|
+
{ providerName: ctx.provider.name, toolTokenBudget },
|
|
717
718
|
);
|
|
718
719
|
|
|
719
720
|
if (overflowRecovery.enabled && preflightTokens > preflightBudget) {
|
|
@@ -747,6 +748,7 @@ export async function runAgentLoopImpl(
|
|
|
747
748
|
systemPrompt: ctx.systemPrompt,
|
|
748
749
|
contextWindow: config.contextWindow,
|
|
749
750
|
targetTokens: preflightBudget,
|
|
751
|
+
toolTokenBudget,
|
|
750
752
|
},
|
|
751
753
|
reducerState,
|
|
752
754
|
(msgs, signal, opts) =>
|
|
@@ -863,7 +865,7 @@ export async function runAgentLoopImpl(
|
|
|
863
865
|
const estimated = estimatePromptTokens(
|
|
864
866
|
checkpoint.history,
|
|
865
867
|
ctx.systemPrompt,
|
|
866
|
-
{ providerName: ctx.provider.name },
|
|
868
|
+
{ providerName: ctx.provider.name, toolTokenBudget },
|
|
867
869
|
);
|
|
868
870
|
if (estimated > midLoopThreshold) {
|
|
869
871
|
rlog.warn(
|
|
@@ -993,6 +995,23 @@ export async function runAgentLoopImpl(
|
|
|
993
995
|
);
|
|
994
996
|
}
|
|
995
997
|
|
|
998
|
+
// If mid-loop compaction exhausted all attempts but the agent loop
|
|
999
|
+
// still yielded (yieldedForBudget is true), the turn is incomplete.
|
|
1000
|
+
// Escalate to the convergence loop's more aggressive reducer tiers
|
|
1001
|
+
// (tool-result truncation, media stubbing, injection downgrade)
|
|
1002
|
+
// instead of silently treating an incomplete turn as done.
|
|
1003
|
+
if (yieldedForBudget && !abortController.signal.aborted) {
|
|
1004
|
+
rlog.warn(
|
|
1005
|
+
{
|
|
1006
|
+
phase: "mid-loop-compact",
|
|
1007
|
+
midLoopCompactAttempts,
|
|
1008
|
+
maxAttempts: overflowRecovery.maxAttempts,
|
|
1009
|
+
},
|
|
1010
|
+
"Mid-loop compaction exhausted all attempts — escalating to convergence loop",
|
|
1011
|
+
);
|
|
1012
|
+
state.contextTooLargeDetected = true;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
996
1015
|
// One-shot ordering error retry
|
|
997
1016
|
if (
|
|
998
1017
|
state.orderingErrorDetected &&
|
|
@@ -1045,6 +1064,7 @@ export async function runAgentLoopImpl(
|
|
|
1045
1064
|
),
|
|
1046
1065
|
});
|
|
1047
1066
|
preRepairMessages = updatedHistory;
|
|
1067
|
+
preRunHistoryLength = updatedHistory.length;
|
|
1048
1068
|
}
|
|
1049
1069
|
if (!reducerState) {
|
|
1050
1070
|
reducerState = createInitialReducerState();
|
|
@@ -1061,7 +1081,7 @@ export async function runAgentLoopImpl(
|
|
|
1061
1081
|
const estimatedTokensAtOverflow = estimatePromptTokens(
|
|
1062
1082
|
ctx.messages,
|
|
1063
1083
|
ctx.systemPrompt,
|
|
1064
|
-
{ providerName: ctx.provider.name },
|
|
1084
|
+
{ providerName: ctx.provider.name, toolTokenBudget },
|
|
1065
1085
|
);
|
|
1066
1086
|
let correctedTarget = preflightBudget;
|
|
1067
1087
|
if (actualTokens && estimatedTokensAtOverflow > 0) {
|
|
@@ -1113,6 +1133,7 @@ export async function runAgentLoopImpl(
|
|
|
1113
1133
|
systemPrompt: ctx.systemPrompt,
|
|
1114
1134
|
contextWindow: config.contextWindow,
|
|
1115
1135
|
targetTokens: correctedTarget,
|
|
1136
|
+
toolTokenBudget,
|
|
1116
1137
|
},
|
|
1117
1138
|
reducerState,
|
|
1118
1139
|
(msgs, signal, opts) =>
|
|
@@ -1124,12 +1145,6 @@ export async function runAgentLoopImpl(
|
|
|
1124
1145
|
ctx.messages = step.messages;
|
|
1125
1146
|
currentInjectionMode = step.state.injectionMode;
|
|
1126
1147
|
|
|
1127
|
-
// If the reducer is now exhausted without compacting, break out
|
|
1128
|
-
// so the overflow policy path can attempt emergency compaction.
|
|
1129
|
-
if (reducerState.exhausted && !step.compactionResult?.compacted) {
|
|
1130
|
-
break;
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
1148
|
if (step.compactionResult?.compacted) {
|
|
1134
1149
|
ctx.contextCompactedMessageCount +=
|
|
1135
1150
|
step.compactionResult.compactedPersistedMessages;
|
|
@@ -1183,77 +1198,10 @@ export async function runAgentLoopImpl(
|
|
|
1183
1198
|
);
|
|
1184
1199
|
}
|
|
1185
1200
|
|
|
1186
|
-
// When all reducer tiers are exhausted but the context is still too
|
|
1187
|
-
// large, attempt one last emergency compaction before consulting the
|
|
1188
|
-
// overflow policy. This covers the case where progress was made
|
|
1189
|
-
// (messages grew) and the normal tiers couldn't compact enough.
|
|
1190
|
-
if (state.contextTooLargeDetected && reducerState.exhausted) {
|
|
1191
|
-
const emergencyCompact = await ctx.contextWindowManager.maybeCompact(
|
|
1192
|
-
ctx.messages,
|
|
1193
|
-
abortController.signal,
|
|
1194
|
-
{
|
|
1195
|
-
lastCompactedAt: ctx.contextCompactedAt ?? undefined,
|
|
1196
|
-
force: true,
|
|
1197
|
-
minKeepRecentUserTurns: 0,
|
|
1198
|
-
targetInputTokensOverride: correctedTarget,
|
|
1199
|
-
},
|
|
1200
|
-
);
|
|
1201
|
-
if (emergencyCompact.compacted) {
|
|
1202
|
-
ctx.messages = emergencyCompact.messages;
|
|
1203
|
-
ctx.contextCompactedMessageCount +=
|
|
1204
|
-
emergencyCompact.compactedPersistedMessages;
|
|
1205
|
-
ctx.contextCompactedAt = Date.now();
|
|
1206
|
-
updateConversationContextWindow(
|
|
1207
|
-
ctx.conversationId,
|
|
1208
|
-
emergencyCompact.summaryText,
|
|
1209
|
-
ctx.contextCompactedMessageCount,
|
|
1210
|
-
);
|
|
1211
|
-
onEvent({
|
|
1212
|
-
type: "context_compacted",
|
|
1213
|
-
previousEstimatedInputTokens:
|
|
1214
|
-
emergencyCompact.previousEstimatedInputTokens,
|
|
1215
|
-
estimatedInputTokens: emergencyCompact.estimatedInputTokens,
|
|
1216
|
-
maxInputTokens: emergencyCompact.maxInputTokens,
|
|
1217
|
-
thresholdTokens: emergencyCompact.thresholdTokens,
|
|
1218
|
-
compactedMessages: emergencyCompact.compactedMessages,
|
|
1219
|
-
summaryCalls: emergencyCompact.summaryCalls,
|
|
1220
|
-
summaryInputTokens: emergencyCompact.summaryInputTokens,
|
|
1221
|
-
summaryOutputTokens: emergencyCompact.summaryOutputTokens,
|
|
1222
|
-
summaryModel: emergencyCompact.summaryModel,
|
|
1223
|
-
});
|
|
1224
|
-
emitUsage(
|
|
1225
|
-
ctx,
|
|
1226
|
-
emergencyCompact.summaryInputTokens,
|
|
1227
|
-
emergencyCompact.summaryOutputTokens,
|
|
1228
|
-
emergencyCompact.summaryModel,
|
|
1229
|
-
onEvent,
|
|
1230
|
-
"context_compactor",
|
|
1231
|
-
reqId,
|
|
1232
|
-
emergencyCompact.summaryCacheCreationInputTokens ?? 0,
|
|
1233
|
-
emergencyCompact.summaryCacheReadInputTokens ?? 0,
|
|
1234
|
-
collapseRawResponses(emergencyCompact.summaryRawResponses),
|
|
1235
|
-
);
|
|
1236
|
-
|
|
1237
|
-
runMessages = applyRuntimeInjections(ctx.messages, {
|
|
1238
|
-
...injectionOpts,
|
|
1239
|
-
mode: currentInjectionMode,
|
|
1240
|
-
});
|
|
1241
|
-
preRepairMessages = runMessages;
|
|
1242
|
-
preRunHistoryLength = runMessages.length;
|
|
1243
|
-
state.contextTooLargeDetected = false;
|
|
1244
|
-
|
|
1245
|
-
updatedHistory = await ctx.agentLoop.run(
|
|
1246
|
-
runMessages,
|
|
1247
|
-
eventHandler,
|
|
1248
|
-
abortController.signal,
|
|
1249
|
-
reqId,
|
|
1250
|
-
onCheckpoint,
|
|
1251
|
-
);
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
|
|
1255
1201
|
// All reducer tiers exhausted but provider still rejects —
|
|
1256
1202
|
// consult the overflow policy for latest-turn compression.
|
|
1203
|
+
// Emergency compaction is deferred to the policy-gated paths below
|
|
1204
|
+
// so that `request_user_approval` sessions collect consent first.
|
|
1257
1205
|
if (state.contextTooLargeDetected) {
|
|
1258
1206
|
const action = resolveOverflowAction({
|
|
1259
1207
|
overflowRecovery,
|
|
@@ -218,7 +218,7 @@ function classifyCore(
|
|
|
218
218
|
return {
|
|
219
219
|
code: "PROVIDER_WEB_SEARCH",
|
|
220
220
|
userMessage:
|
|
221
|
-
"An internal error occurred with web search.
|
|
221
|
+
"An internal error occurred with web search. Please try again.",
|
|
222
222
|
retryable: true,
|
|
223
223
|
errorCategory: "web_search_ordering",
|
|
224
224
|
};
|
|
@@ -226,7 +226,7 @@ function classifyCore(
|
|
|
226
226
|
if (isOrderingError(message)) {
|
|
227
227
|
return {
|
|
228
228
|
code: "PROVIDER_ORDERING",
|
|
229
|
-
userMessage: "An internal error occurred.
|
|
229
|
+
userMessage: "An internal error occurred. Please try again.",
|
|
230
230
|
retryable: true,
|
|
231
231
|
errorCategory: "tool_ordering",
|
|
232
232
|
};
|
|
@@ -308,7 +308,8 @@ function classifyByMessage(
|
|
|
308
308
|
if (isWebSearchOrderingError(message)) {
|
|
309
309
|
return {
|
|
310
310
|
code: "PROVIDER_WEB_SEARCH",
|
|
311
|
-
userMessage:
|
|
311
|
+
userMessage:
|
|
312
|
+
"An internal error occurred with web search. Please try again.",
|
|
312
313
|
retryable: true,
|
|
313
314
|
errorCategory: "web_search_ordering",
|
|
314
315
|
};
|
|
@@ -318,7 +319,7 @@ function classifyByMessage(
|
|
|
318
319
|
if (isOrderingError(message)) {
|
|
319
320
|
return {
|
|
320
321
|
code: "PROVIDER_ORDERING",
|
|
321
|
-
userMessage: "An internal error occurred.
|
|
322
|
+
userMessage: "An internal error occurred. Please try again.",
|
|
322
323
|
retryable: true,
|
|
323
324
|
errorCategory: "tool_ordering",
|
|
324
325
|
};
|