# Task Agent

Run curated LLM tasks from code and get trusted text or JSON back, in complete or streaming mode.

Run a configured task through the SDK and get back text or JSON you can trust, adding AI to a product feature without writing prompts: call a curated, versioned, observable skill from code.

Reach for it when you need:

- **Synchronous AI APIs**: quick, reliable responses inside a product feature.
- **Deterministic contracts**: predictable outputs shaped by a schema.
- **Non-chat tasks**: summaries, classification, extraction, or generation.

Both complete and streaming modes use the same call:
`foldspace.agent('YOUR-AGENT-API-NAME').runTask()`. Passing `streamOptions` switches it to
streaming.

## Parameters

| Parameter | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| `taskKey` | `string` | Yes | The unique identifier for the task you want to run. |
| `data` | `string` \| `object` | Yes | The input payload for the task. |
| `streamOptions` | `object` | No | Enables streaming mode if provided. |
| `cacheOptions` | `object` | No | Configures caching behavior, such as defining a Time-To-Live (TTL) or forcing a fresh execution. |

## Complete mode

Call `runTask()` without `streamOptions` to wait for the server and resolve a Promise
with the full result once the task finishes.

```javascript
foldspace.agent('YOUR-AGENT-API-NAME').runTask({
  taskKey: 'YOUR-TASK-KEY',
  data: 'ANY-STRING-OR-OBJECT'
})
  .then((result) => {
    console.log('Task result:', result);
  })
  .catch((error) => {
    console.error('Task failed:', error);
  });
```

The resolved value depends on the task's configured response type:

- **`string`** for `TEXT` response types.
- **`object`** for `JSON` response types.

## Cache options

The optional `cacheOptions` object controls when cached results are used, when to force
a fresh execution, and how long new results are cached. Caching behaves identically in
both complete and streaming modes.

| Property | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `bypass` | `boolean` | `false` | When `true`, the task executes fresh, ignoring any existing cached result. |
| `ttlSeconds` | `number` | `21600` (6 hours) | How long to cache the new result, in seconds. Set to `0` to disable caching for the new result. |

### Behavior matrix

| `bypass` | `ttlSeconds` | Result |
| :--- | :--- | :--- |
| Omitted / `false` | Omitted | Check cache. If executed, cache new result for 6 hours. |
| Omitted / `false` | `300` (custom) | Check cache. If executed, cache new result for 5 minutes. |
| Omitted / `false` | `0` | Check cache. If executed, do not cache new result. |
| `true` | Omitted | **Skip cache**. Execute fresh & cache new result for 6 hours. |
| `true` | `0` | **Skip cache**. Execute fresh & cache new result for 6 hours. |

### Force a refresh

Ignore any cached value and run the task. The new result is cached for the default 6
hours.

```javascript
foldspace.agent('YOUR-AGENT-API-NAME').runTask({
  taskKey: 'SUMMARIZE_TASK',
  data: 'some long text...',
  cacheOptions: {
    bypass: true
  }
});
```

### Skip caching the new result

Still check for an existing cached result, but if a new result is generated (for
example, because no cache was found), don't store it for future use.

```javascript
foldspace.agent('YOUR-AGENT-API-NAME').runTask({
  taskKey: 'SUMMARIZE_TASK',
  data: 'some long text...',
  cacheOptions: {
    ttlSeconds: 0
  }
});
```

### Full-fresh, no-cache

Skip reading from the cache and prevent the new result from being stored.

```javascript
foldspace.agent('YOUR-AGENT-API-NAME').runTask({
  taskKey: 'SUMMARIZE_TASK',
  data: 'some long text...',
  cacheOptions: {
    bypass: true,
    ttlSeconds: 0
  }
});
```

### Custom TTL with streaming

`cacheOptions` works the same in streaming mode. This caches the streamed result for
10 minutes (600 seconds).

```javascript
foldspace.agent('YOUR-AGENT-API-NAME').runTask({
  taskKey: 'LONG_STREAM_TASK',
  data: { prompt: 'Generate a story...' },
  
  // Cache this specific stream's result for 10 minutes
  cacheOptions: {
    ttlSeconds: 600
  },

  streamOptions: {
    onMessage: ({ textDelta }) => {
      // Append text to UI
    },
    onComplete: () => {
      console.log('Stream done and result is cached.');
    }
  }
});
```

## Streaming mode

Provide a `streamOptions` object to receive incremental chunks as they become
available, ideal for AI text generation, incremental updates, or long-running
processes. Each chunk triggers `onMessage`, letting you render output progressively.

:::note
Streaming mode is only supported for tasks configured with a `TEXT` response type. It
is not compatible with `JSON` response types.
:::

```javascript
foldspace.agent('YOUR-AGENT-API-NAME').runTask({
  taskKey: 'YOUR-TASK-KEY',
  data: { input: "Hello, world" },
  streamOptions: {
    onStart: ({ id, abortStreamTask }) => {
      console.log('Stream started with ID:', id);
      // You can call abortStreamTask() to stop the stream at any time
    },
    onMessage: ({ textDelta, fullText, chunk }) => {
      console.log('New message chunk:', textDelta);
      console.log('Full accumulated text:', fullText);
    },
    onComplete: ({ fullText }) => {
      console.log('Stream completed:', fullText);
    },
    onError: (error) => {
      console.error('Stream error:', error);
    }
  }
});
```

### `streamOptions` callbacks

| Callback | Description | Parameters |
| :--- | :--- | :--- |
| `onStart` | Called when the stream begins. | `{ id: string, abortStreamTask: () => void }` |
| `onMessage` | Called for every data chunk received from the stream. | `{ textDelta: string, fullText: string, chunk: object, id: string }` |
| `onComplete` | Called once the stream ends (naturally or via abort). | `{ textDelta?: string, fullText: string, chunk?: object, id?: string }` |
| `onError` | Called if an error occurs during the stream. | `(error: Error)` |

### Aborting a stream manually

The `onStart` callback provides an `abortStreamTask` function. Store it and call it at
any time to stop the stream from the client side, useful for "Stop Generation"
buttons, handling user navigation, or enforcing a client-side timeout. Calling
`abortStreamTask()` gracefully terminates the stream, and `onComplete` still fires.

```javascript
// Store the abort function in a higher scope
let abortTask = null;

function startStream() {
  foldspace.agent('YOUR-AGENT-API-NAME').runTask({
    taskKey: 'LONG_STREAM_TASK',
    data: { prompt: 'Generate a very long story...' },
    streamOptions: {
      onStart: ({ id, abortStreamTask }) => {
        console.log('Stream started:', id);
        // Store the function so it can be called by other elements
        abortTask = abortStreamTask;
      },
      onMessage: ({ textDelta }) => {
        console.log(textDelta); // Append text to UI
      },
      onComplete: ({ fullText }) => {
        console.log('Stream completed.');
        abortTask = null; // Clean up
      },
      onError: (err) => {
        console.error('Stream error:', err);
        abortTask = null; // Clean up
      },
    }
  });
}

// Imagine this is called by a "Stop" button click
function stopStream() {
  if (abortTask) {
    console.log('Manually aborting stream...');
    abortTask();
  }
}
```

## Notes

- Run any registered agent API using its unique `taskKey`. Create and manage your task
  agents in **Agent Studio → Task Agents** (see the [Task Agents guide](/user-guides/task-agents/)).
- For long tasks, prefer streaming mode to get progressive feedback.
- Both modes use `foldspace.agent('YOUR-AGENT-API-NAME').runTask()`: behavior changes based
  on whether `streamOptions` is provided.
