un-inception/tests/AGENT_REFACTORING_INSTRUCTIONS.md
russell@unturf.com 67a14eae4a Update documentation to include snapshot functions
- Added snapshot functions to SDK requirements
- Updated testing guide with snapshot examples
- Added snapshot checklist items for refactoring
- Clarified image() function in utilities section

All agents refactoring SDKs must now implement:
- sessionSnapshot(session_id, opts)
- serviceSnapshot(service_id, opts)
- listSnapshots(opts)
- restoreSnapshot(snapshot_id, opts)
- deleteSnapshot(snapshot_id, opts)
2026-01-15 15:37:56 -05:00

384 lines
10 KiB
Markdown

# SDK Refactoring Instructions for Agents
This document explains how to refactor UN SDK implementations with proper testing and validation.
## Quick Start
### Step 1: Understand the Reference Implementations
Study these complete, working SDK implementations first:
- **Python**: `/home/fox/git/un-inception/un.py` (DONE - use as reference)
- **JavaScript**: `/home/fox/git/un-inception/un.js` (DONE - use as reference)
- **Go**: Check if exists; if incomplete, use Python/JS as pattern
### Step 2: Apply the Pattern to Your Language
Every refactored SDK needs:
1. **Library functions** (can be imported/required)
```
execute(language, code, opts)
executeAsync(language, code, opts)
run(file, opts)
runAsync(file, opts)
wait(job_id)
getJob(job_id)
cancelJob(job_id)
listJobs()
languages()
detectLanguage(filename)
image(prompt, opts)
# Snapshot functions (NEW!)
sessionSnapshot(session_id, opts)
serviceSnapshot(service_id, opts)
listSnapshots(opts)
restoreSnapshot(snapshot_id, opts)
deleteSnapshot(snapshot_id, opts)
```
2. **Credential system** (4-tier with fallback)
```
Priority: args > env vars > ~/.unsandbox/accounts.csv > ./accounts.csv
```
3. **HMAC-SHA256 request signing**
```
signature = HMAC(secret, "timestamp:METHOD:endpoint:body")
```
4. **1-hour cache** for `/languages` API endpoint
```
~/.unsandbox/languages.json with TTL check
```
5. **CLI functionality** (preserve original behavior)
```
Command-line interface for executing code files
```
6. **Proper docstrings** (language-appropriate style)
```
Python: """ """
JavaScript: /** */
Go: // line comments
Ruby: # line comments
PHP: /** */
Etc.
```
7. **Complete license header** (permacomputer public domain)
```
Must include full 35+ line license notice
```
### Step 3: Test Your Work
Use the provided test framework to validate:
```bash
# Run unit tests (no API key required)
cd /home/fox/git/un-inception
python3 tests/test_sdk_library.py --languages YOUR_LANGUAGE
# Or run the master test runner
./tests/run_sdk_tests.sh --languages YOUR_LANGUAGE
```
Expected output:
```
SDK LIBRARY TEST SUMMARY
========================================
✓ your_language 3/ 4 passed (1 skipped)
========================================
Total: 3 passed, 0 failed, 1 skipped
```
### Step 4: Validate Examples Still Work
After refactoring, ensure the example files execute properly:
```bash
# Set credentials (if available)
export UNSANDBOX_API_KEY='your-test-key'
# Test CLI still works
python un.py examples/hello.py
node un.js examples/hello.js
ruby un.rb examples/hello.rb
# etc.
# Test library imports work
python3 -c "import un; result = un.execute('python', 'print(1)')"
node -e "const un = require('./un.js'); un.execute('javascript', 'console.log(1)')"
```
### Step 5: Update Documentation Examples
Once your SDK is refactored, update the example files:
```
/home/fox/git/unsandbox.com/priv/static/docs/examples/{language}/execute.txt
/home/fox/git/unsandbox.com/priv/static/docs/examples/{language}/execute_async.txt
```
Pattern to follow (from Python/JavaScript):
- Show SDK library import/require
- Demonstrate credential setup
- Show execute() call with proper options
- Show executeAsync() + wait() pattern
- Include error handling
### Step 6: Commit Your Work
```bash
git add un.{ext} tests/test_un_{lang}.{ext}
git commit -m "Refactor {Language} SDK: add library exports + HMAC auth + caching
- Implement execute, executeAsync, wait, getJob, cancelJob, listJobs
- Add 4-tier credential system (args > env > home > local)
- Add 1-hour cache for languages list in ~/.unsandbox/
- Implement HMAC-SHA256 request signing
- Preserve original CLI functionality
- Proper docstrings for {Language}
- Full test coverage with unit + integration tests"
```
## Key Implementation Details
### Credential Loading (4-tier system)
Priority order (stop at first match):
1. **Function arguments** - explicit parameters to execute()
```python
execute('python', code, public_key='...', secret_key='...')
```
2. **Environment variables**
```bash
export UNSANDBOX_PUBLIC_KEY='unsb-pk-xxxx'
export UNSANDBOX_SECRET_KEY='unsb-sk-xxxx'
```
3. **Home directory** (default location)
```
~/.unsandbox/accounts.csv
Format: public_key,secret_key (one per line)
```
4. **Local directory** (current working dir)
```
./accounts.csv
Format: public_key,secret_key (one per line)
```
### HMAC Signature Format
Every API request must include:
```
Authorization: Bearer {public_key}
X-Timestamp: {unix_timestamp}
X-Signature: {hmac_sha256}
```
Where signature is:
```
HMAC-SHA256(
secret_key,
"{timestamp}:{METHOD}:{endpoint}:{json_body}"
)
```
Example with Python:
```python
import hmac
import hashlib
import json
import time
secret = 'unsb-sk-...'
timestamp = str(int(time.time()))
method = 'POST'
endpoint = '/execute'
body = json.dumps({'language': 'python', 'code': 'print(1)'})
message = f"{timestamp}:{method}:{endpoint}:{body}"
signature = hmac.new(
secret.encode(),
message.encode(),
hashlib.sha256
).hexdigest()
```
### Languages Cache (1-hour TTL)
Implement caching to avoid repeated API calls:
1. **Cache location**: `~/.unsandbox/languages.json`
2. **TTL**: 3600 seconds (1 hour)
3. **Check logic**:
- If file exists AND age < TTL → return cached
- Otherwise → fetch from API AND update cache
Example with Python:
```python
from pathlib import Path
import json
import time
def languages(cache_ttl=3600):
cache_path = Path.home() / '.unsandbox' / 'languages.json'
# Check cache
if cache_path.exists():
age = time.time() - cache_path.stat().st_mtime
if age < cache_ttl:
return json.loads(cache_path.read_text())
# Fetch from API
result = api_request('GET', '/languages')
langs = result['languages']
# Update cache
cache_path.parent.mkdir(parents=True, exist_ok=True)
cache_path.write_text(json.dumps(langs))
return langs
```
## Common Patterns
### Exception Hierarchy
Every SDK should define:
```python
class UnsandboxError(Exception): pass
class AuthenticationError(UnsandboxError): pass
class ExecutionError(UnsandboxError): pass
class APIError(UnsandboxError): pass
class TimeoutError(UnsandboxError): pass
```
### Exponential Backoff Polling
When waiting for async jobs:
```
Initial delays (ms): [300, 450, 700, 900, 650, 1600, 2000, ...]
Pattern: Increases generally but with variation to avoid thundering herd
Max polls: Usually around 120 (2+ hours for patience)
```
### CLI Entry Point
Preserve CLI functionality:
```python
# Python: at end of file
if __name__ == '__main__':
import sys
from pathlib import Path
# Parse args, call execute/run, handle errors
```
```javascript
// JavaScript: at end of file
if (require.main === module) {
cliMain().catch(e => {
console.error(e.message);
process.exit(1);
});
}
```
```go
// Go: in main()
if len(os.Args) < 2 {
// Show usage
}
// Parse args, call Execute/Run, handle errors
```
## Testing Checklist
Before committing, verify ALL of these:
- [ ] **Unit tests pass** - Library functions work
- [ ] **Library functions exist** - execute, executeAsync, wait, etc.
- [ ] **Credentials load** - All 4 sources (args, env, home, local)
- [ ] **HMAC signature** - Correct format and length (64 hex chars)
- [ ] **Cache works** - languages.json created and used
- [ ] **CLI still works** - Command-line execution preserved
- [ ] **Error handling** - Appropriate exceptions for errors
- [ ] **Docstrings** - Language-appropriate comment style
- [ ] **License header** - Full permacomputer notice at top
- [ ] **No hardcoded credentials** - All removed
- [ ] **Examples updated** - execute.txt and execute_async.txt
- [ ] **Git status clean** - All files committed
## Troubleshooting
### Problem: "Cannot import/require un module"
**Solution:**
1. Check file is in correct location: `/home/fox/git/un-inception/un.{ext}`
2. Check filename matches language (un.py, un.js, un.go, etc.)
3. Check for syntax errors: try running file directly
### Problem: "HMAC signature invalid"
**Solution:**
1. Verify message format: `"{timestamp}:{METHOD}:{endpoint}:{body}"`
2. Verify secret key encoding: bytes, not string
3. Verify hexdigest: should be 64 lowercase hex characters
4. Verify HMAC algorithm: must be SHA256, not SHA1 or other
### Problem: "Credentials not found"
**Solution:**
1. Check env vars: `echo $UNSANDBOX_PUBLIC_KEY`
2. Check files exist: `ls ~/.unsandbox/accounts.csv`
3. Check file format: one credential pair per line
4. Check loading order: function args, env, home, local
### Problem: "Cache not working"
**Solution:**
1. Check directory exists: `mkdir -p ~/.unsandbox/`
2. Check file created: `ls -la ~/.unsandbox/languages.json`
3. Check TTL logic: age < 3600 seconds
4. Check mtime: `stat ~/.unsandbox/languages.json`
## Examples of Refactored SDKs
To understand the pattern better, study:
1. **Python (un.py)** - Complete, well-commented implementation
- Shows all library functions
- Demonstrates credential system
- Shows HMAC signing
- Shows caching
- Preserves CLI
2. **JavaScript (un.js)** - Node.js implementation
- Shows async/await pattern
- Shows Client class wrapper
- Shows error handling
- Shows function validation
3. **Go** (partially done) - if available
- Shows goroutine patterns
- Shows error handling
- Shows HTTP client usage
## Questions or Blockers?
If you're stuck:
1. **Check the guide**: `/home/fox/git/un-inception/tests/SDK_TESTING_GUIDE.md`
2. **Review Python SDK**: `un.py` is the canonical reference
3. **Look at examples**: `priv/static/docs/examples/python/` and `javascript/`
4. **Run tests**: `python3 tests/test_sdk_library.py --languages YOUR_LANGUAGE`
5. **Check git history**: `git log --oneline un.py` to see refactoring commits
## Final Notes
- **Don't rush** - Quality over speed. Tests will catch errors.
- **Test frequently** - Run tests after each function you implement
- **Copy patterns** - Use Python/JavaScript as templates exactly
- **Preserve functionality** - Original CLI must still work
- **Document clearly** - Use language-appropriate docstrings
- **Commit atomically** - Each language in separate commit
Good luck! The test framework is there to help you validate your work. Use it!