fix: resolve lint errors (unused vars, imports, formatting)
- Prefix unused test variables with underscore - Remove unused piSpec import and idleMs class member - Fix import ordering and code formatting
This commit is contained in:
committed by
Peter Steinberger
parent
518af0ef24
commit
4a35bcec21
@@ -16,8 +16,8 @@ import {
|
||||
formatToolAggregate,
|
||||
shortenMeta,
|
||||
shortenPath,
|
||||
TOOL_RESULT_FLUSH_COUNT,
|
||||
TOOL_RESULT_DEBOUNCE_MS,
|
||||
TOOL_RESULT_FLUSH_COUNT,
|
||||
} from "./tool-meta.js";
|
||||
import type { ReplyPayload } from "./types.js";
|
||||
|
||||
@@ -345,7 +345,11 @@ export async function runCommandReply(
|
||||
|
||||
// Tau (pi agent) needs --continue to reload prior messages when resuming.
|
||||
// Without it, pi starts from a blank state even though we pass the session file path.
|
||||
if (agentKind === "pi" && !isNewSession && !sessionArgList.includes("--continue")) {
|
||||
if (
|
||||
agentKind === "pi" &&
|
||||
!isNewSession &&
|
||||
!sessionArgList.includes("--continue")
|
||||
) {
|
||||
sessionArgList.push("--continue");
|
||||
}
|
||||
|
||||
@@ -433,10 +437,7 @@ export async function runCommandReply(
|
||||
}
|
||||
};
|
||||
let lastStreamedAssistant: string | undefined;
|
||||
const streamAssistant = (msg?: {
|
||||
role?: string;
|
||||
content?: unknown[];
|
||||
}) => {
|
||||
const streamAssistant = (msg?: { role?: string; content?: unknown[] }) => {
|
||||
if (!onPartialReply || msg?.role !== "assistant") return;
|
||||
const textBlocks = Array.isArray(msg.content)
|
||||
? (msg.content as Array<{ type?: string; text?: string }>)
|
||||
@@ -478,68 +479,37 @@ export async function runCommandReply(
|
||||
cwd: reply.cwd,
|
||||
prompt: body,
|
||||
timeoutMs,
|
||||
onEvent:
|
||||
onPartialReply
|
||||
? (line: string) => {
|
||||
try {
|
||||
const ev = JSON.parse(line) as {
|
||||
type?: string;
|
||||
message?: {
|
||||
role?: string;
|
||||
content?: unknown[];
|
||||
details?: Record<string, unknown>;
|
||||
arguments?: Record<string, unknown>;
|
||||
toolCallId?: string;
|
||||
tool_call_id?: string;
|
||||
toolName?: string;
|
||||
name?: string;
|
||||
};
|
||||
onEvent: onPartialReply
|
||||
? (line: string) => {
|
||||
try {
|
||||
const ev = JSON.parse(line) as {
|
||||
type?: string;
|
||||
message?: {
|
||||
role?: string;
|
||||
content?: unknown[];
|
||||
details?: Record<string, unknown>;
|
||||
arguments?: Record<string, unknown>;
|
||||
toolCallId?: string;
|
||||
tool_call_id?: string;
|
||||
toolName?: string;
|
||||
args?: Record<string, unknown>;
|
||||
name?: string;
|
||||
};
|
||||
// Capture metadata as soon as the tool starts (from args).
|
||||
if (ev.type === "tool_execution_start") {
|
||||
const toolName = ev.toolName;
|
||||
const meta = inferToolMeta({
|
||||
toolName,
|
||||
name: ev.toolName,
|
||||
arguments: ev.args,
|
||||
});
|
||||
if (ev.toolCallId) {
|
||||
toolMetaById.set(ev.toolCallId, meta);
|
||||
}
|
||||
if (meta) {
|
||||
if (pendingToolName && toolName && toolName !== pendingToolName) {
|
||||
flushPendingTool();
|
||||
}
|
||||
if (!pendingToolName) pendingToolName = toolName;
|
||||
pendingMetas.push(meta);
|
||||
if (
|
||||
TOOL_RESULT_FLUSH_COUNT > 0 &&
|
||||
pendingMetas.length >= TOOL_RESULT_FLUSH_COUNT
|
||||
) {
|
||||
flushPendingTool();
|
||||
} else {
|
||||
if (pendingTimer) clearTimeout(pendingTimer);
|
||||
pendingTimer = setTimeout(
|
||||
flushPendingTool,
|
||||
TOOL_RESULT_DEBOUNCE_MS,
|
||||
);
|
||||
}
|
||||
}
|
||||
toolCallId?: string;
|
||||
toolName?: string;
|
||||
args?: Record<string, unknown>;
|
||||
};
|
||||
// Capture metadata as soon as the tool starts (from args).
|
||||
if (ev.type === "tool_execution_start") {
|
||||
const toolName = ev.toolName;
|
||||
const meta = inferToolMeta({
|
||||
toolName,
|
||||
name: ev.toolName,
|
||||
arguments: ev.args,
|
||||
});
|
||||
if (ev.toolCallId) {
|
||||
toolMetaById.set(ev.toolCallId, meta);
|
||||
}
|
||||
if (
|
||||
(ev.type === "message" || ev.type === "message_end") &&
|
||||
ev.message?.role === "tool_result" &&
|
||||
Array.isArray(ev.message.content)
|
||||
) {
|
||||
const toolName = inferToolName(ev.message);
|
||||
const toolCallId =
|
||||
ev.message.toolCallId ?? ev.message.tool_call_id;
|
||||
const meta =
|
||||
inferToolMeta(ev.message) ??
|
||||
(toolCallId ? toolMetaById.get(toolCallId) : undefined);
|
||||
if (meta) {
|
||||
if (
|
||||
pendingToolName &&
|
||||
toolName &&
|
||||
@@ -548,32 +518,66 @@ export async function runCommandReply(
|
||||
flushPendingTool();
|
||||
}
|
||||
if (!pendingToolName) pendingToolName = toolName;
|
||||
if (meta) pendingMetas.push(meta);
|
||||
pendingMetas.push(meta);
|
||||
if (
|
||||
TOOL_RESULT_FLUSH_COUNT > 0 &&
|
||||
pendingMetas.length >= TOOL_RESULT_FLUSH_COUNT
|
||||
) {
|
||||
flushPendingTool();
|
||||
return;
|
||||
} else {
|
||||
if (pendingTimer) clearTimeout(pendingTimer);
|
||||
pendingTimer = setTimeout(
|
||||
flushPendingTool,
|
||||
TOOL_RESULT_DEBOUNCE_MS,
|
||||
);
|
||||
}
|
||||
if (pendingTimer) clearTimeout(pendingTimer);
|
||||
pendingTimer = setTimeout(
|
||||
flushPendingTool,
|
||||
TOOL_RESULT_DEBOUNCE_MS,
|
||||
);
|
||||
}
|
||||
if (
|
||||
ev.type === "message_end" ||
|
||||
ev.type === "message_update" ||
|
||||
ev.type === "message"
|
||||
) {
|
||||
streamAssistant(ev.message);
|
||||
}
|
||||
} catch {
|
||||
// ignore malformed lines
|
||||
}
|
||||
if (
|
||||
(ev.type === "message" || ev.type === "message_end") &&
|
||||
ev.message?.role === "tool_result" &&
|
||||
Array.isArray(ev.message.content)
|
||||
) {
|
||||
const toolName = inferToolName(ev.message);
|
||||
const toolCallId =
|
||||
ev.message.toolCallId ?? ev.message.tool_call_id;
|
||||
const meta =
|
||||
inferToolMeta(ev.message) ??
|
||||
(toolCallId ? toolMetaById.get(toolCallId) : undefined);
|
||||
if (
|
||||
pendingToolName &&
|
||||
toolName &&
|
||||
toolName !== pendingToolName
|
||||
) {
|
||||
flushPendingTool();
|
||||
}
|
||||
if (!pendingToolName) pendingToolName = toolName;
|
||||
if (meta) pendingMetas.push(meta);
|
||||
if (
|
||||
TOOL_RESULT_FLUSH_COUNT > 0 &&
|
||||
pendingMetas.length >= TOOL_RESULT_FLUSH_COUNT
|
||||
) {
|
||||
flushPendingTool();
|
||||
return;
|
||||
}
|
||||
if (pendingTimer) clearTimeout(pendingTimer);
|
||||
pendingTimer = setTimeout(
|
||||
flushPendingTool,
|
||||
TOOL_RESULT_DEBOUNCE_MS,
|
||||
);
|
||||
}
|
||||
if (
|
||||
ev.type === "message_end" ||
|
||||
ev.type === "message_update" ||
|
||||
ev.type === "message"
|
||||
) {
|
||||
streamAssistant(ev.message);
|
||||
}
|
||||
} catch {
|
||||
// ignore malformed lines
|
||||
}
|
||||
: undefined,
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
flushPendingTool();
|
||||
return rpcResult;
|
||||
@@ -610,10 +614,10 @@ export async function runCommandReply(
|
||||
type ReplyItem = { text: string; media?: string[] };
|
||||
const replyItems: ReplyItem[] = [];
|
||||
|
||||
const includeToolResultsInline =
|
||||
const includeToolResultsInline =
|
||||
verboseLevel === "on" && !onPartialReply && parsedToolResults.length > 0;
|
||||
|
||||
if (includeToolResultsInline) {
|
||||
if (includeToolResultsInline) {
|
||||
const aggregated = parsedToolResults.reduce<
|
||||
{ toolName?: string; metas: string[]; previews: string[] }[]
|
||||
>((acc, tr) => {
|
||||
@@ -647,7 +651,8 @@ export async function runCommandReply(
|
||||
const formatPreview = (texts: string[]) => {
|
||||
const joined = texts.join(" ").trim();
|
||||
if (!joined) return "";
|
||||
const clipped = joined.length > 120 ? `${joined.slice(0, 117)}…` : joined;
|
||||
const clipped =
|
||||
joined.length > 120 ? `${joined.slice(0, 117)}…` : joined;
|
||||
return ` — “${clipped}”`;
|
||||
};
|
||||
|
||||
@@ -662,7 +667,7 @@ export async function runCommandReply(
|
||||
media: mediaFound?.length ? mediaFound : undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const t of parsedTexts) {
|
||||
const { text: cleanedText, mediaUrls: mediaFound } =
|
||||
|
||||
@@ -11,12 +11,12 @@ import {
|
||||
saveSessionStore,
|
||||
} from "../config/sessions.js";
|
||||
import { info, isVerbose, logVerbose } from "../globals.js";
|
||||
import { triggerWarelayRestart } from "../infra/restart.js";
|
||||
import { ensureMediaHosted } from "../media/host.js";
|
||||
import { runCommandWithTimeout } from "../process/exec.js";
|
||||
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
|
||||
import type { TwilioRequester } from "../twilio/types.js";
|
||||
import { sendTypingIndicator } from "../twilio/typing.js";
|
||||
import { triggerWarelayRestart } from "../infra/restart.js";
|
||||
import { chunkText } from "./chunk.js";
|
||||
import { runCommandReply } from "./command-reply.js";
|
||||
import {
|
||||
@@ -358,7 +358,13 @@ export async function getReplyFromConfig(
|
||||
await saveSessionStore(storePath, sessionStore);
|
||||
}
|
||||
// If verbose directive is also present, persist it too.
|
||||
if (hasVerboseDirective && inlineVerbose && sessionEntry && sessionStore && sessionKey) {
|
||||
if (
|
||||
hasVerboseDirective &&
|
||||
inlineVerbose &&
|
||||
sessionEntry &&
|
||||
sessionStore &&
|
||||
sessionKey
|
||||
) {
|
||||
if (inlineVerbose === "off") {
|
||||
delete sessionEntry.verboseLevel;
|
||||
} else {
|
||||
@@ -431,9 +437,7 @@ export async function getReplyFromConfig(
|
||||
const to = (ctx.To ?? "").replace(/^whatsapp:/, "");
|
||||
const isSamePhone = from && to && from === to;
|
||||
const abortKey = sessionKey ?? (from || undefined) ?? (to || undefined);
|
||||
const rawBodyNormalized = (
|
||||
sessionCtx.BodyStripped ?? sessionCtx.Body ?? ""
|
||||
)
|
||||
const rawBodyNormalized = (sessionCtx.BodyStripped ?? sessionCtx.Body ?? "")
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ describe("sessions", () => {
|
||||
});
|
||||
|
||||
it("keeps group chats distinct", () => {
|
||||
expect(
|
||||
deriveSessionKey("per-sender", { From: "12345-678@g.us" }),
|
||||
).toBe("group:12345-678@g.us");
|
||||
expect(deriveSessionKey("per-sender", { From: "12345-678@g.us" })).toBe(
|
||||
"group:12345-678@g.us",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -678,7 +678,7 @@ describe("config and templating", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const ack = await index.getReplyFromConfig(
|
||||
const _ack = await index.getReplyFromConfig(
|
||||
{ Body: "/v:on", From: "+1", To: "+2" },
|
||||
undefined,
|
||||
cfg,
|
||||
@@ -979,7 +979,7 @@ describe("config and templating", () => {
|
||||
const batchBody =
|
||||
"[Current message - respond to this]\nPeter: @Clawd UK /thinking medium /v on";
|
||||
|
||||
const ack = await index.getReplyFromConfig(
|
||||
const _ack = await index.getReplyFromConfig(
|
||||
{
|
||||
Body: batchBody,
|
||||
From: "group:456@g.us",
|
||||
@@ -1000,7 +1000,7 @@ describe("config and templating", () => {
|
||||
const persisted = JSON.parse(
|
||||
await fs.promises.readFile(storePath, "utf-8"),
|
||||
) as Record<string, { thinkingLevel?: string; verboseLevel?: string }>;
|
||||
const entry = Object.values(persisted)[0] as {
|
||||
const _entry = Object.values(persisted)[0] as {
|
||||
thinkingLevel?: string;
|
||||
verboseLevel?: string;
|
||||
};
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
autoReplyIfConfigured,
|
||||
getReplyFromConfig,
|
||||
} from "./auto-reply/reply.js";
|
||||
import { enableConsoleCapture } from "./logging.js";
|
||||
import { applyTemplate } from "./auto-reply/templating.js";
|
||||
import { createDefaultDeps, monitorTwilio } from "./cli/deps.js";
|
||||
import { promptYesNo } from "./cli/prompt.js";
|
||||
@@ -33,6 +32,7 @@ import {
|
||||
ensureTailscaledInstalled,
|
||||
getTailnetHostname,
|
||||
} from "./infra/tailscale.js";
|
||||
import { enableConsoleCapture } from "./logging.js";
|
||||
import { runCommandWithTimeout, runExec } from "./process/exec.js";
|
||||
import { monitorWebProvider } from "./provider-web.js";
|
||||
import { createClient } from "./twilio/client.js";
|
||||
|
||||
@@ -4,7 +4,8 @@ const DEFAULT_LAUNCHD_LABEL = "com.steipete.warelay";
|
||||
|
||||
export function triggerWarelayRestart(): void {
|
||||
const label = process.env.WARELAY_LAUNCHD_LABEL || DEFAULT_LAUNCHD_LABEL;
|
||||
const uid = typeof process.getuid === "function" ? process.getuid() : undefined;
|
||||
const uid =
|
||||
typeof process.getuid === "function" ? process.getuid() : undefined;
|
||||
const target = uid !== undefined ? `gui/${uid}/${label}` : label;
|
||||
const child = spawn("launchctl", ["kickstart", "-k", target], {
|
||||
detached: true,
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { type ChildProcessWithoutNullStreams, spawn } from "node:child_process";
|
||||
import readline from "node:readline";
|
||||
|
||||
import { piSpec } from "../agents/pi.js";
|
||||
|
||||
type TauRpcOptions = {
|
||||
argv: string[];
|
||||
cwd?: string;
|
||||
@@ -24,7 +22,6 @@ class TauRpcClient {
|
||||
private stderr = "";
|
||||
private buffer: string[] = [];
|
||||
private idleTimer: NodeJS.Timeout | null = null;
|
||||
private readonly idleMs = 120;
|
||||
private pending:
|
||||
| {
|
||||
resolve: (r: TauRpcResult) => void;
|
||||
@@ -58,7 +55,12 @@ class TauRpcClient {
|
||||
const out = this.buffer.join("\n");
|
||||
clearTimeout(pending.timer);
|
||||
// Treat process exit as completion with whatever output we captured.
|
||||
pending.resolve({ stdout: out, stderr: this.stderr, code: code ?? 0, signal });
|
||||
pending.resolve({
|
||||
stdout: out,
|
||||
stderr: this.stderr,
|
||||
code: code ?? 0,
|
||||
signal,
|
||||
});
|
||||
}
|
||||
this.dispose();
|
||||
});
|
||||
|
||||
@@ -84,13 +84,15 @@ function buildMentionConfig(cfg: ReturnType<typeof loadConfig>): MentionConfig {
|
||||
const gc = cfg.inbound?.groupChat;
|
||||
const requireMention = gc?.requireMention !== false; // default true
|
||||
const mentionRegexes =
|
||||
gc?.mentionPatterns?.map((p) => {
|
||||
try {
|
||||
return new RegExp(p, "i");
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}).filter((r): r is RegExp => Boolean(r)) ?? [];
|
||||
gc?.mentionPatterns
|
||||
?.map((p) => {
|
||||
try {
|
||||
return new RegExp(p, "i");
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter((r): r is RegExp => Boolean(r)) ?? [];
|
||||
return { requireMention, mentionRegexes };
|
||||
}
|
||||
|
||||
@@ -728,7 +730,7 @@ export async function monitorWebProvider(
|
||||
const senderLabel =
|
||||
latest.senderName && latest.senderE164
|
||||
? `${latest.senderName} (${latest.senderE164})`
|
||||
: latest.senderName ?? latest.senderE164 ?? "Unknown";
|
||||
: (latest.senderName ?? latest.senderE164 ?? "Unknown");
|
||||
combinedBody = `${combinedBody}\\n[from: ${senderLabel}]`;
|
||||
// Clear stored history after using it
|
||||
groupHistories.set(conversationId, []);
|
||||
@@ -834,7 +836,7 @@ export async function monitorWebProvider(
|
||||
const fromDisplay =
|
||||
latest.chatType === "group"
|
||||
? conversationId
|
||||
: latest.from ?? "unknown";
|
||||
: (latest.from ?? "unknown");
|
||||
if (isVerbose()) {
|
||||
console.log(
|
||||
success(
|
||||
@@ -850,24 +852,26 @@ export async function monitorWebProvider(
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(
|
||||
danger(`Failed sending web auto-reply to ${latest.from ?? conversationId}: ${String(err)}`),
|
||||
danger(
|
||||
`Failed sending web auto-reply to ${latest.from ?? conversationId}: ${String(err)}`,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const enqueueBatch = async (msg: WebInboundMsg) => {
|
||||
const key = msg.conversationId ?? msg.from;
|
||||
const bucket = pendingBatches.get(key) ?? { messages: [] };
|
||||
bucket.messages.push(msg);
|
||||
pendingBatches.set(key, bucket);
|
||||
if (getQueueSize() === 0) {
|
||||
await processBatch(key);
|
||||
} else {
|
||||
bucket.timer =
|
||||
bucket.timer ?? setTimeout(() => void processBatch(key), 150);
|
||||
}
|
||||
};
|
||||
const enqueueBatch = async (msg: WebInboundMsg) => {
|
||||
const key = msg.conversationId ?? msg.from;
|
||||
const bucket = pendingBatches.get(key) ?? { messages: [] };
|
||||
bucket.messages.push(msg);
|
||||
pendingBatches.set(key, bucket);
|
||||
if (getQueueSize() === 0) {
|
||||
await processBatch(key);
|
||||
} else {
|
||||
bucket.timer =
|
||||
bucket.timer ?? setTimeout(() => void processBatch(key), 150);
|
||||
}
|
||||
};
|
||||
|
||||
const listener = await (listenerFactory ?? monitorWebInbox)({
|
||||
verbose,
|
||||
|
||||
@@ -339,7 +339,9 @@ export async function monitorWebInbox(options: {
|
||||
} as const;
|
||||
}
|
||||
|
||||
function unwrapMessage(message: proto.IMessage | undefined): proto.IMessage | undefined {
|
||||
function unwrapMessage(
|
||||
message: proto.IMessage | undefined,
|
||||
): proto.IMessage | undefined {
|
||||
if (!message) return undefined;
|
||||
if (message.ephemeralMessage?.message) {
|
||||
return unwrapMessage(message.ephemeralMessage.message as proto.IMessage);
|
||||
|
||||
Reference in New Issue
Block a user