Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions src/agent/judge-query.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { z } from "zod/v4";
import { buildAgentRuntimeEnv, resolveAgentRuntimeModel } from "../config/providers.ts";
import type { PhantomConfig } from "../config/types.ts";
import { truncate } from "../shared/strings.ts";
import { query } from "./agent-sdk.ts";
import { extractTextFromMessage } from "./message-utils.ts";
import { getThinkingConfig } from "./thinking-config.ts";
Expand Down Expand Up @@ -364,8 +365,3 @@ function formatZodError(error: z.ZodError): string {
const suffix = error.issues.length > 3 ? ` (+${error.issues.length - 3} more)` : "";
return `${issues.join("; ")}${suffix}`;
}

function truncate(text: string, max: number): string {
if (text.length <= max) return text;
return `${text.slice(0, max)}...`;
}
6 changes: 2 additions & 4 deletions src/agent/murph-context.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { isRecord } from "../shared/strings.ts";

export type MurphContextTransform = (messages: unknown[], signal?: AbortSignal) => Promise<unknown[]> | unknown[];
export type MurphContextSource = string | undefined | (() => string | undefined | Promise<string | undefined>);

Expand Down Expand Up @@ -74,10 +76,6 @@ function hasRole(message: unknown, role: string): boolean {
return isRecord(message) && message.role === role;
}

function isRecord(value: unknown): value is Record<string, unknown> {
return value !== null && typeof value === "object";
}

function textField(record: Record<string, unknown>): string {
return typeof record.text === "string" ? record.text : "";
}
13 changes: 7 additions & 6 deletions src/channels/email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

import { randomUUID } from "node:crypto";
import { errorMessage } from "../shared/strings.ts";
import type { Channel, ChannelCapabilities, InboundMessage, OutboundMessage, SentMessage } from "./types.ts";

export type EmailChannelConfig = {
Expand Down Expand Up @@ -91,7 +92,7 @@ export class EmailChannel implements Channel {
this.idleLoopPromise = this.startIdleLoop();
} catch (err: unknown) {
this.connectionState = "error";
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.error(`[email] Failed to connect: ${msg}`);
throw err;
}
Expand All @@ -113,7 +114,7 @@ export class EmailChannel implements Channel {
try {
await this.imapClient?.logout();
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.warn(`[email] Error during IMAP disconnect: ${msg}`);
}

Expand Down Expand Up @@ -182,7 +183,7 @@ export class EmailChannel implements Channel {
try {
await this.imapClient.idle({ abort: this.idleAbort.signal });
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
if (msg.includes("abort")) break;
console.warn(`[email] IDLE error: ${msg}`);
break;
Expand All @@ -195,7 +196,7 @@ export class EmailChannel implements Channel {
lock.release();
}
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.error(`[email] IDLE loop error: ${msg}`);
}
}
Expand Down Expand Up @@ -265,12 +266,12 @@ export class EmailChannel implements Channel {
try {
await this.messageHandler(inbound);
} catch (err: unknown) {
const errMsg = err instanceof Error ? err.message : String(err);
const errMsg = errorMessage(err);
console.error(`[email] Error handling email from ${fromAddress}: ${errMsg}`);
}
}
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.warn(`[email] Error processing unread: ${msg}`);
}
}
Expand Down
13 changes: 7 additions & 6 deletions src/channels/slack-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

import type { App } from "@slack/bolt";
import { errorMessage } from "../shared/strings.ts";
import { FEEDBACK_ACTION_IDS, buildFeedbackAckBlocks, emitFeedback, parseFeedbackAction } from "./feedback.ts";
import {
MORNING_BRIEF_LOCK_ACTION_ID,
Expand Down Expand Up @@ -138,7 +139,7 @@ export function registerSlackActions(app: App): void {
blocks: [...cleaned, ...ackBlocks],
} as unknown as Parameters<typeof client.chat.update>[0]);
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.warn(`[slack] Failed to update feedback buttons: ${msg}`);
}
});
Expand Down Expand Up @@ -191,7 +192,7 @@ export function registerSlackActions(app: App): void {
],
} as unknown as Parameters<typeof client.chat.update>[0]);
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.warn(`[slack] Failed to update action buttons: ${msg}`);
}

