> ## Documentation Index
> Fetch the complete documentation index at: https://docs.standardagentbuilder.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Utilities

> Common utility functions for working with ThreadState

## Overview

Standard Agents provides utility functions that wrap common ThreadState operations. While you can call ThreadState methods directly, these utilities are exported from `@standardagents/builder` for convenience and backwards compatibility.

<Note>
  Most utilities are now methods on ThreadState. You can use either the standalone functions or call methods directly on state.
</Note>

## queueTool

Queue a tool call for execution in the current thread.

```typescript theme={null}
// Using the utility function
import { queueTool } from "@standardagents/builder";
queueTool(state, 'tool_name', { arg: 'value' });

// Or call directly on state
state.queueTool('tool_name', { arg: 'value' });
```

**Parameters:**

* `state`: The ThreadState context
* `toolName`: The name of the tool to call
* `args`: Arguments to pass to the tool

**Example:**

```typescript theme={null}
import { defineTool } from "@standardagents/spec";
import { z } from "zod";

export default defineTool({
  description: "Process user order and send confirmation",
  args: z.object({
    orderId: z.string(),
    userId: z.string(),
  }),
  execute: async (state, args) => {
    // Validate the order
    const order = await validateOrder(args.orderId);

    if (!order.valid) {
      return {
        status: "error",
        error: "Order validation failed",
      };
    }

    // Queue additional tools to execute after this one
    state.queueTool("charge_payment", {
      orderId: args.orderId,
      amount: order.total,
    });

    state.queueTool("send_confirmation_email", {
      userId: args.userId,
      orderId: args.orderId,
    });

    state.queueTool("update_inventory", {
      items: order.items,
    });

    return {
      status: "success",
      result: `Order ${args.orderId} queued for processing`,
    };
  },
});
```

***

## invokeTool

Invoke a tool directly and wait for the result.

```typescript theme={null}
const result = await state.invokeTool('tool_name', { arg: 'value' });

if (result.status === 'success') {
  console.log(result.result);
}
```

**Parameters:**

* `toolName`: The name of the tool to invoke
* `args`: Arguments to pass to the tool

**Returns:** `Promise<ToolResult>`

***

## injectMessage

Inject a message into the thread conversation.

```typescript theme={null}
const message = await state.injectMessage({
  role: 'user',
  content: 'Additional context...',
  silent: true,
  metadata: { source: 'tool' },
});
```

**Options:**

```typescript theme={null}
interface InjectMessageInput {
  role: 'user' | 'assistant' | 'system';
  content: string;
  silent?: boolean;          // Hide from UI
  metadata?: Record<string, unknown>;
}
```

**Examples:**

<Tabs>
  <Tab title="System Context">
    ```typescript theme={null}
    export default defineTool({
      description: "Load user context",
      args: z.object({ userId: z.string() }),
      execute: async (state, args) => {
        const user = await fetchUser(args.userId);

        await state.injectMessage({
          role: "system",
          content: `User context loaded: ${user.name} (${user.email})
            - Account tier: ${user.tier}
            - Preferences: ${JSON.stringify(user.preferences)}`,
        });

        return {
          status: "success",
          result: "User context injected",
        };
      },
    });
    ```
  </Tab>

  <Tab title="Silent Message">
    ```typescript theme={null}
    export default defineTool({
      description: "Add internal note",
      args: z.object({ note: z.string() }),
      execute: async (state, args) => {
        await state.injectMessage({
          role: "system",
          content: args.note,
          silent: true,  // Hidden from LLM, stored for audit
        });

        return {
          status: "success",
          result: "Internal note added",
        };
      },
    });
    ```
  </Tab>
</Tabs>

***

## getMessages

Retrieve message history from the thread.

```typescript theme={null}
const { messages, total, hasMore } = await state.getMessages({
  limit: 50,
  offset: 0,
  order: 'desc',
});
```

**Options:**

| Option          | Type              | Default  | Description             |
| --------------- | ----------------- | -------- | ----------------------- |
| `limit`         | `number`          | -        | Max messages to return  |
| `offset`        | `number`          | 0        | Messages to skip        |
| `order`         | `'asc' \| 'desc'` | `'desc'` | Sort order              |
| `includeSilent` | `boolean`         | false    | Include silent messages |
| `maxDepth`      | `number`          | -        | Max sub-prompt nesting  |

