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

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:

  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:

# 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):

  1. Function arguments - explicit parameters to execute()

    execute('python', code, public_key='...', secret_key='...')
    
  2. Environment variables

    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:

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:

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:

  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!