fix(sdk,slack): correct GitLab verifier and Slack secret provisioning, skip unroutable channel turns
- webhooks.gitlab used the Svix preset (svix-id/svix-timestamp/svix-signature,
HMAC over {id}.{timestamp}.{body}), but GitLab doesn't sign bodies: it echoes
the configured token in X-Gitlab-Token. Every GitLab delivery failed
verification. Switched it to the shared-secret scheme (header, x-gitlab-token).
- The Slack connector declared secretProvisioning 'integrator', so the Connect
panel offered a Generate-secret button, but Slack mints its own Signing Secret
that must be pasted (core already classifies slack as 'provider'). Changed to
'provider'.
- A verified channel delivery naming a connector the running agent doesn't have
fell through to a normal turn with an empty incoming message, so the agent
answered nothing and burned tokens. Handle the unresolved-connector case like a
stale interaction: warn with the connectorId/deliveryId and skip the turn
without consuming a turn.
This commit is contained in:
@@ -145,7 +145,7 @@ export function slack<TEvent = SlackMessageEvent>(
|
||||
const source: WebhookSource<TEvent> = {
|
||||
provider: "slack",
|
||||
verifier: { kind: "config", config: SLACK_VERIFIER, handshake: SLACK_HANDSHAKE },
|
||||
secretProvisioning: "integrator",
|
||||
secretProvisioning: "provider",
|
||||
};
|
||||
const messageFilter = options.filter
|
||||
? `${SELF_MESSAGE_GUARD} && (${options.filter})`
|
||||
|
||||
@@ -6972,6 +6972,7 @@ function chatAgent<
|
||||
let channelAckRef: string | undefined;
|
||||
let channelStreamEditor: ChannelStreamEditor | undefined;
|
||||
let droppedStaleInteraction = false;
|
||||
let droppedUnknownConnector = false;
|
||||
let channelFinalAnswerPosted = false;
|
||||
try {
|
||||
// Extract turn-level context before entering the span. Slim
|
||||
@@ -7085,6 +7086,15 @@ function chatAgent<
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
droppedUnknownConnector = true;
|
||||
logger.warn(
|
||||
"chat.agent: no channel connector matches this delivery; skipping turn",
|
||||
{
|
||||
connectorId: wireChannelEvent.connectorId,
|
||||
deliveryId: wireChannelEvent.deliveryId,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
const incomingMessages: TUIMessage[] = effectiveIncomingMessage
|
||||
@@ -7334,7 +7344,11 @@ function chatAgent<
|
||||
// snapshot + `session.out` replay (or `hydrateMessages`,
|
||||
// which also fires per-turn below). Per-turn handling is
|
||||
// therefore a delta merge, not a full-history reset.
|
||||
if (currentWirePayload.trigger !== "action" && !droppedStaleInteraction) {
|
||||
if (
|
||||
currentWirePayload.trigger !== "action" &&
|
||||
!droppedStaleInteraction &&
|
||||
!droppedUnknownConnector
|
||||
) {
|
||||
let cleanedUIMessages: TUIMessage[] = cleanedIncomingMessages;
|
||||
|
||||
// Turn-0 head-start with hydrateMessages: the boot seeding from
|
||||
@@ -7633,12 +7647,12 @@ function chatAgent<
|
||||
turn--;
|
||||
}
|
||||
|
||||
if (droppedStaleInteraction) {
|
||||
if (droppedStaleInteraction || droppedUnknownConnector) {
|
||||
msgSub.off();
|
||||
turn--;
|
||||
}
|
||||
|
||||
if (!isAction && !droppedStaleInteraction) {
|
||||
if (!isAction && !droppedStaleInteraction && !droppedUnknownConnector) {
|
||||
// Mint a scoped public access token once per turn, reused for
|
||||
// onChatStart, onTurnStart, onTurnComplete, and the turn-complete chunk.
|
||||
const currentRunId = ctx.run.id;
|
||||
|
||||
@@ -163,7 +163,10 @@ export const webhookSources = {
|
||||
gitlab<T = unknown>(): WebhookSource<T> {
|
||||
return {
|
||||
provider: "gitlab",
|
||||
verifier: { kind: "preset", preset: "svix", config: svixVerifierConfig() },
|
||||
verifier: {
|
||||
kind: "config",
|
||||
config: { scheme: "shared-secret", placement: "header", fieldName: "x-gitlab-token" },
|
||||
},
|
||||
secretProvisioning: "integrator",
|
||||
};
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user