| import { SECRET } from "./secret" |
| import { domain } from "./stage" |
|
|
| const description = "Managed by SST (Don't edit in Honeycomb UI)" |
| const alertsDisabled = $app.stage !== "production" |
|
|
| const webhookRecipient = new honeycombio.WebhookRecipient("DiscordAlerts", { |
| name: $app.stage === "production" ? "Discord Alerts" : `Discord Alerts (${$app.stage})`, |
| url: `https://${domain}/honeycomb/webhook`, |
| secret: SECRET.HoneycombWebhookSecret.result, |
| templates: [ |
| { |
| type: "trigger", |
| body: `{ |
| "url": {{ .Result.URL | quote }}, |
| "type": {{ .Vars.type | quote }}, |
| "name": {{ .Name | quote }}, |
| "status": {{ .Alert.Status | quote }}, |
| "isTest": {{ .Alert.IsTest }}, |
| "groups": {{ .Result.GroupsTriggered | toJson }} |
| }`, |
| }, |
| ], |
| variables: [ |
| { |
| name: "type", |
| }, |
| ], |
| }) |
|
|
| |
| |
| |
| const calculatedField = (field: { name: string; expression: string }) => ({ |
| ...field, |
| name: `${field.name}_${( |
| Array.from(field.expression).reduce((result, char) => Math.imul(31, result) + char.charCodeAt(0), 0) >>> 0 |
| ).toString(36)}`, |
| }) |
|
|
| const modelHttpErrorsQuery = (product: "go" | "zen") => { |
| const filters = [ |
| { column: "model", op: "exists" }, |
| { column: "event_type", op: "=", value: "completions" }, |
| { column: "user_agent", op: "contains", value: "opencode" }, |
| { column: "isGoTier", op: "=", value: product === "go" ? "true" : "false" }, |
| ] |
| const failedHttpStatus = calculatedField({ |
| name: "is_failed_http_status", |
| expression: ` |
| IF( |
| AND( |
| GTE($status, "400"), |
| NOT(EQUALS($status, "401")), |
| NOT( |
| AND( |
| EQUALS($status, "429"), |
| OR( |
| EQUALS($error.type, "GoUsageLimitError"), |
| EQUALS($error.type, "FreeUsageLimitError") |
| ) |
| ) |
| ) |
| ), |
| 1, |
| 0 |
| )`, |
| }) |
|
|
| return honeycombio.getQuerySpecificationOutput({ |
| breakdowns: ["model"], |
| calculatedFields: [failedHttpStatus], |
| calculations: [ |
| { op: "COUNT", name: "TOTAL", filterCombination: "AND", filters }, |
| { |
| op: "SUM", |
| name: "FAILED", |
| column: failedHttpStatus.name, |
| filterCombination: "AND", |
| filters, |
| }, |
| ], |
| formulas: [{ name: "ERROR", expression: "IF(GTE($TOTAL, 150), DIV($FAILED, $TOTAL), 0)" }], |
| timeRange: 900, |
| }).json |
| } |
|
|
| const providerHttpErrorsQuery = () => { |
| const filters = [ |
| { column: "provider", op: "exists" }, |
| { column: "user_agent", op: "contains", value: "opencode" }, |
| ] |
| const successHttpStatus = calculatedField({ |
| name: "is_success_http_status", |
| expression: `IF(AND(GTE($status, "200"), LT($status, "400")), 1, 0)`, |
| }) |
| const failedProviderHttpStatus = calculatedField({ |
| name: "is_failed_provider_http_status", |
| expression: `IF(GT($llm.error.code, "400"), 1, 0)`, |
| }) |
|
|
| return honeycombio.getQuerySpecificationOutput({ |
| breakdowns: ["provider"], |
| calculatedFields: [successHttpStatus, failedProviderHttpStatus], |
| calculations: [ |
| { |
| op: "SUM", |
| name: "SUCCESS", |
| column: successHttpStatus.name, |
| filterCombination: "AND", |
| filters: [...filters, { column: "event_type", op: "=", value: "completions" }], |
| }, |
| { |
| op: "SUM", |
| name: "FAILED", |
| column: failedProviderHttpStatus.name, |
| filterCombination: "AND", |
| filters: [ |
| ...filters, |
| { column: "event_type", op: "=", value: "llm.error" }, |
| { column: "llm.error.code", op: "!=", value: "404" }, |
| ], |
| }, |
| ], |
| formulas: [ |
| { name: "ERROR", expression: "IF(GTE(SUM($SUCCESS, $FAILED), 150), DIV($FAILED, SUM($SUCCESS, $FAILED)), 0)" }, |
| ], |
| timeRange: 900, |
| }).json |
| } |
|
|
| const modelLowTpsQuery = (product: "go" | "zen") => { |
| const filters = [ |
| { column: "model", op: "exists" }, |
| { column: "event_type", op: "=", value: "completions" }, |
| { column: "user_agent", op: "contains", value: "opencode" }, |
| { column: "isGoTier", op: "=", value: product === "go" ? "true" : "false" }, |
| { column: "status", op: ">=", value: "200" }, |
| { column: "status", op: "<", value: "400" }, |
| { column: "tps.output", op: "exists" }, |
| ] |
|
|
| return honeycombio.getQuerySpecificationOutput({ |
| breakdowns: ["model"], |
| calculations: [ |
| { op: "COUNT", name: "TOTAL", filterCombination: "AND", filters }, |
| { |
| op: "P50", |
| name: "TPS", |
| column: "tps.output", |
| filterCombination: "AND", |
| filters, |
| }, |
| ], |
| formulas: [{ name: "LOW_TPS", expression: "IF(GTE($TOTAL, 100), $TPS, 999)" }], |
| timeRange: 1800, |
| }).json |
| } |
|
|
| new honeycombio.Trigger("IncreasedModelHttpErrorsGo", { |
| name: "Increased Model HTTP Errors [Go]", |
| description, |
| disabled: alertsDisabled, |
| queryJson: modelHttpErrorsQuery("go"), |
| alertType: "on_change", |
| frequency: 300, |
| thresholds: [{ op: ">=", value: 0.7, exceededLimit: 1 }], |
| recipients: [ |
| { |
| id: webhookRecipient.id, |
| notificationDetails: [ |
| { |
| variables: [{ name: "type", value: "model_http_errors" }], |
| }, |
| ], |
| }, |
| ], |
| }) |
|
|
| new honeycombio.Trigger("IncreasedModelHttpErrorsZen", { |
| name: "Increased Model HTTP Errors [Zen]", |
| description, |
| disabled: alertsDisabled, |
| queryJson: modelHttpErrorsQuery("zen"), |
| alertType: "on_change", |
| frequency: 300, |
| thresholds: [{ op: ">=", value: 0.7, exceededLimit: 1 }], |
| recipients: [ |
| { |
| id: webhookRecipient.id, |
| notificationDetails: [ |
| { |
| variables: [{ name: "type", value: "model_http_errors" }], |
| }, |
| ], |
| }, |
| ], |
| }) |
|
|
| new honeycombio.Trigger("LowModelTpsGo", { |
| name: "Low Model TPS [Go]", |
| description, |
| disabled: alertsDisabled, |
| queryJson: modelLowTpsQuery("go"), |
| alertType: "on_change", |
| frequency: 600, |
| thresholds: [{ op: "<=", value: 10, exceededLimit: 1 }], |
| recipients: [ |
| { |
| id: webhookRecipient.id, |
| notificationDetails: [ |
| { |
| variables: [{ name: "type", value: "model_low_tps" }], |
| }, |
| ], |
| }, |
| ], |
| }) |
|
|
| new honeycombio.Trigger("LowModelTpsZen", { |
| name: "Low Model TPS [Zen]", |
| description, |
| disabled: alertsDisabled, |
| queryJson: modelLowTpsQuery("zen"), |
| alertType: "on_change", |
| frequency: 600, |
| thresholds: [{ op: "<=", value: 10, exceededLimit: 1 }], |
| recipients: [ |
| { |
| id: webhookRecipient.id, |
| notificationDetails: [ |
| { |
| variables: [{ name: "type", value: "model_low_tps" }], |
| }, |
| ], |
| }, |
| ], |
| }) |
|
|
| new honeycombio.Trigger("IncreasedProviderHttpErrors", { |
| name: "Increased Provider HTTP Errors", |
| description, |
| disabled: alertsDisabled, |
| queryJson: providerHttpErrorsQuery(), |
| alertType: "on_change", |
| frequency: 300, |
| thresholds: [{ op: ">=", value: 0.7, exceededLimit: 1 }], |
| recipients: [ |
| { |
| id: webhookRecipient.id, |
| notificationDetails: [ |
| { |
| variables: [{ name: "type", value: "provider_http_errors" }], |
| }, |
| ], |
| }, |
| ], |
| }) |
|
|
| new honeycombio.Trigger("IncreasedFreeTierRequests", { |
| name: "Increased Free Tier Requests", |
| description, |
| disabled: alertsDisabled, |
| queryJson: honeycombio.getQuerySpecificationOutput({ |
| calculations: [{ op: "COUNT" }], |
| filters: [ |
| { column: "event_type", op: "=", value: "completions" }, |
| { column: "user_agent", op: "contains", value: "opencode" }, |
| { column: "isFreeTier", op: "=", value: "true" }, |
| ], |
| timeRange: 3600, |
| }).json, |
| alertType: "on_change", |
| frequency: 900, |
| thresholds: [{ op: ">=", value: 50, exceededLimit: 1 }], |
| baselineDetails: [{ type: "percentage", offsetMinutes: 1440 }], |
| recipients: [ |
| { |
| id: webhookRecipient.id, |
| notificationDetails: [ |
| { |
| variables: [{ name: "type", value: "custom" }], |
| }, |
| ], |
| }, |
| ], |
| }) |
|
|