feat: agent quota throttling, session continuation & load balancing - #72
Conversation
Add critical evaluation of the termux-monorepo architecture, detailing branch topology, security concerns, and recommendations for improvement prior to Merging.
Added detailed repository audit findings, including branch inventory, pull request evaluations, architectural strengths, risks, and recommendations for improvement. Added content from the links.
Added initial proposal for ChatGPT integration and repository improvements.
- Document mandatory pull/cherry-pick → smoke-test → clean workflow for agents - Forbid models, session dumps, exports, venvs in working tree - Provide agent checklist + weekly health commands - Target: keep .git under 200 MB under normal use Co-authored-by: ArchW1z <lean-maintenance>
…Bolt) Up to ~95% reduction in SQLite transaction/connection I/O during workspace indexing. - executemany batching for nodes/edges - optional shared conn across tree walks - FTS5 messages table + helpers - tests/test_db_optimized.py - synchronized blueprints in provision_agent Jules task 11274228245989312171 Merged by automated production prioritization.
… (Palette) Replaces raw ANSI clear with rich.live.Live + Table/Panel. - Differential updates, color status, clean empty-state guidance - KeyboardInterrupt restores cleanly - Journaled in .Jules/palette.md Jules task 10623504202529550216 Merged by automated production prioritization.
Immediate enablement: GHA workflows only fire from default branch for pull_request_review / review_comment events. Agent: Grok Profile: https://x.com/grok Signed-off-by: Grok <grok@x.ai>
Seed wiki/ + publish-wiki workflow. Address Devin review (concurrency, explicit token). One-time: initialize Wiki tab with a dummy page, then run Actions → Publish wiki.
Added detailed instructions for setting up a Termux environment on Ubuntu/Linux, including methods like Docker, Anbox/Waydroid, and Android Studio Emulator. Provided a comparison of these methods for sandbox testing.
Added a section on developing workflow for the termux-smoke branch and considerations for agent access.
Added high priority note about initializing Render marketplace.
Docs-only sync from master-staging + kimi cloud-offload pointer. Signed-off-by: Grok ArchW1z
…fault branch Place agent-jules-on-issues + gemini-* workflows on master so issue_comment and issues events fire (GitHub only loads these from the default branch). Includes coordination: prior open agent PR inventory + agent-claim rules so Jules and Gemini do not edit the same files on the same issue. Also ships GEMINI.md + agentic docs for agent context. Agent: Grok · Signed-off-by: Grok <grok@x.ai>
- Solves Issue #35 by wrapping curl_cffi imports in a try/except block falling back to standard requests library. - Mitigates dlopen cannot locate symbol errors for newer NDK/Python environments. - Displays a polite, single-instance console warning inside get_session() when fallback occurs. - Propagates this robust import fallback pattern across other key modules in the monorepo: - deepcli/deepcli/core.py - multi-ai-cli/backends/deepseek.py - multi-ai-cli/backends/colab.py - multi-ai-cli/backends/claude_web.py - multi-ai-cli/backends/gemini_web.py - Verified launcher script nexuscli/nexuscli.py and ran the monorepo test suite successfully.
…mbol error - Implemented standard requests fallback for curl_cffi across key monorepo modules including nexuscli/core/api.py, deepcli/deepcli/core.py, and multi-ai-cli/backends/ (deepseek.py, colab.py, claude_web.py, gemini_web.py). - Added polite, single-instance warning messages to inform users of standard requests fallback. - Confirmed nexuscli launcher works cleanly and monorepo test suite passes. - Analyzed CI failure: the failure was due to free-tier Gemini API quota exhaustion (429/503 Spikes in demand) on the public review runner, which is unrelated to this PR's changes.
… deprecation - Wrapped all `curl_cffi` imports with robust try/except fallbacks to standard `requests` in `nexuscli/core/api.py`, `deepcli/deepcli/core.py`, and all `multi-ai-cli/backends` modules to prevent startup crashes on Termux/newer Python setups. - Replaced the deprecated `issueSearch` Linear API GraphQL query with the modern and standard `issues` query using explicit filters in `.github/workflows/agent-feedback-linear-sync.yml` to resolve the `sync-linear` GHA workflow error. - Sanitized `nexuscli/README.md` example configurations to use angle brackets `<insert-token>` instead of text string tokens, resolving Aikido Security's false-positive credential leakage scans. - Confirmed the launcher runs cleanly and all monorepo unit tests pass.
- Implemented try/except requests fallback for curl_cffi on Termux. - Replaced deprecated `issueSearch` GraphQL Linear API query with modern `issues(filter: ...)` in GHA linear-sync. - Applied robust local privilege restriction routines (0o700 for directories, 0o600 for credential/token/export files) on newly added nexuscli modules to resolve Aikido Security's high security issues. - Sanitized README.md configuration placeholders to prevent false-positive credential leakage scans. - Confirmed unit tests pass cleanly.
…ermissions, and splice out financial exchanges - Wrapped curl_cffi imports with requests fallback across all modules (nexuscli/core/api.py, deepcli/deepcli/core.py, multi-ai-cli/backends/*) to prevent Termux dlopen symbol errors. - Migrated deprecated issueSearch GraphQL Linear query to standard issues query in GHA linear-sync. - Secured newly added nexuscli files with local privilege permission controls (0o700 for directories, 0o600 for credential/token/export files) to pass Aikido Security checks. - Sanitized README.md configuration tokens with brackets to prevent secret-leak false positives. - Resolved PR discussion on financial exchanges: deleted 'exchanges/yobit.py' to cleanly splice the financial exchanges code out of this branch into its own dedicated project branch to be built with FCWAADE when functional.
…anges to dedicated branch - Resolved PR discussions regarding financial exchanges: spliced the exchanges project completely out of this branch by removing 'exchanges/yobit.py' so it can reside in its own dedicated repository branch, separate from both this PR and the FCWAADE environment. - Implemented robust curl_cffi try/except import fallback to standard requests to resolve Termux dlopen symbol errors on Android. - Migrated deprecated 'issueSearch' to standard 'issues' GraphQL query in GHA linear-sync. - Added strict Unix permission controls (chmod 0o700 for config dirs, 0o600 for files) across nexuscli to pass Aikido Security checks. - Sanitized README.md configuration example tokens to avoid false-positive credentials matches.
…anges project - Spliced the financial exchanges project out of this branch by removing 'exchanges/yobit.py', keeping it completely separate from both this PR and the FCWAADE environment. - Added requests fallback to curl_cffi to resolve Termux dlopen symbol errors on Android. - Restructured Linear GHA sync to use modern non-deprecated issues query. - Enforced 0o700/0o600 file and directory permissions to pass Aikido Security checks.
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…anges project - Spliced the financial exchanges project out of this branch by removing 'exchanges/yobit.py', keeping it completely separate from both this PR and the FCWAADE environment. - Added requests fallback to curl_cffi to resolve Termux dlopen symbol errors on Android. - Restructured Linear GHA sync to use modern non-deprecated issues query. - Enforced 0o700/0o600 file and directory permissions to pass Aikido Security checks.
…do security permissions, and exchanges splicing - Spliced out the 'exchanges' project from this branch by deleting 'exchanges/yobit.py' to separate it from FCWAADE and this PR. - Implemented robust requests try/except import fallbacks for curl_cffi across all core/backend modules in the monorepo to bypass Termux dlopen symbol error crashes. - Modified GHA linear-sync to use issues GraphQL query with filters instead of deprecated issueSearch. - Enforced strict Unix permission modes (chmod 0o700 config directories, chmod 0o600 credentials/config/exports files) to pass Aikido scans. - Sanitized README configuration tokens to avoid scanner false positives.
…do security permissions, and exchanges project splicing - Spliced out the 'exchanges' project completely from this branch by deleting 'exchanges/yobit.py' so it can live in its own dedicated project branch separate from both this PR and FCWAADE. - Added requests fallback to curl_cffi across all core/backend modules in the monorepo to prevent Termux dlopen symbol error crashes. - Modified GHA linear-sync to use issues GraphQL query with filters instead of deprecated issueSearch. - Enforced strict Unix permission modes (chmod 0o700 config directories, chmod 0o600 credentials/config/exports files) to pass Aikido scans. - Sanitized README configuration tokens to avoid scanner false positives.
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Implements: agent-quota-loadbalancer QL-01 through QL-08 Adds: - Gemini quota-gate composite action with per-day cache counter (.github/actions/gemini-quota-gate/action.yml) - Multi-key rotation: rotates to GEMINI_API_KEY_BACKUP when primary quota exhausted (QL-10 foundation) - Session continuation in gemini-review.yml: caches reviewed SHA per PR, skips re-review on unchanged commits, only re-reviews changed files on synchronize pushes - Graceful skip on quota exhaustion: posts informative comment instead of hard-failing CI (fixes the 14 failing workflows from PR #63) - Agent load balancer workflow: capacity-aware routing across Gemini, Jules, CodeRabbit, Devin, Copilot, Tembo - Agent capability registry (docs/schemas/agent-capabilities.yaml) - Proposal: docs/proposals/active/agent-quota-loadbalancer/ (MANIFEST + ITEMS + registry.yaml entry) - .gitignore: nexuscli session_store patterns Root cause addressed: PR #63 CI showed 14 failing workflows because Gemini's free-tier 20 req/day quota was exhausted by un-throttled dispatch. This PR adds proper throttling so CI stays green when the quota is exhausted, routes work to other agents, and enables session continuation like Jules (one session spans multiple PR revisions). Co-authored-by: timerloggedout-spec <timerloggedout@gmail.com>
…dpoints scaffold-aligned Devin: referenced workflow files exist on tembo/agent-quota-loadbalancer (#72), not on this PR branch. Annotate ci_cd.workflows with source_pr and set github.webhooks.endpoints active:false to match webhooks.yaml scaffold. Signed-off-by: Grok
| if os.path.exists(path): | ||
| with open(path) as f: |
There was a problem hiding this comment.
Potential file inclusion attack via reading file - medium severity
If an attacker can control the input leading into the open function, they might be able to read sensitive files and launch further attacks with that information.
Show fix
| if os.path.exists(path): | |
| with open(path) as f: | |
| base_dir = os.path.join(os.path.expanduser("~/.nexuscli/session_store"), account) | |
| base_real = os.path.realpath(base_dir) | |
| target_real = os.path.realpath(path) | |
| if os.path.commonpath([base_real, target_real]) != base_real: | |
| raise ValueError("Invalid file path") | |
| if os.path.exists(target_real): | |
| with open(target_real) as f: |
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info
| os.makedirs(os.path.dirname(path), exist_ok=True) | ||
| try: | ||
| os.chmod(os.path.dirname(path), 0o700) | ||
| except Exception: | ||
| pass | ||
| with open(path, 'w') as f: | ||
| json.dump(messages, f, indent=2) | ||
| try: | ||
| os.chmod(path, 0o600) |
There was a problem hiding this comment.
Potential file inclusion attack via reading file - low severity
If an attacker can control the input leading into the open function, they might be able to read sensitive files and launch further attacks with that information.
Show fix
| os.makedirs(os.path.dirname(path), exist_ok=True) | |
| try: | |
| os.chmod(os.path.dirname(path), 0o700) | |
| except Exception: | |
| pass | |
| with open(path, 'w') as f: | |
| json.dump(messages, f, indent=2) | |
| try: | |
| os.chmod(path, 0o600) | |
| base_dir = os.path.join(os.path.expanduser("~/.nexuscli/session_store"), account) | |
| base_real = os.path.realpath(base_dir) | |
| target_real = os.path.realpath(path) | |
| if os.path.commonpath([base_real, target_real]) != base_real: | |
| raise Exception("Invalid file path") | |
| os.makedirs(os.path.dirname(target_real), exist_ok=True) | |
| try: | |
| os.chmod(os.path.dirname(target_real), 0o700) | |
| except Exception: | |
| pass | |
| with open(target_real, 'w') as f: | |
| json.dump(messages, f, indent=2) | |
| try: | |
| os.chmod(target_real, 0o600) |
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info
| - name: Invoke Jules API (optional) | ||
| if: ${{ secrets.JULES_API_KEY != '' }} |
There was a problem hiding this comment.
🔴 Jules automation workflow fails to start because of an unsupported expression in step conditions
Step run conditions reference the secrets store (if: ${{ secrets.JULES_API_KEY != '' }} at .github/workflows/agent-jules-on-issues.yml:102), which GitHub does not allow in step-level conditions, so the whole workflow errors out instead of running.
Impact: Labeling an issue or mentioning the assistant never triggers the automation — every run fails immediately with an expression error.
The `secrets` context is not available in `jobs..steps[*].if`
GitHub's context availability table allows secrets in jobs.<job_id>.steps[*].with and .env, but not in if. Using it produces Unrecognized named-value: 'secrets' and the workflow file fails to compile at dispatch time, so no job runs at all.
Same pattern appears three times: .github/workflows/agent-jules-on-issues.yml:102 (Invoke Jules API), :138 (Fallback @jules ping), and :232 (Invoke Jules API on mention).
The standard workaround is to surface the secret into a job-level env (or an output of an earlier step) and test that in if, e.g. set env: HAS_JULES_KEY: ${{ secrets.JULES_API_KEY != '' }} on the job and use if: env.HAS_JULES_KEY == 'true'.
Prompt for agents
In .github/workflows/agent-jules-on-issues.yml the steps at lines 102, 138 and 232 use `if: ${{ secrets.JULES_API_KEY != '' }}`. The `secrets` context is not available in step-level `if` expressions, which makes the workflow fail to compile (`Unrecognized named-value: 'secrets'`) for every triggering event. Expose the presence of the key through a job-level `env` entry (secrets ARE allowed there) or via an output from a preceding step, then branch on that value in the `if` conditions.
Was this helpful? React with 👍 or 👎 to provide feedback.
| if args.save: | ||
| cfg = {} | ||
| cfg_dir = Path.home() / ".deepcode-cli" | ||
| cfg_dir.mkdir(parents=True, exist_ok=True) | ||
| try: | ||
| cfg_dir.chmod(0o700) | ||
| except Exception: | ||
| pass | ||
| cfg_file = cfg_dir / "config.json" | ||
| if cfg_file.exists(): | ||
| cfg = json.loads(cfg_file.read_text()) | ||
| if args.save: | ||
| cfg_path = Path.home() / ".nexuscli" / "config.json" | ||
| cfg_path.parent.mkdir(parents=True, exist_ok=True) | ||
| cfg = {} | ||
| if cfg_path.exists(): | ||
| cfg = json.loads(cfg_path.read_text()) | ||
| cfg["last_session"] = session_id | ||
| cfg_path.write_text(json.dumps(cfg, indent=2)) | ||
| console.print("[yellow]Saved as last_session.[/]") |
There was a problem hiding this comment.
🔴 Creating or looking up a saved session in the new CLI crashes
The JSON helper used when writing and reading the saved-session file (json.loads(...) at nexuscli/cli/main.py:80) is only imported inside the program's entry function, so it is undefined wherever it is actually used and the command aborts with an error.
Impact: new-session --save, and any command that relies on the remembered last session, fails outright.
Module-level functions reference a function-local import
import json appears only at nexuscli/cli/main.py:185, inside main(), so it binds a local name in main's scope — it never becomes a module global. cmd_new_session (lines 74, 80, 82) and get_last_session (line 178) reference json at module scope and raise NameError: name 'json' is not defined at runtime.
Additionally cmd_new_session has a dead first if args.save: block (lines 64-74) that creates and chmods ~/.deepcode-cli and reads a config that is then discarded by the second if args.save: block — the directory creation is a leftover that should be removed.
| if args.save: | |
| cfg = {} | |
| cfg_dir = Path.home() / ".deepcode-cli" | |
| cfg_dir.mkdir(parents=True, exist_ok=True) | |
| try: | |
| cfg_dir.chmod(0o700) | |
| except Exception: | |
| pass | |
| cfg_file = cfg_dir / "config.json" | |
| if cfg_file.exists(): | |
| cfg = json.loads(cfg_file.read_text()) | |
| if args.save: | |
| cfg_path = Path.home() / ".nexuscli" / "config.json" | |
| cfg_path.parent.mkdir(parents=True, exist_ok=True) | |
| cfg = {} | |
| if cfg_path.exists(): | |
| cfg = json.loads(cfg_path.read_text()) | |
| cfg["last_session"] = session_id | |
| cfg_path.write_text(json.dumps(cfg, indent=2)) | |
| console.print("[yellow]Saved as last_session.[/]") | |
| if args.save: | |
| cfg_path = Path.home() / ".nexuscli" / "config.json" | |
| cfg_path.parent.mkdir(parents=True, exist_ok=True) | |
| cfg = {} | |
| if cfg_path.exists(): | |
| cfg = json.loads(cfg_path.read_text()) | |
| cfg["last_session"] = session_id | |
| cfg_path.write_text(json.dumps(cfg, indent=2)) | |
| console.print("[yellow]Saved as last_session.[/]") |
Was this helpful? React with 👍 or 👎 to provide feedback.
| import struct | ||
| sid_bytes, msg_idx, blk_idx = struct.unpack('>12sII', data[:20]) | ||
| content_hash = data[20:28].hex() | ||
| content_hash = data[20:52].hex() | ||
| return cls(sid_bytes.rstrip(b'\x00').decode(), msg_idx, blk_idx, content_hash) |
There was a problem hiding this comment.
🔍 Hash width change breaks compatibility with previously written blob files
Content hashes moved from a truncated 16 hex chars to the full 64-char SHA-256 (cli-synthegration/synthegration_index.py:206, :228, :306, :557) and the wire decoder now reads 32 bytes (:45, :138). Any existing blobs/<ch>.blob files, persisted codex_index.json pointers, or serialized wire payloads written with the old 16-char/8-byte layout will no longer match: to_wire will pack 32 bytes while an old reader expects 8, and reverse_lookup/search_by_taxonomy will miss previously indexed content. There is no migration path in the diff.
Was this helpful? React with 👍 or 👎 to provide feedback.
| for p in self.taxonomy.search(term): | ||
| if lang and not any(lang in part for part in [p.session_id, '']): | ||
| continue # simplistic | ||
| blob = self.base_dir / 'blobs' / f"{p.content_hash}.blob" | ||
| if blob.exists(): | ||
| results.append({ | ||
| 'pointer': p.to_key(), | ||
| 'hash': p.content_hash, | ||
| 'code': blob.read_text()[:200] + '...' if len(blob.read_text()) > 200 else blob.read_text(), | ||
| 'timestamp': self.time_index.get(p.content_hash, '').isoformat() | ||
| }) | ||
| blob_path = self.blobs.get(p.content_hash) | ||
| if blob_path: | ||
| blob = Path(blob_path) | ||
| if blob.exists(): | ||
| results.append({ | ||
| 'pointer': p.to_key(), | ||
| 'hash': p.content_hash, |
There was a problem hiding this comment.
🔍 search_by_taxonomy now resolves blobs through an in-memory map that may hold code, not paths
The lookup switched from a direct base_dir/'blobs'/<hash>.blob path to self.blobs.get(p.content_hash). index_conversation stores a filesystem path there (line 319), but _ingest_blocks stores the raw code text (line 238), and _rebuild_hash_index stores paths. For codexes built via from_live_exports, Path(<code text>).exists() is False, so those blocks silently drop out of search results where the old code would have found the on-disk blob if one existed. Also note the pre-existing self.time_index.get(p.content_hash, '').isoformat() on line 346 still raises AttributeError when a hash has no timestamp.
Was this helpful? React with 👍 or 👎 to provide feedback.
| # 1nd3x 4ll pr0j3ct f1l3s (using a single shared sqlite3 connection for speed) | ||
| import sqlite3 | ||
| from src.db import DB_PATH | ||
| try: | ||
| conn = sqlite3.connect(DB_PATH) | ||
| for root, _, files in os.walk(workspace_path): | ||
| for file in files: | ||
| rel_path = os.path.relpath(os.path.join(root, file), workspace_path) | ||
| index_project_file(workspace_path, rel_path, conn=conn) | ||
| conn.commit() | ||
| except Exception: | ||
| pass | ||
| finally: | ||
| try: | ||
| conn.close() | ||
| except Exception: | ||
| pass | ||
|
|
||
| # D3t3rm1n3 t4rg3t f1l3 | ||
| target_name = os.environ.get("TARGET_FILE", "test_script.py") |
There was a problem hiding this comment.
📝 Info: Shared SQLite connection is not committed when indexing raises
index_project_file now accepts an external conn and only commits when it created the connection itself (src/db.py:143-147). The callers in termux-multi-agent/run.py:90-105 and termux-multi-agent/workspace/run.py:93-105 commit after the walk, but the commit is inside the same try that swallows every exception — if any file raises after several files were batched, the outer except Exception: pass skips the commit and the entire indexing pass is lost (the old per-file with sqlite3.connect(...) committed incrementally). Consider committing per file or in the finally block before closing.
Was this helpful? React with 👍 or 👎 to provide feedback.
| if: | | ||
| ( | ||
| github.event_name == 'pull_request' && | ||
| github.event.pull_request.head.repo.fork == false && | ||
| github.event.pull_request.draft == false | ||
| ) || ( | ||
| github.event_name == 'issues' && | ||
| contains(fromJSON('["opened", "reopened"]'), github.event.action) | ||
| ) || ( | ||
| github.event.sender.type == 'User' && | ||
| startsWith(github.event.comment.body || github.event.review.body || '', '@gemini-cli') && | ||
| contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association || github.event.review.author_association || github.event.issue.author_association) | ||
| ) |
There was a problem hiding this comment.
📝 Info: Dispatch trigger condition can throw on non-comment events
The third clause of the dispatch job condition dereferences github.event.comment.body, github.event.review.body and github.event.issue.author_association unconditionally. GitHub expressions return null for missing properties rather than erroring, so startsWith(null || null || '', ...) is safe, but note the pull_request and issues clauses come first only in a boolean OR — all three clauses are still evaluated. Because github.event.sender.type == 'User' is true for human-opened PRs too, a PR whose body-less event has no comment simply falls through to false; behavior is correct but fragile and hard to reason about. Splitting the condition per event name would be clearer.
Was this helpful? React with 👍 or 👎 to provide feedback.
| parent_message_id = None | ||
| while True: | ||
| try: | ||
| prompt = Prompt.ask("[bold cyan]You[/]") | ||
| if prompt.lower() in ["exit", "quit", "q"]: | ||
| break | ||
|
|
||
| console.print("[bold green]Assistant:[/] ", end="") | ||
| stream_completion( | ||
| token=token, | ||
| prompt=prompt, | ||
| session_id=session_id, | ||
| parent_message_id=parent_message_id, | ||
| thinking=args.thinking, | ||
| search=args.search, | ||
| ) | ||
| console.print() | ||
| parent_message_id = None # Reset for next message |
There was a problem hiding this comment.
🔍 Interactive chat never threads replies
parent_message_id is initialized to None and then explicitly reset to None after each turn (line 124, comment "Reset for next message"), so every message in an interactive chat session is sent as a fresh root rather than a continuation. Given the CLI advertises session/branch semantics, the parent id should be updated with the id of the assistant message just produced.
Was this helpful? React with 👍 or 👎 to provide feedback.
| Returns list of (pointer, similarity, snippet).""" | ||
| import hashlib | ||
| from difflib import SequenceMatcher | ||
|
|
There was a problem hiding this comment.
🔍 Multiple pre-existing structural defects remain in the touched indexing module
The diff edits lines inside synthegration_index.py but leaves the surrounding damage in place: Pointer.to_key() and Pointer.citation() both return "" before their real bodies (lines 22-33), so every to_key() used for persistence and dedup returns an empty string; _CodexIndex_v1/CodexIndex have bare @staticmethod decorators immediately above __init__ (lines 107-109, 246-247); and MessageIndex.reverse_lookup (line 552+) references self.hash_to_pointer and self.base_dir, which only exist on CodexIndex — it is dead/broken as written. The PR's hash-width change at line 557 lands inside that broken method.
Was this helpful? React with 👍 or 👎 to provide feedback.
| const bot = | ||
| context.payload.review?.user?.login || | ||
| context.payload.comment?.user?.login || | ||
| 'review-bot'; | ||
| const snippet = ( | ||
| context.payload.review?.body || | ||
| context.payload.comment?.body || | ||
| '' | ||
| ).slice(0, 1200); | ||
| const path = context.payload.comment?.path || ''; | ||
| const body = [ | ||
| marker, | ||
| `@jules **Auto-resolve** (GHA agent-review-auto-jules) — do not wait for a human ping.`, | ||
| ``, | ||
| `Bot feedback from **${bot}** on PR #${prNumber} (branch \`${head}\`).`, | ||
| path ? `File: \`${path}\`` : '', | ||
| ``, | ||
| `### Feedback excerpt`, | ||
| snippet ? '```' : '', | ||
| snippet || '(see review threads)', | ||
| snippet ? '```' : '', | ||
| ``, | ||
| `### Instructions`, | ||
| `1. Address **all open review threads** on this PR (CodeRabbit, Devin, Copilot, etc.).`, | ||
| `2. Prefer minimal diffs; preserve Sentinel 0o600/0o700 if those files are touched.`, | ||
| `3. Push commits to branch \`${head}\`. Do not retarget away from the PR base without cause.`, | ||
| `4. If conflicts with base exist, resolve them.`, | ||
| `5. Skip pure nits only if they conflict with security/gates; otherwise apply autofixes.`, | ||
| ``, | ||
| `Agent: Grok orchestration · Profile: https://x.com/grok`, | ||
| ].filter(Boolean).join('\n'); | ||
| await github.rest.issues.createComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: prNumber, | ||
| body, | ||
| }); |
There was a problem hiding this comment.
🟨 Bot-authored review text is injected verbatim into an automation prompt
.github/workflows/agent-review-auto-jules.yml:120-136 takes the review/comment body of any account whose login merely contains coderabbit/devin/copilot (or any Bot type, including bots on forks' PR reviews) and embeds the first 1200 characters directly into a @jules "Auto-resolve" instruction comment. The trigger conditions at lines 24-53 only match on substring of the login, so a user-created account or app whose name contains those substrings can post a review whose body carries instructions that are then relayed to an autonomous coding agent with write access to the PR branch.
Was this helpful? React with 👍 or 👎 to provide feedback.
| if: | | ||
| ( | ||
| github.event_name == 'pull_request' && | ||
| github.event.pull_request.head.repo.fork == false && | ||
| github.event.pull_request.draft == false | ||
| ) || ( | ||
| github.event_name == 'issues' && | ||
| contains(fromJSON('["opened", "reopened"]'), github.event.action) | ||
| ) || ( | ||
| github.event.sender.type == 'User' && | ||
| startsWith(github.event.comment.body || github.event.review.body || '', '@gemini-cli') && | ||
| contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association || github.event.review.author_association || github.event.issue.author_association) | ||
| ) |
There was a problem hiding this comment.
🟨 Issue text from any reporter is interpolated into an agent prompt on issue open
.github/workflows/gemini-dispatch.yml:32-43 allows the issues opened/reopened path without any author-association restriction, and .github/workflows/gemini-triage.yml:49-63 then runs the agent against that issue. The issue body flows into steps.extract via REQUEST (gemini-dispatch.yml:61) and into downstream prompts, while comment-triggered paths are correctly gated on OWNER/MEMBER/COLLABORATOR. An arbitrary external reporter can therefore steer the triage agent (which holds issues: write / pull-requests: write) and consume the free-tier quota.
Was this helpful? React with 👍 or 👎 to provide feedback.
ADE / Grok — Gemini-CLI integration test + ship statusTest trigger (controlled): @gemini-cli /review Focus on quota-gate correctness, startup-failure root cause, and whether free-tier limits (RPM/RPD) are documented accurately. Skip unrelated nits. Actions noise diagnosis (2500+ runs)Cascade source: every bot comment/review re-fires:
Result: comment storms on #70/#72 produce dozens of short (1–2s) or Startup-failure runs. Not quota alone — feedback loops. Mitigations already in flight via this PR (#72):
Still needed after land:
Merge callDo NOT merge #72 yet. Startup failures on the branch must be green first. Once:
→ then merge #72 → master-staging, then promote Gemini workflows to #70 is already on master-staging. Connectors present. Exchange cleanup remains #74. Signed-off-by: Grok (ADE) |
Narrow after #75 / promoteCore quota-gate + session continuation + graceful skip landed via #75 (master-staging) and is promoting to master via focused workflows-only PR. Still valuable from this PR (if not already on staging/master):
Superseded / do not re-merge as-is:
Please either:
Signed-off-by: Grok (ADE) |
Priority update — Load Balancer LOW; Orchestrations Optimizer HIGHOperator guidance (aligned with #75 discussion + #81 directing comment): Load balancer / token rotation = LOW priority
Orchestrations Optimizer = HIGH priorityMaximize useful results per quota unit, consolidated in dispatch (
Recommendation for this PR (#72)Narrow or close. Much of the quota-gate / session / graceful-skip surface already landed via #75 → master-staging and is promoting on #81 → master. Keep only unique non-overlapping value if any:
Drop or defer:
Refs: #75 (merged), #81 (promote), #71 (superseded). Signed-off-by: Grok (ADE) |
|
sha: 9d98336 @jules opsSweep (heyVern lane) — high-perf unattended advance. PR #72 · Instructions
Monikers: docs/ops/AGENT-MONIKERS.md · Read AGENTS.md. |
|
sha: 9d98336 @jules opsSweep (heyVern lane) — high-perf unattended advance. PR #72 · Instructions
Monikers: docs/ops/AGENT-MONIKERS.md · Read AGENTS.md. |
|
sha: 9d98336 @jules opsSweep (heyVern lane) — high-perf unattended advance. PR #72 · Instructions
Monikers: docs/ops/AGENT-MONIKERS.md · Read AGENTS.md. |
|
sha: 9d98336 @jules opsSweep (heyVern lane) — high-perf unattended advance. PR #72 · Instructions
Monikers: docs/ops/AGENT-MONIKERS.md · Read AGENTS.md. |
|
sha: 9d98336 @jules opsSweep (heyVern lane) — high-perf unattended advance. PR #72 · Instructions
Monikers: docs/ops/AGENT-MONIKERS.md · Read AGENTS.md. |
|
sha: 9d98336 @jules opsSweep (heyVern lane) — high-perf unattended advance. PR #72 · Instructions
Monikers: docs/ops/AGENT-MONIKERS.md · Read AGENTS.md. |
|
sha: 9d98336 @jules opsSweep (heyVern lane) — high-perf unattended advance. PR #72 · Instructions
Monikers: docs/ops/AGENT-MONIKERS.md · Read AGENTS.md. |
…240) * feat(ops): add ML ingestion pipeline and infrastructure dashboard * chore(data): clean ANSI escape sequences from session metadata * docs(eval): update report with phase 2 implementation results * feat(nexuscli): retarget to llm_api_hub and remove PoW solver * docs(eval): final handoff report for integrated infrastructure * feat(hub): add headless Grok/Mistral backends and cookie extraction utility * feat(hub): integrate provider registry and checklist from feature branch * feat(hub): add Anthropic and Google Gemini native API compatibility * docs(eval): update handoff with multi-API compatibility and registry integration * feat(hub): integrate lightwrap backend and harvesters from feature branches * feat(hub): integrate lightwrap, provider checklist API, and dashboard lifecycle monitoring * docs(eval): finalize handoff with lifecycle monitoring and lightwrap details * feat(hub): add Perplexity/Kimi wrappers and xAI upstream support * docs(eval): finalize handoff with PR #72/#92 and MCP integration details * feat(hub): implement WebUI Search and align with deepterm patterns * docs(eval): finalize handoff with WebUI Search and deepterm alignment --------- Co-authored-by: timerloggedout-spec <2.33432881e+08+timerloggedout-spec@users.noreply.github.com>
Summary
Addresses the CI failure root cause from PR #63: Gemini free-tier daily quota exhaustion (20 req/day) causing 14 failing workflows. This PR adds proper throttling, session management/continuation, and load balancing across all agent integrations.
Implements:
agent-quota-loadbalancerQL-01 through QL-08What changed
1. Quota Gate (
.github/actions/gemini-quota-gate/action.yml)GEMINI_API_KEY_BACKUPsecret is set, rotates to the backup key when the primary quota is exhausted (doubles capacity to 36 req/day)2. Session Continuation (
gemini-review.yml)<!-- gemini-review-sha: <sha> -->)synchronizepushes: skips entirely if the commit hasn't changed (saves quota)3. Load Balancer (
.github/workflows/agent-load-balancer.yml)4. Updated Gemini workflows
gemini-review.yml,gemini-triage.yml,gemini-invoke.ymlall now use the quota gate5. Agent Capability Registry (
docs/schemas/agent-capabilities.yaml)6. Proposal registration
docs/proposals/active/agent-quota-loadbalancer/(MANIFEST + ITEMS)docs/proposals/registry.yamlas P0, status: executing7. .gitignore
nexusclisession store patterns (.nexuscli/session_store/,.nexuscli/config.json,.nexuscli/tokens/)Agent capacity model
How it fixes the CI failure
Before: Every PR event (opened/synchronize/ready_for_review) dispatched a Gemini job. 14 events → 14 jobs → quota exhausted → all subsequent jobs hard-failed with
TerminalQuotaError.After: The quota gate tracks daily usage. When the limit is hit, subsequent jobs skip gracefully (exit 0, post a comment) instead of failing. Other agents (CodeRabbit, Jules) continue independently. The quota resets at 00:00 UTC automatically.
Items
Signed-off-by: tembo