@promptbook/node 0.110.0-4 → 0.110.0-7

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.
Files changed (23) hide show
  1. package/esm/index.es.js +1226 -412
  2. package/esm/index.es.js.map +1 -1
  3. package/esm/typings/src/_packages/openai.index.d.ts +8 -4
  4. package/esm/typings/src/_packages/types.index.d.ts +4 -2
  5. package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentsDatabaseSchema.d.ts +0 -3
  6. package/esm/typings/src/execution/LlmExecutionTools.d.ts +2 -1
  7. package/esm/typings/src/llm-providers/agent/Agent.d.ts +1 -1
  8. package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +5 -1
  9. package/esm/typings/src/llm-providers/agent/AgentOptions.d.ts +4 -3
  10. package/esm/typings/src/llm-providers/agent/CreateAgentLlmExecutionToolsOptions.d.ts +7 -5
  11. package/esm/typings/src/llm-providers/agent/RemoteAgent.d.ts +2 -1
  12. package/esm/typings/src/llm-providers/openai/OpenAiAgentKitExecutionTools.d.ts +111 -0
  13. package/esm/typings/src/llm-providers/openai/OpenAiAgentKitExecutionToolsOptions.d.ts +15 -0
  14. package/esm/typings/src/llm-providers/openai/OpenAiAssistantExecutionTools.d.ts +3 -3
  15. package/esm/typings/src/llm-providers/openai/OpenAiAssistantExecutionToolsOptions.d.ts +2 -3
  16. package/esm/typings/src/llm-providers/openai/OpenAiVectorStoreHandler.d.ts +135 -0
  17. package/esm/typings/src/llm-providers/openai/utils/mapToolsToOpenAi.d.ts +1 -1
  18. package/esm/typings/src/version.d.ts +1 -1
  19. package/package.json +7 -3
  20. package/umd/index.umd.js +1229 -416
  21. package/umd/index.umd.js.map +1 -1
  22. package/esm/typings/src/llm-providers/openai/OpenAiAgentExecutionTools.d.ts +0 -43
  23. package/esm/typings/src/llm-providers/openai/createOpenAiAgentExecutionTools.d.ts +0 -11
package/esm/index.es.js CHANGED
@@ -17,6 +17,7 @@ import { Subject, BehaviorSubject } from 'rxjs';
17
17
  import moment from 'moment';
18
18
  import { lookup, extension } from 'mime-types';
19
19
  import { parse, unparse } from 'papaparse';
20
+ import { Agent as Agent$1, setDefaultOpenAIClient, setDefaultOpenAIKey, fileSearchTool, tool, run } from '@openai/agents';
20
21
  import Bottleneck from 'bottleneck';
21
22
  import OpenAI from 'openai';
22
23
 
@@ -34,7 +35,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
34
35
  * @generated
35
36
  * @see https://github.com/webgptorg/promptbook
36
37
  */
