connectonion 0.5.9__py3-none-any.whl → 0.6.0__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.
Files changed (54) hide show
  1. connectonion/__init__.py +16 -16
  2. connectonion/cli/commands/copy_commands.py +24 -1
  3. connectonion/cli/commands/deploy_commands.py +15 -0
  4. connectonion/cli/commands/project_cmd_lib.py +1 -1
  5. connectonion/core/__init__.py +53 -0
  6. connectonion/{agent.py → core/agent.py} +5 -5
  7. connectonion/{tool_executor.py → core/tool_executor.py} +3 -2
  8. connectonion/{tool_factory.py → core/tool_factory.py} +3 -1
  9. connectonion/debug/__init__.py +51 -0
  10. connectonion/{interactive_debugger.py → debug/auto_debug.py} +7 -7
  11. connectonion/{auto_debug_exception.py → debug/auto_debug_exception.py} +3 -3
  12. connectonion/{debugger_ui.py → debug/auto_debug_ui.py} +1 -1
  13. connectonion/{debug_explainer → debug/debug_explainer}/explain_agent.py +1 -1
  14. connectonion/{debug_explainer → debug/debug_explainer}/explain_context.py +1 -1
  15. connectonion/{execution_analyzer → debug/execution_analyzer}/execution_analysis.py +1 -1
  16. connectonion/debug/runtime_inspector/__init__.py +13 -0
  17. connectonion/{debug_agent → debug/runtime_inspector}/agent.py +1 -1
  18. connectonion/{xray.py → debug/xray.py} +1 -1
  19. connectonion/llm_do.py +1 -1
  20. connectonion/network/__init__.py +34 -0
  21. connectonion/{announce.py → network/announce.py} +1 -1
  22. connectonion/{connect.py → network/connect.py} +1 -1
  23. connectonion/{host.py → network/host.py} +47 -17
  24. connectonion/{trust.py → network/trust.py} +1 -1
  25. connectonion/tui/__init__.py +22 -0
  26. connectonion/tui/chat.py +647 -0
  27. connectonion/useful_events_handlers/reflect.py +2 -2
  28. connectonion/useful_plugins/calendar_plugin.py +2 -2
  29. connectonion/useful_plugins/eval.py +2 -2
  30. connectonion/useful_plugins/gmail_plugin.py +2 -2
  31. connectonion/useful_plugins/image_result_formatter.py +2 -2
  32. connectonion/useful_plugins/re_act.py +2 -2
  33. connectonion/useful_plugins/shell_approval.py +2 -2
  34. {connectonion-0.5.9.dist-info → connectonion-0.6.0.dist-info}/METADATA +4 -3
  35. {connectonion-0.5.9.dist-info → connectonion-0.6.0.dist-info}/RECORD +53 -49
  36. connectonion/debug_agent/__init__.py +0 -13
  37. /connectonion/{events.py → core/events.py} +0 -0
  38. /connectonion/{llm.py → core/llm.py} +0 -0
  39. /connectonion/{tool_registry.py → core/tool_registry.py} +0 -0
  40. /connectonion/{usage.py → core/usage.py} +0 -0
  41. /connectonion/{debug_explainer → debug/debug_explainer}/__init__.py +0 -0
  42. /connectonion/{debug_explainer → debug/debug_explainer}/explainer_prompt.md +0 -0
  43. /connectonion/{debug_explainer → debug/debug_explainer}/root_cause_analysis_prompt.md +0 -0
  44. /connectonion/{decorators.py → debug/decorators.py} +0 -0
  45. /connectonion/{execution_analyzer → debug/execution_analyzer}/__init__.py +0 -0
  46. /connectonion/{execution_analyzer → debug/execution_analyzer}/execution_analysis_prompt.md +0 -0
  47. /connectonion/{debug_agent → debug/runtime_inspector}/prompts/debug_assistant.md +0 -0
  48. /connectonion/{debug_agent → debug/runtime_inspector}/runtime_inspector.py +0 -0
  49. /connectonion/{asgi.py → network/asgi.py} +0 -0
  50. /connectonion/{relay.py → network/relay.py} +0 -0
  51. /connectonion/{trust_agents.py → network/trust_agents.py} +0 -0
  52. /connectonion/{trust_functions.py → network/trust_functions.py} +0 -0
  53. {connectonion-0.5.9.dist-info → connectonion-0.6.0.dist-info}/WHEEL +0 -0
  54. {connectonion-0.5.9.dist-info → connectonion-0.6.0.dist-info}/entry_points.txt +0 -0
@@ -9,7 +9,13 @@ Trust parameter accepts three forms:
9
9
  3. Agent: Custom Agent instance for verification
