code-context-control 2.131.0__py3-none-any.whl → 2.136.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cli/c3.py +62 -2
- cli/commands/parser.py +22 -0
- cli/guide/tools.html +38 -11
- cli/hook_access_guard.py +36 -0
- cli/mcp_server.py +7 -4
- cli/tools/delegate.py +863 -145
- cli/tools/status.py +15 -0
- cli/ui/components/settings.js +1 -5
- {code_context_control-2.131.0.dist-info → code_context_control-2.136.0.dist-info}/METADATA +1 -1
- {code_context_control-2.131.0.dist-info → code_context_control-2.136.0.dist-info}/RECORD +21 -19
- core/config.py +19 -1
- oracle/services/c3_bridge.py +6 -1
- services/agents.py +12 -11
- services/bench/delegate_eval.py +575 -0
- services/claude_md.py +1 -1
- services/delegate_agents.py +108 -0
- services/telemetry.py +65 -0
- {code_context_control-2.131.0.dist-info → code_context_control-2.136.0.dist-info}/WHEEL +0 -0
- {code_context_control-2.131.0.dist-info → code_context_control-2.136.0.dist-info}/entry_points.txt +0 -0
- {code_context_control-2.131.0.dist-info → code_context_control-2.136.0.dist-info}/licenses/LICENSE +0 -0
- {code_context_control-2.131.0.dist-info → code_context_control-2.136.0.dist-info}/top_level.txt +0 -0
cli/c3.py
CHANGED
|
@@ -91,7 +91,7 @@ console = Console() if HAS_RICH else None
|
|
|
91
91
|
# Config
|
|
92
92
|
CONFIG_DIR = ".c3"
|
|
93
93
|
CONFIG_FILE = ".c3/config.json"
|
|
94
|
-
__version__ = "2.
|
|
94
|
+
__version__ = "2.136.0"
|
|
95
95
|
|
|
96
96
|
|
|
97
97
|
def _compress_file_cli(compressor, path, mode="smart", **kw):
|
|
@@ -1571,6 +1571,51 @@ def cmd_shell_eval(args):
|
|
|
1571
1571
|
sys.exit(1)
|
|
1572
1572
|
|
|
1573
1573
|
|
|
1574
|
+
def cmd_delegate_eval(args):
|
|
1575
|
+
"""Grade c3_delegate answers per target and name the cheapest passing tier.
|
|
1576
|
+
|
|
1577
|
+
Live by default (every case goes to the real backend and costs what that
|
|
1578
|
+
backend costs); --replay grades a recorded run instead. Exit status 1 when
|
|
1579
|
+
a --floor is given and a target's core pass rate falls under it. See
|
|
1580
|
+
docs/delegate-eval.md.
|
|
1581
|
+
"""
|
|
1582
|
+
from services.bench import delegate_eval as de
|
|
1583
|
+
|
|
1584
|
+
targets = [t.strip() for t in (args.targets or "").split(",") if t.strip()]
|
|
1585
|
+
case_ids = [c.strip() for c in (args.cases or "").split(",") if c.strip()]
|
|
1586
|
+
overrides = json.loads(args.config) if getattr(args, "config", None) else None
|
|
1587
|
+
if overrides is not None and not isinstance(overrides, dict):
|
|
1588
|
+
raise RuntimeError("--config must be a JSON object")
|
|
1589
|
+
|
|
1590
|
+
def progress(res):
|
|
1591
|
+
if not args.json:
|
|
1592
|
+
cost = "" if res.cost_usd is None else f" ${res.cost_usd:.4f}"
|
|
1593
|
+
print(f" {res.target:<16} {res.id:<28} {res.status}{cost} "
|
|
1594
|
+
f"{res.wall_ms / 1000:.1f}s", flush=True)
|
|
1595
|
+
|
|
1596
|
+
try:
|
|
1597
|
+
report = de.run_suite(
|
|
1598
|
+
args.suite, targets=targets or None, replay=args.replay, record=args.record,
|
|
1599
|
+
case_ids=case_ids or None, floor=args.floor if args.floor is not None else de.DEFAULT_FLOOR,
|
|
1600
|
+
allow_write_delegation=args.allow_write_delegation, delegate_overrides=overrides,
|
|
1601
|
+
progress=progress)
|
|
1602
|
+
except (FileNotFoundError, ValueError) as e:
|
|
1603
|
+
raise RuntimeError(str(e))
|
|
1604
|
+
|
|
1605
|
+
if args.json:
|
|
1606
|
+
print(json.dumps(report.to_dict(), indent=2))
|
|
1607
|
+
else:
|
|
1608
|
+
print(report.render())
|
|
1609
|
+
if args.record and report.mode == "live":
|
|
1610
|
+
print(f"recorded: {args.record}")
|
|
1611
|
+
if args.floor is not None:
|
|
1612
|
+
under = [t for t, a in report.aggregates.items()
|
|
1613
|
+
if a["pass_rate_core"] is None or a["pass_rate_core"] < args.floor]
|
|
1614
|
+
if under:
|
|
1615
|
+
print(f"under floor {args.floor}: {', '.join(under)}", file=sys.stderr)
|
|
1616
|
+
sys.exit(1)
|
|
1617
|
+
|
|
1618
|
+
|
|
1574
1619
|
def cmd_map_eval(args):
|
|
1575
1620
|
"""Run the file-map gold suite and compare it to its baseline.
|
|
1576
1621
|
|
|
@@ -5020,7 +5065,7 @@ back to native tools as the task progresses.
|
|
|
5020
5065
|
- **Filter**: `c3_filter(text=...)` — for terminal output >10 lines
|
|
5021
5066
|
- **Shell**: `c3_shell(cmd, timeout=60)` — structured shell exec (tests/git/build). Auto-filters output, logs git mutations to the ledger. Native Bash for interactive/TTY only
|
|
5022
5067
|
- **Memory**: `c3_memory(action='recall')` — full recall. `index` + `fetch` for token-efficient two-step retrieval
|
|
5023
|
-
- **Delegate**: `c3_delegate(task, backend='
|
|
5068
|
+
- **Delegate**: `c3_delegate(task, task_type, context|file_path)` — your own provider one tier down (default `backend='host'`, `tier='small'`; Claude Code: Haiku) for bounded answers: summarize a diff/log, explain a function, triage a traceback. `scout=true` lets it look files up itself. Multi-step work: the `c3-scout` (haiku) / `c3-worker` (sonnet) subagents
|
|
5024
5069
|
- **Local CI** (v2.79.0+): `c3_ci(action='inspect|run|rerun|failures')` — run THIS repo's real `.github/workflows` here instead of pushing for feedback. `run` executes in `needs` order; `failures` gives {file,line,message}; `rerun` retries only what failed. Only `FULL_CI_PASS` means safe to push — `PARTIAL_PASS` means something did not run (other OS, unsupported action, or your selection).
|
|
5025
5070
|
- **Bitbucket** (v2.30.0+, when `c3 bitbucket login` has run): `c3_bitbucket(action='list_prs|get_pr|merge_pr|...')` — self-hosted Bitbucket Data Center / Server. Token in OS keyring; mutating actions auto-log to the edit ledger.
|
|
5026
5071
|
- **Cross-project** (v2.31.0+): `c3_project(action='list|scan|search|read|edit|...', project='<name|path>')` — discover and operate on OTHER c3-installed projects. Reads run freely; writes (edit/shell/memory) need `allow_write=true`.
|
|
@@ -5878,6 +5923,20 @@ def cmd_install_mcp(args):
|
|
|
5878
5923
|
except Exception as e:
|
|
5879
5924
|
print(f"Warning: Could not install /terse skill: {e}")
|
|
5880
5925
|
|
|
5926
|
+
# ── Downshift subagents (c3-scout on haiku, c3-worker on sonnet) ──
|
|
5927
|
+
if profile.name == "claude-code" and not getattr(args, "no_agents", False):
|
|
5928
|
+
try:
|
|
5929
|
+
from services.delegate_agents import install_delegate_agents
|
|
5930
|
+
for path, action in install_delegate_agents(target):
|
|
5931
|
+
if action == "skipped":
|
|
5932
|
+
print(f"Kept {path} (no C3 marker: yours, left untouched)")
|
|
5933
|
+
elif action == "kept":
|
|
5934
|
+
print(f"Kept {path} (subagent up to date)")
|
|
5935
|
+
else:
|
|
5936
|
+
print(f"{action.capitalize()} {path} (subagent)")
|
|
5937
|
+
except Exception as e:
|
|
5938
|
+
print(f"Warning: Could not install c3-scout/c3-worker subagents: {e}")
|
|
5939
|
+
|
|
5881
5940
|
print(f"IDE: {profile.display_name}")
|
|
5882
5941
|
print(f"MCP Mode: {mcp_mode}")
|
|
5883
5942
|
print(f"Server: {server_script}")
|
|
@@ -9380,6 +9439,7 @@ def main():
|
|
|
9380
9439
|
"search-eval": cmd_search_eval,
|
|
9381
9440
|
"shell-eval": cmd_shell_eval,
|
|
9382
9441
|
"map-eval": cmd_map_eval,
|
|
9442
|
+
"delegate-eval": cmd_delegate_eval,
|
|
9383
9443
|
"benchmark": cmd_benchmark,
|
|
9384
9444
|
"session-benchmark": cmd_session_benchmark,
|
|
9385
9445
|
"benchmark-e2e": cmd_benchmark_e2e,
|
cli/commands/parser.py
CHANGED
|
@@ -89,6 +89,26 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
89
89
|
help='With --update-baseline: JSON object of metric ceilings, e.g. \'{"tokens_p95": 4000}\'')
|
|
90
90
|
p_map_eval.add_argument("--json", action="store_true", help="Emit the full report as JSON")
|
|
91
91
|
|
|
92
|
+
p_delegate_eval = subparsers.add_parser(
|
|
93
|
+
"delegate-eval", help="Grade c3_delegate answers per backend/tier (docs/delegate-eval.md)")
|
|
94
|
+
p_delegate_eval.add_argument("--suite", default="gold",
|
|
95
|
+
help="'gold' (bundled) or a .jsonl path")
|
|
96
|
+
p_delegate_eval.add_argument("--targets", default="",
|
|
97
|
+
help="Comma-separated backend[:tier] list, e.g. 'claude:small,claude:medium'")
|
|
98
|
+
p_delegate_eval.add_argument("--cases", default="", help="Comma-separated case ids (default: all)")
|
|
99
|
+
p_delegate_eval.add_argument("--replay", default=None,
|
|
100
|
+
help="Grade a recorded run instead of calling backends")
|
|
101
|
+
p_delegate_eval.add_argument("--record", default=None, help="Write the live answers to this JSON file")
|
|
102
|
+
p_delegate_eval.add_argument("--floor", type=float, default=None,
|
|
103
|
+
help="Core pass-rate floor; exit 1 when a target falls under it")
|
|
104
|
+
p_delegate_eval.add_argument("--allow-write-delegation", action="store_true",
|
|
105
|
+
help="Pass allow_write_delegation=true (needed for write-capable backends "
|
|
106
|
+
"when Access Guard rules exist)")
|
|
107
|
+
p_delegate_eval.add_argument("--config", default=None,
|
|
108
|
+
help='JSON object merged over the delegate config for this run, '
|
|
109
|
+
'e.g. \'{"allow_model_fallback": false}\'')
|
|
110
|
+
p_delegate_eval.add_argument("--json", action="store_true", help="Emit the full report as JSON")
|
|
111
|
+
|
|
92
112
|
p_compress = subparsers.add_parser("compress", help="Compress a file")
|
|
93
113
|
p_compress.add_argument("file", help="File to compress")
|
|
94
114
|
p_compress.add_argument("--mode", choices=["map", "smart", "structure", "outline"], default="map",
|
|
@@ -158,6 +178,7 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
158
178
|
p_install_mcp.add_argument("--global-fallback", action="store_true", help="Also install the machine-wide Codex fallback")
|
|
159
179
|
p_install_mcp.add_argument("--permissions", choices=["read-only", "c3-strict", "standard", "permissive"], default=None, help="Apply Claude Code permission tier (Claude Code only)")
|
|
160
180
|
p_install_mcp.add_argument("--include-mcp-wildcard", action="store_true", help="Add mcp__* wildcard so non-C3 MCP servers don't prompt per-call")
|
|
181
|
+
p_install_mcp.add_argument("--no-agents", action="store_true", help="Do not write the c3-scout/c3-worker subagents to .claude/agents (Claude Code only)")
|
|
161
182
|
|
|
162
183
|
p_mcp_install = subparsers.add_parser("mcp-install", help="Alias for install-mcp")
|
|
163
184
|
p_mcp_install.add_argument("targets", nargs="*", help="Optional project path and/or IDE shorthand")
|
|
@@ -166,6 +187,7 @@ def build_parser(version: str, parse_cli_ide_arg):
|
|
|
166
187
|
p_mcp_install.add_argument("--global-fallback", action="store_true", help="Also install the machine-wide Codex fallback")
|
|
167
188
|
p_mcp_install.add_argument("--permissions", choices=["read-only", "c3-strict", "standard", "permissive"], default=None, help="Apply Claude Code permission tier (Claude Code only)")
|
|
168
189
|
p_mcp_install.add_argument("--include-mcp-wildcard", action="store_true", help="Add mcp__* wildcard so non-C3 MCP servers don't prompt per-call")
|
|
190
|
+
p_mcp_install.add_argument("--no-agents", action="store_true", help="Do not write the c3-scout/c3-worker subagents to .claude/agents (Claude Code only)")
|
|
169
191
|
|
|
170
192
|
p_mcp_remove = subparsers.add_parser("mcp-remove", help="Remove an MCP server from your IDE config")
|
|
171
193
|
p_mcp_remove.add_argument("name", help="Name of the MCP server to remove (e.g. 'c3')")
|
cli/guide/tools.html
CHANGED
|
@@ -898,10 +898,10 @@ c3_status(view=<span class="str">'sessions'</span>) <span class="com">#
|
|
|
898
898
|
<div class="tag-row">
|
|
899
899
|
<span class="badge badge-orange">AI</span>
|
|
900
900
|
</div>
|
|
901
|
-
<span class="tool-tagline">
|
|
901
|
+
<span class="tool-tagline">Hand bounded work to your own provider, one tier down</span>
|
|
902
902
|
</div>
|
|
903
903
|
<div class="tool-card-body">
|
|
904
|
-
<p class="tool-desc">
|
|
904
|
+
<p class="tool-desc">Sends a bounded task (summarize a diff or log, explain a function, triage a traceback, draft a docstring or test cases) to a smaller model from the provider you already run on. In Claude Code that is Haiku by default, through a tool-less <code>claude -p</code> that answers only from the context C3 packs for it. On C3's delegate eval, Haiku passed all 22 bounded cases at about a fifth of Opus's cost.</p>
|
|
905
905
|
|
|
906
906
|
<table class="params-table">
|
|
907
907
|
<thead><tr><th>Parameter</th><th>Type</th><th>Default</th><th>Description</th></tr></thead>
|
|
@@ -916,34 +916,61 @@ c3_status(view=<span class="str">'sessions'</span>) <span class="com">#
|
|
|
916
916
|
<td class="param-name">task_type</td>
|
|
917
917
|
<td class="param-type">string</td>
|
|
918
918
|
<td class="param-default">"ask"</td>
|
|
919
|
-
<td class="param-desc"><code>ask</code>
|
|
919
|
+
<td class="param-desc"><code>ask</code> · <code>explain</code> · <code>summarize</code> · <code>review</code> · <code>diagnose</code> · <code>docstring</code> · <code>test</code> · <code>auto</code> · <code>ping</code> (one live call to check auth) · <code>available</code> (CLI versions only)</td>
|
|
920
920
|
</tr>
|
|
921
921
|
<tr>
|
|
922
922
|
<td class="param-name">context</td>
|
|
923
923
|
<td class="param-type">string</td>
|
|
924
924
|
<td class="param-default">""</td>
|
|
925
|
-
<td class="param-desc">
|
|
925
|
+
<td class="param-desc">The text the delegate answers from</td>
|
|
926
|
+
</tr>
|
|
927
|
+
<tr>
|
|
928
|
+
<td class="param-name">file_path</td>
|
|
929
|
+
<td class="param-type">string</td>
|
|
930
|
+
<td class="param-default">""</td>
|
|
931
|
+
<td class="param-desc">Comma-separated files C3 reads under Access Guard and packs into the prompt (a file over 8k tokens goes as its map; a masked path is refused)</td>
|
|
926
932
|
</tr>
|
|
927
933
|
<tr>
|
|
928
934
|
<td class="param-name">backend</td>
|
|
929
935
|
<td class="param-type">string</td>
|
|
930
|
-
<td class="param-default">"
|
|
931
|
-
<td class="param-desc"><code>
|
|
936
|
+
<td class="param-default">"host"</td>
|
|
937
|
+
<td class="param-desc"><code>host</code> = your own provider (Claude Code → <code>claude</code>, Codex → <code>codex</code>, Grok Build → <code>grok</code>, Antigravity → <code>gemini</code>) · <code>claude</code> · <code>codex</code> · <code>gemini</code> · <code>grok</code> · <code>ollama</code> · <code>auto</code></td>
|
|
938
|
+
</tr>
|
|
939
|
+
<tr>
|
|
940
|
+
<td class="param-name">tier</td>
|
|
941
|
+
<td class="param-type">string</td>
|
|
942
|
+
<td class="param-default">"small"</td>
|
|
943
|
+
<td class="param-desc"><code>small</code> · <code>medium</code> · <code>large</code> · <code>default</code>. Claude: Haiku / Sonnet / Opus. Codex and Grok: reasoning effort low / medium / high on the account's model. Gemini: flash-lite / flash / pro.</td>
|
|
944
|
+
</tr>
|
|
945
|
+
<tr>
|
|
946
|
+
<td class="param-name">model</td>
|
|
947
|
+
<td class="param-type">string</td>
|
|
948
|
+
<td class="param-default">""</td>
|
|
949
|
+
<td class="param-desc">A model alias or id; overrides the tier</td>
|
|
950
|
+
</tr>
|
|
951
|
+
<tr>
|
|
952
|
+
<td class="param-name">scout</td>
|
|
953
|
+
<td class="param-type">bool</td>
|
|
954
|
+
<td class="param-default">false</td>
|
|
955
|
+
<td class="param-desc">Let the delegate Read/Grep/Glob the project itself, for lookups when you cannot name the files. Claude runs <code>--restricted</code> with Access Guard's read denies; Codex uses its read-only sandbox.</td>
|
|
932
956
|
</tr>
|
|
933
957
|
</tbody>
|
|
934
958
|
</table>
|
|
935
959
|
|
|
936
960
|
<h4>Examples</h4>
|
|
937
|
-
<pre><code><span class="com">#
|
|
938
|
-
c3_delegate(task=<span class="str">'Summarize
|
|
961
|
+
<pre><code><span class="com"># Summarize a diff on Haiku (Claude Code host, default tier)</span>
|
|
962
|
+
c3_delegate(task=<span class="str">'Summarize this diff for a changelog in three bullets'</span>, context=<span class="str">'<diff>'</span>, task_type=<span class="str">'summarize'</span>)
|
|
963
|
+
|
|
964
|
+
<span class="com"># Explain a function on Sonnet</span>
|
|
965
|
+
c3_delegate(task=<span class="str">'What does resolve_host return inside a grok child?'</span>, file_path=<span class="str">'core/host.py'</span>, task_type=<span class="str">'explain'</span>, tier=<span class="str">'medium'</span>)
|
|
939
966
|
|
|
940
|
-
<span class="com">#
|
|
941
|
-
c3_delegate(task=<span class="str">'
|
|
967
|
+
<span class="com"># A lookup the delegate does itself</span>
|
|
968
|
+
c3_delegate(task=<span class="str">'Which functions call charge_card, and where?'</span>, scout=<span class="kw">True</span>)</code></pre>
|
|
942
969
|
|
|
943
970
|
<div class="callout callout-info">
|
|
944
971
|
<span class="callout-icon">ℹ️</span>
|
|
945
972
|
<div class="callout-body">
|
|
946
|
-
|
|
973
|
+
For multi-step work in Claude Code, <code>c3 install-mcp</code> also writes two subagents to <code>.claude/agents</code>: <code>c3-scout</code> (Haiku, read-only) and <code>c3-worker</code> (Sonnet). They run inside your session, so C3's hooks apply to them. Skip them with <code>--no-agents</code>. <code>c3 delegate-eval</code> measures pass rate and cost per backend and tier on your machine.
|
|
947
974
|
</div>
|
|
948
975
|
</div>
|
|
949
976
|
</div>
|
cli/hook_access_guard.py
CHANGED
|
@@ -501,3 +501,39 @@ def run(payload: dict, project_path: Path | None = None,
|
|
|
501
501
|
return _scan_shell_writes(cmd, base, session_id, defer_consume)
|
|
502
502
|
|
|
503
503
|
return None
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
def main() -> None:
|
|
507
|
+
"""Standalone PreToolUse entry for a ``c3_delegate`` scout run.
|
|
508
|
+
|
|
509
|
+
A scout is ``claude -p --restricted`` with Read/Grep/Glob and no C3 MCP
|
|
510
|
+
server, so the dispatcher's discipline hook (hook_pretool_enforce) would
|
|
511
|
+
refuse every native read. Only the access guard runs here. It prints a
|
|
512
|
+
deny and nothing else: grants and search footers are for an agent that
|
|
513
|
+
can act on them. Any failure denies (fail closed).
|
|
514
|
+
"""
|
|
515
|
+
import argparse
|
|
516
|
+
import json
|
|
517
|
+
|
|
518
|
+
from _hook_utils import ensure_utf8_stdio
|
|
519
|
+
|
|
520
|
+
ensure_utf8_stdio()
|
|
521
|
+
parser = argparse.ArgumentParser()
|
|
522
|
+
parser.add_argument("--project", required=True)
|
|
523
|
+
args = parser.parse_args()
|
|
524
|
+
try:
|
|
525
|
+
raw = sys.stdin.read()
|
|
526
|
+
payload = json.loads(raw) if raw.strip() else {}
|
|
527
|
+
if not isinstance(payload, dict):
|
|
528
|
+
raise ValueError("hook payload must be a JSON object")
|
|
529
|
+
# access_guard canonicalizes the base itself (no direct resolve here).
|
|
530
|
+
out = run(payload, Path(args.project))
|
|
531
|
+
except Exception as exc:
|
|
532
|
+
out = _deny(f"[c3-access:error] scout guard failed ({type(exc).__name__}: {exc}); "
|
|
533
|
+
"refusing the call")
|
|
534
|
+
if isinstance(out, dict) and isinstance(out.get("hookSpecificOutput"), dict):
|
|
535
|
+
print(json.dumps({"hookSpecificOutput": out["hookSpecificOutput"]}))
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
if __name__ == "__main__":
|
|
539
|
+
main()
|
cli/mcp_server.py
CHANGED
|
@@ -803,13 +803,16 @@ async def c3_status(view: str = "budget", detailed: bool = False,
|
|
|
803
803
|
|
|
804
804
|
@mcp.tool()
|
|
805
805
|
async def c3_delegate(task: str, task_type: str = "ask", context: str = "",
|
|
806
|
-
file_path: str = "", backend: str = "
|
|
806
|
+
file_path: str = "", backend: str = "host",
|
|
807
807
|
allow_write_delegation: bool = False,
|
|
808
|
+
tier: str = "", model: str = "", scout: bool = False,
|
|
808
809
|
ctx: Context = None) -> str:
|
|
809
810
|
"""OFFLOAD to another model — use when the subtask is local-model-sized or needs a different perspective.
|
|
810
|
-
backend:
|
|
811
|
+
backend: host (default: your own provider, one tier down — Claude Code->claude, Codex->codex, Grok->grok, Antigravity->gemini) | claude|codex|gemini|grok|ollama|auto. task_type: auto, summarize, explain, review, ask, test, diagnose, ping (live auth check), available, codex_check, gemini_check, grok_check, codex_resume.
|
|
812
|
+
tier: small (default) | medium | large | default. claude: haiku/sonnet/opus; codex/grok: reasoning effort; gemini: flash-lite/flash/pro. model overrides the tier. Context + file_path are packed by C3 under Access Guard; a file over 8k tokens goes as its map, so for line-level questions on a big file paste the excerpt or use scout=true.
|
|
813
|
+
scout=true: the delegate may Read/Grep/Glob the project itself (claude: read-only, guard-denied paths refused; codex: its read-only sandbox) — for lookups when you cannot name the files.
|
|
811
814
|
grok runs read-only in a temp dir unless delegate.grok_allow_write=true (then --yolo in the project, loading its trusted .grok MCP servers and hooks).
|
|
812
|
-
allow_write_delegation: explicit user opt-in for write-capable backends (gemini/
|
|
815
|
+
allow_write_delegation: explicit user opt-in for write-capable backends (gemini/grok write mode/codex_resume) while Access Guard rules are active; codex is pinned read-only instead."""
|
|
813
816
|
svc = _svc(ctx)
|
|
814
817
|
|
|
815
818
|
def finalize(name, args, resp, summ, **kw):
|
|
@@ -825,7 +828,7 @@ async def c3_delegate(task: str, task_type: str = "ask", context: str = "",
|
|
|
825
828
|
try:
|
|
826
829
|
return await asyncio.to_thread(handle_delegate, task, task_type, context,
|
|
827
830
|
file_path, svc, finalize, backend,
|
|
828
|
-
allow_write_delegation)
|
|
831
|
+
allow_write_delegation, tier, model, scout)
|
|
829
832
|
finally:
|
|
830
833
|
svc._agent_progress_cb = None
|
|
831
834
|
|