@k2b/nessi 0.10.0-rc.0
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/LICENSE +21 -0
- package/README.md +251 -0
- package/aggregates.d.ts +7 -0
- package/aggregates.js +115 -0
- package/ai/complete-from-stream.d.ts +2 -0
- package/ai/complete-from-stream.js +36 -0
- package/ai/index.d.ts +10 -0
- package/ai/index.js +9 -0
- package/ai/providers/anthropic.d.ts +13 -0
- package/ai/providers/anthropic.js +266 -0
- package/ai/providers/gemini.d.ts +12 -0
- package/ai/providers/gemini.js +192 -0
- package/ai/providers/mistral.d.ts +12 -0
- package/ai/providers/mistral.js +287 -0
- package/ai/providers/ollama.d.ts +10 -0
- package/ai/providers/ollama.js +241 -0
- package/ai/providers/openai-compatible.d.ts +2 -0
- package/ai/providers/openai-compatible.js +349 -0
- package/ai/providers/openai.d.ts +12 -0
- package/ai/providers/openai.js +22 -0
- package/ai/providers/openrouter.d.ts +13 -0
- package/ai/providers/openrouter.js +28 -0
- package/ai/providers/vllm.d.ts +11 -0
- package/ai/providers/vllm.js +22 -0
- package/ai/shared/errors.d.ts +15 -0
- package/ai/shared/errors.js +56 -0
- package/ai/shared/json.d.ts +3 -0
- package/ai/shared/json.js +15 -0
- package/ai/shared/messages.d.ts +15 -0
- package/ai/shared/messages.js +58 -0
- package/ai/shared/ndjson.d.ts +4 -0
- package/ai/shared/ndjson.js +60 -0
- package/ai/shared/sse.d.ts +15 -0
- package/ai/shared/sse.js +79 -0
- package/ai/shared/stream-helpers.d.ts +13 -0
- package/ai/shared/stream-helpers.js +105 -0
- package/ai/shared/tool-call-ids.d.ts +5 -0
- package/ai/shared/tool-call-ids.js +38 -0
- package/ai/shared/tool-stream-normalizer.d.ts +6 -0
- package/ai/shared/tool-stream-normalizer.js +271 -0
- package/ai/shared/tools.d.ts +29 -0
- package/ai/shared/tools.js +25 -0
- package/ai/shared/usage.d.ts +3 -0
- package/ai/shared/usage.js +5 -0
- package/ai/types.d.ts +252 -0
- package/ai/types.js +0 -0
- package/compact.d.ts +5 -0
- package/compact.js +108 -0
- package/index.d.ts +11 -0
- package/index.js +12 -0
- package/nessi.d.ts +2 -0
- package/nessi.js +1250 -0
- package/package.json +80 -0
- package/providers/ollama.d.ts +2 -0
- package/providers/ollama.js +1 -0
- package/providers/openai.d.ts +2 -0
- package/providers/openai.js +1 -0
- package/providers/openrouter.d.ts +2 -0
- package/providers/openrouter.js +1 -0
- package/stores.d.ts +11 -0
- package/stores.js +42 -0
- package/structured.d.ts +9 -0
- package/structured.js +413 -0
- package/tools.d.ts +25 -0
- package/tools.js +36 -0
- package/types.d.ts +290 -0
- package/types.js +3 -0
- package/utils.d.ts +15 -0
- package/utils.js +47 -0
package/ai/types.d.ts
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
export type InputFilePart = {
|
|
2
|
+
type: "file";
|
|
3
|
+
data: string;
|
|
4
|
+
mediaType: string;
|
|
5
|
+
};
|
|
6
|
+
export type ContentPart = string | {
|
|
7
|
+
type: "text";
|
|
8
|
+
text: string;
|
|
9
|
+
} | InputFilePart;
|
|
10
|
+
export type TextBlock = {
|
|
11
|
+
type: "text";
|
|
12
|
+
text: string;
|
|
13
|
+
};
|
|
14
|
+
export type ThinkingBlock = {
|
|
15
|
+
type: "thinking";
|
|
16
|
+
thinking: string;
|
|
17
|
+
};
|
|
18
|
+
export type ToolCallBlock = {
|
|
19
|
+
type: "tool_call";
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
args: Record<string, unknown>;
|
|
23
|
+
};
|
|
24
|
+
export type AssistantContentBlock = TextBlock | ThinkingBlock | ToolCallBlock;
|
|
25
|
+
export type AssistantBlockKind = AssistantContentBlock["type"];
|
|
26
|
+
export type UserMessage = {
|
|
27
|
+
role: "user";
|
|
28
|
+
content: ContentPart[];
|
|
29
|
+
};
|
|
30
|
+
export type AssistantStopReason = "stop" | "tool_use" | "max_tokens" | "aborted" | "interrupted" | "error";
|
|
31
|
+
export type AssistantMessage = {
|
|
32
|
+
role: "assistant";
|
|
33
|
+
content: AssistantContentBlock[];
|
|
34
|
+
model?: string;
|
|
35
|
+
usage?: Usage;
|
|
36
|
+
stopReason?: AssistantStopReason;
|
|
37
|
+
};
|
|
38
|
+
export type HistoricalToolResult = {
|
|
39
|
+
originLoopId: string;
|
|
40
|
+
value: unknown;
|
|
41
|
+
};
|
|
42
|
+
export type ToolResultMessage = {
|
|
43
|
+
role: "tool_result";
|
|
44
|
+
callId: string;
|
|
45
|
+
name: string;
|
|
46
|
+
result: unknown;
|
|
47
|
+
historicalResult?: HistoricalToolResult;
|
|
48
|
+
isError?: boolean;
|
|
49
|
+
};
|
|
50
|
+
export type Message = UserMessage | AssistantMessage | ToolResultMessage;
|
|
51
|
+
export type Usage = {
|
|
52
|
+
input: number;
|
|
53
|
+
output: number;
|
|
54
|
+
cacheRead?: number;
|
|
55
|
+
total: number;
|
|
56
|
+
creditsUsed?: number;
|
|
57
|
+
};
|
|
58
|
+
export type JsonSchemaObject = Record<string, unknown>;
|
|
59
|
+
export type ResponseFormat = {
|
|
60
|
+
type: "json_schema";
|
|
61
|
+
name?: string;
|
|
62
|
+
schema: JsonSchemaObject;
|
|
63
|
+
};
|
|
64
|
+
export type ToolStreamIssueKind = "malformed_tool_call" | "cancelled_tool_call";
|
|
65
|
+
export type ToolStreamIssueReason = "text_during_tool_call" | "thinking_during_tool_call" | "tool_delta_without_start" | "missing_tool_name" | "invalid_tool_arguments" | "stream_ended_before_tool_call" | "provider_error_before_tool_call";
|
|
66
|
+
export type ToolStreamIssue = {
|
|
67
|
+
kind: ToolStreamIssueKind;
|
|
68
|
+
reason: ToolStreamIssueReason;
|
|
69
|
+
message: string;
|
|
70
|
+
callId?: string;
|
|
71
|
+
name?: string;
|
|
72
|
+
argsText?: string;
|
|
73
|
+
textDelta?: string;
|
|
74
|
+
};
|
|
75
|
+
export type ProviderIssue = {
|
|
76
|
+
kind: "provider_error";
|
|
77
|
+
message: string;
|
|
78
|
+
retryable: boolean;
|
|
79
|
+
contextOverflow?: boolean;
|
|
80
|
+
overflowRatio?: number;
|
|
81
|
+
};
|
|
82
|
+
export type TimeoutIssue = {
|
|
83
|
+
kind: "timeout";
|
|
84
|
+
scope: "provider_first_byte" | "provider_idle" | "tool";
|
|
85
|
+
message: string;
|
|
86
|
+
retryable: boolean;
|
|
87
|
+
callId?: string;
|
|
88
|
+
name?: string;
|
|
89
|
+
};
|
|
90
|
+
export type ToolExecutionIssue = {
|
|
91
|
+
kind: "tool_execution_error";
|
|
92
|
+
reason: "unknown_tool" | "input_validation_failed" | "output_validation_failed" | "execution_failed" | "approval_denied";
|
|
93
|
+
message: string;
|
|
94
|
+
retryable: boolean;
|
|
95
|
+
callId: string;
|
|
96
|
+
name: string;
|
|
97
|
+
};
|
|
98
|
+
export type ToolHistoricalResultIssue = {
|
|
99
|
+
kind: "tool_historical_result_error";
|
|
100
|
+
message: string;
|
|
101
|
+
retryable: false;
|
|
102
|
+
callId: string;
|
|
103
|
+
name: string;
|
|
104
|
+
};
|
|
105
|
+
export type RuntimeIssue = {
|
|
106
|
+
kind: "runtime_error";
|
|
107
|
+
message: string;
|
|
108
|
+
retryable: boolean;
|
|
109
|
+
};
|
|
110
|
+
export type NessiIssue = ToolStreamIssue | ProviderIssue | TimeoutIssue | ToolExecutionIssue | ToolHistoricalResultIssue | RuntimeIssue;
|
|
111
|
+
export type ToolSpec = {
|
|
112
|
+
name: string;
|
|
113
|
+
description: string;
|
|
114
|
+
inputSchema: unknown;
|
|
115
|
+
};
|
|
116
|
+
export type ProviderFamily = "openai-compatible" | "ollama" | "anthropic" | "mistral" | "gemini";
|
|
117
|
+
export type ProviderCapabilities = {
|
|
118
|
+
streaming: boolean;
|
|
119
|
+
tools: boolean;
|
|
120
|
+
images: boolean;
|
|
121
|
+
thinking: boolean;
|
|
122
|
+
usage: boolean;
|
|
123
|
+
structuredOutput?: boolean;
|
|
124
|
+
};
|
|
125
|
+
export type GenerateRequest = {
|
|
126
|
+
systemPrompt?: string;
|
|
127
|
+
messages: Message[];
|
|
128
|
+
tools?: ToolSpec[];
|
|
129
|
+
responseFormat?: ResponseFormat;
|
|
130
|
+
signal?: AbortSignal;
|
|
131
|
+
temperature?: number;
|
|
132
|
+
maxOutputTokens?: number;
|
|
133
|
+
/**
|
|
134
|
+
* Ask the provider to skip (or minimize) internal reasoning for this call.
|
|
135
|
+
* Useful for simple generative tasks where reasoning tokens would otherwise
|
|
136
|
+
* consume the entire output budget. Provider-specific mapping:
|
|
137
|
+
* - openai-compatible: sets `reasoning_effort: "low"`
|
|
138
|
+
* - gemini: sets `thinkingConfig.thinkingBudget: 0`
|
|
139
|
+
* - anthropic/mistral/ollama/vllm: no-op (reasoning is opt-in or absent)
|
|
140
|
+
*/
|
|
141
|
+
disableReasoning?: boolean;
|
|
142
|
+
};
|
|
143
|
+
export type GenerateResult = {
|
|
144
|
+
message: AssistantMessage;
|
|
145
|
+
usage?: Usage;
|
|
146
|
+
finishReason: AssistantStopReason;
|
|
147
|
+
providerMeta?: {
|
|
148
|
+
requestId?: string;
|
|
149
|
+
model?: string;
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
export type BlockStartEvent = {
|
|
153
|
+
type: "block_start";
|
|
154
|
+
blockId: string;
|
|
155
|
+
index: number;
|
|
156
|
+
kind: AssistantBlockKind;
|
|
157
|
+
callId?: string;
|
|
158
|
+
name?: string;
|
|
159
|
+
};
|
|
160
|
+
export type BlockDeltaEvent = {
|
|
161
|
+
type: "block_delta";
|
|
162
|
+
blockId: string;
|
|
163
|
+
delta: string;
|
|
164
|
+
};
|
|
165
|
+
export type BlockEndEvent = {
|
|
166
|
+
type: "block_end";
|
|
167
|
+
blockId: string;
|
|
168
|
+
index: number;
|
|
169
|
+
block: AssistantContentBlock;
|
|
170
|
+
};
|
|
171
|
+
export type StreamEvent = BlockStartEvent | BlockDeltaEvent | BlockEndEvent | {
|
|
172
|
+
type: "issue";
|
|
173
|
+
issue: NessiIssue;
|
|
174
|
+
} | {
|
|
175
|
+
type: "usage";
|
|
176
|
+
usage: Usage;
|
|
177
|
+
finishReason?: AssistantStopReason;
|
|
178
|
+
};
|
|
179
|
+
export type RawStreamEvent = {
|
|
180
|
+
type: "text";
|
|
181
|
+
delta: string;
|
|
182
|
+
} | {
|
|
183
|
+
type: "thinking";
|
|
184
|
+
delta: string;
|
|
185
|
+
} | {
|
|
186
|
+
type: "tool_start";
|
|
187
|
+
callId: string;
|
|
188
|
+
name: string;
|
|
189
|
+
} | {
|
|
190
|
+
type: "tool_delta";
|
|
191
|
+
callId: string;
|
|
192
|
+
argsDelta: string;
|
|
193
|
+
} | {
|
|
194
|
+
type: "tool_call";
|
|
195
|
+
callId: string;
|
|
196
|
+
name: string;
|
|
197
|
+
args: Record<string, unknown>;
|
|
198
|
+
} | ({
|
|
199
|
+
type: "tool_error";
|
|
200
|
+
} & Omit<ToolStreamIssue, "kind">) | ({
|
|
201
|
+
type: "tool_cancel";
|
|
202
|
+
} & Omit<ToolStreamIssue, "kind">) | {
|
|
203
|
+
type: "usage";
|
|
204
|
+
usage: Usage;
|
|
205
|
+
finishReason?: AssistantStopReason;
|
|
206
|
+
} | {
|
|
207
|
+
type: "timeout";
|
|
208
|
+
scope: "provider_first_byte" | "provider_idle";
|
|
209
|
+
message: string;
|
|
210
|
+
retryable: boolean;
|
|
211
|
+
} | {
|
|
212
|
+
type: "error";
|
|
213
|
+
error: string;
|
|
214
|
+
retryable: boolean;
|
|
215
|
+
contextOverflow?: boolean;
|
|
216
|
+
overflowRatio?: number;
|
|
217
|
+
};
|
|
218
|
+
export type ProviderTimeouts = {
|
|
219
|
+
firstByteMs?: number;
|
|
220
|
+
idleMs?: number;
|
|
221
|
+
};
|
|
222
|
+
export type Provider = {
|
|
223
|
+
name: string;
|
|
224
|
+
family: ProviderFamily;
|
|
225
|
+
model: string;
|
|
226
|
+
contextWindow?: number;
|
|
227
|
+
capabilities: ProviderCapabilities;
|
|
228
|
+
stream(request: GenerateRequest): AsyncIterable<StreamEvent>;
|
|
229
|
+
complete(request: GenerateRequest): Promise<GenerateResult>;
|
|
230
|
+
};
|
|
231
|
+
export type OpenAICompat = {
|
|
232
|
+
toolCallIdPolicy?: "passthrough" | "strict9";
|
|
233
|
+
supportsUsageInStreaming?: boolean;
|
|
234
|
+
requiresToolResultName?: boolean;
|
|
235
|
+
requiresAssistantAfterToolResult?: boolean;
|
|
236
|
+
thinkingFormat?: "none" | "reasoning_details" | "text";
|
|
237
|
+
maxTokensField?: "max_tokens" | "max_completion_tokens";
|
|
238
|
+
structuredOutput?: "response_format" | "vllm_structured_outputs" | false;
|
|
239
|
+
};
|
|
240
|
+
export type OpenAICompatibleConfig = {
|
|
241
|
+
name: string;
|
|
242
|
+
model: string;
|
|
243
|
+
baseURL: string;
|
|
244
|
+
apiKey?: string;
|
|
245
|
+
contextWindow?: number;
|
|
246
|
+
compat?: OpenAICompat;
|
|
247
|
+
timeouts?: ProviderTimeouts;
|
|
248
|
+
temperature?: number;
|
|
249
|
+
creditsPerInputToken?: number;
|
|
250
|
+
creditsPerOutputToken?: number;
|
|
251
|
+
headers?: Record<string, string>;
|
|
252
|
+
};
|
package/ai/types.js
ADDED
|
File without changes
|
package/compact.d.ts
ADDED
package/compact.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { createLoopId, zeroUsage, toErrorMessage } from "./utils.js";
|
|
2
|
+
/**
|
|
3
|
+
* Run compaction as a loop-style operation so consumers can iterate or subscribe to events.
|
|
4
|
+
*/
|
|
5
|
+
export const compact = (options) => {
|
|
6
|
+
const { agentId = "main", loopId: requestedLoopId, store, provider, compact: compactFn, usage = zeroUsage(), force = true, signal: externalSignal, } = options;
|
|
7
|
+
const subscribers = [];
|
|
8
|
+
const abortController = new AbortController();
|
|
9
|
+
const loopId = requestedLoopId?.trim() ? requestedLoopId : createLoopId();
|
|
10
|
+
const eventFields = { agentId, loopId };
|
|
11
|
+
if (externalSignal) {
|
|
12
|
+
if (externalSignal.aborted)
|
|
13
|
+
abortController.abort();
|
|
14
|
+
else
|
|
15
|
+
externalSignal.addEventListener("abort", () => abortController.abort(), { once: true });
|
|
16
|
+
}
|
|
17
|
+
const signal = abortController.signal;
|
|
18
|
+
const mkResult = (applied, entriesBefore, entriesAfter) => ({
|
|
19
|
+
applied,
|
|
20
|
+
entriesBefore,
|
|
21
|
+
entriesAfter,
|
|
22
|
+
forced: force,
|
|
23
|
+
});
|
|
24
|
+
async function* run() {
|
|
25
|
+
let entriesBefore = 0;
|
|
26
|
+
yield { type: "loop_start", ...eventFields };
|
|
27
|
+
try {
|
|
28
|
+
const entries = await store.load();
|
|
29
|
+
entriesBefore = entries.length;
|
|
30
|
+
if (signal.aborted) {
|
|
31
|
+
yield { type: "loop_end", ...eventFields, reason: "aborted", result: mkResult(false, entriesBefore, entriesBefore) };
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const operation = compactFn({
|
|
35
|
+
entries,
|
|
36
|
+
store,
|
|
37
|
+
provider,
|
|
38
|
+
usage,
|
|
39
|
+
force,
|
|
40
|
+
});
|
|
41
|
+
if (!operation) {
|
|
42
|
+
yield { type: "loop_end", ...eventFields, reason: "stop", result: mkResult(false, entriesBefore, entriesBefore) };
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
yield { type: "compaction_start", ...eventFields };
|
|
46
|
+
try {
|
|
47
|
+
await operation;
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
yield { type: "compaction_end", ...eventFields };
|
|
51
|
+
}
|
|
52
|
+
const entriesAfter = (await store.load()).length;
|
|
53
|
+
yield {
|
|
54
|
+
type: "loop_end",
|
|
55
|
+
...eventFields,
|
|
56
|
+
reason: signal.aborted ? "aborted" : "stop",
|
|
57
|
+
result: mkResult(true, entriesBefore, entriesAfter),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
const message = toErrorMessage(err);
|
|
62
|
+
const entriesAfter = await store.load().then(e => e.length).catch(() => entriesBefore);
|
|
63
|
+
yield {
|
|
64
|
+
type: "issue",
|
|
65
|
+
...eventFields,
|
|
66
|
+
issue: { kind: "runtime_error", message, retryable: false },
|
|
67
|
+
};
|
|
68
|
+
yield {
|
|
69
|
+
type: "loop_end",
|
|
70
|
+
...eventFields,
|
|
71
|
+
reason: signal.aborted ? "aborted" : "error",
|
|
72
|
+
result: mkResult(false, entriesBefore, entriesAfter),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const generator = run();
|
|
77
|
+
return {
|
|
78
|
+
[Symbol.asyncIterator]() {
|
|
79
|
+
return {
|
|
80
|
+
async next() {
|
|
81
|
+
const result = await generator.next();
|
|
82
|
+
if (!result.done && result.value) {
|
|
83
|
+
for (const subscriber of subscribers)
|
|
84
|
+
subscriber(result.value);
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
},
|
|
88
|
+
async return(value) {
|
|
89
|
+
return generator.return(value);
|
|
90
|
+
},
|
|
91
|
+
async throw(err) {
|
|
92
|
+
return generator.throw(err);
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
},
|
|
96
|
+
subscribe(listener) {
|
|
97
|
+
subscribers.push(listener);
|
|
98
|
+
return () => {
|
|
99
|
+
const idx = subscribers.indexOf(listener);
|
|
100
|
+
if (idx >= 0)
|
|
101
|
+
subscribers.splice(idx, 1);
|
|
102
|
+
};
|
|
103
|
+
},
|
|
104
|
+
abort() {
|
|
105
|
+
abortController.abort();
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
};
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { structured, StructuredOutputError } from "./structured.js";
|
|
2
|
+
export declare const nessi: ((options: import("./types.js").NessiOptions) => import("./types.js").NessiLoop) & {
|
|
3
|
+
structured: <TOutput extends import("zod").ZodType>(options: import("./types.js").StructuredOptions<TOutput>) => Promise<import("./types.js").StructuredResult<import("zod").infer<TOutput>>>;
|
|
4
|
+
};
|
|
5
|
+
export { structured, StructuredOutputError };
|
|
6
|
+
export { compact } from "./compact.js";
|
|
7
|
+
export { defineTool, toolToJsonSchema, toolToSpec } from "./tools.js";
|
|
8
|
+
export { memoryStore } from "./stores.js";
|
|
9
|
+
export { estimateTokens, truncateMiddle, truncateToolResults } from "./utils.js";
|
|
10
|
+
export { cloneLoopAggregate, cloneUsage, mergeLoopAggregates, mergeUsage } from "./aggregates.js";
|
|
11
|
+
export type { NessiOptions, NessiLoop, SteeringContext, SteeringFn, StructuredInput, StructuredMeta, StructuredMode, StructuredOptions, StructuredResult, ContentPart, JsonSchemaObject, Input, OutboundEvent, InboundEvent, DoneReason, LoopAggregate, LoopTimingAggregate, LoopTurnAggregate, LoopToolCallAggregate, LoopToolIssueAggregate, Message, UserMessage, AssistantMessage, AssistantStopReason, HistoricalToolResult, ToolResultMessage, AssistantContentBlock, TextBlock, ThinkingBlock, ToolCallBlock, ToolStreamIssue, ToolStreamIssueKind, ToolStreamIssueReason, ToolHistoricalResultIssue, Usage, ToolDefinition, HistoricalToolResultContext, ServerTool, ClientTool, Tool, ToolContext, Provider, ProviderRequest, ProviderEvent, ResponseFormat, StoreEntry, SessionStore, CompactFn, CompactContext, CompactOptions, CompactResult, CompactDoneReason, CompactEvent, CompactLoop, CreditStore, } from "./types.js";
|
package/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// nessi – Public API
|
|
3
|
+
// ============================================================================
|
|
4
|
+
import { nessi as createNessiLoop } from "./nessi.js";
|
|
5
|
+
import { structured, StructuredOutputError } from "./structured.js";
|
|
6
|
+
export const nessi = Object.assign(createNessiLoop, { structured });
|
|
7
|
+
export { structured, StructuredOutputError };
|
|
8
|
+
export { compact } from "./compact.js";
|
|
9
|
+
export { defineTool, toolToJsonSchema, toolToSpec } from "./tools.js";
|
|
10
|
+
export { memoryStore } from "./stores.js";
|
|
11
|
+
export { estimateTokens, truncateMiddle, truncateToolResults } from "./utils.js";
|
|
12
|
+
export { cloneLoopAggregate, cloneUsage, mergeLoopAggregates, mergeUsage } from "./aggregates.js";
|
package/nessi.d.ts
ADDED