mirror of
https://github.com/openclaw/openclaw.git
synced 2026-02-19 18:39:20 -05:00
fix: land signal reaction update (#632) (thanks @neist)
This commit is contained in:
@@ -29,6 +29,7 @@
|
||||
- Discord: avoid category parent overrides for channel allowlists and refactor thread context helpers. (#588) — thanks @steipete
|
||||
- Discord: fix forum thread starters and cache channel lookups for thread context. (#585) — thanks @thewilloftheshadow
|
||||
- Discord: log gateway disconnect/reconnect events at info and add verbose gateway metrics. (#595) — thanks @steipete
|
||||
- Signal: match own-mode reactions when target includes uuid + phone. (#632) — thanks @neist
|
||||
- Commands: accept /models as an alias for /model.
|
||||
- Commands: add `/usage` as an alias for `/status`. (#492) — thanks @lc0rp
|
||||
- Models/Auth: add MiniMax Anthropic-compatible API onboarding (minimax-api). (#590) — thanks @mneves75
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
diff --git a/dist/src/classes/RequestClient.js b/dist/src/classes/RequestClient.js
|
||||
index 4a3357a..1cd3130 100644
|
||||
--- a/dist/src/classes/RequestClient.js
|
||||
+++ b/dist/src/classes/RequestClient.js
|
||||
@@ -86,6 +86,9 @@
|
||||
@@ -118,6 +118,9 @@ export class RequestClient {
|
||||
}
|
||||
}
|
||||
this.abortController = new AbortController();
|
||||
@@ -10,7 +12,7 @@
|
||||
let body;
|
||||
if (data?.body &&
|
||||
typeof data.body === "object" &&
|
||||
@@ -146,12 +149,26 @@
|
||||
@@ -178,12 +181,26 @@ export class RequestClient {
|
||||
body = JSON.stringify(data.body);
|
||||
}
|
||||
}
|
||||
@@ -40,6 +42,6 @@
|
||||
+ clearTimeout(timeoutId);
|
||||
+ }
|
||||
+ }
|
||||
if (response.status === 429) {
|
||||
const responseBody = await response.json();
|
||||
const rateLimitError = new RateLimitError(response, responseBody);
|
||||
let rawBody = "";
|
||||
let parsedBody;
|
||||
try {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/dist/providers/google-gemini-cli.js b/dist/providers/google-gemini-cli.js
|
||||
index 0000000..1111111 100644
|
||||
index 93aa26c..7d47d76 100644
|
||||
--- a/dist/providers/google-gemini-cli.js
|
||||
+++ b/dist/providers/google-gemini-cli.js
|
||||
@@ -248,6 +248,12 @@ async function* streamGeminiCli(model, context, credentials, options) {
|
||||
@@ -248,6 +248,12 @@ export const streamGoogleGeminiCli = (model, context, options) => {
|
||||
break; // Success, exit retry loop
|
||||
}
|
||||
const errorText = await response.text();
|
||||
@@ -12,15 +12,34 @@ index 0000000..1111111 100644
|
||||
+ console.log(`[pi-ai] 429 rate limit - failing fast to rotate account`);
|
||||
+ 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
|
||||
|
||||
// Check if retryable
|
||||
if (attempt < MAX_RETRIES && isRetryableError(response.status, errorText)) {
|
||||
// Use server-provided delay or exponential backoff
|
||||
diff --git a/dist/providers/openai-codex-responses.js b/dist/providers/openai-codex-responses.js
|
||||
index 188a829..20b3a32 100644
|
||||
--- a/dist/providers/openai-codex-responses.js
|
||||
+++ b/dist/providers/openai-codex-responses.js
|
||||
@@ -433,9 +433,15 @@ function convertMessages(model, context) {
|
||||
}
|
||||
else if (msg.role === "assistant") {
|
||||
const output = [];
|
||||
+ // OpenAI Responses rejects `reasoning` items that are not followed by a `message`.
|
||||
+ // Tool-call-only turns (thinking + function_call) are valid assistant turns, but
|
||||
+ // their stored reasoning items must not be replayed as standalone `reasoning` input.
|
||||
+ const hasTextBlock = msg.content.some((b) => b.type === "text");
|
||||
for (const block of msg.content) {
|
||||
if (block.type === "thinking" && msg.stopReason !== "error") {
|
||||
if (block.thinkingSignature) {
|
||||
+ if (!hasTextBlock)
|
||||
+ continue;
|
||||
const reasoningItem = JSON.parse(block.thinkingSignature);
|
||||
output.push(reasoningItem);
|
||||
}
|
||||
diff --git a/dist/providers/openai-responses.js b/dist/providers/openai-responses.js
|
||||
index 0000000..1111111 100644
|
||||
index 20fb0a2..1f7cdd1 100644
|
||||
--- a/dist/providers/openai-responses.js
|
||||
+++ b/dist/providers/openai-responses.js
|
||||
@@ -397,9 +397,17 @@ function convertMessages(model, context) {
|
||||
@@ -396,10 +396,16 @@ function convertMessages(model, context) {
|
||||
}
|
||||
else if (msg.role === "assistant") {
|
||||
const output = [];
|
||||
@@ -37,28 +56,3 @@ index 0000000..1111111 100644
|
||||
const reasoningItem = JSON.parse(block.thinkingSignature);
|
||||
output.push(reasoningItem);
|
||||
}
|
||||
}
|
||||
else if (block.type === "text") {
|
||||
|
||||
diff --git a/dist/providers/openai-codex-responses.js b/dist/providers/openai-codex-responses.js
|
||||
index 0000000..1111111 100644
|
||||
--- a/dist/providers/openai-codex-responses.js
|
||||
+++ b/dist/providers/openai-codex-responses.js
|
||||
@@ -434,9 +434,17 @@ function convertMessages(model, context) {
|
||||
}
|
||||
else if (msg.role === "assistant") {
|
||||
const output = [];
|
||||
+ // OpenAI Responses rejects `reasoning` items that are not followed by a `message`.
|
||||
+ // Tool-call-only turns (thinking + function_call) are valid assistant turns, but
|
||||
+ // their stored reasoning items must not be replayed as standalone `reasoning` input.
|
||||
+ const hasTextBlock = msg.content.some((b) => b.type === "text");
|
||||
for (const block of msg.content) {
|
||||
if (block.type === "thinking" && msg.stopReason !== "error") {
|
||||
if (block.thinkingSignature) {
|
||||
+ if (!hasTextBlock)
|
||||
+ continue;
|
||||
const reasoningItem = JSON.parse(block.thinkingSignature);
|
||||
output.push(reasoningItem);
|
||||
}
|
||||
}
|
||||
else if (block.type === "text") {
|
||||
|
||||
12
pnpm-lock.yaml
generated
12
pnpm-lock.yaml
generated
@@ -9,13 +9,13 @@ overrides:
|
||||
|
||||
patchedDependencies:
|
||||
'@buape/carbon':
|
||||
hash: 85885a1d47a37ae00bcd21f2efbeb025284ea98981c300f095fb94c0604ff9ac
|
||||
hash: 35533fc422c2bdc75a3171794bf56af2f46a7e6b29a6c9d11955209b4378eab7
|
||||
path: patches/@buape__carbon.patch
|
||||
'@mariozechner/pi-agent-core':
|
||||
hash: 01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4
|
||||
path: patches/@mariozechner__pi-agent-core.patch
|
||||
'@mariozechner/pi-ai':
|
||||
hash: 3f4c1f943c57dbe2980bf21b1768dc780355f9124eeffbc30b5d5e42d2ea4b7c
|
||||
hash: 24a435c06627b93fb5b0eff150d2075b5f5dd1db66dd8ea96eb366e6999be711
|
||||
path: patches/@mariozechner__pi-ai.patch
|
||||
'@mariozechner/pi-coding-agent':
|
||||
hash: 58af7c712ebe270527c2ad9d3351fac39d6cd4b81cc475a258d87840b446b90e
|
||||
@@ -45,7 +45,7 @@ importers:
|
||||
version: 0.42.1(patch_hash=01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4)(ws@8.19.0)(zod@4.3.5)
|
||||
'@mariozechner/pi-ai':
|
||||
specifier: ^0.42.1
|
||||
version: 0.42.1(patch_hash=3f4c1f943c57dbe2980bf21b1768dc780355f9124eeffbc30b5d5e42d2ea4b7c)(ws@8.19.0)(zod@4.3.5)
|
||||
version: 0.42.1(patch_hash=24a435c06627b93fb5b0eff150d2075b5f5dd1db66dd8ea96eb366e6999be711)(ws@8.19.0)(zod@4.3.5)
|
||||
'@mariozechner/pi-coding-agent':
|
||||
specifier: ^0.42.1
|
||||
version: 0.42.1(patch_hash=58af7c712ebe270527c2ad9d3351fac39d6cd4b81cc475a258d87840b446b90e)(ws@8.19.0)(zod@4.3.5)
|
||||
@@ -3786,7 +3786,7 @@ snapshots:
|
||||
|
||||
'@mariozechner/pi-agent-core@0.42.1(patch_hash=01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4)(ws@8.19.0)(zod@4.3.5)':
|
||||
dependencies:
|
||||
'@mariozechner/pi-ai': 0.42.1(patch_hash=3f4c1f943c57dbe2980bf21b1768dc780355f9124eeffbc30b5d5e42d2ea4b7c)(ws@8.19.0)(zod@4.3.5)
|
||||
'@mariozechner/pi-ai': 0.42.1(patch_hash=24a435c06627b93fb5b0eff150d2075b5f5dd1db66dd8ea96eb366e6999be711)(ws@8.19.0)(zod@4.3.5)
|
||||
'@mariozechner/pi-tui': 0.42.1
|
||||
transitivePeerDependencies:
|
||||
- '@modelcontextprotocol/sdk'
|
||||
@@ -3796,7 +3796,7 @@ snapshots:
|
||||
- ws
|
||||
- zod
|
||||
|
||||
'@mariozechner/pi-ai@0.42.1(patch_hash=3f4c1f943c57dbe2980bf21b1768dc780355f9124eeffbc30b5d5e42d2ea4b7c)(ws@8.19.0)(zod@4.3.5)':
|
||||
'@mariozechner/pi-ai@0.42.1(patch_hash=24a435c06627b93fb5b0eff150d2075b5f5dd1db66dd8ea96eb366e6999be711)(ws@8.19.0)(zod@4.3.5)':
|
||||
dependencies:
|
||||
'@anthropic-ai/sdk': 0.71.2(zod@4.3.5)
|
||||
'@google/genai': 1.34.0
|
||||
@@ -3820,7 +3820,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@mariozechner/clipboard': 0.3.0
|
||||
'@mariozechner/pi-agent-core': 0.42.1(patch_hash=01312ceb1f6be7e42822c24c9a7a4f7db56b24ae114a364855bd3819779d1cf4)(ws@8.19.0)(zod@4.3.5)
|
||||
'@mariozechner/pi-ai': 0.42.1(patch_hash=3f4c1f943c57dbe2980bf21b1768dc780355f9124eeffbc30b5d5e42d2ea4b7c)(ws@8.19.0)(zod@4.3.5)
|
||||
'@mariozechner/pi-ai': 0.42.1(patch_hash=24a435c06627b93fb5b0eff150d2075b5f5dd1db66dd8ea96eb366e6999be711)(ws@8.19.0)(zod@4.3.5)
|
||||
'@mariozechner/pi-tui': 0.42.1
|
||||
chalk: 5.6.2
|
||||
cli-highlight: 2.1.11
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
Signal reaction notifications ("own" mode) investigation
|
||||
|
||||
Context
|
||||
- Code path: `src/signal/monitor.ts` handles reaction-only envelopes and calls `enqueueSystemEvent`.
|
||||
- Default mode is "own" in config, which should notify when someone reacts to a message authored by the bot account.
|
||||
|
||||
Findings
|
||||
- Signal reaction handling only runs when `envelope.reactionMessage` is present and `dataMessage` is absent. If signal-cli includes `reactionMessage` alongside `dataMessage`, the reaction is ignored because the handler only runs in the `reactionMessage && !dataMessage` branch.
|
||||
- `resolveSignalReactionTarget()` prefers `targetAuthorUuid` over `targetAuthor`. If signal-cli includes both (common for sender identity fields), the target becomes `kind: "uuid"`, even when a phone number is also present.
|
||||
- In "own" mode, `shouldEmitSignalReactionNotification()` compares the configured `signal.account` string against the target. With a phone-configured account (e.g., `+14154668323`) and a UUID target, the check fails.
|
||||
- The tests in `src/signal/monitor.tool-result.test.ts` only cover reaction payloads with `targetAuthor` (phone), so UUID-first handling is not exercised.
|
||||
- Discord "own" mode compares `messageAuthorId` to `botUserId` (`shouldEmitDiscordReactionNotification`), which is strictly an ID match. The Signal implementation mirrors this pattern, but the target identity type mismatch (UUID vs E.164) breaks the comparison.
|
||||
|
||||
Likely root cause
|
||||
- Signal-cli reaction payloads appear to include `targetAuthorUuid` even when `targetAuthor` (phone) is present. Because `resolveSignalReactionTarget()` always prefers UUID, "own" mode never matches when `signal.account` is configured as E.164, causing no notification.
|
||||
|
||||
Secondary risk
|
||||
- If signal-cli includes `reactionMessage` alongside `dataMessage` (instead of reaction-only envelopes), the current handler never emits system events for reactions.
|
||||
|
||||
Debug logging to confirm (if needed)
|
||||
- Add a verbose log around the reaction handler to capture the identity fields and decision:
|
||||
- `targetAuthor`, `targetAuthorUuid`, computed `target.kind/id`, `account`, `mode`, and `shouldNotify`.
|
||||
- Log when `reactionMessage` is present but `dataMessage` is also present to verify whether reactions arrive as combined payloads.
|
||||
|
||||
Suggested fixes (not applied)
|
||||
- When mode is "own", compare the configured account against both `targetAuthor` (normalized E.164) and `targetAuthorUuid`, rather than selecting UUID first.
|
||||
- Or, in `resolveSignalReactionTarget()`, if both values exist and the configured account is a phone number, prefer `targetAuthor` over UUID for the "own" check.
|
||||
- Consider emitting reaction notifications even if `reactionMessage` and `dataMessage` coexist (guarded to avoid double-processing).
|
||||
@@ -759,7 +759,6 @@ export async function compactEmbeddedPiSession(params: {
|
||||
const enqueueGlobal =
|
||||
params.enqueue ??
|
||||
((task, opts) => enqueueCommandInLane(globalLane, task, opts));
|
||||
const runAbortController = new AbortController();
|
||||
return enqueueCommandInLane(sessionLane, () =>
|
||||
enqueueGlobal(async () => {
|
||||
const resolvedWorkspace = resolveUserPath(params.workspaceDir);
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
resolveStorePath,
|
||||
type SessionEntry,
|
||||
saveSessionStore,
|
||||
type SessionEntry,
|
||||
} from "../../config/sessions.js";
|
||||
import { parseAgentSessionKey } from "../../routing/session-key.js";
|
||||
import { resolveCommandAuthorization } from "../command-auth.js";
|
||||
|
||||
Reference in New Issue
Block a user