connectonion 0.6.0__py3-none-any.whl → 0.6.1__py3-none-any.whl

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.
@@ -6,13 +6,48 @@ requests. Separated from host.py for better testing and smaller file size.
6
6
  Design decision: Raw ASGI instead of Starlette/FastAPI for full protocol control.
7
7
  See: docs/design-decisions/022-raw-asgi-implementation.md
8
8
  """
9
+ import asyncio
9
10
  import hmac
10
11
  import json
11
12
  import os
13
+ import queue
14
+ import threading
12
15
  from pathlib import Path
16
+ from typing import Any, Dict
13
17
 
14
18
  from pydantic import BaseModel
15
19
 
20
+ from .connection import Connection
21
+
22
+
23
+ class AsyncToSyncConnection(Connection):
24
+ """Bridge async WebSocket to sync Connection interface.
25
+
26
+ Uses queues to communicate between async WebSocket handler and sync agent code.
27
+ The agent runs in a thread, sending/receiving via queues.
28
+ The async handler pumps messages between WebSocket and queues.
29
+ """
30
+
31
+ def __init__(self):
32
+ self._outgoing: queue.Queue[Dict[str, Any]] = queue.Queue()
33
+ self._incoming: queue.Queue[Dict[str, Any]] = queue.Queue()
34
+ self._closed = False
35
+
36
+ def send(self, event: Dict[str, Any]) -> None:
37
+ """Queue event to be sent to client."""
38
+ if not self._closed:
39
+ self._outgoing.put(event)
40
+
41
+ def receive(self) -> Dict[str, Any]:
42
+ """Block until response from client."""
43
+ return self._incoming.get()
44
+
45
+ def close(self):
46
+ """Mark connection as closed."""
47
+ self._closed = True
48
+ # Unblock any waiting receive
49
+ self._incoming.put({"type": "connection_closed"})
50
+
16
51
 
17
52
  def _json_default(obj):
18
53
  """Handle non-serializable objects like Pydantic models.
@@ -190,6 +225,11 @@ async def handle_websocket(
190
225
  ):
