@librechat/agents 3.8.0 → 3.8.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/dist/cjs/agents/AgentContext.cjs +13 -3
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +174 -53
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +15 -5
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -1
- package/dist/cjs/langfuse.cjs +42 -0
- package/dist/cjs/langfuse.cjs.map +1 -1
- package/dist/cjs/langfuseToolOutputTracing.cjs +42 -0
- package/dist/cjs/langfuseToolOutputTracing.cjs.map +1 -1
- package/dist/cjs/langfuseTraceShaping.cjs +7 -1
- package/dist/cjs/langfuseTraceShaping.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +5 -9
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs +2 -7
- package/dist/cjs/llm/bedrock/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/contextPressureMeter.cjs +51 -10
- package/dist/cjs/llm/contextPressureMeter.cjs.map +1 -1
- package/dist/cjs/llm/init.cjs +1 -1
- package/dist/cjs/llm/invoke.cjs +2 -2
- package/dist/cjs/llm/openai/index.cjs +4 -3
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/openai/utils/index.cjs +5 -4
- package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
- package/dist/cjs/llm/preempt.cjs +3 -2
- package/dist/cjs/llm/preempt.cjs.map +1 -1
- package/dist/cjs/llm/prepareProviderRequest.cjs +9 -7
- package/dist/cjs/llm/prepareProviderRequest.cjs.map +1 -1
- package/dist/cjs/llm/providers.cjs +1 -1
- package/dist/cjs/main.cjs +11 -5
- package/dist/cjs/messages/alternation.cjs +1 -5
- package/dist/cjs/messages/alternation.cjs.map +1 -1
- package/dist/cjs/messages/budget.cjs +206 -7
- package/dist/cjs/messages/budget.cjs.map +1 -1
- package/dist/cjs/messages/cache.cjs +3 -9
- package/dist/cjs/messages/cache.cjs.map +1 -1
- package/dist/cjs/messages/core.cjs +25 -37
- package/dist/cjs/messages/core.cjs.map +1 -1
- package/dist/cjs/messages/format.cjs +131 -42
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/messages/index.cjs +2 -0
- package/dist/cjs/messages/prune.cjs +12 -7
- package/dist/cjs/messages/prune.cjs.map +1 -1
- package/dist/cjs/messages/reasoningTypes.cjs +21 -0
- package/dist/cjs/messages/reasoningTypes.cjs.map +1 -0
- package/dist/cjs/messages/recency.cjs +15 -94
- package/dist/cjs/messages/recency.cjs.map +1 -1
- package/dist/cjs/messages/toolHistoryProjection.cjs +243 -0
- package/dist/cjs/messages/toolHistoryProjection.cjs.map +1 -0
- package/dist/cjs/messages/toolResultTypes.cjs +145 -4
- package/dist/cjs/messages/toolResultTypes.cjs.map +1 -1
- package/dist/cjs/run.cjs +5 -4
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/session/AgentSession.cjs +6 -4
- package/dist/cjs/session/AgentSession.cjs.map +1 -1
- package/dist/cjs/session/JsonlSessionStore.cjs +3 -0
- package/dist/cjs/session/JsonlSessionStore.cjs.map +1 -1
- package/dist/cjs/session/index.cjs +1 -1
- package/dist/cjs/session/sessionProjection.cjs +75 -0
- package/dist/cjs/session/sessionProjection.cjs.map +1 -0
- package/dist/cjs/stream.cjs +18 -17
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/summarization/index.cjs.map +1 -1
- package/dist/cjs/summarization/node.cjs +18 -8
- package/dist/cjs/summarization/node.cjs.map +1 -1
- package/dist/cjs/summarization/shared.cjs +9 -0
- package/dist/cjs/summarization/shared.cjs.map +1 -1
- package/dist/cjs/tools/local/CompileCheckTool.cjs +1 -1
- package/dist/cjs/tools/local/LocalCodingTools.cjs +1 -1
- package/dist/cjs/utils/events.cjs +13 -0
- package/dist/cjs/utils/events.cjs.map +1 -1
- package/dist/cjs/utils/tokens.cjs +105 -0
- package/dist/cjs/utils/tokens.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +13 -3
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +176 -55
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +15 -5
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -1
- package/dist/esm/langfuse.mjs +43 -2
- package/dist/esm/langfuse.mjs.map +1 -1
- package/dist/esm/langfuseToolOutputTracing.mjs +41 -1
- package/dist/esm/langfuseToolOutputTracing.mjs.map +1 -1
- package/dist/esm/langfuseTraceShaping.mjs +7 -1
- package/dist/esm/langfuseTraceShaping.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs +5 -9
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs +2 -7
- package/dist/esm/llm/bedrock/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/contextPressureMeter.mjs +52 -11
- package/dist/esm/llm/contextPressureMeter.mjs.map +1 -1
- package/dist/esm/llm/init.mjs +1 -1
- package/dist/esm/llm/invoke.mjs +2 -2
- package/dist/esm/llm/openai/index.mjs +2 -1
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/openai/utils/index.mjs +5 -4
- package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
- package/dist/esm/llm/preempt.mjs +2 -1
- package/dist/esm/llm/preempt.mjs.map +1 -1
- package/dist/esm/llm/prepareProviderRequest.mjs +9 -7
- package/dist/esm/llm/prepareProviderRequest.mjs.map +1 -1
- package/dist/esm/llm/providers.mjs +1 -1
- package/dist/esm/main.mjs +10 -7
- package/dist/esm/messages/alternation.mjs +2 -6
- package/dist/esm/messages/alternation.mjs.map +1 -1
- package/dist/esm/messages/budget.mjs +206 -8
- package/dist/esm/messages/budget.mjs.map +1 -1
- package/dist/esm/messages/cache.mjs +3 -9
- package/dist/esm/messages/cache.mjs.map +1 -1
- package/dist/esm/messages/core.mjs +23 -33
- package/dist/esm/messages/core.mjs.map +1 -1
- package/dist/esm/messages/format.mjs +132 -43
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/messages/index.mjs +2 -0
- package/dist/esm/messages/prune.mjs +12 -7
- package/dist/esm/messages/prune.mjs.map +1 -1
- package/dist/esm/messages/reasoningTypes.mjs +20 -0
- package/dist/esm/messages/reasoningTypes.mjs.map +1 -0
- package/dist/esm/messages/recency.mjs +16 -95
- package/dist/esm/messages/recency.mjs.map +1 -1
- package/dist/esm/messages/toolHistoryProjection.mjs +237 -0
- package/dist/esm/messages/toolHistoryProjection.mjs.map +1 -0
- package/dist/esm/messages/toolResultTypes.mjs +141 -4
- package/dist/esm/messages/toolResultTypes.mjs.map +1 -1
- package/dist/esm/run.mjs +5 -4
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/session/AgentSession.mjs +6 -4
- package/dist/esm/session/AgentSession.mjs.map +1 -1
- package/dist/esm/session/JsonlSessionStore.mjs +3 -0
- package/dist/esm/session/JsonlSessionStore.mjs.map +1 -1
- package/dist/esm/session/index.mjs +1 -1
- package/dist/esm/session/sessionProjection.mjs +72 -0
- package/dist/esm/session/sessionProjection.mjs.map +1 -0
- package/dist/esm/stream.mjs +15 -14
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/summarization/index.mjs.map +1 -1
- package/dist/esm/summarization/node.mjs +19 -9
- package/dist/esm/summarization/node.mjs.map +1 -1
- package/dist/esm/summarization/shared.mjs +9 -1
- package/dist/esm/summarization/shared.mjs.map +1 -1
- package/dist/esm/tools/local/CompileCheckTool.mjs +1 -1
- package/dist/esm/tools/local/LocalCodingTools.mjs +1 -1
- package/dist/esm/utils/events.mjs +13 -0
- package/dist/esm/utils/events.mjs.map +1 -1
- package/dist/esm/utils/tokens.mjs +105 -1
- package/dist/esm/utils/tokens.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +13 -1
- package/dist/types/graphs/Graph.d.ts +27 -0
- package/dist/types/hooks/types.d.ts +4 -2
- package/dist/types/index.d.ts +1 -0
- package/dist/types/langfuse.d.ts +5 -0
- package/dist/types/langfuseToolOutputTracing.d.ts +2 -0
- package/dist/types/llm/contextPressureMeter.d.ts +2 -1
- package/dist/types/llm/prepareProviderRequest.d.ts +7 -1
- package/dist/types/messages/budget.d.ts +15 -10
- package/dist/types/messages/core.d.ts +8 -17
- package/dist/types/messages/format.d.ts +3 -2
- package/dist/types/messages/index.d.ts +1 -1
- package/dist/types/messages/prune.d.ts +1 -1
- package/dist/types/messages/reasoningTypes.d.ts +7 -0
- package/dist/types/messages/recency.d.ts +3 -0
- package/dist/types/messages/toolHistoryProjection.d.ts +65 -0
- package/dist/types/messages/toolResultTypes.d.ts +31 -1
- package/dist/types/session/sessionProjection.d.ts +10 -0
- package/dist/types/summarization/index.d.ts +2 -1
- package/dist/types/summarization/node.d.ts +1 -0
- package/dist/types/summarization/shared.d.ts +12 -0
- package/dist/types/types/graph.d.ts +20 -0
- package/dist/types/types/run.d.ts +4 -0
- package/dist/types/types/summarize.d.ts +4 -1
- package/dist/types/utils/tokens.d.ts +2 -1
- package/package.json +1 -1
- package/src/agents/AgentContext.ts +34 -3
- package/src/graphs/Graph.ts +465 -147
- package/src/graphs/MultiAgentGraph.ts +28 -6
- package/src/hooks/types.ts +4 -1
- package/src/index.ts +1 -0
- package/src/langfuse.ts +67 -9
- package/src/langfuseToolOutputTracing.ts +91 -0
- package/src/langfuseTraceShaping.ts +17 -4
- package/src/llm/anthropic/utils/message_inputs.ts +5 -10
- package/src/llm/bedrock/utils/message_inputs.ts +2 -8
- package/src/llm/contextPressureMeter.ts +80 -12
- package/src/llm/openai/utils/index.ts +5 -4
- package/src/llm/prepareProviderRequest.ts +21 -16
- package/src/messages/alternation.ts +2 -15
- package/src/messages/budget.ts +439 -23
- package/src/messages/cache.ts +8 -9
- package/src/messages/core.ts +65 -95
- package/src/messages/format.ts +262 -78
- package/src/messages/index.ts +1 -1
- package/src/messages/prune.ts +31 -12
- package/src/messages/reasoningTypes.ts +23 -0
- package/src/messages/recency.ts +35 -179
- package/src/messages/toolHistoryProjection.ts +460 -0
- package/src/messages/toolResultTypes.ts +331 -100
- package/src/run.ts +10 -2
- package/src/session/AgentSession.ts +33 -16
- package/src/session/JsonlSessionStore.ts +6 -0
- package/src/session/sessionProjection.ts +126 -0
- package/src/stream.ts +14 -19
- package/src/summarization/index.ts +2 -0
- package/src/summarization/node.ts +62 -13
- package/src/summarization/shared.ts +23 -0
- package/src/types/graph.ts +20 -0
- package/src/types/run.ts +4 -0
- package/src/types/summarize.ts +4 -1
- package/src/utils/events.ts +19 -0
- package/src/utils/tokens.ts +183 -0
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
import { isProxy } from 'node:util/types';
|
|
2
|
+
import type { BaseMessage, ContentBlock } from '@langchain/core/messages';
|
|
3
|
+
import { getProviderToolCallPartDescriptor } from './toolResultTypes';
|
|
4
|
+
import { serializeStructuredValueBounded } from '@/utils/toolContent';
|
|
5
|
+
|
|
6
|
+
interface ToolHistoryCallMirror {
|
|
7
|
+
readonly name?: string;
|
|
8
|
+
readonly arguments: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type ToolHistoryCallMirrors = Map<string, ToolHistoryCallMirror | null>;
|
|
12
|
+
|
|
13
|
+
/** Only complete argument representations can establish that a call is a mirror. */
|
|
14
|
+
export function recordToolHistoryCallMirror(
|
|
15
|
+
mirrors: ToolHistoryCallMirrors,
|
|
16
|
+
block: unknown
|
|
17
|
+
): void {
|
|
18
|
+
const descriptor = getProviderToolCallPartDescriptor(block);
|
|
19
|
+
if (descriptor == null) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (mirrors.has(descriptor.callId)) {
|
|
23
|
+
mirrors.set(descriptor.callId, null);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const call =
|
|
27
|
+
readData(block, 'tool_call') ??
|
|
28
|
+
readData(block, 'toolUse') ??
|
|
29
|
+
readData(block, 'toolCall') ??
|
|
30
|
+
block;
|
|
31
|
+
const args = readData(call, 'args') ?? readData(call, 'input');
|
|
32
|
+
const serialized = serializeStructuredValueBounded(args, 8000);
|
|
33
|
+
mirrors.set(
|
|
34
|
+
descriptor.callId,
|
|
35
|
+
serialized.truncated
|
|
36
|
+
? null
|
|
37
|
+
: {
|
|
38
|
+
name: descriptor.name,
|
|
39
|
+
arguments: serialized.content,
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function isToolHistoryCallMirror(
|
|
45
|
+
mirrors: ToolHistoryCallMirrors | undefined,
|
|
46
|
+
id: unknown,
|
|
47
|
+
name: unknown,
|
|
48
|
+
args: unknown
|
|
49
|
+
): boolean {
|
|
50
|
+
if (typeof id !== 'string') {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
const mirror = mirrors?.get(id);
|
|
54
|
+
if (mirror == null || mirror.name !== name) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
const serialized = serializeStructuredValueBounded(args, 8000);
|
|
58
|
+
return !serialized.truncated && serialized.content === mirror.arguments;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const OPENAI_RESPONSES_REPLAY_POSITIONS_KEY =
|
|
62
|
+
'__openai_responses_replay_positions__';
|
|
63
|
+
|
|
64
|
+
export type ResponsesReplayPosition = {
|
|
65
|
+
contentIndex?: number;
|
|
66
|
+
itemId: string;
|
|
67
|
+
kind: 'message' | 'output' | 'reasoning' | 'text';
|
|
68
|
+
outputIndex: number;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export function isResponsesReplayPosition(
|
|
72
|
+
value: unknown
|
|
73
|
+
): value is ResponsesReplayPosition {
|
|
74
|
+
const kind = readData(value, 'kind');
|
|
75
|
+
const itemId = readData(value, 'itemId');
|
|
76
|
+
const outputIndex = readData(value, 'outputIndex');
|
|
77
|
+
const contentIndex = readData(value, 'contentIndex');
|
|
78
|
+
return (
|
|
79
|
+
(kind === 'message' ||
|
|
80
|
+
kind === 'output' ||
|
|
81
|
+
kind === 'reasoning' ||
|
|
82
|
+
kind === 'text') &&
|
|
83
|
+
typeof itemId === 'string' &&
|
|
84
|
+
itemId.length > 0 &&
|
|
85
|
+
typeof outputIndex === 'number' &&
|
|
86
|
+
Number.isSafeInteger(outputIndex) &&
|
|
87
|
+
outputIndex >= 0 &&
|
|
88
|
+
(contentIndex == null ||
|
|
89
|
+
(typeof contentIndex === 'number' &&
|
|
90
|
+
Number.isSafeInteger(contentIndex) &&
|
|
91
|
+
contentIndex >= 0))
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Provider evidence is selected once; a sidecar never replaces message content. */
|
|
96
|
+
export interface ResponsesHistorySource {
|
|
97
|
+
readonly coverage: 'complete-output' | 'tool-sidecar';
|
|
98
|
+
readonly items: unknown[];
|
|
99
|
+
readonly message?: BaseMessage;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface OrderedToolHistoryProjection {
|
|
103
|
+
readonly source: ResponsesHistorySource;
|
|
104
|
+
readonly contributions: readonly ResponsesHistoryContribution[];
|
|
105
|
+
readonly hasToolContent: boolean;
|
|
106
|
+
readonly truncated: boolean;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface ToolHistoryPreparation {
|
|
110
|
+
get(message: BaseMessage): OrderedToolHistoryProjection | undefined;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** A preparation owns this cache; changed messages must be copy-on-write. */
|
|
114
|
+
export function createToolHistoryPreparation(): ToolHistoryPreparation {
|
|
115
|
+
const projections = new WeakMap<BaseMessage, OrderedToolHistoryProjection>();
|
|
116
|
+
let remainingWork = 100_000;
|
|
117
|
+
return {
|
|
118
|
+
get(message): OrderedToolHistoryProjection | undefined {
|
|
119
|
+
const cached = projections.get(message);
|
|
120
|
+
if (cached != null) {
|
|
121
|
+
return cached;
|
|
122
|
+
}
|
|
123
|
+
const source = getResponsesHistorySource(message);
|
|
124
|
+
if (source == null || source.items.length === 0) {
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
const contributions: ResponsesHistoryContribution[] = [];
|
|
128
|
+
let hasToolContent = false;
|
|
129
|
+
let truncated = false;
|
|
130
|
+
for (const contribution of projectResponsesHistory(source, () => {
|
|
131
|
+
if (remainingWork <= 0) {
|
|
132
|
+
truncated = true;
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
remainingWork--;
|
|
136
|
+
return true;
|
|
137
|
+
})) {
|
|
138
|
+
contributions.push(contribution);
|
|
139
|
+
hasToolContent ||=
|
|
140
|
+
contribution.kind !== 'text' &&
|
|
141
|
+
!(
|
|
142
|
+
contribution.kind === 'provider-item' &&
|
|
143
|
+
contribution.providerType === 'reasoning'
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
const projection = {
|
|
147
|
+
source,
|
|
148
|
+
contributions,
|
|
149
|
+
hasToolContent: hasToolContent || truncated,
|
|
150
|
+
truncated,
|
|
151
|
+
};
|
|
152
|
+
projections.set(message, projection);
|
|
153
|
+
return projection;
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export interface ToolHistoryPosition {
|
|
159
|
+
readonly outputIndex: number;
|
|
160
|
+
readonly contentIndex?: number;
|
|
161
|
+
readonly itemId?: string;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export type ResponsesHistoryContribution = ToolHistoryPosition &
|
|
165
|
+
(
|
|
166
|
+
| { readonly kind: 'text'; readonly actor: 'model'; readonly text: string }
|
|
167
|
+
| {
|
|
168
|
+
readonly kind: 'call';
|
|
169
|
+
readonly actor: 'model';
|
|
170
|
+
readonly name: string;
|
|
171
|
+
readonly callId?: string;
|
|
172
|
+
readonly arguments: unknown;
|
|
173
|
+
}
|
|
174
|
+
| {
|
|
175
|
+
readonly kind: 'image';
|
|
176
|
+
readonly actor: 'tool';
|
|
177
|
+
readonly image: ContentBlock.Multimodal.Image;
|
|
178
|
+
}
|
|
179
|
+
| {
|
|
180
|
+
readonly kind: 'provider-item';
|
|
181
|
+
readonly actor: 'model' | 'tool';
|
|
182
|
+
readonly providerType: string;
|
|
183
|
+
readonly value: unknown;
|
|
184
|
+
}
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
function readData(value: unknown, key: string): unknown {
|
|
188
|
+
if (value == null || typeof value !== 'object' || isProxy(value)) {
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
192
|
+
return descriptor != null && 'value' in descriptor
|
|
193
|
+
? descriptor.value
|
|
194
|
+
: undefined;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function readArray(value: unknown): unknown[] | undefined {
|
|
198
|
+
return Array.isArray(value) && !isProxy(value) ? value : undefined;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export function getResponsesHistorySource(
|
|
202
|
+
message: BaseMessage
|
|
203
|
+
): ResponsesHistorySource | undefined {
|
|
204
|
+
const output = readArray(readData(message.response_metadata, 'output'));
|
|
205
|
+
if (output != null && output.length > 0) {
|
|
206
|
+
return { coverage: 'complete-output', items: output, message };
|
|
207
|
+
}
|
|
208
|
+
const sidecar = readArray(
|
|
209
|
+
readData(message.additional_kwargs, 'tool_outputs')
|
|
210
|
+
);
|
|
211
|
+
return sidecar != null
|
|
212
|
+
? { coverage: 'tool-sidecar', items: sidecar, message }
|
|
213
|
+
: undefined;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** Complete generated images retain their actual format across replay and folding. */
|
|
217
|
+
export function getGeneratedImageMimeType(data: string): string {
|
|
218
|
+
const bytes = Buffer.from(data.slice(0, 16), 'base64');
|
|
219
|
+
if (bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) {
|
|
220
|
+
return 'image/jpeg';
|
|
221
|
+
}
|
|
222
|
+
if (
|
|
223
|
+
bytes[0] === 0x52 &&
|
|
224
|
+
bytes[1] === 0x49 &&
|
|
225
|
+
bytes[2] === 0x46 &&
|
|
226
|
+
bytes[3] === 0x46 &&
|
|
227
|
+
bytes[8] === 0x57 &&
|
|
228
|
+
bytes[9] === 0x45 &&
|
|
229
|
+
bytes[10] === 0x42 &&
|
|
230
|
+
bytes[11] === 0x50
|
|
231
|
+
) {
|
|
232
|
+
return 'image/webp';
|
|
233
|
+
}
|
|
234
|
+
return 'image/png';
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Lazy traversal bounds outer items and nested content together. The caller's
|
|
239
|
+
* shared work allowance also spans subsequent messages. False stops before the
|
|
240
|
+
* next provider value is inspected; payload serialization remains consumer policy.
|
|
241
|
+
*/
|
|
242
|
+
function* projectResponsesItems(
|
|
243
|
+
source: ResponsesHistorySource,
|
|
244
|
+
consumeWork: () => boolean
|
|
245
|
+
): Generator<ResponsesHistoryContribution> {
|
|
246
|
+
for (let outputIndex = 0; outputIndex < source.items.length; outputIndex++) {
|
|
247
|
+
if (!consumeWork()) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const item = readData(source.items, String(outputIndex));
|
|
251
|
+
const type = readData(item, 'type');
|
|
252
|
+
if (typeof type !== 'string') {
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
const id = readData(item, 'id');
|
|
256
|
+
const position: ToolHistoryPosition = {
|
|
257
|
+
outputIndex,
|
|
258
|
+
...(typeof id === 'string' && { itemId: id }),
|
|
259
|
+
};
|
|
260
|
+
if (type === 'message') {
|
|
261
|
+
const content = readArray(readData(item, 'content'));
|
|
262
|
+
if (content == null) {
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
for (
|
|
266
|
+
let contentIndex = 0;
|
|
267
|
+
contentIndex < content.length;
|
|
268
|
+
contentIndex++
|
|
269
|
+
) {
|
|
270
|
+
if (!consumeWork()) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const part = readData(content, String(contentIndex));
|
|
274
|
+
const partType = readData(part, 'type');
|
|
275
|
+
const text = readData(
|
|
276
|
+
part,
|
|
277
|
+
partType === 'refusal' ? 'refusal' : 'text'
|
|
278
|
+
);
|
|
279
|
+
if (typeof text === 'string' && text.length > 0) {
|
|
280
|
+
yield {
|
|
281
|
+
...position,
|
|
282
|
+
contentIndex,
|
|
283
|
+
kind: 'text',
|
|
284
|
+
actor: 'model',
|
|
285
|
+
text,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
if (type === 'computer_call') {
|
|
292
|
+
const callId = readData(item, 'call_id');
|
|
293
|
+
yield {
|
|
294
|
+
...position,
|
|
295
|
+
kind: 'call',
|
|
296
|
+
actor: 'model',
|
|
297
|
+
name: 'computer',
|
|
298
|
+
arguments: readData(item, 'action'),
|
|
299
|
+
...(typeof callId === 'string' && { callId }),
|
|
300
|
+
};
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
if (type === 'function_call' || type === 'custom_tool_call') {
|
|
304
|
+
const name = readData(item, 'name');
|
|
305
|
+
const args = readData(
|
|
306
|
+
item,
|
|
307
|
+
type === 'custom_tool_call' ? 'input' : 'arguments'
|
|
308
|
+
);
|
|
309
|
+
const callId = readData(item, 'call_id');
|
|
310
|
+
yield {
|
|
311
|
+
...position,
|
|
312
|
+
kind: 'call',
|
|
313
|
+
actor: 'model',
|
|
314
|
+
name: typeof name === 'string' ? name : '',
|
|
315
|
+
arguments: typeof args === 'string' ? args : '',
|
|
316
|
+
...(typeof callId === 'string' && { callId }),
|
|
317
|
+
};
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
if (type === 'image_generation_call') {
|
|
321
|
+
const data = readData(item, 'result');
|
|
322
|
+
if (
|
|
323
|
+
readData(item, 'status') === 'completed' &&
|
|
324
|
+
typeof data === 'string' &&
|
|
325
|
+
data
|
|
326
|
+
) {
|
|
327
|
+
yield {
|
|
328
|
+
...position,
|
|
329
|
+
kind: 'image',
|
|
330
|
+
actor: 'tool',
|
|
331
|
+
image: {
|
|
332
|
+
type: 'image',
|
|
333
|
+
mimeType: getGeneratedImageMimeType(data),
|
|
334
|
+
data,
|
|
335
|
+
...(typeof id === 'string' && { id }),
|
|
336
|
+
metadata: { status: 'completed' },
|
|
337
|
+
},
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
if (
|
|
341
|
+
readData(item, 'status') !== 'completed' ||
|
|
342
|
+
typeof data !== 'string' ||
|
|
343
|
+
!data
|
|
344
|
+
) {
|
|
345
|
+
yield {
|
|
346
|
+
...position,
|
|
347
|
+
kind: 'provider-item',
|
|
348
|
+
actor: 'tool',
|
|
349
|
+
providerType: type,
|
|
350
|
+
value: {
|
|
351
|
+
type,
|
|
352
|
+
status: readData(item, 'status'),
|
|
353
|
+
result: '[image unavailable]',
|
|
354
|
+
},
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
yield {
|
|
360
|
+
...position,
|
|
361
|
+
kind: 'provider-item',
|
|
362
|
+
actor:
|
|
363
|
+
type === 'reasoning' || type === 'mcp_approval_request'
|
|
364
|
+
? 'model'
|
|
365
|
+
: 'tool',
|
|
366
|
+
providerType: type,
|
|
367
|
+
value: item,
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/** Streaming positions order sidecar evidence only when text positions map exactly. */
|
|
373
|
+
export function* projectResponsesHistory(
|
|
374
|
+
source: ResponsesHistorySource,
|
|
375
|
+
consumeWork: () => boolean
|
|
376
|
+
): Generator<ResponsesHistoryContribution> {
|
|
377
|
+
if (source.coverage === 'complete-output' || source.message == null) {
|
|
378
|
+
yield* projectResponsesItems(source, consumeWork);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
const positions = readArray(
|
|
382
|
+
readData(
|
|
383
|
+
source.message.additional_kwargs,
|
|
384
|
+
OPENAI_RESPONSES_REPLAY_POSITIONS_KEY
|
|
385
|
+
)
|
|
386
|
+
);
|
|
387
|
+
const outputPositions = new Map<string, number>();
|
|
388
|
+
const textPositions: ResponsesReplayPosition[] = [];
|
|
389
|
+
const seenPositions = new Set<string>();
|
|
390
|
+
for (let index = 0; positions != null && index < positions.length; index++) {
|
|
391
|
+
if (!consumeWork()) {
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
const position = readData(positions, String(index));
|
|
395
|
+
if (!isResponsesReplayPosition(position)) {
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
if (position.kind === 'output') {
|
|
399
|
+
outputPositions.set(position.itemId, position.outputIndex);
|
|
400
|
+
} else if (position.kind === 'text') {
|
|
401
|
+
const key = `${position.itemId}:${position.outputIndex}:${position.contentIndex ?? 0}`;
|
|
402
|
+
if (!seenPositions.has(key)) {
|
|
403
|
+
seenPositions.add(key);
|
|
404
|
+
textPositions.push(position);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
textPositions.sort(
|
|
409
|
+
(left, right) =>
|
|
410
|
+
left.outputIndex - right.outputIndex ||
|
|
411
|
+
(left.contentIndex ?? 0) - (right.contentIndex ?? 0)
|
|
412
|
+
);
|
|
413
|
+
const text: string[] = [];
|
|
414
|
+
const content = source.message.content;
|
|
415
|
+
if (typeof content === 'string' && content) {
|
|
416
|
+
text.push(content);
|
|
417
|
+
} else if (Array.isArray(content)) {
|
|
418
|
+
for (let index = 0; index < content.length; index++) {
|
|
419
|
+
if (!consumeWork()) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
const block = readData(content, String(index));
|
|
423
|
+
const value = readData(block, 'text');
|
|
424
|
+
if (typeof value === 'string' && value) {
|
|
425
|
+
text.push(value);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
const contributions: ResponsesHistoryContribution[] = [];
|
|
430
|
+
for (let index = 0; index < text.length; index++) {
|
|
431
|
+
const position =
|
|
432
|
+
text.length === textPositions.length ? textPositions[index] : undefined;
|
|
433
|
+
contributions.push({
|
|
434
|
+
kind: 'text',
|
|
435
|
+
actor: 'model',
|
|
436
|
+
text: text[index],
|
|
437
|
+
outputIndex: position?.outputIndex ?? -1,
|
|
438
|
+
contentIndex: position?.contentIndex ?? index,
|
|
439
|
+
...(position != null && { itemId: position.itemId }),
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
for (const contribution of projectResponsesItems(source, consumeWork)) {
|
|
443
|
+
contributions.push({
|
|
444
|
+
...contribution,
|
|
445
|
+
outputIndex:
|
|
446
|
+
contribution.itemId != null
|
|
447
|
+
? (outputPositions.get(contribution.itemId) ??
|
|
448
|
+
Number.MAX_SAFE_INTEGER)
|
|
449
|
+
: Number.MAX_SAFE_INTEGER,
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
contributions.sort(
|
|
453
|
+
(left, right) =>
|
|
454
|
+
left.outputIndex - right.outputIndex ||
|
|
455
|
+
(left.contentIndex ?? 0) - (right.contentIndex ?? 0)
|
|
456
|
+
);
|
|
457
|
+
for (const contribution of contributions) {
|
|
458
|
+
yield contribution;
|
|
459
|
+
}
|
|
460
|
+
}
|