10
10
 
11
11
  All forms create a trust agent behind the scenes.
12
+
13
+ Worker Isolation:
14
+ Each request gets a fresh deep copy of the agent template.
15
+ This ensures complete isolation - tools with state (like BrowserTool)
16
+ don't interfere between concurrent requests.
12
17
  """
18
+ import copy
13
19
  import hashlib
14
20
  import json
15
21
  import logging
@@ -102,17 +108,18 @@ class SessionStorage:
102
108
 
103
109
  # === Handlers (pure functions) ===
104
110
 
105
- def input_handler(agent, storage: SessionStorage, prompt: str, result_ttl: int,
111
+ def input_handler(agent_template, storage: SessionStorage, prompt: str, result_ttl: int,
106
112
  session: dict | None = None) -> dict:
107
113
  """POST /input
108
114
 
109
115
  Args:
110
- agent: The agent to process the request
116
+ agent_template: The agent template (deep copied per request for isolation)
111
117
  storage: SessionStorage for persisting results
112
118
  prompt: The user's prompt
113
119
  result_ttl: How long to keep the result on server
114
120
  session: Optional conversation session for continuation
115
121
  """
122
+ agent = copy.deepcopy(agent_template)
116
123
  now = time.time()
117
124
 
118
125
  # Get or generate session_id
@@ -170,7 +177,7 @@ def health_handler(agent, start_time: float) -> dict:
170
177
 
171
178
  def info_handler(agent, trust: str) -> dict:
172
179
  """GET /info"""
173
- from . import __version__
180
+ from .. import __version__
174
181
  tools = agent.tools.list_names() if hasattr(agent.tools, "list_names") else []
175
182
  return {
176
183
  "name": agent.name,
@@ -331,7 +338,7 @@ def evaluate_with_trust_agent(trust_agent, prompt: str, identity: str, sig_valid
331
338
  (accepted, reason) tuple
332
339
  """
333
340
  from pydantic import BaseModel
334
- from .llm_do import llm_do
341
+ from ..llm_do import llm_do
335
342
 
336
343
  class TrustDecision(BaseModel):
337
344
  accept: bool
@@ -393,38 +400,53 @@ def admin_sessions_handler() -> dict:
393
400
 
394
401
  # === Entry Point ===
395
402
 
396
- def _create_handlers(agent, result_ttl: int):
397
- """Create handler dict for ASGI app."""
403
+ def _create_handlers(agent_template, result_ttl: int):
404
+ """Create handler dict for ASGI app.
405
+
406
+ Args:
407
+ agent_template: Agent used as template (deep-copied per request for isolation)
408
+ result_ttl: How long to keep results on server in seconds
409
+ """
410
+ def ws_input(prompt: str) -> str:
411
+ agent = copy.deepcopy(agent_template)
412
+ return agent.input(prompt)
413
+
398
414
  return {
399
- "input": lambda storage, prompt, ttl, session=None: input_handler(agent, storage, prompt, ttl, session),
415
+ "input": lambda storage, prompt, ttl, session=None: input_handler(agent_template, storage, prompt, ttl, session),
400
416
  "session": session_handler,
401
417
  "sessions": sessions_handler,
402
- "health": lambda start_time: health_handler(agent, start_time),
403
- "info": lambda trust: info_handler(agent, trust),
418
+ "health": lambda start_time: health_handler(agent_template, start_time),
419
+ "info": lambda trust: info_handler(agent_template, trust),
404
420
  "auth": extract_and_authenticate,
405
- "ws_input": agent.input,
421
+ "ws_input": ws_input,
406
422
  # Admin endpoints (auth required via OPENONION_API_KEY)
407
- "admin_logs": lambda: admin_logs_handler(agent.name),
423
+ "admin_logs": lambda: admin_logs_handler(agent_template.name),
408
424
  "admin_sessions": admin_sessions_handler,
409
425
  }
410
426
 
411
427
 
412
- def _start_relay_background(agent, relay_url: str, addr_data: dict):
428
+ def _start_relay_background(agent_template, relay_url: str, addr_data: dict):
413
429
  """Start relay connection in background thread.
414
430
 
415
431
  The relay connection runs alongside the HTTP server, allowing the agent
416
432
  to be discovered via P2P network while also serving HTTP requests.
433
+
434
+ Args:
435
+ agent_template: Agent used as template (deep-copied per request for isolation)
436
+ relay_url: WebSocket URL for P2P relay
437
+ addr_data: Agent address data (public key, address)
417
438
  """
418
439
  import asyncio
419
440
  import threading
420
441
  from . import announce, relay
