optio-opencode 0.2.2__tar.gz → 0.2.3__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.
Files changed (50) hide show
  1. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/PKG-INFO +15 -3
  2. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/README.md +12 -0
  3. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/pyproject.toml +3 -3
  4. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/src/optio_opencode/prompt.py +2 -2
  5. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/src/optio_opencode/session.py +6 -1
  6. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/src/optio_opencode/types.py +14 -1
  7. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/src/optio_opencode.egg-info/PKG-INFO +15 -3
  8. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/src/optio_opencode.egg-info/requires.txt +2 -2
  9. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_session_local.py +37 -0
  10. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/setup.cfg +0 -0
  11. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/src/optio_opencode/__init__.py +0 -0
  12. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/src/optio_opencode/conversation.py +0 -0
  13. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/src/optio_opencode/cred_watcher.py +0 -0
  14. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/src/optio_opencode/host_actions.py +0 -0
  15. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/src/optio_opencode/seed_manifest.py +0 -0
  16. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/src/optio_opencode/snapshots.py +0 -0
  17. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/src/optio_opencode/verify.py +0 -0
  18. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/src/optio_opencode.egg-info/SOURCES.txt +0 -0
  19. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/src/optio_opencode.egg-info/dependency_links.txt +0 -0
  20. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/src/optio_opencode.egg-info/top_level.txt +0 -0
  21. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_agent_sender_opencode.py +0 -0
  22. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_conversation_config.py +0 -0
  23. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_conversation_driver.py +0 -0
  24. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_conversation_session.py +0 -0
  25. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_conversation_ui_model.py +0 -0
  26. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_conversation_ui_session.py +0 -0
  27. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_cred_watcher.py +0 -0
  28. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_file_download.py +0 -0
  29. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_file_upload.py +0 -0
  30. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_host_actions.py +0 -0
  31. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_host_local.py +0 -0
  32. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_host_primitives_local.py +0 -0
  33. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_host_primitives_remote.py +0 -0
  34. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_host_remote_resume.py +0 -0
  35. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_host_resume.py +0 -0
  36. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_prompt.py +0 -0
  37. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_purge_seed.py +0 -0
  38. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_resume_sentence_opencode.py +0 -0
  39. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_sanity.py +0 -0
  40. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_seed_config.py +0 -0
  41. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_session_blob_hooks.py +0 -0
  42. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_session_hooks.py +0 -0
  43. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_session_remote.py +0 -0
  44. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_session_resume.py +0 -0
  45. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_session_seed.py +0 -0
  46. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_session_seed_saveback.py +0 -0
  47. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_smart_install.py +0 -0
  48. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_snapshots.py +0 -0
  49. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_types.py +0 -0
  50. {optio_opencode-0.2.2 → optio_opencode-0.2.3}/tests/test_verify_seed.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: optio-opencode
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Run opencode web as an optio task; local subprocess or remote via SSH.
5
5
  Author-email: Kristof Csillag <kristof.csillag@deai-labs.com>
6
6
  License-Expression: Apache-2.0
@@ -20,9 +20,9 @@ Classifier: Topic :: Software Development :: Code Generators
20
20
  Classifier: Framework :: AsyncIO
21
21
  Requires-Python: >=3.11
22
22
  Description-Content-Type: text/markdown
23
- Requires-Dist: optio-core<0.3,>=0.2
23
+ Requires-Dist: optio-core<0.4,>=0.3
24
24
  Requires-Dist: optio-host<0.3,>=0.2
25
- Requires-Dist: optio-agents<0.3,>=0.2
25
+ Requires-Dist: optio-agents<0.4,>=0.3
26
26
  Requires-Dist: asyncssh>=2.14
27
27
  Requires-Dist: aiohttp>=3.9
28
28
  Provides-Extra: dev
@@ -81,6 +81,18 @@ task = create_opencode_task(config)
81
81
 
82
82
  Set `ssh=None` for local subprocess mode.
83
83
 
