Repository navigation
refactor(web): migrate handwritten console API calls to the generated oRPC contract - #44169
Conversation
Pydantic models were registered into each Flask-RESTX namespace by bare class name, so two different types with the same name silently overwrote each other and corrupted the generated @dify/contracts types (e.g. the conversation `ModelConfig` was replaced by the LLM-generator one). - `_register_json_schema` now tracks the source type and schema of every component and raises `SchemaNameCollisionError` when a name (compared the way client generators normalize it, so `JSONValue`/`JsonValue` count as one) is reused by another type or by the same type with a different shape. - Nested `$defs` are named by a custom generator that keeps names stable across schemas; `SCHEMA_NAME_OVERRIDES` gives third-party/core types that share a class name (graphon I18nObject, plugin dependency Github/Marketplace/Package, knowledge FileInfo) unique names. - Renamed controller-local duplicates (ChatMessageExplorePayload, RagPipelineDraftWorkflowRunPayload, RagPipelineWorkflowRunQuery, HumanInputFormPreviewSubmitPayload, AppMessageFeedbackPayload, WebhookTriggerQuery, DatasourceContentPreviewPayload, SnippetPublishWorkflowPayload, SnippetWorkflowRunQuery, ConversationModelConfig, Any/Recursive/ShallowJSONValue, CompletionParamValue) and deduplicated identical response models. - Response-only models are no longer also registered in validation mode. - Regenerated contracts; the log ModelInfo component now owns its prop type instead of borrowing the overwritten generated `ModelConfig`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replace the forwarding hooks in service/use-log.ts with direct consoleQuery calls at each call site and type the log pages with the generated contract instead of handwritten DTOs. - Conversation list/detail, workflow logs, pause details and annotation count now use consoleQuery queryOptions; use-log.ts is removed. - Untyped JSON fields (model_config.model, user_input_form, details) are narrowed at the boundary in list-utils instead of being read as any. - Read the conversation introduction from the top-level field the API actually returns, and skip null backstage input URLs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pyrefly Diffbase → PR--- /tmp/pyrefly_base.txt 2026-10-15 22:12:54.717570585 +0000
+++ /tmp/pyrefly_pr.txt 2026-10-15 22:12:46.133473321 +0000
@@ -1576,6 +1576,8 @@
--> tests/unit_tests/commands/test_upgrade_db.py:128:5
ERROR No attribute `MethodView` in module `builtins` [missing-attribute]
--> tests/unit_tests/controllers/common/test_fields.py:8:5
+ERROR No matching overload found for function `pydantic.main.create_model` called with arguments: (Literal['UserModel'], __module__=Literal['other_module'], **dict[str, tuple[type[Any], EllipsisType]]) [no-matching-overload]
+ --> tests/unit_tests/controllers/common/test_schema.py:133:24
ERROR Object of class `int` has no attribute `lower` [missing-attribute]
--> tests/unit_tests/controllers/console/app/test_annotation_security.py:237:38
ERROR Object of class `int` has no attribute `lower` [missing-attribute]
|
Pyrefly Type Coverage
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #44169 +/- ##
==========================================
+ Coverage 88.94% 89.10% +0.16%
==========================================
Files 5304 5305 +1
Lines 326595 326570 -25
Branches 63840 64242 +402
==========================================
+ Hits 290497 291005 +508
+ Misses 30900 30371 -529
+ Partials 5198 5194 -4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…ontract Call consoleClient directly for annotation settings, list, CRUD, export, hit histories and job status, and type annotation items with the generated contract. Only the multipart batch import stays on the handwritten request layer. The bulk delete endpoint now documents its repeated `annotation_id` query, and the console client sends it as repeated keys: without them the API receives no IDs and clears every annotation of the app. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… contract Chat messages, feedback, log annotations and agent log detail now call consoleClient directly. The log chat formatter and agent log modal read the generated response types; untyped JSON fields are narrowed where they enter the chat UI types. The agent log response schema now matches what the service returns: `tool_label` is a name or i18n labels, `tool_icon` a URL or emoji icon. The never-sent `meta.error` is no longer read, and a missing annotation account no longer crashes the log detail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ract Remove the forwarding hooks in service/use-models.ts. Credential queries and mutations use consoleQuery/consoleClient where they are consumed; useAuthService keeps owning the provider-vs-model dispatch. The load balancing modal normalizes the generated response into its form types at one boundary. The model credential query is skipped without a model instead of requesting `model=undefined`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ace permission Move the remaining calls of service/apps.ts, knowledge/use-import.ts, knowledge/use-hit-testing.ts and use-workspace.ts to the console contract at their call sites, and delete those modules. - Hit testing types now alias the generated response; the record never had a `content` copy of the segment, and the query has no tsne position. - Notion pre-import pages are normalized once in the query `select`; top-level pages without a parent are treated as `root`. - RETRIEVE_METHOD drops `invertedIndex`, which the API never accepts or returns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e contract
Remove service/access-control/use-{member,workspace}-roles.ts and
useMembers. Consumers use consoleQuery directly; the role and member
invalidations those hooks owned now live in query-policies.
Backend contract fixes this depended on:
- RBAC role list/create/update/copy and role-member list now document
their query parameters and request bodies, and the member list and
member role endpoints document `language`; previously the generated
client could not send them.
- Member `roles` is typed as `{id, name}` summaries, which is what the
endpoint returns, instead of a free-form map. The web previously typed
them as full roles and as ISO timestamps; both were wrong.
A shared role-list options factory normalizes the loosely typed role DTOs
into the UI role type. test/console/operation-hooks lets specs answer
console operations by path while other queries stay real.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ervice/common Sign-in, setup/init, forgot/reset password, email-code login, invitation activation, account deletion, email change, ownership transfer, member removal, workspace rename, default model, model enable/disable and the compliance download now call the console contract directly. Only the web-app (public API) helpers and remote file upload remain in common.ts. The generated response types exposed unreachable branches: console login never returns an access token in the body, and email-code verification and password-reset requests raise errors instead of returning failure codes, so those branches are removed. Default model and parameter-rule responses are normalized where they enter the model provider UI types. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e console contract
File upload limits, signup mail flow, account init, invitation checks,
file preview, schema definitions, code-based extensions, structured
output generation, notion binding and model parameter rules now use
consoleQuery at their call sites; use-common.ts keeps only logout and
one documented exception.
Backend contract fixes:
- Code-based extension responses list their items instead of `Any`.
- Structured output generation documents its `{output, error}` body.
Notes:
- The forgot-password token check is left on the handwritten request: the
endpoint requires `email` and `code`, which the token-only link flow
does not have, so that request cannot succeed as written.
- Model provider details keep a feature-owned options factory with a
documented cast; its credential schemas are untyped JSON in the API.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t migration Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vinext bundle analysisJS gzip: 🟢 −4.65 KiB (−0.05%) · CSS gzip: ⚪ No change
Entry changes: 🟠 5 increased · 🟢 166 decreased (gzip). Largest entry changesTop 5 by absolute gzip delta. Static dependencies overlap; do not sum entries.
Top 20 of 171 changed entries (full paths and raw sizes)
📦 3 package attribution changes (uncompressed modules)Showing 3 of 3, ordered by absolute module-size delta.
Measurement details and build revisionsBase: Raw JS change: 🟠 +2.38 KiB (+<0.01%) · Raw CSS change: ⚪ No change 🟠 Increase · 🟢 Decrease · ⚪ Unchanged. Colors indicate direction, not a performance budget verdict. Percentages use the base size. Entries follow only static edges in the official Rolldown chunk graph, deduplicating shared files. Dynamic entries are measured when loaded; they are not page first-load metrics. Entry totals overlap and must not be summed. Download base/merge snapshots and official Rolldown analysis reports. Comparison: event base SHA vs the tested merge commit at GITHUB_SHA (PR or merge queue). |
…nsole contract
- service/datasets.ts and service/knowledge/use-{dataset,document,segment,metadata,create-dataset}
call consoleClient; knowledge UI DTOs are narrowed at the service boundary
- document query params (list, batch delete, batch status) and dataset query history
pagination documented on the backend; repeated-key rules for document_id
- 204 endpoints (delete external API, retry error docs) no longer rely on the legacy
{result: 'success'} rewrite
- dataset update body, notion info and pre-processing rules use generated request types
- drop unused qs dependency
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sole contract - install/upgrade/upload, permission and auto-upgrade settings, debugging key, tasks and dynamic options call consoleClient; plugin UI DTOs are narrowed at the boundary - extract the boundary narrowing helper to service/console/narrow-response - dynamic options default provider_type to 'tool' (the backend requires it) - marketplace (external API) calls stay on getMarketplace/postMarketplace Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- service/tools.ts and service/use-tools.ts call consoleClient; tool UI DTOs are narrowed at the boundary - remove fetchModelToolList and the isModel prop: the backend has no model tool provider type and /tool-provider/model/tools does not exist - keep the legacy built-in credential flow handwritten: it no longer matches the backend (schema moved, credentials became a list, update/delete need credential_id) - MCP provider payloads require server_identifier and send icon_background without null; MCP server payloads require parameters; workflow tool requests carry label - drop the unused _tools_util helper Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ontract Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…vice calls - draft node runs, inspect variables, last run, system/conversation variables, variable reset/edit/delete call the console contract per flow type via callByFlowType - block default configs, environment variables, human input form submission and email delivery tests call consoleClient - debug: suggested questions and conversation messages pass an AbortSignal; rule and instruction generation, prompt templates and message detail use the contract - plugins: upgrade, GitHub upload and task status use the contract - RAG pipelines have no conversation variables, so that query resolves empty for them - hooks that take prebuilt flow URLs (run history, config, version history, publish, restore, delete) stay on the legacy client Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- type the empty form_schema list in the code-based extension test (pyrefly) - e2e document list queries pass numeric page/limit, now typed by the contract - drop the unused legacy put helper and InitValidateStatusResponse type - route the auto-upgrade settings dialog spec through the console transport Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Remove narrowResponse from service/datasets.ts. The dataset, external API, document and indexing calls return the generated response types, and the forwarding hooks in service/knowledge/use-create-dataset are gone: the indexing estimate, document creation, default process rule and pipeline dataset creation use the generated mutation options at their call sites. The indexing estimate payload builders move to create/step-two/creation-params, and step two sends one estimate request for its data source. The creation result, indexing estimate and external API UI types alias the contract. External knowledge API settings are a typed model with optional endpoint and API key, so the edit form reads absent values as empty. Fields the creation response never carried (the dataset icon and retrieval model in step three) use their fallbacks directly, and the document rename spec now answers with the renamed document the endpoint returns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…us/dify into refactor/web-orpc-console-calls # Conflicts: # web/models/datasets.ts
Remove narrowResponse from service/tools.ts. Collection and tool lists and the workflow tool detail go through the existing tool selectors, and the API schema parse and custom provider detail get their own: parsed operations keep an empty label when the schema gives no id or summary, and stored credentials are read by their auth type, which a provider saved without one does not have. The custom tool editor state drops the provider id the detail never returned and stores the parsed operations it actually holds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rceInfo Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Remove narrowResponse from service/plugins.ts and service/use-plugins.ts. Install, upgrade, upload and task responses use the generated types: the plugin task and status UI types derive from the contract and add only the task id the task list attaches, which the task list query now attaches too instead of assuming it. Dynamic parameter options are mapped to form options, with untranslated labels falling back to en_US as renderI18nObject does. The uploaded package card comes from a mapper for the contract manifest (pluginDeclarationToCardPluginProps), and plugin card text drops untranslated locales through toPluginText. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…us/dify into refactor/web-orpc-console-calls
Remove the last narrowResponse callers in service/debug.ts and delete the helper. The rule generator response is a typed model, and the prompt template response declares its chat and completion configs and the stop words the templates carry, which the old untyped model dropped. The instruction generator answers with a rule, code or an LLM-written object depending on the target, so its result is read through a guard. Document settings no longer cast stored source info: step two takes the file and Notion page fields it reads (StepTwoFile, StepTwoNotionPage), and the crawl options are read with type checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- rule-generate spec stubs a rule config matching RuleGenerateResponse - prompt template spec types its parameter for pyrefly - preview picker spec expects the id/name/extension picker value Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adopt main's generated oRPC console calls (#44169) in branch code: the deleted use-dataset/use-datasource/useMembers hooks become consoleQuery queries, the KnowledgeFS dataset list, scope dialog and card header keep their branch behavior, and branch specs mock the new operations instead of the removed modules. Contracts, OpenAPI markdown and oxlint suppressions are regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Summary
Replace the handwritten
get/post/put/patch/delconsole calls inweb/with the generated console contract (consoleQuery/consoleClientfrom@/service/console). The work is split into one commit per module. Where backend endpoints read query params or bodies that their OpenAPI docs did not declare, the docs were fixed so the generated contract types them.Migrated
use-log,annotation, log messages, and agent thoughts.service/common).service/use-common: everything except one broken flow, listed below.service/datasetsandservice/knowledge/use-{dataset,document,segment,metadata,create-dataset}.use-plugins(install, upgrade, upload, permission and auto-upgrade settings, debugging key, tasks, dynamic options) andplugins.ts.tools.tsanduse-tools.ts(built-in, API, workflow and MCP tools, MCP servers, app triggers).use-pipelineanduse-datasource.callByFlowTypehelper.AbortSignal), rule and instruction generation, prompt templates, and message detail.Some UI types narrow fields that backend response models declare as plain strings or loose records: enum-like statuses,
doc_form, pluginsource, locale label maps. Those responses are narrowed once at the service boundary with a documentednarrowResponsehelper (service/console/narrow-response.ts) instead of retyping every consumer. Where a UI type was simply wrong, it now aliases or follows the generated type.Bugs and mismatches the contract surfaced
204responses. Deleting an external knowledge API and retrying error docs return204. The UI only worked because the legacy fetch layer rewrote204into{result: 'success'}; callers now treat a resolved request as success.partial_member_listasstring[], but the UI sends{user_id, role}objects. It now uses the generated type./tool-provider/model/tools(the backend has no model tool provider type; the fetch and theisModelprop chain were removed).provider_type, which callers could leave unset. It now defaults totool.indexing_technique.label.server_identifier.required, Notion icons without a type (now dropped), andicon_backgroundnullability.read_at(the unread dot always renders; behaviour kept) and the conversation introduction, which lives at the top level.Not migrated (intentionally)
emailandcode.credential_id. Only non-plugin providers reach it, and none of them need credentials.plugin-auth/hooks/use-get-api), and the one-step-run iteration/loop endpoints. Each needs its call sites redesigned around ids instead of URLs.share.ts,sso.ts, and the web-app login helpers incommon.ts. They need a web-app contract client./x-versionand/x-env.Follow-ups
doc_form, pluginsource, label maps) sonarrowResponsecall sites can be dropped.json_schema_serialization_defaults_required).share.tsand the web-app helpers.Checklist
make lint && make type-check(backend) andvp staged(frontend) to appease the lint godsVerification per commit:
tsc --noEmit,vp lint,knip, the spec files that import each migrated module, and the touched backend controller tests. The full web suite was not run locally.🤖 Generated with Claude Code