Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 10 additions & 36 deletions docker-compose.agent.yml
Original file line number Diff line number Diff line change
@@ -1,36 +1,10 @@
services:
redis:
image: redis:7-alpine
command: redis-server --appendonly yes --appendfsync everysec
volumes:
- redis-data:/data
healthcheck:
test: [ "CMD", "redis-cli", "ping" ]
interval: 5s
timeout: 3s
retries: 5

omniclaw-agent:
build:
context: .
dockerfile: Dockerfile.agent
command: uv run uvicorn omniclaw.agent.server:app --host 0.0.0.0 --port 9090
env_file: .env
environment:
- OMNICLAW_REDIS_URL=redis://redis:6379/0
- OMNICLAW_AGENT_POLICY_PATH=/config/policy.json
- OMNICLAW_AGENT_TOKEN=buyer-agent-token
- OMNICLAW_LOG_LEVEL=INFO
- OMNICLAW_POLICY_RELOAD_INTERVAL=0
- OMNICLAW_NANOPAYMENTS_ENABLED=true
- OMNICLAW_PRIVATE_KEY=${OMNICLAW_PRIVATE_KEY}
volumes:
- ./examples/policy-advanced.json:/config/policy.json
ports:
- "9090:9090"
depends_on:
redis:
condition: service_healthy

volumes:
redis-data:
# Canonical root-level stacks now live here:
#
# Buyer / payment agent:
# docker compose -f docker-compose.payment-agent.yml up -d --build
#
# Seller agent:
# docker compose -f docker-compose.seller-agent.yml up -d --build
#
# This file is kept as a compatibility stub so existing references do not
# silently point to stale configuration.
40 changes: 40 additions & 0 deletions docker-compose.payment-agent.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
services:
payment-agent-redis:
image: redis:7-alpine
command: redis-server --appendonly yes --appendfsync everysec
volumes:
- payment-agent-redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 10

payment-agent:
build:
context: .
dockerfile: Dockerfile.agent
command: uv run uvicorn omniclaw.agent.server:app --host 0.0.0.0 --port 9090
environment:
OMNICLAW_REDIS_URL: redis://payment-agent-redis:6379/0
OMNICLAW_AGENT_POLICY_PATH: /config/payment-agent.policy.json
OMNICLAW_AGENT_TOKEN: payment-agent-token
OMNICLAW_LOG_LEVEL: INFO
OMNICLAW_POLICY_RELOAD_INTERVAL: 0
OMNICLAW_NANOPAYMENTS_ENABLED: "true"
OMNICLAW_NETWORK: ${OMNICLAW_NETWORK}
OMNICLAW_RPC_URL: ${OMNICLAW_RPC_URL}
OMNICLAW_STORAGE_BACKEND: redis
OMNICLAW_PRIVATE_KEY: ${BUYER_OMNICLAW_PRIVATE_KEY:-${OMNICLAW_PRIVATE_KEY}}
CIRCLE_API_KEY: ${BUYER_CIRCLE_API_KEY:-${CIRCLE_API_KEY}}
ENTITY_SECRET: ${BUYER_ENTITY_SECRET:-${ENTITY_SECRET}}
volumes:
- ./payment-agent.policy.json:/config/payment-agent.policy.json
ports:
- "9090:9090"
depends_on:
payment-agent-redis:
condition: service_healthy

volumes:
payment-agent-redis-data:
40 changes: 40 additions & 0 deletions docker-compose.seller-agent.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
services:
seller-agent-redis:
image: redis:7-alpine
command: redis-server --appendonly yes --appendfsync everysec
volumes:
- seller-agent-redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 10

seller-agent:
build:
context: .
dockerfile: Dockerfile.agent
command: uv run uvicorn omniclaw.agent.server:app --host 0.0.0.0 --port 9091
environment:
OMNICLAW_REDIS_URL: redis://seller-agent-redis:6379/0
OMNICLAW_AGENT_POLICY_PATH: /config/seller-agent.policy.json
OMNICLAW_AGENT_TOKEN: seller-agent-token
OMNICLAW_LOG_LEVEL: INFO
OMNICLAW_POLICY_RELOAD_INTERVAL: 0
OMNICLAW_NANOPAYMENTS_ENABLED: "true"
OMNICLAW_NETWORK: ${OMNICLAW_NETWORK}
OMNICLAW_RPC_URL: ${OMNICLAW_RPC_URL}
OMNICLAW_STORAGE_BACKEND: redis
OMNICLAW_PRIVATE_KEY: ${SELLER_OMNICLAW_PRIVATE_KEY:-${OMNICLAW_PRIVATE_KEY}}
CIRCLE_API_KEY: ${SELLER_CIRCLE_API_KEY:-${CIRCLE_API_KEY}}
ENTITY_SECRET: ${SELLER_ENTITY_SECRET:-${ENTITY_SECRET}}
volumes:
- ./seller-agent.policy.json:/config/seller-agent.policy.json
ports:
- "9091:9091"
depends_on:
seller-agent-redis:
condition: service_healthy

