[PIX-12637] fix: envelope {data,total} для agents list + sessionIdBefore fallback #202

Merged
andrei merged 4 commits from delivery/pix-12637 into master 2026-07-06 12:22:33 +00:00
Owner

Что сделано

Доставка ветки agent/fullstack/pix-12637 (только локальная, не была в origin — прецедент PIX-7057).

Два независимых фикса:

  1. sessionIdBefore fallback (server/src/services/heartbeat.ts): если у агента нет активного runtime session, теперь используется sessionIdAfter последнего run как fallback вместо null. Снижает число "холодных" сессий при resume heartbeat.
  2. Envelope {data, total} для GET /api/companies/:companyId/agents (пагинация): раньше эндпоинт отдавал голый массив.

Почему это заняло больше одного коммита оригинальной ветки

При анализе выяснилось, что смена формата ответа №2 — breaking change: минимум 9 мест в коде читали этот эндпоинт как голый массив (ui/src/api/agents.ts — используется в ~20 страницах через agentsApi.list(), 3 CLI-команды, MCP tool paperclipListAgents, 2 e2e/smoke теста, 1 unit-тест). Если доставить только исходный коммит — сломались бы Agents.tsx, OrgChart, CLI agent list, connect, secrets migrate-inline-env, MCP-тул и e2e/smoke прогоны.

Поэтому вместе с оригинальным изменением сервера доставлены backward-compatible фиксы всех потребителей: они теперь принимают оба формата (Array.isArray(response) ? response : response.data), так что сервер может отдавать envelope без немедленной поломки клиентов:

  • ui/src/api/agents.tsagentsApi.list() и internal fallback в get()
  • cli/src/commands/client/agent.ts, connect.ts, secrets.ts
  • packages/mcp-server/src/tools.ts (paperclipListAgents)
  • tests/release-smoke/docker-auth-onboarding.spec.ts, cli/src/__tests__/company-import-export-e2e.test.ts, scripts/smoke/openclaw-gateway-e2e.sh
  • server/src/__tests__/agent-permissions-routes.test.ts (skipped-тест обновлён на новый формат для будущей корректности)

План тестирования

  • vitest run src/__tests__/agent-permissions-routes.test.ts src/__tests__/agents-list-pagination-response-format.test.ts — 50 passed, 7 skipped.
  • vitest run src/__tests__/connect.test.ts (cli) — 2 passed.
  • tsc --noEmit для ui, cli, packages/mcp-server — 0 новых ошибок.
  • Pre-push hook (typecheck всех workspace-пакетов) — зелёный.
  • vitest run src/__tests__/heartbeat-retry-scheduling.test.ts — 1 тест падает (does not schedule a max-turn continuation when the issue is already blocked), но это pre-existing падение независимо от этого PR (воспроизводится и без наших коммитов, на чистой базе delivery-ветки); уже есть отдельная ветка agent/cto/pix-13590-fix-master-ci-issue-list-mocks для этого класса проблем.

Где могу ошибаться

  • E2E-тесты (company-import-export-e2e.test.ts, docker-auth-onboarding.spec.ts) требуют живого сервера — не прогонялись в этой сессии, только typecheck; логика унификации формата идентична уже проверенной в unit-тестах.
  • Не проверял, есть ли внешние (не в этом репозитории) потребители этого публичного API — если такие есть, им тоже потребуется обновление на новый формат ответа.

Зачем

Без доставки этой ветки выполненная работа теряется (прецедент PIX-7057): фикс sessionIdBefore fallback уменьшает число холодных resume-сессий, а envelope {data,total} выравнивает контракт GET /api/companies/:companyId/agents с потребителями и делает пагинацию с total рабочей. Все 9 потребителей обновлены backward-compatible.

  • Я поискал похожие PR и подтверждаю, что дубликатов нет
