feat(session): raise ping-pong turn ceiling

Co-authored-by: Thirumalesh <thirumaleshpinninti@gmail.com>
This commit is contained in:
Peter Steinberger
2026-05-11 04:15:13 +01:00
parent a3a8f7095c
commit d90ab9a13f
9 changed files with 36 additions and 9 deletions

View File

@@ -10,6 +10,7 @@ Docs: https://docs.openclaw.ai
- Build: enable stricter Vitest lint rules for focused, disabled, conditional, hook, matcher, and expectation hazards.
- Build: pin explicit oxfmt defaults in the shared formatter config to keep formatting behavior stable across upgrades.
- TypeScript: enable stricter compiler checks for implicit returns, side-effect imports, overrides, and unused production code.
- Agents: allow `session.agentToAgent.maxPingPongTurns` up to 20 while keeping the default at 5 for longer agent-to-agent reply chains. Fixes #52382. (#52400) Thanks @thirumaleshp.
- Build: upgrade workspace package management to pnpm 11 and keep Docker, install, update, and release workflows on the pnpm 11 config surface. (#79414) Thanks @altaywtf.
- Models: add provider-level `localService` startup for on-demand local model servers before OpenAI-compatible requests, including one-shot model probes.
- Agents: trim default system prompt guidance and send-only message tool schemas to reduce prompt tokens while preserving GPT-5 personality guidance.

View File

@@ -1,4 +1,4 @@
c9e88800854b697cb3c9721d0087eb2bc7bcf6ae7239cb51d9849c49ef3d48e3 config-baseline.json
67c58457ed2b525975cdb053489f92a5f840c8cf982666393e111fd327dd132e config-baseline.core.json
1cc2cabc41c2261492dea4d927b48864c6992dcfb5b81fa97f2171848d037b1e config-baseline.json
bfa974d070e5ef26fab023506b050cb3a582d1e54a096dbf4dddbc59535de29c config-baseline.core.json
f90c9d96ccc4c0c703d6c489f86d89fde208cd7f697b396aeee96ff3ee087956 config-baseline.channel.json
18f71e9d4a62fe68fbd5bf18d5833a4e380fc705ad641769e1cf05794286344c config-baseline.plugin.json

View File

@@ -104,7 +104,8 @@ provenance. The receiving agent should treat them as tool-routed data, not as a
direct end-user-authored instruction.
After the target responds, OpenClaw can run a **reply-back loop** where the
agents alternate messages (up to 5 turns). The target agent can reply
agents alternate messages (up to `session.agentToAgent.maxPingPongTurns`, range
0-20, default 5). The target agent can reply
`REPLY_SKIP` to stop early.
## Status and orchestration helpers

View File

@@ -1219,7 +1219,7 @@ See [Multi-Agent Sandbox & Tools](/tools/multi-agent-sandbox-tools) for preceden
- **`reset`**: primary reset policy. `daily` resets at `atHour` local time; `idle` resets after `idleMinutes`. When both configured, whichever expires first wins. Daily reset freshness uses the session row's `sessionStartedAt`; idle reset freshness uses `lastInteractionAt`. Background/system-event writes such as heartbeat, cron wakeups, exec notifications, and gateway bookkeeping can update `updatedAt`, but they do not keep daily/idle sessions fresh.
- **`resetByType`**: per-type overrides (`direct`, `group`, `thread`). Legacy `dm` accepted as alias for `direct`.
- **`mainKey`**: legacy field. Runtime always uses `"main"` for the main direct-chat bucket.
- **`agentToAgent.maxPingPongTurns`**: maximum reply-back turns between agents during agent-to-agent exchanges (integer, range: `0``5`). `0` disables ping-pong chaining.
- **`agentToAgent.maxPingPongTurns`**: maximum reply-back turns between agents during agent-to-agent exchanges (integer, range: `0`-`20`, default: `5`). `0` disables ping-pong chaining.
- **`sendPolicy`**: match by `channel`, `chatType` (`direct|group|channel`, with legacy `dm` alias), `keyPrefix`, or `rawKeyPrefix`. First deny wins.
- **`maintenance`**: session-store cleanup + retention controls.
- `mode`: `warn` emits warnings only; `enforce` applies cleanup.

View File

@@ -1,7 +1,7 @@
import { beforeEach, describe, expect, it } from "vitest";
import { setActivePluginRegistry } from "../../plugins/runtime.js";
import { createSessionConversationTestRegistry } from "../../test-utils/session-conversation-registry.js";
import { resolveAnnounceTargetFromKey } from "./sessions-send-helpers.js";
import { resolveAnnounceTargetFromKey, resolvePingPongTurns } from "./sessions-send-helpers.js";
describe("resolveAnnounceTargetFromKey", () => {
beforeEach(() => {
@@ -63,3 +63,28 @@ describe("resolveAnnounceTargetFromKey", () => {
});
});
});
describe("resolvePingPongTurns", () => {
it("defaults to 5 when unset", () => {
expect(resolvePingPongTurns(undefined)).toBe(5);
expect(resolvePingPongTurns({ session: {} } as never)).toBe(5);
});
it("uses configured values through the 20-turn ceiling", () => {
expect(
resolvePingPongTurns({ session: { agentToAgent: { maxPingPongTurns: 10 } } } as never),
).toBe(10);
expect(
resolvePingPongTurns({ session: { agentToAgent: { maxPingPongTurns: 20 } } } as never),
).toBe(20);
});
it("keeps defensive floor and ceiling clamps", () => {
expect(
resolvePingPongTurns({ session: { agentToAgent: { maxPingPongTurns: -1 } } } as never),
).toBe(0);
expect(
resolvePingPongTurns({ session: { agentToAgent: { maxPingPongTurns: 50 } } } as never),
).toBe(20);
});
});

View File

@@ -13,7 +13,7 @@ export {
} from "./sessions-send-tokens.js";
const DEFAULT_PING_PONG_TURNS = 5;
const MAX_PING_PONG_TURNS = 5;
const MAX_PING_PONG_TURNS = 20;
export type AnnounceTarget = {
channel: string;

View File

@@ -1537,7 +1537,7 @@ export const FIELD_HELP: Record<string, string> = {
"session.agentToAgent":
"Groups controls for inter-agent session exchanges, including loop prevention limits on reply chaining. Keep defaults unless you run advanced agent-to-agent automation with strict turn caps.",
"session.agentToAgent.maxPingPongTurns":
"Max reply-back turns between requester and target agents during agent-to-agent exchanges (0-5). Use lower values to hard-limit chatter loops and preserve predictable run completion.",
"Max reply-back turns between requester and target agents during agent-to-agent exchanges (0-20, default 5). Use lower values to hard-limit chatter loops and preserve predictable run completion.",
"session.threadBindings":
"Shared defaults for thread-bound session routing behavior across providers that support thread focus workflows. Configure global defaults here and override per channel only when behavior differs.",
"session.threadBindings.enabled":

View File

@@ -205,7 +205,7 @@ export type SessionConfig = {
/** Session transcript write-lock acquisition policy. */
writeLock?: SessionWriteLockConfig;
agentToAgent?: {
/** Max ping-pong turns between requester/target (05). Default: 5. */
/** Max ping-pong turns between requester/target (0-20). Default: 5. */
maxPingPongTurns?: number;
};
/** Shared defaults for thread-bound session routing across channels/providers. */

View File

@@ -64,7 +64,7 @@ export const SessionSchema = z
.optional(),
agentToAgent: z
.object({
maxPingPongTurns: z.number().int().min(0).max(5).optional(),
maxPingPongTurns: z.number().int().min(0).max(20).optional(),
})
.strict()
.optional(),