Skip to content
This repository was archived by the owner on Aug 22, 2026. It is now read-only.

Commit 82344c0

Browse files
authored
Merge pull request #46 from langoai/dev
MCP Integration, Advanced Multi-Agent Orchestration & P2P Network
2 parents 14d4721 + 22a8c06 commit 82344c0

436 files changed

Lines changed: 25527 additions & 580 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Dockerfile

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,26 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
3535
&& rm -rf /var/lib/apt/lists/*
3636

3737
RUN groupadd -r lango && useradd -r -g lango -m -d /home/lango lango \
38-
&& mkdir -p /home/lango/.lango && chown lango:lango /home/lango/.lango
38+
&& mkdir -p /home/lango/.lango/skills \
39+
&& mkdir -p /home/lango/bin \
40+
&& chown -R lango:lango /home/lango/.lango /home/lango/bin
3941

4042
COPY --from=builder /app/lango /usr/local/bin/lango
4143
COPY --from=builder /app/prompts/ /usr/share/lango/prompts/
4244
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
4345
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
4446

47+
# Optional: install Go toolchain for agents that need `go install` capability.
48+
# Build with --build-arg INSTALL_GO=true to enable.
49+
ARG INSTALL_GO=false
50+
RUN if [ "$INSTALL_GO" = "true" ]; then \
51+
curl -fsSL https://go.dev/dl/go1.25.linux-amd64.tar.gz \
52+
| tar -C /usr/local -xzf - ; \
53+
fi
54+
55+
ENV PATH="/home/lango/bin:/home/lango/go/bin:/usr/local/go/bin:${PATH}"
56+
ENV GOPATH="/home/lango/go"
57+
4558
USER lango
4659
WORKDIR /home/lango
4760

README.md

Lines changed: 106 additions & 4 deletions
Large diffs are not rendered by default.

cmd/lango/main.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,16 @@ import (
1717
"github.com/langoai/lango/internal/app"
1818
"github.com/langoai/lango/internal/background"
1919
"github.com/langoai/lango/internal/bootstrap"
20+
clia2a "github.com/langoai/lango/internal/cli/a2a"
2021
cliagent "github.com/langoai/lango/internal/cli/agent"
22+
cliapproval "github.com/langoai/lango/internal/cli/approval"
2123
clibg "github.com/langoai/lango/internal/cli/bg"
2224
clicron "github.com/langoai/lango/internal/cli/cron"
25+
climcp "github.com/langoai/lango/internal/cli/mcp"
2326
"github.com/langoai/lango/internal/cli/doctor"
2427
cligraph "github.com/langoai/lango/internal/cli/graph"
28+
clilearning "github.com/langoai/lango/internal/cli/learning"
29+
clilibrarian "github.com/langoai/lango/internal/cli/librarian"
2530
climemory "github.com/langoai/lango/internal/cli/memory"
2631
"github.com/langoai/lango/internal/cli/onboard"
2732
clip2p "github.com/langoai/lango/internal/cli/p2p"
@@ -123,6 +128,58 @@ func main() {
123128
graphCmd.GroupID = "data"
124129
rootCmd.AddCommand(graphCmd)
125130

131+
a2aCmd := clia2a.NewA2ACmd(func() (*config.Config, error) {
132+
boot, err := bootstrap.Run(bootstrap.Options{})
133+
if err != nil {
134+
return nil, err
135+
}
136+
defer boot.DBClient.Close()
137+
return boot.Config, nil
138+
})
139+
a2aCmd.GroupID = "data"
140+
rootCmd.AddCommand(a2aCmd)
141+
142+
learningCfgLoader := func() (*config.Config, error) {
143+
boot, err := bootstrap.Run(bootstrap.Options{})
144+
if err != nil {
145+
return nil, err
146+
}
147+
defer boot.DBClient.Close()
148+
return boot.Config, nil
149+
}
150+
learningBootLoader := func() (*bootstrap.Result, error) {
151+
return bootstrap.Run(bootstrap.Options{})
152+
}
153+
learningCmd := clilearning.NewLearningCmd(learningCfgLoader, learningBootLoader)
154+
learningCmd.GroupID = "data"
155+
rootCmd.AddCommand(learningCmd)
156+
157+
librarianCfgLoader := func() (*config.Config, error) {
158+
boot, err := bootstrap.Run(bootstrap.Options{})
159+
if err != nil {
160+
return nil, err
161+
}
162+
defer boot.DBClient.Close()
163+
return boot.Config, nil
164+
}
165+
librarianBootLoader := func() (*bootstrap.Result, error) {
166+
return bootstrap.Run(bootstrap.Options{})
167+
}
168+
librarianCmd := clilibrarian.NewLibrarianCmd(librarianCfgLoader, librarianBootLoader)
169+
librarianCmd.GroupID = "data"
170+
rootCmd.AddCommand(librarianCmd)
171+
172+
approvalCmd := cliapproval.NewApprovalCmd(func() (*config.Config, error) {
173+
boot, err := bootstrap.Run(bootstrap.Options{})
174+
if err != nil {
175+
return nil, err
176+
}
177+
defer boot.DBClient.Close()
178+
return boot.Config, nil
179+
})
180+
approvalCmd.GroupID = "infra"
181+
rootCmd.AddCommand(approvalCmd)
182+
126183
paymentCmd := clipayment.NewPaymentCmd(func() (*bootstrap.Result, error) {
127184
return bootstrap.Run(bootstrap.Options{})
128185
})
@@ -135,6 +192,21 @@ func main() {
135192
p2pCmd.GroupID = "infra"
136193
rootCmd.AddCommand(p2pCmd)
137194

195+
mcpCfgLoader := func() (*config.Config, error) {
196+
boot, err := bootstrap.Run(bootstrap.Options{})
197+
if err != nil {
198+
return nil, err
199+
}
200+
defer boot.DBClient.Close()
201+
return boot.Config, nil
202+
}
203+
mcpBootLoader := func() (*bootstrap.Result, error) {
204+
return bootstrap.Run(bootstrap.Options{})
205+
}
206+
mcpCmd := climcp.NewMCPCmd(mcpCfgLoader, mcpBootLoader)
207+
mcpCmd.GroupID = "infra"
208+
rootCmd.AddCommand(mcpCmd)
209+
138210
cronCmd := clicron.NewCronCmd(func() (*bootstrap.Result, error) {
139211
return bootstrap.Run(bootstrap.Options{})
140212
})

docker-compose.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,18 @@ services:
66
restart: unless-stopped
77
ports:
88
- "18789:18789"
9+
# - "9000:9000" # P2P libp2p (uncomment to enable P2P networking)
910
volumes:
1011
- lango-data:/home/lango/.lango
1112
secrets:
1213
- lango_config
1314
- lango_passphrase
1415
environment:
1516
- LANGO_PROFILE=default
17+
# - LANGO_MULTI_AGENT=true # Enable multi-agent orchestration
18+
# - LANGO_P2P=true # Enable P2P networking
19+
# - LANGO_AGENT_MEMORY=true # Enable per-agent persistent memory
20+
# - LANGO_HOOKS=true # Enable tool execution hooks
1621

1722
presidio-analyzer:
1823
image: mcr.microsoft.com/presidio-analyzer:latest

docker-entrypoint.sh

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,17 @@
22
set -e
33

44
LANGO_DIR="$HOME/.lango"
5-
mkdir -p "$LANGO_DIR"
5+
mkdir -p "$LANGO_DIR/skills" "$HOME/bin"
6+
7+
# Verify write permissions on critical directories.
8+
# Named Docker volumes can inherit stale ownership from previous builds.
9+
for dir in "$LANGO_DIR" "$LANGO_DIR/skills" "$HOME/bin"; do
10+
if [ -d "$dir" ] && ! [ -w "$dir" ]; then
11+
echo "ERROR: $dir is not writable by $(whoami) (uid=$(id -u))." >&2
12+
echo " Hint: remove the volume and recreate it: docker volume rm lango-data" >&2
13+
exit 1
14+
fi
15+
done
616

717
# Set up passphrase keyfile from Docker secret.
818
# The keyfile path (~/.lango/keyfile) is blocked by the agent's filesystem tool.

docs/architecture/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Architecture
22

3-
This section describes the internal architecture of Lango, a Go-based AI agent framework built on Google ADK v0.4.0.
3+
This section describes the internal architecture of Lango, a Go-based AI agent built on Google ADK v0.4.0.
44

55
<div class="grid cards" markdown>
66

docs/architecture/project-structure.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,15 @@ All application code lives under `internal/` to enforce Go's visibility boundary
2828

2929
| Package | Description |
3030
|---------|-------------|
31-
| `adk/` | Google ADK v0.4.0 integration. Contains `Agent` (wraps ADK runner), `ModelAdapter` (bridges `provider.ProviderProxy` to ADK `model.LLM`), `ContextAwareModelAdapter` (injects knowledge/memory/RAG into system prompt), `SessionServiceAdapter` (bridges internal session store to ADK session interface), and `AdaptTool()` (converts `agent.Tool` to ADK `tool.Tool`) |
31+
| `adk/` | Google ADK v0.5.0 integration. Contains `Agent` (wraps ADK runner), `ModelAdapter` (bridges `provider.ProviderProxy` to ADK `model.LLM`), `ContextAwareModelAdapter` (injects knowledge/memory/RAG into system prompt), `SessionServiceAdapter` (bridges internal session store to ADK session interface), `ChildSessionServiceAdapter` (fork/merge child sessions for sub-agent isolation), `Summarizer` (extracts key results from child sessions), and `AdaptTool()` (converts `agent.Tool` to ADK `tool.Tool`) |
3232
| `agent/` | Core agent types: `Tool` struct (name, description, parameters, handler), `ParameterDef`, `PII Redactor` (regex + optional Presidio integration), `SecretScanner` (prevents credential leakage in model output) |
3333
| `app/` | Application bootstrap and wiring. `app.go` defines `New()` (component initialization), `Start()`, and `Stop()`. `wiring.go` contains all `init*` functions that create individual subsystems. `types.go` defines the `App` struct with all component fields. `tools.go` builds tool collections. `sender.go` provides `channelSender` adapter for delivery |
3434
| `bootstrap/` | Pre-application startup: opens database, initializes crypto provider, loads config profile. Returns `bootstrap.Result` with shared `DBClient` and `Crypto` provider for reuse |
35+
| `agentregistry/` | Agent definition registry. `Registry` loads built-in agents and user-defined `AGENT.md` files from `agent.agentsDir`. Provides `Specs()` for orchestrator routing and `Active()` for runtime agent listing |
36+
| `agentmemory/` | Per-agent persistent memory. `Store` interface with `Save()`, `Get()`, `Search()`, `Delete()`, `Prune()` operations. Scoped by agent name for cross-session context retention |
37+
| `ctxkeys/` | Context key helpers. `WithAgentName()` / `AgentNameFromContext()` for propagating agent identity through request contexts |
38+
| `eventbus/` | Typed synchronous event pub/sub. `Bus` with `Subscribe()` / `Publish()`. `SubscribeTyped[T]()` generic helper for type-safe subscriptions. Events: ContentSaved, TriplesExtracted, TurnCompleted, ReputationChanged |
39+
| `types/` | Shared type definitions used across packages: `ProviderType`, `Role`, `RPCSenderFunc`, `ChannelType`, `ConfidenceLevel`, `TokenUsage` |
3540

3641
### Presentation
3742

@@ -51,6 +56,7 @@ All application code lives under `internal/` to enforce Go's visibility boundary
5156
| `cli/workflow/` | `lango workflow run`, `list`, `status`, `cancel`, `history` -- workflow management |
5257
| `cli/prompt/` | Interactive prompt utilities for CLI input |
5358
| `cli/security/` | `lango security status`, `secrets`, `migrate-passphrase`, `keyring store/clear/status`, `db-migrate`, `db-decrypt`, `kms status/test/keys` -- security operations |
59+
| `cli/tuicore/` | Shared TUI components for interactive terminal sessions. `FormModel` (Bubbletea form manager), `Field` struct with input types: `InputText`, `InputInt`, `InputPassword`, `InputBool`, `InputSelect`, `InputSearchSelect` |
5460
| `cli/p2p/` | `lango p2p status`, `peers`, `connect`, `disconnect`, `firewall list/add/remove`, `discover`, `identity`, `reputation`, `pricing`, `session list/revoke/revoke-all`, `sandbox status/test/cleanup` -- P2P network management |
5561
| `cli/tui/` | TUI components and views for interactive terminal sessions |
5662
| `channels/` | Channel bot integrations for Telegram, Discord, and Slack. Each adapter converts platform-specific messages to the Gateway's internal format |
@@ -95,8 +101,12 @@ All application code lives under `internal/` to enforce Go's visibility boundary
95101
| `keyring/` | Hardware keyring integration (Touch ID / TPM 2.0). `Provider` interface backed by OS keyring via go-keyring |
96102
| `sandbox/` | Tool execution isolation. `SubprocessExecutor` for process-isolated P2P tool execution. `ContainerRuntime` interface with Docker/gVisor/native fallback chain. Optional pre-warmed container pool |
97103
| `dbmigrate/` | Database encryption migration. `MigrateToEncrypted` / `DecryptToPlaintext` for SQLCipher transitions. `IsEncrypted` detection and `secureDeleteFile` cleanup |
104+
| `toolcatalog/` | Thread-safe tool registry with category grouping. `Catalog` with `Register()`, `Get()`, `ListCategories()`, `ListTools()`. `ToolEntry` pairs tools with categories, `ToolSchema` provides tool summaries |
105+
| `toolchain/` | HTTP-style middleware chain for tool wrapping. `Middleware` type, `Chain()` / `ChainAll()` functions. Built-in middlewares: security filter, access control, event publishing, knowledge save, approval, browser recovery |
106+
| `appinit/` | Declarative module initialization system. `Module` interface with `Provides` / `DependsOn` keys. `Builder` with Kahn's algorithm topological sort for dependency resolution. Foundation for ordered application bootstrap |
107+
| `asyncbuf/` | Generic async batch processor. `BatchBuffer[T]` with configurable batch size, flush interval, and backpressure. `Start()` / `Enqueue()` / `Stop()` lifecycle. Replaces per-subsystem buffer implementations |
98108
| `passphrase/` | Passphrase prompt and validation helpers for terminal input |
99-
| `orchestration/` | Multi-agent orchestration. `BuildAgentTree()` creates an ADK agent hierarchy with sub-agents: Operator (tool execution), Navigator (research), Vault (security), Librarian (knowledge), Automator (cron/bg/workflow), Planner (task planning), Chronicler (memory) |
109+
| `orchestration/` | Multi-agent orchestration. `BuildAgentTree()` creates an ADK agent hierarchy. `AgentSpec` defines agent metadata (prefixes, keywords, capabilities). `PartitionToolsDynamic()` allocates tools to agents via multi-signal matching (prefix, keyword, capability). `BuiltinSpecs()` returns default agent definitions. Sub-agents: Operator, Navigator, Vault, Librarian, Automator, Planner, Chronicler. Supports user-defined agents via `AgentRegistry` |
100110
| `a2a/` | Agent-to-Agent protocol. `Server` exposes agent card and task endpoints. `LoadRemoteAgents()` discovers and loads remote agent capabilities |
101111
| `tools/` | Built-in tool implementations |
102112
| `tools/browser/` | Headless browser tool with session management |
@@ -105,6 +115,9 @@ All application code lives under `internal/` to enforce Go's visibility boundary
105115
| `tools/filesystem/` | File read/write/list tools with path allowlisting and blocklisting |
106116
| `tools/secrets/` | Secret management tools (store, retrieve, list, delete) |
107117
| `tools/payment/` | Payment tools (balance, send, history) |
118+
| `p2p/team/` | P2P team coordination. `Team` manages task-scoped agent groups with roles (Leader, Worker, Reviewer, Observer). `ScopedContext` controls metadata sharing. Budget tracking via `AddSpend()`. Team lifecycle: Forming → Active → Completed/Disbanded |
119+
| `p2p/agentpool/` | P2P agent pool with health monitoring. `Pool` manages discovered agents. `HealthChecker` runs periodic probes (Healthy/Degraded/Unhealthy/Unknown). `Selector` provides weighted agent selection based on reputation, latency, success rate, and availability |
120+
| `p2p/settlement/` | On-chain USDC settlement for P2P tool invocations. `Service` handles EIP-3009 authorization-based transfers with exponential retry. `ReputationRecorder` interface for outcome tracking. Subscriber pattern for settlement notifications |
108121

109122
## `prompts/`
110123

docs/cli/a2a.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# A2A Commands
2+
3+
Commands for inspecting A2A (Agent-to-Agent) protocol configuration and verifying remote agent connectivity. See the [A2A Protocol](../features/a2a-protocol.md) section for detailed documentation.
4+
5+
```
6+
lango a2a <subcommand>
7+
```
8+
9+
---
10+
11+
## lango a2a card
12+
13+
Show the local A2A agent card configuration, including enabled status, base URL, agent name, and configured remote agents.
14+
15+
```
16+
lango a2a card [--json]
17+
```
18+
19+
| Flag | Type | Default | Description |
20+
|------|------|---------|-------------|
21+
| `--json` | bool | `false` | Output as JSON |
22+
23+
**Example:**
24+
25+
```bash
26+
$ lango a2a card
27+
A2A Agent Card
28+
Enabled: true
29+
Base URL: http://localhost:18789
30+
Agent Name: lango
31+
Description: AI assistant with tools
32+
33+
Remote Agents (2)
34+
NAME AGENT CARD URL
35+
weather-agent http://weather-svc:8080/.well-known/agent.json
36+
search-agent http://search-svc:8080/.well-known/agent.json
37+
```
38+
39+
When A2A is disabled:
40+
41+
```bash
42+
$ lango a2a card
43+
A2A Agent Card
44+
Enabled: false
45+
46+
No remote agents configured.
47+
```
48+
49+
---
50+
51+
## lango a2a check
52+
53+
Fetch and display a remote agent card from a URL. Useful for verifying that a remote A2A agent is reachable and correctly configured before adding it to your configuration.
54+
55+
```
56+
lango a2a check <url> [--json]
57+
```
58+
59+
| Argument | Required | Description |
60+
|----------|----------|-------------|
61+
| `url` | Yes | URL of the remote agent card (e.g., `http://host/.well-known/agent.json`) |
62+
63+
| Flag | Type | Default | Description |
64+
|------|------|---------|-------------|
65+
| `--json` | bool | `false` | Output as JSON |
66+
67+
**Example:**
68+
69+
```bash
70+
$ lango a2a check http://weather-svc:8080/.well-known/agent.json
71+
Remote Agent Card
72+
Name: weather-agent
73+
Description: Provides weather data and forecasts
74+
URL: http://weather-svc:8080
75+
DID: did:lango:02abc...
76+
Capabilities: [weather, forecast]
77+
78+
Skills (2)
79+
ID NAME TAGS
80+
get-weather Get Weather [weather, location]
81+
forecast 5-Day Forecast [weather, forecast]
82+
```
83+
84+
!!! tip
85+
Use `lango a2a check` before adding a remote agent to your configuration to verify connectivity and inspect its capabilities.

0 commit comments

Comments
 (0)