fix(agents): disclose scoped session list results (#86944) · openclaw/openclaw@598aad4
ferminquant
·
2026-05-27
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -49,10 +49,12 @@ effective tool list.
|
49 | 49 | token counts, and timestamps. Filter by kind (`main`, `group`, `cron`, `hook`, |
50 | 50 | `node`), exact `label`, exact `agentId`, search text, or recency |
51 | 51 | (`activeMinutes`). When you need mailbox-style triage, it can also ask for a |
52 | | -visibility-scoped derived title, a last-message preview snippet, or bounded |
53 | | -recent messages on each row. Derived titles and previews are produced only for |
54 | | -sessions the caller can already see under the configured session tool |
55 | | -visibility policy, so unrelated sessions stay hidden. |
| 52 | +visibility-scoped derived title, a last-message preview snippet, or bounded recent |
| 53 | +messages on each row. Derived titles and previews are produced only for sessions |
| 54 | +the caller can already see under the configured session tool visibility policy, so |
| 55 | +unrelated sessions stay hidden. When visibility is restricted, `sessions_list` |
| 56 | +returns optional `visibility` metadata showing the effective mode and a warning that |
| 57 | +results may be scope-limited. |
56 | 58 | |
57 | 59 | `sessions_history` fetches the conversation transcript for a specific session. |
58 | 60 | By default, tool results are excluded -- pass `includeTools: true` to see them. |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -357,6 +357,9 @@ Default: `tree` (current session + sessions spawned by it, such as subagents).
|
357 | 357 | - `agent`: any session belonging to the current agent id (can include other users if you run per-sender sessions under the same agent id). |
358 | 358 | - `all`: any session. Cross-agent targeting still requires `tools.agentToAgent`. |
359 | 359 | - Sandbox clamp: when the current session is sandboxed and `agents.defaults.sandbox.sessionToolsVisibility="spawned"`, visibility is forced to `tree` even if `tools.sessions.visibility="all"`. |
| 360 | +- When not `all`, `sessions_list` includes a compact `visibility` field |
| 361 | + describing the effective mode and a warning that some sessions may be |
| 362 | + omitted outside the current scope. |
360 | 363 | |
361 | 364 | </Accordion> |
362 | 365 | </AccordionGroup> |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -417,9 +417,19 @@ export function createSessionsListTool(opts?: {
|
417 | 417 | await Promise.all(Array.from({ length: maxConcurrent }, () => worker())); |
418 | 418 | } |
419 | 419 | |
| 420 | +const visibilityMetadata = |
| 421 | +visibility === "all" |
| 422 | + ? undefined |
| 423 | + : { |
| 424 | +mode: visibility, |
| 425 | +restricted: true, |
| 426 | +warning: `Session visibility is restricted (effective tools.sessions.visibility=${visibility}). Results may omit sessions outside the current scope. The count field reflects only sessions within the current scope.`, |
| 427 | +}; |
| 428 | + |
420 | 429 | return jsonResult({ |
421 | 430 | count: rows.length, |
422 | 431 | sessions: rows, |
| 432 | + ...(visibilityMetadata ? { visibility: visibilityMetadata } : {}), |
423 | 433 | }); |
424 | 434 | }, |
425 | 435 | }; |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -514,12 +514,34 @@ describe("sessions_list gating", () => {
|
514 | 514 | |
515 | 515 | const details = requireDetails(result); |
516 | 516 | expect(details.count).toBe(1); |
| 517 | +expect(details.visibility).toBeUndefined(); |
517 | 518 | const session = requireSessions(details)[0]; |
518 | 519 | expect(session?.key).toBe("agent:codex:acp:child-1"); |
519 | 520 | expect(session?.parentSessionKey).toBe(MAIN_AGENT_SESSION_KEY); |
520 | 521 | expect(callGatewayMock).toHaveBeenCalledTimes(1); |
521 | 522 | }); |
522 | 523 | |
| 524 | +it("includes visibility metadata when session visibility is restricted", async () => { |
| 525 | +loadConfigMock.mockReturnValue({ |
| 526 | +session: { scope: "per-sender", mainKey: "main" }, |
| 527 | +tools: { |
| 528 | +agentToAgent: { enabled: true }, |
| 529 | +sessions: { visibility: "tree" }, |
| 530 | +}, |
| 531 | +}); |
| 532 | + |
| 533 | +const result = await createMainSessionsListTool().execute("call1", {}); |
| 534 | + |
| 535 | +const details = requireDetails(result); |
| 536 | +expect(details.count).toBe(1); |
| 537 | +expect(details.visibility).toMatchObject({ |
| 538 | +mode: "tree", |
| 539 | +restricted: true, |
| 540 | +warning: |
| 541 | +"Session visibility is restricted (effective tools.sessions.visibility=tree). Results may omit sessions outside the current scope. The count field reflects only sessions within the current scope.", |
| 542 | +}); |
| 543 | +}); |
| 544 | + |
523 | 545 | it("keeps literal current keys for message previews", async () => { |
524 | 546 | callGatewayMock.mockReset(); |
525 | 547 | callGatewayMock |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。