diff --git a/CHANGELOG.md b/CHANGELOG.md index ecd69a823..eca789827 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -89,6 +89,7 @@ - Auto-reply: allow sender fallback for command authorization when `SenderId` is empty (WhatsApp self-chat). (#755) — thanks @juanpablodlc. - Heartbeat: refresh prompt text for updated defaults. - Agents/Tools: use PowerShell on Windows to capture system utility output. (#748) — thanks @myfunc. +- Agents/Tools: normalize Claude Code-style read/write/edit params (file_path/old_string/new_string) and keep sandbox guards in place. (#768) — thanks @hsrvc. - Docker: tolerate unset optional env vars in docker-setup.sh under strict mode. (#725) — thanks @petradonka. - CLI/Update: preserve base environment when passing overrides to update subprocesses. (#713) — thanks @danielz1z. - Agents: treat message tool errors as failures so fallback replies still send; require `to` + `message` for `action=send`. (#717) — thanks @theglove44. diff --git a/src/agents/pi-tools.ts b/src/agents/pi-tools.ts index 34c3926a2..690566e6f 100644 --- a/src/agents/pi-tools.ts +++ b/src/agents/pi-tools.ts @@ -443,75 +443,6 @@ function createSandboxedEditTool(root: string) { const base = createEditTool(root); return wrapSandboxPathGuard(wrapToolParamNormalization(base), root); } -function createWhatsAppLoginTool(): AnyAgentTool { - return { - label: "WhatsApp Login", - name: "whatsapp_login", - description: - "Generate a WhatsApp QR code for linking, or wait for the scan to complete.", - // NOTE: Using Type.Unsafe for action enum instead of Type.Union([Type.Literal(...)]) - // because Claude API on Vertex AI rejects nested anyOf schemas as invalid JSON Schema. - parameters: Type.Object({ - action: Type.Unsafe<"start" | "wait">({ - type: "string", - enum: ["start", "wait"], - }), - timeoutMs: Type.Optional(Type.Number()), - force: Type.Optional(Type.Boolean()), - }), - execute: async (_toolCallId, args) => { - const action = (args as { action?: string })?.action ?? "start"; - if (action === "wait") { - const result = await waitForWebLogin({ - timeoutMs: - typeof (args as { timeoutMs?: unknown }).timeoutMs === "number" - ? (args as { timeoutMs?: number }).timeoutMs - : undefined, - }); - return { - content: [{ type: "text", text: result.message }], - details: { connected: result.connected }, - }; - } - - const result = await startWebLoginWithQr({ - timeoutMs: - typeof (args as { timeoutMs?: unknown }).timeoutMs === "number" - ? (args as { timeoutMs?: number }).timeoutMs - : undefined, - force: - typeof (args as { force?: unknown }).force === "boolean" - ? (args as { force?: boolean }).force - : false, - }); - - if (!result.qrDataUrl) { - return { - content: [ - { - type: "text", - text: result.message, - }, - ], - details: { qr: false }, - }; - } - - const text = [ - result.message, - "", - "Open WhatsApp → Linked Devices and scan:", - "", - `![whatsapp-qr](${result.qrDataUrl})`, - ].join("\n"); - return { - content: [{ type: "text", text }], - details: { qr: true }, - }; - }, - }; -} - // Normalize tool parameters from Claude Code conventions to pi-coding-agent conventions. // Claude Code uses file_path/old_string/new_string while pi-coding-agent uses path/oldText/newText. // This prevents models trained on Claude Code from getting stuck in tool-call loops.