From 7920f1d8508560ceaffeb6e08076a8de2c2eb1ac Mon Sep 17 00:00:00 2001 From: congkechen Date: Fri, 10 Jul 2026 14:50:32 +0800 Subject: [PATCH 1/2] Fix examples and Build Full Pipeline --- examples/langgraph_agent/agent/agent.py | 9 +- .../agent/agent.py | 3 +- .../agent/agent.py | 3 +- examples/mem0_tools/agent/agent.py | 4 +- pipeline_test/run_all_examples.sh | 390 ++++++++++++++++++ 5 files changed, 402 insertions(+), 7 deletions(-) create mode 100644 pipeline_test/run_all_examples.sh diff --git a/examples/langgraph_agent/agent/agent.py b/examples/langgraph_agent/agent/agent.py index dfe7e128..31abe342 100644 --- a/examples/langgraph_agent/agent/agent.py +++ b/examples/langgraph_agent/agent/agent.py @@ -39,8 +39,9 @@ def build_calculator_subgraph(): api_key, url, model_name = get_model_config() model = init_chat_model( model_name, + model_provider="openai", api_key=api_key, - api_base=url, + base_url=url, ) tools = [calculate] @@ -79,8 +80,9 @@ def build_graph_with_subgraph(): api_key, url, model_name = get_model_config() model = init_chat_model( model_name, + model_provider="openai", api_key=api_key, - api_base=url, + base_url=url, ) # Build calculator subgraph @@ -126,8 +128,9 @@ def build_graph(): api_key, url, model_name = get_model_config() model = init_chat_model( model_name, + model_provider="openai", api_key=api_key, - api_base=url, + base_url=url, ) tools = [calculate] diff --git a/examples/langgraph_agent_with_cancel/agent/agent.py b/examples/langgraph_agent_with_cancel/agent/agent.py index 5ec88381..99a57136 100644 --- a/examples/langgraph_agent_with_cancel/agent/agent.py +++ b/examples/langgraph_agent_with_cancel/agent/agent.py @@ -44,8 +44,9 @@ def build_graph(): api_key, url, model_name = get_model_config() model = init_chat_model( model_name, + model_provider="openai", api_key=api_key, - api_base=url, + base_url=url, ) tools = [calculate, analyze_data] diff --git a/examples/langgraphagent_with_human_in_the_loop/agent/agent.py b/examples/langgraphagent_with_human_in_the_loop/agent/agent.py index baf750aa..5a3f7fe1 100644 --- a/examples/langgraphagent_with_human_in_the_loop/agent/agent.py +++ b/examples/langgraphagent_with_human_in_the_loop/agent/agent.py @@ -53,8 +53,9 @@ def _build_graph(): api_key, url, model_name = get_model_config() model = init_chat_model( model_name, + model_provider="openai", api_key=api_key, - api_base=url, + base_url=url, ) tools = [execute_database_operation] llm_with_tools = model.bind_tools(tools) diff --git a/examples/mem0_tools/agent/agent.py b/examples/mem0_tools/agent/agent.py index af69d341..3457f447 100644 --- a/examples/mem0_tools/agent/agent.py +++ b/examples/mem0_tools/agent/agent.py @@ -10,8 +10,8 @@ from trpc_agent_sdk.agents import LlmAgent from trpc_agent_sdk.models import LLMModel from trpc_agent_sdk.models import OpenAIModel -from trpc_agent_sdk.tools.mem0_tools import SaveMemoryTool -from trpc_agent_sdk.tools.mem0_tools import SearchMemoryTool +from trpc_agent_sdk.tools.mem0_tool import SaveMemoryTool +from trpc_agent_sdk.tools.mem0_tool import SearchMemoryTool from .config import get_mem0_platform_config from .config import get_memory_config diff --git a/pipeline_test/run_all_examples.sh b/pipeline_test/run_all_examples.sh new file mode 100644 index 00000000..89c1fb46 --- /dev/null +++ b/pipeline_test/run_all_examples.sh @@ -0,0 +1,390 @@ +#!/bin/bash + +export DISABLE_TRPC_AGENT_REPORT=true + +set -u +set -o pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" + +RUN_MODE="all" +FAIL_FAST=false +INCLUDE_MANUAL=false +EXAMPLE_TIMEOUT_SECONDS="${EXAMPLE_TIMEOUT_SECONDS:-300}" + +PASSED=() +FAILED=() +SKIPPED=() +RUN_AGENT_EXAMPLES=() +EVALUATION_TESTS=() + +TOTAL_TASKS=0 +CURRENT_TASK=0 + +SKIPPED_EXAMPLES=( + "examples/claude_agent_with_travel_planner/run_agent.py" + "examples/dsl/classifier_mcp/run_agent.py" + "examples/evaluation/webui/test_book_finder.py" + "examples/knowledge_with_vectorstore/run_agent.py" + "examples/mem0_tools/run_agent.py" + "examples/memory_service_with_mem0/run_agent.py" + "examples/memory_service_with_mempalace/run_agent.py" + "examples/memory_service_with_redis/run_agent.py" + "examples/memory_service_with_sql/run_agent.py" + "examples/mempalace_tools/run_agent.py" + "examples/session_service_with_redis/run_agent.py" + "examples/session_service_with_sql/run_agent.py" + "examples/skills_hub/run_agent.py" + "examples/skills_with_container/run_agent.py" + "examples/skills_with_cube/run_agent.py" +) + +show_usage() { + cat < 0)); then + percent=$((current * 100 / total)) + fi + + echo + printf '[%d/%d] %3d%% %s\n' "$current" "$total" "$percent" "$name" +} + +skip_example() { + local name="$1" + local reason="$2" + + CURRENT_TASK=$((CURRENT_TASK + 1)) + show_progress "$CURRENT_TASK" "$TOTAL_TASKS" "Skipping: ${name}" + echo "Skipping ${name}: ${reason}" + record_result skip "$name" +} + +should_skip() { + local name="$1" + shift + + if [[ "$INCLUDE_MANUAL" != true ]] && is_in_list "$name" "${SKIPPED_EXAMPLES[@]}"; then + SKIP_REASON="skipped by default" + return 0 + fi + + if (($# > 0)) && is_in_list "$name" "$@"; then + SKIP_REASON="listed in EXTRA_SKIP_EXAMPLES" + return 0 + fi + + return 1 +} + +run_command() { + local name="$1" + shift + local exit_code + + CURRENT_TASK=$((CURRENT_TASK + 1)) + show_progress "$CURRENT_TASK" "$TOTAL_TASKS" "Running: ${name}" + echo "============================================================" + echo "Running: ${name}" + echo "Command: $*" + echo "============================================================" + + "$@" + exit_code=$? + + if [[ "$exit_code" -eq 0 ]]; then + record_result pass "$name" + return 0 + else + echo "FAILED: ${name} (exit code: ${exit_code})" + record_result fail "$name" + + if [[ "$exit_code" -eq 130 ]]; then + print_summary + exit "$exit_code" + fi + + if [[ "$FAIL_FAST" == true ]]; then + print_summary + exit "$exit_code" + fi + + return "$exit_code" + fi +} + +run_python_file_from_dir() { + local file_path="$1" + local work_dir + local file_name + + work_dir="$(dirname "$file_path")" + file_name="$(basename "$file_path")" + + ( + cd "${REPO_ROOT}/${work_dir}" + timeout "$EXAMPLE_TIMEOUT_SECONDS" python3 "$file_name" + ) +} + +run_pytest_file_from_dir() { + local file_path="$1" + local work_dir + local file_name + + work_dir="$(dirname "$file_path")" + file_name="$(basename "$file_path")" + + ( + cd "${REPO_ROOT}/${work_dir}" + timeout "$EXAMPLE_TIMEOUT_SECONDS" pytest "$file_name" -v -s + ) +} + +run_discovered_agents() { + local extra_skip=() + local example + if [[ -n "${EXTRA_SKIP_EXAMPLES:-}" ]]; then + read -r -a extra_skip <<< "${EXTRA_SKIP_EXAMPLES}" + fi + + for example in "${RUN_AGENT_EXAMPLES[@]}"; do + if should_skip "$example" "${extra_skip[@]}"; then + skip_example "$example" "$SKIP_REASON" + continue + fi + + run_command "$example" run_python_file_from_dir "$example" + done +} + +run_evaluation_tests() { + local test_file + for test_file in "${EVALUATION_TESTS[@]}"; do + if should_skip "$test_file"; then + skip_example "$test_file" "$SKIP_REASON" + continue + fi + + run_command "$test_file" run_pytest_file_from_dir "$test_file" + done +} + +wait_for_port() { + local host="$1" + local port="$2" + local timeout_seconds="$3" + + python3 - "$host" "$port" "$timeout_seconds" <<'PY' +import socket +import sys +import time + +host = sys.argv[1] +port = int(sys.argv[2]) +deadline = time.time() + int(sys.argv[3]) + +while time.time() < deadline: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.settimeout(1) + if sock.connect_ex((host, port)) == 0: + sys.exit(0) + time.sleep(1) + +sys.exit(1) +PY +} + +run_a2a_example() { + local server_pid="" + local test_status=0 + + ( + cd "${REPO_ROOT}/examples/a2a" + exec python3 run_server.py + ) & + server_pid=$! + + cleanup_a2a() { + if [[ -n "$server_pid" ]]; then + pkill -TERM -P "$server_pid" 2>/dev/null || true + kill "$server_pid" 2>/dev/null || true + sleep 2 + pkill -KILL -P "$server_pid" 2>/dev/null || true + kill -KILL "$server_pid" 2>/dev/null || true + wait "$server_pid" 2>/dev/null || true + fi + } + + if ! wait_for_port "127.0.0.1" "18081" "30"; then + echo "FAILED: examples/a2a server did not start on 127.0.0.1:18081" + cleanup_a2a + return 1 + fi + + ( + cd "${REPO_ROOT}/examples/a2a" + timeout "$EXAMPLE_TIMEOUT_SECONDS" python3 test_a2a.py + ) + test_status=$? + cleanup_a2a + return "$test_status" +} + +discover_run_agent_examples() { + mapfile -t RUN_AGENT_EXAMPLES < <( + cd "$REPO_ROOT" + find examples -path "*/run_agent.py" -type f | sort + ) +} + +discover_evaluation_tests() { + mapfile -t EVALUATION_TESTS < <( + cd "$REPO_ROOT" + find examples/evaluation -name "test_*.py" -type f | sort + ) +} + +prepare_tasks() { + case "$RUN_MODE" in + all) + discover_run_agent_examples + discover_evaluation_tests + TOTAL_TASKS=$((${#RUN_AGENT_EXAMPLES[@]} + ${#EVALUATION_TESTS[@]} + 1)) + ;; + run-agent) + discover_run_agent_examples + TOTAL_TASKS=${#RUN_AGENT_EXAMPLES[@]} + ;; + evaluation) + discover_evaluation_tests + TOTAL_TASKS=${#EVALUATION_TESTS[@]} + ;; + a2a) + TOTAL_TASKS=1 + ;; + esac +} + +print_summary() { + echo + echo "==================== Example Run Summary ====================" + echo "Passed : ${#PASSED[@]}" + echo "Failed : ${#FAILED[@]}" + echo "Skipped: ${#SKIPPED[@]}" + + if ((${#FAILED[@]} > 0)); then + echo + echo "Failed examples:" + printf ' - %s\n' "${FAILED[@]}" + fi +} + +while (($# > 0)); do + case "$1" in + all|run-agent|evaluation|a2a) + RUN_MODE="$1" + ;; + --fail-fast) + FAIL_FAST=true + ;; + --include-manual) + INCLUDE_MANUAL=true + ;; + -h|--help) + show_usage + exit 0 + ;; + *) + echo "Error: unknown argument '$1'" + show_usage + exit 1 + ;; + esac + shift +done + +cd "$REPO_ROOT" +prepare_tasks + +case "$RUN_MODE" in + all) + run_discovered_agents + run_evaluation_tests + run_command "examples/a2a" run_a2a_example + ;; + run-agent) + run_discovered_agents + ;; + evaluation) + run_evaluation_tests + ;; + a2a) + run_command "examples/a2a" run_a2a_example + ;; +esac + +print_summary + +if ((${#FAILED[@]} > 0)); then + exit 1 +fi From 3a63671fde17ee7b45ef922f3d791207aef31264 Mon Sep 17 00:00:00 2001 From: congkechen Date: Fri, 10 Jul 2026 16:18:56 +0800 Subject: [PATCH 2/2] add release workflow --- .github/workflows/release.yml | 89 +++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..d3626383 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,89 @@ +name: Auto Release when Tag +on: + push: + tags: + - 'v*' + - 'test/v*' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: false + +permissions: + contents: read + +jobs: + release: + runs-on: [self-hosted, trpc-agent-python-ci] + timeout-minutes: 30 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install release dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements-test.txt + pip install build twine flake8 yapf + + - name: Validate tag version + run: | + TAG_VERSION="${GITHUB_REF_NAME#test/v}" + TAG_VERSION="${TAG_VERSION#v}" + PACKAGE_VERSION=$(python -c "from trpc_agent_sdk.version import __version__; print(__version__)") + if [ "$TAG_VERSION" != "$PACKAGE_VERSION" ]; then + echo "::error::Tag version '$TAG_VERSION' does not match package version '$PACKAGE_VERSION'." + exit 1 + fi + + - name: Get changed Python files + id: changed + run: | + FILES=$(git diff --name-only --diff-filter=ACM HEAD~1...HEAD -- '*.py' | grep '^trpc_agent_sdk/' || true) + if [ -z "$FILES" ]; then + echo "has_files=false" >> "$GITHUB_OUTPUT" + else + echo "has_files=true" >> "$GITHUB_OUTPUT" + echo "$FILES" > "$RUNNER_TEMP/changed_py_files.txt" + echo "Changed Python files:" + echo "$FILES" + fi + + - name: Check formatting with YAPF + if: steps.changed.outputs.has_files == 'true' + run: | + FILES=$(cat "$RUNNER_TEMP/changed_py_files.txt" | tr '\n' ' ') + diff_output=$(yapf --diff $FILES) || true + if [ -n "$diff_output" ]; then + echo "$diff_output" + echo "::error::Code formatting check failed for changed files. Run 'yapf -i ' to fix." + exit 1 + fi + + - name: Lint with flake8 + if: steps.changed.outputs.has_files == 'true' + run: | + FILES=$(cat "$RUNNER_TEMP/changed_py_files.txt" | tr '\n' ' ') + flake8 $FILES + + - name: Run tests with coverage + run: | + pytest --cov=trpc_agent_sdk --cov-report=xml --cov-report=term --cov-fail-under=80 tests/ + + - name: Build package + run: | + python -m build + + - name: Check package + run: | + python -m twine check dist/* + + - name: Publish to PyPI + if: startsWith(github.ref, 'refs/tags/v') + run: | + python -m twine upload dist/* + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} \ No newline at end of file