191
226
  """Handle WebSocket connections at /ws.
192
227
 
228
+ Supports bidirectional communication via Connection interface:
229
+ - Agent sends events via connection.log() / connection.send()
230
+ - Agent requests approval via connection.request_approval()
231
+ - Client responds to approval requests
232
+
193
233
  Args:
194
234
  scope: ASGI scope dict
195
235
  receive: ASGI receive callable
@@ -229,9 +269,89 @@ async def handle_websocket(
229
269
  await send({"type": "websocket.send",
230
270
  "text": json.dumps({"type": "ERROR", "message": "prompt required"})})
231
271
  continue
232
- result = handlers["ws_input"](prompt)
272
+
273
+ # Create connection for bidirectional communication
274
+ connection = AsyncToSyncConnection()
275
+ agent_done = threading.Event()
276
+ result_holder = [None]
277
+
278
+ def run_agent():
279
+ result_holder[0] = handlers["ws_input"](prompt, connection)
280
+ agent_done.set()
281
+
282
+ # Start agent in thread
283
+ agent_thread = threading.Thread(target=run_agent, daemon=True)
284
+ agent_thread.start()
285
+
286
+ # Pump messages between WebSocket and connection
287
+ await _pump_messages(receive, send, connection, agent_done)
288
+
289
+ # Send final result
233
290
  await send({"type": "websocket.send",
234
- "text": json.dumps({"type": "OUTPUT", "result": result})})
291
+ "text": json.dumps({"type": "OUTPUT", "result": result_holder[0]})})
292
+
293
+
294
+ async def _pump_messages(ws_receive, ws_send, connection: AsyncToSyncConnection, agent_done: threading.Event):
295
+ """Pump messages between WebSocket and connection queues.
296
+
297
+ Runs until agent completes. Handles:
298
+ - Outgoing: connection._outgoing queue → WebSocket
299
+ - Incoming: WebSocket → connection._incoming queue (for approval responses)
300
+ """
301
+ loop = asyncio.get_event_loop()
302
+
303
+ async def send_outgoing():
304
+ """Send outgoing messages from connection to WebSocket."""
305
+ while not agent_done.is_set():
306
+ # Use run_in_executor for blocking queue.get
307
+ try:
308
+ event = await loop.run_in_executor(
309
+ None, lambda: connection._outgoing.get(timeout=0.05)
310
+ )
311
+ await ws_send({"type": "websocket.send", "text": json.dumps(event)})
312
+ except queue.Empty:
313
+ pass
314
+
315
+ # Drain remaining
316
+ while True:
317
+ try:
318
+ event = connection._outgoing.get_nowait()
319
+ await ws_send({"type": "websocket.send", "text": json.dumps(event)})
320
+ except queue.Empty:
321
+ break
322
+
323
+ async def receive_incoming():
324
+ """Receive incoming messages from WebSocket to connection."""
325
+ while not agent_done.is_set():
326
+ try:
327
+ msg = await asyncio.wait_for(ws_receive(), timeout=0.1)
328
+ if msg["type"] == "websocket.receive":
329
+ try:
330
+ data = json.loads(msg.get("text", "{}"))
331
+ connection._incoming.put(data)
332
+ except json.JSONDecodeError:
333
+ pass
334
+ elif msg["type"] == "websocket.disconnect":
335
+ connection.close()
336
+ break
337
+ except asyncio.TimeoutError:
338
+ continue
339
+
340
+ # Run both tasks concurrently
341
+ send_task = asyncio.create_task(send_outgoing())
342
+ recv_task = asyncio.create_task(receive_incoming())
343
+
344
+ # Wait for agent to complete
345
+ while not agent_done.is_set():
346
+ await asyncio.sleep(0.05)
347
+
348
+ # Cancel receive task and wait for send to finish draining
349
+ recv_task.cancel()
350
+ try:
351
+ await recv_task
352
+ except asyncio.CancelledError:
353
+ pass
354
+ await send_task
235
355
 
236
356
 
237
357
  def create_app(
@@ -0,0 +1,123 @@
1
+ """
2
+ Purpose: Connection interface for agent-client communication during hosted execution
3
+ LLM-Note:
4
+ Dependencies: imports from [abc, typing] | imported by [asgi.py, __init__.py] | tested by [tests/unit/test_connection.py]
5
+ Data flow: receives from host/asgi → WebSocket send/receive → provides log() and request_approval() to agent event handlers
6
+ State/Effects: stateless base class | WebSocketConnection wraps ASGI WebSocket for bidirectional messaging
7
+ Integration: exposes Connection (base), WebSocketConnection (ASGI adapter) | agent.connection set by host() during WebSocket requests
8
+ Performance: log() is fire-and-forget (non-blocking) | request_approval() blocks waiting for client response
9
+ Errors: WebSocketConnection raises if WebSocket closed unexpectedly
10
+ """
11
+
12
+ from abc import ABC, abstractmethod
13
+ from typing import Any, Dict
14
+
15
+
16
+ class Connection(ABC):
17
+ """Base connection interface for agent-client communication.
18
+
19
+ Two-layer API:
20
+ - Low-level: send(event), receive() - primitives for any communication
21
+ - High-level: log(type, **data), request_approval(tool, args) - common patterns
22
+
23
+ Usage in event handlers:
24
+ @after_llm
25
+ def on_thinking(agent):
26
+ if agent.connection:
27
+ agent.connection.log("thinking")
28
+
29
+ @before_each_tool
30
+ def on_tool(agent):
31
+ if agent.connection:
32
+ tool = agent.current_session['pending_tool']
33
+ if tool['name'] in DANGEROUS:
34
+ if not agent.connection.request_approval(tool['name'], tool['arguments']):
35
+ raise ToolRejected()
36
+ """
37
+
38
+ # ═══════════════════════════════════════════════════════
39
+ # LOW-LEVEL API (Primitives)
40
+ # ═══════════════════════════════════════════════════════
41
+
42
+ @abstractmethod
43
+ def send(self, event: Dict[str, Any]) -> None:
44
+ """Send any event to client.
45
+
46
+ Args:
47
+ event: Dict with at least 'type' key, e.g. {"type": "thinking"}
48
+ """
49
+ pass
50
+
51
+ @abstractmethod
52
+ def receive(self) -> Dict[str, Any]:
53
+ """Receive response from client.
54
+
55
+ Returns:
56
+ Dict response from client
57
+ """
58
+ pass
59
+
60
+ # ═══════════════════════════════════════════════════════
61
+ # HIGH-LEVEL API (Patterns)
62
+ # ═══════════════════════════════════════════════════════
63
+
64
+ def log(self, event_type: str, **data) -> None:
65
+ """One-way notification to client.
66
+
67
+ Common event types: thinking, tool_call, tool_result, complete, error
68
+
69
+ Args:
70
+ event_type: Type of event (e.g. "thinking", "tool_call")
71
+ **data: Additional data for the event
72
+
73
+ Example:
74
+ connection.log("thinking")
75
+ connection.log("tool_call", name="search", arguments={"q": "python"})
76
+ """
77
+ self.send({"type": event_type, **data})
78
+
79
+ def request_approval(self, tool: str, arguments: Dict[str, Any]) -> bool:
80
+ """Two-way: request permission, wait for response.
81
+
82
+ Sends approval_needed event and blocks until client responds.
83
+
84
+ Args:
85
+ tool: Name of tool requiring approval
86
+ arguments: Tool arguments to show user
87
+
88
+ Returns:
89
+ True if approved, False if rejected
90
+
91
+ Example:
92
+ if not connection.request_approval("delete_file", {"path": "/tmp/x"}):
93
+ raise ToolRejected()
94
+ """
95
+ self.send({"type": "approval_needed", "tool": tool, "arguments": arguments})
96
+ response = self.receive()
97
+ return response.get("approved", False)
98
+
99
+
100
+ class SyncWebSocketConnection(Connection):
101
+ """Synchronous WebSocket connection adapter.
102
+
103
+ Wraps async WebSocket send/receive for use in synchronous agent code.
104
+ Uses threading events to bridge async/sync boundary.
105
+ """
106
+
107
+ def __init__(self, send_callback, receive_callback):
108
+ """Initialize with send/receive callbacks.
109
+
110
+ Args:
111
+ send_callback: Callable that sends message to WebSocket
112
+ receive_callback: Callable that receives message from WebSocket
113
+ """
114
+ self._send = send_callback
115
+ self._receive = receive_callback
116
+
117
+ def send(self, event: Dict[str, Any]) -> None:
118
+ """Send event to client via WebSocket."""
119
+ self._send(event)
120
+
121
+ def receive(self) -> Dict[str, Any]:
122
+ """Receive response from client via WebSocket."""
123
+ return self._receive()
@@ -178,7 +178,7 @@ def health_handler(agent, start_time: float) -> dict:
178
178
  def info_handler(agent, trust: str) -> dict:
179
179
  """GET /info"""
180
180
  from .. import __version__
181
- tools = agent.tools.list_names() if hasattr(agent.tools, "list_names") else []
181
+ tools = agent.tools.names() if hasattr(agent.tools, "names") else []
182
182
  return {
183
183
  "name": agent.name,
184
184
  "address": get_agent_address(agent),
@@ -382,7 +382,7 @@ def admin_sessions_handler() -> dict:
382
382
  Frontend handles the display logic.
383
383
  """
