Skip to content

Commit f398eaa

Browse files
committed
chore: sync remaining workspace changes (refactors, deletions, and config)
1 parent 18922b1 commit f398eaa

236 files changed

Lines changed: 28974 additions & 4928 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agent/rules/HEALTH_GOVERNANCE.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Health Check Governance
2+
3+
## Rule: Every New Module Must Register a Health Check
4+
5+
When adding a new domain module under `backend/src/`, you **MUST**:
6+
7+
1. Create a `health.ts` file co-located with the module
8+
2. Export `checkHealth(env: Env): Promise<HealthStepResult>`
9+
3. Register the check in `backend/src/health/coordinator.ts``CODE_CHECKS` array
10+
4. Assign a `HealthCategory` from the union in `backend/src/health/types.ts`
11+
12+
## Rule: Dynamic Tests via D1
13+
14+
Runtime endpoint monitoring uses the `health_test_definitions` table. CRUD is available at:
15+
16+
- `GET /api/health/tests` — list all
17+
- `POST /api/health/tests` — create (Zod-validated)
18+
- `DELETE /api/health/tests/:id` — remove
19+
20+
## Rule: AI Remediation
21+
22+
Failed health checks automatically receive AI-powered remediation hints via `analyzeFailure()`. These are stored in the `ai_suggestion` column of `health_results`.
23+
24+
## Rule: Cron Schedule
25+
26+
Health suite runs weekly via cron `0 3 * * 0` (Sundays 3AM UTC).
27+
On-demand runs are available via `POST /api/health/run`.
28+
29+
## Rule: Frontend Sync
30+
31+
The frontend at `/health` **must** display all categories defined in `CATEGORY_META` in `Health.tsx`.
32+
When adding a new `HealthCategory` to `types.ts`, also add an entry to the frontend registry.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
description: Run the full health suite and review results
3+
---
4+
5+
# Run Health Suite
6+
7+
// turbo-all
8+
9+
## Steps
10+
11+
1. Trigger the health check via API:
12+
13+
```bash
14+
curl -s -X POST https://core-github-api.126colby.workers.dev/api/health/run \
15+
-H "Content-Type: application/json" \
16+
-H "x-api-key: $API_KEY" | jq .
17+
```
18+
19+
2. Check the latest results:
20+
21+
```bash
22+
curl -s https://core-github-api.126colby.workers.dev/api/health/latest \
23+
-H "x-api-key: $API_KEY" | jq '.results[] | {category, name, status, ai_suggestion}'
24+
```
25+
26+
3. View run history:
27+
28+
```bash
29+
curl -s "https://core-github-api.126colby.workers.dev/api/health/history?limit=5" \
30+
-H "x-api-key: $API_KEY" | jq '.runs[] | {id: .run.id, status: .run.status, created: .run.created_at}'
31+
```
32+
33+
4. List dynamic test definitions:
34+
35+
```bash
36+
curl -s https://core-github-api.126colby.workers.dev/api/health/tests \
37+
-H "x-api-key: $API_KEY" | jq .
38+
```

.github/workflows/daily-trends.yml

Lines changed: 85 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ on:
66

77
jobs:
88
hunt:
9-
name: Fetch Trends & Updates
9+
name: Fetch Trends & Curate via AI
1010
runs-on: ubuntu-latest
1111
steps:
1212
- uses: actions/checkout@v4
@@ -17,54 +17,58 @@ jobs:
1717
python-version: "3.11"
1818

1919
- name: Install dependencies
20-
run: pip install requests pygithub openai
20+
run: pip install requests pygithub litellm pydantic
2121

