@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/types.d.ts
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import type { AssistantStopReason, BlockDeltaEvent, BlockEndEvent, BlockStartEvent, AssistantMessage, ContentPart, GenerateRequest, GenerateResult, Message, NessiIssue, Provider, StreamEvent, ToolStreamIssue, Usage, UserMessage } from "./ai/index.js";
|
|
3
|
+
export type { AssistantContentBlock, AssistantBlockKind, AssistantMessage, AssistantStopReason, BlockDeltaEvent, BlockEndEvent, BlockStartEvent, ContentPart, JsonSchemaObject, HistoricalToolResult, Message, NessiIssue, Provider, ProviderIssue, ResponseFormat, RuntimeIssue, TextBlock, ThinkingBlock, ToolCallBlock, ToolExecutionIssue, ToolHistoricalResultIssue, ToolResultMessage, ToolStreamIssue, ToolStreamIssueKind, ToolStreamIssueReason, ToolSpec, TimeoutIssue, Usage, UserMessage, } from "./ai/index.js";
|
|
4
|
+
export type ProviderEvent = StreamEvent;
|
|
5
|
+
export type ProviderRequest = GenerateRequest;
|
|
6
|
+
export type Input = string | ContentPart[];
|
|
7
|
+
type LoopEventFields = {
|
|
8
|
+
agentId: string;
|
|
9
|
+
loopId: string;
|
|
10
|
+
};
|
|
11
|
+
type TurnEventFields = LoopEventFields & {
|
|
12
|
+
turnId: string;
|
|
13
|
+
turnIndex: number;
|
|
14
|
+
};
|
|
15
|
+
export type ToolActionKind = "approval" | "client_tool" | "custom_approval";
|
|
16
|
+
export type OutboundEvent = (LoopEventFields & {
|
|
17
|
+
type: "loop_start";
|
|
18
|
+
}) | (TurnEventFields & {
|
|
19
|
+
type: "turn_start";
|
|
20
|
+
resumed?: boolean;
|
|
21
|
+
}) | (TurnEventFields & BlockStartEvent) | (TurnEventFields & BlockDeltaEvent) | (TurnEventFields & BlockEndEvent) | (TurnEventFields & {
|
|
22
|
+
type: "usage";
|
|
23
|
+
usage: Usage;
|
|
24
|
+
finishReason?: AssistantStopReason;
|
|
25
|
+
}) | (LoopEventFields & {
|
|
26
|
+
type: "issue";
|
|
27
|
+
issue: NessiIssue;
|
|
28
|
+
turnId?: string;
|
|
29
|
+
turnIndex?: number;
|
|
30
|
+
}) | (TurnEventFields & {
|
|
31
|
+
type: "tool_execution_start";
|
|
32
|
+
callId: string;
|
|
33
|
+
name: string;
|
|
34
|
+
args: unknown;
|
|
35
|
+
}) | (TurnEventFields & {
|
|
36
|
+
type: "tool_action_request";
|
|
37
|
+
kind: ToolActionKind;
|
|
38
|
+
callId: string;
|
|
39
|
+
name: string;
|
|
40
|
+
args: unknown;
|
|
41
|
+
message?: string;
|
|
42
|
+
}) | (TurnEventFields & {
|
|
43
|
+
type: "tool_execution_end";
|
|
44
|
+
callId: string;
|
|
45
|
+
name: string;
|
|
46
|
+
result: unknown;
|
|
47
|
+
isError?: boolean;
|
|
48
|
+
}) | (TurnEventFields & {
|
|
49
|
+
type: "turn_end";
|
|
50
|
+
message: AssistantMessage;
|
|
51
|
+
}) | (LoopEventFields & {
|
|
52
|
+
type: "steer_applied";
|
|
53
|
+
message: string;
|
|
54
|
+
}) | (LoopEventFields & {
|
|
55
|
+
type: "compaction_start";
|
|
56
|
+
}) | (LoopEventFields & {
|
|
57
|
+
type: "compaction_end";
|
|
58
|
+
}) | (LoopEventFields & {
|
|
59
|
+
type: "loop_end";
|
|
60
|
+
reason: DoneReason;
|
|
61
|
+
aggregate: LoopAggregate;
|
|
62
|
+
});
|
|
63
|
+
export type InboundEvent = {
|
|
64
|
+
type: "approval_response";
|
|
65
|
+
callId: string;
|
|
66
|
+
approved: boolean;
|
|
67
|
+
} | {
|
|
68
|
+
type: "tool_result";
|
|
69
|
+
callId: string;
|
|
70
|
+
result: unknown;
|
|
71
|
+
};
|
|
72
|
+
export type DoneReason = "stop" | "no_credits" | "max_turns" | "context_overflow" | "error" | "aborted";
|
|
73
|
+
export type LoopToolCallAggregate = {
|
|
74
|
+
callId: string;
|
|
75
|
+
name: string;
|
|
76
|
+
args: unknown;
|
|
77
|
+
result?: unknown;
|
|
78
|
+
isError?: boolean;
|
|
79
|
+
};
|
|
80
|
+
export type LoopToolIssueAggregate = ToolStreamIssue;
|
|
81
|
+
export type LoopIssueAggregate = NessiIssue;
|
|
82
|
+
export type LoopTurnAggregate = {
|
|
83
|
+
message: AssistantMessage;
|
|
84
|
+
usage?: Usage;
|
|
85
|
+
stopReason?: AssistantMessage["stopReason"];
|
|
86
|
+
toolCalls: LoopToolCallAggregate[];
|
|
87
|
+
toolIssues?: LoopToolIssueAggregate[];
|
|
88
|
+
issues?: LoopIssueAggregate[];
|
|
89
|
+
};
|
|
90
|
+
export type LoopTimingAggregate = {
|
|
91
|
+
wallMs: number;
|
|
92
|
+
totalElapsedMs: number;
|
|
93
|
+
generationMs: number;
|
|
94
|
+
toolExecutionMs: number;
|
|
95
|
+
actionWaitMs: number;
|
|
96
|
+
outputTokensPerSecond?: number;
|
|
97
|
+
};
|
|
98
|
+
export type LoopAggregate = {
|
|
99
|
+
turns: LoopTurnAggregate[];
|
|
100
|
+
usage?: Usage;
|
|
101
|
+
timing?: LoopTimingAggregate;
|
|
102
|
+
issueCount: number;
|
|
103
|
+
issues: LoopIssueAggregate[];
|
|
104
|
+
toolCallCount: number;
|
|
105
|
+
toolErrorCount: number;
|
|
106
|
+
toolIssueCount: number;
|
|
107
|
+
toolMalformedCount: number;
|
|
108
|
+
toolCancelledCount: number;
|
|
109
|
+
toolIssues: LoopToolIssueAggregate[];
|
|
110
|
+
assistantMessageCount: number;
|
|
111
|
+
};
|
|
112
|
+
export type HistoricalToolResultContext<TInput extends z.ZodType = z.ZodType, TOutput extends z.ZodType = z.ZodType> = {
|
|
113
|
+
input: z.infer<TInput>;
|
|
114
|
+
output: z.infer<TOutput>;
|
|
115
|
+
callId: string;
|
|
116
|
+
};
|
|
117
|
+
export type ToolDefinition<TInput extends z.ZodType = z.ZodType, TOutput extends z.ZodType = z.ZodType> = {
|
|
118
|
+
name: string;
|
|
119
|
+
description: string;
|
|
120
|
+
inputSchema: TInput;
|
|
121
|
+
outputSchema?: TOutput;
|
|
122
|
+
needsApproval?: boolean;
|
|
123
|
+
timeoutMs?: number | false;
|
|
124
|
+
/** Derive a smaller representation that later loops send to the provider instead of the full result. */
|
|
125
|
+
toHistoricalResult?: (context: HistoricalToolResultContext<TInput, TOutput>) => unknown | Promise<unknown>;
|
|
126
|
+
server(execute: (input: z.infer<TInput>, ctx: ToolContext) => Promise<z.infer<TOutput>>): ServerTool<TInput, TOutput>;
|
|
127
|
+
client(execute: (input: z.infer<TInput>) => z.infer<TOutput> | Promise<z.infer<TOutput>>): ClientTool<TInput, TOutput>;
|
|
128
|
+
};
|
|
129
|
+
export type ServerTool<TInput extends z.ZodType = z.ZodType, TOutput extends z.ZodType = z.ZodType> = {
|
|
130
|
+
readonly kind: "server";
|
|
131
|
+
readonly def: ToolDefinition<TInput, TOutput>;
|
|
132
|
+
execute(input: z.infer<TInput>, ctx: ToolContext): Promise<z.infer<TOutput>>;
|
|
133
|
+
};
|
|
134
|
+
export type ClientTool<TInput extends z.ZodType = z.ZodType, TOutput extends z.ZodType = z.ZodType> = {
|
|
135
|
+
readonly kind: "client";
|
|
136
|
+
readonly def: ToolDefinition<TInput, TOutput>;
|
|
137
|
+
execute(input: z.infer<TInput>): z.infer<TOutput> | Promise<z.infer<TOutput>>;
|
|
138
|
+
};
|
|
139
|
+
export type Tool = ServerTool | ClientTool;
|
|
140
|
+
export type ToolContext = {
|
|
141
|
+
signal: AbortSignal;
|
|
142
|
+
/** Request user approval mid-execution. Returns true if approved, false if denied. */
|
|
143
|
+
requestApproval(message: string): Promise<boolean>;
|
|
144
|
+
/** Request a client-side tool execution mid-execution. */
|
|
145
|
+
requestClientTool<T = unknown>(name: string, args: unknown): Promise<T>;
|
|
146
|
+
};
|
|
147
|
+
export type NessiOptions = {
|
|
148
|
+
agentId?: string;
|
|
149
|
+
/** Correlates every outbound event emitted by one logical nessi() loop. Generated when omitted. */
|
|
150
|
+
loopId?: string;
|
|
151
|
+
/**
|
|
152
|
+
* User input for this loop. When omitted, the loop runs directly over the existing
|
|
153
|
+
* store history: a trailing user message acts as the prompt, and unresolved tool_call
|
|
154
|
+
* blocks on the trailing assistant message are resumed (executed or re-requested)
|
|
155
|
+
* before the next provider turn. Push matching approval_response / tool_result events
|
|
156
|
+
* before iterating to seed a resumed loop.
|
|
157
|
+
*/
|
|
158
|
+
input?: Input;
|
|
159
|
+
provider: Provider;
|
|
160
|
+
systemPrompt: string;
|
|
161
|
+
tools?: Tool[];
|
|
162
|
+
store: SessionStore;
|
|
163
|
+
creditStore?: CreditStore;
|
|
164
|
+
compact?: CompactFn;
|
|
165
|
+
/** Supplies pending steering messages at safe loop boundaries. */
|
|
166
|
+
steering?: SteeringFn;
|
|
167
|
+
maxTurns?: number;
|
|
168
|
+
temperature?: number;
|
|
169
|
+
maxOutputTokens?: number;
|
|
170
|
+
disableReasoning?: boolean;
|
|
171
|
+
coalesce?: CoalesceOptions;
|
|
172
|
+
/** Max chars for tool results in the context sent to the provider. Longer results are truncated. */
|
|
173
|
+
maxToolResultChars?: number;
|
|
174
|
+
signal?: AbortSignal;
|
|
175
|
+
};
|
|
176
|
+
export type SteeringContext = {
|
|
177
|
+
agentId: string;
|
|
178
|
+
loopId: string;
|
|
179
|
+
signal: AbortSignal;
|
|
180
|
+
};
|
|
181
|
+
export type SteeringFn = (context: SteeringContext) => string | readonly string[] | undefined | Promise<string | readonly string[] | undefined>;
|
|
182
|
+
export type CoalesceOptions = {
|
|
183
|
+
ms?: number;
|
|
184
|
+
maxChars?: number;
|
|
185
|
+
};
|
|
186
|
+
export type NessiLoop = {
|
|
187
|
+
[Symbol.asyncIterator](): AsyncIterator<OutboundEvent>;
|
|
188
|
+
subscribe(listener: (event: OutboundEvent) => void): () => void;
|
|
189
|
+
push(event: InboundEvent): void;
|
|
190
|
+
steer(message: string): void;
|
|
191
|
+
abort(): void;
|
|
192
|
+
};
|
|
193
|
+
export type StructuredInput = Input | UserMessage;
|
|
194
|
+
export type StructuredMode = "native" | "fallback" | "repair" | "tool_loop";
|
|
195
|
+
export type StructuredMeta = {
|
|
196
|
+
mode: StructuredMode;
|
|
197
|
+
repaired: boolean;
|
|
198
|
+
attempts: number;
|
|
199
|
+
usedResponseFormat: boolean;
|
|
200
|
+
};
|
|
201
|
+
export type StructuredOptions<TOutput extends z.ZodType = z.ZodType> = {
|
|
202
|
+
agentId?: string;
|
|
203
|
+
/** Correlates the internal structured task. Generated when omitted. */
|
|
204
|
+
loopId?: string;
|
|
205
|
+
provider: Provider;
|
|
206
|
+
systemPrompt?: string;
|
|
207
|
+
input: StructuredInput;
|
|
208
|
+
output: TOutput;
|
|
209
|
+
outputName?: string;
|
|
210
|
+
tools?: ServerTool[];
|
|
211
|
+
maxTurns?: number;
|
|
212
|
+
temperature?: number;
|
|
213
|
+
maxOutputTokens?: number;
|
|
214
|
+
disableReasoning?: boolean;
|
|
215
|
+
signal?: AbortSignal;
|
|
216
|
+
onEvent?: (event: OutboundEvent) => void;
|
|
217
|
+
};
|
|
218
|
+
export type StructuredResult<TOutput> = {
|
|
219
|
+
output: TOutput;
|
|
220
|
+
message: AssistantMessage;
|
|
221
|
+
aggregate: LoopAggregate;
|
|
222
|
+
reason: DoneReason;
|
|
223
|
+
loopId: string;
|
|
224
|
+
usage?: Usage;
|
|
225
|
+
providerMeta?: GenerateResult["providerMeta"];
|
|
226
|
+
structuredMeta: StructuredMeta;
|
|
227
|
+
};
|
|
228
|
+
export type StoreEntry = {
|
|
229
|
+
seq: number;
|
|
230
|
+
kind: "message" | "summary";
|
|
231
|
+
message: Message;
|
|
232
|
+
};
|
|
233
|
+
export type SessionStore = {
|
|
234
|
+
load(): Promise<StoreEntry[]>;
|
|
235
|
+
append(message: Message, opts?: {
|
|
236
|
+
seq?: number;
|
|
237
|
+
kind?: "message" | "summary";
|
|
238
|
+
}): Promise<void>;
|
|
239
|
+
};
|
|
240
|
+
export type CompactFn = (ctx: CompactContext) => null | Promise<void>;
|
|
241
|
+
export type CompactContext = {
|
|
242
|
+
entries: StoreEntry[];
|
|
243
|
+
store: SessionStore;
|
|
244
|
+
provider: Provider;
|
|
245
|
+
usage: Usage;
|
|
246
|
+
force: boolean;
|
|
247
|
+
/** Estimated fill ratio (estimatedTokens / contextWindow). Only set when contextWindow is known. */
|
|
248
|
+
fillRatio?: number;
|
|
249
|
+
};
|
|
250
|
+
export type CompactOptions = {
|
|
251
|
+
agentId?: string;
|
|
252
|
+
/** Correlates every event emitted by one standalone compact() run. Generated when omitted. */
|
|
253
|
+
loopId?: string;
|
|
254
|
+
store: SessionStore;
|
|
255
|
+
provider: Provider;
|
|
256
|
+
compact: CompactFn;
|
|
257
|
+
usage?: Usage;
|
|
258
|
+
force?: boolean;
|
|
259
|
+
signal?: AbortSignal;
|
|
260
|
+
};
|
|
261
|
+
export type CompactResult = {
|
|
262
|
+
applied: boolean;
|
|
263
|
+
entriesBefore: number;
|
|
264
|
+
entriesAfter: number;
|
|
265
|
+
forced: boolean;
|
|
266
|
+
};
|
|
267
|
+
export type CompactDoneReason = "stop" | "error" | "aborted";
|
|
268
|
+
export type CompactEvent = (LoopEventFields & {
|
|
269
|
+
type: "loop_start";
|
|
270
|
+
}) | (LoopEventFields & {
|
|
271
|
+
type: "compaction_start";
|
|
272
|
+
}) | (LoopEventFields & {
|
|
273
|
+
type: "compaction_end";
|
|
274
|
+
}) | (LoopEventFields & {
|
|
275
|
+
type: "issue";
|
|
276
|
+
issue: NessiIssue;
|
|
277
|
+
}) | (LoopEventFields & {
|
|
278
|
+
type: "loop_end";
|
|
279
|
+
reason: CompactDoneReason;
|
|
280
|
+
result: CompactResult;
|
|
281
|
+
});
|
|
282
|
+
export type CompactLoop = {
|
|
283
|
+
[Symbol.asyncIterator](): AsyncIterator<CompactEvent>;
|
|
284
|
+
subscribe(listener: (event: CompactEvent) => void): () => void;
|
|
285
|
+
abort(): void;
|
|
286
|
+
};
|
|
287
|
+
export type CreditStore = {
|
|
288
|
+
remaining(): Promise<number>;
|
|
289
|
+
deduct(credits: number): Promise<void>;
|
|
290
|
+
};
|
package/types.js
ADDED
package/utils.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Message, Usage } from "./types.js";
|
|
2
|
+
export declare const zeroUsage: () => Usage;
|
|
3
|
+
export declare const toErrorMessage: (err: unknown) => string;
|
|
4
|
+
export declare const createLoopId: () => `${string}-${string}-${string}-${string}-${string}`;
|
|
5
|
+
/** Rough token estimate: ~4 chars per token. Slightly overestimates due to JSON syntax — that's safer. */
|
|
6
|
+
export declare const estimateTokens: (messages: Message[]) => number;
|
|
7
|
+
/** Truncate text keeping first half and last half with omission notice. */
|
|
8
|
+
export declare const truncateMiddle: (text: string, maxChars: number) => string;
|
|
9
|
+
/**
|
|
10
|
+
* Truncate oversized tool results in a message list.
|
|
11
|
+
* Returns shallow copies — the store is untouched.
|
|
12
|
+
*/
|
|
13
|
+
export declare const truncateToolResults: (messages: Message[], maxChars: number) => Message[];
|
|
14
|
+
/** Select persisted historical tool results for provider calls outside their originating loop. */
|
|
15
|
+
export declare const projectHistoricalToolResults: (messages: Message[], loopId: string) => Message[];
|
package/utils.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// nessi – Shared Utilities
|
|
3
|
+
// ============================================================================
|
|
4
|
+
export const zeroUsage = () => ({ input: 0, output: 0, total: 0 });
|
|
5
|
+
export const toErrorMessage = (err) => err instanceof Error ? err.message : String(err);
|
|
6
|
+
export const createLoopId = () => globalThis.crypto?.randomUUID?.() ?? `loop-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
7
|
+
/** Rough token estimate: ~4 chars per token. Slightly overestimates due to JSON syntax — that's safer. */
|
|
8
|
+
export const estimateTokens = (messages) => Math.ceil(JSON.stringify(messages).length / 4);
|
|
9
|
+
/** Truncate text keeping first half and last half with omission notice. */
|
|
10
|
+
export const truncateMiddle = (text, maxChars) => {
|
|
11
|
+
if (text.length <= maxChars)
|
|
12
|
+
return text;
|
|
13
|
+
const half = Math.floor(maxChars / 2);
|
|
14
|
+
const omitted = text.length - 2 * half;
|
|
15
|
+
return `${text.slice(0, half)}\n[... ${omitted} characters omitted ...]\n${text.slice(-half)}`;
|
|
16
|
+
};
|
|
17
|
+
const stringifyResult = (value) => {
|
|
18
|
+
if (typeof value === "string")
|
|
19
|
+
return value;
|
|
20
|
+
try {
|
|
21
|
+
return JSON.stringify(value);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return String(value);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Truncate oversized tool results in a message list.
|
|
29
|
+
* Returns shallow copies — the store is untouched.
|
|
30
|
+
*/
|
|
31
|
+
export const truncateToolResults = (messages, maxChars) => messages.map((msg) => {
|
|
32
|
+
if (msg.role !== "tool_result")
|
|
33
|
+
return msg;
|
|
34
|
+
const text = stringifyResult(msg.result);
|
|
35
|
+
if (text.length <= maxChars)
|
|
36
|
+
return msg;
|
|
37
|
+
return { ...msg, result: truncateMiddle(text, maxChars) };
|
|
38
|
+
});
|
|
39
|
+
/** Select persisted historical tool results for provider calls outside their originating loop. */
|
|
40
|
+
export const projectHistoricalToolResults = (messages, loopId) => messages.map((message) => {
|
|
41
|
+
if (message.role !== "tool_result" || !message.historicalResult)
|
|
42
|
+
return message;
|
|
43
|
+
const { historicalResult, ...providerMessage } = message;
|
|
44
|
+
if (historicalResult.originLoopId === loopId)
|
|
45
|
+
return providerMessage;
|
|
46
|
+
return { ...providerMessage, result: historicalResult.value };
|
|
47
|
+
});
|