mirror of
https://github.com/lobehub/lobehub.git
synced 2026-09-20 04:56:13 +08:00
fix/topic-switch-message-refresh
5 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
1334209461 |
✨ feat(openapi): expose eval resources and external run lifecycle (#19428)
* ✨ feat(openapi): expose eval resources and external run lifecycle * 🐛 fix(openapi): report and aggregate shared eval dataset cases |
||
|
|
e85ae51880 |
✨ feat(openapi): add eval read routes for runs, datasets and topics (#19423)
* 🐛 fix(openapi): exempt heterogeneous relay routes from spec parity `POST /api/v1/anthropic/v1/messages` and `POST /api/v1/openai/v1/responses` are registered without `describeRoute`, so the generator's parity check has been failing since #18558 and `openapi.yml` could no longer be regenerated. Both relays speak the upstream Anthropic/OpenAI wire formats and are gated by `requireHeteroModelInvocation` (operation JWT), so no API key holder can reach them and their schemas are not LobeHub's to publish. Exempt them the same way the documentation-serving routes already are, instead of describing endpoints that are not part of the public API surface. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HmyR6qUiKJX9VteSJR1hiu * ✨ feat(openapi): add eval read routes for runs, datasets and topics `/api/v1/eval` could create a run and read that one run back, but offered no way to discover what already exists, so API consumers had to know a run id out of band. Add the four missing read endpoints: - `GET /eval/runs` (paginated, filterable by dataset and status) - `GET /eval/datasets` - `GET /eval/datasets/:id` - `GET /eval/runs/:id/topics` All four reuse the domain's existing posture: `AGENT_READ` RBAC, mandatory pagination, and public-field allowlists so internal columns never reach the response. Cross-tenant reads stay 404 rather than 403 so the endpoints do not confirm the existence of other tenants' rows. The models gain only the read primitives the routes need (count + paginated list); no schema or migration changes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HmyR6qUiKJX9VteSJR1hiu --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
9396a5b315 |
♻️ refactor(agent): move Graph Agent config from chatConfig to agencyConfig (#18419)
* ♻️ refactor(agent): move Graph Agent config from chatConfig to agencyConfig A graph is an agent: the ReasoningGraph defines the agent's behavior body (node policies, routing conditions, data contracts), so it belongs on the agency config (how the agent behaves and executes) rather than the chat config (per-session preferences). - types: drop enableGraphMode/graph from LobeAgentChatConfig, add to LobeAgentAgencyConfig next to heterogeneousProvider - runtime: GraphAgent factory reads agencyConfig.graph with a legacy chatConfig.graph fallback so existing rows keep running - cli: --enable-graph / --disable-graph / --graph-file now write agencyConfig - db: graph full-document replace moved to agencyConfig; legacy chatConfig.graph is forwarded to agencyConfig on the next write, migrating old rows in place - openapi / sdk: graph fields moved into agencyConfig, regenerated * ♻️ refactor(agent): rename ReasoningGraph to AgentGraph The graph is the behavior body of a Graph Agent, not a 'reasoning' data structure — the old name was misleading. Aligns the top-level type with its children (AgentGraphNode / AgentGraphEdge / AgentGraphField) and the AGENT_GRAPH_ROOT_NODE_ID constant. - ReasoningGraph -> AgentGraph - ReasoningGraphSchema -> AgentGraphSchema - UI copy in locales updated to match * 🐛 fix(agent): address codex review on graph agency config - openapi: thread agencyConfig through createAgent / updateAgent and the public projection, so API clients can actually persist the graph instead of getting a silent no-op - db: an explicit agency-level graph (including null) now takes ownership of the graph and drops the legacy chatConfig fields, so the runtime fallback cannot resurrect a cleared snapshot - ui: AgentGraphRuntime falls back to the legacy chatConfig values so pre-migration rows render their effective graph instead of an empty, disabled editor |
||
|
|
7abba9672f |
✨ feat(openapi): add api-keys, evals, mcp-servers and usage to the v1 API (#18141)
* ✨ feat(openapi): expand v1 REST surface with api-keys, evals, mcp-servers and usage Add new OpenAPI v1 resources (API keys, evals, MCP servers, usage) and harden the existing controllers with shared validators, pagination helpers and public-field projection so responses no longer leak internal columns. Usage reporting goes through a business-server slot so self-hosted deployments fall back to an unavailable summary. * 🐛 fix(openapi): enforce row-owner checks on MCP writes and drop the unused upload pathname The connector model's ownership predicate is workspace-wide, so the REST MCP write paths let any member with only `agent:update:owner` patch, delete or sync a server created by another member. The connector tRPC mutations already guard this with `assertWorkspaceRowManageable`; add the equivalent `assertRowManageable` to the OpenAPI BaseService and apply it before every MCP mutation. Also remove `pathname` from the public upload schema, route docs and spec: it never reached the storage key, and its validator allowed any 1-1024 char string, so wiring it through would have handed clients an unchecked object path. The batch upload schema already omitted it. * 🐛 fix(openapi): drop request fields the v1 run paths never honor `n` never reached ChatStreamPayload and /chat returns a single content string, so accepting it promised multiple choices and delivered one. `caseSelection` is storage-only for internal runs — this endpoint always creates `mode: 'internal'`, which pre-creates topics for every case in the dataset — so a caller asking for a subset would silently run the whole thing. `maxConcurrency` is consumed nowhere. Remove all three from the public schemas and regenerate the spec, matching the `pathname` removal: the contract should only advertise knobs the run path honors. `k`, `maxSteps` and `timeout` stay because the run service does read them. * 🐛 fix(openapi): admin-gate workspace API-key routes `workspaceAuthMiddleware` only enforces the owner/admin role for `apikey` auth, so an OIDC/session-authenticated workspace member holding `api_key:update:owner` could PATCH or DELETE another member's workspace key by id — `ApiKeyModel`'s predicate is workspace-wide, not row-owner. The tRPC side already gates this: `apiKeyProcedure` applies `requireWorkspaceRoleWhenScoped('admin')` to the whole router, so the REST surface was strictly more permissive. Add the equivalent Hono middleware and apply it to every api-keys route so both transports gate identically. * 🐛 fix(openapi): preserve an explicit temperature of 0 on /chat `ChatStreamPayload` was built with `params.temperature || 1`, so a request asking for deterministic output at `temperature: 0` was silently sent at 1 — the schema has accepted `min(0)` since the endpoint was introduced. Pre-existing since #12758 rather than a regression here, but it is the same contract-vs-implementation mismatch this PR has been clearing up, and the fix is `??` instead of `||`. Scoped to the request path: `generateReply` applies the same falsy fallback to an agent's stored config, which is a separate behavioural change for existing agents and is left alone. * 🐛 fix(openapi): require chat:write to queue an eval run An internal eval run pre-creates real chat topics through `TopicModel`, and the QStash workflow keeps writing topic/message state afterwards. The route gated only on `agent:write` + `model:invoke`, so a restricted API key deliberately denied `chat:write` could still persist chat artifacts through `/eval/runs`. `/responses` already enforces the full `agent:write` + `chat:write` + `model:invoke` trio for exactly this reason; match it here. * 🐛 fix(openapi): correct file response schemas and regenerate the SDK The spec fell back to the bare resource schema for any one-segment path, so `POST /files`, `GET /files/{id}`, `POST /files/batches` and `POST /files/queries` all advertised `File` while the controllers actually return wrapped payloads (`{ file, parsed? }`, `{ successful, failed, summary }`, `{ files, failed, ... }`). Generated clients would have mistyped every one of them. Describe the four explicitly ahead of the fallback. `packages/sdk/src/generated` was also stale — its drift test was already failing locally, since the SDK is not in the PR CI whitelist. Regenerated it from the corrected spec, so the new api-keys / eval / mcp-servers / usage resources are callable and the file operations carry the right types. * 🐛 fix(openapi): keep MCP server routes to base-scope connectors `isPublicMcpServer` ignored `agentId`, but `queryPublic()` (the list path) filters `agent_id IS NULL` while `findPublicById` does not. So the id routes — GET/PATCH/DELETE and POST /:id/sync — could reach agent-scoped connectors the list route cannot even surface. Deleting one that way skipped the connector router's agent-plugin unpin, which exists specifically so a delete never leaves the owning agent with a dangling pinned tool. Require `agentId === null` in the predicate so the whole group is consistently base-scoped; agent-scoped connectors stay managed through the agent profile. * 🐛 fix(openapi): stop typing named sub-operations as the group resource The success-schema fallback treated any single-segment path as a resource operation, so `GET /messages/count` was advertised as `Message` (it returns `{ count }`) and `GET /users/me` as `User` (a caller without `user:read` deliberately gets only `{ id }`). Generated SDK callers were typed against the wrong shapes. Narrow the fallback to the two real resource operations — the collection root and `{id}` — and describe `messages/count`, `messages/replies` and `users/me` explicitly. An undescribed sub-operation now degrades to a permissive object rather than a confidently wrong resource type, which is the failure mode that produced both this and the earlier `/files` mistyping. SDK regenerated. |
||
|
|
3ea7afd5d8 |
✨ feat(openapi): generate openapi.yml from routes via hono-openapi (#17944)
* ✨ feat(openapi): generate openapi.yml from routes via hono-openapi - add src/common/validator.ts: drop-in zValidator built on hono-openapi so every request schema registers into the spec while keeping the exact @hono/zod-validator 400 response shape - describe the four validator-less routes (users/me, agent-groups list, file upload, batch upload incl. multipart bodies) and /health - add scripts/generate-openapi.ts: runtime spec generation with route-vs-spec parity check, --check mode for CI, placeholder responses - commit the generated openapi.yml (79 operations / 38 paths) and guard it with scripts/generate-openapi.test.ts - ignore the generated file in eslint/prettier so formatters don't fight the generator output Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ✨ feat(openapi): serve API docs at /api/v1/docs via Scalar - extract spec assembly into src/spec.ts, shared by the generator script and the new runtime endpoint so both always emit the same document - GET /api/v1/openapi.json: build spec from live routes on first request, cached in memory - GET /api/v1/docs: Scalar interactive reference reading that endpoint - exempt the two docs routes from the generator parity check (real endpoints, deliberately not part of the described API surface) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 💄 style(openapi): match docs site theme to the app's neutral monochrome style - add src/docs-theme.ts: Scalar CSS variable overrides — black accent on light, white accent on true-black dark, antd system font stack - theme: 'none' so the runtime bundle doesn't inject its default theme stylesheet after our customCss (which silently overrode every variable) - reuse the app favicon Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * 🌐 feat(openapi): localize docs UI following the app's language preference Resolve the Scalar UI locale per request with the same priority the main app uses (?hl query > LOBE_LOCALE cookie > Accept-Language), mapped to Scalar's built-in translations (zh-CN, de, fr, es, ru, ar; zh-* all map to zh-CN). English stays the default for unsupported locales. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |