@vellumai/vellum-gateway 0.4.50 → 0.4.51
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/knip.json +3 -6
- package/package.json +3 -2
- package/src/__tests__/telegram-webhook-handler.test.ts +3 -3
- package/src/channels/transport-hints.ts +0 -10
- package/src/http/routes/contacts-control-plane-proxy.ts +4 -0
- package/src/http/routes/telegram-webhook.test.ts +3 -9
- package/src/http/routes/telegram-webhook.ts +3 -1
- package/src/index.ts +7 -0
- package/src/runtime/client.ts +0 -7
- package/src/schema.ts +35 -0
package/knip.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vellumai/vellum-gateway",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.51",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./twilio/verify": "./src/twilio/verify.ts",
|
|
@@ -16,9 +16,10 @@
|
|
|
16
16
|
"format": "prettier --write .",
|
|
17
17
|
"format:check": "prettier --check .",
|
|
18
18
|
"lint": "eslint",
|
|
19
|
+
"lint:unused": "knip --include files,dependencies,unlisted",
|
|
19
20
|
"typecheck": "bunx tsc --noEmit",
|
|
20
21
|
"prebuild": "cd .. && bun run meta/feature-flags/sync-bundled-copies.ts",
|
|
21
|
-
"postinstall": "cd .. && (git config core.hooksPath || git config core.hooksPath .githooks 2>/dev/null || true) && (bun run meta/feature-flags/sync-bundled-copies.ts 2>/dev/null || true)"
|
|
22
|
+
"postinstall": "cd .. && (git config core.hooksPath || git config core.hooksPath .githooks 2>/dev/null || true) && ([ -f meta/feature-flags/sync-bundled-copies.ts ] && bun run meta/feature-flags/sync-bundled-copies.ts 2>/dev/null || true)"
|
|
22
23
|
},
|
|
23
24
|
"dependencies": {
|
|
24
25
|
"file-type": "^21.3.0",
|
|
@@ -246,7 +246,7 @@ describe("telegram webhook handler: gatewayInternalBaseUrl", () => {
|
|
|
246
246
|
});
|
|
247
247
|
|
|
248
248
|
describe("telegram webhook handler: /new rejection", () => {
|
|
249
|
-
test("/start forwards command intent metadata, does not reset conversation, and
|
|
249
|
+
test("/start with payload forwards command intent metadata, does not reset conversation, and suppresses ACK", async () => {
|
|
250
250
|
const config = makeConfig({
|
|
251
251
|
routingEntries: [
|
|
252
252
|
{ type: "conversation_id", key: "12345", assistantId: "assistant-a" },
|
|
@@ -275,11 +275,11 @@ describe("telegram webhook handler: /new rejection", () => {
|
|
|
275
275
|
);
|
|
276
276
|
expect(resetCall).toBeUndefined();
|
|
277
277
|
|
|
278
|
+
// ACK is suppressed when /start has a payload
|
|
278
279
|
const sendMessageCall = fetchCalls.find((c) =>
|
|
279
280
|
c.url.includes("/sendMessage"),
|
|
280
281
|
);
|
|
281
|
-
expect(sendMessageCall).
|
|
282
|
-
expect((sendMessageCall!.body as any).text).toContain("Starting up");
|
|
282
|
+
expect(sendMessageCall).toBeUndefined();
|
|
283
283
|
});
|
|
284
284
|
|
|
285
285
|
test("/start with routing rejection sends setup notice and does not forward", async () => {
|
|
@@ -26,16 +26,6 @@ export const SLACK_CHANNEL_TRANSPORT_HINTS = [
|
|
|
26
26
|
export const SLACK_CHANNEL_TRANSPORT_UX_BRIEF =
|
|
27
27
|
"Slack is a threaded channel medium. Replies should stay in-thread when a thread_ts is present. Use plain text or Slack mrkdwn formatting; avoid markdown tables and complex block layouts.";
|
|
28
28
|
|
|
29
|
-
export function buildSlackTransportMetadata(): {
|
|
30
|
-
hints: string[];
|
|
31
|
-
uxBrief: string;
|
|
32
|
-
} {
|
|
33
|
-
return {
|
|
34
|
-
hints: [...SLACK_CHANNEL_TRANSPORT_HINTS],
|
|
35
|
-
uxBrief: SLACK_CHANNEL_TRANSPORT_UX_BRIEF,
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
29
|
export const WHATSAPP_CHANNEL_TRANSPORT_HINTS = [
|
|
40
30
|
"chat-first-medium",
|
|
41
31
|
"channel-safe-onboarding",
|
|
@@ -146,6 +146,10 @@ export function createContactsControlPlaneProxyHandler(config: GatewayConfig) {
|
|
|
146
146
|
return proxyToRuntime(req, "/v1/contacts/invites/redeem", "");
|
|
147
147
|
},
|
|
148
148
|
|
|
149
|
+
async handleCallInvite(req: Request, inviteId: string): Promise<Response> {
|
|
150
|
+
return proxyToRuntime(req, `/v1/contacts/invites/${inviteId}/call`, "");
|
|
151
|
+
},
|
|
152
|
+
|
|
149
153
|
async handleRevokeInvite(
|
|
150
154
|
req: Request,
|
|
151
155
|
inviteId: string,
|
|
@@ -239,7 +239,7 @@ describe("telegram-webhook callback query acknowledgment", () => {
|
|
|
239
239
|
expect(sendTelegramReplyMock).not.toHaveBeenCalled();
|
|
240
240
|
});
|
|
241
241
|
|
|
242
|
-
it("forwards /start as channel command-intent metadata
|
|
242
|
+
it("forwards /start with payload as channel command-intent metadata without sending ACK", async () => {
|
|
243
243
|
const { handler } = createTelegramWebhookHandler(baseConfig, makeCaches());
|
|
244
244
|
const body = JSON.stringify({
|
|
245
245
|
update_id: 314,
|
|
@@ -263,14 +263,8 @@ describe("telegram-webhook callback query acknowledgment", () => {
|
|
|
263
263
|
type: "start",
|
|
264
264
|
payload: "ref-123",
|
|
265
265
|
});
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
GatewayConfig,
|
|
269
|
-
string,
|
|
270
|
-
string,
|
|
271
|
-
];
|
|
272
|
-
expect(sendArgs[1]).toBe("42");
|
|
273
|
-
expect(sendArgs[2]).toContain("Starting up");
|
|
266
|
+
// ACK is suppressed when /start has a payload
|
|
267
|
+
expect(sendTelegramReplyMock).not.toHaveBeenCalled();
|
|
274
268
|
});
|
|
275
269
|
|
|
276
270
|
it("does not call answerCallbackQuery for regular text messages", async () => {
|
|
@@ -357,7 +357,9 @@ export function createTelegramWebhookHandler(
|
|
|
357
357
|
|
|
358
358
|
// Forward to runtime with command-intent metadata so the assistant
|
|
359
359
|
// generates a natural greeting via the normal agent loop.
|
|
360
|
-
|
|
360
|
+
// Skip the ACK when the /start includes a payload (e.g. invite token) —
|
|
361
|
+
// the runtime will send its own contextual reply during ACL enforcement.
|
|
362
|
+
if (!normalized.message.callbackQueryId && !startCmd.payload) {
|
|
361
363
|
sendTelegramReply(
|
|
362
364
|
config,
|
|
363
365
|
normalized.message.conversationExternalId,
|
package/src/index.ts
CHANGED
|
@@ -466,6 +466,13 @@ async function main() {
|
|
|
466
466
|
auth: "edge",
|
|
467
467
|
handler: (req) => contactsControlPlaneProxy.handleRedeemInvite(req),
|
|
468
468
|
},
|
|
469
|
+
{
|
|
470
|
+
path: /^\/v1\/contacts\/invites\/([^/]+)\/call$/,
|
|
471
|
+
method: "POST",
|
|
472
|
+
auth: "edge",
|
|
473
|
+
handler: (req, params) =>
|
|
474
|
+
contactsControlPlaneProxy.handleCallInvite(req, params[0]),
|
|
475
|
+
},
|
|
469
476
|
{
|
|
470
477
|
path: /^\/v1\/contacts\/invites\/([^/]+)$/,
|
|
471
478
|
method: "DELETE",
|
package/src/runtime/client.ts
CHANGED
|
@@ -90,13 +90,6 @@ function cbOnFailure(): void {
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
/** Exported for testing — resets circuit breaker to initial state. */
|
|
94
|
-
export function _resetCircuitBreaker(): void {
|
|
95
|
-
cbState = CircuitState.CLOSED;
|
|
96
|
-
cbConsecutiveFailures = 0;
|
|
97
|
-
cbOpenedAt = 0;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
93
|
/**
|
|
101
94
|
* Build common headers for runtime requests using JWT auth.
|
|
102
95
|
*
|
package/src/schema.ts
CHANGED
|
@@ -1145,6 +1145,41 @@ export function buildSchema(): Record<string, unknown> {
|
|
|
1145
1145
|
},
|
|
1146
1146
|
},
|
|
1147
1147
|
},
|
|
1148
|
+
"/v1/contacts/invites/{inviteId}/call": {
|
|
1149
|
+
post: {
|
|
1150
|
+
summary: "Call a contacts invite",
|
|
1151
|
+
description:
|
|
1152
|
+
"Authenticated gateway endpoint that initiates a call for a contacts invite via the assistant runtime.",
|
|
1153
|
+
operationId: "contactsInvitesCallPost",
|
|
1154
|
+
security: [{ BearerAuth: [] }],
|
|
1155
|
+
parameters: [
|
|
1156
|
+
{
|
|
1157
|
+
name: "inviteId",
|
|
1158
|
+
in: "path",
|
|
1159
|
+
required: true,
|
|
1160
|
+
schema: { type: "string" },
|
|
1161
|
+
},
|
|
1162
|
+
],
|
|
1163
|
+
requestBody: {
|
|
1164
|
+
required: true,
|
|
1165
|
+
content: {
|
|
1166
|
+
"application/json": {
|
|
1167
|
+
schema: { type: "object", additionalProperties: true },
|
|
1168
|
+
},
|
|
1169
|
+
},
|
|
1170
|
+
},
|
|
1171
|
+
responses: {
|
|
1172
|
+
"200": { description: "Invite call initiated" },
|
|
1173
|
+
"401": {
|
|
1174
|
+
description: "Unauthorized — missing or invalid bearer token",
|
|
1175
|
+
},
|
|
1176
|
+
"404": { description: "Invite not found" },
|
|
1177
|
+
"503": { description: "Bearer token not configured" },
|
|
1178
|
+
"502": { description: "Failed to reach assistant runtime" },
|
|
1179
|
+
"504": { description: "Assistant runtime request timed out" },
|
|
1180
|
+
},
|
|
1181
|
+
},
|
|
1182
|
+
},
|
|
1148
1183
|
"/v1/contacts/invites/{inviteId}": {
|
|
1149
1184
|
delete: {
|
|
1150
1185
|
summary: "Revoke contacts invite",
|