**Example:**

```typescript theme={null}
export default defineTool({
  description: "Analyze recent conversation tone",
  execute: async (state) => {
    // Get last 10 messages
    const { messages } = await state.getMessages({ limit: 10 });

    // Filter user and assistant messages only
    const conversationMessages = messages.filter(
      (m) => m.role === "user" || m.role === "assistant"
    );

    const tone = analyzeTone(conversationMessages);

    return {
      status: "success",
      result: `Conversation tone: ${tone}`,
    };
  },
});
```

***

## emit (Custom Events)

Send custom events to WebSocket clients.

```typescript theme={null}
state.emit('event_type', {
  key: 'value',
  progress: 50,
});
```

**Parameters:**

* `event`: Event type name
* `data`: Event payload (must be JSON-serializable)

**Event Structure (received by clients):**

```json theme={null}
{
  "type": "event",
  "eventType": "<your-type>",
  "data": <your-data>,
  "timestamp": 1234567890
}
```

**Examples:**

<Tabs>
  <Tab title="Progress Updates">
    ```typescript theme={null}
    export default defineTool({
      description: "Process large dataset",
      args: z.object({ datasetId: z.string() }),
      execute: async (state, args) => {
        const dataset = await loadDataset(args.datasetId);
        const total = dataset.length;

        for (let i = 0; i < total; i++) {
          await processItem(dataset[i]);

          // Emit progress event every 10 items
          if (i % 10 === 0) {
            state.emit("progress", {
              current: i + 1,
              total,
              percentage: ((i + 1) / total) * 100,
              message: `Processing item ${i + 1} of ${total}`,
            });
          }
        }

        return {
          status: "success",
          result: `Processed ${total} items`,
        };
      },
    });
    ```
  </Tab>

  <Tab title="Status Updates">
    ```typescript theme={null}
    export default defineTool({
      description: "Upload file",
      args: z.object({ fileUrl: z.string() }),
      execute: async (state, args) => {
        state.emit("upload_status", {
          status: "started",
          message: "Starting download...",
        });

        const file = await downloadFile(args.fileUrl);

        state.emit("upload_status", {
          status: "processing",
          message: "Processing file...",
        });

        const result = await processFile(file);

        state.emit("upload_status", {
          status: "complete",
          message: "Upload complete!",
        });

        return {
          status: "success",
          result: "File processed",
        };
      },
    });
    ```
  </Tab>
</Tabs>

### Frontend Integration

Listen for events on the frontend using `@standardagents/react`:

```tsx theme={null}
import {
  StandardAgentsProvider,
  ThreadProvider,
  useThread,
} from "@standardagents/react";

function App() {
  return (
    <StandardAgentsProvider config={{ endpoint: "https://api.example.com" }}>
      <ThreadProvider threadId="123e4567-e89b-12d3-a456-426614174000">
        <OrderTracker />
      </ThreadProvider>
    </StandardAgentsProvider>
  );
}

function OrderTracker() {
  const { onCustomEvent } = useThread();

  // Listen for custom events
  useEffect(() => {
    const unsubscribe = onCustomEvent('progress', (data) => {
      console.log('Progress:', data.percentage);
    });
    return unsubscribe;
  }, [onCustomEvent]);

  return <div>...</div>;
}
```

***

## forceTurn (Execution Control)

Force the next execution turn to a specific side (for dual\_ai agents).

```typescript theme={null}
// Only available during execution
if (state.execution) {
  state.execution.forceTurn('b');
}
```

**Parameters:**

* `side`: The side to force (`'a'` or `'b'`)

<Note>
  This is primarily used for dual\_ai agents to control turn order.
</Note>

***

## stop (Execution Control)

Stop the current execution after the current operation completes.

```typescript theme={null}
if (state.execution) {
  state.execution.stop();
}
```

***

## scheduleEffect

Schedule an effect for delayed or background execution.

```typescript theme={null}
const effectId = await state.scheduleEffect(
  'send_reminder_email',
  { to: 'user@example.com', subject: 'Reminder' },
  30 * 60 * 1000  // 30 minutes
);
```

**Parameters:**

* `name`: Effect name (file in `agents/effects/`)
* `args`: Arguments passed to effect handler
* `delay`: Delay in milliseconds (default: 0)

