Skip to content

feat(daemon): resource-aware work_max_concurrency (CPU + memory, ported from codegraph's resolver-pool) - #436

Merged
getappz merged 7 commits into
masterfrom
task/66
Aug 11, 2026
Merged

feat(daemon): resource-aware work_max_concurrency (CPU + memory, ported from codegraph's resolver-pool)#436
getappz merged 7 commits into
masterfrom
task/66

Conversation

@getappz

@getappz getappz commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Closes #66.

work_max_concurrency() (src/dashboard/server.rs) previously defaulted to a flat hardcoded 2 regardless of the host's actual CPU/memory. Ports the sizing pattern from codegraph's ResolverPool.resolvePoolSize() + memory-budget.ts (.refs/codegraph/src/resolution/) into a new src/dashboard/concurrency.rs module.

  • resolve_pool_size(available_parallelism, memory_budget_bytes) — pure function: CPU term (available_parallelism - 1, capped at 6) vs. memory term (memory_budget * 0.7 / 512MiB-per-worker, floored at 1), smaller wins. Unlike codegraph's pool (which returns None/no-pool below a threshold and falls back to a sequential path), agentflare has no sequential fallback, so this floors at 1 instead of disabling work entirely.
  • memory_budget_bytes() — cgroup-aware on Linux (/sys/fs/cgroup/memory.{max,current,stat}, v2 then v1, crediting back inactive_file reclaimable cache) combined with /proc/meminfo's MemAvailable; vm_stat-based on macOS; other platforms get a sentinel so the memory term never constrains (CPU-only sizing, same as today's behavior on those platforms).

work_max_concurrency() now uses AGENTFLARE_WORK_MAX_CONCURRENCY as an explicit override when set, otherwise falls back to the resource-aware default instead of a flat 2. parse_work_max_concurrency changed from usize (defaulting to 2) to Option<usize>.

Note on provenance: this PR was pushed manually. The dispatched agent (item #66) did this work correctly and verified it (build clean, clippy clean, 41/41 dashboard tests pass, confirmed independently before pushing) but its session ran on a daemon binary predating #431's auto-commit-on-done fix, so the real work was left uncommitted in the worktree and the item was incorrectly marked completed with no PR. Rescued from the worktree rather than re-doing the work.

Test plan

  • cargo build --bin agentflare — clean
  • cargo test --bin agentflare dashboard:: — 41 passed, 0 failed

Summary by CodeRabbit

  • Improvements
    • Dashboard processing now automatically adjusts its worker pool based on available CPU and memory resources.
    • Memory-aware sizing helps prevent excessive resource usage while maintaining at least one worker.
    • Worker-count overrides are validated more reliably; missing, zero, or invalid values fall back to automatic sizing.
  • Bug Fixes
    • Improved resource detection across supported operating systems and container environments.

…ed from codegraph's resolver-pool)

Agentflare-Agent: claude-code
Agentflare-Branch: task/66
Agentflare-Item: 66
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The dashboard now calculates worker-pool size from CPU parallelism and available memory. Linux and macOS use platform-specific memory measurements. Invalid or absent concurrency overrides use the calculated pool size.

Changes

Resource-aware concurrency

Layer / File(s) Summary
Pool-size calculation
src/dashboard/concurrency.rs
Adds CPU and memory limits, a six-worker CPU cap, a 512 MiB worker footprint, and a minimum pool size of one.
Platform memory accounting
src/dashboard/concurrency.rs
Adds Linux cgroup and /proc/meminfo accounting, macOS vm_stat parsing, fallback handling, and unit tests.
Server integration and validation
src/dashboard/mod.rs, src/dashboard/server.rs
Registers the concurrency module. Positive overrides remain supported; absent, zero, and invalid values use resource-aware sizing. Tests cover parsing and minimum sizing.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DashboardServer
  participant ConcurrencyResolver
  participant PlatformMemory
  DashboardServer->>ConcurrencyResolver: Resolve worker-pool size
  ConcurrencyResolver->>PlatformMemory: Read memory budget
  PlatformMemory-->>ConcurrencyResolver: Return available memory
  ConcurrencyResolver-->>DashboardServer: Return selected pool size
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description check ✅ Passed The description clearly explains the resource-aware concurrency changes and includes a test plan, but it omits the template's reviewer notes and some requested checks.
Title check ✅ Passed The title is specific, concise, and accurately summarizes the main change to resource-aware work_max_concurrency.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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 task/66

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

@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: 2

🤖 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 `@src/dashboard/concurrency.rs`:
- Around line 252-256: Remove the host-state assertion from
memory_budget_bytes_is_positive_and_finite_on_this_platform, including the b > 0
check. Keep the test focused on stable resolver behavior and preserve support
for a zero memory budget.
- Around line 122-130: Update memory_budget_bytes so an unavailable or
unparsable /proc/meminfo result does not become a zero-byte budget; preserve the
CPU-only fallback expected by resolve_pool_size. Represent the memory-read
failure distinctly and ensure cgroup memory is only used when a valid memory
value is available, allowing resolve_pool_size to select its CPU-based worker
count when Linux memory files cannot be read.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6eff6d7b-db4a-4d5d-91aa-03d763deecb2

📥 Commits

Reviewing files that changed from the base of the PR and between 9c05039 and 092f52d.

📒 Files selected for processing (3)
  • src/dashboard/concurrency.rs
  • src/dashboard/mod.rs
  • src/dashboard/server.rs

Comment on lines +122 to +130
pub fn memory_budget_bytes() -> u64 {
let free = fs::read_to_string("/proc/meminfo")
.ok()
.and_then(|s| parse_mem_available(&s))
.unwrap_or(0);
match cgroup_memory_available() {
Some(cgroup) => free.min(cgroup),
None => free,
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Preserve the CPU-only fallback when Linux memory reads fail.

Line 126 converts an unavailable /proc/meminfo reading into 0. resolve_pool_size then converts that value into one worker. This contradicts the documented CPU-only fallback and needlessly restricts a Linux deployment with unavailable memory files.

Proposed fix
-#[cfg(not(target_os = "linux"))]
 const UNMEASURED_MEMORY_SENTINEL: u64 = u64::MAX;
 
 #[cfg(target_os = "linux")]
 pub fn memory_budget_bytes() -> u64 {
-    let free = fs::read_to_string("/proc/meminfo")
+    let host_available = fs::read_to_string("/proc/meminfo")
         .ok()
-        .and_then(|s| parse_mem_available(&s))
-        .unwrap_or(0);
-    match cgroup_memory_available() {
-        Some(cgroup) => free.min(cgroup),
-        None => free,
+        .and_then(|s| parse_mem_available(&s));
+
+    match (host_available, cgroup_memory_available()) {
+        (Some(host), Some(cgroup)) => host.min(cgroup),
+        (Some(host), None) => host,
+        (None, Some(cgroup)) => cgroup,
+        (None, None) => UNMEASURED_MEMORY_SENTINEL,
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub fn memory_budget_bytes() -> u64 {
let free = fs::read_to_string("/proc/meminfo")
.ok()
.and_then(|s| parse_mem_available(&s))
.unwrap_or(0);
match cgroup_memory_available() {
Some(cgroup) => free.min(cgroup),
None => free,
}
pub fn memory_budget_bytes() -> u64 {
let host_available = fs::read_to_string("/proc/meminfo")
.ok()
.and_then(|s| parse_mem_available(&s));
match (host_available, cgroup_memory_available()) {
(Some(host), Some(cgroup)) => host.min(cgroup),
(Some(host), None) => host,
(None, Some(cgroup)) => cgroup,
(None, None) => UNMEASURED_MEMORY_SENTINEL,
}
🤖 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 `@src/dashboard/concurrency.rs` around lines 122 - 130, Update
memory_budget_bytes so an unavailable or unparsable /proc/meminfo result does
not become a zero-byte budget; preserve the CPU-only fallback expected by
resolve_pool_size. Represent the memory-read failure distinctly and ensure
cgroup memory is only used when a valid memory value is available, allowing
resolve_pool_size to select its CPU-based worker count when Linux memory files
cannot be read.

Comment on lines +252 to +256
#[test]
fn memory_budget_bytes_is_positive_and_finite_on_this_platform() {
let b = memory_budget_bytes();
assert!(b > 0);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Remove the host-state assertion.

Line 255 can fail when Linux correctly reports MemAvailable: 0. The resolver explicitly supports a zero memory budget at Lines 207-209. This test depends on live host state instead of a stable contract.

Proposed fix
-    #[test]
-    fn memory_budget_bytes_is_positive_and_finite_on_this_platform() {
-        let b = memory_budget_bytes();
-        assert!(b > 0);
-    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[test]
fn memory_budget_bytes_is_positive_and_finite_on_this_platform() {
let b = memory_budget_bytes();
assert!(b > 0);
}
🤖 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 `@src/dashboard/concurrency.rs` around lines 252 - 256, Remove the host-state
assertion from memory_budget_bytes_is_positive_and_finite_on_this_platform,
including the b > 0 check. Keep the test focused on stable resolver behavior and
preserve support for a zero memory budget.

getappz added a commit that referenced this pull request Aug 11, 2026
…ini/Cloudflare AI Gateway support (#439)

* feat(flare-proxy): provider registry with native Anthropic/Gemini, zero new deps (item #438)

Replaces the hardcoded 3-provider ProviderKind match (NvidiaNim/OpenRouter/
LmStudio) with a small provider-kind registry: OpenAiCompatible (covers
NVIDIA NIM, OpenRouter, LM Studio, and any future OpenAI-compatible
endpoint via config alone), Anthropic, and Gemini.

Patterns vendored (not depended on) from litellm-rust (avivsinai, MIT) --
see items #436 (rig-core, rejected: streaming not raw-JSON-shaped) and
#437 (litellm-rs rejected for dependency weight; litellm-rust's design is
the reference). Zero new Cargo.toml/Cargo.lock entries: reuses reqwest/
serde_json/futures already in flare-proxy instead of importing an SSE
macro crate, an error crate, or a trait-object abstraction.

- providers/openai_compat.rs: header/auth wiring only -- request/response
  translation stays shape_xlat's existing Anthropic<->OpenAI logic.
- providers/anthropic.rs: near-passthrough. Since flare-proxy's own wire
  format already IS Anthropic Messages, native Anthropic upstream needs no
  shape_xlat at all -- forward.rs proxies the byte stream unchanged.
- providers/gemini.rs: new Anthropic<->Gemini translator, scoped to text +
  tool_calls (no image/audio/video/file parts -- out of scope for this
  proxy's actual traffic). New shape_xlat::gemini_chunk_to_anthropic_sse /
  gemini_finish_stream read Gemini's candidates[0].content.parts shape
  instead of OpenAI's choices[0].delta.

forward.rs restructured to dispatch per ProviderKind before body
translation (each upstream needs a different request shape and URL path,
not just different headers), with a shared stream_translated_sse() helper
for the two paths that do need chunk-by-chunk translation.

65/65 tests pass, clippy clean (-A unsafe_code -A clippy::pedantic),
fmt clean.

Agentflare-Agent: claude-code_2-1-225_agent
Agentflare-Branch: task/438
Agentflare-Item: 438

* feat(flare-proxy): Cloudflare AI Gateway support via cf_gateway_anthropic/cf_gateway_openai (item #438)

Cloudflare AI Gateway is a URL prefix in front of a provider's own wire
protocol, not a distinct protocol -- gateway.ai.cloudflare.com/v1/{acct}/
{gw}/anthropic still speaks Anthropic's real Messages API shape,
.../compat still speaks OpenAI's /chat/completions shape. So this needed
no new ProviderKind: just two new provider prefixes whose base_url is
built from CF_AI_GATEWAY_ACCOUNT_ID/CF_AI_GATEWAY_ID, reusing the
Anthropic and OpenAiCompatible paths added earlier in this item unchanged.

cf-aig-authorization (Cloudflare's own gateway-level auth, separate from
the underlying provider's API key) is optional, set from
CF_AI_GATEWAY_TOKEN via the extra_headers mechanism already added for
OpenRouter. Missing CF_AI_GATEWAY_ACCOUNT_ID/ID fails fast to
default_free() at startup rather than shipping an unusable base_url.

Closes the Cloudflare AI Gateway gap identified earlier this session
(flare-proxy previously had zero Cloudflare support of any kind).

68/68 tests pass, clippy clean, fmt clean. Zero new dependencies (single
file changed).

Agentflare-Agent: claude-code_2-1-225_agent
Agentflare-Branch: task/438
Agentflare-Item: 438

* refactor(flare-proxy): registry.toml-driven providers, no more hardcoded match arms (item #438)

Per appz-cli's registry/toolchains.toml pattern (crates/appz-core/src/
toolchain_registry.rs) -- scoped down to just what flare-proxy needs: no
HTTP-fetch-with-cache-TTL layer, just an embedded TOML file (include_str!)
parsed once via OnceLock. Adding a provider -- another OpenAI-compatible
endpoint, another Cloudflare AI Gateway route -- is now a
registry/providers.toml edit, not a Rust change.

providers/registry.rs owns the load/lookup/resolve logic:
- RegistrySpec mirrors ProviderEntry's shape (prefix, id, kind, base_url,
  api_key_env, extra_headers) plus two fields the hardcoded version didn't
  need: base_url_template ({ENV_VAR} placeholders, for Cloudflare's
  per-user account_id/gateway_id) and gateway_auth_env/gateway_auth_header
  (an extra header sourced from an env var, distinct from the provider's
  own api_key_env -- Cloudflare's cf-aig-authorization).
- resolve() returns None when a template references an unset env var, so
  from_env()'s existing 'fail fast to default_free()' behavior is
  preserved without each provider needing its own bespoke resolver
  function (deleted cloudflare_gateway_base_url/_headers and
  openrouter_headers -- all three are now registry.toml entries).

default_free() now also builds its 3 built-in providers by resolving them
out of the same registry, instead of duplicating base_url/api_key_env/
extra_headers as separate hardcoded ProviderEntry literals -- one source
of truth for provider identity, whether reached via MODEL=... or the
zero-config default path.

toml crate added to flare-proxy's Cargo.toml -- already a workspace
dependency (root Cargo.toml), so this adds zero new entries to
Cargo.lock.

74/74 tests pass, clippy clean, fmt clean.

Agentflare-Agent: claude-code_2-1-225_agent
Agentflare-Branch: task/438
Agentflare-Item: 438

* feat(flare-proxy): download the provider registry on demand, not just embed it (item #438)

The embedded-only registry.toml from the previous commit still required a
new agentflare release to add a provider -- it was baked into the binary
at compile time. This closes that gap the same way appz-cli's toolchain
registry does (crates/appz-core/src/{toolchain_registry,registry_cache}.rs),
scoped down to flare-proxy's single call site: no offline-mode CLI flag,
no generic <T> cache helper, since there's nothing else to share it with.

registry() -- used by find()/resolve()/known_prefixes(), and by this
module's own tests -- reads only the embedded TOML plus whatever's
already cached on disk. It never touches the network, so it stays fast
and deterministic in cargo test (77 tests in 0.02s, unchanged from
before this commit).

ensure_fresh() is the explicit 'download on demand' step: called once
from router() before the first ProviderConfig::from_env() read, it
checks the local cache (~/.agentflare/flare-proxy-providers-registry.json)
against a 24h TTL and, if stale, attempts one 3s-timeout live fetch of
registry/providers.toml's latest published version, merging remote
entries over the embedded ones by prefix. Any failure -- offline, DNS,
non-2xx, malformed TOML -- silently falls back to the embedded copy;
existing installs never break because of a network hiccup, they just
don't get the newest provider until the next successful refresh.

dirs and ureq added to flare-proxy's Cargo.toml -- both already
workspace dependencies via the main agentflare crate, so this adds zero
new entries to Cargo.lock (confirmed via diff).

77/77 tests pass, clippy clean (including a result_large_err fix --
ureq::Error is >270 bytes, fetch_remote() now maps to a plain String
error immediately, matching appz-cli's own Result<String, String>
convention for the same kind of fetch function), fmt clean.

Agentflare-Agent: claude-code_2-1-225_agent
Agentflare-Branch: task/438
Agentflare-Item: 438

* data(flare-proxy): populate registry with the broader OpenAI-compatible provider set (item #438)

Adds 17 more openai_compatible entries alongside the original NVIDIA NIM/
OpenRouter/LM Studio/Cloudflare-Gateway set: OpenAI itself, DeepSeek, Groq,
Mistral, xAI, Together, Perplexity, Fireworks, DeepInfra, Moonshot,
Novita, Hyperbolic, Cerebras, SambaNova, GitHub Models, Cohere
(compatibility API), and local Ollama.

base_url values are each provider's own documented OpenAI-SDK-compatible
endpoint as of this session -- best-effort from public docs/conventions,
not individually live-verified against every provider's current docs
given how many there are. Flagged as such directly in the TOML file. If
one drifts, that's exactly what the on-demand refresh added in the
previous commit exists to fix -- correcting registry/providers.toml
upstream reaches every existing install on its next refresh, no new
release needed.

Two new regression tests: every_registry_entry_has_a_resolvable_static_or_
gateway_url (catches a future copy-paste mistake -- a provider block
missing both base_url and base_url_template -- at test time instead of a
confusing request-time 'no route' error) and
broad_openai_compatible_providers_are_present_and_resolve (locks in that
all 17 new prefixes parse, resolve, and produce a well-formed URL).

79/79 tests pass, clippy clean, fmt clean.

Agentflare-Agent: claude-code_2-1-225_agent
Agentflare-Branch: task/438
Agentflare-Item: 438

* data(flare-proxy): add siliconflow, llm7, requesty free-tier coding providers (item #438)

Three more openai_compatible registry entries, picked for coding use:
siliconflow (Qwen3-Coder-480B, DeepSeek-V3.2/R1, permanently free after
identity verification), llm7 (Qwen2.5-Coder-32B, DeepSeek-R1, no-cost
daily tier), requesty (300+ model router, cleanest ToS rating of the
free aggregators surveyed).

base_url values verified against each provider's own docs (SiliconFlow
quickstart, LLM7 live /v1/models endpoint, Requesty gateway docs), not
guessed. Extended broad_openai_compatible_providers_are_present_and_resolve
to cover all three.

11/11 flare-proxy registry tests pass, clippy clean, fmt clean.

Agentflare-Agent: claude-code_2-1-225_agent
Agentflare-Branch: task/438
Agentflare-Item: 438

* data(flare-proxy): add free-tier quota metadata to provider registry (item #438)

New optional RegistrySpec fields -- free_type, monthly_tokens,
credit_tokens -- record each provider's documented free-tier budget:
recurring-daily/monthly (renews), recurring-uncapped (rate-limited, no
token cap), one-time-initial (signup credit), or unmetered (local).
Populated for all 21 providers with a documented free tier; omitted for
paid-key/pass-through providers (openai, xai, together's paid tier,
perplexity, moonshot, anthropic, cf_gateway_*) with no free-tier data.

Data pulled from OmniRoute's freeModelCatalog.data.ts (pool-deduped to
each provider's max), not estimated -- source noted in the TOML header.

Metadata only: no selection/load-balancing logic reads these fields yet.
That's the natural follow-up once this shape has been used for a bit,
scoped separately per plan.

New test (every_registry_free_type_is_a_known_value) catches a typo'd
free_type value against a known set. 12/12 flare-proxy registry tests
pass, clippy clean, fmt clean.

Agentflare-Agent: claude-code_2-1-225_agent
Agentflare-Branch: task/438
Agentflare-Item: 438

* feat(flare-proxy): free-tier usage tracking and fallback selection (item #438)

New providers::quota module: tracks per-provider token consumption
against the free_type/monthly_tokens/credit_tokens registry metadata
added in the previous commit, and picks the first available provider
from a priority-ordered candidate list.

Design ported (not copied) from two real implementations, researched
and cloned locally for reference:
- LiteLLM's provider budget limiter (BerriAI/litellm, MIT,
  litellm/router_strategy/budget_limiter.py) -- the get-or-init window
  start / reset-if-expired / increment-if-current three-way branch,
  without its Redis multi-instance sync (flare-proxy is one process).
- OmniRoute's emergency fallback (diegosouzapw/OmniRoute, MIT,
  open-sse/services/emergencyFallback.ts) -- fail-open on tracking
  errors, walk a short ordered candidate list rather than re-rank a
  large pool.

Usage persists to flare-proxy-usage.json next to the existing registry
cache (agentflare_home(), now pub(super) for quota.rs to reuse rather
than duplicating the home-dir helper).

Scope boundary, called out in the module doc: this is the tracking/
selection primitive only, not wired into forward.rs's request path yet.
ProviderConfig/ModelRoute resolve to exactly one provider per request
today; using select_best for real routing needs a candidate list there,
and record_consumption needs a real token count, which the streaming
response path doesn't currently extract. Both are separate design
decisions, tracked as the next item #438 follow-up rather than bolted
on here unreviewed.

7 new tests (budget exhaustion, window expiry reset, one-time credits
never resetting, priority-ordered fallback selection). 87/87 flare-proxy
tests pass (stable across repeated runs -- fixed a test-isolation race
by reusing crate::test_env_lock() instead of a module-local mutex, since
AGENTFLARE_HOME_OVERRIDE is a process-global env var shared with
registry.rs's own tests). clippy clean, fmt clean.

Agentflare-Agent: claude-code_2-1-225_agent
Agentflare-Branch: task/438
Agentflare-Item: 438

* fix(flare-proxy): address CodeRabbit findings on PR #439

- forward.rs: apply provider.extra_headers on the Anthropic/Gemini paths too, not just OpenAI-compat -- Cloudflare AI Gateway's cf-aig-authorization was silently dropped for cf_gateway_anthropic
- mod.rs: from_env() route construction now resolves MODEL prefixes (e.g. nvidia_nim) to their registry id (nvidia-nim) before storing provider_id, fixing a 400 "unknown provider" for any prefix whose id differs from its prefix
- gemini.rs: recursively strip JSON-Schema fields Gemini's function-calling API rejects ($schema, etc.) from tool input_schema before sending
- shape_xlat.rs: gemini_finish_stream now reports stop_reason "tool_use" whenever a tool block was opened, even when Gemini's finishReason is "STOP" (its common case for a turn containing a functionCall)
- registry.rs: merge() no longer lets a remote/cached registry entry override an existing provider's base_url/api_key_env, only its quota metadata -- a compromised publish path could otherwise redirect API traffic to an attacker host
- providers.toml: remove github_models -- GitHub retired the Models inference endpoint (410)
- registry.rs: add the missing test_env_lock() guard to resolve_template_substitutes_multiple_placeholders
- Cargo.toml: drop ureq's unused json feature
- forward.rs: remove a dead strip_think_tags() call whose result was discarded

Agentflare-Agent: claude-code_2-1-225_agent
Agentflare-Branch: task/438
Agentflare-Item: 438
cargo fmt reformats parse_vm_stat's page-size closure to its multi-line
form; clippy::identity_op flags the test's redundant `1 * GB` (no-op
multiplication) -- change to plain `GB`.

Agentflare-Agent: claude-code
Agentflare-Branch: task/66
Agentflare-Item: 66
getappz pushed a commit that referenced this pull request Aug 11, 2026
Confirmed 5 occurrences (PRs #436/#438/#441/#443 twice) of the identical
signature: a different test each time, always the run's last one to
complete, killed at exactly slow-timeout's 300s boundary while 2100+
other tests pass. This PR's own kill_tree hardening still hit the same
signature on yet another test afterward, ruling out that specific leak
as the sole cause -- reads as generic Windows-runner tail-of-run resource
contention, not a broken test. retries = 2 is nextest's own targeted
mitigation for exactly this shape of flake: a genuinely hung/broken test
fails every retry too, so this doesn't mask real regressions.

Agentflare-Agent: claude-code
Agentflare-Branch: task/78
Agentflare-Item: 78
getappz added a commit that referenced this pull request Aug 11, 2026
… leak detection (#443)

* fix(windows): harden kill_tree against taskkill's tree-kill race, add leak detection

taskkill /T /F builds its process-tree kill list from a single point-in-time
snapshot; a grandchild spawned in the narrow window between that snapshot and
termination can survive undetected, and none of the three Windows kill paths
(agent_launch::kill_tree, flare-git-core::kill_tree, agentflare-jobs's
kill_graceful) ever verified the tree was actually gone before returning.
This is the leading suspect for item #78's recurring Windows CI last-test
slow-timeout: two kill-focused tests always run right before the eventual
timeout, and one of them (timeout_kills_long_running_process) kills a 30s
grandchild with no buffer to let a leak self-correct, unlike its sibling test.

Add a second delayed taskkill /T /F pass to each Windows kill path as cheap
defense-in-depth against the snapshot race, and strengthen both suspect
tests to poll for surviving processes on Windows so a future regression
fails loudly and locally instead of starving an unrelated test downstream.

Agentflare-Agent: claude-code
Agentflare-Branch: task/78
Agentflare-Item: 78

* ci: retry flaky Windows nextest failures instead of failing the run

Confirmed 5 occurrences (PRs #436/#438/#441/#443 twice) of the identical
signature: a different test each time, always the run's last one to
complete, killed at exactly slow-timeout's 300s boundary while 2100+
other tests pass. This PR's own kill_tree hardening still hit the same
signature on yet another test afterward, ruling out that specific leak
as the sole cause -- reads as generic Windows-runner tail-of-run resource
contention, not a broken test. retries = 2 is nextest's own targeted
mitigation for exactly this shape of flake: a genuinely hung/broken test
fails every retry too, so this doesn't mask real regressions.

Agentflare-Agent: claude-code
Agentflare-Branch: task/78
Agentflare-Item: 78

---------

Co-authored-by: shiva <shiva@gosysinfo.tech>
@getappz
getappz merged commit eb2e1fc into master Aug 11, 2026
16 checks passed
@getappz
getappz deleted the task/66 branch August 11, 2026 10:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ponytail#532] Persona wording: lazy = less work for same result

1 participant