@acontext/acontext 0.1.6 → 0.1.7
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/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/integrations/claude-agent.d.ts +124 -0
- package/dist/integrations/claude-agent.js +371 -0
- package/dist/integrations/index.d.ts +4 -0
- package/dist/integrations/index.js +20 -0
- package/dist/resources/sessions.d.ts +3 -0
- package/dist/resources/sessions.js +4 -0
- package/dist/types/session.d.ts +6 -0
- package/dist/types/session.js +10 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -33,3 +33,4 @@ Object.defineProperty(exports, "AcontextError", { enumerable: true, get: functio
|
|
|
33
33
|
__exportStar(require("./types"), exports);
|
|
34
34
|
__exportStar(require("./resources"), exports);
|
|
35
35
|
__exportStar(require("./agent"), exports);
|
|
36
|
+
__exportStar(require("./integrations"), exports);
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Agent SDK integration for Acontext.
|
|
3
|
+
*
|
|
4
|
+
* Provides {@link ClaudeAgentStorage} that accepts messages produced by the
|
|
5
|
+
* Claude Agent SDK `query()` async iterable and persists **only** user and
|
|
6
|
+
* assistant messages to Acontext in Anthropic format via
|
|
7
|
+
* `client.sessions.storeMessage(...)`.
|
|
8
|
+
*
|
|
9
|
+
* Other message types (system, result, stream_event, etc.) are used only for
|
|
10
|
+
* session-id resolution and are **never** stored.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { AcontextClient, ClaudeAgentStorage } from '@acontext/acontext';
|
|
15
|
+
* import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
16
|
+
*
|
|
17
|
+
* const client = new AcontextClient({ apiKey: 'sk-ac-your-api-key' });
|
|
18
|
+
* const storage = new ClaudeAgentStorage({ client });
|
|
19
|
+
*
|
|
20
|
+
* for await (const message of query({ prompt: 'Hello' })) {
|
|
21
|
+
* await storage.saveMessage(message);
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Minimal duck-typed interface for the Acontext client.
|
|
27
|
+
* Both `AcontextClient` and `MockAcontextClient` satisfy this interface.
|
|
28
|
+
*/
|
|
29
|
+
export interface AcontextClientLike {
|
|
30
|
+
sessions: {
|
|
31
|
+
create(options?: {
|
|
32
|
+
useUuid?: string | null;
|
|
33
|
+
user?: string | null;
|
|
34
|
+
}): Promise<{
|
|
35
|
+
id: string;
|
|
36
|
+
}>;
|
|
37
|
+
storeMessage(sessionId: string, blob: Record<string, unknown>, options?: {
|
|
38
|
+
format?: string;
|
|
39
|
+
meta?: Record<string, unknown> | null;
|
|
40
|
+
}): Promise<unknown>;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Options for constructing a {@link ClaudeAgentStorage} instance.
|
|
45
|
+
*/
|
|
46
|
+
export interface ClaudeAgentStorageOptions {
|
|
47
|
+
/** An Acontext client instance (or any object satisfying `AcontextClientLike`). */
|
|
48
|
+
client: AcontextClientLike;
|
|
49
|
+
/** Acontext session UUID. If omitted, discovered from the Claude stream or auto-created. */
|
|
50
|
+
sessionId?: string;
|
|
51
|
+
/** Optional user identifier passed to `sessions.create()`. */
|
|
52
|
+
user?: string;
|
|
53
|
+
/** Whether to store ThinkingBlock content as text blocks. Default: false. */
|
|
54
|
+
includeThinking?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Optional error callback invoked when `storeMessage` raises.
|
|
57
|
+
* Receives `(error, blob)` where `blob` is the **converted** Anthropic blob.
|
|
58
|
+
* If not provided, errors are logged via `console.warn`.
|
|
59
|
+
*/
|
|
60
|
+
onError?: (error: Error, blob: Record<string, unknown>) => void;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Try to extract a Claude session id from a non-storable message.
|
|
64
|
+
*
|
|
65
|
+
* In the TS Claude Agent SDK, `session_id` is a flat field on system,
|
|
66
|
+
* result, stream_event, and other non-storable message types.
|
|
67
|
+
*
|
|
68
|
+
* Returns `null` when the message does not carry a session id.
|
|
69
|
+
*/
|
|
70
|
+
export declare function getSessionIdFromMessage(msg: Record<string, unknown>): string | null;
|
|
71
|
+
/**
|
|
72
|
+
* Convert a Claude Agent SDK user message to an Anthropic blob.
|
|
73
|
+
*
|
|
74
|
+
* TS reads `msg.message?.content ?? ""` (nested under API message object).
|
|
75
|
+
*
|
|
76
|
+
* Returns `null` when the resulting content would be empty (no storable blocks).
|
|
77
|
+
*/
|
|
78
|
+
export declare function claudeUserMessageToAnthropicBlob(msg: Record<string, unknown>): Record<string, unknown> | null;
|
|
79
|
+
/**
|
|
80
|
+
* Convert a Claude Agent SDK assistant message to an Anthropic blob.
|
|
81
|
+
*
|
|
82
|
+
* TS reads `msg.message?.content ?? []` (nested under API message object).
|
|
83
|
+
*
|
|
84
|
+
* Returns `{ blob: ... | null, hasThinking: boolean }`.
|
|
85
|
+
*/
|
|
86
|
+
export declare function claudeAssistantMessageToAnthropicBlob(msg: Record<string, unknown>, includeThinking?: boolean): {
|
|
87
|
+
blob: Record<string, unknown> | null;
|
|
88
|
+
hasThinking: boolean;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Storage adapter for the Claude Agent SDK (TypeScript).
|
|
92
|
+
*
|
|
93
|
+
* Accepts messages from the `query()` async iterable and persists **only**
|
|
94
|
+
* user and assistant messages to Acontext in Anthropic format.
|
|
95
|
+
*/
|
|
96
|
+
export declare class ClaudeAgentStorage {
|
|
97
|
+
private _client;
|
|
98
|
+
private _sessionId;
|
|
99
|
+
private _user;
|
|
100
|
+
private _includeThinking;
|
|
101
|
+
private _onError;
|
|
102
|
+
private _sessionEnsured;
|
|
103
|
+
constructor(options: ClaudeAgentStorageOptions);
|
|
104
|
+
/**
|
|
105
|
+
* The current Acontext session id (may be `null` until resolved).
|
|
106
|
+
*/
|
|
107
|
+
get sessionId(): string | null;
|
|
108
|
+
/**
|
|
109
|
+
* Persist a single Claude Agent SDK message to Acontext.
|
|
110
|
+
*
|
|
111
|
+
* - User and assistant messages are stored.
|
|
112
|
+
* - All other message types (system, result, stream_event, etc.) are used
|
|
113
|
+
* only for session-id resolution and are **not** stored.
|
|
114
|
+
* - Replay messages (`isReplay: true`) are skipped to prevent duplicates.
|
|
115
|
+
* - API errors are caught and either forwarded to `onError` or logged,
|
|
116
|
+
* so the caller's `for await` loop is never interrupted.
|
|
117
|
+
*/
|
|
118
|
+
saveMessage(msg: Record<string, unknown>): Promise<void>;
|
|
119
|
+
private _tryUpdateSessionId;
|
|
120
|
+
private _storeUser;
|
|
121
|
+
private _storeAssistant;
|
|
122
|
+
private _ensureSession;
|
|
123
|
+
private _callStore;
|
|
124
|
+
}
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Claude Agent SDK integration for Acontext.
|
|
4
|
+
*
|
|
5
|
+
* Provides {@link ClaudeAgentStorage} that accepts messages produced by the
|
|
6
|
+
* Claude Agent SDK `query()` async iterable and persists **only** user and
|
|
7
|
+
* assistant messages to Acontext in Anthropic format via
|
|
8
|
+
* `client.sessions.storeMessage(...)`.
|
|
9
|
+
*
|
|
10
|
+
* Other message types (system, result, stream_event, etc.) are used only for
|
|
11
|
+
* session-id resolution and are **never** stored.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { AcontextClient, ClaudeAgentStorage } from '@acontext/acontext';
|
|
16
|
+
* import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
17
|
+
*
|
|
18
|
+
* const client = new AcontextClient({ apiKey: 'sk-ac-your-api-key' });
|
|
19
|
+
* const storage = new ClaudeAgentStorage({ client });
|
|
20
|
+
*
|
|
21
|
+
* for await (const message of query({ prompt: 'Hello' })) {
|
|
22
|
+
* await storage.saveMessage(message);
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
+
exports.ClaudeAgentStorage = void 0;
|
|
28
|
+
exports.getSessionIdFromMessage = getSessionIdFromMessage;
|
|
29
|
+
exports.claudeUserMessageToAnthropicBlob = claudeUserMessageToAnthropicBlob;
|
|
30
|
+
exports.claudeAssistantMessageToAnthropicBlob = claudeAssistantMessageToAnthropicBlob;
|
|
31
|
+
const errors_1 = require("../errors");
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Helpers – message type detection (TS Claude Agent SDK uses `type` field)
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
/**
|
|
36
|
+
* Check if a message is a storable user message.
|
|
37
|
+
* Skips replay messages (`isReplay === true`) which are TS-only.
|
|
38
|
+
*/
|
|
39
|
+
function isUserMessage(msg) {
|
|
40
|
+
return msg.type === 'user' && !msg.isReplay;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Check if a message is a storable assistant message.
|
|
44
|
+
*/
|
|
45
|
+
function isAssistantMessage(msg) {
|
|
46
|
+
return msg.type === 'assistant';
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Check if a message is a replay user message (TS-only).
|
|
50
|
+
*/
|
|
51
|
+
function isReplayMessage(msg) {
|
|
52
|
+
return msg.type === 'user' && msg.isReplay === true;
|
|
53
|
+
}
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// Helpers – session id extraction
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
/**
|
|
58
|
+
* Try to extract a Claude session id from a non-storable message.
|
|
59
|
+
*
|
|
60
|
+
* In the TS Claude Agent SDK, `session_id` is a flat field on system,
|
|
61
|
+
* result, stream_event, and other non-storable message types.
|
|
62
|
+
*
|
|
63
|
+
* Returns `null` when the message does not carry a session id.
|
|
64
|
+
*/
|
|
65
|
+
function getSessionIdFromMessage(msg) {
|
|
66
|
+
// Only extract from non-storable messages
|
|
67
|
+
if (msg.type === 'user' || msg.type === 'assistant') {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const sid = msg.session_id;
|
|
71
|
+
return typeof sid === 'string' ? sid : null;
|
|
72
|
+
}
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// Helpers – block conversion (Claude SDK → Anthropic blob)
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
/**
|
|
77
|
+
* Normalize `ToolResultBlock.content` to a shape accepted by the API.
|
|
78
|
+
*
|
|
79
|
+
* - `null`/`undefined` → `""`
|
|
80
|
+
* - `string` → as-is
|
|
81
|
+
* - `array` → `[{ type: "text", text: item.text ?? "" }]`
|
|
82
|
+
* - other → `String(content)`
|
|
83
|
+
*/
|
|
84
|
+
function normalizeToolResultContent(content) {
|
|
85
|
+
if (content === null || content === undefined) {
|
|
86
|
+
return '';
|
|
87
|
+
}
|
|
88
|
+
if (typeof content === 'string') {
|
|
89
|
+
return content;
|
|
90
|
+
}
|
|
91
|
+
if (Array.isArray(content)) {
|
|
92
|
+
return content.map((item) => ({
|
|
93
|
+
type: 'text',
|
|
94
|
+
text: item?.text ?? '',
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
return String(content);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Convert a single Claude SDK content block to an Anthropic content block.
|
|
101
|
+
*
|
|
102
|
+
* Returns `null` when the block should be skipped.
|
|
103
|
+
*/
|
|
104
|
+
function convertBlock(block, role, includeThinking) {
|
|
105
|
+
const blockType = block.type;
|
|
106
|
+
switch (blockType) {
|
|
107
|
+
case 'thinking': {
|
|
108
|
+
if (!includeThinking) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
const thinkingText = block.thinking;
|
|
112
|
+
if (!thinkingText) {
|
|
113
|
+
return null; // empty thinking text
|
|
114
|
+
}
|
|
115
|
+
return { type: 'text', text: thinkingText };
|
|
116
|
+
}
|
|
117
|
+
case 'tool_use': {
|
|
118
|
+
if (role !== 'assistant') {
|
|
119
|
+
return null; // tool_use only valid in assistant messages
|
|
120
|
+
}
|
|
121
|
+
let inputVal = block.input;
|
|
122
|
+
if (typeof inputVal === 'string') {
|
|
123
|
+
try {
|
|
124
|
+
inputVal = JSON.parse(inputVal);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
inputVal = { raw: inputVal };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
type: 'tool_use',
|
|
132
|
+
id: block.id,
|
|
133
|
+
name: block.name,
|
|
134
|
+
input: inputVal,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
case 'tool_result': {
|
|
138
|
+
if (role !== 'user') {
|
|
139
|
+
return null; // tool_result only valid in user messages
|
|
140
|
+
}
|
|
141
|
+
const result = {
|
|
142
|
+
type: 'tool_result',
|
|
143
|
+
tool_use_id: block.tool_use_id,
|
|
144
|
+
content: normalizeToolResultContent(block.content),
|
|
145
|
+
};
|
|
146
|
+
if (block.is_error) {
|
|
147
|
+
result.is_error = true;
|
|
148
|
+
}
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
case 'text': {
|
|
152
|
+
const text = block.text;
|
|
153
|
+
if (!text) {
|
|
154
|
+
return null; // empty text
|
|
155
|
+
}
|
|
156
|
+
return { type: 'text', text };
|
|
157
|
+
}
|
|
158
|
+
default:
|
|
159
|
+
// Unknown block type – skip silently
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Convert Claude SDK content to Anthropic content block array.
|
|
165
|
+
*
|
|
166
|
+
* Returns `[blocks, hasThinking]` where `hasThinking` is `true` when at
|
|
167
|
+
* least one thinking block was successfully included in the output.
|
|
168
|
+
*/
|
|
169
|
+
function convertContentBlocks(content, role, includeThinking) {
|
|
170
|
+
let hasThinking = false;
|
|
171
|
+
if (typeof content === 'string') {
|
|
172
|
+
if (!content) {
|
|
173
|
+
return [[], false];
|
|
174
|
+
}
|
|
175
|
+
return [[{ type: 'text', text: content }], false];
|
|
176
|
+
}
|
|
177
|
+
if (!Array.isArray(content)) {
|
|
178
|
+
return [[], false];
|
|
179
|
+
}
|
|
180
|
+
const blocks = [];
|
|
181
|
+
for (const block of content) {
|
|
182
|
+
if (typeof block !== 'object' || block === null) {
|
|
183
|
+
continue; // skip non-object items (matching Python's `if not isinstance(block, dict)`)
|
|
184
|
+
}
|
|
185
|
+
const converted = convertBlock(block, role, includeThinking);
|
|
186
|
+
if (converted !== null) {
|
|
187
|
+
blocks.push(converted);
|
|
188
|
+
// Track whether a thinking block was successfully included
|
|
189
|
+
if (block.type === 'thinking' &&
|
|
190
|
+
includeThinking) {
|
|
191
|
+
hasThinking = true;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return [blocks, hasThinking];
|
|
196
|
+
}
|
|
197
|
+
// ---------------------------------------------------------------------------
|
|
198
|
+
// Public conversion helpers
|
|
199
|
+
// ---------------------------------------------------------------------------
|
|
200
|
+
/**
|
|
201
|
+
* Convert a Claude Agent SDK user message to an Anthropic blob.
|
|
202
|
+
*
|
|
203
|
+
* TS reads `msg.message?.content ?? ""` (nested under API message object).
|
|
204
|
+
*
|
|
205
|
+
* Returns `null` when the resulting content would be empty (no storable blocks).
|
|
206
|
+
*/
|
|
207
|
+
function claudeUserMessageToAnthropicBlob(msg) {
|
|
208
|
+
const message = msg.message;
|
|
209
|
+
const content = message?.content ?? '';
|
|
210
|
+
const [blocks] = convertContentBlocks(content, 'user', false);
|
|
211
|
+
if (blocks.length === 0) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
return { role: 'user', content: blocks };
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Convert a Claude Agent SDK assistant message to an Anthropic blob.
|
|
218
|
+
*
|
|
219
|
+
* TS reads `msg.message?.content ?? []` (nested under API message object).
|
|
220
|
+
*
|
|
221
|
+
* Returns `{ blob: ... | null, hasThinking: boolean }`.
|
|
222
|
+
*/
|
|
223
|
+
function claudeAssistantMessageToAnthropicBlob(msg, includeThinking = false) {
|
|
224
|
+
const message = msg.message;
|
|
225
|
+
const content = message?.content ?? [];
|
|
226
|
+
const [blocks, hasThinking] = convertContentBlocks(content, 'assistant', includeThinking);
|
|
227
|
+
if (blocks.length === 0) {
|
|
228
|
+
return { blob: null, hasThinking };
|
|
229
|
+
}
|
|
230
|
+
return {
|
|
231
|
+
blob: { role: 'assistant', content: blocks },
|
|
232
|
+
hasThinking,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
// ---------------------------------------------------------------------------
|
|
236
|
+
// ClaudeAgentStorage
|
|
237
|
+
// ---------------------------------------------------------------------------
|
|
238
|
+
/**
|
|
239
|
+
* Storage adapter for the Claude Agent SDK (TypeScript).
|
|
240
|
+
*
|
|
241
|
+
* Accepts messages from the `query()` async iterable and persists **only**
|
|
242
|
+
* user and assistant messages to Acontext in Anthropic format.
|
|
243
|
+
*/
|
|
244
|
+
class ClaudeAgentStorage {
|
|
245
|
+
constructor(options) {
|
|
246
|
+
this._sessionEnsured = false;
|
|
247
|
+
this._client = options.client;
|
|
248
|
+
this._sessionId = options.sessionId ?? null;
|
|
249
|
+
this._user = options.user ?? null;
|
|
250
|
+
this._includeThinking = options.includeThinking ?? false;
|
|
251
|
+
this._onError = options.onError ?? null;
|
|
252
|
+
}
|
|
253
|
+
// -- properties ----------------------------------------------------------
|
|
254
|
+
/**
|
|
255
|
+
* The current Acontext session id (may be `null` until resolved).
|
|
256
|
+
*/
|
|
257
|
+
get sessionId() {
|
|
258
|
+
return this._sessionId;
|
|
259
|
+
}
|
|
260
|
+
// -- public API ----------------------------------------------------------
|
|
261
|
+
/**
|
|
262
|
+
* Persist a single Claude Agent SDK message to Acontext.
|
|
263
|
+
*
|
|
264
|
+
* - User and assistant messages are stored.
|
|
265
|
+
* - All other message types (system, result, stream_event, etc.) are used
|
|
266
|
+
* only for session-id resolution and are **not** stored.
|
|
267
|
+
* - Replay messages (`isReplay: true`) are skipped to prevent duplicates.
|
|
268
|
+
* - API errors are caught and either forwarded to `onError` or logged,
|
|
269
|
+
* so the caller's `for await` loop is never interrupted.
|
|
270
|
+
*/
|
|
271
|
+
async saveMessage(msg) {
|
|
272
|
+
// -- non-storable message types: update session_id only ----------------
|
|
273
|
+
if (msg.type !== 'user' && msg.type !== 'assistant') {
|
|
274
|
+
this._tryUpdateSessionId(msg);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
// -- replay user message: skip (TS-only) -------------------------------
|
|
278
|
+
if (isReplayMessage(msg)) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
// -- storable: assistant or user ---------------------------------------
|
|
282
|
+
if (isAssistantMessage(msg)) {
|
|
283
|
+
return this._storeAssistant(msg);
|
|
284
|
+
}
|
|
285
|
+
if (isUserMessage(msg)) {
|
|
286
|
+
return this._storeUser(msg);
|
|
287
|
+
}
|
|
288
|
+
// Unknown — ignore
|
|
289
|
+
}
|
|
290
|
+
// -- internal helpers ----------------------------------------------------
|
|
291
|
+
_tryUpdateSessionId(msg) {
|
|
292
|
+
if (this._sessionId !== null) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
const sid = getSessionIdFromMessage(msg);
|
|
296
|
+
if (sid) {
|
|
297
|
+
this._sessionId = sid;
|
|
298
|
+
console.debug(`Resolved session_id=${sid} from message`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// -- private store methods -----------------------------------------------
|
|
302
|
+
async _storeUser(msg) {
|
|
303
|
+
const blob = claudeUserMessageToAnthropicBlob(msg);
|
|
304
|
+
if (blob === null) {
|
|
305
|
+
console.debug('UserMessage produced empty content after conversion – skipping.');
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
await this._callStore(blob, null);
|
|
309
|
+
}
|
|
310
|
+
async _storeAssistant(msg) {
|
|
311
|
+
const { blob, hasThinking } = claudeAssistantMessageToAnthropicBlob(msg, this._includeThinking);
|
|
312
|
+
if (blob === null) {
|
|
313
|
+
console.debug('AssistantMessage produced empty content after conversion – skipping.');
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
const meta = {};
|
|
317
|
+
const message = msg.message;
|
|
318
|
+
const model = message?.model;
|
|
319
|
+
if (model) {
|
|
320
|
+
meta.model = model;
|
|
321
|
+
}
|
|
322
|
+
if (hasThinking) {
|
|
323
|
+
meta.has_thinking = true;
|
|
324
|
+
}
|
|
325
|
+
const error = msg.error;
|
|
326
|
+
if (error) {
|
|
327
|
+
meta.error = error;
|
|
328
|
+
}
|
|
329
|
+
await this._callStore(blob, Object.keys(meta).length > 0 ? meta : null);
|
|
330
|
+
}
|
|
331
|
+
async _ensureSession() {
|
|
332
|
+
if (this._sessionEnsured) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
try {
|
|
336
|
+
const session = await this._client.sessions.create({
|
|
337
|
+
useUuid: this._sessionId ? this._sessionId : null,
|
|
338
|
+
user: this._user,
|
|
339
|
+
});
|
|
340
|
+
this._sessionId = session.id;
|
|
341
|
+
console.debug(`Created Acontext session ${this._sessionId}`);
|
|
342
|
+
}
|
|
343
|
+
catch (err) {
|
|
344
|
+
if (err instanceof errors_1.APIError && err.statusCode === 409) {
|
|
345
|
+
console.debug(`Session ${this._sessionId} already exists (409) – continuing.`);
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
throw err;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
this._sessionEnsured = true;
|
|
352
|
+
}
|
|
353
|
+
async _callStore(blob, meta) {
|
|
354
|
+
try {
|
|
355
|
+
await this._ensureSession();
|
|
356
|
+
await this._client.sessions.storeMessage(this._sessionId, blob, {
|
|
357
|
+
format: 'anthropic',
|
|
358
|
+
meta,
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
catch (err) {
|
|
362
|
+
if (this._onError) {
|
|
363
|
+
this._onError(err, blob);
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
console.warn(`Failed to store message (session=${this._sessionId}):`, err);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
exports.ClaudeAgentStorage = ClaudeAgentStorage;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Integration modules for the Acontext TypeScript SDK.
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
17
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
__exportStar(require("./claude-agent"), exports);
|
|
@@ -101,8 +101,11 @@ export declare class SessionsAPI {
|
|
|
101
101
|
* @param options.editStrategies - Optional list of edit strategies to apply before format conversion.
|
|
102
102
|
* Examples:
|
|
103
103
|
* - Remove tool results: [{ type: 'remove_tool_result', params: { keep_recent_n_tool_results: 3 } }]
|
|
104
|
+
* - Remove large tool results: [{ type: 'remove_tool_result', params: { gt_token: 100 } }]
|
|
105
|
+
* - Remove large tool call params: [{ type: 'remove_tool_call_params', params: { gt_token: 100 } }]
|
|
104
106
|
* - Middle out: [{ type: 'middle_out', params: { token_reduce_to: 5000 } }]
|
|
105
107
|
* - Token limit: [{ type: 'token_limit', params: { limit_tokens: 20000 } }]
|
|
108
|
+
* Throws if editStrategies fail schema validation.
|
|
106
109
|
* @param options.pinEditingStrategiesAtMessage - Message ID to pin editing strategies at.
|
|
107
110
|
* When provided, strategies are only applied to messages up to and including this message ID,
|
|
108
111
|
* keeping subsequent messages unchanged. This helps maintain prompt cache stability by
|
|
@@ -214,8 +214,11 @@ class SessionsAPI {
|
|
|
214
214
|
* @param options.editStrategies - Optional list of edit strategies to apply before format conversion.
|
|
215
215
|
* Examples:
|
|
216
216
|
* - Remove tool results: [{ type: 'remove_tool_result', params: { keep_recent_n_tool_results: 3 } }]
|
|
217
|
+
* - Remove large tool results: [{ type: 'remove_tool_result', params: { gt_token: 100 } }]
|
|
218
|
+
* - Remove large tool call params: [{ type: 'remove_tool_call_params', params: { gt_token: 100 } }]
|
|
217
219
|
* - Middle out: [{ type: 'middle_out', params: { token_reduce_to: 5000 } }]
|
|
218
220
|
* - Token limit: [{ type: 'token_limit', params: { limit_tokens: 20000 } }]
|
|
221
|
+
* Throws if editStrategies fail schema validation.
|
|
219
222
|
* @param options.pinEditingStrategiesAtMessage - Message ID to pin editing strategies at.
|
|
220
223
|
* When provided, strategies are only applied to messages up to and including this message ID,
|
|
221
224
|
* keeping subsequent messages unchanged. This helps maintain prompt cache stability by
|
|
@@ -235,6 +238,7 @@ class SessionsAPI {
|
|
|
235
238
|
time_desc: options?.timeDesc ?? true, // Default to true
|
|
236
239
|
}));
|
|
237
240
|
if (options?.editStrategies !== undefined && options?.editStrategies !== null) {
|
|
241
|
+
types_1.EditStrategySchema.array().parse(options.editStrategies);
|
|
238
242
|
params.edit_strategies = JSON.stringify(options.editStrategies);
|
|
239
243
|
}
|
|
240
244
|
if (options?.pinEditingStrategiesAtMessage !== undefined && options?.pinEditingStrategiesAtMessage !== null) {
|
package/dist/types/session.d.ts
CHANGED
|
@@ -160,6 +160,7 @@ export declare const RemoveToolResultParamsSchema: z.ZodObject<{
|
|
|
160
160
|
keep_recent_n_tool_results: z.ZodOptional<z.ZodNumber>;
|
|
161
161
|
tool_result_placeholder: z.ZodOptional<z.ZodString>;
|
|
162
162
|
keep_tools: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
163
|
+
gt_token: z.ZodOptional<z.ZodNumber>;
|
|
163
164
|
}, z.core.$strip>;
|
|
164
165
|
export type RemoveToolResultParams = z.infer<typeof RemoveToolResultParamsSchema>;
|
|
165
166
|
/**
|
|
@@ -168,6 +169,7 @@ export type RemoveToolResultParams = z.infer<typeof RemoveToolResultParamsSchema
|
|
|
168
169
|
export declare const RemoveToolCallParamsParamsSchema: z.ZodObject<{
|
|
169
170
|
keep_recent_n_tool_calls: z.ZodOptional<z.ZodNumber>;
|
|
170
171
|
keep_tools: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
172
|
+
gt_token: z.ZodOptional<z.ZodNumber>;
|
|
171
173
|
}, z.core.$strip>;
|
|
172
174
|
export type RemoveToolCallParamsParams = z.infer<typeof RemoveToolCallParamsParamsSchema>;
|
|
173
175
|
/**
|
|
@@ -184,6 +186,7 @@ export declare const RemoveToolCallParamsStrategySchema: z.ZodObject<{
|
|
|
184
186
|
params: z.ZodObject<{
|
|
185
187
|
keep_recent_n_tool_calls: z.ZodOptional<z.ZodNumber>;
|
|
186
188
|
keep_tools: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
189
|
+
gt_token: z.ZodOptional<z.ZodNumber>;
|
|
187
190
|
}, z.core.$strip>;
|
|
188
191
|
}, z.core.$strip>;
|
|
189
192
|
export type RemoveToolCallParamsStrategy = z.infer<typeof RemoveToolCallParamsStrategySchema>;
|
|
@@ -198,6 +201,7 @@ export declare const RemoveToolResultStrategySchema: z.ZodObject<{
|
|
|
198
201
|
keep_recent_n_tool_results: z.ZodOptional<z.ZodNumber>;
|
|
199
202
|
tool_result_placeholder: z.ZodOptional<z.ZodString>;
|
|
200
203
|
keep_tools: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
204
|
+
gt_token: z.ZodOptional<z.ZodNumber>;
|
|
201
205
|
}, z.core.$strip>;
|
|
202
206
|
}, z.core.$strip>;
|
|
203
207
|
export type RemoveToolResultStrategy = z.infer<typeof RemoveToolResultStrategySchema>;
|
|
@@ -253,12 +257,14 @@ export declare const EditStrategySchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
253
257
|
keep_recent_n_tool_results: z.ZodOptional<z.ZodNumber>;
|
|
254
258
|
tool_result_placeholder: z.ZodOptional<z.ZodString>;
|
|
255
259
|
keep_tools: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
260
|
+
gt_token: z.ZodOptional<z.ZodNumber>;
|
|
256
261
|
}, z.core.$strip>;
|
|
257
262
|
}, z.core.$strip>, z.ZodObject<{
|
|
258
263
|
type: z.ZodLiteral<"remove_tool_call_params">;
|
|
259
264
|
params: z.ZodObject<{
|
|
260
265
|
keep_recent_n_tool_calls: z.ZodOptional<z.ZodNumber>;
|
|
261
266
|
keep_tools: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
267
|
+
gt_token: z.ZodOptional<z.ZodNumber>;
|
|
262
268
|
}, z.core.$strip>;
|
|
263
269
|
}, z.core.$strip>, z.ZodObject<{
|
|
264
270
|
type: z.ZodLiteral<"token_limit">;
|
package/dist/types/session.js
CHANGED
|
@@ -123,6 +123,11 @@ exports.RemoveToolResultParamsSchema = zod_1.z.object({
|
|
|
123
123
|
* Tool results from these tools are always kept regardless of keep_recent_n_tool_results.
|
|
124
124
|
*/
|
|
125
125
|
keep_tools: zod_1.z.array(zod_1.z.string()).optional(),
|
|
126
|
+
/**
|
|
127
|
+
* Only remove tool results whose text has more than this many tokens.
|
|
128
|
+
* If omitted, all tool results are eligible for removal.
|
|
129
|
+
*/
|
|
130
|
+
gt_token: zod_1.z.number().int().min(1).optional(),
|
|
126
131
|
});
|
|
127
132
|
/**
|
|
128
133
|
* Parameters for the remove_tool_call_params edit strategy.
|
|
@@ -138,6 +143,11 @@ exports.RemoveToolCallParamsParamsSchema = zod_1.z.object({
|
|
|
138
143
|
* Tool calls for these tools always keep their full parameters regardless of keep_recent_n_tool_calls.
|
|
139
144
|
*/
|
|
140
145
|
keep_tools: zod_1.z.array(zod_1.z.string()).optional(),
|
|
146
|
+
/**
|
|
147
|
+
* Only remove tool call params whose arguments have more than this many tokens.
|
|
148
|
+
* If omitted, all tool calls are eligible for removal.
|
|
149
|
+
*/
|
|
150
|
+
gt_token: zod_1.z.number().int().min(1).optional(),
|
|
141
151
|
});
|
|
142
152
|
/**
|
|
143
153
|
* Edit strategy to remove parameters from old tool-call parts.
|