RC version
This commit is contained in:
@@ -152,6 +152,7 @@ testremote/
|
|||||||
*.db
|
*.db
|
||||||
*.patch
|
*.patch
|
||||||
scratch.py
|
scratch.py
|
||||||
|
connpy.code-workspace
|
||||||
|
|
||||||
# Internal planning and implementation docs
|
# Internal planning and implementation docs
|
||||||
PLAN_CAPA_SERVICIOS.md
|
PLAN_CAPA_SERVICIOS.md
|
||||||
|
|||||||
@@ -17,8 +17,12 @@ The v6 release introduces the **AI Copilot**, an interactive terminal assistant
|
|||||||
## 🤖 AI Copilot (New in v6)
|
## 🤖 AI Copilot (New in v6)
|
||||||
The AI Copilot is deeply integrated into your terminal workflow:
|
The AI Copilot is deeply integrated into your terminal workflow:
|
||||||
- **Terminal Context Awareness**: The Copilot can "see" your screen output, helping you diagnose errors or analyze command results in real-time.
|
- **Terminal Context Awareness**: The Copilot can "see" your screen output, helping you diagnose errors or analyze command results in real-time.
|
||||||
|
- **Dynamic Context Selection**: Flexibly select single, range, or line-based terminal blocks to feed the Copilot, filtering out interactive scrolling garbage automatically (e.g., Cisco IOS/XR scrolling, paginators).
|
||||||
- **Hybrid Multi-Agent System**: Automatically escalates complex tasks between the **Network Engineer** (execution) and the **Network Architect** (strategy).
|
- **Hybrid Multi-Agent System**: Automatically escalates complex tasks between the **Network Engineer** (execution) and the **Network Architect** (strategy).
|
||||||
- **MCP Integration**: Dynamically load tools from external providers (6WIND, AWS, etc.) via the Model Context Protocol.
|
- **MCP Integration**: Dynamically load tools from external providers (6WIND, AWS, etc.) via the Model Context Protocol.
|
||||||
|
- **Flexible Auth & Keyless AI**: Support for advanced LiteLLM credentials (`--engineer-auth` / `--architect-auth`) allowing keyless local models (Ollama), cloud engines (Vertex AI), or custom endpoints.
|
||||||
|
- **Enhanced Session Management**: Uniquely generated sessions, robust pagination, and interactive styling translating prompt themes directly to terminal escapes.
|
||||||
|
- **Semantic Prompt Integration**: Emit standard OSC prompt sequences (`\x1b]133;B`) for real-time remote/web front-end command tracking.
|
||||||
- **Interactive Chat**: Launch with `conn ai` for a collaborative troubleshooting session.
|
- **Interactive Chat**: Launch with `conn ai` for a collaborative troubleshooting session.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -19,8 +19,12 @@ The v6 release introduces the **AI Copilot**, an interactive terminal assistant
|
|||||||
## 🤖 AI Copilot (New in v6)
|
## 🤖 AI Copilot (New in v6)
|
||||||
The AI Copilot is deeply integrated into your terminal workflow:
|
The AI Copilot is deeply integrated into your terminal workflow:
|
||||||
- **Terminal Context Awareness**: The Copilot can "see" your screen output, helping you diagnose errors or analyze command results in real-time.
|
- **Terminal Context Awareness**: The Copilot can "see" your screen output, helping you diagnose errors or analyze command results in real-time.
|
||||||
|
- **Dynamic Context Selection**: Flexibly select single, range, or line-based terminal blocks to feed the Copilot, filtering out interactive scrolling garbage automatically (e.g., Cisco IOS/XR scrolling, paginators).
|
||||||
- **Hybrid Multi-Agent System**: Automatically escalates complex tasks between the **Network Engineer** (execution) and the **Network Architect** (strategy).
|
- **Hybrid Multi-Agent System**: Automatically escalates complex tasks between the **Network Engineer** (execution) and the **Network Architect** (strategy).
|
||||||
- **MCP Integration**: Dynamically load tools from external providers (6WIND, AWS, etc.) via the Model Context Protocol.
|
- **MCP Integration**: Dynamically load tools from external providers (6WIND, AWS, etc.) via the Model Context Protocol.
|
||||||
|
- **Flexible Auth & Keyless AI**: Support for advanced LiteLLM credentials (`--engineer-auth` / `--architect-auth`) allowing keyless local models (Ollama), cloud engines (Vertex AI), or custom endpoints.
|
||||||
|
- **Enhanced Session Management**: Uniquely generated sessions, robust pagination, and interactive styling translating prompt themes directly to terminal escapes.
|
||||||
|
- **Semantic Prompt Integration**: Emit standard OSC prompt sequences (`\x1b]133;B`) for real-time remote/web front-end command tracking.
|
||||||
- **Interactive Chat**: Launch with `conn ai` for a collaborative troubleshooting session.
|
- **Interactive Chat**: Launch with `conn ai` for a collaborative troubleshooting session.
|
||||||
|
|
||||||
|
|
||||||
@@ -203,5 +207,7 @@ __pdoc__ = {
|
|||||||
'nodes.deferred_class_hooks': False,
|
'nodes.deferred_class_hooks': False,
|
||||||
'connapp': False,
|
'connapp': False,
|
||||||
'connapp.encrypt': True,
|
'connapp.encrypt': True,
|
||||||
'printer': False
|
'printer': False,
|
||||||
|
'tests': False
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
__version__ = "6.0.0b11"
|
__version__ = "6.0.0b12"
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import pytest
|
||||||
|
from connpy.utils import log_cleaner
|
||||||
|
|
||||||
|
def test_log_cleaner_empty():
|
||||||
|
assert log_cleaner("") == ""
|
||||||
|
assert log_cleaner(None) == ""
|
||||||
|
|
||||||
|
def test_log_cleaner_plain_text():
|
||||||
|
assert log_cleaner("hello world") == "hello world"
|
||||||
|
|
||||||
|
def test_log_cleaner_ansi_colors():
|
||||||
|
# \x1b[31m is red, \x1b[0m is reset
|
||||||
|
assert log_cleaner("\x1b[31mhello\x1b[0m world") == "hello world"
|
||||||
|
|
||||||
|
def test_log_cleaner_osc_window_title():
|
||||||
|
# Set window title OSC: \x1b]0;my title\x07 followed by prompt
|
||||||
|
sample = "\x1b]0;fluzzi32@norman: ~\x07fluzzi32@norman:~$"
|
||||||
|
assert log_cleaner(sample) == "fluzzi32@norman:~$"
|
||||||
|
|
||||||
|
def test_log_cleaner_osc_with_st_terminator():
|
||||||
|
# OSC can also be terminated by \x1b\\ (ST)
|
||||||
|
sample = "\x1b]0;some title\x1b\\my_prompt>"
|
||||||
|
assert log_cleaner(sample) == "my_prompt>"
|
||||||
|
|
||||||
|
def test_log_cleaner_mixed_ansi_and_osc():
|
||||||
|
sample = "\x1b]0;title\x07\x1b[32muser@host\x1b[0m:\x1b[34m/path\x1b[0m$ "
|
||||||
|
assert log_cleaner(sample) == "user@host:/path$"
|
||||||
|
|
||||||
|
def test_log_cleaner_carriage_return_and_backspace():
|
||||||
|
# Test that standard control sequences like \r and \b still work as expected
|
||||||
|
assert log_cleaner("hello\rworld") == "world"
|
||||||
|
assert log_cleaner("hell\bo") == "helo"
|
||||||
@@ -7,6 +7,9 @@ def log_cleaner(data: str) -> str:
|
|||||||
if not data:
|
if not data:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
# Remove OSC (Operating System Command) sequences (e.g., set window title \x1b]0;...\x07)
|
||||||
|
data = re.sub(r'\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)', '', data)
|
||||||
|
|
||||||
lines = data.split('\n')
|
lines = data.split('\n')
|
||||||
cleaned_lines = []
|
cleaned_lines = []
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.cli.ai_handler API documentation</title>
|
<title>connpy.cli.ai_handler API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -61,13 +61,22 @@ el.replaceWith(d);
|
|||||||
|
|
||||||
def dispatch(self, args):
|
def dispatch(self, args):
|
||||||
if args.list_sessions:
|
if args.list_sessions:
|
||||||
sessions = self.app.services.ai.list_sessions()
|
limit = 20 if not getattr(args, "all", False) else None
|
||||||
|
sessions, total = self.app.services.ai.list_sessions(limit=limit)
|
||||||
if not sessions:
|
if not sessions:
|
||||||
printer.info("No saved AI sessions found.")
|
printer.info("No saved AI sessions found.")
|
||||||
return
|
return
|
||||||
|
|
||||||
columns = ["ID", "Title", "Created At", "Model"]
|
columns = ["ID", "Title", "Created At", "Model"]
|
||||||
rows = [[s["id"], s["title"], s["created_at"], s["model"]] for s in sessions]
|
rows = [[s["id"], s["title"], s["created_at"], s["model"]] for s in sessions]
|
||||||
printer.table("AI Persisted Sessions", columns, rows)
|
|
||||||
|
title = "AI Persisted Sessions"
|
||||||
|
if limit and total > limit:
|
||||||
|
title += f" (Showing last {limit} of {total})"
|
||||||
|
|
||||||
|
printer.table(title, columns, rows)
|
||||||
|
if limit and total > limit:
|
||||||
|
printer.info(f"Use '--list --all' to see all {total} sessions.")
|
||||||
return
|
return
|
||||||
|
|
||||||
if args.delete_session:
|
if args.delete_session:
|
||||||
@@ -84,7 +93,7 @@ el.replaceWith(d);
|
|||||||
# Determinar session_id para retomar
|
# Determinar session_id para retomar
|
||||||
session_id = None
|
session_id = None
|
||||||
if args.resume:
|
if args.resume:
|
||||||
sessions = self.app.services.ai.list_sessions()
|
sessions, _ = self.app.services.ai.list_sessions()
|
||||||
session_id = sessions[0]["id"] if sessions else None
|
session_id = sessions[0]["id"] if sessions else None
|
||||||
if not session_id:
|
if not session_id:
|
||||||
printer.warning("No previous session found to resume.")
|
printer.warning("No previous session found to resume.")
|
||||||
@@ -102,16 +111,23 @@ el.replaceWith(d);
|
|||||||
arguments[key] = cli_val[0]
|
arguments[key] = cli_val[0]
|
||||||
elif settings.get(key):
|
elif settings.get(key):
|
||||||
arguments[key] = settings.get(key)
|
arguments[key] = settings.get(key)
|
||||||
|
|
||||||
|
for key in ["engineer_auth", "architect_auth"]:
|
||||||
|
cli_val = getattr(args, key, None)
|
||||||
|
if cli_val:
|
||||||
|
arguments[key] = self._parse_auth_value(cli_val[0])
|
||||||
|
elif settings.get(key):
|
||||||
|
arguments[key] = settings.get(key)
|
||||||
|
|
||||||
# Check keys only if running in local mode (not remote)
|
# Check keys only if running in local mode (not remote)
|
||||||
if getattr(self.app.services, "mode", "local") == "local":
|
if getattr(self.app.services, "mode", "local") == "local":
|
||||||
if not arguments.get("engineer_api_key"):
|
if not arguments.get("engineer_api_key") and not arguments.get("engineer_auth"):
|
||||||
printer.error("Engineer API key not configured. The chat cannot start.")
|
printer.error("Engineer API key/auth not configured. The chat cannot start.")
|
||||||
printer.info("Use 'connpy config --engineer-api-key <key>' to set it.")
|
printer.info("Use 'connpy config --engineer-api-key <key>' or 'connpy config --engineer-auth <auth>' to set it.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if not arguments.get("architect_api_key"):
|
if not arguments.get("architect_api_key") and not arguments.get("architect_auth"):
|
||||||
printer.warning("Architect API key not configured. Architect will be unavailable.")
|
printer.warning("Architect API key/auth not configured. Architect will be unavailable.")
|
||||||
printer.info("Use 'connpy config --architect-api-key <key>' to enable it.")
|
printer.info("Use 'connpy config --architect-api-key <key>' or 'connpy config --architect-auth <auth>' to enable it.")
|
||||||
|
|
||||||
# El resto de la interacción el CLI la maneja con el agente subyacente
|
# El resto de la interacción el CLI la maneja con el agente subyacente
|
||||||
self.app.myai = self.app.services.ai
|
self.app.myai = self.app.services.ai
|
||||||
@@ -148,7 +164,7 @@ el.replaceWith(d);
|
|||||||
if history:
|
if history:
|
||||||
mdprint(f"[debug]Analyzing {len(history)} previous messages...[/debug]\n")
|
mdprint(f"[debug]Analyzing {len(history)} previous messages...[/debug]\n")
|
||||||
else:
|
else:
|
||||||
printer.error(f"Could not load session {session_id}. Starting clean.")
|
printer.info(f"Session '{session_id}' not found. Starting clean.")
|
||||||
|
|
||||||
if not history:
|
if not history:
|
||||||
mdprint(Rule(style="engineer"))
|
mdprint(Rule(style="engineer"))
|
||||||
@@ -162,7 +178,7 @@ el.replaceWith(d);
|
|||||||
if user_query.lower() in ['exit', 'quit', 'bye', 'cancel']: break
|
if user_query.lower() in ['exit', 'quit', 'bye', 'cancel']: break
|
||||||
|
|
||||||
with console.status("[ai_status]Agent is thinking...") as status:
|
with console.status("[ai_status]Agent is thinking...") as status:
|
||||||
result = self.app.myai.ask(user_query, chat_history=history, status=status, debug=args.debug, trust=args.trust, **self.ai_overrides)
|
result = self.app.myai.ask(user_query, chat_history=history, status=status, debug=args.debug, trust=args.trust, session_id=session_id, **self.ai_overrides)
|
||||||
|
|
||||||
new_history = result.get("chat_history")
|
new_history = result.get("chat_history")
|
||||||
if new_history is not None:
|
if new_history is not None:
|
||||||
@@ -193,8 +209,7 @@ el.replaceWith(d);
|
|||||||
action = mcp_args[0].lower()
|
action = mcp_args[0].lower()
|
||||||
|
|
||||||
if action == "list":
|
if action == "list":
|
||||||
settings = self.app.services.config_svc.get_settings()
|
mcp_servers = self.app.services.ai.list_mcp_servers()
|
||||||
mcp_servers = settings.get("ai", {}).get("mcp_servers", {})
|
|
||||||
if not mcp_servers:
|
if not mcp_servers:
|
||||||
printer.info("No MCP servers configured.")
|
printer.info("No MCP servers configured.")
|
||||||
else:
|
else:
|
||||||
@@ -259,8 +274,7 @@ el.replaceWith(d);
|
|||||||
from .forms import Forms
|
from .forms import Forms
|
||||||
self.app.cli_forms = Forms(self.app)
|
self.app.cli_forms = Forms(self.app)
|
||||||
|
|
||||||
settings = self.app.services.config_svc.get_settings()
|
mcp_servers = self.app.services.ai.list_mcp_servers()
|
||||||
mcp_servers = settings.get("ai", {}).get("mcp_servers", {})
|
|
||||||
|
|
||||||
result = self.app.cli_forms.mcp_wizard(mcp_servers)
|
result = self.app.cli_forms.mcp_wizard(mcp_servers)
|
||||||
if not result:
|
if not result:
|
||||||
@@ -294,7 +308,37 @@ el.replaceWith(d);
|
|||||||
printer.success(f"MCP server '{result['name']}' removed.")
|
printer.success(f"MCP server '{result['name']}' removed.")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
printer.error(str(e))</code></pre>
|
printer.error(str(e))
|
||||||
|
|
||||||
|
def _parse_auth_value(self, value):
|
||||||
|
if not value or value.lower() in ["none", "clear"]:
|
||||||
|
return None
|
||||||
|
import os
|
||||||
|
import yaml
|
||||||
|
import json
|
||||||
|
if os.path.exists(value):
|
||||||
|
try:
|
||||||
|
with open(value, "r") as f:
|
||||||
|
content = f.read()
|
||||||
|
try:
|
||||||
|
return json.loads(content)
|
||||||
|
except ValueError:
|
||||||
|
return yaml.safe_load(content)
|
||||||
|
except Exception as e:
|
||||||
|
printer.error(f"Failed to read/parse auth file '{value}': {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return json.loads(value)
|
||||||
|
except ValueError:
|
||||||
|
try:
|
||||||
|
parsed = yaml.safe_load(value)
|
||||||
|
if isinstance(parsed, dict):
|
||||||
|
return parsed
|
||||||
|
raise ValueError()
|
||||||
|
except Exception:
|
||||||
|
printer.error("Auth parameter must be a valid JSON/YAML string, or a path to a JSON/YAML file.")
|
||||||
|
sys.exit(1)</code></pre>
|
||||||
</details>
|
</details>
|
||||||
<div class="desc"></div>
|
<div class="desc"></div>
|
||||||
<h3>Methods</h3>
|
<h3>Methods</h3>
|
||||||
@@ -316,8 +360,7 @@ el.replaceWith(d);
|
|||||||
action = mcp_args[0].lower()
|
action = mcp_args[0].lower()
|
||||||
|
|
||||||
if action == "list":
|
if action == "list":
|
||||||
settings = self.app.services.config_svc.get_settings()
|
mcp_servers = self.app.services.ai.list_mcp_servers()
|
||||||
mcp_servers = settings.get("ai", {}).get("mcp_servers", {})
|
|
||||||
if not mcp_servers:
|
if not mcp_servers:
|
||||||
printer.info("No MCP servers configured.")
|
printer.info("No MCP servers configured.")
|
||||||
else:
|
else:
|
||||||
@@ -382,8 +425,7 @@ el.replaceWith(d);
|
|||||||
from .forms import Forms
|
from .forms import Forms
|
||||||
self.app.cli_forms = Forms(self.app)
|
self.app.cli_forms = Forms(self.app)
|
||||||
|
|
||||||
settings = self.app.services.config_svc.get_settings()
|
mcp_servers = self.app.services.ai.list_mcp_servers()
|
||||||
mcp_servers = settings.get("ai", {}).get("mcp_servers", {})
|
|
||||||
|
|
||||||
result = self.app.cli_forms.mcp_wizard(mcp_servers)
|
result = self.app.cli_forms.mcp_wizard(mcp_servers)
|
||||||
if not result:
|
if not result:
|
||||||
@@ -431,13 +473,22 @@ el.replaceWith(d);
|
|||||||
</summary>
|
</summary>
|
||||||
<pre><code class="python">def dispatch(self, args):
|
<pre><code class="python">def dispatch(self, args):
|
||||||
if args.list_sessions:
|
if args.list_sessions:
|
||||||
sessions = self.app.services.ai.list_sessions()
|
limit = 20 if not getattr(args, "all", False) else None
|
||||||
|
sessions, total = self.app.services.ai.list_sessions(limit=limit)
|
||||||
if not sessions:
|
if not sessions:
|
||||||
printer.info("No saved AI sessions found.")
|
printer.info("No saved AI sessions found.")
|
||||||
return
|
return
|
||||||
|
|
||||||
columns = ["ID", "Title", "Created At", "Model"]
|
columns = ["ID", "Title", "Created At", "Model"]
|
||||||
rows = [[s["id"], s["title"], s["created_at"], s["model"]] for s in sessions]
|
rows = [[s["id"], s["title"], s["created_at"], s["model"]] for s in sessions]
|
||||||
printer.table("AI Persisted Sessions", columns, rows)
|
|
||||||
|
title = "AI Persisted Sessions"
|
||||||
|
if limit and total > limit:
|
||||||
|
title += f" (Showing last {limit} of {total})"
|
||||||
|
|
||||||
|
printer.table(title, columns, rows)
|
||||||
|
if limit and total > limit:
|
||||||
|
printer.info(f"Use '--list --all' to see all {total} sessions.")
|
||||||
return
|
return
|
||||||
|
|
||||||
if args.delete_session:
|
if args.delete_session:
|
||||||
@@ -454,7 +505,7 @@ el.replaceWith(d);
|
|||||||
# Determinar session_id para retomar
|
# Determinar session_id para retomar
|
||||||
session_id = None
|
session_id = None
|
||||||
if args.resume:
|
if args.resume:
|
||||||
sessions = self.app.services.ai.list_sessions()
|
sessions, _ = self.app.services.ai.list_sessions()
|
||||||
session_id = sessions[0]["id"] if sessions else None
|
session_id = sessions[0]["id"] if sessions else None
|
||||||
if not session_id:
|
if not session_id:
|
||||||
printer.warning("No previous session found to resume.")
|
printer.warning("No previous session found to resume.")
|
||||||
@@ -472,16 +523,23 @@ el.replaceWith(d);
|
|||||||
arguments[key] = cli_val[0]
|
arguments[key] = cli_val[0]
|
||||||
elif settings.get(key):
|
elif settings.get(key):
|
||||||
arguments[key] = settings.get(key)
|
arguments[key] = settings.get(key)
|
||||||
|
|
||||||
|
for key in ["engineer_auth", "architect_auth"]:
|
||||||
|
cli_val = getattr(args, key, None)
|
||||||
|
if cli_val:
|
||||||
|
arguments[key] = self._parse_auth_value(cli_val[0])
|
||||||
|
elif settings.get(key):
|
||||||
|
arguments[key] = settings.get(key)
|
||||||
|
|
||||||
# Check keys only if running in local mode (not remote)
|
# Check keys only if running in local mode (not remote)
|
||||||
if getattr(self.app.services, "mode", "local") == "local":
|
if getattr(self.app.services, "mode", "local") == "local":
|
||||||
if not arguments.get("engineer_api_key"):
|
if not arguments.get("engineer_api_key") and not arguments.get("engineer_auth"):
|
||||||
printer.error("Engineer API key not configured. The chat cannot start.")
|
printer.error("Engineer API key/auth not configured. The chat cannot start.")
|
||||||
printer.info("Use 'connpy config --engineer-api-key <key>' to set it.")
|
printer.info("Use 'connpy config --engineer-api-key <key>' or 'connpy config --engineer-auth <auth>' to set it.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if not arguments.get("architect_api_key"):
|
if not arguments.get("architect_api_key") and not arguments.get("architect_auth"):
|
||||||
printer.warning("Architect API key not configured. Architect will be unavailable.")
|
printer.warning("Architect API key/auth not configured. Architect will be unavailable.")
|
||||||
printer.info("Use 'connpy config --architect-api-key <key>' to enable it.")
|
printer.info("Use 'connpy config --architect-api-key <key>' or 'connpy config --architect-auth <auth>' to enable it.")
|
||||||
|
|
||||||
# El resto de la interacción el CLI la maneja con el agente subyacente
|
# El resto de la interacción el CLI la maneja con el agente subyacente
|
||||||
self.app.myai = self.app.services.ai
|
self.app.myai = self.app.services.ai
|
||||||
@@ -512,7 +570,7 @@ el.replaceWith(d);
|
|||||||
if history:
|
if history:
|
||||||
mdprint(f"[debug]Analyzing {len(history)} previous messages...[/debug]\n")
|
mdprint(f"[debug]Analyzing {len(history)} previous messages...[/debug]\n")
|
||||||
else:
|
else:
|
||||||
printer.error(f"Could not load session {session_id}. Starting clean.")
|
printer.info(f"Session '{session_id}' not found. Starting clean.")
|
||||||
|
|
||||||
if not history:
|
if not history:
|
||||||
mdprint(Rule(style="engineer"))
|
mdprint(Rule(style="engineer"))
|
||||||
@@ -526,7 +584,7 @@ el.replaceWith(d);
|
|||||||
if user_query.lower() in ['exit', 'quit', 'bye', 'cancel']: break
|
if user_query.lower() in ['exit', 'quit', 'bye', 'cancel']: break
|
||||||
|
|
||||||
with console.status("[ai_status]Agent is thinking...") as status:
|
with console.status("[ai_status]Agent is thinking...") as status:
|
||||||
result = self.app.myai.ask(user_query, chat_history=history, status=status, debug=args.debug, trust=args.trust, **self.ai_overrides)
|
result = self.app.myai.ask(user_query, chat_history=history, status=status, debug=args.debug, trust=args.trust, session_id=session_id, **self.ai_overrides)
|
||||||
|
|
||||||
new_history = result.get("chat_history")
|
new_history = result.get("chat_history")
|
||||||
if new_history is not None:
|
if new_history is not None:
|
||||||
@@ -608,7 +666,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.cli.api_handler API documentation</title>
|
<title>connpy.cli.api_handler API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -193,7 +193,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.cli.config_handler API documentation</title>
|
<title>connpy.cli.config_handler API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -70,8 +70,10 @@ el.replaceWith(d);
|
|||||||
"theme": self.set_theme,
|
"theme": self.set_theme,
|
||||||
"engineer_model": self.set_ai_config,
|
"engineer_model": self.set_ai_config,
|
||||||
"engineer_api_key": self.set_ai_config,
|
"engineer_api_key": self.set_ai_config,
|
||||||
|
"engineer_auth": self.set_ai_config,
|
||||||
"architect_model": self.set_ai_config,
|
"architect_model": self.set_ai_config,
|
||||||
"architect_api_key": self.set_ai_config,
|
"architect_api_key": self.set_ai_config,
|
||||||
|
"architect_auth": self.set_ai_config,
|
||||||
"trusted_commands": self.set_ai_config,
|
"trusted_commands": self.set_ai_config,
|
||||||
"service_mode": self.set_service_mode,
|
"service_mode": self.set_service_mode,
|
||||||
"remote_host": self.set_remote_host,
|
"remote_host": self.set_remote_host,
|
||||||
@@ -178,11 +180,59 @@ el.replaceWith(d);
|
|||||||
try:
|
try:
|
||||||
settings = self.app.services.config_svc.get_settings()
|
settings = self.app.services.config_svc.get_settings()
|
||||||
aiconfig = settings.get("ai", {})
|
aiconfig = settings.get("ai", {})
|
||||||
aiconfig[args.command] = args.data[0]
|
val = args.data[0]
|
||||||
|
|
||||||
|
# Check for unset/clear request
|
||||||
|
if val.lower() in ["none", "clear", ""]:
|
||||||
|
if args.command in aiconfig:
|
||||||
|
del aiconfig[args.command]
|
||||||
|
else:
|
||||||
|
# If configuring auth, parse as dictionary (JSON/YAML or file path)
|
||||||
|
if args.command in ["engineer_auth", "architect_auth"]:
|
||||||
|
parsed_val = self._parse_auth_value(val)
|
||||||
|
if parsed_val is not None:
|
||||||
|
aiconfig[args.command] = parsed_val
|
||||||
|
else:
|
||||||
|
if args.command in aiconfig:
|
||||||
|
del aiconfig[args.command]
|
||||||
|
else:
|
||||||
|
aiconfig[args.command] = val
|
||||||
|
|
||||||
self.app.services.config_svc.update_setting("ai", aiconfig)
|
self.app.services.config_svc.update_setting("ai", aiconfig)
|
||||||
printer.success("Config saved")
|
printer.success("Config saved")
|
||||||
except ConnpyError as e:
|
except (ConnpyError, InvalidConfigurationError) as e:
|
||||||
printer.error(str(e))</code></pre>
|
printer.error(str(e))
|
||||||
|
|
||||||
|
def _parse_auth_value(self, value):
|
||||||
|
if value.lower() in ["none", "clear", ""]:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Check if it's a file path
|
||||||
|
import os
|
||||||
|
if os.path.exists(value):
|
||||||
|
try:
|
||||||
|
with open(value, "r") as f:
|
||||||
|
content = f.read()
|
||||||
|
import json
|
||||||
|
try:
|
||||||
|
return json.loads(content)
|
||||||
|
except ValueError:
|
||||||
|
return yaml.safe_load(content)
|
||||||
|
except Exception as e:
|
||||||
|
raise InvalidConfigurationError(f"Failed to read/parse auth file '{value}': {e}")
|
||||||
|
|
||||||
|
# Try parsing as inline JSON/YAML
|
||||||
|
try:
|
||||||
|
import json
|
||||||
|
return json.loads(value)
|
||||||
|
except ValueError:
|
||||||
|
try:
|
||||||
|
parsed = yaml.safe_load(value)
|
||||||
|
if isinstance(parsed, dict):
|
||||||
|
return parsed
|
||||||
|
raise ValueError()
|
||||||
|
except Exception:
|
||||||
|
raise InvalidConfigurationError("Auth parameter must be a valid JSON/YAML string, or a path to a JSON/YAML file.")</code></pre>
|
||||||
</details>
|
</details>
|
||||||
<div class="desc"></div>
|
<div class="desc"></div>
|
||||||
<h3>Methods</h3>
|
<h3>Methods</h3>
|
||||||
@@ -206,8 +256,10 @@ el.replaceWith(d);
|
|||||||
"theme": self.set_theme,
|
"theme": self.set_theme,
|
||||||
"engineer_model": self.set_ai_config,
|
"engineer_model": self.set_ai_config,
|
||||||
"engineer_api_key": self.set_ai_config,
|
"engineer_api_key": self.set_ai_config,
|
||||||
|
"engineer_auth": self.set_ai_config,
|
||||||
"architect_model": self.set_ai_config,
|
"architect_model": self.set_ai_config,
|
||||||
"architect_api_key": self.set_ai_config,
|
"architect_api_key": self.set_ai_config,
|
||||||
|
"architect_auth": self.set_ai_config,
|
||||||
"trusted_commands": self.set_ai_config,
|
"trusted_commands": self.set_ai_config,
|
||||||
"service_mode": self.set_service_mode,
|
"service_mode": self.set_service_mode,
|
||||||
"remote_host": self.set_remote_host,
|
"remote_host": self.set_remote_host,
|
||||||
@@ -234,10 +286,27 @@ el.replaceWith(d);
|
|||||||
try:
|
try:
|
||||||
settings = self.app.services.config_svc.get_settings()
|
settings = self.app.services.config_svc.get_settings()
|
||||||
aiconfig = settings.get("ai", {})
|
aiconfig = settings.get("ai", {})
|
||||||
aiconfig[args.command] = args.data[0]
|
val = args.data[0]
|
||||||
|
|
||||||
|
# Check for unset/clear request
|
||||||
|
if val.lower() in ["none", "clear", ""]:
|
||||||
|
if args.command in aiconfig:
|
||||||
|
del aiconfig[args.command]
|
||||||
|
else:
|
||||||
|
# If configuring auth, parse as dictionary (JSON/YAML or file path)
|
||||||
|
if args.command in ["engineer_auth", "architect_auth"]:
|
||||||
|
parsed_val = self._parse_auth_value(val)
|
||||||
|
if parsed_val is not None:
|
||||||
|
aiconfig[args.command] = parsed_val
|
||||||
|
else:
|
||||||
|
if args.command in aiconfig:
|
||||||
|
del aiconfig[args.command]
|
||||||
|
else:
|
||||||
|
aiconfig[args.command] = val
|
||||||
|
|
||||||
self.app.services.config_svc.update_setting("ai", aiconfig)
|
self.app.services.config_svc.update_setting("ai", aiconfig)
|
||||||
printer.success("Config saved")
|
printer.success("Config saved")
|
||||||
except ConnpyError as e:
|
except (ConnpyError, InvalidConfigurationError) as e:
|
||||||
printer.error(str(e))</code></pre>
|
printer.error(str(e))</code></pre>
|
||||||
</details>
|
</details>
|
||||||
<div class="desc"></div>
|
<div class="desc"></div>
|
||||||
@@ -482,7 +551,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.cli.context_handler API documentation</title>
|
<title>connpy.cli.context_handler API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -249,7 +249,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.cli.forms API documentation</title>
|
<title>connpy.cli.forms API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -690,7 +690,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.cli.help_text API documentation</title>
|
<title>connpy.cli.help_text API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -303,7 +303,7 @@ tasks:
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.cli.helpers API documentation</title>
|
<title>connpy.cli.helpers API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -69,7 +69,7 @@ el.replaceWith(d);
|
|||||||
return answer[0]
|
return answer[0]
|
||||||
else:
|
else:
|
||||||
questions = [inquirer.List(name, message="Pick {} to {}:".format(name,action), choices=list_, carousel=True)]
|
questions = [inquirer.List(name, message="Pick {} to {}:".format(name,action), choices=list_, carousel=True)]
|
||||||
answer = inquirer.prompt(questions)
|
answer = inquirer.prompt(questions, theme=theme)
|
||||||
if answer == None:
|
if answer == None:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
@@ -115,6 +115,65 @@ el.replaceWith(d);
|
|||||||
</details>
|
</details>
|
||||||
<div class="desc"></div>
|
<div class="desc"></div>
|
||||||
</dd>
|
</dd>
|
||||||
|
<dt id="connpy.cli.helpers.get_theme"><code class="name flex">
|
||||||
|
<span>def <span class="ident">get_theme</span></span>(<span>)</span>
|
||||||
|
</code></dt>
|
||||||
|
<dd>
|
||||||
|
<details class="source">
|
||||||
|
<summary>
|
||||||
|
<span>Expand source code</span>
|
||||||
|
</summary>
|
||||||
|
<pre><code class="python">def get_theme():
|
||||||
|
"""Returns a fresh instance of the theme with current colors."""
|
||||||
|
return ConnpyTheme()</code></pre>
|
||||||
|
</details>
|
||||||
|
<div class="desc"><p>Returns a fresh instance of the theme with current colors.</p></div>
|
||||||
|
</dd>
|
||||||
|
<dt id="connpy.cli.helpers.hex_to_blessed"><code class="name flex">
|
||||||
|
<span>def <span class="ident">hex_to_blessed</span></span>(<span>hex_str)</span>
|
||||||
|
</code></dt>
|
||||||
|
<dd>
|
||||||
|
<details class="source">
|
||||||
|
<summary>
|
||||||
|
<span>Expand source code</span>
|
||||||
|
</summary>
|
||||||
|
<pre><code class="python">def hex_to_blessed(hex_str):
|
||||||
|
"""Convert hex color string to blessed/ansi format."""
|
||||||
|
if not hex_str or not isinstance(hex_str, str):
|
||||||
|
return term.normal
|
||||||
|
|
||||||
|
# Check for bold prefix
|
||||||
|
prefix = ""
|
||||||
|
if hex_str.startswith('bold '):
|
||||||
|
prefix = term.bold
|
||||||
|
hex_str = hex_str.replace('bold ', '').strip()
|
||||||
|
|
||||||
|
# If it's a standard color name
|
||||||
|
if not hex_str.startswith('#'):
|
||||||
|
return prefix + getattr(term, hex_str, term.normal)
|
||||||
|
|
||||||
|
# Parse hex
|
||||||
|
try:
|
||||||
|
h = hex_str.lstrip('#')
|
||||||
|
if len(h) == 3:
|
||||||
|
h = ''.join([c*2 for c in h])
|
||||||
|
r = int(h[0:2], 16)
|
||||||
|
g = int(h[2:4], 16)
|
||||||
|
b = int(h[4:6], 16)
|
||||||
|
|
||||||
|
# Try RGB, fallback to standard cyan if it fails or returns empty
|
||||||
|
try:
|
||||||
|
c = term.color_rgb(r, g, b)
|
||||||
|
if not c: # Some terms return empty for RGB
|
||||||
|
return prefix + term.cyan
|
||||||
|
return prefix + c
|
||||||
|
except:
|
||||||
|
return prefix + term.cyan
|
||||||
|
except:
|
||||||
|
return prefix + term.normal</code></pre>
|
||||||
|
</details>
|
||||||
|
<div class="desc"><p>Convert hex color string to blessed/ansi format.</p></div>
|
||||||
|
</dd>
|
||||||
<dt id="connpy.cli.helpers.nodes_completer"><code class="name flex">
|
<dt id="connpy.cli.helpers.nodes_completer"><code class="name flex">
|
||||||
<span>def <span class="ident">nodes_completer</span></span>(<span>prefix, parsed_args, **kwargs)</span>
|
<span>def <span class="ident">nodes_completer</span></span>(<span>prefix, parsed_args, **kwargs)</span>
|
||||||
</code></dt>
|
</code></dt>
|
||||||
@@ -181,6 +240,61 @@ el.replaceWith(d);
|
|||||||
</dl>
|
</dl>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
|
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||||
|
<dl>
|
||||||
|
<dt id="connpy.cli.helpers.ConnpyTheme"><code class="flex name class">
|
||||||
|
<span>class <span class="ident">ConnpyTheme</span></span>
|
||||||
|
</code></dt>
|
||||||
|
<dd>
|
||||||
|
<details class="source">
|
||||||
|
<summary>
|
||||||
|
<span>Expand source code</span>
|
||||||
|
</summary>
|
||||||
|
<pre><code class="python">class ConnpyTheme(Default):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
try:
|
||||||
|
from ..printer import _global_active_styles
|
||||||
|
# Use user_prompt as primary accent, fallback to info/cyan
|
||||||
|
accent = _global_active_styles.get("user_prompt", _global_active_styles.get("info", "cyan"))
|
||||||
|
accent_color = hex_to_blessed(accent)
|
||||||
|
|
||||||
|
self.Question.mark_color = accent_color
|
||||||
|
self.List.selection_color = accent_color
|
||||||
|
self.List.selection_cursor = ">"
|
||||||
|
except:
|
||||||
|
# Absolute fallback to standard cyan
|
||||||
|
self.Question.mark_color = term.cyan
|
||||||
|
self.List.selection_color = term.bold_cyan
|
||||||
|
self.List.selection_cursor = ">"</code></pre>
|
||||||
|
</details>
|
||||||
|
<div class="desc"></div>
|
||||||
|
<h3>Ancestors</h3>
|
||||||
|
<ul class="hlist">
|
||||||
|
<li>inquirer.themes.Default</li>
|
||||||
|
<li>inquirer.themes.Theme</li>
|
||||||
|
</ul>
|
||||||
|
</dd>
|
||||||
|
<dt id="connpy.cli.helpers.ThemeProxy"><code class="flex name class">
|
||||||
|
<span>class <span class="ident">ThemeProxy</span></span>
|
||||||
|
</code></dt>
|
||||||
|
<dd>
|
||||||
|
<details class="source">
|
||||||
|
<summary>
|
||||||
|
<span>Expand source code</span>
|
||||||
|
</summary>
|
||||||
|
<pre><code class="python">class ThemeProxy:
|
||||||
|
"""Proxy to ensure theme colors are resolved at runtime."""
|
||||||
|
def __getattr__(self, name):
|
||||||
|
return getattr(get_theme(), name)
|
||||||
|
def __iter__(self):
|
||||||
|
return iter(get_theme())
|
||||||
|
def __getitem__(self, item):
|
||||||
|
return get_theme()[item]</code></pre>
|
||||||
|
</details>
|
||||||
|
<div class="desc"><p>Proxy to ensure theme colors are resolved at runtime.</p></div>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
</section>
|
</section>
|
||||||
</article>
|
</article>
|
||||||
<nav id="sidebar">
|
<nav id="sidebar">
|
||||||
@@ -198,16 +312,28 @@ el.replaceWith(d);
|
|||||||
<li><code><a title="connpy.cli.helpers.choose" href="#connpy.cli.helpers.choose">choose</a></code></li>
|
<li><code><a title="connpy.cli.helpers.choose" href="#connpy.cli.helpers.choose">choose</a></code></li>
|
||||||
<li><code><a title="connpy.cli.helpers.folders_completer" href="#connpy.cli.helpers.folders_completer">folders_completer</a></code></li>
|
<li><code><a title="connpy.cli.helpers.folders_completer" href="#connpy.cli.helpers.folders_completer">folders_completer</a></code></li>
|
||||||
<li><code><a title="connpy.cli.helpers.get_config_dir" href="#connpy.cli.helpers.get_config_dir">get_config_dir</a></code></li>
|
<li><code><a title="connpy.cli.helpers.get_config_dir" href="#connpy.cli.helpers.get_config_dir">get_config_dir</a></code></li>
|
||||||
|
<li><code><a title="connpy.cli.helpers.get_theme" href="#connpy.cli.helpers.get_theme">get_theme</a></code></li>
|
||||||
|
<li><code><a title="connpy.cli.helpers.hex_to_blessed" href="#connpy.cli.helpers.hex_to_blessed">hex_to_blessed</a></code></li>
|
||||||
<li><code><a title="connpy.cli.helpers.nodes_completer" href="#connpy.cli.helpers.nodes_completer">nodes_completer</a></code></li>
|
<li><code><a title="connpy.cli.helpers.nodes_completer" href="#connpy.cli.helpers.nodes_completer">nodes_completer</a></code></li>
|
||||||
<li><code><a title="connpy.cli.helpers.profiles_completer" href="#connpy.cli.helpers.profiles_completer">profiles_completer</a></code></li>
|
<li><code><a title="connpy.cli.helpers.profiles_completer" href="#connpy.cli.helpers.profiles_completer">profiles_completer</a></code></li>
|
||||||
<li><code><a title="connpy.cli.helpers.toplevel_completer" href="#connpy.cli.helpers.toplevel_completer">toplevel_completer</a></code></li>
|
<li><code><a title="connpy.cli.helpers.toplevel_completer" href="#connpy.cli.helpers.toplevel_completer">toplevel_completer</a></code></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<h4><code><a title="connpy.cli.helpers.ConnpyTheme" href="#connpy.cli.helpers.ConnpyTheme">ConnpyTheme</a></code></h4>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<h4><code><a title="connpy.cli.helpers.ThemeProxy" href="#connpy.cli.helpers.ThemeProxy">ThemeProxy</a></code></h4>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.cli.import_export_handler API documentation</title>
|
<title>connpy.cli.import_export_handler API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -272,7 +272,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.cli API documentation</title>
|
<title>connpy.cli API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -142,7 +142,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.cli.node_handler API documentation</title>
|
<title>connpy.cli.node_handler API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -606,7 +606,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.cli.plugin_handler API documentation</title>
|
<title>connpy.cli.plugin_handler API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -385,7 +385,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.cli.profile_handler API documentation</title>
|
<title>connpy.cli.profile_handler API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -314,7 +314,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.cli.run_handler API documentation</title>
|
<title>connpy.cli.run_handler API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -454,7 +454,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.cli.sync_handler API documentation</title>
|
<title>connpy.cli.sync_handler API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -427,7 +427,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.cli.terminal_ui API documentation</title>
|
<title>connpy.cli.terminal_ui API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -168,7 +168,8 @@ el.replaceWith(d);
|
|||||||
if state['context_mode'] == self.mode_single:
|
if state['context_mode'] == self.mode_single:
|
||||||
active_raw = raw_bytes[start:end]
|
active_raw = raw_bytes[start:end]
|
||||||
else:
|
else:
|
||||||
active_raw = raw_bytes[start:]
|
# Concat only the bytes of valid blocks to skip intermediate empty/cancelled prompt noise
|
||||||
|
active_raw = b"".join(raw_bytes[b[0]:b[1]] for b in blocks[idx:])
|
||||||
return preview + "\n" + log_cleaner(active_raw.decode(errors='replace'))
|
return preview + "\n" + log_cleaner(active_raw.decode(errors='replace'))
|
||||||
|
|
||||||
def get_prompt_text():
|
def get_prompt_text():
|
||||||
@@ -207,7 +208,6 @@ el.replaceWith(d);
|
|||||||
base_str = f'\u25b6 Ctrl+\u2191/\u2193 adjusts by 50 lines [Tab: {m_label}]'
|
base_str = f'\u25b6 Ctrl+\u2191/\u2193 adjusts by 50 lines [Tab: {m_label}]'
|
||||||
else:
|
else:
|
||||||
idx = max(0, state['total_cmds'] - state['context_cmd'])
|
idx = max(0, state['total_cmds'] - state['context_cmd'])
|
||||||
import re
|
|
||||||
|
|
||||||
def clean_preview(text):
|
def clean_preview(text):
|
||||||
# Limpia saltos de línea y el prompt inicial (todo hasta #, > o $) para que quede solo el comando
|
# Limpia saltos de línea y el prompt inicial (todo hasta #, > o $) para que quede solo el comando
|
||||||
@@ -370,10 +370,10 @@ el.replaceWith(d);
|
|||||||
persona_title = "Network Architect" if active_persona == "architect" else "Network Engineer"
|
persona_title = "Network Architect" if active_persona == "architect" else "Network Engineer"
|
||||||
|
|
||||||
active_buffer = get_active_buffer()
|
active_buffer = get_active_buffer()
|
||||||
|
|
||||||
live_text = ""
|
live_text = ""
|
||||||
first_chunk = True
|
first_chunk = True
|
||||||
|
|
||||||
import sys
|
|
||||||
from rich.rule import Rule
|
from rich.rule import Rule
|
||||||
from rich.status import Status
|
from rich.status import Status
|
||||||
from connpy.printer import IncrementalMarkdownParser
|
from connpy.printer import IncrementalMarkdownParser
|
||||||
@@ -622,7 +622,8 @@ el.replaceWith(d);
|
|||||||
if state['context_mode'] == self.mode_single:
|
if state['context_mode'] == self.mode_single:
|
||||||
active_raw = raw_bytes[start:end]
|
active_raw = raw_bytes[start:end]
|
||||||
else:
|
else:
|
||||||
active_raw = raw_bytes[start:]
|
# Concat only the bytes of valid blocks to skip intermediate empty/cancelled prompt noise
|
||||||
|
active_raw = b"".join(raw_bytes[b[0]:b[1]] for b in blocks[idx:])
|
||||||
return preview + "\n" + log_cleaner(active_raw.decode(errors='replace'))
|
return preview + "\n" + log_cleaner(active_raw.decode(errors='replace'))
|
||||||
|
|
||||||
def get_prompt_text():
|
def get_prompt_text():
|
||||||
@@ -661,7 +662,6 @@ el.replaceWith(d);
|
|||||||
base_str = f'\u25b6 Ctrl+\u2191/\u2193 adjusts by 50 lines [Tab: {m_label}]'
|
base_str = f'\u25b6 Ctrl+\u2191/\u2193 adjusts by 50 lines [Tab: {m_label}]'
|
||||||
else:
|
else:
|
||||||
idx = max(0, state['total_cmds'] - state['context_cmd'])
|
idx = max(0, state['total_cmds'] - state['context_cmd'])
|
||||||
import re
|
|
||||||
|
|
||||||
def clean_preview(text):
|
def clean_preview(text):
|
||||||
# Limpia saltos de línea y el prompt inicial (todo hasta #, > o $) para que quede solo el comando
|
# Limpia saltos de línea y el prompt inicial (todo hasta #, > o $) para que quede solo el comando
|
||||||
@@ -824,10 +824,10 @@ el.replaceWith(d);
|
|||||||
persona_title = "Network Architect" if active_persona == "architect" else "Network Engineer"
|
persona_title = "Network Architect" if active_persona == "architect" else "Network Engineer"
|
||||||
|
|
||||||
active_buffer = get_active_buffer()
|
active_buffer = get_active_buffer()
|
||||||
|
|
||||||
live_text = ""
|
live_text = ""
|
||||||
first_chunk = True
|
first_chunk = True
|
||||||
|
|
||||||
import sys
|
|
||||||
from rich.rule import Rule
|
from rich.rule import Rule
|
||||||
from rich.status import Status
|
from rich.status import Status
|
||||||
from connpy.printer import IncrementalMarkdownParser
|
from connpy.printer import IncrementalMarkdownParser
|
||||||
@@ -1017,7 +1017,7 @@ on_ai_call: async function(active_buffer, question) -> result_dict</p></div>
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.cli.validators API documentation</title>
|
<title>connpy.cli.validators API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -508,7 +508,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.grpc_layer.connpy_pb2 API documentation</title>
|
<title>connpy.grpc_layer.connpy_pb2 API documentation</title>
|
||||||
<meta name="description" content="Generated protocol buffer code.">
|
<meta name="description" content="Generated protocol buffer code.">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -45,617 +45,6 @@ el.replaceWith(d);
|
|||||||
<section>
|
<section>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.AIResponse"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">AIResponse</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.AIResponse.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.AskRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">AskRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.AskRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.BoolResponse"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">BoolResponse</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.BoolResponse.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.BulkRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">BulkRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.BulkRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.CopilotRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">CopilotRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.CopilotRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.CopilotResponse"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">CopilotResponse</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.CopilotResponse.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.DeleteRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">DeleteRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.DeleteRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.ExportRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">ExportRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.ExportRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.FilterRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">FilterRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.FilterRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.FullReplaceRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">FullReplaceRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.FullReplaceRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.IdRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">IdRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.IdRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.IntRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">IntRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.IntRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.InteractRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">InteractRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.InteractRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.InteractResponse"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">InteractResponse</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.InteractResponse.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.ListRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">ListRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.ListRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.MCPRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">MCPRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.MCPRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.MessageValue"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">MessageValue</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.MessageValue.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.MoveRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">MoveRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.MoveRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.NodeRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">NodeRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.NodeRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.NodeRunResult"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">NodeRunResult</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.NodeRunResult.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.PluginRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">PluginRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.PluginRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.ProfileRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">ProfileRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.ProfileRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.ProviderRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">ProviderRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.ProviderRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.RunRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">RunRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.RunRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.ScriptRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">ScriptRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.ScriptRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.StringRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">StringRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.StringRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.StringResponse"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">StringResponse</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.StringResponse.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.StructRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">StructRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.StructRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.StructResponse"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">StructResponse</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.StructResponse.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.TestRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">TestRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.TestRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.UpdateRequest"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">UpdateRequest</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.UpdateRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.ValueResponse"><code class="flex name class">
|
|
||||||
<span>class <span class="ident">ValueResponse</span></span>
|
|
||||||
<span>(</span><span>*args, **kwargs)</span>
|
|
||||||
</code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"><p>A ProtocolMessage</p></div>
|
|
||||||
<h3>Ancestors</h3>
|
|
||||||
<ul class="hlist">
|
|
||||||
<li>google._upb._message.Message</li>
|
|
||||||
<li>google.protobuf.message.Message</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Class variables</h3>
|
|
||||||
<dl>
|
|
||||||
<dt id="connpy.grpc_layer.connpy_pb2.ValueResponse.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</section>
|
</section>
|
||||||
</article>
|
</article>
|
||||||
<nav id="sidebar">
|
<nav id="sidebar">
|
||||||
@@ -668,207 +57,11 @@ el.replaceWith(d);
|
|||||||
<li><code><a title="connpy.grpc_layer" href="index.html">connpy.grpc_layer</a></code></li>
|
<li><code><a title="connpy.grpc_layer" href="index.html">connpy.grpc_layer</a></code></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.AIResponse" href="#connpy.grpc_layer.connpy_pb2.AIResponse">AIResponse</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.AIResponse.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.AIResponse.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.AskRequest" href="#connpy.grpc_layer.connpy_pb2.AskRequest">AskRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.AskRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.AskRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.BoolResponse" href="#connpy.grpc_layer.connpy_pb2.BoolResponse">BoolResponse</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.BoolResponse.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.BoolResponse.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.BulkRequest" href="#connpy.grpc_layer.connpy_pb2.BulkRequest">BulkRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.BulkRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.BulkRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.CopilotRequest" href="#connpy.grpc_layer.connpy_pb2.CopilotRequest">CopilotRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.CopilotRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.CopilotRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.CopilotResponse" href="#connpy.grpc_layer.connpy_pb2.CopilotResponse">CopilotResponse</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.CopilotResponse.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.CopilotResponse.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.DeleteRequest" href="#connpy.grpc_layer.connpy_pb2.DeleteRequest">DeleteRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.DeleteRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.DeleteRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.ExportRequest" href="#connpy.grpc_layer.connpy_pb2.ExportRequest">ExportRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.ExportRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.ExportRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.FilterRequest" href="#connpy.grpc_layer.connpy_pb2.FilterRequest">FilterRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.FilterRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.FilterRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.FullReplaceRequest" href="#connpy.grpc_layer.connpy_pb2.FullReplaceRequest">FullReplaceRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.FullReplaceRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.FullReplaceRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.IdRequest" href="#connpy.grpc_layer.connpy_pb2.IdRequest">IdRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.IdRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.IdRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.IntRequest" href="#connpy.grpc_layer.connpy_pb2.IntRequest">IntRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.IntRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.IntRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.InteractRequest" href="#connpy.grpc_layer.connpy_pb2.InteractRequest">InteractRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.InteractRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.InteractRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.InteractResponse" href="#connpy.grpc_layer.connpy_pb2.InteractResponse">InteractResponse</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.InteractResponse.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.InteractResponse.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.ListRequest" href="#connpy.grpc_layer.connpy_pb2.ListRequest">ListRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.ListRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.ListRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.MCPRequest" href="#connpy.grpc_layer.connpy_pb2.MCPRequest">MCPRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.MCPRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.MCPRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.MessageValue" href="#connpy.grpc_layer.connpy_pb2.MessageValue">MessageValue</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.MessageValue.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.MessageValue.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.MoveRequest" href="#connpy.grpc_layer.connpy_pb2.MoveRequest">MoveRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.MoveRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.MoveRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.NodeRequest" href="#connpy.grpc_layer.connpy_pb2.NodeRequest">NodeRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.NodeRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.NodeRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.NodeRunResult" href="#connpy.grpc_layer.connpy_pb2.NodeRunResult">NodeRunResult</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.NodeRunResult.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.NodeRunResult.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.PluginRequest" href="#connpy.grpc_layer.connpy_pb2.PluginRequest">PluginRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.PluginRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.PluginRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.ProfileRequest" href="#connpy.grpc_layer.connpy_pb2.ProfileRequest">ProfileRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.ProfileRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.ProfileRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.ProviderRequest" href="#connpy.grpc_layer.connpy_pb2.ProviderRequest">ProviderRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.ProviderRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.ProviderRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.RunRequest" href="#connpy.grpc_layer.connpy_pb2.RunRequest">RunRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.RunRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.RunRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.ScriptRequest" href="#connpy.grpc_layer.connpy_pb2.ScriptRequest">ScriptRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.ScriptRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.ScriptRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.StringRequest" href="#connpy.grpc_layer.connpy_pb2.StringRequest">StringRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.StringRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.StringRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.StringResponse" href="#connpy.grpc_layer.connpy_pb2.StringResponse">StringResponse</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.StringResponse.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.StringResponse.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.StructRequest" href="#connpy.grpc_layer.connpy_pb2.StructRequest">StructRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.StructRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.StructRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.StructResponse" href="#connpy.grpc_layer.connpy_pb2.StructResponse">StructResponse</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.StructResponse.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.StructResponse.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.TestRequest" href="#connpy.grpc_layer.connpy_pb2.TestRequest">TestRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.TestRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.TestRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.UpdateRequest" href="#connpy.grpc_layer.connpy_pb2.UpdateRequest">UpdateRequest</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.UpdateRequest.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.UpdateRequest.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h4><code><a title="connpy.grpc_layer.connpy_pb2.ValueResponse" href="#connpy.grpc_layer.connpy_pb2.ValueResponse">ValueResponse</a></code></h4>
|
|
||||||
<ul class="">
|
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2.ValueResponse.DESCRIPTOR" href="#connpy.grpc_layer.connpy_pb2.ValueResponse.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.grpc_layer API documentation</title>
|
<title>connpy.grpc_layer API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -102,7 +102,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.grpc_layer.remote_plugin_pb2 API documentation</title>
|
<title>connpy.grpc_layer.remote_plugin_pb2 API documentation</title>
|
||||||
<meta name="description" content="Generated protocol buffer code.">
|
<meta name="description" content="Generated protocol buffer code.">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -62,7 +62,7 @@ el.replaceWith(d);
|
|||||||
<dl>
|
<dl>
|
||||||
<dt id="connpy.grpc_layer.remote_plugin_pb2.IdRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
<dt id="connpy.grpc_layer.remote_plugin_pb2.IdRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<div class="desc"></div>
|
<div class="desc"><p>The type of the None singleton.</p></div>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</dd>
|
</dd>
|
||||||
@@ -81,7 +81,7 @@ el.replaceWith(d);
|
|||||||
<dl>
|
<dl>
|
||||||
<dt id="connpy.grpc_layer.remote_plugin_pb2.OutputChunk.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
<dt id="connpy.grpc_layer.remote_plugin_pb2.OutputChunk.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<div class="desc"></div>
|
<div class="desc"><p>The type of the None singleton.</p></div>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</dd>
|
</dd>
|
||||||
@@ -100,7 +100,7 @@ el.replaceWith(d);
|
|||||||
<dl>
|
<dl>
|
||||||
<dt id="connpy.grpc_layer.remote_plugin_pb2.PluginInvokeRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
<dt id="connpy.grpc_layer.remote_plugin_pb2.PluginInvokeRequest.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<div class="desc"></div>
|
<div class="desc"><p>The type of the None singleton.</p></div>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</dd>
|
</dd>
|
||||||
@@ -119,7 +119,7 @@ el.replaceWith(d);
|
|||||||
<dl>
|
<dl>
|
||||||
<dt id="connpy.grpc_layer.remote_plugin_pb2.StringResponse.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
<dt id="connpy.grpc_layer.remote_plugin_pb2.StringResponse.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<div class="desc"></div>
|
<div class="desc"><p>The type of the None singleton.</p></div>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</dd>
|
</dd>
|
||||||
@@ -168,7 +168,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.grpc_layer.remote_plugin_pb2_grpc API documentation</title>
|
<title>connpy.grpc_layer.remote_plugin_pb2_grpc API documentation</title>
|
||||||
<meta name="description" content="Client and server classes corresponding to protobuf-defined services.">
|
<meta name="description" content="Client and server classes corresponding to protobuf-defined services.">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -366,7 +366,7 @@ def invoke_plugin(request,
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.grpc_layer.server API documentation</title>
|
<title>connpy.grpc_layer.server API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -177,9 +177,11 @@ el.replaceWith(d);
|
|||||||
print(f"AI Task Error: {e}")
|
print(f"AI Task Error: {e}")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
chunk_queue.put(("status", f"Error: {str(e)}"))
|
chunk_queue.put(("status", f"Error: {str(e)}"))
|
||||||
|
# Crucial: always send final_mark to avoid client deadlock
|
||||||
|
chunk_queue.put(("final_mark", {"response": f"Error: {str(e)}", "chat_history": history, "error": True}))
|
||||||
|
|
||||||
def request_listener():
|
def request_listener():
|
||||||
nonlocal bridge, is_web, ai_thread, agent_instance
|
nonlocal bridge, is_web, ai_thread, agent_instance, history
|
||||||
try:
|
try:
|
||||||
for req in request_iterator:
|
for req in request_iterator:
|
||||||
if req.interrupt:
|
if req.interrupt:
|
||||||
@@ -193,12 +195,21 @@ el.replaceWith(d);
|
|||||||
|
|
||||||
if req.input_text:
|
if req.input_text:
|
||||||
is_web = "web" in (req.session_id or "").lower() or (req.session_id or "").lower().startswith("ws-")
|
is_web = "web" in (req.session_id or "").lower() or (req.session_id or "").lower().startswith("ws-")
|
||||||
|
|
||||||
|
# Hydrate history from client if it's the first interaction in this stream
|
||||||
|
if not history and req.chat_history:
|
||||||
|
from .utils import from_value
|
||||||
|
history = from_value(req.chat_history) or []
|
||||||
if not bridge:
|
if not bridge:
|
||||||
bridge = StatusBridge(chunk_queue, request_queue=request_queue, is_web=is_web)
|
bridge = StatusBridge(chunk_queue, request_queue=request_queue, is_web=is_web)
|
||||||
|
|
||||||
overrides = {}
|
overrides = {}
|
||||||
if req.engineer_model: overrides["engineer_model"] = req.engineer_model
|
if req.engineer_model: overrides["engineer_model"] = req.engineer_model
|
||||||
if req.engineer_api_key: overrides["engineer_api_key"] = req.engineer_api_key
|
if req.engineer_api_key: overrides["engineer_api_key"] = req.engineer_api_key
|
||||||
|
if req.architect_model: overrides["architect_model"] = req.architect_model
|
||||||
|
if req.architect_api_key: overrides["architect_api_key"] = req.architect_api_key
|
||||||
|
if req.HasField("engineer_auth"): overrides["engineer_auth"] = from_struct(req.engineer_auth)
|
||||||
|
if req.HasField("architect_auth"): overrides["architect_auth"] = from_struct(req.architect_auth)
|
||||||
|
|
||||||
# Start AI in its own thread so we can keep listening for interrupts
|
# Start AI in its own thread so we can keep listening for interrupts
|
||||||
ai_thread = threading.Thread(
|
ai_thread = threading.Thread(
|
||||||
@@ -263,7 +274,8 @@ el.replaceWith(d);
|
|||||||
|
|
||||||
@handle_errors
|
@handle_errors
|
||||||
def list_sessions(self, request, context):
|
def list_sessions(self, request, context):
|
||||||
return connpy_pb2.ValueResponse(data=to_value(self.service.list_sessions()))
|
sessions, total = self.service.list_sessions()
|
||||||
|
return connpy_pb2.ValueResponse(data=to_value(sessions))
|
||||||
|
|
||||||
@handle_errors
|
@handle_errors
|
||||||
def delete_session(self, request, context):
|
def delete_session(self, request, context):
|
||||||
@@ -272,7 +284,8 @@ el.replaceWith(d);
|
|||||||
|
|
||||||
@handle_errors
|
@handle_errors
|
||||||
def configure_provider(self, request, context):
|
def configure_provider(self, request, context):
|
||||||
self.service.configure_provider(request.provider, request.model, request.api_key)
|
auth_dict = from_struct(request.auth) if request.HasField("auth") else None
|
||||||
|
self.service.configure_provider(request.provider, request.model, request.api_key, auth=auth_dict)
|
||||||
return Empty()
|
return Empty()
|
||||||
|
|
||||||
@handle_errors
|
@handle_errors
|
||||||
@@ -286,6 +299,11 @@ el.replaceWith(d);
|
|||||||
)
|
)
|
||||||
return Empty()
|
return Empty()
|
||||||
|
|
||||||
|
@handle_errors
|
||||||
|
def list_mcp_servers(self, request, context):
|
||||||
|
mcp_servers = self.service.list_mcp_servers()
|
||||||
|
return connpy_pb2.ValueResponse(data=to_value(mcp_servers))
|
||||||
|
|
||||||
@handle_errors
|
@handle_errors
|
||||||
def load_session_data(self, request, context):
|
def load_session_data(self, request, context):
|
||||||
return connpy_pb2.StructResponse(data=to_struct(self.service.load_session_data(request.value)))</code></pre>
|
return connpy_pb2.StructResponse(data=to_struct(self.service.load_session_data(request.value)))</code></pre>
|
||||||
@@ -305,6 +323,7 @@ el.replaceWith(d);
|
|||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.configure_provider" href="connpy_pb2_grpc.html#connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.configure_provider">configure_provider</a></code></li>
|
<li><code><a title="connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.configure_provider" href="connpy_pb2_grpc.html#connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.configure_provider">configure_provider</a></code></li>
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.confirm" href="connpy_pb2_grpc.html#connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.confirm">confirm</a></code></li>
|
<li><code><a title="connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.confirm" href="connpy_pb2_grpc.html#connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.confirm">confirm</a></code></li>
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.delete_session" href="connpy_pb2_grpc.html#connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.delete_session">delete_session</a></code></li>
|
<li><code><a title="connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.delete_session" href="connpy_pb2_grpc.html#connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.delete_session">delete_session</a></code></li>
|
||||||
|
<li><code><a title="connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.list_mcp_servers" href="connpy_pb2_grpc.html#connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.list_mcp_servers">list_mcp_servers</a></code></li>
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.list_sessions" href="connpy_pb2_grpc.html#connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.list_sessions">list_sessions</a></code></li>
|
<li><code><a title="connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.list_sessions" href="connpy_pb2_grpc.html#connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.list_sessions">list_sessions</a></code></li>
|
||||||
<li><code><a title="connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.load_session_data" href="connpy_pb2_grpc.html#connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.load_session_data">load_session_data</a></code></li>
|
<li><code><a title="connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.load_session_data" href="connpy_pb2_grpc.html#connpy.grpc_layer.connpy_pb2_grpc.AIServiceServicer.load_session_data">load_session_data</a></code></li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -975,7 +994,9 @@ interceptor chooses to service this RPC, or None otherwise.</p></div>
|
|||||||
|
|
||||||
asyncio.run(n._async_interact_loop(remote_stream, resize_callback, copilot_handler=remote_copilot_handler))
|
asyncio.run(n._async_interact_loop(remote_stream, resize_callback, copilot_handler=remote_copilot_handler))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pass
|
import traceback
|
||||||
|
print(f"[ERROR in run_async_loop] {e}")
|
||||||
|
traceback.print_exc()
|
||||||
finally:
|
finally:
|
||||||
n._teardown_interact_environment()
|
n._teardown_interact_environment()
|
||||||
response_queue.put(None) # Signal EOF
|
response_queue.put(None) # Signal EOF
|
||||||
@@ -1195,6 +1216,7 @@ interceptor chooses to service this RPC, or None otherwise.</p></div>
|
|||||||
self.service = ProfileService(config)
|
self.service = ProfileService(config)
|
||||||
self.node_service = NodeService(config)
|
self.node_service = NodeService(config)
|
||||||
|
|
||||||
|
|
||||||
@handle_errors
|
@handle_errors
|
||||||
def list_profiles(self, request, context):
|
def list_profiles(self, request, context):
|
||||||
f = request.filter_str if request.filter_str else None
|
f = request.filter_str if request.filter_str else None
|
||||||
@@ -1261,6 +1283,7 @@ interceptor chooses to service this RPC, or None otherwise.</p></div>
|
|||||||
self.on_interrupt = self._force_interrupt
|
self.on_interrupt = self._force_interrupt
|
||||||
self.thread = None
|
self.thread = None
|
||||||
self.is_web = is_web
|
self.is_web = is_web
|
||||||
|
self.is_remote = True
|
||||||
|
|
||||||
def _force_interrupt(self):
|
def _force_interrupt(self):
|
||||||
"""Forcefully raise KeyboardInterrupt in the target thread."""
|
"""Forcefully raise KeyboardInterrupt in the target thread."""
|
||||||
@@ -1560,7 +1583,7 @@ interceptor chooses to service this RPC, or None otherwise.</p></div>
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.grpc_layer.stubs API documentation</title>
|
<title>connpy.grpc_layer.stubs API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -122,6 +122,10 @@ el.replaceWith(d);
|
|||||||
)
|
)
|
||||||
if chat_history is not None:
|
if chat_history is not None:
|
||||||
initial_req.chat_history.CopyFrom(to_value(chat_history))
|
initial_req.chat_history.CopyFrom(to_value(chat_history))
|
||||||
|
if "engineer_auth" in overrides and overrides["engineer_auth"]:
|
||||||
|
initial_req.engineer_auth.CopyFrom(to_struct(overrides["engineer_auth"]))
|
||||||
|
if "architect_auth" in overrides and overrides["architect_auth"]:
|
||||||
|
initial_req.architect_auth.CopyFrom(to_struct(overrides["architect_auth"]))
|
||||||
|
|
||||||
req_queue.put(initial_req)
|
req_queue.put(initial_req)
|
||||||
|
|
||||||
@@ -135,6 +139,7 @@ el.replaceWith(d);
|
|||||||
|
|
||||||
full_content = ""
|
full_content = ""
|
||||||
header_printed = False
|
header_printed = False
|
||||||
|
current_responder = "engineer"
|
||||||
final_result = {"response": "", "chat_history": []}
|
final_result = {"response": "", "chat_history": []}
|
||||||
|
|
||||||
# Background thread to pull responses from gRPC into a local queue
|
# Background thread to pull responses from gRPC into a local queue
|
||||||
@@ -179,6 +184,10 @@ el.replaceWith(d);
|
|||||||
break
|
break
|
||||||
|
|
||||||
if response.status_update:
|
if response.status_update:
|
||||||
|
if response.status_update.startswith("__RESPONDER__:"):
|
||||||
|
current_responder = response.status_update.split(":")[1].lower()
|
||||||
|
continue
|
||||||
|
|
||||||
if response.requires_confirmation:
|
if response.requires_confirmation:
|
||||||
if status: status.stop()
|
if status: status.stop()
|
||||||
|
|
||||||
@@ -231,7 +240,9 @@ el.replaceWith(d);
|
|||||||
stable_console = RichConsole(theme=connpy_theme, file=get_original_stdout())
|
stable_console = RichConsole(theme=connpy_theme, file=get_original_stdout())
|
||||||
|
|
||||||
# Print header on first chunk
|
# Print header on first chunk
|
||||||
stable_console.print(Rule("[bold engineer]Network Engineer[/bold engineer]", style="engineer"))
|
alias = "architect" if current_responder == "architect" else "engineer"
|
||||||
|
role_label = "Network Architect" if current_responder == "architect" else "Network Engineer"
|
||||||
|
stable_console.print(Rule(f"[bold {alias}]{role_label}[/bold {alias}]", style=alias))
|
||||||
header_printed = True
|
header_printed = True
|
||||||
|
|
||||||
# Initialize parser
|
# Initialize parser
|
||||||
@@ -283,16 +294,23 @@ el.replaceWith(d);
|
|||||||
return self.stub.confirm(connpy_pb2.StringRequest(value=input_text)).value
|
return self.stub.confirm(connpy_pb2.StringRequest(value=input_text)).value
|
||||||
|
|
||||||
@handle_errors
|
@handle_errors
|
||||||
def list_sessions(self):
|
def list_sessions(self, limit=None):
|
||||||
return from_value(self.stub.list_sessions(Empty()).data)
|
from .utils import from_value
|
||||||
|
res = self.stub.list_sessions(Empty())
|
||||||
|
sessions = from_value(res.data) or []
|
||||||
|
if limit and len(sessions) > limit:
|
||||||
|
return sessions[:limit], len(sessions)
|
||||||
|
return sessions, len(sessions)
|
||||||
|
|
||||||
@handle_errors
|
@handle_errors
|
||||||
def delete_session(self, session_id):
|
def delete_session(self, session_id):
|
||||||
self.stub.delete_session(connpy_pb2.StringRequest(value=session_id))
|
self.stub.delete_session(connpy_pb2.StringRequest(value=session_id))
|
||||||
|
|
||||||
@handle_errors
|
@handle_errors
|
||||||
def configure_provider(self, provider, model=None, api_key=None):
|
def configure_provider(self, provider, model=None, api_key=None, auth=None):
|
||||||
req = connpy_pb2.ProviderRequest(provider=provider, model=model or "", api_key=api_key or "")
|
req = connpy_pb2.ProviderRequest(provider=provider, model=model or "", api_key=api_key or "")
|
||||||
|
if auth:
|
||||||
|
req.auth.CopyFrom(to_struct(auth))
|
||||||
self.stub.configure_provider(req)
|
self.stub.configure_provider(req)
|
||||||
|
|
||||||
@handle_errors
|
@handle_errors
|
||||||
@@ -306,6 +324,11 @@ el.replaceWith(d);
|
|||||||
)
|
)
|
||||||
self.stub.configure_mcp(req)
|
self.stub.configure_mcp(req)
|
||||||
|
|
||||||
|
@handle_errors
|
||||||
|
def list_mcp_servers(self):
|
||||||
|
res = self.stub.list_mcp_servers(Empty())
|
||||||
|
return from_value(res.data) or {}
|
||||||
|
|
||||||
@handle_errors
|
@handle_errors
|
||||||
def load_session_data(self, session_id):
|
def load_session_data(self, session_id):
|
||||||
return from_struct(self.stub.load_session_data(connpy_pb2.StringRequest(value=session_id)).data)</code></pre>
|
return from_struct(self.stub.load_session_data(connpy_pb2.StringRequest(value=session_id)).data)</code></pre>
|
||||||
@@ -344,6 +367,10 @@ def ask(self, input_text, dryrun=False, chat_history=None, session_id=None, debu
|
|||||||
)
|
)
|
||||||
if chat_history is not None:
|
if chat_history is not None:
|
||||||
initial_req.chat_history.CopyFrom(to_value(chat_history))
|
initial_req.chat_history.CopyFrom(to_value(chat_history))
|
||||||
|
if "engineer_auth" in overrides and overrides["engineer_auth"]:
|
||||||
|
initial_req.engineer_auth.CopyFrom(to_struct(overrides["engineer_auth"]))
|
||||||
|
if "architect_auth" in overrides and overrides["architect_auth"]:
|
||||||
|
initial_req.architect_auth.CopyFrom(to_struct(overrides["architect_auth"]))
|
||||||
|
|
||||||
req_queue.put(initial_req)
|
req_queue.put(initial_req)
|
||||||
|
|
||||||
@@ -357,6 +384,7 @@ def ask(self, input_text, dryrun=False, chat_history=None, session_id=None, debu
|
|||||||
|
|
||||||
full_content = ""
|
full_content = ""
|
||||||
header_printed = False
|
header_printed = False
|
||||||
|
current_responder = "engineer"
|
||||||
final_result = {"response": "", "chat_history": []}
|
final_result = {"response": "", "chat_history": []}
|
||||||
|
|
||||||
# Background thread to pull responses from gRPC into a local queue
|
# Background thread to pull responses from gRPC into a local queue
|
||||||
@@ -401,6 +429,10 @@ def ask(self, input_text, dryrun=False, chat_history=None, session_id=None, debu
|
|||||||
break
|
break
|
||||||
|
|
||||||
if response.status_update:
|
if response.status_update:
|
||||||
|
if response.status_update.startswith("__RESPONDER__:"):
|
||||||
|
current_responder = response.status_update.split(":")[1].lower()
|
||||||
|
continue
|
||||||
|
|
||||||
if response.requires_confirmation:
|
if response.requires_confirmation:
|
||||||
if status: status.stop()
|
if status: status.stop()
|
||||||
|
|
||||||
@@ -453,7 +485,9 @@ def ask(self, input_text, dryrun=False, chat_history=None, session_id=None, debu
|
|||||||
stable_console = RichConsole(theme=connpy_theme, file=get_original_stdout())
|
stable_console = RichConsole(theme=connpy_theme, file=get_original_stdout())
|
||||||
|
|
||||||
# Print header on first chunk
|
# Print header on first chunk
|
||||||
stable_console.print(Rule("[bold engineer]Network Engineer[/bold engineer]", style="engineer"))
|
alias = "architect" if current_responder == "architect" else "engineer"
|
||||||
|
role_label = "Network Architect" if current_responder == "architect" else "Network Engineer"
|
||||||
|
stable_console.print(Rule(f"[bold {alias}]{role_label}[/bold {alias}]", style=alias))
|
||||||
header_printed = True
|
header_printed = True
|
||||||
|
|
||||||
# Initialize parser
|
# Initialize parser
|
||||||
@@ -524,7 +558,7 @@ def configure_mcp(self, name, url=None, enabled=True, auto_load_on_os=None, remo
|
|||||||
<div class="desc"></div>
|
<div class="desc"></div>
|
||||||
</dd>
|
</dd>
|
||||||
<dt id="connpy.grpc_layer.stubs.AIStub.configure_provider"><code class="name flex">
|
<dt id="connpy.grpc_layer.stubs.AIStub.configure_provider"><code class="name flex">
|
||||||
<span>def <span class="ident">configure_provider</span></span>(<span>self, provider, model=None, api_key=None)</span>
|
<span>def <span class="ident">configure_provider</span></span>(<span>self, provider, model=None, api_key=None, auth=None)</span>
|
||||||
</code></dt>
|
</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<details class="source">
|
<details class="source">
|
||||||
@@ -532,8 +566,10 @@ def configure_mcp(self, name, url=None, enabled=True, auto_load_on_os=None, remo
|
|||||||
<span>Expand source code</span>
|
<span>Expand source code</span>
|
||||||
</summary>
|
</summary>
|
||||||
<pre><code class="python">@handle_errors
|
<pre><code class="python">@handle_errors
|
||||||
def configure_provider(self, provider, model=None, api_key=None):
|
def configure_provider(self, provider, model=None, api_key=None, auth=None):
|
||||||
req = connpy_pb2.ProviderRequest(provider=provider, model=model or "", api_key=api_key or "")
|
req = connpy_pb2.ProviderRequest(provider=provider, model=model or "", api_key=api_key or "")
|
||||||
|
if auth:
|
||||||
|
req.auth.CopyFrom(to_struct(auth))
|
||||||
self.stub.configure_provider(req)</code></pre>
|
self.stub.configure_provider(req)</code></pre>
|
||||||
</details>
|
</details>
|
||||||
<div class="desc"></div>
|
<div class="desc"></div>
|
||||||
@@ -566,8 +602,8 @@ def delete_session(self, session_id):
|
|||||||
</details>
|
</details>
|
||||||
<div class="desc"></div>
|
<div class="desc"></div>
|
||||||
</dd>
|
</dd>
|
||||||
<dt id="connpy.grpc_layer.stubs.AIStub.list_sessions"><code class="name flex">
|
<dt id="connpy.grpc_layer.stubs.AIStub.list_mcp_servers"><code class="name flex">
|
||||||
<span>def <span class="ident">list_sessions</span></span>(<span>self)</span>
|
<span>def <span class="ident">list_mcp_servers</span></span>(<span>self)</span>
|
||||||
</code></dt>
|
</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<details class="source">
|
<details class="source">
|
||||||
@@ -575,8 +611,28 @@ def delete_session(self, session_id):
|
|||||||
<span>Expand source code</span>
|
<span>Expand source code</span>
|
||||||
</summary>
|
</summary>
|
||||||
<pre><code class="python">@handle_errors
|
<pre><code class="python">@handle_errors
|
||||||
def list_sessions(self):
|
def list_mcp_servers(self):
|
||||||
return from_value(self.stub.list_sessions(Empty()).data)</code></pre>
|
res = self.stub.list_mcp_servers(Empty())
|
||||||
|
return from_value(res.data) or {}</code></pre>
|
||||||
|
</details>
|
||||||
|
<div class="desc"></div>
|
||||||
|
</dd>
|
||||||
|
<dt id="connpy.grpc_layer.stubs.AIStub.list_sessions"><code class="name flex">
|
||||||
|
<span>def <span class="ident">list_sessions</span></span>(<span>self, limit=None)</span>
|
||||||
|
</code></dt>
|
||||||
|
<dd>
|
||||||
|
<details class="source">
|
||||||
|
<summary>
|
||||||
|
<span>Expand source code</span>
|
||||||
|
</summary>
|
||||||
|
<pre><code class="python">@handle_errors
|
||||||
|
def list_sessions(self, limit=None):
|
||||||
|
from .utils import from_value
|
||||||
|
res = self.stub.list_sessions(Empty())
|
||||||
|
sessions = from_value(res.data) or []
|
||||||
|
if limit and len(sessions) > limit:
|
||||||
|
return sessions[:limit], len(sessions)
|
||||||
|
return sessions, len(sessions)</code></pre>
|
||||||
</details>
|
</details>
|
||||||
<div class="desc"></div>
|
<div class="desc"></div>
|
||||||
</dd>
|
</dd>
|
||||||
@@ -2470,6 +2526,7 @@ def stop_api(self):
|
|||||||
<li><code><a title="connpy.grpc_layer.stubs.AIStub.configure_provider" href="#connpy.grpc_layer.stubs.AIStub.configure_provider">configure_provider</a></code></li>
|
<li><code><a title="connpy.grpc_layer.stubs.AIStub.configure_provider" href="#connpy.grpc_layer.stubs.AIStub.configure_provider">configure_provider</a></code></li>
|
||||||
<li><code><a title="connpy.grpc_layer.stubs.AIStub.confirm" href="#connpy.grpc_layer.stubs.AIStub.confirm">confirm</a></code></li>
|
<li><code><a title="connpy.grpc_layer.stubs.AIStub.confirm" href="#connpy.grpc_layer.stubs.AIStub.confirm">confirm</a></code></li>
|
||||||
<li><code><a title="connpy.grpc_layer.stubs.AIStub.delete_session" href="#connpy.grpc_layer.stubs.AIStub.delete_session">delete_session</a></code></li>
|
<li><code><a title="connpy.grpc_layer.stubs.AIStub.delete_session" href="#connpy.grpc_layer.stubs.AIStub.delete_session">delete_session</a></code></li>
|
||||||
|
<li><code><a title="connpy.grpc_layer.stubs.AIStub.list_mcp_servers" href="#connpy.grpc_layer.stubs.AIStub.list_mcp_servers">list_mcp_servers</a></code></li>
|
||||||
<li><code><a title="connpy.grpc_layer.stubs.AIStub.list_sessions" href="#connpy.grpc_layer.stubs.AIStub.list_sessions">list_sessions</a></code></li>
|
<li><code><a title="connpy.grpc_layer.stubs.AIStub.list_sessions" href="#connpy.grpc_layer.stubs.AIStub.list_sessions">list_sessions</a></code></li>
|
||||||
<li><code><a title="connpy.grpc_layer.stubs.AIStub.load_session_data" href="#connpy.grpc_layer.stubs.AIStub.load_session_data">load_session_data</a></code></li>
|
<li><code><a title="connpy.grpc_layer.stubs.AIStub.load_session_data" href="#connpy.grpc_layer.stubs.AIStub.load_session_data">load_session_data</a></code></li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -2561,7 +2618,7 @@ def stop_api(self):
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.grpc_layer.utils API documentation</title>
|
<title>connpy.grpc_layer.utils API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -138,7 +138,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+157
-62
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy API documentation</title>
|
<title>connpy API documentation</title>
|
||||||
<meta name="description" content="<p align="center">
|
<meta name="description" content="<p align="center">
|
||||||
<img src="https://nginx.gederico.dynu.net/images/CONNPY-resized.png" alt="App Logo">
|
<img src="https://nginx.gederico.dynu.net/images/CONNPY-resized.png" alt="App Logo">
|
||||||
@@ -205,10 +205,6 @@ response = myai.ask("What is the status of the BGP neighbors in the office?
|
|||||||
<dd>
|
<dd>
|
||||||
<div class="desc"></div>
|
<div class="desc"></div>
|
||||||
</dd>
|
</dd>
|
||||||
<dt><code class="name"><a title="connpy.tests" href="tests/index.html">connpy.tests</a></code></dt>
|
|
||||||
<dd>
|
|
||||||
<div class="desc"></div>
|
|
||||||
</dd>
|
|
||||||
<dt><code class="name"><a title="connpy.tunnels" href="tunnels.html">connpy.tunnels</a></code></dt>
|
<dt><code class="name"><a title="connpy.tunnels" href="tunnels.html">connpy.tunnels</a></code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<div class="desc"></div>
|
<div class="desc"></div>
|
||||||
@@ -620,7 +616,7 @@ indicating successful verification.</p>
|
|||||||
</dd>
|
</dd>
|
||||||
<dt id="connpy.ai"><code class="flex name class">
|
<dt id="connpy.ai"><code class="flex name class">
|
||||||
<span>class <span class="ident">ai</span></span>
|
<span>class <span class="ident">ai</span></span>
|
||||||
<span>(</span><span>config,<br>org=None,<br>api_key=None,<br>engineer_model=None,<br>architect_model=None,<br>engineer_api_key=None,<br>architect_api_key=None,<br>console=None,<br>confirm_handler=None,<br>trust=False)</span>
|
<span>(</span><span>config,<br>org=None,<br>api_key=None,<br>engineer_model=None,<br>architect_model=None,<br>engineer_api_key=None,<br>architect_api_key=None,<br>console=None,<br>confirm_handler=None,<br>trust=False,<br>engineer_auth=None,<br>architect_auth=None,<br>**kwargs)</span>
|
||||||
</code></dt>
|
</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<details class="source">
|
<details class="source">
|
||||||
@@ -638,7 +634,7 @@ class ai:
|
|||||||
r'^systemctl\s+status\s+', r'^journalctl\s+'
|
r'^systemctl\s+status\s+', r'^journalctl\s+'
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, config, org=None, api_key=None, engineer_model=None, architect_model=None, engineer_api_key=None, architect_api_key=None, console=None, confirm_handler=None, trust=False):
|
def __init__(self, config, org=None, api_key=None, engineer_model=None, architect_model=None, engineer_api_key=None, architect_api_key=None, console=None, confirm_handler=None, trust=False, engineer_auth=None, architect_auth=None, **kwargs):
|
||||||
self.config = config
|
self.config = config
|
||||||
self.console = console or printer.console
|
self.console = console or printer.console
|
||||||
self.confirm_handler = confirm_handler or self._local_confirm_handler
|
self.confirm_handler = confirm_handler or self._local_confirm_handler
|
||||||
@@ -657,6 +653,29 @@ class ai:
|
|||||||
self.engineer_key = engineer_api_key or aiconfig.get("engineer_api_key")
|
self.engineer_key = engineer_api_key or aiconfig.get("engineer_api_key")
|
||||||
self.architect_key = architect_api_key or aiconfig.get("architect_api_key")
|
self.architect_key = architect_api_key or aiconfig.get("architect_api_key")
|
||||||
|
|
||||||
|
# Auth configurations (Prioridad: Argumento -> Config)
|
||||||
|
self.engineer_auth = engineer_auth if engineer_auth is not None else aiconfig.get("engineer_auth")
|
||||||
|
if self.engineer_auth is None:
|
||||||
|
self.engineer_auth = {}
|
||||||
|
elif not isinstance(self.engineer_auth, dict):
|
||||||
|
self.engineer_auth = {}
|
||||||
|
|
||||||
|
self.architect_auth = architect_auth if architect_auth is not None else aiconfig.get("architect_auth")
|
||||||
|
if self.architect_auth is None:
|
||||||
|
self.architect_auth = {}
|
||||||
|
elif not isinstance(self.architect_auth, dict):
|
||||||
|
self.architect_auth = {}
|
||||||
|
|
||||||
|
# Backward compatibility fallbacks: only inject api_key if the auth dict is empty/not configured
|
||||||
|
if self.engineer_key and not self.engineer_auth:
|
||||||
|
self.engineer_auth["api_key"] = self.engineer_key
|
||||||
|
if self.architect_key and not self.architect_auth:
|
||||||
|
self.architect_auth["api_key"] = self.architect_key
|
||||||
|
|
||||||
|
# Strategic Reasoning Engine (Architect) availability
|
||||||
|
is_architect_keyless = "vertex" in self.architect_model.lower() or "ollama" in self.architect_model.lower() or "local" in self.architect_model.lower()
|
||||||
|
self.has_architect = bool(self.architect_key or self.architect_auth or is_architect_keyless)
|
||||||
|
|
||||||
# Custom Trusted Commands Regexes
|
# Custom Trusted Commands Regexes
|
||||||
custom_trusted = aiconfig.get("trusted_commands", [])
|
custom_trusted = aiconfig.get("trusted_commands", [])
|
||||||
if isinstance(custom_trusted, str):
|
if isinstance(custom_trusted, str):
|
||||||
@@ -697,12 +716,12 @@ class ai:
|
|||||||
# Session Management
|
# Session Management
|
||||||
self.sessions_dir = os.path.join(self.config.defaultdir, "ai_sessions")
|
self.sessions_dir = os.path.join(self.config.defaultdir, "ai_sessions")
|
||||||
os.makedirs(self.sessions_dir, exist_ok=True)
|
os.makedirs(self.sessions_dir, exist_ok=True)
|
||||||
self.session_id = None
|
self.session_id = getattr(self.config, "session_id", None)
|
||||||
self.session_path = None
|
self.session_path = os.path.join(self.sessions_dir, f"{self.session_id}.json") if self.session_id else None
|
||||||
|
|
||||||
# Prompts base agnósticos
|
# Prompts base agnósticos
|
||||||
architect_instructions = ""
|
architect_instructions = ""
|
||||||
if self.architect_key:
|
if self.has_architect:
|
||||||
architect_instructions = """
|
architect_instructions = """
|
||||||
CRITICAL - CONSULT vs ESCALATE:
|
CRITICAL - CONSULT vs ESCALATE:
|
||||||
- ALWAYS use 'consult_architect' for: Configuration planning, design decisions, complex troubleshooting.
|
- ALWAYS use 'consult_architect' for: Configuration planning, design decisions, complex troubleshooting.
|
||||||
@@ -718,7 +737,7 @@ class ai:
|
|||||||
else:
|
else:
|
||||||
architect_instructions = """
|
architect_instructions = """
|
||||||
CRITICAL - ARCHITECT UNAVAILABLE:
|
CRITICAL - ARCHITECT UNAVAILABLE:
|
||||||
- The Strategic Reasoning Engine (Architect) is currently UNAVAILABLE because its API key is not configured.
|
- The Strategic Reasoning Engine (Architect) is currently UNAVAILABLE because its API key or authentication is not configured.
|
||||||
- DO NOT attempt to consult or escalate to the architect.
|
- DO NOT attempt to consult or escalate to the architect.
|
||||||
- If the user asks to consult the architect, inform them that the Architect is offline and offer to help them directly to the best of your abilities.
|
- If the user asks to consult the architect, inform them that the Architect is offline and offer to help them directly to the best of your abilities.
|
||||||
"""
|
"""
|
||||||
@@ -824,15 +843,19 @@ class ai:
|
|||||||
if status_formatter:
|
if status_formatter:
|
||||||
self.tool_status_formatters[name] = status_formatter
|
self.tool_status_formatters[name] = status_formatter
|
||||||
|
|
||||||
def _stream_completion(self, model, messages, tools, api_key, status=None, label="", debug=False, chunk_callback=None, **kwargs):
|
def _stream_completion(self, model, messages, tools, api_key=None, status=None, label="", debug=False, chunk_callback=None, auth=None, **kwargs):
|
||||||
"""Stream a completion call, rendering styled Markdown in real-time.
|
"""Stream a completion call, rendering styled Markdown in real-time.
|
||||||
|
|
||||||
Returns (response, streamed) where:
|
Returns (response, streamed) where:
|
||||||
- response: reconstructed ModelResponse (same as non-streaming)
|
- response: reconstructed ModelResponse (same as non-streaming)
|
||||||
- streamed: True if text was rendered to console during streaming
|
- streamed: True if text was rendered to console during streaming
|
||||||
"""
|
"""
|
||||||
|
auth_dict = auth if auth is not None else {}
|
||||||
|
if api_key and "api_key" not in auth_dict:
|
||||||
|
auth_dict = auth_dict.copy()
|
||||||
|
auth_dict["api_key"] = api_key
|
||||||
|
|
||||||
stream_resp = completion(model=model, messages=messages, tools=tools, api_key=api_key, stream=True, **kwargs)
|
stream_resp = completion(model=model, messages=messages, tools=tools, stream=True, **auth_dict, **kwargs)
|
||||||
|
|
||||||
chunks = []
|
chunks = []
|
||||||
full_content = ""
|
full_content = ""
|
||||||
@@ -1275,7 +1298,7 @@ class ai:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
safe_messages = self._sanitize_messages(messages)
|
safe_messages = self._sanitize_messages(messages)
|
||||||
response = completion(model=self.engineer_model, messages=safe_messages, tools=tools, api_key=self.engineer_key)
|
response = completion(model=self.engineer_model, messages=safe_messages, tools=tools, **self.engineer_auth)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if status: status.stop()
|
if status: status.stop()
|
||||||
raise ValueError(f"Engineer failed to connect: {str(e)}")
|
raise ValueError(f"Engineer failed to connect: {str(e)}")
|
||||||
@@ -1409,16 +1432,27 @@ class ai:
|
|||||||
continue
|
continue
|
||||||
return sorted(sessions, key=lambda x: x["created_at"], reverse=True)
|
return sorted(sessions, key=lambda x: x["created_at"], reverse=True)
|
||||||
|
|
||||||
def list_sessions(self):
|
def list_sessions(self, limit=20):
|
||||||
"""Prints a list of sessions using printer.table."""
|
"""Prints a list of sessions using printer.table."""
|
||||||
sessions = self._get_sessions()
|
sessions = self._get_sessions()
|
||||||
if not sessions:
|
if not sessions:
|
||||||
printer.info("No saved AI sessions found.")
|
printer.info("No saved AI sessions found.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
total = len(sessions)
|
||||||
|
if limit and total > limit:
|
||||||
|
sessions = sessions[:limit]
|
||||||
|
|
||||||
columns = ["ID", "Title", "Created At", "Model"]
|
columns = ["ID", "Title", "Created At", "Model"]
|
||||||
rows = [[s["id"], s["title"], s["created_at"], s["model"]] for s in sessions]
|
rows = [[s["id"], s["title"], s["created_at"], s["model"]] for s in sessions]
|
||||||
printer.table("AI Persisted Sessions", columns, rows)
|
|
||||||
|
title = "AI Persisted Sessions"
|
||||||
|
if limit and total > limit:
|
||||||
|
title += f" (Showing last {limit} of {total})"
|
||||||
|
|
||||||
|
printer.table(title, columns, rows)
|
||||||
|
if limit and total > limit:
|
||||||
|
printer.info(f"Use '--list --all' (if supported) or check the sessions directory to see all {total} sessions.")
|
||||||
|
|
||||||
def load_session_data(self, session_id):
|
def load_session_data(self, session_id):
|
||||||
"""Loads a session's raw data by ID."""
|
"""Loads a session's raw data by ID."""
|
||||||
@@ -1449,8 +1483,10 @@ class ai:
|
|||||||
return sessions[0]["id"] if sessions else None
|
return sessions[0]["id"] if sessions else None
|
||||||
|
|
||||||
def _generate_session_id(self, query):
|
def _generate_session_id(self, query):
|
||||||
"""Generates a unique session ID based on timestamp."""
|
"""Generates a unique session ID based on timestamp and a random suffix."""
|
||||||
return datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
|
ts = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
|
||||||
|
suffix = secrets.token_hex(2)
|
||||||
|
return f"{ts}-{suffix}"
|
||||||
|
|
||||||
def save_session(self, history, title=None, model=None):
|
def save_session(self, history, title=None, model=None):
|
||||||
"""Saves current history to the session file."""
|
"""Saves current history to the session file."""
|
||||||
@@ -1459,6 +1495,8 @@ class ai:
|
|||||||
first_user_msg = next((m["content"] for m in history if m["role"] == "user"), "new-session")
|
first_user_msg = next((m["content"] for m in history if m["role"] == "user"), "new-session")
|
||||||
self.session_id = self._generate_session_id(first_user_msg)
|
self.session_id = self._generate_session_id(first_user_msg)
|
||||||
self.session_path = os.path.join(self.sessions_dir, f"{self.session_id}.json")
|
self.session_path = os.path.join(self.sessions_dir, f"{self.session_id}.json")
|
||||||
|
elif not self.session_path:
|
||||||
|
self.session_path = os.path.join(self.sessions_dir, f"{self.session_id}.json")
|
||||||
|
|
||||||
# If it's a new file, we might want to set a better title
|
# If it's a new file, we might want to set a better title
|
||||||
if not os.path.exists(self.session_path) and not title:
|
if not os.path.exists(self.session_path) and not title:
|
||||||
@@ -1496,16 +1534,22 @@ class ai:
|
|||||||
|
|
||||||
@MethodHook
|
@MethodHook
|
||||||
def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=False, stream=True, session_id=None, chunk_callback=None):
|
def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=False, stream=True, session_id=None, chunk_callback=None):
|
||||||
if not self.engineer_key:
|
is_engineer_keyless = "vertex" in self.engineer_model.lower() or "ollama" in self.engineer_model.lower() or "local" in self.engineer_model.lower()
|
||||||
raise ValueError("Engineer API key not configured. Use 'connpy config --engineer-api-key <key>' to set it.")
|
if not self.engineer_key and not self.engineer_auth and not is_engineer_keyless:
|
||||||
|
raise ValueError("Engineer API key or authentication not configured. Use 'connpy config --engineer-auth <auth>' to set it.")
|
||||||
|
|
||||||
if chat_history is None: chat_history = []
|
if chat_history is None: chat_history = []
|
||||||
|
|
||||||
# Load session if provided and history is empty
|
# Load session if provided and history is empty
|
||||||
if session_id and not chat_history:
|
if session_id:
|
||||||
session_data = self.load_session_data(session_id)
|
# Force the session_id even if it doesn't exist yet
|
||||||
if session_data:
|
self.session_id = session_id
|
||||||
chat_history = session_data.get("history", [])
|
self.session_path = os.path.join(self.sessions_dir, f"{session_id}.json")
|
||||||
|
|
||||||
|
if not chat_history:
|
||||||
|
session_data = self.load_session_data(session_id)
|
||||||
|
if session_data:
|
||||||
|
chat_history = session_data.get("history", [])
|
||||||
# If we loaded history, the caller might need it back
|
# If we loaded history, the caller might need it back
|
||||||
# But typically ask() is called in a loop with an external history object
|
# But typically ask() is called in a loop with an external history object
|
||||||
|
|
||||||
@@ -1541,6 +1585,7 @@ class ai:
|
|||||||
tools = self._get_architect_tools() if current_brain == "architect" else self._get_engineer_tools()
|
tools = self._get_architect_tools() if current_brain == "architect" else self._get_engineer_tools()
|
||||||
model = self.architect_model if current_brain == "architect" else self.engineer_model
|
model = self.architect_model if current_brain == "architect" else self.engineer_model
|
||||||
key = self.architect_key if current_brain == "architect" else self.engineer_key
|
key = self.architect_key if current_brain == "architect" else self.engineer_key
|
||||||
|
current_auth = self.architect_auth if current_brain == "architect" else self.engineer_auth
|
||||||
|
|
||||||
# Estructura optimizada para Prompt Caching (Solo para Anthropic directo, Vertex tiene reglas distintas)
|
# Estructura optimizada para Prompt Caching (Solo para Anthropic directo, Vertex tiene reglas distintas)
|
||||||
if "claude" in model.lower() and "vertex" not in model.lower():
|
if "claude" in model.lower() and "vertex" not in model.lower():
|
||||||
@@ -1590,8 +1635,8 @@ class ai:
|
|||||||
|
|
||||||
label = "[architect][bold]Architect[/bold][/architect]" if current_brain == "architect" else "[engineer][bold]Engineer[/bold][/engineer]"
|
label = "[architect][bold]Architect[/bold][/architect]" if current_brain == "architect" else "[engineer][bold]Engineer[/bold][/engineer]"
|
||||||
if status:
|
if status:
|
||||||
# Notify responder identity ONLY for web/remote clients (StatusBridge has is_web)
|
# Notify responder identity for web/remote clients
|
||||||
if getattr(status, "is_web", False):
|
if getattr(status, "is_web", False) or getattr(status, "is_remote", False):
|
||||||
status.update(f"__RESPONDER__:{current_brain}")
|
status.update(f"__RESPONDER__:{current_brain}")
|
||||||
status.update(f"{label} is thinking... (step {iteration})")
|
status.update(f"{label} is thinking... (step {iteration})")
|
||||||
|
|
||||||
@@ -1600,12 +1645,12 @@ class ai:
|
|||||||
safe_messages = self._sanitize_messages(messages)
|
safe_messages = self._sanitize_messages(messages)
|
||||||
if stream:
|
if stream:
|
||||||
response, streamed_response = self._stream_completion(
|
response, streamed_response = self._stream_completion(
|
||||||
model=model, messages=safe_messages, tools=tools, api_key=key,
|
model=model, messages=safe_messages, tools=tools, auth=current_auth,
|
||||||
status=status, label=label, debug=debug, num_retries=3,
|
status=status, label=label, debug=debug, num_retries=3,
|
||||||
chunk_callback=chunk_callback
|
chunk_callback=chunk_callback
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
response = completion(model=model, messages=safe_messages, tools=tools, api_key=key, num_retries=3)
|
response = completion(model=model, messages=safe_messages, tools=tools, num_retries=3, **current_auth)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if current_brain == "architect":
|
if current_brain == "architect":
|
||||||
if status: status.update("[unavailable]Architect unavailable! Falling back to Engineer...")
|
if status: status.update("[unavailable]Architect unavailable! Falling back to Engineer...")
|
||||||
@@ -1614,6 +1659,7 @@ class ai:
|
|||||||
model = self.engineer_model
|
model = self.engineer_model
|
||||||
tools = self._get_engineer_tools()
|
tools = self._get_engineer_tools()
|
||||||
key = self.engineer_key
|
key = self.engineer_key
|
||||||
|
current_auth = self.engineer_auth
|
||||||
# Rebuild messages with Engineer system prompt and original user request
|
# Rebuild messages with Engineer system prompt and original user request
|
||||||
messages = [{"role": "system", "content": self.engineer_system_prompt}]
|
messages = [{"role": "system", "content": self.engineer_system_prompt}]
|
||||||
# Add chat history if exists (excluding system prompt)
|
# Add chat history if exists (excluding system prompt)
|
||||||
@@ -1706,6 +1752,7 @@ class ai:
|
|||||||
model = self.architect_model
|
model = self.architect_model
|
||||||
tools = self._get_architect_tools()
|
tools = self._get_architect_tools()
|
||||||
key = self.architect_key
|
key = self.architect_key
|
||||||
|
current_auth = self.architect_auth
|
||||||
messages[0] = {"role": "system", "content": self.architect_system_prompt}
|
messages[0] = {"role": "system", "content": self.architect_system_prompt}
|
||||||
# Prepare handover context to inject AFTER all tool responses
|
# Prepare handover context to inject AFTER all tool responses
|
||||||
handover_msg = f"HANDOVER FROM EXECUTION ENGINE\n\nReason: {args['reason']}\n\nContext: {args['context']}\n\nYou are now in control of this conversation."
|
handover_msg = f"HANDOVER FROM EXECUTION ENGINE\n\nReason: {args['reason']}\n\nContext: {args['context']}\n\nYou are now in control of this conversation."
|
||||||
@@ -1727,6 +1774,7 @@ class ai:
|
|||||||
model = self.engineer_model
|
model = self.engineer_model
|
||||||
tools = self._get_engineer_tools()
|
tools = self._get_engineer_tools()
|
||||||
key = self.engineer_key
|
key = self.engineer_key
|
||||||
|
current_auth = self.engineer_auth
|
||||||
messages[0] = {"role": "system", "content": self.engineer_system_prompt}
|
messages[0] = {"role": "system", "content": self.engineer_system_prompt}
|
||||||
# Prepare handover context to inject AFTER all tool responses
|
# Prepare handover context to inject AFTER all tool responses
|
||||||
handover_msg = f"HANDOVER FROM ARCHITECT\n\nSummary: {args['summary']}\n\nYou are now back in control. Continue handling the user's requests."
|
handover_msg = f"HANDOVER FROM ARCHITECT\n\nSummary: {args['summary']}\n\nYou are now back in control. Continue handling the user's requests."
|
||||||
@@ -1768,7 +1816,7 @@ class ai:
|
|||||||
messages.append({"role": "user", "content": "Hard iteration limit reached. Please provide a summary of your findings so far."})
|
messages.append({"role": "user", "content": "Hard iteration limit reached. Please provide a summary of your findings so far."})
|
||||||
try:
|
try:
|
||||||
safe_messages = self._sanitize_messages(messages)
|
safe_messages = self._sanitize_messages(messages)
|
||||||
response = completion(model=model, messages=safe_messages, tools=[], api_key=key)
|
response = completion(model=model, messages=safe_messages, tools=[], **current_auth)
|
||||||
resp_msg = response.choices[0].message
|
resp_msg = response.choices[0].message
|
||||||
messages.append(resp_msg.model_dump(exclude_none=True))
|
messages.append(resp_msg.model_dump(exclude_none=True))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -1788,7 +1836,7 @@ class ai:
|
|||||||
try:
|
try:
|
||||||
safe_messages = self._sanitize_messages(summary_messages)
|
safe_messages = self._sanitize_messages(summary_messages)
|
||||||
# Use tools=None to force a text summary during interruption
|
# Use tools=None to force a text summary during interruption
|
||||||
response = completion(model=model, messages=safe_messages, tools=None, api_key=key)
|
response = completion(model=model, messages=safe_messages, tools=None, **current_auth)
|
||||||
resp_msg = response.choices[0].message
|
resp_msg = response.choices[0].message
|
||||||
messages.append(resp_msg.model_dump(exclude_none=True))
|
messages.append(resp_msg.model_dump(exclude_none=True))
|
||||||
|
|
||||||
@@ -1925,6 +1973,7 @@ Node: {node_name}"""
|
|||||||
# Use models based on persona
|
# Use models based on persona
|
||||||
current_model = self.architect_model if persona == "architect" else self.engineer_model
|
current_model = self.architect_model if persona == "architect" else self.engineer_model
|
||||||
current_key = self.architect_key if persona == "architect" else self.engineer_key
|
current_key = self.architect_key if persona == "architect" else self.engineer_key
|
||||||
|
current_auth = self.architect_auth if persona == "architect" else self.engineer_auth
|
||||||
|
|
||||||
try:
|
try:
|
||||||
while iteration < max_iterations:
|
while iteration < max_iterations:
|
||||||
@@ -1934,8 +1983,8 @@ Node: {node_name}"""
|
|||||||
model=current_model,
|
model=current_model,
|
||||||
messages=messages,
|
messages=messages,
|
||||||
tools=mcp_tools if mcp_tools else None,
|
tools=mcp_tools if mcp_tools else None,
|
||||||
api_key=current_key,
|
stream=True,
|
||||||
stream=True
|
**current_auth
|
||||||
)
|
)
|
||||||
|
|
||||||
full_content = ""
|
full_content = ""
|
||||||
@@ -2008,8 +2057,8 @@ Node: {node_name}"""
|
|||||||
model=self.engineer_model,
|
model=self.engineer_model,
|
||||||
messages=messages,
|
messages=messages,
|
||||||
tools=None,
|
tools=None,
|
||||||
api_key=self.engineer_key,
|
stream=True,
|
||||||
stream=True
|
**self.engineer_auth
|
||||||
)
|
)
|
||||||
|
|
||||||
full_content = ""
|
full_content = ""
|
||||||
@@ -2095,7 +2144,7 @@ Node: {node_name}"""
|
|||||||
<dl>
|
<dl>
|
||||||
<dt id="connpy.ai.SAFE_COMMANDS"><code class="name">var <span class="ident">SAFE_COMMANDS</span></code></dt>
|
<dt id="connpy.ai.SAFE_COMMANDS"><code class="name">var <span class="ident">SAFE_COMMANDS</span></code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<div class="desc"></div>
|
<div class="desc"><p>The type of the None singleton.</p></div>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<h3>Instance variables</h3>
|
<h3>Instance variables</h3>
|
||||||
@@ -2255,6 +2304,7 @@ Node: {node_name}"""
|
|||||||
# Use models based on persona
|
# Use models based on persona
|
||||||
current_model = self.architect_model if persona == "architect" else self.engineer_model
|
current_model = self.architect_model if persona == "architect" else self.engineer_model
|
||||||
current_key = self.architect_key if persona == "architect" else self.engineer_key
|
current_key = self.architect_key if persona == "architect" else self.engineer_key
|
||||||
|
current_auth = self.architect_auth if persona == "architect" else self.engineer_auth
|
||||||
|
|
||||||
try:
|
try:
|
||||||
while iteration < max_iterations:
|
while iteration < max_iterations:
|
||||||
@@ -2264,8 +2314,8 @@ Node: {node_name}"""
|
|||||||
model=current_model,
|
model=current_model,
|
||||||
messages=messages,
|
messages=messages,
|
||||||
tools=mcp_tools if mcp_tools else None,
|
tools=mcp_tools if mcp_tools else None,
|
||||||
api_key=current_key,
|
stream=True,
|
||||||
stream=True
|
**current_auth
|
||||||
)
|
)
|
||||||
|
|
||||||
full_content = ""
|
full_content = ""
|
||||||
@@ -2338,8 +2388,8 @@ Node: {node_name}"""
|
|||||||
model=self.engineer_model,
|
model=self.engineer_model,
|
||||||
messages=messages,
|
messages=messages,
|
||||||
tools=None,
|
tools=None,
|
||||||
api_key=self.engineer_key,
|
stream=True,
|
||||||
stream=True
|
**self.engineer_auth
|
||||||
)
|
)
|
||||||
|
|
||||||
full_content = ""
|
full_content = ""
|
||||||
@@ -2429,16 +2479,22 @@ Node: {node_name}"""
|
|||||||
</summary>
|
</summary>
|
||||||
<pre><code class="python">@MethodHook
|
<pre><code class="python">@MethodHook
|
||||||
def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=False, stream=True, session_id=None, chunk_callback=None):
|
def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=False, stream=True, session_id=None, chunk_callback=None):
|
||||||
if not self.engineer_key:
|
is_engineer_keyless = "vertex" in self.engineer_model.lower() or "ollama" in self.engineer_model.lower() or "local" in self.engineer_model.lower()
|
||||||
raise ValueError("Engineer API key not configured. Use 'connpy config --engineer-api-key <key>' to set it.")
|
if not self.engineer_key and not self.engineer_auth and not is_engineer_keyless:
|
||||||
|
raise ValueError("Engineer API key or authentication not configured. Use 'connpy config --engineer-auth <auth>' to set it.")
|
||||||
|
|
||||||
if chat_history is None: chat_history = []
|
if chat_history is None: chat_history = []
|
||||||
|
|
||||||
# Load session if provided and history is empty
|
# Load session if provided and history is empty
|
||||||
if session_id and not chat_history:
|
if session_id:
|
||||||
session_data = self.load_session_data(session_id)
|
# Force the session_id even if it doesn't exist yet
|
||||||
if session_data:
|
self.session_id = session_id
|
||||||
chat_history = session_data.get("history", [])
|
self.session_path = os.path.join(self.sessions_dir, f"{session_id}.json")
|
||||||
|
|
||||||
|
if not chat_history:
|
||||||
|
session_data = self.load_session_data(session_id)
|
||||||
|
if session_data:
|
||||||
|
chat_history = session_data.get("history", [])
|
||||||
# If we loaded history, the caller might need it back
|
# If we loaded history, the caller might need it back
|
||||||
# But typically ask() is called in a loop with an external history object
|
# But typically ask() is called in a loop with an external history object
|
||||||
|
|
||||||
@@ -2474,6 +2530,7 @@ def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=Fa
|
|||||||
tools = self._get_architect_tools() if current_brain == "architect" else self._get_engineer_tools()
|
tools = self._get_architect_tools() if current_brain == "architect" else self._get_engineer_tools()
|
||||||
model = self.architect_model if current_brain == "architect" else self.engineer_model
|
model = self.architect_model if current_brain == "architect" else self.engineer_model
|
||||||
key = self.architect_key if current_brain == "architect" else self.engineer_key
|
key = self.architect_key if current_brain == "architect" else self.engineer_key
|
||||||
|
current_auth = self.architect_auth if current_brain == "architect" else self.engineer_auth
|
||||||
|
|
||||||
# Estructura optimizada para Prompt Caching (Solo para Anthropic directo, Vertex tiene reglas distintas)
|
# Estructura optimizada para Prompt Caching (Solo para Anthropic directo, Vertex tiene reglas distintas)
|
||||||
if "claude" in model.lower() and "vertex" not in model.lower():
|
if "claude" in model.lower() and "vertex" not in model.lower():
|
||||||
@@ -2523,8 +2580,8 @@ def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=Fa
|
|||||||
|
|
||||||
label = "[architect][bold]Architect[/bold][/architect]" if current_brain == "architect" else "[engineer][bold]Engineer[/bold][/engineer]"
|
label = "[architect][bold]Architect[/bold][/architect]" if current_brain == "architect" else "[engineer][bold]Engineer[/bold][/engineer]"
|
||||||
if status:
|
if status:
|
||||||
# Notify responder identity ONLY for web/remote clients (StatusBridge has is_web)
|
# Notify responder identity for web/remote clients
|
||||||
if getattr(status, "is_web", False):
|
if getattr(status, "is_web", False) or getattr(status, "is_remote", False):
|
||||||
status.update(f"__RESPONDER__:{current_brain}")
|
status.update(f"__RESPONDER__:{current_brain}")
|
||||||
status.update(f"{label} is thinking... (step {iteration})")
|
status.update(f"{label} is thinking... (step {iteration})")
|
||||||
|
|
||||||
@@ -2533,12 +2590,12 @@ def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=Fa
|
|||||||
safe_messages = self._sanitize_messages(messages)
|
safe_messages = self._sanitize_messages(messages)
|
||||||
if stream:
|
if stream:
|
||||||
response, streamed_response = self._stream_completion(
|
response, streamed_response = self._stream_completion(
|
||||||
model=model, messages=safe_messages, tools=tools, api_key=key,
|
model=model, messages=safe_messages, tools=tools, auth=current_auth,
|
||||||
status=status, label=label, debug=debug, num_retries=3,
|
status=status, label=label, debug=debug, num_retries=3,
|
||||||
chunk_callback=chunk_callback
|
chunk_callback=chunk_callback
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
response = completion(model=model, messages=safe_messages, tools=tools, api_key=key, num_retries=3)
|
response = completion(model=model, messages=safe_messages, tools=tools, num_retries=3, **current_auth)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if current_brain == "architect":
|
if current_brain == "architect":
|
||||||
if status: status.update("[unavailable]Architect unavailable! Falling back to Engineer...")
|
if status: status.update("[unavailable]Architect unavailable! Falling back to Engineer...")
|
||||||
@@ -2547,6 +2604,7 @@ def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=Fa
|
|||||||
model = self.engineer_model
|
model = self.engineer_model
|
||||||
tools = self._get_engineer_tools()
|
tools = self._get_engineer_tools()
|
||||||
key = self.engineer_key
|
key = self.engineer_key
|
||||||
|
current_auth = self.engineer_auth
|
||||||
# Rebuild messages with Engineer system prompt and original user request
|
# Rebuild messages with Engineer system prompt and original user request
|
||||||
messages = [{"role": "system", "content": self.engineer_system_prompt}]
|
messages = [{"role": "system", "content": self.engineer_system_prompt}]
|
||||||
# Add chat history if exists (excluding system prompt)
|
# Add chat history if exists (excluding system prompt)
|
||||||
@@ -2639,6 +2697,7 @@ def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=Fa
|
|||||||
model = self.architect_model
|
model = self.architect_model
|
||||||
tools = self._get_architect_tools()
|
tools = self._get_architect_tools()
|
||||||
key = self.architect_key
|
key = self.architect_key
|
||||||
|
current_auth = self.architect_auth
|
||||||
messages[0] = {"role": "system", "content": self.architect_system_prompt}
|
messages[0] = {"role": "system", "content": self.architect_system_prompt}
|
||||||
# Prepare handover context to inject AFTER all tool responses
|
# Prepare handover context to inject AFTER all tool responses
|
||||||
handover_msg = f"HANDOVER FROM EXECUTION ENGINE\n\nReason: {args['reason']}\n\nContext: {args['context']}\n\nYou are now in control of this conversation."
|
handover_msg = f"HANDOVER FROM EXECUTION ENGINE\n\nReason: {args['reason']}\n\nContext: {args['context']}\n\nYou are now in control of this conversation."
|
||||||
@@ -2660,6 +2719,7 @@ def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=Fa
|
|||||||
model = self.engineer_model
|
model = self.engineer_model
|
||||||
tools = self._get_engineer_tools()
|
tools = self._get_engineer_tools()
|
||||||
key = self.engineer_key
|
key = self.engineer_key
|
||||||
|
current_auth = self.engineer_auth
|
||||||
messages[0] = {"role": "system", "content": self.engineer_system_prompt}
|
messages[0] = {"role": "system", "content": self.engineer_system_prompt}
|
||||||
# Prepare handover context to inject AFTER all tool responses
|
# Prepare handover context to inject AFTER all tool responses
|
||||||
handover_msg = f"HANDOVER FROM ARCHITECT\n\nSummary: {args['summary']}\n\nYou are now back in control. Continue handling the user's requests."
|
handover_msg = f"HANDOVER FROM ARCHITECT\n\nSummary: {args['summary']}\n\nYou are now back in control. Continue handling the user's requests."
|
||||||
@@ -2701,7 +2761,7 @@ def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=Fa
|
|||||||
messages.append({"role": "user", "content": "Hard iteration limit reached. Please provide a summary of your findings so far."})
|
messages.append({"role": "user", "content": "Hard iteration limit reached. Please provide a summary of your findings so far."})
|
||||||
try:
|
try:
|
||||||
safe_messages = self._sanitize_messages(messages)
|
safe_messages = self._sanitize_messages(messages)
|
||||||
response = completion(model=model, messages=safe_messages, tools=[], api_key=key)
|
response = completion(model=model, messages=safe_messages, tools=[], **current_auth)
|
||||||
resp_msg = response.choices[0].message
|
resp_msg = response.choices[0].message
|
||||||
messages.append(resp_msg.model_dump(exclude_none=True))
|
messages.append(resp_msg.model_dump(exclude_none=True))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -2721,7 +2781,7 @@ def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=Fa
|
|||||||
try:
|
try:
|
||||||
safe_messages = self._sanitize_messages(summary_messages)
|
safe_messages = self._sanitize_messages(summary_messages)
|
||||||
# Use tools=None to force a text summary during interruption
|
# Use tools=None to force a text summary during interruption
|
||||||
response = completion(model=model, messages=safe_messages, tools=None, api_key=key)
|
response = completion(model=model, messages=safe_messages, tools=None, **current_auth)
|
||||||
resp_msg = response.choices[0].message
|
resp_msg = response.choices[0].message
|
||||||
messages.append(resp_msg.model_dump(exclude_none=True))
|
messages.append(resp_msg.model_dump(exclude_none=True))
|
||||||
|
|
||||||
@@ -2844,23 +2904,34 @@ def confirm(self, user_input): return True</code></pre>
|
|||||||
<div class="desc"><p>List nodes matching the filter pattern. Returns metadata for <=5 nodes, names only for more.</p></div>
|
<div class="desc"><p>List nodes matching the filter pattern. Returns metadata for <=5 nodes, names only for more.</p></div>
|
||||||
</dd>
|
</dd>
|
||||||
<dt id="connpy.ai.list_sessions"><code class="name flex">
|
<dt id="connpy.ai.list_sessions"><code class="name flex">
|
||||||
<span>def <span class="ident">list_sessions</span></span>(<span>self)</span>
|
<span>def <span class="ident">list_sessions</span></span>(<span>self, limit=20)</span>
|
||||||
</code></dt>
|
</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<details class="source">
|
<details class="source">
|
||||||
<summary>
|
<summary>
|
||||||
<span>Expand source code</span>
|
<span>Expand source code</span>
|
||||||
</summary>
|
</summary>
|
||||||
<pre><code class="python">def list_sessions(self):
|
<pre><code class="python">def list_sessions(self, limit=20):
|
||||||
"""Prints a list of sessions using printer.table."""
|
"""Prints a list of sessions using printer.table."""
|
||||||
sessions = self._get_sessions()
|
sessions = self._get_sessions()
|
||||||
if not sessions:
|
if not sessions:
|
||||||
printer.info("No saved AI sessions found.")
|
printer.info("No saved AI sessions found.")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
total = len(sessions)
|
||||||
|
if limit and total > limit:
|
||||||
|
sessions = sessions[:limit]
|
||||||
|
|
||||||
columns = ["ID", "Title", "Created At", "Model"]
|
columns = ["ID", "Title", "Created At", "Model"]
|
||||||
rows = [[s["id"], s["title"], s["created_at"], s["model"]] for s in sessions]
|
rows = [[s["id"], s["title"], s["created_at"], s["model"]] for s in sessions]
|
||||||
printer.table("AI Persisted Sessions", columns, rows)</code></pre>
|
|
||||||
|
title = "AI Persisted Sessions"
|
||||||
|
if limit and total > limit:
|
||||||
|
title += f" (Showing last {limit} of {total})"
|
||||||
|
|
||||||
|
printer.table(title, columns, rows)
|
||||||
|
if limit and total > limit:
|
||||||
|
printer.info(f"Use '--list --all' (if supported) or check the sessions directory to see all {total} sessions.")</code></pre>
|
||||||
</details>
|
</details>
|
||||||
<div class="desc"><p>Prints a list of sessions using printer.table.</p></div>
|
<div class="desc"><p>Prints a list of sessions using printer.table.</p></div>
|
||||||
</dd>
|
</dd>
|
||||||
@@ -3070,6 +3141,8 @@ def confirm(self, user_input): return True</code></pre>
|
|||||||
first_user_msg = next((m["content"] for m in history if m["role"] == "user"), "new-session")
|
first_user_msg = next((m["content"] for m in history if m["role"] == "user"), "new-session")
|
||||||
self.session_id = self._generate_session_id(first_user_msg)
|
self.session_id = self._generate_session_id(first_user_msg)
|
||||||
self.session_path = os.path.join(self.sessions_dir, f"{self.session_id}.json")
|
self.session_path = os.path.join(self.sessions_dir, f"{self.session_id}.json")
|
||||||
|
elif not self.session_path:
|
||||||
|
self.session_path = os.path.join(self.sessions_dir, f"{self.session_id}.json")
|
||||||
|
|
||||||
# If it's a new file, we might want to set a better title
|
# If it's a new file, we might want to set a better title
|
||||||
if not os.path.exists(self.session_path) and not title:
|
if not os.path.exists(self.session_path) and not title:
|
||||||
@@ -4226,8 +4299,11 @@ class node:
|
|||||||
|
|
||||||
|
|
||||||
def _setup_interact_environment(self, debug=False, logger=None, async_mode=False):
|
def _setup_interact_environment(self, debug=False, logger=None, async_mode=False):
|
||||||
size = re.search('columns=([0-9]+).*lines=([0-9]+)',str(os.get_terminal_size()))
|
try:
|
||||||
self.child.setwinsize(int(size.group(2)),int(size.group(1)))
|
size = re.search('columns=([0-9]+).*lines=([0-9]+)',str(os.get_terminal_size()))
|
||||||
|
self.child.setwinsize(int(size.group(2)),int(size.group(1)))
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
if logger:
|
if logger:
|
||||||
port_str = f":{self.port}" if self.port and self.protocol not in ["ssm", "kubectl", "docker"] else ""
|
port_str = f":{self.port}" if self.port and self.protocol not in ["ssm", "kubectl", "docker"] else ""
|
||||||
logger("success", f"Connected to {self.unique} at {self.host}{port_str} via: {self.protocol}")
|
logger("success", f"Connected to {self.unique} at {self.host}{port_str} via: {self.protocol}")
|
||||||
@@ -4264,6 +4340,7 @@ class node:
|
|||||||
|
|
||||||
async def _async_interact_loop(self, local_stream, resize_callback, copilot_handler=None):
|
async def _async_interact_loop(self, local_stream, resize_callback, copilot_handler=None):
|
||||||
local_stream.setup(resize_callback=resize_callback)
|
local_stream.setup(resize_callback=resize_callback)
|
||||||
|
self.current_local_stream = local_stream
|
||||||
try:
|
try:
|
||||||
child_fd = self.child.child_fd
|
child_fd = self.child.child_fd
|
||||||
|
|
||||||
@@ -4346,11 +4423,19 @@ class node:
|
|||||||
# Remove any stray \x00 bytes and forward normally
|
# Remove any stray \x00 bytes and forward normally
|
||||||
clean_data = data.replace(b'\x00', b'')
|
clean_data = data.replace(b'\x00', b'')
|
||||||
if clean_data:
|
if clean_data:
|
||||||
# Track command boundaries when user hits Enter
|
# Track command boundaries when user hits Enter or presses Ctrl+C
|
||||||
if hasattr(self, 'mylog') and (b'\r' in clean_data or b'\n' in clean_data):
|
if hasattr(self, 'mylog') and (b'\r' in clean_data or b'\n' in clean_data or b'\x03' in clean_data):
|
||||||
self.cmd_byte_positions.append((self.mylog.tell(), None))
|
pos = self.mylog.tell()
|
||||||
|
marker_cmd = "CANCELLED" if b'\x03' in clean_data else None
|
||||||
|
self.cmd_byte_positions.append((pos, marker_cmd))
|
||||||
|
if hasattr(self, 'current_local_stream') and self.current_local_stream is not None:
|
||||||
|
try:
|
||||||
|
await self.current_local_stream.write(f'\x1b]133;B;{pos}\x07'.encode())
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
try: os.write(child_fd, clean_data)
|
try:
|
||||||
|
os.write(child_fd, clean_data)
|
||||||
except OSError:
|
except OSError:
|
||||||
break
|
break
|
||||||
self.lastinput = time()
|
self.lastinput = time()
|
||||||
@@ -4470,6 +4555,7 @@ class node:
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
finally:
|
finally:
|
||||||
|
self.current_local_stream = None
|
||||||
local_stream.teardown()
|
local_stream.teardown()
|
||||||
|
|
||||||
@MethodHook
|
@MethodHook
|
||||||
@@ -4498,6 +4584,11 @@ class node:
|
|||||||
if cmd != slc and hasattr(self, 'cmd_byte_positions') and self.cmd_byte_positions is not None:
|
if cmd != slc and hasattr(self, 'cmd_byte_positions') and self.cmd_byte_positions is not None:
|
||||||
log_pos = self.mylog.tell() if hasattr(self, 'mylog') else 0
|
log_pos = self.mylog.tell() if hasattr(self, 'mylog') else 0
|
||||||
self.cmd_byte_positions.append((log_pos, cmd))
|
self.cmd_byte_positions.append((log_pos, cmd))
|
||||||
|
if hasattr(self, 'current_local_stream') and self.current_local_stream is not None:
|
||||||
|
try:
|
||||||
|
await self.current_local_stream.write(f'\x1b]133;B;{log_pos}\x07'.encode())
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
# Write physically to PTY
|
# Write physically to PTY
|
||||||
os.write(child_fd, (cmd + "\n").encode())
|
os.write(child_fd, (cmd + "\n").encode())
|
||||||
@@ -5137,6 +5228,11 @@ async def inject_commands(self, commands, child_fd, on_inject=None):
|
|||||||
if cmd != slc and hasattr(self, 'cmd_byte_positions') and self.cmd_byte_positions is not None:
|
if cmd != slc and hasattr(self, 'cmd_byte_positions') and self.cmd_byte_positions is not None:
|
||||||
log_pos = self.mylog.tell() if hasattr(self, 'mylog') else 0
|
log_pos = self.mylog.tell() if hasattr(self, 'mylog') else 0
|
||||||
self.cmd_byte_positions.append((log_pos, cmd))
|
self.cmd_byte_positions.append((log_pos, cmd))
|
||||||
|
if hasattr(self, 'current_local_stream') and self.current_local_stream is not None:
|
||||||
|
try:
|
||||||
|
await self.current_local_stream.write(f'\x1b]133;B;{log_pos}\x07'.encode())
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
# Write physically to PTY
|
# Write physically to PTY
|
||||||
os.write(child_fd, (cmd + "\n").encode())
|
os.write(child_fd, (cmd + "\n").encode())
|
||||||
@@ -6225,7 +6321,6 @@ def test(self, commands, expected, vars = None,*, folder = None, prompt = None,
|
|||||||
<li><code><a title="connpy.mcp_client" href="mcp_client.html">connpy.mcp_client</a></code></li>
|
<li><code><a title="connpy.mcp_client" href="mcp_client.html">connpy.mcp_client</a></code></li>
|
||||||
<li><code><a title="connpy.proto" href="proto/index.html">connpy.proto</a></code></li>
|
<li><code><a title="connpy.proto" href="proto/index.html">connpy.proto</a></code></li>
|
||||||
<li><code><a title="connpy.services" href="services/index.html">connpy.services</a></code></li>
|
<li><code><a title="connpy.services" href="services/index.html">connpy.services</a></code></li>
|
||||||
<li><code><a title="connpy.tests" href="tests/index.html">connpy.tests</a></code></li>
|
|
||||||
<li><code><a title="connpy.tunnels" href="tunnels.html">connpy.tunnels</a></code></li>
|
<li><code><a title="connpy.tunnels" href="tunnels.html">connpy.tunnels</a></code></li>
|
||||||
<li><code><a title="connpy.utils" href="utils.html">connpy.utils</a></code></li>
|
<li><code><a title="connpy.utils" href="utils.html">connpy.utils</a></code></li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -6289,7 +6384,7 @@ def test(self, commands, expected, vars = None,*, folder = None, prompt = None,
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.mcp_client API documentation</title>
|
<title>connpy.mcp_client API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -343,7 +343,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.proto API documentation</title>
|
<title>connpy.proto API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -60,7 +60,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.services.ai_service API documentation</title>
|
<title>connpy.services.ai_service API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -58,6 +58,37 @@ el.replaceWith(d);
|
|||||||
<pre><code class="python">class AIService(BaseService):
|
<pre><code class="python">class AIService(BaseService):
|
||||||
"""Business logic for interacting with AI agents and LLM configurations."""
|
"""Business logic for interacting with AI agents and LLM configurations."""
|
||||||
|
|
||||||
|
def _clean_cisco_scrolling(self, text: str) -> str:
|
||||||
|
"""Resolves horizontal scrolling artifacts (backspaces, \r, ANSI) by merging overlapping segments."""
|
||||||
|
def merge_overlapping(s1, s2):
|
||||||
|
s2_clean = s2.lstrip(' $')
|
||||||
|
max_overlap = min(len(s1), len(s2_clean))
|
||||||
|
for i in range(max_overlap, 0, -1):
|
||||||
|
if s1[-i:] == s2_clean[:i]:
|
||||||
|
return s1 + s2_clean[i:]
|
||||||
|
return s1 + s2_clean
|
||||||
|
|
||||||
|
scroll_re = re.compile(r'(\x08{5,}\s*\$?|\$\r|\x1b\[\d+[GD]\s*\$?)')
|
||||||
|
parts = scroll_re.split(text)
|
||||||
|
merged = ""
|
||||||
|
|
||||||
|
for part in parts:
|
||||||
|
if scroll_re.match(part):
|
||||||
|
continue
|
||||||
|
|
||||||
|
cleaned = log_cleaner(part)
|
||||||
|
if not merged:
|
||||||
|
merged = cleaned
|
||||||
|
else:
|
||||||
|
merged_lines = merged.split('\n')
|
||||||
|
cleaned_lines = cleaned.split('\n')
|
||||||
|
|
||||||
|
merged_lines[-1] = merge_overlapping(merged_lines[-1], cleaned_lines[0])
|
||||||
|
merged_lines.extend(cleaned_lines[1:])
|
||||||
|
merged = "\n".join(merged_lines)
|
||||||
|
|
||||||
|
return merged
|
||||||
|
|
||||||
def build_context_blocks(self, raw_bytes: bytes, cmd_byte_positions: list, node_info: dict, last_line: str = "") -> list:
|
def build_context_blocks(self, raw_bytes: bytes, cmd_byte_positions: list, node_info: dict, last_line: str = "") -> list:
|
||||||
"""Identifies command blocks in the terminal history."""
|
"""Identifies command blocks in the terminal history."""
|
||||||
blocks = []
|
blocks = []
|
||||||
@@ -79,28 +110,69 @@ el.replaceWith(d);
|
|||||||
prev_pos = cmd_byte_positions[i-1][0]
|
prev_pos = cmd_byte_positions[i-1][0]
|
||||||
|
|
||||||
if known_cmd:
|
if known_cmd:
|
||||||
prev_chunk = raw_bytes[prev_pos:pos]
|
if known_cmd == "CANCELLED":
|
||||||
prev_cleaned = log_cleaner(prev_chunk.decode(errors='replace'))
|
parsed_positions.append({"pos": pos, "type": "CANCELLED", "preview": ""})
|
||||||
prev_lines = [l for l in prev_cleaned.split('\n') if l.strip()]
|
else:
|
||||||
prompt_text = prev_lines[-1].strip() if prev_lines else ""
|
prev_chunk = raw_bytes[prev_pos:pos]
|
||||||
preview = f"{prompt_text}{known_cmd}" if prompt_text else known_cmd
|
prev_cleaned = self._clean_cisco_scrolling(prev_chunk.decode(errors='replace'))
|
||||||
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": preview[:80]})
|
prev_lines = [l for l in prev_cleaned.split('\n') if l.strip()]
|
||||||
|
prompt_text = prev_lines[-1].strip() if prev_lines else ""
|
||||||
|
preview = f"{prompt_text}{known_cmd}" if prompt_text else known_cmd
|
||||||
|
|
||||||
|
if len(preview) > 80:
|
||||||
|
preview = preview[:77] + "..."
|
||||||
|
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": preview})
|
||||||
else:
|
else:
|
||||||
chunk = raw_bytes[prev_pos:pos]
|
chunk = raw_bytes[prev_pos:pos]
|
||||||
cleaned = log_cleaner(chunk.decode(errors='replace'))
|
|
||||||
lines = [l for l in cleaned.split('\n') if l.strip()]
|
|
||||||
preview = lines[-1].strip() if lines else ""
|
|
||||||
|
|
||||||
if preview:
|
cleaned = self._clean_cisco_scrolling(chunk.decode(errors='replace'))
|
||||||
match = prompt_re.search(preview)
|
lines = [l for l in cleaned.split('\n') if l.strip()]
|
||||||
if match:
|
|
||||||
cmd_text = preview[match.end():].strip()
|
found_in_pass1 = False
|
||||||
if cmd_text:
|
if lines:
|
||||||
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": preview[:80]})
|
# Search backwards through the last few lines for the prompt
|
||||||
else:
|
for idx in range(len(lines) - 1, max(-1, len(lines) - 10), -1):
|
||||||
parsed_positions.append({"pos": pos, "type": "EMPTY_PROMPT", "preview": ""})
|
match = prompt_re.search(lines[idx])
|
||||||
else:
|
if match:
|
||||||
parsed_positions.append({"pos": pos, "type": "SCROLLING", "preview": ""})
|
ptxt = match.group(0).strip()
|
||||||
|
cmd_first_line = lines[idx][match.end():].strip()
|
||||||
|
cmd_rest = [l.strip() for l in lines[idx+1:]]
|
||||||
|
cmd_text = " ".join([cmd_first_line] + cmd_rest).strip()
|
||||||
|
|
||||||
|
if cmd_text:
|
||||||
|
pv = f"{ptxt} {cmd_text}".strip()
|
||||||
|
if len(pv) > 80:
|
||||||
|
pv = pv[:77] + "..."
|
||||||
|
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": pv})
|
||||||
|
else:
|
||||||
|
parsed_positions.append({"pos": pos, "type": "EMPTY_PROMPT", "preview": ""})
|
||||||
|
found_in_pass1 = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not found_in_pass1:
|
||||||
|
# Fallback: The prompt might have been isolated in the previous chunk
|
||||||
|
# due to asynchronous network delays splitting the output exactly at the newline.
|
||||||
|
prev_was_valid_cmd = i >= 2 and parsed_positions[i-2]["type"] == "VALID_CMD"
|
||||||
|
if prev_pos > 0 and not prev_was_valid_cmd:
|
||||||
|
# Fetch the very last chunk that we just processed
|
||||||
|
prev_prev_pos = cmd_byte_positions[i-2][0] if i >= 2 else 0
|
||||||
|
prev_chunk_text = self._clean_cisco_scrolling(raw_bytes[prev_prev_pos:prev_pos].decode(errors='replace'))
|
||||||
|
prev_lines_text = [l for l in prev_chunk_text.split('\n') if l.strip()]
|
||||||
|
|
||||||
|
if prev_lines_text:
|
||||||
|
prev_match = prompt_re.search(prev_lines_text[-1])
|
||||||
|
if prev_match:
|
||||||
|
ptxt = prev_match.group(0).strip()
|
||||||
|
cmd_text = " ".join([l.strip() for l in lines]).strip()
|
||||||
|
if cmd_text:
|
||||||
|
pv = f"{ptxt} {cmd_text}".strip()
|
||||||
|
if len(pv) > 80:
|
||||||
|
pv = pv[:77] + "..."
|
||||||
|
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": pv})
|
||||||
|
found_in_pass1 = True
|
||||||
|
|
||||||
|
if not found_in_pass1:
|
||||||
|
parsed_positions.append({"pos": pos, "type": "SCROLLING", "preview": ""})
|
||||||
else:
|
else:
|
||||||
parsed_positions.append({"pos": pos, "type": "SCROLLING", "preview": ""})
|
parsed_positions.append({"pos": pos, "type": "SCROLLING", "preview": ""})
|
||||||
|
|
||||||
@@ -113,11 +185,11 @@ el.replaceWith(d);
|
|||||||
start_pos = item["pos"]
|
start_pos = item["pos"]
|
||||||
preview = item["preview"]
|
preview = item["preview"]
|
||||||
|
|
||||||
# Find the end position: next VALID_CMD or EMPTY_PROMPT
|
# Find the end position: next VALID_CMD or EMPTY_PROMPT or CANCELLED
|
||||||
end_pos = current_prompt_pos
|
end_pos = current_prompt_pos
|
||||||
for j in range(i + 1, len(parsed_positions)):
|
for j in range(i + 1, len(parsed_positions)):
|
||||||
next_item = parsed_positions[j]
|
next_item = parsed_positions[j]
|
||||||
if next_item["type"] in ("VALID_CMD", "EMPTY_PROMPT"):
|
if next_item["type"] in ("VALID_CMD", "EMPTY_PROMPT", "CANCELLED"):
|
||||||
end_pos = next_item["pos"]
|
end_pos = next_item["pos"]
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -219,11 +291,14 @@ el.replaceWith(d);
|
|||||||
return await asyncio.wrap_future(future)
|
return await asyncio.wrap_future(future)
|
||||||
|
|
||||||
|
|
||||||
def list_sessions(self):
|
def list_sessions(self, limit=None):
|
||||||
"""Return a list of all saved AI sessions."""
|
"""Return a list of saved AI sessions, optionally limited."""
|
||||||
from connpy.ai import ai
|
from connpy.ai import ai
|
||||||
agent = ai(self.config)
|
agent = ai(self.config)
|
||||||
return agent._get_sessions()
|
sessions = agent._get_sessions()
|
||||||
|
if limit and len(sessions) > limit:
|
||||||
|
return sessions[:limit], len(sessions)
|
||||||
|
return sessions, len(sessions)
|
||||||
|
|
||||||
def delete_session(self, session_id):
|
def delete_session(self, session_id):
|
||||||
"""Delete an AI session by ID."""
|
"""Delete an AI session by ID."""
|
||||||
@@ -235,13 +310,15 @@ el.replaceWith(d);
|
|||||||
else:
|
else:
|
||||||
raise InvalidConfigurationError(f"Session '{session_id}' not found.")
|
raise InvalidConfigurationError(f"Session '{session_id}' not found.")
|
||||||
|
|
||||||
def configure_provider(self, provider, model=None, api_key=None):
|
def configure_provider(self, provider, model=None, api_key=None, auth=None):
|
||||||
"""Update AI provider settings in the configuration."""
|
"""Update AI provider settings in the configuration."""
|
||||||
settings = self.config.config.get("ai", {})
|
settings = self.config.config.get("ai", {})
|
||||||
if model:
|
if model:
|
||||||
settings[f"{provider}_model"] = model
|
settings[f"{provider}_model"] = model
|
||||||
if api_key:
|
if api_key:
|
||||||
settings[f"{provider}_api_key"] = api_key
|
settings[f"{provider}_api_key"] = api_key
|
||||||
|
if auth is not None:
|
||||||
|
settings[f"{provider}_auth"] = auth
|
||||||
|
|
||||||
self.config.config["ai"] = settings
|
self.config.config["ai"] = settings
|
||||||
self.config._saveconfig(self.config.file)
|
self.config._saveconfig(self.config.file)
|
||||||
@@ -280,6 +357,11 @@ el.replaceWith(d);
|
|||||||
self.config.config["ai"] = ai_settings
|
self.config.config["ai"] = ai_settings
|
||||||
self.config._saveconfig(self.config.file)
|
self.config._saveconfig(self.config.file)
|
||||||
|
|
||||||
|
def list_mcp_servers(self) -> dict:
|
||||||
|
"""Get the configured MCP servers."""
|
||||||
|
ai_settings = self.config.config.get("ai", {})
|
||||||
|
return ai_settings.get("mcp_servers", {})
|
||||||
|
|
||||||
def load_session_data(self, session_id):
|
def load_session_data(self, session_id):
|
||||||
"""Load a session's raw data by ID."""
|
"""Load a session's raw data by ID."""
|
||||||
from connpy.ai import ai
|
from connpy.ai import ai
|
||||||
@@ -379,28 +461,69 @@ el.replaceWith(d);
|
|||||||
prev_pos = cmd_byte_positions[i-1][0]
|
prev_pos = cmd_byte_positions[i-1][0]
|
||||||
|
|
||||||
if known_cmd:
|
if known_cmd:
|
||||||
prev_chunk = raw_bytes[prev_pos:pos]
|
if known_cmd == "CANCELLED":
|
||||||
prev_cleaned = log_cleaner(prev_chunk.decode(errors='replace'))
|
parsed_positions.append({"pos": pos, "type": "CANCELLED", "preview": ""})
|
||||||
prev_lines = [l for l in prev_cleaned.split('\n') if l.strip()]
|
else:
|
||||||
prompt_text = prev_lines[-1].strip() if prev_lines else ""
|
prev_chunk = raw_bytes[prev_pos:pos]
|
||||||
preview = f"{prompt_text}{known_cmd}" if prompt_text else known_cmd
|
prev_cleaned = self._clean_cisco_scrolling(prev_chunk.decode(errors='replace'))
|
||||||
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": preview[:80]})
|
prev_lines = [l for l in prev_cleaned.split('\n') if l.strip()]
|
||||||
|
prompt_text = prev_lines[-1].strip() if prev_lines else ""
|
||||||
|
preview = f"{prompt_text}{known_cmd}" if prompt_text else known_cmd
|
||||||
|
|
||||||
|
if len(preview) > 80:
|
||||||
|
preview = preview[:77] + "..."
|
||||||
|
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": preview})
|
||||||
else:
|
else:
|
||||||
chunk = raw_bytes[prev_pos:pos]
|
chunk = raw_bytes[prev_pos:pos]
|
||||||
cleaned = log_cleaner(chunk.decode(errors='replace'))
|
|
||||||
lines = [l for l in cleaned.split('\n') if l.strip()]
|
|
||||||
preview = lines[-1].strip() if lines else ""
|
|
||||||
|
|
||||||
if preview:
|
cleaned = self._clean_cisco_scrolling(chunk.decode(errors='replace'))
|
||||||
match = prompt_re.search(preview)
|
lines = [l for l in cleaned.split('\n') if l.strip()]
|
||||||
if match:
|
|
||||||
cmd_text = preview[match.end():].strip()
|
found_in_pass1 = False
|
||||||
if cmd_text:
|
if lines:
|
||||||
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": preview[:80]})
|
# Search backwards through the last few lines for the prompt
|
||||||
else:
|
for idx in range(len(lines) - 1, max(-1, len(lines) - 10), -1):
|
||||||
parsed_positions.append({"pos": pos, "type": "EMPTY_PROMPT", "preview": ""})
|
match = prompt_re.search(lines[idx])
|
||||||
else:
|
if match:
|
||||||
parsed_positions.append({"pos": pos, "type": "SCROLLING", "preview": ""})
|
ptxt = match.group(0).strip()
|
||||||
|
cmd_first_line = lines[idx][match.end():].strip()
|
||||||
|
cmd_rest = [l.strip() for l in lines[idx+1:]]
|
||||||
|
cmd_text = " ".join([cmd_first_line] + cmd_rest).strip()
|
||||||
|
|
||||||
|
if cmd_text:
|
||||||
|
pv = f"{ptxt} {cmd_text}".strip()
|
||||||
|
if len(pv) > 80:
|
||||||
|
pv = pv[:77] + "..."
|
||||||
|
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": pv})
|
||||||
|
else:
|
||||||
|
parsed_positions.append({"pos": pos, "type": "EMPTY_PROMPT", "preview": ""})
|
||||||
|
found_in_pass1 = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not found_in_pass1:
|
||||||
|
# Fallback: The prompt might have been isolated in the previous chunk
|
||||||
|
# due to asynchronous network delays splitting the output exactly at the newline.
|
||||||
|
prev_was_valid_cmd = i >= 2 and parsed_positions[i-2]["type"] == "VALID_CMD"
|
||||||
|
if prev_pos > 0 and not prev_was_valid_cmd:
|
||||||
|
# Fetch the very last chunk that we just processed
|
||||||
|
prev_prev_pos = cmd_byte_positions[i-2][0] if i >= 2 else 0
|
||||||
|
prev_chunk_text = self._clean_cisco_scrolling(raw_bytes[prev_prev_pos:prev_pos].decode(errors='replace'))
|
||||||
|
prev_lines_text = [l for l in prev_chunk_text.split('\n') if l.strip()]
|
||||||
|
|
||||||
|
if prev_lines_text:
|
||||||
|
prev_match = prompt_re.search(prev_lines_text[-1])
|
||||||
|
if prev_match:
|
||||||
|
ptxt = prev_match.group(0).strip()
|
||||||
|
cmd_text = " ".join([l.strip() for l in lines]).strip()
|
||||||
|
if cmd_text:
|
||||||
|
pv = f"{ptxt} {cmd_text}".strip()
|
||||||
|
if len(pv) > 80:
|
||||||
|
pv = pv[:77] + "..."
|
||||||
|
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": pv})
|
||||||
|
found_in_pass1 = True
|
||||||
|
|
||||||
|
if not found_in_pass1:
|
||||||
|
parsed_positions.append({"pos": pos, "type": "SCROLLING", "preview": ""})
|
||||||
else:
|
else:
|
||||||
parsed_positions.append({"pos": pos, "type": "SCROLLING", "preview": ""})
|
parsed_positions.append({"pos": pos, "type": "SCROLLING", "preview": ""})
|
||||||
|
|
||||||
@@ -413,11 +536,11 @@ el.replaceWith(d);
|
|||||||
start_pos = item["pos"]
|
start_pos = item["pos"]
|
||||||
preview = item["preview"]
|
preview = item["preview"]
|
||||||
|
|
||||||
# Find the end position: next VALID_CMD or EMPTY_PROMPT
|
# Find the end position: next VALID_CMD or EMPTY_PROMPT or CANCELLED
|
||||||
end_pos = current_prompt_pos
|
end_pos = current_prompt_pos
|
||||||
for j in range(i + 1, len(parsed_positions)):
|
for j in range(i + 1, len(parsed_positions)):
|
||||||
next_item = parsed_positions[j]
|
next_item = parsed_positions[j]
|
||||||
if next_item["type"] in ("VALID_CMD", "EMPTY_PROMPT"):
|
if next_item["type"] in ("VALID_CMD", "EMPTY_PROMPT", "CANCELLED"):
|
||||||
end_pos = next_item["pos"]
|
end_pos = next_item["pos"]
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -478,20 +601,22 @@ el.replaceWith(d);
|
|||||||
<div class="desc"><p>Update MCP server settings in the configuration with smart merging.</p></div>
|
<div class="desc"><p>Update MCP server settings in the configuration with smart merging.</p></div>
|
||||||
</dd>
|
</dd>
|
||||||
<dt id="connpy.services.ai_service.AIService.configure_provider"><code class="name flex">
|
<dt id="connpy.services.ai_service.AIService.configure_provider"><code class="name flex">
|
||||||
<span>def <span class="ident">configure_provider</span></span>(<span>self, provider, model=None, api_key=None)</span>
|
<span>def <span class="ident">configure_provider</span></span>(<span>self, provider, model=None, api_key=None, auth=None)</span>
|
||||||
</code></dt>
|
</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<details class="source">
|
<details class="source">
|
||||||
<summary>
|
<summary>
|
||||||
<span>Expand source code</span>
|
<span>Expand source code</span>
|
||||||
</summary>
|
</summary>
|
||||||
<pre><code class="python">def configure_provider(self, provider, model=None, api_key=None):
|
<pre><code class="python">def configure_provider(self, provider, model=None, api_key=None, auth=None):
|
||||||
"""Update AI provider settings in the configuration."""
|
"""Update AI provider settings in the configuration."""
|
||||||
settings = self.config.config.get("ai", {})
|
settings = self.config.config.get("ai", {})
|
||||||
if model:
|
if model:
|
||||||
settings[f"{provider}_model"] = model
|
settings[f"{provider}_model"] = model
|
||||||
if api_key:
|
if api_key:
|
||||||
settings[f"{provider}_api_key"] = api_key
|
settings[f"{provider}_api_key"] = api_key
|
||||||
|
if auth is not None:
|
||||||
|
settings[f"{provider}_auth"] = auth
|
||||||
|
|
||||||
self.config.config["ai"] = settings
|
self.config.config["ai"] = settings
|
||||||
self.config._saveconfig(self.config.file)</code></pre>
|
self.config._saveconfig(self.config.file)</code></pre>
|
||||||
@@ -534,21 +659,39 @@ el.replaceWith(d);
|
|||||||
</details>
|
</details>
|
||||||
<div class="desc"><p>Delete an AI session by ID.</p></div>
|
<div class="desc"><p>Delete an AI session by ID.</p></div>
|
||||||
</dd>
|
</dd>
|
||||||
<dt id="connpy.services.ai_service.AIService.list_sessions"><code class="name flex">
|
<dt id="connpy.services.ai_service.AIService.list_mcp_servers"><code class="name flex">
|
||||||
<span>def <span class="ident">list_sessions</span></span>(<span>self)</span>
|
<span>def <span class="ident">list_mcp_servers</span></span>(<span>self) ‑> dict</span>
|
||||||
</code></dt>
|
</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<details class="source">
|
<details class="source">
|
||||||
<summary>
|
<summary>
|
||||||
<span>Expand source code</span>
|
<span>Expand source code</span>
|
||||||
</summary>
|
</summary>
|
||||||
<pre><code class="python">def list_sessions(self):
|
<pre><code class="python">def list_mcp_servers(self) -> dict:
|
||||||
"""Return a list of all saved AI sessions."""
|
"""Get the configured MCP servers."""
|
||||||
|
ai_settings = self.config.config.get("ai", {})
|
||||||
|
return ai_settings.get("mcp_servers", {})</code></pre>
|
||||||
|
</details>
|
||||||
|
<div class="desc"><p>Get the configured MCP servers.</p></div>
|
||||||
|
</dd>
|
||||||
|
<dt id="connpy.services.ai_service.AIService.list_sessions"><code class="name flex">
|
||||||
|
<span>def <span class="ident">list_sessions</span></span>(<span>self, limit=None)</span>
|
||||||
|
</code></dt>
|
||||||
|
<dd>
|
||||||
|
<details class="source">
|
||||||
|
<summary>
|
||||||
|
<span>Expand source code</span>
|
||||||
|
</summary>
|
||||||
|
<pre><code class="python">def list_sessions(self, limit=None):
|
||||||
|
"""Return a list of saved AI sessions, optionally limited."""
|
||||||
from connpy.ai import ai
|
from connpy.ai import ai
|
||||||
agent = ai(self.config)
|
agent = ai(self.config)
|
||||||
return agent._get_sessions()</code></pre>
|
sessions = agent._get_sessions()
|
||||||
|
if limit and len(sessions) > limit:
|
||||||
|
return sessions[:limit], len(sessions)
|
||||||
|
return sessions, len(sessions)</code></pre>
|
||||||
</details>
|
</details>
|
||||||
<div class="desc"><p>Return a list of all saved AI sessions.</p></div>
|
<div class="desc"><p>Return a list of saved AI sessions, optionally limited.</p></div>
|
||||||
</dd>
|
</dd>
|
||||||
<dt id="connpy.services.ai_service.AIService.load_session_data"><code class="name flex">
|
<dt id="connpy.services.ai_service.AIService.load_session_data"><code class="name flex">
|
||||||
<span>def <span class="ident">load_session_data</span></span>(<span>self, session_id)</span>
|
<span>def <span class="ident">load_session_data</span></span>(<span>self, session_id)</span>
|
||||||
@@ -671,6 +814,7 @@ el.replaceWith(d);
|
|||||||
<li><code><a title="connpy.services.ai_service.AIService.configure_provider" href="#connpy.services.ai_service.AIService.configure_provider">configure_provider</a></code></li>
|
<li><code><a title="connpy.services.ai_service.AIService.configure_provider" href="#connpy.services.ai_service.AIService.configure_provider">configure_provider</a></code></li>
|
||||||
<li><code><a title="connpy.services.ai_service.AIService.confirm" href="#connpy.services.ai_service.AIService.confirm">confirm</a></code></li>
|
<li><code><a title="connpy.services.ai_service.AIService.confirm" href="#connpy.services.ai_service.AIService.confirm">confirm</a></code></li>
|
||||||
<li><code><a title="connpy.services.ai_service.AIService.delete_session" href="#connpy.services.ai_service.AIService.delete_session">delete_session</a></code></li>
|
<li><code><a title="connpy.services.ai_service.AIService.delete_session" href="#connpy.services.ai_service.AIService.delete_session">delete_session</a></code></li>
|
||||||
|
<li><code><a title="connpy.services.ai_service.AIService.list_mcp_servers" href="#connpy.services.ai_service.AIService.list_mcp_servers">list_mcp_servers</a></code></li>
|
||||||
<li><code><a title="connpy.services.ai_service.AIService.list_sessions" href="#connpy.services.ai_service.AIService.list_sessions">list_sessions</a></code></li>
|
<li><code><a title="connpy.services.ai_service.AIService.list_sessions" href="#connpy.services.ai_service.AIService.list_sessions">list_sessions</a></code></li>
|
||||||
<li><code><a title="connpy.services.ai_service.AIService.load_session_data" href="#connpy.services.ai_service.AIService.load_session_data">load_session_data</a></code></li>
|
<li><code><a title="connpy.services.ai_service.AIService.load_session_data" href="#connpy.services.ai_service.AIService.load_session_data">load_session_data</a></code></li>
|
||||||
<li><code><a title="connpy.services.ai_service.AIService.process_copilot_input" href="#connpy.services.ai_service.AIService.process_copilot_input">process_copilot_input</a></code></li>
|
<li><code><a title="connpy.services.ai_service.AIService.process_copilot_input" href="#connpy.services.ai_service.AIService.process_copilot_input">process_copilot_input</a></code></li>
|
||||||
@@ -682,7 +826,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.services.base API documentation</title>
|
<title>connpy.services.base API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -152,7 +152,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.services.config_service API documentation</title>
|
<title>connpy.services.config_service API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -319,7 +319,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.services.context_service API documentation</title>
|
<title>connpy.services.context_service API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -370,7 +370,7 @@ def current_context(self) -> str:
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.services.exceptions API documentation</title>
|
<title>connpy.services.exceptions API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -268,7 +268,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.services.execution_service API documentation</title>
|
<title>connpy.services.execution_service API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -449,7 +449,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.services.import_export_service API documentation</title>
|
<title>connpy.services.import_export_service API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -361,7 +361,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+200
-56
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.services API documentation</title>
|
<title>connpy.services API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -113,6 +113,37 @@ el.replaceWith(d);
|
|||||||
<pre><code class="python">class AIService(BaseService):
|
<pre><code class="python">class AIService(BaseService):
|
||||||
"""Business logic for interacting with AI agents and LLM configurations."""
|
"""Business logic for interacting with AI agents and LLM configurations."""
|
||||||
|
|
||||||
|
def _clean_cisco_scrolling(self, text: str) -> str:
|
||||||
|
"""Resolves horizontal scrolling artifacts (backspaces, \r, ANSI) by merging overlapping segments."""
|
||||||
|
def merge_overlapping(s1, s2):
|
||||||
|
s2_clean = s2.lstrip(' $')
|
||||||
|
max_overlap = min(len(s1), len(s2_clean))
|
||||||
|
for i in range(max_overlap, 0, -1):
|
||||||
|
if s1[-i:] == s2_clean[:i]:
|
||||||
|
return s1 + s2_clean[i:]
|
||||||
|
return s1 + s2_clean
|
||||||
|
|
||||||
|
scroll_re = re.compile(r'(\x08{5,}\s*\$?|\$\r|\x1b\[\d+[GD]\s*\$?)')
|
||||||
|
parts = scroll_re.split(text)
|
||||||
|
merged = ""
|
||||||
|
|
||||||
|
for part in parts:
|
||||||
|
if scroll_re.match(part):
|
||||||
|
continue
|
||||||
|
|
||||||
|
cleaned = log_cleaner(part)
|
||||||
|
if not merged:
|
||||||
|
merged = cleaned
|
||||||
|
else:
|
||||||
|
merged_lines = merged.split('\n')
|
||||||
|
cleaned_lines = cleaned.split('\n')
|
||||||
|
|
||||||
|
merged_lines[-1] = merge_overlapping(merged_lines[-1], cleaned_lines[0])
|
||||||
|
merged_lines.extend(cleaned_lines[1:])
|
||||||
|
merged = "\n".join(merged_lines)
|
||||||
|
|
||||||
|
return merged
|
||||||
|
|
||||||
def build_context_blocks(self, raw_bytes: bytes, cmd_byte_positions: list, node_info: dict, last_line: str = "") -> list:
|
def build_context_blocks(self, raw_bytes: bytes, cmd_byte_positions: list, node_info: dict, last_line: str = "") -> list:
|
||||||
"""Identifies command blocks in the terminal history."""
|
"""Identifies command blocks in the terminal history."""
|
||||||
blocks = []
|
blocks = []
|
||||||
@@ -134,28 +165,69 @@ el.replaceWith(d);
|
|||||||
prev_pos = cmd_byte_positions[i-1][0]
|
prev_pos = cmd_byte_positions[i-1][0]
|
||||||
|
|
||||||
if known_cmd:
|
if known_cmd:
|
||||||
prev_chunk = raw_bytes[prev_pos:pos]
|
if known_cmd == "CANCELLED":
|
||||||
prev_cleaned = log_cleaner(prev_chunk.decode(errors='replace'))
|
parsed_positions.append({"pos": pos, "type": "CANCELLED", "preview": ""})
|
||||||
prev_lines = [l for l in prev_cleaned.split('\n') if l.strip()]
|
else:
|
||||||
prompt_text = prev_lines[-1].strip() if prev_lines else ""
|
prev_chunk = raw_bytes[prev_pos:pos]
|
||||||
preview = f"{prompt_text}{known_cmd}" if prompt_text else known_cmd
|
prev_cleaned = self._clean_cisco_scrolling(prev_chunk.decode(errors='replace'))
|
||||||
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": preview[:80]})
|
prev_lines = [l for l in prev_cleaned.split('\n') if l.strip()]
|
||||||
|
prompt_text = prev_lines[-1].strip() if prev_lines else ""
|
||||||
|
preview = f"{prompt_text}{known_cmd}" if prompt_text else known_cmd
|
||||||
|
|
||||||
|
if len(preview) > 80:
|
||||||
|
preview = preview[:77] + "..."
|
||||||
|
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": preview})
|
||||||
else:
|
else:
|
||||||
chunk = raw_bytes[prev_pos:pos]
|
chunk = raw_bytes[prev_pos:pos]
|
||||||
cleaned = log_cleaner(chunk.decode(errors='replace'))
|
|
||||||
lines = [l for l in cleaned.split('\n') if l.strip()]
|
|
||||||
preview = lines[-1].strip() if lines else ""
|
|
||||||
|
|
||||||
if preview:
|
cleaned = self._clean_cisco_scrolling(chunk.decode(errors='replace'))
|
||||||
match = prompt_re.search(preview)
|
lines = [l for l in cleaned.split('\n') if l.strip()]
|
||||||
if match:
|
|
||||||
cmd_text = preview[match.end():].strip()
|
found_in_pass1 = False
|
||||||
if cmd_text:
|
if lines:
|
||||||
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": preview[:80]})
|
# Search backwards through the last few lines for the prompt
|
||||||
else:
|
for idx in range(len(lines) - 1, max(-1, len(lines) - 10), -1):
|
||||||
parsed_positions.append({"pos": pos, "type": "EMPTY_PROMPT", "preview": ""})
|
match = prompt_re.search(lines[idx])
|
||||||
else:
|
if match:
|
||||||
parsed_positions.append({"pos": pos, "type": "SCROLLING", "preview": ""})
|
ptxt = match.group(0).strip()
|
||||||
|
cmd_first_line = lines[idx][match.end():].strip()
|
||||||
|
cmd_rest = [l.strip() for l in lines[idx+1:]]
|
||||||
|
cmd_text = " ".join([cmd_first_line] + cmd_rest).strip()
|
||||||
|
|
||||||
|
if cmd_text:
|
||||||
|
pv = f"{ptxt} {cmd_text}".strip()
|
||||||
|
if len(pv) > 80:
|
||||||
|
pv = pv[:77] + "..."
|
||||||
|
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": pv})
|
||||||
|
else:
|
||||||
|
parsed_positions.append({"pos": pos, "type": "EMPTY_PROMPT", "preview": ""})
|
||||||
|
found_in_pass1 = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not found_in_pass1:
|
||||||
|
# Fallback: The prompt might have been isolated in the previous chunk
|
||||||
|
# due to asynchronous network delays splitting the output exactly at the newline.
|
||||||
|
prev_was_valid_cmd = i >= 2 and parsed_positions[i-2]["type"] == "VALID_CMD"
|
||||||
|
if prev_pos > 0 and not prev_was_valid_cmd:
|
||||||
|
# Fetch the very last chunk that we just processed
|
||||||
|
prev_prev_pos = cmd_byte_positions[i-2][0] if i >= 2 else 0
|
||||||
|
prev_chunk_text = self._clean_cisco_scrolling(raw_bytes[prev_prev_pos:prev_pos].decode(errors='replace'))
|
||||||
|
prev_lines_text = [l for l in prev_chunk_text.split('\n') if l.strip()]
|
||||||
|
|
||||||
|
if prev_lines_text:
|
||||||
|
prev_match = prompt_re.search(prev_lines_text[-1])
|
||||||
|
if prev_match:
|
||||||
|
ptxt = prev_match.group(0).strip()
|
||||||
|
cmd_text = " ".join([l.strip() for l in lines]).strip()
|
||||||
|
if cmd_text:
|
||||||
|
pv = f"{ptxt} {cmd_text}".strip()
|
||||||
|
if len(pv) > 80:
|
||||||
|
pv = pv[:77] + "..."
|
||||||
|
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": pv})
|
||||||
|
found_in_pass1 = True
|
||||||
|
|
||||||
|
if not found_in_pass1:
|
||||||
|
parsed_positions.append({"pos": pos, "type": "SCROLLING", "preview": ""})
|
||||||
else:
|
else:
|
||||||
parsed_positions.append({"pos": pos, "type": "SCROLLING", "preview": ""})
|
parsed_positions.append({"pos": pos, "type": "SCROLLING", "preview": ""})
|
||||||
|
|
||||||
@@ -168,11 +240,11 @@ el.replaceWith(d);
|
|||||||
start_pos = item["pos"]
|
start_pos = item["pos"]
|
||||||
preview = item["preview"]
|
preview = item["preview"]
|
||||||
|
|
||||||
# Find the end position: next VALID_CMD or EMPTY_PROMPT
|
# Find the end position: next VALID_CMD or EMPTY_PROMPT or CANCELLED
|
||||||
end_pos = current_prompt_pos
|
end_pos = current_prompt_pos
|
||||||
for j in range(i + 1, len(parsed_positions)):
|
for j in range(i + 1, len(parsed_positions)):
|
||||||
next_item = parsed_positions[j]
|
next_item = parsed_positions[j]
|
||||||
if next_item["type"] in ("VALID_CMD", "EMPTY_PROMPT"):
|
if next_item["type"] in ("VALID_CMD", "EMPTY_PROMPT", "CANCELLED"):
|
||||||
end_pos = next_item["pos"]
|
end_pos = next_item["pos"]
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -274,11 +346,14 @@ el.replaceWith(d);
|
|||||||
return await asyncio.wrap_future(future)
|
return await asyncio.wrap_future(future)
|
||||||
|
|
||||||
|
|
||||||
def list_sessions(self):
|
def list_sessions(self, limit=None):
|
||||||
"""Return a list of all saved AI sessions."""
|
"""Return a list of saved AI sessions, optionally limited."""
|
||||||
from connpy.ai import ai
|
from connpy.ai import ai
|
||||||
agent = ai(self.config)
|
agent = ai(self.config)
|
||||||
return agent._get_sessions()
|
sessions = agent._get_sessions()
|
||||||
|
if limit and len(sessions) > limit:
|
||||||
|
return sessions[:limit], len(sessions)
|
||||||
|
return sessions, len(sessions)
|
||||||
|
|
||||||
def delete_session(self, session_id):
|
def delete_session(self, session_id):
|
||||||
"""Delete an AI session by ID."""
|
"""Delete an AI session by ID."""
|
||||||
@@ -290,13 +365,15 @@ el.replaceWith(d);
|
|||||||
else:
|
else:
|
||||||
raise InvalidConfigurationError(f"Session '{session_id}' not found.")
|
raise InvalidConfigurationError(f"Session '{session_id}' not found.")
|
||||||
|
|
||||||
def configure_provider(self, provider, model=None, api_key=None):
|
def configure_provider(self, provider, model=None, api_key=None, auth=None):
|
||||||
"""Update AI provider settings in the configuration."""
|
"""Update AI provider settings in the configuration."""
|
||||||
settings = self.config.config.get("ai", {})
|
settings = self.config.config.get("ai", {})
|
||||||
if model:
|
if model:
|
||||||
settings[f"{provider}_model"] = model
|
settings[f"{provider}_model"] = model
|
||||||
if api_key:
|
if api_key:
|
||||||
settings[f"{provider}_api_key"] = api_key
|
settings[f"{provider}_api_key"] = api_key
|
||||||
|
if auth is not None:
|
||||||
|
settings[f"{provider}_auth"] = auth
|
||||||
|
|
||||||
self.config.config["ai"] = settings
|
self.config.config["ai"] = settings
|
||||||
self.config._saveconfig(self.config.file)
|
self.config._saveconfig(self.config.file)
|
||||||
@@ -335,6 +412,11 @@ el.replaceWith(d);
|
|||||||
self.config.config["ai"] = ai_settings
|
self.config.config["ai"] = ai_settings
|
||||||
self.config._saveconfig(self.config.file)
|
self.config._saveconfig(self.config.file)
|
||||||
|
|
||||||
|
def list_mcp_servers(self) -> dict:
|
||||||
|
"""Get the configured MCP servers."""
|
||||||
|
ai_settings = self.config.config.get("ai", {})
|
||||||
|
return ai_settings.get("mcp_servers", {})
|
||||||
|
|
||||||
def load_session_data(self, session_id):
|
def load_session_data(self, session_id):
|
||||||
"""Load a session's raw data by ID."""
|
"""Load a session's raw data by ID."""
|
||||||
from connpy.ai import ai
|
from connpy.ai import ai
|
||||||
@@ -434,28 +516,69 @@ el.replaceWith(d);
|
|||||||
prev_pos = cmd_byte_positions[i-1][0]
|
prev_pos = cmd_byte_positions[i-1][0]
|
||||||
|
|
||||||
if known_cmd:
|
if known_cmd:
|
||||||
prev_chunk = raw_bytes[prev_pos:pos]
|
if known_cmd == "CANCELLED":
|
||||||
prev_cleaned = log_cleaner(prev_chunk.decode(errors='replace'))
|
parsed_positions.append({"pos": pos, "type": "CANCELLED", "preview": ""})
|
||||||
prev_lines = [l for l in prev_cleaned.split('\n') if l.strip()]
|
else:
|
||||||
prompt_text = prev_lines[-1].strip() if prev_lines else ""
|
prev_chunk = raw_bytes[prev_pos:pos]
|
||||||
preview = f"{prompt_text}{known_cmd}" if prompt_text else known_cmd
|
prev_cleaned = self._clean_cisco_scrolling(prev_chunk.decode(errors='replace'))
|
||||||
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": preview[:80]})
|
prev_lines = [l for l in prev_cleaned.split('\n') if l.strip()]
|
||||||
|
prompt_text = prev_lines[-1].strip() if prev_lines else ""
|
||||||
|
preview = f"{prompt_text}{known_cmd}" if prompt_text else known_cmd
|
||||||
|
|
||||||
|
if len(preview) > 80:
|
||||||
|
preview = preview[:77] + "..."
|
||||||
|
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": preview})
|
||||||
else:
|
else:
|
||||||
chunk = raw_bytes[prev_pos:pos]
|
chunk = raw_bytes[prev_pos:pos]
|
||||||
cleaned = log_cleaner(chunk.decode(errors='replace'))
|
|
||||||
lines = [l for l in cleaned.split('\n') if l.strip()]
|
|
||||||
preview = lines[-1].strip() if lines else ""
|
|
||||||
|
|
||||||
if preview:
|
cleaned = self._clean_cisco_scrolling(chunk.decode(errors='replace'))
|
||||||
match = prompt_re.search(preview)
|
lines = [l for l in cleaned.split('\n') if l.strip()]
|
||||||
if match:
|
|
||||||
cmd_text = preview[match.end():].strip()
|
found_in_pass1 = False
|
||||||
if cmd_text:
|
if lines:
|
||||||
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": preview[:80]})
|
# Search backwards through the last few lines for the prompt
|
||||||
else:
|
for idx in range(len(lines) - 1, max(-1, len(lines) - 10), -1):
|
||||||
parsed_positions.append({"pos": pos, "type": "EMPTY_PROMPT", "preview": ""})
|
match = prompt_re.search(lines[idx])
|
||||||
else:
|
if match:
|
||||||
parsed_positions.append({"pos": pos, "type": "SCROLLING", "preview": ""})
|
ptxt = match.group(0).strip()
|
||||||
|
cmd_first_line = lines[idx][match.end():].strip()
|
||||||
|
cmd_rest = [l.strip() for l in lines[idx+1:]]
|
||||||
|
cmd_text = " ".join([cmd_first_line] + cmd_rest).strip()
|
||||||
|
|
||||||
|
if cmd_text:
|
||||||
|
pv = f"{ptxt} {cmd_text}".strip()
|
||||||
|
if len(pv) > 80:
|
||||||
|
pv = pv[:77] + "..."
|
||||||
|
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": pv})
|
||||||
|
else:
|
||||||
|
parsed_positions.append({"pos": pos, "type": "EMPTY_PROMPT", "preview": ""})
|
||||||
|
found_in_pass1 = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not found_in_pass1:
|
||||||
|
# Fallback: The prompt might have been isolated in the previous chunk
|
||||||
|
# due to asynchronous network delays splitting the output exactly at the newline.
|
||||||
|
prev_was_valid_cmd = i >= 2 and parsed_positions[i-2]["type"] == "VALID_CMD"
|
||||||
|
if prev_pos > 0 and not prev_was_valid_cmd:
|
||||||
|
# Fetch the very last chunk that we just processed
|
||||||
|
prev_prev_pos = cmd_byte_positions[i-2][0] if i >= 2 else 0
|
||||||
|
prev_chunk_text = self._clean_cisco_scrolling(raw_bytes[prev_prev_pos:prev_pos].decode(errors='replace'))
|
||||||
|
prev_lines_text = [l for l in prev_chunk_text.split('\n') if l.strip()]
|
||||||
|
|
||||||
|
if prev_lines_text:
|
||||||
|
prev_match = prompt_re.search(prev_lines_text[-1])
|
||||||
|
if prev_match:
|
||||||
|
ptxt = prev_match.group(0).strip()
|
||||||
|
cmd_text = " ".join([l.strip() for l in lines]).strip()
|
||||||
|
if cmd_text:
|
||||||
|
pv = f"{ptxt} {cmd_text}".strip()
|
||||||
|
if len(pv) > 80:
|
||||||
|
pv = pv[:77] + "..."
|
||||||
|
parsed_positions.append({"pos": pos, "type": "VALID_CMD", "preview": pv})
|
||||||
|
found_in_pass1 = True
|
||||||
|
|
||||||
|
if not found_in_pass1:
|
||||||
|
parsed_positions.append({"pos": pos, "type": "SCROLLING", "preview": ""})
|
||||||
else:
|
else:
|
||||||
parsed_positions.append({"pos": pos, "type": "SCROLLING", "preview": ""})
|
parsed_positions.append({"pos": pos, "type": "SCROLLING", "preview": ""})
|
||||||
|
|
||||||
@@ -468,11 +591,11 @@ el.replaceWith(d);
|
|||||||
start_pos = item["pos"]
|
start_pos = item["pos"]
|
||||||
preview = item["preview"]
|
preview = item["preview"]
|
||||||
|
|
||||||
# Find the end position: next VALID_CMD or EMPTY_PROMPT
|
# Find the end position: next VALID_CMD or EMPTY_PROMPT or CANCELLED
|
||||||
end_pos = current_prompt_pos
|
end_pos = current_prompt_pos
|
||||||
for j in range(i + 1, len(parsed_positions)):
|
for j in range(i + 1, len(parsed_positions)):
|
||||||
next_item = parsed_positions[j]
|
next_item = parsed_positions[j]
|
||||||
if next_item["type"] in ("VALID_CMD", "EMPTY_PROMPT"):
|
if next_item["type"] in ("VALID_CMD", "EMPTY_PROMPT", "CANCELLED"):
|
||||||
end_pos = next_item["pos"]
|
end_pos = next_item["pos"]
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -533,20 +656,22 @@ el.replaceWith(d);
|
|||||||
<div class="desc"><p>Update MCP server settings in the configuration with smart merging.</p></div>
|
<div class="desc"><p>Update MCP server settings in the configuration with smart merging.</p></div>
|
||||||
</dd>
|
</dd>
|
||||||
<dt id="connpy.services.AIService.configure_provider"><code class="name flex">
|
<dt id="connpy.services.AIService.configure_provider"><code class="name flex">
|
||||||
<span>def <span class="ident">configure_provider</span></span>(<span>self, provider, model=None, api_key=None)</span>
|
<span>def <span class="ident">configure_provider</span></span>(<span>self, provider, model=None, api_key=None, auth=None)</span>
|
||||||
</code></dt>
|
</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<details class="source">
|
<details class="source">
|
||||||
<summary>
|
<summary>
|
||||||
<span>Expand source code</span>
|
<span>Expand source code</span>
|
||||||
</summary>
|
</summary>
|
||||||
<pre><code class="python">def configure_provider(self, provider, model=None, api_key=None):
|
<pre><code class="python">def configure_provider(self, provider, model=None, api_key=None, auth=None):
|
||||||
"""Update AI provider settings in the configuration."""
|
"""Update AI provider settings in the configuration."""
|
||||||
settings = self.config.config.get("ai", {})
|
settings = self.config.config.get("ai", {})
|
||||||
if model:
|
if model:
|
||||||
settings[f"{provider}_model"] = model
|
settings[f"{provider}_model"] = model
|
||||||
if api_key:
|
if api_key:
|
||||||
settings[f"{provider}_api_key"] = api_key
|
settings[f"{provider}_api_key"] = api_key
|
||||||
|
if auth is not None:
|
||||||
|
settings[f"{provider}_auth"] = auth
|
||||||
|
|
||||||
self.config.config["ai"] = settings
|
self.config.config["ai"] = settings
|
||||||
self.config._saveconfig(self.config.file)</code></pre>
|
self.config._saveconfig(self.config.file)</code></pre>
|
||||||
@@ -589,21 +714,39 @@ el.replaceWith(d);
|
|||||||
</details>
|
</details>
|
||||||
<div class="desc"><p>Delete an AI session by ID.</p></div>
|
<div class="desc"><p>Delete an AI session by ID.</p></div>
|
||||||
</dd>
|
</dd>
|
||||||
<dt id="connpy.services.AIService.list_sessions"><code class="name flex">
|
<dt id="connpy.services.AIService.list_mcp_servers"><code class="name flex">
|
||||||
<span>def <span class="ident">list_sessions</span></span>(<span>self)</span>
|
<span>def <span class="ident">list_mcp_servers</span></span>(<span>self) ‑> dict</span>
|
||||||
</code></dt>
|
</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<details class="source">
|
<details class="source">
|
||||||
<summary>
|
<summary>
|
||||||
<span>Expand source code</span>
|
<span>Expand source code</span>
|
||||||
</summary>
|
</summary>
|
||||||
<pre><code class="python">def list_sessions(self):
|
<pre><code class="python">def list_mcp_servers(self) -> dict:
|
||||||
"""Return a list of all saved AI sessions."""
|
"""Get the configured MCP servers."""
|
||||||
|
ai_settings = self.config.config.get("ai", {})
|
||||||
|
return ai_settings.get("mcp_servers", {})</code></pre>
|
||||||
|
</details>
|
||||||
|
<div class="desc"><p>Get the configured MCP servers.</p></div>
|
||||||
|
</dd>
|
||||||
|
<dt id="connpy.services.AIService.list_sessions"><code class="name flex">
|
||||||
|
<span>def <span class="ident">list_sessions</span></span>(<span>self, limit=None)</span>
|
||||||
|
</code></dt>
|
||||||
|
<dd>
|
||||||
|
<details class="source">
|
||||||
|
<summary>
|
||||||
|
<span>Expand source code</span>
|
||||||
|
</summary>
|
||||||
|
<pre><code class="python">def list_sessions(self, limit=None):
|
||||||
|
"""Return a list of saved AI sessions, optionally limited."""
|
||||||
from connpy.ai import ai
|
from connpy.ai import ai
|
||||||
agent = ai(self.config)
|
agent = ai(self.config)
|
||||||
return agent._get_sessions()</code></pre>
|
sessions = agent._get_sessions()
|
||||||
|
if limit and len(sessions) > limit:
|
||||||
|
return sessions[:limit], len(sessions)
|
||||||
|
return sessions, len(sessions)</code></pre>
|
||||||
</details>
|
</details>
|
||||||
<div class="desc"><p>Return a list of all saved AI sessions.</p></div>
|
<div class="desc"><p>Return a list of saved AI sessions, optionally limited.</p></div>
|
||||||
</dd>
|
</dd>
|
||||||
<dt id="connpy.services.AIService.load_session_data"><code class="name flex">
|
<dt id="connpy.services.AIService.load_session_data"><code class="name flex">
|
||||||
<span>def <span class="ident">load_session_data</span></span>(<span>self, session_id)</span>
|
<span>def <span class="ident">load_session_data</span></span>(<span>self, session_id)</span>
|
||||||
@@ -3726,6 +3869,7 @@ el.replaceWith(d);
|
|||||||
<li><code><a title="connpy.services.AIService.configure_provider" href="#connpy.services.AIService.configure_provider">configure_provider</a></code></li>
|
<li><code><a title="connpy.services.AIService.configure_provider" href="#connpy.services.AIService.configure_provider">configure_provider</a></code></li>
|
||||||
<li><code><a title="connpy.services.AIService.confirm" href="#connpy.services.AIService.confirm">confirm</a></code></li>
|
<li><code><a title="connpy.services.AIService.confirm" href="#connpy.services.AIService.confirm">confirm</a></code></li>
|
||||||
<li><code><a title="connpy.services.AIService.delete_session" href="#connpy.services.AIService.delete_session">delete_session</a></code></li>
|
<li><code><a title="connpy.services.AIService.delete_session" href="#connpy.services.AIService.delete_session">delete_session</a></code></li>
|
||||||
|
<li><code><a title="connpy.services.AIService.list_mcp_servers" href="#connpy.services.AIService.list_mcp_servers">list_mcp_servers</a></code></li>
|
||||||
<li><code><a title="connpy.services.AIService.list_sessions" href="#connpy.services.AIService.list_sessions">list_sessions</a></code></li>
|
<li><code><a title="connpy.services.AIService.list_sessions" href="#connpy.services.AIService.list_sessions">list_sessions</a></code></li>
|
||||||
<li><code><a title="connpy.services.AIService.load_session_data" href="#connpy.services.AIService.load_session_data">load_session_data</a></code></li>
|
<li><code><a title="connpy.services.AIService.load_session_data" href="#connpy.services.AIService.load_session_data">load_session_data</a></code></li>
|
||||||
<li><code><a title="connpy.services.AIService.process_copilot_input" href="#connpy.services.AIService.process_copilot_input">process_copilot_input</a></code></li>
|
<li><code><a title="connpy.services.AIService.process_copilot_input" href="#connpy.services.AIService.process_copilot_input">process_copilot_input</a></code></li>
|
||||||
@@ -3840,7 +3984,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.services.node_service API documentation</title>
|
<title>connpy.services.node_service API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -786,7 +786,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.services.plugin_service API documentation</title>
|
<title>connpy.services.plugin_service API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -709,7 +709,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.services.profile_service API documentation</title>
|
<title>connpy.services.profile_service API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -429,7 +429,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.services.provider API documentation</title>
|
<title>connpy.services.provider API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -164,7 +164,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.services.sync_service API documentation</title>
|
<title>connpy.services.sync_service API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -964,7 +964,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.services.system_service API documentation</title>
|
<title>connpy.services.system_service API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -325,7 +325,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.tunnels API documentation</title>
|
<title>connpy.tunnels API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -545,7 +545,7 @@ Bridges the blocking gRPC iterators with the async _async_interact_loop.</p></di
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
||||||
<meta name="generator" content="pdoc3 0.11.5">
|
<meta name="generator" content="pdoc3 0.11.6">
|
||||||
<title>connpy.utils API documentation</title>
|
<title>connpy.utils API documentation</title>
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/13.0.0/sanitize.min.css" integrity="sha512-y1dtMcuvtTMJc1yPgEqF0ZjQbhnc/bFhyvIyVNb9Zk5mIGtqVaAB1Ttl28su8AvFMOY0EwRbAe+HCLqj6W7/KA==" crossorigin>
|
||||||
@@ -59,11 +59,14 @@ el.replaceWith(d);
|
|||||||
if not data:
|
if not data:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
# Remove OSC (Operating System Command) sequences (e.g., set window title \x1b]0;...\x07)
|
||||||
|
data = re.sub(r'\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)', '', data)
|
||||||
|
|
||||||
lines = data.split('\n')
|
lines = data.split('\n')
|
||||||
cleaned_lines = []
|
cleaned_lines = []
|
||||||
|
|
||||||
# Regex to capture: ANSI sequences, control characters (\r, \b, etc), and plain text chunks
|
# Regex to capture: ANSI sequences, control characters (\r, \b, etc), and plain text chunks
|
||||||
token_re = re.compile(r'(\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/ ]*[@-~])|\r|\b|\x7f|[\x00-\x1F]|[^\x1B\r\b\x7f\x00-\x1F]+)')
|
token_re = re.compile(r'(\x1B(?:[\x30-\x5A\x5C-\x7E]|\[[0-?]*[ -/ ]*[@-~])|\r|\b|\x7f|[\x00-\x1F]|[^\x1B\r\b\x7f\x00-\x1F]+)')
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
buffer = []
|
buffer = []
|
||||||
@@ -144,7 +147,7 @@ el.replaceWith(d);
|
|||||||
</nav>
|
</nav>
|
||||||
</main>
|
</main>
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.5</a>.</p>
|
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.11.6</a>.</p>
|
||||||
</footer>
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user