Skip to content

Commit 70a6f02

Browse files
jeremymanningclaude
andcommitted
Add a Dartmouth Chat probe workflow, and stop .env being committable
Onboarding rewrites bios with an LLM, and that should go to Dartmouth's own chat.dartmouth.edu rather than a paid third-party API. Before wiring it up, this enumerates what the account can actually reach, so the model is pinned from the live list instead of guessed. The key is a repo secret and secrets are write-only, so a real call can only be made from Actions. The workflow passes it through env rather than an inline ${{ }} and prints only model identifiers, never the key. Also adds .env to .gitignore. It was absent, so a local secrets file in this repo would have been picked up by `git add -A`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RA2V7NZ1hQ4fQSoZcBQgHp
1 parent 4f561d3 commit 70a6f02

2 files changed

Lines changed: 77 additions & 0 deletions

File tree

‎.github/workflows/test-llm-api.yml‎

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
name: Test Dartmouth Chat API
2+
3+
# Onboarding rewrites member bios with an LLM. That call goes to Dartmouth's
4+
# own chat.dartmouth.edu rather than a paid third-party API, so this workflow
5+
# is what proves the key still works, the model we name still exists, and the
6+
# response still has the shape the code unpacks.
7+
#
8+
# Runs on demand, weekly, and whenever the client or its callers change.
9+
# It never prints the key -- only model identifiers and generated text.
10+
11+
on:
12+
push:
13+
branches:
14+
- main
15+
paths:
16+
- 'scripts/dartmouth_chat.py'
17+
- 'scripts/onboard_member.py'
18+
- '.github/workflows/test-llm-api.yml'
19+
workflow_dispatch:
20+
schedule:
21+
# Mondays, 09:30 UTC. Catches a revoked key or a retired model before an
22+
# onboarding run does.
23+
- cron: '30 9 * * 1'
24+
25+
jobs:
26+
probe:
27+
runs-on: ubuntu-latest
28+
timeout-minutes: 15
29+
steps:
30+
- uses: actions/checkout@v4
31+
32+
- name: Set up Python
33+
uses: actions/setup-python@v5
34+
with:
35+
python-version: '3.11'
36+
37+
- name: Install dependencies
38+
run: pip install requests
39+
40+
- name: List the models this account can reach
41+
env:
42+
# Via env, never inline in the script: an inline ${{ }} would be
43+
# substituted into the source before it runs.
44+
DARTMOUTH_CHAT_API_KEY: ${{ secrets.DARTMOUTH_CHAT_API_KEY }}
45+
run: |
46+
python - <<'PY'
47+
import json, os, sys
48+
import requests
49+
50+
key = os.environ.get("DARTMOUTH_CHAT_API_KEY")
51+
if not key:
52+
sys.exit("::error::DARTMOUTH_CHAT_API_KEY is not set")
53+
print(f"key present, {len(key)} chars")
54+
55+
base = "https://chat.dartmouth.edu"
56+
headers = {"Authorization": f"Bearer {key}"}
57+
58+
for path in ("/api/models", "/openai/v1/models"):
59+
r = requests.get(base + path, headers=headers, timeout=60)
60+
print(f"\n=== GET {path} -> {r.status_code} ===")
61+
if r.status_code != 200:
62+
print(" ", r.text[:300])
63+
continue
64+
data = r.json().get("data", [])
65+
print(f" {len(data)} models")
66+
ids = sorted(m.get("id", "?") for m in data)
67+
for i in ids:
68+
print(" ", i)
69+
qwen = [i for i in ids if "qwen" in i.lower()]
70+
print(f"\n QWEN MODELS: {qwen}")
71+
PY

‎.gitignore‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,9 @@ missfont.log
4444
.omc/
4545
.specify/
4646
data/~$publications.xlsx
47+
48+
# Local secrets. onboard_member.py reads DARTMOUTH_CHAT_API_KEY from here;
49+
# it must never be committed.
50+
.env
51+
.env.*
52+
!.env.example

0 commit comments

Comments
 (0)