codegpt-ai 1.27.0 → 1.28.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/chat.py +212 -2
  2. package/package.json +1 -1
package/chat.py CHANGED
@@ -422,6 +422,8 @@ COMMANDS = {
422
422
  "/vote": "All agents vote on a question",
423
423
  "/swarm": "Agents collaborate on a task step by step",
424
424
  "/team": "Start a team chat with 2 AIs (/team coder reviewer)",
425
+ "/room": "AI chat room — multiple AIs talk (/room coder reviewer architect)",
426
+ "/spectate": "Watch AIs chat without you (/spectate claude codex topic)",
425
427
  "/github": "GitHub tools (/github repos, issues, prs)",
426
428
  "/weather": "Get weather (/weather London)",
427
429
  "/open": "Open URL in browser (/open google.com)",
@@ -2412,10 +2414,35 @@ def get_weather(city):
2412
2414
 
2413
2415
 
2414
2416
  def open_url(url):
2415
- """Open a URL in the default browser."""
2417
+ """Open a URL or search query in the default browser."""
2416
2418
  import webbrowser
2417
- if not url.startswith("http"):
2419
+
2420
+ # Shortcuts
2421
+ shortcuts = {
2422
+ "google": "https://google.com",
2423
+ "youtube": "https://youtube.com",
2424
+ "github": "https://github.com",
2425
+ "reddit": "https://reddit.com",
2426
+ "twitter": "https://x.com",
2427
+ "x": "https://x.com",
2428
+ "stackoverflow": "https://stackoverflow.com",
2429
+ "npm": "https://npmjs.com",
2430
+ "pypi": "https://pypi.org",
2431
+ "ollama": "https://ollama.com",
2432
+ "claude": "https://claude.ai",
2433
+ "chatgpt": "https://chat.openai.com",
2434
+ "gemini": "https://gemini.google.com",
2435
+ }
2436
+
2437
+ if url.lower() in shortcuts:
2438
+ url = shortcuts[url.lower()]
2439
+ elif "." not in url and ":" not in url:
2440
+ # No dots = search query, not a URL
2441
+ query = url.replace(" ", "+")
2442
+ url = f"https://google.com/search?q={query}"
2443
+ elif not url.startswith("http"):
2418
2444
  url = "https://" + url
2445
+
2419
2446
  webbrowser.open(url)
2420
2447
  print_sys(f"Opened: {url}")
2421
2448
  audit_log("OPEN_URL", url)
@@ -3884,6 +3911,149 @@ def team_chat(name1, name2, default_model, system):
3884
3911
  return history
3885
3912
 
3886
3913
 
3914
+ # --- Chat Room ---
3915
+
3916
+ def chat_room(member_names, default_model, system, user_joins=True):
3917
+ """Multi-AI chat room. User can join or spectate."""
3918
+ members = [resolve_team_member(n) for n in member_names]
3919
+
3920
+ names_display = ", ".join(f"[{m['color']}]{m['name']}[/]" for m in members)
3921
+ mode = "Join" if user_joins else "Spectate"
3922
+
3923
+ console.print(Rule(style="bright_green", characters="─"))
3924
+ console.print(Text.from_markup(
3925
+ f" [bold]Chat Room[/] — {mode} mode\n"
3926
+ f" Members: {names_display}\n"
3927
+ ))
3928
+ if user_joins:
3929
+ console.print(Text(" Type to talk. @name to address one AI. 'exit' to leave.", style="dim"))
3930
+ else:
3931
+ console.print(Text(" Watching AIs chat. Ctrl+C to stop.", style="dim"))
3932
+ console.print(Rule(style="bright_green", characters="─"))
3933
+ console.print()
3934
+
3935
+ history = []
3936
+
3937
+ if user_joins:
3938
+ # Interactive room — user + multiple AIs
3939
+ while True:
3940
+ try:
3941
+ user_input = prompt(
3942
+ [("class:prompt", " You ❯ ")],
3943
+ style=input_style,
3944
+ history=input_history,
3945
+ ).strip()
3946
+ except (KeyboardInterrupt, EOFError):
3947
+ break
3948
+
3949
+ if not user_input or user_input.lower() in ("exit", "/exit", "quit"):
3950
+ break
3951
+
3952
+ console.print(Text(f" {user_input}", style="bold white"))
3953
+ console.print()
3954
+ history.append({"speaker": "user", "content": user_input})
3955
+
3956
+ # Check for @mentions
3957
+ mentioned = []
3958
+ for m in members:
3959
+ if f"@{m['name']}" in user_input.lower():
3960
+ mentioned.append(m)
3961
+
3962
+ # If no mentions, all respond
3963
+ responders = mentioned if mentioned else members
3964
+
3965
+ for member in responders:
3966
+ others = [m['name'] for m in members if m != member] + ["user"]
3967
+ conv = "\n".join(
3968
+ f"{h['speaker']}: {h['content'][:200]}"
3969
+ for h in history[-10:]
3970
+ )
3971
+
3972
+ room_prompt = (
3973
+ f"You are {member['name']} in a group chat with {', '.join(others)}.\n"
3974
+ f"Chat so far:\n{conv}\n\n"
3975
+ f"Respond as {member['name']}. Keep it short (2-4 sentences). "
3976
+ f"React to what was said. Agree, disagree, or add something new. "
3977
+ f"Don't repeat what others said."
3978
+ )
3979
+
3980
+ try:
3981
+ resp = requests.post(OLLAMA_URL, json={
3982
+ "model": member["model"] or default_model,
3983
+ "messages": [
3984
+ {"role": "system", "content": member["system"]},
3985
+ {"role": "user", "content": room_prompt},
3986
+ ],
3987
+ "stream": False,
3988
+ }, timeout=60)
3989
+ response = resp.json().get("message", {}).get("content", "")
3990
+ except Exception as e:
3991
+ response = f"(offline)"
3992
+
3993
+ console.print(Text.from_markup(f" [{member['color']}]{member['name']}[/] {response}"))
3994
+ console.print()
3995
+ history.append({"speaker": member["name"], "content": response})
3996
+ bus_send(member["name"], "codegpt", response[:200], "response")
3997
+
3998
+ else:
3999
+ # Spectate mode — AIs chat with each other, user watches
4000
+ try:
4001
+ # Get initial topic from last arg or default
4002
+ topic = "Introduce yourselves and start a technical discussion."
4003
+ if history:
4004
+ topic = history[-1]["content"]
4005
+
4006
+ current_input = topic
4007
+ rounds = 0
4008
+ max_rounds = 12
4009
+
4010
+ while rounds < max_rounds:
4011
+ for member in members:
4012
+ rounds += 1
4013
+ if rounds > max_rounds:
4014
+ break
4015
+
4016
+ others = [m['name'] for m in members if m != member]
4017
+ conv = "\n".join(
4018
+ f"{h['speaker']}: {h['content'][:200]}"
4019
+ for h in history[-8:]
4020
+ )
4021
+
4022
+ room_prompt = (
4023
+ f"You are {member['name']} in a group chat with {', '.join(others)}.\n"
4024
+ f"{'Topic: ' + current_input if not history else 'Chat so far:'}\n"
4025
+ f"{conv}\n\n"
4026
+ f"Respond as {member['name']}. Keep it short (2-3 sentences). "
4027
+ f"Build on the conversation. Be opinionated."
4028
+ )
4029
+
4030
+ try:
4031
+ resp = requests.post(OLLAMA_URL, json={
4032
+ "model": member["model"] or default_model,
4033
+ "messages": [
4034
+ {"role": "system", "content": member["system"]},
4035
+ {"role": "user", "content": room_prompt},
4036
+ ],
4037
+ "stream": False,
4038
+ }, timeout=60)
4039
+ response = resp.json().get("message", {}).get("content", "")
4040
+ except Exception as e:
4041
+ response = "(offline)"
4042
+
4043
+ console.print(Text.from_markup(f" [{member['color']}]{member['name']}[/] {response}"))
4044
+ console.print()
4045
+ history.append({"speaker": member["name"], "content": response})
4046
+ time.sleep(0.5)
4047
+
4048
+ except KeyboardInterrupt:
4049
+ pass
4050
+
4051
+ console.print(Rule(style="dim", characters="─"))
4052
+ console.print(Text(f" Room closed. {len(history)} messages.", style="dim"))
4053
+ console.print()
4054
+ return history
4055
+
4056
+
3887
4057
  # --- Split Screen ---
3888
4058
 
3889
4059
  def get_tool_cmd(name):
@@ -5656,6 +5826,46 @@ def main():
5656
5826
  print_sys("Terminal too narrow for sidebar. Widen to 80+ chars.")
5657
5827
  continue
5658
5828
 
5829
+ elif cmd == "/room":
5830
+ parts = user_input[len("/room "):].strip().split()
5831
+ if len(parts) >= 2:
5832
+ history = chat_room(parts, model, system, user_joins=True)
5833
+ for h in history:
5834
+ if h["speaker"] == "user":
5835
+ messages.append({"role": "user", "content": h["content"]})
5836
+ else:
5837
+ messages.append({"role": "assistant", "content": f"[{h['speaker']}] {h['content']}"})
5838
+ session_stats["messages"] += len(history)
5839
+ else:
5840
+ print_sys("Usage: /room coder reviewer architect")
5841
+ print_sys(" /room claude codex gemini deepseek")
5842
+ print_sys(f"\nAvailable: {', '.join(list(AI_AGENTS.keys()) + list(TOOL_PERSONAS.keys()))}")
5843
+ continue
5844
+
5845
+ elif cmd == "/spectate":
5846
+ args = user_input[len("/spectate "):].strip().split()
5847
+ if len(args) >= 2:
5848
+ # Last arg could be a topic
5849
+ names = args
5850
+ topic = ""
5851
+ # Check if last args aren't AI names — treat as topic
5852
+ all_names = set(AI_AGENTS.keys()) | set(TOOL_PERSONAS.keys())
5853
+ topic_words = []
5854
+ while names and names[-1] not in all_names:
5855
+ topic_words.insert(0, names.pop())
5856
+ topic = " ".join(topic_words) if topic_words else "Discuss the best programming practices"
5857
+
5858
+ if len(names) >= 2:
5859
+ # Inject topic
5860
+ history_init = [{"speaker": "moderator", "content": topic}]
5861
+ h = chat_room(names, model, system, user_joins=False)
5862
+ else:
5863
+ print_sys("Need at least 2 AIs. Example: /spectate coder reviewer discuss Python")
5864
+ else:
5865
+ print_sys("Usage: /spectate coder reviewer discuss error handling")
5866
+ print_sys(" /spectate claude codex gemini debate which is best")
5867
+ continue
5868
+
5659
5869
  elif cmd == "/monitor":
5660
5870
  # Live updating dashboard — press Ctrl+C to exit
5661
5871
  console.print(Text(" Live monitor — Ctrl+C to stop\n", style="dim"))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codegpt-ai",
3
- "version": "1.27.0",
3
+ "version": "1.28.1",
4
4
  "description": "Local AI Assistant Hub — 80+ commands, 29 tools, 8 agents, training, security",
5
5
  "author": "ArukuX",
6
6
  "license": "MIT",