22-
- name: Run Hunter Script
22+
- name: Run Hunter & AI Curation Script
2323
env:
2424
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
25-
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} # Optional: if you want AI summarization
26-
WORKER_API_URL: "https://core-github-api.hacolby.workers.dev/upsert/daily-trends"
25+
CF_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
26+
CF_GATEWAY_ID: ${{ secrets.CLOUDFLARE_GATEWAY_ID }}
27+
CF_API_TOKEN: ${{ secrets.CLOUDFLARE_AI_GATEWAY_TOKEN }}
28+
WORKER_API_URL: ${{ secrets.WORKER_API_URL_BASE }}/upsert/daily-trends
2729
WORKER_API_KEY: ${{ secrets.WORKER_API_KEY }}
2830
run: |
29-
cat <<EOF > hunter.py
31+
cat << 'EOF' > hunter.py
3032
import os
3133
import requests
3234
import json
3335
from datetime import datetime, timedelta
3436
from github import Github
37+
from pydantic import BaseModel
38+
from litellm import completion
3539
36-
def main():
37-
g = Github(os.environ["GITHUB_TOKEN"])
38-
worker_url = os.environ["WORKER_API_URL"]
39-
worker_secret = os.environ["WORKER_API_KEY"]
40-
41-
# 1. Get User's Existing Stars (to avoid duplicates)
42-
# We optimize by only fetching the IDs
40+
# --- 1. Define the Structured Output Schema ---
41+
class CuratedRepo(BaseModel):
42+
name: str
43+
url: str
44+
category: str
45+
why_its_interesting: str
46+
innovation_score: int
47+
48+
class DailyReport(BaseModel):
49+
trend_summary: str
50+
top_picks: list[CuratedRepo]
51+
52+
def get_raw_trends(g):
53+
# Get User's Existing Stars (to avoid duplicates)
54+
# Note: PyGithub get_starred() can be slow if you have thousands of stars.
4355
me = g.get_user("${{ github.repository_owner }}")
4456
starred_ids = set()
4557
print("Fetching user stars...")
4658
for repo in me.get_starred():
4759
starred_ids.add(repo.id)
4860
49-
# 2. Define Search Queries
5061
date_since = (datetime.now() - timedelta(days=30)).strftime('%Y-%m-%d')
5162
queries = [
5263
f"language:typescript created:>{date_since} sort:stars",
5364
f"language:python created:>{date_since} sort:stars",
5465
f"topic:google-apps-script created:>{date_since}",
5566
f"topic:cloudflare-workers created:>{date_since}"
5667
]
57-
58-
# 3. Define Watched Orgs for "New Releases"
59-
watched_orgs = ["cloudflare", "openai", "google-gemini", "langchain-ai"]
6068
61-
results = {
62-
"date": datetime.now().isoformat(),
63-
"trending": [],
64-
"org_updates": []
65-
}
69+
watched_orgs = ["cloudflare", "openai", "google-gemini", "langchain-ai"]
70+
raw_repos = []
6671
67-
# Execute Searches
6872
print("Scanning for trending repos...")
6973
for q in queries:
7074
repos = g.search_repositories(query=q)
@@ -73,47 +77,83 @@ jobs:
7377
if count >= 10: break # Top 10 per category
7478
if repo.id in starred_ids: continue
7579
76-
results["trending"].append({
80+
raw_repos.append({
7781
"name": repo.full_name,
78-
"description": repo.description,
79-
"stars": repo.stargazers_count,
82+
"description": repo.description or "No description",
8083
"url": repo.html_url,
81-
"language": repo.language,
8284
"category": q.split(" ")[0]
8385
})
8486
count += 1
8587
86-
# Execute Org Watch
8788
print("Scanning watched orgs...")
8889
for org_name in watched_orgs:
8990
try:
9091
org = g.get_organization(org_name)
91-
# check recent repos
9292
for repo in org.get_repos(sort="created", direction="desc"):
9393
if (datetime.now() - repo.created_at).days > 30: break
94-
results["org_updates"].append({
95-
"type": "new_repo",
96-
"org": org_name,
97-
"name": repo.name,
94+
raw_repos.append({
95+
"name": repo.full_name,
96+
"description": repo.description or "No description",
9897
"url": repo.html_url,
99-
"description": repo.description
98+
"category": "org_watch"
10099
})
101100
except Exception as e:
102101
print(f"Skipping {org_name}: {e}")
103102
104-
# 4. Post to Worker
105-
print(f"Found {len(results['trending'])} trending and {len(results['org_updates'])} org updates.")
106-
headers = {
107-
"Content-Type": "application/json",
108-
"X-API-Key": worker_secret,
109-
"User-Agent": "github-actions/hunter"
110-
}
111-
resp = requests.post(worker_url, json=results, headers=headers)
112-
resp.raise_for_status()
113-
print("Successfully uploaded to Worker.")
103+
return raw_repos
104+
105+
def curate_with_ai(raw_repos):
106+
print(f"Sending {len(raw_repos)} repos to Cloudflare AI Gateway for curation...")
107+
108+
api_base = f"https://gateway.ai.cloudflare.com/v1/{os.environ['CF_ACCOUNT_ID']}/{os.environ['CF_GATEWAY_ID']}/workers-ai/v1"
109+
110+
prompt = f"Review the following list of newly created repositories. Select the top 5 most innovative or interesting ones, and provide a brief summary of today's trends.\n\nData: {json.dumps(raw_repos)}"
111+
112+
response = completion(
113+
model="openai/@cf/openai/gpt-oss-120b",
114+
api_base=api_base,
115+
api_key=os.environ["CF_API_TOKEN"],
116+
messages=[
117+
{"role": "system", "content": "You are an expert developer curating daily tech trends. Return ONLY valid JSON matching the requested schema."},
118+
{"role": "user", "content": prompt}
119+
],
120+
response_format=DailyReport,
121+
max_tokens=4096,
122+
extra_body={"reasoning": {"effort": "high"}}
123+
)
124+
125+
return response.choices[0].message.content
126+
127+
def main():
128+
g = Github(os.environ["GITHUB_TOKEN"])
129+
130+
# 1. Fetch raw data from GitHub
131+
raw_repos = get_raw_trends(g)
132+
133+
# 2. Curate using Cloudflare Workers AI + LiteLLM
134+
ai_curated_json_str = curate_with_ai(raw_repos)
135+
136+
# 3. Post to Worker
137+
worker_url = os.environ.get("WORKER_API_URL")
138+
if worker_url:
139+
print("Posting curated trends to Worker API...")
140+
141+
# Parse string to dict to ensure valid JSON payload
142+
payload = json.loads(ai_curated_json_str)
143+
payload["date"] = datetime.now().isoformat()
144+
145+
headers = {
146+
"Content-Type": "application/json",
147+
"X-API-Key": os.environ["WORKER_API_KEY"],
148+
"User-Agent": "github-actions/hunter"
149+
}
150+
151+
resp = requests.post(worker_url, json=payload, headers=headers)
152+
resp.raise_for_status()
153+
print("Successfully uploaded to Worker.")
114154
115155
if __name__ == "__main__":
116156
main()
117157
EOF
118158
119-
python hunter.py
159+
python hunter.py

.github/workflows/deep-research.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,15 @@ jobs:
1616
- name: Run Research Agent
1717
env:
1818
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
19-
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
2019
PAYLOAD: ${{ toJSON(github.event.client_payload) }}
20+
21+
# GitHub & Worker Auth
22+
CF_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
23+
CF_GATEWAY_ID: ${{ secrets.CLOUDFLARE_GATEWAY_ID }}
24+
CF_API_TOKEN: ${{ secrets.CLOUDFLARE_AI_GATEWAY_TOKEN }}
25+
WORKER_API_URL: ${{ secrets.WORKER_API_URL_BASE }}
2126
WORKER_API_KEY: ${{ secrets.WORKER_API_KEY }}
27+
2228
run: |
2329
cat <<EOF > agent.py
2430
import os
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
name: LiteLLM Deep Research Agent
2+
on:
3+
workflow_dispatch:
4+
inputs:
5+
query:
6+
description: 'Research target (e.g., astro shadcn assistant-ui)'
7+
required: true
8+
default: 'astro shadcn assistant-ui'
9+
10+
jobs:
11+
research:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- uses: actions/setup-python@v5
17+
with:
18+
python-version: "3.11"
19+
20+
- name: Install Dependencies
21+
# Install LiteLLM and Pydantic for structured outputs
22+
run: pip install litellm pydantic requests
23+
24+
- name: Run LiteLLM Gateway Agent
25+
env:
26+
# Add these to your GitHub Repo Secrets
27+
CF_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
28+
CF_GATEWAY_ID: ${{ secrets.CLOUDFLARE_GATEWAY_ID }}
29+
CF_API_TOKEN: ${{ secrets.CLOUDFLARE_AI_GATEWAY_TOKEN }}
30+
WORKER_API_URL: ${{ secrets.WORKER_API_URL_BASE }}/upsert/daily-trends
31+
WORKER_API_KEY: ${{ secrets.WORKER_API_KEY }}
32+
QUERY: ${{ github.event.inputs.query }}
33+
run: |
34+
cat << 'EOF' > agent.py
35+
import os
36+
import json
37+
import requests
38+
from pydantic import BaseModel
39+
from litellm import completion
40+
41+
# 1. Define your exact structured output using Pydantic
42+
class RepoAnalysis(BaseModel):
43+
is_relevant: bool
44+
ai_features_found: list[str]
45+
summary: str
46+
confidence_score: float
47+
48+
def main():
49+
account_id = os.environ["CF_ACCOUNT_ID"]
50+
gateway_id = os.environ["CF_GATEWAY_ID"]
51+
api_token = os.environ["CF_API_TOKEN"]
52+
query = os.environ["QUERY"]
53+
54+
# 2. Format the Cloudflare AI Gateway URL
55+
# Note: We use the /workers-ai/v1 endpoint to enable OpenAI compatibility
56+
api_base = f"https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id}/workers-ai/v1"
57+
58+
print(f"Executing Deep Research analysis for: {query}")
59+
60+
# 3. Call the model using LiteLLM
61+
response = completion(
62+
# The 'openai/' prefix tells LiteLLM to treat this custom endpoint exactly like OpenAI
63+
model="openai/@cf/openai/gpt-oss-120b",
64+
api_base=api_base,
65+
api_key=api_token,
66+
messages=[
67+
{"role": "system", "content": "You are a code analyzer. Extract structured data from the provided repository description. You must strictly adhere to the requested JSON schema."},
68+
{"role": "user", "content": f"Analyze this repository based on the search query: '{query}'."}
69+
],
70+
71+
# 4. Enforce Structured Output
72+
# LiteLLM automatically converts this Pydantic class into JSON Schema for Cloudflare
73+
response_format=RepoAnalysis,
74+
75+
# 5. Reasoning Tokens Configuration
76+
# Allocate 4096 tokens and force 'high' effort to simulate a "minimum" reasoning constraint
77+
max_tokens=4096,
78+
extra_body={
79+
"reasoning": {
80+
"effort": "high"
81+
}
82+
}
83+
)
84+
85+
# 6. Extract and validate the response
86+
# The model returns a stringified JSON object matching our Pydantic schema
87+
raw_json_str = response.choices[0].message.content
88+
print("\n--- AI Analysis Result ---")
89+
print(raw_json_str)
90+
91+
# 7. Post the verified data in a batch to your Cloudflare Worker API
92+
worker_url = os.environ.get("WORKER_API_URL")
93+
if worker_url:
94+
print(f"Posting data to Worker API: {worker_url}...")
95+
# We parse it just to ensure it's valid JSON before sending
96+
payload = json.loads(raw_json_str)
97+
98+
requests.post(
99+
worker_url,
100+
json={"query": query, "results": payload},
101+
headers={"X-API-Key": os.environ.get("WORKER_API_KEY", "")}
102+
)
103+
print("Data successfully synced to Worker.")
104+
105+
if __name__ == "__main__":
106+
main()
107+
EOF
108+
109+
python agent.py

0 commit comments

Comments
 (0)