Expand Down Expand Up @@ -259,15 +260,15 @@ export function registerSlackActions(app: App): void {
],
} as unknown as Parameters<typeof client.chat.update>[0]);
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.warn(`[slack] Failed to update morning-brief buttons: ${msg}`);
}

if (morningBriefRecorder) {
try {
await morningBriefRecorder({ userId, channel: channelId, choice: meta.choice, clickedAt: Date.now() });
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.warn(`[slack] morning-brief recorder failed: ${msg}`);
}
} else {
Expand Down Expand Up @@ -315,7 +316,7 @@ export function registerSlackActions(app: App): void {
clickedAt: Date.now(),
});
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.warn(`[slack] first-hour draft recorder failed: ${msg}`);
}
} else {
Expand Down Expand Up @@ -346,7 +347,7 @@ export function registerSlackActions(app: App): void {
blocks: updatedBlocks,
} as unknown as Parameters<typeof client.chat.update>[0]);
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.warn(`[slack] Failed to update first-hour draft buttons: ${msg}`);
}
});
Expand Down
17 changes: 9 additions & 8 deletions src/channels/slack-egress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import { randomUUID } from "node:crypto";
import type { App } from "@slack/bolt";
import { errorMessage } from "../shared/strings.ts";
import type { SlackBlock } from "./feedback.ts";
import { buildFeedbackBlocks } from "./feedback.ts";
import { splitMessage, toSlackMarkdown, truncateForSlack } from "./slack-formatter.ts";
Expand Down Expand Up @@ -57,7 +58,7 @@ export async function egressPostToChannel(ctx: EgressContext, channelId: string,
const result = await ctx.client.chat.postMessage({ channel: channelId, text: chunk });
lastTs = result.ts ?? null;
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.error(`[${ctx.logTag}] Failed to post to channel ${channelId}: ${msg}`);
return null;
}
Expand Down Expand Up @@ -97,12 +98,12 @@ export async function egressSendDm(
);
return result.ts ?? null;
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.error(`[${ctx.logTag}] Failed to post DM blocks to user ${userId}: ${msg}`);
return null;
}
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.error(`[${ctx.logTag}] Failed to send DM to user ${userId}: ${msg}`);
return null;
}
Expand All @@ -121,7 +122,7 @@ export async function egressPostThinking(
});
return result.ts ?? null;
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.warn(`[${ctx.logTag}] Failed to post thinking indicator: ${msg}`);
return null;
}
Expand All @@ -145,7 +146,7 @@ export async function egressUpdateMessage(
if (blocks) updateArgs.blocks = blocks;
await ctx.client.chat.update(updateArgs as unknown as Parameters<typeof ctx.client.chat.update>[0]);
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.warn(`[${ctx.logTag}] Failed to update message: ${msg}`);
}
}
Expand All @@ -165,7 +166,7 @@ export async function egressUpdateWithFeedback(
const updateArgs: Record<string, unknown> = { channel, ts, text: truncated, blocks };
await ctx.client.chat.update(updateArgs as unknown as Parameters<typeof ctx.client.chat.update>[0]);
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.warn(`[${ctx.logTag}] Failed to update message with feedback: ${msg}`);
}
}
Expand All @@ -179,7 +180,7 @@ export async function egressAddReaction(
try {
await ctx.client.reactions.add({ channel, timestamp: messageTs, name: emoji });
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
if (!msg.includes("already_reacted")) {
console.warn(`[${ctx.logTag}] Failed to add reaction :${emoji}:: ${msg}`);
}
Expand All @@ -195,7 +196,7 @@ export async function egressRemoveReaction(
try {
await ctx.client.reactions.remove({ channel, timestamp: messageTs, name: emoji });
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
if (!msg.includes("no_reaction")) {
console.warn(`[${ctx.logTag}] Failed to remove reaction :${emoji}:: ${msg}`);
}
Expand Down
9 changes: 5 additions & 4 deletions src/channels/slack.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { App, type LogLevel, SocketModeReceiver } from "@slack/bolt";
import { errorMessage } from "../shared/strings.ts";
import type { SlackBlock } from "./feedback.ts";
import { registerSlackActions } from "./slack-actions.ts";
import {
Expand Down Expand Up @@ -242,7 +243,7 @@ export class SlackChannel implements Channel {
// down tenant even though no `disconnected` event ever fired
// (the SocketModeClient never made it past handshake).
this.metrics.recordState("error");
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.error(`[slack] Failed to connect: ${msg}`);
throw err;
}
Expand All @@ -254,7 +255,7 @@ export class SlackChannel implements Channel {
try {
await this.app.stop();
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.warn(`[slack] Error during disconnect: ${msg}`);
}

Expand Down Expand Up @@ -351,7 +352,7 @@ export class SlackChannel implements Channel {
try {
await this.messageHandler(inbound);
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.error(`[slack] Error handling app_mention: ${msg}`);
}
});
Expand Down Expand Up @@ -405,7 +406,7 @@ export class SlackChannel implements Channel {
try {
await this.messageHandler(inbound);
} catch (err: unknown) {
const errMsg = err instanceof Error ? err.message : String(err);
const errMsg = errorMessage(err);
console.error(`[slack] Error handling DM: ${errMsg}`);
}
});
Expand Down
7 changes: 2 additions & 5 deletions src/channels/slack/render-first-hour-dm.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { truncate } from "../../shared/strings.ts";

// Block Kit renderer for the do_first_hour_of_work DM (architect §5).
//
// Shape: 1 header + 1 markdown summary + N draft sections (each with 3
Expand Down Expand Up @@ -178,8 +180,3 @@ export function renderFirstHourDmFallbackText(persona: PersonaWorkPlan, draftCou
const tail = draftCount === 1 ? "1 item" : `${draftCount} items`;
return `${persona.intro_line} I drafted ${tail} for you. ${persona.footer_line}`;
}

function truncate(s: string, max: number): string {
if (s.length <= max) return s;
return `${s.slice(0, Math.max(0, max - 3))}...`;
}
11 changes: 6 additions & 5 deletions src/channels/telegram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* MarkdownV2 formatting, and command handling.
*/

import { errorMessage } from "../shared/strings.ts";
import type { Channel, ChannelCapabilities, InboundMessage, OutboundMessage, SentMessage } from "./types.ts";

type TelegrafBot = {
Expand Down Expand Up @@ -91,7 +92,7 @@ export class TelegramChannel implements Channel {
console.log("[telegram] Bot connected via long polling");
} catch (err: unknown) {
this.connectionState = "error";
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.error(`[telegram] Failed to connect: ${msg}`);
throw err;
}
Expand All @@ -109,7 +110,7 @@ export class TelegramChannel implements Channel {
try {
this.bot?.stop();
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.warn(`[telegram] Error during disconnect: ${msg}`);
}

Expand Down Expand Up @@ -190,7 +191,7 @@ export class TelegramChannel implements Channel {
parse_mode: "MarkdownV2",
});
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
// "message is not modified" is expected when text hasn't changed
if (!msg.includes("message is not modified")) {
console.warn(`[telegram] Failed to edit message: ${msg}`);
Expand Down Expand Up @@ -243,7 +244,7 @@ export class TelegramChannel implements Channel {
try {
await this.messageHandler(inbound);
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.error(`[telegram] Error handling message: ${msg}`);
}
});
Expand Down Expand Up @@ -281,7 +282,7 @@ export class TelegramChannel implements Channel {
try {
await this.messageHandler(inbound);
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
const msg = errorMessage(err);
console.error(`[telegram] Error handling callback: ${msg}`);
}
});
Expand Down
Loading
Loading