From c6e9cca47fca85b45eabea88a435384530090af8 Mon Sep 17 00:00:00 2001 From: chariri Date: Fri, 26 Jun 2026 03:31:26 +0900 Subject: [PATCH 1/2] refactor(api): remove remaining legacy field remnants --- api/controllers/console/files.py | 8 +- api/controllers/console/spec.py | 16 +++- api/controllers/mcp/mcp.py | 21 ++--- api/fields/raws.py | 20 ----- api/openapi/markdown/console-openapi.md | 10 ++- api/services/summary_index_service.py | 1 + .../controllers/console/test_spec.py | 18 ++++- .../generated/api/console/spec/types.gen.ts | 10 ++- .../generated/api/console/spec/zod.gen.ts | 11 ++- packages/contracts/openapi-ts.api.config.ts | 78 ++++++++++++++++++- 10 files changed, 148 insertions(+), 45 deletions(-) delete mode 100644 api/fields/raws.py diff --git a/api/controllers/console/files.py b/api/controllers/console/files.py index 5197120c135..a81be1e77f0 100644 --- a/api/controllers/console/files.py +++ b/api/controllers/console/files.py @@ -27,6 +27,7 @@ from controllers.console.wraps import ( ) from extensions.ext_database import db from fields.file_fields import FileResponse, UploadConfig +from libs.helper import dump_response from libs.login import login_required from models import Account from services.file_service import FileService @@ -100,8 +101,7 @@ class FileApi(Resource): except services.errors.file.BlockedFileExtensionError as blocked_extension_error: raise BlockedFileExtensionError(blocked_extension_error.description) - response = FileResponse.model_validate(upload_file, from_attributes=True) - return response.model_dump(mode="json"), 201 + return dump_response(FileResponse, upload_file), 201 @console_ns.route("/files//preview") @@ -114,7 +114,7 @@ class FilePreviewApi(Resource): def get(self, current_tenant_id: str, file_id: UUID): file_id_str = str(file_id) text = FileService(db.engine).get_file_preview(file_id_str, current_tenant_id) - return {"content": text} + return TextContentResponse(content=text).model_dump(mode="json") @console_ns.route("/files/support-type") @@ -124,4 +124,4 @@ class FileSupportTypeApi(Resource): @account_initialization_required @console_ns.response(200, "Success", console_ns.models[AllowedExtensionsResponse.__name__]) def get(self): - return {"allowed_extensions": list(DOCUMENT_EXTENSIONS)} + return AllowedExtensionsResponse(allowed_extensions=list(DOCUMENT_EXTENSIONS)).model_dump(mode="json") diff --git a/api/controllers/console/spec.py b/api/controllers/console/spec.py index 27b07b4dd81..70e0d1d14ae 100644 --- a/api/controllers/console/spec.py +++ b/api/controllers/console/spec.py @@ -1,8 +1,9 @@ import logging +from collections.abc import Mapping from typing import Any from flask_restx import Resource -from pydantic import RootModel +from pydantic import Field, RootModel from controllers.common.schema import register_response_schema_models from controllers.console.wraps import ( @@ -10,6 +11,7 @@ from controllers.console.wraps import ( setup_required, ) from core.schemas.schema_manager import SchemaManager +from fields.base import ResponseModel from libs.login import login_required from . import console_ns @@ -17,11 +19,17 @@ from . import console_ns logger = logging.getLogger(__name__) -class SchemaDefinitionsResponse(RootModel[Any]): - root: Any +class SchemaDefinitionItemResponse(ResponseModel): + name: str + label: str + schema_: Mapping[str, Any] = Field(alias="schema") -register_response_schema_models(console_ns, SchemaDefinitionsResponse) +class SchemaDefinitionsResponse(RootModel[list[SchemaDefinitionItemResponse]]): + pass + + +register_response_schema_models(console_ns, SchemaDefinitionItemResponse, SchemaDefinitionsResponse) @console_ns.route("/spec/schema-definitions") diff --git a/api/controllers/mcp/mcp.py b/api/controllers/mcp/mcp.py index cda6b915018..46f9ab644b5 100644 --- a/api/controllers/mcp/mcp.py +++ b/api/controllers/mcp/mcp.py @@ -2,11 +2,11 @@ from typing import Any, Union from flask import Response from flask_restx import Resource -from pydantic import BaseModel, Field, ValidationError +from pydantic import BaseModel, Field, RootModel, ValidationError from sqlalchemy import select from sqlalchemy.orm import Session, sessionmaker -from controllers.common.schema import register_schema_model +from controllers.common.schema import register_response_schema_models, register_schema_model from controllers.mcp import mcp_ns from core.mcp import types as mcp_types from core.mcp.server.streamable_http import handle_mcp_request @@ -33,7 +33,12 @@ class MCPRequestPayload(BaseModel): id: int | str | None = Field(default=None, description="Request ID for tracking responses") +class MCPJSONRPCResponse(RootModel[mcp_types.JSONRPCResponse | mcp_types.JSONRPCError]): + pass + + register_schema_model(mcp_ns, MCPRequestPayload) +register_response_schema_models(mcp_ns, MCPJSONRPCResponse) @mcp_ns.route("/server//mcp") @@ -42,13 +47,10 @@ class MCPAppApi(Resource): @mcp_ns.doc("handle_mcp_request") @mcp_ns.doc(description="Handle Model Context Protocol (MCP) requests for a specific server") @mcp_ns.doc(params={"server_code": "Unique identifier for the MCP server"}) - @mcp_ns.doc( - responses={ - 200: "MCP response successfully processed", - 400: "Invalid MCP request or parameters", - 404: "Server or app not found", - } - ) + @mcp_ns.response(200, "MCP JSON-RPC response", mcp_ns.models[MCPJSONRPCResponse.__name__]) + @mcp_ns.response(202, "MCP notification accepted") + @mcp_ns.response(400, "Invalid MCP request or parameters") + @mcp_ns.response(404, "Server or app not found") def post(self, server_code: str): """Handle MCP requests for a specific server. @@ -64,6 +66,7 @@ class MCPAppApi(Resource): Raises: ValidationError: Invalid request format or parameters """ + # response-contract:ignore MCP route returns Flask Response from JSON-RPC handler args = MCPRequestPayload.model_validate(mcp_ns.payload or {}) request_id: Union[int, str] | None = args.id mcp_request = self._parse_mcp_request(args.model_dump(exclude_none=True)) diff --git a/api/fields/raws.py b/api/fields/raws.py deleted file mode 100644 index c7e047626f1..00000000000 --- a/api/fields/raws.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import override - -from flask_restx import fields - -from graphon.file import File - - -class FilesContainedField(fields.Raw): - @override - def format(self, value): - return self._format_file_object(value) - - def _format_file_object(self, v): - if isinstance(v, File): - return v.model_dump() - if isinstance(v, dict): - return {k: self._format_file_object(vv) for k, vv in v.items()} - if isinstance(v, list): - return [self._format_file_object(vv) for vv in v] - return v diff --git a/api/openapi/markdown/console-openapi.md b/api/openapi/markdown/console-openapi.md index b3a0b8a6a71..58bb08f563d 100644 --- a/api/openapi/markdown/console-openapi.md +++ b/api/openapi/markdown/console-openapi.md @@ -19026,11 +19026,19 @@ Model class for provider quota configuration. | last_id | string | | No | | limit | integer,
**Default:** 20 | | No | +#### SchemaDefinitionItemResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| label | string | | Yes | +| name | string | | Yes | +| schema | object | | Yes | + #### SchemaDefinitionsResponse | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| SchemaDefinitionsResponse | | | | +| SchemaDefinitionsResponse | array | | | #### SegmentAttachmentResponse diff --git a/api/services/summary_index_service.py b/api/services/summary_index_service.py index 1657cfdd256..97aee92812c 100644 --- a/api/services/summary_index_service.py +++ b/api/services/summary_index_service.py @@ -1423,6 +1423,7 @@ class SummaryIndexService: - generating: Number of summaries being generated - error: Number of summaries with errors - not_started: Number of segments without summary records + - timeout: Number of summaries that timed out - summaries: List of summary records with status and content preview """ from services.dataset_service import SegmentService diff --git a/api/tests/unit_tests/controllers/console/test_spec.py b/api/tests/unit_tests/controllers/console/test_spec.py index 84c2004ec70..8b79bcd82fc 100644 --- a/api/tests/unit_tests/controllers/console/test_spec.py +++ b/api/tests/unit_tests/controllers/console/test_spec.py @@ -9,7 +9,17 @@ class TestSpecSchemaDefinitionsApi: api = spec_module.SpecSchemaDefinitionsApi() method = unwrap(api.get) - schema_definitions = [{"type": "string"}] + schema_definitions = [ + { + "name": "conversation-variable", + "label": "Conversation variable", + "schema": { + "type": "object", + "properties": {"name": {"type": "string"}}, + "required": ["name"], + }, + } + ] with patch.object( spec_module, @@ -21,6 +31,12 @@ class TestSpecSchemaDefinitionsApi: assert status == 200 assert resp == schema_definitions + assert spec_module.SchemaDefinitionsResponse.model_validate(resp).model_dump(mode="json") == schema_definitions + + def test_get_documents_tight_response_model(self): + response = spec_module.SpecSchemaDefinitionsApi.get.__apidoc__["responses"]["200"] + + assert response[1].name == spec_module.SchemaDefinitionsResponse.__name__ def test_get_exception_returns_empty_list(self): api = spec_module.SpecSchemaDefinitionsApi() diff --git a/packages/contracts/generated/api/console/spec/types.gen.ts b/packages/contracts/generated/api/console/spec/types.gen.ts index e7b9c0ea9b2..853fb2cccb1 100644 --- a/packages/contracts/generated/api/console/spec/types.gen.ts +++ b/packages/contracts/generated/api/console/spec/types.gen.ts @@ -4,7 +4,15 @@ export type ClientOptions = { baseUrl: `${string}://${string}/console/api` | (string & {}) } -export type SchemaDefinitionsResponse = unknown +export type SchemaDefinitionsResponse = Array + +export type SchemaDefinitionItemResponse = { + label: string + name: string + schema: { + [key: string]: unknown + } +} export type GetSpecSchemaDefinitionsData = { body?: never diff --git a/packages/contracts/generated/api/console/spec/zod.gen.ts b/packages/contracts/generated/api/console/spec/zod.gen.ts index 8fc487d5ac4..b1135d7f34d 100644 --- a/packages/contracts/generated/api/console/spec/zod.gen.ts +++ b/packages/contracts/generated/api/console/spec/zod.gen.ts @@ -2,10 +2,19 @@ import * as z from 'zod' +/** + * SchemaDefinitionItemResponse + */ +export const zSchemaDefinitionItemResponse = z.object({ + label: z.string(), + name: z.string(), + schema: z.record(z.string(), z.unknown()), +}) + /** * SchemaDefinitionsResponse */ -export const zSchemaDefinitionsResponse = z.unknown() +export const zSchemaDefinitionsResponse = z.array(zSchemaDefinitionItemResponse) /** * Success diff --git a/packages/contracts/openapi-ts.api.config.ts b/packages/contracts/openapi-ts.api.config.ts index 8fce8a25bd3..1adbf4fda8e 100644 --- a/packages/contracts/openapi-ts.api.config.ts +++ b/packages/contracts/openapi-ts.api.config.ts @@ -10,13 +10,21 @@ type SwaggerSchema = JsonObject & { $ref?: string } +type OpenApiMediaType = JsonObject & { + schema?: SwaggerSchema +} + +type OpenApiResponse = JsonObject & { + content?: Record +} + type OpenApiComponents = JsonObject & { schemas?: Record } type SwaggerOperation = JsonObject & { operationId?: string - responses?: Record + responses?: Record } type SwaggerDocument = JsonObject & { @@ -52,6 +60,17 @@ const currentDir = path.dirname(fileURLToPath(import.meta.url)) const apiOpenApiDir = path.resolve(currentDir, 'openapi') const operationMethods = new Set(['delete', 'get', 'patch', 'post', 'put']) +const pydanticDecimalStringPattern = '^(?!^[-+.]*$)[+-]?0*\\d*\\.?\\d*$' +const codegenSafeDecimalStringPattern = '^(?![-+.]*$)[+-]?0*\\d*\\.?\\d*$' + +const opaqueJsonContent = (): Record => ({ + 'application/json': { + schema: { + additionalProperties: true, + type: 'object', + }, + }, +}) const apiSpecs: ApiSpec[] = [ { filename: 'console-openapi.json', name: 'console' }, @@ -182,6 +201,46 @@ const addOperationIds = (document: SwaggerDocument) => { } } +const isOpaqueContractResponse = (response: OpenApiResponse) => { + const content = response.content + if (!isObject(content)) + return false + + return Object.entries(content).some(([mediaType, media]) => { + if (!isObject(media)) + return false + + return (mediaType === 'application/json' || mediaType === 'text/event-stream') && !('schema' in media) + }) +} + +const hasOpaqueContractSuccessResponse = (operation: SwaggerOperation) => { + return Object.entries(operation.responses ?? {}).some(([status, response]) => { + return /^2\d\d$/.test(status) && isObject(response) && isOpaqueContractResponse(response) + }) +} + +const normalizeOpaqueContractResponses = (document: SwaggerDocument) => { + // Some backend endpoints has no schema (e.g. external) and will trap heyapi here + // So we forge an opaque schema here + for (const pathItem of Object.values(document.paths ?? {})) { + for (const [method, operation] of Object.entries(pathItem)) { + if (!operationMethods.has(method) || !isObject(operation)) + continue + + const swaggerOperation = operation as SwaggerOperation + if (!hasOpaqueContractSuccessResponse(swaggerOperation)) + continue + + Object.values(swaggerOperation.responses ?? {}) + .filter(response => isObject(response) && isOpaqueContractResponse(response)) + .forEach((response) => { + response.content = opaqueJsonContent() + }) + } + } +} + const hasSuccessResponse = (operation: SwaggerOperation) => { return Object.entries(operation.responses ?? {}).some(([status, response]) => { if (!/^2\d\d$/.test(status)) @@ -215,6 +274,7 @@ const filterContractOperations = (document: SwaggerDocument) => { } const normalizeApiSwagger = (document: SwaggerDocument) => { + normalizeOpaqueContractResponses(document) filterContractOperations(document) addOperationIds(document) @@ -380,10 +440,20 @@ const createApiConfig = (job: ApiJob): UserConfig => ({ 'name': 'zod', '~resolvers': { string: (ctx) => { - if (ctx.schema.format !== 'binary') - return undefined + if (ctx.schema.format === 'binary') + return $(ctx.symbols.z).attr('custom').call().generic($.type.or($.type('Blob'), $.type('File'))) - return $(ctx.symbols.z).attr('custom').call().generic($.type.or($.type('Blob'), $.type('File'))) + if (ctx.schema.pattern === pydanticDecimalStringPattern) { + // the pydantic generated regex will emit error like + // regexp/no-useless-assertions, so patch the regex here + return $(ctx.symbols.z) + .attr('string') + .call() + .attr('regex') + .call($.regexp(codegenSafeDecimalStringPattern)) + } + + return undefined }, }, }, From cc795d13a2d37480e654deb12c5538a16366eb0f Mon Sep 17 00:00:00 2001 From: chariri Date: Fri, 26 Jun 2026 03:31:58 +0900 Subject: [PATCH 2/2] fix(api): document message responses as serialized contracts --- api/controllers/console/app/message.py | 6 ++++- api/core/rag/extractor/extract_processor.py | 26 ++++++++++++++++--- api/openapi/markdown/console-openapi.md | 7 +++-- .../generated/api/console/agent/types.gen.ts | 7 +++-- .../generated/api/console/agent/zod.gen.ts | 7 +++-- .../generated/api/console/apps/types.gen.ts | 7 +++-- .../generated/api/console/apps/zod.gen.ts | 7 +++-- .../api/console/installed-apps/types.gen.ts | 1 - .../api/console/installed-apps/zod.gen.ts | 1 - .../configure/components/preview/chat.tsx | 8 +----- 10 files changed, 44 insertions(+), 33 deletions(-) diff --git a/api/controllers/console/app/message.py b/api/controllers/console/app/message.py index 195a41f2888..f987ecca745 100644 --- a/api/controllers/console/app/message.py +++ b/api/controllers/console/app/message.py @@ -167,12 +167,16 @@ register_schema_models( ChatMessagesQuery, MessageFeedbackPayload, FeedbackExportQuery, +) +register_response_schema_models( + console_ns, AnnotationCountResponse, SuggestedQuestionsResponse, MessageDetailResponse, MessageInfiniteScrollPaginationResponse, + SimpleResultResponse, + TextFileResponse, ) -register_response_schema_models(console_ns, SimpleResultResponse, TextFileResponse) @console_ns.route("/apps//chat-messages") diff --git a/api/core/rag/extractor/extract_processor.py b/api/core/rag/extractor/extract_processor.py index 4d11ebe5005..36d879427a5 100644 --- a/api/core/rag/extractor/extract_processor.py +++ b/api/core/rag/extractor/extract_processor.py @@ -1,7 +1,7 @@ import re import tempfile from pathlib import Path -from typing import Union +from typing import Literal, overload from urllib.parse import unquote from configs import dify_config @@ -40,10 +40,22 @@ USER_AGENT = ( class ExtractProcessor: + @overload + @classmethod + def load_from_upload_file( + cls, upload_file: UploadFile, return_text: Literal[True], is_automatic: bool = False + ) -> str: ... + + @overload + @classmethod + def load_from_upload_file( + cls, upload_file: UploadFile, return_text: Literal[False] = False, is_automatic: bool = False + ) -> list[Document]: ... + @classmethod def load_from_upload_file( cls, upload_file: UploadFile, return_text: bool = False, is_automatic: bool = False - ) -> Union[list[Document], str]: + ) -> list[Document] | str: extract_setting = ExtractSetting( datasource_type=DatasourceType.FILE, upload_file=upload_file, document_model="text_model" ) @@ -53,8 +65,16 @@ class ExtractProcessor: else: return cls.extract(extract_setting, is_automatic) + @overload @classmethod - def load_from_url(cls, url: str, return_text: bool = False) -> Union[list[Document], str]: + def load_from_url(cls, url: str, return_text: Literal[True]) -> str: ... + + @overload + @classmethod + def load_from_url(cls, url: str, return_text: Literal[False] = False) -> list[Document]: ... + + @classmethod + def load_from_url(cls, url: str, return_text: bool = False) -> list[Document] | str: response = remote_fetcher.make_request("GET", url, headers={"User-Agent": USER_AGENT}) with tempfile.TemporaryDirectory() as temp_dir: diff --git a/api/openapi/markdown/console-openapi.md b/api/openapi/markdown/console-openapi.md index 58bb08f563d..28837e9dd3b 100644 --- a/api/openapi/markdown/console-openapi.md +++ b/api/openapi/markdown/console-openapi.md @@ -13429,7 +13429,6 @@ Soft lifecycle state for Agent records. | created_at | integer | | No | | files | [ string ] | | Yes | | id | string | | Yes | -| message_chain_id | string | | No | | message_id | string | | Yes | | observation | string | | No | | position | integer | | Yes | @@ -14540,8 +14539,8 @@ Enum class for configurate method of provider model. | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | | annotation_create_account | [SimpleAccount](#simpleaccount) | | No | +| annotation_id | string | | Yes | | created_at | integer | | No | -| id | string | | Yes | #### ConversationDetail @@ -17079,6 +17078,7 @@ Enum class for large language model mode. | agent_thoughts | [ [AgentThought](#agentthought) ] | | No | | annotation | [ConversationAnnotation](#conversationannotation) | | No | | annotation_hit_history | [ConversationAnnotationHitHistory](#conversationannotationhithistory) | | No | +| answer | string | | Yes | | answer_tokens | integer | | No | | conversation_id | string | | Yes | | created_at | integer | | No | @@ -17092,12 +17092,11 @@ Enum class for large language model mode. | inputs | object | | Yes | | message | [JSONValue](#jsonvalue) | | No | | message_files | [ [MessageFile](#messagefile) ] | | No | -| message_metadata_dict | [JSONValue](#jsonvalue) | | No | | message_tokens | integer | | No | +| metadata | [JSONValue](#jsonvalue) | | No | | parent_message_id | string | | No | | provider_response_latency | number | | No | | query | string | | Yes | -| re_sign_file_url_answer | string | | Yes | | status | string | | Yes | | workflow_run_id | string | | No | diff --git a/packages/contracts/generated/api/console/agent/types.gen.ts b/packages/contracts/generated/api/console/agent/types.gen.ts index 43119c4f1f4..4026c0d35eb 100644 --- a/packages/contracts/generated/api/console/agent/types.gen.ts +++ b/packages/contracts/generated/api/console/agent/types.gen.ts @@ -269,6 +269,7 @@ export type MessageDetailResponse = { agent_thoughts?: Array annotation?: ConversationAnnotation | null annotation_hit_history?: ConversationAnnotationHitHistory | null + answer: string answer_tokens?: number | null conversation_id: string created_at?: number | null @@ -284,12 +285,11 @@ export type MessageDetailResponse = { } message?: JsonValue | null message_files?: Array - message_metadata_dict?: JsonValue | null message_tokens?: number | null + metadata?: JsonValue | null parent_message_id?: string | null provider_response_latency?: number | null query: string - re_sign_file_url_answer: string status: string workflow_run_id?: string | null } @@ -723,7 +723,6 @@ export type AgentThought = { created_at?: number | null files: Array id: string - message_chain_id?: string | null message_id: string observation?: string | null position: number @@ -743,8 +742,8 @@ export type ConversationAnnotation = { export type ConversationAnnotationHitHistory = { annotation_create_account?: SimpleAccount | null + annotation_id: string created_at?: number | null - id: string } export type HumanInputContent = { diff --git a/packages/contracts/generated/api/console/agent/zod.gen.ts b/packages/contracts/generated/api/console/agent/zod.gen.ts index d7f5681ffc4..45a68beb8a6 100644 --- a/packages/contracts/generated/api/console/agent/zod.gen.ts +++ b/packages/contracts/generated/api/console/agent/zod.gen.ts @@ -570,7 +570,6 @@ export const zAgentThought = z.object({ created_at: z.int().nullish(), files: z.array(z.string()), id: z.string(), - message_chain_id: z.string().nullish(), message_id: z.string(), observation: z.string().nullish(), position: z.int(), @@ -1056,8 +1055,8 @@ export const zConversationAnnotation = z.object({ */ export const zConversationAnnotationHitHistory = z.object({ annotation_create_account: zSimpleAccount.nullish(), + annotation_id: z.string(), created_at: z.int().nullish(), - id: z.string(), }) /** @@ -2035,6 +2034,7 @@ export const zMessageDetailResponse = z.object({ agent_thoughts: z.array(zAgentThought).optional(), annotation: zConversationAnnotation.nullish(), annotation_hit_history: zConversationAnnotationHitHistory.nullish(), + answer: z.string(), answer_tokens: z.int().nullish(), conversation_id: z.string(), created_at: z.int().nullish(), @@ -2048,12 +2048,11 @@ export const zMessageDetailResponse = z.object({ inputs: z.record(z.string(), zJsonValue), message: zJsonValue.nullish(), message_files: z.array(zMessageFile).optional(), - message_metadata_dict: zJsonValue.nullish(), message_tokens: z.int().nullish(), + metadata: zJsonValue.nullish(), parent_message_id: z.string().nullish(), provider_response_latency: z.number().nullish(), query: z.string(), - re_sign_file_url_answer: z.string(), status: z.string(), workflow_run_id: z.string().nullish(), }) diff --git a/packages/contracts/generated/api/console/apps/types.gen.ts b/packages/contracts/generated/api/console/apps/types.gen.ts index 9e79518f3cd..3a046dc4727 100644 --- a/packages/contracts/generated/api/console/apps/types.gen.ts +++ b/packages/contracts/generated/api/console/apps/types.gen.ts @@ -472,6 +472,7 @@ export type MessageDetailResponse = { agent_thoughts?: Array annotation?: ConversationAnnotation | null annotation_hit_history?: ConversationAnnotationHitHistory | null + answer: string answer_tokens?: number | null conversation_id: string created_at?: number | null @@ -487,12 +488,11 @@ export type MessageDetailResponse = { } message?: JsonValue | null message_files?: Array - message_metadata_dict?: JsonValue | null message_tokens?: number | null + metadata?: JsonValue | null parent_message_id?: string | null provider_response_latency?: number | null query: string - re_sign_file_url_answer: string status: string workflow_run_id?: string | null } @@ -1498,7 +1498,6 @@ export type AgentThought = { created_at?: number | null files: Array id: string - message_chain_id?: string | null message_id: string observation?: string | null position: number @@ -1518,8 +1517,8 @@ export type ConversationAnnotation = { export type ConversationAnnotationHitHistory = { annotation_create_account?: SimpleAccount | null + annotation_id: string created_at?: number | null - id: string } export type HumanInputContent = { diff --git a/packages/contracts/generated/api/console/apps/zod.gen.ts b/packages/contracts/generated/api/console/apps/zod.gen.ts index 9b86fda0a62..c881edbc9f1 100644 --- a/packages/contracts/generated/api/console/apps/zod.gen.ts +++ b/packages/contracts/generated/api/console/apps/zod.gen.ts @@ -1150,7 +1150,6 @@ export const zAgentThought = z.object({ created_at: z.int().nullish(), files: z.array(z.string()), id: z.string(), - message_chain_id: z.string().nullish(), message_id: z.string(), observation: z.string().nullish(), position: z.int(), @@ -1371,8 +1370,8 @@ export const zConversationAnnotation = z.object({ */ export const zConversationAnnotationHitHistory = z.object({ annotation_create_account: zSimpleAccount.nullish(), + annotation_id: z.string(), created_at: z.int().nullish(), - id: z.string(), }) /** @@ -3455,6 +3454,7 @@ export const zMessageDetailResponse = z.object({ agent_thoughts: z.array(zAgentThought).optional(), annotation: zConversationAnnotation.nullish(), annotation_hit_history: zConversationAnnotationHitHistory.nullish(), + answer: z.string(), answer_tokens: z.int().nullish(), conversation_id: z.string(), created_at: z.int().nullish(), @@ -3468,12 +3468,11 @@ export const zMessageDetailResponse = z.object({ inputs: z.record(z.string(), zJsonValue), message: zJsonValue.nullish(), message_files: z.array(zMessageFile).optional(), - message_metadata_dict: zJsonValue.nullish(), message_tokens: z.int().nullish(), + metadata: zJsonValue.nullish(), parent_message_id: z.string().nullish(), provider_response_latency: z.number().nullish(), query: z.string(), - re_sign_file_url_answer: z.string(), status: z.string(), workflow_run_id: z.string().nullish(), }) diff --git a/packages/contracts/generated/api/console/installed-apps/types.gen.ts b/packages/contracts/generated/api/console/installed-apps/types.gen.ts index f9a5eb01edc..61b1303d5b5 100644 --- a/packages/contracts/generated/api/console/installed-apps/types.gen.ts +++ b/packages/contracts/generated/api/console/installed-apps/types.gen.ts @@ -246,7 +246,6 @@ export type AgentThought = { created_at?: number | null files: Array id: string - message_chain_id?: string | null message_id: string observation?: string | null position: number diff --git a/packages/contracts/generated/api/console/installed-apps/zod.gen.ts b/packages/contracts/generated/api/console/installed-apps/zod.gen.ts index a4556058506..53439d132c8 100644 --- a/packages/contracts/generated/api/console/installed-apps/zod.gen.ts +++ b/packages/contracts/generated/api/console/installed-apps/zod.gen.ts @@ -266,7 +266,6 @@ export const zAgentThought = z.object({ created_at: z.int().nullish(), files: z.array(z.string()), id: z.string(), - message_chain_id: z.string().nullish(), message_id: z.string(), observation: z.string().nullish(), position: z.int(), diff --git a/web/features/agent-v2/agent-detail/configure/components/preview/chat.tsx b/web/features/agent-v2/agent-detail/configure/components/preview/chat.tsx index a3127b4bd49..9ad0555d196 100644 --- a/web/features/agent-v2/agent-detail/configure/components/preview/chat.tsx +++ b/web/features/agent-v2/agent-detail/configure/components/preview/chat.tsx @@ -217,14 +217,8 @@ const toFeedback = (feedback: NonNullable[nu } } -type AgentDebugMessageWithLegacyAnswer = MessageDetailResponse & { - answer?: string | null -} - const getAgentDebugMessageAnswer = (message: MessageDetailResponse) => { - const legacyAnswer = (message as AgentDebugMessageWithLegacyAnswer).answer - - return message.re_sign_file_url_answer ?? legacyAnswer ?? '' + return message.answer ?? '' } function getFormattedAgentDebugChatTree(messages: MessageDetailResponse[]): ChatItemInTree[] {