@vellumai/assistant 0.4.48 → 0.4.49
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/README.md +2 -23
- package/docs/architecture/integrations.md +45 -41
- package/docs/architecture/keychain-broker.md +3 -3
- package/docs/runbook-trusted-contacts.md +3 -8
- package/hook-templates/debug-prompt-logger/hook.json +1 -1
- package/hook-templates/debug-prompt-logger/run.sh +1 -3
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +0 -1
- package/src/__tests__/anthropic-provider.test.ts +156 -0
- package/src/__tests__/approval-cascade.test.ts +810 -0
- package/src/__tests__/approval-primitive.test.ts +0 -1
- package/src/__tests__/approval-routes-http.test.ts +2 -0
- package/src/__tests__/assistant-attachments.test.ts +12 -34
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +76 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -1
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +2 -2
- package/src/__tests__/channel-guardian.test.ts +0 -2
- package/src/__tests__/channel-readiness-routes.test.ts +15 -6
- package/src/__tests__/channel-readiness-service.test.ts +10 -9
- package/src/__tests__/checker.test.ts +9 -29
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +1 -1
- package/src/__tests__/computer-use-tools.test.ts +2 -19
- package/src/__tests__/config-watcher.test.ts +0 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/context-image-dimensions.test.ts +332 -0
- package/src/__tests__/context-token-estimator.test.ts +196 -13
- package/src/__tests__/conversation-attention-store.test.ts +0 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -1
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +144 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/credential-metadata-store.test.ts +64 -73
- package/src/__tests__/credential-security-invariants.test.ts +13 -7
- package/src/__tests__/credential-vault-unit.test.ts +280 -49
- package/src/__tests__/credential-vault.test.ts +138 -16
- package/src/__tests__/credentials-cli.test.ts +71 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/ephemeral-permissions.test.ts +3 -3
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -1
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +0 -1
- package/src/__tests__/guardian-routing-invariants.test.ts +0 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -1
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -39
- package/src/__tests__/heartbeat-service.test.ts +0 -1
- package/src/__tests__/host-cu-proxy.test.ts +629 -0
- package/src/__tests__/host-shell-tool.test.ts +27 -15
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/ingress-url-consistency.test.ts +14 -21
- package/src/__tests__/integration-status.test.ts +32 -51
- package/src/__tests__/intent-routing.test.ts +0 -1
- package/src/__tests__/invite-routes-http.test.ts +10 -9
- package/src/__tests__/keychain-broker-client.test.ts +11 -43
- package/src/__tests__/notification-routing-intent.test.ts +0 -1
- package/src/__tests__/oauth-cli.test.ts +373 -14
- package/src/__tests__/oauth-provider-profiles.test.ts +9 -9
- package/src/__tests__/oauth-scope-policy.test.ts +4 -6
- package/src/__tests__/oauth-store.test.ts +756 -0
- package/src/__tests__/onboarding-starter-tasks.test.ts +0 -1
- package/src/__tests__/provider-error-scenarios.test.ts +0 -1
- package/src/__tests__/provider-streaming.benchmark.test.ts +0 -1
- package/src/__tests__/public-ingress-urls.test.ts +15 -21
- package/src/__tests__/recording-handler.test.ts +3 -4
- package/src/__tests__/registry.test.ts +2 -2
- package/src/__tests__/runtime-events-sse.test.ts +55 -7
- package/src/__tests__/schedule-store.test.ts +0 -1
- package/src/__tests__/scheduler-recurrence.test.ts +0 -1
- package/src/__tests__/scoped-approval-grants.test.ts +0 -1
- package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -1
- package/src/__tests__/secret-ingress-handler.test.ts +0 -1
- package/src/__tests__/send-endpoint-busy.test.ts +21 -6
- package/src/__tests__/sequence-store.test.ts +0 -1
- package/src/__tests__/session-init.benchmark.test.ts +4 -5
- package/src/__tests__/skill-include-graph.test.ts +66 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +0 -1
- package/src/__tests__/skill-load-tool.test.ts +149 -1
- package/src/__tests__/skill-projection-feature-flag.test.ts +0 -1
- package/src/__tests__/skills-uninstall.test.ts +1 -1
- package/src/__tests__/skills.test.ts +3 -3
- package/src/__tests__/slack-channel-config.test.ts +67 -3
- package/src/__tests__/slack-share-routes.test.ts +17 -19
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/telegram-invite-adapter.test.ts +18 -22
- package/src/__tests__/terminal-tools.test.ts +4 -3
- package/src/__tests__/test-support/computer-use-skill-harness.ts +3 -2
- package/src/__tests__/tool-approval-handler.test.ts +0 -1
- package/src/__tests__/tool-execution-pipeline.benchmark.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__/tool-grant-request-escalation.test.ts +0 -1
- package/src/__tests__/trust-store-pattern-matches.test.ts +29 -0
- package/src/__tests__/trust-store.test.ts +1 -22
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
- package/src/__tests__/twilio-routes.test.ts +0 -16
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -1
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
- package/src/agent/ax-tree-compaction.test.ts +235 -0
- package/src/agent/loop.ts +76 -130
- package/src/calls/call-domain.ts +1 -6
- package/src/calls/relay-server.ts +9 -13
- package/src/calls/twilio-config.ts +2 -7
- package/src/calls/twilio-routes.ts +1 -2
- package/src/calls/voice-ingress-preflight.ts +1 -1
- package/src/cli/commands/browser-relay.ts +18 -12
- package/src/cli/commands/completions.ts +0 -3
- package/src/cli/commands/credentials.ts +101 -15
- package/src/cli/commands/oauth/apps.ts +255 -0
- package/src/cli/commands/oauth/connections.ts +299 -0
- package/src/cli/commands/oauth/index.ts +52 -0
- package/src/cli/commands/oauth/providers.ts +242 -0
- package/src/cli/commands/skills.ts +4 -338
- package/src/cli/program.ts +1 -5
- package/src/cli/reference.ts +1 -3
- package/src/config/assistant-feature-flags.ts +0 -3
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +3 -6
- package/src/config/bundled-skills/computer-use/TOOLS.json +22 -4
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +21 -16
- package/src/config/bundled-skills/messaging/tools/shared.ts +1 -4
- package/src/config/bundled-skills/settings/SKILL.md +1 -1
- package/src/config/bundled-skills/settings/TOOLS.json +2 -8
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +5 -33
- package/src/config/env-registry.ts +14 -83
- package/src/config/env.ts +11 -50
- package/src/config/feature-flag-registry.json +16 -16
- package/src/config/loader.ts +0 -6
- package/src/config/schema.ts +3 -1
- package/src/config/skills.ts +21 -2
- package/src/context/image-dimensions.ts +229 -0
- package/src/context/token-estimator.ts +75 -12
- package/src/context/window-manager.ts +49 -10
- package/src/daemon/assistant-attachments.ts +1 -13
- package/src/daemon/handlers/config-ingress.ts +8 -33
- package/src/daemon/handlers/config-slack-channel.ts +49 -46
- package/src/daemon/handlers/config-telegram.ts +32 -16
- package/src/daemon/handlers/sessions.ts +10 -24
- package/src/daemon/handlers/shared.ts +0 -130
- package/src/daemon/host-cu-proxy.ts +401 -0
- package/src/daemon/lifecycle.ts +36 -68
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/computer-use.ts +2 -119
- package/src/daemon/message-types/host-cu.ts +19 -0
- package/src/daemon/message-types/messages.ts +3 -0
- package/src/daemon/server.ts +14 -21
- package/src/daemon/session-agent-loop-handlers.ts +2 -0
- package/src/daemon/session-attachments.ts +1 -2
- package/src/daemon/session-slash.ts +1 -1
- package/src/daemon/session-surfaces.ts +40 -28
- package/src/daemon/session-tool-setup.ts +2 -9
- package/src/daemon/session.ts +138 -15
- package/src/daemon/tool-side-effects.ts +2 -8
- package/src/daemon/watch-handler.ts +2 -2
- package/src/events/tool-metrics-listener.ts +2 -2
- package/src/hooks/manager.ts +1 -4
- package/src/inbound/public-ingress-urls.ts +7 -7
- package/src/logfire.ts +16 -5
- package/src/memory/conversation-key-store.ts +21 -0
- package/src/memory/db-init.ts +4 -0
- package/src/memory/migrations/149-oauth-tables.ts +60 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/oauth.ts +65 -0
- package/src/messaging/provider.ts +4 -4
- package/src/messaging/providers/gmail/client.ts +82 -2
- package/src/messaging/providers/gmail/people-client.ts +10 -10
- package/src/messaging/providers/telegram-bot/adapter.ts +17 -17
- package/src/messaging/providers/whatsapp/adapter.ts +11 -8
- package/src/messaging/registry.ts +2 -32
- package/src/notifications/copy-composer.ts +0 -5
- package/src/notifications/signal.ts +4 -5
- package/src/oauth/byo-connection.test.ts +126 -25
- package/src/oauth/byo-connection.ts +22 -6
- package/src/oauth/connect-orchestrator.ts +113 -57
- package/src/oauth/connect-types.ts +17 -23
- package/src/oauth/connection-resolver.ts +35 -11
- package/src/oauth/connection.ts +1 -1
- package/src/oauth/manual-token-connection.ts +104 -0
- package/src/oauth/oauth-store.ts +496 -0
- package/src/oauth/platform-connection.test.ts +29 -0
- package/src/oauth/platform-connection.ts +6 -5
- package/src/oauth/provider-behaviors.ts +124 -0
- package/src/oauth/scope-policy.ts +9 -2
- package/src/oauth/seed-providers.ts +161 -0
- package/src/oauth/token-persistence.ts +74 -78
- package/src/permissions/checker.ts +3 -3
- package/src/permissions/defaults.ts +0 -1
- package/src/permissions/prompter.ts +10 -1
- package/src/permissions/trust-store.ts +13 -0
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +3 -1
- package/src/prompts/system-prompt.ts +28 -40
- package/src/providers/anthropic/client.ts +133 -24
- package/src/providers/retry.ts +1 -27
- package/src/runtime/auth/route-policy.ts +0 -3
- package/src/runtime/channel-reply-delivery.ts +0 -40
- package/src/runtime/gateway-client.ts +0 -7
- package/src/runtime/http-server.ts +8 -6
- package/src/runtime/http-types.ts +2 -2
- package/src/runtime/middleware/twilio-validation.ts +1 -11
- package/src/runtime/pending-interactions.ts +14 -12
- package/src/runtime/routes/channel-delivery-routes.ts +0 -1
- package/src/runtime/routes/conversation-routes.ts +73 -19
- package/src/runtime/routes/events-routes.ts +21 -11
- package/src/runtime/routes/host-cu-routes.ts +97 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +12 -111
- package/src/runtime/routes/integrations/slack/share.ts +6 -7
- package/src/runtime/routes/log-export-routes.ts +126 -8
- package/src/runtime/routes/settings-routes.ts +55 -48
- package/src/runtime/routes/surface-action-routes.ts +1 -1
- package/src/runtime/routes/watch-routes.ts +128 -0
- package/src/schedule/integration-status.ts +10 -9
- package/src/security/credential-key.ts +0 -156
- package/src/security/keychain-broker-client.ts +5 -6
- package/src/security/oauth2.ts +1 -1
- package/src/security/token-manager.ts +119 -46
- package/src/skills/catalog-install.ts +358 -0
- package/src/skills/include-graph.ts +32 -0
- package/src/telegram/bot-username.ts +2 -3
- package/src/tools/browser/network-recorder.ts +1 -1
- package/src/tools/browser/network-recording-types.ts +1 -1
- package/src/tools/computer-use/definitions.ts +46 -11
- package/src/tools/computer-use/registry.ts +4 -5
- package/src/tools/credentials/broker.ts +1 -2
- package/src/tools/credentials/metadata-store.ts +17 -121
- package/src/tools/credentials/vault.ts +94 -167
- package/src/tools/registry.ts +2 -7
- package/src/tools/skills/load.ts +62 -3
- package/src/tools/watch/watch-state.ts +0 -12
- package/src/util/logger.ts +7 -41
- package/src/util/platform.ts +9 -28
- package/src/watcher/providers/google-calendar.ts +2 -1
- package/src/__tests__/computer-use-session-compaction.test.ts +0 -143
- package/src/__tests__/computer-use-session-lifecycle.test.ts +0 -322
- package/src/__tests__/computer-use-session-working-dir.test.ts +0 -166
- package/src/__tests__/computer-use-skill-baseline.test.ts +0 -78
- package/src/__tests__/computer-use-skill-endstate.test.ts +0 -105
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +0 -249
- package/src/__tests__/ride-shotgun-handler.test.ts +0 -452
- package/src/cli/commands/dev.ts +0 -129
- package/src/cli/commands/map.ts +0 -391
- package/src/cli/commands/oauth.ts +0 -77
- package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +0 -16
- package/src/daemon/computer-use-session.ts +0 -1026
- package/src/daemon/ride-shotgun-handler.ts +0 -569
- package/src/oauth/provider-base-urls.ts +0 -21
- package/src/oauth/provider-profiles.ts +0 -192
- package/src/prompts/computer-use-prompt.ts +0 -98
- package/src/runtime/routes/computer-use-routes.ts +0 -641
- package/src/runtime/telegram-streaming-delivery.test.ts +0 -729
- package/src/runtime/telegram-streaming-delivery.ts +0 -393
- package/src/tools/computer-use/request-computer-control.ts +0 -56
|
@@ -778,7 +778,6 @@ describe("Trust Store", () => {
|
|
|
778
778
|
"computer_use_drag",
|
|
779
779
|
"computer_use_key",
|
|
780
780
|
"computer_use_open_app",
|
|
781
|
-
"computer_use_request_control",
|
|
782
781
|
"computer_use_run_applescript",
|
|
783
782
|
"computer_use_scroll",
|
|
784
783
|
"computer_use_type_text",
|
|
@@ -901,22 +900,6 @@ describe("Trust Store", () => {
|
|
|
901
900
|
);
|
|
902
901
|
});
|
|
903
902
|
|
|
904
|
-
test("findHighestPriorityRule matches default ask for computer_use_request_control", () => {
|
|
905
|
-
const match = findHighestPriorityRule(
|
|
906
|
-
"computer_use_request_control",
|
|
907
|
-
["computer_use_request_control:"],
|
|
908
|
-
"/tmp",
|
|
909
|
-
);
|
|
910
|
-
expect(match).not.toBeNull();
|
|
911
|
-
expect(match!.id).toBe("default:ask-computer_use_request_control-global");
|
|
912
|
-
expect(match!.decision).toBe("ask");
|
|
913
|
-
expect(match!.priority).toBe(
|
|
914
|
-
DEFAULT_PRIORITY_BY_ID.get(
|
|
915
|
-
"default:ask-computer_use_request_control-global",
|
|
916
|
-
)!,
|
|
917
|
-
);
|
|
918
|
-
});
|
|
919
|
-
|
|
920
903
|
test("bootstrap delete rule matches only when workingDir is the workspace dir", () => {
|
|
921
904
|
const workspaceDir = join(testDir, "workspace");
|
|
922
905
|
// Should match when workingDir is the workspace directory — the bootstrap
|
|
@@ -1755,11 +1738,7 @@ describe("computer-use tool trust rule matching", () => {
|
|
|
1755
1738
|
test("actionable CU tools have default ask trust rules", () => {
|
|
1756
1739
|
// Actionable CU tools (those that perform screen interactions) should
|
|
1757
1740
|
// have default "ask" rules so strict mode prompts before use.
|
|
1758
|
-
const actionableCuTools = [
|
|
1759
|
-
"computer_use_click",
|
|
1760
|
-
"computer_use_type_text",
|
|
1761
|
-
"computer_use_request_control",
|
|
1762
|
-
];
|
|
1741
|
+
const actionableCuTools = ["computer_use_click", "computer_use_type_text"];
|
|
1763
1742
|
|
|
1764
1743
|
for (const name of actionableCuTools) {
|
|
1765
1744
|
const rule = findHighestPriorityRule(name, [name], "/tmp/test");
|
|
@@ -77,7 +77,6 @@ function resolveIngressBaseUrlFromConfig(ingressConfig: unknown): string {
|
|
|
77
77
|
|
|
78
78
|
mock.module("../config/env.js", () => ({
|
|
79
79
|
isHttpAuthDisabled: () => true,
|
|
80
|
-
getCallWelcomeGreeting: () => process.env.CALL_WELCOME_GREETING || undefined,
|
|
81
80
|
getGatewayInternalBaseUrl: () => "http://gateway.internal:7830",
|
|
82
81
|
getIngressPublicBaseUrl: () => mockIngressPublicBaseUrl,
|
|
83
82
|
setIngressPublicBaseUrl: (value: string | undefined) => {
|
|
@@ -109,13 +108,11 @@ mock.module("../util/logger.js", () => ({
|
|
|
109
108
|
debug: () => {},
|
|
110
109
|
trace: () => {},
|
|
111
110
|
fatal: () => {},
|
|
112
|
-
isDebug: () => false,
|
|
113
111
|
child: () => ({
|
|
114
112
|
info: () => {},
|
|
115
113
|
warn: () => {},
|
|
116
114
|
error: () => {},
|
|
117
115
|
debug: () => {},
|
|
118
|
-
isDebug: () => false,
|
|
119
116
|
}),
|
|
120
117
|
}),
|
|
121
118
|
}));
|
|
@@ -438,7 +435,6 @@ describe("twilio webhook routes", () => {
|
|
|
438
435
|
updatePhoneNumberWebhookCalls = [];
|
|
439
436
|
mockTwilioApiValidationStatus = 200;
|
|
440
437
|
mockTwilioApiValidationBody = JSON.stringify({ sid: "AC_validated" });
|
|
441
|
-
delete process.env.CALL_WELCOME_GREETING;
|
|
442
438
|
|
|
443
439
|
globalThis.fetch = (async (
|
|
444
440
|
url: string | URL | Request,
|
|
@@ -819,18 +815,6 @@ describe("twilio webhook routes", () => {
|
|
|
819
815
|
const twiml = await res.text();
|
|
820
816
|
expect(twiml).not.toContain("welcomeGreeting=");
|
|
821
817
|
});
|
|
822
|
-
|
|
823
|
-
test("TwiML includes explicit welcome greeting override when configured", async () => {
|
|
824
|
-
process.env.CALL_WELCOME_GREETING = "Custom transport greeting";
|
|
825
|
-
const session = createTestSession("conv-twiml-4", "CA_twiml_4");
|
|
826
|
-
const req = makeVoiceRequest(session.id, { CallSid: "CA_twiml_4" });
|
|
827
|
-
|
|
828
|
-
const res = await handleVoiceWebhook(req);
|
|
829
|
-
|
|
830
|
-
expect(res.status).toBe(200);
|
|
831
|
-
const twiml = await res.text();
|
|
832
|
-
expect(twiml).toContain('welcomeGreeting="Custom transport greeting"');
|
|
833
|
-
});
|
|
834
818
|
});
|
|
835
819
|
|
|
836
820
|
// ── Handler-level idempotency concurrency tests ─────────────────
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import type { Message } from "../providers/types.js";
|
|
4
|
+
import { compactAxTreeHistory, escapeAxTreeContent } from "./loop.js";
|
|
5
|
+
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Helpers
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
/** Build a user message with a single tool_result containing an AX tree. */
|
|
11
|
+
function axTreeToolResult(id: string, axContent: string): Message {
|
|
12
|
+
return {
|
|
13
|
+
role: "user",
|
|
14
|
+
content: [
|
|
15
|
+
{
|
|
16
|
+
type: "tool_result",
|
|
17
|
+
tool_use_id: id,
|
|
18
|
+
content: `Some preamble\n<ax-tree>\n${axContent}\n</ax-tree>`,
|
|
19
|
+
is_error: false,
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Build an assistant message (no tool use). */
|
|
26
|
+
function assistantText(text: string): Message {
|
|
27
|
+
return {
|
|
28
|
+
role: "assistant",
|
|
29
|
+
content: [{ type: "text", text }],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Build a user message without AX tree content. */
|
|
34
|
+
function userText(text: string): Message {
|
|
35
|
+
return {
|
|
36
|
+
role: "user",
|
|
37
|
+
content: [{ type: "text", text }],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// compactAxTreeHistory
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
describe("compactAxTreeHistory", () => {
|
|
46
|
+
test("returns messages unchanged when fewer than MAX_AX_TREES_IN_HISTORY AX trees", () => {
|
|
47
|
+
const messages: Message[] = [
|
|
48
|
+
axTreeToolResult("t1", "tree-1"),
|
|
49
|
+
assistantText("ok"),
|
|
50
|
+
axTreeToolResult("t2", "tree-2"),
|
|
51
|
+
];
|
|
52
|
+
const result = compactAxTreeHistory(messages);
|
|
53
|
+
expect(result).toBe(messages); // same reference — no copy
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("returns messages unchanged when exactly MAX_AX_TREES_IN_HISTORY AX trees", () => {
|
|
57
|
+
const messages: Message[] = [
|
|
58
|
+
axTreeToolResult("t1", "tree-1"),
|
|
59
|
+
assistantText("ok"),
|
|
60
|
+
axTreeToolResult("t2", "tree-2"),
|
|
61
|
+
];
|
|
62
|
+
const result = compactAxTreeHistory(messages);
|
|
63
|
+
expect(result).toBe(messages);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("strips oldest AX trees, keeps only last 2 from 5", () => {
|
|
67
|
+
const messages: Message[] = [
|
|
68
|
+
axTreeToolResult("t1", "tree-1"),
|
|
69
|
+
assistantText("ok"),
|
|
70
|
+
axTreeToolResult("t2", "tree-2"),
|
|
71
|
+
assistantText("ok"),
|
|
72
|
+
axTreeToolResult("t3", "tree-3"),
|
|
73
|
+
assistantText("ok"),
|
|
74
|
+
axTreeToolResult("t4", "tree-4"),
|
|
75
|
+
assistantText("ok"),
|
|
76
|
+
axTreeToolResult("t5", "tree-5"),
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
const result = compactAxTreeHistory(messages);
|
|
80
|
+
|
|
81
|
+
// Messages at indices 0, 2, 4 should have AX trees stripped (t1, t2, t3)
|
|
82
|
+
for (const idx of [0, 2, 4]) {
|
|
83
|
+
const block = result[idx].content[0];
|
|
84
|
+
expect(block.type).toBe("tool_result");
|
|
85
|
+
if (block.type === "tool_result") {
|
|
86
|
+
expect(block.content).not.toContain("<ax-tree>");
|
|
87
|
+
expect(block.content).toContain("<ax_tree_omitted />");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Messages at indices 6, 8 should still have AX trees (t4, t5)
|
|
92
|
+
for (const idx of [6, 8]) {
|
|
93
|
+
const block = result[idx].content[0];
|
|
94
|
+
expect(block.type).toBe("tool_result");
|
|
95
|
+
if (block.type === "tool_result") {
|
|
96
|
+
expect(block.content).toContain("<ax-tree>");
|
|
97
|
+
expect(block.content).not.toContain("<ax_tree_omitted />");
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("does not modify assistant messages", () => {
|
|
103
|
+
const messages: Message[] = [
|
|
104
|
+
axTreeToolResult("t1", "tree-1"),
|
|
105
|
+
assistantText("ok"),
|
|
106
|
+
axTreeToolResult("t2", "tree-2"),
|
|
107
|
+
assistantText("response with <ax-tree>fake</ax-tree>"),
|
|
108
|
+
axTreeToolResult("t3", "tree-3"),
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
const result = compactAxTreeHistory(messages);
|
|
112
|
+
|
|
113
|
+
// Assistant message should be unchanged
|
|
114
|
+
const assistantMsg = result[3];
|
|
115
|
+
expect(assistantMsg.content[0].type).toBe("text");
|
|
116
|
+
if (assistantMsg.content[0].type === "text") {
|
|
117
|
+
expect(assistantMsg.content[0].text).toContain("<ax-tree>");
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("does not modify user messages without tool_result blocks", () => {
|
|
122
|
+
const messages: Message[] = [
|
|
123
|
+
axTreeToolResult("t1", "tree-1"),
|
|
124
|
+
assistantText("ok"),
|
|
125
|
+
axTreeToolResult("t2", "tree-2"),
|
|
126
|
+
assistantText("ok"),
|
|
127
|
+
userText("Please help"),
|
|
128
|
+
axTreeToolResult("t3", "tree-3"),
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
const result = compactAxTreeHistory(messages);
|
|
132
|
+
|
|
133
|
+
// The plain user text message should be untouched
|
|
134
|
+
expect(result[4]).toBe(messages[4]);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("preserves non-AX-tree tool_result blocks in stripped messages", () => {
|
|
138
|
+
const messages: Message[] = [
|
|
139
|
+
{
|
|
140
|
+
role: "user",
|
|
141
|
+
content: [
|
|
142
|
+
{
|
|
143
|
+
type: "tool_result",
|
|
144
|
+
tool_use_id: "t1",
|
|
145
|
+
content: "normal result without ax tree",
|
|
146
|
+
is_error: false,
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
type: "tool_result",
|
|
150
|
+
tool_use_id: "t1-ax",
|
|
151
|
+
content: "<ax-tree>\ntree-1\n</ax-tree>",
|
|
152
|
+
is_error: false,
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
},
|
|
156
|
+
assistantText("ok"),
|
|
157
|
+
axTreeToolResult("t2", "tree-2"),
|
|
158
|
+
assistantText("ok"),
|
|
159
|
+
axTreeToolResult("t3", "tree-3"),
|
|
160
|
+
];
|
|
161
|
+
|
|
162
|
+
const result = compactAxTreeHistory(messages);
|
|
163
|
+
|
|
164
|
+
// First message should have the AX tree stripped but normal result preserved
|
|
165
|
+
const firstMsg = result[0];
|
|
166
|
+
const normalBlock = firstMsg.content[0];
|
|
167
|
+
expect(normalBlock.type).toBe("tool_result");
|
|
168
|
+
if (normalBlock.type === "tool_result") {
|
|
169
|
+
expect(normalBlock.content).toBe("normal result without ax tree");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const axBlock = firstMsg.content[1];
|
|
173
|
+
expect(axBlock.type).toBe("tool_result");
|
|
174
|
+
if (axBlock.type === "tool_result") {
|
|
175
|
+
expect(axBlock.content).toContain("<ax_tree_omitted />");
|
|
176
|
+
expect(axBlock.content).not.toContain("<ax-tree>");
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test("returns empty array for empty input", () => {
|
|
181
|
+
const result = compactAxTreeHistory([]);
|
|
182
|
+
expect(result).toEqual([]);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test("is pure — does not mutate input messages", () => {
|
|
186
|
+
const messages: Message[] = [
|
|
187
|
+
axTreeToolResult("t1", "tree-1"),
|
|
188
|
+
assistantText("ok"),
|
|
189
|
+
axTreeToolResult("t2", "tree-2"),
|
|
190
|
+
assistantText("ok"),
|
|
191
|
+
axTreeToolResult("t3", "tree-3"),
|
|
192
|
+
];
|
|
193
|
+
|
|
194
|
+
// Deep copy to compare later
|
|
195
|
+
const originalContent = messages[0].content[0];
|
|
196
|
+
const originalText =
|
|
197
|
+
originalContent.type === "tool_result" ? originalContent.content : "";
|
|
198
|
+
|
|
199
|
+
compactAxTreeHistory(messages);
|
|
200
|
+
|
|
201
|
+
// Original message should be unchanged
|
|
202
|
+
const afterContent = messages[0].content[0];
|
|
203
|
+
const afterText =
|
|
204
|
+
afterContent.type === "tool_result" ? afterContent.content : "";
|
|
205
|
+
expect(afterText).toBe(originalText);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// ---------------------------------------------------------------------------
|
|
210
|
+
// escapeAxTreeContent
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
|
|
213
|
+
describe("escapeAxTreeContent", () => {
|
|
214
|
+
test("escapes literal </ax-tree> inside content", () => {
|
|
215
|
+
const input = "Some XML: <div></ax-tree></div>";
|
|
216
|
+
const result = escapeAxTreeContent(input);
|
|
217
|
+
expect(result).toBe("Some XML: <div></ax-tree></div>");
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
test("handles case-insensitive matches", () => {
|
|
221
|
+
const input = "</AX-TREE> and </Ax-Tree>";
|
|
222
|
+
const result = escapeAxTreeContent(input);
|
|
223
|
+
expect(result).toBe("</ax-tree> and </ax-tree>");
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test("returns content unchanged when no closing tags present", () => {
|
|
227
|
+
const input = "Normal AX tree content with <ax-tree> opening tag";
|
|
228
|
+
const result = escapeAxTreeContent(input);
|
|
229
|
+
expect(result).toBe(input);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
test("handles empty string", () => {
|
|
233
|
+
expect(escapeAxTreeContent("")).toBe("");
|
|
234
|
+
});
|
|
235
|
+
});
|
package/src/agent/loop.ts
CHANGED
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
applyStreamingSubstitution,
|
|
15
15
|
applySubstitutions,
|
|
16
16
|
} from "../tools/sensitive-output-placeholders.js";
|
|
17
|
-
import { getLogger
|
|
17
|
+
import { getLogger } from "../util/logger.js";
|
|
18
18
|
|
|
19
19
|
const log = getLogger("agent-loop");
|
|
20
20
|
|
|
@@ -179,7 +179,6 @@ export class AgentLoop {
|
|
|
179
179
|
let toolUseTurns = 0;
|
|
180
180
|
let nudgedForEmptyResponse = false;
|
|
181
181
|
let lastLlmCallTime = 0;
|
|
182
|
-
const debug = isDebug();
|
|
183
182
|
const rlog = requestId ? log.child({ requestId }) : log;
|
|
184
183
|
|
|
185
184
|
// Per-run substitution map for sensitive output placeholders.
|
|
@@ -191,7 +190,6 @@ export class AgentLoop {
|
|
|
191
190
|
while (true) {
|
|
192
191
|
if (signal?.aborted) break;
|
|
193
192
|
|
|
194
|
-
const turnStart = Date.now();
|
|
195
193
|
let toolUseBlocks: Extract<ContentBlock, { type: "tool_use" }>[] = [];
|
|
196
194
|
|
|
197
195
|
try {
|
|
@@ -227,22 +225,6 @@ export class AgentLoop {
|
|
|
227
225
|
providerConfig.tool_choice = this.config.toolChoice;
|
|
228
226
|
}
|
|
229
227
|
|
|
230
|
-
if (debug) {
|
|
231
|
-
rlog.debug(
|
|
232
|
-
{
|
|
233
|
-
systemPrompt: truncateForLog(turnSystemPrompt, 200),
|
|
234
|
-
messageCount: history.length,
|
|
235
|
-
lastMessage:
|
|
236
|
-
history.length > 0
|
|
237
|
-
? summarizeMessage(history[history.length - 1])
|
|
238
|
-
: null,
|
|
239
|
-
toolCount: currentTools.length,
|
|
240
|
-
config: providerConfig,
|
|
241
|
-
},
|
|
242
|
-
"Sending request to provider",
|
|
243
|
-
);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
228
|
const preLlmResult = await getHookManager().trigger("pre-llm-call", {
|
|
247
229
|
systemPrompt: turnSystemPrompt,
|
|
248
230
|
messages: history,
|
|
@@ -275,7 +257,11 @@ export class AgentLoop {
|
|
|
275
257
|
// screenshots from accumulating in the context window. The LLM
|
|
276
258
|
// already saw each image on the turn it was captured; keeping
|
|
277
259
|
// base64 blobs in history rapidly exhausts the context budget.
|
|
278
|
-
|
|
260
|
+
// Also strip old AX tree snapshots to keep TTFT from growing
|
|
261
|
+
// linearly with step count in computer-use sessions.
|
|
262
|
+
const providerHistory = compactAxTreeHistory(
|
|
263
|
+
stripOldImageBlocks(history),
|
|
264
|
+
);
|
|
279
265
|
|
|
280
266
|
const response = await this.provider.sendMessage(
|
|
281
267
|
providerHistory,
|
|
@@ -328,33 +314,6 @@ export class AgentLoop {
|
|
|
328
314
|
|
|
329
315
|
const providerDurationMs = Date.now() - providerStart;
|
|
330
316
|
|
|
331
|
-
if (debug) {
|
|
332
|
-
rlog.debug(
|
|
333
|
-
{
|
|
334
|
-
providerDurationMs,
|
|
335
|
-
model: response.model,
|
|
336
|
-
stopReason: response.stopReason,
|
|
337
|
-
inputTokens: response.usage.inputTokens,
|
|
338
|
-
outputTokens: response.usage.outputTokens,
|
|
339
|
-
cacheCreationInputTokens: response.usage.cacheCreationInputTokens,
|
|
340
|
-
cacheReadInputTokens: response.usage.cacheReadInputTokens,
|
|
341
|
-
contentBlocks: response.content.map((b) => ({
|
|
342
|
-
type: b.type,
|
|
343
|
-
...(b.type === "text"
|
|
344
|
-
? { text: truncateForLog(b.text, 1200) }
|
|
345
|
-
: {}),
|
|
346
|
-
...(b.type === "tool_use"
|
|
347
|
-
? {
|
|
348
|
-
name: b.name,
|
|
349
|
-
input: truncateForLog(JSON.stringify(b.input), 1200),
|
|
350
|
-
}
|
|
351
|
-
: {}),
|
|
352
|
-
})),
|
|
353
|
-
},
|
|
354
|
-
"Provider response received",
|
|
355
|
-
);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
317
|
onEvent({
|
|
359
318
|
type: "usage",
|
|
360
319
|
inputTokens: response.usage.inputTokens,
|
|
@@ -443,16 +402,6 @@ export class AgentLoop {
|
|
|
443
402
|
name: toolUse.name,
|
|
444
403
|
input: toolUse.input,
|
|
445
404
|
});
|
|
446
|
-
|
|
447
|
-
if (debug) {
|
|
448
|
-
rlog.debug(
|
|
449
|
-
{
|
|
450
|
-
tool: toolUse.name,
|
|
451
|
-
input: truncateForLog(JSON.stringify(toolUse.input), 300),
|
|
452
|
-
},
|
|
453
|
-
"Executing tool",
|
|
454
|
-
);
|
|
455
|
-
}
|
|
456
405
|
}
|
|
457
406
|
|
|
458
407
|
// If already cancelled, synthesize cancelled results and stop
|
|
@@ -469,49 +418,11 @@ export class AgentLoop {
|
|
|
469
418
|
break;
|
|
470
419
|
}
|
|
471
420
|
|
|
472
|
-
// Guard against dual-control-mode conflicts in a single turn.
|
|
473
|
-
// If the model escalates to foreground computer control, browser_* tools
|
|
474
|
-
// in the same response create competing browser sessions/windows and can
|
|
475
|
-
// thrash renderer CPU. Reject browser_* calls in that turn.
|
|
476
|
-
const hasComputerUseEscalation = toolUseBlocks.some(
|
|
477
|
-
(toolUse) => toolUse.name === "computer_use_request_control",
|
|
478
|
-
);
|
|
479
|
-
const blockedBrowserToolIds = hasComputerUseEscalation
|
|
480
|
-
? new Set(
|
|
481
|
-
toolUseBlocks
|
|
482
|
-
.filter((toolUse) => toolUse.name.startsWith("browser_"))
|
|
483
|
-
.map((toolUse) => toolUse.id),
|
|
484
|
-
)
|
|
485
|
-
: new Set<string>();
|
|
486
|
-
|
|
487
|
-
if (blockedBrowserToolIds.size > 0) {
|
|
488
|
-
log.warn(
|
|
489
|
-
{
|
|
490
|
-
blockedBrowserToolCount: blockedBrowserToolIds.size,
|
|
491
|
-
toolNames: toolUseBlocks.map((toolUse) => toolUse.name),
|
|
492
|
-
},
|
|
493
|
-
"Blocking browser_* tools: computer_use_request_control was requested in same turn",
|
|
494
|
-
);
|
|
495
|
-
}
|
|
496
|
-
|
|
497
421
|
// Execute all tools concurrently for reduced latency.
|
|
498
422
|
// Race against the abort signal so cancellation isn't blocked by
|
|
499
423
|
// stuck tools (e.g. a hung browser navigation).
|
|
500
424
|
const toolExecutionPromise = Promise.all(
|
|
501
425
|
toolUseBlocks.map(async (toolUse) => {
|
|
502
|
-
const toolStart = Date.now();
|
|
503
|
-
|
|
504
|
-
if (blockedBrowserToolIds.has(toolUse.id)) {
|
|
505
|
-
return {
|
|
506
|
-
toolUse,
|
|
507
|
-
result: {
|
|
508
|
-
content:
|
|
509
|
-
"Error: browser_* tools cannot run in the same turn as computer_use_request_control. Continue using the foreground computer-use session only.",
|
|
510
|
-
isError: true,
|
|
511
|
-
},
|
|
512
|
-
};
|
|
513
|
-
}
|
|
514
|
-
|
|
515
426
|
const result = await this.toolExecutor!(
|
|
516
427
|
toolUse.name,
|
|
517
428
|
toolUse.input,
|
|
@@ -525,20 +436,6 @@ export class AgentLoop {
|
|
|
525
436
|
toolUse.id,
|
|
526
437
|
);
|
|
527
438
|
|
|
528
|
-
const toolDurationMs = Date.now() - toolStart;
|
|
529
|
-
|
|
530
|
-
if (debug) {
|
|
531
|
-
rlog.debug(
|
|
532
|
-
{
|
|
533
|
-
tool: toolUse.name,
|
|
534
|
-
toolDurationMs,
|
|
535
|
-
isError: result.isError,
|
|
536
|
-
output: truncateForLog(result.content, 300),
|
|
537
|
-
},
|
|
538
|
-
"Tool execution complete",
|
|
539
|
-
);
|
|
540
|
-
}
|
|
541
|
-
|
|
542
439
|
return { toolUse, result };
|
|
543
440
|
}),
|
|
544
441
|
);
|
|
@@ -658,19 +555,6 @@ export class AgentLoop {
|
|
|
658
555
|
// Add tool results as a user message and continue the loop
|
|
659
556
|
history.push({ role: "user", content: resultBlocks });
|
|
660
557
|
|
|
661
|
-
if (debug) {
|
|
662
|
-
const turnDurationMs = Date.now() - turnStart;
|
|
663
|
-
rlog.debug(
|
|
664
|
-
{
|
|
665
|
-
turnDurationMs,
|
|
666
|
-
providerDurationMs,
|
|
667
|
-
toolCount: toolUseBlocks.length,
|
|
668
|
-
turn: toolUseTurns,
|
|
669
|
-
},
|
|
670
|
-
"Turn complete",
|
|
671
|
-
);
|
|
672
|
-
}
|
|
673
|
-
|
|
674
558
|
// Invoke checkpoint callback after tool results are in history
|
|
675
559
|
if (onCheckpoint) {
|
|
676
560
|
const decision = onCheckpoint({
|
|
@@ -715,14 +599,76 @@ export class AgentLoop {
|
|
|
715
599
|
}
|
|
716
600
|
}
|
|
717
601
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
602
|
+
/** Number of most-recent AX tree snapshots to keep in conversation history. */
|
|
603
|
+
const MAX_AX_TREES_IN_HISTORY = 2;
|
|
604
|
+
|
|
605
|
+
/** Regex that matches the `<ax-tree>...</ax-tree>` markers. */
|
|
606
|
+
const AX_TREE_PATTERN = /<ax-tree>[\s\S]*?<\/ax-tree>/g;
|
|
607
|
+
const AX_TREE_PLACEHOLDER = "<ax_tree_omitted />";
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Escapes any literal `</ax-tree>` occurrences inside AX tree content so
|
|
611
|
+
* that the non-greedy compaction regex (`AX_TREE_PATTERN`) does not stop
|
|
612
|
+
* prematurely when the user happens to be viewing XML/HTML source that
|
|
613
|
+
* contains the closing tag. The escaped content does not need to be
|
|
614
|
+
* unescaped because compaction replaces the entire block with a placeholder.
|
|
615
|
+
*/
|
|
616
|
+
export function escapeAxTreeContent(content: string): string {
|
|
617
|
+
return content.replace(/<\/ax-tree>/gi, "</ax-tree>");
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Returns a shallow copy of `messages` where all but the most recent
|
|
622
|
+
* `MAX_AX_TREES_IN_HISTORY` `<ax-tree>` blocks have been replaced with a
|
|
623
|
+
* short placeholder. This keeps the conversation context small so that
|
|
624
|
+
* TTFT does not grow linearly with step count in computer-use sessions.
|
|
625
|
+
*/
|
|
626
|
+
export function compactAxTreeHistory(messages: Message[]): Message[] {
|
|
627
|
+
// Collect indices of user messages that contain an <ax-tree> block
|
|
628
|
+
const indicesWithAxTree: number[] = [];
|
|
629
|
+
for (let i = 0; i < messages.length; i++) {
|
|
630
|
+
const msg = messages[i];
|
|
631
|
+
if (msg.role !== "user") continue;
|
|
632
|
+
for (const block of msg.content) {
|
|
633
|
+
if (
|
|
634
|
+
block.type === "tool_result" &&
|
|
635
|
+
typeof block.content === "string" &&
|
|
636
|
+
block.content.includes("<ax-tree>")
|
|
637
|
+
) {
|
|
638
|
+
indicesWithAxTree.push(i);
|
|
639
|
+
break;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
if (indicesWithAxTree.length <= MAX_AX_TREES_IN_HISTORY) {
|
|
645
|
+
return messages;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
const toStrip = new Set(indicesWithAxTree.slice(0, -MAX_AX_TREES_IN_HISTORY));
|
|
649
|
+
|
|
650
|
+
return messages.map((msg, idx) => {
|
|
651
|
+
if (!toStrip.has(idx)) return msg;
|
|
652
|
+
return {
|
|
653
|
+
...msg,
|
|
654
|
+
content: msg.content.map((block) => {
|
|
655
|
+
if (
|
|
656
|
+
block.type === "tool_result" &&
|
|
657
|
+
typeof block.content === "string" &&
|
|
658
|
+
block.content.includes("<ax-tree>")
|
|
659
|
+
) {
|
|
660
|
+
return {
|
|
661
|
+
...block,
|
|
662
|
+
content: block.content.replace(
|
|
663
|
+
AX_TREE_PATTERN,
|
|
664
|
+
AX_TREE_PLACEHOLDER,
|
|
665
|
+
),
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
return block;
|
|
669
|
+
}),
|
|
670
|
+
};
|
|
671
|
+
});
|
|
726
672
|
}
|
|
727
673
|
|
|
728
674
|
/**
|
package/src/calls/call-domain.ts
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* to these functions so business logic lives in one place.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { getTwilioUserPhoneNumber } from "../config/env.js";
|
|
9
8
|
import { loadConfig } from "../config/loader.js";
|
|
10
9
|
import { VALID_CALLER_IDENTITY_MODES } from "../config/schema.js";
|
|
11
10
|
import type { AssistantConfig } from "../config/types.js";
|
|
@@ -111,8 +110,7 @@ export type CallerIdentitySource =
|
|
|
111
110
|
| "per_call_override"
|
|
112
111
|
| "implicit_default"
|
|
113
112
|
| "user_config"
|
|
114
|
-
| "secure_key"
|
|
115
|
-
| "env_var";
|
|
113
|
+
| "secure_key";
|
|
116
114
|
|
|
117
115
|
export type CallerIdentityResult =
|
|
118
116
|
| {
|
|
@@ -194,9 +192,6 @@ export async function resolveCallerIdentity(
|
|
|
194
192
|
if (identityConfig.userNumber) {
|
|
195
193
|
userNumber = identityConfig.userNumber;
|
|
196
194
|
numberSource = "user_config";
|
|
197
|
-
} else if (getTwilioUserPhoneNumber()) {
|
|
198
|
-
userNumber = getTwilioUserPhoneNumber()!;
|
|
199
|
-
numberSource = "env_var";
|
|
200
195
|
} else {
|
|
201
196
|
const secureKeyValue = getSecureKey(
|
|
202
197
|
credentialKey("twilio", "user_phone_number"),
|