477 lines
8.6 KiB
Markdown
477 lines
8.6 KiB
Markdown
# Context Output JS API
|
|
|
|
The Context object now provides `Send`, `SendGroup`, and `Flush` methods directly for sending messages to clients from JavaScript.
|
|
|
|
## Usage
|
|
|
|
### ctx.Send(message)
|
|
|
|
Send a single message to the client.
|
|
|
|
**Parameters:**
|
|
|
|
- `message`: Can be a string (shorthand) or an object
|
|
|
|
**String Shorthand:**
|
|
|
|
```javascript
|
|
// Automatically converts to a text message
|
|
ctx.Send("Hello World");
|
|
```
|
|
|
|
**Object Format:**
|
|
|
|
```javascript
|
|
// Send text message
|
|
ctx.Send({
|
|
type: "text",
|
|
props: {
|
|
content: "Hello from JavaScript",
|
|
},
|
|
});
|
|
|
|
// Send loading message
|
|
ctx.Send({
|
|
type: "loading",
|
|
props: {
|
|
message: "Processing...",
|
|
},
|
|
});
|
|
|
|
// Send error message
|
|
ctx.Send({
|
|
type: "error",
|
|
props: {
|
|
message: "Something went wrong",
|
|
code: "ERR_500",
|
|
},
|
|
});
|
|
|
|
// Send custom message
|
|
ctx.Send({
|
|
type: "custom_widget",
|
|
props: {
|
|
data: { foo: "bar" },
|
|
},
|
|
});
|
|
```
|
|
|
|
**Complete Message Object:**
|
|
|
|
```javascript
|
|
ctx.Send({
|
|
type: "text",
|
|
props: {
|
|
content: "Hello",
|
|
},
|
|
id: "msg_123", // Optional: message ID
|
|
delta: true, // Optional: incremental update
|
|
done: false, // Optional: whether complete
|
|
delta_path: "content", // Optional: update path
|
|
delta_action: "append", // Optional: update action (append, replace, merge, set)
|
|
group_id: "grp_1", // Optional: message group ID
|
|
metadata: {
|
|
// Optional: metadata
|
|
timestamp: Date.now(),
|
|
sequence: 1,
|
|
trace_id: "trace_123",
|
|
},
|
|
});
|
|
```
|
|
|
|
### ctx.SendGroup(group)
|
|
|
|
Send a group of messages to the client.
|
|
|
|
**Parameters:**
|
|
|
|
- `group`: Message group object
|
|
|
|
**Example:**
|
|
|
|
```javascript
|
|
ctx.SendGroup({
|
|
id: "group_123",
|
|
messages: [
|
|
{
|
|
type: "text",
|
|
props: { content: "First message" },
|
|
},
|
|
{
|
|
type: "text",
|
|
props: { content: "Second message" },
|
|
},
|
|
],
|
|
metadata: {
|
|
timestamp: Date.now(),
|
|
},
|
|
});
|
|
```
|
|
|
|
### ctx.Flush()
|
|
|
|
Flush the output buffer to ensure all messages are sent to the client.
|
|
|
|
**Example:**
|
|
|
|
```javascript
|
|
ctx.Send("Processing...");
|
|
ctx.Flush(); // Send immediately
|
|
```
|
|
|
|
## Complete Examples
|
|
|
|
### Using in Hook Functions
|
|
|
|
```javascript
|
|
/**
|
|
* Create hook - called before assistant processes
|
|
*/
|
|
function Create(input, options) {
|
|
const ctx = input.context;
|
|
|
|
// Send welcome message
|
|
ctx.Send("Welcome to AI Assistant!");
|
|
|
|
// Send loading indicator
|
|
ctx.Send({
|
|
type: "loading",
|
|
props: {
|
|
message: "Thinking...",
|
|
},
|
|
});
|
|
|
|
return { messages: input.messages };
|
|
}
|
|
|
|
/**
|
|
* Done hook - called after assistant completes
|
|
*/
|
|
function Done(input, output) {
|
|
const ctx = input.context;
|
|
|
|
// Send completion message
|
|
ctx.Send({
|
|
type: "text",
|
|
props: {
|
|
content: "Processing completed!",
|
|
},
|
|
});
|
|
|
|
// Flush output
|
|
ctx.Flush();
|
|
|
|
return {};
|
|
}
|
|
```
|
|
|
|
### Streaming Response Example
|
|
|
|
```javascript
|
|
function StreamingResponse(input) {
|
|
const ctx = input.context;
|
|
|
|
// Send initial message
|
|
ctx.Send({
|
|
type: "text",
|
|
props: { content: "Starting process" },
|
|
id: "msg_1",
|
|
delta: false,
|
|
});
|
|
|
|
// Send incremental updates
|
|
ctx.Send({
|
|
type: "text",
|
|
props: { content: "..." },
|
|
id: "msg_1",
|
|
delta: true,
|
|
delta_path: "content",
|
|
delta_action: "append",
|
|
});
|
|
|
|
// Send completion marker
|
|
ctx.Send({
|
|
type: "text",
|
|
props: { content: "" },
|
|
id: "msg_1",
|
|
delta: false,
|
|
done: true,
|
|
});
|
|
|
|
ctx.Flush();
|
|
}
|
|
```
|
|
|
|
### Error Handling Example
|
|
|
|
```javascript
|
|
function ProcessWithErrorHandling(input) {
|
|
const ctx = input.context;
|
|
|
|
try {
|
|
// Processing logic
|
|
ctx.Send("Processing...");
|
|
|
|
// Simulate error
|
|
throw new Error("Something went wrong");
|
|
} catch (error) {
|
|
// Send error message
|
|
ctx.Send({
|
|
type: "error",
|
|
props: {
|
|
message: error.message,
|
|
code: "ERR_PROCESSING",
|
|
},
|
|
});
|
|
|
|
ctx.Flush();
|
|
}
|
|
}
|
|
```
|
|
|
|
### Multi-step Process Example
|
|
|
|
```javascript
|
|
function MultiStepProcess(input) {
|
|
const ctx = input.context;
|
|
|
|
// Step 1
|
|
ctx.Send({
|
|
type: "loading",
|
|
props: { message: "Step 1: Analyzing input..." },
|
|
});
|
|
ctx.Flush();
|
|
|
|
// ... processing ...
|
|
|
|
// Step 2
|
|
ctx.Send({
|
|
type: "loading",
|
|
props: { message: "Step 2: Generating response..." },
|
|
});
|
|
ctx.Flush();
|
|
|
|
// ... processing ...
|
|
|
|
// Final result
|
|
ctx.Send({
|
|
type: "text",
|
|
props: { content: "Process completed successfully!" },
|
|
});
|
|
ctx.Flush();
|
|
}
|
|
```
|
|
|
|
## Message Types
|
|
|
|
Built-in message types supported:
|
|
|
|
- `user_input` - User input (display only)
|
|
- `text` - Text content (supports Markdown)
|
|
- `thinking` - Reasoning/thinking process
|
|
- `loading` - Loading indicator
|
|
- `tool_call` - Tool/function call
|
|
- `error` - Error message
|
|
- `image` - Image content
|
|
- `audio` - Audio content
|
|
- `video` - Video content
|
|
- `action` - System action (silent in OpenAI clients)
|
|
- `event` - Lifecycle event (CUI only)
|
|
|
|
## Message Props by Type
|
|
|
|
### Text Message
|
|
|
|
```javascript
|
|
{
|
|
type: "text",
|
|
props: {
|
|
content: "Text content (supports Markdown)"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Thinking Message
|
|
|
|
```javascript
|
|
{
|
|
type: "thinking",
|
|
props: {
|
|
content: "Reasoning process..."
|
|
}
|
|
}
|
|
```
|
|
|
|
### Loading Message
|
|
|
|
```javascript
|
|
{
|
|
type: "loading",
|
|
props: {
|
|
message: "Loading message..."
|
|
}
|
|
}
|
|
```
|
|
|
|
### Tool Call Message
|
|
|
|
```javascript
|
|
{
|
|
type: "tool_call",
|
|
props: {
|
|
id: "call_123",
|
|
name: "function_name",
|
|
arguments: '{"key": "value"}'
|
|
}
|
|
}
|
|
```
|
|
|
|
### Error Message
|
|
|
|
```javascript
|
|
{
|
|
type: "error",
|
|
props: {
|
|
message: "Error message",
|
|
code: "ERROR_CODE",
|
|
details: "Additional details"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Image Message
|
|
|
|
```javascript
|
|
{
|
|
type: "image",
|
|
props: {
|
|
url: "https://example.com/image.jpg",
|
|
alt: "Image description",
|
|
width: 800,
|
|
height: 600
|
|
}
|
|
}
|
|
```
|
|
|
|
### Audio Message
|
|
|
|
```javascript
|
|
{
|
|
type: "audio",
|
|
props: {
|
|
url: "https://example.com/audio.mp3",
|
|
format: "mp3",
|
|
duration: 120.5,
|
|
transcript: "Audio transcript...",
|
|
autoplay: false,
|
|
controls: true
|
|
}
|
|
}
|
|
```
|
|
|
|
### Video Message
|
|
|
|
```javascript
|
|
{
|
|
type: "video",
|
|
props: {
|
|
url: "https://example.com/video.mp4",
|
|
format: "mp4",
|
|
thumbnail: "https://example.com/thumb.jpg",
|
|
width: 1920,
|
|
height: 1080,
|
|
autoplay: false,
|
|
controls: true
|
|
}
|
|
}
|
|
```
|
|
|
|
## Delta Updates
|
|
|
|
Use delta updates for streaming scenarios:
|
|
|
|
```javascript
|
|
// Initial message
|
|
ctx.Send({
|
|
type: "text",
|
|
props: { content: "Hello" },
|
|
id: "msg_1",
|
|
delta: false,
|
|
});
|
|
|
|
// Append to content
|
|
ctx.Send({
|
|
type: "text",
|
|
props: { content: " World" },
|
|
id: "msg_1",
|
|
delta: true,
|
|
delta_path: "content",
|
|
delta_action: "append",
|
|
});
|
|
|
|
// Mark as complete
|
|
ctx.Send({
|
|
type: "text",
|
|
props: {},
|
|
id: "msg_1",
|
|
done: true,
|
|
});
|
|
```
|
|
|
|
**Delta Actions:**
|
|
|
|
- `append` - Append to string or array
|
|
- `replace` - Replace value
|
|
- `merge` - Merge objects
|
|
- `set` - Set new field
|
|
|
|
## Notes
|
|
|
|
1. **No Separate Output API Needed**: The previous `const output = new Output(ctx)` approach is deprecated. Now use `ctx.Send()` methods directly.
|
|
|
|
2. **Automatic Client Handling**: Messages are automatically converted to the appropriate format based on `ctx.accept`:
|
|
|
|
- `standard` → OpenAI format
|
|
- `cui-web`/`cui-native`/`cui-desktop` → CUI native format
|
|
|
|
3. **Performance Optimization**: Output objects are automatically cached and managed, no manual management needed.
|
|
|
|
4. **Error Handling**: All methods throw JavaScript exceptions on failure, which can be caught with try-catch.
|
|
|
|
5. **Streaming Support**: Use delta updates with unique message IDs for real-time streaming scenarios.
|
|
|
|
6. **Metadata**: Optional metadata can be attached to messages for tracking, debugging, or custom processing.
|
|
|
|
## Migration Guide
|
|
|
|
**Before (Deprecated):**
|
|
|
|
```javascript
|
|
// Old way - no longer needed
|
|
const output = new Output(ctx)
|
|
output.Send("Hello")
|
|
output.SendGroup({ id: "grp1", messages: [...] })
|
|
```
|
|
|
|
**After (Current):**
|
|
|
|
```javascript
|
|
// New way - simpler and cleaner
|
|
ctx.Send("Hello")
|
|
ctx.SendGroup({ id: "grp1", messages: [...] })
|
|
ctx.Flush()
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
1. **Use String Shorthand for Simple Messages**: `ctx.Send("Hello")` instead of `ctx.Send({ type: "text", props: { content: "Hello" } })`
|
|
|
|
2. **Always Flush After Important Messages**: Use `ctx.Flush()` to ensure messages are sent immediately
|
|
|
|
3. **Use Unique IDs for Delta Updates**: Assign unique IDs to messages that will receive incremental updates
|
|
|
|
4. **Handle Errors Gracefully**: Wrap Send operations in try-catch blocks for robust error handling
|
|
|
|
5. **Use Loading Indicators**: Show loading messages for long-running operations to improve UX
|
|
|
|
6. **Group Related Messages**: Use `SendGroup` for semantically related messages that should be displayed together
|