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/requirements.txt
ADDED
|
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
|