2881 lines
120 KiB
HTML
2881 lines
120 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1">
|
|
<meta name="generator" content="pdoc3 0.11.5">
|
|
<title>connpy.grpc_layer.stubs API documentation</title>
|
|
<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/typography.min.css" integrity="sha512-Y1DYSb995BAfxobCkKepB1BqJJTPrOp3zPL74AWFugHHmmdcvO+C48WLrUOlhGMc0QG7AE3f7gmvvcrmX2fDoA==" crossorigin>
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css" crossorigin>
|
|
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:1.5em;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:2em 0 .50em 0}h3{font-size:1.4em;margin:1.6em 0 .7em 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .2s ease-in-out}a:visited{color:#503}a:hover{color:#b62}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900;font-weight:bold}pre code{font-size:.8em;line-height:1.4em;padding:1em;display:block}code{background:#f3f3f3;font-family:"DejaVu Sans Mono",monospace;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source > summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible;min-width:max-content}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em 1em;margin:1em 0}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
|
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul ul{padding-left:1em}.toc > ul > li{margin-top:.5em}}</style>
|
|
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js" integrity="sha512-D9gUyxqja7hBtkWpPWGt9wfbfaMGVt9gnyCvYa+jojwwPHLCzUm5i8rpk7vD7wNee9bA35eYIjobYPaQuKS1MQ==" crossorigin></script>
|
|
<script>window.addEventListener('DOMContentLoaded', () => {
|
|
hljs.configure({languages: ['bash', 'css', 'diff', 'graphql', 'ini', 'javascript', 'json', 'plaintext', 'python', 'python-repl', 'rust', 'shell', 'sql', 'typescript', 'xml', 'yaml']});
|
|
hljs.highlightAll();
|
|
/* Collapse source docstrings */
|
|
setTimeout(() => {
|
|
[...document.querySelectorAll('.hljs.language-python > .hljs-string')]
|
|
.filter(el => el.innerHTML.length > 200 && ['"""', "'''"].includes(el.innerHTML.substring(0, 3)))
|
|
.forEach(el => {
|
|
let d = document.createElement('details');
|
|
d.classList.add('hljs-string');
|
|
d.innerHTML = '<summary>"""</summary>' + el.innerHTML.substring(3);
|
|
el.replaceWith(d);
|
|
});
|
|
}, 100);
|
|
})</script>
|
|
</head>
|
|
<body>
|
|
<main>
|
|
<article id="content">
|
|
<header>
|
|
<h1 class="title">Module <code>connpy.grpc_layer.stubs</code></h1>
|
|
</header>
|
|
<section id="section-intro">
|
|
</section>
|
|
<section>
|
|
</section>
|
|
<section>
|
|
</section>
|
|
<section>
|
|
<h2 class="section-title" id="header-functions">Functions</h2>
|
|
<dl>
|
|
<dt id="connpy.grpc_layer.stubs.handle_errors"><code class="name flex">
|
|
<span>def <span class="ident">handle_errors</span></span>(<span>func)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def handle_errors(func):
|
|
@wraps(func)
|
|
def wrapper(*args, **kwargs):
|
|
try:
|
|
return func(*args, **kwargs)
|
|
except grpc.RpcError as e:
|
|
# Re-raise gRPC errors as native ConnpyError to keep CLI handlers agnostic
|
|
details = e.details()
|
|
|
|
# Identify the host if available on the instance
|
|
instance = args[0] if args else None
|
|
host = getattr(instance, "remote_host", "remote host")
|
|
|
|
# Make common gRPC errors more readable
|
|
if "failed to connect to all addresses" in details:
|
|
simplified = f"Failed to connect to remote host at {host} (Connection refused)"
|
|
elif "Method not found" in details:
|
|
simplified = f"Remote server at {host} is using an incompatible version"
|
|
elif "Deadline Exceeded" in details:
|
|
simplified = f"Request to {host} timed out"
|
|
else:
|
|
simplified = details
|
|
|
|
raise ConnpyError(simplified)
|
|
return wrapper</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
</dl>
|
|
</section>
|
|
<section>
|
|
<h2 class="section-title" id="header-classes">Classes</h2>
|
|
<dl>
|
|
<dt id="connpy.grpc_layer.stubs.AIStub"><code class="flex name class">
|
|
<span>class <span class="ident">AIStub</span></span>
|
|
<span>(</span><span>channel, remote_host)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">class AIStub:
|
|
def __init__(self, channel, remote_host):
|
|
self.stub = connpy_pb2_grpc.AIServiceStub(channel)
|
|
self.remote_host = remote_host
|
|
|
|
def _ai_chat_stream(self, stub_method, input_text, dryrun=False, chat_history=None, session_id=None, debug=False, status=None, chunk_callback=None, **overrides):
|
|
import queue
|
|
from rich.prompt import Prompt
|
|
from rich.text import Text
|
|
from rich.panel import Panel
|
|
from rich.markdown import Markdown
|
|
|
|
req_queue = queue.Queue()
|
|
|
|
initial_req = connpy_pb2.AskRequest(
|
|
input_text=input_text,
|
|
dryrun=dryrun,
|
|
session_id=session_id or "",
|
|
debug=debug,
|
|
engineer_model=overrides.get("engineer_model", ""),
|
|
engineer_api_key=overrides.get("engineer_api_key", ""),
|
|
architect_model=overrides.get("architect_model", ""),
|
|
architect_api_key=overrides.get("architect_api_key", ""),
|
|
trust=overrides.get("trust", False)
|
|
)
|
|
if chat_history is not None:
|
|
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)
|
|
|
|
def request_generator():
|
|
while True:
|
|
req = req_queue.get()
|
|
if req is None: break
|
|
yield req
|
|
|
|
responses = stub_method(request_generator())
|
|
|
|
full_content = ""
|
|
header_printed = False
|
|
current_responder = "engineer"
|
|
final_result = {"response": "", "chat_history": []}
|
|
|
|
# Background thread to pull responses from gRPC into a local queue
|
|
# This prevents KeyboardInterrupt from corrupting the gRPC iterator state
|
|
response_queue = queue.Queue()
|
|
|
|
def pull_responses():
|
|
try:
|
|
for response in responses:
|
|
response_queue.put(("data", response))
|
|
except Exception as e:
|
|
response_queue.put(("error", e))
|
|
finally:
|
|
response_queue.put((None, None))
|
|
|
|
threading.Thread(target=pull_responses, daemon=True).start()
|
|
|
|
try:
|
|
while True:
|
|
try:
|
|
# BLOCKING GET from local queue (interruptible by signal)
|
|
msg_type, response = response_queue.get()
|
|
except KeyboardInterrupt:
|
|
# Signal interruption to the server
|
|
if status:
|
|
status.update("[error]Interrupted! Closing pending tasks...")
|
|
|
|
# Send the interrupt signal to the server
|
|
req_queue.put(connpy_pb2.AskRequest(interrupt=True))
|
|
|
|
# CONTINUE the loop to receive remaining data and summary from the queue
|
|
continue
|
|
|
|
if msg_type is None: # Sentinel
|
|
break
|
|
|
|
if msg_type == "error":
|
|
# Re-raise or handle gRPC error from background thread
|
|
if isinstance(response, grpc.RpcError):
|
|
raise response
|
|
printer.warning(f"Stream interrupted: {response}")
|
|
break
|
|
|
|
if response.status_update:
|
|
if response.status_update.startswith("__RESPONDER__:"):
|
|
current_responder = response.status_update.split(":")[1].lower()
|
|
continue
|
|
|
|
if response.requires_confirmation:
|
|
if status: status.stop()
|
|
|
|
# Show prompt and wait for answer
|
|
prompt_text = Text.from_ansi(response.status_update)
|
|
ans = Prompt.ask(prompt_text)
|
|
|
|
if status:
|
|
status.update("[ai_status]Agent: Resuming...")
|
|
status.start()
|
|
|
|
req_queue.put(connpy_pb2.AskRequest(confirmation_answer=ans))
|
|
continue
|
|
|
|
if status:
|
|
status.update(response.status_update)
|
|
continue
|
|
|
|
if response.debug_message:
|
|
if debug:
|
|
if status:
|
|
try: status.stop()
|
|
except: pass
|
|
printer.console.print(Text.from_ansi(response.debug_message))
|
|
if status:
|
|
try: status.start()
|
|
except: pass
|
|
continue
|
|
|
|
if response.important_message:
|
|
if status:
|
|
try: status.stop()
|
|
except: pass
|
|
printer.console.print(Text.from_ansi(response.important_message))
|
|
if status:
|
|
try: status.start()
|
|
except: pass
|
|
continue
|
|
|
|
if not response.is_final:
|
|
if response.text_chunk:
|
|
if not header_printed:
|
|
if status:
|
|
try: status.stop()
|
|
except: pass
|
|
|
|
if chunk_callback:
|
|
header_printed = True
|
|
else:
|
|
from rich.console import Console as RichConsole
|
|
from rich.rule import Rule
|
|
from ..printer import connpy_theme, get_original_stdout, IncrementalMarkdownParser
|
|
stable_console = RichConsole(theme=connpy_theme, file=get_original_stdout())
|
|
|
|
# Print header on first chunk
|
|
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
|
|
|
|
# Initialize parser
|
|
md_parser = IncrementalMarkdownParser(console=stable_console)
|
|
|
|
full_content += response.text_chunk
|
|
if chunk_callback:
|
|
chunk_callback(response.text_chunk)
|
|
elif md_parser:
|
|
md_parser.feed(response.text_chunk)
|
|
continue
|
|
|
|
if response.is_final:
|
|
if not chunk_callback and header_printed:
|
|
from rich.rule import Rule
|
|
md_parser.flush()
|
|
|
|
if status:
|
|
try: status.stop()
|
|
except: pass
|
|
|
|
final_result = from_struct(response.full_result)
|
|
|
|
if not chunk_callback and header_printed:
|
|
from rich.console import Console as RichConsole
|
|
from ..printer import connpy_theme, get_original_stdout
|
|
stable_console = RichConsole(theme=connpy_theme, file=get_original_stdout())
|
|
stable_console.print(Rule(style=alias))
|
|
break
|
|
except Exception as e:
|
|
# Check if it was a gRPC error that we should let handle_errors catch
|
|
if isinstance(e, grpc.RpcError):
|
|
raise
|
|
printer.warning(f"Stream interrupted: {e}")
|
|
finally:
|
|
req_queue.put(None)
|
|
|
|
if full_content:
|
|
final_result["streamed"] = True
|
|
|
|
return final_result
|
|
|
|
@handle_errors
|
|
def ask(self, input_text, dryrun=False, chat_history=None, session_id=None, debug=False, status=None, **overrides):
|
|
return self._ai_chat_stream(self.stub.ask, input_text, dryrun=dryrun, chat_history=chat_history, session_id=session_id, debug=debug, status=status, **overrides)
|
|
|
|
@handle_errors
|
|
def build_playbook_chat(self, user_input, chat_history=None, status=None, chunk_callback=None):
|
|
return self._ai_chat_stream(self.stub.build_playbook_chat, user_input, chat_history=chat_history, status=status, chunk_callback=chunk_callback)
|
|
|
|
def _process_unary_stream(self, responses, status=None, chunk_callback=None):
|
|
full_content = ""
|
|
header_printed = False
|
|
final_result = {"response": "", "chat_history": []}
|
|
md_parser = None
|
|
|
|
try:
|
|
for response in responses:
|
|
if response.status_update:
|
|
if status:
|
|
status.update(response.status_update)
|
|
continue
|
|
|
|
if response.important_message:
|
|
if status:
|
|
try: status.stop()
|
|
except: pass
|
|
printer.console.print(Text.from_ansi(response.important_message))
|
|
if status:
|
|
try: status.start()
|
|
except: pass
|
|
continue
|
|
|
|
if not response.is_final:
|
|
if response.text_chunk:
|
|
if not header_printed:
|
|
if status:
|
|
try: status.stop()
|
|
except: pass
|
|
|
|
if chunk_callback:
|
|
header_printed = True
|
|
else:
|
|
from rich.console import Console as RichConsole
|
|
from rich.rule import Rule
|
|
from ..printer import connpy_theme, get_original_stdout, IncrementalMarkdownParser
|
|
stable_console = RichConsole(theme=connpy_theme, file=get_original_stdout())
|
|
|
|
# Print default header
|
|
stable_console.print(Rule("[bold engineer]AI Analysis[/bold engineer]", style="engineer"))
|
|
header_printed = True
|
|
md_parser = IncrementalMarkdownParser(console=stable_console)
|
|
|
|
full_content += response.text_chunk
|
|
if chunk_callback:
|
|
chunk_callback(response.text_chunk)
|
|
elif md_parser:
|
|
md_parser.feed(response.text_chunk)
|
|
continue
|
|
|
|
if response.is_final:
|
|
if md_parser:
|
|
md_parser.flush()
|
|
|
|
if status:
|
|
try: status.stop()
|
|
except: pass
|
|
|
|
final_result = from_struct(response.full_result)
|
|
|
|
if md_parser:
|
|
from rich.console import Console as RichConsole
|
|
from rich.rule import Rule
|
|
from ..printer import connpy_theme, get_original_stdout
|
|
stable_console = RichConsole(theme=connpy_theme, file=get_original_stdout())
|
|
stable_console.print(Rule(style="engineer"))
|
|
break
|
|
except Exception as e:
|
|
if isinstance(e, grpc.RpcError):
|
|
raise
|
|
printer.warning(f"Stream interrupted: {e}")
|
|
|
|
if full_content:
|
|
final_result["streamed"] = True
|
|
|
|
return final_result
|
|
|
|
@handle_errors
|
|
def analyze_execution_results(self, results, query=None, status=None, chunk_callback=None):
|
|
req = connpy_pb2.AnalyzeRequest(query=query or "")
|
|
req.results.CopyFrom(to_struct(results))
|
|
responses = self.stub.analyze_execution_results(req)
|
|
return self._process_unary_stream(responses, status, chunk_callback)
|
|
|
|
@handle_errors
|
|
def predict_execution_results(self, target_nodes, commands, status=None, chunk_callback=None):
|
|
req = connpy_pb2.PreflightRequest(target_nodes=target_nodes, commands=commands)
|
|
responses = self.stub.predict_execution_results(req)
|
|
return self._process_unary_stream(responses, status, chunk_callback)
|
|
|
|
@handle_errors
|
|
def confirm(self, input_text, console=None):
|
|
return self.stub.confirm(connpy_pb2.StringRequest(value=input_text)).value
|
|
|
|
@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)
|
|
|
|
@handle_errors
|
|
def delete_session(self, session_id):
|
|
self.stub.delete_session(connpy_pb2.StringRequest(value=session_id))
|
|
|
|
@handle_errors
|
|
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 "")
|
|
if auth:
|
|
req.auth.CopyFrom(to_struct(auth))
|
|
self.stub.configure_provider(req)
|
|
|
|
@handle_errors
|
|
def configure_mcp(self, name, url=None, enabled=True, auto_load_on_os=None, remove=False):
|
|
req = connpy_pb2.MCPRequest(
|
|
name=name,
|
|
url=url or "",
|
|
enabled=enabled,
|
|
auto_load_on_os=auto_load_on_os or "",
|
|
remove=remove
|
|
)
|
|
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
|
|
def load_session_data(self, session_id):
|
|
return from_struct(self.stub.load_session_data(connpy_pb2.StringRequest(value=session_id)).data)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
<h3>Methods</h3>
|
|
<dl>
|
|
<dt id="connpy.grpc_layer.stubs.AIStub.analyze_execution_results"><code class="name flex">
|
|
<span>def <span class="ident">analyze_execution_results</span></span>(<span>self, results, query=None, status=None, chunk_callback=None)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def analyze_execution_results(self, results, query=None, status=None, chunk_callback=None):
|
|
req = connpy_pb2.AnalyzeRequest(query=query or "")
|
|
req.results.CopyFrom(to_struct(results))
|
|
responses = self.stub.analyze_execution_results(req)
|
|
return self._process_unary_stream(responses, status, chunk_callback)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.AIStub.ask"><code class="name flex">
|
|
<span>def <span class="ident">ask</span></span>(<span>self,<br>input_text,<br>dryrun=False,<br>chat_history=None,<br>session_id=None,<br>debug=False,<br>status=None,<br>**overrides)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def ask(self, input_text, dryrun=False, chat_history=None, session_id=None, debug=False, status=None, **overrides):
|
|
return self._ai_chat_stream(self.stub.ask, input_text, dryrun=dryrun, chat_history=chat_history, session_id=session_id, debug=debug, status=status, **overrides)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.AIStub.build_playbook_chat"><code class="name flex">
|
|
<span>def <span class="ident">build_playbook_chat</span></span>(<span>self, user_input, chat_history=None, status=None, chunk_callback=None)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def build_playbook_chat(self, user_input, chat_history=None, status=None, chunk_callback=None):
|
|
return self._ai_chat_stream(self.stub.build_playbook_chat, user_input, chat_history=chat_history, status=status, chunk_callback=chunk_callback)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.AIStub.configure_mcp"><code class="name flex">
|
|
<span>def <span class="ident">configure_mcp</span></span>(<span>self, name, url=None, enabled=True, auto_load_on_os=None, remove=False)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def configure_mcp(self, name, url=None, enabled=True, auto_load_on_os=None, remove=False):
|
|
req = connpy_pb2.MCPRequest(
|
|
name=name,
|
|
url=url or "",
|
|
enabled=enabled,
|
|
auto_load_on_os=auto_load_on_os or "",
|
|
remove=remove
|
|
)
|
|
self.stub.configure_mcp(req)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<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, auth=None)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
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 "")
|
|
if auth:
|
|
req.auth.CopyFrom(to_struct(auth))
|
|
self.stub.configure_provider(req)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.AIStub.confirm"><code class="name flex">
|
|
<span>def <span class="ident">confirm</span></span>(<span>self, input_text, console=None)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def confirm(self, input_text, console=None):
|
|
return self.stub.confirm(connpy_pb2.StringRequest(value=input_text)).value</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.AIStub.delete_session"><code class="name flex">
|
|
<span>def <span class="ident">delete_session</span></span>(<span>self, session_id)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def delete_session(self, session_id):
|
|
self.stub.delete_session(connpy_pb2.StringRequest(value=session_id))</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.AIStub.list_mcp_servers"><code class="name flex">
|
|
<span>def <span class="ident">list_mcp_servers</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def list_mcp_servers(self):
|
|
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>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.AIStub.load_session_data"><code class="name flex">
|
|
<span>def <span class="ident">load_session_data</span></span>(<span>self, session_id)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def load_session_data(self, session_id):
|
|
return from_struct(self.stub.load_session_data(connpy_pb2.StringRequest(value=session_id)).data)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.AIStub.predict_execution_results"><code class="name flex">
|
|
<span>def <span class="ident">predict_execution_results</span></span>(<span>self, target_nodes, commands, status=None, chunk_callback=None)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def predict_execution_results(self, target_nodes, commands, status=None, chunk_callback=None):
|
|
req = connpy_pb2.PreflightRequest(target_nodes=target_nodes, commands=commands)
|
|
responses = self.stub.predict_execution_results(req)
|
|
return self._process_unary_stream(responses, status, chunk_callback)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
</dl>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.AuthClientInterceptor"><code class="flex name class">
|
|
<span>class <span class="ident">AuthClientInterceptor</span></span>
|
|
<span>(</span><span>token_provider)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">class AuthClientInterceptor(grpc.UnaryUnaryClientInterceptor,
|
|
grpc.UnaryStreamClientInterceptor,
|
|
grpc.StreamUnaryClientInterceptor,
|
|
grpc.StreamStreamClientInterceptor):
|
|
def __init__(self, token_provider):
|
|
self.token_provider = token_provider
|
|
|
|
def _add_metadata(self, client_call_details):
|
|
token = self.token_provider()
|
|
if not token:
|
|
return client_call_details
|
|
|
|
metadata = []
|
|
if client_call_details.metadata:
|
|
metadata = list(client_call_details.metadata)
|
|
|
|
# Check if already present to avoid duplicates
|
|
if not any(k.lower() == "authorization" for k, v in metadata):
|
|
metadata.append(("authorization", f"Bearer {token}"))
|
|
|
|
return _ClientCallDetails(
|
|
method=client_call_details.method,
|
|
timeout=client_call_details.timeout,
|
|
metadata=metadata,
|
|
credentials=client_call_details.credentials,
|
|
wait_for_ready=client_call_details.wait_for_ready,
|
|
compression=client_call_details.compression,
|
|
)
|
|
|
|
def intercept_unary_unary(self, continuation, client_call_details, request):
|
|
new_details = self._add_metadata(client_call_details)
|
|
return continuation(new_details, request)
|
|
|
|
def intercept_unary_stream(self, continuation, client_call_details, request):
|
|
new_details = self._add_metadata(client_call_details)
|
|
return continuation(new_details, request)
|
|
|
|
def intercept_stream_unary(self, continuation, client_call_details, request_iterator):
|
|
new_details = self._add_metadata(client_call_details)
|
|
return continuation(new_details, request_iterator)
|
|
|
|
def intercept_stream_stream(self, continuation, client_call_details, request_iterator):
|
|
new_details = self._add_metadata(client_call_details)
|
|
return continuation(new_details, request_iterator)</code></pre>
|
|
</details>
|
|
<div class="desc"><p>Affords intercepting unary-unary invocations.</p></div>
|
|
<h3>Ancestors</h3>
|
|
<ul class="hlist">
|
|
<li>grpc.UnaryUnaryClientInterceptor</li>
|
|
<li>grpc.UnaryStreamClientInterceptor</li>
|
|
<li>grpc.StreamUnaryClientInterceptor</li>
|
|
<li>grpc.StreamStreamClientInterceptor</li>
|
|
<li>abc.ABC</li>
|
|
</ul>
|
|
<h3>Methods</h3>
|
|
<dl>
|
|
<dt id="connpy.grpc_layer.stubs.AuthClientInterceptor.intercept_stream_stream"><code class="name flex">
|
|
<span>def <span class="ident">intercept_stream_stream</span></span>(<span>self, continuation, client_call_details, request_iterator)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def intercept_stream_stream(self, continuation, client_call_details, request_iterator):
|
|
new_details = self._add_metadata(client_call_details)
|
|
return continuation(new_details, request_iterator)</code></pre>
|
|
</details>
|
|
<div class="desc"><p>Intercepts a stream-stream invocation.</p>
|
|
<h2 id="args">Args</h2>
|
|
<dl>
|
|
<dt><strong><code>continuation</code></strong></dt>
|
|
<dd>A function that proceeds with the invocation by
|
|
executing the next interceptor in chain or invoking the
|
|
actual RPC on the underlying Channel. It is the interceptor's
|
|
responsibility to call it if it decides to move the RPC forward.
|
|
The interceptor can use
|
|
<code>response_iterator = continuation(client_call_details, request_iterator)</code>
|
|
to continue with the RPC. <code>continuation</code> returns an object that is
|
|
both a Call for the RPC and an iterator for response values.
|
|
Drawing response values from the returned Call-iterator may
|
|
raise RpcError indicating termination of the RPC with non-OK
|
|
status.</dd>
|
|
<dt><strong><code>client_call_details</code></strong></dt>
|
|
<dd>A ClientCallDetails object describing the
|
|
outgoing RPC.</dd>
|
|
<dt><strong><code>request_iterator</code></strong></dt>
|
|
<dd>An iterator that yields request values for the RPC.</dd>
|
|
</dl>
|
|
<h2 id="returns">Returns</h2>
|
|
<p>An object that is both a Call for the RPC and an iterator of
|
|
response values. Drawing response values from the returned
|
|
Call-iterator may raise RpcError indicating termination of
|
|
the RPC with non-OK status. This object <em>should</em> also fulfill the
|
|
Future interface, though it may not.</p></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.AuthClientInterceptor.intercept_stream_unary"><code class="name flex">
|
|
<span>def <span class="ident">intercept_stream_unary</span></span>(<span>self, continuation, client_call_details, request_iterator)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def intercept_stream_unary(self, continuation, client_call_details, request_iterator):
|
|
new_details = self._add_metadata(client_call_details)
|
|
return continuation(new_details, request_iterator)</code></pre>
|
|
</details>
|
|
<div class="desc"><p>Intercepts a stream-unary invocation asynchronously.</p>
|
|
<h2 id="args">Args</h2>
|
|
<dl>
|
|
<dt><strong><code>continuation</code></strong></dt>
|
|
<dd>A function that proceeds with the invocation by
|
|
executing the next interceptor in chain or invoking the
|
|
actual RPC on the underlying Channel. It is the interceptor's
|
|
responsibility to call it if it decides to move the RPC forward.
|
|
The interceptor can use
|
|
<code>response_future = continuation(client_call_details, request_iterator)</code>
|
|
to continue with the RPC. <code>continuation</code> returns an object that is
|
|
both a Call for the RPC and a Future. In the event of RPC completion,
|
|
the return Call-Future's result value will be the response message
|
|
of the RPC. Should the event terminate with non-OK status, the
|
|
returned Call-Future's exception value will be an RpcError.</dd>
|
|
<dt><strong><code>client_call_details</code></strong></dt>
|
|
<dd>A ClientCallDetails object describing the
|
|
outgoing RPC.</dd>
|
|
<dt><strong><code>request_iterator</code></strong></dt>
|
|
<dd>An iterator that yields request values for the RPC.</dd>
|
|
</dl>
|
|
<h2 id="returns">Returns</h2>
|
|
<p>An object that is both a Call for the RPC and a Future.
|
|
In the event of RPC completion, the return Call-Future's
|
|
result value will be the response message of the RPC.
|
|
Should the event terminate with non-OK status, the returned
|
|
Call-Future's exception value will be an RpcError.</p></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.AuthClientInterceptor.intercept_unary_stream"><code class="name flex">
|
|
<span>def <span class="ident">intercept_unary_stream</span></span>(<span>self, continuation, client_call_details, request)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def intercept_unary_stream(self, continuation, client_call_details, request):
|
|
new_details = self._add_metadata(client_call_details)
|
|
return continuation(new_details, request)</code></pre>
|
|
</details>
|
|
<div class="desc"><p>Intercepts a unary-stream invocation.</p>
|
|
<h2 id="args">Args</h2>
|
|
<dl>
|
|
<dt><strong><code>continuation</code></strong></dt>
|
|
<dd>A function that proceeds with the invocation by
|
|
executing the next interceptor in chain or invoking the
|
|
actual RPC on the underlying Channel. It is the interceptor's
|
|
responsibility to call it if it decides to move the RPC forward.
|
|
The interceptor can use
|
|
<code>response_iterator = continuation(client_call_details, request)</code>
|
|
to continue with the RPC. <code>continuation</code> returns an object that is
|
|
both a Call for the RPC and an iterator for response values.
|
|
Drawing response values from the returned Call-iterator may
|
|
raise RpcError indicating termination of the RPC with non-OK
|
|
status.</dd>
|
|
<dt><strong><code>client_call_details</code></strong></dt>
|
|
<dd>A ClientCallDetails object describing the
|
|
outgoing RPC.</dd>
|
|
<dt><strong><code>request</code></strong></dt>
|
|
<dd>The request value for the RPC.</dd>
|
|
</dl>
|
|
<h2 id="returns">Returns</h2>
|
|
<p>An object that is both a Call for the RPC and an iterator of
|
|
response values. Drawing response values from the returned
|
|
Call-iterator may raise RpcError indicating termination of
|
|
the RPC with non-OK status. This object <em>should</em> also fulfill the
|
|
Future interface, though it may not.</p></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.AuthClientInterceptor.intercept_unary_unary"><code class="name flex">
|
|
<span>def <span class="ident">intercept_unary_unary</span></span>(<span>self, continuation, client_call_details, request)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">def intercept_unary_unary(self, continuation, client_call_details, request):
|
|
new_details = self._add_metadata(client_call_details)
|
|
return continuation(new_details, request)</code></pre>
|
|
</details>
|
|
<div class="desc"><p>Intercepts a unary-unary invocation asynchronously.</p>
|
|
<h2 id="args">Args</h2>
|
|
<dl>
|
|
<dt><strong><code>continuation</code></strong></dt>
|
|
<dd>A function that proceeds with the invocation by
|
|
executing the next interceptor in chain or invoking the
|
|
actual RPC on the underlying Channel. It is the interceptor's
|
|
responsibility to call it if it decides to move the RPC forward.
|
|
The interceptor can use
|
|
<code>response_future = continuation(client_call_details, request)</code>
|
|
to continue with the RPC. <code>continuation</code> returns an object that is
|
|
both a Call for the RPC and a Future. In the event of RPC
|
|
completion, the return Call-Future's result value will be
|
|
the response message of the RPC. Should the event terminate
|
|
with non-OK status, the returned Call-Future's exception value
|
|
will be an RpcError.</dd>
|
|
<dt><strong><code>client_call_details</code></strong></dt>
|
|
<dd>A ClientCallDetails object describing the
|
|
outgoing RPC.</dd>
|
|
<dt><strong><code>request</code></strong></dt>
|
|
<dd>The request value for the RPC.</dd>
|
|
</dl>
|
|
<h2 id="returns">Returns</h2>
|
|
<p>An object that is both a Call for the RPC and a Future.
|
|
In the event of RPC completion, the return Call-Future's
|
|
result value will be the response message of the RPC.
|
|
Should the event terminate with non-OK status, the returned
|
|
Call-Future's exception value will be an RpcError.</p></div>
|
|
</dd>
|
|
</dl>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.AuthStub"><code class="flex name class">
|
|
<span>class <span class="ident">AuthStub</span></span>
|
|
<span>(</span><span>channel, remote_host)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">class AuthStub:
|
|
def __init__(self, channel, remote_host):
|
|
self.stub = connpy_pb2_grpc.AuthServiceStub(channel)
|
|
self.remote_host = remote_host
|
|
|
|
@handle_errors
|
|
def login(self, username, password):
|
|
req = connpy_pb2.LoginRequest(username=username, password=password)
|
|
resp = self.stub.login(req)
|
|
return {
|
|
"token": resp.token,
|
|
"username": resp.username,
|
|
"expires_at": resp.expires_at
|
|
}
|
|
|
|
@handle_errors
|
|
def change_password(self, old_password, new_password):
|
|
req = connpy_pb2.ChangePasswordRequest(old_password=old_password, new_password=new_password)
|
|
self.stub.change_password(req)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
<h3>Methods</h3>
|
|
<dl>
|
|
<dt id="connpy.grpc_layer.stubs.AuthStub.change_password"><code class="name flex">
|
|
<span>def <span class="ident">change_password</span></span>(<span>self, old_password, new_password)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def change_password(self, old_password, new_password):
|
|
req = connpy_pb2.ChangePasswordRequest(old_password=old_password, new_password=new_password)
|
|
self.stub.change_password(req)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.AuthStub.login"><code class="name flex">
|
|
<span>def <span class="ident">login</span></span>(<span>self, username, password)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def login(self, username, password):
|
|
req = connpy_pb2.LoginRequest(username=username, password=password)
|
|
resp = self.stub.login(req)
|
|
return {
|
|
"token": resp.token,
|
|
"username": resp.username,
|
|
"expires_at": resp.expires_at
|
|
}</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
</dl>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.ConfigStub"><code class="flex name class">
|
|
<span>class <span class="ident">ConfigStub</span></span>
|
|
<span>(</span><span>channel, remote_host)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">class ConfigStub:
|
|
def __init__(self, channel, remote_host):
|
|
self.stub = connpy_pb2_grpc.ConfigServiceStub(channel)
|
|
self.remote_host = remote_host
|
|
|
|
@handle_errors
|
|
def get_settings(self):
|
|
return from_struct(self.stub.get_settings(Empty()).data)
|
|
|
|
@handle_errors
|
|
def update_setting(self, key, value):
|
|
self.stub.update_setting(connpy_pb2.UpdateRequest(key=key, value=to_value(value)))
|
|
|
|
@handle_errors
|
|
def get_default_dir(self):
|
|
return self.stub.get_default_dir(Empty()).value
|
|
|
|
@handle_errors
|
|
def set_config_folder(self, folder):
|
|
self.stub.set_config_folder(connpy_pb2.StringRequest(value=folder))
|
|
|
|
@handle_errors
|
|
def encrypt_password(self, password):
|
|
return self.stub.encrypt_password(connpy_pb2.StringRequest(value=password)).value</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
<h3>Methods</h3>
|
|
<dl>
|
|
<dt id="connpy.grpc_layer.stubs.ConfigStub.encrypt_password"><code class="name flex">
|
|
<span>def <span class="ident">encrypt_password</span></span>(<span>self, password)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def encrypt_password(self, password):
|
|
return self.stub.encrypt_password(connpy_pb2.StringRequest(value=password)).value</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.ConfigStub.get_default_dir"><code class="name flex">
|
|
<span>def <span class="ident">get_default_dir</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def get_default_dir(self):
|
|
return self.stub.get_default_dir(Empty()).value</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.ConfigStub.get_settings"><code class="name flex">
|
|
<span>def <span class="ident">get_settings</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def get_settings(self):
|
|
return from_struct(self.stub.get_settings(Empty()).data)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.ConfigStub.set_config_folder"><code class="name flex">
|
|
<span>def <span class="ident">set_config_folder</span></span>(<span>self, folder)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def set_config_folder(self, folder):
|
|
self.stub.set_config_folder(connpy_pb2.StringRequest(value=folder))</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.ConfigStub.update_setting"><code class="name flex">
|
|
<span>def <span class="ident">update_setting</span></span>(<span>self, key, value)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def update_setting(self, key, value):
|
|
self.stub.update_setting(connpy_pb2.UpdateRequest(key=key, value=to_value(value)))</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
</dl>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.ExecutionStub"><code class="flex name class">
|
|
<span>class <span class="ident">ExecutionStub</span></span>
|
|
<span>(</span><span>channel, remote_host)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">class ExecutionStub:
|
|
def __init__(self, channel, remote_host):
|
|
self.stub = connpy_pb2_grpc.ExecutionServiceStub(channel)
|
|
self.remote_host = remote_host
|
|
|
|
@handle_errors
|
|
def run_commands(self, nodes_filter, commands, variables=None, parallel=10, timeout=10, folder=None, prompt=None, **kwargs):
|
|
nodes_list = [nodes_filter] if isinstance(nodes_filter, str) else list(nodes_filter)
|
|
req = connpy_pb2.RunRequest(
|
|
nodes=nodes_list,
|
|
commands=commands,
|
|
folder=folder or "",
|
|
prompt=prompt or "",
|
|
parallel=parallel,
|
|
timeout=timeout,
|
|
name=kwargs.get("name", "")
|
|
)
|
|
if variables is not None:
|
|
req.vars.CopyFrom(to_struct(variables))
|
|
|
|
final_results = {}
|
|
on_complete = kwargs.get("on_node_complete")
|
|
|
|
for response in self.stub.run_commands(req):
|
|
if on_complete:
|
|
on_complete(response.unique_id, response.output, response.status)
|
|
final_results[response.unique_id] = {
|
|
"output": response.output,
|
|
"status": response.status
|
|
}
|
|
|
|
return final_results
|
|
|
|
@handle_errors
|
|
def test_commands(self, nodes_filter, commands, expected, variables=None, parallel=10, timeout=10, prompt=None, **kwargs):
|
|
nodes_list = [nodes_filter] if isinstance(nodes_filter, str) else list(nodes_filter)
|
|
req = connpy_pb2.TestRequest(
|
|
nodes=nodes_list,
|
|
commands=commands,
|
|
expected=expected if isinstance(expected, list) else [expected],
|
|
folder=kwargs.get("folder", ""),
|
|
prompt=prompt or "",
|
|
parallel=parallel,
|
|
timeout=timeout,
|
|
name=kwargs.get("name", "")
|
|
)
|
|
if variables is not None:
|
|
req.vars.CopyFrom(to_struct(variables))
|
|
|
|
final_results = {}
|
|
on_complete = kwargs.get("on_node_complete")
|
|
|
|
for response in self.stub.test_commands(req):
|
|
result_dict = from_struct(response.test_result) if response.HasField("test_result") else {}
|
|
if on_complete:
|
|
on_complete(response.unique_id, response.output, response.status, result_dict)
|
|
final_results[response.unique_id] = result_dict
|
|
|
|
return final_results
|
|
|
|
@handle_errors
|
|
def run_cli_script(self, nodes_filter, script_path, parallel=10):
|
|
req = connpy_pb2.ScriptRequest(param1=nodes_filter, param2=script_path, parallel=parallel)
|
|
return from_struct(self.stub.run_cli_script(req).data)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
<h3>Methods</h3>
|
|
<dl>
|
|
<dt id="connpy.grpc_layer.stubs.ExecutionStub.run_cli_script"><code class="name flex">
|
|
<span>def <span class="ident">run_cli_script</span></span>(<span>self, nodes_filter, script_path, parallel=10)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def run_cli_script(self, nodes_filter, script_path, parallel=10):
|
|
req = connpy_pb2.ScriptRequest(param1=nodes_filter, param2=script_path, parallel=parallel)
|
|
return from_struct(self.stub.run_cli_script(req).data)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.ExecutionStub.run_commands"><code class="name flex">
|
|
<span>def <span class="ident">run_commands</span></span>(<span>self,<br>nodes_filter,<br>commands,<br>variables=None,<br>parallel=10,<br>timeout=10,<br>folder=None,<br>prompt=None,<br>**kwargs)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def run_commands(self, nodes_filter, commands, variables=None, parallel=10, timeout=10, folder=None, prompt=None, **kwargs):
|
|
nodes_list = [nodes_filter] if isinstance(nodes_filter, str) else list(nodes_filter)
|
|
req = connpy_pb2.RunRequest(
|
|
nodes=nodes_list,
|
|
commands=commands,
|
|
folder=folder or "",
|
|
prompt=prompt or "",
|
|
parallel=parallel,
|
|
timeout=timeout,
|
|
name=kwargs.get("name", "")
|
|
)
|
|
if variables is not None:
|
|
req.vars.CopyFrom(to_struct(variables))
|
|
|
|
final_results = {}
|
|
on_complete = kwargs.get("on_node_complete")
|
|
|
|
for response in self.stub.run_commands(req):
|
|
if on_complete:
|
|
on_complete(response.unique_id, response.output, response.status)
|
|
final_results[response.unique_id] = {
|
|
"output": response.output,
|
|
"status": response.status
|
|
}
|
|
|
|
return final_results</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.ExecutionStub.test_commands"><code class="name flex">
|
|
<span>def <span class="ident">test_commands</span></span>(<span>self,<br>nodes_filter,<br>commands,<br>expected,<br>variables=None,<br>parallel=10,<br>timeout=10,<br>prompt=None,<br>**kwargs)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def test_commands(self, nodes_filter, commands, expected, variables=None, parallel=10, timeout=10, prompt=None, **kwargs):
|
|
nodes_list = [nodes_filter] if isinstance(nodes_filter, str) else list(nodes_filter)
|
|
req = connpy_pb2.TestRequest(
|
|
nodes=nodes_list,
|
|
commands=commands,
|
|
expected=expected if isinstance(expected, list) else [expected],
|
|
folder=kwargs.get("folder", ""),
|
|
prompt=prompt or "",
|
|
parallel=parallel,
|
|
timeout=timeout,
|
|
name=kwargs.get("name", "")
|
|
)
|
|
if variables is not None:
|
|
req.vars.CopyFrom(to_struct(variables))
|
|
|
|
final_results = {}
|
|
on_complete = kwargs.get("on_node_complete")
|
|
|
|
for response in self.stub.test_commands(req):
|
|
result_dict = from_struct(response.test_result) if response.HasField("test_result") else {}
|
|
if on_complete:
|
|
on_complete(response.unique_id, response.output, response.status, result_dict)
|
|
final_results[response.unique_id] = result_dict
|
|
|
|
return final_results</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
</dl>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.ImportExportStub"><code class="flex name class">
|
|
<span>class <span class="ident">ImportExportStub</span></span>
|
|
<span>(</span><span>channel, remote_host)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">class ImportExportStub:
|
|
def __init__(self, channel, remote_host):
|
|
self.stub = connpy_pb2_grpc.ImportExportServiceStub(channel)
|
|
self.remote_host = remote_host
|
|
|
|
@handle_errors
|
|
def export_to_file(self, file_path, folders=None):
|
|
req = connpy_pb2.ExportRequest(file_path=file_path, folders=folders or [])
|
|
self.stub.export_to_file(req)
|
|
|
|
@handle_errors
|
|
def import_from_file(self, file_path):
|
|
with open(file_path, "r") as f:
|
|
content = f.read()
|
|
# Marker to tell the server this is content, not a path
|
|
marker_content = f"---YAML---\n{content}"
|
|
self.stub.import_from_file(connpy_pb2.StringRequest(value=marker_content))
|
|
|
|
@handle_errors
|
|
def set_reserved_names(self, names):
|
|
self.stub.set_reserved_names(connpy_pb2.ListRequest(items=names))</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
<h3>Methods</h3>
|
|
<dl>
|
|
<dt id="connpy.grpc_layer.stubs.ImportExportStub.export_to_file"><code class="name flex">
|
|
<span>def <span class="ident">export_to_file</span></span>(<span>self, file_path, folders=None)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def export_to_file(self, file_path, folders=None):
|
|
req = connpy_pb2.ExportRequest(file_path=file_path, folders=folders or [])
|
|
self.stub.export_to_file(req)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.ImportExportStub.import_from_file"><code class="name flex">
|
|
<span>def <span class="ident">import_from_file</span></span>(<span>self, file_path)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def import_from_file(self, file_path):
|
|
with open(file_path, "r") as f:
|
|
content = f.read()
|
|
# Marker to tell the server this is content, not a path
|
|
marker_content = f"---YAML---\n{content}"
|
|
self.stub.import_from_file(connpy_pb2.StringRequest(value=marker_content))</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.ImportExportStub.set_reserved_names"><code class="name flex">
|
|
<span>def <span class="ident">set_reserved_names</span></span>(<span>self, names)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def set_reserved_names(self, names):
|
|
self.stub.set_reserved_names(connpy_pb2.ListRequest(items=names))</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
</dl>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.NodeStub"><code class="flex name class">
|
|
<span>class <span class="ident">NodeStub</span></span>
|
|
<span>(</span><span>channel, remote_host, config=None)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">class NodeStub:
|
|
def __init__(self, channel, remote_host, config=None):
|
|
self.stub = connpy_pb2_grpc.NodeServiceStub(channel)
|
|
self.remote_host = remote_host
|
|
self.config = config
|
|
|
|
def _handle_remote_copilot(self, res, request_queue, response_queue, client_buffer_bytes, pause_generator, resume_generator, old_tty):
|
|
import json, asyncio, termios, sys, tty, queue
|
|
from ..core import copilot_terminal_mode
|
|
from . import connpy_pb2
|
|
|
|
pause_generator()
|
|
|
|
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
|
|
|
|
node_info = json.loads(res.copilot_node_info_json) if res.copilot_node_info_json else {}
|
|
blocks = node_info.get("context_blocks", [])
|
|
|
|
interface = CopilotInterface(
|
|
self.config,
|
|
history=getattr(self, 'copilot_history', None),
|
|
session_state=getattr(self, 'copilot_state', None)
|
|
)
|
|
self.copilot_history = interface.history
|
|
self.copilot_state = interface.session_state
|
|
|
|
async def on_ai_call_remote(active_buffer, question, chunk_callback, merged_node_info):
|
|
# Send request to server
|
|
request_queue.put(connpy_pb2.InteractRequest(
|
|
copilot_question=question,
|
|
copilot_context_buffer=active_buffer,
|
|
copilot_node_info_json=json.dumps(merged_node_info)
|
|
))
|
|
# Wait for chunks from server
|
|
while True:
|
|
try:
|
|
chunk_res = response_queue.get(timeout=0.1)
|
|
if chunk_res is None: return {"error": "Server disconnected"}
|
|
if chunk_res.copilot_stream_chunk:
|
|
chunk_callback(chunk_res.copilot_stream_chunk)
|
|
elif chunk_res.copilot_response_json:
|
|
return json.loads(chunk_res.copilot_response_json)
|
|
except queue.Empty:
|
|
await asyncio.sleep(0.05)
|
|
|
|
# Wrap in async loop
|
|
async def run_remote_copilot():
|
|
while True:
|
|
action, commands, custom_cmd = await interface.run_session(
|
|
raw_bytes=bytes(client_buffer_bytes),
|
|
node_info=node_info,
|
|
on_ai_call=on_ai_call_remote,
|
|
blocks=blocks
|
|
)
|
|
|
|
if action == "continue":
|
|
# Send continue signal to server to loop back for another question
|
|
request_queue.put(connpy_pb2.InteractRequest(copilot_action="continue"))
|
|
continue
|
|
|
|
return action, commands, custom_cmd
|
|
|
|
with copilot_terminal_mode():
|
|
action, commands, custom_cmd = asyncio.run(run_remote_copilot())
|
|
|
|
print("\033[2m Returning to session...\033[0m", flush=True)
|
|
# Prepare final action for server
|
|
action_sent = "cancel"
|
|
if action == "send_all" and commands:
|
|
# In remote mode, send the selected commands as a custom block
|
|
# so the server executes exactly what the user picked (e.g., selection '1')
|
|
action_sent = f"custom:{chr(10).join(commands)}"
|
|
elif action == "custom" and custom_cmd:
|
|
action_sent = f"custom:{chr(10).join(custom_cmd)}"
|
|
request_queue.put(connpy_pb2.InteractRequest(copilot_action=action_sent))
|
|
resume_generator()
|
|
tty.setraw(sys.stdin.fileno())
|
|
|
|
@handle_errors
|
|
def connect_node(self, unique_id, sftp=False, debug=False, logger=None):
|
|
import sys
|
|
import select
|
|
import tty
|
|
import termios
|
|
import queue
|
|
import os
|
|
import threading
|
|
|
|
request_queue = queue.Queue()
|
|
client_buffer_bytes = bytearray()
|
|
pause_stdin = [False]
|
|
wake_r, wake_w = os.pipe()
|
|
|
|
def pause_generator():
|
|
pause_stdin[0] = True
|
|
os.write(wake_w, b'\x00')
|
|
|
|
def resume_generator():
|
|
pause_stdin[0] = False
|
|
|
|
def request_generator():
|
|
cols, rows = 80, 24
|
|
try:
|
|
size = os.get_terminal_size()
|
|
cols, rows = size.columns, size.lines
|
|
except OSError:
|
|
pass
|
|
|
|
yield connpy_pb2.InteractRequest(
|
|
id=unique_id, sftp=sftp, debug=debug, cols=cols, rows=rows
|
|
)
|
|
|
|
while True:
|
|
try:
|
|
while True:
|
|
req = request_queue.get_nowait()
|
|
if req is None:
|
|
return
|
|
yield req
|
|
except queue.Empty:
|
|
pass
|
|
|
|
if pause_stdin[0]:
|
|
import time
|
|
time.sleep(0.05)
|
|
continue
|
|
|
|
r, _, _ = select.select([sys.stdin.fileno(), wake_r], [], [], 0.05)
|
|
if wake_r in r:
|
|
os.read(wake_r, 1)
|
|
continue
|
|
if sys.stdin.fileno() in r and not pause_stdin[0]:
|
|
try:
|
|
data = os.read(sys.stdin.fileno(), 1024)
|
|
if not data:
|
|
break
|
|
yield connpy_pb2.InteractRequest(stdin_data=data)
|
|
except OSError:
|
|
break
|
|
|
|
# Fetch node details for the connection message
|
|
try:
|
|
node_details = self.get_node_details(unique_id)
|
|
host = node_details.get("host", "unknown")
|
|
port = str(node_details.get("port", ""))
|
|
protocol = "sftp" if sftp else node_details.get("protocol", "ssh")
|
|
port_str = f":{port}" if port and protocol not in ["ssm", "kubectl", "docker"] else ""
|
|
conn_msg = f"Connected to {unique_id} at {host}{port_str} via: {protocol}"
|
|
except Exception:
|
|
conn_msg = f"Connected to {unique_id}"
|
|
|
|
old_tty = termios.tcgetattr(sys.stdin)
|
|
try:
|
|
import time
|
|
tty.setraw(sys.stdin.fileno())
|
|
response_iterator = self.stub.interact_node(request_generator())
|
|
|
|
import queue
|
|
response_queue = queue.Queue()
|
|
|
|
def response_consumer():
|
|
try:
|
|
for r in response_iterator:
|
|
response_queue.put(r)
|
|
except Exception:
|
|
pass
|
|
response_queue.put(None)
|
|
|
|
t_consumer = threading.Thread(target=response_consumer, daemon=True)
|
|
t_consumer.start()
|
|
|
|
# First phase: Wait for connection status, print early data
|
|
try:
|
|
while True:
|
|
res = response_queue.get()
|
|
if res is None:
|
|
return
|
|
if res.stdout_data:
|
|
data = res.stdout_data
|
|
if debug:
|
|
data = data.replace(b'\x1b[H\x1b[2J', b'').replace(b'\x1bc', b'').replace(b'\x1b[3J', b'')
|
|
os.write(sys.stdout.fileno(), data)
|
|
|
|
if res.success:
|
|
# Connection established on server, show success message
|
|
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
|
|
printer.success(conn_msg)
|
|
pause_stdin[0] = False
|
|
tty.setraw(sys.stdin.fileno())
|
|
break
|
|
|
|
if res.error_message:
|
|
# Connection failed on server
|
|
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
|
|
printer.error(f"Connection failed: {res.error_message}")
|
|
return
|
|
except queue.Empty:
|
|
return
|
|
|
|
# Second phase: Stream active session
|
|
# Clear screen filter is only applied before success (Phase 1).
|
|
# Once the user has a prompt, Ctrl+L must work normally.
|
|
while True:
|
|
res = response_queue.get()
|
|
if res is None:
|
|
break
|
|
if res.copilot_prompt:
|
|
self._handle_remote_copilot(
|
|
res, request_queue, response_queue,
|
|
client_buffer_bytes,
|
|
pause_generator, resume_generator, old_tty
|
|
)
|
|
continue
|
|
|
|
if res.stdout_data:
|
|
os.write(sys.stdout.fileno(), res.stdout_data)
|
|
client_buffer_bytes.extend(res.stdout_data)
|
|
finally:
|
|
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
|
|
os.close(wake_r)
|
|
os.close(wake_w)
|
|
|
|
@handle_errors
|
|
def connect_dynamic(self, connection_params, debug=False):
|
|
import sys
|
|
import select
|
|
import tty
|
|
import termios
|
|
import queue
|
|
import os
|
|
import json
|
|
|
|
params_json = json.dumps(connection_params)
|
|
request_queue = queue.Queue()
|
|
client_buffer_bytes = bytearray()
|
|
pause_stdin = [False]
|
|
wake_r, wake_w = os.pipe()
|
|
|
|
def pause_generator():
|
|
pause_stdin[0] = True
|
|
os.write(wake_w, b'\x00')
|
|
|
|
def resume_generator():
|
|
pause_stdin[0] = False
|
|
|
|
def request_generator():
|
|
cols, rows = 80, 24
|
|
try:
|
|
size = os.get_terminal_size()
|
|
cols, rows = size.columns, size.lines
|
|
except OSError:
|
|
pass
|
|
|
|
yield connpy_pb2.InteractRequest(
|
|
id="dynamic", debug=debug, cols=cols, rows=rows,
|
|
connection_params_json=params_json
|
|
)
|
|
|
|
while True:
|
|
try:
|
|
while True:
|
|
req = request_queue.get_nowait()
|
|
if req is None:
|
|
return
|
|
yield req
|
|
except queue.Empty:
|
|
pass
|
|
|
|
if pause_stdin[0]:
|
|
import time
|
|
time.sleep(0.05)
|
|
continue
|
|
|
|
r, _, _ = select.select([sys.stdin.fileno(), wake_r], [], [], 0.05)
|
|
if wake_r in r:
|
|
os.read(wake_r, 1)
|
|
continue
|
|
if sys.stdin.fileno() in r and not pause_stdin[0]:
|
|
try:
|
|
data = os.read(sys.stdin.fileno(), 1024)
|
|
if not data:
|
|
break
|
|
yield connpy_pb2.InteractRequest(stdin_data=data)
|
|
except OSError:
|
|
break
|
|
|
|
# Prepare connection message
|
|
try:
|
|
node_name = connection_params.get("name", "dynamic@remote")
|
|
host = connection_params.get("host", "dynamic")
|
|
port = str(connection_params.get("port", ""))
|
|
protocol = connection_params.get("protocol", "ssh")
|
|
port_str = f":{port}" if port and protocol not in ["ssm", "kubectl", "docker"] else ""
|
|
conn_msg = f"Connected to {node_name} at {host}{port_str} via: {protocol}"
|
|
except Exception:
|
|
node_name = connection_params.get("name", "dynamic@remote") if isinstance(connection_params, dict) else "dynamic@remote"
|
|
conn_msg = f"Connected to {node_name}"
|
|
|
|
old_tty = termios.tcgetattr(sys.stdin)
|
|
try:
|
|
import time
|
|
tty.setraw(sys.stdin.fileno())
|
|
response_iterator = self.stub.interact_node(request_generator())
|
|
|
|
import queue
|
|
response_queue = queue.Queue()
|
|
|
|
def response_consumer():
|
|
try:
|
|
for r in response_iterator:
|
|
response_queue.put(r)
|
|
except Exception:
|
|
pass
|
|
response_queue.put(None)
|
|
|
|
t_consumer = threading.Thread(target=response_consumer, daemon=True)
|
|
t_consumer.start()
|
|
|
|
# First phase: Wait for connection status, print early data
|
|
try:
|
|
while True:
|
|
res = response_queue.get()
|
|
if res is None:
|
|
return
|
|
if res.stdout_data:
|
|
data = res.stdout_data
|
|
if debug:
|
|
data = data.replace(b'\x1b[H\x1b[2J', b'').replace(b'\x1bc', b'').replace(b'\x1b[3J', b'')
|
|
os.write(sys.stdout.fileno(), data)
|
|
|
|
if res.success:
|
|
# Connection established on server, show success message
|
|
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
|
|
printer.success(conn_msg)
|
|
pause_stdin[0] = False
|
|
tty.setraw(sys.stdin.fileno())
|
|
break
|
|
|
|
if res.error_message:
|
|
# Connection failed on server
|
|
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
|
|
printer.error(f"Connection failed: {res.error_message}")
|
|
return
|
|
except queue.Empty:
|
|
return
|
|
|
|
# Second phase: Stream active session
|
|
while True:
|
|
res = response_queue.get()
|
|
if res is None:
|
|
break
|
|
if res.copilot_prompt:
|
|
self._handle_remote_copilot(
|
|
res, request_queue, response_queue,
|
|
client_buffer_bytes,
|
|
pause_generator, resume_generator, old_tty
|
|
)
|
|
continue
|
|
|
|
if res.stdout_data:
|
|
os.write(sys.stdout.fileno(), res.stdout_data)
|
|
client_buffer_bytes.extend(res.stdout_data)
|
|
finally:
|
|
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
|
|
os.close(wake_r)
|
|
os.close(wake_w)
|
|
|
|
@MethodHook
|
|
@handle_errors
|
|
def list_nodes(self, filter_str=None, format_str=None):
|
|
req = connpy_pb2.FilterRequest(filter_str=filter_str or "", format_str=format_str or "")
|
|
return from_value(self.stub.list_nodes(req).data) or []
|
|
|
|
@MethodHook
|
|
@handle_errors
|
|
def list_folders(self, filter_str=None):
|
|
req = connpy_pb2.FilterRequest(filter_str=filter_str or "")
|
|
return from_value(self.stub.list_folders(req).data) or []
|
|
|
|
@handle_errors
|
|
def get_node_details(self, unique_id):
|
|
return from_struct(self.stub.get_node_details(connpy_pb2.IdRequest(id=unique_id)).data)
|
|
|
|
@handle_errors
|
|
def explode_unique(self, unique_id):
|
|
return from_value(self.stub.explode_unique(connpy_pb2.IdRequest(id=unique_id)).data)
|
|
|
|
@handle_errors
|
|
def validate_parent_folder(self, unique_id):
|
|
self.stub.validate_parent_folder(connpy_pb2.IdRequest(id=unique_id))
|
|
|
|
@handle_errors
|
|
def generate_cache(self, nodes=None, folders=None, profiles=None):
|
|
# 1. Update remote cache on server
|
|
self.stub.generate_cache(Empty())
|
|
|
|
# 2. Update local fzf/text cache files
|
|
# If no data provided, we fetch it all from remote to sync local files
|
|
if nodes is None and folders is None and profiles is None:
|
|
nodes = self.list_nodes()
|
|
folders = self.list_folders()
|
|
# We don't have direct access to ProfileStub here, but usually
|
|
# node cache is what matters for fzf. We'll fetch profiles if we can.
|
|
# For now, let's sync what we have.
|
|
|
|
if nodes is not None or folders is not None or profiles is not None:
|
|
self.config._generate_nodes_cache(nodes=nodes, folders=folders, profiles=profiles)
|
|
|
|
def _trigger_local_cache_sync(self):
|
|
"""Helper to fetch remote data and update local fzf cache files after a change."""
|
|
try:
|
|
nodes = self.list_nodes()
|
|
folders = self.list_folders()
|
|
self.generate_cache(nodes=nodes, folders=folders)
|
|
except Exception:
|
|
# Failure to sync cache shouldn't break the main operation's success feedback
|
|
pass
|
|
|
|
@handle_errors
|
|
def add_node(self, unique_id, data, is_folder=False):
|
|
req = connpy_pb2.NodeRequest(id=unique_id, data=to_struct(data), is_folder=is_folder)
|
|
self.stub.add_node(req)
|
|
self._trigger_local_cache_sync()
|
|
|
|
@handle_errors
|
|
def update_node(self, unique_id, data, save=True):
|
|
req = connpy_pb2.NodeRequest(id=unique_id, data=to_struct(data), is_folder=False)
|
|
self.stub.update_node(req)
|
|
if save:
|
|
self._trigger_local_cache_sync()
|
|
|
|
@handle_errors
|
|
def delete_node(self, unique_id, is_folder=False, save=True):
|
|
req = connpy_pb2.DeleteRequest(id=unique_id, is_folder=is_folder)
|
|
self.stub.delete_node(req)
|
|
if save:
|
|
self._trigger_local_cache_sync()
|
|
|
|
@handle_errors
|
|
def move_node(self, src_id, dst_id, copy=False):
|
|
req = connpy_pb2.MoveRequest(src_id=src_id, dst_id=dst_id, copy=copy)
|
|
self.stub.move_node(req)
|
|
self._trigger_local_cache_sync()
|
|
|
|
@handle_errors
|
|
def bulk_add(self, ids, hosts, common_data):
|
|
req = connpy_pb2.BulkRequest(ids=ids, hosts=hosts, common_data=to_struct(common_data))
|
|
self.stub.bulk_add(req)
|
|
self._trigger_local_cache_sync()
|
|
|
|
@handle_errors
|
|
def set_reserved_names(self, names):
|
|
self.stub.set_reserved_names(connpy_pb2.ListRequest(items=names))
|
|
self._trigger_local_cache_sync()
|
|
|
|
@handle_errors
|
|
def full_replace(self, connections, profiles):
|
|
req = connpy_pb2.FullReplaceRequest(
|
|
connections=to_struct(connections),
|
|
profiles=to_struct(profiles)
|
|
)
|
|
self.stub.full_replace(req)
|
|
self._trigger_local_cache_sync()
|
|
|
|
@handle_errors
|
|
def get_inventory(self):
|
|
resp = self.stub.get_inventory(Empty())
|
|
return {
|
|
"connections": from_struct(resp.connections),
|
|
"profiles": from_struct(resp.profiles)
|
|
}</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
<h3>Methods</h3>
|
|
<dl>
|
|
<dt id="connpy.grpc_layer.stubs.NodeStub.add_node"><code class="name flex">
|
|
<span>def <span class="ident">add_node</span></span>(<span>self, unique_id, data, is_folder=False)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def add_node(self, unique_id, data, is_folder=False):
|
|
req = connpy_pb2.NodeRequest(id=unique_id, data=to_struct(data), is_folder=is_folder)
|
|
self.stub.add_node(req)
|
|
self._trigger_local_cache_sync()</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.NodeStub.bulk_add"><code class="name flex">
|
|
<span>def <span class="ident">bulk_add</span></span>(<span>self, ids, hosts, common_data)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def bulk_add(self, ids, hosts, common_data):
|
|
req = connpy_pb2.BulkRequest(ids=ids, hosts=hosts, common_data=to_struct(common_data))
|
|
self.stub.bulk_add(req)
|
|
self._trigger_local_cache_sync()</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.NodeStub.connect_dynamic"><code class="name flex">
|
|
<span>def <span class="ident">connect_dynamic</span></span>(<span>self, connection_params, debug=False)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def connect_dynamic(self, connection_params, debug=False):
|
|
import sys
|
|
import select
|
|
import tty
|
|
import termios
|
|
import queue
|
|
import os
|
|
import json
|
|
|
|
params_json = json.dumps(connection_params)
|
|
request_queue = queue.Queue()
|
|
client_buffer_bytes = bytearray()
|
|
pause_stdin = [False]
|
|
wake_r, wake_w = os.pipe()
|
|
|
|
def pause_generator():
|
|
pause_stdin[0] = True
|
|
os.write(wake_w, b'\x00')
|
|
|
|
def resume_generator():
|
|
pause_stdin[0] = False
|
|
|
|
def request_generator():
|
|
cols, rows = 80, 24
|
|
try:
|
|
size = os.get_terminal_size()
|
|
cols, rows = size.columns, size.lines
|
|
except OSError:
|
|
pass
|
|
|
|
yield connpy_pb2.InteractRequest(
|
|
id="dynamic", debug=debug, cols=cols, rows=rows,
|
|
connection_params_json=params_json
|
|
)
|
|
|
|
while True:
|
|
try:
|
|
while True:
|
|
req = request_queue.get_nowait()
|
|
if req is None:
|
|
return
|
|
yield req
|
|
except queue.Empty:
|
|
pass
|
|
|
|
if pause_stdin[0]:
|
|
import time
|
|
time.sleep(0.05)
|
|
continue
|
|
|
|
r, _, _ = select.select([sys.stdin.fileno(), wake_r], [], [], 0.05)
|
|
if wake_r in r:
|
|
os.read(wake_r, 1)
|
|
continue
|
|
if sys.stdin.fileno() in r and not pause_stdin[0]:
|
|
try:
|
|
data = os.read(sys.stdin.fileno(), 1024)
|
|
if not data:
|
|
break
|
|
yield connpy_pb2.InteractRequest(stdin_data=data)
|
|
except OSError:
|
|
break
|
|
|
|
# Prepare connection message
|
|
try:
|
|
node_name = connection_params.get("name", "dynamic@remote")
|
|
host = connection_params.get("host", "dynamic")
|
|
port = str(connection_params.get("port", ""))
|
|
protocol = connection_params.get("protocol", "ssh")
|
|
port_str = f":{port}" if port and protocol not in ["ssm", "kubectl", "docker"] else ""
|
|
conn_msg = f"Connected to {node_name} at {host}{port_str} via: {protocol}"
|
|
except Exception:
|
|
node_name = connection_params.get("name", "dynamic@remote") if isinstance(connection_params, dict) else "dynamic@remote"
|
|
conn_msg = f"Connected to {node_name}"
|
|
|
|
old_tty = termios.tcgetattr(sys.stdin)
|
|
try:
|
|
import time
|
|
tty.setraw(sys.stdin.fileno())
|
|
response_iterator = self.stub.interact_node(request_generator())
|
|
|
|
import queue
|
|
response_queue = queue.Queue()
|
|
|
|
def response_consumer():
|
|
try:
|
|
for r in response_iterator:
|
|
response_queue.put(r)
|
|
except Exception:
|
|
pass
|
|
response_queue.put(None)
|
|
|
|
t_consumer = threading.Thread(target=response_consumer, daemon=True)
|
|
t_consumer.start()
|
|
|
|
# First phase: Wait for connection status, print early data
|
|
try:
|
|
while True:
|
|
res = response_queue.get()
|
|
if res is None:
|
|
return
|
|
if res.stdout_data:
|
|
data = res.stdout_data
|
|
if debug:
|
|
data = data.replace(b'\x1b[H\x1b[2J', b'').replace(b'\x1bc', b'').replace(b'\x1b[3J', b'')
|
|
os.write(sys.stdout.fileno(), data)
|
|
|
|
if res.success:
|
|
# Connection established on server, show success message
|
|
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
|
|
printer.success(conn_msg)
|
|
pause_stdin[0] = False
|
|
tty.setraw(sys.stdin.fileno())
|
|
break
|
|
|
|
if res.error_message:
|
|
# Connection failed on server
|
|
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
|
|
printer.error(f"Connection failed: {res.error_message}")
|
|
return
|
|
except queue.Empty:
|
|
return
|
|
|
|
# Second phase: Stream active session
|
|
while True:
|
|
res = response_queue.get()
|
|
if res is None:
|
|
break
|
|
if res.copilot_prompt:
|
|
self._handle_remote_copilot(
|
|
res, request_queue, response_queue,
|
|
client_buffer_bytes,
|
|
pause_generator, resume_generator, old_tty
|
|
)
|
|
continue
|
|
|
|
if res.stdout_data:
|
|
os.write(sys.stdout.fileno(), res.stdout_data)
|
|
client_buffer_bytes.extend(res.stdout_data)
|
|
finally:
|
|
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
|
|
os.close(wake_r)
|
|
os.close(wake_w)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.NodeStub.connect_node"><code class="name flex">
|
|
<span>def <span class="ident">connect_node</span></span>(<span>self, unique_id, sftp=False, debug=False, logger=None)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def connect_node(self, unique_id, sftp=False, debug=False, logger=None):
|
|
import sys
|
|
import select
|
|
import tty
|
|
import termios
|
|
import queue
|
|
import os
|
|
import threading
|
|
|
|
request_queue = queue.Queue()
|
|
client_buffer_bytes = bytearray()
|
|
pause_stdin = [False]
|
|
wake_r, wake_w = os.pipe()
|
|
|
|
def pause_generator():
|
|
pause_stdin[0] = True
|
|
os.write(wake_w, b'\x00')
|
|
|
|
def resume_generator():
|
|
pause_stdin[0] = False
|
|
|
|
def request_generator():
|
|
cols, rows = 80, 24
|
|
try:
|
|
size = os.get_terminal_size()
|
|
cols, rows = size.columns, size.lines
|
|
except OSError:
|
|
pass
|
|
|
|
yield connpy_pb2.InteractRequest(
|
|
id=unique_id, sftp=sftp, debug=debug, cols=cols, rows=rows
|
|
)
|
|
|
|
while True:
|
|
try:
|
|
while True:
|
|
req = request_queue.get_nowait()
|
|
if req is None:
|
|
return
|
|
yield req
|
|
except queue.Empty:
|
|
pass
|
|
|
|
if pause_stdin[0]:
|
|
import time
|
|
time.sleep(0.05)
|
|
continue
|
|
|
|
r, _, _ = select.select([sys.stdin.fileno(), wake_r], [], [], 0.05)
|
|
if wake_r in r:
|
|
os.read(wake_r, 1)
|
|
continue
|
|
if sys.stdin.fileno() in r and not pause_stdin[0]:
|
|
try:
|
|
data = os.read(sys.stdin.fileno(), 1024)
|
|
if not data:
|
|
break
|
|
yield connpy_pb2.InteractRequest(stdin_data=data)
|
|
except OSError:
|
|
break
|
|
|
|
# Fetch node details for the connection message
|
|
try:
|
|
node_details = self.get_node_details(unique_id)
|
|
host = node_details.get("host", "unknown")
|
|
port = str(node_details.get("port", ""))
|
|
protocol = "sftp" if sftp else node_details.get("protocol", "ssh")
|
|
port_str = f":{port}" if port and protocol not in ["ssm", "kubectl", "docker"] else ""
|
|
conn_msg = f"Connected to {unique_id} at {host}{port_str} via: {protocol}"
|
|
except Exception:
|
|
conn_msg = f"Connected to {unique_id}"
|
|
|
|
old_tty = termios.tcgetattr(sys.stdin)
|
|
try:
|
|
import time
|
|
tty.setraw(sys.stdin.fileno())
|
|
response_iterator = self.stub.interact_node(request_generator())
|
|
|
|
import queue
|
|
response_queue = queue.Queue()
|
|
|
|
def response_consumer():
|
|
try:
|
|
for r in response_iterator:
|
|
response_queue.put(r)
|
|
except Exception:
|
|
pass
|
|
response_queue.put(None)
|
|
|
|
t_consumer = threading.Thread(target=response_consumer, daemon=True)
|
|
t_consumer.start()
|
|
|
|
# First phase: Wait for connection status, print early data
|
|
try:
|
|
while True:
|
|
res = response_queue.get()
|
|
if res is None:
|
|
return
|
|
if res.stdout_data:
|
|
data = res.stdout_data
|
|
if debug:
|
|
data = data.replace(b'\x1b[H\x1b[2J', b'').replace(b'\x1bc', b'').replace(b'\x1b[3J', b'')
|
|
os.write(sys.stdout.fileno(), data)
|
|
|
|
if res.success:
|
|
# Connection established on server, show success message
|
|
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
|
|
printer.success(conn_msg)
|
|
pause_stdin[0] = False
|
|
tty.setraw(sys.stdin.fileno())
|
|
break
|
|
|
|
if res.error_message:
|
|
# Connection failed on server
|
|
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
|
|
printer.error(f"Connection failed: {res.error_message}")
|
|
return
|
|
except queue.Empty:
|
|
return
|
|
|
|
# Second phase: Stream active session
|
|
# Clear screen filter is only applied before success (Phase 1).
|
|
# Once the user has a prompt, Ctrl+L must work normally.
|
|
while True:
|
|
res = response_queue.get()
|
|
if res is None:
|
|
break
|
|
if res.copilot_prompt:
|
|
self._handle_remote_copilot(
|
|
res, request_queue, response_queue,
|
|
client_buffer_bytes,
|
|
pause_generator, resume_generator, old_tty
|
|
)
|
|
continue
|
|
|
|
if res.stdout_data:
|
|
os.write(sys.stdout.fileno(), res.stdout_data)
|
|
client_buffer_bytes.extend(res.stdout_data)
|
|
finally:
|
|
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
|
|
os.close(wake_r)
|
|
os.close(wake_w)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.NodeStub.delete_node"><code class="name flex">
|
|
<span>def <span class="ident">delete_node</span></span>(<span>self, unique_id, is_folder=False, save=True)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def delete_node(self, unique_id, is_folder=False, save=True):
|
|
req = connpy_pb2.DeleteRequest(id=unique_id, is_folder=is_folder)
|
|
self.stub.delete_node(req)
|
|
if save:
|
|
self._trigger_local_cache_sync()</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.NodeStub.explode_unique"><code class="name flex">
|
|
<span>def <span class="ident">explode_unique</span></span>(<span>self, unique_id)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def explode_unique(self, unique_id):
|
|
return from_value(self.stub.explode_unique(connpy_pb2.IdRequest(id=unique_id)).data)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.NodeStub.full_replace"><code class="name flex">
|
|
<span>def <span class="ident">full_replace</span></span>(<span>self, connections, profiles)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def full_replace(self, connections, profiles):
|
|
req = connpy_pb2.FullReplaceRequest(
|
|
connections=to_struct(connections),
|
|
profiles=to_struct(profiles)
|
|
)
|
|
self.stub.full_replace(req)
|
|
self._trigger_local_cache_sync()</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.NodeStub.generate_cache"><code class="name flex">
|
|
<span>def <span class="ident">generate_cache</span></span>(<span>self, nodes=None, folders=None, profiles=None)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def generate_cache(self, nodes=None, folders=None, profiles=None):
|
|
# 1. Update remote cache on server
|
|
self.stub.generate_cache(Empty())
|
|
|
|
# 2. Update local fzf/text cache files
|
|
# If no data provided, we fetch it all from remote to sync local files
|
|
if nodes is None and folders is None and profiles is None:
|
|
nodes = self.list_nodes()
|
|
folders = self.list_folders()
|
|
# We don't have direct access to ProfileStub here, but usually
|
|
# node cache is what matters for fzf. We'll fetch profiles if we can.
|
|
# For now, let's sync what we have.
|
|
|
|
if nodes is not None or folders is not None or profiles is not None:
|
|
self.config._generate_nodes_cache(nodes=nodes, folders=folders, profiles=profiles)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.NodeStub.get_inventory"><code class="name flex">
|
|
<span>def <span class="ident">get_inventory</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def get_inventory(self):
|
|
resp = self.stub.get_inventory(Empty())
|
|
return {
|
|
"connections": from_struct(resp.connections),
|
|
"profiles": from_struct(resp.profiles)
|
|
}</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.NodeStub.get_node_details"><code class="name flex">
|
|
<span>def <span class="ident">get_node_details</span></span>(<span>self, unique_id)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def get_node_details(self, unique_id):
|
|
return from_struct(self.stub.get_node_details(connpy_pb2.IdRequest(id=unique_id)).data)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.NodeStub.list_folders"><code class="name flex">
|
|
<span>def <span class="ident">list_folders</span></span>(<span>self, filter_str=None)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@MethodHook
|
|
@handle_errors
|
|
def list_folders(self, filter_str=None):
|
|
req = connpy_pb2.FilterRequest(filter_str=filter_str or "")
|
|
return from_value(self.stub.list_folders(req).data) or []</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.NodeStub.list_nodes"><code class="name flex">
|
|
<span>def <span class="ident">list_nodes</span></span>(<span>self, filter_str=None, format_str=None)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@MethodHook
|
|
@handle_errors
|
|
def list_nodes(self, filter_str=None, format_str=None):
|
|
req = connpy_pb2.FilterRequest(filter_str=filter_str or "", format_str=format_str or "")
|
|
return from_value(self.stub.list_nodes(req).data) or []</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.NodeStub.move_node"><code class="name flex">
|
|
<span>def <span class="ident">move_node</span></span>(<span>self, src_id, dst_id, copy=False)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def move_node(self, src_id, dst_id, copy=False):
|
|
req = connpy_pb2.MoveRequest(src_id=src_id, dst_id=dst_id, copy=copy)
|
|
self.stub.move_node(req)
|
|
self._trigger_local_cache_sync()</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.NodeStub.set_reserved_names"><code class="name flex">
|
|
<span>def <span class="ident">set_reserved_names</span></span>(<span>self, names)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def set_reserved_names(self, names):
|
|
self.stub.set_reserved_names(connpy_pb2.ListRequest(items=names))
|
|
self._trigger_local_cache_sync()</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.NodeStub.update_node"><code class="name flex">
|
|
<span>def <span class="ident">update_node</span></span>(<span>self, unique_id, data, save=True)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def update_node(self, unique_id, data, save=True):
|
|
req = connpy_pb2.NodeRequest(id=unique_id, data=to_struct(data), is_folder=False)
|
|
self.stub.update_node(req)
|
|
if save:
|
|
self._trigger_local_cache_sync()</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.NodeStub.validate_parent_folder"><code class="name flex">
|
|
<span>def <span class="ident">validate_parent_folder</span></span>(<span>self, unique_id)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def validate_parent_folder(self, unique_id):
|
|
self.stub.validate_parent_folder(connpy_pb2.IdRequest(id=unique_id))</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
</dl>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.PluginStub"><code class="flex name class">
|
|
<span>class <span class="ident">PluginStub</span></span>
|
|
<span>(</span><span>channel, remote_host)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">class PluginStub:
|
|
def __init__(self, channel, remote_host):
|
|
self.stub = connpy_pb2_grpc.PluginServiceStub(channel)
|
|
self.remote_stub = remote_plugin_pb2_grpc.RemotePluginServiceStub(channel)
|
|
self.remote_host = remote_host
|
|
|
|
@handle_errors
|
|
def list_plugins(self):
|
|
return from_value(self.stub.list_plugins(Empty()).data)
|
|
|
|
@handle_errors
|
|
def add_plugin(self, name, source_file, update=False):
|
|
# Read the local file content to send it to the server
|
|
with open(source_file, "r") as f:
|
|
content = f.read()
|
|
|
|
# Use source_file as a marker for "content-inside"
|
|
marker_content = f"---CONTENT---\n{content}"
|
|
req = connpy_pb2.PluginRequest(name=name, source_file=marker_content, update=update)
|
|
self.stub.add_plugin(req)
|
|
|
|
@handle_errors
|
|
def delete_plugin(self, name):
|
|
self.stub.delete_plugin(connpy_pb2.IdRequest(id=name))
|
|
|
|
@handle_errors
|
|
def enable_plugin(self, name):
|
|
self.stub.enable_plugin(connpy_pb2.IdRequest(id=name))
|
|
|
|
@handle_errors
|
|
def disable_plugin(self, name):
|
|
self.stub.disable_plugin(connpy_pb2.IdRequest(id=name))
|
|
|
|
@handle_errors
|
|
def get_plugin_source(self, name):
|
|
resp = self.remote_stub.get_plugin_source(remote_plugin_pb2.IdRequest(id=name))
|
|
return resp.value
|
|
|
|
@handle_errors
|
|
def invoke_plugin(self, name, args_namespace):
|
|
import json
|
|
args_dict = {k: v for k, v in vars(args_namespace).items()
|
|
if isinstance(v, (str, int, float, bool, list, type(None)))}
|
|
if hasattr(args_namespace, "func") and hasattr(args_namespace.func, "__name__"):
|
|
args_dict["__func_name__"] = args_namespace.func.__name__
|
|
|
|
req = remote_plugin_pb2.PluginInvokeRequest(name=name, args_json=json.dumps(args_dict))
|
|
for chunk in self.remote_stub.invoke_plugin(req):
|
|
yield chunk.text</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
<h3>Methods</h3>
|
|
<dl>
|
|
<dt id="connpy.grpc_layer.stubs.PluginStub.add_plugin"><code class="name flex">
|
|
<span>def <span class="ident">add_plugin</span></span>(<span>self, name, source_file, update=False)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def add_plugin(self, name, source_file, update=False):
|
|
# Read the local file content to send it to the server
|
|
with open(source_file, "r") as f:
|
|
content = f.read()
|
|
|
|
# Use source_file as a marker for "content-inside"
|
|
marker_content = f"---CONTENT---\n{content}"
|
|
req = connpy_pb2.PluginRequest(name=name, source_file=marker_content, update=update)
|
|
self.stub.add_plugin(req)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.PluginStub.delete_plugin"><code class="name flex">
|
|
<span>def <span class="ident">delete_plugin</span></span>(<span>self, name)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def delete_plugin(self, name):
|
|
self.stub.delete_plugin(connpy_pb2.IdRequest(id=name))</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.PluginStub.disable_plugin"><code class="name flex">
|
|
<span>def <span class="ident">disable_plugin</span></span>(<span>self, name)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def disable_plugin(self, name):
|
|
self.stub.disable_plugin(connpy_pb2.IdRequest(id=name))</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.PluginStub.enable_plugin"><code class="name flex">
|
|
<span>def <span class="ident">enable_plugin</span></span>(<span>self, name)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def enable_plugin(self, name):
|
|
self.stub.enable_plugin(connpy_pb2.IdRequest(id=name))</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.PluginStub.get_plugin_source"><code class="name flex">
|
|
<span>def <span class="ident">get_plugin_source</span></span>(<span>self, name)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def get_plugin_source(self, name):
|
|
resp = self.remote_stub.get_plugin_source(remote_plugin_pb2.IdRequest(id=name))
|
|
return resp.value</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.PluginStub.invoke_plugin"><code class="name flex">
|
|
<span>def <span class="ident">invoke_plugin</span></span>(<span>self, name, args_namespace)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def invoke_plugin(self, name, args_namespace):
|
|
import json
|
|
args_dict = {k: v for k, v in vars(args_namespace).items()
|
|
if isinstance(v, (str, int, float, bool, list, type(None)))}
|
|
if hasattr(args_namespace, "func") and hasattr(args_namespace.func, "__name__"):
|
|
args_dict["__func_name__"] = args_namespace.func.__name__
|
|
|
|
req = remote_plugin_pb2.PluginInvokeRequest(name=name, args_json=json.dumps(args_dict))
|
|
for chunk in self.remote_stub.invoke_plugin(req):
|
|
yield chunk.text</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.PluginStub.list_plugins"><code class="name flex">
|
|
<span>def <span class="ident">list_plugins</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def list_plugins(self):
|
|
return from_value(self.stub.list_plugins(Empty()).data)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
</dl>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.ProfileStub"><code class="flex name class">
|
|
<span>class <span class="ident">ProfileStub</span></span>
|
|
<span>(</span><span>channel, remote_host, node_stub=None)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">class ProfileStub:
|
|
def __init__(self, channel, remote_host, node_stub=None):
|
|
self.stub = connpy_pb2_grpc.ProfileServiceStub(channel)
|
|
self.remote_host = remote_host
|
|
self.node_stub = node_stub
|
|
|
|
@handle_errors
|
|
def list_profiles(self, filter_str=None):
|
|
req = connpy_pb2.FilterRequest(filter_str=filter_str or "")
|
|
return from_value(self.stub.list_profiles(req).data) or []
|
|
|
|
@handle_errors
|
|
def get_profile(self, name, resolve=True):
|
|
req = connpy_pb2.ProfileRequest(name=name, resolve=resolve)
|
|
return from_struct(self.stub.get_profile(req).data)
|
|
|
|
@handle_errors
|
|
def add_profile(self, name, data):
|
|
req = connpy_pb2.NodeRequest(id=name, data=to_struct(data))
|
|
self.stub.add_profile(req)
|
|
if self.node_stub:
|
|
self.node_stub._trigger_local_cache_sync()
|
|
|
|
@handle_errors
|
|
def resolve_node_data(self, node_data):
|
|
req = connpy_pb2.StructRequest(data=to_struct(node_data))
|
|
return from_struct(self.stub.resolve_node_data(req).data)
|
|
|
|
@handle_errors
|
|
def delete_profile(self, name):
|
|
req = connpy_pb2.IdRequest(id=name)
|
|
self.stub.delete_profile(req)
|
|
if self.node_stub:
|
|
self.node_stub._trigger_local_cache_sync()
|
|
|
|
@handle_errors
|
|
def update_profile(self, name, data):
|
|
req = connpy_pb2.NodeRequest(id=name, data=to_struct(data))
|
|
self.stub.update_profile(req)
|
|
if self.node_stub:
|
|
self.node_stub._trigger_local_cache_sync()</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
<h3>Methods</h3>
|
|
<dl>
|
|
<dt id="connpy.grpc_layer.stubs.ProfileStub.add_profile"><code class="name flex">
|
|
<span>def <span class="ident">add_profile</span></span>(<span>self, name, data)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def add_profile(self, name, data):
|
|
req = connpy_pb2.NodeRequest(id=name, data=to_struct(data))
|
|
self.stub.add_profile(req)
|
|
if self.node_stub:
|
|
self.node_stub._trigger_local_cache_sync()</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.ProfileStub.delete_profile"><code class="name flex">
|
|
<span>def <span class="ident">delete_profile</span></span>(<span>self, name)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def delete_profile(self, name):
|
|
req = connpy_pb2.IdRequest(id=name)
|
|
self.stub.delete_profile(req)
|
|
if self.node_stub:
|
|
self.node_stub._trigger_local_cache_sync()</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.ProfileStub.get_profile"><code class="name flex">
|
|
<span>def <span class="ident">get_profile</span></span>(<span>self, name, resolve=True)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def get_profile(self, name, resolve=True):
|
|
req = connpy_pb2.ProfileRequest(name=name, resolve=resolve)
|
|
return from_struct(self.stub.get_profile(req).data)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.ProfileStub.list_profiles"><code class="name flex">
|
|
<span>def <span class="ident">list_profiles</span></span>(<span>self, filter_str=None)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def list_profiles(self, filter_str=None):
|
|
req = connpy_pb2.FilterRequest(filter_str=filter_str or "")
|
|
return from_value(self.stub.list_profiles(req).data) or []</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.ProfileStub.resolve_node_data"><code class="name flex">
|
|
<span>def <span class="ident">resolve_node_data</span></span>(<span>self, node_data)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def resolve_node_data(self, node_data):
|
|
req = connpy_pb2.StructRequest(data=to_struct(node_data))
|
|
return from_struct(self.stub.resolve_node_data(req).data)</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.ProfileStub.update_profile"><code class="name flex">
|
|
<span>def <span class="ident">update_profile</span></span>(<span>self, name, data)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def update_profile(self, name, data):
|
|
req = connpy_pb2.NodeRequest(id=name, data=to_struct(data))
|
|
self.stub.update_profile(req)
|
|
if self.node_stub:
|
|
self.node_stub._trigger_local_cache_sync()</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
</dl>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.SystemStub"><code class="flex name class">
|
|
<span>class <span class="ident">SystemStub</span></span>
|
|
<span>(</span><span>channel, remote_host)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">class SystemStub:
|
|
def __init__(self, channel, remote_host):
|
|
self.stub = connpy_pb2_grpc.SystemServiceStub(channel)
|
|
self.remote_host = remote_host
|
|
|
|
@handle_errors
|
|
def start_api(self, port=None):
|
|
self.stub.start_api(connpy_pb2.IntRequest(value=port or 8048))
|
|
|
|
@handle_errors
|
|
def debug_api(self, port=None):
|
|
self.stub.debug_api(connpy_pb2.IntRequest(value=port or 8048))
|
|
|
|
@handle_errors
|
|
def stop_api(self):
|
|
self.stub.stop_api(Empty())
|
|
|
|
@handle_errors
|
|
def restart_api(self, port=None):
|
|
self.stub.restart_api(connpy_pb2.IntRequest(value=port or 8048))
|
|
|
|
@handle_errors
|
|
def get_api_status(self):
|
|
return self.stub.get_api_status(Empty()).value</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
<h3>Methods</h3>
|
|
<dl>
|
|
<dt id="connpy.grpc_layer.stubs.SystemStub.debug_api"><code class="name flex">
|
|
<span>def <span class="ident">debug_api</span></span>(<span>self, port=None)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def debug_api(self, port=None):
|
|
self.stub.debug_api(connpy_pb2.IntRequest(value=port or 8048))</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.SystemStub.get_api_status"><code class="name flex">
|
|
<span>def <span class="ident">get_api_status</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def get_api_status(self):
|
|
return self.stub.get_api_status(Empty()).value</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.SystemStub.restart_api"><code class="name flex">
|
|
<span>def <span class="ident">restart_api</span></span>(<span>self, port=None)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def restart_api(self, port=None):
|
|
self.stub.restart_api(connpy_pb2.IntRequest(value=port or 8048))</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.SystemStub.start_api"><code class="name flex">
|
|
<span>def <span class="ident">start_api</span></span>(<span>self, port=None)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def start_api(self, port=None):
|
|
self.stub.start_api(connpy_pb2.IntRequest(value=port or 8048))</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
<dt id="connpy.grpc_layer.stubs.SystemStub.stop_api"><code class="name flex">
|
|
<span>def <span class="ident">stop_api</span></span>(<span>self)</span>
|
|
</code></dt>
|
|
<dd>
|
|
<details class="source">
|
|
<summary>
|
|
<span>Expand source code</span>
|
|
</summary>
|
|
<pre><code class="python">@handle_errors
|
|
def stop_api(self):
|
|
self.stub.stop_api(Empty())</code></pre>
|
|
</details>
|
|
<div class="desc"></div>
|
|
</dd>
|
|
</dl>
|
|
</dd>
|
|
</dl>
|
|
</section>
|
|
</article>
|
|
<nav id="sidebar">
|
|
<div class="toc">
|
|
<ul></ul>
|
|
</div>
|
|
<ul id="index">
|
|
<li><h3>Super-module</h3>
|
|
<ul>
|
|
<li><code><a title="connpy.grpc_layer" href="index.html">connpy.grpc_layer</a></code></li>
|
|
</ul>
|
|
</li>
|
|
<li><h3><a href="#header-functions">Functions</a></h3>
|
|
<ul class="">
|
|
<li><code><a title="connpy.grpc_layer.stubs.handle_errors" href="#connpy.grpc_layer.stubs.handle_errors">handle_errors</a></code></li>
|
|
</ul>
|
|
</li>
|
|
<li><h3><a href="#header-classes">Classes</a></h3>
|
|
<ul>
|
|
<li>
|
|
<h4><code><a title="connpy.grpc_layer.stubs.AIStub" href="#connpy.grpc_layer.stubs.AIStub">AIStub</a></code></h4>
|
|
<ul class="">
|
|
<li><code><a title="connpy.grpc_layer.stubs.AIStub.analyze_execution_results" href="#connpy.grpc_layer.stubs.AIStub.analyze_execution_results">analyze_execution_results</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.AIStub.ask" href="#connpy.grpc_layer.stubs.AIStub.ask">ask</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.AIStub.build_playbook_chat" href="#connpy.grpc_layer.stubs.AIStub.build_playbook_chat">build_playbook_chat</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.AIStub.configure_mcp" href="#connpy.grpc_layer.stubs.AIStub.configure_mcp">configure_mcp</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.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.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.predict_execution_results" href="#connpy.grpc_layer.stubs.AIStub.predict_execution_results">predict_execution_results</a></code></li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<h4><code><a title="connpy.grpc_layer.stubs.AuthClientInterceptor" href="#connpy.grpc_layer.stubs.AuthClientInterceptor">AuthClientInterceptor</a></code></h4>
|
|
<ul class="">
|
|
<li><code><a title="connpy.grpc_layer.stubs.AuthClientInterceptor.intercept_stream_stream" href="#connpy.grpc_layer.stubs.AuthClientInterceptor.intercept_stream_stream">intercept_stream_stream</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.AuthClientInterceptor.intercept_stream_unary" href="#connpy.grpc_layer.stubs.AuthClientInterceptor.intercept_stream_unary">intercept_stream_unary</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.AuthClientInterceptor.intercept_unary_stream" href="#connpy.grpc_layer.stubs.AuthClientInterceptor.intercept_unary_stream">intercept_unary_stream</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.AuthClientInterceptor.intercept_unary_unary" href="#connpy.grpc_layer.stubs.AuthClientInterceptor.intercept_unary_unary">intercept_unary_unary</a></code></li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<h4><code><a title="connpy.grpc_layer.stubs.AuthStub" href="#connpy.grpc_layer.stubs.AuthStub">AuthStub</a></code></h4>
|
|
<ul class="">
|
|
<li><code><a title="connpy.grpc_layer.stubs.AuthStub.change_password" href="#connpy.grpc_layer.stubs.AuthStub.change_password">change_password</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.AuthStub.login" href="#connpy.grpc_layer.stubs.AuthStub.login">login</a></code></li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<h4><code><a title="connpy.grpc_layer.stubs.ConfigStub" href="#connpy.grpc_layer.stubs.ConfigStub">ConfigStub</a></code></h4>
|
|
<ul class="">
|
|
<li><code><a title="connpy.grpc_layer.stubs.ConfigStub.encrypt_password" href="#connpy.grpc_layer.stubs.ConfigStub.encrypt_password">encrypt_password</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.ConfigStub.get_default_dir" href="#connpy.grpc_layer.stubs.ConfigStub.get_default_dir">get_default_dir</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.ConfigStub.get_settings" href="#connpy.grpc_layer.stubs.ConfigStub.get_settings">get_settings</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.ConfigStub.set_config_folder" href="#connpy.grpc_layer.stubs.ConfigStub.set_config_folder">set_config_folder</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.ConfigStub.update_setting" href="#connpy.grpc_layer.stubs.ConfigStub.update_setting">update_setting</a></code></li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<h4><code><a title="connpy.grpc_layer.stubs.ExecutionStub" href="#connpy.grpc_layer.stubs.ExecutionStub">ExecutionStub</a></code></h4>
|
|
<ul class="">
|
|
<li><code><a title="connpy.grpc_layer.stubs.ExecutionStub.run_cli_script" href="#connpy.grpc_layer.stubs.ExecutionStub.run_cli_script">run_cli_script</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.ExecutionStub.run_commands" href="#connpy.grpc_layer.stubs.ExecutionStub.run_commands">run_commands</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.ExecutionStub.test_commands" href="#connpy.grpc_layer.stubs.ExecutionStub.test_commands">test_commands</a></code></li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<h4><code><a title="connpy.grpc_layer.stubs.ImportExportStub" href="#connpy.grpc_layer.stubs.ImportExportStub">ImportExportStub</a></code></h4>
|
|
<ul class="">
|
|
<li><code><a title="connpy.grpc_layer.stubs.ImportExportStub.export_to_file" href="#connpy.grpc_layer.stubs.ImportExportStub.export_to_file">export_to_file</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.ImportExportStub.import_from_file" href="#connpy.grpc_layer.stubs.ImportExportStub.import_from_file">import_from_file</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.ImportExportStub.set_reserved_names" href="#connpy.grpc_layer.stubs.ImportExportStub.set_reserved_names">set_reserved_names</a></code></li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<h4><code><a title="connpy.grpc_layer.stubs.NodeStub" href="#connpy.grpc_layer.stubs.NodeStub">NodeStub</a></code></h4>
|
|
<ul class="">
|
|
<li><code><a title="connpy.grpc_layer.stubs.NodeStub.add_node" href="#connpy.grpc_layer.stubs.NodeStub.add_node">add_node</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.NodeStub.bulk_add" href="#connpy.grpc_layer.stubs.NodeStub.bulk_add">bulk_add</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.NodeStub.connect_dynamic" href="#connpy.grpc_layer.stubs.NodeStub.connect_dynamic">connect_dynamic</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.NodeStub.connect_node" href="#connpy.grpc_layer.stubs.NodeStub.connect_node">connect_node</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.NodeStub.delete_node" href="#connpy.grpc_layer.stubs.NodeStub.delete_node">delete_node</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.NodeStub.explode_unique" href="#connpy.grpc_layer.stubs.NodeStub.explode_unique">explode_unique</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.NodeStub.full_replace" href="#connpy.grpc_layer.stubs.NodeStub.full_replace">full_replace</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.NodeStub.generate_cache" href="#connpy.grpc_layer.stubs.NodeStub.generate_cache">generate_cache</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.NodeStub.get_inventory" href="#connpy.grpc_layer.stubs.NodeStub.get_inventory">get_inventory</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.NodeStub.get_node_details" href="#connpy.grpc_layer.stubs.NodeStub.get_node_details">get_node_details</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.NodeStub.list_folders" href="#connpy.grpc_layer.stubs.NodeStub.list_folders">list_folders</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.NodeStub.list_nodes" href="#connpy.grpc_layer.stubs.NodeStub.list_nodes">list_nodes</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.NodeStub.move_node" href="#connpy.grpc_layer.stubs.NodeStub.move_node">move_node</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.NodeStub.set_reserved_names" href="#connpy.grpc_layer.stubs.NodeStub.set_reserved_names">set_reserved_names</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.NodeStub.update_node" href="#connpy.grpc_layer.stubs.NodeStub.update_node">update_node</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.NodeStub.validate_parent_folder" href="#connpy.grpc_layer.stubs.NodeStub.validate_parent_folder">validate_parent_folder</a></code></li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<h4><code><a title="connpy.grpc_layer.stubs.PluginStub" href="#connpy.grpc_layer.stubs.PluginStub">PluginStub</a></code></h4>
|
|
<ul class="two-column">
|
|
<li><code><a title="connpy.grpc_layer.stubs.PluginStub.add_plugin" href="#connpy.grpc_layer.stubs.PluginStub.add_plugin">add_plugin</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.PluginStub.delete_plugin" href="#connpy.grpc_layer.stubs.PluginStub.delete_plugin">delete_plugin</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.PluginStub.disable_plugin" href="#connpy.grpc_layer.stubs.PluginStub.disable_plugin">disable_plugin</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.PluginStub.enable_plugin" href="#connpy.grpc_layer.stubs.PluginStub.enable_plugin">enable_plugin</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.PluginStub.get_plugin_source" href="#connpy.grpc_layer.stubs.PluginStub.get_plugin_source">get_plugin_source</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.PluginStub.invoke_plugin" href="#connpy.grpc_layer.stubs.PluginStub.invoke_plugin">invoke_plugin</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.PluginStub.list_plugins" href="#connpy.grpc_layer.stubs.PluginStub.list_plugins">list_plugins</a></code></li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<h4><code><a title="connpy.grpc_layer.stubs.ProfileStub" href="#connpy.grpc_layer.stubs.ProfileStub">ProfileStub</a></code></h4>
|
|
<ul class="two-column">
|
|
<li><code><a title="connpy.grpc_layer.stubs.ProfileStub.add_profile" href="#connpy.grpc_layer.stubs.ProfileStub.add_profile">add_profile</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.ProfileStub.delete_profile" href="#connpy.grpc_layer.stubs.ProfileStub.delete_profile">delete_profile</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.ProfileStub.get_profile" href="#connpy.grpc_layer.stubs.ProfileStub.get_profile">get_profile</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.ProfileStub.list_profiles" href="#connpy.grpc_layer.stubs.ProfileStub.list_profiles">list_profiles</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.ProfileStub.resolve_node_data" href="#connpy.grpc_layer.stubs.ProfileStub.resolve_node_data">resolve_node_data</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.ProfileStub.update_profile" href="#connpy.grpc_layer.stubs.ProfileStub.update_profile">update_profile</a></code></li>
|
|
</ul>
|
|
</li>
|
|
<li>
|
|
<h4><code><a title="connpy.grpc_layer.stubs.SystemStub" href="#connpy.grpc_layer.stubs.SystemStub">SystemStub</a></code></h4>
|
|
<ul class="">
|
|
<li><code><a title="connpy.grpc_layer.stubs.SystemStub.debug_api" href="#connpy.grpc_layer.stubs.SystemStub.debug_api">debug_api</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.SystemStub.get_api_status" href="#connpy.grpc_layer.stubs.SystemStub.get_api_status">get_api_status</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.SystemStub.restart_api" href="#connpy.grpc_layer.stubs.SystemStub.restart_api">restart_api</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.SystemStub.start_api" href="#connpy.grpc_layer.stubs.SystemStub.start_api">start_api</a></code></li>
|
|
<li><code><a title="connpy.grpc_layer.stubs.SystemStub.stop_api" href="#connpy.grpc_layer.stubs.SystemStub.stop_api">stop_api</a></code></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
</main>
|
|
<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>
|
|
</footer>
|
|
</body>
|
|
</html>
|