Signed-off-by: -LAN- <laipz8200@outlook.com>tags/1.5.0
| @@ -6,7 +6,7 @@ import json | |||
| import logging | |||
| from typing import Optional, Union | |||
| from sqlalchemy import func, select | |||
| from sqlalchemy import select | |||
| from sqlalchemy.engine import Engine | |||
| from sqlalchemy.orm import sessionmaker | |||
| @@ -146,20 +146,7 @@ class SQLAlchemyWorkflowExecutionRepository(WorkflowExecutionRepository): | |||
| db_model.workflow_id = domain_model.workflow_id | |||
| db_model.triggered_from = self._triggered_from | |||
| # Check if this is a new record | |||
| with self._session_factory() as session: | |||
| existing = session.scalar(select(WorkflowRun).where(WorkflowRun.id == domain_model.id_)) | |||
| if not existing: | |||
| # For new records, get the next sequence number | |||
| stmt = select(func.max(WorkflowRun.sequence_number)).where( | |||
| WorkflowRun.app_id == self._app_id, | |||
| WorkflowRun.tenant_id == self._tenant_id, | |||
| ) | |||
| max_sequence = session.scalar(stmt) | |||
| db_model.sequence_number = (max_sequence or 0) + 1 | |||
| else: | |||
| # For updates, keep the existing sequence number | |||
| db_model.sequence_number = existing.sequence_number | |||
| # No sequence number generation needed anymore | |||
| db_model.type = domain_model.workflow_type | |||
| db_model.version = domain_model.workflow_version | |||
| @@ -19,7 +19,6 @@ workflow_run_for_log_fields = { | |||
| workflow_run_for_list_fields = { | |||
| "id": fields.String, | |||
| "sequence_number": fields.Integer, | |||
| "version": fields.String, | |||
| "status": fields.String, | |||
| "elapsed_time": fields.Float, | |||
| @@ -36,7 +35,6 @@ advanced_chat_workflow_run_for_list_fields = { | |||
| "id": fields.String, | |||
| "conversation_id": fields.String, | |||
| "message_id": fields.String, | |||
| "sequence_number": fields.Integer, | |||
| "version": fields.String, | |||
| "status": fields.String, | |||
| "elapsed_time": fields.Float, | |||
| @@ -63,7 +61,6 @@ workflow_run_pagination_fields = { | |||
| workflow_run_detail_fields = { | |||
| "id": fields.String, | |||
| "sequence_number": fields.Integer, | |||
| "version": fields.String, | |||
| "graph": fields.Raw(attribute="graph_dict"), | |||
| "inputs": fields.Raw(attribute="inputs_dict"), | |||
| @@ -0,0 +1,66 @@ | |||
| """remove sequence_number from workflow_runs | |||
| Revision ID: 0ab65e1cc7fa | |||
| Revises: 4474872b0ee6 | |||
| Create Date: 2025-06-19 16:33:13.377215 | |||
| """ | |||
| from alembic import op | |||
| import models as models | |||
| import sqlalchemy as sa | |||
| # revision identifiers, used by Alembic. | |||
| revision = '0ab65e1cc7fa' | |||
| down_revision = '4474872b0ee6' | |||
| branch_labels = None | |||
| depends_on = None | |||
| def upgrade(): | |||
| # ### commands auto generated by Alembic - please adjust! ### | |||
| with op.batch_alter_table('workflow_runs', schema=None) as batch_op: | |||
| batch_op.drop_index(batch_op.f('workflow_run_tenant_app_sequence_idx')) | |||
| batch_op.drop_column('sequence_number') | |||
| # ### end Alembic commands ### | |||
| def downgrade(): | |||
| # ### commands auto generated by Alembic - please adjust! ### | |||
| # WARNING: This downgrade CANNOT recover the original sequence_number values! | |||
| # The original sequence numbers are permanently lost after the upgrade. | |||
| # This downgrade will regenerate sequence numbers based on created_at order, | |||
| # which may result in different values than the original sequence numbers. | |||
| # | |||
| # If you need to preserve original sequence numbers, use the alternative | |||
| # migration approach that creates a backup table before removal. | |||
| # Step 1: Add sequence_number column as nullable first | |||
| with op.batch_alter_table('workflow_runs', schema=None) as batch_op: | |||
| batch_op.add_column(sa.Column('sequence_number', sa.INTEGER(), autoincrement=False, nullable=True)) | |||
| # Step 2: Populate sequence_number values based on created_at order within each app | |||
| # NOTE: This recreates sequence numbering logic but values will be different | |||
| # from the original sequence numbers that were removed in the upgrade | |||
| connection = op.get_bind() | |||
| connection.execute(sa.text(""" | |||
| UPDATE workflow_runs | |||
| SET sequence_number = subquery.row_num | |||
| FROM ( | |||
| SELECT id, ROW_NUMBER() OVER ( | |||
| PARTITION BY tenant_id, app_id | |||
| ORDER BY created_at, id | |||
| ) as row_num | |||
| FROM workflow_runs | |||
| ) subquery | |||
| WHERE workflow_runs.id = subquery.id | |||
| """)) | |||
| # Step 3: Make the column NOT NULL and add the index | |||
| with op.batch_alter_table('workflow_runs', schema=None) as batch_op: | |||
| batch_op.alter_column('sequence_number', nullable=False) | |||
| batch_op.create_index(batch_op.f('workflow_run_tenant_app_sequence_idx'), ['tenant_id', 'app_id', 'sequence_number'], unique=False) | |||
| # ### end Alembic commands ### | |||
| @@ -386,7 +386,7 @@ class WorkflowRun(Base): | |||
| - id (uuid) Run ID | |||
| - tenant_id (uuid) Workspace ID | |||
| - app_id (uuid) App ID | |||
| - sequence_number (int) Auto-increment sequence number, incremented within the App, starting from 1 | |||
| - workflow_id (uuid) Workflow ID | |||
| - type (string) Workflow type | |||
| - triggered_from (string) Trigger source | |||
| @@ -419,13 +419,12 @@ class WorkflowRun(Base): | |||
| __table_args__ = ( | |||
| db.PrimaryKeyConstraint("id", name="workflow_run_pkey"), | |||
| db.Index("workflow_run_triggerd_from_idx", "tenant_id", "app_id", "triggered_from"), | |||
| db.Index("workflow_run_tenant_app_sequence_idx", "tenant_id", "app_id", "sequence_number"), | |||
| ) | |||
| id: Mapped[str] = mapped_column(StringUUID, server_default=db.text("uuid_generate_v4()")) | |||
| tenant_id: Mapped[str] = mapped_column(StringUUID) | |||
| app_id: Mapped[str] = mapped_column(StringUUID) | |||
| sequence_number: Mapped[int] = mapped_column() | |||
| workflow_id: Mapped[str] = mapped_column(StringUUID) | |||
| type: Mapped[str] = mapped_column(db.String(255)) | |||
| triggered_from: Mapped[str] = mapped_column(db.String(255)) | |||
| @@ -485,7 +484,6 @@ class WorkflowRun(Base): | |||
| "id": self.id, | |||
| "tenant_id": self.tenant_id, | |||
| "app_id": self.app_id, | |||
| "sequence_number": self.sequence_number, | |||
| "workflow_id": self.workflow_id, | |||
| "type": self.type, | |||
| "triggered_from": self.triggered_from, | |||
| @@ -511,7 +509,6 @@ class WorkflowRun(Base): | |||
| id=data.get("id"), | |||
| tenant_id=data.get("tenant_id"), | |||
| app_id=data.get("app_id"), | |||
| sequence_number=data.get("sequence_number"), | |||
| workflow_id=data.get("workflow_id"), | |||
| type=data.get("type"), | |||
| triggered_from=data.get("triggered_from"), | |||
| @@ -163,7 +163,6 @@ def real_workflow_run(): | |||
| workflow_run.tenant_id = "test-tenant-id" | |||
| workflow_run.app_id = "test-app-id" | |||
| workflow_run.workflow_id = "test-workflow-id" | |||
| workflow_run.sequence_number = 1 | |||
| workflow_run.type = "chat" | |||
| workflow_run.triggered_from = "app-run" | |||
| workflow_run.version = "1.0" | |||
| @@ -152,7 +152,6 @@ Chat applications support session persistence, allowing previous chat history to | |||
| - `data` (object) detail | |||
| - `id` (string) Unique ID of workflow execution | |||
| - `workflow_id` (string) ID of related workflow | |||
| - `sequence_number` (int) Self-increasing serial number, self-increasing in the App, starting from 1 | |||
| - `created_at` (timestamp) Creation timestamp, e.g., 1705395332 | |||
| - `event: node_started` node execution started | |||
| - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API | |||
| @@ -287,7 +286,7 @@ Chat applications support session persistence, allowing previous chat history to | |||
| ### Streaming Mode | |||
| <CodeGroup title="Response"> | |||
| ```streaming {{ title: 'Response' }} | |||
| data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "sequence_number": 1, "created_at": 1679586595}} | |||
| data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "created_at": 1679586595}} | |||
| data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}} | |||
| data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}} | |||
| data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": "1", "created_at": 1679586595, "finished_at": 1679976595}} | |||
| @@ -152,7 +152,6 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from | |||
| - `data` (object) 詳細 | |||
| - `id` (string) ワークフロー実行の一意ID | |||
| - `workflow_id` (string) 関連ワークフローのID | |||
| - `sequence_number` (int) 自己増加シリアル番号、アプリ内で自己増加し、1から始まります | |||
| - `created_at` (timestamp) 作成タイムスタンプ、例:1705395332 | |||
| - `event: node_started` ノード実行が開始 | |||
| - `task_id` (string) タスクID、リクエスト追跡と以下のStop Generate APIに使用 | |||
| @@ -287,7 +286,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from | |||
| ### ストリーミングモード | |||
| <CodeGroup title="応答"> | |||
| ```streaming {{ title: '応答' }} | |||
| data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "sequence_number": 1, "created_at": 1679586595}} | |||
| data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "created_at": 1679586595}} | |||
| data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}} | |||
| data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}} | |||
| data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": "1", "created_at": 1679586595, "finished_at": 1679976595}} | |||
| @@ -153,7 +153,6 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' | |||
| - `data` (object) 详细内容 | |||
| - `id` (string) workflow 执行 ID | |||
| - `workflow_id` (string) 关联 Workflow ID | |||
| - `sequence_number` (int) 自增序号,App 内自增,从 1 开始 | |||
| - `created_at` (timestamp) 开始时间 | |||
| - `event: node_started` node 开始执行 | |||
| - `task_id` (string) 任务 ID,用于请求跟踪和下方的停止响应接口 | |||
| @@ -297,7 +296,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' | |||
| ### 流式模式 | |||
| <CodeGroup title="Response"> | |||
| ```streaming {{ title: 'Response' }} | |||
| data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "sequence_number": 1, "created_at": 1679586595}} | |||
| data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "created_at": 1679586595}} | |||
| data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}} | |||
| data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}} | |||
| data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": "1", "created_at": 1679586595, "finished_at": 1679976595}} | |||
| @@ -103,7 +103,6 @@ Workflow applications offers non-session support and is ideal for translation, a | |||
| - `data` (object) detail | |||
| - `id` (string) Unique ID of workflow execution | |||
| - `workflow_id` (string) ID of related workflow | |||
| - `sequence_number` (int) Self-increasing serial number, self-increasing in the App, starting from 1 | |||
| - `created_at` (timestamp) Creation timestamp, e.g., 1705395332 | |||
| - `event: node_started` node execution started | |||
| - `task_id` (string) Task ID, used for request tracking and the below Stop Generate API | |||
| @@ -241,7 +240,7 @@ Workflow applications offers non-session support and is ideal for translation, a | |||
| ### Streaming Mode | |||
| <CodeGroup title="Response"> | |||
| ```streaming {{ title: 'Response' }} | |||
| data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "sequence_number": 1, "created_at": 1679586595}} | |||
| data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "created_at": 1679586595}} | |||
| data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}} | |||
| data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}} | |||
| data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": "1", "created_at": 1679586595, "finished_at": 1679976595}} | |||
| @@ -104,7 +104,6 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from | |||
| - `data` (object) 詳細 | |||
| - `id` (string) ワークフロー実行の一意の ID | |||
| - `workflow_id` (string) 関連するワークフローの ID | |||
| - `sequence_number` (int) 自己増加シリアル番号、アプリ内で自己増加し、1 から始まります | |||
| - `created_at` (timestamp) 作成タイムスタンプ、例:1705395332 | |||
| - `event: node_started` ノード実行開始 | |||
| - `task_id` (string) タスク ID、リクエスト追跡と以下の Stop Generate API に使用 | |||
| @@ -242,7 +241,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from | |||
| ### ストリーミングモード | |||
| <CodeGroup title="応答"> | |||
| ```streaming {{ title: '応答' }} | |||
| data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "sequence_number": 1, "created_at": 1679586595}} | |||
| data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "created_at": 1679586595}} | |||
| data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}} | |||
| data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}} | |||
| data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": "1", "created_at": 1679586595, "finished_at": 1679976595}} | |||
| @@ -98,7 +98,6 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等 | |||
| - `data` (object) 详细内容 | |||
| - `id` (string) workflow 执行 ID | |||
| - `workflow_id` (string) 关联 Workflow ID | |||
| - `sequence_number` (int) 自增序号,App 内自增,从 1 开始 | |||
| - `created_at` (timestamp) 开始时间 | |||
| - `event: node_started` node 开始执行 | |||
| - `task_id` (string) 任务 ID,用于请求跟踪和下方的停止响应接口 | |||
| @@ -232,7 +231,7 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等 | |||
| ### Streaming Mode | |||
| <CodeGroup title="Response"> | |||
| ```streaming {{ title: 'Response' }} | |||
| data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "sequence_number": 1, "created_at": 1679586595}} | |||
| data: {"event": "workflow_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "created_at": 1679586595}} | |||
| data: {"event": "node_started", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "created_at": 1679586595}} | |||
| data: {"event": "node_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "node_id": "dfjasklfjdslag", "node_type": "start", "title": "Start", "index": 0, "predecessor_node_id": "fdljewklfklgejlglsd", "inputs": {}, "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "execution_metadata": {"total_tokens": 63127864, "total_price": 2.378, "currency": "USD"}, "created_at": 1679586595}} | |||
| data: {"event": "workflow_finished", "task_id": "5ad4cb98-f0c7-4085-b384-88c403be6290", "workflow_run_id": "5ad498-f0c7-4085-b384-88cbe6290", "data": {"id": "5ad498-f0c7-4085-b384-88cbe6290", "workflow_id": "dfjasklfjdslag", "outputs": {}, "status": "succeeded", "elapsed_time": 0.324, "total_tokens": 63127864, "total_steps": "1", "created_at": 1679586595, "finished_at": 1679976595}} | |||
| @@ -2,6 +2,7 @@ import { memo } from 'react' | |||
| import { useTranslation } from 'react-i18next' | |||
| import { useIsChatMode } from '../hooks' | |||
| import { useStore } from '../store' | |||
| import { formatWorkflowRunIdentifier } from '../utils' | |||
| import { ClockPlay } from '@/app/components/base/icons/src/vender/line/time' | |||
| const RunningTitle = () => { | |||
| @@ -12,7 +13,7 @@ const RunningTitle = () => { | |||
| return ( | |||
| <div className='flex h-[18px] items-center text-xs text-gray-500'> | |||
| <ClockPlay className='mr-1 h-3 w-3 text-gray-500' /> | |||
| <span>{isChatMode ? `Test Chat#${historyWorkflowData?.sequence_number}` : `Test Run#${historyWorkflowData?.sequence_number}`}</span> | |||
| <span>{isChatMode ? `Test Chat${formatWorkflowRunIdentifier(historyWorkflowData?.finished_at)}` : `Test Run${formatWorkflowRunIdentifier(historyWorkflowData?.finished_at)}`}</span> | |||
| <span className='mx-1'>·</span> | |||
| <span className='ml-1 flex h-[18px] items-center rounded-[5px] border border-indigo-300 bg-white/[0.48] px-1 text-[10px] font-semibold uppercase text-indigo-600'> | |||
| {t('workflow.common.viewOnly')} | |||
| @@ -18,6 +18,7 @@ import { | |||
| useWorkflowRun, | |||
| } from '../hooks' | |||
| import { ControlMode, WorkflowRunningStatus } from '../types' | |||
| import { formatWorkflowRunIdentifier } from '../utils' | |||
| import cn from '@/utils/classnames' | |||
| import { | |||
| PortalToFollowElem, | |||
| @@ -199,7 +200,7 @@ const ViewHistory = ({ | |||
| item.id === historyWorkflowData?.id && 'text-text-accent', | |||
| )} | |||
| > | |||
| {`Test ${isChatMode ? 'Chat' : 'Run'} #${item.sequence_number}`} | |||
| {`Test ${isChatMode ? 'Chat' : 'Run'}${formatWorkflowRunIdentifier(item.finished_at)}`} | |||
| </div> | |||
| <div className='flex items-center text-xs leading-[18px] text-text-tertiary'> | |||
| {item.created_by_account?.name} · {formatTimeFromNow((item.finished_at || item.created_at) * 1000)} | |||
| @@ -10,6 +10,7 @@ import { | |||
| useWorkflowStore, | |||
| } from '../../store' | |||
| import { useWorkflowRun } from '../../hooks' | |||
| import { formatWorkflowRunIdentifier } from '../../utils' | |||
| import UserInput from './user-input' | |||
| import Chat from '@/app/components/base/chat/chat' | |||
| import type { ChatItem, ChatItemInTree } from '@/app/components/base/chat/types' | |||
| @@ -99,7 +100,7 @@ const ChatRecord = () => { | |||
| {fetched && ( | |||
| <> | |||
| <div className='flex shrink-0 items-center justify-between p-4 pb-1 text-base font-semibold text-text-primary'> | |||
| {`TEST CHAT#${historyWorkflowData?.sequence_number}`} | |||
| {`TEST CHAT${formatWorkflowRunIdentifier(historyWorkflowData?.finished_at)}`} | |||
| <div | |||
| className='flex h-6 w-6 cursor-pointer items-center justify-center' | |||
| onClick={() => { | |||
| @@ -3,6 +3,7 @@ import type { WorkflowDataUpdater } from '../types' | |||
| import Run from '../run' | |||
| import { useStore } from '../store' | |||
| import { useWorkflowUpdate } from '../hooks' | |||
| import { formatWorkflowRunIdentifier } from '../utils' | |||
| const Record = () => { | |||
| const historyWorkflowData = useStore(s => s.historyWorkflowData) | |||
| @@ -20,7 +21,7 @@ const Record = () => { | |||
| return ( | |||
| <div className='flex h-full w-[400px] flex-col rounded-l-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xl'> | |||
| <div className='system-xl-semibold flex items-center justify-between p-4 pb-0 text-text-primary'> | |||
| {`Test Run#${historyWorkflowData?.sequence_number}`} | |||
| {`Test Run${formatWorkflowRunIdentifier(historyWorkflowData?.finished_at)}`} | |||
| </div> | |||
| <Run | |||
| runID={historyWorkflowData?.id || ''} | |||
| @@ -20,6 +20,7 @@ import { useStore } from '../store' | |||
| import { | |||
| WorkflowRunningStatus, | |||
| } from '../types' | |||
| import { formatWorkflowRunIdentifier } from '../utils' | |||
| import Toast from '../../base/toast' | |||
| import InputsPanel from './inputs-panel' | |||
| import cn from '@/utils/classnames' | |||
| @@ -88,7 +89,7 @@ const WorkflowPreview = () => { | |||
| onMouseDown={startResizing} | |||
| /> | |||
| <div className='flex items-center justify-between p-4 pb-1 text-base font-semibold text-text-primary'> | |||
| {`Test Run${!workflowRunningData?.result.sequence_number ? '' : `#${workflowRunningData?.result.sequence_number}`}`} | |||
| {`Test Run${formatWorkflowRunIdentifier(workflowRunningData?.result.finished_at)}`} | |||
| <div className='cursor-pointer p-1' onClick={() => handleCancelDebugAndPreviewPanel()}> | |||
| <RiCloseLine className='h-4 w-4 text-text-tertiary' /> | |||
| </div> | |||
| @@ -360,7 +360,6 @@ export type WorkflowRunningData = { | |||
| message_id?: string | |||
| conversation_id?: string | |||
| result: { | |||
| sequence_number?: number | |||
| workflow_id?: string | |||
| inputs?: string | |||
| process_data?: string | |||
| @@ -383,9 +382,9 @@ export type WorkflowRunningData = { | |||
| export type HistoryWorkflowData = { | |||
| id: string | |||
| sequence_number: number | |||
| status: string | |||
| conversation_id?: string | |||
| finished_at?: number | |||
| } | |||
| export enum ChangeType { | |||
| @@ -33,3 +33,22 @@ export const isEventTargetInputArea = (target: HTMLElement) => { | |||
| if (target.contentEditable === 'true') | |||
| return true | |||
| } | |||
| /** | |||
| * Format workflow run identifier using finished_at timestamp | |||
| * @param finishedAt - Unix timestamp in seconds | |||
| * @param fallbackText - Text to show when finishedAt is not available (default: 'Running') | |||
| * @returns Formatted string like " (14:30:25)" or " (Running)" | |||
| */ | |||
| export const formatWorkflowRunIdentifier = (finishedAt?: number, fallbackText = 'Running'): string => { | |||
| if (!finishedAt) | |||
| return ` (${fallbackText})` | |||
| const date = new Date(finishedAt * 1000) | |||
| const timeStr = date.toLocaleTimeString([], { | |||
| hour: '2-digit', | |||
| minute: '2-digit', | |||
| second: '2-digit', | |||
| }) | |||
| return ` (${timeStr})` | |||
| } | |||
| @@ -278,7 +278,6 @@ export type WorkflowLogsRequest = { | |||
| export type WorkflowRunDetailResponse = { | |||
| id: string | |||
| sequence_number: number | |||
| version: string | |||
| graph: { | |||
| nodes: Node[] | |||
| @@ -152,7 +152,6 @@ export type WorkflowStartedResponse = { | |||
| data: { | |||
| id: string | |||
| workflow_id: string | |||
| sequence_number: number | |||
| created_at: number | |||
| } | |||
| } | |||
| @@ -289,7 +288,6 @@ export type AgentLogResponse = { | |||
| export type WorkflowRunHistory = { | |||
| id: string | |||
| sequence_number: number | |||
| version: string | |||
| conversation_id?: string | |||
| message_id?: string | |||