84
+ ## Messages
85
+
86
+ - `use_client_messages` (bool, default `False`) — enable the `CLIENT_MESSAGE:`
87
+ log keyword: the agent can push `{keyword, data}` messages to the browser
88
+ session that launched the task (surfaced via optio-ui's `onClientMessage`).
89
+ - `on_caller_message` (async callback, default `None`) — enable the
90
+ `CALLER_MESSAGE:` log keyword: the agent can push `{keyword, data}` messages
91
+ to your application. Signature `(hook_ctx, keyword, data) -> str | None`;
92
+ a non-None return is sent back to the agent as feedback. Keywords that are
93
+ not enabled are absent from both the parser and the agent-facing protocol
94
+ documentation.
95
+
84
96
  ## License
85
97
 
86
98
  Apache-2.0.
@@ -50,6 +50,18 @@ task = create_opencode_task(config)
50
50
 
51
51
  Set `ssh=None` for local subprocess mode.
52
52
 
53
+ ## Messages
54
+
55
+ - `use_client_messages` (bool, default `False`) — enable the `CLIENT_MESSAGE:`
56
+ log keyword: the agent can push `{keyword, data}` messages to the browser
57
+ session that launched the task (surfaced via optio-ui's `onClientMessage`).
58
+ - `on_caller_message` (async callback, default `None`) — enable the
59
+ `CALLER_MESSAGE:` log keyword: the agent can push `{keyword, data}` messages
60
+ to your application. Signature `(hook_ctx, keyword, data) -> str | None`;
61
+ a non-None return is sent back to the agent as feedback. Keywords that are
62
+ not enabled are absent from both the parser and the agent-facing protocol
63
+ documentation.
64
+
53
65
  ## License
54
66
 
55
67
  Apache-2.0.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "optio-opencode"
7
- version = "0.2.2"
7
+ version = "0.2.3"
8
8
  description = "Run opencode web as an optio task; local subprocess or remote via SSH."
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -26,11 +26,11 @@ classifiers = [
26
26
  "Framework :: AsyncIO",
27
27
  ]
28
28
  dependencies = [
29
- "optio-core>=0.2,<0.3",
29
+ "optio-core>=0.3,<0.4",
30
30
  # 0.1.1 introduces the bind_addr kwarg on Host.establish_tunnel —
31
31
  # required for OPTIO_WIDGET_TUNNEL_BIND to work.
32
32
  "optio-host>=0.2,<0.3",
33
- "optio-agents>=0.2,<0.3",
33
+ "optio-agents>=0.3,<0.4",
34
34
  "asyncssh>=2.14",
35
35
  "aiohttp>=3.9",
36
36
  ]
@@ -8,7 +8,7 @@ addressed. The consumer's own task description is then appended verbatim.
8
8
 
9
9
 
10
10
  from optio_agents.prompt import downloadables_block
11
- from optio_agents.protocol import build_log_channel_prompt
11
+ from optio_agents.protocol import ProtocolFeatures, build_log_channel_prompt
12
12
 
13
13
 
14
14
  _OPENCODE_INTRO = """# Coordination protocol with the host (optio-opencode)
@@ -163,7 +163,7 @@ def compose_agents_md(
163
163
  )
164
164
  if host_protocol:
165
165
  if documentation is None:
166
- documentation = build_log_channel_prompt("suppress")
166
+ documentation = build_log_channel_prompt(ProtocolFeatures(browser="suppress"))
167
167
  base_prompt_pre = _OPENCODE_INTRO + documentation
168
168
  else:
169
169
  # Conversation mode without the optio.log channel: no keyword docs,
@@ -97,7 +97,11 @@ async def run_opencode_session(ctx: ProcessContext, config: OpencodeTaskConfig)
97
97
  """Execute function body for one optio-opencode task instance."""
98
98
  # --- per-task filesystem layout ---------------------------------------
99
99
  host: Host = _build_host(config, ctx.process_id)
100
- protocol = get_protocol(browser="suppress")
100
+ protocol = get_protocol(
101
+ browser="suppress",
102
+ client_messages=config.use_client_messages,
103
+ caller_messages=config.on_caller_message is not None,
104
+ )
101
105
 
102
106
  instructions = config.consumer_instructions
103
107
  omit_task_framing = False
@@ -502,6 +506,7 @@ async def run_opencode_session(ctx: ProcessContext, config: OpencodeTaskConfig)
502
506
  body=_opencode_body,
503
507
  prepare=_prepare,
504
508
  on_deliverable=config.on_deliverable,
509
+ on_caller_message=config.on_caller_message,
505
510
  after_execute=config.after_execute,
506
511
  protocol=protocol,
507
512
  agent_sender=_agent_sender,
@@ -9,7 +9,11 @@ is owned by ``optio-host``. This module re-exports them so existing
9
9
  from dataclasses import dataclass, field
10
10
  from typing import Any, Awaitable, Callable, Literal
11
11
 
12
- from optio_agents.protocol.session import DeliverableCallback, HookCallback
12
+ from optio_agents.protocol.session import (
13
+ CallerMessageCallback,
14
+ DeliverableCallback,
15
+ HookCallback,
16
+ )
13
17
  from optio_host.types import SSHConfig
14
18
 
15
19
 
@@ -28,6 +32,7 @@ _VALID_TOOL_VERBOSITY = {"silent", "description-only", "verbose"}
28
32
 
29
33
 
30
34
  __all__ = [
35
+ "CallerMessageCallback",
31
36
  "DeliverableCallback",
32
37
  "HookCallback",
33
38
  "SSHConfig",
@@ -52,6 +57,14 @@ class OpencodeTaskConfig:
52
57
  opencode_config: dict[str, Any] = field(default_factory=dict)
53
58
  ssh: SSHConfig | None = None
54
59
  on_deliverable: DeliverableCallback | None = None
60
+ # Enable the CLIENT_MESSAGE keyword: agent-pushed messages routed to the
61
+ # originating browser session's frontend (stored as sessionEvents,
62
+ # surfaced via optio-ui's onClientMessage). Off by default.
63
+ use_client_messages: bool = False
64
+ # Enable the CALLER_MESSAGE keyword: agent-pushed messages routed to this
65
+ # callback in the embedding application. A non-None return value is sent
66
+ # back to the agent as feedback. Off (None) by default.
67
+ on_caller_message: CallerMessageCallback | None = None
55
68
  install_if_missing: bool = True
56
69
  # Override for the optio-owned opencode binary **cache** directory (where
57
70
  # the opencode binary is installed/cached on the worker). ``None``
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: optio-opencode
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Run opencode web as an optio task; local subprocess or remote via SSH.
5
5
  Author-email: Kristof Csillag <kristof.csillag@deai-labs.com>
6
6
  License-Expression: Apache-2.0
@@ -20,9 +20,9 @@ Classifier: Topic :: Software Development :: Code Generators
20
20
  Classifier: Framework :: AsyncIO
21
21
  Requires-Python: >=3.11
22
22
  Description-Content-Type: text/markdown
23
- Requires-Dist: optio-core<0.3,>=0.2
23
+ Requires-Dist: optio-core<0.4,>=0.3
24
24
  Requires-Dist: optio-host<0.3,>=0.2
25
- Requires-Dist: optio-agents<0.3,>=0.2
25
+ Requires-Dist: optio-agents<0.4,>=0.3
26
26
  Requires-Dist: asyncssh>=2.14
27
27
  Requires-Dist: aiohttp>=3.9
28
28
  Provides-Extra: dev
@@ -81,6 +81,18 @@ task = create_opencode_task(config)
81
81
 
82
82
  Set `ssh=None` for local subprocess mode.
83
83
 
84
+ ## Messages
85
+
86
+ - `use_client_messages` (bool, default `False`) — enable the `CLIENT_MESSAGE:`
87
+ log keyword: the agent can push `{keyword, data}` messages to the browser
88
+ session that launched the task (surfaced via optio-ui's `onClientMessage`).
89
+ - `on_caller_message` (async callback, default `None`) — enable the
90
+ `CALLER_MESSAGE:` log keyword: the agent can push `{keyword, data}` messages
91
+ to your application. Signature `(hook_ctx, keyword, data) -> str | None`;
92
+ a non-None return is sent back to the agent as feedback. Keywords that are
93
+ not enabled are absent from both the parser and the agent-facing protocol
94
+ documentation.
95
+
84
96
  ## License
85
97
 
86
98
  Apache-2.0.
@@ -1,6 +1,6 @@
1
- optio-core<0.3,>=0.2
1
+ optio-core<0.4,>=0.3
2
2
  optio-host<0.3,>=0.2
3
- optio-agents<0.3,>=0.2
3
+ optio-agents<0.4,>=0.3
4
4
  asyncssh>=2.14
5
5
  aiohttp>=3.9
6
6
 
@@ -315,6 +315,43 @@ async def test_widget_upstream_and_data_are_set(ctx_and_captures, _supply_scenar
315
315
  assert decoded.startswith("/") and "optio-opencode" in decoded
316
316
 
317
317
 
318
+ async def test_caller_message_reaches_callback(ctx_and_captures, _supply_scenario):
319
+ ctx, _cap, _ = ctx_and_captures
320
+ _supply_scenario["name"] = "caller_message"
321
+
322
+ received: list[tuple[str, object]] = []
323
+ async def on_caller(hook_ctx, keyword, data):
324
+ received.append((keyword, data))
325
+ return "pong"
326
+
327
+ cfg = OpencodeTaskConfig(
328
+ consumer_instructions="(scenario: caller_message)",
329
+ on_caller_message=on_caller,
330
+ )
331
+ await run_opencode_session(ctx, cfg)
332
+
333
+ assert received == [("ping", {"n": 1})]
334
+
335
+
336
+ async def test_client_message_stored_as_session_event(
337
+ ctx_and_captures, _supply_scenario, mongo_db,
338
+ ):
339
+ ctx, _cap, _ = ctx_and_captures
340
+ _supply_scenario["name"] = "client_message"
341
+
342
+ cfg = OpencodeTaskConfig(
343
+ consumer_instructions="(scenario: client_message)",
344
+ use_client_messages=True,
345
+ )
346
+ await run_opencode_session(ctx, cfg)
347
+
348
+ doc = await mongo_db["test_processes"].find_one({"processId": "p"})
349
+ events = [e for e in doc.get("sessionEvents", []) if e["type"] == "client"]
350
+ assert len(events) == 1
351
+ assert events[0]["keyword"] == "notify"
352
+ assert events[0]["data"] == {"msg": "hi"}
353
+
354
+
318
355
  # ---- resume log -----------------------------------------------------------
319
356
 
320
357
 
File without changes