volumes:
seller-agent-redis-data:
2 changes: 1 addition & 1 deletion examples/agent/buyer/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ services:
- OMNICLAW_REDIS_URL=redis://redis:6379/1
- OMNICLAW_AGENT_POLICY_PATH=/config/policy.json
- OMNICLAW_LOG_LEVEL=INFO
- OMNICLAW_AGENT_TOKEN=buyer-agent-token
- OMNICLAW_AGENT_TOKEN=payment-agent-token
- CIRCLE_API_KEY=${BUYER_CIRCLE_API_KEY}
- OMNICLAW_PRIVATE_KEY=${BUYER_OMNICLAW_PRIVATE_KEY}
- ENTITY_SECRET=${BUYER_ENTITY_SECRET}
Expand Down
36 changes: 24 additions & 12 deletions examples/agent/buyer/policy.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"version": "2.0",
"tokens": {
"buyer-agent-token": {
"wallet_alias": "buyer-wallet",
"payment-agent-token": {
"wallet_alias": "payment-agent",
"active": true,
"label": "Buyer Agent"
"label": "Payment Agent"
}
},
"wallets": {
"buyer-wallet": {
"name": "Buyer Wallet",
"payment-agent": {
"name": "Payment Agent",
"wallet_id": "fe1409e8-3948-56eb-b847-8c0a72c1b1d4",
"address": "0xcf9baaf6bb37677488c041fdb9166708407ebb3b",
"limits": {
Expand All @@ -20,9 +20,15 @@
},
"rate_limits": null,
"recipients": {
"mode": "allow_all",
"addresses": [],
"domains": []
"mode": "whitelist",
"addresses": [
"0x5a4e248fa08c37b15ea0efdfdf336e92317d5243"
],
"domains": [
"api.stripe.com",
"localhost",
"127.0.0.1"
]
},
"confirm_threshold": null
}
Expand All @@ -38,9 +44,15 @@
"per_hour": null
},
"recipients": {
"mode": "allow_all",
"addresses": [],
"domains": []
"mode": "whitelist",
"addresses": [
"0x5a4e248fa08c37b15ea0efdfdf336e92317d5243"
],
"domains": [
"api.stripe.com",
"localhost",
"127.0.0.1"
]
},
"confirm_threshold": null
}
}
12 changes: 7 additions & 5 deletions examples/demo/foundation/buyer-policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
"version": "2.0",
"tokens": {
"payment-agent-token": {
"wallet_alias": "omni-bot-v4",
"wallet_alias": "payment-agent",
"active": true,
"label": "Omni Bot v4"
"label": "Payment Agent"
}
},
"wallets": {
"omni-bot-v4": {
"name": "Omni Bot v4",
"payment-agent": {
"name": "Payment Agent",
"limits": {
"daily_max": "25.00",
"hourly_max": "10.00",
Expand All @@ -22,7 +22,9 @@
},
"recipients": {
"mode": "whitelist",
"addresses": [],
"addresses": [
"0x5a4e248fa08c37b15ea0efdfdf336e92317d5243"
],
"domains": [
"api.stripe.com",
"localhost",
Expand Down
22 changes: 14 additions & 8 deletions examples/policy-advanced.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"version": "2.0",
"tokens": {
"buyer-agent-token": {
"wallet_alias": "primary",
"payment-agent-token": {
"wallet_alias": "payment-agent",
"active": true,
"label": "Buyer Agent"
"label": "Payment Agent"
}
},
"wallets": {
"primary": {
"name": "Primary Wallet",
"payment-agent": {
"name": "Payment Agent",
"wallet_id": "82e93f7f-ad08-5436-b876-d856f6fd36b4",
"address": "0x1cb6540be09f4fc41f8d3aab15dfb136e274a9b3",
"limits": {
Expand All @@ -23,9 +23,15 @@
"per_hour": 100
},
"recipients": {
"mode": "allow_all",
"addresses": [],
"domains": []
"mode": "whitelist",
"addresses": [
"0x5a4e248fa08c37b15ea0efdfdf336e92317d5243"
],
"domains": [
"api.stripe.com",
"localhost",
"127.0.0.1"
]
},
"confirm_threshold": "50.00"
}
Expand Down
39 changes: 39 additions & 0 deletions payment-agent.policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"version": "2.0",
"tokens": {
"payment-agent-token": {
"wallet_alias": "payment-agent",
"active": true,
"label": "Payment Agent"
}
},
"wallets": {
"payment-agent": {
"name": "Payment Agent",
"wallet_id": "2c9bf657-c70e-5d33-873e-08f9b3fcb9c9",
"address": "0x1c3c4c77088494fbc3f9ce1e87bfd7b4cfec0e18",
"limits": {
"daily_max": "25.00",
"hourly_max": "10.00",
"per_tx_max": "1.00",
"per_tx_min": "0.01"
},
"rate_limits": {
"per_minute": 10,
"per_hour": 100
},
"recipients": {
"mode": "whitelist",
"addresses": [
"0x5a4e248fa08c37b15ea0efdfdf336e92317d5243"
],
"domains": [
"api.stripe.com",
"localhost",
"127.0.0.1"
]
},
"confirm_threshold": "0.005"
}
}
}
31 changes: 31 additions & 0 deletions seller-agent.policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"version": "2.0",
"tokens": {
"seller-agent-token": {
"wallet_alias": "seller-agent",
"active": true,
"label": "Seller Agent"
}
},
"wallets": {
"seller-agent": {
"name": "Seller Agent",
"limits": {
"daily_max": "100.00",
"hourly_max": "25.00",
"per_tx_max": "10.00",
"per_tx_min": "0.01"
},
"rate_limits": {
"per_minute": 30,
"per_hour": 500
},
"recipients": {
"mode": "allow_all",
"addresses": [],
"domains": []
},
"confirm_threshold": null
}
}
}
8 changes: 6 additions & 2 deletions src/omniclaw/agent/policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,9 @@ async def initialize_wallets(self) -> dict[str, str]:
# PHASE 1: Pre-populate token map with placeholder
for alias, tokens in alias_to_tokens.items():
for token in tokens:
self._policy.set_mapping(token, f"pending-{alias}", wallet_map.get(alias, {}))
cfg = dict(wallet_map.get(alias, {}))
cfg.setdefault("alias", alias)
self._policy.set_mapping(token, f"pending-{alias}", cfg)

changed = False
results: dict[str, str] = {}
Expand Down Expand Up @@ -628,7 +630,9 @@ async def init_alias(alias: str) -> tuple[str, str | None, str | None]:
changed = True
# Map all tokens sharing this alias
for token in alias_to_tokens.get(alias, []):
self._policy.set_mapping(token, wallet_id, wallet_map.get(alias, {}))
cfg = dict(wallet_map.get(alias, {}))
cfg.setdefault("alias", alias)
self._policy.set_mapping(token, wallet_id, cfg)
results[token] = wallet_id
self._logger.info(f"Initialized wallet '{wallet_id}' for alias '{alias}'")

Expand Down
11 changes: 7 additions & 4 deletions src/omniclaw/agent/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ async def health_check():
@router.get("/address", response_model=AddressResponse)
async def get_address(
agent: AuthenticatedAgent = Depends(get_current_agent),
policy_mgr: PolicyManager = Depends(get_policy_manager),
wallet_mgr: WalletManager = Depends(get_wallet_manager),
client: OmniClaw = Depends(get_omniclaw_client),
):
Expand All @@ -100,9 +101,12 @@ async def get_address(
if not address:
raise HTTPException(status_code=404, detail="Wallet not found")

wallet_cfg = policy_mgr.get_wallet_config(agent.wallet_id)
alias = wallet_cfg.get("alias") or agent.wallet_id.replace("pending-", "")

return AddressResponse(
wallet_id=agent.wallet_id,
alias="primary",
alias=alias,
address=address,
eoa_address=eoa_address,
circle_wallet_address=circle_address,
Expand Down Expand Up @@ -880,9 +884,8 @@ async def list_wallets(
is_pending = agent.wallet_id.startswith("pending-")
address = await wallet_mgr.get_wallet_address(agent.wallet_id)

alias = agent.wallet_id.replace("pending-", "") if is_pending else "primary"
# Simplest is just to use the alias from the policy if we can find it
# but for now "primary" is a safe default for single-agent case.
wallet_cfg = policy_mgr.get_wallet_config(agent.wallet_id)
alias = wallet_cfg.get("alias") or agent.wallet_id.replace("pending-", "")

policy = policy_mgr.get_policy()

Expand Down
Loading
Loading