@h-ai/ai 0.1.0-alpha.49 → 0.1.0-alpha.51

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.js CHANGED
@@ -1,5 +1,5 @@
1
- import { aiM, AIConfigSchema, MemoryConfigSchema, RetrievalConfigSchema, KnowledgeConfigSchema, TokenConfigSchema, SummaryConfigSchema, CompressConfigSchema, AudioConfigSchema, ImageConfigSchema, resolveImageModel, resolveModelEntry, resolveAudioModel, resolveModelApi } from './chunk-4FDOGXIS.js';
2
- export { A2AConfigSchema, A2ASkillConfigSchema, AIConfigSchema, AUDIO_WS_PATH, ApiTypeSchema, AudioConfigSchema, AudioFormatSchema, AudioModelEntrySchema, AudioProviderSchema, AudioWsClientMessageSchema, AudioWsDoneMessageSchema, AudioWsStartMessageSchema, AudioWsTextMessageSchema, CompressConfigSchema, CompressionStrategySchema, EmbeddingConfigSchema, EntityTypeSchema, FileConfigSchema, ImageConfigSchema, ImageModelEntrySchema, ImageProviderSchema, KnowledgeConfigSchema, LLMConfigSchema, MCPConfigSchema, MCPServerCapabilitiesSchema, MCPServerConfigSchema, MemoryConfigSchema, MemoryTypeSchema, ModelEntrySchema, ModelScenarioSchema, OptionalSecretSchema, RetrievalConfigSchema, RetrievalSourceSchema, SummaryConfigSchema, TokenConfigSchema, resolveAudioModel, resolveImageModel, resolveModelApi, resolveModelEntry, serializePlayableAudio } from './chunk-4FDOGXIS.js';
1
+ import { aiM, AIConfigSchema, MemoryConfigSchema, RetrievalConfigSchema, KnowledgeConfigSchema, TokenConfigSchema, SummaryConfigSchema, CompressConfigSchema, AudioConfigSchema, ImageConfigSchema, resolveImageModel, resolveModelEntry, resolveAudioModel, ensureAudioCredential, resolveModelApi } from './chunk-PLNY4UUT.js';
2
+ export { A2AConfigSchema, A2ASkillConfigSchema, AIConfigSchema, AUDIO_WS_PATH, ApiTypeSchema, AudioConfigSchema, AudioFormatSchema, AudioModelEntrySchema, AudioOperationSchema, AudioOperationsSchema, AudioProviderSchema, AudioWsClientMessageSchema, AudioWsDoneMessageSchema, AudioWsStartMessageSchema, AudioWsTextMessageSchema, CompressConfigSchema, CompressionStrategySchema, EmbeddingConfigSchema, EntityTypeSchema, FileConfigSchema, ImageConfigSchema, ImageModelEntrySchema, ImageProviderSchema, KnowledgeConfigSchema, LLMConfigSchema, MCPConfigSchema, MCPServerCapabilitiesSchema, MCPServerConfigSchema, MemoryConfigSchema, MemoryTypeSchema, ModelEntrySchema, ModelScenarioSchema, OptionalSecretSchema, RetrievalConfigSchema, RetrievalSourceSchema, SummaryConfigSchema, TokenConfigSchema, ensureAudioCredential, resolveAudioModel, resolveImageModel, resolveModelApi, resolveModelEntry, serializePlayableAudio } from './chunk-PLNY4UUT.js';
3
3
  import { HaiAIError } from './chunk-JC7QBT3C.js';
4
4
  export { HaiAIError } from './chunk-JC7QBT3C.js';
5
5
  import { core, err, ok } from '@h-ai/core';
