@lota-sdk/core 0.1.17 → 0.1.19
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/package.json +2 -2
- package/src/ai-gateway/ai-gateway.ts +431 -0
- package/src/ai-gateway/cache-headers.ts +33 -0
- package/src/{bifrost → ai-gateway}/index.ts +1 -1
- package/src/config/model-constants.ts +1 -1
- package/src/embeddings/provider.ts +2 -2
- package/src/index.ts +1 -1
- package/src/runtime/chat-run-registry.ts +4 -0
- package/src/runtime/context-compaction.ts +100 -12
- package/src/runtime/memory-prompts-fact.ts +3 -1
- package/src/runtime/runtime-config.ts +0 -4
- package/src/services/workstream-title.service.ts +1 -1
- package/src/services/workstream-turn-preparation.service.ts +4 -1
- package/src/services/workstream.service.ts +19 -2
- package/src/system-agents/context-compaction.agent.ts +4 -4
- package/src/system-agents/delegated-agent-factory.ts +2 -9
- package/src/system-agents/memory-reranker.agent.ts +4 -4
- package/src/system-agents/memory.agent.ts +4 -4
- package/src/system-agents/recent-activity-title-refiner.agent.ts +4 -4
- package/src/system-agents/regular-chat-memory-digest.agent.ts +4 -4
- package/src/system-agents/skill-extractor.agent.ts +4 -4
- package/src/system-agents/skill-manager.agent.ts +4 -4
- package/src/system-agents/title-generator.agent.ts +4 -4
- package/src/tools/research-topic.tool.ts +4 -4
- package/src/utils/date-time.ts +11 -0
- package/src/workers/utils/file-section-chunker.ts +1 -1
- package/src/bifrost/bifrost.ts +0 -325
- package/src/bifrost/cache-headers.ts +0 -8
package/src/bifrost/bifrost.ts
DELETED
|
@@ -1,325 +0,0 @@
|
|
|
1
|
-
import { devToolsMiddleware } from '@ai-sdk/devtools'
|
|
2
|
-
import { createOpenAI } from '@ai-sdk/openai'
|
|
3
|
-
import { wrapLanguageModel } from 'ai'
|
|
4
|
-
import type { LanguageModelMiddleware } from 'ai'
|
|
5
|
-
|
|
6
|
-
import { getRequiredEnv } from '../utils/env'
|
|
7
|
-
import { isRecord, readString } from '../utils/string'
|
|
8
|
-
|
|
9
|
-
type BifrostLanguageModel = Parameters<typeof wrapLanguageModel>[0]['model']
|
|
10
|
-
type BifrostExtraParams = Record<string, unknown>
|
|
11
|
-
type BifrostChatResponse = { body?: unknown }
|
|
12
|
-
type BifrostTransformParamsOptions = Parameters<NonNullable<LanguageModelMiddleware['transformParams']>>[0]
|
|
13
|
-
type WrapStreamOptions = Parameters<NonNullable<LanguageModelMiddleware['wrapStream']>>[0]
|
|
14
|
-
type BifrostCallOptions = WrapStreamOptions['params']
|
|
15
|
-
type BifrostGenerateResult = Awaited<ReturnType<WrapStreamOptions['doGenerate']>>
|
|
16
|
-
type BifrostStreamResult = Awaited<ReturnType<WrapStreamOptions['doStream']>>
|
|
17
|
-
type BifrostGeneratedContent = BifrostGenerateResult['content'][number]
|
|
18
|
-
type BifrostStreamPart = BifrostStreamResult['stream'] extends ReadableStream<infer T> ? T : never
|
|
19
|
-
|
|
20
|
-
const OPENROUTER_RESPONSE_HEALING_EXTRA_PARAMS = {
|
|
21
|
-
plugins: [{ id: 'response-healing' }],
|
|
22
|
-
} as const satisfies BifrostExtraParams
|
|
23
|
-
|
|
24
|
-
function readRequiredGatewayEnv(name: 'AI_GATEWAY_KEY' | 'AI_GATEWAY_URL'): string {
|
|
25
|
-
return getRequiredEnv(name).trim()
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function readReasoningDetailsText(value: unknown): string | null {
|
|
29
|
-
if (!Array.isArray(value)) return null
|
|
30
|
-
|
|
31
|
-
const textParts = value
|
|
32
|
-
.map((item) => (isRecord(item) ? readString(item.text) : null))
|
|
33
|
-
.filter((item): item is string => item !== null)
|
|
34
|
-
|
|
35
|
-
if (textParts.length === 0) return null
|
|
36
|
-
|
|
37
|
-
return textParts.join('\n\n')
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function readReasoningDeltaText(value: unknown): string | null {
|
|
41
|
-
return typeof value === 'string' && value.length > 0 ? value : null
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function readBifrostChatReasoningText(message: Record<string, unknown>): string | null {
|
|
45
|
-
return (
|
|
46
|
-
readString(message.reasoning) ??
|
|
47
|
-
readString(message.reasoning_content) ??
|
|
48
|
-
readReasoningDetailsText(message.reasoning_details)
|
|
49
|
-
)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function extractBifrostChatReasoningText(responseBody: unknown): string | null {
|
|
53
|
-
if (!isRecord(responseBody) || !Array.isArray(responseBody.choices)) return null
|
|
54
|
-
|
|
55
|
-
for (const choice of responseBody.choices) {
|
|
56
|
-
if (!isRecord(choice) || !isRecord(choice.message)) continue
|
|
57
|
-
|
|
58
|
-
const reasoningText = readBifrostChatReasoningText(choice.message)
|
|
59
|
-
if (reasoningText) return reasoningText
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return null
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function extractBifrostChatReasoningDeltaText(rawChunk: unknown): string | null {
|
|
66
|
-
if (!isRecord(rawChunk) || !Array.isArray(rawChunk.choices)) return null
|
|
67
|
-
|
|
68
|
-
for (const choice of rawChunk.choices) {
|
|
69
|
-
if (!isRecord(choice) || !isRecord(choice.delta)) continue
|
|
70
|
-
|
|
71
|
-
const reasoningText =
|
|
72
|
-
readReasoningDeltaText(choice.delta.reasoning) ??
|
|
73
|
-
readReasoningDeltaText(choice.delta.reasoning_content) ??
|
|
74
|
-
readReasoningDetailsText(choice.delta.reasoning_details)
|
|
75
|
-
if (reasoningText) return reasoningText
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return null
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
type BifrostResponsesReasoningDelta = { id: string; delta: string; itemId: string }
|
|
82
|
-
|
|
83
|
-
export function extractBifrostResponsesReasoningDelta(rawChunk: unknown): BifrostResponsesReasoningDelta | null {
|
|
84
|
-
if (!isRecord(rawChunk) || rawChunk.type !== 'response.reasoning_summary_text.delta') return null
|
|
85
|
-
if ('summary_index' in rawChunk) return null
|
|
86
|
-
|
|
87
|
-
const itemId = readString(rawChunk.item_id)
|
|
88
|
-
const delta = readReasoningDeltaText(rawChunk.delta)
|
|
89
|
-
if (!itemId || !delta) return null
|
|
90
|
-
|
|
91
|
-
return { id: `${itemId}:0`, delta, itemId }
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function injectBifrostChatReasoningContent(
|
|
95
|
-
content: readonly BifrostGeneratedContent[],
|
|
96
|
-
response?: BifrostChatResponse,
|
|
97
|
-
): BifrostGeneratedContent[] {
|
|
98
|
-
if (content.some((part) => part.type === 'reasoning')) {
|
|
99
|
-
return [...content]
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const reasoningText = extractBifrostChatReasoningText(response?.body)
|
|
103
|
-
if (!reasoningText) return [...content]
|
|
104
|
-
|
|
105
|
-
return [{ type: 'reasoning', text: reasoningText }, ...content]
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function isReasoningEnabled(params: BifrostCallOptions): boolean {
|
|
109
|
-
if (!isRecord(params.providerOptions) || !isRecord(params.providerOptions.openai)) return false
|
|
110
|
-
|
|
111
|
-
const openaiOptions = params.providerOptions.openai
|
|
112
|
-
if (openaiOptions.forceReasoning === true) return true
|
|
113
|
-
if (typeof openaiOptions.reasoningSummary === 'string' && openaiOptions.reasoningSummary.length > 0) return true
|
|
114
|
-
return typeof openaiOptions.reasoningEffort === 'string' && openaiOptions.reasoningEffort !== 'none'
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function shouldCloseInjectedReasoning(chunk: BifrostStreamPart): boolean {
|
|
118
|
-
return chunk.type !== 'stream-start' && chunk.type !== 'response-metadata' && chunk.type !== 'raw'
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export function injectBifrostChatReasoningStream(
|
|
122
|
-
stream: ReadableStream<BifrostStreamPart>,
|
|
123
|
-
): ReadableStream<BifrostStreamPart> {
|
|
124
|
-
const reasoningId = 'bifrost-reasoning-0'
|
|
125
|
-
let reasoningOpen = false
|
|
126
|
-
let reasoningClosed = false
|
|
127
|
-
|
|
128
|
-
return stream.pipeThrough(
|
|
129
|
-
new TransformStream<BifrostStreamPart, BifrostStreamPart>({
|
|
130
|
-
transform(chunk, controller) {
|
|
131
|
-
const closeReasoning = () => {
|
|
132
|
-
if (!reasoningOpen || reasoningClosed) return
|
|
133
|
-
|
|
134
|
-
controller.enqueue({ type: 'reasoning-end', id: reasoningId } satisfies BifrostStreamPart)
|
|
135
|
-
reasoningClosed = true
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (chunk.type === 'raw') {
|
|
139
|
-
const reasoningDelta = reasoningClosed ? null : extractBifrostChatReasoningDeltaText(chunk.rawValue)
|
|
140
|
-
controller.enqueue(chunk)
|
|
141
|
-
|
|
142
|
-
if (reasoningDelta) {
|
|
143
|
-
if (!reasoningOpen) {
|
|
144
|
-
controller.enqueue({ type: 'reasoning-start', id: reasoningId } satisfies BifrostStreamPart)
|
|
145
|
-
reasoningOpen = true
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
controller.enqueue({
|
|
149
|
-
type: 'reasoning-delta',
|
|
150
|
-
id: reasoningId,
|
|
151
|
-
delta: reasoningDelta,
|
|
152
|
-
} satisfies BifrostStreamPart)
|
|
153
|
-
}
|
|
154
|
-
return
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (shouldCloseInjectedReasoning(chunk)) {
|
|
158
|
-
closeReasoning()
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
controller.enqueue(chunk)
|
|
162
|
-
},
|
|
163
|
-
flush(controller) {
|
|
164
|
-
if (!reasoningOpen || reasoningClosed) return
|
|
165
|
-
controller.enqueue({ type: 'reasoning-end', id: reasoningId } satisfies BifrostStreamPart)
|
|
166
|
-
},
|
|
167
|
-
}),
|
|
168
|
-
)
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
export function injectBifrostResponsesReasoningStream(
|
|
172
|
-
stream: ReadableStream<BifrostStreamPart>,
|
|
173
|
-
): ReadableStream<BifrostStreamPart> {
|
|
174
|
-
return stream.pipeThrough(
|
|
175
|
-
new TransformStream<BifrostStreamPart, BifrostStreamPart>({
|
|
176
|
-
transform(chunk, controller) {
|
|
177
|
-
controller.enqueue(chunk)
|
|
178
|
-
|
|
179
|
-
if (chunk.type !== 'raw') return
|
|
180
|
-
|
|
181
|
-
const reasoningDelta = extractBifrostResponsesReasoningDelta(chunk.rawValue)
|
|
182
|
-
if (!reasoningDelta) return
|
|
183
|
-
|
|
184
|
-
controller.enqueue({
|
|
185
|
-
type: 'reasoning-delta',
|
|
186
|
-
id: reasoningDelta.id,
|
|
187
|
-
delta: reasoningDelta.delta,
|
|
188
|
-
providerMetadata: { openai: { itemId: reasoningDelta.itemId } },
|
|
189
|
-
} satisfies BifrostStreamPart)
|
|
190
|
-
},
|
|
191
|
-
}),
|
|
192
|
-
)
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function addBifrostReasoningRawChunks(
|
|
196
|
-
params: BifrostCallOptions,
|
|
197
|
-
type: BifrostTransformParamsOptions['type'],
|
|
198
|
-
): BifrostCallOptions {
|
|
199
|
-
if (type !== 'stream' || !isReasoningEnabled(params) || params.includeRawChunks === true) {
|
|
200
|
-
return params
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return { ...params, includeRawChunks: true }
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
export function injectBifrostExtraParamsRequestBody(
|
|
207
|
-
body: BodyInit | null | undefined,
|
|
208
|
-
extraParams: BifrostExtraParams,
|
|
209
|
-
): BodyInit | null | undefined {
|
|
210
|
-
if (typeof body !== 'string') return body
|
|
211
|
-
|
|
212
|
-
let parsed: unknown
|
|
213
|
-
try {
|
|
214
|
-
parsed = JSON.parse(body)
|
|
215
|
-
} catch {
|
|
216
|
-
return body
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (!isRecord(parsed)) return body
|
|
220
|
-
|
|
221
|
-
const mergedExtraParams = isRecord(parsed.extra_params)
|
|
222
|
-
? { ...parsed.extra_params, ...extraParams }
|
|
223
|
-
: { ...extraParams }
|
|
224
|
-
|
|
225
|
-
return JSON.stringify({ ...parsed, extra_params: mergedExtraParams })
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function createBifrostFetchWithExtraParams(extraParams: BifrostExtraParams): typeof fetch {
|
|
229
|
-
const fetchWithExtraParams = (input: RequestInfo | URL, init?: RequestInit | BunFetchRequestInit) =>
|
|
230
|
-
globalThis.fetch(input, { ...init, body: injectBifrostExtraParamsRequestBody(init?.body, extraParams) })
|
|
231
|
-
|
|
232
|
-
return Object.assign(fetchWithExtraParams, { preconnect: globalThis.fetch.preconnect.bind(globalThis.fetch) })
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
function createBifrostProvider(extraParams?: BifrostExtraParams) {
|
|
236
|
-
const apiKey = readRequiredGatewayEnv('AI_GATEWAY_KEY')
|
|
237
|
-
if (!apiKey.startsWith('sk-bf-')) {
|
|
238
|
-
throw new Error('[bifrost] AI_GATEWAY_KEY must use the Bifrost virtual-key format (sk-bf-*).')
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
return createOpenAI({
|
|
242
|
-
baseURL: readRequiredGatewayEnv('AI_GATEWAY_URL'),
|
|
243
|
-
apiKey,
|
|
244
|
-
headers: { 'x-bf-vk': apiKey, ...(extraParams ? { 'x-bf-passthrough-extra-params': 'true' } : {}) },
|
|
245
|
-
...(extraParams ? { fetch: createBifrostFetchWithExtraParams(extraParams) } : {}),
|
|
246
|
-
})
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
function withBifrostDevTools<TModel extends BifrostLanguageModel>(model: TModel): TModel {
|
|
250
|
-
return wrapLanguageModel({ model, middleware: devToolsMiddleware() }) as TModel
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
let provider: ReturnType<typeof createOpenAI> | null = null
|
|
254
|
-
let openRouterResponseHealingProvider: ReturnType<typeof createOpenAI> | null = null
|
|
255
|
-
|
|
256
|
-
export function getBifrostProvider() {
|
|
257
|
-
if (provider) return provider
|
|
258
|
-
|
|
259
|
-
provider = createBifrostProvider()
|
|
260
|
-
|
|
261
|
-
return provider
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
export function getBifrostOpenRouterResponseHealingProvider() {
|
|
265
|
-
if (openRouterResponseHealingProvider) return openRouterResponseHealingProvider
|
|
266
|
-
|
|
267
|
-
openRouterResponseHealingProvider = createBifrostProvider(OPENROUTER_RESPONSE_HEALING_EXTRA_PARAMS)
|
|
268
|
-
|
|
269
|
-
return openRouterResponseHealingProvider
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
export function bifrostModel(modelId: string) {
|
|
273
|
-
return withBifrostDevTools(
|
|
274
|
-
wrapLanguageModel({
|
|
275
|
-
model: getBifrostProvider()(modelId),
|
|
276
|
-
middleware: {
|
|
277
|
-
specificationVersion: 'v3',
|
|
278
|
-
transformParams: async ({ params, type }) => addBifrostReasoningRawChunks(params, type),
|
|
279
|
-
wrapStream: async ({ doStream, params }) => {
|
|
280
|
-
const result = await doStream()
|
|
281
|
-
if (!isReasoningEnabled(params)) return result
|
|
282
|
-
|
|
283
|
-
return { ...result, stream: injectBifrostResponsesReasoningStream(result.stream) }
|
|
284
|
-
},
|
|
285
|
-
},
|
|
286
|
-
}),
|
|
287
|
-
)
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
export function bifrostOpenRouterResponseHealingModel(modelId: string) {
|
|
291
|
-
return withBifrostDevTools(getBifrostOpenRouterResponseHealingProvider()(modelId))
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
export function bifrostChatModel(modelId: string) {
|
|
295
|
-
return withBifrostDevTools(
|
|
296
|
-
wrapLanguageModel({
|
|
297
|
-
model: getBifrostProvider().chat(modelId),
|
|
298
|
-
middleware: {
|
|
299
|
-
specificationVersion: 'v3',
|
|
300
|
-
transformParams: async ({ params, type }) => addBifrostReasoningRawChunks(params, type),
|
|
301
|
-
wrapGenerate: async ({ doGenerate }) => {
|
|
302
|
-
const result = await doGenerate()
|
|
303
|
-
|
|
304
|
-
return {
|
|
305
|
-
...result,
|
|
306
|
-
content: injectBifrostChatReasoningContent(
|
|
307
|
-
result.content,
|
|
308
|
-
result.response as BifrostChatResponse | undefined,
|
|
309
|
-
),
|
|
310
|
-
}
|
|
311
|
-
},
|
|
312
|
-
wrapStream: async ({ doStream, params }) => {
|
|
313
|
-
const result = await doStream()
|
|
314
|
-
if (!isReasoningEnabled(params)) return result
|
|
315
|
-
|
|
316
|
-
return { ...result, stream: injectBifrostChatReasoningStream(result.stream) }
|
|
317
|
-
},
|
|
318
|
-
},
|
|
319
|
-
}),
|
|
320
|
-
)
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
export function bifrostEmbeddingModel(modelId: string) {
|
|
324
|
-
return getBifrostProvider().embeddingModel(modelId)
|
|
325
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
const BIFROST_CACHE_KEY_HEADER = 'x-bf-cache-key'
|
|
2
|
-
const BIFROST_CACHE_TTL_HEADER = 'x-bf-cache-ttl'
|
|
3
|
-
|
|
4
|
-
export function buildBifrostCacheHeaders(cacheKey: string, ttl?: string): Record<string, string> {
|
|
5
|
-
const headers: Record<string, string> = { [BIFROST_CACHE_KEY_HEADER]: cacheKey }
|
|
6
|
-
if (ttl) headers[BIFROST_CACHE_TTL_HEADER] = ttl
|
|
7
|
-
return headers
|
|
8
|
-
}
|