**Returns:** Effect ID (UUID) for later cancellation

***

## Complete Example

Here's a comprehensive example showing multiple utilities working together:

```typescript theme={null}
import { defineTool } from "@standardagents/spec";
import { z } from "zod";

export default defineTool({
  description: "Complete order processing workflow",
  args: z.object({
    orderId: z.string(),
    userId: z.string(),
    notifyUser: z.boolean().default(true),
  }),
  execute: async (state, args) => {
    // Emit initial status event
    state.emit("order_status", {
      orderId: args.orderId,
      status: "started",
    });

    // Inject system message for context
    await state.injectMessage({
      role: "system",
      content: `Processing order ${args.orderId} for user ${args.userId}`,
    });

    // Queue validation tool
    state.queueTool("validate_order", {
      orderId: args.orderId,
    });

    // Queue payment processing
    state.queueTool("process_payment", {
      orderId: args.orderId,
      userId: args.userId,
    });

    // Queue inventory update
    state.queueTool("update_inventory", {
      orderId: args.orderId,
    });

    // Conditionally queue notification
    if (args.notifyUser) {
      state.queueTool("send_notification", {
        userId: args.userId,
        type: "order_confirmation",
        orderId: args.orderId,
      });
    }

    // Get conversation history for audit
    const { messages } = await state.getMessages({ limit: 50 });
    const orderMessages = messages.filter(
      (m) => m.content?.includes(args.orderId)
    );

    // Emit completion event
    state.emit("order_status", {
      orderId: args.orderId,
      status: "queued",
      steps: 4,
      relatedMessages: orderMessages.length,
    });

    return {
      status: "success",
      result: `Order ${args.orderId} workflow initiated`,
    };
  },
});
```

## Best Practices

<AccordionGroup>
  <Accordion title="Error Handling">
    Always wrap async operations in try-catch blocks:

    ```typescript theme={null}
    try {
      await state.injectMessage({
        role: "system",
        content: "Context updated",
      });
    } catch (error) {
      console.error("Failed to inject message:", error);
      return {
        status: "error",
        error: `Message injection failed: ${error.message}`,
      };
    }
    ```
  </Accordion>

  <Accordion title="Throttle Event Emissions">
    Avoid excessive event emissions that could overwhelm WebSocket clients:

    ```typescript theme={null}
    // Good: Throttle emissions
    for (let i = 0; i < 10000; i++) {
      if (i % 100 === 0) {
        state.emit("progress", {
          current: i,
          total: 10000,
        });
      }
    }

    // Avoid: Emitting inside tight loop
    for (let i = 0; i < 10000; i++) {
      state.emit("progress", { value: i });
    }
    ```
  </Accordion>

  <Accordion title="Message Pagination">
    When retrieving large message histories, use pagination:

    ```typescript theme={null}
    const pageSize = 50;
    let offset = 0;
    let hasMore = true;

    while (hasMore) {
      const result = await state.getMessages({ limit: pageSize, offset });
      await processMessages(result.messages);
      hasMore = result.hasMore;
      offset += pageSize;
    }
    ```
  </Accordion>

  <Accordion title="Check Execution State">
    When using execution-specific features, check if execution is active:

    ```typescript theme={null}
    if (state.execution) {
      console.log(`Step: ${state.execution.stepCount}`);
      state.execution.forceTurn('b');
    }
    ```
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Events not received by frontend">
    **Solution:** Ensure you're using `ThreadProvider` and that you've subscribed to the correct event type name.
  </Accordion>

  <Accordion title="Tool not executing after queueTool">
    **Solution:** Tools are queued for sequential execution. Ensure the current tool completes successfully and doesn't stop execution.
  </Accordion>

  <Accordion title="getMessages returns empty">
    **Solution:** Check that messages exist in the thread and that limit/offset parameters are correct.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="ThreadState" icon="diagram-project" href="/core-concepts/flowstate">
    Understand the ThreadState interface
  </Card>

  <Card title="Tools" icon="wrench" href="/core-concepts/tools">
    Create custom tools
  </Card>

  <Card title="Hooks" icon="hook" href="/core-concepts/hooks">
    Use utilities in lifecycle hooks
  </Card>

  <Card title="React Integration" icon="react" href="/user-interfaces/react">
    Connect frontend to backend events
  </Card>
</CardGroup>
