Skip to content

feat: QGo multi-agent system, copyright headers, logo, enhanced README#1

Merged
Rahulchaube1 merged 2 commits intomainfrom
copilot/improve-qgo-functionality
Mar 28, 2026
Merged

feat: QGo multi-agent system, copyright headers, logo, enhanced README#1
Rahulchaube1 merged 2 commits intomainfrom
copilot/improve-qgo-functionality

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 28, 2026

Builds out QGo into a full AI coding assistant with a multi-agent orchestration layer, Rahul Chaube copyright attribution across the codebase, an SVG logo, and an updated README.

Multi-Agent System (qgo/agents/)

Eight specialist agents coordinated by AgentOrchestrator:

Agent Responsibility
PlannerAgent Decomposes task → ordered sub-task JSON plan
CoderAgent Produces SEARCH/REPLACE edit blocks
ReviewerAgent Correctness, perf, best-practice review
TesterAgent Generates pytest suites with edge cases
DebuggerAgent Root-cause analysis + minimal fix
DocWriterAgent Docstrings, README sections, inline comments
SecurityAgent Injection, path traversal, secret exposure audits
RefactorAgent DRY/SRP/naming improvements, behaviour-preserving

AgentOrchestrator.run() drives the pipeline: planner emits a JSON plan, agents execute sequentially with accumulated context passed forward, results compiled into a Markdown report.

orchestrator = AgentOrchestrator(llm=llm, io=io)
report = orchestrator.run("add JWT authentication to the Flask API")

# Or target a specific agent directly
result = orchestrator.run_single("security", "audit auth.py")

Message-bus broadcasts (_broadcast) let agents receive outputs from peers via AgentMessage.

Copyright & Branding

  • Copyright (c) 2024 Rahul Chaube. All Rights Reserved. headers added to all 28 source files
  • SVG logo added at assets/logo.svg
  • README updated: logo, copyright section, multi-agent architecture diagram, agent table, usage examples, new feature badges

Tests

61 new tests in tests/test_agents.py covering AgentMessage, AgentResult, BaseAgent, all 8 specialist agents (parametrised), and AgentOrchestrator (plan parsing, routing, max_agents cap, error paths, report compilation).

Copilot AI and others added 2 commits March 28, 2026 22:34
Agent-Logs-Url: https://github.com/Rahulchaube1/QGo/sessions/18f64b0a-1c03-4cfb-a2cc-17e2eead44a9

Co-authored-by: Rahulchaube1 <157899057+Rahulchaube1@users.noreply.github.com>
@Rahulchaube1 Rahulchaube1 marked this pull request as ready for review March 28, 2026 23:21
Copilot AI review requested due to automatic review settings March 28, 2026 23:21
@Rahulchaube1 Rahulchaube1 merged commit b77ea05 into main Mar 28, 2026
9 checks passed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR turns QGo into a more complete terminal-based AI coding assistant by adding a multi-agent orchestration layer, expanding core coding/editing utilities (repo map, diff/whole-file coders, token counting, web scraping, UI/REPL), and updating packaging/docs/branding with a logo and a much richer README.

Changes:

  • Added multi-agent system (qgo/agents/*) with an orchestrator coordinating specialist agents and report compilation.
  • Implemented core assistant building blocks: coders (editblock/udiff/whole/architect), repo mapping, git integration, terminal UI + REPL commands, token counting, and web scraping.
  • Added CI + packaging metadata, extensive pytest coverage, and updated README/logo/branding.

Reviewed changes

Copilot reviewed 42 out of 45 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
tests/test_repo_map.py Adds symbol-extraction and repo-map behavior tests
tests/test_llm.py Tests model metadata/aliasing and token counter utilities
tests/test_file_utils.py Tests file utilities (read/write/diff/language detection)
tests/test_editblock_coder.py Tests SEARCH/REPLACE parsing and edit application
tests/test_config.py Tests config loading/saving via YAML + env vars
tests/test_agents.py Tests multi-agent core types, agents, and orchestrator behavior
tests/init.py Defines tests package marker/docstring
requirements.txt Adds runtime + dev dependency list
qgo/utils/web_scraper.py Adds URL fetching and HTML-to-text/Markdown extraction
qgo/utils/token_counter.py Adds token counting + truncation helpers
qgo/utils/file_utils.py Adds filesystem helpers and unified diff generation
qgo/utils/init.py Exposes utility functions as public imports
qgo/ui/terminal.py Implements Rich-based terminal output + streaming
qgo/ui/repl.py Adds prompt_toolkit REPL with history and completion
qgo/ui/commands.py Adds slash commands for context/files/git/web/run/etc.
qgo/ui/init.py Exposes UI entry points
qgo/repo/repo_map.py Implements regex-based repository symbol mapping
qgo/repo/git_repo.py Implements git operations via subprocess
qgo/repo/file_watcher.py Adds watchdog-based file watching (with stub fallback)
qgo/repo/init.py Exposes repo helpers
qgo/models.py Adds core dataclasses/enums for messages/files/edits/session
qgo/main.py Adds Click CLI entry point with config + REPL/one-shot flow
qgo/llm/streaming.py Adds streaming helpers for litellm responses
qgo/llm/model_info.py Adds model metadata registry, aliasing, and formatting
qgo/llm/litellm_provider.py Implements BaseLLM provider on top of litellm
qgo/llm/base.py Defines BaseLLM interface + capability properties
qgo/llm/init.py Exposes LLM provider + model info helpers
qgo/coders/whole_coder.py Whole-file editing parser + apply logic
qgo/coders/udiff_coder.py Unified-diff parsing + application logic
qgo/coders/editblock_coder.py SEARCH/REPLACE parsing + fuzzy replacement logic
qgo/coders/base_coder.py Core chat loop, prompt construction, auto-commit/lint hooks
qgo/coders/architect_coder.py Two-pass plan+implement “architect” mode
qgo/coders/init.py Coder factory + exports
qgo/agents/specialist_agents.py Defines 8 specialist agents and their system prompts
qgo/agents/orchestrator.py Implements planner-driven execution + message bus + report
qgo/agents/base_agent.py Defines base agent, message/result dataclasses, and run logic
qgo/agents/init.py Exposes multi-agent system public API
qgo/main.py Enables python -m qgo entry
qgo/init.py Package metadata/version
pyproject.toml Packaging metadata, dependencies, and tool configs
assets/logo.svg Adds project logo asset
README.md Expands documentation: features, architecture, usage, commands
.gitignore Adds standard Python + QGo-specific ignores
.github/workflows/ci.yml Adds CI workflow for lint/test/build

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +26 to +30
except ImportError:
# tiktoken not installed — rough estimate: ~4 characters per token
return max(1, len(text) // 4)
except Exception:
# Network error downloading encoding files, or other runtime error
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

Fallback token estimation uses max(1, len(text)//4), so count_tokens("") becomes 1 when tiktoken isn’t installed, while tiktoken returns 0. Return 0 for empty input in the fallback path to keep behavior consistent.

Copilot uses AI. Check for mistakes.
Comment thread qgo/utils/web_scraper.py
Comment on lines +92 to +96
except ImportError:
return _fetch_plain(url, timeout)
except Exception as exc:
return f"[Error fetching {url}: {exc}]"

Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

On exceptions, fetch_url returns a non-empty error string ([Error fetching ...]), which contradicts the docstring contract that failures return an empty string. Returning "" (and optionally logging via io) would make callers easier to reason about.

Copilot uses AI. Check for mistakes.
Comment thread pyproject.toml
"click>=8.1",
"rich>=13.0",
"prompt_toolkit>=3.0",
"gitpython>=3.1",
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

gitpython>=3.1 is listed as a core dependency but there are no GitPython imports/usages in qgo/ (git integration is via subprocess). Consider removing it from dependencies to avoid pulling an unused heavy dependency unless it’s needed in this PR.

Suggested change
"gitpython>=3.1",

Copilot uses AI. Check for mistakes.
**kwargs,
) -> None:
self._model = resolve_model(model)
self._api_key = api_key or os.environ.get("OPENAI_API_KEY")
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

self._api_key defaults to OPENAI_API_KEY even when the chosen model/provider is not OpenAI, which can prevent provider-specific env var detection and send the wrong key. Prefer self._api_key = api_key and only fall back to provider-specific env vars based on get_model_info(self._model).

Suggested change
self._api_key = api_key or os.environ.get("OPENAI_API_KEY")
self._api_key = api_key

Copilot uses AI. Check for mistakes.
Comment thread qgo/coders/whole_coder.py
# ```python path/to/file.py\n...```
# path/to/file.py\n```python\n...```
_FENCE_RE = re.compile(
r"```[\w]*\s*\n(.*?)```",
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

The comment says the parser supports fences like python path/to/file.py\n..., but _FENCE_RE requires a newline immediately after the language token (it won’t match a filename on the same fence line). Either widen the regex to accept an optional filename after the language or update the documented supported formats.

Suggested change
r"```[\w]*\s*\n(.*?)```",
r"```[\w]*?(?:\s+[^\n`]+)?\s*\n(.*?)```",

Copilot uses AI. Check for mistakes.
Comment thread qgo/coders/whole_coder.py
Comment on lines +82 to +85
try:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(block.updated, encoding="utf-8")
action = "Created" if block.is_new_file or not path.exists() else "Updated"
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

action is computed after writing the file, so not path.exists() will always be false here. Also, EditBlock(original="") marks every whole-file block as is_new_file=True, so updates will be logged as "Created". Capture existed_before = path.exists() before writing and base the action on that (or set is_new_file explicitly for whole-file edits).

Suggested change
try:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(block.updated, encoding="utf-8")
action = "Created" if block.is_new_file or not path.exists() else "Updated"
existed_before = path.exists()
try:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(block.updated, encoding="utf-8")
# Determine action based on whether the file existed before writing
block.is_new_file = not existed_before
action = "Created" if not existed_before else "Updated"

Copilot uses AI. Check for mistakes.
Comment thread qgo/coders/base_coder.py
Comment on lines +205 to +209
if stream and self.io:
iterator = self.llm.complete(messages, stream=True)
if hasattr(iterator, "__iter__"):
response = self.io.stream_response(iterator)
else:
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

hasattr(iterator, "__iter__") will be true for strings, so if an LLM provider ever returns a plain string while stream=True, it will be streamed character-by-character. Consider checking isinstance(iterator, str) (or collections.abc.Iterator) before calling io.stream_response.

Copilot uses AI. Check for mistakes.
Comment thread qgo/utils/web_scraper.py
Comment on lines +23 to +26
Returns:
Cleaned text content suitable for LLM context.
Empty string if fetching fails.
"""
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

Docstring promises "Empty string if fetching fails", but the function later returns a formatted error string on exceptions. Either adjust the docstring or change the error-path return value to "" to match the contract.

Copilot uses AI. Check for mistakes.
Comment thread qgo/main.py
@click.option("--model", "-m", default=None, help="LLM model to use (e.g. gpt-4o, claude-3-7-sonnet-20250219)")
@click.option("--api-key", default=None, envvar="QGO_API_KEY", help="LLM API key")
@click.option("--api-base", default=None, envvar="QGO_API_BASE", help="Custom API base URL (for Ollama, vLLM, etc.)")
@click.option("--edit-format", "-f",
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

-f is registered for --edit-format here, but it’s also used for --file later in the same command, which will cause a Click option conflict and prevent the CLI from starting. Use distinct short flags (or remove one).

Suggested change
@click.option("--edit-format", "-f",
@click.option("--edit-format", "-e",

Copilot uses AI. Check for mistakes.
Comment thread qgo/agents/base_agent.py
Comment on lines +143 to +147
if stream and self.io and hasattr(self.io, "stream_response"):
iterator = self.llm.complete(messages, stream=True)
# Consume iterator
if hasattr(iterator, "__iter__"):
return self.io.stream_response(iterator)
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

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

Same streaming detection issue as in BaseCoder._send: hasattr(iterator, "__iter__") is true for strings, which can cause character-by-character streaming if llm.complete(..., stream=True) returns a string. Prefer an explicit iterator check and guard against str/bytes.

Copilot uses AI. Check for mistakes.
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.

3 participants