diff --git a/src/langbot/pkg/persistence/migrations/dbm021_merge_exception_handling.py b/src/langbot/pkg/persistence/migrations/dbm021_merge_exception_handling.py new file mode 100644 index 00000000..59c1e357 --- /dev/null +++ b/src/langbot/pkg/persistence/migrations/dbm021_merge_exception_handling.py @@ -0,0 +1,74 @@ +from .. import migration + +import sqlalchemy +import json + + +@migration.migration_class(21) +class DBMigrateMergeExceptionHandling(migration.DBMigration): + """Merge hide-exception and block-failed-request-output into a single exception-handling select option, + and add failure-hint field. + + Conversion logic: + - block-failed-request-output=true -> exception-handling: hide + - hide-exception=true -> exception-handling: show-hint + - hide-exception=false -> exception-handling: show-error + """ + + async def upgrade(self): + """Upgrade""" + result = await self.ap.persistence_mgr.execute_async( + sqlalchemy.text('SELECT uuid, config FROM legacy_pipelines') + ) + pipelines = result.fetchall() + + current_version = self.ap.ver_mgr.get_current_version() + + for pipeline_row in pipelines: + uuid = pipeline_row[0] + config = json.loads(pipeline_row[1]) if isinstance(pipeline_row[1], str) else pipeline_row[1] + + if 'output' not in config: + config['output'] = {} + if 'misc' not in config['output']: + config['output']['misc'] = {} + + misc = config['output']['misc'] + + # Determine new exception-handling value from legacy fields + hide_exception = misc.get('hide-exception', True) + block_failed = misc.get('block-failed-request-output', False) + + if block_failed: + exception_handling = 'hide' + elif hide_exception: + exception_handling = 'show-hint' + else: + exception_handling = 'show-error' + + misc['exception-handling'] = exception_handling + + # Add failure-hint with default value + misc['failure-hint'] = 'Request failed.' + + # Remove legacy fields + misc.pop('hide-exception', None) + + if self.ap.persistence_mgr.db.name == 'postgresql': + await self.ap.persistence_mgr.execute_async( + sqlalchemy.text( + 'UPDATE legacy_pipelines SET config = :config::jsonb, for_version = :for_version WHERE uuid = :uuid' + ), + {'config': json.dumps(config), 'for_version': current_version, 'uuid': uuid}, + ) + else: + await self.ap.persistence_mgr.execute_async( + sqlalchemy.text( + 'UPDATE legacy_pipelines SET config = :config, for_version = :for_version WHERE uuid = :uuid' + ), + {'config': json.dumps(config), 'for_version': current_version, 'uuid': uuid}, + ) + + async def downgrade(self): + """Downgrade""" + pass diff --git a/src/langbot/pkg/pipeline/process/handlers/chat.py b/src/langbot/pkg/pipeline/process/handlers/chat.py index 7e130b04..6f971333 100644 --- a/src/langbot/pkg/pipeline/process/handlers/chat.py +++ b/src/langbot/pkg/pipeline/process/handlers/chat.py @@ -149,12 +149,19 @@ class ChatMessageHandler(handler.MessageHandler): self.ap.logger.error(f'Conversation({query.query_id}) Request Failed: {error_info}') traceback.print_exc() - hide_exception_info = query.pipeline_config['output']['misc']['hide-exception'] + exception_handling = query.pipeline_config['output']['misc'].get('exception-handling', 'show-hint') + + if exception_handling == 'show-error': + user_notice = f'{e}' + elif exception_handling == 'show-hint': + user_notice = query.pipeline_config['output']['misc'].get('failure-hint', 'Request failed.') + else: # hide + user_notice = None yield entities.StageProcessResult( result_type=entities.ResultType.INTERRUPT, new_query=query, - user_notice='请求失败' if hide_exception_info else f'{e}', + user_notice=user_notice, error_notice=f'{e}', debug_notice=traceback.format_exc(), ) diff --git a/src/langbot/pkg/utils/constants.py b/src/langbot/pkg/utils/constants.py index cd058a88..8d8e972a 100644 --- a/src/langbot/pkg/utils/constants.py +++ b/src/langbot/pkg/utils/constants.py @@ -2,7 +2,7 @@ import langbot semantic_version = f'v{langbot.__version__}' -required_database_version = 20 +required_database_version = 21 """Tag the version of the database schema, used to check if the database needs to be migrated""" debug_mode = False diff --git a/src/langbot/templates/default-pipeline-config.json b/src/langbot/templates/default-pipeline-config.json index ee47ef9f..1c6fdb64 100644 --- a/src/langbot/templates/default-pipeline-config.json +++ b/src/langbot/templates/default-pipeline-config.json @@ -95,11 +95,12 @@ "max": 0 }, "misc": { - "hide-exception": true, + "exception-handling": "show-hint", + "failure-hint": "Request failed.", "at-sender": true, "quote-origin": true, "track-function-calls": false, "remove-think": false } } -} \ No newline at end of file +} diff --git a/src/langbot/templates/metadata/pipeline/output.yaml b/src/langbot/templates/metadata/pipeline/output.yaml index 1978dea4..d5e0fae0 100644 --- a/src/langbot/templates/metadata/pipeline/output.yaml +++ b/src/langbot/templates/metadata/pipeline/output.yaml @@ -78,13 +78,39 @@ stages: en_US: Misc zh_Hans: 杂项 config: - - name: hide-exception + - name: exception-handling label: - en_US: Hide Exception - zh_Hans: 不输出异常信息给用户 - type: boolean + en_US: Exception Handling Strategy + zh_Hans: 异常处理策略 + description: + en_US: Controls how error messages are displayed to the user when an AI request fails + zh_Hans: 控制 AI 请求失败时向用户展示错误信息的方式 + type: select required: true - default: true + default: show-hint + options: + - name: show-error + label: + en_US: Show Full Error + zh_Hans: 显示完整报错信息 + - name: show-hint + label: + en_US: Show Failure Hint + zh_Hans: 仅文字提示 + - name: hide + label: + en_US: Hide All + zh_Hans: 不显示任何异常信息 + - name: failure-hint + label: + en_US: Failure Hint Text + zh_Hans: 失败提示文本 + description: + en_US: The text to display when a request fails. Only effective when Exception Handling Strategy is set to "Show Failure Hint" + zh_Hans: 请求失败时显示的提示文本,仅在异常处理策略设置为"仅文字提示"时生效 + type: string + required: false + default: 'Request failed.' - name: at-sender label: en_US: At Sender @@ -119,3 +145,4 @@ stages: type: boolean required: true default: false +