Skip to content

Commit 9436baf

Browse files
committed
fix: opencode run uses positional argument, not --instruction flag
- opencode run takes prompt as positional [message..], not --instruction - Updated legacy cli_map in daemon.py - Updated all docs (configuration, engine-examples, troubleshooting, security) - Fixed smoke.py test assertion - Removed all --instruction references across the codebase
1 parent 12de874 commit 9436baf

6 files changed

Lines changed: 77 additions & 8 deletions

File tree

daemon.py

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import sys
2121
import time
2222
from datetime import datetime
23+
from urllib.parse import urlencode, urlparse
2324

2425
import requests
2526
from dotenv import load_dotenv
@@ -51,13 +52,16 @@ def _first_present(*values):
5152
class OdooAgentRuntime:
5253
"""Runtime daemon that connects to Odoo and executes agent work."""
5354

54-
def __init__(self, odoo_url, api_key, name, poll_interval=10, max_concurrent=3):
55+
def __init__(self, odoo_url, api_key, name, poll_interval=10, max_concurrent=3, database=None):
5556
self.odoo_url = odoo_url.rstrip('/')
5657
self.api_key = api_key
5758
self.name = name
5859
self.poll_interval = poll_interval
5960
self.max_concurrent = max_concurrent
61+
self.database = (database or '').strip() or None
6062
self.active_tasks = {}
63+
self._database_bootstrapped = not self.database
64+
self._database_bootstrap_failed = False
6165
self.session = requests.Session()
6266
self.session.headers.update({
6367
'X-API-Key': api_key,
@@ -67,8 +71,48 @@ def __init__(self, odoo_url, api_key, name, poll_interval=10, max_concurrent=3):
6771
def _api_url(self, path):
6872
return f'{self.odoo_url}{path}'
6973

74+
def _bootstrap_database_session(self):
75+
"""Select the configured Odoo database and retain its session cookie."""
76+
if self._database_bootstrapped:
77+
return True
78+
if self._database_bootstrap_failed:
79+
return False
80+
81+
login_url = f'{self.odoo_url}/web/login?{urlencode({"db": self.database})}'
82+
try:
83+
response = self.session.get(login_url, allow_redirects=True, timeout=30)
84+
response.raise_for_status()
85+
except requests.exceptions.RequestException as exc:
86+
self._database_bootstrap_failed = True
87+
logger.error(
88+
'Database bootstrap failed for ODOO_DATABASE=%r: %s. '
89+
'Runtime API calls were not attempted.',
90+
self.database,
91+
exc,
92+
)
93+
return False
94+
95+
final_url = getattr(response, 'url', '')
96+
if (
97+
isinstance(final_url, str)
98+
and urlparse(final_url).path.rstrip('/') == '/web/database/selector'
99+
):
100+
self._database_bootstrap_failed = True
101+
logger.error(
102+
'Database bootstrap failed for ODOO_DATABASE=%r: redirected to '
103+
'/web/database/selector. Runtime API calls were not attempted.',
104+
self.database,
105+
)
106+
return False
107+
108+
self._database_bootstrapped = True
109+
logger.info('Selected Odoo database %r for this runtime session.', self.database)
110+
return True
111+
70112
def _request(self, method, path, **kwargs):
71113
"""Make an API request with error handling."""
114+
if not self._bootstrap_database_session():
115+
return None
72116
try:
73117
resp = self.session.request(method, self._api_url(path), timeout=30, **kwargs)
74118
resp.raise_for_status()
@@ -310,7 +354,7 @@ def _resolve_command(self, agent_config, instruction, task_name, task_id):
310354

311355
cli_map = {
312356
'hermes': ['hermes', 'run', '--task', task_name, '--context', instruction],
313-
'opencode': ['opencode', 'run', '--instruction', instruction],
357+
'opencode': ['opencode', 'run', instruction],
314358
'openclaw': ['openclaw', 'agent', '--task', task_name, '--context', instruction],
315359
}
316360

@@ -390,6 +434,13 @@ def run(self):
390434
logger.info(f'Starting Odoo Agent Runtime: {self.name}')
391435
logger.info(f'Connecting to: {self.odoo_url}')
392436

437+
if not self._bootstrap_database_session():
438+
logger.error(
439+
'Cannot start runtime because ODOO_DATABASE bootstrap failed. '
440+
'Verify the database name and Odoo access; this is not an API key error.'
441+
)
442+
return False
443+
393444
if not self.send_heartbeat():
394445
logger.error('Failed to connect to Odoo. Check URL and API key.')
395446
return False
@@ -443,6 +494,8 @@ def main():
443494
parser = argparse.ArgumentParser(description='Odoo Agent Runtime Daemon')
444495
parser.add_argument('--odoo-url', default=os.getenv('ODOO_URL', 'http://localhost:8069'),
445496
help='Odoo instance URL')
497+
parser.add_argument('--odoo-database', default=os.getenv('ODOO_DATABASE', ''),
498+
help='Optional Odoo database for multi-database instances')
446499
parser.add_argument('--api-key', default=os.getenv('API_KEY', ''),
447500
help='Runtime API key')
448501
parser.add_argument('--name', default=os.getenv('RUNTIME_NAME', get_hostname()),
@@ -464,6 +517,7 @@ def main():
464517
api_key=args.api_key,
465518
name=args.name,
466519
poll_interval=args.poll_interval,
520+
database=args.odoo_database,
467521
)
468522

469523
success = runtime.run()

docs/configuration.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ The runtime can be configured through `.env` or command-line flags.
77
```env
88
ODOO_URL=https://odoo.example.com
99
API_KEY=your-runtime-api-key
10+
# Optional: select this Odoo database before runtime API calls.
11+
ODOO_DATABASE=production
1012
RUNTIME_NAME=agent-worker-01
1113
POLL_INTERVAL=10
1214
```
@@ -17,10 +19,24 @@ POLL_INTERVAL=10
1719
python3 daemon.py \
1820
--odoo-url https://odoo.example.com \
1921
--api-key your-runtime-api-key \
22+
--odoo-database production \
2023
--name agent-worker-01 \
2124
--poll-interval 10
2225
```
2326

27+
## Multi-database Odoo
28+
29+
`ODOO_DATABASE` (or `--odoo-database`) is optional. Configure it only when the
30+
Odoo server hosts more than one database and the runtime must use a specific
31+
one. Leaving it unset or blank preserves the existing single-database behavior.
32+
33+
Before making runtime API calls, the runtime selects the configured database by
34+
requesting `/web/login?db=<URL-encoded database>` and following redirects. The
35+
resulting session cookie is retained and used for subsequent runtime API calls.
36+
37+
Keep the Odoo URL free of credentials and API keys. Set `API_KEY` through the
38+
environment variable or `--api-key` flag; never put API keys in a URL.
39+
2440
## Poll interval
2541

2642
Start with `10` seconds. Lower values feel more responsive but increase traffic. Higher values reduce traffic but make queues feel slower.
@@ -58,5 +74,5 @@ Supported placeholders:
5874
Example:
5975

6076
```text
61-
opencode run --instruction {instruction}
77+
opencode run {instruction}
6278
```

docs/engine-examples.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ The runtime uses `agent.cli_command` from Odoo when present. Keep commands expli
1414
## Examples
1515

1616
```text
17-
opencode run --instruction {instruction}
17+
opencode run {instruction}
1818
hermes run --context {instruction}
1919
openclaw agent --task {task_name} --context {instruction}
2020
claude --print {instruction}

docs/security.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ The runtime executes agent `cli_command` values configured in Odoo. Review those
3030
Prefer direct executable invocation:
3131

3232
```text
33-
opencode run --instruction {instruction}
33+
opencode run {instruction}
3434
```
3535

3636
Avoid commands that download and execute remote scripts.

docs/troubleshooting.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ Get-Command opencode
5151
Prefer placeholder-based commands:
5252

5353
```text
54-
opencode run --instruction {instruction}
54+
opencode run {instruction}
5555
```
5656

5757
Avoid shell-specific command strings when possible.

scripts/smoke.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def main():
6565
{
6666
'name': 'Example',
6767
'engine': 'custom',
68-
'cli_command': 'agent-cli run --instruction {instruction} --name "{task_name}"',
68+
'cli_command': 'agent-cli run {instruction} --name "{task_name}"',
6969
},
7070
complex_instruction,
7171
'Task with spaces',
@@ -74,7 +74,6 @@ def main():
7474
assert cmd == [
7575
'agent-cli',
7676
'run',
77-
'--instruction',
7877
complex_instruction,
7978
'--name',
8079
'Task with spaces',

0 commit comments

Comments
 (0)