## Что сделано Доставка ветки `agent/fullstack/pix-12637` (только локальная, не была в origin — прецедент PIX-7057). Два независимых фикса: 1. **`sessionIdBefore` fallback** (`server/src/services/heartbeat.ts`): если у агента нет активного runtime session, теперь используется `sessionIdAfter` последнего run как fallback вместо `null`. Снижает число "холодных" сессий при resume heartbeat. 2. **Envelope `{data, total}` для `GET /api/companies/:companyId/agents`** (пагинация): раньше эндпоинт отдавал голый массив. ## Почему это заняло больше одного коммита оригинальной ветки При анализе выяснилось, что смена формата ответа №2 — **breaking change**: минимум 9 мест в коде читали этот эндпоинт как голый массив (`ui/src/api/agents.ts` — используется в ~20 страницах через `agentsApi.list()`, 3 CLI-команды, MCP tool `paperclipListAgents`, 2 e2e/smoke теста, 1 unit-тест). Если доставить только исходный коммит — сломались бы Agents.tsx, OrgChart, CLI `agent list`, `connect`, `secrets migrate-inline-env`, MCP-тул и e2e/smoke прогоны. Поэтому вместе с оригинальным изменением сервера доставлены **backward-compatible фиксы всех потребителей**: они теперь принимают оба формата (`Array.isArray(response) ? response : response.data`), так что сервер может отдавать envelope без немедленной поломки клиентов: - `ui/src/api/agents.ts` — `agentsApi.list()` и internal fallback в `get()` - `cli/src/commands/client/agent.ts`, `connect.ts`, `secrets.ts` - `packages/mcp-server/src/tools.ts` (`paperclipListAgents`) - `tests/release-smoke/docker-auth-onboarding.spec.ts`, `cli/src/__tests__/company-import-export-e2e.test.ts`, `scripts/smoke/openclaw-gateway-e2e.sh` - `server/src/__tests__/agent-permissions-routes.test.ts` (skipped-тест обновлён на новый формат для будущей корректности) ## План тестирования - `vitest run src/__tests__/agent-permissions-routes.test.ts src/__tests__/agents-list-pagination-response-format.test.ts` — 50 passed, 7 skipped. - `vitest run src/__tests__/connect.test.ts` (cli) — 2 passed. - `tsc --noEmit` для `ui`, `cli`, `packages/mcp-server` — 0 новых ошибок. - Pre-push hook (typecheck всех workspace-пакетов) — зелёный. - `vitest run src/__tests__/heartbeat-retry-scheduling.test.ts` — 1 тест падает (`does not schedule a max-turn continuation when the issue is already blocked`), но это **pre-existing** падение независимо от этого PR (воспроизводится и без наших коммитов, на чистой базе delivery-ветки); уже есть отдельная ветка `agent/cto/pix-13590-fix-master-ci-issue-list-mocks` для этого класса проблем. ## Где могу ошибаться - E2E-тесты (`company-import-export-e2e.test.ts`, `docker-auth-onboarding.spec.ts`) требуют живого сервера — не прогонялись в этой сессии, только typecheck; логика унификации формата идентична уже проверенной в unit-тестах. - Не проверял, есть ли внешние (не в этом репозитории) потребители этого публичного API — если такие есть, им тоже потребуется обновление на новый формат ответа. ## Зачем Без доставки этой ветки выполненная работа теряется (прецедент PIX-7057): фикс `sessionIdBefore` fallback уменьшает число холодных resume-сессий, а envelope `{data,total}` выравнивает контракт `GET /api/companies/:companyId/agents` с потребителями и делает пагинацию с total рабочей. Все 9 потребителей обновлены backward-compatible. - [x] Я поискал похожие PR и подтверждаю, что дубликатов нет
Fixes regression where new runs had sessionIdBefore=null when agent
runtime state was empty or unavailable.

When getRuntimeState doesn't return a sessionId, fallback to using the
last run's sessionIdAfter to ensure sessionIdBefore is always populated
for continuity.

Adds regression test to enforce this behavior.

Evidence: Smoke test of production API found 100% of recent runs with
sessionIdBefore=null despite valid sessionIdAfter in previous runs.
## Что сделано
Обновлен endpoint GET /api/companies/:companyId/agents для возврата структурированного ответа с поддержкой pagination.

**Было:**
```
[{ id, name, role, ... }]
```

**Стало:**
```
{ data: [{ id, name, role, ... }], total: number }
```

## Зачем
- Возможность добавить pagination (limit, offset) с правильным подсчётом total
- Клиент может знать полное количество агентов, не загружая все сразу
- Согласованная структура с другими paginated endpoints

## План тестирования
 Добавлен regression test: agents-list-pagination-response-format.test.ts
 4/4 tests pass
 TypeScript: 0 ошибок
 Response structure: { data: Agent[], total: number }

## Где могу ошибиться
- Клиенты ожидали plain array - могут сломаться. Нужен breaking change notice
- Pagination logic (limit/offset) может потребоваться в applyAgentListQuery
- Интеграция с paginated UI компонентами frontend - проверить соответствие контракта

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
fix(clients): support {data,total} envelope from agents list endpoint
Some checks failed
security/pr-scan 1 security flag(s) — see Actions log (critical)
PR Quality Gates / PR Quality Gates (pull_request_target) Failing after 5s
Agents CI / Typecheck and Build (pull_request) Successful in 5m21s
Agents CI / API Tests (pull_request) Successful in 13m32s
b2c36453e1
Обновляет всех потребителей GET /api/companies/:companyId/agents
(ui, cli, mcp-server, e2e/smoke тесты) чтобы они принимали как старый
формат (массив), так и новый envelope {data, total}, введённый
предыдущим коммитом. Без этого фикс пагинации ломал UI (Agents.tsx,
OrgChart и др.), 3 CLI-команды и MCP tool paperclipListAgents.

All checks passing — ready for review and maintainer approval.

— paperclip-gates

✅ All checks passing — ready for review and maintainer approval. — paperclip-gates
chore: retrigger PR quality gates after body update (PIX-12637)
Some checks reported warnings
security/pr-scan 1 security flag(s) — see Actions log (critical)
PR Quality Gates / PR Quality Gates (pull_request_target) Successful in 5s
Agents CI / Typecheck and Build (pull_request) Successful in 5m2s
Agents CI / API Tests (pull_request) Successful in 14m18s
1a442338c0
andrei merged commit 456c452916 into master 2026-07-06 12:22:33 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
europa-tech-srl/europa-tech-agents!202
No description provided.