format: apply repo prettier (3.8.1) to the folded skills tree
963 markdown files reformatted with the repository's pinned prettier so pnpm format:check covers the folded tree like every other repo file. The formatter's embedded-language pass also normalized code fences (TS semicolons, closed HTML tags in examples, lowercased CSS hex colors, one renumbered list that skipped an index). Alphanumeric token deltas vs the fold commit were audited file-by-file; all are formatter-equivalent markup normalizations plus the four sanitized skills.
This commit is contained in:
@@ -121,19 +121,18 @@ export interface Message {
|
||||
export interface AgentEvents {
|
||||
'message:user': (message: Message) => void;
|
||||
'message:assistant': (message: Message) => void;
|
||||
'item:update': (item: StreamableOutputItem) => void; // Items emitted with same ID, replace by ID
|
||||
'item:update': (item: StreamableOutputItem) => void; // Items emitted with same ID, replace by ID
|
||||
'stream:start': () => void;
|
||||
'stream:delta': (delta: string, accumulated: string) => void;
|
||||
'stream:end': (fullText: string) => void;
|
||||
'tool:call': (name: string, args: unknown) => void;
|
||||
'tool:result': (name: string, result: unknown) => void;
|
||||
'reasoning:update': (text: string) => void; // Extended thinking content
|
||||
'error': (error: Error) => void;
|
||||
'reasoning:update': (text: string) => void; // Extended thinking content
|
||||
error: (error: Error) => void;
|
||||
'thinking:start': () => void;
|
||||
'thinking:end': () => void;
|
||||
}
|
||||
|
||||
|
||||
// Agent configuration
|
||||
export interface AgentConfig {
|
||||
apiKey: string;
|
||||
@@ -211,7 +210,9 @@ export class Agent extends EventEmitter<AgentEvents> {
|
||||
switch (item.type) {
|
||||
case 'message':
|
||||
// Message items contain progressively updated content
|
||||
const textContent = item.content?.find((c: { type: string }) => c.type === 'output_text');
|
||||
const textContent = item.content?.find(
|
||||
(c: { type: string }) => c.type === 'output_text',
|
||||
);
|
||||
if (textContent && 'text' in textContent) {
|
||||
const newText = textContent.text;
|
||||
if (newText !== fullText) {
|
||||
@@ -232,7 +233,9 @@ export class Agent extends EventEmitter<AgentEvents> {
|
||||
break;
|
||||
case 'reasoning':
|
||||
// Extended thinking/reasoning content
|
||||
const reasoningText = item.content?.find((c: { type: string }) => c.type === 'reasoning_text');
|
||||
const reasoningText = item.content?.find(
|
||||
(c: { type: string }) => c.type === 'reasoning_text',
|
||||
);
|
||||
if (reasoningText && 'text' in reasoningText) {
|
||||
this.emit('reasoning:update', reasoningText.text);
|
||||
}
|
||||
@@ -426,7 +429,9 @@ function ItemRenderer({ item }: { item: StreamableOutputItem }) {
|
||||
const text = textContent && 'text' in textContent ? textContent.text : '';
|
||||
return (
|
||||
<Box flexDirection="column" marginBottom={1}>
|
||||
<Text bold color="green">◀ Assistant</Text>
|
||||
<Text bold color="green">
|
||||
◀ Assistant
|
||||
</Text>
|
||||
<Text wrap="wrap">{text}</Text>
|
||||
{item.status !== 'completed' && <Text color="gray">▌</Text>}
|
||||
</Box>
|
||||
@@ -440,12 +445,18 @@ function ItemRenderer({ item }: { item: StreamableOutputItem }) {
|
||||
</Text>
|
||||
);
|
||||
case 'reasoning': {
|
||||
const reasoningText = item.content?.find((c: { type: string }) => c.type === 'reasoning_text');
|
||||
const reasoningText = item.content?.find(
|
||||
(c: { type: string }) => c.type === 'reasoning_text',
|
||||
);
|
||||
const text = reasoningText && 'text' in reasoningText ? reasoningText.text : '';
|
||||
return (
|
||||
<Box flexDirection="column" marginBottom={1}>
|
||||
<Text bold color="magenta">💭 Thinking</Text>
|
||||
<Text wrap="wrap" color="gray">{text}</Text>
|
||||
<Text bold color="magenta">
|
||||
💭 Thinking
|
||||
</Text>
|
||||
<Text wrap="wrap" color="gray">
|
||||
{text}
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -539,7 +550,9 @@ function App() {
|
||||
return (
|
||||
<Box flexDirection="column" padding={1}>
|
||||
<Box marginBottom={1}>
|
||||
<Text bold color="magenta">🤖 OpenRouter Agent</Text>
|
||||
<Text bold color="magenta">
|
||||
🤖 OpenRouter Agent
|
||||
</Text>
|
||||
<Text color="gray"> (Esc to exit)</Text>
|
||||
</Box>
|
||||
|
||||
@@ -556,12 +569,7 @@ function App() {
|
||||
</Box>
|
||||
|
||||
<Box borderStyle="single" borderColor="gray" paddingX={1}>
|
||||
<InputField
|
||||
value={input}
|
||||
onChange={setInput}
|
||||
onSubmit={sendMessage}
|
||||
disabled={isLoading}
|
||||
/>
|
||||
<InputField value={input} onChange={setInput} onSubmit={sendMessage} disabled={isLoading} />
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
@@ -601,24 +609,27 @@ For function calls, arguments stream progressively:
|
||||
### Why Items Are Better
|
||||
|
||||
**Traditional (accumulation required):**
|
||||
|
||||
```typescript
|
||||
let text = '';
|
||||
for await (const chunk of result.getTextStream()) {
|
||||
text += chunk; // Manual accumulation
|
||||
text += chunk; // Manual accumulation
|
||||
updateUI(text);
|
||||
}
|
||||
```
|
||||
|
||||
**Items (complete replacement):**
|
||||
|
||||
```typescript
|
||||
const items = new Map<string, StreamableOutputItem>();
|
||||
for await (const item of result.getItemsStream()) {
|
||||
items.set(item.id, item); // Replace by ID
|
||||
items.set(item.id, item); // Replace by ID
|
||||
updateUI(items);
|
||||
}
|
||||
```
|
||||
|
||||
Benefits:
|
||||
|
||||
- **No manual chunk management** - each item is complete
|
||||
- **Handles concurrent outputs** - function calls and messages can stream in parallel
|
||||
- **Full TypeScript inference** for all item types
|
||||
@@ -710,55 +721,55 @@ discord.login(process.env.DISCORD_TOKEN);
|
||||
|
||||
### Constructor Options
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| apiKey | string | required | OpenRouter API key |
|
||||
| model | string | 'openrouter/auto' | Model to use |
|
||||
| instructions | string | 'You are a helpful assistant.' | System prompt |
|
||||
| tools | Tool[] | [] | Available tools |
|
||||
| maxSteps | number | 5 | Max agentic loop iterations |
|
||||
| Option | Type | Default | Description |
|
||||
| ------------ | ------ | ------------------------------ | --------------------------- |
|
||||
| apiKey | string | required | OpenRouter API key |
|
||||
| model | string | 'openrouter/auto' | Model to use |
|
||||
| instructions | string | 'You are a helpful assistant.' | System prompt |
|
||||
| tools | Tool[] | [] | Available tools |
|
||||
| maxSteps | number | 5 | Max agentic loop iterations |
|
||||
|
||||
### Methods
|
||||
|
||||
| Method | Returns | Description |
|
||||
|--------|---------|-------------|
|
||||
| `send(content)` | Promise<string> | Send message with streaming |
|
||||
| `sendSync(content)` | Promise<string> | Send message without streaming |
|
||||
| `getMessages()` | Message[] | Get conversation history |
|
||||
| `clearHistory()` | void | Clear conversation |
|
||||
| `setInstructions(text)` | void | Update system prompt |
|
||||
| `addTool(tool)` | void | Add tool at runtime |
|
||||
| Method | Returns | Description |
|
||||
| ----------------------- | --------------- | ------------------------------ |
|
||||
| `send(content)` | Promise<string> | Send message with streaming |
|
||||
| `sendSync(content)` | Promise<string> | Send message without streaming |
|
||||
| `getMessages()` | Message[] | Get conversation history |
|
||||
| `clearHistory()` | void | Clear conversation |
|
||||
| `setInstructions(text)` | void | Update system prompt |
|
||||
| `addTool(tool)` | void | Add tool at runtime |
|
||||
|
||||
### Events
|
||||
|
||||
| Event | Payload | Description |
|
||||
|-------|---------|-------------|
|
||||
| `message:user` | Message | User message added |
|
||||
| `message:assistant` | Message | Assistant response complete |
|
||||
| `item:update` | StreamableOutputItem | Item emitted (replace by ID, don't accumulate) |
|
||||
| `stream:start` | - | Streaming started |
|
||||
| `stream:delta` | (delta, accumulated) | New text chunk |
|
||||
| `stream:end` | fullText | Streaming complete |
|
||||
| `tool:call` | (name, args) | Tool being called |
|
||||
| `tool:result` | (name, result) | Tool returned result |
|
||||
| `reasoning:update` | text | Extended thinking content |
|
||||
| `thinking:start` | - | Agent processing |
|
||||
| `thinking:end` | - | Agent done processing |
|
||||
| `error` | Error | Error occurred |
|
||||
| Event | Payload | Description |
|
||||
| ------------------- | -------------------- | ---------------------------------------------- |
|
||||
| `message:user` | Message | User message added |
|
||||
| `message:assistant` | Message | Assistant response complete |
|
||||
| `item:update` | StreamableOutputItem | Item emitted (replace by ID, don't accumulate) |
|
||||
| `stream:start` | - | Streaming started |
|
||||
| `stream:delta` | (delta, accumulated) | New text chunk |
|
||||
| `stream:end` | fullText | Streaming complete |
|
||||
| `tool:call` | (name, args) | Tool being called |
|
||||
| `tool:result` | (name, result) | Tool returned result |
|
||||
| `reasoning:update` | text | Extended thinking content |
|
||||
| `thinking:start` | - | Agent processing |
|
||||
| `thinking:end` | - | Agent done processing |
|
||||
| `error` | Error | Error occurred |
|
||||
|
||||
### Item Types (from getItemsStream)
|
||||
|
||||
The SDK uses an items-based streaming model where items are emitted multiple times with the same ID but progressively updated content. Replace items by their ID rather than accumulating chunks.
|
||||
|
||||
| Type | Purpose |
|
||||
|------|---------|
|
||||
| `message` | Assistant text responses |
|
||||
| `function_call` | Tool invocations with streaming arguments |
|
||||
| `function_call_output` | Results from executed tools |
|
||||
| `reasoning` | Extended thinking content |
|
||||
| `web_search_call` | Web search operations |
|
||||
| `file_search_call` | File search operations |
|
||||
| `image_generation_call` | Image generation operations |
|
||||
| Type | Purpose |
|
||||
| ----------------------- | ----------------------------------------- |
|
||||
| `message` | Assistant text responses |
|
||||
| `function_call` | Tool invocations with streaming arguments |
|
||||
| `function_call_output` | Results from executed tools |
|
||||
| `reasoning` | Extended thinking content |
|
||||
| `web_search_call` | Web search operations |
|
||||
| `file_search_call` | File search operations |
|
||||
| `image_generation_call` | Image generation operations |
|
||||
|
||||
## Discovering Models
|
||||
|
||||
@@ -784,8 +795,8 @@ async function fetchModels(): Promise<OpenRouterModel[]> {
|
||||
|
||||
// Find models by criteria
|
||||
async function findModels(filter: {
|
||||
author?: string; // e.g., 'anthropic', 'openai', 'google'
|
||||
minContext?: number; // e.g., 100000 for 100k context
|
||||
author?: string; // e.g., 'anthropic', 'openai', 'google'
|
||||
minContext?: number; // e.g., 100000 for 100k context
|
||||
maxPromptPrice?: number; // e.g., 0.001 for cheap models
|
||||
}): Promise<OpenRouterModel[]> {
|
||||
const models = await fetchModels();
|
||||
@@ -821,7 +832,7 @@ const bestModel = models.find((m) => m.id.includes('claude')) || models[0];
|
||||
|
||||
const agent = createAgent({
|
||||
apiKey: process.env.OPENROUTER_API_KEY!,
|
||||
model: bestModel.id, // Use discovered model
|
||||
model: bestModel.id, // Use discovered model
|
||||
instructions: 'You are a helpful assistant.',
|
||||
});
|
||||
```
|
||||
@@ -834,7 +845,7 @@ available model for your request:
|
||||
```typescript
|
||||
const agent = createAgent({
|
||||
apiKey: process.env.OPENROUTER_API_KEY!,
|
||||
model: 'openrouter/auto', // Auto-selects best model
|
||||
model: 'openrouter/auto', // Auto-selects best model
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user