-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall.py
More file actions
134 lines (112 loc) · 5.18 KB
/
Copy pathinstall.py
File metadata and controls
134 lines (112 loc) · 5.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
"""
One-shot installer for the Patient Organization Navigator.
Run this from a Claude Science conversation, in the `repl` tool, from the root
of this repository:
exec(open("install.py").read())
It reads the skill and agent definitions in this repo and installs them into
your Claude Science organization via the customize SDK (host.skills.* /
host.agents.*). It is idempotent — safe to re-run; it updates in place.
Requires: a Claude Science `repl` kernel (the `host` object). The figure
renderers also want a conda env with pandas/numpy/matplotlib/seaborn — the
script prints the one tool call to create it (the agent runs that separately,
since environment creation is a tool, not part of this SDK).
"""
import os, json
def _repo_root():
# Prefer cwd if it looks like the repo; else the script's own directory.
for cand in (os.getcwd(), os.path.dirname(os.path.abspath(
globals().get("__file__", "install.py")))):
if os.path.isfile(os.path.join(cand, "agent", "profile.json")):
return cand
raise RuntimeError(
"Cannot find repo root. Run this from the repository root "
"(the folder containing agent/profile.json and skills/).")
_PKGMAP = {"numpy": "numpy", "pandas": "pandas", "matplotlib": "matplotlib",
"seaborn": "seaborn", "scipy": "scipy", "sklearn": "scikit-learn",
"PIL": "pillow", "networkx": "networkx", "requests": "requests",
"yaml": "pyyaml"}
def _env_slug(agent_name):
return agent_name.lower().replace("_", "-")
def _scan_packages(skills_dir):
"""Third-party packages imported by the bundled kernel.py files."""
import re
found = set()
for base, _, files in os.walk(skills_dir):
for f in files:
if f == "kernel.py":
src = open(os.path.join(base, f)).read()
for m in re.findall(r'^\s*(?:import|from)\s+([A-Za-z_][\w]*)',
src, re.M):
if m in _PKGMAP:
found.add(_PKGMAP[m])
return sorted(found) or ["pandas", "numpy", "matplotlib", "seaborn"]
def _put_file(host, skill, path, content):
"""Create the file, or replace it if it already exists (idempotent)."""
try:
host.skills.edit(skill, path, content) # create (fails if exists)
except Exception:
cur = host.skills.read(skill, path)["content"]
if cur != content:
host.skills.edit(skill, path, content, old_string=cur)
def install(host):
root = _repo_root()
skills_dir = os.path.join(root, "skills")
skills = sorted(d for d in os.listdir(skills_dir)
if os.path.isdir(os.path.join(skills_dir, d)))
print("Installing %d skills from %s" % (len(skills), root))
for s in skills:
sd = os.path.join(skills_dir, s)
# Publish EVERY file in the skill dir (SKILL.md, kernel.py, assets/,
# templates/, references/, scripts/, ...), preserving sub-paths.
n = 0
for base, _, files in os.walk(sd):
for f in files:
if f == ".catalog_stamp":
continue
fp = os.path.join(base, f)
rel = os.path.relpath(fp, sd).replace(os.sep, "/")
try:
content = open(fp, encoding="utf-8").read()
except UnicodeDecodeError:
import base64 as _b64
content = _b64.b64encode(open(fp, "rb").read()).decode()
_put_file(host, s, rel, content)
n += 1
host.skills.publish(s, overwrite=True)
print(" published skill: %s (%d files)" % (s, n))
# --- Agent profile ---
prof = json.load(open(os.path.join(root, "agent", "profile.json")))
system_prompt = open(os.path.join(root, "agent", "system_prompt.md")).read()
name = prof["name"]
exists = any(a["name"] == name for a in host.agents.list())
if exists:
host.agents.update(name, {
"display_name": prof["displayName"],
"description": prof["description"],
"system_prompt": system_prompt,
"unrestricted": prof.get("unrestricted", True),
})
print(" updated agent:", name)
else:
# Leave skill_names unset => full catalog + all connectors (unrestricted).
host.agents.create(
name=name,
display_name=prof["displayName"],
description=prof["description"],
system_prompt=system_prompt,
)
print(" created agent:", name, "(full access)")
env = _env_slug(name)
pkgs = _scan_packages(skills_dir)
print("\nDone. The '%s' specialist is now in your agent picker." % prof["displayName"])
print("\nOptional — create its analysis environment (run as a tool call):")
print(" manage_environments(mode='create', name='%s'," % env)
print(" packages=%r, python_version='3.13')" % pkgs)
print("\nThen switch to it: host.agents.switch('%s')" % name)
return name
# Auto-run when exec'd in a repl kernel that has `host`.
if "host" in globals():
install(host) # noqa: F821
else:
print("No `host` found. Run this in the Claude Science `repl` tool:")
print(' exec(open("install.py").read())')