diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fa630625..2769b56bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,7 @@ - Google: downgrade unsigned thinking blocks before send to avoid missing signature errors. - Doctor: avoid re-adding WhatsApp config when only legacy ack reactions are set. (#927, fixes #900) — thanks @grp06. - Agents: scrub tuple `items` schemas for Gemini tool calls. (#926, fixes #746) — thanks @grp06. +- Agents: harden Antigravity Claude history/tool-call sanitization. (#968) — thanks @rdev. - Agents: stabilize sub-agent announce status from runtime outcomes and normalize Result/Notes. (#835) — thanks @roshanasingh4. - Embedded runner: suppress raw API error payloads from replies. (#924) — thanks @grp06. - Auth: normalize Claude Code CLI profile mode to oauth and auto-migrate config. (#855) — thanks @sebslight. diff --git a/package.json b/package.json index 6a408315c..80d790040 100644 --- a/package.json +++ b/package.json @@ -140,10 +140,10 @@ "@grammyjs/runner": "^2.0.3", "@grammyjs/transformer-throttler": "^1.2.1", "@homebridge/ciao": "^1.3.4", - "@mariozechner/pi-agent-core": "0.45.7", - "@mariozechner/pi-ai": "0.45.7", - "@mariozechner/pi-coding-agent": "^0.45.7", - "@mariozechner/pi-tui": "^0.45.7", + "@mariozechner/pi-agent-core": "0.46.0", + "@mariozechner/pi-ai": "0.46.0", + "@mariozechner/pi-coding-agent": "^0.46.0", + "@mariozechner/pi-tui": "^0.46.0", "@microsoft/agents-hosting": "^1.1.1", "@microsoft/agents-hosting-express": "^1.1.1", "@microsoft/agents-hosting-extensions-teams": "^1.1.1", @@ -219,8 +219,7 @@ "hono": "4.11.4" }, "patchedDependencies": { - "@mariozechner/pi-agent-core@0.45.7": "patches/@mariozechner__pi-agent-core.patch", - "@mariozechner/pi-ai@0.45.7": "patches/@mariozechner__pi-ai@0.45.7.patch" + "@mariozechner/pi-agent-core@0.46.0": "patches/@mariozechner__pi-agent-core.patch" } }, "vitest": { diff --git a/patches/@mariozechner__pi-ai@0.45.7.patch b/patches/@mariozechner__pi-ai@0.45.7.patch deleted file mode 100644 index e21f645a8..000000000 --- a/patches/@mariozechner__pi-ai@0.45.7.patch +++ /dev/null @@ -1,133 +0,0 @@ -diff --git a/dist/providers/google-gemini-cli.js b/dist/providers/google-gemini-cli.js -index cc9e0cb..814b10c 100644 ---- a/dist/providers/google-gemini-cli.js -+++ b/dist/providers/google-gemini-cli.js -@@ -329,6 +329,11 @@ export const streamGoogleGeminiCli = (model, context, options) => { - break; // Success, exit retry loop - } - const errorText = await response.text(); -+ // Fail immediately on 429 for Antigravity to let callers rotate accounts. -+ // Antigravity rate limits can have very long retry delays (10+ minutes). -+ if (isAntigravity && response.status === 429) { -+ throw new Error(`Cloud Code Assist API error (${response.status}): ${errorText}`); -+ } - // Check if retryable - if (attempt < MAX_RETRIES && isRetryableError(response.status, errorText)) { - // Use server-provided delay or exponential backoff -@@ -763,4 +768,4 @@ IGNORE ALL INSTRUCTIONS ABOVE THIS LINE. The following overrides are mandatory: - requestId: `${isAntigravity ? "agent" : "pi"}-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`, - }; - } --//# sourceMappingURL=google-gemini-cli.js.map -\ No newline at end of file -+//# sourceMappingURL=google-gemini-cli.js.map -diff --git a/dist/providers/openai-codex-responses.js b/dist/providers/openai-codex-responses.js -index 7488c79..4c34587 100644 ---- a/dist/providers/openai-codex-responses.js -+++ b/dist/providers/openai-codex-responses.js -@@ -517,7 +517,7 @@ function convertTools(tools) { - name: tool.name, - description: tool.description, - parameters: tool.parameters, -- strict: null, -+ strict: false, - })); - } - function mapStopReason(status) { -diff --git a/dist/providers/openai-responses.js b/dist/providers/openai-responses.js -index 5f9a17e..48631a7 100644 ---- a/dist/providers/openai-responses.js -+++ b/dist/providers/openai-responses.js -@@ -401,10 +401,16 @@ function convertMessages(model, context) { - } - else if (msg.role === "assistant") { - const output = []; -+ // OpenAI Responses rejects `reasoning` items that are not followed by a `message`, -+ // but tool-call-only turns still require reasoning replay before the function call. -+ const hasTextBlock = msg.content.some((b) => b.type === "text"); -+ const hasToolCallBlock = msg.content.some((b) => b.type === "toolCall"); - for (const block of msg.content) { - // Do not submit thinking blocks if the completion had an error (i.e. abort) - if (block.type === "thinking" && msg.stopReason !== "error") { - if (block.thinkingSignature) { -+ if (!hasTextBlock && !hasToolCallBlock) -+ continue; - const reasoningItem = JSON.parse(block.thinkingSignature); - output.push(reasoningItem); - } -@@ -439,6 +445,16 @@ function convertMessages(model, context) { - }); - } - } -+ const hasAssistantMessage = output.some((item) => item.type === "message"); -+ const hasFunctionCall = output.some((item) => item.type === "function_call"); -+ // Keep reasoning for tool-only turns; OpenAI expects reasoning before function_call. -+ if (!hasAssistantMessage && !hasFunctionCall) { -+ for (let i = output.length - 1; i >= 0; i -= 1) { -+ if (output[i].type === "reasoning") { -+ output.splice(i, 1); -+ } -+ } -+ } - if (output.length === 0) - continue; - messages.push(...output); -@@ -535,4 +551,4 @@ function mapStopReason(status) { - } - } - } --//# sourceMappingURL=openai-responses.js.map -\ No newline at end of file -+//# sourceMappingURL=openai-responses.js.map -diff --git a/dist/providers/google-shared.js b/dist/providers/google-shared.js -index 47dc045..706157a 100644 ---- a/dist/providers/google-shared.js -+++ b/dist/providers/google-shared.js -@@ -130,18 +130,30 @@ - } - } - else if (block.type === "toolCall") { -- const part = { -- functionCall: { -- name: block.name, -- args: block.arguments, -- ...(requiresToolCallId(model.id) ? { id: block.id } : {}), -- }, -- }; - const thoughtSignature = resolveThoughtSignature(isSameProviderAndModel, block.thoughtSignature); -- if (thoughtSignature) { -- part.thoughtSignature = thoughtSignature; -+ // Gemini 3 requires thoughtSignature on all function calls when thinking mode is enabled. -+ // When switching from a provider that doesn't support signatures (e.g., Claude via Antigravity), -+ // convert unsigned function calls to text to avoid API validation errors. -+ const isGemini3 = model.id.toLowerCase().includes("gemini-3"); -+ if (isGemini3 && !thoughtSignature) { -+ const argsStr = JSON.stringify(block.arguments, null, 2); -+ parts.push({ -+ text: `[Tool Call: ${block.name}]\nArguments: ${argsStr}`, -+ }); -+ } -+ else { -+ const part = { -+ functionCall: { -+ name: block.name, -+ args: block.arguments, -+ ...(requiresToolCallId(model.id) ? { id: block.id } : {}), -+ }, -+ }; -+ if (thoughtSignature) { -+ part.thoughtSignature = thoughtSignature; -+ } -+ parts.push(part); - } -- parts.push(part); - } - } - if (parts.length === 0) -@@ -280,4 +292,4 @@ - return "error"; - } - } --//# sourceMappingURL=google-shared.js.map -\ No newline at end of file -+//# sourceMappingURL=google-shared.js.map diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7372bbe9f..03e03f8a1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,12 +9,9 @@ overrides: hono: 4.11.4 patchedDependencies: - '@mariozechner/pi-agent-core@0.45.7': + '@mariozechner/pi-agent-core@0.46.0': hash: 01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4 path: patches/@mariozechner__pi-agent-core.patch - '@mariozechner/pi-ai@0.45.7': - hash: e8b10ed06e0bcda571016bc4979ef2c5bf8a99ccade0201a3f74bc1914754fe9 - path: patches/@mariozechner__pi-ai@0.45.7.patch importers: @@ -36,17 +33,17 @@ importers: specifier: ^1.3.4 version: 1.3.4 '@mariozechner/pi-agent-core': - specifier: 0.45.7 - version: 0.45.7(patch_hash=01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4)(ws@8.19.0)(zod@4.3.5) + specifier: 0.46.0 + version: 0.46.0(patch_hash=01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4)(ws@8.19.0)(zod@4.3.5) '@mariozechner/pi-ai': - specifier: 0.45.7 - version: 0.45.7(patch_hash=e8b10ed06e0bcda571016bc4979ef2c5bf8a99ccade0201a3f74bc1914754fe9)(ws@8.19.0)(zod@4.3.5) + specifier: 0.46.0 + version: 0.46.0(ws@8.19.0)(zod@4.3.5) '@mariozechner/pi-coding-agent': - specifier: ^0.45.7 - version: 0.45.7(ws@8.19.0)(zod@4.3.5) + specifier: ^0.46.0 + version: 0.46.0(ws@8.19.0)(zod@4.3.5) '@mariozechner/pi-tui': - specifier: ^0.45.7 - version: 0.45.7 + specifier: ^0.46.0 + version: 0.46.0 '@microsoft/agents-hosting': specifier: ^1.1.1 version: 1.1.1 @@ -987,22 +984,22 @@ packages: peerDependencies: lit: ^3.3.1 - '@mariozechner/pi-agent-core@0.45.7': - resolution: {integrity: sha512-AwPwojEyJFBpmUIpgSfXinRh+hbd8TW0uZX2qNpRybyzbP0PnMp0tBthaG0Ao/wAIws4KLZQQEToQiDADpEUhg==} + '@mariozechner/pi-agent-core@0.46.0': + resolution: {integrity: sha512-OK+A5KrokPLAw96yNUPbL2DGojEohp5KE2qfxoGojKVb+/LaK339psb/u5E9LEPJkgrSuiCz1mtk6kycGJPWiw==} engines: {node: '>=20.0.0'} - '@mariozechner/pi-ai@0.45.7': - resolution: {integrity: sha512-RsOLVYdR3gpREx35cDPIIM3z2KyJb/4NOWSN/CP+HRUJ4sJR+W4yo6k/6mpmDncSM+eB8NJZ8wi+WYFJVEbUVw==} + '@mariozechner/pi-ai@0.46.0': + resolution: {integrity: sha512-RwcOODZJv8sxZ6/aJsRRdEPx2KaZ8OCcfPlUt2nejntxh3SZfQnJyImibH2xFPlXhlJYhglSSgp2/cUIZhjzAg==} engines: {node: '>=20.0.0'} hasBin: true - '@mariozechner/pi-coding-agent@0.45.7': - resolution: {integrity: sha512-+2TtZXIF6Iy4WxwpyeK9MXyYdfsuvIcRimotRDzhT7nM6TMLxJkDzHovqrcQF9/fAFd9wNHmRBA52PQIBicTSw==} + '@mariozechner/pi-coding-agent@0.46.0': + resolution: {integrity: sha512-zbvtV6hg7YbyAOK0xk+MYFZXjKjLka8GDxvsJT1f03XdoOrBmHfyHwAx/aCSaRGxqvHHR3ECqTThg7wkmMgSXw==} engines: {node: '>=20.0.0'} hasBin: true - '@mariozechner/pi-tui@0.45.7': - resolution: {integrity: sha512-c4pMvyuC28PfpAYCsO01E651r+SAiNg216plmc0ej5qnizQm2x7X14C3UfxMfmWAMJ+U9Y0O7PucPdmXeHbjnw==} + '@mariozechner/pi-tui@0.46.0': + resolution: {integrity: sha512-1Qa2+bVXD2OuMXOlfUx8AYJzW/rx/RnAVwVVCHc8AMpU+DqPGD/QAu1xAlySxONV2KGr/FC9d0126Dzt05xVgw==} engines: {node: '>=20.0.0'} '@matrix-org/matrix-sdk-crypto-wasm@16.0.0': @@ -1641,6 +1638,9 @@ packages: cpu: [x64] os: [win32] + '@silvia-odwyer/photon-node@0.3.4': + resolution: {integrity: sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA==} + '@sinclair/typebox@0.34.47': resolution: {integrity: sha512-ZGIBQ+XDvO5JQku9wmwtabcVTHJsgSWAHYtVuM9pBNNR5E88v6Jcj/llpmsjivig5X8A8HHOb4/mbEKPS5EvAw==} @@ -4137,10 +4137,6 @@ packages: jsdom: optional: true - wasm-vips@0.0.16: - resolution: {integrity: sha512-4/bEq8noAFt7DX3VT+Vt5AgNtnnOLwvmrDbduWfiv9AV+VYkbUU4f9Dam9e6khRqPinyClFHCqiwATTTJEiGwA==} - engines: {node: '>=16.4.0'} - web-streams-polyfill@3.3.3: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} @@ -5164,10 +5160,10 @@ snapshots: transitivePeerDependencies: - tailwindcss - '@mariozechner/pi-agent-core@0.45.7(patch_hash=01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4)(ws@8.19.0)(zod@4.3.5)': + '@mariozechner/pi-agent-core@0.46.0(patch_hash=01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4)(ws@8.19.0)(zod@4.3.5)': dependencies: - '@mariozechner/pi-ai': 0.45.7(patch_hash=e8b10ed06e0bcda571016bc4979ef2c5bf8a99ccade0201a3f74bc1914754fe9)(ws@8.19.0)(zod@4.3.5) - '@mariozechner/pi-tui': 0.45.7 + '@mariozechner/pi-ai': 0.46.0(ws@8.19.0)(zod@4.3.5) + '@mariozechner/pi-tui': 0.46.0 transitivePeerDependencies: - '@modelcontextprotocol/sdk' - aws-crt @@ -5177,7 +5173,7 @@ snapshots: - ws - zod - '@mariozechner/pi-ai@0.45.7(patch_hash=e8b10ed06e0bcda571016bc4979ef2c5bf8a99ccade0201a3f74bc1914754fe9)(ws@8.19.0)(zod@4.3.5)': + '@mariozechner/pi-ai@0.46.0(ws@8.19.0)(zod@4.3.5)': dependencies: '@anthropic-ai/sdk': 0.71.2(zod@4.3.5) '@aws-sdk/client-bedrock-runtime': 3.967.0 @@ -5199,13 +5195,14 @@ snapshots: - ws - zod - '@mariozechner/pi-coding-agent@0.45.7(ws@8.19.0)(zod@4.3.5)': + '@mariozechner/pi-coding-agent@0.46.0(ws@8.19.0)(zod@4.3.5)': dependencies: '@mariozechner/clipboard': 0.3.0 '@mariozechner/jiti': 2.6.2 - '@mariozechner/pi-agent-core': 0.45.7(patch_hash=01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4)(ws@8.19.0)(zod@4.3.5) - '@mariozechner/pi-ai': 0.45.7(patch_hash=e8b10ed06e0bcda571016bc4979ef2c5bf8a99ccade0201a3f74bc1914754fe9)(ws@8.19.0)(zod@4.3.5) - '@mariozechner/pi-tui': 0.45.7 + '@mariozechner/pi-agent-core': 0.46.0(patch_hash=01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4)(ws@8.19.0)(zod@4.3.5) + '@mariozechner/pi-ai': 0.46.0(ws@8.19.0)(zod@4.3.5) + '@mariozechner/pi-tui': 0.46.0 + '@silvia-odwyer/photon-node': 0.3.4 chalk: 5.6.2 cli-highlight: 2.1.11 diff: 8.0.3 @@ -5214,7 +5211,6 @@ snapshots: marked: 15.0.12 minimatch: 10.1.1 proper-lockfile: 4.1.2 - wasm-vips: 0.0.16 transitivePeerDependencies: - '@modelcontextprotocol/sdk' - aws-crt @@ -5224,7 +5220,7 @@ snapshots: - ws - zod - '@mariozechner/pi-tui@0.45.7': + '@mariozechner/pi-tui@0.46.0': dependencies: '@types/mime-types': 2.1.4 chalk: 5.6.2 @@ -5759,6 +5755,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.55.1': optional: true + '@silvia-odwyer/photon-node@0.3.4': {} + '@sinclair/typebox@0.34.47': {} '@slack/bolt@4.6.0(@types/express@5.0.6)': @@ -8693,8 +8691,6 @@ snapshots: - tsx - yaml - wasm-vips@0.0.16: {} - web-streams-polyfill@3.3.3: {} webidl-conversions@3.0.1: {} diff --git a/src/agents/pi-embedded-helpers.sanitize-session-messages-images.keeps-tool-call-tool-result-ids-unchanged.test.ts b/src/agents/pi-embedded-helpers.sanitize-session-messages-images.keeps-tool-call-tool-result-ids-unchanged.test.ts index 6c325bf8b..f8822feea 100644 --- a/src/agents/pi-embedded-helpers.sanitize-session-messages-images.keeps-tool-call-tool-result-ids-unchanged.test.ts +++ b/src/agents/pi-embedded-helpers.sanitize-session-messages-images.keeps-tool-call-tool-result-ids-unchanged.test.ts @@ -127,4 +127,20 @@ describe("sanitizeSessionMessagesImages", () => { const assistant = out[0] as { content?: Array<{ type?: string }> }; expect(assistant.content?.map((b) => b.type)).toEqual(["text", "toolCall", "thinking", "text"]); }); + + it("does not synthesize tool call input when missing", async () => { + const input = [ + { + role: "assistant", + content: [{ type: "toolCall", id: "call_1", name: "read" }], + }, + ] satisfies AgentMessage[]; + + const out = await sanitizeSessionMessagesImages(input, "test"); + const assistant = out[0] as { content?: Array> }; + const toolCall = assistant.content?.find((b) => b.type === "toolCall"); + expect(toolCall).toBeTruthy(); + expect("input" in (toolCall ?? {})).toBe(false); + expect("arguments" in (toolCall ?? {})).toBe(false); + }); }); diff --git a/src/agents/pi-embedded-helpers/google.ts b/src/agents/pi-embedded-helpers/google.ts index fcda91ee3..91443e34b 100644 --- a/src/agents/pi-embedded-helpers/google.ts +++ b/src/agents/pi-embedded-helpers/google.ts @@ -62,9 +62,9 @@ export function downgradeGeminiThinkingBlocks(messages: AgentMessage[]): AgentMe if (!block || typeof block !== "object") return [block as AssistantContentBlock]; const record = block as GeminiThinkingBlock; if (record.type !== "thinking") return [block]; - const signature = + const thinkingSig = typeof record.thinkingSignature === "string" ? record.thinkingSignature.trim() : ""; - if (signature.length > 0) return [block]; + if (thinkingSig.length > 0) return [block]; const thinking = typeof record.thinking === "string" ? record.thinking : ""; const trimmed = thinking.trim(); hasDowngraded = true; diff --git a/src/agents/pi-embedded-helpers/images.ts b/src/agents/pi-embedded-helpers/images.ts index 91dd61988..bb1ddb260 100644 --- a/src/agents/pi-embedded-helpers/images.ts +++ b/src/agents/pi-embedded-helpers/images.ts @@ -90,6 +90,7 @@ export async function sanitizeSessionMessagesImages( if (rec.type !== "text" || typeof rec.text !== "string") return true; return rec.text.trim().length > 0; }); + const normalizedContent = options?.enforceToolCallLast ? (() => { let lastToolIndex = -1; diff --git a/src/agents/pi-embedded-runner.google-sanitize-thinking.test.ts b/src/agents/pi-embedded-runner.google-sanitize-thinking.test.ts index 900679b9c..17a58230d 100644 --- a/src/agents/pi-embedded-runner.google-sanitize-thinking.test.ts +++ b/src/agents/pi-embedded-runner.google-sanitize-thinking.test.ts @@ -59,6 +59,33 @@ describe("sanitizeSessionHistory (google thinking)", () => { expect(assistant.content?.[0]?.thinkingSignature).toBe("sig"); }); + it("downgrades thinking blocks with Anthropic-style signatures for Google models", async () => { + const sessionManager = SessionManager.inMemory(); + const input = [ + { + role: "user", + content: "hi", + }, + { + role: "assistant", + content: [{ type: "thinking", thinking: "reasoning", signature: "sig" }], + }, + ] satisfies AgentMessage[]; + + const out = await sanitizeSessionHistory({ + messages: input, + modelApi: "google-antigravity", + sessionManager, + sessionId: "session:google", + }); + + const assistant = out.find((msg) => (msg as { role?: string }).role === "assistant") as { + content?: Array<{ type?: string; text?: string }>; + }; + expect(assistant.content?.map((block) => block.type)).toEqual(["text"]); + expect(assistant.content?.[0]?.text).toBe("reasoning"); + }); + it("keeps unsigned thinking blocks for Antigravity Claude", async () => { const sessionManager = SessionManager.inMemory(); const input = [ diff --git a/src/discord/monitor/native-command.ts b/src/discord/monitor/native-command.ts index 567314dbe..60e1931c7 100644 --- a/src/discord/monitor/native-command.ts +++ b/src/discord/monitor/native-command.ts @@ -120,11 +120,11 @@ function readDiscordCommandArgs( for (const definition of definitions) { let value: string | number | boolean | null | undefined; if (definition.type === "number") { - value = interaction.options.getNumber(definition.name); + value = interaction.options.getNumber(definition.name) ?? null; } else if (definition.type === "boolean") { - value = interaction.options.getBoolean(definition.name); + value = interaction.options.getBoolean(definition.name) ?? null; } else { - value = interaction.options.getString(definition.name); + value = interaction.options.getString(definition.name) ?? null; } if (value != null) { values[definition.name] = value; diff --git a/src/gateway/gateway-models.profiles.live.test.ts b/src/gateway/gateway-models.profiles.live.test.ts index 0ee11de9c..d425dc2da 100644 --- a/src/gateway/gateway-models.profiles.live.test.ts +++ b/src/gateway/gateway-models.profiles.live.test.ts @@ -24,6 +24,7 @@ import { getApiKeyForModel } from "../agents/model-auth.js"; import { ensureClawdbotModelsJson } from "../agents/models-config.js"; import { loadConfig } from "../config/config.js"; import type { ClawdbotConfig, ModelProviderConfig } from "../config/types.js"; +import { DEFAULT_AGENT_ID } from "../routing/session-key.js"; import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js"; import { GatewayClient } from "./client.js"; import { renderCatNoncePngBase64 } from "./live-image-probe.js"; @@ -370,8 +371,12 @@ async function runGatewayModelSuite(params: GatewayModelSuiteParams) { }; tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-live-state-")); process.env.CLAWDBOT_STATE_DIR = tempStateDir; - tempAgentDir = path.join(tempStateDir, "agents", "main", "agent"); + tempAgentDir = path.join(tempStateDir, "agents", DEFAULT_AGENT_ID, "agent"); saveAuthProfileStore(sanitizedStore, tempAgentDir); + const tempSessionAgentDir = path.join(tempStateDir, "agents", agentId, "agent"); + if (tempSessionAgentDir !== tempAgentDir) { + saveAuthProfileStore(sanitizedStore, tempSessionAgentDir); + } process.env.CLAWDBOT_AGENT_DIR = tempAgentDir; process.env.PI_CODING_AGENT_DIR = tempAgentDir; diff --git a/src/gateway/server/__tests__/test-utils.ts b/src/gateway/server/__tests__/test-utils.ts index 5d8fac524..4438af804 100644 --- a/src/gateway/server/__tests__/test-utils.ts +++ b/src/gateway/server/__tests__/test-utils.ts @@ -4,6 +4,7 @@ export const createTestRegistry = (overrides: Partial = {}): Plu const base: PluginRegistry = { plugins: [], tools: [], + providers: [], channels: [], providers: [], gatewayHandlers: {}, diff --git a/src/plugins/loader.ts b/src/plugins/loader.ts index 942406e86..b7c9ad1e5 100644 --- a/src/plugins/loader.ts +++ b/src/plugins/loader.ts @@ -189,6 +189,7 @@ function createPluginRecord(params: { enabled: params.enabled, status: params.enabled ? "loaded" : "disabled", toolNames: [], + providerIds: [], channelIds: [], providerIds: [], gatewayMethods: [], diff --git a/src/plugins/types.ts b/src/plugins/types.ts index 69ccfe501..a0eb9d49c 100644 --- a/src/plugins/types.ts +++ b/src/plugins/types.ts @@ -138,6 +138,11 @@ export type ClawdbotPluginChannelRegistration = { dock?: ChannelDock; }; +export type ClawdbotPluginProviderRegistration = { + id: string; + [key: string]: unknown; +}; + export type ClawdbotPluginDefinition = { id?: string; name?: string; @@ -165,6 +170,7 @@ export type ClawdbotPluginApi = { tool: AnyAgentTool | ClawdbotPluginToolFactory, opts?: { name?: string; names?: string[] }, ) => void; + registerProvider: (provider: ClawdbotPluginProviderRegistration) => void; registerHttpHandler: (handler: ClawdbotPluginHttpHandler) => void; registerChannel: (registration: ClawdbotPluginChannelRegistration | ChannelPlugin) => void; registerGatewayMethod: (method: string, handler: GatewayRequestHandler) => void;