Native Runtime v2.0 launch: degraded VRAM admission + live status - #100
Conversation
…ol auth relaxation, trust-level wiring, Daemon CI Native Runtime robustness (the actual v2.0 launch content): OrcScheduler.TryAdmit no longer hard-denies a role that doesn't fit full GPU residency -- it searches for the largest GPU-layer count that DOES fit and admits in degraded (partial GPU + CPU) mode instead, so a VRAM-tight box still runs, just slower, rather than refusing every native call outright. RuntimeOrchestrator.EnsureAdmitted threads the reduced GpuLayers through to the actual load so the degraded admission takes effect, and tracks a distinct DegradedAdmissionCount/LastDegradedReason (never conflated with real rejections). MainWindow gets an always-on status-bar VRAM badge (nvidia-smi, 5s poll, color-coded by headroom) surfacing this live, independent of opening Settings. Also included, each self-contained and reviewed as its own concern: - Studio-tool bearer tokens (Art Forge/CaseForge/KeyHound) become optional -- hardcoreerik's own local instances run unauthenticated; LocalIntegrationHost still gates every call on IsLocal (loopback/private-IP/single-label only), so dropping the token requirement never exposes a public-host path. - ChatPanel: OrcChat's tool-call/file-write approvals now honor the global Plan/Guarded/Standard/Full-Auto trust level (previously only the per-conversation "Always approve" checkbox had any effect), and the status bar's model badge updates when a model is switched from inside OrcChat. - CI now builds OrchestratorIDE.Daemon explicitly (it cherry-picks shared source via <Compile Include> rather than a ProjectReference, so it can silently break while the main Avalonia build stays green) and the Daemon project carries the headless browser-automation source set (Playwright, NativeToolCapability, PathSandbox) for Warband nodes. Deliberately excluded: SkillLoader.cs / SkillLoaderTests.cs and the NATIVE_RUNTIME_V2_SPEC.md §8 "self-authored skills" section. That mechanism's loader half is solid (verified rejecting malformed input safely across 3 distinct real failure modes), but the swarm-authoring half has failed both live attempts so far (documented NOT CLOSED in the spec's own run log) -- not launch material yet. Verified: OrchestratorIDE.Avalonia, OrchestratorIDE.Daemon, and OrchestratorIDE.UnitTests all build clean with SkillLoader fully absent from this branch's scope; the 41 tests covering OrcScheduler/OrcChatToolCatalog/ArtForge/ CaseForge/KeyHoundAtlas all pass (including two new OrcScheduler tests: degrade instead of deny, and fail closed when even zero GPU layers can't fit the fixed overhead floor). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe PR adds progressive GPU-layer degradation with telemetry, live VRAM monitoring, optional authentication for local integrations, global chat approval handling, active-model synchronization, and daemon browser-automation build coverage. ChangesRuntime admission and VRAM telemetry
Local integrations and chat controls
Daemon browser automation build
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant RuntimeOrchestrator
participant OrcScheduler
participant NativeRuntime
participant MainWindow
RuntimeOrchestrator->>OrcScheduler: Request VRAM admission
OrcScheduler-->>RuntimeOrchestrator: Return effective GPU layers
RuntimeOrchestrator->>NativeRuntime: Load using effective options
MainWindow->>NativeRuntime: Read reservation telemetry
NativeRuntime-->>MainWindow: Return VRAM and degradation status
sequenceDiagram
participant User
participant ChatPanel
participant ApprovalQueue
participant MainWindow
User->>ChatPanel: Trigger tool or file-write action
ChatPanel->>ApprovalQueue: Apply global trust level
ApprovalQueue-->>ChatPanel: Approve or deny action
ChatPanel-->>MainWindow: Report active-model change
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 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 `@OrchestratorIDE.Avalonia/Tools/LocalIntegrationHost.cs`:
- Around line 24-36: Update LocalIntegrationHost.CreateClient and its callers so
bearer tokens are attached only for HTTPS endpoints; validate the target URI or
enforce the HTTPS check before invoking CreateClient. Preserve unauthenticated
local HTTP support, but never send a nonblank bearerToken over cleartext HTTP.
- Around line 24-36: Update CreateClient and the local-tool registration flow so
tokenless requests are permitted only for loopback endpoints; private-IP and
single-label hosts must require a bearer token or an explicit authentication
opt-in. Preserve the existing IsLocal gating while ensuring image_create and
atlas_start cannot target non-loopback local services without authentication.
In `@OrchestratorIDE/Core/Runtime/OrcScheduler.cs`:
- Around line 164-168: Update the admission calculation around requestedLayers
and requiredBytes to estimate memory using the resolved requested GPU-layer
count rather than full GPU residency. Return normal admission when that estimate
fits, including GpuLayers = 0 and partial requests; only enter the descending
fallback loop when the requested count does not fit, preserving the loop’s
lower-layer search. Add tests covering zero and partial GpuLayers requests.
In `@OrchestratorIDE/Core/Runtime/RuntimeOrchestrator.cs`:
- Around line 399-403: The RecordDegradation call currently executes before
LoadBindingAsync and CreateConversationAsync, so it records a degradation even
if those operations fail and the conversation never loads. Return the
decision.Reason or degradation information from the current location to
GetConversationForBindingAsync, then move the RecordDegradation call to execute
after both LoadBindingAsync and CreateConversationAsync succeed, placing it
alongside the reservation commit.
🪄 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 Plus
Run ID: 736f5e3e-cbd7-486b-a391-5345df6ee314
📒 Files selected for processing (17)
.github/workflows/ci.ymlOrchestratorIDE.Avalonia/MainWindow.axamlOrchestratorIDE.Avalonia/MainWindow.axaml.csOrchestratorIDE.Avalonia/Tools/ArtForgeTools.csOrchestratorIDE.Avalonia/Tools/CaseForgeTools.csOrchestratorIDE.Avalonia/Tools/KeyHoundAtlasTools.csOrchestratorIDE.Avalonia/Tools/LocalIntegrationHost.csOrchestratorIDE.Avalonia/UI/Panels/ChatPanel.axaml.csOrchestratorIDE.Daemon/OrchestratorIDE.Daemon.csprojOrchestratorIDE.UnitTests/ArtForgeToolsTests.csOrchestratorIDE.UnitTests/CaseForgeToolsTests.csOrchestratorIDE.UnitTests/KeyHoundAtlasToolsTests.csOrchestratorIDE.UnitTests/OrcChatToolCatalogTests.csOrchestratorIDE.UnitTests/OrcSchedulerTests.csOrchestratorIDE/Core/Runtime/OrcScheduler.csOrchestratorIDE/Core/Runtime/RuntimeOrchestrator.csOrchestratorIDE/Research/OrcChatToolCatalog.cs
💤 Files with no reviewable changes (1)
- OrchestratorIDE.Avalonia/Tools/CaseForgeTools.cs
| /// <summary> | ||
| /// <paramref name="bearerToken"/> is optional (hardcoreerik, 2026-08-01: his own local | ||
| /// Art Forge Studio / ComfyUI / KeyHound instances run with no auth at all — a hobby-project | ||
| /// front end for ComfyUI he wrote himself, not a service that issues device tokens). No | ||
| /// Authorization header is sent when it's null/blank; this is only safe because every caller | ||
| /// already gates on <see cref="IsLocal"/> first, so an unauthenticated request can only ever | ||
| /// reach a loopback/private-IP/single-label host, never a public one. | ||
| /// </summary> | ||
| public static HttpClient CreateClient(string? bearerToken) | ||
| { | ||
| var http = new HttpClient(SharedHandler, disposeHandler: false) { Timeout = TimeSpan.FromMinutes(2) }; | ||
| http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken); | ||
| if (!string.IsNullOrWhiteSpace(bearerToken)) | ||
| http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken); |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== files =="
git ls-files | rg 'LocalIntegrationHost\.cs|Integration|Service|Api|Client' | sed -n '1,120p'
echo "== outline LocalIntegrationHost.cs =="
file="OrchestratorIDE.Avalonia/Tools/LocalIntegrationHost.cs"
if [ -f "$file" ]; then
ast-grep outline "$file" --view expanded || true
echo "== relevant lines =="
nl -ba "$file" | sed -n '1,220p'
fi
echo "== CreareClient/IsLocal callers =="
rg -n "CreateClient|IsLocal|Authorization|DefaultRequestHeaders" -S . --glob '!bin/**' --glob '!obj/**' | sed -n '1,240p'Repository: hardcoreerik/TheOrc
Length of output: 7379
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== LocalIntegrationHost.cs =="
python3 - <<'PY'
from pathlib import Path
p=Path('OrchestratorIDE.Avalonia/Tools/LocalIntegrationHost.cs')
lines=p.read_text().splitlines()
for i,l in enumerate(lines,1):
print(f'{i:4}: {l}')
PY
echo "== usages =="
rg -n "CreateClient|IsLocal\\(|DefaultRequestHeaders\\.Authorization|Authorization" -S . --glob '!bin/**' --glob '!obj/**' | sed -n '1,240p'
echo "== scheme-related checks in relevant tools/services =="
rg -n "http://|https://|Uri\\(|Scheme|IsLocal|CreateClient" -S OrchestratorIDE.Avalonia OrchestratorIDE --glob '!bin/**' --glob '!obj/**' | sed -n '1,320p'Repository: hardcoreerik/TheOrc
Length of output: 30587
🏁 Script executed:
#!/bin/bash
set -euo pipefail
for src in \
OrchestratorIDE.Avalonia/Tools/ArtForgeTools.cs \
OrchestratorIDE.Avalonia/Tools/KeyHoundAtlasTools.cs \
OrchestratorIDE.Avalonia/Tools/CaseForgeTools.cs
do
echo "== $src =="
python3 - <<'PY' "$src"
from pathlib import Path
import sys
p=Path(sys.argv[1])
lines=p.read_text().splitlines()
for i,l in enumerate(lines,1):
print(f'{i:4}: {l}')
PY
done
echo "== settings/config field names around local URLs/token storage =="
rg -n "ArtForge|ComfyUI|KeyHound|bearerToken|bearer_token|Bearer|Token|LocalIntegrationHost|WorkerUrl|WarchiefUrl|Url" \
OrchestratorIDE.Avalonia OrchestratorIDE --glob '!bin/**' --glob '!obj/**' | sed -n '1,320p'
echo "== request URL construction near CreateClient calls =="
rg -n -A30 -B30 "CreateClient\\(|IsLocal\\(" OrchestratorIDE.Avalonia/Tools/ArtForgeTools.cs OrchestratorIDE.Avalonia/Tools/KeyHoundAtlasTools.cs OrchestratorIDE.Avalonia/Tools/CaseForgeTools.cs | sed -n '1,320p'Repository: hardcoreerik/TheOrc
Length of output: 50375
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== RegisterTool calls / art forge / keyhound / caseforge integration wiring =="
rg -n -A20 -B20 "ArtForgeTools\\.Register|KeyHoundAtlasTools\\.Register|CaseForgeTools\\.Register|Art Forge|KeyHound|CaseForge|Bearer|bearer" \
OrchestratorIDE.Avalonia --glob '!bin/**' --glob '!obj/**' | sed -n '1,360p'
echo "== focused config/dialog text =="
rg -n -A5 -B5 "Local Studio|Art Forge|KeyHound|CaseForge|bearer|Bearer Token|Token" \
OrchestratorIDE.Avalonia/OrchestratorIDE.Avalonia.csproj OrchestratorIDE.Avalonia UI Dialog Windows Controls Panels --glob '*.cs' --glob '*.acsl' --glob '*.axaml' --glob '*.md' -S 2>/dev/null | sed -n '1,280p'Repository: hardcoreerik/TheOrc
Length of output: 50375
Sensitive Data Exposure (CWE-319): Cleartext Transmission of Sensitive Information
Reachability: Internal
Require HTTPS before attaching a bearer token.
These registerers accept http URLs and only call IsLocal, while CreateClient attaches Authorization for any nonblank token. A bearer token can therefore be sent over cleartext HTTP to a loopback/private-IP/single-label endpoint. Enforce https before calling LocalIntegrationHost.CreateClient, or validate the target URI in the helper.
🤖 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 `@OrchestratorIDE.Avalonia/Tools/LocalIntegrationHost.cs` around lines 24 - 36,
Update LocalIntegrationHost.CreateClient and its callers so bearer tokens are
attached only for HTTPS endpoints; validate the target URI or enforce the HTTPS
check before invoking CreateClient. Preserve unauthenticated local HTTP support,
but never send a nonblank bearerToken over cleartext HTTP.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Locate file =="
fd -a 'LocalIntegrationHost.cs' . || true
echo "== File outline =="
ast-grep outline OrchestratorIDE.Avalonia/Tools/LocalIntegrationHost.cs --view expanded || true
echo "== Relevant file content =="
cat -n OrchestratorIDE.Avalonia/Tools/LocalIntegrationHost.cs
echo "== Search IsLocal and CreateClient usages =="
rg -n "IsLocal|CreateClient|bearerToken|image_create|atlas_start|LocalIntegrationHost" -S .Repository: hardcoreerik/TheOrc
Length of output: 12974
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== ArtForgeTools.cs relevant sections =="
cat -n OrchestratorIDE.Avalonia/Tools/ArtForgeTools.cs | sed -n '1,80p'
cat -n OrchestratorIDE.Avalonia/Tools/ArtForgeTools.cs | sed -n '120,230p'
echo "== KeyHoundAtlasTools.cs relevant sections =="
cat -n OrchestratorIDE.Avalonia/Tools/KeyHoundAtlasTools.cs | sed -n '1,80p'
cat -n OrchestratorIDE.Avalonia/Tools/KeyHoundAtlasTools.cs | sed -n '120,230p'
echo "== CaseForgeTools.cs relevant sections =="
cat -n OrchestratorIDE.Avalonia/Tools/CaseForgeTools.cs | sed -n '1,80p'
cat -n OrchestratorIDE.Avalonia/Tools/CaseForgeTools.cs | sed -n '160,230p'
echo "== Configuration references for bearer token/service URLs =="
rg -n "Bearer|bearer|BearerToken|ArtForge|KeyHound|CaseForge|ServiceUrl|WorkerUrl|WorkspaceUrl|RequiresApproval|Approval" OrchestratorIDE.Avalonia OrchestratorIDE -S
echo "== HTTP request methods and URLs in tool implementations =="
rg -n "CreateRequest|PostAsJson|SendAsync|http\.|Image |Atlas |Create|Start|Worker|Service|Workflow|Target" OrchestratorIDE.Avalonia/Tools/*Tools.cs -SRepository: hardcoreerik/TheOrc
Length of output: 50375
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
src = {
"art": Path("OrchestratorIDE.Avalonia/Tools/ArtForgeTools.cs").read_text(),
"keyhound": Path("OrchestratorIDE.Avalonia/Tools/KeyHoundAtlasTools.cs").read_text(),
"caseforge": Path("OrchestratorIDE.Avalonia/Tools/CaseForgeTools.cs").read_text(),
"host": Path("OrchestratorIDE.Avalonia/Tools/LocalIntegrationHost.cs").read_text(),
}
checks = {
"CreateClient sends bearer only when non-blank": 'bearerToken' in src["host"] and 'new AuthenticationHeaderValue("Bearer", bearerToken)' in src["host"],
"CreateClient never adds Authorization on blank token": src["host"].count('new AuthenticationHeaderValue("Bearer", bearerToken)') == 1 and src["host"].index("bearerToken is optional") < src["host"].index("new AuthenticationHeaderValue") < src["host"].index("return http;"),
"ArtForge image_create is POST to configured api": 'Name = "image_create"' in src["art"] and 'HttpMethod.Post' in src["art"] and 'api/v1/generations/images' in src["art"],
"KeyHound atlas_start is POST to configured api": 'Name = "atlas_start"' in src["keyhound"] and 'HttpMethod.Post' in src["keyhound"] and 'api/pepe-core/runs' in src["keyhound"],
"ArtForge Register accepts blank bearer token": 'string? bearerToken = null' in src["art"] and 'if (!IsLocal(serviceUrl))' in src["art"],
"KeyHound Register accepts blank bearer token": 'string? bearerToken = null' in src["keyhound"] and 'if (!IsLocal(serviceUrl))' in src["keyhound"],
"CaseForge Register accepts blank bearer token": 'string? bearerToken = null' in src["caseforge"] and 'if (!IsLocal(workerUrl))' in src["caseforge"],
"IsLocal includes private IPv4 ranges": 'bytes[0] == 10' in src["host"] and 'bytes[0] == 192 && bytes[1] == 168' in src["host"] and 'bytes[0] == 172 && bytes[1]' in src["host"],
}
for name, ok in checks.items():
print(f"{name}: {ok}")
PYRepository: hardcoreerik/TheOrc
Length of output: 263
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
src = {
"art": Path("OrchestratorIDE.Avalonia/Tools/ArtForgeTools.cs").read_text(),
"keyhound": Path("OrchestratorIDE.Avalonia/Tools/KeyHoundAtlasTools.cs").read_text(),
"caseforge": Path("OrchestratorIDE.Avalonia/Tools/CaseForgeTools.cs").read_text(),
"host": Path("OrchestratorIDE.Avalonia/Tools/LocalIntegrationHost.cs").read_text(),
}
checks = {
"Host optionality and bearer token behavior": all(x in src["host"] for x in [
"bearerToken is optional",
'"Bearer", bearerToken',
"return http;"
]),
"ArtForge accepts URL plus bearer token and sends POST image_create": all(x in src["art"] for x in [
"string? bearerToken = null",
"ImageForgeStudioRegistration? ",
"Name = \"image_create\"",
"HttpMethod.Post",
"api/v1/generations/images"
]),
"KeyHound accepts URL plus bearer token and sends POST atlas_start": all(x in src["keyhound"] for x in [
"string? bearerToken = null",
"Name = \"atlas_start\"",
"HttpMethod.Post",
"api/pepe-core/runs"
]),
"CaseForge accepts URL plus bearer token": all(x in src["caseforge"] for x in [
"string? bearerToken = null",
"Name = \"model3d_create\"",
"HttpMethod.Post",
"v1/jobs"
]),
"IsLocal accepts private IPv4 ranges": all(x in src["host"] for x in [
"bytes[0] == 10",
"bytes[0] == 192 && bytes[1] == 168",
"bytes[0] == 172 && bytes[1] is >= 16 and <= 31"
]),
"IsLocal accepts loopback and private IPv6 ranges": all(x in src["host"] for x in [
"IPAddress.IsLoopback(ip)",
"bytes[0] == 0xfe" in src["host"],
"bytes[0] == 0xfc"
]),
}
for name, ok in checks.items():
print(f"{name}: {ok}")
PY
echo "== Tool definition context =="
rg -n "ImageForgeStudioRegistration|KeyHoundAtlasRegistration|caseForgeToken|CaseForgeUri|KeyHound|ArtForgeUri|caseForgeUri|serviceUri" -S .
echo "== Read-only source scan for approval before Register calls =="
rg -n "Register\(.*CaseForge|Register\(.*ArtForge|Register\(.*KeyHound|Token\s*=|BearerToken\s*=|caseForgeToken|artForgeToken|KeyHoundToken" OrchestratorIDE.Avalonia OrchestratorIDE -SRepository: hardcoreerik/TheOrc
Length of output: 338
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
checks = {}
for name in ("host", "art", "keyhound", "caseforge"):
src = Path(f"OrchestratorIDE.Avalonia/Tools/{('LocalIntegrationHost' if name=='host' else {'art':'ArtForge','keyhound':'KeyHoundAtlas','caseforge':'CaseForge'}[name]+'Tools').replace('KeyHoundAtlas','KeyHoundAtlas')}.cs").read_text() if name != 'host' else Path("OrchestratorIDE.Avalonia/Tools/LocalIntegrationHost.cs").read_text()
print(f"-- {name} contains essential terms --")
for term in ["BearerToken", "bearerToken", "Bearer", "IsLocal"]:
print(f"{name}.{term}: {term in src}")
print()
print("Search registration callers:")
for pattern in ["Register(\s*", "Token\s*=", "BearerToken\s*=", "caseForgeToken", "artForgeToken", "KeyHoundToken", "ImageForgeStudioRegistration", "KeyHoundAtlasRegistration"]:
out = __import__('subprocess').check_output(["rg", "-n", pattern, "-S", "."], text=True)
if out:
print(pattern)
print(out[:1200])
print("---")
PYRepository: hardcoreerik/TheOrc
Length of output: 1228
Broken Authentication (CWE-306): Missing Authentication for Critical Function
Require authentication for non-loopback local tools.
IsLocal allows private-IP and single-label LAN hosts, but CreateClient only sends a bearer token when one is configured. For image_create / atlas_start, approval gates the user action but not the endpoint identity. If private-LAN services are not fully trusted, restrict tokenless tool registration to loopback addresses, or require explicit opt-in authentication for private/single-label addresses.
🤖 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 `@OrchestratorIDE.Avalonia/Tools/LocalIntegrationHost.cs` around lines 24 - 36,
Update CreateClient and the local-tool registration flow so tokenless requests
are permitted only for loopback endpoints; private-IP and single-label hosts
must require a bearer token or an explicit authentication opt-in. Preserve the
existing IsLocal gating while ensuring image_create and atlas_start cannot
target non-loopback local services without authentication.
| var requestedLayers = options.GpuLayers < 0 | ||
| ? header.BlockCount | ||
| : Math.Min(options.GpuLayers, header.BlockCount); | ||
|
|
||
| for (var layers = requestedLayers - 1; layers >= 0; layers--) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Evaluate the requested GPU-layer count before degrading it.
The initial requiredBytes estimate uses full GPU residency, regardless of options.GpuLayers. The loop then starts at requestedLayers - 1.
As a result, GpuLayers = 0 skips the loop and can be denied even when CPU-only execution fits. A partial request such as GpuLayers = 10 can also be reduced to 9 even when 10 layers fit.
Calculate the initial estimate with the resolved requested layer count. Return a normal admission if that estimate fits. Search lower counts only if the requested count does not fit. Add explicit tests for zero and partial GpuLayers values.
🤖 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 `@OrchestratorIDE/Core/Runtime/OrcScheduler.cs` around lines 164 - 168, Update
the admission calculation around requestedLayers and requiredBytes to estimate
memory using the resolved requested GPU-layer count rather than full GPU
residency. Return normal admission when that estimate fits, including GpuLayers
= 0 and partial requests; only enter the descending fallback loop when the
requested count does not fit, preserving the loop’s lower-layer search. Add
tests covering zero and partial GpuLayers requests.
| requiredBytes = OrcScheduler.EstimateRequiredBytes( | ||
| binding, options, reusesBaseWeights, gpuLayerOverride: reducedLayers); | ||
| effectiveOptions = options! with { GpuLayers = reducedLayers }; | ||
| RecordDegradation(decision.Reason); | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Record degradation only after the admission pipeline succeeds.
RecordDegradation runs before LoadBindingAsync and CreateConversationAsync. If either operation fails, the snapshot reports a degraded admission that never loaded or ran.
Return the degradation reason to GetConversationForBindingAsync. Record it after conversation creation succeeds, beside the reservation commit.
🤖 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 `@OrchestratorIDE/Core/Runtime/RuntimeOrchestrator.cs` around lines 399 - 403,
The RecordDegradation call currently executes before LoadBindingAsync and
CreateConversationAsync, so it records a degradation even if those operations
fail and the conversation never loads. Return the decision.Reason or degradation
information from the current location to GetConversationForBindingAsync, then
move the RecordDegradation call to execute after both LoadBindingAsync and
CreateConversationAsync succeed, placing it alongside the reservation commit.
…Ollama-default gaps CodeRabbit findings fixed, each verified with a real test: - LocalIntegrationHost.cs (Broken Authentication, CWE-306, Major): the optional- bearer-token change let ANY IsLocal host skip auth, not just loopback -- a private-IP/single-label LAN host is reachable by another machine on the same network. CreateClient now requires a token unless the target is genuinely loopback; callers already catch the resulting ArgumentException the same way they catch an invalid URL, so this fails safe (tool doesn't register) rather than crashing. New test: RejectsNoTokenOnAPrivateLanHost (confirmed it throws). - OrcScheduler.cs (degraded-admission math, Major): the initial admission check always estimated full GPU residency regardless of what GpuLayers was actually requested, and the degrade-search loop always started from requestedLayers-1 -- so an explicit partial request that already fit got needlessly reduced further, and GpuLayers=0 (explicit CPU-only) could never be evaluated at all (the loop's own bound, -1, was already below its lower bound of 0 before it started). Fixed by resolving the requested layer count BEFORE the first estimate, so the first check evaluates against what was actually asked. Two new tests added and verified red (against the old code, via git stash) before green: a partial request that fits no longer degrades further, and GpuLayers=0 that fits is now admitted instead of denied. - RuntimeOrchestrator.cs (degradation recorded too early, Minor): RecordDegradation ran inside EnsureAdmitted, before the caller's own load/conversation-create ever ran -- a load failure after a degraded admission still left the telemetry counter claiming a successful degraded admission that never happened. EnsureAdmitted now only REPORTS the degradation (a new DegradedReason return value); GetConversationForBindingAsync records it, only after its own load and conversation-create succeed, beside the reservation commit. New test proves EnsureAdmitted alone leaves DegradedAdmissionCount at 0. Also closes the two remaining Ollama-default gaps found while auditing "is Ollama actually optional everywhere" against the 2026-07-29 native-default decision: - SwarmSession (the local Swarm board's boss/worker/researcher pipeline) was the one core surface still hardcoded to Ollama with no native option at all, hard- erroring if Ollama wasn't configured. New AppSettings.ExperimentalNativeSwarmEnabled (default true) gates a BuildSwarmRuntime() mirroring BuildAgentLoopRuntime()'s exact fail-closed pattern (no silent Ollama fallback -- a native failure surfaces as an explicit error). One NativeWithFallbackRuntime instance serves boss/coder/ researcher via NativeRoleRuntime's existing modelNameFilter resolution, the same mechanism OrcChat's model switcher already relies on. Settings UI toggle added. - OrcChat/Research's own Backend setting still defaulted to Ollama for the fallback path used when native main chat is explicitly disabled. Flipped to LlamaCpp, same "never silently default to Ollama" policy -- an unconfigured fallback should surface loudly as something to fix, not be quietly absorbed. Doc-drift fixes: README.md's two "native runtime becomes default -- not yet started" blocks were stale (the flip landed 2026-07-29); PROJECT_TRUTH.md's "SwarmSession genuinely not touched" note was stale after the fix above. Verified: full test suite 800/800 (13 real-model lanes correctly skipped, no GGUF configured in this environment), OrchestratorIDE.Avalonia builds clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ase D)
SkillLoader.cs (declarative HTTP-tool manifests -- {workspace}/.orc/skills/*/tools.json,
the data-driven counterpart to ToolCompiler's compiled-C# tools) existed with a full
test suite but was never actually registered: not in the csproj's explicit compile
list, and never called from MainWindow.AutoLoadWorkspaceToolsAsync despite its own doc
comment claiming it was. Also fixes a stale call site -- LocalIntegrationHost.CreateClient
gained a required serviceUri parameter in PR #100 (the loopback-vs-bearer-token auth
gap fix) after this file was written, which SkillLoader.cs's build was silently never
catching since it wasn't compiled at all.
Now wired for real: added to the compile list, called alongside ToolCompiler's scan on
workspace open, and the CreateClient call site updated to pass the skill's resolved base
URI. Full suite (819 tests) passes.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Summary
The core native-runtime robustness fix for the v2.0 launch:
OrcScheduler.TryAdmitno longer hard-denies a role that doesn't fit full GPU residency. It now searches for the largest GPU-layer count that does fit and admits in degraded (partial GPU + CPU) mode instead — a VRAM-tight box still runs, just slower, rather than refusing every native call outright.RuntimeOrchestrator.EnsureAdmittedthreads the reducedGpuLayersthrough to the actual model load so the degraded admission actually takes effect, and tracks a distinctDegradedAdmissionCount/LastDegradedReason(never conflated with real rejections).MainWindowgets an always-on status-bar VRAM badge (nvidia-smi, 5s poll, color-coded by headroom) surfacing this live, independent of opening Settings.Also included, each a self-contained concern reviewed on its own:
LocalIntegrationHoststill gates every call onIsLocal(loopback/private-IP/single-label host only), so dropping the token requirement never opens a path to a public host.OrchestratorIDE.Daemonexplicitly (it cherry-picks shared source via<Compile Include>rather than aProjectReference, so it can silently break while the main Avalonia build stays green), and the Daemon project carries the headless browser-automation source set (Playwright,NativeToolCapability,PathSandbox) for Warband nodes.Deliberately excluded:
SkillLoader.cs/SkillLoaderTests.csand theNATIVE_RUNTIME_V2_SPEC.md§8 "self-authored skills" section. That mechanism's loader half is solid (verified rejecting malformed input safely across 3 distinct real failure modes), but the swarm-authoring half has failed both live attempts so far (documentedNOT CLOSEDin the spec's own run log) — not launch material yet.Test plan
OrchestratorIDE.Avaloniabuilds clean (Debug)OrchestratorIDE.Daemonbuilds clean (Debug)OrchestratorIDE.UnitTestsbuilds clean withSkillLoaderfully absent from this branch's scopeOrcSchedulerTests,OrcChatToolCatalogTests,ArtForgeToolsTests,CaseForgeToolsTests,KeyHoundAtlasToolsTests— including two newOrcSchedulertests (degrade instead of deny; fail closed when even zero GPU layers can't fit the fixed overhead floor)🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes