gemcode 0.3.121__tar.gz → 0.4.0__tar.gz
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.
- {gemcode-0.3.121/src/gemcode.egg-info → gemcode-0.4.0}/PKG-INFO +39 -32
- {gemcode-0.3.121 → gemcode-0.4.0}/README.md +37 -30
- {gemcode-0.3.121 → gemcode-0.4.0}/pyproject.toml +2 -2
- gemcode-0.4.0/src/gemcode/a2a_bridge.py +258 -0
- gemcode-0.4.0/src/gemcode/agent_intelligence.py +259 -0
- gemcode-0.4.0/src/gemcode/agent_mesh.py +536 -0
- gemcode-0.4.0/src/gemcode/agent_triggers.py +332 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/checkpoints.py +18 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/cli.py +1 -1
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/config.py +3 -0
- gemcode-0.4.0/src/gemcode/delegation_learning.py +245 -0
- gemcode-0.4.0/src/gemcode/event_bus.py +201 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/fleet_reports.py +3 -1
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/invoke.py +33 -220
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/kaira_client.py +4 -2
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/kaira_daemon.py +21 -7
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/kaira_ipc.py +67 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/repl_slash.py +36 -13
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/__init__.py +52 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/automations_tools.py +3 -3
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/org_tools.py +113 -104
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/subtask.py +21 -10
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tui/scrollback.py +6 -3
- {gemcode-0.3.121 → gemcode-0.4.0/src/gemcode.egg-info}/PKG-INFO +39 -32
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode.egg-info/SOURCES.txt +9 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode.egg-info/requires.txt +1 -1
- gemcode-0.4.0/tests/test_agent_mesh.py +96 -0
- gemcode-0.4.0/tests/test_event_bus.py +151 -0
- gemcode-0.4.0/tests/test_kaira_ipc_paths.py +39 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/LICENSE +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/MANIFEST.in +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/setup.cfg +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/__init__.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/__main__.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/agent.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/audit.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/autocompact.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/automations.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/autotune.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/callbacks.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/capability_routing.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/compaction.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/computer_use/__init__.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/computer_use/browser_computer.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/context_budget.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/context_warning.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/credentials.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/curated_memory.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/dynamic_policy.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/evals/harness.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/hitl_session.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/hooks.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/ide_protocol.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/ide_stdio.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/intent_classifier.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/interactions.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/kaira_job_store.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/learning.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/limits.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/live_audio_engine.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/logging_config.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/mcp_loader.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/memory/__init__.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/memory/embedding_memory_service.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/memory/file_memory_service.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/modality_tools.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/model_errors.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/model_routing.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/multimodal_input.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/openapi_loader.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/org.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/output_styles.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/paths.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/permissions.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/plugins/__init__.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/plugins/terminal_hooks_plugin.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/plugins/tool_recovery_plugin.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/policy_profile.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/pricing.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/prompt_suggestions.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/query/__init__.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/query/config.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/query/deps.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/query/engine.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/query/stop_hooks.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/query/token_budget.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/query/transitions.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/query_sanitizer.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/refine.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/repl_commands.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/review_agent.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/rules.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/session_runtime.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/session_store.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/session_summariser.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/skills.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/slash_commands.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/thinking.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tool_prompt_manifest.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tool_registry.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tool_result_store.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/bash.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/browser.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/compress_memory.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/curated_memory.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/edit.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/filesystem.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/notebook.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/notes.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/repo_map.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/search.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/shell.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/shell_gate.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/skills.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/tasks.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/think.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/todo.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/user_choice.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/veomem_tools.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/web.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools/web_search.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tools_inspector.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/trust.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tui/input_handler.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tui/spinner.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tui/welcome_banner.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/tui/welcome_rich.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/veomem_bridge.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/version.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/vertex.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/wal.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/web/__init__.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/web/sse_adapter.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/web/terminal_repl.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/web/web_sse_compat.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode/workspace_hints.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode.egg-info/dependency_links.txt +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode.egg-info/entry_points.txt +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/src/gemcode.egg-info/top_level.txt +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_add_dir.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_agent_instruction.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_autocompact.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_automations.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_capability_routing.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_checkpoint_diff_command.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_cli_init.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_compress_memory_tool.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_computer_use_permissions.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_context_budget.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_context_warning.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_credentials.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_eval_harness_layout.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_fleet_reports.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_ide_stdio_attachments.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_interactive_permission_ask.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_kaira_scheduler.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_modality_tools.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_model_error_retry.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_model_errors.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_model_routing.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_multimodal_input.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_output_styles_and_rules.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_paths.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_permissions.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_prompt_suggestions.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_repl_commands.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_repl_slash.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_session_runtime_cache.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_skills.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_slash_commands.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_slash_completion_registry.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_thinking_config.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_token_budget.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_tool_context_circulation.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_tools.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_tools_inspector.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_web_sse_adapter.py +0 -0
- {gemcode-0.3.121 → gemcode-0.4.0}/tests/test_workspace_hints.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gemcode
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Local-first coding agent on Google Gemini + ADK
|
|
5
5
|
Author: GemCode Contributors
|
|
6
6
|
License: Apache License
|
|
@@ -175,7 +175,7 @@ Classifier: Topic :: Terminals
|
|
|
175
175
|
Requires-Python: >=3.11
|
|
176
176
|
Description-Content-Type: text/markdown
|
|
177
177
|
License-File: LICENSE
|
|
178
|
-
Requires-Dist: google-adk>=1.0.0
|
|
178
|
+
Requires-Dist: google-adk[a2a]>=1.0.0
|
|
179
179
|
Requires-Dist: google-genai>=1.0.0
|
|
180
180
|
Requires-Dist: python-dotenv>=1.0.0
|
|
181
181
|
Requires-Dist: rich>=13.0.0
|
|
@@ -212,8 +212,10 @@ GemCode is designed for repository-native work rather than copy-paste chat workf
|
|
|
212
212
|
| REPL | Stateful terminal interaction |
|
|
213
213
|
| TUI | GemCode terminal UI (scrollback-style; `tui/scrollback.py`) |
|
|
214
214
|
| IDE stdio | Editor integration over JSONL stdin/stdout |
|
|
215
|
-
|
|
|
216
|
-
|
|
|
215
|
+
| Agent Mesh | In-process multi-agent orchestration (automatic) |
|
|
216
|
+
| Kaira daemon | Optional always-on background scheduler |
|
|
217
|
+
| A2A server | Cross-machine agent communication via Google A2A protocol |
|
|
218
|
+
| Live audio (experimental) | Microphone-driven Gemini Live sessions |
|
|
217
219
|
|
|
218
220
|
## Recommended reading order
|
|
219
221
|
|
|
@@ -360,34 +362,25 @@ gemcode -C . --attach ./report.pdf "Summarize this"
|
|
|
360
362
|
gemcode kaira -C .
|
|
361
363
|
```
|
|
362
364
|
|
|
363
|
-
### Orchestration (
|
|
365
|
+
### Orchestration (Agent Mesh + Multi-Agent)
|
|
364
366
|
|
|
365
|
-
|
|
367
|
+
GemCode includes a built-in multi-agent orchestration system that works automatically — no separate daemon required.
|
|
366
368
|
|
|
367
|
-
|
|
368
|
-
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
gemcode kaira -C .
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
In another terminal:
|
|
377
|
-
|
|
378
|
-
```bash
|
|
379
|
-
gemcode -C .
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
Then in the REPL/TUI:
|
|
369
|
+
**Key features:**
|
|
370
|
+
- **Agent Mesh** — in-process concurrent agent execution with full tool access
|
|
371
|
+
- **Event Bus** — agents communicate via pub/sub (no Unix sockets needed)
|
|
372
|
+
- **Self-Triggering Agents** — agents auto-activate on events (e.g., verifier reviews completed work)
|
|
373
|
+
- **Delegation Learning** — remembers which agents succeed at which tasks
|
|
374
|
+
- **A2A Bridge** — expose/consume agents across machines via Google's A2A protocol
|
|
383
375
|
|
|
376
|
+
Quick example in the REPL:
|
|
384
377
|
```text
|
|
385
|
-
|
|
386
|
-
/org hire verifier "QA / test planner" subagent gemcode "Find risks, propose tests, review plans."
|
|
387
|
-
/org assign verifier "Review the plan and propose tests"
|
|
388
|
-
/kaira jobs
|
|
389
|
-
/kaira follow <job_id_prefix>
|
|
378
|
+
> Analyze the auth module. Delegate security review to the verifier.
|
|
390
379
|
```
|
|
380
|
+
The agent calls `org_delegate("verifier", ...)` → mesh runs a full-power verifier agent → result flows back automatically.
|
|
381
|
+
|
|
382
|
+
Docs:
|
|
383
|
+
- [`../docs/orchestration.md`](../docs/orchestration.md)
|
|
391
384
|
|
|
392
385
|
### Start the IDE bridge
|
|
393
386
|
```bash
|
|
@@ -420,11 +413,21 @@ Status note:
|
|
|
420
413
|
| `/rules` | Inspect active rules |
|
|
421
414
|
| `/diff` | Show current diff/checkpoint diff |
|
|
422
415
|
| `/rewind` | Restore checkpoints |
|
|
423
|
-
| `/review` | Run a review
|
|
416
|
+
| `/review` | Run a parallel code review pipeline |
|
|
424
417
|
| `/eval` | Run evaluation gates |
|
|
425
418
|
| `/kaira` | Show scheduler usage help |
|
|
426
419
|
| `/super` | Super mode: auto-approve tools, no GemCode HITL · `/super off` |
|
|
427
420
|
|
|
421
|
+
## Orchestration commands
|
|
422
|
+
|
|
423
|
+
| Command | Purpose |
|
|
424
|
+
|---|---|
|
|
425
|
+
| `/agent list` | Show all org members |
|
|
426
|
+
| `/agent tree` | Show org hierarchy |
|
|
427
|
+
| `/agent create` | Create a new agent member |
|
|
428
|
+
| `/agent assign <member> <task>` | Delegate work to a member |
|
|
429
|
+
| `/agent improve <member> <lessons>` | Improve a member's skill |
|
|
430
|
+
|
|
428
431
|
Detailed behavior:
|
|
429
432
|
- [`../docs/cli-and-repl.md`](../docs/cli-and-repl.md)
|
|
430
433
|
|
|
@@ -432,11 +435,15 @@ Detailed behavior:
|
|
|
432
435
|
|
|
433
436
|
| Capability | What it adds |
|
|
434
437
|
|---|---|
|
|
435
|
-
|
|
|
436
|
-
|
|
|
437
|
-
|
|
|
438
|
+
| Agent Mesh | In-process multi-agent orchestration (automatic, no daemon needed) |
|
|
439
|
+
| A2A Bridge | Cross-machine agent communication via Google A2A protocol |
|
|
440
|
+
| Self-Triggers | Agents auto-activate on events (verification, failure recovery) |
|
|
441
|
+
| Delegation Learning | Remembers successful patterns, suggests optimal routing |
|
|
442
|
+
| Deep research | Research-focused tool routing and optional dedicated model path |
|
|
443
|
+
| Embeddings | Semantic search and optional embedding-backed memory |
|
|
444
|
+
| Memory | Retrieval-oriented persistent memory |
|
|
438
445
|
| Browser/computer use | Playwright-backed browser automation and inspection |
|
|
439
|
-
| Live audio | Gemini Live microphone sessions |
|
|
446
|
+
| Live audio | Gemini Live microphone sessions (experimental) |
|
|
440
447
|
|
|
441
448
|
Detailed behavior:
|
|
442
449
|
- [`../docs/capabilities.md`](../docs/capabilities.md)
|
|
@@ -20,8 +20,10 @@ GemCode is designed for repository-native work rather than copy-paste chat workf
|
|
|
20
20
|
| REPL | Stateful terminal interaction |
|
|
21
21
|
| TUI | GemCode terminal UI (scrollback-style; `tui/scrollback.py`) |
|
|
22
22
|
| IDE stdio | Editor integration over JSONL stdin/stdout |
|
|
23
|
-
|
|
|
24
|
-
|
|
|
23
|
+
| Agent Mesh | In-process multi-agent orchestration (automatic) |
|
|
24
|
+
| Kaira daemon | Optional always-on background scheduler |
|
|
25
|
+
| A2A server | Cross-machine agent communication via Google A2A protocol |
|
|
26
|
+
| Live audio (experimental) | Microphone-driven Gemini Live sessions |
|
|
25
27
|
|
|
26
28
|
## Recommended reading order
|
|
27
29
|
|
|
@@ -168,34 +170,25 @@ gemcode -C . --attach ./report.pdf "Summarize this"
|
|
|
168
170
|
gemcode kaira -C .
|
|
169
171
|
```
|
|
170
172
|
|
|
171
|
-
### Orchestration (
|
|
173
|
+
### Orchestration (Agent Mesh + Multi-Agent)
|
|
172
174
|
|
|
173
|
-
|
|
175
|
+
GemCode includes a built-in multi-agent orchestration system that works automatically — no separate daemon required.
|
|
174
176
|
|
|
175
|
-
|
|
176
|
-
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
gemcode kaira -C .
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
In another terminal:
|
|
185
|
-
|
|
186
|
-
```bash
|
|
187
|
-
gemcode -C .
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
Then in the REPL/TUI:
|
|
177
|
+
**Key features:**
|
|
178
|
+
- **Agent Mesh** — in-process concurrent agent execution with full tool access
|
|
179
|
+
- **Event Bus** — agents communicate via pub/sub (no Unix sockets needed)
|
|
180
|
+
- **Self-Triggering Agents** — agents auto-activate on events (e.g., verifier reviews completed work)
|
|
181
|
+
- **Delegation Learning** — remembers which agents succeed at which tasks
|
|
182
|
+
- **A2A Bridge** — expose/consume agents across machines via Google's A2A protocol
|
|
191
183
|
|
|
184
|
+
Quick example in the REPL:
|
|
192
185
|
```text
|
|
193
|
-
|
|
194
|
-
/org hire verifier "QA / test planner" subagent gemcode "Find risks, propose tests, review plans."
|
|
195
|
-
/org assign verifier "Review the plan and propose tests"
|
|
196
|
-
/kaira jobs
|
|
197
|
-
/kaira follow <job_id_prefix>
|
|
186
|
+
> Analyze the auth module. Delegate security review to the verifier.
|
|
198
187
|
```
|
|
188
|
+
The agent calls `org_delegate("verifier", ...)` → mesh runs a full-power verifier agent → result flows back automatically.
|
|
189
|
+
|
|
190
|
+
Docs:
|
|
191
|
+
- [`../docs/orchestration.md`](../docs/orchestration.md)
|
|
199
192
|
|
|
200
193
|
### Start the IDE bridge
|
|
201
194
|
```bash
|
|
@@ -228,11 +221,21 @@ Status note:
|
|
|
228
221
|
| `/rules` | Inspect active rules |
|
|
229
222
|
| `/diff` | Show current diff/checkpoint diff |
|
|
230
223
|
| `/rewind` | Restore checkpoints |
|
|
231
|
-
| `/review` | Run a review
|
|
224
|
+
| `/review` | Run a parallel code review pipeline |
|
|
232
225
|
| `/eval` | Run evaluation gates |
|
|
233
226
|
| `/kaira` | Show scheduler usage help |
|
|
234
227
|
| `/super` | Super mode: auto-approve tools, no GemCode HITL · `/super off` |
|
|
235
228
|
|
|
229
|
+
## Orchestration commands
|
|
230
|
+
|
|
231
|
+
| Command | Purpose |
|
|
232
|
+
|---|---|
|
|
233
|
+
| `/agent list` | Show all org members |
|
|
234
|
+
| `/agent tree` | Show org hierarchy |
|
|
235
|
+
| `/agent create` | Create a new agent member |
|
|
236
|
+
| `/agent assign <member> <task>` | Delegate work to a member |
|
|
237
|
+
| `/agent improve <member> <lessons>` | Improve a member's skill |
|
|
238
|
+
|
|
236
239
|
Detailed behavior:
|
|
237
240
|
- [`../docs/cli-and-repl.md`](../docs/cli-and-repl.md)
|
|
238
241
|
|
|
@@ -240,11 +243,15 @@ Detailed behavior:
|
|
|
240
243
|
|
|
241
244
|
| Capability | What it adds |
|
|
242
245
|
|---|---|
|
|
243
|
-
|
|
|
244
|
-
|
|
|
245
|
-
|
|
|
246
|
+
| Agent Mesh | In-process multi-agent orchestration (automatic, no daemon needed) |
|
|
247
|
+
| A2A Bridge | Cross-machine agent communication via Google A2A protocol |
|
|
248
|
+
| Self-Triggers | Agents auto-activate on events (verification, failure recovery) |
|
|
249
|
+
| Delegation Learning | Remembers successful patterns, suggests optimal routing |
|
|
250
|
+
| Deep research | Research-focused tool routing and optional dedicated model path |
|
|
251
|
+
| Embeddings | Semantic search and optional embedding-backed memory |
|
|
252
|
+
| Memory | Retrieval-oriented persistent memory |
|
|
246
253
|
| Browser/computer use | Playwright-backed browser automation and inspection |
|
|
247
|
-
| Live audio | Gemini Live microphone sessions |
|
|
254
|
+
| Live audio | Gemini Live microphone sessions (experimental) |
|
|
248
255
|
|
|
249
256
|
Detailed behavior:
|
|
250
257
|
- [`../docs/capabilities.md`](../docs/capabilities.md)
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "gemcode"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
8
8
|
description = "Local-first coding agent on Google Gemini + ADK"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -27,7 +27,7 @@ classifiers = [
|
|
|
27
27
|
"Topic :: Terminals",
|
|
28
28
|
]
|
|
29
29
|
dependencies = [
|
|
30
|
-
"google-adk>=1.0.0",
|
|
30
|
+
"google-adk[a2a]>=1.0.0",
|
|
31
31
|
"google-genai>=1.0.0",
|
|
32
32
|
"python-dotenv>=1.0.0",
|
|
33
33
|
"rich>=13.0.0",
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A2A Bridge — Expose and consume GemCode agents via Google's Agent2Agent protocol.
|
|
3
|
+
|
|
4
|
+
This module bridges the org system with ADK's native A2A support:
|
|
5
|
+
- `expose_agent()` — Turn an org member into a network-accessible A2A server
|
|
6
|
+
- `connect_remote_agent()` — Consume a remote A2A agent as an org member
|
|
7
|
+
- Auto-generate agent cards from org.json metadata
|
|
8
|
+
|
|
9
|
+
Requires: google-adk[a2a] (pip install google-adk[a2a])
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
from gemcode.config import GemCodeConfig
|
|
19
|
+
from gemcode.org import OrgMember, find_member, resolve_fleet_root
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def a2a_available() -> bool:
|
|
23
|
+
"""Check if A2A support is installed."""
|
|
24
|
+
try:
|
|
25
|
+
from google.adk.a2a.utils.agent_to_a2a import to_a2a # noqa: F401
|
|
26
|
+
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent # noqa: F401
|
|
27
|
+
return True
|
|
28
|
+
except ImportError:
|
|
29
|
+
# Try auto-installing the a2a-sdk dependency
|
|
30
|
+
try:
|
|
31
|
+
import subprocess
|
|
32
|
+
import sys
|
|
33
|
+
subprocess.check_call(
|
|
34
|
+
[sys.executable, "-m", "pip", "install", "a2a-sdk>=0.3.4,<0.4.0", "--quiet"],
|
|
35
|
+
stdout=subprocess.DEVNULL,
|
|
36
|
+
stderr=subprocess.DEVNULL,
|
|
37
|
+
)
|
|
38
|
+
# Retry import after install
|
|
39
|
+
from google.adk.a2a.utils.agent_to_a2a import to_a2a # noqa: F401
|
|
40
|
+
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent # noqa: F401
|
|
41
|
+
return True
|
|
42
|
+
except Exception:
|
|
43
|
+
return False
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def build_agent_card_dict(member: OrgMember, *, base_url: str = "") -> dict[str, Any]:
|
|
47
|
+
"""
|
|
48
|
+
Build an A2A agent card dictionary from an org member.
|
|
49
|
+
|
|
50
|
+
This is the metadata that describes what an agent can do,
|
|
51
|
+
following the A2A protocol specification.
|
|
52
|
+
"""
|
|
53
|
+
skills = []
|
|
54
|
+
|
|
55
|
+
# Primary skill based on the member's role
|
|
56
|
+
skills.append({
|
|
57
|
+
"id": f"{member.name}_primary",
|
|
58
|
+
"name": member.title,
|
|
59
|
+
"description": member.description or f"Agent: {member.name} ({member.title})",
|
|
60
|
+
"tags": [member.kind, "gemcode"],
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
url = base_url or f"http://localhost:0/a2a/{member.name}"
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
"name": member.name,
|
|
67
|
+
"description": member.description or f"{member.name} — {member.title}",
|
|
68
|
+
"version": "1.0.0",
|
|
69
|
+
"url": url,
|
|
70
|
+
"capabilities": {
|
|
71
|
+
"streaming": True,
|
|
72
|
+
"pushNotifications": False,
|
|
73
|
+
},
|
|
74
|
+
"defaultInputModes": ["text/plain"],
|
|
75
|
+
"defaultOutputModes": ["text/plain", "application/json"],
|
|
76
|
+
"skills": skills,
|
|
77
|
+
"supportsAuthenticatedExtendedCard": False,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def expose_member_as_a2a(
|
|
82
|
+
cfg: GemCodeConfig,
|
|
83
|
+
member_name: str,
|
|
84
|
+
*,
|
|
85
|
+
port: int = 0,
|
|
86
|
+
host: str = "localhost",
|
|
87
|
+
) -> Any | None:
|
|
88
|
+
"""
|
|
89
|
+
Expose an org member as an A2A server using ADK's to_a2a().
|
|
90
|
+
|
|
91
|
+
Returns the Starlette app (can be served with uvicorn) or None if A2A unavailable.
|
|
92
|
+
"""
|
|
93
|
+
if not a2a_available():
|
|
94
|
+
return None
|
|
95
|
+
|
|
96
|
+
from google.adk.a2a.utils.agent_to_a2a import to_a2a
|
|
97
|
+
|
|
98
|
+
fleet_root = resolve_fleet_root(cfg.project_root)
|
|
99
|
+
m = find_member(fleet_root, member_name)
|
|
100
|
+
if m is None:
|
|
101
|
+
return None
|
|
102
|
+
|
|
103
|
+
# Build a real ADK agent for this member
|
|
104
|
+
from gemcode.agent import build_root_agent
|
|
105
|
+
from gemcode.tools import build_function_tools
|
|
106
|
+
|
|
107
|
+
import copy
|
|
108
|
+
agent_cfg = copy.deepcopy(cfg)
|
|
109
|
+
tools = build_function_tools(agent_cfg, include_subtask=False)
|
|
110
|
+
agent = build_root_agent(agent_cfg, _tools=tools)
|
|
111
|
+
|
|
112
|
+
# Generate agent card
|
|
113
|
+
base_url = f"http://{host}:{port}" if port else f"http://{host}"
|
|
114
|
+
card_dict = build_agent_card_dict(m, base_url=base_url)
|
|
115
|
+
|
|
116
|
+
# Create A2A app
|
|
117
|
+
try:
|
|
118
|
+
a2a_app = to_a2a(agent, port=port or 8001, agent_card=card_dict)
|
|
119
|
+
return a2a_app
|
|
120
|
+
except Exception:
|
|
121
|
+
# Fallback: try without custom card
|
|
122
|
+
try:
|
|
123
|
+
a2a_app = to_a2a(agent, port=port or 8001)
|
|
124
|
+
return a2a_app
|
|
125
|
+
except Exception:
|
|
126
|
+
return None
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def create_remote_a2a_member(
|
|
130
|
+
*,
|
|
131
|
+
name: str,
|
|
132
|
+
description: str,
|
|
133
|
+
agent_card_url: str,
|
|
134
|
+
use_legacy: bool = False,
|
|
135
|
+
) -> Any | None:
|
|
136
|
+
"""
|
|
137
|
+
Create a RemoteA2aAgent that can be used as a sub-agent.
|
|
138
|
+
|
|
139
|
+
This lets GemCode consume external A2A agents as if they were local org members.
|
|
140
|
+
"""
|
|
141
|
+
if not a2a_available():
|
|
142
|
+
return None
|
|
143
|
+
|
|
144
|
+
try:
|
|
145
|
+
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
|
|
146
|
+
|
|
147
|
+
remote_agent = RemoteA2aAgent(
|
|
148
|
+
name=name,
|
|
149
|
+
description=description,
|
|
150
|
+
agent_card=agent_card_url,
|
|
151
|
+
use_legacy=use_legacy,
|
|
152
|
+
)
|
|
153
|
+
return remote_agent
|
|
154
|
+
except Exception:
|
|
155
|
+
return None
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def list_exposed_agents(cfg: GemCodeConfig) -> list[dict[str, Any]]:
|
|
159
|
+
"""List all org members that could be exposed via A2A."""
|
|
160
|
+
from gemcode.org import list_members
|
|
161
|
+
|
|
162
|
+
fleet_root = resolve_fleet_root(cfg.project_root)
|
|
163
|
+
members = list_members(fleet_root)
|
|
164
|
+
return [
|
|
165
|
+
{
|
|
166
|
+
"name": m.name,
|
|
167
|
+
"title": m.title,
|
|
168
|
+
"kind": m.kind,
|
|
169
|
+
"description": m.description,
|
|
170
|
+
"a2a_available": a2a_available(),
|
|
171
|
+
"card": build_agent_card_dict(m),
|
|
172
|
+
}
|
|
173
|
+
for m in members
|
|
174
|
+
]
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def make_a2a_tools(cfg: GemCodeConfig) -> list:
|
|
178
|
+
"""Build A2A-related tools for the agent."""
|
|
179
|
+
|
|
180
|
+
def a2a_expose(member: str, port: int = 8001, host: str = "localhost") -> dict:
|
|
181
|
+
"""
|
|
182
|
+
Expose an org member as an A2A server (network-accessible agent).
|
|
183
|
+
|
|
184
|
+
Other GemCode instances or any A2A-compatible agent can then communicate
|
|
185
|
+
with this member over HTTP.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
member: Name or ID of the org member to expose.
|
|
189
|
+
port: Port to serve on (default 8001).
|
|
190
|
+
host: Host to bind to (default localhost).
|
|
191
|
+
"""
|
|
192
|
+
if not a2a_available():
|
|
193
|
+
return {"ok": False, "error": "A2A auto-install failed. Try: pip install a2a-sdk"}
|
|
194
|
+
|
|
195
|
+
app = expose_member_as_a2a(cfg, member, port=port, host=host)
|
|
196
|
+
if app is None:
|
|
197
|
+
return {"ok": False, "error": f"Failed to expose member '{member}'. Check org_list() for available members."}
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
"ok": True,
|
|
201
|
+
"member": member,
|
|
202
|
+
"url": f"http://{host}:{port}",
|
|
203
|
+
"agent_card_url": f"http://{host}:{port}/.well-known/agent-card.json",
|
|
204
|
+
"note": f"Start with: uvicorn ... --host {host} --port {port}",
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
def a2a_connect(name: str, description: str, agent_card_url: str) -> dict:
|
|
208
|
+
"""
|
|
209
|
+
Connect to a remote A2A agent and register it as an org member.
|
|
210
|
+
|
|
211
|
+
This lets you delegate tasks to agents running on other machines or
|
|
212
|
+
in other frameworks (LangGraph, CrewAI, etc.) via the A2A protocol.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
name: Local name for this remote agent.
|
|
216
|
+
description: What this agent does.
|
|
217
|
+
agent_card_url: URL to the agent's card (e.g., http://host:port/.well-known/agent-card.json)
|
|
218
|
+
"""
|
|
219
|
+
if not a2a_available():
|
|
220
|
+
return {"ok": False, "error": "A2A auto-install failed. Try: pip install a2a-sdk"}
|
|
221
|
+
|
|
222
|
+
remote = create_remote_a2a_member(
|
|
223
|
+
name=name,
|
|
224
|
+
description=description,
|
|
225
|
+
agent_card_url=agent_card_url,
|
|
226
|
+
)
|
|
227
|
+
if remote is None:
|
|
228
|
+
return {"ok": False, "error": f"Failed to connect to remote agent at {agent_card_url}"}
|
|
229
|
+
|
|
230
|
+
# Register in org
|
|
231
|
+
from gemcode.org import hire_member
|
|
232
|
+
fleet_root = resolve_fleet_root(cfg.project_root)
|
|
233
|
+
m = hire_member(
|
|
234
|
+
fleet_root,
|
|
235
|
+
name=name,
|
|
236
|
+
title=f"Remote A2A Agent",
|
|
237
|
+
kind="subagent",
|
|
238
|
+
description=f"[A2A] {description} (card: {agent_card_url})",
|
|
239
|
+
reports_to="manager",
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
"ok": True,
|
|
244
|
+
"member": m.to_dict() if hasattr(m, "to_dict") else {"name": name},
|
|
245
|
+
"agent_card_url": agent_card_url,
|
|
246
|
+
"note": "Use org_delegate to send tasks to this remote agent.",
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
def a2a_list() -> dict:
|
|
250
|
+
"""List all agents that can be exposed or are connected via A2A."""
|
|
251
|
+
agents = list_exposed_agents(cfg)
|
|
252
|
+
return {"ok": True, "agents": agents, "a2a_installed": a2a_available()}
|
|
253
|
+
|
|
254
|
+
a2a_expose.__name__ = "a2a_expose"
|
|
255
|
+
a2a_connect.__name__ = "a2a_connect"
|
|
256
|
+
a2a_list.__name__ = "a2a_list"
|
|
257
|
+
|
|
258
|
+
return [a2a_expose, a2a_connect, a2a_list]
|