Skip to content

chore: sync workflow templates#869

Closed
stranske wants to merge 1 commit into
mainfrom
sync/workflows-1243c652ce3c
Closed

chore: sync workflow templates#869
stranske wants to merge 1 commit into
mainfrom
sync/workflows-1243c652ce3c

Conversation

@stranske

@stranske stranske commented Jun 22, 2026

Copy link
Copy Markdown
Owner

Sync Summary

Files Updated

  • progress_reviewer.py: Progress reviewer - evaluates agent progress for keepalive rounds
  • llm_provider.py: LLM provider configuration - GitHub Models and OpenAI client setup

Files Skipped

  • pr-00-gate.yml: File exists and sync_mode is create_only
  • ci.yml: File exists and sync_mode is create_only
  • renovate.json: File exists and sync_mode is create_only
  • cross-repo-smoke.yml: File exists and sync_mode is create_only
  • llm_slots.json: None

Review Checklist

  • CI passes with updated workflows
  • No repo-specific customizations were overwritten

Source: stranske/Workflows
Source SHA: 680260c913e1c136e0b0ba11c07a760e23c26b0c
Template hash: 1243c652ce3c
Sync branch: sync/workflows-1243c652ce3c
Consumer repo: stranske/Collab-Admin
Manifest: .github/sync-manifest.yml

Summary by CodeRabbit

  • Refactor
    • Reorganized internal LLM client construction and model selection logic to support dynamic configuration with fallback handling.

Automated sync from stranske/Workflows
Template hash: 1243c652ce3c

Changes synced from sync-manifest.yml
@stranske stranske added sync Automated sync from Workflows automated Automated sync from Workflows labels Jun 22, 2026
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

tools/llm_provider.py gains a _configured_langchain_model helper that looks up provider-specific model names from tools.llm_registry, with a hardcoded fallback. Both OpenAIProvider and AnthropicProvider now use this helper and delegate LangChain client construction to tools.langchain_client.build_chat_client. scripts/langchain/progress_reviewer.py switches its client builder import to scripts.langchain._llm_client.build_client.

Changes

LangChain client builder and dynamic model resolution

