recursive-agent 0.6.0

A minimal, orthogonal, self-improving coding agent kernel in Rust
Documentation
name: "TypeScript SDK smoke test"
description: |
  Verify the TypeScript SDK (@recursive/sdk) works end-to-end against the
  HTTP server:
    - Agent.create() opens a session
    - agent.send() returns a Run
    - run.wait() returns RunResult with all Phase-A fields populated:
        status, result (concatenated assistant text), numTurns, durationMs

  Requires nodejs to be installed in the e2e container.
  The Dockerfile copies sdk/typescript/dist to /sdk/typescript/dist.
sequential: true

setup:
  - name: "Kill any leftover server on port 9097"
    ignoreError: true
    exec:
      container: recursive-e2e
      command: |
        pkill -f 'http --addr 0.0.0.0:9097' 2>/dev/null || true
        sleep 1
        echo cleaned

  - name: "Reset state files"
    ignoreError: true
    exec:
      container: recursive-e2e
      command: rm -f /tmp/ts-sdk-result.txt /tmp/ts-sdk-http.log && echo reset

  - name: "Start HTTP server on port 9097"
    exec:
      container: recursive-e2e
      command: |
        nohup recursive \
          --api-base http://aimock:4010/v1 \
          --api-key mock-key -m mock-chat \
          http --addr 0.0.0.0:9097 \
          > /tmp/ts-sdk-http.log 2>&1 &
        sleep 2
        echo started

  - name: "Sanity: GET /health returns ok"
    exec:
      container: recursive-e2e
      command: curl -sf http://localhost:9097/health
    expect:
      exitCode: 0
      output:
        contains: "ok"

  - name: "Run TypeScript SDK test script, save result to /tmp/ts-sdk-result.txt"
    exec:
      container: recursive-e2e
      command: |
        node - <<'JSEOF' > /tmp/ts-sdk-result.txt
        const { Agent } = require('/sdk/typescript/dist/index.js');

        async function main() {
          const agent = await Agent.create({ baseUrl: 'http://localhost:9097', apiKey: 'test' });
          try {
            const run = await agent.send('sdk-typescript-hello');
            const result = await run.wait();
            console.log('status=' + result.status);
            console.log('has_result=' + (result.result != null));
            console.log('num_turns=' + result.numTurns);
            console.log('has_duration=' + (result.durationMs != null && result.durationMs >= 0));
          } finally {
            await agent[Symbol.asyncDispose]();
          }
        }

        main().catch(e => { console.error(e); process.exit(1); });
        JSEOF
        cat /tmp/ts-sdk-result.txt
    expect:
      exitCode: 0
      output:
        contains:
          - "status=finished"
          - "has_result=true"

cases:
  - name: "TypeScript SDK RunResult status is finished"
    file:
      container: recursive-e2e
      path: /tmp/ts-sdk-result.txt
      exists: true
      contains: "status=finished"

  - name: "TypeScript SDK RunResult has non-null result field"
    file:
      container: recursive-e2e
      path: /tmp/ts-sdk-result.txt
      exists: true
      contains: "has_result=true"

  - name: "TypeScript SDK RunResult has numTurns >= 1"
    file:
      container: recursive-e2e
      path: /tmp/ts-sdk-result.txt
      exists: true
      contains: "num_turns=1"

  - name: "TypeScript SDK RunResult has durationMs populated"
    file:
      container: recursive-e2e
      path: /tmp/ts-sdk-result.txt
      exists: true
      contains: "has_duration=true"

teardown:
  - name: "Stop HTTP server on 9097 and clean up"
    ignoreError: true
    exec:
      container: recursive-e2e
      command: |
        pkill -f 'http --addr 0.0.0.0:9097' 2>/dev/null || true
        rm -f /tmp/ts-sdk-result.txt /tmp/ts-sdk-http.log
        echo stopped