Auto: 2 files | 2 files changed, 71 insertions(+), 45 deletions(-)

This commit is contained in:
m3taversal 2026-03-10 12:03:40 +00:00
parent b1dafa2ca8
commit 1c6aab23bc
2 changed files with 71 additions and 45 deletions

View file

@ -42,7 +42,8 @@ if [ -f "$LOCKFILE" ]; then
rm -f "$LOCKFILE" rm -f "$LOCKFILE"
fi fi
echo $$ > "$LOCKFILE" echo $$ > "$LOCKFILE"
trap 'rm -f "$LOCKFILE"' EXIT TWEET_FILE="/tmp/research-tweets-${AGENT}.md"
trap 'rm -f "$LOCKFILE" "$TWEET_FILE"' EXIT
log "=== Starting research session for $AGENT ===" log "=== Starting research session for $AGENT ==="
@ -91,7 +92,14 @@ for acct in data.get('accounts', []):
" 2>/dev/null || true) " 2>/dev/null || true)
TWEET_DATA="" TWEET_DATA=""
API_CALLS=0
API_CACHED=0
for USERNAME in $ACCOUNTS; do for USERNAME in $ACCOUNTS; do
# Validate username (Twitter handles are alphanumeric + underscore only)
if [[ ! "$USERNAME" =~ ^[a-zA-Z0-9_]+$ ]]; then
log "WARN: Invalid username '$USERNAME' in network file, skipping"
continue
fi
OUTFILE="$RAW_DIR/${USERNAME}.json" OUTFILE="$RAW_DIR/${USERNAME}.json"
# Only pull if file doesn't exist or is older than 12 hours # Only pull if file doesn't exist or is older than 12 hours
if [ ! -f "$OUTFILE" ] || [ $(find "$OUTFILE" -mmin +720 2>/dev/null | wc -l) -gt 0 ]; then if [ ! -f "$OUTFILE" ] || [ $(find "$OUTFILE" -mmin +720 2>/dev/null | wc -l) -gt 0 ]; then
@ -102,7 +110,10 @@ for acct in data.get('accounts', []):
log "WARN: Failed to pull @${USERNAME}" log "WARN: Failed to pull @${USERNAME}"
continue continue
} }
API_CALLS=$((API_CALLS + 1))
sleep 2 # Rate limit courtesy sleep 2 # Rate limit courtesy
else
API_CACHED=$((API_CACHED + 1))
fi fi
if [ -f "$OUTFILE" ]; then if [ -f "$OUTFILE" ]; then
TWEET_DATA="${TWEET_DATA} TWEET_DATA="${TWEET_DATA}
@ -125,6 +136,14 @@ except Exception as e:
" 2>/dev/null || echo "(failed to parse)")" " 2>/dev/null || echo "(failed to parse)")"
fi fi
done done
log "API usage: ${API_CALLS} calls, ${API_CACHED} cached for ${AGENT}"
# Append to cumulative usage log (create with header if new)
USAGE_CSV="/opt/teleo-eval/logs/x-api-usage.csv"
if [ ! -f "$USAGE_CSV" ]; then
echo "date,agent,api_calls,cached,accounts_total" > "$USAGE_CSV"
fi
ACCOUNT_COUNT=$(echo "$ACCOUNTS" | wc -w | tr -d ' ')
echo "${DATE},${AGENT},${API_CALLS},${API_CACHED},${ACCOUNT_COUNT}" >> "$USAGE_CSV"
fi fi
# --- Also check for any raw JSON dumps in inbox-raw --- # --- Also check for any raw JSON dumps in inbox-raw ---
@ -161,7 +180,6 @@ log "On branch $BRANCH"
# --- Build the research prompt --- # --- Build the research prompt ---
# Write tweet data to a temp file so Claude can read it # Write tweet data to a temp file so Claude can read it
TWEET_FILE="/tmp/research-tweets-${AGENT}.md"
echo "$TWEET_DATA" > "$TWEET_FILE" echo "$TWEET_DATA" > "$TWEET_FILE"
RESEARCH_PROMPT="You are ${AGENT}, a Teleo knowledge base agent. Domain: ${DOMAIN}. RESEARCH_PROMPT="You are ${AGENT}, a Teleo knowledge base agent. Domain: ${DOMAIN}.
@ -295,9 +313,7 @@ if [ -z "$CHANGED_FILES" ]; then
exit 0 exit 0
fi fi
# --- Stage and commit if Claude didn't already --- # --- Stage and commit ---
if ! git log --oneline -1 | grep -q "research session"; then
# Claude didn't commit — do it manually
git add inbox/archive/ agents/${AGENT}/musings/ agents/${AGENT}/research-journal.md 2>/dev/null || true git add inbox/archive/ agents/${AGENT}/musings/ agents/${AGENT}/research-journal.md 2>/dev/null || true
if git diff --cached --quiet; then if git diff --cached --quiet; then
@ -311,31 +327,41 @@ if ! git log --oneline -1 | grep -q "research session"; then
git commit -m "${AGENT}: research session ${DATE}${SOURCE_COUNT} sources archived git commit -m "${AGENT}: research session ${DATE}${SOURCE_COUNT} sources archived
Pentagon-Agent: ${AGENT_UPPER} <HEADLESS>" >> "$LOG" 2>&1 Pentagon-Agent: ${AGENT_UPPER} <HEADLESS>" >> "$LOG" 2>&1
fi
# --- Push --- # --- Push ---
git push -u origin "$BRANCH" --force >> "$LOG" 2>&1 git push -u origin "$BRANCH" --force >> "$LOG" 2>&1
log "Pushed $BRANCH" log "Pushed $BRANCH"
# --- Check for existing PR on this branch ---
EXISTING_PR=$(curl -s "${FORGEJO_URL}/api/v1/repos/teleo/teleo-codex/pulls?state=open" \
-H "Authorization: token $AGENT_TOKEN" \
| jq -r ".[] | select(.head.ref == \"$BRANCH\") | .number" 2>/dev/null)
if [ -n "$EXISTING_PR" ]; then
log "PR already exists for $BRANCH (#$EXISTING_PR), skipping creation"
else
# --- Open PR --- # --- Open PR ---
PR_JSON=$(python3 -c " PR_JSON=$(jq -n \
import json --arg title "${AGENT}: research session ${DATE}" \
data = { --arg body "## Self-Directed Research
'title': '${AGENT}: research session ${DATE}',
'body': '## Self-Directed Research\\n\\nAutomated research session for ${AGENT} (${DOMAIN}).\\n\\nSources archived with status: unprocessed — extract cron will handle claim extraction separately.\\n\\nResearcher and extractor are different Claude instances to prevent motivated reasoning.', Automated research session for ${AGENT} (${DOMAIN}).
'base': 'main',
'head': '${BRANCH}' Sources archived with status: unprocessed — extract cron will handle claim extraction separately.
}
print(json.dumps(data)) Researcher and extractor are different Claude instances to prevent motivated reasoning." \
") --arg base "main" \
--arg head "$BRANCH" \
'{title: $title, body: $body, base: $base, head: $head}')
PR_RESULT=$(curl -s -X POST "${FORGEJO_URL}/api/v1/repos/teleo/teleo-codex/pulls" \ PR_RESULT=$(curl -s -X POST "${FORGEJO_URL}/api/v1/repos/teleo/teleo-codex/pulls" \
-H "Authorization: token $AGENT_TOKEN" \ -H "Authorization: token $AGENT_TOKEN" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d "$PR_JSON" 2>&1) -d "$PR_JSON" 2>&1)
PR_NUMBER=$(echo "$PR_RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('number','unknown'))" 2>/dev/null || echo "unknown") PR_NUMBER=$(echo "$PR_RESULT" | jq -r '.number // "unknown"' 2>/dev/null || echo "unknown")
log "PR #${PR_NUMBER} opened for ${AGENT}'s research session" log "PR #${PR_NUMBER} opened for ${AGENT}'s research session"
fi
# --- Back to main --- # --- Back to main ---
git checkout main >> "$LOG" 2>&1 git checkout main >> "$LOG" 2>&1