384
384
  import yaml
385
- sessions_dir = Path(".co/sessions")
385
+ sessions_dir = Path(".co/evals")
386
386
  if not sessions_dir.exists():
387
387
  return {"sessions": []}
388
388
 
@@ -407,9 +407,11 @@ def _create_handlers(agent_template, result_ttl: int):
407
407
  agent_template: Agent used as template (deep-copied per request for isolation)
408
408
  result_ttl: How long to keep results on server in seconds
409
409
  """
410
- def ws_input(prompt: str) -> str:
411
- agent = copy.deepcopy(agent_template)
412
- return agent.input(prompt)
410
+ def ws_input(prompt: str, connection) -> str:
411
+ """WebSocket input with bidirectional connection support."""
412
+ agent_template.reset_conversation()
413
+ agent_template.connection = connection
414
+ return agent_template.input(prompt)
413
415
 
414
416
  return {
415
417
  "input": lambda storage, prompt, ttl, session=None: input_handler(agent_template, storage, prompt, ttl, session),
@@ -1,10 +1,10 @@
1
1
  """
2
2
  Purpose: Export pre-built plugins that extend agent behavior via event hooks
3
3
  LLM-Note:
4
- Dependencies: imports from [re_act, image_result_formatter, shell_approval, gmail_plugin, calendar_plugin] | imported by [__init__.py main package] | re-exports plugins for agent consumption
4
+ Dependencies: imports from [re_act, image_result_formatter, shell_approval, gmail_plugin, calendar_plugin, ui_stream] | imported by [__init__.py main package] | re-exports plugins for agent consumption
5
5
  Data flow: agent imports plugin → passes to Agent(plugins=[plugin]) → plugin event handlers fire on agent lifecycle events
6
6
  State/Effects: no state | pure re-exports | plugins modify agent behavior at runtime
7
- Integration: exposes re_act (ReAct prompting), image_result_formatter (base64 image handling), shell_approval (user confirmation for shell commands), gmail_plugin (Gmail OAuth flow), calendar_plugin (Google Calendar integration) | plugins are lists of event handlers
7
+ Integration: exposes re_act (ReAct prompting), image_result_formatter (base64 image handling), shell_approval (user confirmation for shell commands), gmail_plugin (Gmail OAuth flow), calendar_plugin (Google Calendar integration), ui_stream (WebSocket event streaming) | plugins are lists of event handlers
8
8
  Errors: ImportError if underlying plugin dependencies not installed
9
9
 
