fix: add stream toggle back to agent (#13155)

* add stream toggle back to agent

* chore: auto-bake note keys and regenerate backend locales/en.json [skip ci]

* ci: stop transient Windows npm/cache flakes from failing frontend tests

The nightly frontend job fails almost every day on a single Windows
Playwright shard, never on actual test logic. With fail-fast:false over
~70 Windows shards each making several cache/artifact-service calls, a
transient GitHub Actions cache/artifact hiccup on any one shard flips
needs.setup-and-test.result to failure and reds the whole nightly
(observed steps: Setup Node.js Environment, Cache Playwright Browsers,
Upload Playwright Coverage Artifact).

- Decouple npm caching from actions/setup-node (its internal cache step
  can't be made non-fatal) and replace it with a standalone
  actions/cache@v5 step marked continue-on-error.
- Mark Cache Playwright Browsers and the artifact-upload steps
  continue-on-error so an infra blip can no longer fail a test shard.

Only a real test/browser failure can fail a shard now.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* [autofix.ci] apply automated fixes

* [autofix.ci] apply automated fixes (attempt 2/3)

* [autofix.ci] apply automated fixes

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Cristhian Zanforlin Lousa
2026-05-18 10:30:08 -03:00
committed by GitHub
parent 851a48401b
commit d017e156cd
20 changed files with 572 additions and 45 deletions

View File

@ -227,8 +227,22 @@ jobs:
id: setup-node
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
cache-dependency-path: ./src/frontend/package-lock.json
# npm caching is decoupled from setup-node so a transient cache-service
# hiccup (frequent on Windows runners) never fails the job. See #25 / #1.
- name: Get npm cache directory
id: npm-cache-dir
shell: bash
run: echo "dir=$(npm config get cache)" >> "$GITHUB_OUTPUT"
- name: Cache npm dependencies
uses: actions/cache@v5
continue-on-error: true
with:
path: ${{ steps.npm-cache-dir.outputs.dir }}
key: ${{ runner.os }}-npm-${{ env.NODE_VERSION }}-${{ hashFiles('src/frontend/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-${{ env.NODE_VERSION }}-
- name: Install Frontend Dependencies
run: npm ci
@ -298,8 +312,23 @@ jobs:
id: setup-node
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
cache-dependency-path: ./src/frontend/package-lock.json
# npm caching is decoupled from setup-node so a transient cache-service
# hiccup (frequent on Windows runners) never fails the job. See #25 / #1.
- name: Get npm cache directory
id: npm-cache-dir
shell: bash
run: echo "dir=$(npm config get cache)" >> "$GITHUB_OUTPUT"
- name: Cache npm dependencies
uses: actions/cache@v5
continue-on-error: true
with:
path: ${{ steps.npm-cache-dir.outputs.dir }}
key: ${{ runner.os }}-npm-${{ env.NODE_VERSION }}-${{ hashFiles('src/frontend/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-${{ env.NODE_VERSION }}-
- name: Install Frontend Dependencies
run: npm ci
working-directory: ./src/frontend
@ -308,6 +337,7 @@ jobs:
- name: Cache Playwright Browsers
id: cache-playwright
uses: actions/cache@v5
continue-on-error: true
with:
path: ${{ env.PLAYWRIGHT_BROWSERS_PATH }}
key: playwright-${{ env.PLAYWRIGHT_VERSION }}-chromium-${{ runner.os }}
@ -366,6 +396,7 @@ jobs:
- name: Upload Test Results
if: always()
continue-on-error: true
uses: actions/upload-artifact@v6
with:
name: blob-report-${{ runner.os }}-${{ matrix.shardIndex }}
@ -375,6 +406,7 @@ jobs:
- name: Upload Playwright Coverage Artifact
if: always() && hashFiles('src/frontend/coverage/playwright/**') != ''
continue-on-error: true
uses: actions/upload-artifact@v6
with:
name: playwright-coverage-${{ matrix.shardIndex }}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -65,6 +65,8 @@
"components.agent.inputs.output_schema.info.3b7a7b80": "Schema Validation: Define the structure and data types for structured output. No validation if no output schema.",
"components.agent.inputs.project_id.display_name.c7feb8db": "watsonx Project ID",
"components.agent.inputs.project_id.info.0d91e5f5": "The project ID associated with the foundation model (IBM watsonx.ai only)",
"components.agent.inputs.stream.display_name.1eec3071": "Stream",
"components.agent.inputs.stream.info.f835b3ff": "Stream the response from the model. Streaming works only in Chat.",
"components.agent.inputs.system_prompt.display_name.55ce85ab": "Agent Instructions",
"components.agent.inputs.system_prompt.info.a1fa7781": "System Prompt: Initial instructions and context provided to guide the agent's behavior. Supports dynamic placeholders: {current_date}, {model_name}, {optional_user_context}.",
"components.agent.inputs.tools.display_name.ea93d6a2": "Tools",
@ -173,6 +175,8 @@
"components.altkagent.inputs.project_id.info.0d91e5f5": "The project ID associated with the foundation model (IBM watsonx.ai only)",
"components.altkagent.inputs.response_processing_size_threshold.display_name.84c35424": "Response Processing Size Threshold",
"components.altkagent.inputs.response_processing_size_threshold.info.d6aeb95b": "Tool output is post-processed only if response exceeds this character threshold.",
"components.altkagent.inputs.stream.display_name.1eec3071": "Stream",
"components.altkagent.inputs.stream.info.f835b3ff": "Stream the response from the model. Streaming works only in Chat.",
"components.altkagent.inputs.system_prompt.display_name.55ce85ab": "Agent Instructions",
"components.altkagent.inputs.system_prompt.info.a1fa7781": "System Prompt: Initial instructions and context provided to guide the agent's behavior. Supports dynamic placeholders: {current_date}, {model_name}, {optional_user_context}.",
"components.altkagent.inputs.tools.display_name.ea93d6a2": "Tools",

View File

@ -451,6 +451,47 @@ class TestAgentComponent(ComponentTestBaseWithoutClient):
# Note: The provider-specific field name mapping happens inside get_llm,
# so we just verify max_tokens is passed correctly
async def test_should_expose_stream_input_when_agent_component_is_loaded(self, component_class, default_kwargs):
"""Regression: the Stream toggle disappeared from the Agent after the ModelInput unification (#12025).
Given the Agent component is loaded, When its inputs are inspected,
Then a 'stream' input field must be present so users can control LLM streaming.
"""
component = await self.component_setup(component_class, default_kwargs)
input_names = [inp.name for inp in component.inputs if hasattr(inp, "name")]
assert "stream" in input_names, "stream input field should be present on the Agent component"
assert hasattr(component, "stream"), "Component should have a stream attribute"
@patch("lfx.components.models_and_agents.agent.AgentComponent.get_memory_data")
@patch("lfx.components.models_and_agents.agent.get_llm")
async def test_should_pass_stream_value_to_get_llm_when_stream_input_is_enabled(
self, mock_get_llm, mock_get_memory_data, component_class, default_kwargs
):
"""Regression: the Agent must forward the Stream toggle value to get_llm().
Given stream=True on the Agent, When get_agent_requirements runs,
Then get_llm() must be called with stream=True so the LLM streams responses.
"""
from unittest.mock import AsyncMock, MagicMock
mock_get_memory_data.return_value = AsyncMock(return_value=[])
mock_get_llm.return_value = MagicMock()
default_kwargs["stream"] = True
component = await self.component_setup(component_class, default_kwargs)
# validate_model_selection requires a list — set a valid model selection
component.model = [{"name": "gpt-4o", "provider": "OpenAI", "metadata": {}}]
await component.get_agent_requirements()
mock_get_llm.assert_called_once()
call_kwargs = mock_get_llm.call_args.kwargs
assert "stream" in call_kwargs, "stream should be passed to get_llm"
assert call_kwargs["stream"] is True
async def test_should_append_calculator_tool_when_add_calculator_toggle_is_true(
self, component_class, default_kwargs
):

File diff suppressed because one or more lines are too long

View File

@ -12,6 +12,7 @@ if TYPE_CHECKING:
from lfx.base.agents.agent import LCToolsAgentComponent
from lfx.base.agents.default_system_prompt import DEFAULT_SYSTEM_PROMPT_TEMPLATE
from lfx.base.agents.events import ExceptionWithMessageError
from lfx.base.constants import STREAM_INFO_TEXT
from lfx.base.models.unified_models import (
get_language_model_options,
get_llm,
@ -211,6 +212,13 @@ class AgentComponent(ToolCallingAgentComponent):
*LCToolsAgentComponent.get_base_inputs(),
# removed memory inputs from agent component
# *memory_inputs,
BoolInput(
name="stream",
display_name="Stream",
info=STREAM_INFO_TEXT,
value=False,
advanced=True,
),
BoolInput(
name="add_current_date_tool",
display_name="Current Date",
@ -283,6 +291,7 @@ class AgentComponent(ToolCallingAgentComponent):
model=self.model,
user_id=self.user_id,
api_key=getattr(self, "api_key", None),
stream=bool(getattr(self, "stream", False)),
max_tokens=self._get_max_tokens_value(),
watsonx_url=getattr(self, "base_url_ibm_watsonx", None),
watsonx_project_id=getattr(self, "project_id", None),