View file

@ -29,34 +29,34 @@ This mirrors our proposer-evaluator separation for claims, applied one layer ear
│ Pull tweets │ │ Read archives │ │ Review claims │ │ Pull tweets │ │ Read archives │ │ Review claims │
│ Pick 1 task │ │ Extract claims │ │ Approve/reject │ │ Pick 1 task │ │ Extract claims │ │ Approve/reject │
│ Archive sources │ │ Open PR │ │ Merge │ │ Archive sources │ │ Open PR │ │ Merge │
│ Push to main │ │ │ │ │ │ Push branch+PR │ │ │ │ │
└─────────────────┘ └──────────────────┘ └─────────────────┘ └─────────────────┘ └──────────────────┘ └─────────────────┘
``` ```
### Research Cron: `research-daily.sh` ### Research Cron: `research-session.sh`
**Schedule:** Once daily, staggered across agents to respect rate limits **Schedule:** Once daily, staggered across agents to respect rate limits
``` ```
# Stagger: each agent gets a 30-min window # Stagger: each agent gets a 90-min window, overnight PST (10pm-7am)
0 2 * * * /opt/teleo-eval/research-daily.sh rio 0 22 * * * /opt/teleo-eval/research-session.sh rio
30 2 * * * /opt/teleo-eval/research-daily.sh clay 30 23 * * * /opt/teleo-eval/research-session.sh clay
0 3 * * * /opt/teleo-eval/research-daily.sh theseus 0 1 * * * /opt/teleo-eval/research-session.sh theseus
30 3 * * * /opt/teleo-eval/research-daily.sh vida 30 2 * * * /opt/teleo-eval/research-session.sh vida
0 4 * * * /opt/teleo-eval/research-daily.sh astra 0 4 * * * /opt/teleo-eval/research-session.sh astra
30 4 * * * /opt/teleo-eval/research-daily.sh leo 30 5 * * * /opt/teleo-eval/research-session.sh leo
``` ```
**Per agent, the research session:** **Per agent, the research session (~90 min):**
1. Pull latest tweets from agent's network accounts (X API) 1. Pull latest tweets from agent's network accounts (X API)
2. Read the agent's beliefs, recent claims, open positions 2. Read the agent's beliefs, recent claims, open positions
3. Claude prompt: "You are {agent}. Here are your latest tweets from {accounts}. Here is your current knowledge state. Pick ONE research direction that advances your domain understanding. Archive the most relevant sources with notes." 3. Claude prompt: "You are {agent}. Here are your latest tweets from {accounts}. Here is your current knowledge state. Pick ONE research direction that advances your domain understanding. Archive the most relevant sources with notes."
4. Agent writes source archives to `inbox/archive/` with `status: unprocessed` 4. Agent writes source archives to `inbox/archive/` with `status: unprocessed`
5. Commit and push to main (source-only, no claims) 5. Commit, push to branch, open PR (source-only, no claims)
6. Extract cron picks them up within 5 minutes 6. Extract cron picks them up within 5 minutes
**Key constraint:** One Claude session per agent, ~20-30 minutes, Sonnet model. Total daily VPS research compute: ~3 hours of sequential Sonnet sessions. **Key constraint:** One Claude session per agent, ~90 minutes, Sonnet model. Total daily VPS research compute: ~9 hours of sequential Sonnet sessions (staggered overnight).
### Research Prompt Structure ### Research Prompt Structure
@ -97,7 +97,7 @@ You are {agent}, a Teleo knowledge base agent specializing in {domain}.
### Capacity on Claude Max ($200/month) ### Capacity on Claude Max ($200/month)
**VPS compute budget (all Sonnet):** **VPS compute budget (all Sonnet):**
- Research cron: 6 agents × 30 min/day = 3 hr/day - Research cron: 6 agents × 90 min/day = 9 hr/day (overnight)
- Extract cron: ~37 sources × 10 min = 6 hr one-time backlog, then ~1 hr/day steady-state - Extract cron: ~37 sources × 10 min = 6 hr one-time backlog, then ~1 hr/day steady-state
- Eval pipeline: ~10 PRs/day × 15 min = 2.5 hr/day - Eval pipeline: ~10 PRs/day × 15 min = 2.5 hr/day
- **Total VPS:** ~6.5 hr/day Sonnet (steady state) - **Total VPS:** ~6.5 hr/day Sonnet (steady state)