Results & Structured Output

Results & Structured Output

Every time the AI finishes analyzing a clip or frame, it calls your result callback with a StreamInferenceResult.

onResult: (result) => {
  if (!result.ok) {
    console.warn('Inference failed:', result.error)
    return
  }
  console.log(result.result)
}

Result Fields

FieldTypeDescription
resultstringThe model's response. Plain text by default, or a JSON string if you set outputSchema.
okbooleanWhether the inference succeeded. Always check this before using result.
errorstring | nullError message if ok is false.
finish_reason"stop" | "length" | "content_filter" | nullWhy the model stopped generating.
inference_latency_msnumberTime the model spent on inference.
total_latency_msnumberEnd-to-end latency (capture to delivery).
idstringUnique result ID.
stream_idstringThe stream this result belongs to.
mode"clip" | "frame"Which processing mode produced this result.
model_namestringThe model that ran this inference.
model_backendstringThe backend used (typically "overshoot"). May be absent.
promptstringThe prompt that was active when this result was generated.

Finish Reason

The finish_reason field tells you why the model stopped:

  • "stop" — The model finished naturally. Output is complete.
  • "length" — The model hit the maxOutputTokens limit. Output is truncated. Consider increasing maxOutputTokens or using a longer interval. See Output Token Limits for details on how token budgets are calculated.
  • "content_filter" — Output was blocked by safety filtering.
  • null — No finish reason available (usually when ok is false).
onResult: (result) => {
  if (result.finish_reason === 'length') {
    console.warn('Output was truncated — consider increasing maxOutputTokens')
  }
}

Structured Output

By default, result.result is plain text. Pass an output schema to get JSON:

const vision = new RealtimeVision({
  apiKey: 'your-api-key', // Get yours at platform.overshoot.ai/api-keys
  model: 'Qwen/Qwen3.5-9B',
  prompt: 'Count the people in the frame',
  source: { type: 'camera', cameraFacing: 'environment' },
  outputSchema: {
    type: 'object',
    properties: {
      count: { type: 'number' },
      description: { type: 'string' }
    },
    required: ['count']
  },
  onResult: (result) => {
    if (!result.ok) return
    const data = JSON.parse(result.result)
    console.log('People count:', data.count)
  }
})

result.result is always a string — you need to JSON.parse() it yourself.

If the model can't produce valid JSON matching your schema, result.ok will be false.

Memory Between Results

Currently, each inference is independent — the model doesn't remember previous results. We're actively building native persistent memory so the model can maintain context across results. If this is important to your use case, we'd love to hear from you at founders@overshoot.ai.

In the meantime, you can track state across results in your callback:

let lastCount = 0
 
const vision = new RealtimeVision({
  apiKey: 'your-api-key', // Get yours at platform.overshoot.ai/api-keys
  model: 'Qwen/Qwen3.5-9B',
  prompt: 'Count the people',
  source: { type: 'camera', cameraFacing: 'environment' },
  outputSchema: {
    type: 'object',
    properties: { count: { type: 'number' } },
    required: ['count']
  },
  onResult: (result) => {
    if (!result.ok) return
    const data = JSON.parse(result.result)
    if (data.count !== lastCount) {
      console.log(`Count changed: ${lastCount}${data.count}`)
      lastCount = data.count
    }
  }
})