Layer / File(s) Summary
Dynamic model resolution helper and provider client updates
tools/llm_provider.py
_configured_langchain_model(provider, fallback) added to resolve model names from tools.llm_registry. OpenAIProvider._get_client() and AnthropicProvider._get_client() updated to call tools.langchain_client.build_chat_client with the resolved model and store it on self._model_name. Both analyze_completion methods switch model_name from hardcoded strings to self._model_name with dynamic fallback.
progress_reviewer import path update
scripts/langchain/progress_reviewer.py
review_progress_with_llm replaces tools.langchain_client.build_chat_client import with scripts.langchain._llm_client.build_client, setting it to None on ImportError.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'chore: sync workflow templates' does not match the actual changes, which are LLM client construction updates in progress_reviewer.py and llm_provider.py, not workflow template synchronization. Update the title to accurately reflect the main changes, such as 'refactor: update LLM client construction and model selection logic' or similar.
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sync/workflows-1243c652ce3c

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tools/llm_provider.py`:
- Around line 638-642: The analyze_completion() method uses getattr() with a
default parameter that calls _configured_langchain_model() on every invocation,
but since _model_name is guaranteed to be set by _get_client() before
analyze_completion() is reached, this creates unnecessary registry lookups on a
frequently-called path. Replace the getattr() pattern with direct attribute
access to self._model_name (around line 638 and also at line 722-726 where the
same pattern applies) since the attribute is guaranteed to already exist,
eliminating the redundant function call and improving performance.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d8d40aed-b145-48f8-aebf-b468411eb007

📥 Commits

Reviewing files that changed from the base of the PR and between efc468b and ec88053.

📒 Files selected for processing (2)
  • scripts/langchain/progress_reviewer.py
  • tools/llm_provider.py
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • stranske/Workflows (auto-detected)
  • stranske/Template (auto-detected)
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Python CI / python 3.13
  • GitHub Check: Python CI / python 3.12
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

In the Manager-Database repository, use Prefect 2.x and import schedules from prefect.client.schemas.schedules

Files:

  • scripts/langchain/progress_reviewer.py
  • tools/llm_provider.py
🔀 Multi-repo context stranske/Template, stranske/Workflows

Perfect! I now have a complete picture of the cross-repository impact. Let me document my findings:

Linked repositories findings

stranske/Template

Critical Breaking Change in llm_provider.py:

Template's current OpenAIProvider._get_client() [::stranske/Template::] directly instantiates ChatOpenAI with a hardcoded model string:

return ChatOpenAI(
    model="gpt-5.1-codex",
    api_key=os.environ.get("OPENAI_API_KEY"),
    temperature=0.1,
)

However, Workflows' refactored version [::stranske/Workflows::] delegates client creation to build_chat_client() and expects to extract the model name from the returned ClientInfo object:

resolved = build_chat_client(provider="openai", model=model_name)
if resolved:
    self._model_name = resolved.model
    return resolved.client

Issue: The Workflows version calls _configured_langchain_model("openai", fallback="gpt-5.1-codex") [::stranske/Workflows::] on line 601 of llm_provider.py, but Template does not have this function. When Template syncs this code, it will fail with NameError: name '_configured_langchain_model' is not defined.

Similarly for AnthropicProvider._get_client() [::stranske/Workflows::] on line 672, which calls _configured_langchain_model("anthropic", fallback="claude-sonnet-4-5-20250929").

Secondary Issue - Model Name Reporting:

In both providers' analyze_completion() method, Workflows now uses:

model_name=getattr(
    self,
    "_model_name",
    _configured_langchain_model("openai", fallback="gpt-5.1-codex"),
),

[::stranske/Workflows::] (lines 641 and 721)

While Template hardcodes:

model_name="gpt-5.1-codex"  # Actual model used by OpenAIProvider

[::stranske/Template::]

This means the synced code will again call the non-existent _configured_langchain_model() function.

Impact on progress_reviewer.py:

Template's progress_reviewer.py line 430 currently imports from tools.langchain_client:

from tools.langchain_client import build_chat_client

[::stranske/Template::]

Workflows changes this to import from a new wrapper:

from scripts.langchain._llm_client import build_client

[::stranske/Workflows::] (line 430)

Both build_chat_client and build_client return ClientInfo objects with compatible interfaces, so this change should be forward-compatible. However, Template must have the _llm_client module available at that import path.


🔇 Additional comments (2)
tools/llm_provider.py (1)

45-52: LGTM!

Also applies to: 596-606, 667-677

scripts/langchain/progress_reviewer.py (1)

430-434: LGTM!

Comment thread tools/llm_provider.py
Comment on lines +638 to +642
model_name=getattr(
self,
"_model_name",
_configured_langchain_model("openai", fallback="gpt-5.1-codex"),
),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify call sites using eager default expression
rg -n 'getattr\(\s*self,\s*"_model_name",\s*_configured_langchain_model' tools/llm_provider.py

# Demonstrate Python eager evaluation of function-call args (language behavior)
python - <<'PY'
def fallback():
    print("fallback evaluated")
    return "fallback"

class Obj:
    _model_name = "already-set"

print(getattr(Obj(), "_model_name", fallback()))
PY

Repository: stranske/Collab-Admin

Length of output: 47


🏁 Script executed:

#!/bin/bash
# List files to understand repo structure
git ls-files | head -20

# Look for llm_provider files
find . -name "*llm_provider*" -o -name "*langchain*" | head -20

Repository: stranske/Collab-Admin

Length of output: 996


🏁 Script executed:

#!/bin/bash
# Check if tools directory exists
ls -la tools/ 2>/dev/null || echo "tools/ does not exist"

# List Python files in root and common locations
find . -maxdepth 3 -name "*.py" -type f | grep -E "(llm|provider|langchain)" | head -20

Repository: stranske/Collab-Admin

Length of output: 1795


🏁 Script executed:

#!/bin/bash
# Read the specific lines mentioned in the review
echo "=== Lines 638-642 ==="
sed -n '638,642p' tools/llm_provider.py

echo ""
echo "=== Lines 719-723 ==="
sed -n '719,723p' tools/llm_provider.py

echo ""
echo "=== Check for _configured_langchain_model definition ==="
grep -n "_configured_langchain_model" tools/llm_provider.py | head -20

Repository: stranske/Collab-Admin

Length of output: 1050


🏁 Script executed:

#!/bin/bash
# Look at the context around line 641 to understand when _model_name gets set
echo "=== Context around line 641 (OpenAI) ==="
sed -n '595,650p' tools/llm_provider.py

echo ""
echo "=== Context around line 722 (Anthropic) ==="
sed -n '665,730p' tools/llm_provider.py

Repository: stranske/Collab-Admin

Length of output: 4903


🏁 Script executed:

#!/bin/bash
# Look at the _configured_langchain_model function definition
echo "=== _configured_langchain_model function ==="
sed -n '45,80p' tools/llm_provider.py

Repository: stranske/Collab-Admin

Length of output: 1367


🏁 Script executed:

#!/bin/bash
# Check how often analyze_completion is called and confirm _model_name flow
echo "=== Check if _model_name is always set before getattr call ==="
sed -n '620,645p' tools/llm_provider.py

# Count how many times analyze_completion is called in the codebase
echo ""
echo "=== Call sites of analyze_completion ==="
rg -n "\.analyze_completion\(" --type py | head -20

Repository: stranske/Collab-Admin

Length of output: 1527


🏁 Script executed:

#!/bin/bash
# Trace the exact control flow - when is analyze_completion called?
echo "=== Callers of analyze_completion in llm_provider.py ==="
sed -n '10,25p' tools/llm_provider.py

echo ""
echo "=== Line 935 context ==="
sed -n '930,945p' tools/llm_provider.py

echo ""
echo "=== Line 949 context ==="
sed -n '945,955p' tools/llm_provider.py

Repository: stranske/Collab-Admin

Length of output: 1672


🏁 Script executed:

#!/bin/bash
# Verify that _model_name IS always set before analyze_completion returns CompletionAnalysis
echo "=== Full analyze_completion flow for OpenAI ==="
sed -n '612,655p' tools/llm_provider.py

# Check if there's any path where analyze_completion exits before setting _model_name
echo ""
echo "=== Check exception handling path ==="
sed -n '650,660p' tools/llm_provider.py

Repository: stranske/Collab-Admin

Length of output: 2053


🏁 Script executed:

#!/bin/bash
# Demonstrate the eager evaluation behavior with the exact code pattern
python3 << 'PY'
def expensive_fallback():
    print("WARNING: expensive_fallback was evaluated")
    return "fallback_value"

class Provider:
    def __init__(self):
        self._model_name = "already_set"

# Current pattern - default is ALWAYS evaluated
print("=== Current getattr() pattern ===")
provider = Provider()
result = getattr(provider, "_model_name", expensive_fallback())
print(f"Result: {result}")

print("\n=== Proposed pattern - lazy evaluation ===")
provider2 = Provider()
result2 = getattr(provider2, "_model_name", None) or expensive_fallback()
print(f"Result: {result2}")

# Verify the attribute IS set after _get_client
print("\n=== Checking if _model_name is always set when analyze_completion runs ===")
provider3 = Provider()
# Simulating: if _get_client() returns successfully, _model_name is already set
# Then analyze_completion calls getattr without needing the fallback
print(f"_model_name exists: {hasattr(provider3, '_model_name')}")
print(f"_model_name value: {getattr(provider3, '_model_name', 'NOT_SET')}")
PY

Repository: stranske/Collab-Admin

Length of output: 357


Optimize model name resolution to avoid unnecessary registry lookups.

The getattr() pattern evaluates _configured_langchain_model(...) as a default argument on every call to analyze_completion(), even though _model_name is guaranteed to be set by _get_client() before reaching this code. This causes redundant registry lookups on a frequently-called path.

Proposed fix
-                model_name=getattr(
-                    self,
-                    "_model_name",
-                    _configured_langchain_model("openai", fallback="gpt-5.1-codex"),
-                ),
+                model_name=(
+                    getattr(self, "_model_name", None)
+                    or _configured_langchain_model("openai", fallback="gpt-5.1-codex")
+                ),
-                model_name=getattr(
-                    self,
-                    "_model_name",
-                    _configured_langchain_model("anthropic", fallback="claude-sonnet-4-5-20250929"),
-                ),
+                model_name=(
+                    getattr(self, "_model_name", None)
+                    or _configured_langchain_model(
+                        "anthropic", fallback="claude-sonnet-4-5-20250929"
+                    )
+                ),

Also applies to: 722–726

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tools/llm_provider.py` around lines 638 - 642, The analyze_completion()
method uses getattr() with a default parameter that calls
_configured_langchain_model() on every invocation, but since _model_name is
guaranteed to be set by _get_client() before analyze_completion() is reached,
this creates unnecessary registry lookups on a frequently-called path. Replace
the getattr() pattern with direct attribute access to self._model_name (around
line 638 and also at line 722-726 where the same pattern applies) since the
attribute is guaranteed to already exist, eliminating the redundant function
call and improving performance.

@stranske-keepalive stranske-keepalive Bot deleted the sync/workflows-1243c652ce3c branch June 23, 2026 06:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automated Automated sync from Workflows sync Automated sync from Workflows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant