@agentionai/agents 0.9.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -0
- package/dist/agents/BaseAgent.d.ts +2 -2
- package/dist/agents/anthropic/ClaudeAgent.d.ts +2 -2
- package/dist/agents/anthropic/ClaudeAgent.js +13 -2
- package/dist/agents/google/GeminiAgent.d.ts +2 -2
- package/dist/agents/google/GeminiAgent.js +11 -2
- package/dist/agents/mistral/MistralAgent.d.ts +2 -2
- package/dist/agents/mistral/MistralAgent.js +11 -2
- package/dist/agents/openai/OpenAiAgent.d.ts +2 -2
- package/dist/agents/openai/OpenAiAgent.js +11 -2
- package/dist/history/History.d.ts +31 -3
- package/dist/history/History.js +80 -8
- package/dist/history/RedisHistory.d.ts +5 -3
- package/dist/history/RedisHistory.js +22 -11
- package/dist/history/plugins/toolResultMaskingPlugin.js +6 -0
- package/dist/history/transformers.js +101 -14
- package/dist/history/types.d.ts +39 -1
- package/dist/history/types.js +26 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -73,6 +73,7 @@ import { ClaudeAgent, OpenAiAgent } from '@agentionai/agents';
|
|
|
73
73
|
|
|
74
74
|
- **Multi-Provider, No Lock-in** - Claude, OpenAI, Gemini, Mistral—same interface. Switch models with one line.
|
|
75
75
|
- **Composable, Not Magical** - Agents are objects. Pipelines are arrays. No hidden state, no surprises.
|
|
76
|
+
- **Multimodal / Vision** - Send images alongside text with a unified `MessageContent[]` API across all providers.
|
|
76
77
|
- **Full Observability** - Per-call token counts, execution timing, pipeline structure visualization.
|
|
77
78
|
- **TypeScript-Native** - Strict typing, interfaces, and generics from the ground up.
|
|
78
79
|
- **RAG Ready** - LanceDB vector store, token-aware chunking, ingestion pipeline out of the box.
|
|
@@ -175,6 +176,43 @@ const researcher = new ClaudeAgent({
|
|
|
175
176
|
const result = await researcher.execute('Latest developments in quantum computing');
|
|
176
177
|
```
|
|
177
178
|
|
|
179
|
+
### Multimodal / Vision
|
|
180
|
+
|
|
181
|
+
Send images alongside text using `imageUrl()` or `imageBase64()`. The same `MessageContent[]` interface works across all providers:
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
import { ClaudeAgent } from '@agentionai/agents/claude';
|
|
185
|
+
import { imageUrl, imageBase64 } from '@agentionai/agents/core';
|
|
186
|
+
import * as fs from 'fs';
|
|
187
|
+
|
|
188
|
+
const agent = new ClaudeAgent({
|
|
189
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
190
|
+
model: 'claude-opus-4-6',
|
|
191
|
+
name: 'VisionAgent',
|
|
192
|
+
description: 'You analyze images.',
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// Remote image by URL
|
|
196
|
+
const response = await agent.execute([
|
|
197
|
+
imageUrl('https://example.com/chart.png'),
|
|
198
|
+
{ type: 'text', text: 'Summarize this chart in one sentence.' },
|
|
199
|
+
]);
|
|
200
|
+
|
|
201
|
+
// Local image as base64
|
|
202
|
+
const data = fs.readFileSync('./photo.jpg').toString('base64');
|
|
203
|
+
const response2 = await agent.execute([
|
|
204
|
+
imageBase64(data, 'image/jpeg'),
|
|
205
|
+
{ type: 'text', text: 'What plant is this?' },
|
|
206
|
+
]);
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
| Provider | URL | Base64 |
|
|
210
|
+
|----------|:---:|:------:|
|
|
211
|
+
| Claude | ✅ | ✅ |
|
|
212
|
+
| OpenAI | ✅ | ✅ |
|
|
213
|
+
| Gemini | ✅ | ✅ |
|
|
214
|
+
| Mistral | ✅ | ❌ |
|
|
215
|
+
|
|
178
216
|
## Core Concepts
|
|
179
217
|
|
|
180
218
|
### Agents
|
|
@@ -187,6 +225,11 @@ JSON Schema + handler pattern. Unique capability: wrap any agent as a tool for d
|
|
|
187
225
|
|
|
188
226
|
[Learn more →](https://docs.agention.ai/guide/tools)
|
|
189
227
|
|
|
228
|
+
### Multimodal / Vision
|
|
229
|
+
Unified `MessageContent[]` interface for images across all providers. URL and base64 images, mix text and images freely in a single call.
|
|
230
|
+
|
|
231
|
+
[Learn more →](https://docs.agention.ai/guide/multimodal)
|
|
232
|
+
|
|
190
233
|
### History
|
|
191
234
|
Provider-agnostic, persistent (Redis, file, custom), shareable across agents of different providers.
|
|
192
235
|
|
|
@@ -213,6 +256,7 @@ Per-call and per-node token counts, duration metrics, full execution visibility.
|
|
|
213
256
|
- **[Quick Start](https://docs.agention.ai/guide/quickstart)** - Build a weather assistant in 5 minutes
|
|
214
257
|
- **[Agents](https://docs.agention.ai/guide/agents)** - Agent configuration and providers
|
|
215
258
|
- **[Tools](https://docs.agention.ai/guide/tools)** - Adding capabilities and agent delegation
|
|
259
|
+
- **[Multimodal / Vision](https://docs.agention.ai/guide/multimodal)** - Sending images across all providers
|
|
216
260
|
- **[Graph Pipelines](https://docs.agention.ai/guide/graph-pipelines)** - Multi-agent workflows
|
|
217
261
|
- **[Vector Stores](https://docs.agention.ai/guide/vector-stores)** - RAG and semantic search
|
|
218
262
|
- **[Examples](https://docs.agention.ai/guide/examples)** - Real-world implementations
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import EventEmitter from "events";
|
|
2
2
|
import { Tool } from "../tools/Tool";
|
|
3
|
-
import { History, HistoryEntry, MessageRole, MessageContent } from "../history/History";
|
|
3
|
+
import { History, HistoryEntry, MessageRole, MessageContent, ImageMimeType } from "../history/History";
|
|
4
4
|
import { AgentVendor, CommonAgentConfig, VendorSpecificConfig } from "./AgentConfig";
|
|
5
|
-
export type { HistoryEntry, MessageRole, MessageContent };
|
|
5
|
+
export type { HistoryEntry, MessageRole, MessageContent, ImageMimeType };
|
|
6
6
|
export type { AgentVendor };
|
|
7
7
|
/**
|
|
8
8
|
* Agent config as used across all agents
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Message, Usage } from "@anthropic-ai/sdk/resources";
|
|
2
2
|
import { type ToolDefinition } from "../../tools/Tool";
|
|
3
3
|
import { BaseAgent, BaseAgentConfig, TokenUsage } from "../BaseAgent";
|
|
4
|
-
import { History } from "../../history/History";
|
|
4
|
+
import { History, MessageContent } from "../../history/History";
|
|
5
5
|
import { ClaudeModel } from "../model-types";
|
|
6
6
|
type AgentConfig = BaseAgentConfig & {
|
|
7
7
|
apiKey: string;
|
|
@@ -37,7 +37,7 @@ export declare class ClaudeAgent extends BaseAgent {
|
|
|
37
37
|
constructor(config: Omit<AgentConfig, "vendor">, history?: History);
|
|
38
38
|
protected getToolDefinitions(): ToolDefinition[];
|
|
39
39
|
protected process(_input: string): Promise<string>;
|
|
40
|
-
execute(input: string): Promise<string>;
|
|
40
|
+
execute(input: string | MessageContent[]): Promise<string>;
|
|
41
41
|
protected handleResponse(response: Message): Promise<string>;
|
|
42
42
|
private handleToolUse;
|
|
43
43
|
protected parseUsage(input: Usage): TokenUsage;
|
|
@@ -64,16 +64,26 @@ class ClaudeAgent extends BaseAgent_1.BaseAgent {
|
|
|
64
64
|
// Reset token usage for this execution
|
|
65
65
|
this.lastTokenUsage = undefined;
|
|
66
66
|
this.currentToolCallCount = 0;
|
|
67
|
+
// Normalise input to a display string for viz reporting
|
|
68
|
+
const inputPreview = typeof input === "string" ? input : JSON.stringify(input);
|
|
67
69
|
// Start visualization reporting
|
|
68
70
|
if (VizConfig_1.vizConfig.isEnabled()) {
|
|
69
|
-
this.vizEventId = VizReporter_1.vizReporter.agentStart(this.id, this.name, this.config.model, "anthropic",
|
|
71
|
+
this.vizEventId = VizReporter_1.vizReporter.agentStart(this.id, this.name, this.config.model, "anthropic", inputPreview);
|
|
70
72
|
}
|
|
71
73
|
if (this.history.transient) {
|
|
72
74
|
this.history.clear();
|
|
73
75
|
// Re-add system message after clear
|
|
74
76
|
this.addSystemMessage(this.getSystemMessage());
|
|
75
77
|
}
|
|
76
|
-
|
|
78
|
+
if (typeof input === "string") {
|
|
79
|
+
this.addTextToHistory("user", input);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
this.addMessageToHistory("user", input);
|
|
83
|
+
}
|
|
84
|
+
// Mark session boundary so transform plugins (e.g. toolResultMaskingPlugin)
|
|
85
|
+
// don't mask tool results produced within this execute() loop.
|
|
86
|
+
this.history.setSessionAnchor();
|
|
77
87
|
try {
|
|
78
88
|
const messages = transformers_1.anthropicTransformer.toProvider(this.history.getEntries());
|
|
79
89
|
const systemMessage = this.history.getSystemMessage();
|
|
@@ -180,6 +190,7 @@ class ClaudeAgent extends BaseAgent_1.BaseAgent {
|
|
|
180
190
|
const messages = transformers_1.anthropicTransformer.toProvider(this.history.getEntries());
|
|
181
191
|
const newResponse = await this.client.messages.create({
|
|
182
192
|
model: this.config.model,
|
|
193
|
+
system: this.history.getSystemMessage(),
|
|
183
194
|
max_tokens: this.config.maxTokens,
|
|
184
195
|
messages,
|
|
185
196
|
tools: this.getToolDefinitions(),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FunctionDeclarationsTool, GenerateContentResult, Schema } from "@google/generative-ai";
|
|
2
2
|
import { BaseAgent, BaseAgentConfig, TokenUsage } from "../BaseAgent";
|
|
3
|
-
import { History } from "../../history/History";
|
|
3
|
+
import { History, MessageContent } from "../../history/History";
|
|
4
4
|
import { GeminiModel } from "../model-types";
|
|
5
5
|
type AgentConfig = BaseAgentConfig & {
|
|
6
6
|
apiKey: string;
|
|
@@ -50,7 +50,7 @@ export declare class GeminiAgent extends BaseAgent {
|
|
|
50
50
|
*/
|
|
51
51
|
private mapJsonSchemaTypeToGemini;
|
|
52
52
|
protected process(_input: string): Promise<string>;
|
|
53
|
-
execute(input: string): Promise<string>;
|
|
53
|
+
execute(input: string | MessageContent[]): Promise<string>;
|
|
54
54
|
protected handleResponse(response: GenerateContentResult): Promise<string>;
|
|
55
55
|
private handleFunctionCalls;
|
|
56
56
|
protected parseUsage(input: {
|
|
@@ -165,16 +165,25 @@ class GeminiAgent extends BaseAgent_1.BaseAgent {
|
|
|
165
165
|
// Reset token usage for this execution
|
|
166
166
|
this.lastTokenUsage = undefined;
|
|
167
167
|
this.currentToolCallCount = 0;
|
|
168
|
+
const inputPreview = typeof input === "string" ? input : JSON.stringify(input);
|
|
168
169
|
// Start visualization reporting
|
|
169
170
|
if (VizConfig_1.vizConfig.isEnabled()) {
|
|
170
|
-
this.vizEventId = VizReporter_1.vizReporter.agentStart(this.id, this.name, this.config.model, "gemini",
|
|
171
|
+
this.vizEventId = VizReporter_1.vizReporter.agentStart(this.id, this.name, this.config.model, "gemini", inputPreview);
|
|
171
172
|
}
|
|
172
173
|
if (this.history.transient) {
|
|
173
174
|
this.history.clear();
|
|
174
175
|
// Re-add system message after clear
|
|
175
176
|
this.addSystemMessage(this.getSystemMessage());
|
|
176
177
|
}
|
|
177
|
-
|
|
178
|
+
if (typeof input === "string") {
|
|
179
|
+
this.addTextToHistory("user", input);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
this.addMessageToHistory("user", input);
|
|
183
|
+
}
|
|
184
|
+
// Mark session boundary so transform plugins (e.g. toolResultMaskingPlugin)
|
|
185
|
+
// don't mask tool results produced within this execute() loop.
|
|
186
|
+
this.history.setSessionAnchor();
|
|
178
187
|
try {
|
|
179
188
|
const contents = transformers_1.geminiTransformer.toProvider(this.history.getEntries());
|
|
180
189
|
const systemMessage = this.history.getSystemMessage();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BaseAgent, BaseAgentConfig, TokenUsage } from "../BaseAgent";
|
|
2
|
-
import { History } from "../../history/History";
|
|
2
|
+
import { History, MessageContent } from "../../history/History";
|
|
3
3
|
import { ChatCompletionResponse, Tool, UsageInfo } from "@mistralai/mistralai/models/components";
|
|
4
4
|
import { MistralModel } from "../model-types";
|
|
5
5
|
type AgentConfig = BaseAgentConfig & {
|
|
@@ -38,7 +38,7 @@ export declare class MistralAgent extends BaseAgent {
|
|
|
38
38
|
constructor(config: Omit<AgentConfig, "vendor">, history?: History);
|
|
39
39
|
protected getToolDefinitions(): Tool[];
|
|
40
40
|
protected process(_input: string): Promise<string>;
|
|
41
|
-
execute(input: string): Promise<string>;
|
|
41
|
+
execute(input: string | MessageContent[]): Promise<string>;
|
|
42
42
|
protected handleResponse(response: ChatCompletionResponse): Promise<string>;
|
|
43
43
|
private handleToolCalls;
|
|
44
44
|
protected parseUsage(input: UsageInfo): TokenUsage;
|
|
@@ -75,16 +75,25 @@ class MistralAgent extends BaseAgent_1.BaseAgent {
|
|
|
75
75
|
// Reset token usage for this execution
|
|
76
76
|
this.lastTokenUsage = undefined;
|
|
77
77
|
this.currentToolCallCount = 0;
|
|
78
|
+
const inputPreview = typeof input === "string" ? input : JSON.stringify(input);
|
|
78
79
|
// Start visualization reporting
|
|
79
80
|
if (VizConfig_1.vizConfig.isEnabled()) {
|
|
80
|
-
this.vizEventId = VizReporter_1.vizReporter.agentStart(this.id, this.name, this.config.model, "mistral",
|
|
81
|
+
this.vizEventId = VizReporter_1.vizReporter.agentStart(this.id, this.name, this.config.model, "mistral", inputPreview);
|
|
81
82
|
}
|
|
82
83
|
if (this.history.transient) {
|
|
83
84
|
this.history.clear();
|
|
84
85
|
// Re-add system message after clear
|
|
85
86
|
this.addSystemMessage(this.getSystemMessage());
|
|
86
87
|
}
|
|
87
|
-
|
|
88
|
+
if (typeof input === "string") {
|
|
89
|
+
this.addTextToHistory("user", input);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
this.addMessageToHistory("user", input);
|
|
93
|
+
}
|
|
94
|
+
// Mark session boundary so transform plugins (e.g. toolResultMaskingPlugin)
|
|
95
|
+
// don't mask tool results produced within this execute() loop.
|
|
96
|
+
this.history.setSessionAnchor();
|
|
88
97
|
try {
|
|
89
98
|
const messages = transformers_1.mistralTransformer.toProvider(this.history.getEntries());
|
|
90
99
|
const response = await this.client.chat.complete({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BaseAgent, BaseAgentConfig, TokenUsage } from "../BaseAgent";
|
|
2
|
-
import { History } from "../../history/History";
|
|
2
|
+
import { History, MessageContent } from "../../history/History";
|
|
3
3
|
import { Tool, Response, ResponseUsage } from "openai/resources/responses/responses";
|
|
4
4
|
import { OpenAIModel } from "../model-types";
|
|
5
5
|
type AgentConfig = BaseAgentConfig & {
|
|
@@ -39,7 +39,7 @@ export declare class OpenAiAgent extends BaseAgent {
|
|
|
39
39
|
constructor(config: Omit<AgentConfig, "vendor">, history?: History);
|
|
40
40
|
protected getToolDefinitions(): Tool[];
|
|
41
41
|
protected process(_input: string): Promise<string>;
|
|
42
|
-
execute(input: string): Promise<string>;
|
|
42
|
+
execute(input: string | MessageContent[]): Promise<string>;
|
|
43
43
|
protected handleResponse(response: Response): Promise<string>;
|
|
44
44
|
private handleToolUse;
|
|
45
45
|
protected parseUsage(input: ResponseUsage): TokenUsage;
|
|
@@ -86,16 +86,25 @@ class OpenAiAgent extends BaseAgent_1.BaseAgent {
|
|
|
86
86
|
// Reset token usage for this execution
|
|
87
87
|
this.lastTokenUsage = undefined;
|
|
88
88
|
this.currentToolCallCount = 0;
|
|
89
|
+
const inputPreview = typeof input === "string" ? input : JSON.stringify(input);
|
|
89
90
|
// Start visualization reporting
|
|
90
91
|
if (VizConfig_1.vizConfig.isEnabled()) {
|
|
91
|
-
this.vizEventId = VizReporter_1.vizReporter.agentStart(this.id, this.name, this.config.model, "openai",
|
|
92
|
+
this.vizEventId = VizReporter_1.vizReporter.agentStart(this.id, this.name, this.config.model, "openai", inputPreview);
|
|
92
93
|
}
|
|
93
94
|
if (this.history.transient) {
|
|
94
95
|
this.history.clear();
|
|
95
96
|
// Re-add system message after clear
|
|
96
97
|
this.addSystemMessage(this.getSystemMessage());
|
|
97
98
|
}
|
|
98
|
-
|
|
99
|
+
if (typeof input === "string") {
|
|
100
|
+
this.addTextToHistory("user", input);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
this.addMessageToHistory("user", input);
|
|
104
|
+
}
|
|
105
|
+
// Mark session boundary so transform plugins (e.g. toolResultMaskingPlugin)
|
|
106
|
+
// don't mask tool results produced within this execute() loop.
|
|
107
|
+
this.history.setSessionAnchor();
|
|
99
108
|
try {
|
|
100
109
|
const inputMessages = transformers_1.openAiTransformer.toProvider(this.history.getEntries());
|
|
101
110
|
const response = await this.client.responses.create({
|
|
@@ -3,8 +3,8 @@ import { HistoryEntry, MessageRole, MessageContent } from "./types";
|
|
|
3
3
|
import type { ReduceOptions } from "./types";
|
|
4
4
|
/** @internal — exposed for test teardown only */
|
|
5
5
|
export declare function resetTokenxCache(): void;
|
|
6
|
-
export type { HistoryEntry, MessageRole, MessageContent, ReduceOptions } from "./types";
|
|
7
|
-
export { text, toolUse, toolResult, textMessage, isTextContent, isToolUseContent, isToolResultContent, } from "./types";
|
|
6
|
+
export type { HistoryEntry, MessageRole, MessageContent, ReduceOptions, ImageMimeType, ImageUrlContent, ImageBase64Content, } from "./types";
|
|
7
|
+
export { text, toolUse, toolResult, textMessage, imageUrl, imageBase64, isTextContent, isToolUseContent, isToolResultContent, isImageUrlContent, isImageBase64Content, isImageContent, } from "./types";
|
|
8
8
|
/**
|
|
9
9
|
* Metadata stored alongside each history entry.
|
|
10
10
|
* Extended with summary tracking fields for the compression plugin.
|
|
@@ -61,7 +61,7 @@ type EntryWithMetadata = ReducibleEntry;
|
|
|
61
61
|
/**
|
|
62
62
|
* History configuration options
|
|
63
63
|
*/
|
|
64
|
-
type HistoryOptions = {
|
|
64
|
+
export type HistoryOptions = {
|
|
65
65
|
maxLength?: number;
|
|
66
66
|
/**
|
|
67
67
|
* Maximum estimated tokens to retain in history. When exceeded, oldest
|
|
@@ -123,6 +123,7 @@ export declare class History extends EventEmitter {
|
|
|
123
123
|
transient: boolean;
|
|
124
124
|
private _plugins;
|
|
125
125
|
private _reducing;
|
|
126
|
+
private _sessionAnchor;
|
|
126
127
|
constructor(entries?: HistoryEntry[], options?: HistoryOptions);
|
|
127
128
|
/**
|
|
128
129
|
* Register a plugin with this history instance.
|
|
@@ -137,6 +138,20 @@ export declare class History extends EventEmitter {
|
|
|
137
138
|
* ```
|
|
138
139
|
*/
|
|
139
140
|
use(plugin: HistoryPlugin): this;
|
|
141
|
+
/**
|
|
142
|
+
* Mark the current entry count as the session boundary.
|
|
143
|
+
* Call this at the start of each agent `execute()` after adding the user
|
|
144
|
+
* message. Transform plugins (e.g. toolResultMaskingPlugin) will not mask
|
|
145
|
+
* any entries added at or after this position, preventing tool results from
|
|
146
|
+
* the current execution loop from being masked mid-session.
|
|
147
|
+
*/
|
|
148
|
+
setSessionAnchor(): void;
|
|
149
|
+
/**
|
|
150
|
+
* The entry index set by the last call to `setSessionAnchor()`, or `null`
|
|
151
|
+
* if no anchor has been set. Entries at this index or beyond belong to the
|
|
152
|
+
* current session and should not be masked by transform plugins.
|
|
153
|
+
*/
|
|
154
|
+
get sessionAnchor(): number | null;
|
|
140
155
|
/**
|
|
141
156
|
* Add a complete history entry
|
|
142
157
|
*/
|
|
@@ -232,11 +247,24 @@ export declare class History extends EventEmitter {
|
|
|
232
247
|
* Create a copy of this history
|
|
233
248
|
*/
|
|
234
249
|
clone(options?: HistoryOptions): History;
|
|
250
|
+
/**
|
|
251
|
+
* Apply maxLength and maxTokens trimming to the current entry list.
|
|
252
|
+
* Safe to call after bulk-loading entries (e.g. RedisHistory.load()).
|
|
253
|
+
* Subclasses may call this after directly manipulating _entries.
|
|
254
|
+
*/
|
|
255
|
+
protected applyTrimming(): void;
|
|
235
256
|
/**
|
|
236
257
|
* Drop oldest non-system entries until totalEstimatedTokens fits within budget.
|
|
237
258
|
* Called synchronously from addEntry() as a safety net.
|
|
238
259
|
* The system message is always preserved.
|
|
239
260
|
*/
|
|
240
261
|
private trimToTokenBudget;
|
|
262
|
+
/**
|
|
263
|
+
* After any trim, remove tool_result blocks whose paired tool_use was dropped.
|
|
264
|
+
* Entries that become empty after filtering are also removed.
|
|
265
|
+
* This prevents 400 errors from providers that require tool_result blocks to
|
|
266
|
+
* have a corresponding tool_use in the conversation history.
|
|
267
|
+
*/
|
|
268
|
+
private sanitizeToolPairs;
|
|
241
269
|
}
|
|
242
270
|
//# sourceMappingURL=History.d.ts.map
|
package/dist/history/History.js
CHANGED
|
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.History = exports.isToolResultContent = exports.isToolUseContent = exports.isTextContent = exports.textMessage = exports.toolResult = exports.toolUse = exports.text = void 0;
|
|
39
|
+
exports.History = exports.isImageContent = exports.isImageBase64Content = exports.isImageUrlContent = exports.isToolResultContent = exports.isToolUseContent = exports.isTextContent = exports.imageBase64 = exports.imageUrl = exports.textMessage = exports.toolResult = exports.toolUse = exports.text = void 0;
|
|
40
40
|
exports.resetTokenxCache = resetTokenxCache;
|
|
41
41
|
const events_1 = __importDefault(require("events"));
|
|
42
42
|
const types_1 = require("./types");
|
|
@@ -53,14 +53,32 @@ void Promise.resolve().then(() => __importStar(require("tokenx"))).then((mod) =>
|
|
|
53
53
|
function resetTokenxCache() {
|
|
54
54
|
_estimateTokenCount = (t) => Math.ceil(t.length / 4);
|
|
55
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Estimate token count for a content block array.
|
|
58
|
+
* Image blocks use a flat 1000-token estimate (resolution-independent conservative value).
|
|
59
|
+
* Text and tool blocks fall through to the tokenx estimator.
|
|
60
|
+
*/
|
|
61
|
+
function estimateContentTokens(content) {
|
|
62
|
+
return content.reduce((sum, block) => {
|
|
63
|
+
if ((0, types_1.isImageContent)(block)) {
|
|
64
|
+
return sum + 1000;
|
|
65
|
+
}
|
|
66
|
+
return sum + _estimateTokenCount(JSON.stringify(block));
|
|
67
|
+
}, 0);
|
|
68
|
+
}
|
|
56
69
|
var types_2 = require("./types");
|
|
57
70
|
Object.defineProperty(exports, "text", { enumerable: true, get: function () { return types_2.text; } });
|
|
58
71
|
Object.defineProperty(exports, "toolUse", { enumerable: true, get: function () { return types_2.toolUse; } });
|
|
59
72
|
Object.defineProperty(exports, "toolResult", { enumerable: true, get: function () { return types_2.toolResult; } });
|
|
60
73
|
Object.defineProperty(exports, "textMessage", { enumerable: true, get: function () { return types_2.textMessage; } });
|
|
74
|
+
Object.defineProperty(exports, "imageUrl", { enumerable: true, get: function () { return types_2.imageUrl; } });
|
|
75
|
+
Object.defineProperty(exports, "imageBase64", { enumerable: true, get: function () { return types_2.imageBase64; } });
|
|
61
76
|
Object.defineProperty(exports, "isTextContent", { enumerable: true, get: function () { return types_2.isTextContent; } });
|
|
62
77
|
Object.defineProperty(exports, "isToolUseContent", { enumerable: true, get: function () { return types_2.isToolUseContent; } });
|
|
63
78
|
Object.defineProperty(exports, "isToolResultContent", { enumerable: true, get: function () { return types_2.isToolResultContent; } });
|
|
79
|
+
Object.defineProperty(exports, "isImageUrlContent", { enumerable: true, get: function () { return types_2.isImageUrlContent; } });
|
|
80
|
+
Object.defineProperty(exports, "isImageBase64Content", { enumerable: true, get: function () { return types_2.isImageBase64Content; } });
|
|
81
|
+
Object.defineProperty(exports, "isImageContent", { enumerable: true, get: function () { return types_2.isImageContent; } });
|
|
64
82
|
/**
|
|
65
83
|
* Manages conversation history in a provider-agnostic format.
|
|
66
84
|
*
|
|
@@ -109,6 +127,7 @@ class History extends events_1.default {
|
|
|
109
127
|
this.transient = false;
|
|
110
128
|
this._plugins = [];
|
|
111
129
|
this._reducing = false;
|
|
130
|
+
this._sessionAnchor = null;
|
|
112
131
|
this.options = options;
|
|
113
132
|
this.transient = Boolean(options?.transient);
|
|
114
133
|
// Convert initial entries to internal format with metadata
|
|
@@ -136,6 +155,24 @@ class History extends events_1.default {
|
|
|
136
155
|
plugin.onRegistered?.(this);
|
|
137
156
|
return this;
|
|
138
157
|
}
|
|
158
|
+
/**
|
|
159
|
+
* Mark the current entry count as the session boundary.
|
|
160
|
+
* Call this at the start of each agent `execute()` after adding the user
|
|
161
|
+
* message. Transform plugins (e.g. toolResultMaskingPlugin) will not mask
|
|
162
|
+
* any entries added at or after this position, preventing tool results from
|
|
163
|
+
* the current execution loop from being masked mid-session.
|
|
164
|
+
*/
|
|
165
|
+
setSessionAnchor() {
|
|
166
|
+
this._sessionAnchor = this._entries.length;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* The entry index set by the last call to `setSessionAnchor()`, or `null`
|
|
170
|
+
* if no anchor has been set. Entries at this index or beyond belong to the
|
|
171
|
+
* current session and should not be masked by transform plugins.
|
|
172
|
+
*/
|
|
173
|
+
get sessionAnchor() {
|
|
174
|
+
return this._sessionAnchor;
|
|
175
|
+
}
|
|
139
176
|
// ===========================================================================
|
|
140
177
|
// Core write operations
|
|
141
178
|
// ===========================================================================
|
|
@@ -148,18 +185,13 @@ class History extends events_1.default {
|
|
|
148
185
|
const __metadata = {
|
|
149
186
|
date: new Date().toISOString(),
|
|
150
187
|
contentLength,
|
|
151
|
-
estimatedTokens:
|
|
188
|
+
estimatedTokens: estimateContentTokens(entry.content),
|
|
152
189
|
};
|
|
153
190
|
this._entries.push({
|
|
154
191
|
...entry,
|
|
155
192
|
__metadata,
|
|
156
193
|
});
|
|
157
|
-
|
|
158
|
-
this._entries = this._entries.slice(this._entries.length - this.options.maxLength);
|
|
159
|
-
}
|
|
160
|
-
if (this.options.maxTokens) {
|
|
161
|
-
this.trimToTokenBudget();
|
|
162
|
-
}
|
|
194
|
+
this.applyTrimming();
|
|
163
195
|
this.emit("entry", entry);
|
|
164
196
|
// Fire plugin afterAdd hooks. Skipped during reduce() to avoid recursion
|
|
165
197
|
// when compression plugins add summary entries to the history.
|
|
@@ -367,6 +399,20 @@ class History extends events_1.default {
|
|
|
367
399
|
// ===========================================================================
|
|
368
400
|
// Private helpers
|
|
369
401
|
// ===========================================================================
|
|
402
|
+
/**
|
|
403
|
+
* Apply maxLength and maxTokens trimming to the current entry list.
|
|
404
|
+
* Safe to call after bulk-loading entries (e.g. RedisHistory.load()).
|
|
405
|
+
* Subclasses may call this after directly manipulating _entries.
|
|
406
|
+
*/
|
|
407
|
+
applyTrimming() {
|
|
408
|
+
if (this.options.maxLength && this._entries.length > this.options.maxLength) {
|
|
409
|
+
this._entries = this._entries.slice(this._entries.length - this.options.maxLength);
|
|
410
|
+
this.sanitizeToolPairs();
|
|
411
|
+
}
|
|
412
|
+
if (this.options.maxTokens) {
|
|
413
|
+
this.trimToTokenBudget();
|
|
414
|
+
}
|
|
415
|
+
}
|
|
370
416
|
/**
|
|
371
417
|
* Drop oldest non-system entries until totalEstimatedTokens fits within budget.
|
|
372
418
|
* Called synchronously from addEntry() as a safety net.
|
|
@@ -382,6 +428,32 @@ class History extends events_1.default {
|
|
|
382
428
|
break;
|
|
383
429
|
this._entries.splice(firstNonSystem, 1);
|
|
384
430
|
}
|
|
431
|
+
this.sanitizeToolPairs();
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* After any trim, remove tool_result blocks whose paired tool_use was dropped.
|
|
435
|
+
* Entries that become empty after filtering are also removed.
|
|
436
|
+
* This prevents 400 errors from providers that require tool_result blocks to
|
|
437
|
+
* have a corresponding tool_use in the conversation history.
|
|
438
|
+
*/
|
|
439
|
+
sanitizeToolPairs() {
|
|
440
|
+
// Collect all tool_use IDs still present in the history
|
|
441
|
+
const toolUseIds = new Set();
|
|
442
|
+
for (const entry of this._entries) {
|
|
443
|
+
for (const block of entry.content) {
|
|
444
|
+
if ((0, types_1.isToolUseContent)(block)) {
|
|
445
|
+
toolUseIds.add(block.id);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
// Filter out orphaned tool_result blocks; drop entries that become empty
|
|
450
|
+
this._entries = this._entries.filter((entry) => {
|
|
451
|
+
const filtered = entry.content.filter((block) => !(0, types_1.isToolResultContent)(block) || toolUseIds.has(block.tool_use_id));
|
|
452
|
+
if (filtered.length === 0)
|
|
453
|
+
return false;
|
|
454
|
+
entry.content = filtered;
|
|
455
|
+
return true;
|
|
456
|
+
});
|
|
385
457
|
}
|
|
386
458
|
}
|
|
387
459
|
exports.History = History;
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { History } from "./History";
|
|
1
|
+
import { History, HistoryOptions } from "./History";
|
|
2
2
|
interface RedisInstance {
|
|
3
3
|
get(key: string): Promise<string | null>;
|
|
4
4
|
set(key: string, content: string): Promise<"OK">;
|
|
5
5
|
}
|
|
6
6
|
export declare class RedisHistory extends History {
|
|
7
7
|
private redisInstance;
|
|
8
|
-
constructor(redisInstance: RedisInstance);
|
|
8
|
+
constructor(redisInstance: RedisInstance, options?: HistoryOptions);
|
|
9
9
|
/**
|
|
10
|
-
* Loads history entries from Redis using the specified key
|
|
10
|
+
* Loads history entries from Redis using the specified key.
|
|
11
|
+
* Entries are re-added via addEntry() so metadata is computed correctly.
|
|
12
|
+
* Trimming (maxLength / maxTokens) is applied after load.
|
|
11
13
|
*
|
|
12
14
|
* @param {string} key - The Redis key to retrieve history entries from
|
|
13
15
|
* @returns {Promise<void>} A promise that resolves when history is loaded
|
|
@@ -3,12 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.RedisHistory = void 0;
|
|
4
4
|
const History_1 = require("./History");
|
|
5
5
|
class RedisHistory extends History_1.History {
|
|
6
|
-
constructor(redisInstance) {
|
|
7
|
-
super([],
|
|
6
|
+
constructor(redisInstance, options = {}) {
|
|
7
|
+
super([], options);
|
|
8
8
|
this.redisInstance = redisInstance;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* Loads history entries from Redis using the specified key
|
|
11
|
+
* Loads history entries from Redis using the specified key.
|
|
12
|
+
* Entries are re-added via addEntry() so metadata is computed correctly.
|
|
13
|
+
* Trimming (maxLength / maxTokens) is applied after load.
|
|
12
14
|
*
|
|
13
15
|
* @param {string} key - The Redis key to retrieve history entries from
|
|
14
16
|
* @returns {Promise<void>} A promise that resolves when history is loaded
|
|
@@ -16,15 +18,26 @@ class RedisHistory extends History_1.History {
|
|
|
16
18
|
*/
|
|
17
19
|
async load(key) {
|
|
18
20
|
try {
|
|
19
|
-
// Retrieve the serialized history from Redis
|
|
20
21
|
const serializedHistory = await this.redisInstance.get(key);
|
|
21
|
-
|
|
22
|
-
if (!serializedHistory) {
|
|
22
|
+
if (!serializedHistory)
|
|
23
23
|
return;
|
|
24
|
-
}
|
|
25
|
-
// Parse the serialized history and create a new History instance
|
|
26
24
|
const entries = JSON.parse(serializedHistory);
|
|
27
|
-
this._entries =
|
|
25
|
+
this._entries = [];
|
|
26
|
+
// Re-add via addEntry to compute metadata; suppress plugins during bulk load
|
|
27
|
+
// by temporarily bypassing plugin afterAdd hooks (handled by _reducing flag
|
|
28
|
+
// which is private — so we push entries directly and call applyTrimming once).
|
|
29
|
+
for (const entry of entries) {
|
|
30
|
+
const serialized = JSON.stringify(entry.content);
|
|
31
|
+
this._entries.push({
|
|
32
|
+
...entry,
|
|
33
|
+
__metadata: {
|
|
34
|
+
date: new Date().toISOString(),
|
|
35
|
+
contentLength: serialized.length,
|
|
36
|
+
estimatedTokens: Math.ceil(serialized.length / 4),
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
this.applyTrimming();
|
|
28
41
|
}
|
|
29
42
|
catch (error) {
|
|
30
43
|
console.error(`Error loading history from Redis key "${key}":`, error);
|
|
@@ -40,9 +53,7 @@ class RedisHistory extends History_1.History {
|
|
|
40
53
|
*/
|
|
41
54
|
async save(key) {
|
|
42
55
|
try {
|
|
43
|
-
// Serialize the current history entries
|
|
44
56
|
const serializedHistory = this.toJSON();
|
|
45
|
-
// Save the serialized history to Redis
|
|
46
57
|
await this.redisInstance.set(key, serializedHistory);
|
|
47
58
|
}
|
|
48
59
|
catch (error) {
|
|
@@ -88,7 +88,13 @@ function toolResultMaskingPlugin(options) {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
const maskable = [];
|
|
91
|
+
const sessionAnchor = _history?.sessionAnchor ?? null;
|
|
91
92
|
for (let ei = 0; ei < entries.length; ei++) {
|
|
93
|
+
// Never mask entries from the current execute() session — doing so
|
|
94
|
+
// would cause the model to call retrieve_tool_result mid-loop, whose
|
|
95
|
+
// result would itself be masked, creating an infinite retrieval loop.
|
|
96
|
+
if (sessionAnchor !== null && ei >= sessionAnchor)
|
|
97
|
+
continue;
|
|
92
98
|
const entry = entries[ei];
|
|
93
99
|
for (let bi = 0; bi < entry.content.length; bi++) {
|
|
94
100
|
const block = entry.content[bi];
|
|
@@ -40,6 +40,22 @@ exports.anthropicTransformer = {
|
|
|
40
40
|
is_error: block.is_error,
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
|
+
if ((0, types_1.isImageUrlContent)(block)) {
|
|
44
|
+
return {
|
|
45
|
+
type: "image",
|
|
46
|
+
source: { type: "url", url: block.url },
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if ((0, types_1.isImageBase64Content)(block)) {
|
|
50
|
+
return {
|
|
51
|
+
type: "image",
|
|
52
|
+
source: {
|
|
53
|
+
type: "base64",
|
|
54
|
+
media_type: block.mimeType,
|
|
55
|
+
data: block.data,
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
43
59
|
throw new Error(`Unknown content type: ${block.type}`);
|
|
44
60
|
});
|
|
45
61
|
return { role, content };
|
|
@@ -122,11 +138,14 @@ exports.openAiTransformer = {
|
|
|
122
138
|
});
|
|
123
139
|
continue;
|
|
124
140
|
}
|
|
125
|
-
// Separate
|
|
141
|
+
// Separate content blocks by type for OpenAI format
|
|
126
142
|
const textBlocks = entry.content.filter(types_1.isTextContent);
|
|
127
143
|
const toolUseBlocks = entry.content.filter(types_1.isToolUseContent);
|
|
128
144
|
const toolResultBlocks = entry.content.filter(types_1.isToolResultContent);
|
|
129
|
-
|
|
145
|
+
const imageUrlBlocks = entry.content.filter(types_1.isImageUrlContent);
|
|
146
|
+
const imageBase64Blocks = entry.content.filter(types_1.isImageBase64Content);
|
|
147
|
+
const hasImages = imageUrlBlocks.length > 0 || imageBase64Blocks.length > 0;
|
|
148
|
+
// Add text/image message if present
|
|
130
149
|
if (textBlocks.length > 0 && entry.role !== "user") {
|
|
131
150
|
items.push({
|
|
132
151
|
type: "message",
|
|
@@ -135,13 +154,42 @@ exports.openAiTransformer = {
|
|
|
135
154
|
});
|
|
136
155
|
}
|
|
137
156
|
else if (entry.role === "user" &&
|
|
138
|
-
textBlocks.length > 0 &&
|
|
157
|
+
(textBlocks.length > 0 || hasImages) &&
|
|
139
158
|
toolResultBlocks.length === 0) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
159
|
+
if (hasImages) {
|
|
160
|
+
// Mixed content: build an array of content parts
|
|
161
|
+
const parts = [];
|
|
162
|
+
for (const block of entry.content) {
|
|
163
|
+
if ((0, types_1.isTextContent)(block)) {
|
|
164
|
+
parts.push({ type: "input_text", text: block.text });
|
|
165
|
+
}
|
|
166
|
+
else if ((0, types_1.isImageUrlContent)(block)) {
|
|
167
|
+
parts.push({
|
|
168
|
+
type: "input_image",
|
|
169
|
+
image_url: block.url,
|
|
170
|
+
...(block.detail ? { detail: block.detail } : {}),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
else if ((0, types_1.isImageBase64Content)(block)) {
|
|
174
|
+
parts.push({
|
|
175
|
+
type: "input_image",
|
|
176
|
+
image_url: `data:${block.mimeType};base64,${block.data}`,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
items.push({
|
|
181
|
+
type: "message",
|
|
182
|
+
role: "user",
|
|
183
|
+
content: parts,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
items.push({
|
|
188
|
+
type: "message",
|
|
189
|
+
role: "user",
|
|
190
|
+
content: textBlocks.map((c) => c.text).join("\n"),
|
|
191
|
+
});
|
|
192
|
+
}
|
|
145
193
|
}
|
|
146
194
|
// Add tool calls as separate function_call items (OpenAI format)
|
|
147
195
|
// Convert IDs to OpenAI format if they came from another provider
|
|
@@ -243,7 +291,7 @@ exports.mistralTransformer = {
|
|
|
243
291
|
messages.push(msg);
|
|
244
292
|
continue;
|
|
245
293
|
}
|
|
246
|
-
// User role - could be text or tool results
|
|
294
|
+
// User role - could be text, images, or tool results
|
|
247
295
|
if (toolResultBlocks.length > 0) {
|
|
248
296
|
// Mistral uses separate "tool" role messages for each result
|
|
249
297
|
// We need to find the corresponding tool name from the assistant's tool_calls
|
|
@@ -258,11 +306,31 @@ exports.mistralTransformer = {
|
|
|
258
306
|
});
|
|
259
307
|
}
|
|
260
308
|
}
|
|
261
|
-
else
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
309
|
+
else {
|
|
310
|
+
const imageUrlBlocks = entry.content.filter(types_1.isImageUrlContent);
|
|
311
|
+
const imageBase64Blocks = entry.content.filter(types_1.isImageBase64Content);
|
|
312
|
+
if (imageBase64Blocks.length > 0) {
|
|
313
|
+
throw new Error("Mistral does not support base64 image inputs. Convert images to URLs before using with MistralAgent.");
|
|
314
|
+
}
|
|
315
|
+
if (imageUrlBlocks.length > 0) {
|
|
316
|
+
// Mistral vision: array content with text + image_url parts
|
|
317
|
+
const parts = [];
|
|
318
|
+
for (const block of entry.content) {
|
|
319
|
+
if ((0, types_1.isTextContent)(block)) {
|
|
320
|
+
parts.push({ type: "text", text: block.text });
|
|
321
|
+
}
|
|
322
|
+
else if ((0, types_1.isImageUrlContent)(block)) {
|
|
323
|
+
parts.push({ type: "image_url", image_url: block.url });
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
messages.push({ role: "user", content: parts });
|
|
327
|
+
}
|
|
328
|
+
else if (textBlocks.length > 0) {
|
|
329
|
+
messages.push({
|
|
330
|
+
role: "user",
|
|
331
|
+
content: textBlocks.map((c) => c.text).join("\n"),
|
|
332
|
+
});
|
|
333
|
+
}
|
|
266
334
|
}
|
|
267
335
|
}
|
|
268
336
|
return messages;
|
|
@@ -336,6 +404,25 @@ exports.geminiTransformer = {
|
|
|
336
404
|
for (const block of textBlocks) {
|
|
337
405
|
parts.push({ text: block.text });
|
|
338
406
|
}
|
|
407
|
+
// Add image parts
|
|
408
|
+
for (const block of entry.content) {
|
|
409
|
+
if ((0, types_1.isImageUrlContent)(block)) {
|
|
410
|
+
parts.push({
|
|
411
|
+
fileData: {
|
|
412
|
+
mimeType: block.mimeType ?? "image/jpeg",
|
|
413
|
+
fileUri: block.url,
|
|
414
|
+
},
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
else if ((0, types_1.isImageBase64Content)(block)) {
|
|
418
|
+
parts.push({
|
|
419
|
+
inlineData: {
|
|
420
|
+
mimeType: block.mimeType,
|
|
421
|
+
data: block.data,
|
|
422
|
+
},
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
}
|
|
339
426
|
// Add function call parts (for assistant/model messages)
|
|
340
427
|
for (const block of toolUseBlocks) {
|
|
341
428
|
parts.push({
|
package/dist/history/types.d.ts
CHANGED
|
@@ -29,10 +29,34 @@ export type ToolResultContent = {
|
|
|
29
29
|
content: string;
|
|
30
30
|
is_error?: boolean;
|
|
31
31
|
};
|
|
32
|
+
/**
|
|
33
|
+
* Supported image MIME types across all providers
|
|
34
|
+
*/
|
|
35
|
+
export type ImageMimeType = "image/jpeg" | "image/png" | "image/gif" | "image/webp";
|
|
36
|
+
/**
|
|
37
|
+
* Image referenced by URL
|
|
38
|
+
*/
|
|
39
|
+
export type ImageUrlContent = {
|
|
40
|
+
type: "image_url";
|
|
41
|
+
url: string;
|
|
42
|
+
/** Required hint for Gemini (fileData); optional for other providers */
|
|
43
|
+
mimeType?: ImageMimeType;
|
|
44
|
+
/** OpenAI detail level hint — ignored by other providers */
|
|
45
|
+
detail?: "low" | "high" | "auto";
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Image provided as raw base64-encoded data (no data: URI prefix)
|
|
49
|
+
*/
|
|
50
|
+
export type ImageBase64Content = {
|
|
51
|
+
type: "image_base64";
|
|
52
|
+
/** Raw base64 string — do not include the `data:<mime>;base64,` prefix */
|
|
53
|
+
data: string;
|
|
54
|
+
mimeType: ImageMimeType;
|
|
55
|
+
};
|
|
32
56
|
/**
|
|
33
57
|
* Union of all content types
|
|
34
58
|
*/
|
|
35
|
-
export type MessageContent = TextContent | ToolUseContent | ToolResultContent;
|
|
59
|
+
export type MessageContent = TextContent | ToolUseContent | ToolResultContent | ImageUrlContent | ImageBase64Content;
|
|
36
60
|
/**
|
|
37
61
|
* Anthropic-specific metadata
|
|
38
62
|
*/
|
|
@@ -111,6 +135,9 @@ export type HistoryEntry = {
|
|
|
111
135
|
export declare function isTextContent(content: MessageContent): content is TextContent;
|
|
112
136
|
export declare function isToolUseContent(content: MessageContent): content is ToolUseContent;
|
|
113
137
|
export declare function isToolResultContent(content: MessageContent): content is ToolResultContent;
|
|
138
|
+
export declare function isImageUrlContent(content: MessageContent): content is ImageUrlContent;
|
|
139
|
+
export declare function isImageBase64Content(content: MessageContent): content is ImageBase64Content;
|
|
140
|
+
export declare function isImageContent(content: MessageContent): content is ImageUrlContent | ImageBase64Content;
|
|
114
141
|
/**
|
|
115
142
|
* Create a text content block
|
|
116
143
|
*/
|
|
@@ -127,6 +154,17 @@ export declare function toolResult(tool_use_id: string, content: string, is_erro
|
|
|
127
154
|
* Create a simple text message entry
|
|
128
155
|
*/
|
|
129
156
|
export declare function textMessage(role: MessageRole, value: string): HistoryEntry;
|
|
157
|
+
/**
|
|
158
|
+
* Create an image URL content block
|
|
159
|
+
*/
|
|
160
|
+
export declare function imageUrl(url: string, options?: {
|
|
161
|
+
mimeType?: ImageMimeType;
|
|
162
|
+
detail?: "low" | "high" | "auto";
|
|
163
|
+
}): ImageUrlContent;
|
|
164
|
+
/**
|
|
165
|
+
* Create a base64 image content block
|
|
166
|
+
*/
|
|
167
|
+
export declare function imageBase64(data: string, mimeType: ImageMimeType): ImageBase64Content;
|
|
130
168
|
/**
|
|
131
169
|
* Options controlling how history.reduce() compacts stored entries.
|
|
132
170
|
* All fields are optional — supply whichever constraints apply.
|
package/dist/history/types.js
CHANGED
|
@@ -9,10 +9,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
9
9
|
exports.isTextContent = isTextContent;
|
|
10
10
|
exports.isToolUseContent = isToolUseContent;
|
|
11
11
|
exports.isToolResultContent = isToolResultContent;
|
|
12
|
+
exports.isImageUrlContent = isImageUrlContent;
|
|
13
|
+
exports.isImageBase64Content = isImageBase64Content;
|
|
14
|
+
exports.isImageContent = isImageContent;
|
|
12
15
|
exports.text = text;
|
|
13
16
|
exports.toolUse = toolUse;
|
|
14
17
|
exports.toolResult = toolResult;
|
|
15
18
|
exports.textMessage = textMessage;
|
|
19
|
+
exports.imageUrl = imageUrl;
|
|
20
|
+
exports.imageBase64 = imageBase64;
|
|
16
21
|
// =============================================================================
|
|
17
22
|
// Helper Type Guards
|
|
18
23
|
// =============================================================================
|
|
@@ -25,6 +30,15 @@ function isToolUseContent(content) {
|
|
|
25
30
|
function isToolResultContent(content) {
|
|
26
31
|
return content.type === "tool_result";
|
|
27
32
|
}
|
|
33
|
+
function isImageUrlContent(content) {
|
|
34
|
+
return content.type === "image_url";
|
|
35
|
+
}
|
|
36
|
+
function isImageBase64Content(content) {
|
|
37
|
+
return content.type === "image_base64";
|
|
38
|
+
}
|
|
39
|
+
function isImageContent(content) {
|
|
40
|
+
return content.type === "image_url" || content.type === "image_base64";
|
|
41
|
+
}
|
|
28
42
|
// =============================================================================
|
|
29
43
|
// Utility Functions
|
|
30
44
|
// =============================================================================
|
|
@@ -52,4 +66,16 @@ function toolResult(tool_use_id, content, is_error) {
|
|
|
52
66
|
function textMessage(role, value) {
|
|
53
67
|
return { role, content: [text(value)] };
|
|
54
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Create an image URL content block
|
|
71
|
+
*/
|
|
72
|
+
function imageUrl(url, options) {
|
|
73
|
+
return { type: "image_url", url, ...options };
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Create a base64 image content block
|
|
77
|
+
*/
|
|
78
|
+
function imageBase64(data, mimeType) {
|
|
79
|
+
return { type: "image_base64", data, mimeType };
|
|
80
|
+
}
|
|
55
81
|
//# sourceMappingURL=types.js.map
|