Build the agent-native compute CRM platform
CI / verify (push) Successful in 3m6s

This commit is contained in:
2026-08-13 01:39:01 -07:00
parent bfd2f8d95a
commit 853bde2265
160 changed files with 61812 additions and 483 deletions
+124
View File
@@ -0,0 +1,124 @@
import { createHash } from 'node:crypto';
import {
NotificationDeliveryError,
type Notification,
type NotificationEnvelope,
type NotificationReceipt,
type Notifier,
} from './notifier';
interface SlackNotifierOptions {
botToken: string;
fetchImpl?: typeof fetch;
apiBase?: string;
}
interface SlackResponse {
ok?: boolean;
error?: string;
ts?: string;
}
export class SlackNotifier implements Notifier {
readonly provider = 'slack';
private readonly fetchImpl: typeof fetch;
private readonly apiBase: string;
constructor(private readonly options: SlackNotifierOptions) {
this.fetchImpl = options.fetchImpl ?? fetch;
this.apiBase = options.apiBase ?? 'https://slack.com/api';
}
async send(
envelope: NotificationEnvelope,
signal?: AbortSignal,
): Promise<NotificationReceipt> {
let response: Response;
try {
response = await this.fetchImpl(`${this.apiBase}/chat.postMessage`, {
method: 'POST',
headers: {
authorization: `Bearer ${this.options.botToken}`,
'content-type': 'application/json; charset=utf-8',
},
body: JSON.stringify({
channel: envelope.destination,
text: formatSlackNotification(envelope.notification),
client_msg_id: slackClientMessageId(envelope.idempotencyKey),
unfurl_links: false,
unfurl_media: false,
}),
signal,
});
} catch {
throw new NotificationDeliveryError('network_error', true);
}
if (response.status === 429) {
const retrySeconds = Number(response.headers.get('retry-after'));
throw new NotificationDeliveryError(
'rate_limited',
true,
Number.isFinite(retrySeconds) && retrySeconds > 0 ? retrySeconds * 1_000 : undefined,
);
}
if (response.status >= 500) {
throw new NotificationDeliveryError('slack_unavailable', true);
}
if (!response.ok) {
throw new NotificationDeliveryError('slack_http_error', false);
}
let result: SlackResponse;
try {
result = (await response.json()) as SlackResponse;
} catch {
throw new NotificationDeliveryError('invalid_slack_response', true);
}
if (!result.ok) {
const code = normaliseSlackError(result.error);
throw new NotificationDeliveryError(code, isRetryableSlackError(code));
}
return { externalId: result.ts ?? null };
}
}
export function slackClientMessageId(idempotencyKey: string): string {
const digest = createHash('sha256').update(idempotencyKey).digest('hex');
return `${digest.slice(0, 8)}-${digest.slice(8, 12)}-4${digest.slice(13, 16)}-a${digest.slice(17, 20)}-${digest.slice(20, 32)}`;
}
function formatSlackNotification(notification: Notification): string {
if (notification.kind === 'stage_change') {
return [
`*${notification.dealName}* moved from \`${notification.fromStage}\` to \`${notification.toStage}\`.`,
`${notification.dealSide === 'demand' ? 'Demand' : 'Supply'} pipeline stage changed in PIG.`,
].join('\n');
}
return [
`*Idle capacity: ${notification.commitmentName}*`,
`${notification.gpuType} has ${formatNumber(notification.idleGpuHours)} unsold GPU-hours (${Math.round(notification.utilisation * 100)}% utilised).`,
`Idle committed cost: ${formatMoney(notification.idleCostCents)}.`,
].join('\n');
}
function formatNumber(value: number): string {
return new Intl.NumberFormat('en-US', { maximumFractionDigits: 1 }).format(value);
}
function formatMoney(cents: number): string {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
maximumFractionDigits: 0,
}).format(cents / 100);
}
function normaliseSlackError(error: string | undefined): string {
return error && /^[a-z0-9_]+$/i.test(error) ? error : 'unknown_slack_error';
}
function isRetryableSlackError(code: string): boolean {
return ['ratelimited', 'internal_error', 'fatal_error', 'request_timeout'].includes(code);
}