421
442
 
422
443
  # Create ANNOUNCE message
423
- summary = agent.system_prompt[:1000] if agent.system_prompt else f"{agent.name} agent"
444
+ summary = agent_template.system_prompt[:1000] if agent_template.system_prompt else f"{agent_template.name} agent"
424
445
  announce_msg = announce.create_announce_message(addr_data, summary, endpoints=[])
425
446
 
426
- # Task handler that routes to agent.input()
447
+ # Task handler - deep copy for each request
427
448
  async def task_handler(prompt: str) -> str:
449
+ agent = copy.deepcopy(agent_template)
428
450
  return agent.input(prompt)
429
451
 
430
452
  async def relay_loop():
@@ -454,8 +476,12 @@ def host(
454
476
  """
455
477
  Host an agent over HTTP/WebSocket with optional P2P relay discovery.
456
478
 
479
+ The agent is used as a template - each request gets a fresh deep copy
480
+ for complete isolation. This ensures tools with state (like BrowserTool)
481
+ don't interfere between concurrent requests.
482
+
457
483
  Args:
458
- agent: Agent to host
484
+ agent: Agent template (deep-copied per request for isolation)
459
485
  port: HTTP port (default: PORT env var or 8000)
460
486
  trust: Trust level, policy, or Agent:
461
487
  - Level: "open", "careful", "strict"
@@ -480,7 +506,7 @@ def host(
480
506
  GET /logs/sessions - Activity sessions (requires OPENONION_API_KEY)
481
507
  """
482
508
  import uvicorn
483
- from . import address
509
+ from .. import address
484
510
 
485
511
  # Use PORT env var if port not specified (for container deployments)
486
512
  if port is None:
@@ -531,8 +557,11 @@ def host(
531
557
  def _make_app(agent, trust: Union[str, "Agent"] = "careful", result_ttl=86400, *, blacklist=None, whitelist=None):
532
558
  """Create ASGI app for external uvicorn/gunicorn usage.
533
559
 
560
+ The agent is used as a template - each request gets a fresh deep copy
561
+ for complete isolation.
562
+
534
563
  Args:
535
- agent: Agent to host
564
+ agent: Agent template (deep-copied per request for isolation)
536
565
  trust: Trust level, policy, or Agent
537
566
  result_ttl: How long to keep results on server in seconds
538
567
  blacklist: Blocked identities
@@ -567,6 +596,7 @@ host.app = _make_app
567
596
  def create_app_compat(agent, storage, trust="careful", result_ttl=86400, *, blacklist=None, whitelist=None):
568
597
  """Create ASGI app (backward-compatible wrapper).
569
598
 
599
+ The agent is used as a template (deep-copied per request for isolation).
570
600
  Prefer using host.app(agent) for new code.
571
601
  """
572
602
  handlers = _create_handlers(agent, result_ttl)
@@ -59,7 +59,7 @@ def create_trust_agent(trust: Union[str, Path, 'Agent', None], api_key: Optional
59
59
  ValueError: If trust level is invalid
60
60
  FileNotFoundError: If trust policy file doesn't exist
61
61
  """
62
- from .agent import Agent # Import here to avoid circular dependency
62
+ from ..core.agent import Agent # Import here to avoid circular dependency
63
63
 
64
64
  # If None, check for environment default
65
65
  if trust is None:
@@ -37,8 +37,20 @@ from .status_bar import StatusBar, SimpleStatusBar, ProgressSegment
37
37
  from .divider import Divider
38
38
  from .pick import pick
39
39
  from .footer import Footer
40
+ from .chat import (
41
+ Chat,
42
+ TriggerAutoComplete,
43
+ ChatStatusBar,
44
+ HintsFooter,
45
+ WelcomeMessage,
46
+ UserMessage,
47
+ AssistantMessage,
48
+ ThinkingIndicator,
49
+ )
50
+ from textual_autocomplete import DropdownItem as CommandItem
40
51
 
41
52
  __all__ = [
53
+ # Rich-based TUI (legacy)
42
54
  "Input",
43
55
  "Dropdown",
44
56
  "DropdownItem",
@@ -54,4 +66,14 @@ __all__ = [
54
66
  "Divider",
55
67
  "pick",
56
68
  "Footer",
69
+ # Textual-based Chat
70
+ "Chat",
71
+ "TriggerAutoComplete",
72
+ "CommandItem",
73
+ "ChatStatusBar",
74
+ "HintsFooter",
75
+ "WelcomeMessage",
76
+ "UserMessage",
77
+ "AssistantMessage",
78
+ "ThinkingIndicator",
57
79
  ]