feat(pipeline): add multi-agent pipeline engine, sidechat auto-provisioning, and CDP event isolation
- Add bin/pipeline_engine.py for persistent multi-agent execution tracking in pipelines.json - Add jobs/pipe-demo-step1.json and jobs/pipe-demo-step2.json demo pipeline definitions - Use ev1 in bin/muse-chat-api.py across send/messages/compose/create to avoid dropping return values on CDP event chatter - Support Muse unconfirmed signup error handling in bin/muse-signin.py - Add runtime state and telemetry files to .gitignore - Track dynamic pipe sidechat mappings in job-sidechats.json
This commit is contained in:
+35
-46
@@ -39,6 +39,18 @@ def _registry_port(node):
|
||||
return None
|
||||
|
||||
|
||||
def is_registered_in_accounts(email):
|
||||
path = "/home/super/Projects/NetVM/ACCOUNTS.md"
|
||||
try:
|
||||
with open(path) as f:
|
||||
for line in f:
|
||||
if line.startswith("|") and email.lower() in line.lower():
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
|
||||
|
||||
def get_page(port):
|
||||
cdp_url = "http://127.0.0.1:%s/json/list" % port
|
||||
with urllib.request.urlopen(cdp_url, timeout=5) as r:
|
||||
@@ -70,6 +82,9 @@ def main():
|
||||
'(never the "+1" entry)')
|
||||
args = p.parse_args()
|
||||
|
||||
if is_registered_in_accounts(args.email):
|
||||
print(f"Registry check: {args.email} is registered in ACCOUNTS.md")
|
||||
|
||||
if args.cdp_port:
|
||||
port = args.cdp_port
|
||||
elif args.node:
|
||||
@@ -126,13 +141,8 @@ def main():
|
||||
time.sleep(4)
|
||||
|
||||
# Step 5: Check for OTP prompt
|
||||
body = ev(ws, "document.body.innerText.slice(0,400)")
|
||||
if "To confirm your account" in body:
|
||||
print(f"NEEDS_SIGNUP: Account not yet confirmed/created on Muse for {args.email}. Client must complete signup first at https://muse.ai", file=sys.stderr)
|
||||
ws.close()
|
||||
sys.exit(4)
|
||||
|
||||
if "Enter your code" in body or "code we sent" in body or "To log in" in body:
|
||||
body = ev(ws, "document.body.innerText.slice(0,500)")
|
||||
if "Enter your code" in body or "code we sent" in body or "To log in" in body or "To confirm your account" in body:
|
||||
print(f"OTP prompt detected for {args.email}")
|
||||
if not args.otp:
|
||||
print(f"APPROVAL_NEEDED: OTP required for {args.email}")
|
||||
@@ -143,7 +153,7 @@ def main():
|
||||
# Enter OTP
|
||||
print("Entering OTP...")
|
||||
result = ev(ws, f"""(async()=>{{
|
||||
const inp=[...document.querySelectorAll('input')].find(i=>i.type==='text');
|
||||
const inp=[...document.querySelectorAll('input')].find(i=>i.type==='text'||i.type==='number');
|
||||
if(!inp) return 'NOINPUT';
|
||||
inp.focus();
|
||||
document.execCommand('insertText',false,'{args.otp}');
|
||||
@@ -153,20 +163,20 @@ def main():
|
||||
print(f"OTP: {result}")
|
||||
time.sleep(1)
|
||||
|
||||
# Click Next/Verify
|
||||
# Click Next/Verify/Confirm
|
||||
print("Submitting OTP...")
|
||||
ev(ws, """(async()=>{
|
||||
const b=[...document.querySelectorAll('button')].find(x=>
|
||||
x.innerText.includes('Next')||x.innerText.includes('Verify')
|
||||
x.innerText.includes('Next')||x.innerText.includes('Verify')||x.innerText.includes('Confirm')
|
||||
);
|
||||
if(b) b.click(); return !!b;
|
||||
})()""", True)
|
||||
time.sleep(5)
|
||||
|
||||
# Verify login
|
||||
body = ev(ws, "document.body.innerText.slice(0,200)")
|
||||
title = ev(ws, "document.title")
|
||||
if "Connected" in body or "Chats" in body:
|
||||
body = ev(ws, "document.body.innerText.slice(0,500)")
|
||||
title = ev(ws, "document.title") or ""
|
||||
if "Connected" in body or "Chats" in body or "Muse" in title or "Chat" in title:
|
||||
print(f"SUCCESS: Logged in as {args.email} (title: {title})")
|
||||
ws.close()
|
||||
return 0
|
||||
@@ -195,8 +205,9 @@ def main():
|
||||
sys.exit(3)
|
||||
print(f"Selected account '{args.account_name}', waiting...")
|
||||
time.sleep(5)
|
||||
body = ev(ws, "document.body.innerText.slice(0,200)")
|
||||
if "Connected" in body or "Chats" in body:
|
||||
body = ev(ws, "document.body.innerText.slice(0,500)")
|
||||
title = ev(ws, "document.title") or ""
|
||||
if "Connected" in body or "Chats" in body or "Muse" in title or "Chat" in title:
|
||||
print(f"SUCCESS: Logged in as {args.email} "
|
||||
f"(account: {args.account_name})")
|
||||
ws.close()
|
||||
@@ -207,41 +218,19 @@ def main():
|
||||
sys.exit(1)
|
||||
else:
|
||||
print(f"WARNING: Login may have failed. Title: {title}", file=sys.stderr)
|
||||
print(f"Body: {body[:100]}", file=sys.stderr)
|
||||
print(f"Body: {body[:150]}", file=sys.stderr)
|
||||
ws.close()
|
||||
sys.exit(1)
|
||||
else:
|
||||
body_full = ev(ws, "document.body.innerText.slice(0,2000)") or ""
|
||||
body_lower = body_full.lower()
|
||||
signup_cues = [
|
||||
"no account found",
|
||||
"couldn't find your account",
|
||||
"cannot find",
|
||||
"create an account",
|
||||
"create your account",
|
||||
"create account",
|
||||
"sign up",
|
||||
"sign-up",
|
||||
"doesn't have an account",
|
||||
"not registered",
|
||||
"register",
|
||||
"get started"
|
||||
]
|
||||
has_signup_cue = any(cue in body_lower for cue in signup_cues)
|
||||
has_name_or_pwd = ev(ws, """(()=>{
|
||||
const inps = [...document.querySelectorAll('input')];
|
||||
return inps.some(i => (i.placeholder && i.placeholder.toLowerCase().includes('name')) ||
|
||||
(i.name && i.name.toLowerCase().includes('name')) ||
|
||||
(i.type === 'password'));
|
||||
err_msg = ev(ws, """(()=>{
|
||||
const el = document.querySelector('[role="alert"], .error, [data-error]');
|
||||
return el ? el.innerText.trim() : '';
|
||||
})()""")
|
||||
|
||||
if has_signup_cue or has_name_or_pwd:
|
||||
print(f"NEEDS_SIGNUP: Account does not exist on Muse for {args.email}. Client must sign up first at https://muse.ai", file=sys.stderr)
|
||||
ws.close()
|
||||
sys.exit(4)
|
||||
|
||||
print("No OTP prompt found - check page state", file=sys.stderr)
|
||||
print(f"Body: {body[:200]}", file=sys.stderr)
|
||||
if err_msg:
|
||||
print(f"ERROR: {err_msg}", file=sys.stderr)
|
||||
else:
|
||||
print("No OTP prompt found - check page state", file=sys.stderr)
|
||||
print(f"Body: {body[:200]}", file=sys.stderr)
|
||||
ws.close()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user