For building dynamic, real-time applications, waiting for an agent's full response can lead to a slow user experience. The SmythOS SDK solves this with streaming, allowing you to process the agent's output token-by-token as it's generated. This is perfect for creating "typewriter" effects in UIs and providing immediate feedback to the user.
The script in examples/01-agent-code-skill/02-streaming.ts
provides a complete, runnable example of the concepts below.
Instead of await
-ing the agent.prompt()
call directly, you chain the .stream()
method. This doesn't return the final string response. Instead, it returns a standard Node.js EventEmitter
that you can subscribe to.
This EventEmitter
will emit different events during the lifecycle of the agent's response generation, as defined in the TLLMEvent
enum.
The most common use case is to listen for content chunks and the end of the stream.
TLLMEvent.Content
: This event fires whenever a new chunk of text (usually a word or a few tokens) is available from the LLM.TLLMEvent.End
: This event fires once the entire response has been generated and the stream is closed.TLLMEvent.Error
: This event fires if an error occurs during generation.Here's how you can use it to print a response to the console in real-time:
import { Agent, TLLMEvent } from '@smythos/sdk';
const agent = new Agent({
name: 'Storyteller',
model: 'gpt-4o',
behavior: 'You are a master storyteller who weaves short, captivating tales.',
});
/*... implement skills here ...*/
// Chain .stream() to the prompt command
const stream = await agent.prompt('Tell me a short story about a robot who discovers music.').stream();
console.log('Storyteller is thinking...');
// Listen for the 'content' event to get text chunks
stream.on(TLLMEvent.Content, (chunk) => {
// Write each piece of the story to the console as it arrives
process.stdout.write(chunk);
});
// Listen for the 'end' event to know when the story is complete
stream.on(TLLMEvent.End, () => {
console.log('\n\n--- The End ---');
});
// Always good practice to handle potential errors
stream.on(TLLMEvent.Error, (err) => {
console.error('\nAn error occurred:', err);
});
The stream doesn't just give you the final text output; it also provides visibility into the agent's "thought process". You can listen for events related to skill execution.
TLLMEvent.ToolCall
: Fires when the agent decides to use a skill. The event payload includes the name of the skill and the arguments it's using.TLLMEvent.ToolResult
: Fires after the skill's process
function has completed. The payload contains the result that was returned by the skill.This is incredibly useful for debugging or showing the user that the agent is performing an action in the background.
// Assuming the 'getWeather' skill from the previous guide is added to the agent...
import { Agent, TLLMEvent } from '@smythos/sdk';
const stream = await agent.prompt('What is the weather in London?').stream();
stream.on(TLLMEvent.ToolCall, ({ name, args }) => {
console.log(`\n[Agent is using the '${name}' skill with args: ${JSON.stringify(args)}]`);
});
stream.on(TLLMEvent.ToolResult, ({ result }) => {
console.log(`\n[Skill returned: ${JSON.stringify(result)}]`);
});
stream.on(TLLMEvent.Content, (chunk) => process.stdout.write(chunk));
stream.on(TLLMEvent.End, () => console.log('\n\n--- Done ---'));
When you run this, you will see the ToolCall
and ToolResult
messages appear in your console before the final natural language response is streamed.
With streaming, you can build highly responsive and transparent agentic applications. Now, let's explore how to maintain context over multiple interactions by using Conversations.