fix(web): render first-token timeout only for panels that consume it

isInWorkflow was a proxy for 'this panel's model config reaches
fetch_model_config', which is false for the knowledge-retrieval metadata
filter and single-retrieval model, and for tool/trigger model-selector
params rendered through form-input-item — the field showed up there but the
backend never consumed it. Gate the rule on an explicit
supportFirstTokenTimeout prop passed only by the LLM, question classifier
and parameter extractor panels, and extend the help text with the
inter-token semantics of the read window.
This commit is contained in:
L1nSn0w
2026-07-14 18:28:52 +08:00
parent 20a205488b
commit 450d76ada5
6 changed files with 28 additions and 7 deletions
@@ -388,16 +388,26 @@ describe('ModelParameterModal', () => {
expect(screen.getByText(/debugAsSingleModel/i)).toBeInTheDocument()
})
it('should append the first token timeout parameter only in workflow advanced mode', () => {
render(<ModelParameterModal {...defaultProps} isAdvancedMode isInWorkflow />)
it('should append the first token timeout parameter when the panel supports it', () => {
render(
<ModelParameterModal
{...defaultProps}
isAdvancedMode
isInWorkflow
supportFirstTokenTimeout
/>,
)
openSettings()
expect(screen.getByTestId('param-first_token_timeout_ms')).toBeInTheDocument()
})
it('should not append the first token timeout parameter outside workflow', () => {
render(<ModelParameterModal {...defaultProps} isAdvancedMode />)
it('should not append the first token timeout parameter for workflow panels that do not support it', () => {
// Being in a workflow is not enough: panels whose model config is not consumed
// by fetch_model_config (knowledge retrieval, tool/trigger model params) must
// not render a dead setting.
render(<ModelParameterModal {...defaultProps} isAdvancedMode isInWorkflow />)
openSettings()
@@ -40,6 +40,10 @@ export type ModelParameterModalProps = {
renderTrigger?: (v: TriggerProps) => ReactNode
readonly?: boolean
isInWorkflow?: boolean
// Only LLM-compatible node panels (LLM / question classifier / parameter
// extractor) should pass this: the backend consumes the value solely on
// their model-config path, so rendering it elsewhere yields dead config.
supportFirstTokenTimeout?: boolean
scope?: string
nodesOutputVars?: NodeOutPutVar[]
availableNodes?: Node[]
@@ -59,6 +63,7 @@ const ModelParameterModal: FC<ModelParameterModalProps> = ({
renderTrigger,
readonly,
isInWorkflow,
supportFirstTokenTimeout,
nodesOutputVars,
availableNodes,
}) => {
@@ -223,7 +228,9 @@ const ModelParameterModal: FC<ModelParameterModalProps> = ({
[
...parameterRules,
...(isAdvancedMode ? [STOP_PARAMETER_RULE] : []),
...(isAdvancedMode && isInWorkflow ? [FIRST_TOKEN_TIMEOUT_PARAMETER_RULE] : []),
...(isAdvancedMode && supportFirstTokenTimeout
? [FIRST_TOKEN_TIMEOUT_PARAMETER_RULE]
: []),
].map((parameter) => (
<ParameterItem
key={`${modelId}-${parameter.name}`}
@@ -117,6 +117,7 @@ const Panel: FC<NodePanelProps<LLMNodeType>> = ({ id, data }) => {
popupClassName="w-[387px]!"
isInWorkflow
isAdvancedMode={true}
supportFirstTokenTimeout
provider={model?.provider}
completionParams={model?.completion_params}
modelId={model?.name}
@@ -61,6 +61,7 @@ const Panel: FC<NodePanelProps<ParameterExtractorNodeType>> = ({ id, data }) =>
popupClassName="w-[387px]!"
isInWorkflow
isAdvancedMode={true}
supportFirstTokenTimeout
provider={model?.provider}
completionParams={model?.completion_params}
modelId={model?.name}
@@ -50,6 +50,7 @@ const Panel: FC<NodePanelProps<QuestionClassifierNodeType>> = ({ id, data }) =>
popupClassName="w-[387px]!"
isInWorkflow
isAdvancedMode={true}
supportFirstTokenTimeout
provider={model?.provider}
completionParams={model.completion_params}
modelId={model.name}
+3 -2
View File
@@ -337,8 +337,9 @@ export const FIRST_TOKEN_TIMEOUT_PARAMETER_RULE: ModelParameterRule = {
precision: 0,
help: {
en_US:
'Max milliseconds to wait for the first streamed token. On timeout the node fails; combine with node retry to re-run it automatically.',
zh_Hans: '等待首个流式 Token 的最长毫秒数。超时后节点失败,可配合节点重试自动重跑。',
'Max milliseconds to wait for the first streamed token; the same window also bounds each gap between tokens. On timeout the node fails; combine with node retry to re-run it automatically.',
zh_Hans:
'等待首个流式 Token 的最长毫秒数;同一窗口也约束后续每次 Token 间隔。超时后节点失败,可配合节点重试自动重跑。',
},
label: {
en_US: 'First token timeout (ms)',