@vellumai/assistant 0.4.31 → 0.4.33
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 +1 -1
- package/docs/architecture/memory.md +1 -1
- package/package.json +1 -1
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +0 -7
- package/src/__tests__/access-request-decision.test.ts +83 -1
- package/src/__tests__/actor-token-service.test.ts +0 -1
- package/src/__tests__/anthropic-provider.test.ts +86 -1
- package/src/__tests__/approval-routes-http.test.ts +0 -1
- package/src/__tests__/assistant-feature-flags-integration.test.ts +2 -2
- package/src/__tests__/call-controller.test.ts +0 -1
- package/src/__tests__/call-routes-http.test.ts +0 -1
- package/src/__tests__/channel-guardian.test.ts +0 -1
- package/src/__tests__/channel-invite-transport.test.ts +52 -40
- package/src/__tests__/checker.test.ts +37 -98
- package/src/__tests__/commit-message-enrichment-service.test.ts +4 -23
- package/src/__tests__/computer-use-session-working-dir.test.ts +0 -1
- package/src/__tests__/config-schema.test.ts +6 -5
- package/src/__tests__/credential-security-invariants.test.ts +2 -0
- package/src/__tests__/daemon-server-session-init.test.ts +1 -19
- package/src/__tests__/deterministic-verification-control-plane.test.ts +0 -1
- package/src/__tests__/followup-tools.test.ts +0 -30
- package/src/__tests__/gemini-provider.test.ts +79 -1
- package/src/__tests__/guardian-action-followup-executor.test.ts +0 -1
- package/src/__tests__/guardian-dispatch.test.ts +0 -1
- package/src/__tests__/guardian-outbound-http.test.ts +0 -1
- package/src/__tests__/handlers-telegram-config.test.ts +0 -1
- package/src/__tests__/inbound-invite-redemption.test.ts +1 -4
- package/src/__tests__/ingress-reconcile.test.ts +3 -36
- package/src/__tests__/ipc-snapshot.test.ts +0 -4
- package/src/__tests__/managed-proxy-context.test.ts +163 -0
- package/src/__tests__/memory-lifecycle-e2e.test.ts +2 -2
- package/src/__tests__/memory-regressions.test.ts +6 -6
- 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__/non-member-access-request.test.ts +0 -1
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- package/src/__tests__/notification-telegram-adapter.test.ts +0 -4
- package/src/__tests__/openai-provider.test.ts +82 -0
- package/src/__tests__/provider-fail-open-selection.test.ts +134 -1
- package/src/__tests__/provider-managed-proxy-integration.test.ts +269 -0
- package/src/__tests__/recurrence-types.test.ts +0 -15
- package/src/__tests__/relay-server.test.ts +145 -2
- package/src/__tests__/sandbox-host-parity.test.ts +5 -2
- package/src/__tests__/schedule-tools.test.ts +28 -44
- package/src/__tests__/session-init.benchmark.test.ts +0 -2
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/slack-channel-config.test.ts +0 -1
- package/src/__tests__/slack-inbound-verification.test.ts +0 -1
- package/src/__tests__/sms-messaging-provider.test.ts +0 -4
- package/src/__tests__/task-management-tools.test.ts +111 -0
- package/src/__tests__/terminal-tools.test.ts +5 -2
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +66 -74
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +0 -1
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
- package/src/__tests__/trusted-contact-verification.test.ts +0 -1
- package/src/__tests__/twilio-config.test.ts +0 -3
- package/src/__tests__/twilio-routes.test.ts +0 -1
- package/src/__tests__/update-bulletin.test.ts +0 -2
- package/src/__tests__/user-reference.test.ts +47 -1
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -1
- package/src/__tests__/workspace-git-service.test.ts +2 -2
- package/src/amazon/session.ts +30 -91
- package/src/calls/call-controller.ts +423 -571
- package/src/calls/finalize-call.ts +20 -0
- package/src/calls/relay-access-wait.ts +340 -0
- package/src/calls/relay-server.ts +271 -956
- package/src/calls/relay-setup-router.ts +307 -0
- package/src/calls/relay-verification.ts +280 -0
- package/src/calls/twilio-config.ts +1 -8
- package/src/calls/voice-control-protocol.ts +184 -0
- package/src/calls/voice-session-bridge.ts +1 -8
- package/src/channels/config.ts +41 -2
- package/src/config/agent-schema.ts +1 -1
- package/src/config/bundled-skills/followups/TOOLS.json +0 -4
- package/src/config/bundled-skills/schedule/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +2 -10
- package/src/config/bundled-skills/slack/SKILL.md +2 -0
- package/src/config/bundled-skills/slack-digest-setup/SKILL.md +164 -0
- package/src/config/core-schema.ts +1 -1
- package/src/config/env.ts +0 -14
- package/src/config/feature-flag-registry.json +5 -5
- package/src/config/loader.ts +19 -0
- package/src/config/schema.ts +2 -2
- package/src/config/user-reference.ts +47 -9
- package/src/daemon/handlers/config-channels.ts +11 -10
- package/src/daemon/handlers/contacts.ts +5 -1
- package/src/daemon/handlers/session-history.ts +398 -0
- package/src/daemon/handlers/session-user-message.ts +982 -0
- package/src/daemon/handlers/sessions.ts +9 -1338
- package/src/daemon/ipc-contract/sessions.ts +0 -6
- package/src/daemon/ipc-contract-inventory.json +0 -1
- package/src/daemon/lifecycle.ts +18 -55
- package/src/home-base/app-link-store.ts +0 -7
- package/src/memory/channel-delivery-store.ts +1 -0
- package/src/memory/conversation-attention-store.ts +1 -1
- package/src/memory/conversation-store.ts +0 -51
- package/src/memory/db-init.ts +9 -1
- package/src/memory/delivery-crud.ts +13 -0
- package/src/memory/invite-store.ts +71 -1
- package/src/memory/job-handlers/conflict.ts +24 -0
- package/src/memory/migrations/040-invite-code-hash-column.ts +16 -0
- package/src/memory/migrations/105-contacts-and-triage.ts +4 -7
- package/src/memory/migrations/134-contacts-notes-column.ts +50 -33
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/migrations/registry.ts +6 -0
- package/src/memory/recall-cache.ts +0 -5
- package/src/memory/schema/calls.ts +274 -0
- package/src/memory/schema/contacts.ts +127 -0
- package/src/memory/schema/conversations.ts +129 -0
- package/src/memory/schema/guardian.ts +172 -0
- package/src/memory/schema/index.ts +8 -0
- package/src/memory/schema/infrastructure.ts +205 -0
- package/src/memory/schema/memory-core.ts +196 -0
- package/src/memory/schema/notifications.ts +191 -0
- package/src/memory/schema/tasks.ts +78 -0
- package/src/memory/schema.ts +1 -1385
- package/src/memory/slack-thread-store.ts +0 -69
- package/src/notifications/decisions-store.ts +2 -105
- package/src/notifications/deliveries-store.ts +0 -11
- package/src/notifications/preferences-store.ts +1 -58
- package/src/permissions/checker.ts +6 -17
- package/src/providers/anthropic/client.ts +6 -2
- package/src/providers/gemini/client.ts +13 -2
- package/src/providers/managed-proxy/constants.ts +55 -0
- package/src/providers/managed-proxy/context.ts +77 -0
- package/src/providers/registry.ts +112 -0
- package/src/runtime/auth/__tests__/guard-tests.test.ts +52 -26
- package/src/runtime/auth/token-service.ts +50 -0
- package/src/runtime/channel-guardian-service.ts +1 -3
- package/src/runtime/channel-invite-transport.ts +121 -34
- package/src/runtime/channel-invite-transports/email.ts +50 -0
- package/src/runtime/channel-invite-transports/slack.ts +81 -0
- package/src/runtime/channel-invite-transports/sms.ts +70 -0
- package/src/runtime/channel-invite-transports/telegram.ts +29 -11
- package/src/runtime/channel-invite-transports/voice.ts +12 -12
- package/src/runtime/http-server.ts +83 -722
- package/src/runtime/http-types.ts +0 -16
- package/src/runtime/invite-redemption-service.ts +193 -0
- package/src/runtime/invite-redemption-templates.ts +6 -6
- package/src/runtime/invite-service.ts +81 -11
- package/src/runtime/middleware/auth.ts +0 -12
- package/src/runtime/routes/access-request-decision.ts +52 -6
- package/src/runtime/routes/app-routes.ts +33 -0
- package/src/runtime/routes/approval-routes.ts +32 -0
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +6 -0
- package/src/runtime/routes/attachment-routes.ts +32 -0
- package/src/runtime/routes/brain-graph-routes.ts +27 -0
- package/src/runtime/routes/call-routes.ts +41 -0
- package/src/runtime/routes/channel-readiness-routes.ts +20 -0
- package/src/runtime/routes/channel-routes.ts +70 -0
- package/src/runtime/routes/contact-routes.ts +96 -6
- package/src/runtime/routes/conversation-attention-routes.ts +15 -0
- package/src/runtime/routes/conversation-routes.ts +190 -193
- package/src/runtime/routes/debug-routes.ts +15 -0
- package/src/runtime/routes/events-routes.ts +16 -0
- package/src/runtime/routes/global-search-routes.ts +15 -0
- package/src/runtime/routes/guardian-action-routes.ts +22 -0
- package/src/runtime/routes/guardian-bootstrap-routes.ts +21 -6
- package/src/runtime/routes/guardian-refresh-routes.ts +20 -0
- package/src/runtime/routes/identity-routes.ts +20 -0
- package/src/runtime/routes/inbound-message-handler.ts +9 -3
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +295 -10
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +9 -42
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +10 -0
- package/src/runtime/routes/integration-routes.ts +83 -0
- package/src/runtime/routes/invite-routes.ts +32 -0
- package/src/runtime/routes/migration-routes.ts +30 -0
- package/src/runtime/routes/pairing-routes.ts +18 -0
- package/src/runtime/routes/secret-routes.ts +20 -0
- package/src/runtime/routes/surface-action-routes.ts +26 -0
- package/src/runtime/routes/trust-rules-routes.ts +31 -0
- package/src/runtime/routes/twilio-routes.ts +79 -0
- package/src/schedule/recurrence-types.ts +1 -11
- package/src/tools/browser/browser-manager.ts +10 -1
- package/src/tools/browser/runtime-check.ts +3 -1
- package/src/tools/followups/followup_create.ts +9 -3
- package/src/tools/mcp/mcp-tool-factory.ts +0 -17
- package/src/tools/memory/definitions.ts +0 -6
- package/src/tools/network/script-proxy/session-manager.ts +38 -3
- package/src/tools/schedule/create.ts +1 -3
- package/src/tools/schedule/update.ts +9 -6
- package/src/tools/shared/shell-output.ts +7 -2
- package/src/twitter/session.ts +29 -77
- package/src/util/cookie-session.ts +114 -0
- package/src/util/platform.ts +0 -4
- package/src/workspace/git-service.ts +10 -4
- package/src/__tests__/conversation-routes.test.ts +0 -99
- package/src/__tests__/task-tools.test.ts +0 -685
- package/src/contacts/startup-migration.ts +0 -21
|
@@ -18,6 +18,7 @@ import { resetDb } from "../../memory/db-connection.js";
|
|
|
18
18
|
import { getLogger } from "../../util/logger.js";
|
|
19
19
|
import { getDbPath, getWorkspaceConfigPath } from "../../util/platform.js";
|
|
20
20
|
import { httpError } from "../http-errors.js";
|
|
21
|
+
import type { RouteDefinition } from "../http-router.js";
|
|
21
22
|
import { buildExportVBundle } from "../migrations/vbundle-builder.js";
|
|
22
23
|
import {
|
|
23
24
|
analyzeImport,
|
|
@@ -432,3 +433,32 @@ export async function handleMigrationImport(req: Request): Promise<Response> {
|
|
|
432
433
|
);
|
|
433
434
|
}
|
|
434
435
|
}
|
|
436
|
+
|
|
437
|
+
// ---------------------------------------------------------------------------
|
|
438
|
+
// Route definitions
|
|
439
|
+
// ---------------------------------------------------------------------------
|
|
440
|
+
|
|
441
|
+
export function migrationRouteDefinitions(): RouteDefinition[] {
|
|
442
|
+
return [
|
|
443
|
+
{
|
|
444
|
+
endpoint: "migrations/validate",
|
|
445
|
+
method: "POST",
|
|
446
|
+
handler: async ({ req }) => handleMigrationValidate(req),
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
endpoint: "migrations/export",
|
|
450
|
+
method: "POST",
|
|
451
|
+
handler: async ({ req }) => handleMigrationExport(req),
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
endpoint: "migrations/import-preflight",
|
|
455
|
+
method: "POST",
|
|
456
|
+
handler: async ({ req }) => handleMigrationImportPreflight(req),
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
endpoint: "migrations/import",
|
|
460
|
+
method: "POST",
|
|
461
|
+
handler: async ({ req }) => handleMigrationImport(req),
|
|
462
|
+
},
|
|
463
|
+
];
|
|
464
|
+
}
|
|
@@ -14,6 +14,7 @@ import { DAEMON_INTERNAL_ASSISTANT_ID } from "../assistant-scope.js";
|
|
|
14
14
|
import { mintCredentialPair } from "../auth/credential-service.js";
|
|
15
15
|
import { ensureVellumGuardianBinding } from "../guardian-vellum-migration.js";
|
|
16
16
|
import { httpError } from "../http-errors.js";
|
|
17
|
+
import type { RouteDefinition } from "../http-router.js";
|
|
17
18
|
|
|
18
19
|
const log = getLogger("runtime-http");
|
|
19
20
|
|
|
@@ -404,3 +405,20 @@ export function handlePairingStatus(
|
|
|
404
405
|
|
|
405
406
|
return Response.json({ status: entry.status });
|
|
406
407
|
}
|
|
408
|
+
|
|
409
|
+
// ---------------------------------------------------------------------------
|
|
410
|
+
// Route definitions
|
|
411
|
+
// ---------------------------------------------------------------------------
|
|
412
|
+
|
|
413
|
+
export function pairingRouteDefinitions(deps: {
|
|
414
|
+
getPairingContext: () => PairingHandlerContext;
|
|
415
|
+
}): RouteDefinition[] {
|
|
416
|
+
return [
|
|
417
|
+
{
|
|
418
|
+
endpoint: "pairing/register",
|
|
419
|
+
method: "POST",
|
|
420
|
+
handler: async ({ req }) =>
|
|
421
|
+
handlePairingRegister(req, deps.getPairingContext()),
|
|
422
|
+
},
|
|
423
|
+
];
|
|
424
|
+
}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from "../../tools/credentials/metadata-store.js";
|
|
13
13
|
import { getLogger } from "../../util/logger.js";
|
|
14
14
|
import { httpError } from "../http-errors.js";
|
|
15
|
+
import type { RouteDefinition } from "../http-router.js";
|
|
15
16
|
|
|
16
17
|
const log = getLogger("runtime-http");
|
|
17
18
|
|
|
@@ -170,3 +171,22 @@ export async function handleDeleteSecret(req: Request): Promise<Response> {
|
|
|
170
171
|
return httpError("INTERNAL_ERROR", message, 500);
|
|
171
172
|
}
|
|
172
173
|
}
|
|
174
|
+
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
// Route definitions
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
|
|
179
|
+
export function secretRouteDefinitions(): RouteDefinition[] {
|
|
180
|
+
return [
|
|
181
|
+
{
|
|
182
|
+
endpoint: "secrets",
|
|
183
|
+
method: "POST",
|
|
184
|
+
handler: async ({ req }) => handleAddSecret(req),
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
endpoint: "secrets",
|
|
188
|
+
method: "DELETE",
|
|
189
|
+
handler: async ({ req }) => handleDeleteSecret(req),
|
|
190
|
+
},
|
|
191
|
+
];
|
|
192
|
+
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { getLogger } from "../../util/logger.js";
|
|
8
8
|
import { httpError } from "../http-errors.js";
|
|
9
|
+
import type { RouteDefinition } from "../http-router.js";
|
|
9
10
|
|
|
10
11
|
const log = getLogger("surface-action-routes");
|
|
11
12
|
|
|
@@ -74,3 +75,28 @@ export async function handleSurfaceAction(
|
|
|
74
75
|
return httpError("INTERNAL_ERROR", "Failed to handle surface action", 500);
|
|
75
76
|
}
|
|
76
77
|
}
|
|
78
|
+
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// Route definitions
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
|
|
83
|
+
export function surfaceActionRouteDefinitions(deps: {
|
|
84
|
+
findSession?: SessionLookup;
|
|
85
|
+
}): RouteDefinition[] {
|
|
86
|
+
return [
|
|
87
|
+
{
|
|
88
|
+
endpoint: "surface-actions",
|
|
89
|
+
method: "POST",
|
|
90
|
+
handler: async ({ req }) => {
|
|
91
|
+
if (!deps.findSession) {
|
|
92
|
+
return httpError(
|
|
93
|
+
"NOT_IMPLEMENTED",
|
|
94
|
+
"Surface actions not available",
|
|
95
|
+
501,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
return handleSurfaceAction(req, deps.findSession);
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
];
|
|
102
|
+
}
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
} from "../../permissions/trust-store.js";
|
|
14
14
|
import { getLogger } from "../../util/logger.js";
|
|
15
15
|
import { httpError } from "../http-errors.js";
|
|
16
|
+
import type { RouteDefinition } from "../http-router.js";
|
|
16
17
|
|
|
17
18
|
const log = getLogger("trust-rules-routes");
|
|
18
19
|
|
|
@@ -151,3 +152,33 @@ export async function handleUpdateTrustRuleManage(
|
|
|
151
152
|
return httpError("INTERNAL_ERROR", "Failed to update trust rule", 500);
|
|
152
153
|
}
|
|
153
154
|
}
|
|
155
|
+
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
// Route definitions
|
|
158
|
+
// ---------------------------------------------------------------------------
|
|
159
|
+
|
|
160
|
+
export function trustRulesRouteDefinitions(): RouteDefinition[] {
|
|
161
|
+
return [
|
|
162
|
+
{
|
|
163
|
+
endpoint: "trust-rules/manage",
|
|
164
|
+
method: "GET",
|
|
165
|
+
handler: () => handleListTrustRules(),
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
endpoint: "trust-rules/manage",
|
|
169
|
+
method: "POST",
|
|
170
|
+
handler: async ({ req }) => handleAddTrustRuleManage(req),
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
endpoint: "trust-rules/manage/:id",
|
|
174
|
+
method: "DELETE",
|
|
175
|
+
handler: ({ params }) => handleRemoveTrustRuleManage(params.id),
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
endpoint: "trust-rules/manage/:id",
|
|
179
|
+
method: "PATCH",
|
|
180
|
+
handler: async ({ req, params }) =>
|
|
181
|
+
handleUpdateTrustRuleManage(req, params.id),
|
|
182
|
+
},
|
|
183
|
+
];
|
|
184
|
+
}
|
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
upsertCredentialMetadata,
|
|
47
47
|
} from "../../tools/credentials/metadata-store.js";
|
|
48
48
|
import { mintDaemonDeliveryToken } from "../auth/token-service.js";
|
|
49
|
+
import type { RouteDefinition } from "../http-router.js";
|
|
49
50
|
|
|
50
51
|
// ---------------------------------------------------------------------------
|
|
51
52
|
// Shared helpers
|
|
@@ -1126,3 +1127,81 @@ export async function handleSmsDoctor(): Promise<Response> {
|
|
|
1126
1127
|
},
|
|
1127
1128
|
});
|
|
1128
1129
|
}
|
|
1130
|
+
|
|
1131
|
+
// ---------------------------------------------------------------------------
|
|
1132
|
+
// Route definitions
|
|
1133
|
+
// ---------------------------------------------------------------------------
|
|
1134
|
+
|
|
1135
|
+
export function twilioRouteDefinitions(): RouteDefinition[] {
|
|
1136
|
+
return [
|
|
1137
|
+
{
|
|
1138
|
+
endpoint: "integrations/twilio/config",
|
|
1139
|
+
method: "GET",
|
|
1140
|
+
handler: () => handleGetTwilioConfig(),
|
|
1141
|
+
},
|
|
1142
|
+
{
|
|
1143
|
+
endpoint: "integrations/twilio/credentials",
|
|
1144
|
+
method: "POST",
|
|
1145
|
+
handler: async ({ req }) => handleSetTwilioCredentials(req),
|
|
1146
|
+
},
|
|
1147
|
+
{
|
|
1148
|
+
endpoint: "integrations/twilio/credentials",
|
|
1149
|
+
method: "DELETE",
|
|
1150
|
+
handler: () => handleClearTwilioCredentials(),
|
|
1151
|
+
},
|
|
1152
|
+
{
|
|
1153
|
+
endpoint: "integrations/twilio/numbers",
|
|
1154
|
+
method: "GET",
|
|
1155
|
+
handler: async () => handleListTwilioNumbers(),
|
|
1156
|
+
},
|
|
1157
|
+
{
|
|
1158
|
+
endpoint: "integrations/twilio/numbers/provision",
|
|
1159
|
+
method: "POST",
|
|
1160
|
+
handler: async ({ req }) => handleProvisionTwilioNumber(req),
|
|
1161
|
+
},
|
|
1162
|
+
{
|
|
1163
|
+
endpoint: "integrations/twilio/numbers/assign",
|
|
1164
|
+
method: "POST",
|
|
1165
|
+
handler: async ({ req }) => handleAssignTwilioNumber(req),
|
|
1166
|
+
},
|
|
1167
|
+
{
|
|
1168
|
+
endpoint: "integrations/twilio/numbers/release",
|
|
1169
|
+
method: "POST",
|
|
1170
|
+
handler: async ({ req }) => handleReleaseTwilioNumber(req),
|
|
1171
|
+
},
|
|
1172
|
+
{
|
|
1173
|
+
endpoint: "integrations/twilio/sms/compliance",
|
|
1174
|
+
method: "GET",
|
|
1175
|
+
handler: async () => handleGetSmsCompliance(),
|
|
1176
|
+
},
|
|
1177
|
+
{
|
|
1178
|
+
endpoint: "integrations/twilio/sms/compliance/tollfree",
|
|
1179
|
+
method: "POST",
|
|
1180
|
+
handler: async ({ req }) => handleSubmitTollfreeVerification(req),
|
|
1181
|
+
},
|
|
1182
|
+
{
|
|
1183
|
+
endpoint: "integrations/twilio/sms/compliance/tollfree/:sid",
|
|
1184
|
+
method: "PATCH",
|
|
1185
|
+
policyKey: "integrations/twilio/sms/compliance/tollfree",
|
|
1186
|
+
handler: async ({ req, params }) =>
|
|
1187
|
+
handleUpdateTollfreeVerification(req, params.sid),
|
|
1188
|
+
},
|
|
1189
|
+
{
|
|
1190
|
+
endpoint: "integrations/twilio/sms/compliance/tollfree/:sid",
|
|
1191
|
+
method: "DELETE",
|
|
1192
|
+
policyKey: "integrations/twilio/sms/compliance/tollfree",
|
|
1193
|
+
handler: async ({ params }) =>
|
|
1194
|
+
handleDeleteTollfreeVerification(params.sid),
|
|
1195
|
+
},
|
|
1196
|
+
{
|
|
1197
|
+
endpoint: "integrations/twilio/sms/test",
|
|
1198
|
+
method: "POST",
|
|
1199
|
+
handler: async ({ req }) => handleSmsSendTest(req),
|
|
1200
|
+
},
|
|
1201
|
+
{
|
|
1202
|
+
endpoint: "integrations/twilio/sms/doctor",
|
|
1203
|
+
method: "POST",
|
|
1204
|
+
handler: async () => handleSmsDoctor(),
|
|
1205
|
+
},
|
|
1206
|
+
];
|
|
1207
|
+
}
|
|
@@ -34,13 +34,11 @@ export function detectScheduleSyntax(
|
|
|
34
34
|
* Resolution order:
|
|
35
35
|
* 1. If explicit `syntax` is provided, use it
|
|
36
36
|
* 2. If `expression` is provided, auto-detect from expression
|
|
37
|
-
* 3.
|
|
38
|
-
* 4. Return null if nothing resolved
|
|
37
|
+
* 3. Return null if nothing resolved
|
|
39
38
|
*/
|
|
40
39
|
export function normalizeScheduleSyntax(input: {
|
|
41
40
|
syntax?: ScheduleSyntax;
|
|
42
41
|
expression?: string;
|
|
43
|
-
legacyCronExpression?: string;
|
|
44
42
|
}): { syntax: ScheduleSyntax; expression: string } | null {
|
|
45
43
|
// Explicit syntax + expression
|
|
46
44
|
if (input.syntax && input.expression) {
|
|
@@ -60,13 +58,5 @@ export function normalizeScheduleSyntax(input: {
|
|
|
60
58
|
return null;
|
|
61
59
|
}
|
|
62
60
|
|
|
63
|
-
// Legacy cron_expression fallback
|
|
64
|
-
if (input.legacyCronExpression) {
|
|
65
|
-
return {
|
|
66
|
-
syntax: input.syntax ?? "cron",
|
|
67
|
-
expression: input.legacyCronExpression,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
61
|
return null;
|
|
72
62
|
}
|
|
@@ -131,7 +131,16 @@ export function setLaunchFn(fn: LaunchFn | null): void {
|
|
|
131
131
|
|
|
132
132
|
async function getDefaultLaunchFn(): Promise<LaunchFn> {
|
|
133
133
|
const pw = await import("playwright");
|
|
134
|
-
|
|
134
|
+
// In compiled Bun binaries, CJS→ESM interop may place named exports
|
|
135
|
+
// under .default instead of at the top level of the module namespace.
|
|
136
|
+
const chromium =
|
|
137
|
+
pw.chromium ?? (pw.default as typeof pw | undefined)?.chromium;
|
|
138
|
+
if (!chromium) {
|
|
139
|
+
throw new Error(
|
|
140
|
+
"Failed to resolve Playwright chromium — the module loaded but 'chromium' is missing",
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
return chromium.launchPersistentContext.bind(chromium);
|
|
135
144
|
}
|
|
136
145
|
|
|
137
146
|
function getProfileDir(): string {
|
|
@@ -12,7 +12,9 @@ export async function checkBrowserRuntime(): Promise<BrowserRuntimeStatus> {
|
|
|
12
12
|
let chromium: { executablePath: () => string };
|
|
13
13
|
try {
|
|
14
14
|
const pw = await import("playwright");
|
|
15
|
-
|
|
15
|
+
// In compiled Bun binaries, CJS→ESM interop may place named exports
|
|
16
|
+
// under .default instead of at the top level of the module namespace.
|
|
17
|
+
chromium = pw.chromium ?? (pw.default as typeof pw | undefined)?.chromium;
|
|
16
18
|
} catch {
|
|
17
19
|
return {
|
|
18
20
|
playwrightAvailable: false,
|
|
@@ -47,13 +47,19 @@ export async function executeFollowupCreate(
|
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
if (input.reminder_cron_id !== undefined) {
|
|
51
|
+
return {
|
|
52
|
+
content:
|
|
53
|
+
'Error: "reminder_cron_id" is deprecated. Use "reminder_schedule_id" instead.',
|
|
54
|
+
isError: true,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
50
58
|
const contactId = input.contact_id as string | undefined;
|
|
51
59
|
const expectedResponseHours = input.expected_response_hours as
|
|
52
60
|
| number
|
|
53
61
|
| undefined;
|
|
54
|
-
|
|
55
|
-
const reminderScheduleId = (input.reminder_schedule_id ??
|
|
56
|
-
input.reminder_cron_id) as string | undefined;
|
|
62
|
+
const reminderScheduleId = input.reminder_schedule_id as string | undefined;
|
|
57
63
|
|
|
58
64
|
// Validate contact exists if provided
|
|
59
65
|
if (contactId) {
|
|
@@ -18,23 +18,6 @@ export function mcpToolName(serverId: string, toolName: string): string {
|
|
|
18
18
|
return `mcp__${serverId}__${toolName}`;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
/**
|
|
22
|
-
* Parse a namespaced MCP tool name back into serverId and original tool name.
|
|
23
|
-
* Returns null if the name doesn't match the MCP naming convention.
|
|
24
|
-
*/
|
|
25
|
-
export function parseMcpToolName(
|
|
26
|
-
name: string,
|
|
27
|
-
): { serverId: string; toolName: string } | null {
|
|
28
|
-
if (!name.startsWith("mcp__")) return null;
|
|
29
|
-
const prefixRemoved = name.slice(5); // remove 'mcp__'
|
|
30
|
-
const firstSep = prefixRemoved.indexOf("__");
|
|
31
|
-
if (firstSep === -1) return null;
|
|
32
|
-
return {
|
|
33
|
-
serverId: prefixRemoved.slice(0, firstSep),
|
|
34
|
-
toolName: prefixRemoved.slice(firstSep + 2),
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
21
|
export interface McpToolMetadata {
|
|
39
22
|
name: string;
|
|
40
23
|
description: string;
|
|
@@ -42,6 +42,32 @@ const DEFAULT_CONFIG: ProxySessionConfig = {
|
|
|
42
42
|
maxSessionsPerConversation: 3,
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Host patterns that are allowed by default through the proxy policy engine,
|
|
47
|
+
* regardless of session configuration. Supports exact matches (e.g.
|
|
48
|
+
* `"localhost"`) and wildcard subdomain patterns (e.g. `"*.vellum.ai"`
|
|
49
|
+
* matches `platform.vellum.ai`, `dev-platform.vellum.ai`, etc.).
|
|
50
|
+
*/
|
|
51
|
+
const ALLOWED_HOST_PATTERNS: readonly string[] = ["*.vellum.ai", "localhost"];
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Returns `true` when `hostname` matches any entry in
|
|
55
|
+
* {@link ALLOWED_HOST_PATTERNS}.
|
|
56
|
+
*/
|
|
57
|
+
function isAllowedHost(hostname: string): boolean {
|
|
58
|
+
for (const pattern of ALLOWED_HOST_PATTERNS) {
|
|
59
|
+
if (pattern.startsWith("*.")) {
|
|
60
|
+
const suffix = pattern.slice(1); // e.g. ".vellum.ai"
|
|
61
|
+
if (hostname.endsWith(suffix) || hostname === pattern.slice(2)) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
} else if (hostname === pattern) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
|
|
45
71
|
interface ManagedSession {
|
|
46
72
|
session: ProxySession;
|
|
47
73
|
server: Server | null;
|
|
@@ -309,6 +335,13 @@ export async function startSession(
|
|
|
309
335
|
reqPath: string,
|
|
310
336
|
scheme: "http" | "https",
|
|
311
337
|
) => {
|
|
338
|
+
// Allowed hosts are always passed through the proxy, regardless of
|
|
339
|
+
// session configuration or credential state.
|
|
340
|
+
if (isAllowedHost(hostname)) {
|
|
341
|
+
log.debug({ hostname }, "Allowing always-permitted host");
|
|
342
|
+
return {};
|
|
343
|
+
}
|
|
344
|
+
|
|
312
345
|
const decision = evaluateRequestWithApproval(
|
|
313
346
|
hostname,
|
|
314
347
|
port,
|
|
@@ -506,7 +539,8 @@ export async function getOrStartSession(
|
|
|
506
539
|
): Promise<{ session: ProxySession; created: boolean }> {
|
|
507
540
|
const requestedHost = options?.listenHost ?? "127.0.0.1";
|
|
508
541
|
|
|
509
|
-
// Fast path — session already active with matching credentials and listen
|
|
542
|
+
// Fast path — session already active with matching credentials and listen
|
|
543
|
+
// host, no lock needed.
|
|
510
544
|
const existing = getActiveSession(conversationId);
|
|
511
545
|
if (existing && credentialIdsMatch(existing.credentialIds, credentialIds)) {
|
|
512
546
|
const managed = sessions.get(existing.id);
|
|
@@ -533,8 +567,9 @@ export async function getOrStartSession(
|
|
|
533
567
|
return { session, created: false };
|
|
534
568
|
}
|
|
535
569
|
}
|
|
536
|
-
// Credential or listenHost mismatch — tear down and loop back to
|
|
537
|
-
// whether another waiter has already started a replacement
|
|
570
|
+
// Credential or listenHost mismatch — tear down and loop back to
|
|
571
|
+
// re-check whether another waiter has already started a replacement
|
|
572
|
+
// session.
|
|
538
573
|
await stopSession(session.id);
|
|
539
574
|
}
|
|
540
575
|
|
|
@@ -31,16 +31,14 @@ export async function executeScheduleCreate(
|
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
// Resolve syntax and expression from new or legacy fields
|
|
35
34
|
const resolved = normalizeScheduleSyntax({
|
|
36
35
|
syntax: input.syntax as "cron" | "rrule" | undefined,
|
|
37
36
|
expression: input.expression as string | undefined,
|
|
38
|
-
legacyCronExpression: input.cron_expression as string | undefined,
|
|
39
37
|
});
|
|
40
38
|
|
|
41
39
|
if (!resolved) {
|
|
42
40
|
return {
|
|
43
|
-
content: "Error: expression
|
|
41
|
+
content: "Error: expression is required",
|
|
44
42
|
isError: true,
|
|
45
43
|
};
|
|
46
44
|
}
|
|
@@ -20,6 +20,14 @@ export async function executeScheduleUpdate(
|
|
|
20
20
|
return { content: "Error: job_id is required", isError: true };
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
if (input.cron_expression !== undefined) {
|
|
24
|
+
return {
|
|
25
|
+
content:
|
|
26
|
+
'Error: "cron_expression" is deprecated. Use "expression" instead.',
|
|
27
|
+
isError: true,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
23
31
|
const updates: Record<string, unknown> = {};
|
|
24
32
|
if (input.name !== undefined) updates.name = input.name;
|
|
25
33
|
if (input.timezone !== undefined) updates.timezone = input.timezone;
|
|
@@ -27,13 +35,10 @@ export async function executeScheduleUpdate(
|
|
|
27
35
|
if (input.enabled !== undefined) updates.enabled = input.enabled;
|
|
28
36
|
|
|
29
37
|
// Auto-detect syntax when expression changes without explicit syntax
|
|
30
|
-
|
|
31
|
-
input.expression !== undefined || input.cron_expression !== undefined;
|
|
32
|
-
if (hasExpression || input.syntax !== undefined) {
|
|
38
|
+
if (input.expression !== undefined || input.syntax !== undefined) {
|
|
33
39
|
const resolved = normalizeScheduleSyntax({
|
|
34
40
|
syntax: input.syntax as "cron" | "rrule" | undefined,
|
|
35
41
|
expression: input.expression as string | undefined,
|
|
36
|
-
legacyCronExpression: input.cron_expression as string | undefined,
|
|
37
42
|
});
|
|
38
43
|
if (resolved) {
|
|
39
44
|
updates.syntax = resolved.syntax;
|
|
@@ -42,8 +47,6 @@ export async function executeScheduleUpdate(
|
|
|
42
47
|
updates.expression = input.expression;
|
|
43
48
|
const detected = detectScheduleSyntax(input.expression as string);
|
|
44
49
|
if (detected) updates.syntax = detected;
|
|
45
|
-
} else if (input.cron_expression !== undefined) {
|
|
46
|
-
updates.cronExpression = input.cron_expression;
|
|
47
50
|
}
|
|
48
51
|
// When only syntax is provided (no expression), normalizeScheduleSyntax returns null
|
|
49
52
|
// but we still need to persist the explicit syntax value.
|
|
@@ -39,8 +39,13 @@ export function formatShellOutput(
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
if (!output.trim()) {
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
if (code === 0) {
|
|
43
|
+
output = "<command_completed />";
|
|
44
|
+
} else {
|
|
45
|
+
const exitTag = `<command_exit code="${code}" />`;
|
|
46
|
+
output = `${exitTag}\nCommand failed with exit code ${code}. No stdout or stderr output was produced.`;
|
|
47
|
+
statusParts.push(exitTag);
|
|
48
|
+
}
|
|
44
49
|
} else if (code !== 0 && !timedOut) {
|
|
45
50
|
statusParts.push(`<command_exit code="${code}" />`);
|
|
46
51
|
}
|
package/src/twitter/session.ts
CHANGED
|
@@ -1,97 +1,49 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Twitter session persistence.
|
|
3
|
-
*
|
|
3
|
+
* Delegates to the shared cookie-session primitive for CRUD and cookie header
|
|
4
|
+
* logic; keeps Twitter-specific cookie validation and CSRF extraction.
|
|
4
5
|
*/
|
|
5
6
|
|
|
7
|
+
import type { CookieSession } from "../util/cookie-session.js";
|
|
6
8
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
unlinkSync,
|
|
11
|
-
writeFileSync,
|
|
12
|
-
} from "node:fs";
|
|
13
|
-
import { join } from "node:path";
|
|
14
|
-
|
|
15
|
-
import type {
|
|
16
|
-
ExtractedCredential,
|
|
17
|
-
SessionRecording,
|
|
18
|
-
} from "../tools/browser/network-recording-types.js";
|
|
9
|
+
createSessionStore,
|
|
10
|
+
importFromRecordingBase,
|
|
11
|
+
} from "../util/cookie-session.js";
|
|
19
12
|
import { ConfigError } from "../util/errors.js";
|
|
20
|
-
import { getDataDir } from "../util/platform.js";
|
|
21
|
-
|
|
22
|
-
export interface TwitterSession {
|
|
23
|
-
cookies: ExtractedCredential[];
|
|
24
|
-
importedAt: string;
|
|
25
|
-
recordingId?: string;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function getSessionDir(): string {
|
|
29
|
-
return join(getDataDir(), "twitter");
|
|
30
|
-
}
|
|
31
13
|
|
|
32
|
-
|
|
33
|
-
return join(getSessionDir(), "session.json");
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function loadSession(): TwitterSession | null {
|
|
37
|
-
const path = getSessionPath();
|
|
38
|
-
if (!existsSync(path)) return null;
|
|
39
|
-
try {
|
|
40
|
-
return JSON.parse(readFileSync(path, "utf-8")) as TwitterSession;
|
|
41
|
-
} catch {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
14
|
+
export type TwitterSession = CookieSession;
|
|
45
15
|
|
|
46
|
-
|
|
47
|
-
const dir = getSessionDir();
|
|
48
|
-
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
49
|
-
writeFileSync(getSessionPath(), JSON.stringify(session, null, 2));
|
|
50
|
-
}
|
|
16
|
+
const store = createSessionStore("twitter");
|
|
51
17
|
|
|
52
|
-
export
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
18
|
+
export const loadSession: () => TwitterSession | null = store.loadSession;
|
|
19
|
+
export const saveSession: (session: TwitterSession) => void = store.saveSession;
|
|
20
|
+
export const clearSession: () => void = store.clearSession;
|
|
21
|
+
export const getCookieHeader: (session: TwitterSession) => string =
|
|
22
|
+
store.getCookieHeader;
|
|
58
23
|
|
|
59
24
|
/**
|
|
60
25
|
* Import cookies from a Ride Shotgun recording file.
|
|
61
26
|
*/
|
|
62
27
|
export function importFromRecording(recordingPath: string): TwitterSession {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
28
|
+
try {
|
|
29
|
+
const session = importFromRecordingBase(recordingPath, (cookieNames) => {
|
|
30
|
+
// Require the two cookies that prove a logged-in Twitter session:
|
|
31
|
+
// the auth session cookie and the ct0 CSRF cookie.
|
|
32
|
+
if (!cookieNames.has("ct0") || !cookieNames.has(`auth_${"token"}`)) {
|
|
33
|
+
throw new ConfigError(
|
|
34
|
+
"Recording is missing required Twitter session cookies. " +
|
|
35
|
+
"Make sure you are logged in to x.com before recording.",
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
saveSession(session);
|
|
40
|
+
return session;
|
|
41
|
+
} catch (error) {
|
|
42
|
+
if (error instanceof ConfigError) throw error;
|
|
76
43
|
throw new ConfigError(
|
|
77
|
-
|
|
78
|
-
"Make sure you are logged in to x.com before recording.",
|
|
44
|
+
error instanceof Error ? error.message : String(error),
|
|
79
45
|
);
|
|
80
46
|
}
|
|
81
|
-
const session: TwitterSession = {
|
|
82
|
-
cookies: recording.cookies,
|
|
83
|
-
importedAt: new Date().toISOString(),
|
|
84
|
-
recordingId: recording.id,
|
|
85
|
-
};
|
|
86
|
-
saveSession(session);
|
|
87
|
-
return session;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Build a Cookie header string from the session.
|
|
92
|
-
*/
|
|
93
|
-
export function getCookieHeader(session: TwitterSession): string {
|
|
94
|
-
return session.cookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
95
47
|
}
|
|
96
48
|
|
|
97
49
|
/**
|