chore: harden claude json parsing and logging
This commit is contained in:
@@ -51,10 +51,18 @@ export type ClaudeJsonParseResult = {
|
|||||||
parsed: unknown;
|
parsed: unknown;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function parseClaudeJson(raw: string): ClaudeJsonParseResult | undefined {
|
export function parseClaudeJson(
|
||||||
|
raw: string,
|
||||||
|
): ClaudeJsonParseResult | undefined {
|
||||||
// Handle a single JSON blob or newline-delimited JSON; return the first parsed payload.
|
// Handle a single JSON blob or newline-delimited JSON; return the first parsed payload.
|
||||||
let firstParsed: unknown;
|
let firstParsed: unknown;
|
||||||
const candidates = [raw, ...raw.split(/\n+/).map((s) => s.trim()).filter(Boolean)];
|
const candidates = [
|
||||||
|
raw,
|
||||||
|
...raw
|
||||||
|
.split(/\n+/)
|
||||||
|
.map((s) => s.trim())
|
||||||
|
.filter(Boolean),
|
||||||
|
];
|
||||||
for (const candidate of candidates) {
|
for (const candidate of candidates) {
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(candidate);
|
const parsed = JSON.parse(candidate);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import crypto from "node:crypto";
|
import crypto from "node:crypto";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
|
||||||
|
import type { MessageInstance } from "twilio/lib/rest/api/v2010/account/message.js";
|
||||||
import { CLAUDE_BIN, parseClaudeJson } from "./claude.js";
|
import { CLAUDE_BIN, parseClaudeJson } from "./claude.js";
|
||||||
import {
|
import {
|
||||||
applyTemplate,
|
applyTemplate,
|
||||||
@@ -15,25 +16,11 @@ import {
|
|||||||
resolveStorePath,
|
resolveStorePath,
|
||||||
saveSessionStore,
|
saveSessionStore,
|
||||||
} from "../config/sessions.js";
|
} from "../config/sessions.js";
|
||||||
import {
|
import { loadConfig, type WarelayConfig } from "../config/config.js";
|
||||||
type WarelayConfig,
|
import { info, isVerbose, logVerbose } from "../globals.js";
|
||||||
loadConfig,
|
import { runCommandWithTimeout } from "../process/exec.js";
|
||||||
} from "../config/config.js";
|
|
||||||
import {
|
|
||||||
danger,
|
|
||||||
info,
|
|
||||||
isVerbose,
|
|
||||||
logVerbose,
|
|
||||||
warn,
|
|
||||||
} from "../globals.js";
|
|
||||||
import { normalizeE164, withWhatsAppPrefix } from "../utils.js";
|
|
||||||
import {
|
|
||||||
runCommandWithTimeout,
|
|
||||||
type SpawnResult,
|
|
||||||
} from "../process/exec.js";
|
|
||||||
import { sendTypingIndicator } from "../twilio/typing.js";
|
import { sendTypingIndicator } from "../twilio/typing.js";
|
||||||
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
|
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
|
||||||
import type { MessageInstance } from "twilio/lib/rest/api/v2010/account/message.js";
|
|
||||||
|
|
||||||
type GetReplyOptions = {
|
type GetReplyOptions = {
|
||||||
onReplyStart?: () => Promise<void> | void;
|
onReplyStart?: () => Promise<void> | void;
|
||||||
@@ -59,8 +46,9 @@ function summarizeClaudeMetadata(payload: unknown): string | undefined {
|
|||||||
|
|
||||||
const usage = obj.usage;
|
const usage = obj.usage;
|
||||||
if (usage && typeof usage === "object") {
|
if (usage && typeof usage === "object") {
|
||||||
const serverToolUse = (usage as { server_tool_use?: Record<string, unknown> })
|
const serverToolUse = (
|
||||||
.server_tool_use;
|
usage as { server_tool_use?: Record<string, unknown> }
|
||||||
|
).server_tool_use;
|
||||||
if (serverToolUse && typeof serverToolUse === "object") {
|
if (serverToolUse && typeof serverToolUse === "object") {
|
||||||
const toolCalls = Object.values(serverToolUse).reduce((sum, val) => {
|
const toolCalls = Object.values(serverToolUse).reduce((sum, val) => {
|
||||||
if (typeof val === "number") return sum + val;
|
if (typeof val === "number") return sum + val;
|
||||||
@@ -330,7 +318,11 @@ export async function getReplyFromConfig(
|
|||||||
|
|
||||||
type TwilioLikeClient = {
|
type TwilioLikeClient = {
|
||||||
messages: {
|
messages: {
|
||||||
create: (opts: { from?: string; to?: string; body: string }) => Promise<unknown>;
|
create: (opts: {
|
||||||
|
from?: string;
|
||||||
|
to?: string;
|
||||||
|
body: string;
|
||||||
|
}) => Promise<unknown>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -380,9 +372,7 @@ export async function autoReplyIfConfigured(
|
|||||||
});
|
});
|
||||||
if (isVerbose()) {
|
if (isVerbose()) {
|
||||||
console.log(
|
console.log(
|
||||||
info(
|
info(`↩️ Auto-replied to ${replyTo} (sid ${message.sid ?? "no-sid"})`),
|
||||||
`↩️ Auto-replied to ${replyTo} (sid ${message.sid ?? "no-sid"})`,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
Reference in New Issue
Block a user