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.
@@ -0,0 +1,11 @@
1
+ azure-ai-agents>=1.1.0
2
+ azure-identity>=1.17.0
3
+ azure-ai-projects>=2.0.0b4
4
+ opentelemetry-sdk
5
+ azure-core-tracing-opentelemetry
6
+ click>=8.1.0
7
+ rich>=13.0.0
8
+ prompt-toolkit>=3.0.0
9
+ python-dotenv>=1.0.0
10
+ httpx>=0.27.0
11
+ beautifulsoup4>=4.12.0
File without changes
@@ -0,0 +1,163 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Crowe Logic Agent — Create & Configure
4
+
5
+ Creates the Crowe Logic agent on Azure AI Foundry with all available tools:
6
+ - Custom function tools (filesystem, shell, browser, search)
7
+ - Code Interpreter (sandboxed Python execution)
8
+ - Bing Grounding (live web search via Azure)
9
+ - File Search (RAG over uploaded documents)
10
+ - Azure AI Search (vector search over knowledge base)
11
+
12
+ Usage:
13
+ python scripts/create_agent.py
14
+ python scripts/create_agent.py --name "crowe-logic-v2" --verbose
15
+ """
16
+
17
+ import os
18
+ import sys
19
+ import json
20
+ import argparse
21
+
22
+ # Add project root to path
23
+ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
24
+
25
+ from azure.ai.agents import AgentsClient
26
+ from azure.ai.agents.models import (
27
+ CodeInterpreterTool,
28
+ FileSearchTool,
29
+ BingGroundingTool,
30
+ AzureAISearchTool,
31
+ AzureAISearchQueryType,
32
+ FunctionTool,
33
+ ToolSet,
34
+ )
35
+ from azure.identity import DefaultAzureCredential
36
+
37
+ from config.agent_config import (
38
+ PROJECT_ENDPOINT,
39
+ MODEL_DEPLOYMENT_NAME,
40
+ SYSTEM_INSTRUCTIONS,
41
+ AGENT_NAME,
42
+ AGENT_VERSION,
43
+ BING_CONNECTION_ID,
44
+ AI_SEARCH_CONNECTION_ID,
45
+ AI_SEARCH_INDEX_NAME,
46
+ )
47
+ from tools import user_functions
48
+
49
+
50
+ def create_agent(name: str = AGENT_NAME, verbose: bool = False):
51
+ """Create the Crowe Logic agent with all available tools."""
52
+
53
+ print(f" Connecting to Azure AI Foundry at {PROJECT_ENDPOINT}")
54
+ client = AgentsClient(
55
+ endpoint=PROJECT_ENDPOINT,
56
+ credential=DefaultAzureCredential(),
57
+ )
58
+
59
+ # Build the toolset with all available tools
60
+ toolset = ToolSet()
61
+
62
+ # 1. Custom function tools (Claude-like local capabilities)
63
+ functions = FunctionTool(user_functions)
64
+ toolset.add(functions)
65
+ print(" Added custom function tools (filesystem, shell, browser, search)")
66
+
67
+ # 2. Code Interpreter (sandboxed Python)
68
+ code_interpreter = CodeInterpreterTool()
69
+ toolset.add(code_interpreter)
70
+ print(" Added Code Interpreter")
71
+
72
+ # Enable auto-execution of function calls
73
+ client.enable_auto_function_calls(toolset)
74
+
75
+ # Build additional tools list (for tools that use tools+tool_resources pattern)
76
+ extra_tools = []
77
+ extra_resources = {}
78
+
79
+ # 3. Bing Grounding (web search via Azure connection)
80
+ if BING_CONNECTION_ID:
81
+ bing = BingGroundingTool(connection_id=BING_CONNECTION_ID)
82
+ extra_tools.extend(bing.definitions)
83
+ print(f" Added Bing Grounding (connection: {BING_CONNECTION_ID[:20]}...)")
84
+ else:
85
+ print(" Skipped Bing Grounding (no AZURE_BING_CONNECTION_ID set)")
86
+
87
+ # 4. Azure AI Search (vector search over knowledge base)
88
+ if AI_SEARCH_CONNECTION_ID:
89
+ ai_search = AzureAISearchTool(
90
+ index_connection_id=AI_SEARCH_CONNECTION_ID,
91
+ index_name=AI_SEARCH_INDEX_NAME,
92
+ query_type=AzureAISearchQueryType.SEMANTIC,
93
+ top_k=5,
94
+ )
95
+ extra_tools.extend(ai_search.definitions)
96
+ if hasattr(ai_search, "resources") and ai_search.resources:
97
+ extra_resources.update(ai_search.resources)
98
+ print(f" Added Azure AI Search (index: {AI_SEARCH_INDEX_NAME})")
99
+ else:
100
+ print(" Skipped Azure AI Search (no AI_AZURE_AI_CONNECTION_ID set)")
101
+
102
+ # Create the agent
103
+ print(f"\n Creating agent '{name}' with model '{MODEL_DEPLOYMENT_NAME}'...")
104
+
105
+ create_kwargs = dict(
106
+ model=MODEL_DEPLOYMENT_NAME,
107
+ name=name,
108
+ instructions=SYSTEM_INSTRUCTIONS,
109
+ toolset=toolset,
110
+ )
111
+
112
+ # Add extra tools if any connection-based tools were configured
113
+ if extra_tools:
114
+ create_kwargs["tools"] = extra_tools
115
+ if extra_resources:
116
+ create_kwargs["tool_resources"] = extra_resources
117
+
118
+ agent = client.create_agent(**create_kwargs)
119
+
120
+ print(f"\n Agent created successfully!")
121
+ print(f" Agent ID: {agent.id}")
122
+ print(f" Agent Name: {agent.name}")
123
+ print(f" Model: {agent.model}")
124
+
125
+ # Save agent ID for CLI use
126
+ agent_file = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".agent_id")
127
+ with open(agent_file, "w") as f:
128
+ json.dump({"agent_id": agent.id, "name": name, "version": AGENT_VERSION, "model": MODEL_DEPLOYMENT_NAME}, f, indent=2)
129
+ print(f" Saved agent ID to .agent_id")
130
+
131
+ if verbose:
132
+ print(f"\n Full agent config:")
133
+ print(f" Instructions: {SYSTEM_INSTRUCTIONS[:200]}...")
134
+ print(f" Tools: {[t.__class__.__name__ for t in [functions, code_interpreter]]}")
135
+
136
+ return agent
137
+
138
+
139
+ def main():
140
+ parser = argparse.ArgumentParser(description="Create the Crowe Logic agent on Azure AI Foundry")
141
+ parser.add_argument("--name", default=AGENT_NAME, help="Agent name")
142
+ parser.add_argument("--verbose", "-v", action="store_true", help="Verbose output")
143
+ args = parser.parse_args()
144
+
145
+ print(f"\n{'='*60}")
146
+ print(f" CROWE LOGIC AGENT — CREATE")
147
+ print(f" Version {AGENT_VERSION}")
148
+ print(f"{'='*60}\n")
149
+
150
+ try:
151
+ agent = create_agent(name=args.name, verbose=args.verbose)
152
+ print(f"\n{'='*60}")
153
+ print(f" READY — Run: crowe-logic chat")
154
+ print(f"{'='*60}\n")
155
+ except Exception as e:
156
+ print(f"\n ERROR: {e}")
157
+ print(f" Make sure you've run: az login")
158
+ print(f" And set PROJECT_ENDPOINT in .env")
159
+ sys.exit(1)
160
+
161
+
162
+ if __name__ == "__main__":
163
+ main()
@@ -0,0 +1,271 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Crowe Logic Agent — Fine-Tuning Pipeline
4
+
5
+ Converts CroweLM unified datasets to Azure AI Foundry format and
6
+ initiates fine-tuning of gpt-oss-120b with domain knowledge:
7
+ - Biotech / Pharma / Drug Discovery
8
+ - Mycology / Mushroom Cultivation
9
+ - Molecular Biology / Gene/RNA/Protein
10
+ - Scientific Coding / Reasoning
11
+
12
+ Usage:
13
+ python scripts/fine_tune.py convert # Convert datasets to Azure format
14
+ python scripts/fine_tune.py upload # Upload to Azure AI Foundry
15
+ python scripts/fine_tune.py train # Start fine-tuning job
16
+ python scripts/fine_tune.py status # Check training status
17
+ python scripts/fine_tune.py pipeline # Run full pipeline
18
+ """
19
+
20
+ import os
21
+ import sys
22
+ import json
23
+ import argparse
24
+ from pathlib import Path
25
+
26
+ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
27
+
28
+ from config.agent_config import PROJECT_ENDPOINT, MODEL_DEPLOYMENT_NAME
29
+
30
+ # Dataset paths
31
+ DATA_DIR = Path(__file__).parent.parent / "data"
32
+ CROWELM_UNIFIED = DATA_DIR / "crowelm-unified"
33
+ CROWELM_BIOTECH = DATA_DIR / "crowelm-biotech"
34
+ OUTPUT_DIR = DATA_DIR / "azure-ft"
35
+
36
+
37
+ def convert_nemo_sft_to_openai(input_path: Path, output_path: Path, max_samples: int = 0):
38
+ """
39
+ Convert NeMo SFT JSONL to OpenAI chat completion format for Azure fine-tuning.
40
+
41
+ NeMo SFT format:
42
+ {"conversations": [{"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}]}
43
+
44
+ Azure/OpenAI format:
45
+ {"messages": [{"role": "system", "content": "..."}, {"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}]}
46
+ """
47
+ print(f" Converting: {input_path.name}")
48
+
49
+ system_msg = {
50
+ "role": "system",
51
+ "content": (
52
+ "You are CroweLM, an expert AI assistant specializing in biotech, "
53
+ "pharmaceutical science, mycology, mushroom cultivation, molecular biology, "
54
+ "drug discovery, and scientific research. You provide accurate, detailed, "
55
+ "and actionable information grounded in scientific literature and practical experience. "
56
+ "Created by Crowe Logic, Inc."
57
+ )
58
+ }
59
+
60
+ converted = 0
61
+ skipped = 0
62
+ output_path.parent.mkdir(parents=True, exist_ok=True)
63
+
64
+ with open(input_path, "r", encoding="utf-8") as fin, \
65
+ open(output_path, "w", encoding="utf-8") as fout:
66
+ for line in fin:
67
+ if max_samples and converted >= max_samples:
68
+ break
69
+ try:
70
+ entry = json.loads(line.strip())
71
+
72
+ # Handle different input formats
73
+ messages = [system_msg]
74
+
75
+ if "conversations" in entry:
76
+ # NeMo SFT format
77
+ for turn in entry["conversations"]:
78
+ role = turn.get("role", turn.get("from", "user"))
79
+ content = turn.get("content", turn.get("value", ""))
80
+ if role in ("human", "user"):
81
+ messages.append({"role": "user", "content": content})
82
+ elif role in ("gpt", "assistant", "model"):
83
+ messages.append({"role": "assistant", "content": content})
84
+
85
+ elif "instruction" in entry and "output" in entry:
86
+ # Instruction format
87
+ user_content = entry["instruction"]
88
+ if entry.get("input"):
89
+ user_content += f"\n\n{entry['input']}"
90
+ messages.append({"role": "user", "content": user_content})
91
+ messages.append({"role": "assistant", "content": entry["output"]})
92
+
93
+ elif "question" in entry and "answer" in entry:
94
+ # QA format
95
+ messages.append({"role": "user", "content": entry["question"]})
96
+ messages.append({"role": "assistant", "content": entry["answer"]})
97
+
98
+ elif "text" in entry:
99
+ # Pretraining text — wrap as a knowledge entry
100
+ messages.append({"role": "user", "content": "Explain the following topic in detail."})
101
+ messages.append({"role": "assistant", "content": entry["text"]})
102
+
103
+ else:
104
+ skipped += 1
105
+ continue
106
+
107
+ # Validate: must have at least system + user + assistant
108
+ if len(messages) >= 3:
109
+ fout.write(json.dumps({"messages": messages}, ensure_ascii=False) + "\n")
110
+ converted += 1
111
+ else:
112
+ skipped += 1
113
+
114
+ except (json.JSONDecodeError, KeyError):
115
+ skipped += 1
116
+
117
+ print(f" Converted: {converted:,} | Skipped: {skipped:,}")
118
+ return converted
119
+
120
+
121
+ def cmd_convert(args):
122
+ """Convert all CroweLM datasets to Azure fine-tuning format."""
123
+ print(f"\n{'='*60}")
124
+ print(f" DATASET CONVERSION — CroweLM → Azure FT Format")
125
+ print(f"{'='*60}\n")
126
+
127
+ total = 0
128
+
129
+ # Find all JSONL files in the unified dataset
130
+ jsonl_files = list(CROWELM_UNIFIED.rglob("*.jsonl"))
131
+ if not jsonl_files:
132
+ print(" No JSONL files found in data/crowelm-unified/")
133
+ print(" Looking in Azure blob storage...")
134
+ # Try downloading from Azure
135
+ print(" Run: az storage blob download-batch --account-name crowelmdata7595 --source nvidia-curated-datasets -d data/crowelm-unified/")
136
+ return
137
+
138
+ for jsonl_file in sorted(jsonl_files):
139
+ output_name = f"azure_ft_{jsonl_file.stem}.jsonl"
140
+ output_path = OUTPUT_DIR / output_name
141
+ count = convert_nemo_sft_to_openai(
142
+ jsonl_file, output_path,
143
+ max_samples=args.max_samples if hasattr(args, 'max_samples') else 0
144
+ )
145
+ total += count
146
+
147
+ print(f"\n Total converted: {total:,} samples")
148
+ print(f" Output directory: {OUTPUT_DIR}")
149
+
150
+ # Create a merged training file
151
+ merged_path = OUTPUT_DIR / "crowelm_merged_train.jsonl"
152
+ print(f"\n Merging all files into: {merged_path.name}")
153
+ with open(merged_path, "w") as fout:
154
+ for ft_file in sorted(OUTPUT_DIR.glob("azure_ft_*.jsonl")):
155
+ with open(ft_file) as fin:
156
+ for line in fin:
157
+ fout.write(line)
158
+
159
+ line_count = sum(1 for _ in open(merged_path))
160
+ print(f" Merged file: {line_count:,} samples")
161
+
162
+
163
+ def cmd_upload(args):
164
+ """Upload converted dataset to Azure AI Foundry."""
165
+ print(f"\n{'='*60}")
166
+ print(f" DATASET UPLOAD — Azure AI Foundry")
167
+ print(f"{'='*60}\n")
168
+
169
+ from azure.ai.agents import AgentsClient
170
+ from azure.ai.agents.models import FilePurpose
171
+ from azure.identity import DefaultAzureCredential
172
+
173
+ merged_path = OUTPUT_DIR / "crowelm_merged_train.jsonl"
174
+ if not merged_path.exists():
175
+ print(" ERROR: Run 'convert' first to generate the training file.")
176
+ return
177
+
178
+ client = AgentsClient(
179
+ endpoint=PROJECT_ENDPOINT,
180
+ credential=DefaultAzureCredential(),
181
+ )
182
+
183
+ print(f" Uploading: {merged_path.name}")
184
+ file = client.files.upload_and_poll(
185
+ file_path=str(merged_path),
186
+ purpose=FilePurpose.AGENTS,
187
+ )
188
+ print(f" Uploaded! File ID: {file.id}")
189
+
190
+ # Save file ID for training
191
+ meta_path = OUTPUT_DIR / "upload_meta.json"
192
+ with open(meta_path, "w") as f:
193
+ json.dump({"file_id": file.id, "filename": merged_path.name}, f, indent=2)
194
+ print(f" Saved metadata to: {meta_path}")
195
+
196
+
197
+ def cmd_train(args):
198
+ """Start fine-tuning job on Azure (placeholder — requires Azure ML or OpenAI FT API)."""
199
+ print(f"\n{'='*60}")
200
+ print(f" FINE-TUNING — gpt-oss-120b + CroweLM Data")
201
+ print(f"{'='*60}\n")
202
+
203
+ print(" NOTE: gpt-oss-120b fine-tuning options:")
204
+ print()
205
+ print(" 1. Azure AI Foundry Managed Fine-Tuning:")
206
+ print(" az ml job create --file training_config.yaml")
207
+ print()
208
+ print(" 2. Self-hosted via vLLM + LoRA (RunPod / local H100):")
209
+ print(" See data/crowelm-unified/RUNPOD_TRAINING_GUIDE.md")
210
+ print()
211
+ print(" 3. HuggingFace Transformers + PEFT:")
212
+ print(" python scripts/hf_fine_tune.py")
213
+ print()
214
+
215
+ merged_path = OUTPUT_DIR / "crowelm_merged_train.jsonl"
216
+ if merged_path.exists():
217
+ line_count = sum(1 for _ in open(merged_path))
218
+ size_mb = merged_path.stat().st_size / (1024 * 1024)
219
+ print(f" Dataset ready: {line_count:,} samples ({size_mb:.1f} MB)")
220
+ else:
221
+ print(" Dataset not converted yet. Run: python scripts/fine_tune.py convert")
222
+
223
+
224
+ def cmd_status(args):
225
+ """Check fine-tuning job status."""
226
+ meta_path = OUTPUT_DIR / "upload_meta.json"
227
+ if meta_path.exists():
228
+ with open(meta_path) as f:
229
+ meta = json.load(f)
230
+ print(f" Uploaded file: {meta.get('file_id', 'unknown')}")
231
+ else:
232
+ print(" No upload metadata found.")
233
+
234
+
235
+ def cmd_pipeline(args):
236
+ """Run full pipeline: convert → upload."""
237
+ cmd_convert(args)
238
+ cmd_upload(args)
239
+ cmd_train(args)
240
+
241
+
242
+ def main():
243
+ parser = argparse.ArgumentParser(description="CroweLM Fine-Tuning Pipeline")
244
+ sub = parser.add_subparsers(dest="command")
245
+
246
+ p_convert = sub.add_parser("convert", help="Convert datasets to Azure format")
247
+ p_convert.add_argument("--max-samples", type=int, default=0, help="Limit samples (0=all)")
248
+
249
+ sub.add_parser("upload", help="Upload to Azure AI Foundry")
250
+ sub.add_parser("train", help="Start fine-tuning")
251
+ sub.add_parser("status", help="Check status")
252
+ sub.add_parser("pipeline", help="Full pipeline")
253
+
254
+ args = parser.parse_args()
255
+
256
+ if not args.command:
257
+ parser.print_help()
258
+ return
259
+
260
+ commands = {
261
+ "convert": cmd_convert,
262
+ "upload": cmd_upload,
263
+ "train": cmd_train,
264
+ "status": cmd_status,
265
+ "pipeline": cmd_pipeline,
266
+ }
267
+ commands[args.command](args)
268
+
269
+
270
+ if __name__ == "__main__":
271
+ main()
@@ -0,0 +1,15 @@
1
+ #!/bin/bash
2
+ # Quick npm publish with live OTP input
3
+ cd ~/Projects/crowe-logic-foundry
4
+ echo ""
5
+ echo "=== CROWE LOGIC — npm Publish ==="
6
+ echo ""
7
+ read -p "Enter your authenticator OTP code: " otp
8
+ npm publish --access public --otp="$otp"
9
+ if [ $? -eq 0 ]; then
10
+ echo ""
11
+ echo "Published! https://www.npmjs.com/package/crowe-logic"
12
+ else
13
+ echo ""
14
+ echo "Failed — try again with: bash scripts/npm-publish.sh"
15
+ fi
@@ -0,0 +1,162 @@
1
+ -- ============================================================
2
+ -- Crowe Logic Agent — macOS AppleScript Orchestrator
3
+ -- ============================================================
4
+ -- One-click automation for agent development workflow:
5
+ -- 1. Deploy/update the agent on Azure AI Foundry
6
+ -- 2. Launch interactive chat in Terminal
7
+ -- 3. Open Azure dashboard for monitoring
8
+ -- 4. Run test suite
9
+ -- 5. Full pipeline (deploy + test + chat)
10
+ --
11
+ -- Usage:
12
+ -- osascript scripts/orchestrator.applescript deploy
13
+ -- osascript scripts/orchestrator.applescript chat
14
+ -- osascript scripts/orchestrator.applescript dashboard
15
+ -- osascript scripts/orchestrator.applescript test
16
+ -- osascript scripts/orchestrator.applescript pipeline
17
+ -- osascript scripts/orchestrator.applescript (shows menu)
18
+ -- ============================================================
19
+
20
+ property projectPath : "/Users/crowelogic/Projects/crowe-logic-foundry"
21
+ property venvPath : "/Users/crowelogic/Projects/crowe-logic-foundry/.venv"
22
+ property azureDashboard : "https://ai.azure.com/nextgen/r/mVYda6I5Q7uWtGK2g4Co8A,rg-crowelogicos-7858,,crowelogicos-7858-resource,crowelogicos-7858/build/agents/crowe-logic/build"
23
+ property pythonCmd : "source .venv/bin/activate 2>/dev/null || true && python3"
24
+
25
+ -- ============================================================
26
+ -- MAIN ENTRY POINT
27
+ -- ============================================================
28
+
29
+ on run argv
30
+ if (count of argv) > 0 then
31
+ set action to item 1 of argv
32
+ else
33
+ set action to showMenu()
34
+ end if
35
+
36
+ if action is "deploy" then
37
+ doDeployAgent()
38
+ else if action is "chat" then
39
+ doLaunchChat()
40
+ else if action is "dashboard" then
41
+ doOpenDashboard()
42
+ else if action is "test" then
43
+ doRunTests()
44
+ else if action is "pipeline" then
45
+ doFullPipeline()
46
+ else if action is "setup" then
47
+ doInitialSetup()
48
+ else if action is "status" then
49
+ doShowStatus()
50
+ else
51
+ display dialog "Unknown action: " & action buttons {"OK"} default button "OK" with icon caution
52
+ end if
53
+ end run
54
+
55
+ -- ============================================================
56
+ -- MENU
57
+ -- ============================================================
58
+
59
+ on showMenu()
60
+ set menuItems to {"Deploy Agent", "Launch Chat", "Open Azure Dashboard", "Run Tests", "Full Pipeline (Deploy + Test + Chat)", "Initial Setup", "Show Status"}
61
+ set menuActions to {"deploy", "chat", "dashboard", "test", "pipeline", "setup", "status"}
62
+
63
+ set chosen to choose from list menuItems with prompt "Crowe Logic Agent — Choose Action:" with title "Crowe Logic" default items {"Launch Chat"}
64
+
65
+ if chosen is false then
66
+ error number -128 -- User cancelled
67
+ end if
68
+
69
+ set chosenItem to item 1 of chosen
70
+ repeat with i from 1 to count of menuItems
71
+ if item i of menuItems is chosenItem then
72
+ return item i of menuActions
73
+ end if
74
+ end repeat
75
+
76
+ return "chat"
77
+ end showMenu
78
+
79
+ -- ============================================================
80
+ -- ACTIONS
81
+ -- ============================================================
82
+
83
+ on doInitialSetup()
84
+ display notification "Setting up Crowe Logic..." with title "Crowe Logic"
85
+
86
+ runInTerminal("cd " & quoted form of projectPath & " && " & ¬
87
+ "python3 -m venv .venv && " & ¬
88
+ "source .venv/bin/activate && " & ¬
89
+ "pip install -r requirements.txt && " & ¬
90
+ "pip install -e . && " & ¬
91
+ "echo '' && echo '========================================' && " & ¬
92
+ "echo ' Setup complete!' && " & ¬
93
+ "echo ' Next: cp .env.example .env && edit .env' && " & ¬
94
+ "echo ' Then: crowe-logic deploy' && " & ¬
95
+ "echo '========================================'")
96
+
97
+ display notification "Setup complete! Edit .env next." with title "Crowe Logic"
98
+ end doInitialSetup
99
+
100
+ on doDeployAgent()
101
+ display notification "Deploying Crowe Logic agent..." with title "Crowe Logic"
102
+
103
+ runInTerminal("cd " & quoted form of projectPath & " && " & ¬
104
+ pythonCmd & " scripts/create_agent.py --verbose")
105
+
106
+ display notification "Agent deployed successfully!" with title "Crowe Logic" sound name "Glass"
107
+ end doDeployAgent
108
+
109
+ on doLaunchChat()
110
+ runInTerminal("cd " & quoted form of projectPath & " && " & ¬
111
+ pythonCmd & " -m cli.crowe_logic chat")
112
+ end doLaunchChat
113
+
114
+ on doOpenDashboard()
115
+ open location azureDashboard
116
+ display notification "Azure AI Foundry dashboard opened" with title "Crowe Logic"
117
+ end doOpenDashboard
118
+
119
+ on doRunTests()
120
+ display notification "Running agent tests..." with title "Crowe Logic"
121
+
122
+ runInTerminal("cd " & quoted form of projectPath & " && " & ¬
123
+ pythonCmd & " scripts/test_agent.py")
124
+ end doRunTests
125
+
126
+ on doFullPipeline()
127
+ display notification "Starting full pipeline..." with title "Crowe Logic"
128
+
129
+ -- Step 1: Deploy
130
+ runInTerminal("cd " & quoted form of projectPath & " && " & ¬
131
+ pythonCmd & " scripts/create_agent.py && " & ¬
132
+ "echo '' && echo 'Agent deployed. Running tests...' && " & ¬
133
+ "echo '' && " & ¬
134
+ pythonCmd & " scripts/test_agent.py && " & ¬
135
+ "echo '' && echo '========================================' && " & ¬
136
+ "echo ' Pipeline complete! Starting chat...' && " & ¬
137
+ "echo '========================================' && " & ¬
138
+ "echo '' && " & ¬
139
+ pythonCmd & " -m cli.crowe_logic chat")
140
+
141
+ -- Step 2: Open dashboard in background
142
+ delay 2
143
+ open location azureDashboard
144
+
145
+ display notification "Pipeline complete!" with title "Crowe Logic" sound name "Glass"
146
+ end doFullPipeline
147
+
148
+ on doShowStatus()
149
+ runInTerminal("cd " & quoted form of projectPath & " && " & ¬
150
+ pythonCmd & " -m cli.crowe_logic status")
151
+ end doShowStatus
152
+
153
+ -- ============================================================
154
+ -- HELPERS
155
+ -- ============================================================
156
+
157
+ on runInTerminal(cmd)
158
+ tell application "Terminal"
159
+ activate
160
+ do script cmd
161
+ end tell
162
+ end runInTerminal