crowe-logic 0.1.0
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.
- package/.dockerignore +14 -0
- package/.env.example +24 -0
- package/Dockerfile +62 -0
- package/cli/__init__.py +0 -0
- package/cli/branding.py +105 -0
- package/cli/crowe_logic.py +268 -0
- package/cli/icon.png +0 -0
- package/config/__init__.py +0 -0
- package/config/agent_config.py +54 -0
- package/npm/bin.js +34 -0
- package/package.json +32 -0
- package/pyproject.toml +70 -0
- package/requirements.txt +11 -0
- package/scripts/__init__.py +0 -0
- package/scripts/create_agent.py +163 -0
- package/scripts/fine_tune.py +271 -0
- package/scripts/npm-publish.sh +15 -0
- package/scripts/orchestrator.applescript +162 -0
- package/scripts/test_agent.py +200 -0
- package/setup.py +24 -0
- package/tools/__init__.py +57 -0
- package/tools/applescript.py +58 -0
- package/tools/browser.py +79 -0
- package/tools/filesystem.py +115 -0
- package/tools/git_ops.py +107 -0
- package/tools/playwright_browser.py +101 -0
- package/tools/quantum.py +89 -0
- package/tools/search.py +108 -0
- package/tools/shell.py +47 -0
- package/tools/talon_music.py +112 -0
package/.dockerignore
ADDED
package/.env.example
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Azure AI Foundry — Crowe Logic Agent
|
|
2
|
+
# Copy to .env and fill in your values
|
|
3
|
+
|
|
4
|
+
# Your Azure AI Foundry project endpoint (found in project overview)
|
|
5
|
+
PROJECT_ENDPOINT=https://crowelogicos-7858.services.ai.azure.com
|
|
6
|
+
|
|
7
|
+
# Model deployment name (the gpt-oss-120b deployment you created in Azure)
|
|
8
|
+
MODEL_DEPLOYMENT_NAME=gpt-oss-120b
|
|
9
|
+
|
|
10
|
+
# Bing Search connection ID (for web grounding — create in Azure AI Foundry connections)
|
|
11
|
+
AZURE_BING_CONNECTION_ID=
|
|
12
|
+
|
|
13
|
+
# Azure AI Search connection ID (for vector search — create in Azure AI Foundry connections)
|
|
14
|
+
AI_AZURE_AI_CONNECTION_ID=
|
|
15
|
+
|
|
16
|
+
# Azure AI Search index name
|
|
17
|
+
AI_SEARCH_INDEX_NAME=crowe-logic-kb
|
|
18
|
+
|
|
19
|
+
# Azure subscription details (for Azure Function tools)
|
|
20
|
+
AZURE_SUBSCRIPTION_ID=
|
|
21
|
+
AZURE_RESOURCE_GROUP=rg-crowelogicos-7858
|
|
22
|
+
|
|
23
|
+
# Optional: Application Insights for tracing
|
|
24
|
+
APPLICATIONINSIGHTS_CONNECTION_STRING=
|
package/Dockerfile
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
FROM python:3.12-slim AS base
|
|
2
|
+
|
|
3
|
+
LABEL maintainer="michael@crowelogic.com"
|
|
4
|
+
LABEL org.opencontainers.image.title="Crowe Logic Agent"
|
|
5
|
+
LABEL org.opencontainers.image.description="Universal AI Agent powered by gpt-oss-120b on Azure AI Foundry"
|
|
6
|
+
LABEL org.opencontainers.image.vendor="Crowe Logic, Inc."
|
|
7
|
+
|
|
8
|
+
WORKDIR /app
|
|
9
|
+
|
|
10
|
+
# System dependencies for playwright and ripgrep
|
|
11
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
12
|
+
git \
|
|
13
|
+
ripgrep \
|
|
14
|
+
curl \
|
|
15
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
16
|
+
|
|
17
|
+
# Install Node.js for MCP servers
|
|
18
|
+
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
|
|
19
|
+
&& apt-get install -y nodejs \
|
|
20
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
21
|
+
|
|
22
|
+
# Python dependencies
|
|
23
|
+
COPY requirements.txt .
|
|
24
|
+
RUN pip install --no-cache-dir -r requirements.txt
|
|
25
|
+
|
|
26
|
+
# MCP servers
|
|
27
|
+
COPY package.json package-lock.json* ./
|
|
28
|
+
RUN npm install --production
|
|
29
|
+
|
|
30
|
+
# Application code
|
|
31
|
+
COPY . .
|
|
32
|
+
|
|
33
|
+
# Install crowe-logic CLI
|
|
34
|
+
RUN pip install --no-cache-dir -e .
|
|
35
|
+
|
|
36
|
+
# Default: interactive chat
|
|
37
|
+
ENTRYPOINT ["crowe-logic"]
|
|
38
|
+
CMD ["chat"]
|
|
39
|
+
|
|
40
|
+
# ── GPU variant for fine-tuning ─────────────────
|
|
41
|
+
FROM nvidia/cuda:12.4.1-runtime-ubuntu22.04 AS gpu
|
|
42
|
+
|
|
43
|
+
LABEL maintainer="michael@crowelogic.com"
|
|
44
|
+
LABEL org.opencontainers.image.title="Crowe Logic Agent (GPU)"
|
|
45
|
+
|
|
46
|
+
WORKDIR /app
|
|
47
|
+
|
|
48
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
49
|
+
python3.12 python3-pip git ripgrep curl \
|
|
50
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
51
|
+
|
|
52
|
+
COPY requirements.txt .
|
|
53
|
+
RUN pip install --no-cache-dir -r requirements.txt
|
|
54
|
+
RUN pip install --no-cache-dir qiskit qiskit-aer cirq pennylane \
|
|
55
|
+
synapse-lang synapse-qubit-flow \
|
|
56
|
+
torch --index-url https://download.pytorch.org/whl/cu124
|
|
57
|
+
|
|
58
|
+
COPY . .
|
|
59
|
+
RUN pip install --no-cache-dir -e ".[quantum]"
|
|
60
|
+
|
|
61
|
+
ENTRYPOINT ["crowe-logic"]
|
|
62
|
+
CMD ["chat"]
|
package/cli/__init__.py
ADDED
|
File without changes
|
package/cli/branding.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Crowe Logic CLI — Branding & Terminal Art
|
|
3
|
+
|
|
4
|
+
Provides the logo, banner, and styled prompt for the CLI.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
# Gold/amber ANSI escape — closest to the gold ring in the logo
|
|
10
|
+
GOLD = "\033[38;2;191;166;105m"
|
|
11
|
+
WHITE = "\033[97m"
|
|
12
|
+
BLACK_BG = "\033[40m"
|
|
13
|
+
DIM = "\033[2m"
|
|
14
|
+
BOLD = "\033[1m"
|
|
15
|
+
RESET = "\033[0m"
|
|
16
|
+
CYAN = "\033[36m"
|
|
17
|
+
|
|
18
|
+
# ── Compact logo mark for the prompt ────────────────────────────
|
|
19
|
+
# Uses Unicode block/braille characters for a tiny circular icon
|
|
20
|
+
PROMPT_ICON = f"{GOLD}\u25C9{RESET}" # ◉ gold ring dot
|
|
21
|
+
|
|
22
|
+
# ── ASCII art banner ────────────────────────────────────────────
|
|
23
|
+
# Stencil-style portrait in the gold ring — simplified for terminal
|
|
24
|
+
BANNER = f"""{GOLD}
|
|
25
|
+
╭━━━━━━━━━━━━━━━━━╮
|
|
26
|
+
╭━━━╯ ╰━━━╮
|
|
27
|
+
╭━╯ {WHITE}▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄{GOLD} ╰━╮
|
|
28
|
+
╭━╯ {WHITE}▄████████████████▄{GOLD} ╰━╮
|
|
29
|
+
╭╯ {WHITE}▄██▀▀▀▀▀▀▀▀▀▀▀▀▀██▄{GOLD} ╰╮
|
|
30
|
+
╭╯ {WHITE}███ ▄▄▄ ▄▄▄ ███{GOLD} ╰╮
|
|
31
|
+
┃ {WHITE}████ ▀▄▄▀ ▀▄▄▀ ████{GOLD} ┃
|
|
32
|
+
┃ {WHITE}████ ████{GOLD} ┃
|
|
33
|
+
┃ {WHITE}████ ▄ ▄ ████{GOLD} ┃
|
|
34
|
+
┃ {WHITE}███ ▀▄▄▄▄▄▀ ███{GOLD} ┃
|
|
35
|
+
╰╮ {WHITE}███▄ ▄███{GOLD} ╭╯
|
|
36
|
+
╰╮ {WHITE}▀████▄▄▄▄▄▄████▀{GOLD} ╭╯
|
|
37
|
+
╰━╮ {WHITE}▀▀██████████▀▀{GOLD} ╭━╯
|
|
38
|
+
╰━╮ ╭━╯
|
|
39
|
+
╰━━━╮ ╭━━━╯
|
|
40
|
+
╰━━━━━━━━━━━━━━━╯{RESET}
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
# ── Minimal banner for compact mode ────────────────────────────
|
|
44
|
+
BANNER_COMPACT = f"""{GOLD} ╭━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╮
|
|
45
|
+
┃ {WHITE}{BOLD}◉ C R O W E L O G I C{RESET}{GOLD} ┃
|
|
46
|
+
┃ {DIM}Universal AI Agent • gpt-oss-120b{RESET}{GOLD} ┃
|
|
47
|
+
╰━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╯{RESET}"""
|
|
48
|
+
|
|
49
|
+
# ── Title text ──────────────────────────────────────────────────
|
|
50
|
+
TITLE = f"""{GOLD}{BOLD}
|
|
51
|
+
██████╗██████╗ ██████╗ ██╗ ██╗███████╗
|
|
52
|
+
██╔════╝██╔══██╗██╔═══██╗██║ ██║██╔════╝
|
|
53
|
+
██║ ██████╔╝██║ ██║██║ █╗ ██║█████╗
|
|
54
|
+
██║ ██╔══██╗██║ ██║██║███╗██║██╔══╝
|
|
55
|
+
╚██████╗██║ ██║╚██████╔╝╚███╔███╔╝███████╗
|
|
56
|
+
╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝
|
|
57
|
+
{DIM}L O G I C{RESET}{GOLD} {DIM}v0.1.0{RESET}
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
# ── Full welcome screen ────────────────────────────────────────
|
|
61
|
+
def welcome_screen(model: str = "gpt-oss-120b", version: str = "0.1.0"):
|
|
62
|
+
"""Return the full welcome screen string."""
|
|
63
|
+
return f"""{GOLD}{BOLD}
|
|
64
|
+
██████╗██████╗ ██████╗ ██╗ ██╗███████╗
|
|
65
|
+
██╔════╝██╔══██╗██╔═══██╗██║ ██║██╔════╝
|
|
66
|
+
██║ ██████╔╝██║ ██║██║ █╗ ██║█████╗
|
|
67
|
+
██║ ██╔══██╗██║ ██║██║███╗██║██╔══╝
|
|
68
|
+
╚██████╗██║ ██║╚██████╔╝╚███╔███╔╝███████╗
|
|
69
|
+
╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝
|
|
70
|
+
{RESET}{GOLD}{DIM}L O G I C{RESET}
|
|
71
|
+
|
|
72
|
+
{DIM}Model: {RESET}{WHITE}{model}{RESET}
|
|
73
|
+
{DIM}Platform: {RESET}{WHITE}Azure AI Foundry{RESET}
|
|
74
|
+
{DIM}Tools: {RESET}{WHITE}29 function tools + code interpreter{RESET}
|
|
75
|
+
{DIM}Version: {RESET}{WHITE}{version}{RESET}
|
|
76
|
+
|
|
77
|
+
{DIM}Type naturally. The agent auto-selects tools.{RESET}
|
|
78
|
+
{DIM}Commands: /exit /tools /status /clear{RESET}
|
|
79
|
+
{GOLD} {'━' * 52}{RESET}
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def prompt_string() -> str:
|
|
84
|
+
"""Return the styled prompt string for input."""
|
|
85
|
+
return f"{GOLD}{BOLD}you {PROMPT_ICON}{RESET} "
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def agent_prefix() -> str:
|
|
89
|
+
"""Return the styled prefix for agent responses."""
|
|
90
|
+
return f"{GOLD}{BOLD}crowe-logic {PROMPT_ICON}{RESET} "
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# ── iTerm2 inline image protocol ───────────────────────────────
|
|
94
|
+
def show_inline_image(path: str, width: int = 10):
|
|
95
|
+
"""Display the icon inline in iTerm2/compatible terminals."""
|
|
96
|
+
import base64
|
|
97
|
+
if not os.path.exists(path):
|
|
98
|
+
return
|
|
99
|
+
term = os.environ.get("TERM_PROGRAM", "")
|
|
100
|
+
if term not in ("iTerm.app", "WezTerm", "ghostty"):
|
|
101
|
+
return # Only works in supported terminals
|
|
102
|
+
with open(path, "rb") as f:
|
|
103
|
+
data = base64.b64encode(f.read()).decode()
|
|
104
|
+
# iTerm2 inline image escape sequence
|
|
105
|
+
print(f"\033]1337;File=inline=1;width={width};preserveAspectRatio=1:{data}\a")
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Crowe Logic CLI — Universal AI Agent
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
crowe-logic chat # Interactive chat session
|
|
7
|
+
crowe-logic run "your prompt" # Single prompt, get response
|
|
8
|
+
crowe-logic deploy # Create/recreate the agent
|
|
9
|
+
crowe-logic status # Show agent status
|
|
10
|
+
crowe-logic tools # List available tools
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
import sys
|
|
15
|
+
import json
|
|
16
|
+
import time
|
|
17
|
+
|
|
18
|
+
# Add project root to path
|
|
19
|
+
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
20
|
+
sys.path.insert(0, PROJECT_ROOT)
|
|
21
|
+
|
|
22
|
+
import click
|
|
23
|
+
from rich.console import Console
|
|
24
|
+
from rich.markdown import Markdown
|
|
25
|
+
from rich.panel import Panel
|
|
26
|
+
from rich.text import Text
|
|
27
|
+
|
|
28
|
+
from dotenv import load_dotenv
|
|
29
|
+
load_dotenv(os.path.join(PROJECT_ROOT, ".env"))
|
|
30
|
+
|
|
31
|
+
from cli.branding import (
|
|
32
|
+
welcome_screen, prompt_string, agent_prefix,
|
|
33
|
+
show_inline_image, BANNER_COMPACT, PROMPT_ICON, GOLD, RESET, BOLD,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
console = Console()
|
|
37
|
+
|
|
38
|
+
ICON_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "icon.png")
|
|
39
|
+
|
|
40
|
+
AGENT_ID_FILE = os.path.join(PROJECT_ROOT, ".agent_id")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def get_agent_id() -> str:
|
|
44
|
+
"""Load saved agent ID from .agent_id file."""
|
|
45
|
+
if not os.path.exists(AGENT_ID_FILE):
|
|
46
|
+
console.print("[red]No agent found. Run: crowe-logic deploy[/red]")
|
|
47
|
+
sys.exit(1)
|
|
48
|
+
with open(AGENT_ID_FILE) as f:
|
|
49
|
+
data = json.load(f)
|
|
50
|
+
return data["agent_id"]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_client():
|
|
54
|
+
"""Create and return an AgentsClient."""
|
|
55
|
+
from azure.ai.agents import AgentsClient
|
|
56
|
+
from azure.identity import DefaultAzureCredential
|
|
57
|
+
from config.agent_config import PROJECT_ENDPOINT
|
|
58
|
+
|
|
59
|
+
return AgentsClient(
|
|
60
|
+
endpoint=PROJECT_ENDPOINT,
|
|
61
|
+
credential=DefaultAzureCredential(),
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def setup_toolset(client):
|
|
66
|
+
"""Configure the toolset with auto function calling."""
|
|
67
|
+
from azure.ai.agents.models import FunctionTool, ToolSet, CodeInterpreterTool
|
|
68
|
+
from tools import user_functions
|
|
69
|
+
|
|
70
|
+
toolset = ToolSet()
|
|
71
|
+
toolset.add(FunctionTool(user_functions))
|
|
72
|
+
toolset.add(CodeInterpreterTool())
|
|
73
|
+
client.enable_auto_function_calls(toolset)
|
|
74
|
+
return toolset
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def stream_response(client, thread_id: str, agent_id: str):
|
|
78
|
+
"""Stream agent response with rich formatting."""
|
|
79
|
+
from azure.ai.agents.models import MessageDeltaChunk, ThreadMessage, ThreadRun, RunStep, AgentStreamEvent
|
|
80
|
+
|
|
81
|
+
full_text = ""
|
|
82
|
+
|
|
83
|
+
with client.runs.stream(thread_id=thread_id, agent_id=agent_id) as stream:
|
|
84
|
+
for event_type, event_data, _ in stream:
|
|
85
|
+
if isinstance(event_data, MessageDeltaChunk):
|
|
86
|
+
if event_data.text:
|
|
87
|
+
console.print(event_data.text, end="")
|
|
88
|
+
full_text += event_data.text
|
|
89
|
+
|
|
90
|
+
elif isinstance(event_data, ThreadRun):
|
|
91
|
+
if event_data.status == "failed":
|
|
92
|
+
console.print(f"\n[red]Run failed: {event_data.last_error}[/red]")
|
|
93
|
+
|
|
94
|
+
elif isinstance(event_data, RunStep):
|
|
95
|
+
if event_data.type == "tool_calls" and event_data.status == "in_progress":
|
|
96
|
+
console.print("\n[dim] (calling tools...)[/dim]", end="")
|
|
97
|
+
|
|
98
|
+
elif event_type == AgentStreamEvent.ERROR:
|
|
99
|
+
console.print(f"\n[red]Error: {event_data}[/red]")
|
|
100
|
+
|
|
101
|
+
elif event_type == AgentStreamEvent.DONE:
|
|
102
|
+
break
|
|
103
|
+
|
|
104
|
+
console.print() # Final newline
|
|
105
|
+
return full_text
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@click.group()
|
|
109
|
+
@click.version_option(version="0.1.0", prog_name="crowe-logic")
|
|
110
|
+
def main():
|
|
111
|
+
"""Crowe Logic — Universal AI Agent powered by gpt-oss-120b"""
|
|
112
|
+
pass
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
@main.command()
|
|
116
|
+
def chat():
|
|
117
|
+
"""Start an interactive chat session with the agent."""
|
|
118
|
+
from prompt_toolkit import PromptSession
|
|
119
|
+
from prompt_toolkit.history import FileHistory
|
|
120
|
+
|
|
121
|
+
agent_id = get_agent_id()
|
|
122
|
+
client = get_client()
|
|
123
|
+
setup_toolset(client)
|
|
124
|
+
|
|
125
|
+
# Create a thread for this session
|
|
126
|
+
thread = client.threads.create()
|
|
127
|
+
|
|
128
|
+
# Show inline image in supported terminals (iTerm2, WezTerm, Ghostty)
|
|
129
|
+
show_inline_image(ICON_PATH, width=8)
|
|
130
|
+
|
|
131
|
+
# Print the branded welcome screen
|
|
132
|
+
print(welcome_screen())
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
history_file = os.path.join(PROJECT_ROOT, ".chat_history")
|
|
136
|
+
session = PromptSession(history=FileHistory(history_file))
|
|
137
|
+
|
|
138
|
+
while True:
|
|
139
|
+
try:
|
|
140
|
+
user_input = session.prompt(prompt_string(), multiline=False)
|
|
141
|
+
except (EOFError, KeyboardInterrupt):
|
|
142
|
+
print(f"\n{GOLD}{BOLD}Goodbye.{RESET}")
|
|
143
|
+
break
|
|
144
|
+
|
|
145
|
+
user_input = user_input.strip()
|
|
146
|
+
if not user_input:
|
|
147
|
+
continue
|
|
148
|
+
if user_input.lower() in ("exit", "quit", "/exit", "/quit"):
|
|
149
|
+
print(f"{GOLD}{BOLD}Goodbye.{RESET}")
|
|
150
|
+
break
|
|
151
|
+
|
|
152
|
+
# Handle CLI meta-commands
|
|
153
|
+
if user_input.lower() == "/tools":
|
|
154
|
+
_list_tools_inline()
|
|
155
|
+
continue
|
|
156
|
+
if user_input.lower() == "/clear":
|
|
157
|
+
console.clear()
|
|
158
|
+
print(welcome_screen())
|
|
159
|
+
continue
|
|
160
|
+
if user_input.lower() == "/status":
|
|
161
|
+
_show_status_inline()
|
|
162
|
+
continue
|
|
163
|
+
|
|
164
|
+
# Send message
|
|
165
|
+
client.messages.create(thread_id=thread.id, role="user", content=user_input)
|
|
166
|
+
|
|
167
|
+
# Stream response
|
|
168
|
+
console.print()
|
|
169
|
+
print(agent_prefix(), end="", flush=True)
|
|
170
|
+
stream_response(client, thread.id, agent_id)
|
|
171
|
+
console.print()
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _list_tools_inline():
|
|
175
|
+
"""Show tools inside the chat session."""
|
|
176
|
+
from tools import user_functions
|
|
177
|
+
print(f"\n{GOLD}{'━' * 52}")
|
|
178
|
+
print(f" Available Tools ({len(user_functions)} custom + code interpreter){RESET}\n")
|
|
179
|
+
for func in sorted(user_functions, key=lambda f: f.__name__):
|
|
180
|
+
doc = (func.__doc__ or "").strip().split("\n")[0]
|
|
181
|
+
print(f" {GOLD}{func.__name__:25s}{RESET} {doc}")
|
|
182
|
+
print(f"\n{GOLD}{'━' * 52}{RESET}\n")
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _show_status_inline():
|
|
186
|
+
"""Show status inside the chat session."""
|
|
187
|
+
if not os.path.exists(AGENT_ID_FILE):
|
|
188
|
+
print(f" {GOLD}Status:{RESET} No agent deployed")
|
|
189
|
+
return
|
|
190
|
+
with open(AGENT_ID_FILE) as f:
|
|
191
|
+
data = json.load(f)
|
|
192
|
+
print(f"\n{GOLD}{'━' * 52}{RESET}")
|
|
193
|
+
print(f" {GOLD}Agent ID:{RESET} {data.get('agent_id', 'unknown')}")
|
|
194
|
+
print(f" {GOLD}Name:{RESET} {data.get('name', 'unknown')}")
|
|
195
|
+
print(f" {GOLD}Model:{RESET} {data.get('model', 'unknown')}")
|
|
196
|
+
print(f" {GOLD}Version:{RESET} {data.get('version', 'unknown')}")
|
|
197
|
+
print(f"{GOLD}{'━' * 52}{RESET}\n")
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
@main.command()
|
|
201
|
+
@click.argument("prompt")
|
|
202
|
+
def run(prompt: str):
|
|
203
|
+
"""Run a single prompt and print the response."""
|
|
204
|
+
agent_id = get_agent_id()
|
|
205
|
+
client = get_client()
|
|
206
|
+
setup_toolset(client)
|
|
207
|
+
|
|
208
|
+
thread = client.threads.create()
|
|
209
|
+
client.messages.create(thread_id=thread.id, role="user", content=prompt)
|
|
210
|
+
|
|
211
|
+
stream_response(client, thread.id, agent_id)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
@main.command()
|
|
215
|
+
@click.option("--name", default="crowe-logic", help="Agent name")
|
|
216
|
+
def deploy(name: str):
|
|
217
|
+
"""Create or recreate the Crowe Logic agent."""
|
|
218
|
+
from scripts.create_agent import create_agent
|
|
219
|
+
create_agent(name=name, verbose=True)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
@main.command()
|
|
223
|
+
def status():
|
|
224
|
+
"""Show current agent status."""
|
|
225
|
+
if not os.path.exists(AGENT_ID_FILE):
|
|
226
|
+
console.print("[red]No agent deployed. Run: crowe-logic deploy[/red]")
|
|
227
|
+
return
|
|
228
|
+
|
|
229
|
+
with open(AGENT_ID_FILE) as f:
|
|
230
|
+
data = json.load(f)
|
|
231
|
+
|
|
232
|
+
console.print(Panel(
|
|
233
|
+
Text.from_markup(
|
|
234
|
+
f"[bold cyan]CROWE LOGIC STATUS[/bold cyan]\n\n"
|
|
235
|
+
f"[bold]Agent ID:[/bold] {data.get('agent_id', 'unknown')}\n"
|
|
236
|
+
f"[bold]Name:[/bold] {data.get('name', 'unknown')}\n"
|
|
237
|
+
f"[bold]Version:[/bold] {data.get('version', 'unknown')}\n"
|
|
238
|
+
f"[bold]Model:[/bold] {data.get('model', 'unknown')}"
|
|
239
|
+
),
|
|
240
|
+
border_style="cyan",
|
|
241
|
+
padding=(1, 2),
|
|
242
|
+
))
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
@main.command()
|
|
246
|
+
def tools():
|
|
247
|
+
"""List all available tools."""
|
|
248
|
+
from tools import user_functions
|
|
249
|
+
|
|
250
|
+
console.print(Panel("[bold cyan]CROWE LOGIC — AVAILABLE TOOLS[/bold cyan]", border_style="cyan"))
|
|
251
|
+
console.print()
|
|
252
|
+
|
|
253
|
+
# Custom function tools
|
|
254
|
+
console.print("[bold]Custom Function Tools:[/bold]")
|
|
255
|
+
for func in sorted(user_functions, key=lambda f: f.__name__):
|
|
256
|
+
doc = (func.__doc__ or "").strip().split("\n")[0]
|
|
257
|
+
console.print(f" [cyan]{func.__name__:25s}[/cyan] {doc}")
|
|
258
|
+
|
|
259
|
+
console.print()
|
|
260
|
+
console.print("[bold]Built-in Azure Tools:[/bold]")
|
|
261
|
+
console.print(f" [cyan]{'code_interpreter':25s}[/cyan] Run Python code in a sandboxed environment")
|
|
262
|
+
console.print(f" [cyan]{'bing_grounding':25s}[/cyan] Search the web via Bing (requires connection)")
|
|
263
|
+
console.print(f" [cyan]{'file_search':25s}[/cyan] RAG over uploaded documents (requires vector store)")
|
|
264
|
+
console.print(f" [cyan]{'azure_ai_search':25s}[/cyan] Vector search over knowledge base (requires index)")
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
if __name__ == "__main__":
|
|
268
|
+
main()
|
package/cli/icon.png
ADDED
|
Binary file
|
|
File without changes
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Crowe Logic Agent — Central Configuration
|
|
3
|
+
|
|
4
|
+
All agent settings, system instructions, and tool selection live here.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
from dotenv import load_dotenv
|
|
9
|
+
|
|
10
|
+
load_dotenv()
|
|
11
|
+
|
|
12
|
+
# Azure AI Foundry
|
|
13
|
+
PROJECT_ENDPOINT = os.environ.get("PROJECT_ENDPOINT", "https://crowelogicos-7858-resource.services.ai.azure.com/api/projects/crowelogicos-7858")
|
|
14
|
+
MODEL_DEPLOYMENT_NAME = os.environ.get("MODEL_DEPLOYMENT_NAME", "gpt-oss-120b")
|
|
15
|
+
|
|
16
|
+
# Connections (optional — leave empty to skip those tools)
|
|
17
|
+
BING_CONNECTION_ID = os.environ.get("AZURE_BING_CONNECTION_ID", "")
|
|
18
|
+
AI_SEARCH_CONNECTION_ID = os.environ.get("AI_AZURE_AI_CONNECTION_ID", "")
|
|
19
|
+
AI_SEARCH_INDEX_NAME = os.environ.get("AI_SEARCH_INDEX_NAME", "crowe-logic-kb")
|
|
20
|
+
|
|
21
|
+
# Azure
|
|
22
|
+
SUBSCRIPTION_ID = os.environ.get("AZURE_SUBSCRIPTION_ID", "")
|
|
23
|
+
RESOURCE_GROUP = os.environ.get("AZURE_RESOURCE_GROUP", "rg-crowelogicos-7858")
|
|
24
|
+
|
|
25
|
+
# Agent identity
|
|
26
|
+
AGENT_NAME = "crowe-logic"
|
|
27
|
+
AGENT_VERSION = "0.1.0"
|
|
28
|
+
|
|
29
|
+
SYSTEM_INSTRUCTIONS = """You are Crowe Logic, a universal AI agent created by Michael Crowe.
|
|
30
|
+
|
|
31
|
+
You can do anything and everything across all domains. You have access to tools for:
|
|
32
|
+
- Reading, writing, and editing files on the local filesystem
|
|
33
|
+
- Executing shell commands
|
|
34
|
+
- Searching the web for current information
|
|
35
|
+
- Browsing and fetching web pages
|
|
36
|
+
- Searching file contents with pattern matching
|
|
37
|
+
- Listing directory structures
|
|
38
|
+
- Running Python code via Code Interpreter
|
|
39
|
+
- Searching knowledge bases and vector stores
|
|
40
|
+
|
|
41
|
+
When given a task:
|
|
42
|
+
1. Understand what's being asked — clarify if ambiguous
|
|
43
|
+
2. Plan your approach — break complex tasks into steps
|
|
44
|
+
3. Execute using the right tools — don't guess when you can look things up
|
|
45
|
+
4. Verify your work — check outputs, run tests if applicable
|
|
46
|
+
5. Report results concisely
|
|
47
|
+
|
|
48
|
+
You are direct, capable, and thorough. You don't hedge or over-explain.
|
|
49
|
+
You write clean, production-quality code. You think before you act.
|
|
50
|
+
|
|
51
|
+
You operate from: /Users/crowelogic
|
|
52
|
+
Current model: gpt-oss-120b (OpenAI open-weight, Apache 2.0)
|
|
53
|
+
Platform: Azure AI Foundry
|
|
54
|
+
"""
|
package/npm/bin.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Crowe Logic CLI — npm wrapper
|
|
4
|
+
*
|
|
5
|
+
* Delegates to the Python CLI. Requires Python 3.10+ and pip.
|
|
6
|
+
* Usage: npx crowe-logic chat
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { execFileSync, spawn } = require("child_process");
|
|
10
|
+
|
|
11
|
+
const args = process.argv.slice(2);
|
|
12
|
+
|
|
13
|
+
// Check if crowe-logic is installed as a Python package
|
|
14
|
+
try {
|
|
15
|
+
execFileSync("crowe-logic", ["--version"], { stdio: "pipe" });
|
|
16
|
+
} catch {
|
|
17
|
+
console.log("Installing crowe-logic Python package...");
|
|
18
|
+
try {
|
|
19
|
+
execFileSync("pip", ["install", "crowe-logic"], { stdio: "inherit" });
|
|
20
|
+
} catch {
|
|
21
|
+
console.error(
|
|
22
|
+
"\nCrowe Logic requires Python 3.10+. Install via:\n" +
|
|
23
|
+
" pip install crowe-logic\n"
|
|
24
|
+
);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Delegate to the Python CLI (no shell, no injection risk)
|
|
30
|
+
const child = spawn("crowe-logic", args, {
|
|
31
|
+
stdio: "inherit",
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
child.on("exit", (code) => process.exit(code || 0));
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "crowe-logic",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Crowe Logic — Universal AI Agent powered by gpt-oss-120b on Azure AI Foundry",
|
|
5
|
+
"main": "npm/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"crowe-logic": "npm/bin.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node npm/bin.js chat",
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
|
+
},
|
|
13
|
+
"keywords": ["ai", "agent", "azure", "llm", "biotech", "quantum", "tool-calling", "crowe-logic"],
|
|
14
|
+
"author": {
|
|
15
|
+
"name": "Michael Crowe",
|
|
16
|
+
"email": "michael@crowelogic.com",
|
|
17
|
+
"url": "https://crowelogic.com"
|
|
18
|
+
},
|
|
19
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
20
|
+
"homepage": "https://crowelogic.com",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/MichaelCrowe11/crowe-logic-foundry"
|
|
24
|
+
},
|
|
25
|
+
"type": "commonjs",
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@modelcontextprotocol/sdk": "^1.28.0",
|
|
28
|
+
"@modelcontextprotocol/server-filesystem": "^2026.1.14",
|
|
29
|
+
"@modelcontextprotocol/server-github": "^2025.4.8",
|
|
30
|
+
"@playwright/mcp": "^0.0.68"
|
|
31
|
+
}
|
|
32
|
+
}
|
package/pyproject.toml
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "crowe-logic"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Crowe Logic — Universal AI Agent powered by gpt-oss-120b on Azure AI Foundry"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "Proprietary"}
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Michael Crowe", email = "michael@crowelogic.com"},
|
|
14
|
+
]
|
|
15
|
+
maintainers = [
|
|
16
|
+
{name = "Michael Crowe", email = "michael@crowelogic.com"},
|
|
17
|
+
]
|
|
18
|
+
keywords = ["ai", "agent", "azure", "llm", "biotech", "quantum", "tool-calling", "mycology", "mushroom"]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 3 - Alpha",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"Intended Audience :: Science/Research",
|
|
23
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
24
|
+
"Topic :: Scientific/Engineering :: Bio-Informatics",
|
|
25
|
+
"Programming Language :: Python :: 3.10",
|
|
26
|
+
"Programming Language :: Python :: 3.11",
|
|
27
|
+
"Programming Language :: Python :: 3.12",
|
|
28
|
+
"Operating System :: MacOS",
|
|
29
|
+
"Operating System :: POSIX :: Linux",
|
|
30
|
+
]
|
|
31
|
+
dependencies = [
|
|
32
|
+
"azure-ai-agents>=1.1.0",
|
|
33
|
+
"azure-identity>=1.17.0",
|
|
34
|
+
"click>=8.1.0",
|
|
35
|
+
"rich>=13.0.0",
|
|
36
|
+
"prompt-toolkit>=3.0.0",
|
|
37
|
+
"python-dotenv>=1.0.0",
|
|
38
|
+
"httpx>=0.27.0",
|
|
39
|
+
"beautifulsoup4>=4.12.0",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[project.optional-dependencies]
|
|
43
|
+
quantum = [
|
|
44
|
+
"qiskit>=1.0.0",
|
|
45
|
+
"qiskit-aer>=0.15.0",
|
|
46
|
+
"cirq>=1.4.0",
|
|
47
|
+
"pennylane>=0.39.0",
|
|
48
|
+
"synapse-lang>=2.0.0",
|
|
49
|
+
"synapse-qubit-flow>=1.0.0",
|
|
50
|
+
]
|
|
51
|
+
nvidia = [
|
|
52
|
+
"nvidia-cuda-runtime-cu12",
|
|
53
|
+
"cupy-cuda12x",
|
|
54
|
+
]
|
|
55
|
+
all = [
|
|
56
|
+
"crowe-logic[quantum,nvidia]",
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
[project.urls]
|
|
60
|
+
Homepage = "https://crowelogic.com"
|
|
61
|
+
Repository = "https://github.com/MichaelCrowe11/crowe-logic-foundry"
|
|
62
|
+
|
|
63
|
+
[project.scripts]
|
|
64
|
+
crowe-logic = "cli.crowe_logic:main"
|
|
65
|
+
|
|
66
|
+
[tool.setuptools.packages.find]
|
|
67
|
+
include = ["cli*", "tools*", "config*", "scripts*"]
|
|
68
|
+
|
|
69
|
+
[tool.setuptools.package-data]
|
|
70
|
+
cli = ["icon.png", "icons/*.icns"]
|