- 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)
10 KiB
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:
-
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) -
Credential system (4-tier with fallback)
Priority: args > env vars > ~/.unsandbox/accounts.csv > ./accounts.csv -
HMAC-SHA256 request signing
signature = HMAC(secret, "timestamp:METHOD:endpoint:body") -
1-hour cache for
/languagesAPI endpoint~/.unsandbox/languages.json with TTL check -
CLI functionality (preserve original behavior)
Command-line interface for executing code files -
Proper docstrings (language-appropriate style)
Python: """ """ JavaScript: /** */ Go: // line comments Ruby: # line comments PHP: /** */ Etc. -
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:
# 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:
# 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
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):
-
Function arguments - explicit parameters to execute()
execute('python', code, public_key='...', secret_key='...') -
Environment variables
export UNSANDBOX_PUBLIC_KEY='unsb-pk-xxxx' export UNSANDBOX_SECRET_KEY='unsb-sk-xxxx' -
Home directory (default location)
~/.unsandbox/accounts.csv Format: public_key,secret_key (one per line) -
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:
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:
- Cache location:
~/.unsandbox/languages.json - TTL: 3600 seconds (1 hour)
- Check logic:
- If file exists AND age < TTL → return cached
- Otherwise → fetch from API AND update cache
Example with 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:
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: at end of file
if __name__ == '__main__':
import sys
from pathlib import Path
# Parse args, call execute/run, handle errors
// JavaScript: at end of file
if (require.main === module) {
cliMain().catch(e => {
console.error(e.message);
process.exit(1);
});
}
// 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:
- Check file is in correct location:
/home/fox/git/un-inception/un.{ext} - Check filename matches language (un.py, un.js, un.go, etc.)
- Check for syntax errors: try running file directly
Problem: "HMAC signature invalid"
Solution:
- Verify message format:
"{timestamp}:{METHOD}:{endpoint}:{body}" - Verify secret key encoding: bytes, not string
- Verify hexdigest: should be 64 lowercase hex characters
- Verify HMAC algorithm: must be SHA256, not SHA1 or other
Problem: "Credentials not found"
Solution:
- Check env vars:
echo $UNSANDBOX_PUBLIC_KEY - Check files exist:
ls ~/.unsandbox/accounts.csv - Check file format: one credential pair per line
- Check loading order: function args, env, home, local
Problem: "Cache not working"
Solution:
- Check directory exists:
mkdir -p ~/.unsandbox/ - Check file created:
ls -la ~/.unsandbox/languages.json - Check TTL logic: age < 3600 seconds
- Check mtime:
stat ~/.unsandbox/languages.json
Examples of Refactored SDKs
To understand the pattern better, study:
-
Python (un.py) - Complete, well-commented implementation
- Shows all library functions
- Demonstrates credential system
- Shows HMAC signing
- Shows caching
- Preserves CLI
-
JavaScript (un.js) - Node.js implementation
- Shows async/await pattern
- Shows Client class wrapper
- Shows error handling
- Shows function validation
-
Go (partially done) - if available
- Shows goroutine patterns
- Shows error handling
- Shows HTTP client usage
Questions or Blockers?
If you're stuck:
- Check the guide:
/home/fox/git/un-inception/tests/SDK_TESTING_GUIDE.md - Review Python SDK:
un.pyis the canonical reference - Look at examples:
priv/static/docs/examples/python/andjavascript/ - Run tests:
python3 tests/test_sdk_library.py --languages YOUR_LANGUAGE - Check git history:
git log --oneline un.pyto 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!