10
10
  Pre-built plugins that can be easily imported and used across agents.
@@ -16,5 +16,6 @@ from .image_result_formatter import image_result_formatter
16
16
  from .shell_approval import shell_approval
17
17
  from .gmail_plugin import gmail_plugin
18
18
  from .calendar_plugin import calendar_plugin
19
+ from .ui_stream import ui_stream
19
20
 
20
- __all__ = ['re_act', 'eval', 'image_result_formatter', 'shell_approval', 'gmail_plugin', 'calendar_plugin']
21
+ __all__ = ['re_act', 'eval', 'image_result_formatter', 'shell_approval', 'gmail_plugin', 'calendar_plugin', 'ui_stream']
@@ -0,0 +1,164 @@
1
+ """
2
+ Purpose: Stream agent activity to UI via Connection API
3
+ LLM-Note:
4
+ Dependencies: imports from [typing, core.events] | imported by [useful_plugins/__init__.py] | tested by [tests/unit/test_ui_stream.py]
5
+ Data flow: Event handlers check agent.connection → if present, call connection.log() to stream events
6
+ State/Effects: Streams events to WebSocket client | no file I/O | no blocking
7
+ Integration: exposes ui_stream list of event handlers | used via Agent(plugins=[ui_stream]) | works with host() WebSocket
8
+ Performance: O(1) event dispatch | no blocking | no LLM calls
9
+ Errors: Silently skips if connection is None (local execution)
10
+
11
+ UI Stream Plugin - Stream agent activity to connected UI clients.
12
+
13
+ When agent.connection is set (by host() for WebSocket connections), this plugin
14
+ streams real-time events for:
15
+ - LLM responses (thinking, tool_calls)
16
+ - Tool execution (before/after each tool)
17
+ - Errors and completion
18
+
19
+ Usage:
20
+ from connectonion import Agent
21
+ from connectonion.useful_plugins import ui_stream
22
+
23
+ agent = Agent("assistant", plugins=[ui_stream])
24
+ host(agent) # WebSocket clients receive real-time events
25
+ """
26
+
27
+ from typing import TYPE_CHECKING
28
+ from ..core.events import (
29
+ after_llm,
30
+ before_each_tool,
31
+ after_each_tool,
32
+ on_error,
33
+ on_complete,
34
+ )
35
+
36
+ if TYPE_CHECKING:
37
+ from ..core.agent import Agent
38
+
39
+
40
+ @after_llm
41
+ def stream_llm_response(agent: 'Agent') -> None:
42
+ """Stream LLM response to connected UI."""
43
+ if not agent.connection:
44
+ return
45
+
46
+ trace = agent.current_session.get('trace', [])
47
+ if not trace:
48
+ return
49
+
50
+ last = trace[-1]
51
+ if last.get('type') != 'llm_call':
52
+ return
53
+
54
+ # Stream content if present
55
+ content = last.get('content', '')
56
+ if content:
57
+ agent.connection.log('message', content=content)
58
+
59
+ # Stream tool calls if present
60
+ tool_calls = last.get('tool_calls', [])
61
+ for tc in tool_calls:
62
+ agent.connection.log(
63
+ 'tool_pending',
64
+ name=tc.get('function', {}).get('name', ''),
65
+ arguments=tc.get('function', {}).get('arguments', {}),
66
+ id=tc.get('id', ''),
67
+ )
68
+
69
+
70
+ @before_each_tool
71
+ def stream_tool_start(agent: 'Agent') -> None:
72
+ """Stream tool execution start to connected UI."""
73
+ if not agent.connection:
74
+ return
75
+
76
+ pending = agent.current_session.get('pending_tool')
77
+ if not pending:
78
+ return
79
+
80
+ agent.connection.log(
81
+ 'tool_start',
82
+ name=pending['name'],
83
+ arguments=pending['arguments'],
84
+ id=pending.get('id', ''),
85
+ )
86
+
87
+
88
+ @after_each_tool
89
+ def stream_tool_result(agent: 'Agent') -> None:
90
+ """Stream tool execution result to connected UI."""
91
+ if not agent.connection:
92
+ return
93
+
94
+ trace = agent.current_session.get('trace', [])
95
+ if not trace:
96
+ return
97
+
98
+ last = trace[-1]
99
+ if last.get('type') != 'tool_execution':
100
+ return
101
+
102
+ status = last.get('status', 'unknown')
103
+ result = last.get('result', '')
104
+
105
+ # Truncate large results for UI
106
+ if isinstance(result, str) and len(result) > 1000:
107
+ result = result[:1000] + '...'
108
+
109
+ agent.connection.log(
110
+ 'tool_result',
111
+ name=last.get('tool_name', ''),
112
+ status=status,
113
+ result=result,
114
+ timing_ms=last.get('timing', 0),
115
+ )
116
+
117
+
118
+ @on_error
119
+ def stream_error(agent: 'Agent') -> None:
120
+ """Stream error to connected UI."""
121
+ if not agent.connection:
122
+ return
123
+
124
+ trace = agent.current_session.get('trace', [])
125
+ if not trace:
126
+ return
127
+
128
+ last = trace[-1]
129
+ if last.get('status') != 'error':
130
+ return
131
+
132
+ agent.connection.log(
133
+ 'error',
134
+ tool_name=last.get('tool_name', ''),
135
+ error=str(last.get('error', '')),
136
+ )
137
+
138
+
139
+ @on_complete
140
+ def stream_complete(agent: 'Agent') -> None:
141
+ """Stream completion to connected UI."""
142
+ if not agent.connection:
143
+ return
144
+
145
+ trace = agent.current_session.get('trace', [])
146
+ tools_used = [t.get('tool_name', '') for t in trace if t.get('type') == 'tool_execution']
147
+ llm_calls = len([t for t in trace if t.get('type') == 'llm_call'])
148
+
149
+ agent.connection.log(
150
+ 'complete',
151
+ tools_used=tools_used,
152
+ llm_calls=llm_calls,
153
+ iterations=agent.current_session.get('iteration', 0),
154
+ )
155
+
156
+
157
+ # Bundle as plugin
158
+ ui_stream = [
159
+ stream_llm_response,
160
+ stream_tool_start,
161
+ stream_tool_result,
162
+ stream_error,
163
+ stream_complete,
164
+ ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: connectonion
3
- Version: 0.6.0
3
+ Version: 0.6.1
4
4
  Summary: A simple Python framework for creating AI agents with behavior tracking
5
5
  Project-URL: Homepage, https://github.com/openonion/connectonion
6
6
  Project-URL: Documentation, https://docs.connectonion.com
@@ -1,16 +1,17 @@
1
- connectonion/__init__.py,sha256=yZ48fcAYjXYU-toEky4aiE1w0l6aKuoJIvaGLQ7GkpY,1928
1
+ connectonion/__init__.py,sha256=7geVck4xTtsy0x9UbmCpSuFaCzaTTiT5PgHHXIGUKLU,1958
2
2
  connectonion/address.py,sha256=YOzpMOej-HqJUE6o0i0fG8rB7HM-Iods36s9OD--5ig,10852
3
- connectonion/console.py,sha256=6_J1ItkLJCHDpdJY-tCuw4jMcS09S-a5juZSDSIr1Nc,21254
3
+ connectonion/console.py,sha256=zmnhavw359iqY9HFI1gbZolRSqiDlzJPEkwI1CllWfY,21239
4
4
  connectonion/llm_do.py,sha256=rwgSsTreNGAq5xV3m9lbA7U5AE0XOZNdihJwW5FHz0k,12005
5
- connectonion/logger.py,sha256=7xt9fT-Ubdu6zzFZ5JPwScWDo9LJehuYDn6PB3f3icg,12651
5
+ connectonion/logger.py,sha256=AtyMuBUB7zbCuAQcySMZpRJ9qdAwU5q0V61mLVSx7Ec,17660
6
6
  connectonion/prompts.py,sha256=hmbx8ACOJzystbRPQ6bMqx8BQKBKJHNJnMogtAZgDGA,5661
7
7
  connectonion/transcribe.py,sha256=m2qd7A2qMKFAbmbLLgvcd-yUFz8FHgjUKtvtFffnK00,7730
8
8
  connectonion/cli/__init__.py,sha256=Pd1iKp0rUghs2kmdAhyp9hK8j0uWkNxOagBkdCGrG4I,55
9
9
  connectonion/cli/docs.md,sha256=Fk_JT8jFXXDpXTvU0ZUigMW1UR6ERmX-HDheYPPRNY8,3231
10
- connectonion/cli/main.py,sha256=2FWi-yhnyLQzZl_esOXYY3-u0Q1wbpdE4XG3QYoGm_Q,6893
10
+ connectonion/cli/main.py,sha256=ys0L_zwV4lkrln_86XrJ_U_1ARQ6oxoADtHWj3tSIkg,7315
11
11
  connectonion/cli/browser_agent/__init__.py,sha256=xZCoxS3dGVBBMnaasHOE1vxMDdIwUloRP67rGR-4obo,173
12
- connectonion/cli/browser_agent/browser.py,sha256=EdBAvpcfCHh8q6_-3-LVBw6OHyMYnz1_8m6gryWQdzM,8830
12
+ connectonion/cli/browser_agent/browser.py,sha256=P3ceJrHVS63NJvuQltjeOy4rZj1H-8kDy-qOZSWK9AA,21532
13
13
  connectonion/cli/browser_agent/prompt.md,sha256=tF0PhGcl3gkmVK1F5SG9GZwnPPXTZYWEaatAZtOYZZg,4479
14
+ connectonion/cli/browser_agent/scroll_strategies.py,sha256=t_noSlzbEptgBiRWgrlIv4L_jv33xHvKgxbg1qUFDL4,10109
14
15
  connectonion/cli/commands/__init__.py,sha256=IPZy9NwrE0hs4f7hIqyFM9GjFZpeCS8mC0Jf-5Ooy4c,43
15
16
  connectonion/cli/commands/auth_commands.py,sha256=D76_0yd77d23bXRvsTAY6HOcGJswo9-6z2dRi9CR9sE,21635
16
17
  connectonion/cli/commands/browser_commands.py,sha256=lB4N6XwP43qdcthwQWlbFU2S3INfxhRDXznAw1PSTsQ,1803
@@ -18,6 +19,7 @@ connectonion/cli/commands/copy_commands.py,sha256=f59STrC4Yy3OtYiUSz99K0zkU3tiWo
18
19
  connectonion/cli/commands/create.py,sha256=0TrsPulS6dqwr_gtIWWBQ03Q_BnNro-CV4qOV5VkHAg,22011
19
20
  connectonion/cli/commands/deploy_commands.py,sha256=l-o6XDxh5kDB0YUCb_LeVERvdUY4gUogOlNalRv1OdM,8774
20
21
  connectonion/cli/commands/doctor_commands.py,sha256=EOk8CMclvVqLq4-Dg2JghWehH9VQnthBejrhIBX66_4,7244
22
+ connectonion/cli/commands/eval_commands.py,sha256=PwWEtnfLZqkgWzFF9Fa1bHkf6TxmIf6D8_M9D6rwuJA,10012
21
23
  connectonion/cli/commands/init.py,sha256=8zpY01Ux25BM6UCMvs66DRtiHKHsq7Yo9N_KOhAhOOA,20979
22
24
  connectonion/cli/commands/project_cmd_lib.py,sha256=SfqTpbQmYgMiUdi94Rkn1jF6hIlEnfgV0cSWqxUhJiw,32197
23
25
  connectonion/cli/commands/reset_commands.py,sha256=FkK6tMn7QOY3X5ulTYQ7VnLfeYpStgbZ5UnnbD3zudY,7016
@@ -38,9 +40,9 @@ connectonion/cli/templates/playwright/prompt.md,sha256=wsvpWTzxrWYs4t4WLhXgJ7Auk
38
40
  connectonion/cli/templates/playwright/requirements.txt,sha256=oSyGEC1-DyWm3_vE1QkREeWx4odSlS-K2UjlUCTw4tM,38
39
41
  connectonion/cli/templates/web-research/agent.py,sha256=PS50oxPg8GX8RIjjZ6iSVhKDrS00riCjTPSrP3RIFV0,3970
40
42
  connectonion/core/__init__.py,sha256=NIUXpkxalSzbchqklnaxUsG-X5ZUNO4wdZ3lOwwzb_Q,1363
41
- connectonion/core/agent.py,sha256=dKYKDHbk1RKJP0YvXPvt9w3kBemWoO5AgS5PLtW66f4,18869
43
+ connectonion/core/agent.py,sha256=RXd-0DOWZg_u6iJXMPYlg4oH45BlbH5PULLWtB32h38,18944
42
44
  connectonion/core/events.py,sha256=jJOMt1PhRl-ef4R8-WpAq8pUbZ8GKIl0wOB2kJUVyWg,9151
43
- connectonion/core/llm.py,sha256=IzjlOT6Dj5xIplIymjcaHZ_abwE5wDHEE4pa8zjlEGY,32952
45
+ connectonion/core/llm.py,sha256=i-jCvaryIPGqYx7SXR5yuhh64W4DdlnmCqklESYpg78,32425
44
46
  connectonion/core/tool_executor.py,sha256=YGvgJpkFPFIxfFEVeASfvkYLreH6kXeTFoVZ_IqVJPU,10690
45
47
  connectonion/core/tool_factory.py,sha256=j0DoRuHoVqx8ej07c8nOOyHLPzSzCah1D3mY4P9I8yg,6853
46
48
  connectonion/core/tool_registry.py,sha256=rTe8RJnWXpmHXWznP468fhWvmRknk-TlF9Iz8G9_qus,4367
@@ -63,22 +65,23 @@ connectonion/debug/runtime_inspector/__init__.py,sha256=6Hf88LTZ1iEAnNzfTkjp7iRb
63
65
  connectonion/debug/runtime_inspector/agent.py,sha256=kGXncq8AOffUQ_fuj9Sw15of6_mtsvrsYNZ5-lU74ao,2510
64
66
  connectonion/debug/runtime_inspector/runtime_inspector.py,sha256=rxFOqTxSvyKxqagYL4V2Pf-ii0Ie8l14a5xHzgIb810,15336
65
67
  connectonion/debug/runtime_inspector/prompts/debug_assistant.md,sha256=sR17NHwBY-8EgIZwK4AoTKW9D6vEDUf1Aq7i936tqco,2816
66
- connectonion/network/__init__.py,sha256=e8bBYwY36tB5xVepsJG3j9lGz_JRPSkkubLHU30mr_Y,928
68
+ connectonion/network/__init__.py,sha256=S8p7lvq74WpCrVNTI_X3myZgFecjdq93Xdve3XwyWII,1037
67
69
  connectonion/network/announce.py,sha256=roS_PIYef7g-HlXhIkUrCEtGNUDBEStqFodCU8qEy5M,3366
68
- connectonion/network/asgi.py,sha256=VTMwwEWLq5RYvIufRImMcv-AB5D5pZmM8INaXqwUt4Q,9621
70
+ connectonion/network/asgi.py,sha256=F1aF9lzaA78I_2mCWngQ0oTVtEGEukP-viXLBs2hmDM,13909
69
71
  connectonion/network/connect.py,sha256=w6moVt1alBZjHoGgHzaWMf9SgHVPlN1drO4lqWeYWyY,9795
70
- connectonion/network/host.py,sha256=ZnmXkLOPb5DUjZnCHtLbNcEeja3UWHJ1XuiRTex6k50,20277
72
+ connectonion/network/connection.py,sha256=HqaENrlAh2RCNig8ntte2Nxw4dUT4pz2xNu400bRZeM,4852
73
+ connectonion/network/host.py,sha256=Xl6aaQFx4NLapPoTrCkMODGx6kxLmsmWo1zIbjuljRE,20399
71
74
  connectonion/network/relay.py,sha256=a8wj4UZDZpGEhvpyDuRjZJg1S1VzxqiPioQRLq1EAao,7160
72
75
  connectonion/network/trust.py,sha256=yGnmFq5QVxCqdXgpQD7PPZPrYj3_nhRx0iorVD8Htjg,6698
73
76
  connectonion/network/trust_agents.py,sha256=XDedEhxGRfu9KeYhX-Z1a5tRA-2Zbwz4ztnlA2Lnaf0,2968
74
77
  connectonion/network/trust_functions.py,sha256=jRgfPm5z8oy9x8IYJd20UUMCz7cc1Pd7zyqQK5SDdLc,3564
78
+ connectonion/network/static/docs.html,sha256=rSffkCAy2fA512XcMC6z1wyZH9iYeAsSP213G3l1OOk,31085
75
79
  connectonion/prompt_files/__init__.py,sha256=5o5xg0VzZt4e0O4JKh7AO7gbflkw78oNM37yC3VqFRU,56
76
80
  connectonion/prompt_files/analyze_contact.md,sha256=ZTCUhO8mM1mbYswfz4zjBxlv4r0DICLoYm0YaQBpiXk,2110
77
81
  connectonion/prompt_files/eval_expected.md,sha256=ZnVmyF9S9m49UzTKCMajJhfGaxUhUkDxDm75xDYNLPs,435
78
82
  connectonion/prompt_files/react_evaluate.md,sha256=1qzq_ShlhWUQnh8PkdMl9IpHSwR67FguNc8vaLxzSkA,404
79
83
  connectonion/prompt_files/react_plan.md,sha256=QwEDnHsCs1A9AGTyuA1puLRHT0MkUrNEAbVhF3yWNEc,492
80
84
  connectonion/prompt_files/reflect.md,sha256=aMaWNbHCyxX3AtqyUrrJurAG6w45lcSo05RrAv6UiIM,627
81
- connectonion/static/docs.html,sha256=rSffkCAy2fA512XcMC6z1wyZH9iYeAsSP213G3l1OOk,31085
82
85
  connectonion/tui/__init__.py,sha256=q8N5Z5lfTmRx-g_m6KfEv7IHOMkChz2PquUGP77vwlg,2711
83
86
  connectonion/tui/chat.py,sha256=0vIxfPcf7hWw3pi1mO6AuF4sIEwxKi-Mw25HGnotX80,20941
84
87
  connectonion/tui/divider.py,sha256=pKOj7Y3lPwB4TxoWs9J7Pi1axyzMELuw5TIARLyud0o,1018
@@ -92,13 +95,14 @@ connectonion/tui/providers.py,sha256=czD130jKA9FYUCkLp3eSZ4o7jF7-58uAvCC_9COzApI
92
95
  connectonion/tui/status_bar.py,sha256=DVqDdc6fr9yHDIDGgLGIuR_4yaPzKPM-kAUJ_dXcNAk,4774
93
96
  connectonion/useful_events_handlers/__init__.py,sha256=EMgvTx-MtvMZXtCpyTJkJpSSKJNcTqRKhLmQ8qDoobk,386
94
97
  connectonion/useful_events_handlers/reflect.py,sha256=5ZRkc5t-E9KgU02bp8GsquoTAkYG0x71ygARlxr1-fc,3418
95
- connectonion/useful_plugins/__init__.py,sha256=gWFzMmd5mJjAj_rTGNL4PGZYjEWddZmRD5HlMP81lAQ,1259
98
+ connectonion/useful_plugins/__init__.py,sha256=nqG7B4OtqkTVGOFAF36-K52c_0FzcofHrqsLc9DyXxM,1355
96
99
  connectonion/useful_plugins/calendar_plugin.py,sha256=PoQoOfLcprDDBRrt1Ykzlh2RDiOofIyL7tO-hERkYV8,6004
97
100
  connectonion/useful_plugins/eval.py,sha256=E0bdzVHRQOnJFcF1jxbvPr0AtEcXux7h9ao5uawsXHQ,4940
98
101
  connectonion/useful_plugins/gmail_plugin.py,sha256=xuPR13lnXxn-12zncHPoMNApYJ_zxuoehuavvdGvjvE,5715
99
102
  connectonion/useful_plugins/image_result_formatter.py,sha256=d6ME-bVRiSbXoTvIAnwqMyDkJ-xVExOBqbdG9N4ZASE,5342
100
103
  connectonion/useful_plugins/re_act.py,sha256=aWBj3lr2d6It3XYAOQp0LbQneM9CPXLxQHW16MgJNKM,3011
101
104
  connectonion/useful_plugins/shell_approval.py,sha256=mNPyLcdz8F5Hek77ABGYCdpiefRziyFwc_L8TFVcyoo,6324
105
+ connectonion/useful_plugins/ui_stream.py,sha256=YeS7a0YowUcnhoiffw6uSPlJS7ne5Vkwr_Bbj_6mM_A,4410
102
106
  connectonion/useful_tools/__init__.py,sha256=ZG7DVNNSoY7lvyREXleRzqpp53OjttMSiNMS6uA3F4M,1743
103
107
  connectonion/useful_tools/diff_writer.py,sha256=ZhuSmTvJRd7RmavCRN9Xp-8Q07mBAgV9_HufWd-i9Lc,6796
104
108
  connectonion/useful_tools/get_emails.py,sha256=cechjvRkPH2K-mjoZEnvo1Z6uD1YsVNYQSu56elERm0,6300
@@ -113,7 +117,7 @@ connectonion/useful_tools/slash_command.py,sha256=VKl7SKLyaxHcHwfE8rgzBCQ2-KQtL0
113
117
  connectonion/useful_tools/terminal.py,sha256=PtzGHN6vnWROmssi37YOZ5U-d0Z7Fe79bocoKAngoxg,9330
114
118
  connectonion/useful_tools/todo_list.py,sha256=wVEt4kt-MczIcP3xvKelfshGHZ6EATpDFzQx0zov8cw,7483
115
119
  connectonion/useful_tools/web_fetch.py,sha256=CysJLOdDIkbMVJ12Dj3WgsytLu1-o2wrwNopqA_S1jk,7253
116
- connectonion-0.6.0.dist-info/METADATA,sha256=VgB7VV7LFKUeAfg3Q_VnU9qmQAyFKvQmxEiSUpccIOA,21932
117
- connectonion-0.6.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
118
- connectonion-0.6.0.dist-info/entry_points.txt,sha256=XDB-kVN7Qgy4DmYTkjQB_O6hZeUND-SqmZbdoQPn6WA,90
119
- connectonion-0.6.0.dist-info/RECORD,,
120
+ connectonion-0.6.1.dist-info/METADATA,sha256=UfECn-oR2IqKWVKkgNwbOXKQlt_SymSu7O7pkMoNIR0,21932
121
+ connectonion-0.6.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
122
+ connectonion-0.6.1.dist-info/entry_points.txt,sha256=XDB-kVN7Qgy4DmYTkjQB_O6hZeUND-SqmZbdoQPn6WA,90
123
+ connectonion-0.6.1.dist-info/RECORD,,
File without changes