@@ -339,6 +339,40 @@ function fromBase64(base64) {
339
339
  function concatChunks(chunks) {
340
340
  return new Uint8Array(Buffer.concat(chunks.map((c) => Buffer.from(c))));
341
341
  }
342
+ var AUDIO_UPLOAD_EXT = { pcm16: "wav", wav: "wav", mp3: "mp3", opus: "ogg" };
343
+ var AUDIO_UPLOAD_MIME = { pcm16: "audio/wav", wav: "audio/wav", mp3: "audio/mpeg", opus: "audio/opus" };
344
+ function toAudioUploadPart(audio, baseName = "audio") {
345
+ if (audio.format === "pcm16") {
346
+ const wav = wrapPcm16ToWav(audio.data, audio.sampleRate ?? 16e3, audio.channels ?? 1);
347
+ return { data: wav, filename: `${baseName}.wav`, mimeType: "audio/wav" };
348
+ }
349
+ return { data: audio.data, filename: `${baseName}.${AUDIO_UPLOAD_EXT[audio.format]}`, mimeType: AUDIO_UPLOAD_MIME[audio.format] };
350
+ }
351
+ function toAudioBlob(part) {
352
+ return new Blob([new Uint8Array(part.data)], { type: part.mimeType });
353
+ }
354
+ function wrapPcm16ToWav(pcm, sampleRate, channels = 1) {
355
+ const bitsPerSample = 16;
356
+ const byteRate = sampleRate * channels * bitsPerSample / 8;
357
+ const blockAlign = channels * bitsPerSample / 8;
358
+ const dataSize = pcm.length;
359
+ const buffer = Buffer.alloc(44 + dataSize);
360
+ buffer.write("RIFF", 0);
361
+ buffer.writeUInt32LE(36 + dataSize, 4);
362
+ buffer.write("WAVE", 8);
363
+ buffer.write("fmt ", 12);
364
+ buffer.writeUInt32LE(16, 16);
365
+ buffer.writeUInt16LE(1, 20);
366
+ buffer.writeUInt16LE(channels, 22);
367
+ buffer.writeUInt32LE(sampleRate, 24);
368
+ buffer.writeUInt32LE(byteRate, 28);
369
+ buffer.writeUInt16LE(blockAlign, 32);
370
+ buffer.writeUInt16LE(bitsPerSample, 34);
371
+ buffer.write("data", 36);
372
+ buffer.writeUInt32LE(dataSize, 40);
373
+ Buffer.from(pcm).copy(buffer, 44);
374
+ return new Uint8Array(buffer);
375
+ }
342
376
  function errorMessage(error) {
343
377
  return error instanceof Error ? error.message : String(error);
344
378
  }
@@ -362,6 +396,14 @@ function mapStreamError(error, signal) {
362
396
  function toAudioErrorResult(error, signal) {
363
397
  return { success: false, error: mapStreamError(error, signal) };
364
398
  }
399
+ function combineSignal(signal, timeout) {
400
+ const timeoutSignal = AbortSignal.timeout(timeout);
401
+ return signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
402
+ }
403
+ async function describeHttpError(response) {
404
+ const text = await response.text().catch(() => "");
405
+ return `HTTP ${response.status} ${text.slice(0, 200)}`.trim();
406
+ }
365
407
  var logger2 = core.logger.child({ module: "ai", scope: "audio-ws" });
366
408
  function openAudioWebSocket(url, headers, options) {
367
409
  return new Promise((resolve, reject) => {
@@ -759,7 +801,11 @@ function createDoubaoAudioProvider() {
759
801
  conn.close();
760
802
  }
761
803
  }
762
- return { transcribe, transcribeStream, synthesize, synthesizeStream, resolveSynthesisOutput, capabilities: DOUBAO_CAPABILITIES };
804
+ return {
805
+ transcription: { transcribe, transcribeStream },
806
+ synthesis: { synthesize, synthesizeStream, resolveSynthesisOutput },
807
+ getCapabilities: () => DOUBAO_CAPABILITIES
808
+ };
763
809
  }
764
810
  function resolveSynthesisOutput(request) {
765
811
  const format = request.format ?? "pcm16";
@@ -776,6 +822,120 @@ function decodeBinaryMessage(message) {
776
822
  return void 0;
777
823
  return decodeFrame(message.binary);
778
824
  }
825
+ var logger4 = core.logger.child({ module: "ai", scope: "audio-indextts" });
826
+ var INDEX_TTS_CAPABILITIES = {
827
+ synthesize: {
828
+ supported: true,
829
+ incrementalTextInput: false,
830
+ streamingAudioOutput: false,
831
+ languageSelection: true,
832
+ presetVoice: false,
833
+ speakerReference: true,
834
+ speakerReferenceRequired: true,
835
+ styleReference: true,
836
+ instruction: false,
837
+ speedControl: true,
838
+ targetDuration: true,
839
+ supportedLanguages: ["zh", "en", "ja"]
840
+ }
841
+ };
842
+ var HEADER_DURATION_MS = "x-hai-audio-duration-ms";
843
+ var HEADER_DURATION_MATCHED = "x-hai-duration-matched";
844
+ var HEADER_APPLIED_SPEED = "x-hai-applied-speed";
845
+ var HEADER_SAMPLE_RATE = "x-hai-audio-sample-rate";
846
+ var HEADER_CHANNELS = "x-hai-audio-channels";
847
+ function createIndexTtsAudioProvider() {
848
+ async function synthesize(request) {
849
+ const { model, text, language, speakerReference, styleReference, styleStrength, speed, targetDurationMs, durationToleranceMs, format, sampleRate, signal } = request;
850
+ if (!speakerReference)
851
+ return err(HaiAIError.AUDIO_INVALID_REQUEST, aiM("ai_audioInvalidRequest", { params: { reason: "speaker_reference is required" } }));
852
+ const out = resolveSynthesisOutput2({ format, sampleRate });
853
+ try {
854
+ const form = new FormData();
855
+ form.append("text", text);
856
+ form.append("model", model.model);
857
+ if (language)
858
+ form.append("language", language);
859
+ appendReference(form, "speaker_reference", speakerReference);
860
+ if (styleReference)
861
+ appendReference(form, "style_reference", styleReference);
862
+ if (styleStrength !== void 0)
863
+ form.append("style_strength", String(styleStrength));
864
+ if (speed !== void 0)
865
+ form.append("speed", String(speed));
866
+ if (targetDurationMs !== void 0)
867
+ form.append("target_duration_ms", String(targetDurationMs));
868
+ if (durationToleranceMs !== void 0)
869
+ form.append("duration_tolerance_ms", String(durationToleranceMs));
870
+ form.append("response_format", out.format);
871
+ if (out.sampleRate !== void 0)
872
+ form.append("sample_rate", String(out.sampleRate));
873
+ const headers = {};
874
+ if (model.apiKey)
875
+ headers.Authorization = `Bearer ${model.apiKey}`;
876
+ const response = await fetch(`${model.baseUrl.replace(/\/$/, "")}/audio/speech`, {
877
+ method: "POST",
878
+ headers,
879
+ body: form,
880
+ signal: combineSignal(signal, model.timeout)
881
+ });
882
+ if (!response.ok)
883
+ return err(HaiAIError.AUDIO_UPSTREAM_ERROR, aiM("ai_audioUpstreamError", { params: { error: await describeHttpError(response) } }));
884
+ const data = new Uint8Array(await response.arrayBuffer());
885
+ return ok(buildSynthesisResult(data, out, response.headers));
886
+ } catch (error) {
887
+ logger4.debug("IndexTTS synthesize failed", { error: errorMessage(error) });
888
+ return toAudioErrorResult(error, signal);
889
+ }
890
+ }
891
+ return {
892
+ synthesis: { synthesize, resolveSynthesisOutput: resolveSynthesisOutput2 },
893
+ getCapabilities: () => INDEX_TTS_CAPABILITIES
894
+ };
895
+ }
896
+ function resolveSynthesisOutput2(request) {
897
+ const format = request.format ?? "wav";
898
+ return { format, sampleRate: format === "pcm16" ? request.sampleRate ?? 24e3 : void 0, channels: 1 };
899
+ }
900
+ function appendReference(form, field, reference) {
901
+ const part = toAudioUploadPart(reference.audio, field);
902
+ form.append(field, toAudioBlob(part), part.filename);
903
+ if (reference.transcript)
904
+ form.append(`${field}_text`, reference.transcript);
905
+ if (reference.language)
906
+ form.append(`${field}_language`, reference.language);
907
+ }
908
+ function buildSynthesisResult(data, out, headers) {
909
+ const durationMs = parseNumberHeader(headers.get(HEADER_DURATION_MS));
910
+ const sampleRate = parseNumberHeader(headers.get(HEADER_SAMPLE_RATE)) ?? out.sampleRate;
911
+ const channels = parseNumberHeader(headers.get(HEADER_CHANNELS)) === 2 ? 2 : out.channels;
912
+ const durationMatched = parseBooleanHeader(headers.get(HEADER_DURATION_MATCHED));
913
+ const appliedSpeed = parseNumberHeader(headers.get(HEADER_APPLIED_SPEED));
914
+ const metadata = {};
915
+ if (durationMatched !== void 0)
916
+ metadata.durationMatched = durationMatched;
917
+ if (appliedSpeed !== void 0)
918
+ metadata.speed = appliedSpeed;
919
+ return {
920
+ data,
921
+ format: out.format,
922
+ sampleRate,
923
+ channels,
924
+ ...durationMs !== void 0 ? { durationMs } : {},
925
+ ...Object.keys(metadata).length ? { metadata } : {}
926
+ };
927
+ }
928
+ function parseNumberHeader(value) {
929
+ if (value === null)
930
+ return void 0;
931
+ const parsed = Number(value);
932
+ return Number.isFinite(parsed) ? parsed : void 0;
933
+ }
934
+ function parseBooleanHeader(value) {
935
+ if (value === null)
936
+ return void 0;
937
+ return value === "true" || value === "1";
938
+ }
779
939
 
780
940
  // src/llm/ai-llm-stream.ts
781
941
  function createStreamProcessor() {
@@ -928,7 +1088,7 @@ function encodeSSE(event) {
928
1088
  }
929
1089
 
930
1090
  // src/audio/providers/ai-audio-provider-mimo.ts
931
- var logger4 = core.logger.child({ module: "ai", scope: "audio-mimo" });
1091
+ var logger5 = core.logger.child({ module: "ai", scope: "audio-mimo" });
932
1092
  var MIMO_CAPABILITIES = {
933
1093
  transcribe: { supported: true, realtimeAudioInput: false, speechBoundaryEvents: false, streamingTranscriptOutput: true },
934
1094
  synthesize: { supported: true, incrementalTextInput: false, streamingAudioOutput: true }
@@ -955,7 +1115,7 @@ function createMimoAudioProvider() {
955
1115
  const text = body.choices?.[0]?.message?.content ?? "";
956
1116
  return ok({ text });
957
1117
  } catch (error) {
958
- logger4.debug("MiMo transcribe failed", { error: errorMessage(error) });
1118
+ logger5.debug("MiMo transcribe failed", { error: errorMessage(error) });
959
1119
  return toAudioErrorResult(error, signal);
960
1120
  }
961
1121
  }
@@ -988,7 +1148,7 @@ function createMimoAudioProvider() {
988
1148
  }
989
1149
  async function synthesize(request) {
990
1150
  const { model, text, voice, instruction, format, sampleRate, signal } = request;
991
- const out = resolveSynthesisOutput2({ format, sampleRate });
1151
+ const out = resolveSynthesisOutput3({ format, sampleRate });
992
1152
  try {
993
1153
  const response = await postChat(model.baseUrl, model.apiKey, {
994
1154
  model: model.model,
@@ -1003,13 +1163,13 @@ function createMimoAudioProvider() {
1003
1163
  return err(HaiAIError.AUDIO_UPSTREAM_ERROR, aiM("ai_audioUpstreamError", { params: { error: "missing audio data" } }));
1004
1164
  return ok({ data: fromBase64(base64), format: out.format, sampleRate: out.sampleRate, channels: out.channels });
1005
1165
  } catch (error) {
1006
- logger4.debug("MiMo synthesize failed", { error: errorMessage(error) });
1166
+ logger5.debug("MiMo synthesize failed", { error: errorMessage(error) });
1007
1167
  return toAudioErrorResult(error, signal);
1008
1168
  }
1009
1169
  }
1010
1170
  async function* synthesizeStream(request) {
1011
1171
  const { model, text, voice, instruction, format, signal } = request;
1012
- const outFormat = resolveSynthesisOutput2({ format }).format;
1172
+ const outFormat = resolveSynthesisOutput3({ format }).format;
1013
1173
  const segments = typeof text === "string" ? [text] : streamSentences(text);
1014
1174
  for await (const segment of segments) {
1015
1175
  if (!segment)
@@ -1029,9 +1189,13 @@ function createMimoAudioProvider() {
1029
1189
  }
1030
1190
  }
1031
1191
  }
1032
- return { transcribe, transcribeStream, synthesize, synthesizeStream, resolveSynthesisOutput: resolveSynthesisOutput2, capabilities: MIMO_CAPABILITIES };
1192
+ return {
1193
+ transcription: { transcribe, transcribeStream },
1194
+ synthesis: { synthesize, synthesizeStream, resolveSynthesisOutput: resolveSynthesisOutput3 },
1195
+ getCapabilities: () => MIMO_CAPABILITIES
1196
+ };
1033
1197
  }
1034
- function resolveSynthesisOutput2(request) {
1198
+ function resolveSynthesisOutput3(request) {
1035
1199
  const format = request.format === "wav" ? "wav" : "pcm16";
1036
1200
  return { format, sampleRate: format === "pcm16" ? request.sampleRate ?? 24e3 : void 0, channels: 1 };
1037
1201
  }
@@ -1080,15 +1244,7 @@ async function* readChunks(response) {
1080
1244
  reader.releaseLock();
1081
1245
  }
1082
1246
  }
1083
- function combineSignal(signal, timeout) {
1084
- const timeoutSignal = AbortSignal.timeout(timeout);
1085
- return signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
1086
- }
1087
- async function describeHttpError(response) {
1088
- const text = await response.text().catch(() => "");
1089
- return `HTTP ${response.status} ${text.slice(0, 200)}`.trim();
1090
- }
1091
- var logger5 = core.logger.child({ module: "ai", scope: "audio-openai" });
1247
+ var logger6 = core.logger.child({ module: "ai", scope: "audio-openai" });
1092
1248
  var OPENAI_CAPABILITIES = {
1093
1249
  transcribe: { supported: true, realtimeAudioInput: false, speechBoundaryEvents: false, streamingTranscriptOutput: false },
1094
1250
  synthesize: { supported: true, incrementalTextInput: false, streamingAudioOutput: true }
@@ -1099,12 +1255,6 @@ var OPENAI_SPEECH_FORMAT = {
1099
1255
  mp3: "mp3",
1100
1256
  opus: "opus"
1101
1257
  };
1102
- var OPENAI_UPLOAD_FILENAME = {
1103
- pcm16: "audio.wav",
1104
- wav: "audio.wav",
1105
- mp3: "audio.mp3",
1106
- opus: "audio.ogg"
1107
- };
1108
1258
  function createOpenAIAudioProvider() {
1109
1259
  function createClient(apiKey, baseUrl, timeout) {
1110
1260
  return new OpenAI3({ apiKey, baseURL: baseUrl, timeout });
@@ -1124,7 +1274,7 @@ function createOpenAIAudioProvider() {
1124
1274
  }, { signal });
1125
1275
  return ok({ text: result.text });
1126
1276
  } catch (error) {
1127
- logger5.debug("OpenAI transcribe failed", { error: errorMessage(error) });
1277
+ logger6.debug("OpenAI transcribe failed", { error: errorMessage(error) });
1128
1278
  return toAudioErrorResult(error, signal);
1129
1279
  }
1130
1280
  }
@@ -1161,7 +1311,7 @@ function createOpenAIAudioProvider() {
1161
1311
  const { model, text, voice, instruction, format, sampleRate, signal } = request;
1162
1312
  if (!model.apiKey)
1163
1313
  return err(HaiAIError.CONFIGURATION_ERROR, aiM("ai_audioMissingApiKey", { params: { provider: "openai" } }));
1164
- const out = resolveSynthesisOutput3({ format, sampleRate });
1314
+ const out = resolveSynthesisOutput4({ format, sampleRate });
1165
1315
  try {
1166
1316
  const client = createClient(model.apiKey, model.baseUrl, model.timeout);
1167
1317
  const response = await client.audio.speech.create({
@@ -1174,7 +1324,7 @@ function createOpenAIAudioProvider() {
1174
1324
  const data = new Uint8Array(await response.arrayBuffer());
1175
1325
  return ok({ data, format: out.format, sampleRate: out.sampleRate, channels: out.channels });
1176
1326
  } catch (error) {
1177
- logger5.debug("OpenAI synthesize failed", { error: errorMessage(error) });
1327
+ logger6.debug("OpenAI synthesize failed", { error: errorMessage(error) });
1178
1328
  return toAudioErrorResult(error, signal);
1179
1329
  }
1180
1330
  }
@@ -1182,7 +1332,7 @@ function createOpenAIAudioProvider() {
1182
1332
  const { model, text, voice, instruction, format, signal } = request;
1183
1333
  if (!model.apiKey)
1184
1334
  throw audioError(HaiAIError.CONFIGURATION_ERROR, aiM("ai_audioMissingApiKey", { params: { provider: "openai" } }));
1185
- const outFormat = resolveSynthesisOutput3({ format }).format;
1335
+ const outFormat = resolveSynthesisOutput4({ format }).format;
1186
1336
  const client = createClient(model.apiKey, model.baseUrl, model.timeout);
1187
1337
  const segments = typeof text === "string" ? [text] : streamSentences(text);
1188
1338
  for await (const segment of segments) {
@@ -1214,42 +1364,21 @@ function createOpenAIAudioProvider() {
1214
1364
  }
1215
1365
  }
1216
1366
  }
1217
- return { transcribe, transcribeStream, synthesize, synthesizeStream, resolveSynthesisOutput: resolveSynthesisOutput3, capabilities: OPENAI_CAPABILITIES };
1367
+ return {
1368
+ transcription: { transcribe, transcribeStream },
1369
+ synthesis: { synthesize, synthesizeStream, resolveSynthesisOutput: resolveSynthesisOutput4 },
1370
+ getCapabilities: () => OPENAI_CAPABILITIES
1371
+ };
1218
1372
  }
1219
- function resolveSynthesisOutput3(request) {
1373
+ function resolveSynthesisOutput4(request) {
1220
1374
  const format = request.format ?? "mp3";
1221
1375
  return { format, sampleRate: format === "pcm16" ? request.sampleRate ?? 24e3 : void 0, channels: 1 };
1222
1376
  }
1223
1377
  async function toUploadFile(audio) {
1224
- if (audio.format === "pcm16") {
1225
- const wav = wrapPcmToWav(audio.data, audio.sampleRate ?? 16e3, audio.channels ?? 1);
1226
- return toFile(Buffer.from(wav), "audio.wav");
1227
- }
1228
- return toFile(Buffer.from(audio.data), OPENAI_UPLOAD_FILENAME[audio.format]);
1378
+ const part = toAudioUploadPart(audio);
1379
+ return toFile(Buffer.from(part.data), part.filename);
1229
1380
  }
1230
- function wrapPcmToWav(pcm, sampleRate, channels) {
1231
- const bitsPerSample = 16;
1232
- const byteRate = sampleRate * channels * bitsPerSample / 8;
1233
- const blockAlign = channels * bitsPerSample / 8;
1234
- const dataSize = pcm.length;
1235
- const buffer = Buffer.alloc(44 + dataSize);
1236
- buffer.write("RIFF", 0);
1237
- buffer.writeUInt32LE(36 + dataSize, 4);
1238
- buffer.write("WAVE", 8);
1239
- buffer.write("fmt ", 12);
1240
- buffer.writeUInt32LE(16, 16);
1241
- buffer.writeUInt16LE(1, 20);
1242
- buffer.writeUInt16LE(channels, 22);
1243
- buffer.writeUInt32LE(sampleRate, 24);
1244
- buffer.writeUInt32LE(byteRate, 28);
1245
- buffer.writeUInt16LE(blockAlign, 32);
1246
- buffer.writeUInt16LE(bitsPerSample, 34);
1247
- buffer.write("data", 36);
1248
- buffer.writeUInt32LE(dataSize, 40);
1249
- Buffer.from(pcm).copy(buffer, 44);
1250
- return new Uint8Array(buffer);
1251
- }
1252
- var logger6 = core.logger.child({ module: "ai", scope: "audio-qwen" });
1381
+ var logger7 = core.logger.child({ module: "ai", scope: "audio-qwen" });
1253
1382
  var QWEN_CAPABILITIES = {
1254
1383
  transcribe: { supported: true, realtimeAudioInput: true, speechBoundaryEvents: true, streamingTranscriptOutput: true },
1255
1384
  synthesize: { supported: true, incrementalTextInput: true, streamingAudioOutput: true }
@@ -1282,7 +1411,7 @@ function createQwenAudioProvider() {
1282
1411
  }
1283
1412
  return ok({ text: finalText });
1284
1413
  } catch (error) {
1285
- logger6.debug("Qwen transcribe failed", { error: errorMessage(error) });
1414
+ logger7.debug("Qwen transcribe failed", { error: errorMessage(error) });
1286
1415
  return toAudioErrorResult(error);
1287
1416
  }
1288
1417
  }
@@ -1354,21 +1483,21 @@ function createQwenAudioProvider() {
1354
1483
  }
1355
1484
  async function synthesize(request) {
1356
1485
  const { format, sampleRate } = request;
1357
- const out = resolveSynthesisOutput4({ format, sampleRate });
1486
+ const out = resolveSynthesisOutput5({ format, sampleRate });
1358
1487
  try {
1359
1488
  const chunks = [];
1360
1489
  for await (const audio of synthesizeStream({ model: request.model, text: request.text, voice: request.voice, instruction: request.instruction, format: out.format, sampleRate, signal: request.signal }))
1361
1490
  chunks.push(audio);
1362
1491
  return ok({ data: concatChunks(chunks), format: out.format, sampleRate: out.sampleRate, channels: out.channels });
1363
1492
  } catch (error) {
1364
- logger6.debug("Qwen synthesize failed", { error: errorMessage(error) });
1493
+ logger7.debug("Qwen synthesize failed", { error: errorMessage(error) });
1365
1494
  return toAudioErrorResult(error);
1366
1495
  }
1367
1496
  }
1368
1497
  async function* synthesizeStream(request) {
1369
1498
  const { model, text, voice, instruction, format, sampleRate, signal } = request;
1370
1499
  const isStreamInput = typeof text !== "string";
1371
- const outFormat = resolveSynthesisOutput4({ format }).format;
1500
+ const outFormat = resolveSynthesisOutput5({ format }).format;
1372
1501
  const conn = await connect(model, signal);
1373
1502
  try {
1374
1503
  conn.send(JSON.stringify({
@@ -1417,9 +1546,13 @@ function createQwenAudioProvider() {
1417
1546
  conn.close();
1418
1547
  }
1419
1548
  }
1420
- return { transcribe, transcribeStream, synthesize, synthesizeStream, resolveSynthesisOutput: resolveSynthesisOutput4, capabilities: QWEN_CAPABILITIES };
1549
+ return {
1550
+ transcription: { transcribe, transcribeStream },
1551
+ synthesis: { synthesize, synthesizeStream, resolveSynthesisOutput: resolveSynthesisOutput5 },
1552
+ getCapabilities: () => QWEN_CAPABILITIES
1553
+ };
1421
1554
  }
1422
- function resolveSynthesisOutput4(request) {
1555
+ function resolveSynthesisOutput5(request) {
1423
1556
  const format = request.format ?? "pcm16";
1424
1557
  return { format, sampleRate: format === "pcm16" ? request.sampleRate ?? 24e3 : void 0, channels: 1 };
1425
1558
  }
@@ -1430,9 +1563,95 @@ function parseEvent(text) {
1430
1563
  return {};
1431
1564
  }
1432
1565
  }
1566
+ var logger8 = core.logger.child({ module: "ai", scope: "audio-whisper" });
1567
+ var WHISPER_CAPABILITIES = {
1568
+ transcribe: {
1569
+ supported: true,
1570
+ realtimeAudioInput: false,
1571
+ speechBoundaryEvents: false,
1572
+ streamingTranscriptOutput: false,
1573
+ languageHint: true,
1574
+ languageDetection: true,
1575
+ segmentTimestamps: true,
1576
+ wordTimestamps: true,
1577
+ contextHints: true,
1578
+ vad: true,
1579
+ speakerDiarization: false
1580
+ }
1581
+ };
1582
+ function createWhisperAudioProvider() {
1583
+ async function transcribe(request) {
1584
+ const { model, audio, language, contextHints, timestampGranularities, vad, signal } = request;
1585
+ try {
1586
+ const part = toAudioUploadPart(audio);
1587
+ const form = new FormData();
1588
+ form.append("file", toAudioBlob(part), part.filename);
1589
+ form.append("model", model.model);
1590
+ if (language)
1591
+ form.append("language", language);
1592
+ if (contextHints?.length)
1593
+ form.append("prompt", contextHints.join(", "));
1594
+ for (const granularity of timestampGranularities ?? [])
1595
+ form.append("timestamp_granularities", granularity);
1596
+ if (vad !== void 0)
1597
+ form.append("vad", String(vad));
1598
+ const headers = {};
1599
+ if (model.apiKey)
1600
+ headers.Authorization = `Bearer ${model.apiKey}`;
1601
+ const response = await fetch(`${model.baseUrl.replace(/\/$/, "")}/audio/transcriptions`, {
1602
+ method: "POST",
1603
+ headers,
1604
+ body: form,
1605
+ signal: combineSignal(signal, model.timeout)
1606
+ });
1607
+ if (!response.ok)
1608
+ return err(HaiAIError.AUDIO_UPSTREAM_ERROR, aiM("ai_audioUpstreamError", { params: { error: await describeHttpError(response) } }));
1609
+ const body = await response.json();
1610
+ return ok(mapWhisperResponse(body));
1611
+ } catch (error) {
1612
+ logger8.debug("Whisper transcribe failed", { error: errorMessage(error) });
1613
+ return toAudioErrorResult(error, signal);
1614
+ }
1615
+ }
1616
+ return {
1617
+ transcription: { transcribe },
1618
+ getCapabilities: () => WHISPER_CAPABILITIES
1619
+ };
1620
+ }
1621
+ function mapWhisperResponse(body) {
1622
+ const segments = body.segments?.map(mapWhisperSegment).filter((segment) => segment !== null);
1623
+ return {
1624
+ text: body.text ?? "",
1625
+ language: body.language,
1626
+ durationMs: body.durationMs,
1627
+ ...segments?.length ? { segments } : {}
1628
+ };
1629
+ }
1630
+ function mapWhisperSegment(segment) {
1631
+ if (typeof segment.startMs !== "number" || typeof segment.endMs !== "number")
1632
+ return null;
1633
+ const words = segment.words?.map(mapWhisperWord).filter((word) => word !== null);
1634
+ return {
1635
+ ...segment.id !== void 0 ? { id: String(segment.id) } : {},
1636
+ text: segment.text ?? "",
1637
+ startMs: segment.startMs,
1638
+ endMs: segment.endMs,
1639
+ ...words?.length ? { words } : {}
1640
+ };
1641
+ }
1642
+ function mapWhisperWord(word) {
1643
+ if (typeof word.startMs !== "number" || typeof word.endMs !== "number")
1644
+ return null;
1645
+ return {
1646
+ text: word.text ?? "",
1647
+ startMs: word.startMs,
1648
+ endMs: word.endMs,
1649
+ ...typeof word.confidence === "number" ? { confidence: word.confidence } : {}
1650
+ };
1651
+ }
1433
1652
 
1434
1653
  // src/audio/ai-audio-functions.ts
1435
- var logger7 = core.logger.child({ module: "ai", scope: "audio" });
1654
+ var logger9 = core.logger.child({ module: "ai", scope: "audio" });
1436
1655
  function createAudioOperations(config) {
1437
1656
  const audioConfig = AudioConfigSchema.parse(config.audio ?? {});
1438
1657
  const providerCache = /* @__PURE__ */ new Map();
@@ -1449,6 +1668,19 @@ function createAudioOperations(config) {
1449
1668
  return audioError(HaiAIError.AUDIO_INPUT_TOO_LARGE, aiM("ai_audioInputTooLarge", { params: { limit: audioConfig.maxAudioBytes } }));
1450
1669
  return null;
1451
1670
  }
1671
+ function guardSynthesisReferences(options) {
1672
+ if (options.speakerReference) {
1673
+ const e = guardAudioSize(options.speakerReference.audio);
1674
+ if (e)
1675
+ return e;
1676
+ }
1677
+ if (options.styleReference) {
1678
+ const e = guardAudioSize(options.styleReference.audio);
1679
+ if (e)
1680
+ return e;
1681
+ }
1682
+ return null;
1683
+ }
1452
1684
  function withStreamTimeout(signal) {
1453
1685
  const timeout = AbortSignal.timeout(audioConfig.maxStreamDurationMs);
1454
1686
  return signal ? AbortSignal.any([signal, timeout]) : timeout;
@@ -1462,14 +1694,26 @@ function createAudioOperations(config) {
1462
1694
  const resolved = resolveAudioModel(audioConfig, "transcribe", request.model, config.llm.apiKey);
1463
1695
  if (!resolved.success)
1464
1696
  return resolved;
1697
+ const provider = getProvider(resolved.data.provider);
1698
+ const transcription = provider.transcription;
1699
+ if (!transcription)
1700
+ return err(HaiAIError.AUDIO_UNSUPPORTED_INPUT, aiM("ai_audioUnsupportedInput", { params: { provider: resolved.data.provider, reason: "transcription" } }));
1701
+ const credErr = ensureAudioCredential(resolved.data);
1702
+ if (credErr)
1703
+ return { success: false, error: credErr };
1704
+ if (request.strictCapabilities) {
1705
+ const capErr = checkTranscribeCapabilities(resolved.data.provider, request, provider.getCapabilities(resolved.data));
1706
+ if (capErr)
1707
+ return { success: false, error: capErr };
1708
+ }
1465
1709
  const startedAt = Date.now();
1466
1710
  const context = { provider: resolved.data.provider, model: resolved.data.model, audioBytes: request.audio.data.length };
1467
- logger7.debug("Audio transcription started", context);
1468
- const result = await getProvider(resolved.data.provider).transcribe({ model: resolved.data, audio: request.audio, language: request.language, contextHints: request.contextHints, signal: request.signal });
1711
+ logger9.debug("Audio transcription started", context);
1712
+ const result = await transcription.transcribe({ model: resolved.data, audio: request.audio, language: request.language, contextHints: request.contextHints, timestampGranularities: request.timestampGranularities, vad: request.vad, signal: request.signal });
1469
1713
  if (result.success)
1470
- logger7.info("Audio transcription completed", { ...context, durationMs: Date.now() - startedAt, textLength: result.data.text.length });
1714
+ logger9.info("Audio transcription completed", { ...context, durationMs: Date.now() - startedAt, textLength: result.data.text.length });
1471
1715
  else
1472
- logger7.warn("Audio transcription failed", { ...context, durationMs: Date.now() - startedAt, code: result.error.code, error: result.error.message });
1716
+ logger9.warn("Audio transcription failed", { ...context, durationMs: Date.now() - startedAt, code: result.error.code, error: result.error.message });
1473
1717
  return result;
1474
1718
  }
1475
1719
  async function* transcribeStream(request) {
@@ -1483,75 +1727,112 @@ function createAudioOperations(config) {
1483
1727
  const resolved = resolveAudioModel(audioConfig, "transcribe", request.model, config.llm.apiKey);
1484
1728
  if (!resolved.success)
1485
1729
  throw resolved.error;
1730
+ const provider = getProvider(resolved.data.provider);
1731
+ const transcription = provider.transcription;
1732
+ if (!transcription)
1733
+ throw audioError(HaiAIError.AUDIO_UNSUPPORTED_INPUT, aiM("ai_audioUnsupportedInput", { params: { provider: resolved.data.provider, reason: "transcription" } }));
1734
+ const credErr = ensureAudioCredential(resolved.data);
1735
+ if (credErr)
1736
+ throw credErr;
1737
+ if (request.strictCapabilities) {
1738
+ const capErr = checkTranscribeCapabilities(resolved.data.provider, request, provider.getCapabilities(resolved.data));
1739
+ if (capErr)
1740
+ throw capErr;
1741
+ }
1486
1742
  const startedAt = Date.now();
1487
1743
  const context = { provider: resolved.data.provider, model: resolved.data.model };
1488
- logger7.debug("Audio transcription stream started", context);
1744
+ logger9.debug("Audio transcription stream started", context);
1489
1745
  const signal = withStreamTimeout(request.signal);
1490
1746
  try {
1491
- yield* getProvider(resolved.data.provider).transcribeStream({ model: resolved.data, audio: request.audio, language: request.language, contextHints: request.contextHints, signal });
1492
- logger7.info("Audio transcription stream completed", { ...context, durationMs: Date.now() - startedAt });
1747
+ yield* transcribeStreamOrFallback(transcription, { model: resolved.data, audio: request.audio, language: request.language, contextHints: request.contextHints, timestampGranularities: request.timestampGranularities, vad: request.vad, signal });
1748
+ logger9.info("Audio transcription stream completed", { ...context, durationMs: Date.now() - startedAt });
1493
1749
  } catch (error) {
1494
- logger7.warn("Audio transcription stream failed", { ...context, durationMs: Date.now() - startedAt, error });
1750
+ logger9.warn("Audio transcription stream failed", { ...context, durationMs: Date.now() - startedAt, error });
1495
1751
  throw mapStreamError(error, signal);
1496
1752
  }
1497
1753
  }
1498
1754
  async function synthesize(request) {
1499
1755
  if (!request.text)
1500
1756
  return err(HaiAIError.AUDIO_INVALID_REQUEST, aiM("ai_audioInvalidRequest", { params: { reason: "empty text" } }));
1757
+ const validErr = validateSynthesisRequest(request);
1758
+ if (validErr)
1759
+ return { success: false, error: validErr };
1760
+ const refErr = guardSynthesisReferences(request);
1761
+ if (refErr)
1762
+ return { success: false, error: refErr };
1501
1763
  const resolved = resolveAudioModel(audioConfig, "synthesize", request.model, config.llm.apiKey);
1502
1764
  if (!resolved.success)
1503
1765
  return resolved;
1766
+ const provider = getProvider(resolved.data.provider);
1767
+ const synthesis = provider.synthesis;
1768
+ if (!synthesis)
1769
+ return err(HaiAIError.AUDIO_UNSUPPORTED_INPUT, aiM("ai_audioUnsupportedInput", { params: { provider: resolved.data.provider, reason: "synthesis" } }));
1770
+ const credErr = ensureAudioCredential(resolved.data);
1771
+ if (credErr)
1772
+ return { success: false, error: credErr };
1773
+ if (request.strictCapabilities) {
1774
+ const capErr = checkSynthesizeCapabilities(resolved.data.provider, request, provider.getCapabilities(resolved.data));
1775
+ if (capErr)
1776
+ return { success: false, error: capErr };
1777
+ }
1504
1778
  const startedAt = Date.now();
1505
1779
  const context = { provider: resolved.data.provider, model: resolved.data.model, textLength: request.text.length, voice: request.voice };
1506
- logger7.debug("Audio synthesis started", context);
1507
- const result = await getProvider(resolved.data.provider).synthesize({ model: resolved.data, text: request.text, voice: request.voice, instruction: request.instruction, format: request.format, sampleRate: request.sampleRate, signal: request.signal });
1780
+ logger9.debug("Audio synthesis started", context);
1781
+ const result = await synthesis.synthesize({ model: resolved.data, text: request.text, language: request.language, voice: request.voice, speakerReference: request.speakerReference, styleReference: request.styleReference, styleStrength: request.styleStrength, instruction: request.instruction, speed: request.speed, targetDurationMs: request.targetDurationMs, durationToleranceMs: request.durationToleranceMs, format: request.format, sampleRate: request.sampleRate, signal: request.signal });
1508
1782
  if (result.success)
1509
- logger7.info("Audio synthesis completed", { ...context, durationMs: Date.now() - startedAt, audioBytes: result.data.data.length, format: result.data.format });
1783
+ logger9.info("Audio synthesis completed", { ...context, durationMs: Date.now() - startedAt, audioBytes: result.data.data.length, format: result.data.format });
1510
1784
  else
1511
- logger7.warn("Audio synthesis failed", { ...context, durationMs: Date.now() - startedAt, code: result.error.code, error: result.error.message });
1785
+ logger9.warn("Audio synthesis failed", { ...context, durationMs: Date.now() - startedAt, code: result.error.code, error: result.error.message });
1512
1786
  return result;
1513
1787
  }
1514
1788
  async function* synthesizeStream(request) {
1789
+ const validErr = validateSynthesisRequest(request);
1790
+ if (validErr)
1791
+ throw validErr;
1792
+ const refErr = guardSynthesisReferences(request);
1793
+ if (refErr)
1794
+ throw refErr;
1515
1795
  const resolved = resolveAudioModel(audioConfig, "synthesize", request.model, config.llm.apiKey);
1516
1796
  if (!resolved.success)
1517
1797
  throw resolved.error;
1798
+ const provider = getProvider(resolved.data.provider);
1799
+ const synthesis = provider.synthesis;
1800
+ if (!synthesis)
1801
+ throw audioError(HaiAIError.AUDIO_UNSUPPORTED_INPUT, aiM("ai_audioUnsupportedInput", { params: { provider: resolved.data.provider, reason: "synthesis" } }));
1802
+ const credErr = ensureAudioCredential(resolved.data);
1803
+ if (credErr)
1804
+ throw credErr;
1805
+ if (request.strictCapabilities) {
1806
+ const capErr = checkSynthesizeCapabilities(resolved.data.provider, request, provider.getCapabilities(resolved.data));
1807
+ if (capErr)
1808
+ throw capErr;
1809
+ }
1518
1810
  const startedAt = Date.now();
1519
1811
  const context = { provider: resolved.data.provider, model: resolved.data.model, voice: request.voice };
1520
- logger7.debug("Audio synthesis stream started", context);
1812
+ logger9.debug("Audio synthesis stream started", context);
1521
1813
  const signal = withStreamTimeout(request.signal);
1522
- const provider = getProvider(resolved.data.provider);
1523
- const output = provider.resolveSynthesisOutput({ format: request.format, sampleRate: request.sampleRate });
1814
+ const output = synthesis.resolveSynthesisOutput({ format: request.format, sampleRate: request.sampleRate });
1524
1815
  try {
1525
1816
  const segments = isSynthesisTextSegment(request.text) ? singleSegment(request.text) : request.text;
1526
1817
  for await (const segment of segments) {
1527
1818
  if (!segment.id || !segment.text)
1528
1819
  throw audioError(HaiAIError.AUDIO_INVALID_REQUEST, aiM("ai_audioInvalidRequest", { params: { reason: "empty segment id or text" } }));
1529
1820
  yield { type: "segment_started", segmentId: segment.id, text: segment.text, format: output.format, sampleRate: output.sampleRate, channels: output.channels };
1530
- for await (const data of provider.synthesizeStream({ model: resolved.data, text: segment.text, voice: request.voice, instruction: request.instruction, format: request.format, sampleRate: request.sampleRate, signal }))
1821
+ for await (const data of synthesizeSegmentAudio(synthesis, { model: resolved.data, text: segment.text, language: request.language, voice: request.voice, speakerReference: request.speakerReference, styleReference: request.styleReference, styleStrength: request.styleStrength, instruction: request.instruction, speed: request.speed, format: request.format, sampleRate: request.sampleRate, signal }))
1531
1822
  yield { type: "audio", segmentId: segment.id, data };
1532
1823
  yield { type: "segment_done", segmentId: segment.id };
1533
1824
  }
1534
- logger7.info("Audio synthesis stream completed", { ...context, durationMs: Date.now() - startedAt });
1825
+ logger9.info("Audio synthesis stream completed", { ...context, durationMs: Date.now() - startedAt });
1535
1826
  } catch (error) {
1536
- logger7.warn("Audio synthesis stream failed", { ...context, durationMs: Date.now() - startedAt, error });
1827
+ logger9.warn("Audio synthesis stream failed", { ...context, durationMs: Date.now() - startedAt, error });
1537
1828
  throw mapStreamError(error, signal);
1538
1829
  }
1539
1830
  }
1540
1831
  function getCapabilities(request) {
1541
- const targetId = request.model ?? (request.operation === "transcribe" ? audioConfig.transcribeModel : audioConfig.synthesizeModel);
1542
- if (!targetId)
1543
- return err(HaiAIError.AUDIO_MODEL_NOT_FOUND, aiM("ai_audioModelNotFound", { params: { model: `<${request.operation}>` } }));
1544
- const entry = audioConfig.models?.find((model) => model.id === targetId || model.model === targetId);
1545
- if (!entry)
1546
- return err(HaiAIError.AUDIO_MODEL_NOT_FOUND, aiM("ai_audioModelNotFound", { params: { model: targetId } }));
1547
- const operations = entry.operations;
1548
- if (!operations.includes(request.operation)) {
1549
- return err(
1550
- HaiAIError.AUDIO_UNSUPPORTED_INPUT,
1551
- aiM("ai_audioUnsupportedInput", { params: { provider: entry.provider, reason: `model ${entry.id} does not support ${request.operation}` } })
1552
- );
1553
- }
1554
- const capabilities = getProvider(entry.provider).capabilities;
1832
+ const resolved = resolveAudioModel(audioConfig, request.operation, request.model, config.llm.apiKey);
1833
+ if (!resolved.success)
1834
+ return resolved;
1835
+ const capabilities = getProvider(resolved.data.provider).getCapabilities(resolved.data);
1555
1836
  return ok(request.operation === "transcribe" ? { transcribe: capabilities.transcribe } : { synthesize: capabilities.synthesize });
1556
1837
  }
1557
1838
  return { transcribe, transcribeStream, synthesize, synthesizeStream, getCapabilities };
@@ -1562,6 +1843,96 @@ function isSynthesisTextSegment(value) {
1562
1843
  async function* singleSegment(segment) {
1563
1844
  yield segment;
1564
1845
  }
1846
+ function invalidRequest(reason) {
1847
+ return audioError(HaiAIError.AUDIO_INVALID_REQUEST, aiM("ai_audioInvalidRequest", { params: { reason } }));
1848
+ }
1849
+ function unsupportedCapability(provider, feature) {
1850
+ return audioError(HaiAIError.AUDIO_UNSUPPORTED_INPUT, aiM("ai_audioUnsupportedInput", { params: { provider, reason: `${feature} not supported by this model` } }));
1851
+ }
1852
+ function validateSynthesisOptions(options) {
1853
+ if (options.styleStrength !== void 0 && (options.styleStrength < 0 || options.styleStrength > 1))
1854
+ return invalidRequest("styleStrength must be between 0 and 1");
1855
+ if (options.styleStrength !== void 0 && !options.styleReference)
1856
+ return invalidRequest("styleStrength requires styleReference");
1857
+ if (options.speed !== void 0 && (!Number.isFinite(options.speed) || options.speed <= 0))
1858
+ return invalidRequest("speed must be greater than 0");
1859
+ return null;
1860
+ }
1861
+ function validateSynthesisRequest(request) {
1862
+ const base = validateSynthesisOptions(request);
1863
+ if (base)
1864
+ return base;
1865
+ const targetDurationMs = "targetDurationMs" in request ? request.targetDurationMs : void 0;
1866
+ const durationToleranceMs = "durationToleranceMs" in request ? request.durationToleranceMs : void 0;
1867
+ if (targetDurationMs !== void 0 && (!Number.isInteger(targetDurationMs) || targetDurationMs <= 0))
1868
+ return invalidRequest("targetDurationMs must be a positive integer");
1869
+ if (durationToleranceMs !== void 0 && targetDurationMs === void 0)
1870
+ return invalidRequest("durationToleranceMs requires targetDurationMs");
1871
+ if (durationToleranceMs !== void 0 && (!Number.isInteger(durationToleranceMs) || durationToleranceMs < 0))
1872
+ return invalidRequest("durationToleranceMs must be a non-negative integer");
1873
+ if (request.speed !== void 0 && targetDurationMs !== void 0)
1874
+ return invalidRequest("speed and targetDurationMs cannot be used together");
1875
+ return null;
1876
+ }
1877
+ function checkTranscribeCapabilities(provider, options, capabilities) {
1878
+ const caps = capabilities.transcribe;
1879
+ if (!caps?.supported)
1880
+ return unsupportedCapability(provider, "transcription");
1881
+ if (options.timestampGranularities?.includes("word") && !caps.wordTimestamps)
1882
+ return unsupportedCapability(provider, "word timestamps");
1883
+ if (options.timestampGranularities?.includes("segment") && !caps.segmentTimestamps)
1884
+ return unsupportedCapability(provider, "segment timestamps");
1885
+ if (options.vad && !caps.vad)
1886
+ return unsupportedCapability(provider, "vad");
1887
+ if (options.contextHints?.length && !caps.contextHints)
1888
+ return unsupportedCapability(provider, "context hints");
1889
+ return null;
1890
+ }
1891
+ function checkSynthesizeCapabilities(provider, options, capabilities) {
1892
+ const caps = capabilities.synthesize;
1893
+ if (!caps?.supported)
1894
+ return unsupportedCapability(provider, "synthesis");
1895
+ if (options.speakerReference && !caps.speakerReference)
1896
+ return unsupportedCapability(provider, "speaker reference");
1897
+ if (options.styleReference && !caps.styleReference)
1898
+ return unsupportedCapability(provider, "style reference");
1899
+ if (options.instruction && !caps.instruction)
1900
+ return unsupportedCapability(provider, "instruction");
1901
+ if (options.speed !== void 0 && !caps.speedControl)
1902
+ return unsupportedCapability(provider, "speed control");
1903
+ if (options.targetDurationMs !== void 0 && !caps.targetDuration)
1904
+ return unsupportedCapability(provider, "target duration");
1905
+ return null;
1906
+ }
1907
+ async function* transcribeStreamOrFallback(transcription, request) {
1908
+ if (transcription.transcribeStream) {
1909
+ yield* transcription.transcribeStream(request);
1910
+ return;
1911
+ }
1912
+ if ("chunks" in request.audio)
1913
+ throw audioError(HaiAIError.AUDIO_UNSUPPORTED_INPUT, aiM("ai_audioUnsupportedInput", { params: { provider: request.model.provider, reason: "streaming audio input" } }));
1914
+ const result = await transcription.transcribe({ model: request.model, audio: request.audio, language: request.language, contextHints: request.contextHints, timestampGranularities: request.timestampGranularities, vad: request.vad, signal: request.signal });
1915
+ if (!result.success)
1916
+ throw result.error;
1917
+ yield { type: "transcript", text: result.data.text, final: true };
1918
+ }
1919
+ async function* synthesizeSegmentAudio(synthesis, request) {
1920
+ if (synthesis.synthesizeStream) {
1921
+ yield* synthesis.synthesizeStream(request);
1922
+ return;
1923
+ }
1924
+ const text = typeof request.text === "string" ? request.text : await collectText(request.text);
1925
+ const result = await synthesis.synthesize({ model: request.model, text, language: request.language, voice: request.voice, speakerReference: request.speakerReference, styleReference: request.styleReference, styleStrength: request.styleStrength, instruction: request.instruction, speed: request.speed, format: request.format, sampleRate: request.sampleRate, signal: request.signal });
1926
+ if (!result.success)
1927
+ throw result.error;
1928
+ yield result.data.data;
1929
+ }
1930
+ async function collectText(stream) {
1931
+ let text = "";
1932
+ for await (const part of stream)
1933
+ text += part;
1934
+ return text;
1935
+ }
1565
1936
  function createProvider(name) {
1566
1937
  switch (name) {
1567
1938
  case "openai":
@@ -1572,9 +1943,13 @@ function createProvider(name) {
1572
1943
  return createQwenAudioProvider();
1573
1944
  case "doubao":
1574
1945
  return createDoubaoAudioProvider();
1946
+ case "whisper":
1947
+ return createWhisperAudioProvider();
1948
+ case "indextts":
1949
+ return createIndexTtsAudioProvider();
1575
1950
  }
1576
1951
  }
1577
- var logger8 = core.logger.child({ module: "ai", scope: "compress" });
1952
+ var logger10 = core.logger.child({ module: "ai", scope: "compress" });
1578
1953
  var CONVERSATION_SUMMARY_PREFIX = "[Conversation Summary]";
1579
1954
  var CONVERSATION_SUMMARY_NAME = "hai_internal_conversation_summary_v1";
1580
1955
  function completeCompression(result, maxTokens) {
@@ -1712,7 +2087,7 @@ function createCompressOperations(config, token, summary, modelMaxTokens) {
1712
2087
  const maxTokens = resolveMaxTokens(options?.maxTokens);
1713
2088
  const preserveSystem = options?.preserveSystem ?? true;
1714
2089
  const preserveLastN = options?.preserveLastN ?? config.preserveLastN;
1715
- logger8.trace("Compressing context", { strategy, maxTokens, messageCount: messages.length });
2090
+ logger10.trace("Compressing context", { strategy, maxTokens, messageCount: messages.length });
1716
2091
  try {
1717
2092
  const originalTokens = token.estimateMessages(messages);
1718
2093
  if (originalTokens <= maxTokens) {
@@ -1731,7 +2106,7 @@ function createCompressOperations(config, token, summary, modelMaxTokens) {
1731
2106
  preserveLastN
1732
2107
  );
1733
2108
  const compressedTokens = token.estimateMessages(compressed);
1734
- logger8.trace("Sliding window compression completed", { originalTokens, compressedTokens, removedCount });
2109
+ logger10.trace("Sliding window compression completed", { originalTokens, compressedTokens, removedCount });
1735
2110
  return completeCompression({
1736
2111
  messages: compressed,
1737
2112
  originalTokens,
@@ -1764,7 +2139,7 @@ ${summaryText}`
1764
2139
  };
1765
2140
  const compressed = [...systemMessages2, summaryMessage, ...preserved];
1766
2141
  const compressedTokens = token.estimateMessages(compressed);
1767
- logger8.trace("Summary compression completed", { originalTokens, compressedTokens, removedCount: toSummarize2.length });
2142
+ logger10.trace("Summary compression completed", { originalTokens, compressedTokens, removedCount: toSummarize2.length });
1768
2143
  return completeCompression({
1769
2144
  messages: compressed,
1770
2145
  originalTokens,
@@ -1805,7 +2180,7 @@ ${summaryText}`
1805
2180
  };
1806
2181
  const compressed = [...systemMessages, summaryMessage, ...preservedMessages];
1807
2182
  const compressedTokens = token.estimateMessages(compressed);
1808
- logger8.trace("Hybrid compression completed", { originalTokens, compressedTokens, removedCount: toSummarize.length });
2183
+ logger10.trace("Hybrid compression completed", { originalTokens, compressedTokens, removedCount: toSummarize.length });
1809
2184
  return completeCompression({
1810
2185
  messages: compressed,
1811
2186
  originalTokens,
@@ -1821,7 +2196,7 @@ ${summaryText}`
1821
2196
  removedCount: windowRemoved
1822
2197
  }, maxTokens);
1823
2198
  } catch (error) {
1824
- logger8.error("Context compression failed", { error });
2199
+ logger10.error("Context compression failed", { error });
1825
2200
  return err(HaiAIError.CONTEXT_COMPRESS_FAILED, aiM("ai_contextCompressFailed", { params: { error: String(error) } }), error);
1826
2201
  }
1827
2202
  }
@@ -1836,7 +2211,7 @@ function sessionStoreKey(scope) {
1836
2211
  }
1837
2212
 
1838
2213
  // src/context/ai-context-functions.ts
1839
- var logger9 = core.logger.child({ module: "ai", scope: "context" });
2214
+ var logger11 = core.logger.child({ module: "ai", scope: "context" });
1840
2215
  function createContextOperations(compressConfig, tokenOps, compressOps, contextStore, sessionStore, deps) {
1841
2216
  function resolveMaxTokens(optionMaxTokens) {
1842
2217
  const fromOption = optionMaxTokens ?? compressConfig.defaultMaxTokens;
@@ -1882,7 +2257,7 @@ function createContextOperations(compressConfig, tokenOps, compressOps, contextS
1882
2257
  types: options.memory.types,
1883
2258
  model: options.memory.extractionModel,
1884
2259
  systemPrompt: options.memory.extractionSystemPrompt
1885
- }).catch((e) => logger9.warn("Memory extract failed", { error: e })).finally(() => {
2260
+ }).catch((e) => logger11.warn("Memory extract failed", { error: e })).finally(() => {
1886
2261
  pendingMemoryTasks.delete(task);
1887
2262
  });
1888
2263
  pendingMemoryTasks.add(task);
@@ -1961,7 +2336,7 @@ function createContextOperations(compressConfig, tokenOps, compressOps, contextS
1961
2336
  const currentTokens = tokenOps.estimateMessages(state.messages);
1962
2337
  if (currentTokens <= managerMaxTokens)
1963
2338
  return ok(void 0);
1964
- logger9.trace("Auto-compressing context", { currentTokens, budget: managerMaxTokens });
2339
+ logger11.trace("Auto-compressing context", { currentTokens, budget: managerMaxTokens });
1965
2340
  const compressResult = await compressOps.tryCompress(state.messages, {
1966
2341
  strategy,
1967
2342
  maxTokens: managerMaxTokens,
@@ -1970,7 +2345,7 @@ function createContextOperations(compressConfig, tokenOps, compressOps, contextS
1970
2345
  summaryModel
1971
2346
  });
1972
2347
  if (!compressResult.success) {
1973
- logger9.warn("Auto-compression failed, keeping original messages", { error: compressResult.error });
2348
+ logger11.warn("Auto-compression failed, keeping original messages", { error: compressResult.error });
1974
2349
  return compressResult;
1975
2350
  }
1976
2351
  if (compressResult.data.summary) {
@@ -2104,7 +2479,7 @@ function createContextOperations(compressConfig, tokenOps, compressOps, contextS
2104
2479
  return extracted;
2105
2480
  return ok({ summary: summaryText, memories: extracted.data });
2106
2481
  } catch (error) {
2107
- logger9.error("Context consolidate failed", { error });
2482
+ logger11.error("Context consolidate failed", { error });
2108
2483
  return err(HaiAIError.MEMORY_PROMOTE_FAILED, aiM("ai_memoryPromoteFailed", { params: { error: String(error) } }), error);
2109
2484
  }
2110
2485
  },
@@ -2239,7 +2614,7 @@ function createContextOperations(compressConfig, tokenOps, compressOps, contextS
2239
2614
  turnId = await finalizeAssistantReply(message, fallbackReply, epoch);
2240
2615
  return ok({ reply: fallbackReply, model: lastModel, turnId, usage: lastUsage });
2241
2616
  } catch (error) {
2242
- logger9.error("Context chat failed", { error });
2617
+ logger11.error("Context chat failed", { error });
2243
2618
  return err(HaiAIError.INTERNAL_ERROR, aiM("ai_internalError", { params: { error: String(error) } }), error);
2244
2619
  } finally {
2245
2620
  settleGeneration(turnId, release);
@@ -2504,7 +2879,7 @@ function createContextOperations(compressConfig, tokenOps, compressOps, contextS
2504
2879
  if (persisted) {
2505
2880
  initialMessages = persisted.messages;
2506
2881
  initialSummaries = persisted.summaries;
2507
- logger9.trace("Context manager restored from store", { scope, messageCount: initialMessages.length });
2882
+ logger11.trace("Context manager restored from store", { scope, messageCount: initialMessages.length });
2508
2883
  }
2509
2884
  }
2510
2885
  const manager = buildManager(
@@ -2566,7 +2941,7 @@ function createContextOperations(compressConfig, tokenOps, compressOps, contextS
2566
2941
  }
2567
2942
  };
2568
2943
  }
2569
- var logger10 = core.logger.child({ module: "ai", scope: "embedding" });
2944
+ var logger12 = core.logger.child({ module: "ai", scope: "embedding" });
2570
2945
  function createEmbeddingOperations(config) {
2571
2946
  const embeddingConfig = config.embedding ?? { batchSize: 100 };
2572
2947
  let cachedClient = null;
@@ -2612,7 +2987,7 @@ function createEmbeddingOperations(config) {
2612
2987
  }
2613
2988
  });
2614
2989
  } catch (error) {
2615
- logger10.error("Embedding API call failed", { error });
2990
+ logger12.error("Embedding API call failed", { error });
2616
2991
  return err(HaiAIError.EMBEDDING_API_ERROR, aiM("ai_internalError", { params: { error: String(error) } }), error);
2617
2992
  }
2618
2993
  }
@@ -2670,7 +3045,7 @@ function createEmbeddingOperations(config) {
2670
3045
  }
2671
3046
  };
2672
3047
  }
2673
- var logger11 = core.logger.child({ module: "ai", scope: "file" });
3048
+ var logger13 = core.logger.child({ module: "ai", scope: "file" });
2674
3049
  var HTML_SCRIPT_BLOCK_REGEX = /<script[^>]*>[\s\S]*?<\/script[^>]*>/gi;
2675
3050
  var HTML_STYLE_BLOCK_REGEX = /<style[^>]*>[\s\S]*?<\/style[^>]*>/gi;
2676
3051
  var HTML_LIST_OPEN_TAG_REGEX = /<[ou]l[^>]*>/gi;
@@ -2910,7 +3285,7 @@ async function parseImageWithOcr(content, mimeType, llmOps, model, outputFormat
2910
3285
  const dataUrl = `data:${mimeType};base64,${base64}`;
2911
3286
  const defaultPrompt = outputFormat === "markdown" ? "Please extract all text content from this image as Markdown, preserving document structure (headings, bullet lists, bold/italic). Return only the Markdown without additional commentary." : "Please extract all text content from this image accurately. Return only the extracted text without any additional commentary.";
2912
3287
  const prompt = customPrompt ?? defaultPrompt;
2913
- logger11.trace("Running OCR via vision LLM", { mimeType, model });
3288
+ logger13.trace("Running OCR via vision LLM", { mimeType, model });
2914
3289
  const result = await llmOps.chat({
2915
3290
  model,
2916
3291
  messages: [
@@ -2961,7 +3336,7 @@ function createFileOperations(config, llmOps) {
2961
3336
  const { content, filename, options = {} } = request;
2962
3337
  const mimeType = detectMimeType(content, filename, options.mimeType);
2963
3338
  const outputFormat = options.outputFormat ?? "text";
2964
- logger11.trace("Parsing file", { filename, mimeType, outputFormat, useOcr: options.useOcr });
3339
+ logger13.trace("Parsing file", { filename, mimeType, outputFormat, useOcr: options.useOcr });
2965
3340
  if (options.useOcr) {
2966
3341
  if (!Buffer.isBuffer(content)) {
2967
3342
  return err(HaiAIError.FILE_INVALID_CONTENT, aiM("ai_fileInvalidContent", { params: { reason: "OCR requires Buffer content" } }));
@@ -2997,7 +3372,7 @@ function createFileOperations(config, llmOps) {
2997
3372
  metadata: { filename, mimeType, charCount: pdfResult.data.text.length }
2998
3373
  });
2999
3374
  }
3000
- logger11.warn("PDF native parser failed, falling back to OCR", { filename });
3375
+ logger13.warn("PDF native parser failed, falling back to OCR", { filename });
3001
3376
  return runOcr(content, mimeType, filename, options.model, outputFormat, options.systemPrompt);
3002
3377
  }
3003
3378
  if (mimeType === "application/vnd.openxmlformats-officedocument.wordprocessingml.document" || mimeType === "application/msword" || mimeType === "application/zip") {
@@ -3012,7 +3387,7 @@ function createFileOperations(config, llmOps) {
3012
3387
  metadata: { filename, mimeType, charCount: docxResult.data.length }
3013
3388
  });
3014
3389
  }
3015
- logger11.warn("DOCX native parser failed, falling back to OCR", { filename });
3390
+ logger13.warn("DOCX native parser failed, falling back to OCR", { filename });
3016
3391
  return runOcr(content, mimeType, filename, options.model, outputFormat, options.systemPrompt);
3017
3392
  }
3018
3393
  if (IMAGE_MIME_TYPES.has(mimeType)) {
@@ -3028,7 +3403,7 @@ function createFileOperations(config, llmOps) {
3028
3403
  try {
3029
3404
  return await doParse(request);
3030
3405
  } catch (error) {
3031
- logger11.error("File parse failed unexpectedly", { filename: request.filename, error });
3406
+ logger13.error("File parse failed unexpectedly", { filename: request.filename, error });
3032
3407
  return err(HaiAIError.FILE_PARSE_FAILED, aiM("ai_fileParseFailed", { params: { error: String(error) } }), error);
3033
3408
  }
3034
3409
  },
@@ -3376,7 +3751,7 @@ function createSeedreamImageProvider() {
3376
3751
  }
3377
3752
 
3378
3753
  // src/image/ai-image-functions.ts
3379
- var logger12 = core.logger.child({ module: "ai", scope: "image" });
3754
+ var logger14 = core.logger.child({ module: "ai", scope: "image" });
3380
3755
  function createImageOperations(config) {
3381
3756
  const imageConfig = ImageConfigSchema.parse(config.image ?? {});
3382
3757
  const providers = /* @__PURE__ */ new Map();
@@ -3400,7 +3775,7 @@ function createImageOperations(config) {
3400
3775
  return err(HaiAIError.IMAGE_CANCELLED, aiM("ai_imageCancelled"));
3401
3776
  const resolved = resolveImageModel(imageConfig, request.model);
3402
3777
  if (!resolved.success) {
3403
- logger12.warn("Image model resolution failed", {
3778
+ logger14.warn("Image model resolution failed", {
3404
3779
  code: resolved.error.code,
3405
3780
  error: resolved.error.message,
3406
3781
  requestedModel: request.model
@@ -3415,7 +3790,7 @@ function createImageOperations(config) {
3415
3790
  width: request.size?.width,
3416
3791
  height: request.size?.height
3417
3792
  };
3418
- logger12.debug("Image generation started", logContext);
3793
+ logger14.debug("Image generation started", logContext);
3419
3794
  const generated = await provider(resolved.data.provider).generate({
3420
3795
  model: resolved.data,
3421
3796
  prompt: request.prompt.trim(),
@@ -3424,7 +3799,7 @@ function createImageOperations(config) {
3424
3799
  signal: request.signal
3425
3800
  });
3426
3801
  if (!generated.success) {
3427
- logger12.warn("Image generation failed", {
3802
+ logger14.warn("Image generation failed", {
3428
3803
  ...logContext,
3429
3804
  durationMs: Date.now() - startedAt,
3430
3805
  code: generated.error.code,
@@ -3433,7 +3808,7 @@ function createImageOperations(config) {
3433
3808
  });
3434
3809
  return generated;
3435
3810
  }
3436
- logger12.info("Image generation completed", {
3811
+ logger14.info("Image generation completed", {
3437
3812
  ...logContext,
3438
3813
  durationMs: Date.now() - startedAt,
3439
3814
  imageCount: generated.data.length,
@@ -3457,7 +3832,7 @@ function createProvider2(name) {
3457
3832
  return createPollinationsImageProvider();
3458
3833
  }
3459
3834
  }
3460
- var logger13 = core.logger.child({ module: "ai", scope: "knowledge-entity" });
3835
+ var logger15 = core.logger.child({ module: "ai", scope: "knowledge-entity" });
3461
3836
  var LEADING_MARKDOWN_FENCE_REGEX = /^```(?:json)?\n?/;
3462
3837
  var TRAILING_MARKDOWN_FENCE_REGEX = /\n?```$/;
3463
3838
  var DEFAULT_ENTITY_TYPES = ["person", "project", "concept", "organization", "location", "event", "other"];
@@ -3495,16 +3870,16 @@ async function extractEntities(llm, text, model, entityTypes, systemPrompt) {
3495
3870
  enablePersist: false
3496
3871
  });
3497
3872
  if (!chatResult.success) {
3498
- logger13.warn("Entity extraction LLM call failed", { error: chatResult.error });
3873
+ logger15.warn("Entity extraction LLM call failed", { error: chatResult.error });
3499
3874
  return err(HaiAIError.KNOWLEDGE_ENTITY_EXTRACT_FAILED, aiM("ai_knowledgeEntityExtractFailed", { params: { error: String(chatResult.error.message) } }), chatResult.error);
3500
3875
  }
3501
3876
  const content = chatResult.data.choices[0]?.message?.content ?? "";
3502
3877
  const validTypes = new Set(resolvedTypes);
3503
3878
  const entities = parseEntityResponse(content, validTypes);
3504
- logger13.trace("Entity extraction completed", { textLength: text.length, entityCount: entities.length });
3879
+ logger15.trace("Entity extraction completed", { textLength: text.length, entityCount: entities.length });
3505
3880
  return ok(entities);
3506
3881
  } catch (error) {
3507
- logger13.error("Entity extraction failed", { error });
3882
+ logger15.error("Entity extraction failed", { error });
3508
3883
  return err(HaiAIError.KNOWLEDGE_ENTITY_EXTRACT_FAILED, aiM("ai_knowledgeEntityExtractFailed", { params: { error: String(error) } }), error);
3509
3884
  }
3510
3885
  }
@@ -3524,10 +3899,10 @@ function parseEntityResponse(content, validTypes) {
3524
3899
  return entities.filter(isValidEntity).map((e) => normalizeEntity(e, validTypes));
3525
3900
  }
3526
3901
  }
3527
- logger13.warn("Entity extraction returned unexpected format", { content: content.slice(0, 200) });
3902
+ logger15.warn("Entity extraction returned unexpected format", { content: content.slice(0, 200) });
3528
3903
  return [];
3529
3904
  } catch {
3530
- logger13.warn("Entity extraction returned invalid JSON", { content: content.slice(0, 200) });
3905
+ logger15.warn("Entity extraction returned invalid JSON", { content: content.slice(0, 200) });
3531
3906
  return [];
3532
3907
  }
3533
3908
  }
@@ -3556,7 +3931,7 @@ async function extractEntitiesBatch(llm, chunks, model, entityTypes, systemPromp
3556
3931
  if (result.success) {
3557
3932
  return result.data.map((e) => ({ entity: e, chunkId: chunk.chunkId }));
3558
3933
  }
3559
- logger13.warn("Entity extraction failed for chunk", { chunkId: chunk.chunkId });
3934
+ logger15.warn("Entity extraction failed for chunk", { chunkId: chunk.chunkId });
3560
3935
  return [];
3561
3936
  })
3562
3937
  );
@@ -3590,7 +3965,7 @@ async function extractEntitiesBatch(llm, chunks, model, entityTypes, systemPromp
3590
3965
  }
3591
3966
 
3592
3967
  // src/knowledge/ai-knowledge-functions.ts
3593
- var logger14 = core.logger.child({ module: "ai", scope: "knowledge" });
3968
+ var logger16 = core.logger.child({ module: "ai", scope: "knowledge" });
3594
3969
  var DEFAULT_KNOWLEDGE_ASK_SYSTEM_PROMPT = `You are an expert assistant. Answer the user's question based ONLY on the provided context.
3595
3970
 
3596
3971
  Rules:
@@ -3622,14 +3997,14 @@ function createKnowledgeOperations(config, llm, embedding, datapipe2, store) {
3622
3997
  }
3623
3998
  const collection = options?.collection ?? config.collection;
3624
3999
  const dimension = options?.dimension ?? config.dimension;
3625
- logger14.debug("Setting up knowledge base", { collection, dimension });
4000
+ logger16.debug("Setting up knowledge base", { collection, dimension });
3626
4001
  try {
3627
4002
  await store.initialize(collection, dimension);
3628
4003
  await store.registerCollection(collection, dimension);
3629
- logger14.debug("Knowledge base setup completed", { collection });
4004
+ logger16.debug("Knowledge base setup completed", { collection });
3630
4005
  return ok(void 0);
3631
4006
  } catch (error) {
3632
- logger14.error("Knowledge base setup failed", { error });
4007
+ logger16.error("Knowledge base setup failed", { error });
3633
4008
  return err(HaiAIError.KNOWLEDGE_SETUP_FAILED, aiM("ai_knowledgeSetupFailed", { params: { error: String(error) } }), error);
3634
4009
  }
3635
4010
  },
@@ -3667,7 +4042,7 @@ function createKnowledgeOperations(config, llm, embedding, datapipe2, store) {
3667
4042
  ...config.chunkOptions,
3668
4043
  ...input.chunkOptions
3669
4044
  };
3670
- logger14.trace("Ingesting document", { documentId: input.documentId, collection, contentLength: input.content.length });
4045
+ logger16.trace("Ingesting document", { documentId: input.documentId, collection, contentLength: input.content.length });
3671
4046
  try {
3672
4047
  const cleanResult = datapipe2.clean(input.content, cleanOptions);
3673
4048
  const cleanedText = cleanResult.success ? cleanResult.data : input.content;
@@ -3742,11 +4117,11 @@ function createKnowledgeOperations(config, llm, embedding, datapipe2, store) {
3742
4117
  }
3743
4118
  }
3744
4119
  } else {
3745
- logger14.warn("Entity extraction failed, skipping", { error: entityResult.error });
4120
+ logger16.warn("Entity extraction failed, skipping", { error: entityResult.error });
3746
4121
  }
3747
4122
  }
3748
4123
  const duration = Date.now() - startTime;
3749
- logger14.debug("Document ingested", {
4124
+ logger16.debug("Document ingested", {
3750
4125
  documentId: input.documentId,
3751
4126
  chunkCount: chunks.length,
3752
4127
  entityCount: extractedEntities.length,
@@ -3759,7 +4134,7 @@ function createKnowledgeOperations(config, llm, embedding, datapipe2, store) {
3759
4134
  duration
3760
4135
  });
3761
4136
  } catch (error) {
3762
- logger14.error("Document ingestion failed", { documentId: input.documentId, error });
4137
+ logger16.error("Document ingestion failed", { documentId: input.documentId, error });
3763
4138
  return err(HaiAIError.KNOWLEDGE_INGEST_FAILED, aiM("ai_knowledgeIngestFailed", { params: { error: String(error) } }), error);
3764
4139
  }
3765
4140
  },
@@ -3782,7 +4157,7 @@ function createKnowledgeOperations(config, llm, embedding, datapipe2, store) {
3782
4157
  const startTime = Date.now();
3783
4158
  const topK = options?.topK ?? 10;
3784
4159
  const enableEntityBoost = options?.enableEntityBoost ?? true;
3785
- logger14.trace("Knowledge retrieval", { query: query.slice(0, 100), collection, topK });
4160
+ logger16.trace("Knowledge retrieval", { query: query.slice(0, 100), collection, topK });
3786
4161
  try {
3787
4162
  const embedResult = await embedding.embedText(query);
3788
4163
  if (!embedResult.success) {
@@ -3860,7 +4235,7 @@ function createKnowledgeOperations(config, llm, embedding, datapipe2, store) {
3860
4235
  }
3861
4236
  }
3862
4237
  const duration = Date.now() - startTime;
3863
- logger14.trace("Knowledge retrieval completed", { resultCount: items.length, duration });
4238
+ logger16.trace("Knowledge retrieval completed", { resultCount: items.length, duration });
3864
4239
  return ok({
3865
4240
  items,
3866
4241
  citations: Array.from(citationMap.values()),
@@ -3868,7 +4243,7 @@ function createKnowledgeOperations(config, llm, embedding, datapipe2, store) {
3868
4243
  duration
3869
4244
  });
3870
4245
  } catch (error) {
3871
- logger14.error("Knowledge retrieval failed", { error });
4246
+ logger16.error("Knowledge retrieval failed", { error });
3872
4247
  return err(HaiAIError.KNOWLEDGE_RETRIEVE_FAILED, aiM("ai_knowledgeRetrieveFailed", { params: { error: String(error) } }), error);
3873
4248
  }
3874
4249
  },
@@ -3916,7 +4291,7 @@ ${contextText}
3916
4291
  }
3917
4292
  const choice = chatResult.data.choices[0];
3918
4293
  const answer = choice?.message?.content ?? "";
3919
- logger14.trace("Knowledge ask completed", {
4294
+ logger16.trace("Knowledge ask completed", {
3920
4295
  contextCount: items.length,
3921
4296
  model: chatResult.data.model
3922
4297
  });
@@ -4032,13 +4407,13 @@ ${contextText}
4032
4407
  try {
4033
4408
  await store.removeVectors(collection, vectorIds);
4034
4409
  } catch (vecError) {
4035
- logger14.warn("Failed to delete some vectors", { documentId, error: vecError });
4410
+ logger16.warn("Failed to delete some vectors", { documentId, error: vecError });
4036
4411
  }
4037
4412
  }
4038
4413
  await store.deleteDocumentEntities(documentId, collection);
4039
4414
  await store.removeDocumentEntityRelations(documentId, collection);
4040
4415
  await store.removeDocument(documentId, collection);
4041
- logger14.debug("Document removed", { documentId, collection });
4416
+ logger16.debug("Document removed", { documentId, collection });
4042
4417
  return ok(void 0);
4043
4418
  } catch (error) {
4044
4419
  return err(HaiAIError.KNOWLEDGE_INGEST_FAILED, aiM("ai_knowledgeIngestFailed", { params: { error: String(error) } }), error);
@@ -4099,13 +4474,13 @@ ${contextText}
4099
4474
  return err(HaiAIError.KNOWLEDGE_SETUP_FAILED, aiM("ai_knowledgeSetupFailed", { params: { error: "KnowledgeStore not available. Provider may not support knowledge operations." } }));
4100
4475
  }
4101
4476
  const col = collection ?? config.collection;
4102
- logger14.debug("Deleting knowledge collection", { collection: col });
4477
+ logger16.debug("Deleting knowledge collection", { collection: col });
4103
4478
  try {
4104
4479
  await store.deleteCollection(col);
4105
- logger14.debug("Knowledge collection deleted", { collection: col });
4480
+ logger16.debug("Knowledge collection deleted", { collection: col });
4106
4481
  return ok(void 0);
4107
4482
  } catch (error) {
4108
- logger14.error("Knowledge collection deletion failed", { collection: col, error });
4483
+ logger16.error("Knowledge collection deletion failed", { collection: col, error });
4109
4484
  return err(HaiAIError.KNOWLEDGE_SETUP_FAILED, aiM("ai_knowledgeSetupFailed", { params: { error: String(error) } }), error);
4110
4485
  }
4111
4486
  }
@@ -4938,7 +5313,7 @@ function createLLMProvider(deps) {
4938
5313
  }
4939
5314
 
4940
5315
  // src/llm/ai-llm-functions.ts
4941
- var logger15 = core.logger.child({ module: "ai", scope: "llm" });
5316
+ var logger17 = core.logger.child({ module: "ai", scope: "llm" });
4942
5317
  function createAILLMFunctions(config, deps) {
4943
5318
  const provider = createLLMProvider({ config });
4944
5319
  const recordStore = deps?.recordStore;
@@ -4956,7 +5331,7 @@ function createAILLMFunctions(config, deps) {
4956
5331
  }
4957
5332
  async function saveRecordAndSession(record, messages) {
4958
5333
  await recordStore.save(record.id, record, { objectId: record.objectId, sessionId: record.sessionId });
4959
- logger15.trace("Chat record saved", { id: record.id, objectId: record.objectId, sessionId: record.sessionId });
5334
+ logger17.trace("Chat record saved", { id: record.id, objectId: record.objectId, sessionId: record.sessionId });
4960
5335
  if (sessionStore) {
4961
5336
  const sessionKey = sessionStoreKey({ objectId: record.objectId, sessionId: record.sessionId });
4962
5337
  const existing = await sessionStore.get(sessionKey);
@@ -4977,10 +5352,10 @@ function createAILLMFunctions(config, deps) {
4977
5352
  async function chatWithRecord(request) {
4978
5353
  const start = Date.now();
4979
5354
  const context = { model: request.model ?? request.tempModel?.model, messageCount: request.messages.length };
4980
- logger15.debug("LLM chat started", context);
5355
+ logger17.debug("LLM chat started", context);
4981
5356
  const result = await provider.chat(request);
4982
5357
  if (result.success) {
4983
- logger15.info("LLM chat completed", {
5358
+ logger17.info("LLM chat completed", {
4984
5359
  ...context,
4985
5360
  model: result.data.model,
4986
5361
  durationMs: Date.now() - start,
@@ -4988,7 +5363,7 @@ function createAILLMFunctions(config, deps) {
4988
5363
  totalTokens: result.data.usage?.total_tokens
4989
5364
  });
4990
5365
  } else {
4991
- logger15.warn("LLM chat failed", {
5366
+ logger17.warn("LLM chat failed", {
4992
5367
  ...context,
4993
5368
  durationMs: Date.now() - start,
4994
5369
  code: result.error.code,
@@ -5018,7 +5393,7 @@ function createAILLMFunctions(config, deps) {
5018
5393
  };
5019
5394
  await saveRecordAndSession(record, request.messages);
5020
5395
  } catch (error) {
5021
- logger15.debug("Failed to save chat record", { error });
5396
+ logger17.debug("Failed to save chat record", { error });
5022
5397
  }
5023
5398
  }
5024
5399
  return result;
@@ -5026,7 +5401,7 @@ function createAILLMFunctions(config, deps) {
5026
5401
  async function* chatStreamWithRecord(request) {
5027
5402
  const start = Date.now();
5028
5403
  const logContext = { model: request.model ?? request.tempModel?.model, messageCount: request.messages.length };
5029
- logger15.debug("LLM chat stream started", logContext);
5404
+ logger17.debug("LLM chat stream started", logContext);
5030
5405
  const shouldRecord = !!(request.objectId && recordStore && request.enablePersist !== false);
5031
5406
  let content = "";
5032
5407
  let finishReason = null;
@@ -5062,7 +5437,7 @@ function createAILLMFunctions(config, deps) {
5062
5437
  }
5063
5438
  }
5064
5439
  }
5065
- logger15.info("LLM chat stream completed", {
5440
+ logger17.info("LLM chat stream completed", {
5066
5441
  ...logContext,
5067
5442
  model: resolvedModel || logContext.model,
5068
5443
  durationMs: Date.now() - start,
@@ -5070,7 +5445,7 @@ function createAILLMFunctions(config, deps) {
5070
5445
  finishReason
5071
5446
  });
5072
5447
  } catch (error) {
5073
- logger15.warn("LLM chat stream failed", { ...logContext, durationMs: Date.now() - start, error });
5448
+ logger17.warn("LLM chat stream failed", { ...logContext, durationMs: Date.now() - start, error });
5074
5449
  throw error;
5075
5450
  }
5076
5451
  if (shouldRecord) {
@@ -5095,7 +5470,7 @@ function createAILLMFunctions(config, deps) {
5095
5470
  };
5096
5471
  await saveRecordAndSession(record, request.messages);
5097
5472
  } catch (error) {
5098
- logger15.debug("Failed to save stream chat record", { error });
5473
+ logger17.debug("Failed to save stream chat record", { error });
5099
5474
  }
5100
5475
  }
5101
5476
  }
@@ -5335,25 +5710,25 @@ function createAIMCPFunctions(_deps) {
5335
5710
  }
5336
5711
  };
5337
5712
  }
5338
- function createScopedMemory(core30, binding) {
5713
+ function createScopedMemory(core32, binding) {
5339
5714
  const { objectId, scope } = binding;
5340
5715
  const accessScope = { objectId, scope };
5341
5716
  return {
5342
- extract: (messages, options) => core30.extract(messages, { ...options, objectId, scope }),
5343
- recall: (query, options) => core30.recall(query, { ...options, objectId, scope }),
5344
- injectMemories: (messages, options) => core30.injectMemories(messages, { ...options, objectId, scope }),
5345
- add: (entry) => core30.add({ ...entry, objectId, scope }),
5346
- update: (memoryId, updates) => core30.update(memoryId, updates, accessScope),
5347
- get: (memoryId) => core30.get(memoryId, accessScope),
5348
- remove: (memoryId) => core30.remove(memoryId, accessScope),
5349
- list: (options) => core30.list({ ...options, objectId, scope }),
5350
- listPage: (options) => core30.listPage({ ...options, objectId, scope }),
5351
- clear: (options) => core30.clear({ ...options, objectId, scope })
5717
+ extract: (messages, options) => core32.extract(messages, { ...options, objectId, scope }),
5718
+ recall: (query, options) => core32.recall(query, { ...options, objectId, scope }),
5719
+ injectMemories: (messages, options) => core32.injectMemories(messages, { ...options, objectId, scope }),
5720
+ add: (entry) => core32.add({ ...entry, objectId, scope }),
5721
+ update: (memoryId, updates) => core32.update(memoryId, updates, accessScope),
5722
+ get: (memoryId) => core32.get(memoryId, accessScope),
5723
+ remove: (memoryId) => core32.remove(memoryId, accessScope),
5724
+ list: (options) => core32.list({ ...options, objectId, scope }),
5725
+ listPage: (options) => core32.listPage({ ...options, objectId, scope }),
5726
+ clear: (options) => core32.clear({ ...options, objectId, scope })
5352
5727
  };
5353
5728
  }
5354
- function createMemoryOperations(core30) {
5729
+ function createMemoryOperations(core32) {
5355
5730
  return {
5356
- ...core30,
5731
+ ...core32,
5357
5732
  /**
5358
5733
  * 清空记忆(空过滤保护)。
5359
5734
  *
@@ -5365,20 +5740,20 @@ function createMemoryOperations(core30) {
5365
5740
  if (!hasFilter) {
5366
5741
  return err(HaiAIError.MEMORY_STORE_FAILED, aiM("ai_memoryClearRequiresFilter"));
5367
5742
  }
5368
- return core30.clear(options);
5743
+ return core32.clear(options);
5369
5744
  },
5370
- scoped: (binding) => createScopedMemory(core30, binding),
5745
+ scoped: (binding) => createScopedMemory(core32, binding),
5371
5746
  admin: {
5372
5747
  async clearAll(options) {
5373
5748
  if (options?.confirm !== true) {
5374
5749
  return err(HaiAIError.MEMORY_STORE_FAILED, aiM("ai_memoryClearAllUnconfirmed"));
5375
5750
  }
5376
- return core30.clear();
5751
+ return core32.clear();
5377
5752
  }
5378
5753
  }
5379
5754
  };
5380
5755
  }
5381
- var logger16 = core.logger.child({ module: "ai", scope: "memory-extractor" });
5756
+ var logger18 = core.logger.child({ module: "ai", scope: "memory-extractor" });
5382
5757
  var LEADING_MARKDOWN_FENCE_REGEX2 = /^```(?:json)?\n?/;
5383
5758
  var TRAILING_MARKDOWN_FENCE_REGEX2 = /\n?```$/;
5384
5759
  var MEMORY_EXTRACTION_SYSTEM_PROMPT = `You are a memory extraction assistant. Analyze the conversation and extract important information worth remembering for future interactions.
@@ -5431,7 +5806,7 @@ Only extract memories of these types: ${options.types.join(", ")}`;
5431
5806
  signal: options?.signal
5432
5807
  });
5433
5808
  if (!chatResult.success) {
5434
- logger16.warn("Memory extraction LLM call failed", { error: chatResult.error });
5809
+ logger18.warn("Memory extraction LLM call failed", { error: chatResult.error });
5435
5810
  return err(HaiAIError.MEMORY_EXTRACT_FAILED, aiM("ai_memoryExtractFailed", { params: { error: String(chatResult.error.message) } }), chatResult.error);
5436
5811
  }
5437
5812
  const content = chatResult.data.choices[0]?.message?.content ?? "";
@@ -5446,10 +5821,10 @@ Only extract memories of these types: ${options.types.join(", ")}`;
5446
5821
  if (options?.objectId) {
5447
5822
  entries = entries.map((e) => ({ ...e, objectId: options.objectId }));
5448
5823
  }
5449
- logger16.trace("Memory extraction completed", { messageCount: messages.length, extractedCount: entries.length });
5824
+ logger18.trace("Memory extraction completed", { messageCount: messages.length, extractedCount: entries.length });
5450
5825
  return ok(entries);
5451
5826
  } catch (error) {
5452
- logger16.error("Memory extraction failed", { error });
5827
+ logger18.error("Memory extraction failed", { error });
5453
5828
  return err(HaiAIError.MEMORY_EXTRACT_FAILED, aiM("ai_memoryExtractFailed", { params: { error: String(error) } }), error);
5454
5829
  }
5455
5830
  }
@@ -5470,10 +5845,10 @@ function parseMemoryResponse(content) {
5470
5845
  return memories.filter(isValidMemoryItem).map(normalizeMemoryItem);
5471
5846
  }
5472
5847
  }
5473
- logger16.warn("Memory extraction returned unexpected format", { content: content.slice(0, 200) });
5848
+ logger18.warn("Memory extraction returned unexpected format", { content: content.slice(0, 200) });
5474
5849
  return [];
5475
5850
  } catch {
5476
- logger16.warn("Memory extraction returned invalid JSON", { content: content.slice(0, 200) });
5851
+ logger18.warn("Memory extraction returned invalid JSON", { content: content.slice(0, 200) });
5477
5852
  return [];
5478
5853
  }
5479
5854
  }
@@ -5492,7 +5867,7 @@ function normalizeMemoryItem(item) {
5492
5867
  importance
5493
5868
  };
5494
5869
  }
5495
- var logger17 = core.logger.child({ module: "ai", scope: "memory" });
5870
+ var logger19 = core.logger.child({ module: "ai", scope: "memory" });
5496
5871
  function isMemoryAccessDenied(entry, accessScope) {
5497
5872
  if (!accessScope)
5498
5873
  return false;
@@ -5577,16 +5952,16 @@ ${memoryText}
5577
5952
  });
5578
5953
  }
5579
5954
  }
5580
- logger17.trace("Memories enriched", { count: recallResult.data.length, position });
5955
+ logger19.trace("Memories enriched", { count: recallResult.data.length, position });
5581
5956
  return ok(result);
5582
5957
  } catch (error) {
5583
- logger17.error("Memory enrichment failed", { error });
5958
+ logger19.error("Memory enrichment failed", { error });
5584
5959
  return err(HaiAIError.MEMORY_ENRICH_FAILED, aiM("ai_memoryEnrichFailed", { params: { error: String(error) } }), error);
5585
5960
  }
5586
5961
  }
5587
5962
 
5588
5963
  // src/memory/providers/ai-memory-provider-mem0-oss.ts
5589
- var logger18 = core.logger.child({ module: "ai", scope: "memory-mem0-oss" });
5964
+ var logger20 = core.logger.child({ module: "ai", scope: "memory-mem0-oss" });
5590
5965
  var DEFAULT_IMPORTANCE = 0.5;
5591
5966
  var DEFAULT_OBJECT_ID = "hai-global";
5592
5967
  var MEMORY_TYPES = /* @__PURE__ */ new Set(["fact", "preference", "event", "entity", "instruction"]);
@@ -5697,7 +6072,7 @@ function buildVectorStoreConfig(deps) {
5697
6072
  );
5698
6073
  }
5699
6074
  if (backend)
5700
- logger18.warn("Mem0 OSS falls back to in-memory vector store (allowEphemeralFallback=true); data will not survive restart", { backend: backend.type });
6075
+ logger20.warn("Mem0 OSS falls back to in-memory vector store (allowEphemeralFallback=true); data will not survive restart", { backend: backend.type });
5701
6076
  return ok({
5702
6077
  provider: "memory",
5703
6078
  persistent: false,
@@ -5779,7 +6154,7 @@ async function extractMemories2(context, messages, options) {
5779
6154
  }));
5780
6155
  return ok(stored.filter((entry) => entry !== void 0));
5781
6156
  } catch (error) {
5782
- logger18.error("Mem0 OSS extract failed", { error });
6157
+ logger20.error("Mem0 OSS extract failed", { error });
5783
6158
  return err(HaiAIError.MEMORY_EXTRACT_FAILED, aiM("ai_memoryExtractFailed", { params: { error: String(error) } }), error);
5784
6159
  }
5785
6160
  }
@@ -5807,7 +6182,7 @@ async function recallMemories(context, query, options) {
5807
6182
  }
5808
6183
  return ok(entries.slice(0, topK));
5809
6184
  } catch (error) {
5810
- logger18.error("Mem0 OSS recall failed", { error });
6185
+ logger20.error("Mem0 OSS recall failed", { error });
5811
6186
  return err(HaiAIError.MEMORY_RECALL_FAILED, aiM("ai_memoryRecallFailed", { params: { error: String(error) } }), error);
5812
6187
  }
5813
6188
  }
@@ -5824,7 +6199,7 @@ async function addMemory(context, entry) {
5824
6199
  throw new Error("Mem0 OSS did not return the stored memory");
5825
6200
  return ok(toMemoryEntry(stored, objectId));
5826
6201
  } catch (error) {
5827
- logger18.error("Mem0 OSS add failed", { error });
6202
+ logger20.error("Mem0 OSS add failed", { error });
5828
6203
  return err(HaiAIError.MEMORY_STORE_FAILED, aiM("ai_memoryStoreFailed", { params: { error: String(error) } }), error);
5829
6204
  }
5830
6205
  }
@@ -5863,7 +6238,7 @@ async function updateMemory(context, memoryId, updates, accessScope) {
5863
6238
  throw new Error("Mem0 OSS did not return the updated memory");
5864
6239
  return ok(toMemoryEntry(stored, objectId));
5865
6240
  } catch (error) {
5866
- logger18.error("Mem0 OSS update failed", { id: memoryId, error });
6241
+ logger20.error("Mem0 OSS update failed", { id: memoryId, error });
5867
6242
  return err(HaiAIError.MEMORY_STORE_FAILED, aiM("ai_memoryStoreFailed", { params: { error: String(error) } }), error);
5868
6243
  }
5869
6244
  }
@@ -5911,10 +6286,10 @@ async function createMem0OssMemoryOperations(deps) {
5911
6286
  try {
5912
6287
  mod = await import('mem0ai/oss');
5913
6288
  } catch (error) {
5914
- logger18.error("Failed to load mem0ai/oss", { error });
6289
+ logger20.error("Failed to load mem0ai/oss", { error });
5915
6290
  throw new Error('mem0ai is required for memory.provider="mem0"; install it with `pnpm add mem0ai`');
5916
6291
  }
5917
- logger18.info("Mem0 OSS memory initialized", {
6292
+ logger20.info("Mem0 OSS memory initialized", {
5918
6293
  vectorProvider: configResult.data.vectorProvider,
5919
6294
  persistent: configResult.data.persistent
5920
6295
  });
@@ -5981,7 +6356,7 @@ async function createMem0OssMemoryOperations(deps) {
5981
6356
  const matched = await listMemories(context, { objectId: options?.objectId, types: options?.types, scope: options?.scope });
5982
6357
  for (const entry of matched)
5983
6358
  await context.memory.delete(entry.id);
5984
- logger18.debug("Mem0 OSS memories cleared", { removed: matched.length, objectId: options?.objectId, types: options?.types, scoped: Boolean(options?.scope) });
6359
+ logger20.debug("Mem0 OSS memories cleared", { removed: matched.length, objectId: options?.objectId, types: options?.types, scoped: Boolean(options?.scope) });
5985
6360
  return ok(void 0);
5986
6361
  } catch (error) {
5987
6362
  return err(HaiAIError.MEMORY_STORE_FAILED, aiM("ai_memoryStoreFailed", { params: { error: String(error) } }), error);
@@ -5989,7 +6364,7 @@ async function createMem0OssMemoryOperations(deps) {
5989
6364
  }
5990
6365
  };
5991
6366
  }
5992
- var logger19 = core.logger.child({ module: "ai", scope: "memory-consolidation" });
6367
+ var logger21 = core.logger.child({ module: "ai", scope: "memory-consolidation" });
5993
6368
  var DEFAULT_IMPORTANCE2 = 0.5;
5994
6369
  var MEMORY_TYPES2 = /* @__PURE__ */ new Set(["fact", "preference", "event", "entity", "instruction"]);
5995
6370
  var LEADING_CODE_FENCE_REGEX = /^```(?:json)?\n?/;
@@ -6090,7 +6465,7 @@ async function applyConsolidationOps(deps, ops, options) {
6090
6465
  if (op.event === "DELETE" && op.id) {
6091
6466
  const removeResult = await deps.remove(op.id);
6092
6467
  if (!removeResult.success)
6093
- logger19.warn("Consolidation delete skipped", { id: op.id, error: removeResult.error.message });
6468
+ logger21.warn("Consolidation delete skipped", { id: op.id, error: removeResult.error.message });
6094
6469
  continue;
6095
6470
  }
6096
6471
  if (op.event === "UPDATE" && op.id) {
@@ -6120,7 +6495,7 @@ async function applyConsolidationOps(deps, ops, options) {
6120
6495
  return ok(entries);
6121
6496
  }
6122
6497
  async function extractAndConsolidate(deps, messages, options) {
6123
- logger19.trace("Consolidation extract", { messageCount: messages.length });
6498
+ logger21.trace("Consolidation extract", { messageCount: messages.length });
6124
6499
  const extractResult = await extractMemories(deps.llm, messages, {
6125
6500
  types: options?.types,
6126
6501
  model: options?.model,
@@ -6174,7 +6549,7 @@ async function extractAndConsolidate(deps, messages, options) {
6174
6549
  try {
6175
6550
  ops = parseConsolidationOps(rawContent, candidates, relatedIds);
6176
6551
  } catch {
6177
- logger19.warn("Consolidation returned invalid JSON, falling back to ADD-all", { content: rawContent.slice(0, 200) });
6552
+ logger21.warn("Consolidation returned invalid JSON, falling back to ADD-all", { content: rawContent.slice(0, 200) });
6178
6553
  ops = candidates.map((candidate) => ({
6179
6554
  event: "ADD",
6180
6555
  text: candidate.content,
@@ -6185,12 +6560,12 @@ async function extractAndConsolidate(deps, messages, options) {
6185
6560
  const applyResult = await applyConsolidationOps(deps, ops, options);
6186
6561
  if (!applyResult.success)
6187
6562
  return applyResult;
6188
- logger19.trace("Consolidation completed", { candidates: candidates.length, related: related.length, ops: ops.length, written: applyResult.data.length });
6563
+ logger21.trace("Consolidation completed", { candidates: candidates.length, related: related.length, ops: ops.length, written: applyResult.data.length });
6189
6564
  return ok(applyResult.data);
6190
6565
  }
6191
6566
 
6192
6567
  // src/memory/providers/ai-memory-provider-native.ts
6193
- var logger20 = core.logger.child({ module: "ai", scope: "memory-native" });
6568
+ var logger22 = core.logger.child({ module: "ai", scope: "memory-native" });
6194
6569
  var EVICTION_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
6195
6570
  function generateId() {
6196
6571
  return `mem_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
@@ -6221,7 +6596,7 @@ function createNativeMemoryOperations(config, llm, embedding, store, vectorStore
6221
6596
  const result = await embedding.embedText(text);
6222
6597
  if (result.success)
6223
6598
  return result.data;
6224
- logger20.warn("Failed to compute embedding for memory", { error: result.error });
6599
+ logger22.warn("Failed to compute embedding for memory", { error: result.error });
6225
6600
  return void 0;
6226
6601
  }
6227
6602
  async function evictLowest(candidates) {
@@ -6308,10 +6683,10 @@ function createNativeMemoryOperations(config, llm, embedding, store, vectorStore
6308
6683
  }
6309
6684
  }
6310
6685
  await store.save(memoryId, existing, { objectId: existing.objectId });
6311
- logger20.trace("Memory updated", { id: memoryId });
6686
+ logger22.trace("Memory updated", { id: memoryId });
6312
6687
  return ok(existing);
6313
6688
  } catch (error) {
6314
- logger20.error("Memory update failed", { id: memoryId, error });
6689
+ logger22.error("Memory update failed", { id: memoryId, error });
6315
6690
  return err(HaiAIError.MEMORY_STORE_FAILED, aiM("ai_memoryStoreFailed", { params: { error: String(error) } }), error);
6316
6691
  }
6317
6692
  }
@@ -6319,7 +6694,7 @@ function createNativeMemoryOperations(config, llm, embedding, store, vectorStore
6319
6694
  const topK = options?.topK ?? config.defaultTopK;
6320
6695
  const recencyWeight = options?.recencyWeight ?? 1 - config.recencyDecay;
6321
6696
  const candidateMultiplier = Math.max(1, options?.candidateMultiplier ?? config.candidateMultiplier);
6322
- logger20.trace("Recalling memories", { query: query.slice(0, 100), topK, updateAccessStats });
6697
+ logger22.trace("Recalling memories", { query: query.slice(0, 100), topK, updateAccessStats });
6323
6698
  try {
6324
6699
  const where = {};
6325
6700
  const types = options?.types;
@@ -6385,10 +6760,10 @@ function createNativeMemoryOperations(config, llm, embedding, store, vectorStore
6385
6760
  }
6386
6761
  results.push({ ...entry });
6387
6762
  }
6388
- logger20.trace("Memory recall completed", { query: query.slice(0, 50), resultCount: results.length, updateAccessStats });
6763
+ logger22.trace("Memory recall completed", { query: query.slice(0, 50), resultCount: results.length, updateAccessStats });
6389
6764
  return ok(results);
6390
6765
  } catch (error) {
6391
- logger20.error("Memory recall failed", { error });
6766
+ logger22.error("Memory recall failed", { error });
6392
6767
  return err(HaiAIError.MEMORY_RECALL_FAILED, aiM("ai_memoryRecallFailed", { params: { error: String(error) } }), error);
6393
6768
  }
6394
6769
  }
@@ -6436,10 +6811,10 @@ function createNativeMemoryOperations(config, llm, embedding, store, vectorStore
6436
6811
  try {
6437
6812
  const vector = await computeVector(entry.content);
6438
6813
  const stored = await saveEntry(entry, vector);
6439
- logger20.trace("Memory added", { id: stored.id, type: stored.type });
6814
+ logger22.trace("Memory added", { id: stored.id, type: stored.type });
6440
6815
  return ok(stored);
6441
6816
  } catch (error) {
6442
- logger20.error("Memory add failed", { error });
6817
+ logger22.error("Memory add failed", { error });
6443
6818
  return err(HaiAIError.MEMORY_STORE_FAILED, aiM("ai_memoryStoreFailed", { params: { error: String(error) } }), error);
6444
6819
  }
6445
6820
  },
@@ -6485,7 +6860,7 @@ function createNativeMemoryOperations(config, llm, embedding, store, vectorStore
6485
6860
  return err(HaiAIError.MEMORY_NOT_FOUND, aiM("ai_memoryNotFound", { params: { id: memoryId } }));
6486
6861
  }
6487
6862
  await vectorStore.remove(memoryId);
6488
- logger20.trace("Memory removed", { id: memoryId });
6863
+ logger22.trace("Memory removed", { id: memoryId });
6489
6864
  return ok(void 0);
6490
6865
  },
6491
6866
  /**
@@ -6565,7 +6940,7 @@ function createNativeMemoryOperations(config, llm, embedding, store, vectorStore
6565
6940
  if (!options?.types && !options?.objectId && !options?.scope) {
6566
6941
  await store.clear();
6567
6942
  await vectorStore.clear();
6568
- logger20.debug("All memories cleared");
6943
+ logger22.debug("All memories cleared");
6569
6944
  return ok(void 0);
6570
6945
  }
6571
6946
  const where = {};
@@ -6583,13 +6958,13 @@ function createNativeMemoryOperations(config, llm, embedding, store, vectorStore
6583
6958
  await store.remove(entry.id);
6584
6959
  await vectorStore.remove(entry.id);
6585
6960
  }
6586
- logger20.debug("Memories cleared", { removed: toRemove.length, objectId: options.objectId, types: options.types, scoped: Boolean(options.scope) });
6961
+ logger22.debug("Memories cleared", { removed: toRemove.length, objectId: options.objectId, types: options.types, scoped: Boolean(options.scope) });
6587
6962
  return ok(void 0);
6588
6963
  }
6589
6964
  };
6590
6965
  return operations;
6591
6966
  }
6592
- var logger21 = core.logger.child({ module: "ai", scope: "persona" });
6967
+ var logger23 = core.logger.child({ module: "ai", scope: "persona" });
6593
6968
  var DEFAULT_OBJECT_ID2 = "system";
6594
6969
  function personaKey(objectId, id) {
6595
6970
  return JSON.stringify([objectId, id]);
@@ -6622,7 +6997,7 @@ function createPersonaOperations(store) {
6622
6997
  updatedAt: now
6623
6998
  };
6624
6999
  await store.save(key, profile, { objectId });
6625
- logger21.trace("Persona saved", { id: profile.id, objectId });
7000
+ logger23.trace("Persona saved", { id: profile.id, objectId });
6626
7001
  return ok(profile);
6627
7002
  } catch (error) {
6628
7003
  return err(HaiAIError.PERSONA_SAVE_FAILED, aiM("ai_personaSaveFailed", { params: { error: String(error) } }), error);
@@ -6675,7 +7050,7 @@ function createPersonaOperations(store) {
6675
7050
  }
6676
7051
  };
6677
7052
  }
6678
- var logger22 = core.logger.child({ module: "ai", scope: "rag" });
7053
+ var logger24 = core.logger.child({ module: "ai", scope: "rag" });
6679
7054
  var DEFAULT_RAG_SYSTEM_PROMPT = `You are a helpful assistant. Answer the user's question based on the provided context.
6680
7055
  If the context doesn't contain relevant information, say so honestly.
6681
7056
  When using information from the context, cite the source by its number, e.g. [1] or [2].`;
@@ -6704,7 +7079,7 @@ function createRagOperations(llm, retrieval) {
6704
7079
  * @returns `ok(RagResult)` 含 answer、context 列表与引用信源;检索或生成失败时返回错误
6705
7080
  */
6706
7081
  async query(query, options) {
6707
- logger22.trace("Starting RAG query", { query: query.slice(0, 100) });
7082
+ logger24.trace("Starting RAG query", { query: query.slice(0, 100) });
6708
7083
  try {
6709
7084
  const retrieveResult = await retrieval.retrieve({
6710
7085
  query,
@@ -6753,7 +7128,7 @@ ${contextText}
6753
7128
  }
6754
7129
  const choice = chatResult.data.choices[0];
6755
7130
  const answer = choice?.message?.content ?? "";
6756
- logger22.trace("RAG query completed", {
7131
+ logger24.trace("RAG query completed", {
6757
7132
  contextCount: contextItems.length,
6758
7133
  model: chatResult.data.model
6759
7134
  });
@@ -6780,7 +7155,7 @@ ${contextText}
6780
7155
  } : void 0
6781
7156
  });
6782
7157
  } catch (error) {
6783
- logger22.error("RAG query failed", { error });
7158
+ logger24.error("RAG query failed", { error });
6784
7159
  return err(HaiAIError.RAG_FAILED, aiM("ai_internalError", { params: { error: String(error) } }), error);
6785
7160
  }
6786
7161
  },
@@ -6788,7 +7163,7 @@ ${contextText}
6788
7163
  * 流式 RAG 查询:先产出 context,再逐 chunk 产出 delta,最后 done
6789
7164
  */
6790
7165
  async *queryStream(query, options) {
6791
- logger22.trace("Starting RAG stream", { query: query.slice(0, 100) });
7166
+ logger24.trace("Starting RAG stream", { query: query.slice(0, 100) });
6792
7167
  const retrieveResult = await retrieval.retrieve({
6793
7168
  query,
6794
7169
  sources: options?.sources,
@@ -6865,7 +7240,7 @@ ${contextText}
6865
7240
  }
6866
7241
  };
6867
7242
  }
6868
- var logger23 = core.logger.child({ module: "ai", scope: "reasoning" });
7243
+ var logger25 = core.logger.child({ module: "ai", scope: "reasoning" });
6869
7244
  var REACT_SYSTEM_PROMPT = `You are a reasoning agent that follows the ReAct (Reasoning and Acting) framework.
6870
7245
  For each step:
6871
7246
  1. Think: Analyze what you know and what you need to find out.
@@ -7105,7 +7480,7 @@ ${query}` }
7105
7480
  return {
7106
7481
  async run(query, options) {
7107
7482
  const strategy = options?.strategy ?? "react";
7108
- logger23.trace("Starting reasoning", { strategy, maxRounds: options?.maxRounds });
7483
+ logger25.trace("Starting reasoning", { strategy, maxRounds: options?.maxRounds });
7109
7484
  try {
7110
7485
  switch (strategy) {
7111
7486
  case "react":
@@ -7118,7 +7493,7 @@ ${query}` }
7118
7493
  return err(HaiAIError.REASONING_STRATEGY_NOT_FOUND, aiM("ai_internalError", { params: { error: `Unknown strategy: ${strategy}` } }));
7119
7494
  }
7120
7495
  } catch (error) {
7121
- logger23.error("Reasoning failed", { error });
7496
+ logger25.error("Reasoning failed", { error });
7122
7497
  return err(HaiAIError.REASONING_FAILED, aiM("ai_internalError", { params: { error: String(error) } }), error);
7123
7498
  }
7124
7499
  },
@@ -7146,7 +7521,7 @@ ${query}` }
7146
7521
  }
7147
7522
  };
7148
7523
  }
7149
- var logger24 = core.logger.child({ module: "ai", scope: "rerank" });
7524
+ var logger26 = core.logger.child({ module: "ai", scope: "rerank" });
7150
7525
  function createRerankOperations(config) {
7151
7526
  function normalizeDocuments(documents) {
7152
7527
  if (documents.length === 0) {
@@ -7184,7 +7559,7 @@ function createRerankOperations(config) {
7184
7559
  if (request.returnDocuments) {
7185
7560
  body.return_documents = true;
7186
7561
  }
7187
- logger24.trace("Calling rerank API", { model: resolved.model, documentCount: texts.length, topN: request.topN });
7562
+ logger26.trace("Calling rerank API", { model: resolved.model, documentCount: texts.length, topN: request.topN });
7188
7563
  try {
7189
7564
  const response = await fetch(`${resolved.baseUrl}/v1/rerank`, {
7190
7565
  method: "POST",
@@ -7196,7 +7571,7 @@ function createRerankOperations(config) {
7196
7571
  });
7197
7572
  if (!response.ok) {
7198
7573
  const errorText = await response.text().catch(() => response.statusText);
7199
- logger24.error("Rerank API request failed", { status: response.status, error: errorText });
7574
+ logger26.error("Rerank API request failed", { status: response.status, error: errorText });
7200
7575
  return err(HaiAIError.RERANK_API_ERROR, aiM("ai_rerankApiFailed", { params: { error: `HTTP ${response.status}: ${errorText}` } }));
7201
7576
  }
7202
7577
  const data = await response.json();
@@ -7206,10 +7581,10 @@ function createRerankOperations(config) {
7206
7581
  relevanceScore: item.relevance_score,
7207
7582
  document: item.document?.text
7208
7583
  }));
7209
- logger24.trace("Rerank completed", { resultCount: results.length });
7584
+ logger26.trace("Rerank completed", { resultCount: results.length });
7210
7585
  return ok({ model: resolved.model, results });
7211
7586
  } catch (error) {
7212
- logger24.error("Rerank API call failed", { error });
7587
+ logger26.error("Rerank API call failed", { error });
7213
7588
  return err(HaiAIError.RERANK_API_ERROR, aiM("ai_rerankApiFailed", { params: { error: String(error) } }), error);
7214
7589
  }
7215
7590
  }
@@ -7241,7 +7616,7 @@ function createRerankOperations(config) {
7241
7616
  }
7242
7617
  };
7243
7618
  }
7244
- var logger25 = core.logger.child({ module: "ai", scope: "retrieval" });
7619
+ var logger27 = core.logger.child({ module: "ai", scope: "retrieval" });
7245
7620
  function createRetrievalOperations(embeddingOps, storeProvider, sourceStore, rerankOps) {
7246
7621
  const vectorStoreCache = /* @__PURE__ */ new Map();
7247
7622
  function getVectorStore(collection) {
@@ -7268,7 +7643,7 @@ function createRetrievalOperations(embeddingOps, storeProvider, sourceStore, rer
7268
7643
  return err(HaiAIError.RETRIEVAL_FAILED, aiM("ai_internalError", { params: { error: `Source '${source.id}' already exists` } }));
7269
7644
  }
7270
7645
  await sourceStore.save(source.id, source);
7271
- logger25.debug("Retrieval source added", { sourceId: source.id, collection: source.collection });
7646
+ logger27.debug("Retrieval source added", { sourceId: source.id, collection: source.collection });
7272
7647
  return ok(void 0);
7273
7648
  },
7274
7649
  /**
@@ -7285,7 +7660,7 @@ function createRetrievalOperations(embeddingOps, storeProvider, sourceStore, rer
7285
7660
  return err(HaiAIError.RETRIEVAL_SOURCE_NOT_FOUND, aiM("ai_internalError", { params: { error: `Source '${sourceId}' not found` } }));
7286
7661
  }
7287
7662
  await sourceStore.remove(sourceId);
7288
- logger25.debug("Retrieval source removed", { sourceId });
7663
+ logger27.debug("Retrieval source removed", { sourceId });
7289
7664
  return ok(void 0);
7290
7665
  },
7291
7666
  /**
@@ -7364,27 +7739,27 @@ function createRetrievalOperations(embeddingOps, storeProvider, sourceStore, rer
7364
7739
  allItems.length = 0;
7365
7740
  allItems.push(...reranked);
7366
7741
  } else {
7367
- logger25.warn("Rerank failed, falling back to vector scores", { error: rerankResult.error });
7742
+ logger27.warn("Rerank failed, falling back to vector scores", { error: rerankResult.error });
7368
7743
  }
7369
7744
  }
7370
7745
  allItems.sort((a, b) => b.score - a.score);
7371
7746
  const topK = request.topK ?? 10;
7372
7747
  const limitedItems = allItems.slice(0, topK);
7373
7748
  const duration = Date.now() - startTime;
7374
- logger25.trace("Retrieval completed", { query: request.query, resultCount: limitedItems.length, duration });
7749
+ logger27.trace("Retrieval completed", { query: request.query, resultCount: limitedItems.length, duration });
7375
7750
  return ok({
7376
7751
  items: limitedItems,
7377
7752
  query: request.query,
7378
7753
  duration
7379
7754
  });
7380
7755
  } catch (error) {
7381
- logger25.error("Retrieval failed", { error });
7756
+ logger27.error("Retrieval failed", { error });
7382
7757
  return err(HaiAIError.RETRIEVAL_FAILED, aiM("ai_internalError", { params: { error: String(error) } }), error);
7383
7758
  }
7384
7759
  }
7385
7760
  };
7386
7761
  }
7387
- var logger26 = core.logger.child({ module: "ai", scope: "summary" });
7762
+ var logger28 = core.logger.child({ module: "ai", scope: "summary" });
7388
7763
  var SUMMARIZE_SYSTEM_PROMPT = `You are a conversation summarizer. Create a concise summary of the conversation that preserves:
7389
7764
  1. Key facts and decisions made
7390
7765
  2. Important context and background information
@@ -7438,7 +7813,7 @@ ${INCREMENTAL_SUMMARIZE_SUFFIX.replace("{previousSummary}", options.previousSumm
7438
7813
  return ok(chatResult.data.choices[0]?.message?.content ?? "");
7439
7814
  }
7440
7815
  async function summarize(messages, options) {
7441
- logger26.trace("Summarizing messages", { messageCount: messages.length });
7816
+ logger28.trace("Summarizing messages", { messageCount: messages.length });
7442
7817
  try {
7443
7818
  const result = await generate(messages, options);
7444
7819
  if (!result.success)
@@ -7450,7 +7825,7 @@ ${INCREMENTAL_SUMMARIZE_SUFFIX.replace("{previousSummary}", options.previousSumm
7450
7825
  coveredMessages: messages.filter((m) => m.role !== "system").length
7451
7826
  });
7452
7827
  } catch (error) {
7453
- logger26.error("Context summarization failed", { error });
7828
+ logger28.error("Context summarization failed", { error });
7454
7829
  return err(HaiAIError.CONTEXT_SUMMARIZE_FAILED, aiM("ai_contextSummarizeFailed", { params: { error: String(error) } }), error);
7455
7830
  }
7456
7831
  }
@@ -7494,7 +7869,7 @@ function createTokenOperations(config) {
7494
7869
  }
7495
7870
 
7496
7871
  // src/ai-functions.ts
7497
- var logger27 = core.logger.child({ module: "ai", scope: "functions" });
7872
+ var logger29 = core.logger.child({ module: "ai", scope: "functions" });
7498
7873
  async function createAISubsystems(config, deps) {
7499
7874
  const { storeProvider, datapipe: datapipeDep } = deps;
7500
7875
  const memoryParsed = MemoryConfigSchema.parse(config.memory ?? {});
@@ -7516,7 +7891,7 @@ async function createAISubsystems(config, deps) {
7516
7891
  const retrieval = createRetrievalOperations(embedding, storeProvider, sourceStore, rerank);
7517
7892
  if (config.retrieval?.sources?.length) {
7518
7893
  const configSources = RetrievalConfigSchema.parse(config.retrieval).sources ?? [];
7519
- sourceStore.saveMany(configSources.map((s) => ({ id: s.id, data: s }))).catch((e) => logger27.warn("Failed to pre-register retrieval sources", { error: e }));
7894
+ sourceStore.saveMany(configSources.map((s) => ({ id: s.id, data: s }))).catch((e) => logger29.warn("Failed to pre-register retrieval sources", { error: e }));
7520
7895
  }
7521
7896
  const rag = createRagOperations(llm, retrieval);
7522
7897
  const knowledgeParsed = KnowledgeConfigSchema.parse(config.knowledge ?? {});
@@ -7550,7 +7925,7 @@ async function createAISubsystems(config, deps) {
7550
7925
  const image = createImageOperations(config);
7551
7926
  return { llm, mcp, embedding, reasoning, rerank, retrieval, rag, knowledge, memory, persona, token, summary, compress, context, file, audio, image };
7552
7927
  }
7553
- var logger28 = core.logger.child({ module: "ai", scope: "store-provider-db" });
7928
+ var logger30 = core.logger.child({ module: "ai", scope: "store-provider-db" });
7554
7929
  var MAX_BATCH_SQL_PARAMS = 900;
7555
7930
  var ReldbAIRelStore = class {
7556
7931
  sql;
@@ -8007,7 +8382,7 @@ var DbKnowledgeStore = class {
8007
8382
  for (const stmt of statements) {
8008
8383
  const result = await this.sql.execute(stmt);
8009
8384
  if (!result.success) {
8010
- logger28.error("Knowledge schema creation failed", { sql: stmt.trim().slice(0, 60), error: result.error });
8385
+ logger30.error("Knowledge schema creation failed", { sql: stmt.trim().slice(0, 60), error: result.error });
8011
8386
  throw new Error(`Knowledge schema creation failed: ${String(result.error)}`);
8012
8387
  }
8013
8388
  }
@@ -8275,7 +8650,7 @@ function createDbStoreProvider(deps) {
8275
8650
  async initialize() {
8276
8651
  if (relStores.length > 0) {
8277
8652
  await Promise.all(relStores.map((s) => s.createTable()));
8278
- logger28.debug("DB store provider initialized", { tableCount: relStores.length });
8653
+ logger30.debug("DB store provider initialized", { tableCount: relStores.length });
8279
8654
  }
8280
8655
  },
8281
8656
  async close() {
@@ -8488,7 +8863,7 @@ function createMemoryStoreProvider() {
8488
8863
  }
8489
8864
 
8490
8865
  // src/ai-main.ts
8491
- var logger29 = core.logger.child({ module: "ai", scope: "main" });
8866
+ var logger31 = core.logger.child({ module: "ai", scope: "main" });
8492
8867
  var initInProgress = false;
8493
8868
  var currentConfig = null;
8494
8869
  var currentLLM = null;
@@ -8629,7 +9004,7 @@ async function resetAllState() {
8629
9004
  try {
8630
9005
  await storeProvider.close();
8631
9006
  } catch (error) {
8632
- logger29.error("AI store provider close failed", { error });
9007
+ logger31.error("AI store provider close failed", { error });
8633
9008
  }
8634
9009
  }
8635
9010
  }
@@ -8646,19 +9021,19 @@ var streamOperations = {
8646
9021
  var ai = {
8647
9022
  async init(config, options) {
8648
9023
  if (initInProgress) {
8649
- logger29.warn("AI init already in progress, skipping concurrent call");
9024
+ logger31.warn("AI init already in progress, skipping concurrent call");
8650
9025
  return err(HaiAIError.INIT_IN_PROGRESS, aiM("ai_initInProgress"));
8651
9026
  }
8652
9027
  initInProgress = true;
8653
9028
  try {
8654
9029
  if (currentConfig) {
8655
- logger29.warn("AI module is already initialized, reinitializing");
9030
+ logger31.warn("AI module is already initialized, reinitializing");
8656
9031
  await ai.close();
8657
9032
  }
8658
- logger29.info("Initializing AI module");
9033
+ logger31.info("Initializing AI module");
8659
9034
  const parseResult = AIConfigSchema.safeParse(config ?? {});
8660
9035
  if (!parseResult.success) {
8661
- logger29.error("AI config validation failed", { error: parseResult.error.message });
9036
+ logger31.error("AI config validation failed", { error: parseResult.error.message });
8662
9037
  return err(
8663
9038
  HaiAIError.CONFIGURATION_ERROR,
8664
9039
  aiM("ai_configError", { params: { error: parseResult.error.message } }),
@@ -8673,7 +9048,7 @@ var ai = {
8673
9048
  storeProvider = createDbStoreProviderFromModules();
8674
9049
  } else {
8675
9050
  storeProvider = createMemoryStoreProvider();
8676
- logger29.warn("AI is using the ephemeral in-memory store; initialize reldb and vecdb before ai.init() for persistent data");
9051
+ logger31.warn("AI is using the ephemeral in-memory store; initialize reldb and vecdb before ai.init() for persistent data");
8677
9052
  }
8678
9053
  currentStoreProvider = storeProvider;
8679
9054
  const subs = await createAISubsystems(parsed, {
@@ -8699,11 +9074,11 @@ var ai = {
8699
9074
  currentImage = subs.image;
8700
9075
  currentA2AConfig = parsed.a2a;
8701
9076
  currentConfig = parsed;
8702
- logger29.info("AI module initialized", { model: parsed.llm?.model });
9077
+ logger31.info("AI module initialized", { model: parsed.llm?.model });
8703
9078
  return ok(void 0);
8704
9079
  } catch (error) {
8705
9080
  await resetAllState();
8706
- logger29.error("AI module initialization failed", { error });
9081
+ logger31.error("AI module initialization failed", { error });
8707
9082
  return err(
8708
9083
  HaiAIError.CONFIGURATION_ERROR,
8709
9084
  aiM("ai_initFailed", {
@@ -8783,12 +9158,12 @@ var ai = {
8783
9158
  },
8784
9159
  async close() {
8785
9160
  if (!currentConfig) {
8786
- logger29.info("AI module already closed, skipping");
9161
+ logger31.info("AI module already closed, skipping");
8787
9162
  return;
8788
9163
  }
8789
- logger29.info("Closing AI module");
9164
+ logger31.info("Closing AI module");
8790
9165
  await resetAllState();
8791
- logger29.info("AI module closed");
9166
+ logger31.info("AI module closed");
8792
9167
  }
8793
9168
  };
8794
9169
  function createMcpServer(options) {