37
- const PROMPTBOOK_ENGINE_VERSION = '0.110.0-4';
38
+ const PROMPTBOOK_ENGINE_VERSION = '0.110.0-7';
38
39
  /**
39
40
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
40
41
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -22358,16 +22359,11 @@ class OpenAiCompatibleExecutionTools {
22358
22359
  const openAiOptions = { ...this.options };
22359
22360
  delete openAiOptions.isVerbose;
22360
22361
  delete openAiOptions.userId;
22361
- // Enhanced configuration for better ECONNRESET handling
22362
+ // Enhanced configuration with retries and timeouts.
22362
22363
  const enhancedOptions = {
22363
22364
  ...openAiOptions,
22364
22365
  timeout: API_REQUEST_TIMEOUT,
22365
22366
  maxRetries: CONNECTION_RETRIES_LIMIT,
22366
- defaultHeaders: {
22367
- Connection: 'keep-alive',
22368
- 'Keep-Alive': 'timeout=30, max=100',
22369
- ...openAiOptions.defaultHeaders,
22370
- },
22371
22367
  };
22372
22368
  this.client = new OpenAI(enhancedOptions);
22373
22369
  }
@@ -23256,18 +23252,6 @@ class OpenAiExecutionTools extends OpenAiCompatibleExecutionTools {
23256
23252
  get profile() {
23257
23253
  return OPENAI_PROVIDER_PROFILE;
23258
23254
  }
23259
- /*
23260
- Note: Commenting this out to avoid circular dependency
23261
- /**
23262
- * Create (sub)tools for calling OpenAI API Assistants
23263
- *
23264
- * @param assistantId Which assistant to use
23265
- * @returns Tools for calling OpenAI API Assistants with same token
23266
- * /
23267
- public createAssistantSubtools(assistantId: string_token): OpenAiAssistantExecutionTools {
23268
- return new OpenAiAssistantExecutionTools({ ...this.options, assistantId });
23269
- }
23270
- */
23271
23255
  /**
23272
23256
  * List all available models (non dynamically)
23273
23257
  *
@@ -23295,213 +23279,1180 @@ class OpenAiExecutionTools extends OpenAiCompatibleExecutionTools {
23295
23279
  return this.getDefaultModel('text-embedding-3-large');
23296
23280
  }
23297
23281
  /**
23298
- * Default model for image generation variant.
23282
+ * Default model for image generation variant.
23283
+ */
23284
+ getDefaultImageGenerationModel() {
23285
+ return this.getDefaultModel('dall-e-3');
23286
+ }
23287
+ }
23288
+
23289
+ const DEFAULT_KNOWLEDGE_SOURCE_DOWNLOAD_TIMEOUT_MS = 30000;
23290
+ const DEFAULT_KNOWLEDGE_SOURCE_UPLOAD_TIMEOUT_MS = 900000;
23291
+ const VECTOR_STORE_PROGRESS_LOG_INTERVAL_MIN_MS = 15000;
23292
+ const VECTOR_STORE_STALL_LOG_THRESHOLD_MS = 30000;
23293
+ /**
23294
+ * Base class for OpenAI execution tools that need hosted vector stores.
23295
+ *
23296
+ * @public exported from `@promptbook/openai`
23297
+ */
23298
+ class OpenAiVectorStoreHandler extends OpenAiExecutionTools {
23299
+ /**
23300
+ * Returns the per-knowledge-source download timeout in milliseconds.
23301
+ */
23302
+ getKnowledgeSourceDownloadTimeoutMs() {
23303
+ var _a;
23304
+ return (_a = this.vectorStoreOptions.knowledgeSourceDownloadTimeoutMs) !== null && _a !== void 0 ? _a : DEFAULT_KNOWLEDGE_SOURCE_DOWNLOAD_TIMEOUT_MS;
23305
+ }
23306
+ /**
23307
+ * Returns the max concurrency for knowledge source uploads.
23308
+ */
23309
+ getKnowledgeSourceUploadMaxConcurrency() {
23310
+ var _a;
23311
+ return (_a = this.vectorStoreOptions.knowledgeSourceUploadMaxConcurrency) !== null && _a !== void 0 ? _a : 5;
23312
+ }
23313
+ /**
23314
+ * Returns the polling interval in milliseconds for vector store uploads.
23315
+ */
23316
+ getKnowledgeSourceUploadPollIntervalMs() {
23317
+ var _a;
23318
+ return (_a = this.vectorStoreOptions.knowledgeSourceUploadPollIntervalMs) !== null && _a !== void 0 ? _a : 5000;
23319
+ }
23320
+ /**
23321
+ * Returns the overall upload timeout in milliseconds for vector store uploads.
23322
+ */
23323
+ getKnowledgeSourceUploadTimeoutMs() {
23324
+ var _a;
23325
+ return (_a = this.vectorStoreOptions.knowledgeSourceUploadTimeoutMs) !== null && _a !== void 0 ? _a : DEFAULT_KNOWLEDGE_SOURCE_UPLOAD_TIMEOUT_MS;
23326
+ }
23327
+ /**
23328
+ * Returns true if we should continue even if vector store ingestion stalls.
23329
+ */
23330
+ shouldContinueOnVectorStoreStall() {
23331
+ var _a;
23332
+ return (_a = this.vectorStoreOptions.shouldContinueOnVectorStoreStall) !== null && _a !== void 0 ? _a : true;
23333
+ }
23334
+ /**
23335
+ * Returns vector-store-specific options with extended settings.
23336
+ */
23337
+ get vectorStoreOptions() {
23338
+ return this.options;
23339
+ }
23340
+ /**
23341
+ * Returns the OpenAI vector stores API surface, supporting stable and beta SDKs.
23342
+ */
23343
+ getVectorStoresApi(client) {
23344
+ var _a, _b;
23345
+ const vectorStores = (_a = client.vectorStores) !== null && _a !== void 0 ? _a : (_b = client.beta) === null || _b === void 0 ? void 0 : _b.vectorStores;
23346
+ if (!vectorStores) {
23347
+ throw new Error('OpenAI client does not support vector stores. Please ensure you are using a compatible version of the OpenAI SDK with vector store support.');
23348
+ }
23349
+ return vectorStores;
23350
+ }
23351
+ /**
23352
+ * Downloads a knowledge source URL into a File for vector store upload.
23353
+ */
23354
+ async downloadKnowledgeSourceFile(options) {
23355
+ var _a;
23356
+ const { source, timeoutMs, logLabel } = options;
23357
+ const startedAtMs = Date.now();
23358
+ const controller = new AbortController();
23359
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
23360
+ if (this.options.isVerbose) {
23361
+ console.info('[🤰]', 'Downloading knowledge source', {
23362
+ source,
23363
+ timeoutMs,
23364
+ logLabel,
23365
+ });
23366
+ }
23367
+ try {
23368
+ const response = await fetch(source, { signal: controller.signal });
23369
+ const contentType = (_a = response.headers.get('content-type')) !== null && _a !== void 0 ? _a : undefined;
23370
+ if (!response.ok) {
23371
+ console.error('[🤰]', 'Failed to download knowledge source', {
23372
+ source,
23373
+ status: response.status,
23374
+ statusText: response.statusText,
23375
+ contentType,
23376
+ elapsedMs: Date.now() - startedAtMs,
23377
+ logLabel,
23378
+ });
23379
+ return null;
23380
+ }
23381
+ const buffer = await response.arrayBuffer();
23382
+ let filename = source.split('/').pop() || 'downloaded-file';
23383
+ try {
23384
+ const url = new URL(source);
23385
+ filename = url.pathname.split('/').pop() || filename;
23386
+ }
23387
+ catch (error) {
23388
+ // Keep default filename
23389
+ }
23390
+ const file = new File([buffer], filename, contentType ? { type: contentType } : undefined);
23391
+ const elapsedMs = Date.now() - startedAtMs;
23392
+ const sizeBytes = buffer.byteLength;
23393
+ if (this.options.isVerbose) {
23394
+ console.info('[🤰]', 'Downloaded knowledge source', {
23395
+ source,
23396
+ filename,
23397
+ sizeBytes,
23398
+ contentType,
23399
+ elapsedMs,
23400
+ logLabel,
23401
+ });
23402
+ }
23403
+ return { file, sizeBytes, filename, elapsedMs };
23404
+ }
23405
+ catch (error) {
23406
+ assertsError(error);
23407
+ console.error('[🤰]', 'Error downloading knowledge source', {
23408
+ source,
23409
+ elapsedMs: Date.now() - startedAtMs,
23410
+ logLabel,
23411
+ error: serializeError(error),
23412
+ });
23413
+ return null;
23414
+ }
23415
+ finally {
23416
+ clearTimeout(timeoutId);
23417
+ }
23418
+ }
23419
+ /**
23420
+ * Logs vector store file batch diagnostics to help trace ingestion stalls or failures.
23421
+ */
23422
+ async logVectorStoreFileBatchDiagnostics(options) {
23423
+ var _a, _b, _c, _d, _e;
23424
+ const { client, vectorStoreId, batchId, uploadedFiles, logLabel, reason } = options;
23425
+ if (reason === 'stalled' && !this.options.isVerbose) {
23426
+ return;
23427
+ }
23428
+ if (!batchId.startsWith('vsfb_')) {
23429
+ console.error('[🤰]', 'Vector store file batch diagnostics skipped (invalid batch id)', {
23430
+ vectorStoreId,
23431
+ batchId,
23432
+ reason,
23433
+ logLabel,
23434
+ });
23435
+ return;
23436
+ }
23437
+ const fileIdToMetadata = new Map();
23438
+ for (const file of uploadedFiles) {
23439
+ fileIdToMetadata.set(file.fileId, file);
23440
+ }
23441
+ try {
23442
+ const vectorStores = this.getVectorStoresApi(client);
23443
+ const limit = Math.min(100, Math.max(10, uploadedFiles.length));
23444
+ const batchFilesPage = await vectorStores.fileBatches.listFiles(batchId, {
23445
+ vector_store_id: vectorStoreId,
23446
+ limit,
23447
+ });
23448
+ const batchFiles = (_a = batchFilesPage.data) !== null && _a !== void 0 ? _a : [];
23449
+ const statusCounts = {
23450
+ in_progress: 0,
23451
+ completed: 0,
23452
+ failed: 0,
23453
+ cancelled: 0,
23454
+ };
23455
+ const errorSamples = [];
23456
+ const inProgressSamples = [];
23457
+ const batchFileIds = new Set();
23458
+ for (const file of batchFiles) {
23459
+ const status = (_b = file.status) !== null && _b !== void 0 ? _b : 'unknown';
23460
+ statusCounts[status] = ((_c = statusCounts[status]) !== null && _c !== void 0 ? _c : 0) + 1;
23461
+ const vectorStoreFileId = file.id;
23462
+ const uploadedFileId = (_d = file.file_id) !== null && _d !== void 0 ? _d : file.fileId;
23463
+ const fileId = uploadedFileId !== null && uploadedFileId !== void 0 ? uploadedFileId : vectorStoreFileId;
23464
+ batchFileIds.add(fileId);
23465
+ const metadata = fileIdToMetadata.get(fileId);
23466
+ if (status === 'failed') {
23467
+ errorSamples.push({
23468
+ fileId,
23469
+ status,
23470
+ error: (_e = file.last_error) === null || _e === void 0 ? void 0 : _e.message,
23471
+ filename: metadata === null || metadata === void 0 ? void 0 : metadata.filename,
23472
+ vectorStoreFileId: uploadedFileId ? vectorStoreFileId : undefined,
23473
+ });
23474
+ }
23475
+ if (status === 'in_progress') {
23476
+ inProgressSamples.push({
23477
+ fileId,
23478
+ filename: metadata === null || metadata === void 0 ? void 0 : metadata.filename,
23479
+ vectorStoreFileId: uploadedFileId ? vectorStoreFileId : undefined,
23480
+ });
23481
+ }
23482
+ }
23483
+ const missingSamples = uploadedFiles
23484
+ .filter((file) => !batchFileIds.has(file.fileId))
23485
+ .slice(0, 5)
23486
+ .map((file) => ({
23487
+ fileId: file.fileId,
23488
+ filename: file.filename,
23489
+ sizeBytes: file.sizeBytes,
23490
+ }));
23491
+ const vectorStore = await vectorStores.retrieve(vectorStoreId);
23492
+ const logPayload = {
23493
+ vectorStoreId,
23494
+ batchId,
23495
+ reason,
23496
+ vectorStoreStatus: vectorStore.status,
23497
+ vectorStoreFileCounts: vectorStore.file_counts,
23498
+ vectorStoreUsageBytes: vectorStore.usage_bytes,
23499
+ batchFileCount: batchFiles.length,
23500
+ statusCounts,
23501
+ errorSamples: errorSamples.slice(0, 5),
23502
+ inProgressSamples,
23503
+ missingFileCount: uploadedFiles.length - batchFileIds.size,
23504
+ missingSamples,
23505
+ logLabel,
23506
+ };
23507
+ const logFunction = reason === 'stalled' ? console.info : console.error;
23508
+ logFunction('[🤰]', 'Vector store file batch diagnostics', logPayload);
23509
+ }
23510
+ catch (error) {
23511
+ assertsError(error);
23512
+ console.error('[🤰]', 'Vector store file batch diagnostics failed', {
23513
+ vectorStoreId,
23514
+ batchId,
23515
+ reason,
23516
+ logLabel,
23517
+ error: serializeError(error),
23518
+ });
23519
+ }
23520
+ }
23521
+ /**
23522
+ * Uploads knowledge source files to the vector store and polls until processing completes.
23523
+ */
23524
+ async uploadKnowledgeSourceFilesToVectorStore(options) {
23525
+ var _a, _b, _c, _d, _e, _f;
23526
+ const { client, vectorStoreId, files, totalBytes, logLabel } = options;
23527
+ const vectorStores = this.getVectorStoresApi(client);
23528
+ const uploadStartedAtMs = Date.now();
23529
+ const maxConcurrency = Math.max(1, this.getKnowledgeSourceUploadMaxConcurrency());
23530
+ const pollIntervalMs = Math.max(1000, this.getKnowledgeSourceUploadPollIntervalMs());
23531
+ const uploadTimeoutMs = Math.max(1000, this.getKnowledgeSourceUploadTimeoutMs());
23532
+ if (this.options.isVerbose) {
23533
+ console.info('[🤰]', 'Uploading knowledge source files to OpenAI', {
23534
+ vectorStoreId,
23535
+ fileCount: files.length,
23536
+ totalBytes,
23537
+ maxConcurrency,
23538
+ pollIntervalMs,
23539
+ uploadTimeoutMs,
23540
+ logLabel,
23541
+ });
23542
+ }
23543
+ const fileTypeSummary = {};
23544
+ for (const file of files) {
23545
+ const filename = (_a = file.name) !== null && _a !== void 0 ? _a : '';
23546
+ const extension = filename.includes('.')
23547
+ ? (_c = (_b = filename.split('.').pop()) === null || _b === void 0 ? void 0 : _b.toLowerCase()) !== null && _c !== void 0 ? _c : 'unknown'
23548
+ : 'unknown';
23549
+ const sizeBytes = typeof file.size === 'number' ? file.size : 0;
23550
+ const summary = (_d = fileTypeSummary[extension]) !== null && _d !== void 0 ? _d : { count: 0, totalBytes: 0 };
23551
+ summary.count += 1;
23552
+ summary.totalBytes += sizeBytes;
23553
+ fileTypeSummary[extension] = summary;
23554
+ }
23555
+ if (this.options.isVerbose) {
23556
+ console.info('[🤰]', 'Knowledge source file summary', {
23557
+ vectorStoreId,
23558
+ fileCount: files.length,
23559
+ totalBytes,
23560
+ fileTypeSummary,
23561
+ logLabel,
23562
+ });
23563
+ }
23564
+ const fileEntries = files.map((file, index) => ({ file, index }));
23565
+ const fileIterator = fileEntries.values();
23566
+ const fileIds = [];
23567
+ const uploadedFiles = [];
23568
+ const failedUploads = [];
23569
+ let uploadedCount = 0;
23570
+ const processFiles = async (iterator) => {
23571
+ var _a, _b;
23572
+ for (const { file, index } of iterator) {
23573
+ const uploadIndex = index + 1;
23574
+ const filename = file.name || `knowledge-source-${uploadIndex}`;
23575
+ const extension = filename.includes('.')
23576
+ ? (_b = (_a = filename.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : 'unknown'
23577
+ : 'unknown';
23578
+ const sizeBytes = typeof file.size === 'number' ? file.size : undefined;
23579
+ const fileUploadStartedAtMs = Date.now();
23580
+ if (this.options.isVerbose) {
23581
+ console.info('[🤰]', 'Uploading knowledge source file', {
23582
+ index: uploadIndex,
23583
+ total: files.length,
23584
+ filename,
23585
+ extension,
23586
+ sizeBytes,
23587
+ logLabel,
23588
+ });
23589
+ }
23590
+ try {
23591
+ const uploaded = await client.files.create({ file, purpose: 'assistants' });
23592
+ fileIds.push(uploaded.id);
23593
+ uploadedFiles.push({ fileId: uploaded.id, filename, sizeBytes });
23594
+ uploadedCount += 1;
23595
+ if (this.options.isVerbose) {
23596
+ console.info('[🤰]', 'Uploaded knowledge source file', {
23597
+ index: uploadIndex,
23598
+ total: files.length,
23599
+ filename,
23600
+ sizeBytes,
23601
+ fileId: uploaded.id,
23602
+ elapsedMs: Date.now() - fileUploadStartedAtMs,
23603
+ logLabel,
23604
+ });
23605
+ }
23606
+ }
23607
+ catch (error) {
23608
+ assertsError(error);
23609
+ const serializedError = serializeError(error);
23610
+ failedUploads.push({ index: uploadIndex, filename, error: serializedError });
23611
+ console.error('[🤰]', 'Failed to upload knowledge source file', {
23612
+ index: uploadIndex,
23613
+ total: files.length,
23614
+ filename,
23615
+ sizeBytes,
23616
+ elapsedMs: Date.now() - fileUploadStartedAtMs,
23617
+ logLabel,
23618
+ error: serializedError,
23619
+ });
23620
+ }
23621
+ }
23622
+ };
23623
+ const workerCount = Math.min(maxConcurrency, files.length);
23624
+ const workers = Array.from({ length: workerCount }, () => processFiles(fileIterator));
23625
+ await Promise.all(workers);
23626
+ if (this.options.isVerbose) {
23627
+ console.info('[🤰]', 'Finished uploading knowledge source files', {
23628
+ vectorStoreId,
23629
+ fileCount: files.length,
23630
+ uploadedCount,
23631
+ failedCount: failedUploads.length,
23632
+ elapsedMs: Date.now() - uploadStartedAtMs,
23633
+ failedSamples: failedUploads.slice(0, 3),
23634
+ logLabel,
23635
+ });
23636
+ }
23637
+ if (fileIds.length === 0) {
23638
+ console.error('[🤰]', 'No knowledge source files were uploaded', {
23639
+ vectorStoreId,
23640
+ fileCount: files.length,
23641
+ failedCount: failedUploads.length,
23642
+ logLabel,
23643
+ });
23644
+ return null;
23645
+ }
23646
+ const batch = await vectorStores.fileBatches.create(vectorStoreId, {
23647
+ file_ids: fileIds,
23648
+ });
23649
+ const expectedBatchId = batch.id;
23650
+ const expectedBatchIdValid = expectedBatchId.startsWith('vsfb_');
23651
+ if (!expectedBatchIdValid) {
23652
+ console.error('[🤰]', 'Vector store file batch id looks invalid', {
23653
+ vectorStoreId,
23654
+ batchId: expectedBatchId,
23655
+ batchVectorStoreId: batch.vector_store_id,
23656
+ logLabel,
23657
+ });
23658
+ }
23659
+ else if (batch.vector_store_id !== vectorStoreId) {
23660
+ console.error('[🤰]', 'Vector store file batch vector store id mismatch', {
23661
+ vectorStoreId,
23662
+ batchId: expectedBatchId,
23663
+ batchVectorStoreId: batch.vector_store_id,
23664
+ logLabel,
23665
+ });
23666
+ }
23667
+ if (this.options.isVerbose) {
23668
+ console.info('[🤰]', 'Created vector store file batch', {
23669
+ vectorStoreId,
23670
+ batchId: expectedBatchId,
23671
+ fileCount: fileIds.length,
23672
+ logLabel,
23673
+ });
23674
+ }
23675
+ const pollStartedAtMs = Date.now();
23676
+ const progressLogIntervalMs = Math.max(VECTOR_STORE_PROGRESS_LOG_INTERVAL_MIN_MS, pollIntervalMs);
23677
+ const diagnosticsIntervalMs = Math.max(60000, pollIntervalMs * 5);
23678
+ // let lastStatus: string | undefined;
23679
+ let lastCountsKey = '';
23680
+ let lastProgressKey = '';
23681
+ let lastLogAtMs = 0;
23682
+ let lastProgressAtMs = pollStartedAtMs;
23683
+ let lastDiagnosticsAtMs = pollStartedAtMs;
23684
+ let latestBatch = batch;
23685
+ let loggedBatchIdMismatch = false;
23686
+ let loggedBatchIdFallback = false;
23687
+ let loggedBatchIdInvalid = false;
23688
+ let shouldPoll = true;
23689
+ while (shouldPoll) {
23690
+ const nowMs = Date.now();
23691
+ // [🤰] Note: Sometimes OpenAI returns Vector Store object instead of Batch object, or IDs get swapped.
23692
+ const rawBatchId = typeof latestBatch.id === 'string' ? latestBatch.id : '';
23693
+ const rawVectorStoreId = latestBatch.vector_store_id;
23694
+ let returnedBatchId = rawBatchId;
23695
+ let returnedBatchIdValid = typeof returnedBatchId === 'string' && returnedBatchId.startsWith('vsfb_');
23696
+ if (!returnedBatchIdValid && expectedBatchIdValid) {
23697
+ if (!loggedBatchIdFallback) {
23698
+ console.error('[🤰]', 'Vector store file batch id missing from response; falling back to expected', {
23699
+ vectorStoreId,
23700
+ expectedBatchId,
23701
+ returnedBatchId,
23702
+ rawVectorStoreId,
23703
+ logLabel,
23704
+ });
23705
+ loggedBatchIdFallback = true;
23706
+ }
23707
+ returnedBatchId = expectedBatchId;
23708
+ returnedBatchIdValid = true;
23709
+ }
23710
+ if (!returnedBatchIdValid && !loggedBatchIdInvalid) {
23711
+ console.error('[🤰]', 'Vector store file batch id is invalid; stopping polling', {
23712
+ vectorStoreId,
23713
+ expectedBatchId,
23714
+ returnedBatchId,
23715
+ rawVectorStoreId,
23716
+ logLabel,
23717
+ });
23718
+ loggedBatchIdInvalid = true;
23719
+ }
23720
+ const batchIdMismatch = expectedBatchIdValid && returnedBatchIdValid && returnedBatchId !== expectedBatchId;
23721
+ if (batchIdMismatch && !loggedBatchIdMismatch) {
23722
+ console.error('[🤰]', 'Vector store file batch id mismatch', {
23723
+ vectorStoreId,
23724
+ expectedBatchId,
23725
+ returnedBatchId,
23726
+ logLabel,
23727
+ });
23728
+ loggedBatchIdMismatch = true;
23729
+ }
23730
+ if (returnedBatchIdValid) {
23731
+ latestBatch = await vectorStores.fileBatches.retrieve(returnedBatchId, {
23732
+ vector_store_id: vectorStoreId,
23733
+ });
23734
+ }
23735
+ else {
23736
+ shouldPoll = false;
23737
+ continue;
23738
+ }
23739
+ const status = (_e = latestBatch.status) !== null && _e !== void 0 ? _e : 'unknown';
23740
+ const fileCounts = (_f = latestBatch.file_counts) !== null && _f !== void 0 ? _f : {};
23741
+ const progressKey = JSON.stringify(fileCounts);
23742
+ const statusCountsKey = `${status}-${progressKey}`;
23743
+ const isProgressing = progressKey !== lastProgressKey;
23744
+ if (isProgressing) {
23745
+ lastProgressAtMs = nowMs;
23746
+ lastProgressKey = progressKey;
23747
+ }
23748
+ if (this.options.isVerbose &&
23749
+ (statusCountsKey !== lastCountsKey || nowMs - lastLogAtMs >= progressLogIntervalMs)) {
23750
+ console.info('[🤰]', 'Vector store file batch status', {
23751
+ vectorStoreId,
23752
+ batchId: returnedBatchId,
23753
+ status,
23754
+ fileCounts,
23755
+ elapsedMs: nowMs - pollStartedAtMs,
23756
+ logLabel,
23757
+ });
23758
+ lastCountsKey = statusCountsKey;
23759
+ lastLogAtMs = nowMs;
23760
+ }
23761
+ if (status === 'in_progress' &&
23762
+ nowMs - lastProgressAtMs >= VECTOR_STORE_STALL_LOG_THRESHOLD_MS &&
23763
+ nowMs - lastDiagnosticsAtMs >= diagnosticsIntervalMs) {
23764
+ lastDiagnosticsAtMs = nowMs;
23765
+ await this.logVectorStoreFileBatchDiagnostics({
23766
+ client,
23767
+ vectorStoreId,
23768
+ batchId: returnedBatchId,
23769
+ uploadedFiles,
23770
+ logLabel,
23771
+ reason: 'stalled',
23772
+ });
23773
+ }
23774
+ if (status === 'completed') {
23775
+ if (this.options.isVerbose) {
23776
+ console.info('[🤰]', 'Vector store file batch completed', {
23777
+ vectorStoreId,
23778
+ batchId: returnedBatchId,
23779
+ fileCounts,
23780
+ elapsedMs: nowMs - pollStartedAtMs,
23781
+ logLabel,
23782
+ });
23783
+ }
23784
+ shouldPoll = false;
23785
+ continue;
23786
+ }
23787
+ if (status === 'failed') {
23788
+ console.error('[🤰]', 'Vector store file batch completed with failures', {
23789
+ vectorStoreId,
23790
+ batchId: returnedBatchId,
23791
+ fileCounts,
23792
+ elapsedMs: nowMs - pollStartedAtMs,
23793
+ logLabel,
23794
+ });
23795
+ await this.logVectorStoreFileBatchDiagnostics({
23796
+ client,
23797
+ vectorStoreId,
23798
+ batchId: returnedBatchId,
23799
+ uploadedFiles,
23800
+ logLabel,
23801
+ reason: 'failed',
23802
+ });
23803
+ shouldPoll = false;
23804
+ continue;
23805
+ }
23806
+ if (status === 'cancelled') {
23807
+ console.error('[🤰]', 'Vector store file batch did not complete', {
23808
+ vectorStoreId,
23809
+ batchId: returnedBatchId,
23810
+ status,
23811
+ fileCounts,
23812
+ elapsedMs: nowMs - pollStartedAtMs,
23813
+ logLabel,
23814
+ });
23815
+ await this.logVectorStoreFileBatchDiagnostics({
23816
+ client,
23817
+ vectorStoreId,
23818
+ batchId: returnedBatchId,
23819
+ uploadedFiles,
23820
+ logLabel,
23821
+ reason: 'failed',
23822
+ });
23823
+ shouldPoll = false;
23824
+ continue;
23825
+ }
23826
+ if (nowMs - pollStartedAtMs >= uploadTimeoutMs) {
23827
+ console.error('[🤰]', 'Timed out waiting for vector store file batch', {
23828
+ vectorStoreId,
23829
+ batchId: returnedBatchId,
23830
+ fileCounts,
23831
+ elapsedMs: nowMs - pollStartedAtMs,
23832
+ uploadTimeoutMs,
23833
+ logLabel,
23834
+ });
23835
+ await this.logVectorStoreFileBatchDiagnostics({
23836
+ client,
23837
+ vectorStoreId,
23838
+ batchId: returnedBatchId,
23839
+ uploadedFiles,
23840
+ logLabel,
23841
+ reason: 'timeout',
23842
+ });
23843
+ if (this.shouldContinueOnVectorStoreStall()) {
23844
+ console.warn('[🤰]', 'Continuing despite vector store timeout as requested', {
23845
+ vectorStoreId,
23846
+ logLabel,
23847
+ });
23848
+ shouldPoll = false;
23849
+ continue;
23850
+ }
23851
+ try {
23852
+ const cancelBatchId = batchIdMismatch && returnedBatchId.startsWith('vsfb_') ? returnedBatchId : expectedBatchId;
23853
+ if (!cancelBatchId.startsWith('vsfb_')) {
23854
+ console.error('[🤰]', 'Skipping vector store file batch cancel (invalid batch id)', {
23855
+ vectorStoreId,
23856
+ batchId: cancelBatchId,
23857
+ logLabel,
23858
+ });
23859
+ }
23860
+ else {
23861
+ await vectorStores.fileBatches.cancel(cancelBatchId, {
23862
+ vector_store_id: vectorStoreId,
23863
+ });
23864
+ }
23865
+ if (this.options.isVerbose) {
23866
+ console.info('[🤰]', 'Cancelled vector store file batch after timeout', {
23867
+ vectorStoreId,
23868
+ batchId: batchIdMismatch && returnedBatchId.startsWith('vsfb_')
23869
+ ? returnedBatchId
23870
+ : expectedBatchId,
23871
+ ...(batchIdMismatch ? { returnedBatchId } : {}),
23872
+ logLabel,
23873
+ });
23874
+ }
23875
+ }
23876
+ catch (error) {
23877
+ assertsError(error);
23878
+ console.error('[🤰]', 'Failed to cancel vector store file batch after timeout', {
23879
+ vectorStoreId,
23880
+ batchId: expectedBatchId,
23881
+ ...(batchIdMismatch ? { returnedBatchId } : {}),
23882
+ logLabel,
23883
+ error: serializeError(error),
23884
+ });
23885
+ }
23886
+ shouldPoll = false;
23887
+ continue;
23888
+ }
23889
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
23890
+ }
23891
+ return latestBatch;
23892
+ }
23893
+ /**
23894
+ * Creates a vector store and uploads knowledge sources, returning its ID.
23895
+ */
23896
+ async createVectorStoreWithKnowledgeSources(options) {
23897
+ const { client, name, knowledgeSources, logLabel } = options;
23898
+ const vectorStores = this.getVectorStoresApi(client);
23899
+ const knowledgeSourcesCount = knowledgeSources.length;
23900
+ const downloadTimeoutMs = this.getKnowledgeSourceDownloadTimeoutMs();
23901
+ if (this.options.isVerbose) {
23902
+ console.info('[🤰]', 'Creating vector store with knowledge sources', {
23903
+ name,
23904
+ knowledgeSourcesCount,
23905
+ downloadTimeoutMs,
23906
+ logLabel,
23907
+ });
23908
+ }
23909
+ const vectorStore = await vectorStores.create({
23910
+ name: `${name} Knowledge Base`,
23911
+ });
23912
+ const vectorStoreId = vectorStore.id;
23913
+ if (this.options.isVerbose) {
23914
+ console.info('[🤰]', 'Vector store created', {
23915
+ vectorStoreId,
23916
+ logLabel,
23917
+ });
23918
+ }
23919
+ const fileStreams = [];
23920
+ const skippedSources = [];
23921
+ let totalBytes = 0;
23922
+ const processingStartedAtMs = Date.now();
23923
+ for (const [index, source] of knowledgeSources.entries()) {
23924
+ try {
23925
+ const sourceType = source.startsWith('http') || source.startsWith('https') ? 'url' : 'file';
23926
+ if (this.options.isVerbose) {
23927
+ console.info('[🤰]', 'Processing knowledge source', {
23928
+ index: index + 1,
23929
+ total: knowledgeSourcesCount,
23930
+ source,
23931
+ sourceType,
23932
+ logLabel,
23933
+ });
23934
+ }
23935
+ // Check if it's a URL
23936
+ if (source.startsWith('http://') || source.startsWith('https://')) {
23937
+ const downloadResult = await this.downloadKnowledgeSourceFile({
23938
+ source,
23939
+ timeoutMs: downloadTimeoutMs,
23940
+ logLabel,
23941
+ });
23942
+ if (downloadResult) {
23943
+ fileStreams.push(downloadResult.file);
23944
+ totalBytes += downloadResult.sizeBytes;
23945
+ }
23946
+ else {
23947
+ skippedSources.push({ source, reason: 'download_failed' });
23948
+ }
23949
+ }
23950
+ else {
23951
+ skippedSources.push({ source, reason: 'unsupported_source_type' });
23952
+ if (this.options.isVerbose) {
23953
+ console.info('[🤰]', 'Skipping knowledge source (unsupported type)', {
23954
+ source,
23955
+ sourceType,
23956
+ logLabel,
23957
+ });
23958
+ }
23959
+ /*
23960
+ TODO: [🤰] Resolve problem with browser environment
23961
+ // Assume it's a local file path
23962
+ // Note: This will work in Node.js environment
23963
+ // For browser environments, this would need different handling
23964
+ const fs = await import('fs');
23965
+ const fileStream = fs.createReadStream(source);
23966
+ fileStreams.push(fileStream);
23967
+ */
23968
+ }
23969
+ }
23970
+ catch (error) {
23971
+ assertsError(error);
23972
+ skippedSources.push({ source, reason: 'processing_error' });
23973
+ console.error('[🤰]', 'Error processing knowledge source', {
23974
+ source,
23975
+ logLabel,
23976
+ error: serializeError(error),
23977
+ });
23978
+ }
23979
+ }
23980
+ if (this.options.isVerbose) {
23981
+ console.info('[🤰]', 'Finished processing knowledge sources', {
23982
+ total: knowledgeSourcesCount,
23983
+ downloadedCount: fileStreams.length,
23984
+ skippedCount: skippedSources.length,
23985
+ totalBytes,
23986
+ elapsedMs: Date.now() - processingStartedAtMs,
23987
+ skippedSamples: skippedSources.slice(0, 3),
23988
+ logLabel,
23989
+ });
23990
+ }
23991
+ if (fileStreams.length > 0) {
23992
+ if (this.options.isVerbose) {
23993
+ console.info('[🤰]', 'Uploading files to vector store', {
23994
+ vectorStoreId,
23995
+ fileCount: fileStreams.length,
23996
+ totalBytes,
23997
+ maxConcurrency: this.getKnowledgeSourceUploadMaxConcurrency(),
23998
+ pollIntervalMs: this.getKnowledgeSourceUploadPollIntervalMs(),
23999
+ uploadTimeoutMs: this.getKnowledgeSourceUploadTimeoutMs(),
24000
+ logLabel,
24001
+ });
24002
+ }
24003
+ try {
24004
+ await this.uploadKnowledgeSourceFilesToVectorStore({
24005
+ client,
24006
+ vectorStoreId,
24007
+ files: fileStreams,
24008
+ totalBytes,
24009
+ logLabel,
24010
+ });
24011
+ }
24012
+ catch (error) {
24013
+ assertsError(error);
24014
+ console.error('[🤰]', 'Error uploading files to vector store', {
24015
+ vectorStoreId,
24016
+ logLabel,
24017
+ error: serializeError(error),
24018
+ });
24019
+ }
24020
+ }
24021
+ else if (this.options.isVerbose) {
24022
+ console.info('[🤰]', 'No knowledge source files to upload', {
24023
+ vectorStoreId,
24024
+ skippedCount: skippedSources.length,
24025
+ logLabel,
24026
+ });
24027
+ }
24028
+ return {
24029
+ vectorStoreId,
24030
+ uploadedFileCount: fileStreams.length,
24031
+ skippedCount: skippedSources.length,
24032
+ totalBytes,
24033
+ };
24034
+ }
24035
+ }
24036
+
24037
+ const DEFAULT_AGENT_KIT_MODEL_NAME = 'gpt-5.2';
24038
+ /**
24039
+ * Execution tools for OpenAI AgentKit (Agents SDK).
24040
+ *
24041
+ * @public exported from `@promptbook/openai`
24042
+ */
24043
+ class OpenAiAgentKitExecutionTools extends OpenAiVectorStoreHandler {
24044
+ /**
24045
+ * Creates OpenAI AgentKit execution tools.
24046
+ */
24047
+ constructor(options) {
24048
+ var _a;
24049
+ if (options.isProxied) {
24050
+ throw new NotYetImplementedError(`Proxy mode is not yet implemented for OpenAI AgentKit`);
24051
+ }
24052
+ super(options);
24053
+ this.preparedAgentKitAgent = null;
24054
+ this.agentKitModelName = (_a = options.agentKitModelName) !== null && _a !== void 0 ? _a : DEFAULT_AGENT_KIT_MODEL_NAME;
24055
+ }
24056
+ get title() {
24057
+ return 'OpenAI AgentKit';
24058
+ }
24059
+ get description() {
24060
+ return 'Use OpenAI AgentKit for agent-style chat with tools and knowledge';
24061
+ }
24062
+ /**
24063
+ * Calls OpenAI AgentKit with a chat prompt (non-streaming).
24064
+ */
24065
+ async callChatModel(prompt) {
24066
+ return this.callChatModelStream(prompt, () => { });
24067
+ }
24068
+ /**
24069
+ * Calls OpenAI AgentKit with a chat prompt (streaming).
24070
+ */
24071
+ async callChatModelStream(prompt, onProgress) {
24072
+ const { content, parameters, modelRequirements } = prompt;
24073
+ if (modelRequirements.modelVariant !== 'CHAT') {
24074
+ throw new PipelineExecutionError('Use callChatModel only for CHAT variant');
24075
+ }
24076
+ for (const key of ['maxTokens', 'modelName', 'seed', 'temperature']) {
24077
+ if (modelRequirements[key] !== undefined) {
24078
+ throw new NotYetImplementedError(`In \`OpenAiAgentKitExecutionTools\` you cannot specify \`${key}\``);
24079
+ }
24080
+ }
24081
+ const rawPromptContent = templateParameters(content, {
24082
+ ...parameters,
24083
+ modelName: this.agentKitModelName,
24084
+ });
24085
+ const preparedAgentKitAgent = await this.prepareAgentKitAgent({
24086
+ name: (prompt.title || 'Agent'),
24087
+ instructions: modelRequirements.systemMessage || '',
24088
+ knowledgeSources: modelRequirements.knowledgeSources,
24089
+ tools: 'tools' in prompt && Array.isArray(prompt.tools) ? prompt.tools : modelRequirements.tools,
24090
+ });
24091
+ return this.callChatModelStreamWithPreparedAgent({
24092
+ openAiAgentKitAgent: preparedAgentKitAgent.agent,
24093
+ prompt,
24094
+ rawPromptContent,
24095
+ onProgress,
24096
+ });
24097
+ }
24098
+ /**
24099
+ * Returns a prepared AgentKit agent when the server wants to manage caching externally.
24100
+ */
24101
+ getPreparedAgentKitAgent() {
24102
+ return this.preparedAgentKitAgent;
24103
+ }
24104
+ /**
24105
+ * Stores a prepared AgentKit agent for later reuse by external cache managers.
24106
+ */
24107
+ setPreparedAgentKitAgent(preparedAgent) {
24108
+ this.preparedAgentKitAgent = preparedAgent;
24109
+ }
24110
+ /**
24111
+ * Creates a new tools instance bound to a prepared AgentKit agent.
24112
+ */
24113
+ getPreparedAgentTools(preparedAgent) {
24114
+ const tools = new OpenAiAgentKitExecutionTools(this.agentKitOptions);
24115
+ tools.setPreparedAgentKitAgent(preparedAgent);
24116
+ return tools;
24117
+ }
24118
+ /**
24119
+ * Prepares an AgentKit agent with optional knowledge sources and tool definitions.
24120
+ */
24121
+ async prepareAgentKitAgent(options) {
24122
+ var _a, _b;
24123
+ const { name, instructions, knowledgeSources, tools, vectorStoreId: cachedVectorStoreId, storeAsPrepared, } = options;
24124
+ await this.ensureAgentKitDefaults();
24125
+ if (this.options.isVerbose) {
24126
+ console.info('[🤰]', 'Preparing OpenAI AgentKit agent', {
24127
+ name,
24128
+ instructionsLength: instructions.length,
24129
+ knowledgeSourcesCount: (_a = knowledgeSources === null || knowledgeSources === void 0 ? void 0 : knowledgeSources.length) !== null && _a !== void 0 ? _a : 0,
24130
+ toolsCount: (_b = tools === null || tools === void 0 ? void 0 : tools.length) !== null && _b !== void 0 ? _b : 0,
24131
+ });
24132
+ }
24133
+ let vectorStoreId = cachedVectorStoreId;
24134
+ if (!vectorStoreId && knowledgeSources && knowledgeSources.length > 0) {
24135
+ const vectorStoreResult = await this.createVectorStoreWithKnowledgeSources({
24136
+ client: await this.getClient(),
24137
+ name,
24138
+ knowledgeSources,
24139
+ logLabel: 'agentkit preparation',
24140
+ });
24141
+ vectorStoreId = vectorStoreResult.vectorStoreId;
24142
+ }
24143
+ else if (vectorStoreId && this.options.isVerbose) {
24144
+ console.info('[🤰]', 'Using cached vector store for AgentKit agent', {
24145
+ name,
24146
+ vectorStoreId,
24147
+ });
24148
+ }
24149
+ const agentKitTools = this.buildAgentKitTools({ tools, vectorStoreId });
24150
+ const openAiAgentKitAgent = new Agent$1({
24151
+ name,
24152
+ model: this.agentKitModelName,
24153
+ instructions: instructions || 'You are a helpful assistant.',
24154
+ tools: agentKitTools,
24155
+ });
24156
+ const preparedAgent = {
24157
+ agent: openAiAgentKitAgent,
24158
+ vectorStoreId,
24159
+ };
24160
+ if (storeAsPrepared) {
24161
+ this.setPreparedAgentKitAgent(preparedAgent);
24162
+ }
24163
+ if (this.options.isVerbose) {
24164
+ console.info('[🤰]', 'OpenAI AgentKit agent ready', {
24165
+ name,
24166
+ model: this.agentKitModelName,
24167
+ toolCount: agentKitTools.length,
24168
+ hasVectorStore: Boolean(vectorStoreId),
24169
+ });
24170
+ }
24171
+ return preparedAgent;
24172
+ }
24173
+ /**
24174
+ * Ensures the AgentKit SDK is wired to the OpenAI client and API key.
24175
+ */
24176
+ async ensureAgentKitDefaults() {
24177
+ const client = await this.getClient();
24178
+ setDefaultOpenAIClient(client);
24179
+ const apiKey = this.agentKitOptions.apiKey;
24180
+ if (apiKey && typeof apiKey === 'string') {
24181
+ setDefaultOpenAIKey(apiKey);
24182
+ }
24183
+ }
24184
+ /**
24185
+ * Builds the tool list for AgentKit, including hosted file search when applicable.
24186
+ */
24187
+ buildAgentKitTools(options) {
24188
+ var _a;
24189
+ const { tools, vectorStoreId } = options;
24190
+ const agentKitTools = [];
24191
+ if (vectorStoreId) {
24192
+ agentKitTools.push(fileSearchTool(vectorStoreId));
24193
+ }
24194
+ if (tools && tools.length > 0) {
24195
+ const scriptTools = this.resolveScriptTools();
24196
+ for (const toolDefinition of tools) {
24197
+ agentKitTools.push(tool({
24198
+ name: toolDefinition.name,
24199
+ description: toolDefinition.description,
24200
+ parameters: toolDefinition.parameters
24201
+ ? {
24202
+ ...toolDefinition.parameters,
24203
+ additionalProperties: false,
24204
+ required: (_a = toolDefinition.parameters.required) !== null && _a !== void 0 ? _a : [],
24205
+ }
24206
+ : undefined,
24207
+ strict: false,
24208
+ execute: async (input, runContext, details) => {
24209
+ var _a, _b, _c;
24210
+ const scriptTool = scriptTools[0];
24211
+ const functionName = toolDefinition.name;
24212
+ const calledAt = $getCurrentDate();
24213
+ const callId = (_a = details === null || details === void 0 ? void 0 : details.toolCall) === null || _a === void 0 ? void 0 : _a.callId;
24214
+ const functionArgs = input !== null && input !== void 0 ? input : {};
24215
+ if (this.options.isVerbose) {
24216
+ console.info('[🤰]', 'Executing AgentKit tool', {
24217
+ functionName,
24218
+ callId,
24219
+ calledAt,
24220
+ });
24221
+ }
24222
+ try {
24223
+ return await scriptTool.execute({
24224
+ scriptLanguage: 'javascript',
24225
+ script: `
24226
+ const args = ${JSON.stringify(functionArgs)};
24227
+ return await ${functionName}(args);
24228
+ `,
24229
+ parameters: (_c = (_b = runContext === null || runContext === void 0 ? void 0 : runContext.context) === null || _b === void 0 ? void 0 : _b.parameters) !== null && _c !== void 0 ? _c : {},
24230
+ });
24231
+ }
24232
+ catch (error) {
24233
+ assertsError(error);
24234
+ const serializedError = serializeError(error);
24235
+ const errorMessage = spaceTrim$2((block) => `
24236
+
24237
+ The invoked tool \`${functionName}\` failed with error:
24238
+
24239
+ \`\`\`json
24240
+ ${block(JSON.stringify(serializedError, null, 4))}
24241
+ \`\`\`
24242
+
24243
+ `);
24244
+ console.error('[🤰]', 'AgentKit tool execution failed', {
24245
+ functionName,
24246
+ callId,
24247
+ error: serializedError,
24248
+ });
24249
+ return errorMessage;
24250
+ }
24251
+ },
24252
+ }));
24253
+ }
24254
+ }
24255
+ return agentKitTools;
24256
+ }
24257
+ /**
24258
+ * Resolves the configured script tools for tool execution.
23299
24259
  */
23300
- getDefaultImageGenerationModel() {
23301
- return this.getDefaultModel('dall-e-3');
23302
- }
23303
- }
23304
-
23305
- /**
23306
- * Execution Tools for calling OpenAI API using the Responses API (Agents)
23307
- *
23308
- * @public exported from `@promptbook/openai`
23309
- */
23310
- class OpenAiAgentExecutionTools extends OpenAiExecutionTools {
23311
- constructor(options) {
23312
- super(options);
23313
- this.vectorStoreId = options.vectorStoreId;
23314
- }
23315
- get title() {
23316
- return 'OpenAI Agent';
23317
- }
23318
- get description() {
23319
- return 'Use OpenAI Responses API (Agentic)';
24260
+ resolveScriptTools() {
24261
+ const executionTools = this.options.executionTools;
24262
+ if (!executionTools || !executionTools.script) {
24263
+ throw new PipelineExecutionError(`Model requested tools but no executionTools.script were provided in OpenAiAgentKitExecutionTools options`);
24264
+ }
24265
+ return Array.isArray(executionTools.script) ? executionTools.script : [executionTools.script];
23320
24266
  }
23321
24267
  /**
23322
- * Calls OpenAI API to use a chat model with streaming.
24268
+ * Runs a prepared AgentKit agent and streams results back to the caller.
23323
24269
  */
23324
- async callChatModelStream(prompt, onProgress) {
23325
- if (this.options.isVerbose) {
23326
- console.info('💬 OpenAI Agent callChatModel call', { prompt });
23327
- }
23328
- const { content, parameters, modelRequirements } = prompt;
23329
- const client = await this.getClient();
23330
- if (modelRequirements.modelVariant !== 'CHAT') {
23331
- throw new PipelineExecutionError('Use callChatModel only for CHAT variant');
23332
- }
23333
- const rawPromptContent = templateParameters(content, {
23334
- ...parameters,
23335
- modelName: 'agent',
23336
- });
23337
- // Build input items
23338
- const input = []; // TODO: Type properly when OpenAI types are updated
23339
- // Add previous messages from thread (if any)
23340
- if ('thread' in prompt && Array.isArray(prompt.thread)) {
23341
- const previousMessages = prompt.thread.map((msg) => ({
23342
- role: msg.sender === 'assistant' ? 'assistant' : 'user',
23343
- content: msg.content,
23344
- }));
23345
- input.push(...previousMessages);
23346
- }
23347
- // Add current user message
23348
- input.push({
23349
- role: 'user',
23350
- content: rawPromptContent,
24270
+ async callChatModelStreamWithPreparedAgent(options) {
24271
+ var _a, _b, _c, _d;
24272
+ const { openAiAgentKitAgent, prompt, onProgress } = options;
24273
+ const rawPromptContent = (_a = options.rawPromptContent) !== null && _a !== void 0 ? _a : templateParameters(prompt.content, {
24274
+ ...prompt.parameters,
24275
+ modelName: this.agentKitModelName,
23351
24276
  });
23352
- // Prepare tools
23353
- const tools = modelRequirements.tools ? mapToolsToOpenAi(modelRequirements.tools) : undefined;
23354
- // Add file_search if vector store is present
23355
- const agentTools = tools ? [...tools] : [];
23356
- let toolResources = undefined;
23357
- if (this.vectorStoreId) {
23358
- agentTools.push({ type: 'file_search' });
23359
- toolResources = {
23360
- file_search: {
23361
- vector_store_ids: [this.vectorStoreId],
23362
- },
23363
- };
23364
- }
23365
- // Add file_search also if knowledgeSources are present in the prompt (passed via AgentLlmExecutionTools)
23366
- if (modelRequirements.knowledgeSources &&
23367
- modelRequirements.knowledgeSources.length > 0 &&
23368
- !this.vectorStoreId) {
23369
- // Note: Vector store should have been created by AgentLlmExecutionTools and passed via options.
23370
- // If we are here, it means we have knowledge sources but no vector store ID.
23371
- // We can't easily create one here without persisting it.
23372
- console.warn('Knowledge sources provided but no vector store ID. Creating temporary vector store is not implemented in callChatModelStream.');
23373
- }
23374
24277
  const start = $getCurrentDate();
23375
- // Construct the request
24278
+ let latestContent = '';
24279
+ const toolCalls = [];
24280
+ const toolCallIndexById = new Map();
24281
+ const inputItems = await this.buildAgentKitInputItems(prompt, rawPromptContent);
23376
24282
  const rawRequest = {
23377
- // TODO: Type properly as OpenAI.Responses.CreateResponseParams
23378
- model: modelRequirements.modelName || 'gpt-4o',
23379
- input,
23380
- instructions: modelRequirements.systemMessage,
23381
- tools: agentTools.length > 0 ? agentTools : undefined,
23382
- tool_resources: toolResources,
23383
- store: false, // Stateless by default as we pass full history
24283
+ agentName: openAiAgentKitAgent.name,
24284
+ input: inputItems,
23384
24285
  };
23385
- if (this.options.isVerbose) {
23386
- console.info(colors.bgWhite('rawRequest (Responses API)'), JSON.stringify(rawRequest, null, 4));
23387
- }
23388
- // Call Responses API
23389
- // Note: Using any cast because types might not be updated yet
23390
- const response = await client.responses.create(rawRequest);
23391
- if (this.options.isVerbose) {
23392
- console.info(colors.bgWhite('rawResponse'), JSON.stringify(response, null, 4));
23393
- }
23394
- const complete = $getCurrentDate();
23395
- let resultContent = '';
23396
- const toolCalls = [];
23397
- // Parse output items
23398
- if (response.output) {
23399
- for (const item of response.output) {
23400
- if (item.type === 'message' && item.role === 'assistant') {
23401
- for (const contentPart of item.content) {
23402
- if (contentPart.type === 'output_text') {
23403
- // "output_text" based on migration guide, or "text"? Guide says "output_text" in example.
23404
- resultContent += contentPart.text;
23405
- }
23406
- else if (contentPart.type === 'text') {
23407
- resultContent += contentPart.text.value || contentPart.text;
23408
- }
24286
+ const streamResult = await run(openAiAgentKitAgent, inputItems, {
24287
+ stream: true,
24288
+ context: { parameters: prompt.parameters },
24289
+ });
24290
+ for await (const event of streamResult) {
24291
+ if (event.type === 'raw_model_stream_event' && ((_b = event.data) === null || _b === void 0 ? void 0 : _b.type) === 'output_text_delta') {
24292
+ latestContent += event.data.delta;
24293
+ onProgress({
24294
+ content: latestContent,
24295
+ modelName: this.agentKitModelName,
24296
+ timing: { start, complete: $getCurrentDate() },
24297
+ usage: UNCERTAIN_USAGE,
24298
+ rawPromptContent: rawPromptContent,
24299
+ rawRequest: null,
24300
+ rawResponse: {},
24301
+ });
24302
+ continue;
24303
+ }
24304
+ if (event.type === 'run_item_stream_event') {
24305
+ const rawItem = (_c = event.item) === null || _c === void 0 ? void 0 : _c.rawItem;
24306
+ if (event.name === 'tool_called' && (rawItem === null || rawItem === void 0 ? void 0 : rawItem.type) === 'function_call') {
24307
+ const toolCall = {
24308
+ name: rawItem.name,
24309
+ arguments: rawItem.arguments,
24310
+ rawToolCall: rawItem,
24311
+ createdAt: $getCurrentDate(),
24312
+ };
24313
+ toolCallIndexById.set(rawItem.callId, toolCalls.length);
24314
+ toolCalls.push(toolCall);
24315
+ onProgress({
24316
+ content: latestContent,
24317
+ modelName: this.agentKitModelName,
24318
+ timing: { start, complete: $getCurrentDate() },
24319
+ usage: UNCERTAIN_USAGE,
24320
+ rawPromptContent: rawPromptContent,
24321
+ rawRequest: null,
24322
+ rawResponse: {},
24323
+ toolCalls: [toolCall],
24324
+ });
24325
+ }
24326
+ if (event.name === 'tool_output' && (rawItem === null || rawItem === void 0 ? void 0 : rawItem.type) === 'function_call_result') {
24327
+ const index = toolCallIndexById.get(rawItem.callId);
24328
+ const result = this.formatAgentKitToolOutput(rawItem.output);
24329
+ if (index !== undefined) {
24330
+ const existingToolCall = toolCalls[index];
24331
+ const completedToolCall = {
24332
+ ...existingToolCall,
24333
+ result,
24334
+ rawToolCall: rawItem,
24335
+ };
24336
+ toolCalls[index] = completedToolCall;
24337
+ onProgress({
24338
+ content: latestContent,
24339
+ modelName: this.agentKitModelName,
24340
+ timing: { start, complete: $getCurrentDate() },
24341
+ usage: UNCERTAIN_USAGE,
24342
+ rawPromptContent: rawPromptContent,
24343
+ rawRequest: null,
24344
+ rawResponse: {},
24345
+ toolCalls: [completedToolCall],
24346
+ });
23409
24347
  }
23410
24348
  }
23411
- else if (item.type === 'function_call') ;
23412
24349
  }
23413
24350
  }
23414
- // Use output_text helper if available (mentioned in guide)
23415
- if (response.output_text) {
23416
- resultContent = response.output_text;
23417
- }
23418
- // TODO: Handle tool calls properly (Requires clearer docs or experimentation)
23419
- onProgress({
23420
- content: resultContent,
23421
- modelName: response.model || 'agent',
24351
+ await streamResult.completed;
24352
+ const complete = $getCurrentDate();
24353
+ const finalContent = ((_d = streamResult.finalOutput) !== null && _d !== void 0 ? _d : latestContent);
24354
+ const finalResult = {
24355
+ content: finalContent,
24356
+ modelName: this.agentKitModelName,
23422
24357
  timing: { start, complete },
23423
24358
  usage: UNCERTAIN_USAGE,
23424
- rawPromptContent,
24359
+ rawPromptContent: rawPromptContent,
23425
24360
  rawRequest,
23426
- rawResponse: response,
23427
- });
23428
- return exportJson({
23429
- name: 'promptResult',
23430
- message: `Result of \`OpenAiAgentExecutionTools.callChatModelStream\``,
23431
- order: [],
23432
- value: {
23433
- content: resultContent,
23434
- modelName: response.model || 'agent',
23435
- timing: { start, complete },
23436
- usage: UNCERTAIN_USAGE,
23437
- rawPromptContent,
23438
- rawRequest,
23439
- rawResponse: response,
23440
- toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
23441
- },
23442
- });
24361
+ rawResponse: { runResult: streamResult },
24362
+ toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
24363
+ };
24364
+ onProgress(finalResult);
24365
+ return finalResult;
23443
24366
  }
23444
24367
  /**
23445
- * Creates a vector store from knowledge sources
24368
+ * Builds AgentKit input items from the prompt and optional thread.
23446
24369
  */
23447
- static async createVectorStore(client, name, knowledgeSources) {
23448
- // Create a vector store
23449
- const vectorStore = await client.beta.vectorStores.create({
23450
- name: `${name} Knowledge Base`,
23451
- });
23452
- const vectorStoreId = vectorStore.id;
23453
- // Upload files from knowledge sources to the vector store
23454
- const fileStreams = [];
23455
- for (const source of knowledgeSources) {
23456
- try {
23457
- // Check if it's a URL
23458
- if (source.startsWith('http://') || source.startsWith('https://')) {
23459
- // Download the file
23460
- const response = await fetch(source);
23461
- if (!response.ok) {
23462
- console.error(`Failed to download ${source}: ${response.statusText}`);
23463
- continue;
23464
- }
23465
- const buffer = await response.arrayBuffer();
23466
- const filename = source.split('/').pop() || 'downloaded-file';
23467
- const blob = new Blob([buffer]);
23468
- const file = new File([blob], filename);
23469
- fileStreams.push(file);
24370
+ async buildAgentKitInputItems(prompt, rawPromptContent) {
24371
+ var _a;
24372
+ const inputItems = [];
24373
+ if ('thread' in prompt && Array.isArray(prompt.thread)) {
24374
+ for (const message of prompt.thread) {
24375
+ const sender = message.sender;
24376
+ const content = (_a = message.content) !== null && _a !== void 0 ? _a : '';
24377
+ if (sender === 'assistant' || sender === 'agent') {
24378
+ inputItems.push({
24379
+ role: 'assistant',
24380
+ status: 'completed',
24381
+ content: [{ type: 'output_text', text: content }],
24382
+ });
23470
24383
  }
23471
24384
  else {
23472
- // Local files not supported in browser env easily, same as before
24385
+ inputItems.push({
24386
+ role: 'user',
24387
+ content,
24388
+ });
23473
24389
  }
23474
24390
  }
23475
- catch (error) {
23476
- console.error(`Error processing knowledge source ${source}:`, error);
23477
- }
23478
24391
  }
23479
- // Batch upload files to the vector store
23480
- if (fileStreams.length > 0) {
23481
- try {
23482
- await client.beta.vectorStores.fileBatches.uploadAndPoll(vectorStoreId, {
23483
- files: fileStreams,
23484
- });
23485
- }
23486
- catch (error) {
23487
- console.error('Error uploading files to vector store:', error);
24392
+ const userContent = await this.buildAgentKitUserContent(prompt, rawPromptContent);
24393
+ inputItems.push({
24394
+ role: 'user',
24395
+ content: userContent,
24396
+ });
24397
+ return inputItems;
24398
+ }
24399
+ /**
24400
+ * Builds the user message content for AgentKit runs, including file inputs when provided.
24401
+ */
24402
+ async buildAgentKitUserContent(prompt, rawPromptContent) {
24403
+ if ('files' in prompt && Array.isArray(prompt.files) && prompt.files.length > 0) {
24404
+ const fileItems = await Promise.all(prompt.files.map(async (file) => {
24405
+ const arrayBuffer = await file.arrayBuffer();
24406
+ const base64 = Buffer.from(arrayBuffer).toString('base64');
24407
+ return {
24408
+ type: 'input_image',
24409
+ image: `data:${file.type};base64,${base64}`,
24410
+ };
24411
+ }));
24412
+ return [{ type: 'input_text', text: rawPromptContent }, ...fileItems];
24413
+ }
24414
+ return rawPromptContent;
24415
+ }
24416
+ /**
24417
+ * Normalizes AgentKit tool outputs into a string for Promptbook tool call results.
24418
+ */
24419
+ formatAgentKitToolOutput(output) {
24420
+ if (typeof output === 'string') {
24421
+ return output;
24422
+ }
24423
+ if (output && typeof output === 'object') {
24424
+ const textOutput = output;
24425
+ if (textOutput.type === 'text' && typeof textOutput.text === 'string') {
24426
+ return textOutput.text;
23488
24427
  }
23489
24428
  }
23490
- return vectorStoreId;
24429
+ return JSON.stringify(output !== null && output !== void 0 ? output : null);
23491
24430
  }
23492
24431
  /**
23493
- * Discriminant for type guards
24432
+ * Returns AgentKit-specific options.
24433
+ */
24434
+ get agentKitOptions() {
24435
+ return this.options;
24436
+ }
24437
+ /**
24438
+ * Discriminant for type guards.
23494
24439
  */
23495
24440
  get discriminant() {
23496
- return 'OPEN_AI_AGENT';
24441
+ return DISCRIMINANT$1;
23497
24442
  }
23498
24443
  /**
23499
- * Type guard to check if given `LlmExecutionTools` are instanceof `OpenAiAgentExecutionTools`
24444
+ * Type guard to check if given `LlmExecutionTools` are instanceof `OpenAiAgentKitExecutionTools`.
23500
24445
  */
23501
- static isOpenAiAgentExecutionTools(llmExecutionTools) {
23502
- return llmExecutionTools.discriminant === 'OPEN_AI_AGENT';
24446
+ static isOpenAiAgentKitExecutionTools(llmExecutionTools) {
24447
+ return llmExecutionTools.discriminant === DISCRIMINANT$1;
23503
24448
  }
23504
24449
  }
24450
+ /**
24451
+ * Discriminant for type guards.
24452
+ *
24453
+ * @private const of `OpenAiAgentKitExecutionTools`
24454
+ */
24455
+ const DISCRIMINANT$1 = 'OPEN_AI_AGENT_KIT_V1';
23505
24456
 
23506
24457
  /**
23507
24458
  * Uploads files to OpenAI and returns their IDs
@@ -23536,10 +24487,10 @@ async function uploadFilesToOpenAi(client, files) {
23536
24487
  * - `OpenAiAssistantExecutionTools` - which is a specific implementation of `LlmExecutionTools` for OpenAI models with assistant capabilities, recommended for usage in `Agent` or `AgentLlmExecutionTools`
23537
24488
  * - `RemoteAgent` - which is an `Agent` that connects to a Promptbook Agents Server
23538
24489
  *
24490
+ * @deprecated Use `OpenAiAgentKitExecutionTools` instead.
23539
24491
  * @public exported from `@promptbook/openai`
23540
- * @deprecated Use `OpenAiAgentExecutionTools` instead which uses the new OpenAI Responses API
23541
24492
  */
23542
- class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
24493
+ class OpenAiAssistantExecutionTools extends OpenAiVectorStoreHandler {
23543
24494
  /**
23544
24495
  * Creates OpenAI Execution Tools.
23545
24496
  *
@@ -23668,8 +24619,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
23668
24619
  console.info(colors.bgWhite('rawRequest (non-streaming with tools)'), JSON.stringify(rawRequest, null, 4));
23669
24620
  }
23670
24621
  // Create thread and run
23671
- const threadAndRun = await client.beta.threads.createAndRun(rawRequest);
23672
- let run = threadAndRun;
24622
+ let run = (await client.beta.threads.createAndRun(rawRequest));
23673
24623
  const completedToolCalls = [];
23674
24624
  const toolCallStartedAt = new Map();
23675
24625
  // Poll until run completes or requires action
@@ -23764,14 +24714,14 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
23764
24714
  }
23765
24715
  }
23766
24716
  // Submit tool outputs
23767
- run = await client.beta.threads.runs.submitToolOutputs(run.thread_id, run.id, {
24717
+ run = (await client.beta.threads.runs.submitToolOutputs(run.thread_id, run.id, {
23768
24718
  tool_outputs: toolOutputs,
23769
- });
24719
+ }));
23770
24720
  }
23771
24721
  else {
23772
24722
  // Wait a bit before polling again
23773
24723
  await new Promise((resolve) => setTimeout(resolve, 500));
23774
- run = await client.beta.threads.runs.retrieve(run.thread_id, run.id);
24724
+ run = (await client.beta.threads.runs.retrieve(run.thread_id, run.id));
23775
24725
  }
23776
24726
  }
23777
24727
  if (run.status !== 'completed') {
@@ -23996,88 +24946,13 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
23996
24946
  let vectorStoreId;
23997
24947
  // If knowledge sources are provided, create a vector store with them
23998
24948
  if (knowledgeSources && knowledgeSources.length > 0) {
23999
- if (this.options.isVerbose) {
24000
- console.info('[🤰]', 'Creating vector store with knowledge sources', {
24001
- name,
24002
- knowledgeSourcesCount,
24003
- });
24004
- }
24005
- // Create a vector store
24006
- const vectorStore = await client.beta.vectorStores.create({
24007
- name: `${name} Knowledge Base`,
24949
+ const vectorStoreResult = await this.createVectorStoreWithKnowledgeSources({
24950
+ client,
24951
+ name,
24952
+ knowledgeSources,
24953
+ logLabel: 'assistant creation',
24008
24954
  });
24009
- vectorStoreId = vectorStore.id;
24010
- if (this.options.isVerbose) {
24011
- console.info('[🤰]', 'Vector store created', {
24012
- vectorStoreId,
24013
- });
24014
- }
24015
- // Upload files from knowledge sources to the vector store
24016
- const fileStreams = [];
24017
- for (const [index, source] of knowledgeSources.entries()) {
24018
- try {
24019
- if (this.options.isVerbose) {
24020
- console.info('[🤰]', 'Processing knowledge source', {
24021
- index: index + 1,
24022
- total: knowledgeSources.length,
24023
- source,
24024
- sourceType: source.startsWith('http') || source.startsWith('https') ? 'url' : 'file',
24025
- });
24026
- }
24027
- // Check if it's a URL
24028
- if (source.startsWith('http://') || source.startsWith('https://')) {
24029
- // Download the file
24030
- const response = await fetch(source);
24031
- if (!response.ok) {
24032
- console.error(`Failed to download ${source}: ${response.statusText}`);
24033
- continue;
24034
- }
24035
- const buffer = await response.arrayBuffer();
24036
- let filename = source.split('/').pop() || 'downloaded-file';
24037
- try {
24038
- const url = new URL(source);
24039
- filename = url.pathname.split('/').pop() || filename;
24040
- }
24041
- catch (error) {
24042
- // Keep default filename
24043
- }
24044
- const blob = new Blob([buffer]);
24045
- const file = new File([blob], filename);
24046
- fileStreams.push(file);
24047
- }
24048
- else {
24049
- /*
24050
- TODO: [🐱‍🚀] Resolve problem with browser environment
24051
- // Assume it's a local file path
24052
- // Note: This will work in Node.js environment
24053
- // For browser environments, this would need different handling
24054
- const fs = await import('fs');
24055
- const fileStream = fs.createReadStream(source);
24056
- fileStreams.push(fileStream);
24057
- */
24058
- }
24059
- }
24060
- catch (error) {
24061
- console.error(`Error processing knowledge source ${source}:`, error);
24062
- }
24063
- }
24064
- // Batch upload files to the vector store
24065
- if (fileStreams.length > 0) {
24066
- try {
24067
- await client.beta.vectorStores.fileBatches.uploadAndPoll(vectorStoreId, {
24068
- files: fileStreams,
24069
- });
24070
- if (this.options.isVerbose) {
24071
- console.info('[🤰]', 'Uploaded files to vector store', {
24072
- vectorStoreId,
24073
- fileCount: fileStreams.length,
24074
- });
24075
- }
24076
- }
24077
- catch (error) {
24078
- console.error('Error uploading files to vector store:', error);
24079
- }
24080
- }
24955
+ vectorStoreId = vectorStoreResult.vectorStoreId;
24081
24956
  }
24082
24957
  // Create assistant with vector store attached
24083
24958
  const assistantConfig = {
@@ -24144,91 +25019,14 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
24144
25019
  const client = await this.getClient();
24145
25020
  let vectorStoreId;
24146
25021
  // If knowledge sources are provided, create a vector store with them
24147
- // TODO: [🧠] Reuse vector store creation logic from createNewAssistant
24148
25022
  if (knowledgeSources && knowledgeSources.length > 0) {
24149
- if (this.options.isVerbose) {
24150
- console.info('[🤰]', 'Creating vector store for assistant update', {
24151
- assistantId,
24152
- name,
24153
- knowledgeSourcesCount,
24154
- });
24155
- }
24156
- // Create a vector store
24157
- const vectorStore = await client.beta.vectorStores.create({
24158
- name: `${name} Knowledge Base`,
25023
+ const vectorStoreResult = await this.createVectorStoreWithKnowledgeSources({
25024
+ client,
25025
+ name: name !== null && name !== void 0 ? name : assistantId,
25026
+ knowledgeSources,
25027
+ logLabel: 'assistant update',
24159
25028
  });
24160
- vectorStoreId = vectorStore.id;
24161
- if (this.options.isVerbose) {
24162
- console.info('[🤰]', 'Vector store created for assistant update', {
24163
- vectorStoreId,
24164
- });
24165
- }
24166
- // Upload files from knowledge sources to the vector store
24167
- const fileStreams = [];
24168
- for (const [index, source] of knowledgeSources.entries()) {
24169
- try {
24170
- if (this.options.isVerbose) {
24171
- console.info('[🤰]', 'Processing knowledge source for update', {
24172
- index: index + 1,
24173
- total: knowledgeSources.length,
24174
- source,
24175
- sourceType: source.startsWith('http') || source.startsWith('https') ? 'url' : 'file',
24176
- });
24177
- }
24178
- // Check if it's a URL
24179
- if (source.startsWith('http://') || source.startsWith('https://')) {
24180
- // Download the file
24181
- const response = await fetch(source);
24182
- if (!response.ok) {
24183
- console.error(`Failed to download ${source}: ${response.statusText}`);
24184
- continue;
24185
- }
24186
- const buffer = await response.arrayBuffer();
24187
- let filename = source.split('/').pop() || 'downloaded-file';
24188
- try {
24189
- const url = new URL(source);
24190
- filename = url.pathname.split('/').pop() || filename;
24191
- }
24192
- catch (error) {
24193
- // Keep default filename
24194
- }
24195
- const blob = new Blob([buffer]);
24196
- const file = new File([blob], filename);
24197
- fileStreams.push(file);
24198
- }
24199
- else {
24200
- /*
24201
- TODO: [🐱‍🚀] Resolve problem with browser environment
24202
- // Assume it's a local file path
24203
- // Note: This will work in Node.js environment
24204
- // For browser environments, this would need different handling
24205
- const fs = await import('fs');
24206
- const fileStream = fs.createReadStream(source);
24207
- fileStreams.push(fileStream);
24208
- */
24209
- }
24210
- }
24211
- catch (error) {
24212
- console.error(`Error processing knowledge source ${source}:`, error);
24213
- }
24214
- }
24215
- // Batch upload files to the vector store
24216
- if (fileStreams.length > 0) {
24217
- try {
24218
- await client.beta.vectorStores.fileBatches.uploadAndPoll(vectorStoreId, {
24219
- files: fileStreams,
24220
- });
24221
- if (this.options.isVerbose) {
24222
- console.info('[🤰]', 'Uploaded files to vector store for update', {
24223
- vectorStoreId,
24224
- fileCount: fileStreams.length,
24225
- });
24226
- }
24227
- }
24228
- catch (error) {
24229
- console.error('Error uploading files to vector store:', error);
24230
- }
24231
- }
25029
+ vectorStoreId = vectorStoreResult.vectorStoreId;
24232
25030
  }
24233
25031
  const assistantUpdate = {
24234
25032
  name,
@@ -24332,8 +25130,8 @@ function emitAssistantPreparationProgress(options) {
24332
25130
  * - `Agent` - which represents an AI Agent with its source, memories, actions, etc. Agent is a higher-level abstraction which is internally using:
24333
25131
  * - `LlmExecutionTools` - which wraps one or more LLM models and provides an interface to execute them
24334
25132
  * - `AgentLlmExecutionTools` - which is a specific implementation of `LlmExecutionTools` that wraps another LlmExecutionTools and applies agent-specific system prompts and requirements
24335
- * - `OpenAiAgentExecutionTools` - which is a specific implementation of `LlmExecutionTools` for OpenAI models with agent capabilities (using Responses API), recommended for usage in `Agent` or `AgentLlmExecutionTools`
24336
25133
  * - `OpenAiAssistantExecutionTools` - (Deprecated) which is a specific implementation of `LlmExecutionTools` for OpenAI models with assistant capabilities
25134
+ * - `OpenAiAgentKitExecutionTools` - which is a specific implementation of `LlmExecutionTools` backed by OpenAI AgentKit
24337
25135
  * - `RemoteAgent` - which is an `Agent` that connects to a Promptbook Agents Server
24338
25136
  *
24339
25137
  * @public exported from `@promptbook/core`
@@ -24468,6 +25266,7 @@ class AgentLlmExecutionTools {
24468
25266
  * Calls the chat model with agent-specific system prompt and requirements with streaming
24469
25267
  */
24470
25268
  async callChatModelStream(prompt, onProgress) {
25269
+ var _a, _b;
24471
25270
  // Ensure we're working with a chat prompt
24472
25271
  if (prompt.modelRequirements.modelVariant !== 'CHAT') {
24473
25272
  throw new Error('AgentLlmExecutionTools only supports chat prompts');
@@ -24495,63 +25294,73 @@ class AgentLlmExecutionTools {
24495
25294
  }, // Cast to avoid readonly mismatch from spread
24496
25295
  };
24497
25296
  console.log('!!!! promptWithAgentModelRequirements:', promptWithAgentModelRequirements);
24498
- if (OpenAiAgentExecutionTools.isOpenAiAgentExecutionTools(this.options.llmTools)) {
25297
+ if (OpenAiAgentKitExecutionTools.isOpenAiAgentKitExecutionTools(this.options.llmTools)) {
24499
25298
  const requirementsHash = SHA256(JSON.stringify(modelRequirements)).toString();
24500
- const cached = AgentLlmExecutionTools.vectorStoreCache.get(this.title);
24501
- let agentTools;
24502
- if (cached && cached.requirementsHash === requirementsHash) {
25299
+ const vectorStoreHash = SHA256(JSON.stringify((_a = modelRequirements.knowledgeSources) !== null && _a !== void 0 ? _a : [])).toString();
25300
+ const cachedVectorStore = AgentLlmExecutionTools.vectorStoreCache.get(this.title);
25301
+ const cachedAgentKit = AgentLlmExecutionTools.agentKitAgentCache.get(this.title);
25302
+ let preparedAgentKit = this.options.assistantPreparationMode === 'external'
25303
+ ? this.options.llmTools.getPreparedAgentKitAgent()
25304
+ : null;
25305
+ const vectorStoreId = (preparedAgentKit === null || preparedAgentKit === void 0 ? void 0 : preparedAgentKit.vectorStoreId) ||
25306
+ (cachedVectorStore && cachedVectorStore.requirementsHash === vectorStoreHash
25307
+ ? cachedVectorStore.vectorStoreId
25308
+ : undefined);
25309
+ if (!preparedAgentKit && cachedAgentKit && cachedAgentKit.requirementsHash === requirementsHash) {
24503
25310
  if (this.options.isVerbose) {
24504
- console.log(`1️⃣ Using cached OpenAI Agent Vector Store for agent ${this.title}...`);
25311
+ console.info('[🤰]', 'Using cached OpenAI AgentKit agent', {
25312
+ agent: this.title,
25313
+ });
24505
25314
  }
24506
- // Create new instance with cached vectorStoreId
24507
- // We need to access options from the original tool.
24508
- // We assume isOpenAiAgentExecutionTools implies it has options we can clone.
24509
- // But protected options are not accessible.
24510
- // We can cast to access options if they were public, or use a method to clone.
24511
- // OpenAiAgentExecutionTools doesn't have a clone method.
24512
- // However, we can just assume the passed tool *might* not have the vector store yet, or we are replacing it.
24513
- // Actually, if the passed tool IS OpenAiAgentExecutionTools, we should use it as a base.
24514
- // TODO: [🧠] This is a bit hacky, accessing protected options or recreating tools.
24515
- // Ideally OpenAiAgentExecutionTools should have a method `withVectorStoreId`.
24516
- agentTools = new OpenAiAgentExecutionTools({
24517
- ...this.options.llmTools.options,
24518
- vectorStoreId: cached.vectorStoreId,
24519
- });
25315
+ preparedAgentKit = {
25316
+ agent: cachedAgentKit.agent,
25317
+ vectorStoreId: cachedAgentKit.vectorStoreId,
25318
+ };
24520
25319
  }
24521
- else {
25320
+ if (!preparedAgentKit) {
24522
25321
  if (this.options.isVerbose) {
24523
- console.log(`1️⃣ Creating/Updating OpenAI Agent Vector Store for agent ${this.title}...`);
24524
- }
24525
- let vectorStoreId;
24526
- if (modelRequirements.knowledgeSources && modelRequirements.knowledgeSources.length > 0) {
24527
- const client = await this.options.llmTools.getClient();
24528
- vectorStoreId = await OpenAiAgentExecutionTools.createVectorStore(client, this.title, modelRequirements.knowledgeSources);
25322
+ console.info('[🤰]', 'Preparing OpenAI AgentKit agent', {
25323
+ agent: this.title,
25324
+ });
24529
25325
  }
24530
- if (vectorStoreId) {
24531
- AgentLlmExecutionTools.vectorStoreCache.set(this.title, {
24532
- vectorStoreId,
24533
- requirementsHash,
25326
+ if (!vectorStoreId && ((_b = modelRequirements.knowledgeSources) === null || _b === void 0 ? void 0 : _b.length)) {
25327
+ emitAssistantPreparationProgress({
25328
+ onProgress,
25329
+ prompt,
25330
+ modelName: this.modelName,
25331
+ phase: 'Creating knowledge base',
24534
25332
  });
24535
25333
  }
24536
- agentTools = new OpenAiAgentExecutionTools({
24537
- ...this.options.llmTools.options,
25334
+ emitAssistantPreparationProgress({
25335
+ onProgress,
25336
+ prompt,
25337
+ modelName: this.modelName,
25338
+ phase: 'Preparing AgentKit agent',
25339
+ });
25340
+ preparedAgentKit = await this.options.llmTools.prepareAgentKitAgent({
25341
+ name: this.title,
25342
+ instructions: modelRequirements.systemMessage || '',
25343
+ knowledgeSources: modelRequirements.knowledgeSources,
25344
+ tools: modelRequirements.tools ? [...modelRequirements.tools] : undefined,
24538
25345
  vectorStoreId,
24539
25346
  });
24540
25347
  }
24541
- // Create modified chat prompt with agent system message specific to OpenAI Agent
24542
- // Note: Unlike Assistants API, Responses API expects instructions (system message) to be passed in the call.
24543
- // So we use promptWithAgentModelRequirements which has the system message prepended.
24544
- // But we need to make sure we pass knowledgeSources in modelRequirements so OpenAiAgentExecutionTools can fallback to warning if vectorStoreId is missing (though we just handled it).
24545
- const promptForAgent = {
24546
- ...promptWithAgentModelRequirements,
24547
- modelRequirements: {
24548
- ...promptWithAgentModelRequirements.modelRequirements,
24549
- knowledgeSources: modelRequirements.knowledgeSources
24550
- ? [...modelRequirements.knowledgeSources]
24551
- : undefined, // Pass knowledge sources explicitly
24552
- },
24553
- };
24554
- underlyingLlmResult = await agentTools.callChatModelStream(promptForAgent, onProgress);
25348
+ if (preparedAgentKit.vectorStoreId) {
25349
+ AgentLlmExecutionTools.vectorStoreCache.set(this.title, {
25350
+ vectorStoreId: preparedAgentKit.vectorStoreId,
25351
+ requirementsHash: vectorStoreHash,
25352
+ });
25353
+ }
25354
+ AgentLlmExecutionTools.agentKitAgentCache.set(this.title, {
25355
+ agent: preparedAgentKit.agent,
25356
+ requirementsHash,
25357
+ vectorStoreId: preparedAgentKit.vectorStoreId,
25358
+ });
25359
+ underlyingLlmResult = await this.options.llmTools.callChatModelStreamWithPreparedAgent({
25360
+ openAiAgentKitAgent: preparedAgentKit.agent,
25361
+ prompt: promptWithAgentModelRequirements,
25362
+ onProgress,
25363
+ });
24555
25364
  }
24556
25365
  else if (OpenAiAssistantExecutionTools.isOpenAiAssistantExecutionTools(this.options.llmTools)) {
24557
25366
  // ... deprecated path ...
@@ -24678,6 +25487,10 @@ class AgentLlmExecutionTools {
24678
25487
  return agentResult;
24679
25488
  }
24680
25489
  }
25490
+ /**
25491
+ * Cached AgentKit agents to avoid rebuilding identical instances.
25492
+ */
25493
+ AgentLlmExecutionTools.agentKitAgentCache = new Map();
24681
25494
  /**
24682
25495
  * Cache of OpenAI assistants to avoid creating duplicates
24683
25496
  */
@@ -24758,8 +25571,8 @@ function buildTeacherSummary(commitments, used) {
24758
25571
  * - `Agent` - which represents an AI Agent with its source, memories, actions, etc. Agent is a higher-level abstraction which is internally using:
24759
25572
  * - `LlmExecutionTools` - which wraps one or more LLM models and provides an interface to execute them
24760
25573
  * - `AgentLlmExecutionTools` - which is a specific implementation of `LlmExecutionTools` that wraps another LlmExecutionTools and applies agent-specific system prompts and requirements
24761
- * - `OpenAiAgentExecutionTools` - which is a specific implementation of `LlmExecutionTools` for OpenAI models with agent capabilities (using Responses API), recommended for usage in `Agent` or `AgentLlmExecutionTools`
24762
25574
  * - `OpenAiAssistantExecutionTools` - (Deprecated) which is a specific implementation of `LlmExecutionTools` for OpenAI models with assistant capabilities
25575
+ * - `OpenAiAgentKitExecutionTools` - which is a specific implementation of `LlmExecutionTools` backed by OpenAI AgentKit
24763
25576
  * - `RemoteAgent` - which is an `Agent` that connects to a Promptbook Agents Server
24764
25577
  *
24765
25578
  * @public exported from `@promptbook/core`
@@ -25130,7 +25943,8 @@ function buildRemoteAgentSource(profile, meta) {
25130
25943
  * - `Agent` - which represents an AI Agent with its source, memories, actions, etc. Agent is a higher-level abstraction which is internally using:
25131
25944
  * - `LlmExecutionTools` - which wraps one or more LLM models and provides an interface to execute them
25132
25945
  * - `AgentLlmExecutionTools` - which is a specific implementation of `LlmExecutionTools` that wraps another LlmExecutionTools and applies agent-specific system prompts and requirements
25133
- * - `OpenAiAssistantExecutionTools` - which is a specific implementation of `LlmExecutionTools` for OpenAI models with assistant capabilities, recommended for usage in `Agent` or `AgentLlmExecutionTools`
25946
+ * - `OpenAiAssistantExecutionTools` - (Deprecated) which is a specific implementation of `LlmExecutionTools` for OpenAI models with assistant capabilities
25947
+ * - `OpenAiAgentKitExecutionTools` - which is a specific implementation of `LlmExecutionTools` backed by OpenAI AgentKit
25134
25948
  * - `RemoteAgent` - which is an `Agent` that connects to a Promptbook Agents Server
25135
25949
  *
25136
25950
  * @public exported from `@promptbook/core`