A Python framework for self-hosted LLM tool-calling and multi-step agentic workflows
This report summarizes scanner evidence for antoinezambelli/forge, a Python project with 2,255 GitHub stars. SynthScan examined 78,789 lines of code across 230 source files, recording 1981 pattern matches distributed across 18 syntactic categories. The legacy adjusted pattern signal is 32.8 (High pattern signal); it is not an authorship estimate.
Use the findings to ask whether maintainers can explain intent, verify dependencies, simplify unnecessary scaffolding, and focus review effort. Risk Payload v1 adds ownership, supply-chain, over-engineering, and review-effort vectors when available. These are prompts for human verification, not probabilities, security findings, or measured maintenance costs.
Use each vector to guide manual verification of the underlying findings.
Can maintainers explain intent, assumptions, and trade-offs? 1397 finding(s).
Are imports declared and package/API names verified? 271 finding(s).
Are wrappers, guards, and repeated structures necessary? 1597 finding(s).
Which changes need focused human review? 1981 finding(s).
This chart tracks the legacy adjusted pattern score across scan runs. Changes can reflect source changes, scan coverage, or detector/scoring versions; they do not measure AI adoption or prove that a team refactored code. Compare runs only when their scoring versions are compatible. The dashed line tracks the raw pattern-hit count.
Groups findings by configured severity weight. Severity is not a confidence estimate, security rating, or proof that a package is missing. Verify imports against the project's manifests and inspect each finding in its local design context.
This horizontal bar chart shows where configured pattern scores accumulate across directories. Treat the bars as locations to inspect, not as evidence of authorship or code quality. Use the file-level findings to decide whether a directory needs a focused ownership, dependency, complexity, or review check.
The scanner identified 1981 distinct pattern matches across 18 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a detector match to inspect in context. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the configured finding weight (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — legacy comment-context matches receive a ×1.5 score weight. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier under the legacy scoring model.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/conftest.py | 17 | def mock_httpx_client_constructor() -> Iterator[MagicMock]: | CODE |
| LOW | tests/http_mocks.py | 32 | def patch_httpx_client_constructor() -> Iterator[MagicMock]: | CODE |
| LOW | tests/unit/test_argument_transformation.py | 39 | def test_lambda_and_stateful_tools_share_output_contracts() -> None: | CODE |
| LOW | tests/unit/test_argument_transformation.py | 180 | def test_lambda_and_stateful_validators_accept_equivalent_formats() -> None: | CODE |
| LOW | tests/unit/test_argument_transformation.py | 195 | def test_lambda_and_stateful_validators_reject_benchmark_failure_modes() -> None: | CODE |
| LOW | tests/unit/test_argument_transformation.py | 233 | def test_stateful_tools_record_successful_reasoning_path() -> None: | CODE |
| LOW | tests/unit/test_argument_transformation.py | 257 | def test_stateful_tools_do_not_record_rejected_paths() -> None: | CODE |
| LOW | tests/unit/test_argument_transformation.py | 267 | def _exercise_required_stateful_calls(workflow: Any) -> None: | CODE |
| LOW | tests/unit/test_argument_transformation.py | 278 | def test_validate_state_requires_full_reasoning_path_and_submission() -> None: | CODE |
| LOW | tests/unit/test_argument_transformation.py | 297 | def test_validate_state_rejects_skipped_conversion() -> None: | CODE |
| LOW | tests/unit/test_argument_transformation.py | 308 | def test_validate_state_rejects_wrong_submission() -> None: | CODE |
| LOW⚡ | tests/unit/test_openai_compat_client.py | 90 | async def test_returns_text_response(self) -> None: | CODE |
| LOW⚡ | tests/unit/test_openai_compat_client.py | 100 | async def test_missing_choices_raises_backend_error(self) -> None: | CODE |
| LOW⚡ | tests/unit/test_openai_compat_client.py | 110 | async def test_null_content_returns_empty_text(self) -> None: | CODE |
| LOW⚡ | tests/unit/test_openai_compat_client.py | 120 | async def test_malformed_tool_args_kept_as_raw_args(self) -> None: | CODE |
| LOW⚡ | tests/unit/test_openai_compat_client.py | 454 | def test_bearer_header_set_when_key_provided(self) -> None: | CODE |
| LOW⚡ | tests/unit/test_openai_compat_client.py | 460 | def test_no_auth_header_when_no_key(self) -> None: | CODE |
| LOW⚡ | tests/unit/test_openai_compat_client.py | 464 | def test_base_url_trailing_slash_stripped(self) -> None: | CODE |
| LOW⚡ | tests/unit/test_openai_compat_client.py | 474 | async def test_yields_text_deltas_and_final(self) -> None: | CODE |
| LOW⚡ | tests/unit/test_openai_compat_client.py | 827 | def test_recommended_sampling_off_is_silent_for_unknown_model(self) -> None: | CODE |
| LOW⚡ | tests/unit/test_openai_compat_client.py | 837 | def test_recommended_sampling_on_raises_for_unknown_model(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 142 | async def test_malformed_tool_args_kept_even_with_assistant_text(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 163 | async def test_malformed_among_several_kept_per_call(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 185 | async def test_dict_tool_args_accepted(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 204 | async def test_formats_tools_in_request(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 219 | async def test_request_body_structure(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 234 | async def test_posts_to_chat_completions(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 256 | async def test_http_error_raises_backend_error(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 265 | async def test_structured_reasoning_field_captured(self, field) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 286 | async def test_extracts_think_tags_from_content_with_tool_call(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 306 | async def test_reasoning_field_preferred_over_content_tags(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 325 | async def test_content_preamble_not_treated_as_reasoning(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 347 | async def test_think_tags_stripped_from_text_response(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 362 | async def test_plain_preamble_text_response_survives(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 377 | async def test_reasoning_attached_to_first_tool_call_only(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 398 | async def test_empty_string_structured_field_falls_through_to_tags(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 419 | async def test_non_string_reasoning_field_raises(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 496 | async def test_yields_final_with_tool_call(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 525 | async def test_stream_malformed_tool_args_kept_as_raw_args(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 552 | async def test_stream_non_string_arg_fragment_not_dropped(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 574 | async def test_accumulates_reasoning_across_deltas(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 597 | async def test_stream_extracts_think_tags_from_content_with_tool_call(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 620 | async def test_stream_content_preamble_not_treated_as_reasoning(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 643 | async def test_stream_strips_think_tags_from_text_response(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 661 | async def test_stream_other_canonical_fields_accumulate(self, field) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 682 | async def test_stream_structured_preferred_over_content_tags(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 703 | async def test_stream_reasoning_first_tool_call_only(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 725 | async def test_stream_non_string_reasoning_raises(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 741 | async def test_stream_http_error_raises(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 752 | async def test_ignores_non_data_lines(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 777 | def test_extra_headers_merged_alongside_bearer(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 789 | def test_api_key_plus_auth_header_raises(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 802 | def test_extra_headers_alone_set_custom_scheme(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 811 | def test_sampling_kwargs_stored_as_instance_fields(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 859 | async def test_instance_sampling_flows_into_body(self, field, value) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 881 | async def test_passthrough_fields_appear_in_body(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 896 | async def test_forge_owned_fields_override_passthrough(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 917 | async def test_inbound_anthropic_body_accepted_and_ignored(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 933 | async def test_send_stream_accepts_passthrough_and_inbound(self) -> None: | CODE |
| LOW | tests/unit/test_openai_compat_client.py | 954 | async def test_aclose_closes_http_pool(self) -> None: | CODE |
| 1206 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | tests/conftest.py | 23 | # ── Shared LLM client double ───────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_openai_compat_client.py | 450 | # ── auth ───────────────────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_openai_compat_client.py | 469 | # ── send_stream ────────────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_openai_compat_client.py | 847 | # ── instance sampling flows into request body ──────────────────── | COMMENT |
| MEDIUM | tests/unit/test_openai_compat_client.py | 61 | # ── send ───────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_openai_compat_client.py | 773 | # ── constructor ────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_openai_compat_client.py | 876 | # ── passthrough + inbound_anthropic_body ───────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_openai_compat_client.py | 949 | # ── aclose ─────────────────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_inconsistent_api_recovery.py | 27 | # ── Lambda tool callables ─────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_inconsistent_api_recovery.py | 243 | # ── Stateful backend ──────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_inconsistent_api_recovery.py | 327 | # ── Stateful validate_state ───────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_inconsistent_api_recovery.py | 200 | # ── Validator (lambda) ────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_ollama_client.py | 849 | # ── outbound message normalization (#111 / #115) ───────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_ollama_client.py | 960 | # ── get_context_length + set_num_ctx ───────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_ollama_client.py | 982 | # ── format_tool ────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_ollama_client.py | 47 | # ── send ───────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_ollama_client.py | 476 | # ── send_stream ────────────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_proxy_auth.py | 101 | # ── relocate_credential ────────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_proxy_auth.py | 191 | # ── resolve_inbound_credential ─────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_proxy_auth.py | 28 | # ── extract_inbound_credentials ────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_proxy_auth.py | 300 | # ── handler threading ──────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_anthropic_client.py | 137 | # ── _convert_tools ─────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_anthropic_client.py | 177 | # ── _convert_messages ──────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_anthropic_client.py | 450 | # ── _parse_response ────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_anthropic_client.py | 727 | # ── Prompt caching (static tools+system breakpoint) ────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_llamafile_client.py | 1135 | # ── _merge_consecutive ──────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_llamafile_client.py | 1138 | # ── think flag behavior — sync ──────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_llamafile_client.py | 160 | # ── send — native mode ────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_llamafile_client.py | 659 | # ── send — prompt mode ────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_llamafile_client.py | 749 | # ── get_context_length ─────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_llamafile_client.py | 792 | # ── send_stream ────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_llamafile_client.py | 969 | # ── send_stream — malformed-500 transport boundaries ────────── | COMMENT |
| MEDIUM | tests/unit/test_llamafile_client.py | 1049 | # ── mode ───────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_llamafile_client.py | 1059 | # ── _apply_sampling ────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_llamafile_client.py | 1391 | # ── think flag behavior — stream ────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_llamafile_client.py | 1486 | # ── id_slot ──────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_llamafile_client.py | 1658 | # ── Issue #121: Path.stem truncates dotted model names ───────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_guardrails.py | 22 | # ── check(): response validation ───────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_guardrails.py | 126 | # ── check(): step enforcement ──────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_guardrails.py | 162 | # ── record() ───────────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_guardrails.py | 191 | # ── CheckResult dataclass ──────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_guardrails.py | 220 | # ── Custom retry nudge ─────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_guardrails.py | 9 | # ── Helpers ────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_guardrails.py | 206 | # ── Imports ────────────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_proxy_path1.py | 27 | # ── ProxyServer construction validation ────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_proxy_path1.py | 94 | # ── AnthropicClient verbatim path ──────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_proxy_path1.py | 182 | # ── AnthropicClient base_url ───────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_proxy_path1.py | 198 | # ── End-to-end: cache_control wire preservation ────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_proxy_convert_anthropic.py | 19 | # ── Inbound: Anthropic → forge ───────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_proxy_convert_anthropic.py | 237 | # ── Outbound: forge → Anthropic ──────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_proxy_convert_anthropic.py | 293 | # ── SSE event sequence ───────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_context_manager.py | 89 | # ── estimate_tokens ───────────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_context_manager.py | 187 | # ── maybe_compact — under threshold ───────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_context_manager.py | 200 | # ── maybe_compact — over threshold ────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_context_manager.py | 14 | # ── Helpers ────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/unit/test_context_manager.py | 268 | # ── CompactEvent fields ───────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_vllm_client.py | 89 | # ── constructor / identity derivation ────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_vllm_client.py | 119 | # ── send (non-streaming) ────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_vllm_client.py | 689 | # ── get_served_model_name ────────────────────────────────────── | COMMENT |
| MEDIUM⚡ | tests/unit/test_vllm_client.py | 715 | # ── removed proxy discovery helper ───────────────────────────── | COMMENT |
| 186 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/conftest.py | 3 | CODE | |
| LOW | tests/http_mocks.py | 3 | CODE | |
| LOW | tests/unit/test_argument_transformation.py | 3 | CODE | |
| LOW | tests/unit/test_inconsistent_api_recovery.py | 13 | CODE | |
| LOW | tests/unit/test_proxy_installation_docs.py | 3 | CODE | |
| LOW | tests/unit/test_eval_outcomes.py | 3 | CODE | |
| LOW | tests/unit/test_standalone_build.py | 3 | CODE | |
| LOW | tests/unit/test_eval_dataset_builder.py | 3 | CODE | |
| LOW | tests/unit/test_clients_base.py | 3 | CODE | |
| LOW | tests/unit/test_batch_eval_recipes.py | 3 | CODE | |
| LOW | tests/unit/test_server_rpc.py | 3 | CODE | |
| LOW | tests/unit/test_eval_reporting_metrics.py | 3 | CODE | |
| LOW | tests/unit/test_proxy_profiles.py | 3 | CODE | |
| LOW | tests/unit/test_proxy_path1.py | 13 | CODE | |
| LOW | tests/unit/test_data_gap_recovery_extended.py | 3 | CODE | |
| LOW | tests/unit/test_proxy_cli.py | 3 | CODE | |
| LOW | tests/unit/test_proxy_installer.py | 3 | CODE | |
| LOW | tests/unit/test_backend_profiles.py | 3 | CODE | |
| LOW | tests/unit/test_server.py | 3 | CODE | |
| LOW | tests/unit/test_proxy_config.py | 3 | CODE | |
| LOW | tests/unit/test_slot_worker.py | 3 | CODE | |
| LOW | tests/unit/test_slot_worker.py | 6 | CODE | |
| LOW | tests/unit/test_slot_worker.py | 8 | CODE | |
| LOW | tests/unit/test_slot_worker.py | 14 | CODE | |
| LOW | tests/unit/test_slot_worker.py | 389 | CODE | |
| LOW | tests/unit/test_runner.py | 3 | CODE | |
| LOW | tests/unit/test_eval_budget.py | 3 | CODE | |
| LOW | tests/unit/test_eval_budget.py | 15 | CODE | |
| LOW | tests/unit/test_proxy_release.py | 3 | CODE | |
| LOW | tests/unit/test_proxy_proxy.py | 9 | CODE | |
| LOW | tests/unit/test_proxy_release_workflows.py | 3 | CODE | |
| LOW | tests/unit/test_batch_eval_resume.py | 3 | CODE | |
| LOW | tests/unit/test_rpc.py | 3 | CODE | |
| LOW | tests/unit/test_client_auth.py | 16 | CODE | |
| LOW | tests/unit/test_eval_publication.py | 3 | CODE | |
| LOW | tests/unit/test_proxy_lifecycle_smoke.py | 3 | CODE | |
| LOW | tests/unit/test_eval_generation.py | 3 | CODE | |
| LOW | tests/unit/test_grounded_synthesis.py | 12 | CODE | |
| LOW | tests/unit/test_batch_eval_lifecycle.py | 3 | CODE | |
| LOW | tests/integration/_bootstrap_support.py | 3 | CODE | |
| LOW | …egration/bootstrap_contract/test_bootstrap_contract.py | 8 | CODE | |
| LOW | …egration/platform_acceptance/test_windows_installer.py | 3 | CODE | |
| LOW | tests/eval/metrics.py | 3 | CODE | |
| LOW | tests/eval/generation.py | 7 | CODE | |
| LOW | tests/eval/batch_eval.py | 11 | CODE | |
| LOW | tests/eval/batch_eval.py | 19 | CODE | |
| LOW | tests/eval/batch_eval.py | 33 | CODE | |
| LOW | tests/eval/batch_eval.py | 38 | CODE | |
| LOW | tests/eval/ablation.py | 3 | CODE | |
| LOW | tests/eval/dataset_builder.py | 13 | CODE | |
| LOW | tests/eval/outcomes.py | 8 | CODE | |
| LOW | tests/eval/significance.py | 15 | CODE | |
| LOW | tests/eval/publication.py | 15 | CODE | |
| LOW | tests/eval/eval_runner.py | 3 | CODE | |
| LOW | tests/eval/eval_runner.py | 12 | CODE | |
| LOW | tests/eval/eval_runner.py | 18 | CODE | |
| LOW | tests/eval/provenance.py | 3 | CODE | |
| LOW | tests/eval/report.py | 17 | CODE | |
| LOW | tests/eval/scenarios/_base.py | 3 | CODE | |
| LOW | tests/eval/scenarios/_stateful_plumbing.py | 3 | CODE | |
| 187 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | tests/unit/test_context_manager.py | 316 | except AttributeError: | CODE |
| HIGH | tests/eval/batch_eval.py | 961 | except Exception: | CODE |
| HIGH | scripts/integration_test_proxy.py | 148 | except (httpx.ConnectError, httpx.ReadTimeout, httpx.RemoteProtocolError): | CODE |
| HIGH | scripts/smoke_test_proxy.py | 318 | except Exception: | CODE |
| HIGH | scripts/standalone/lifecycle_smoke.py | 612 | except OSError: | CODE |
| HIGH | src/forge/server.py | 996 | except (httpx.HTTPError, ValueError): | CODE |
| HIGH | src/forge/server.py | 1088 | except BaseException: | CODE |
| HIGH | src/forge/core/slot_worker.py | 54 | except asyncio.CancelledError: | CODE |
| HIGH | src/forge/proxy/server.py | 392 | except (asyncio.TimeoutError, asyncio.IncompleteReadError, ConnectionError): | CODE |
| HIGH | src/forge/proxy/server.py | 296 | except asyncio.CancelledError: | CODE |
| HIGH | src/forge/proxy/server.py | 404 | except Exception: | CODE |
| HIGH | src/forge/proxy/server.py | 398 | except Exception: | CODE |
| HIGH | src/forge/proxy/_installer.py | 1062 | except OSError: | CODE |
| HIGH | src/forge/prompts/templates.py | 269 | except json.JSONDecodeError: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | README.md | 3 | [](https://pypi.org/project/forge-guardrails/) | CODE |
| MEDIUM | README.md | 15 | - **Not a coding harness.** Forge is domain-agnostic. If you're building a coding agent (or already using one like openc | CODE |
| MEDIUM | README.md | 174 | Drop-in proxy that sits between any client and a local model server, speaking both the OpenAI chat-completions API and t | CODE |
| MEDIUM | README.md | 325 | runner.py # WorkflowRunner — the agentic loop | CODE |
| MEDIUM | CONTRIBUTING.md | 122 | ### Adding or modifying guardrails | COMMENT |
| MEDIUM | tests/unit/test_openai_compat_client.py | 421 | # it into replayable chain-of-thought. | COMMENT |
| MEDIUM | tests/unit/test_openai_compat_client.py | 727 | # never repr-coerced into chain-of-thought. | COMMENT |
| MEDIUM | tests/eval/report.py | 1327 | ("## Full Ablation — which guardrails do the work?", lambda rp: rp == "ablation.md"), | CODE |
| MEDIUM | tests/eval/scenarios/_model_reasoning.py | 569 | # guardrails-vs-bare ablation: bare runs hit the first error and | COMMENT |
| MEDIUM | docs/USER_GUIDE.md | 138 | ### Mode 3: Middleware (composable guardrails) | COMMENT |
| MEDIUM | docs/WORKFLOW.md | 474 | └── reasoning: str | None # chain-of-thought (thinking models) | CODE |
| MEDIUM | docs/EVAL_GUIDE.md | 87 | # Ablation — bare (all guardrails off) | COMMENT |
| MEDIUM | docs/decisions/MULTI_MODEL_ROUTING.md | 170 | # Consumer orchestration code | COMMENT |
| MEDIUM | src/forge/clients/sampling_defaults.py | 80 | # documented default reasoning effort for complex coding and agentic work. | COMMENT |
| MEDIUM | src/forge/clients/sampling_defaults.py | 120 | # DeepSeek-V4-Flash-0731 — agentic profile: T=1.0, top_p=0.95. The card | COMMENT |
| MEDIUM | src/forge/clients/sampling_defaults.py | 190 | # explicit chain of thought). Card recommends temperature=0.2, top_k=80, repetition_penalty=1.05 | COMMENT |
| MEDIUM | src/forge/clients/openai_compat.py | 397 | # chain-of-thought. | COMMENT |
| MEDIUM | src/forge/proxy/handler.py | 431 | # in tool-calling mode where guardrails apply. The respond call is | COMMENT |
| MEDIUM | src/forge/proxy/handler.py | 445 | # No tools → plain chat completion, no guardrails needed. | COMMENT |
| MEDIUM | src/forge/proxy/handler.py | 476 | # Set up guardrails | COMMENT |
| MEDIUM | src/forge/proxy/handler.py | 500 | # error. The client's own agentic loop can decide what to do. | COMMENT |
| MEDIUM | src/forge/proxy/proxy.py | 346 | # guardrails wrap its inference loop like any other client. | COMMENT |
| MEDIUM | src/forge/proxy/proxy.py | 348 | # (forge-guardrails[anthropic]). Only Path 1 needs it, so | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/unit/test_eval_dataset_builder.py | 314 | CODE | |
| LOW | tests/unit/test_proxy_release.py | 69 | CODE | |
| LOW | tests/eval/metrics.py | 275 | CODE | |
| LOW | tests/eval/batch_eval.py | 639 | CODE | |
| LOW | tests/eval/batch_eval.py | 1065 | CODE | |
| LOW | tests/eval/dataset_builder.py | 684 | CODE | |
| LOW | tests/eval/dataset_builder.py | 746 | CODE | |
| LOW | tests/eval/significance.py | 106 | CODE | |
| LOW | tests/eval/publication.py | 465 | CODE | |
| LOW | tests/eval/eval_runner.py | 413 | CODE | |
| LOW | tests/eval/report.py | 278 | CODE | |
| LOW | tests/eval/report.py | 762 | CODE | |
| LOW | scripts/run_ablation.py | 102 | CODE | |
| LOW | scripts/migrate_eval_jsonl_gguf_identity.py | 100 | CODE | |
| LOW | scripts/standalone/release.py | 297 | CODE | |
| LOW | scripts/standalone/release.py | 401 | CODE | |
| LOW | scripts/standalone/evidence.py | 23 | CODE | |
| LOW | scripts/standalone/evidence.py | 29 | CODE | |
| LOW | src/forge/server.py | 1004 | CODE | |
| LOW | src/forge/clients/llamafile.py | 215 | CODE | |
| LOW | src/forge/clients/llamafile.py | 258 | CODE | |
| LOW | src/forge/clients/anthropic.py | 261 | CODE | |
| LOW | src/forge/clients/anthropic.py | 388 | CODE | |
| LOW | src/forge/clients/anthropic.py | 558 | CODE | |
| LOW | src/forge/clients/ollama.py | 37 | CODE | |
| LOW | src/forge/clients/ollama.py | 399 | CODE | |
| LOW | src/forge/clients/base.py | 249 | CODE | |
| LOW | src/forge/context/strategies.py | 248 | CODE | |
| LOW | src/forge/core/steps.py | 53 | CODE | |
| LOW | src/forge/core/runner.py | 89 | CODE | |
| LOW | src/forge/core/workflow.py | 68 | CODE | |
| LOW | src/forge/proxy/server.py | 324 | CODE | |
| LOW | src/forge/proxy/server.py | 542 | CODE | |
| LOW | src/forge/proxy/server.py | 807 | CODE | |
| LOW | src/forge/proxy/convert.py | 17 | CODE | |
| LOW | src/forge/proxy/convert_anthropic.py | 20 | CODE | |
| LOW | src/forge/proxy/_profiles.py | 60 | CODE | |
| LOW | src/forge/proxy/_installer.py | 815 | CODE | |
| LOW | src/forge/proxy/__main__.py | 152 | CODE | |
| LOW | src/forge/prompts/templates.py | 12 | CODE | |
| LOW | src/forge/prompts/templates.py | 55 | CODE | |
| LOW | src/forge/prompts/templates.py | 185 | CODE | |
| LOW | src/forge/prompts/templates.py | 238 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | tests/eval/batch_eval.py | 961 | except Exception: | CODE |
| LOW⚡ | tests/eval/batch_eval.py | 971 | except Exception as exc: | CODE |
| LOW | tests/eval/dataset_builder.py | 709 | except Exception as exc: | STRING |
| LOW | tests/eval/dataset_builder.py | 950 | except Exception as exc: | STRING |
| LOW | tests/eval/dataset_builder.py | 989 | except Exception as exc: | CODE |
| MEDIUM | tests/eval/dataset_builder.py | 91 | def _require_pyarrow() -> tuple[Any, Any]: | CODE |
| LOW | tests/eval/eval_runner.py | 218 | except Exception as exc: | CODE |
| LOW | tests/eval/eval_runner.py | 223 | except Exception as exc: | CODE |
| LOW | tests/eval/eval_runner.py | 377 | except Exception as exc: | CODE |
| LOW | tests/eval/eval_runner.py | 674 | except Exception as exc: | CODE |
| LOW | docs/ARCHITECTURE.md | 27 | except Exception: | CODE |
| LOW | scripts/integration_test_proxy.py | 291 | except Exception as exc: | CODE |
| LOW | scripts/integration_test_proxy.py | 839 | except Exception as exc: | CODE |
| LOW | scripts/run_ablation.py | 170 | except Exception as e: | CODE |
| LOW | scripts/smoke_test_proxy.py | 161 | except Exception as exc: # make fixture bugs visible at the HTTP boundary | CODE |
| LOW | scripts/smoke_test_proxy.py | 318 | except Exception: | CODE |
| LOW | scripts/standalone/lifecycle_smoke.py | 263 | except Exception: | CODE |
| LOW | src/forge/server.py | 451 | except Exception as exc: | CODE |
| LOW | src/forge/server.py | 459 | except Exception as exc: | CODE |
| LOW | src/forge/server.py | 559 | except Exception: | CODE |
| LOW | src/forge/core/runner.py | 346 | except Exception as exc: | CODE |
| LOW | src/forge/core/slot_worker.py | 137 | except Exception as exc: | CODE |
| LOW | src/forge/proxy/server.py | 273 | except Exception: | CODE |
| LOW | src/forge/proxy/server.py | 318 | except Exception as exc: | CODE |
| LOW⚡ | src/forge/proxy/server.py | 394 | except Exception: | CODE |
| LOW⚡ | src/forge/proxy/server.py | 398 | except Exception: | CODE |
| LOW⚡ | src/forge/proxy/server.py | 404 | except Exception: | CODE |
| LOW | src/forge/proxy/server.py | 652 | except Exception: | CODE |
| LOW | src/forge/proxy/server.py | 804 | except Exception as exc: | CODE |
| LOW | src/forge/proxy/server.py | 900 | except Exception as exc: | CODE |
| LOW | src/forge/proxy/_installer.py | 896 | except Exception: | CODE |
| LOW | src/forge/proxy/__main__.py | 347 | except Exception as exc: | STRING |
| LOW | src/forge/proxy/__main__.py | 370 | except Exception as exc: | STRING |
| LOW | src/forge/proxy/__main__.py | 389 | except Exception as exc: | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | tests/eval/dataset_builder.py | 696 | if not parquet_file.schema_arrow.equals(schema, check_metadata=True): | STRING |
| HIGH⚡ | src/forge/proxy/_installer.py | 760 | 'while kill -0 "$parent" 2>/dev/null; do sleep 0.1; done', | CODE |
| HIGH⚡ | src/forge/proxy/_installer.py | 763 | '[ "$(cat "$marker" 2>/dev/null)" = "$expected" ] || exit 2', | CODE |
| HIGH | src/forge/proxy/_installer.py | 788 | f"rmdir -- {q(str(paths.command_dir))} 2>/dev/null || true", | CODE |
| HIGH | src/forge/proxy/_installer.py | 789 | f"rmdir -- {q(str(paths.root))} 2>/dev/null || true", | CODE |
| HIGH | src/forge/prompts/nudges.py | 69 | args content (e.g. an empty string, null, a list, or a primitive | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | tests/eval/scenarios/_compaction_chain.py | 532 | # Step 1: patient MRN (not in user message) | COMMENT |
| LOW⚡ | tests/eval/scenarios/_compaction_chain.py | 534 | # Step 3: lab values (only from tool result) | COMMENT |
| LOW⚡ | tests/eval/scenarios/_compaction_chain.py | 536 | # Step 4: imaging findings (only from tool result) | COMMENT |
| LOW⚡ | tests/eval/scenarios/_compaction_chain.py | 538 | # Step 5: specialist (only from tool result) | COMMENT |
| LOW⚡ | tests/eval/scenarios/_compaction_chain.py | 540 | # Step 6: medication concern (only from tool result) | COMMENT |
| LOW | docs/decisions/003-thinking-label-ux.md | 64 | ### Step 1: Add `_resolve_reasoning()` to OllamaClient | COMMENT |
| LOW | docs/decisions/003-thinking-label-ux.md | 86 | ### Step 2: Use it in `send()` (batch path) | COMMENT |
| LOW | docs/decisions/003-thinking-label-ux.md | 102 | ### Step 3: Use it in `_iter_stream()` (streaming path) | COMMENT |
| LOW | docs/decisions/003-thinking-label-ux.md | 124 | ### Step 4: Add unit tests | COMMENT |
| LOW | docs/decisions/003-thinking-label-ux.md | 187 | ### Step 5: Update README roadmap | COMMENT |
| LOW | docs/decisions/004-async-on-chunk.md | 75 | ### Step 1: Change type signature | COMMENT |
| LOW | docs/decisions/004-async-on-chunk.md | 91 | ### Step 2: Await the callback in `_send_streaming()` | COMMENT |
| LOW | docs/decisions/004-async-on-chunk.md | 107 | ### Step 3: Update `_make_runner` helper type hint | COMMENT |
| LOW | docs/decisions/004-async-on-chunk.md | 127 | ### Step 4: Update the test | COMMENT |
| LOW | docs/decisions/004-async-on-chunk.md | 171 | ### Step 5: Update docstring | COMMENT |
| LOW | docs/decisions/004-async-on-chunk.md | 180 | ### Step 6: Update README roadmap | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | src/forge/server.py | 656 | Resolve the ContextManager budget for the given mode. Args: mode: The budget mode to use. | STRING |
| HIGH | src/forge/server.py | 711 | Start server with the specified budget mode and return the resolved budget. Handles the mode-specific startup d | STRING |
| HIGH | src/forge/clients/sampling_defaults.py | 254 | Apply the recommended-sampling policy for ``model``. Called by client constructors at instantiation time. The four- | STRING |
| HIGH | src/forge/core/inference.py | 200 | Send messages to the LLM with compaction, folding, validation, and retry. Retries are handled internally — the call | STRING |
| HIGH | src/forge/core/slot_worker.py | 65 | Submit a workflow for execution and wait for the result. Args: workflow: The workflow to execute. | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/unit/test_argument_transformation.py | 68 | "Acme Corp", | CODE |
| LOW | tests/unit/test_argument_transformation.py | 87 | {"vendor_name": "Acme Corp"}, | CODE |
| LOW | tests/unit/test_argument_transformation.py | 237 | assert "Acme Corp" in system.get_approved_vendors() | CODE |
| LOW⚡ | tests/unit/test_inconsistent_api_recovery.py | 38 | assert "Acme Corp" in out | CODE |
| LOW⚡ | tests/unit/test_inconsistent_api_recovery.py | 261 | assert "Acme Corp" in out | CODE |
| LOW | tests/eval/scenarios/_base.py | 15 | placeholder_field: str = Field(description="placeholder") | CODE |
| LOW⚡ | tests/eval/scenarios/_base.py | 49 | spec=ToolSpec(name=terminal_tool, description="placeholder", | CODE |
| LOW⚡ | tests/eval/scenarios/_base.py | 56 | spec=ToolSpec(name=s, description="placeholder", | CODE |
| LOW⚡ | tests/eval/scenarios/_base.py | 64 | description="placeholder", | CODE |
| LOW | tests/eval/scenarios/_model_reasoning.py | 300 | # approved 'Acme Corp'. Literal string compare over-flags it; | COMMENT |
| LOW | tests/eval/scenarios/_model_reasoning.py | 313 | "Acme Corp", | CODE |
| LOW | tests/eval/scenarios/_model_reasoning.py | 326 | ("TX-1002", "2024-10-12", "Acme Corp", 12000, "USD", False), # approved | CODE |
| LOW | tests/eval/scenarios/_model_reasoning.py | 377 | if name == "Acme Corp": | CODE |
| LOW | tests/eval/scenarios/_model_reasoning.py | 621 | (12345, "Acme Corp"), | CODE |
| LOW⚡ | tests/eval/scenarios/_stateful_model_reasoning.py | 368 | "Acme Corp", | CODE |
| LOW⚡ | tests/eval/scenarios/_stateful_model_reasoning.py | 378 | ("TX-1002", "2024-10-12", "Acme Corp", 12000, "USD"), | CODE |
| LOW | tests/eval/scenarios/_stateful_model_reasoning.py | 441 | if name == "Acme Corp": | CODE |
| LOW | tests/eval/scenarios/_stateful_model_reasoning.py | 681 | (12345, "Acme Corp"), | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | src/forge/clients/vllm.py | 0 | per-call headers to apply, enforcing the one-credential rule. returns the dict to pass as httpx ``headers=`` (merged ove | STRING |
| HIGH | src/forge/clients/llamafile.py | 0 | per-call headers to apply, enforcing the one-credential rule. returns the dict to pass as httpx ``headers=`` (merged ove | STRING |
| HIGH | src/forge/clients/openai_compat.py | 0 | per-call headers to apply, enforcing the one-credential rule. returns the dict to pass as httpx ``headers=`` (merged ove | STRING |
| HIGH | src/forge/clients/ollama.py | 0 | per-call headers to apply, enforcing the one-credential rule. returns the dict to pass as httpx ``headers=`` (merged ove | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | install.sh | 1 | #!/bin/sh | COMMENT |
| LOW | tests/eval/report.py | 501 | # model under different identity strings: | COMMENT |
| LOW | tests/eval/scenarios/_model_reasoning.py | 61 | top_vendor: str = Field(description="Vendor of the single largest flagged transaction") | COMMENT |
| LOW | tests/eval/scenarios/_model_reasoning.py | 281 | tags=["advanced_reasoning", "reasoning", "model_quality"], | COMMENT |
| LOW | tests/eval/scenarios/_model_reasoning.py | 561 | COMMENT | |
| LOW | tests/eval/scenarios/_model_reasoning.py | 881 | "txn_count (int)." | COMMENT |
| LOW | tests/eval/scenarios/_model_reasoning.py | 901 | # Sarah Chen — top-decile attractor; BLOCKER: Stripe non-compete | COMMENT |
| LOW | examples/foreign_loop.py | 141 | # The respond tool eliminates this ambiguity: the model calls | COMMENT |
| LOW | src/forge/clients/sampling_defaults.py | 101 | "gemma4:e4b-it-q4_K_M": {"temperature": 1.0, "top_p": 0.95, "top_k": 64}, # https://huggingface.co/go | COMMENT |
| LOW | src/forge/clients/sampling_defaults.py | 121 | # supports low/high/max reasoning effort. This one registry value is the | COMMENT |
| LOW | src/forge/clients/sampling_defaults.py | 141 | # so the model emits something substantive instead of empty <think> blocks. Native tool format is | COMMENT |
| LOW | src/forge/clients/sampling_defaults.py | 181 | "ministral-3:8b-reasoning-2512-q8_0": {"temperature": 0.7}, # https://huggingface.co/mistralai/Ministral-3-8B-Re | COMMENT |
| LOW | src/forge/clients/sampling_defaults.py | 201 | "Mellum2-12B-A2.5B-Instruct-Q4_K_M": {"temperature": 0.6, "top_p": 0.95, "top_k": 20}, # https://huggingface.co/ | COMMENT |
| LOW | src/forge/clients/llamafile.py | 41 | # index is filesystem layout, not model identity, so strip it for the | COMMENT |
| LOW | src/forge/clients/llamafile.py | 61 | # The gate is STRUCTURAL, not phrase-based: a 500 is rescuable iff its body | COMMENT |
| LOW | src/forge/clients/anthropic.py | 41 | # lowercases all inbound header keys, so a relocated ``x-api-key`` would fail | COMMENT |
| LOW | src/forge/clients/anthropic.py | 121 | ) -> None: | COMMENT |
| LOW | src/forge/clients/anthropic.py | 141 | log.debug( | COMMENT |
| LOW | src/forge/guardrails/nudge.py | 41 | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/unit/test_runner.py | 69 | CODE | |
| LOW | tests/unit/test_proxy_server.py | 143 | CODE | |
| LOW | tests/eval/batch_eval.py | 1065 | CODE | |
| LOW | src/forge/server.py | 1004 | CODE | |
| LOW | src/forge/server.py | 1106 | CODE | |
| LOW | src/forge/server.py | 236 | CODE | |
| LOW | src/forge/server.py | 695 | CODE | |
| LOW | src/forge/clients/vllm.py | 67 | CODE | |
| LOW | src/forge/clients/llamafile.py | 332 | CODE | |
| LOW | src/forge/clients/openai_compat.py | 61 | CODE | |
| LOW | src/forge/clients/anthropic.py | 108 | CODE | |
| LOW | src/forge/clients/ollama.py | 106 | CODE | |
| LOW | src/forge/core/runner.py | 35 | CODE | |
| LOW | src/forge/core/inference.py | 179 | CODE | |
| LOW | src/forge/proxy/server.py | 184 | CODE | |
| LOW | src/forge/proxy/handler.py | 256 | CODE | |
| LOW | src/forge/proxy/proxy.py | 62 | CODE | |
| LOW | src/forge/proxy/_installer.py | 924 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/eval/scenarios/__init__.py | 81 | __all__ = [ | CODE |
| LOW | scripts/integration_test_proxy.py | 98 | def _setup_logging() -> None: | CODE |
| LOW | src/forge/server.py | 221 | def _set_resolved_daemon_target(self, target: ResolvedBackend) -> None: | CODE |
| LOW | src/forge/__init__.py | 78 | __all__ = [ | CODE |
| LOW | src/forge/clients/vllm.py | 173 | def _set_model_identity(self, wire_id: str | Path) -> None: | CODE |
| LOW | src/forge/clients/__init__.py | 14 | __all__ = [ | CODE |
| LOW | src/forge/clients/ollama.py | 462 | def set_num_ctx(self, num_ctx: int | None) -> None: | CODE |
| LOW | src/forge/tools/__init__.py | 9 | __all__ = [ | CODE |
| LOW | src/forge/context/__init__.py | 20 | __all__ = [ | CODE |
| LOW | src/forge/context/hardware.py | 21 | logger = logging.getLogger(__name__) | CODE |
| LOW | src/forge/context/manager.py | 131 | def update_token_count(self, total_tokens: int) -> None: | CODE |
| LOW | src/forge/core/__init__.py | 3 | __all__ = ["WorkflowRunner"] | CODE |
| LOW | src/forge/guardrails/__init__.py | 19 | __all__ = [ | CODE |
| LOW | src/forge/proxy/__init__.py | 5 | __all__ = ["ProxyServer"] | CODE |
| LOW | src/forge/prompts/__init__.py | 6 | __all__ = [ | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | tests/eval/scenarios/_compaction_chain.py | 532 | # Step 1: patient MRN (not in user message) | COMMENT |
| LOW⚡ | tests/eval/scenarios/_compaction_chain.py | 534 | # Step 3: lab values (only from tool result) | COMMENT |
| LOW⚡ | tests/eval/scenarios/_compaction_chain.py | 536 | # Step 4: imaging findings (only from tool result) | COMMENT |
| LOW⚡ | tests/eval/scenarios/_compaction_chain.py | 538 | # Step 5: specialist (only from tool result) | COMMENT |
| LOW⚡ | tests/eval/scenarios/_compaction_chain.py | 540 | # Step 6: medication concern (only from tool result) | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM⚡ | tests/unit/test_proxy_auth.py | 46 | # The proxy lowercases keys, but be robust to mixed case anyway. | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | examples/foreign_loop.py | 175 | # Check if the model called respond -- extract the message | COMMENT |