@promptbook/wizard 0.110.0-0 → 0.110.0-10
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/esm/index.es.js +1879 -603
- package/esm/index.es.js.map +1 -1
- package/esm/typings/src/_packages/components.index.d.ts +4 -0
- package/esm/typings/src/_packages/core.index.d.ts +2 -2
- package/esm/typings/src/_packages/openai.index.d.ts +8 -4
- package/esm/typings/src/_packages/types.index.d.ts +12 -4
- package/esm/typings/src/book-2.0/agent-source/AgentModelRequirements.d.ts +22 -21
- package/esm/typings/src/book-2.0/agent-source/AgentReferenceResolver.d.ts +18 -0
- package/esm/typings/src/book-2.0/agent-source/CreateAgentModelRequirementsOptions.d.ts +12 -0
- package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirements.d.ts +8 -2
- package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.agentReferenceResolver.test.d.ts +1 -0
- package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.d.ts +4 -5
- package/esm/typings/src/book-components/Chat/AgentChip/AgentChip.d.ts +5 -1
- package/esm/typings/src/book-components/Chat/Chat/ChatActionsBar.d.ts +4 -2
- package/esm/typings/src/book-components/Chat/Chat/ChatInputArea.d.ts +1 -0
- package/esm/typings/src/book-components/Chat/Chat/ChatMessageItem.d.ts +4 -0
- package/esm/typings/src/book-components/Chat/Chat/ChatMessageList.d.ts +1 -0
- package/esm/typings/src/book-components/Chat/Chat/ChatProps.d.ts +15 -0
- package/esm/typings/src/book-components/Chat/Chat/ChatSoundToggle.d.ts +31 -0
- package/esm/typings/src/book-components/Chat/LlmChat/LlmChatProps.d.ts +10 -1
- package/esm/typings/src/book-components/Chat/SourceChip/SourceChip.d.ts +5 -1
- package/esm/typings/src/book-components/Chat/utils/collectTeamToolCallSummary.d.ts +69 -0
- package/esm/typings/src/book-components/Chat/utils/getToolCallChipletInfo.d.ts +13 -13
- package/esm/typings/src/book-components/Chat/utils/parseCitationsFromContent.d.ts +9 -0
- package/esm/typings/src/book-components/Chat/utils/toolCallParsing.d.ts +4 -0
- package/esm/typings/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentsDatabaseSchema.d.ts +0 -3
- package/esm/typings/src/commitments/_base/BaseCommitmentDefinition.d.ts +9 -0
- package/esm/typings/src/execution/LlmExecutionTools.d.ts +2 -1
- package/esm/typings/src/llm-providers/agent/Agent.d.ts +1 -1
- package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +5 -1
- package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.test.d.ts +1 -0
- package/esm/typings/src/llm-providers/agent/AgentOptions.d.ts +10 -0
- package/esm/typings/src/llm-providers/agent/CreateAgentLlmExecutionToolsOptions.d.ts +13 -2
- package/esm/typings/src/llm-providers/agent/RemoteAgent.d.ts +2 -1
- package/esm/typings/src/llm-providers/openai/OpenAiAgentKitExecutionTools.d.ts +150 -0
- package/esm/typings/src/llm-providers/openai/OpenAiAgentKitExecutionToolsOptions.d.ts +15 -0
- package/esm/typings/src/llm-providers/openai/OpenAiAssistantExecutionTools.d.ts +3 -3
- package/esm/typings/src/llm-providers/openai/OpenAiAssistantExecutionToolsOptions.d.ts +3 -4
- package/esm/typings/src/llm-providers/openai/OpenAiVectorStoreHandler.d.ts +135 -0
- package/esm/typings/src/llm-providers/openai/utils/mapToolsToOpenAi.d.ts +1 -1
- package/esm/typings/src/types/LlmToolDefinition.d.ts +1 -0
- package/esm/typings/src/types/ModelRequirements.d.ts +9 -0
- package/esm/typings/src/utils/DEFAULT_THINKING_MESSAGES.d.ts +8 -0
- package/esm/typings/src/utils/agents/resolveAgentAvatarImageUrl.d.ts +29 -0
- package/esm/typings/src/utils/knowledge/inlineKnowledgeSource.d.ts +38 -0
- package/esm/typings/src/utils/knowledge/inlineKnowledgeSource.test.d.ts +1 -0
- package/esm/typings/src/utils/language/getBrowserPreferredSpeechRecognitionLanguage.d.ts +35 -0
- package/esm/typings/src/utils/toolCalls/getToolCallIdentity.d.ts +10 -0
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +7 -3
- package/umd/index.umd.js +1882 -607
- package/umd/index.umd.js.map +1 -1
- package/esm/typings/src/llm-providers/openai/OpenAiAgentExecutionTools.d.ts +0 -43
- package/esm/typings/src/llm-providers/openai/createOpenAiAgentExecutionTools.d.ts +0 -11
package/esm/index.es.js
CHANGED
|
@@ -21,6 +21,7 @@ import { Subject, BehaviorSubject } from 'rxjs';
|
|
|
21
21
|
import moment from 'moment';
|
|
22
22
|
import { lookup, extension } from 'mime-types';
|
|
23
23
|
import { parse, unparse } from 'papaparse';
|
|
24
|
+
import { Agent as Agent$1, setDefaultOpenAIClient, setDefaultOpenAIKey, fileSearchTool, tool, run } from '@openai/agents';
|
|
24
25
|
import OpenAI from 'openai';
|
|
25
26
|
|
|
26
27
|
// ⚠️ WARNING: This code has been generated so that any manual changes will be overwritten
|
|
@@ -37,7 +38,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
37
38
|
* @generated
|
|
38
39
|
* @see https://github.com/webgptorg/promptbook
|
|
39
40
|
*/
|
|
40
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.110.0-
|
|
41
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.110.0-10';
|
|
41
42
|
/**
|
|
42
43
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
43
44
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -3775,6 +3776,66 @@ const OPENAI_MODELS = exportJson({
|
|
|
3775
3776
|
},
|
|
3776
3777
|
/**/
|
|
3777
3778
|
/**/
|
|
3779
|
+
{
|
|
3780
|
+
modelVariant: 'CHAT',
|
|
3781
|
+
modelTitle: 'gpt-5.2-codex',
|
|
3782
|
+
modelName: 'gpt-5.2-codex',
|
|
3783
|
+
modelDescription: 'High-capability Codex variant tuned for agentic code generation with large contexts and reasoning effort controls. Ideal for long-horizon coding workflows and multi-step reasoning.',
|
|
3784
|
+
pricing: {
|
|
3785
|
+
prompt: pricing(`$1.75 / 1M tokens`),
|
|
3786
|
+
output: pricing(`$14.00 / 1M tokens`),
|
|
3787
|
+
},
|
|
3788
|
+
},
|
|
3789
|
+
/**/
|
|
3790
|
+
/**/
|
|
3791
|
+
{
|
|
3792
|
+
modelVariant: 'CHAT',
|
|
3793
|
+
modelTitle: 'gpt-5.1-codex-max',
|
|
3794
|
+
modelName: 'gpt-5.1-codex-max',
|
|
3795
|
+
modelDescription: 'Premium GPT-5.1 Codex flavor that mirrors gpt-5.1 in capability and pricing while adding Codex tooling optimizations.',
|
|
3796
|
+
pricing: {
|
|
3797
|
+
prompt: pricing(`$1.25 / 1M tokens`),
|
|
3798
|
+
output: pricing(`$10.00 / 1M tokens`),
|
|
3799
|
+
},
|
|
3800
|
+
},
|
|
3801
|
+
/**/
|
|
3802
|
+
/**/
|
|
3803
|
+
{
|
|
3804
|
+
modelVariant: 'CHAT',
|
|
3805
|
+
modelTitle: 'gpt-5.1-codex',
|
|
3806
|
+
modelName: 'gpt-5.1-codex',
|
|
3807
|
+
modelDescription: 'Core GPT-5.1 Codex model focused on agentic coding tasks with a balanced trade-off between reasoning and cost.',
|
|
3808
|
+
pricing: {
|
|
3809
|
+
prompt: pricing(`$1.25 / 1M tokens`),
|
|
3810
|
+
output: pricing(`$10.00 / 1M tokens`),
|
|
3811
|
+
},
|
|
3812
|
+
},
|
|
3813
|
+
/**/
|
|
3814
|
+
/**/
|
|
3815
|
+
{
|
|
3816
|
+
modelVariant: 'CHAT',
|
|
3817
|
+
modelTitle: 'gpt-5.1-codex-mini',
|
|
3818
|
+
modelName: 'gpt-5.1-codex-mini',
|
|
3819
|
+
modelDescription: 'Compact, cost-effective GPT-5.1 Codex variant with a smaller context window ideal for cheap assistant iterations that still require coding awareness.',
|
|
3820
|
+
pricing: {
|
|
3821
|
+
prompt: pricing(`$0.25 / 1M tokens`),
|
|
3822
|
+
output: pricing(`$2.00 / 1M tokens`),
|
|
3823
|
+
},
|
|
3824
|
+
},
|
|
3825
|
+
/**/
|
|
3826
|
+
/**/
|
|
3827
|
+
{
|
|
3828
|
+
modelVariant: 'CHAT',
|
|
3829
|
+
modelTitle: 'gpt-5-codex',
|
|
3830
|
+
modelName: 'gpt-5-codex',
|
|
3831
|
+
modelDescription: 'Legacy GPT-5 Codex model built for agentic coding workloads with the same pricing as GPT-5 and a focus on stability.',
|
|
3832
|
+
pricing: {
|
|
3833
|
+
prompt: pricing(`$1.25 / 1M tokens`),
|
|
3834
|
+
output: pricing(`$10.00 / 1M tokens`),
|
|
3835
|
+
},
|
|
3836
|
+
},
|
|
3837
|
+
/**/
|
|
3838
|
+
/**/
|
|
3778
3839
|
{
|
|
3779
3840
|
modelVariant: 'CHAT',
|
|
3780
3841
|
modelTitle: 'gpt-5-mini',
|
|
@@ -8670,6 +8731,32 @@ function isUnsupportedParameterError(error) {
|
|
|
8670
8731
|
errorMessage.includes('does not support'));
|
|
8671
8732
|
}
|
|
8672
8733
|
|
|
8734
|
+
/**
|
|
8735
|
+
* Provides access to the structured clone implementation when available.
|
|
8736
|
+
*/
|
|
8737
|
+
function getStructuredCloneFunction() {
|
|
8738
|
+
return globalThis.structuredClone;
|
|
8739
|
+
}
|
|
8740
|
+
/**
|
|
8741
|
+
* Checks whether the prompt is a chat prompt that carries file attachments.
|
|
8742
|
+
*/
|
|
8743
|
+
function hasChatPromptFiles(prompt) {
|
|
8744
|
+
return 'files' in prompt && Array.isArray(prompt.files);
|
|
8745
|
+
}
|
|
8746
|
+
/**
|
|
8747
|
+
* Creates a deep copy of the prompt while keeping attached files intact when structured clone is not available.
|
|
8748
|
+
*/
|
|
8749
|
+
function clonePromptPreservingFiles(prompt) {
|
|
8750
|
+
const structuredCloneFn = getStructuredCloneFunction();
|
|
8751
|
+
if (typeof structuredCloneFn === 'function') {
|
|
8752
|
+
return structuredCloneFn(prompt);
|
|
8753
|
+
}
|
|
8754
|
+
const clonedPrompt = JSON.parse(JSON.stringify(prompt));
|
|
8755
|
+
if (hasChatPromptFiles(prompt)) {
|
|
8756
|
+
clonedPrompt.files = prompt.files;
|
|
8757
|
+
}
|
|
8758
|
+
return clonedPrompt;
|
|
8759
|
+
}
|
|
8673
8760
|
/**
|
|
8674
8761
|
* Execution Tools for calling OpenAI API or other OpenAI compatible provider
|
|
8675
8762
|
*
|
|
@@ -8699,16 +8786,11 @@ class OpenAiCompatibleExecutionTools {
|
|
|
8699
8786
|
const openAiOptions = { ...this.options };
|
|
8700
8787
|
delete openAiOptions.isVerbose;
|
|
8701
8788
|
delete openAiOptions.userId;
|
|
8702
|
-
// Enhanced configuration
|
|
8789
|
+
// Enhanced configuration with retries and timeouts.
|
|
8703
8790
|
const enhancedOptions = {
|
|
8704
8791
|
...openAiOptions,
|
|
8705
8792
|
timeout: API_REQUEST_TIMEOUT,
|
|
8706
8793
|
maxRetries: CONNECTION_RETRIES_LIMIT,
|
|
8707
|
-
defaultHeaders: {
|
|
8708
|
-
Connection: 'keep-alive',
|
|
8709
|
-
'Keep-Alive': 'timeout=30, max=100',
|
|
8710
|
-
...openAiOptions.defaultHeaders,
|
|
8711
|
-
},
|
|
8712
8794
|
};
|
|
8713
8795
|
this.client = new OpenAI(enhancedOptions);
|
|
8714
8796
|
}
|
|
@@ -8759,7 +8841,7 @@ class OpenAiCompatibleExecutionTools {
|
|
|
8759
8841
|
*/
|
|
8760
8842
|
async callChatModelStream(prompt, onProgress) {
|
|
8761
8843
|
// Deep clone prompt and modelRequirements to avoid mutation across calls
|
|
8762
|
-
const clonedPrompt =
|
|
8844
|
+
const clonedPrompt = clonePromptPreservingFiles(prompt);
|
|
8763
8845
|
// Use local Set for retried parameters to ensure independence and thread safety
|
|
8764
8846
|
const retriedUnsupportedParameters = new Set();
|
|
8765
8847
|
return this.callChatModelWithRetry(clonedPrompt, clonedPrompt.modelRequirements, [], retriedUnsupportedParameters, onProgress);
|
|
@@ -8786,7 +8868,10 @@ class OpenAiCompatibleExecutionTools {
|
|
|
8786
8868
|
// <- TODO: [🈁] Use `seed` here AND/OR use is `isDeterministic` for entire execution tools
|
|
8787
8869
|
// <- Note: [🧆]
|
|
8788
8870
|
}; // <- TODO: [💩] Guard here types better
|
|
8789
|
-
if (
|
|
8871
|
+
if (currentModelRequirements.responseFormat !== undefined) {
|
|
8872
|
+
modelSettings.response_format = currentModelRequirements.responseFormat;
|
|
8873
|
+
}
|
|
8874
|
+
else if (format === 'JSON') {
|
|
8790
8875
|
modelSettings.response_format = {
|
|
8791
8876
|
type: 'json_object',
|
|
8792
8877
|
};
|
|
@@ -9999,6 +10084,7 @@ const _OpenAiAssistantMetadataRegistration = $llmToolsMetadataRegister.register(
|
|
|
9999
10084
|
apiKey: 'sk-',
|
|
10000
10085
|
assistantId: 'asst_',
|
|
10001
10086
|
maxRequestsPerMinute: DEFAULT_MAX_REQUESTS_PER_MINUTE,
|
|
10087
|
+
isCreatingNewAssistantsAllowed: false,
|
|
10002
10088
|
},
|
|
10003
10089
|
};
|
|
10004
10090
|
},
|
|
@@ -10093,18 +10179,6 @@ class OpenAiExecutionTools extends OpenAiCompatibleExecutionTools {
|
|
|
10093
10179
|
get profile() {
|
|
10094
10180
|
return OPENAI_PROVIDER_PROFILE;
|
|
10095
10181
|
}
|
|
10096
|
-
/*
|
|
10097
|
-
Note: Commenting this out to avoid circular dependency
|
|
10098
|
-
/**
|
|
10099
|
-
* Create (sub)tools for calling OpenAI API Assistants
|
|
10100
|
-
*
|
|
10101
|
-
* @param assistantId Which assistant to use
|
|
10102
|
-
* @returns Tools for calling OpenAI API Assistants with same token
|
|
10103
|
-
* /
|
|
10104
|
-
public createAssistantSubtools(assistantId: string_token): OpenAiAssistantExecutionTools {
|
|
10105
|
-
return new OpenAiAssistantExecutionTools({ ...this.options, assistantId });
|
|
10106
|
-
}
|
|
10107
|
-
*/
|
|
10108
10182
|
/**
|
|
10109
10183
|
* List all available models (non dynamically)
|
|
10110
10184
|
*
|
|
@@ -10140,128 +10214,1027 @@ class OpenAiExecutionTools extends OpenAiCompatibleExecutionTools {
|
|
|
10140
10214
|
}
|
|
10141
10215
|
|
|
10142
10216
|
/**
|
|
10143
|
-
*
|
|
10217
|
+
* @@@
|
|
10144
10218
|
*
|
|
10145
|
-
* @private
|
|
10219
|
+
* @private thing of inline knowledge
|
|
10146
10220
|
*/
|
|
10147
|
-
|
|
10148
|
-
|
|
10149
|
-
|
|
10150
|
-
|
|
10151
|
-
|
|
10152
|
-
|
|
10153
|
-
|
|
10154
|
-
|
|
10155
|
-
|
|
10156
|
-
|
|
10157
|
-
|
|
10158
|
-
|
|
10221
|
+
const INLINE_KNOWLEDGE_BASE_NAME = 'inline-knowledge';
|
|
10222
|
+
/**
|
|
10223
|
+
* @@@
|
|
10224
|
+
*
|
|
10225
|
+
* @private thing of inline knowledge
|
|
10226
|
+
*/
|
|
10227
|
+
const INLINE_KNOWLEDGE_EXTENSION = '.txt';
|
|
10228
|
+
/**
|
|
10229
|
+
* @@@
|
|
10230
|
+
*
|
|
10231
|
+
* @private thing of inline knowledge
|
|
10232
|
+
*/
|
|
10233
|
+
const DATA_URL_PREFIX = 'data:';
|
|
10234
|
+
/**
|
|
10235
|
+
* @@@
|
|
10236
|
+
*
|
|
10237
|
+
* @private thing of inline knowledge
|
|
10238
|
+
*/
|
|
10239
|
+
function getFirstNonEmptyLine(content) {
|
|
10240
|
+
const lines = content.split(/\r?\n/);
|
|
10241
|
+
for (const line of lines) {
|
|
10242
|
+
const trimmed = line.trim();
|
|
10243
|
+
if (trimmed) {
|
|
10244
|
+
return trimmed;
|
|
10245
|
+
}
|
|
10159
10246
|
}
|
|
10160
|
-
return
|
|
10247
|
+
return null;
|
|
10161
10248
|
}
|
|
10162
|
-
|
|
10163
10249
|
/**
|
|
10164
|
-
*
|
|
10250
|
+
* @@@
|
|
10165
10251
|
*
|
|
10166
|
-
*
|
|
10252
|
+
* @private thing of inline knowledge
|
|
10253
|
+
*/
|
|
10254
|
+
function deriveBaseFilename(content) {
|
|
10255
|
+
const firstLine = getFirstNonEmptyLine(content);
|
|
10256
|
+
if (!firstLine) {
|
|
10257
|
+
return INLINE_KNOWLEDGE_BASE_NAME;
|
|
10258
|
+
}
|
|
10259
|
+
const normalized = normalizeToKebabCase(firstLine);
|
|
10260
|
+
return normalized || INLINE_KNOWLEDGE_BASE_NAME;
|
|
10261
|
+
}
|
|
10262
|
+
/**
|
|
10263
|
+
* Creates a data URL that represents the inline knowledge content as a text file.
|
|
10167
10264
|
*
|
|
10168
|
-
*
|
|
10169
|
-
|
|
10170
|
-
|
|
10171
|
-
|
|
10172
|
-
|
|
10173
|
-
|
|
10265
|
+
* @private thing of inline knowledge
|
|
10266
|
+
*/
|
|
10267
|
+
function createInlineKnowledgeSourceFile(content) {
|
|
10268
|
+
const trimmedContent = content.trim();
|
|
10269
|
+
const baseName = deriveBaseFilename(trimmedContent);
|
|
10270
|
+
const filename = `${baseName}${INLINE_KNOWLEDGE_EXTENSION}`;
|
|
10271
|
+
const mimeType = 'text/plain';
|
|
10272
|
+
const base64 = Buffer.from(trimmedContent, 'utf-8').toString('base64');
|
|
10273
|
+
const encodedFilename = encodeURIComponent(filename);
|
|
10274
|
+
const url = `${DATA_URL_PREFIX}${mimeType};name=${encodedFilename};charset=utf-8;base64,${base64}`;
|
|
10275
|
+
return {
|
|
10276
|
+
filename,
|
|
10277
|
+
mimeType,
|
|
10278
|
+
url,
|
|
10279
|
+
};
|
|
10280
|
+
}
|
|
10281
|
+
/**
|
|
10282
|
+
* Checks whether the provided source string is a data URL that can be decoded.
|
|
10283
|
+
*
|
|
10284
|
+
* @private thing of inline knowledge
|
|
10285
|
+
*/
|
|
10286
|
+
function isDataUrlKnowledgeSource(source) {
|
|
10287
|
+
return typeof source === 'string' && source.startsWith(DATA_URL_PREFIX);
|
|
10288
|
+
}
|
|
10289
|
+
/**
|
|
10290
|
+
* Parses a data URL-based knowledge source into its raw buffer, filename, and MIME type.
|
|
10291
|
+
*
|
|
10292
|
+
* @private thing of inline knowledge
|
|
10293
|
+
*/
|
|
10294
|
+
function parseDataUrlKnowledgeSource(source) {
|
|
10295
|
+
if (!isDataUrlKnowledgeSource(source)) {
|
|
10296
|
+
return null;
|
|
10297
|
+
}
|
|
10298
|
+
const commaIndex = source.indexOf(',');
|
|
10299
|
+
if (commaIndex === -1) {
|
|
10300
|
+
return null;
|
|
10301
|
+
}
|
|
10302
|
+
const header = source.slice(DATA_URL_PREFIX.length, commaIndex);
|
|
10303
|
+
const payload = source.slice(commaIndex + 1);
|
|
10304
|
+
const tokens = header.split(';');
|
|
10305
|
+
const mediaType = tokens[0] || 'text/plain';
|
|
10306
|
+
let filename = `${INLINE_KNOWLEDGE_BASE_NAME}${INLINE_KNOWLEDGE_EXTENSION}`;
|
|
10307
|
+
let isBase64 = false;
|
|
10308
|
+
for (let i = 1; i < tokens.length; i++) {
|
|
10309
|
+
const token = tokens[i];
|
|
10310
|
+
if (!token) {
|
|
10311
|
+
continue;
|
|
10312
|
+
}
|
|
10313
|
+
if (token.toLowerCase() === 'base64') {
|
|
10314
|
+
isBase64 = true;
|
|
10315
|
+
continue;
|
|
10316
|
+
}
|
|
10317
|
+
const [key, value] = token.split('=');
|
|
10318
|
+
if (key === 'name' && value !== undefined) {
|
|
10319
|
+
try {
|
|
10320
|
+
filename = decodeURIComponent(value);
|
|
10321
|
+
}
|
|
10322
|
+
catch (_a) {
|
|
10323
|
+
filename = value;
|
|
10324
|
+
}
|
|
10325
|
+
}
|
|
10326
|
+
}
|
|
10327
|
+
if (!isBase64) {
|
|
10328
|
+
return null;
|
|
10329
|
+
}
|
|
10330
|
+
try {
|
|
10331
|
+
const buffer = Buffer.from(payload, 'base64');
|
|
10332
|
+
return {
|
|
10333
|
+
buffer,
|
|
10334
|
+
filename,
|
|
10335
|
+
mimeType: mediaType,
|
|
10336
|
+
};
|
|
10337
|
+
}
|
|
10338
|
+
catch (_b) {
|
|
10339
|
+
return null;
|
|
10340
|
+
}
|
|
10341
|
+
}
|
|
10342
|
+
/**
|
|
10343
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
10344
|
+
*/
|
|
10345
|
+
|
|
10346
|
+
const DEFAULT_KNOWLEDGE_SOURCE_DOWNLOAD_TIMEOUT_MS = 30000;
|
|
10347
|
+
const DEFAULT_KNOWLEDGE_SOURCE_UPLOAD_TIMEOUT_MS = 900000;
|
|
10348
|
+
const VECTOR_STORE_PROGRESS_LOG_INTERVAL_MIN_MS = 15000;
|
|
10349
|
+
const VECTOR_STORE_STALL_LOG_THRESHOLD_MS = 30000;
|
|
10350
|
+
/**
|
|
10351
|
+
* Base class for OpenAI execution tools that need hosted vector stores.
|
|
10174
10352
|
*
|
|
10175
10353
|
* @public exported from `@promptbook/openai`
|
|
10176
|
-
* @deprecated Use `OpenAiAgentExecutionTools` instead which uses the new OpenAI Responses API
|
|
10177
10354
|
*/
|
|
10178
|
-
class
|
|
10355
|
+
class OpenAiVectorStoreHandler extends OpenAiExecutionTools {
|
|
10179
10356
|
/**
|
|
10180
|
-
*
|
|
10181
|
-
*
|
|
10182
|
-
* @param options which are relevant are directly passed to the OpenAI client
|
|
10357
|
+
* Returns the per-knowledge-source download timeout in milliseconds.
|
|
10183
10358
|
*/
|
|
10184
|
-
|
|
10359
|
+
getKnowledgeSourceDownloadTimeoutMs() {
|
|
10185
10360
|
var _a;
|
|
10186
|
-
|
|
10187
|
-
throw new NotYetImplementedError(`Proxy mode is not yet implemented for OpenAI assistants`);
|
|
10188
|
-
}
|
|
10189
|
-
super(options);
|
|
10190
|
-
this.isCreatingNewAssistantsAllowed = false;
|
|
10191
|
-
this.assistantId = options.assistantId;
|
|
10192
|
-
this.isCreatingNewAssistantsAllowed = (_a = options.isCreatingNewAssistantsAllowed) !== null && _a !== void 0 ? _a : false;
|
|
10193
|
-
if (this.assistantId === null && !this.isCreatingNewAssistantsAllowed) {
|
|
10194
|
-
throw new NotAllowed(`Assistant ID is null and creating new assistants is not allowed - this configuration does not make sense`);
|
|
10195
|
-
}
|
|
10196
|
-
// <- TODO: !!! `OpenAiAssistantExecutionToolsOptions` - Allow `assistantId: null` together with `isCreatingNewAssistantsAllowed: true`
|
|
10197
|
-
// TODO: [👱] Make limiter same as in `OpenAiExecutionTools`
|
|
10361
|
+
return (_a = this.vectorStoreOptions.knowledgeSourceDownloadTimeoutMs) !== null && _a !== void 0 ? _a : DEFAULT_KNOWLEDGE_SOURCE_DOWNLOAD_TIMEOUT_MS;
|
|
10198
10362
|
}
|
|
10199
|
-
|
|
10200
|
-
|
|
10363
|
+
/**
|
|
10364
|
+
* Returns the max concurrency for knowledge source uploads.
|
|
10365
|
+
*/
|
|
10366
|
+
getKnowledgeSourceUploadMaxConcurrency() {
|
|
10367
|
+
var _a;
|
|
10368
|
+
return (_a = this.vectorStoreOptions.knowledgeSourceUploadMaxConcurrency) !== null && _a !== void 0 ? _a : 5;
|
|
10201
10369
|
}
|
|
10202
|
-
|
|
10203
|
-
|
|
10370
|
+
/**
|
|
10371
|
+
* Returns the polling interval in milliseconds for vector store uploads.
|
|
10372
|
+
*/
|
|
10373
|
+
getKnowledgeSourceUploadPollIntervalMs() {
|
|
10374
|
+
var _a;
|
|
10375
|
+
return (_a = this.vectorStoreOptions.knowledgeSourceUploadPollIntervalMs) !== null && _a !== void 0 ? _a : 5000;
|
|
10204
10376
|
}
|
|
10205
10377
|
/**
|
|
10206
|
-
*
|
|
10378
|
+
* Returns the overall upload timeout in milliseconds for vector store uploads.
|
|
10207
10379
|
*/
|
|
10208
|
-
|
|
10209
|
-
|
|
10380
|
+
getKnowledgeSourceUploadTimeoutMs() {
|
|
10381
|
+
var _a;
|
|
10382
|
+
return (_a = this.vectorStoreOptions.knowledgeSourceUploadTimeoutMs) !== null && _a !== void 0 ? _a : DEFAULT_KNOWLEDGE_SOURCE_UPLOAD_TIMEOUT_MS;
|
|
10210
10383
|
}
|
|
10211
10384
|
/**
|
|
10212
|
-
*
|
|
10385
|
+
* Returns true if we should continue even if vector store ingestion stalls.
|
|
10213
10386
|
*/
|
|
10214
|
-
|
|
10215
|
-
var _a
|
|
10216
|
-
|
|
10217
|
-
|
|
10387
|
+
shouldContinueOnVectorStoreStall() {
|
|
10388
|
+
var _a;
|
|
10389
|
+
return (_a = this.vectorStoreOptions.shouldContinueOnVectorStoreStall) !== null && _a !== void 0 ? _a : true;
|
|
10390
|
+
}
|
|
10391
|
+
/**
|
|
10392
|
+
* Returns vector-store-specific options with extended settings.
|
|
10393
|
+
*/
|
|
10394
|
+
get vectorStoreOptions() {
|
|
10395
|
+
return this.options;
|
|
10396
|
+
}
|
|
10397
|
+
/**
|
|
10398
|
+
* Returns the OpenAI vector stores API surface, supporting stable and beta SDKs.
|
|
10399
|
+
*/
|
|
10400
|
+
getVectorStoresApi(client) {
|
|
10401
|
+
var _a, _b;
|
|
10402
|
+
const vectorStores = (_a = client.vectorStores) !== null && _a !== void 0 ? _a : (_b = client.beta) === null || _b === void 0 ? void 0 : _b.vectorStores;
|
|
10403
|
+
if (!vectorStores) {
|
|
10404
|
+
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.');
|
|
10218
10405
|
}
|
|
10219
|
-
|
|
10220
|
-
|
|
10221
|
-
|
|
10222
|
-
|
|
10223
|
-
|
|
10406
|
+
return vectorStores;
|
|
10407
|
+
}
|
|
10408
|
+
/**
|
|
10409
|
+
* Downloads a knowledge source URL into a File for vector store upload.
|
|
10410
|
+
*/
|
|
10411
|
+
async downloadKnowledgeSourceFile(options) {
|
|
10412
|
+
var _a;
|
|
10413
|
+
const { source, timeoutMs, logLabel } = options;
|
|
10414
|
+
const startedAtMs = Date.now();
|
|
10415
|
+
const controller = new AbortController();
|
|
10416
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
10417
|
+
if (this.options.isVerbose) {
|
|
10418
|
+
console.info('[🤰]', 'Downloading knowledge source', {
|
|
10419
|
+
source,
|
|
10420
|
+
timeoutMs,
|
|
10421
|
+
logLabel,
|
|
10422
|
+
});
|
|
10224
10423
|
}
|
|
10225
|
-
|
|
10226
|
-
|
|
10227
|
-
|
|
10228
|
-
|
|
10424
|
+
try {
|
|
10425
|
+
const response = await fetch(source, { signal: controller.signal });
|
|
10426
|
+
const contentType = (_a = response.headers.get('content-type')) !== null && _a !== void 0 ? _a : undefined;
|
|
10427
|
+
if (!response.ok) {
|
|
10428
|
+
console.error('[🤰]', 'Failed to download knowledge source', {
|
|
10429
|
+
source,
|
|
10430
|
+
status: response.status,
|
|
10431
|
+
statusText: response.statusText,
|
|
10432
|
+
contentType,
|
|
10433
|
+
elapsedMs: Date.now() - startedAtMs,
|
|
10434
|
+
logLabel,
|
|
10435
|
+
});
|
|
10436
|
+
return null;
|
|
10437
|
+
}
|
|
10438
|
+
const buffer = await response.arrayBuffer();
|
|
10439
|
+
let filename = source.split('/').pop() || 'downloaded-file';
|
|
10440
|
+
try {
|
|
10441
|
+
const url = new URL(source);
|
|
10442
|
+
filename = url.pathname.split('/').pop() || filename;
|
|
10443
|
+
}
|
|
10444
|
+
catch (error) {
|
|
10445
|
+
// Keep default filename
|
|
10229
10446
|
}
|
|
10447
|
+
const file = new File([buffer], filename, contentType ? { type: contentType } : undefined);
|
|
10448
|
+
const elapsedMs = Date.now() - startedAtMs;
|
|
10449
|
+
const sizeBytes = buffer.byteLength;
|
|
10450
|
+
if (this.options.isVerbose) {
|
|
10451
|
+
console.info('[🤰]', 'Downloaded knowledge source', {
|
|
10452
|
+
source,
|
|
10453
|
+
filename,
|
|
10454
|
+
sizeBytes,
|
|
10455
|
+
contentType,
|
|
10456
|
+
elapsedMs,
|
|
10457
|
+
logLabel,
|
|
10458
|
+
});
|
|
10459
|
+
}
|
|
10460
|
+
return { file, sizeBytes, filename, elapsedMs };
|
|
10230
10461
|
}
|
|
10231
|
-
|
|
10232
|
-
|
|
10233
|
-
|
|
10234
|
-
|
|
10235
|
-
|
|
10236
|
-
|
|
10237
|
-
|
|
10238
|
-
|
|
10239
|
-
|
|
10240
|
-
// <- Note: [🧆]
|
|
10241
|
-
} as OpenAI.Chat.Completions.CompletionCreateParamsNonStreaming; // <- TODO: Guard here types better
|
|
10242
|
-
|
|
10243
|
-
if (format === 'JSON') {
|
|
10244
|
-
modelSettings.response_format = {
|
|
10245
|
-
type: 'json_object',
|
|
10246
|
-
};
|
|
10462
|
+
catch (error) {
|
|
10463
|
+
assertsError(error);
|
|
10464
|
+
console.error('[🤰]', 'Error downloading knowledge source', {
|
|
10465
|
+
source,
|
|
10466
|
+
elapsedMs: Date.now() - startedAtMs,
|
|
10467
|
+
logLabel,
|
|
10468
|
+
error: serializeError(error),
|
|
10469
|
+
});
|
|
10470
|
+
return null;
|
|
10247
10471
|
}
|
|
10248
|
-
|
|
10249
|
-
|
|
10250
|
-
|
|
10251
|
-
|
|
10252
|
-
|
|
10253
|
-
|
|
10254
|
-
|
|
10255
|
-
|
|
10256
|
-
|
|
10257
|
-
const
|
|
10258
|
-
|
|
10259
|
-
|
|
10260
|
-
|
|
10261
|
-
|
|
10262
|
-
|
|
10263
|
-
|
|
10264
|
-
|
|
10472
|
+
finally {
|
|
10473
|
+
clearTimeout(timeoutId);
|
|
10474
|
+
}
|
|
10475
|
+
}
|
|
10476
|
+
/**
|
|
10477
|
+
* Logs vector store file batch diagnostics to help trace ingestion stalls or failures.
|
|
10478
|
+
*/
|
|
10479
|
+
async logVectorStoreFileBatchDiagnostics(options) {
|
|
10480
|
+
var _a, _b, _c, _d, _e;
|
|
10481
|
+
const { client, vectorStoreId, batchId, uploadedFiles, logLabel, reason } = options;
|
|
10482
|
+
if (reason === 'stalled' && !this.options.isVerbose) {
|
|
10483
|
+
return;
|
|
10484
|
+
}
|
|
10485
|
+
if (!batchId.startsWith('vsfb_')) {
|
|
10486
|
+
console.error('[🤰]', 'Vector store file batch diagnostics skipped (invalid batch id)', {
|
|
10487
|
+
vectorStoreId,
|
|
10488
|
+
batchId,
|
|
10489
|
+
reason,
|
|
10490
|
+
logLabel,
|
|
10491
|
+
});
|
|
10492
|
+
return;
|
|
10493
|
+
}
|
|
10494
|
+
const fileIdToMetadata = new Map();
|
|
10495
|
+
for (const file of uploadedFiles) {
|
|
10496
|
+
fileIdToMetadata.set(file.fileId, file);
|
|
10497
|
+
}
|
|
10498
|
+
try {
|
|
10499
|
+
const vectorStores = this.getVectorStoresApi(client);
|
|
10500
|
+
const limit = Math.min(100, Math.max(10, uploadedFiles.length));
|
|
10501
|
+
const batchFilesPage = await vectorStores.fileBatches.listFiles(batchId, {
|
|
10502
|
+
vector_store_id: vectorStoreId,
|
|
10503
|
+
limit,
|
|
10504
|
+
});
|
|
10505
|
+
const batchFiles = (_a = batchFilesPage.data) !== null && _a !== void 0 ? _a : [];
|
|
10506
|
+
const statusCounts = {
|
|
10507
|
+
in_progress: 0,
|
|
10508
|
+
completed: 0,
|
|
10509
|
+
failed: 0,
|
|
10510
|
+
cancelled: 0,
|
|
10511
|
+
};
|
|
10512
|
+
const errorSamples = [];
|
|
10513
|
+
const inProgressSamples = [];
|
|
10514
|
+
const batchFileIds = new Set();
|
|
10515
|
+
for (const file of batchFiles) {
|
|
10516
|
+
const status = (_b = file.status) !== null && _b !== void 0 ? _b : 'unknown';
|
|
10517
|
+
statusCounts[status] = ((_c = statusCounts[status]) !== null && _c !== void 0 ? _c : 0) + 1;
|
|
10518
|
+
const vectorStoreFileId = file.id;
|
|
10519
|
+
const uploadedFileId = (_d = file.file_id) !== null && _d !== void 0 ? _d : file.fileId;
|
|
10520
|
+
const fileId = uploadedFileId !== null && uploadedFileId !== void 0 ? uploadedFileId : vectorStoreFileId;
|
|
10521
|
+
batchFileIds.add(fileId);
|
|
10522
|
+
const metadata = fileIdToMetadata.get(fileId);
|
|
10523
|
+
if (status === 'failed') {
|
|
10524
|
+
errorSamples.push({
|
|
10525
|
+
fileId,
|
|
10526
|
+
status,
|
|
10527
|
+
error: (_e = file.last_error) === null || _e === void 0 ? void 0 : _e.message,
|
|
10528
|
+
filename: metadata === null || metadata === void 0 ? void 0 : metadata.filename,
|
|
10529
|
+
vectorStoreFileId: uploadedFileId ? vectorStoreFileId : undefined,
|
|
10530
|
+
});
|
|
10531
|
+
}
|
|
10532
|
+
if (status === 'in_progress') {
|
|
10533
|
+
inProgressSamples.push({
|
|
10534
|
+
fileId,
|
|
10535
|
+
filename: metadata === null || metadata === void 0 ? void 0 : metadata.filename,
|
|
10536
|
+
vectorStoreFileId: uploadedFileId ? vectorStoreFileId : undefined,
|
|
10537
|
+
});
|
|
10538
|
+
}
|
|
10539
|
+
}
|
|
10540
|
+
const missingSamples = uploadedFiles
|
|
10541
|
+
.filter((file) => !batchFileIds.has(file.fileId))
|
|
10542
|
+
.slice(0, 5)
|
|
10543
|
+
.map((file) => ({
|
|
10544
|
+
fileId: file.fileId,
|
|
10545
|
+
filename: file.filename,
|
|
10546
|
+
sizeBytes: file.sizeBytes,
|
|
10547
|
+
}));
|
|
10548
|
+
const vectorStore = await vectorStores.retrieve(vectorStoreId);
|
|
10549
|
+
const logPayload = {
|
|
10550
|
+
vectorStoreId,
|
|
10551
|
+
batchId,
|
|
10552
|
+
reason,
|
|
10553
|
+
vectorStoreStatus: vectorStore.status,
|
|
10554
|
+
vectorStoreFileCounts: vectorStore.file_counts,
|
|
10555
|
+
vectorStoreUsageBytes: vectorStore.usage_bytes,
|
|
10556
|
+
batchFileCount: batchFiles.length,
|
|
10557
|
+
statusCounts,
|
|
10558
|
+
errorSamples: errorSamples.slice(0, 5),
|
|
10559
|
+
inProgressSamples,
|
|
10560
|
+
missingFileCount: uploadedFiles.length - batchFileIds.size,
|
|
10561
|
+
missingSamples,
|
|
10562
|
+
logLabel,
|
|
10563
|
+
};
|
|
10564
|
+
const logFunction = reason === 'stalled' ? console.info : console.error;
|
|
10565
|
+
logFunction('[🤰]', 'Vector store file batch diagnostics', logPayload);
|
|
10566
|
+
}
|
|
10567
|
+
catch (error) {
|
|
10568
|
+
assertsError(error);
|
|
10569
|
+
console.error('[🤰]', 'Vector store file batch diagnostics failed', {
|
|
10570
|
+
vectorStoreId,
|
|
10571
|
+
batchId,
|
|
10572
|
+
reason,
|
|
10573
|
+
logLabel,
|
|
10574
|
+
error: serializeError(error),
|
|
10575
|
+
});
|
|
10576
|
+
}
|
|
10577
|
+
}
|
|
10578
|
+
/**
|
|
10579
|
+
* Uploads knowledge source files to the vector store and polls until processing completes.
|
|
10580
|
+
*/
|
|
10581
|
+
async uploadKnowledgeSourceFilesToVectorStore(options) {
|
|
10582
|
+
var _a, _b, _c, _d, _e, _f;
|
|
10583
|
+
const { client, vectorStoreId, files, totalBytes, logLabel } = options;
|
|
10584
|
+
const vectorStores = this.getVectorStoresApi(client);
|
|
10585
|
+
const uploadStartedAtMs = Date.now();
|
|
10586
|
+
const maxConcurrency = Math.max(1, this.getKnowledgeSourceUploadMaxConcurrency());
|
|
10587
|
+
const pollIntervalMs = Math.max(1000, this.getKnowledgeSourceUploadPollIntervalMs());
|
|
10588
|
+
const uploadTimeoutMs = Math.max(1000, this.getKnowledgeSourceUploadTimeoutMs());
|
|
10589
|
+
if (this.options.isVerbose) {
|
|
10590
|
+
console.info('[🤰]', 'Uploading knowledge source files to OpenAI', {
|
|
10591
|
+
vectorStoreId,
|
|
10592
|
+
fileCount: files.length,
|
|
10593
|
+
totalBytes,
|
|
10594
|
+
maxConcurrency,
|
|
10595
|
+
pollIntervalMs,
|
|
10596
|
+
uploadTimeoutMs,
|
|
10597
|
+
logLabel,
|
|
10598
|
+
});
|
|
10599
|
+
}
|
|
10600
|
+
const fileTypeSummary = {};
|
|
10601
|
+
for (const file of files) {
|
|
10602
|
+
const filename = (_a = file.name) !== null && _a !== void 0 ? _a : '';
|
|
10603
|
+
const extension = filename.includes('.')
|
|
10604
|
+
? (_c = (_b = filename.split('.').pop()) === null || _b === void 0 ? void 0 : _b.toLowerCase()) !== null && _c !== void 0 ? _c : 'unknown'
|
|
10605
|
+
: 'unknown';
|
|
10606
|
+
const sizeBytes = typeof file.size === 'number' ? file.size : 0;
|
|
10607
|
+
const summary = (_d = fileTypeSummary[extension]) !== null && _d !== void 0 ? _d : { count: 0, totalBytes: 0 };
|
|
10608
|
+
summary.count += 1;
|
|
10609
|
+
summary.totalBytes += sizeBytes;
|
|
10610
|
+
fileTypeSummary[extension] = summary;
|
|
10611
|
+
}
|
|
10612
|
+
if (this.options.isVerbose) {
|
|
10613
|
+
console.info('[🤰]', 'Knowledge source file summary', {
|
|
10614
|
+
vectorStoreId,
|
|
10615
|
+
fileCount: files.length,
|
|
10616
|
+
totalBytes,
|
|
10617
|
+
fileTypeSummary,
|
|
10618
|
+
logLabel,
|
|
10619
|
+
});
|
|
10620
|
+
}
|
|
10621
|
+
const fileEntries = files.map((file, index) => ({ file, index }));
|
|
10622
|
+
const fileIterator = fileEntries.values();
|
|
10623
|
+
const fileIds = [];
|
|
10624
|
+
const uploadedFiles = [];
|
|
10625
|
+
const failedUploads = [];
|
|
10626
|
+
let uploadedCount = 0;
|
|
10627
|
+
const processFiles = async (iterator) => {
|
|
10628
|
+
var _a, _b;
|
|
10629
|
+
for (const { file, index } of iterator) {
|
|
10630
|
+
const uploadIndex = index + 1;
|
|
10631
|
+
const filename = file.name || `knowledge-source-${uploadIndex}`;
|
|
10632
|
+
const extension = filename.includes('.')
|
|
10633
|
+
? (_b = (_a = filename.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== null && _b !== void 0 ? _b : 'unknown'
|
|
10634
|
+
: 'unknown';
|
|
10635
|
+
const sizeBytes = typeof file.size === 'number' ? file.size : undefined;
|
|
10636
|
+
const fileUploadStartedAtMs = Date.now();
|
|
10637
|
+
if (this.options.isVerbose) {
|
|
10638
|
+
console.info('[🤰]', 'Uploading knowledge source file', {
|
|
10639
|
+
index: uploadIndex,
|
|
10640
|
+
total: files.length,
|
|
10641
|
+
filename,
|
|
10642
|
+
extension,
|
|
10643
|
+
sizeBytes,
|
|
10644
|
+
logLabel,
|
|
10645
|
+
});
|
|
10646
|
+
}
|
|
10647
|
+
try {
|
|
10648
|
+
const uploaded = await client.files.create({ file, purpose: 'assistants' });
|
|
10649
|
+
fileIds.push(uploaded.id);
|
|
10650
|
+
uploadedFiles.push({ fileId: uploaded.id, filename, sizeBytes });
|
|
10651
|
+
uploadedCount += 1;
|
|
10652
|
+
if (this.options.isVerbose) {
|
|
10653
|
+
console.info('[🤰]', 'Uploaded knowledge source file', {
|
|
10654
|
+
index: uploadIndex,
|
|
10655
|
+
total: files.length,
|
|
10656
|
+
filename,
|
|
10657
|
+
sizeBytes,
|
|
10658
|
+
fileId: uploaded.id,
|
|
10659
|
+
elapsedMs: Date.now() - fileUploadStartedAtMs,
|
|
10660
|
+
logLabel,
|
|
10661
|
+
});
|
|
10662
|
+
}
|
|
10663
|
+
}
|
|
10664
|
+
catch (error) {
|
|
10665
|
+
assertsError(error);
|
|
10666
|
+
const serializedError = serializeError(error);
|
|
10667
|
+
failedUploads.push({ index: uploadIndex, filename, error: serializedError });
|
|
10668
|
+
console.error('[🤰]', 'Failed to upload knowledge source file', {
|
|
10669
|
+
index: uploadIndex,
|
|
10670
|
+
total: files.length,
|
|
10671
|
+
filename,
|
|
10672
|
+
sizeBytes,
|
|
10673
|
+
elapsedMs: Date.now() - fileUploadStartedAtMs,
|
|
10674
|
+
logLabel,
|
|
10675
|
+
error: serializedError,
|
|
10676
|
+
});
|
|
10677
|
+
}
|
|
10678
|
+
}
|
|
10679
|
+
};
|
|
10680
|
+
const workerCount = Math.min(maxConcurrency, files.length);
|
|
10681
|
+
const workers = Array.from({ length: workerCount }, () => processFiles(fileIterator));
|
|
10682
|
+
await Promise.all(workers);
|
|
10683
|
+
if (this.options.isVerbose) {
|
|
10684
|
+
console.info('[🤰]', 'Finished uploading knowledge source files', {
|
|
10685
|
+
vectorStoreId,
|
|
10686
|
+
fileCount: files.length,
|
|
10687
|
+
uploadedCount,
|
|
10688
|
+
failedCount: failedUploads.length,
|
|
10689
|
+
elapsedMs: Date.now() - uploadStartedAtMs,
|
|
10690
|
+
failedSamples: failedUploads.slice(0, 3),
|
|
10691
|
+
logLabel,
|
|
10692
|
+
});
|
|
10693
|
+
}
|
|
10694
|
+
if (fileIds.length === 0) {
|
|
10695
|
+
console.error('[🤰]', 'No knowledge source files were uploaded', {
|
|
10696
|
+
vectorStoreId,
|
|
10697
|
+
fileCount: files.length,
|
|
10698
|
+
failedCount: failedUploads.length,
|
|
10699
|
+
logLabel,
|
|
10700
|
+
});
|
|
10701
|
+
return null;
|
|
10702
|
+
}
|
|
10703
|
+
const batch = await vectorStores.fileBatches.create(vectorStoreId, {
|
|
10704
|
+
file_ids: fileIds,
|
|
10705
|
+
});
|
|
10706
|
+
const expectedBatchId = batch.id;
|
|
10707
|
+
const expectedBatchIdValid = expectedBatchId.startsWith('vsfb_');
|
|
10708
|
+
if (!expectedBatchIdValid) {
|
|
10709
|
+
console.error('[🤰]', 'Vector store file batch id looks invalid', {
|
|
10710
|
+
vectorStoreId,
|
|
10711
|
+
batchId: expectedBatchId,
|
|
10712
|
+
batchVectorStoreId: batch.vector_store_id,
|
|
10713
|
+
logLabel,
|
|
10714
|
+
});
|
|
10715
|
+
}
|
|
10716
|
+
else if (batch.vector_store_id !== vectorStoreId) {
|
|
10717
|
+
console.error('[🤰]', 'Vector store file batch vector store id mismatch', {
|
|
10718
|
+
vectorStoreId,
|
|
10719
|
+
batchId: expectedBatchId,
|
|
10720
|
+
batchVectorStoreId: batch.vector_store_id,
|
|
10721
|
+
logLabel,
|
|
10722
|
+
});
|
|
10723
|
+
}
|
|
10724
|
+
if (this.options.isVerbose) {
|
|
10725
|
+
console.info('[🤰]', 'Created vector store file batch', {
|
|
10726
|
+
vectorStoreId,
|
|
10727
|
+
batchId: expectedBatchId,
|
|
10728
|
+
fileCount: fileIds.length,
|
|
10729
|
+
logLabel,
|
|
10730
|
+
});
|
|
10731
|
+
}
|
|
10732
|
+
const pollStartedAtMs = Date.now();
|
|
10733
|
+
const progressLogIntervalMs = Math.max(VECTOR_STORE_PROGRESS_LOG_INTERVAL_MIN_MS, pollIntervalMs);
|
|
10734
|
+
const diagnosticsIntervalMs = Math.max(60000, pollIntervalMs * 5);
|
|
10735
|
+
// let lastStatus: string | undefined;
|
|
10736
|
+
let lastCountsKey = '';
|
|
10737
|
+
let lastProgressKey = '';
|
|
10738
|
+
let lastLogAtMs = 0;
|
|
10739
|
+
let lastProgressAtMs = pollStartedAtMs;
|
|
10740
|
+
let lastDiagnosticsAtMs = pollStartedAtMs;
|
|
10741
|
+
let latestBatch = batch;
|
|
10742
|
+
let loggedBatchIdMismatch = false;
|
|
10743
|
+
let loggedBatchIdFallback = false;
|
|
10744
|
+
let loggedBatchIdInvalid = false;
|
|
10745
|
+
let shouldPoll = true;
|
|
10746
|
+
while (shouldPoll) {
|
|
10747
|
+
const nowMs = Date.now();
|
|
10748
|
+
// [🤰] Note: Sometimes OpenAI returns Vector Store object instead of Batch object, or IDs get swapped.
|
|
10749
|
+
const rawBatchId = typeof latestBatch.id === 'string' ? latestBatch.id : '';
|
|
10750
|
+
const rawVectorStoreId = latestBatch.vector_store_id;
|
|
10751
|
+
let returnedBatchId = rawBatchId;
|
|
10752
|
+
let returnedBatchIdValid = typeof returnedBatchId === 'string' && returnedBatchId.startsWith('vsfb_');
|
|
10753
|
+
if (!returnedBatchIdValid && expectedBatchIdValid) {
|
|
10754
|
+
if (!loggedBatchIdFallback) {
|
|
10755
|
+
console.error('[🤰]', 'Vector store file batch id missing from response; falling back to expected', {
|
|
10756
|
+
vectorStoreId,
|
|
10757
|
+
expectedBatchId,
|
|
10758
|
+
returnedBatchId,
|
|
10759
|
+
rawVectorStoreId,
|
|
10760
|
+
logLabel,
|
|
10761
|
+
});
|
|
10762
|
+
loggedBatchIdFallback = true;
|
|
10763
|
+
}
|
|
10764
|
+
returnedBatchId = expectedBatchId;
|
|
10765
|
+
returnedBatchIdValid = true;
|
|
10766
|
+
}
|
|
10767
|
+
if (!returnedBatchIdValid && !loggedBatchIdInvalid) {
|
|
10768
|
+
console.error('[🤰]', 'Vector store file batch id is invalid; stopping polling', {
|
|
10769
|
+
vectorStoreId,
|
|
10770
|
+
expectedBatchId,
|
|
10771
|
+
returnedBatchId,
|
|
10772
|
+
rawVectorStoreId,
|
|
10773
|
+
logLabel,
|
|
10774
|
+
});
|
|
10775
|
+
loggedBatchIdInvalid = true;
|
|
10776
|
+
}
|
|
10777
|
+
const batchIdMismatch = expectedBatchIdValid && returnedBatchIdValid && returnedBatchId !== expectedBatchId;
|
|
10778
|
+
if (batchIdMismatch && !loggedBatchIdMismatch) {
|
|
10779
|
+
console.error('[🤰]', 'Vector store file batch id mismatch', {
|
|
10780
|
+
vectorStoreId,
|
|
10781
|
+
expectedBatchId,
|
|
10782
|
+
returnedBatchId,
|
|
10783
|
+
logLabel,
|
|
10784
|
+
});
|
|
10785
|
+
loggedBatchIdMismatch = true;
|
|
10786
|
+
}
|
|
10787
|
+
if (returnedBatchIdValid) {
|
|
10788
|
+
latestBatch = await vectorStores.fileBatches.retrieve(returnedBatchId, {
|
|
10789
|
+
vector_store_id: vectorStoreId,
|
|
10790
|
+
});
|
|
10791
|
+
}
|
|
10792
|
+
else {
|
|
10793
|
+
shouldPoll = false;
|
|
10794
|
+
continue;
|
|
10795
|
+
}
|
|
10796
|
+
const status = (_e = latestBatch.status) !== null && _e !== void 0 ? _e : 'unknown';
|
|
10797
|
+
const fileCounts = (_f = latestBatch.file_counts) !== null && _f !== void 0 ? _f : {};
|
|
10798
|
+
const progressKey = JSON.stringify(fileCounts);
|
|
10799
|
+
const statusCountsKey = `${status}-${progressKey}`;
|
|
10800
|
+
const isProgressing = progressKey !== lastProgressKey;
|
|
10801
|
+
if (isProgressing) {
|
|
10802
|
+
lastProgressAtMs = nowMs;
|
|
10803
|
+
lastProgressKey = progressKey;
|
|
10804
|
+
}
|
|
10805
|
+
if (this.options.isVerbose &&
|
|
10806
|
+
(statusCountsKey !== lastCountsKey || nowMs - lastLogAtMs >= progressLogIntervalMs)) {
|
|
10807
|
+
console.info('[🤰]', 'Vector store file batch status', {
|
|
10808
|
+
vectorStoreId,
|
|
10809
|
+
batchId: returnedBatchId,
|
|
10810
|
+
status,
|
|
10811
|
+
fileCounts,
|
|
10812
|
+
elapsedMs: nowMs - pollStartedAtMs,
|
|
10813
|
+
logLabel,
|
|
10814
|
+
});
|
|
10815
|
+
lastCountsKey = statusCountsKey;
|
|
10816
|
+
lastLogAtMs = nowMs;
|
|
10817
|
+
}
|
|
10818
|
+
if (status === 'in_progress' &&
|
|
10819
|
+
nowMs - lastProgressAtMs >= VECTOR_STORE_STALL_LOG_THRESHOLD_MS &&
|
|
10820
|
+
nowMs - lastDiagnosticsAtMs >= diagnosticsIntervalMs) {
|
|
10821
|
+
lastDiagnosticsAtMs = nowMs;
|
|
10822
|
+
await this.logVectorStoreFileBatchDiagnostics({
|
|
10823
|
+
client,
|
|
10824
|
+
vectorStoreId,
|
|
10825
|
+
batchId: returnedBatchId,
|
|
10826
|
+
uploadedFiles,
|
|
10827
|
+
logLabel,
|
|
10828
|
+
reason: 'stalled',
|
|
10829
|
+
});
|
|
10830
|
+
}
|
|
10831
|
+
if (status === 'completed') {
|
|
10832
|
+
if (this.options.isVerbose) {
|
|
10833
|
+
console.info('[🤰]', 'Vector store file batch completed', {
|
|
10834
|
+
vectorStoreId,
|
|
10835
|
+
batchId: returnedBatchId,
|
|
10836
|
+
fileCounts,
|
|
10837
|
+
elapsedMs: nowMs - pollStartedAtMs,
|
|
10838
|
+
logLabel,
|
|
10839
|
+
});
|
|
10840
|
+
}
|
|
10841
|
+
shouldPoll = false;
|
|
10842
|
+
continue;
|
|
10843
|
+
}
|
|
10844
|
+
if (status === 'failed') {
|
|
10845
|
+
console.error('[🤰]', 'Vector store file batch completed with failures', {
|
|
10846
|
+
vectorStoreId,
|
|
10847
|
+
batchId: returnedBatchId,
|
|
10848
|
+
fileCounts,
|
|
10849
|
+
elapsedMs: nowMs - pollStartedAtMs,
|
|
10850
|
+
logLabel,
|
|
10851
|
+
});
|
|
10852
|
+
await this.logVectorStoreFileBatchDiagnostics({
|
|
10853
|
+
client,
|
|
10854
|
+
vectorStoreId,
|
|
10855
|
+
batchId: returnedBatchId,
|
|
10856
|
+
uploadedFiles,
|
|
10857
|
+
logLabel,
|
|
10858
|
+
reason: 'failed',
|
|
10859
|
+
});
|
|
10860
|
+
shouldPoll = false;
|
|
10861
|
+
continue;
|
|
10862
|
+
}
|
|
10863
|
+
if (status === 'cancelled') {
|
|
10864
|
+
console.error('[🤰]', 'Vector store file batch did not complete', {
|
|
10865
|
+
vectorStoreId,
|
|
10866
|
+
batchId: returnedBatchId,
|
|
10867
|
+
status,
|
|
10868
|
+
fileCounts,
|
|
10869
|
+
elapsedMs: nowMs - pollStartedAtMs,
|
|
10870
|
+
logLabel,
|
|
10871
|
+
});
|
|
10872
|
+
await this.logVectorStoreFileBatchDiagnostics({
|
|
10873
|
+
client,
|
|
10874
|
+
vectorStoreId,
|
|
10875
|
+
batchId: returnedBatchId,
|
|
10876
|
+
uploadedFiles,
|
|
10877
|
+
logLabel,
|
|
10878
|
+
reason: 'failed',
|
|
10879
|
+
});
|
|
10880
|
+
shouldPoll = false;
|
|
10881
|
+
continue;
|
|
10882
|
+
}
|
|
10883
|
+
if (nowMs - pollStartedAtMs >= uploadTimeoutMs) {
|
|
10884
|
+
console.error('[🤰]', 'Timed out waiting for vector store file batch', {
|
|
10885
|
+
vectorStoreId,
|
|
10886
|
+
batchId: returnedBatchId,
|
|
10887
|
+
fileCounts,
|
|
10888
|
+
elapsedMs: nowMs - pollStartedAtMs,
|
|
10889
|
+
uploadTimeoutMs,
|
|
10890
|
+
logLabel,
|
|
10891
|
+
});
|
|
10892
|
+
await this.logVectorStoreFileBatchDiagnostics({
|
|
10893
|
+
client,
|
|
10894
|
+
vectorStoreId,
|
|
10895
|
+
batchId: returnedBatchId,
|
|
10896
|
+
uploadedFiles,
|
|
10897
|
+
logLabel,
|
|
10898
|
+
reason: 'timeout',
|
|
10899
|
+
});
|
|
10900
|
+
if (this.shouldContinueOnVectorStoreStall()) {
|
|
10901
|
+
console.warn('[🤰]', 'Continuing despite vector store timeout as requested', {
|
|
10902
|
+
vectorStoreId,
|
|
10903
|
+
logLabel,
|
|
10904
|
+
});
|
|
10905
|
+
shouldPoll = false;
|
|
10906
|
+
continue;
|
|
10907
|
+
}
|
|
10908
|
+
try {
|
|
10909
|
+
const cancelBatchId = batchIdMismatch && returnedBatchId.startsWith('vsfb_') ? returnedBatchId : expectedBatchId;
|
|
10910
|
+
if (!cancelBatchId.startsWith('vsfb_')) {
|
|
10911
|
+
console.error('[🤰]', 'Skipping vector store file batch cancel (invalid batch id)', {
|
|
10912
|
+
vectorStoreId,
|
|
10913
|
+
batchId: cancelBatchId,
|
|
10914
|
+
logLabel,
|
|
10915
|
+
});
|
|
10916
|
+
}
|
|
10917
|
+
else {
|
|
10918
|
+
await vectorStores.fileBatches.cancel(cancelBatchId, {
|
|
10919
|
+
vector_store_id: vectorStoreId,
|
|
10920
|
+
});
|
|
10921
|
+
}
|
|
10922
|
+
if (this.options.isVerbose) {
|
|
10923
|
+
console.info('[🤰]', 'Cancelled vector store file batch after timeout', {
|
|
10924
|
+
vectorStoreId,
|
|
10925
|
+
batchId: batchIdMismatch && returnedBatchId.startsWith('vsfb_')
|
|
10926
|
+
? returnedBatchId
|
|
10927
|
+
: expectedBatchId,
|
|
10928
|
+
...(batchIdMismatch ? { returnedBatchId } : {}),
|
|
10929
|
+
logLabel,
|
|
10930
|
+
});
|
|
10931
|
+
}
|
|
10932
|
+
}
|
|
10933
|
+
catch (error) {
|
|
10934
|
+
assertsError(error);
|
|
10935
|
+
console.error('[🤰]', 'Failed to cancel vector store file batch after timeout', {
|
|
10936
|
+
vectorStoreId,
|
|
10937
|
+
batchId: expectedBatchId,
|
|
10938
|
+
...(batchIdMismatch ? { returnedBatchId } : {}),
|
|
10939
|
+
logLabel,
|
|
10940
|
+
error: serializeError(error),
|
|
10941
|
+
});
|
|
10942
|
+
}
|
|
10943
|
+
shouldPoll = false;
|
|
10944
|
+
continue;
|
|
10945
|
+
}
|
|
10946
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
10947
|
+
}
|
|
10948
|
+
return latestBatch;
|
|
10949
|
+
}
|
|
10950
|
+
/**
|
|
10951
|
+
* Creates a vector store and uploads knowledge sources, returning its ID.
|
|
10952
|
+
*/
|
|
10953
|
+
async createVectorStoreWithKnowledgeSources(options) {
|
|
10954
|
+
const { client, name, knowledgeSources, logLabel } = options;
|
|
10955
|
+
const vectorStores = this.getVectorStoresApi(client);
|
|
10956
|
+
const knowledgeSourcesCount = knowledgeSources.length;
|
|
10957
|
+
const downloadTimeoutMs = this.getKnowledgeSourceDownloadTimeoutMs();
|
|
10958
|
+
if (this.options.isVerbose) {
|
|
10959
|
+
console.info('[🤰]', 'Creating vector store with knowledge sources', {
|
|
10960
|
+
name,
|
|
10961
|
+
knowledgeSourcesCount,
|
|
10962
|
+
downloadTimeoutMs,
|
|
10963
|
+
logLabel,
|
|
10964
|
+
});
|
|
10965
|
+
}
|
|
10966
|
+
const vectorStore = await vectorStores.create({
|
|
10967
|
+
name: `${name} Knowledge Base`,
|
|
10968
|
+
});
|
|
10969
|
+
const vectorStoreId = vectorStore.id;
|
|
10970
|
+
if (this.options.isVerbose) {
|
|
10971
|
+
console.info('[🤰]', 'Vector store created', {
|
|
10972
|
+
vectorStoreId,
|
|
10973
|
+
logLabel,
|
|
10974
|
+
});
|
|
10975
|
+
}
|
|
10976
|
+
const fileStreams = [];
|
|
10977
|
+
const skippedSources = [];
|
|
10978
|
+
let totalBytes = 0;
|
|
10979
|
+
const processingStartedAtMs = Date.now();
|
|
10980
|
+
for (const [index, source] of knowledgeSources.entries()) {
|
|
10981
|
+
try {
|
|
10982
|
+
const isDataUrl = isDataUrlKnowledgeSource(source);
|
|
10983
|
+
const isHttp = source.startsWith('http://') || source.startsWith('https://');
|
|
10984
|
+
const sourceType = isDataUrl ? 'data_url' : isHttp ? 'url' : 'file';
|
|
10985
|
+
if (this.options.isVerbose) {
|
|
10986
|
+
console.info('[🤰]', 'Processing knowledge source', {
|
|
10987
|
+
index: index + 1,
|
|
10988
|
+
total: knowledgeSourcesCount,
|
|
10989
|
+
source,
|
|
10990
|
+
sourceType,
|
|
10991
|
+
logLabel,
|
|
10992
|
+
});
|
|
10993
|
+
}
|
|
10994
|
+
if (isDataUrl) {
|
|
10995
|
+
const parsed = parseDataUrlKnowledgeSource(source);
|
|
10996
|
+
if (!parsed) {
|
|
10997
|
+
skippedSources.push({ source, reason: 'invalid_data_url' });
|
|
10998
|
+
if (this.options.isVerbose) {
|
|
10999
|
+
console.info('[🤰]', 'Skipping knowledge source (invalid data URL)', {
|
|
11000
|
+
source,
|
|
11001
|
+
sourceType,
|
|
11002
|
+
logLabel,
|
|
11003
|
+
});
|
|
11004
|
+
}
|
|
11005
|
+
continue;
|
|
11006
|
+
}
|
|
11007
|
+
const dataUrlFile = new File([parsed.buffer], parsed.filename, {
|
|
11008
|
+
type: parsed.mimeType,
|
|
11009
|
+
});
|
|
11010
|
+
fileStreams.push(dataUrlFile);
|
|
11011
|
+
totalBytes += parsed.buffer.length;
|
|
11012
|
+
continue;
|
|
11013
|
+
}
|
|
11014
|
+
if (isHttp) {
|
|
11015
|
+
const downloadResult = await this.downloadKnowledgeSourceFile({
|
|
11016
|
+
source,
|
|
11017
|
+
timeoutMs: downloadTimeoutMs,
|
|
11018
|
+
logLabel,
|
|
11019
|
+
});
|
|
11020
|
+
if (downloadResult) {
|
|
11021
|
+
fileStreams.push(downloadResult.file);
|
|
11022
|
+
totalBytes += downloadResult.sizeBytes;
|
|
11023
|
+
}
|
|
11024
|
+
else {
|
|
11025
|
+
skippedSources.push({ source, reason: 'download_failed' });
|
|
11026
|
+
}
|
|
11027
|
+
}
|
|
11028
|
+
else {
|
|
11029
|
+
skippedSources.push({ source, reason: 'unsupported_source_type' });
|
|
11030
|
+
if (this.options.isVerbose) {
|
|
11031
|
+
console.info('[🤰]', 'Skipping knowledge source (unsupported type)', {
|
|
11032
|
+
source,
|
|
11033
|
+
sourceType,
|
|
11034
|
+
logLabel,
|
|
11035
|
+
});
|
|
11036
|
+
}
|
|
11037
|
+
/*
|
|
11038
|
+
TODO: [🤰] Resolve problem with browser environment
|
|
11039
|
+
// Assume it's a local file path
|
|
11040
|
+
// Note: This will work in Node.js environment
|
|
11041
|
+
// For browser environments, this would need different handling
|
|
11042
|
+
const fs = await import('fs');
|
|
11043
|
+
const fileStream = fs.createReadStream(source);
|
|
11044
|
+
fileStreams.push(fileStream);
|
|
11045
|
+
*/
|
|
11046
|
+
}
|
|
11047
|
+
}
|
|
11048
|
+
catch (error) {
|
|
11049
|
+
assertsError(error);
|
|
11050
|
+
skippedSources.push({ source, reason: 'processing_error' });
|
|
11051
|
+
console.error('[🤰]', 'Error processing knowledge source', {
|
|
11052
|
+
source,
|
|
11053
|
+
logLabel,
|
|
11054
|
+
error: serializeError(error),
|
|
11055
|
+
});
|
|
11056
|
+
}
|
|
11057
|
+
}
|
|
11058
|
+
if (this.options.isVerbose) {
|
|
11059
|
+
console.info('[🤰]', 'Finished processing knowledge sources', {
|
|
11060
|
+
total: knowledgeSourcesCount,
|
|
11061
|
+
downloadedCount: fileStreams.length,
|
|
11062
|
+
skippedCount: skippedSources.length,
|
|
11063
|
+
totalBytes,
|
|
11064
|
+
elapsedMs: Date.now() - processingStartedAtMs,
|
|
11065
|
+
skippedSamples: skippedSources.slice(0, 3),
|
|
11066
|
+
logLabel,
|
|
11067
|
+
});
|
|
11068
|
+
}
|
|
11069
|
+
if (fileStreams.length > 0) {
|
|
11070
|
+
if (this.options.isVerbose) {
|
|
11071
|
+
console.info('[🤰]', 'Uploading files to vector store', {
|
|
11072
|
+
vectorStoreId,
|
|
11073
|
+
fileCount: fileStreams.length,
|
|
11074
|
+
totalBytes,
|
|
11075
|
+
maxConcurrency: this.getKnowledgeSourceUploadMaxConcurrency(),
|
|
11076
|
+
pollIntervalMs: this.getKnowledgeSourceUploadPollIntervalMs(),
|
|
11077
|
+
uploadTimeoutMs: this.getKnowledgeSourceUploadTimeoutMs(),
|
|
11078
|
+
logLabel,
|
|
11079
|
+
});
|
|
11080
|
+
}
|
|
11081
|
+
try {
|
|
11082
|
+
await this.uploadKnowledgeSourceFilesToVectorStore({
|
|
11083
|
+
client,
|
|
11084
|
+
vectorStoreId,
|
|
11085
|
+
files: fileStreams,
|
|
11086
|
+
totalBytes,
|
|
11087
|
+
logLabel,
|
|
11088
|
+
});
|
|
11089
|
+
}
|
|
11090
|
+
catch (error) {
|
|
11091
|
+
assertsError(error);
|
|
11092
|
+
console.error('[🤰]', 'Error uploading files to vector store', {
|
|
11093
|
+
vectorStoreId,
|
|
11094
|
+
logLabel,
|
|
11095
|
+
error: serializeError(error),
|
|
11096
|
+
});
|
|
11097
|
+
}
|
|
11098
|
+
}
|
|
11099
|
+
else if (this.options.isVerbose) {
|
|
11100
|
+
console.info('[🤰]', 'No knowledge source files to upload', {
|
|
11101
|
+
vectorStoreId,
|
|
11102
|
+
skippedCount: skippedSources.length,
|
|
11103
|
+
logLabel,
|
|
11104
|
+
});
|
|
11105
|
+
}
|
|
11106
|
+
return {
|
|
11107
|
+
vectorStoreId,
|
|
11108
|
+
uploadedFileCount: fileStreams.length,
|
|
11109
|
+
skippedCount: skippedSources.length,
|
|
11110
|
+
totalBytes,
|
|
11111
|
+
};
|
|
11112
|
+
}
|
|
11113
|
+
}
|
|
11114
|
+
|
|
11115
|
+
/**
|
|
11116
|
+
* Uploads files to OpenAI and returns their IDs
|
|
11117
|
+
*
|
|
11118
|
+
* @private utility for `OpenAiAssistantExecutionTools` and `OpenAiCompatibleExecutionTools`
|
|
11119
|
+
*/
|
|
11120
|
+
async function uploadFilesToOpenAi(client, files) {
|
|
11121
|
+
const fileIds = [];
|
|
11122
|
+
for (const file of files) {
|
|
11123
|
+
// Note: OpenAI API expects a File object or a ReadStream
|
|
11124
|
+
// In browser environment, we can pass the File object directly
|
|
11125
|
+
// In Node.js environment, we might need to convert it or use a different approach
|
|
11126
|
+
// But since `Prompt.files` already contains `File` objects, we try to pass them directly
|
|
11127
|
+
const uploadedFile = await client.files.create({
|
|
11128
|
+
file: file,
|
|
11129
|
+
purpose: 'assistants',
|
|
11130
|
+
});
|
|
11131
|
+
fileIds.push(uploadedFile.id);
|
|
11132
|
+
}
|
|
11133
|
+
return fileIds;
|
|
11134
|
+
}
|
|
11135
|
+
|
|
11136
|
+
/**
|
|
11137
|
+
* Execution Tools for calling OpenAI API Assistants
|
|
11138
|
+
*
|
|
11139
|
+
* This is useful for calling OpenAI API with a single assistant, for more wide usage use `OpenAiExecutionTools`.
|
|
11140
|
+
*
|
|
11141
|
+
* Note: [🦖] There are several different things in Promptbook:
|
|
11142
|
+
* - `Agent` - which represents an AI Agent with its source, memories, actions, etc. Agent is a higher-level abstraction which is internally using:
|
|
11143
|
+
* - `LlmExecutionTools` - which wraps one or more LLM models and provides an interface to execute them
|
|
11144
|
+
* - `AgentLlmExecutionTools` - which is a specific implementation of `LlmExecutionTools` that wraps another LlmExecutionTools and applies agent-specific system prompts and requirements
|
|
11145
|
+
* - `OpenAiAssistantExecutionTools` - which is a specific implementation of `LlmExecutionTools` for OpenAI models with assistant capabilities, recommended for usage in `Agent` or `AgentLlmExecutionTools`
|
|
11146
|
+
* - `RemoteAgent` - which is an `Agent` that connects to a Promptbook Agents Server
|
|
11147
|
+
*
|
|
11148
|
+
* @deprecated Use `OpenAiAgentKitExecutionTools` instead.
|
|
11149
|
+
* @public exported from `@promptbook/openai`
|
|
11150
|
+
*/
|
|
11151
|
+
class OpenAiAssistantExecutionTools extends OpenAiVectorStoreHandler {
|
|
11152
|
+
/**
|
|
11153
|
+
* Creates OpenAI Execution Tools.
|
|
11154
|
+
*
|
|
11155
|
+
* @param options which are relevant are directly passed to the OpenAI client
|
|
11156
|
+
*/
|
|
11157
|
+
constructor(options) {
|
|
11158
|
+
var _a;
|
|
11159
|
+
if (options.isProxied) {
|
|
11160
|
+
throw new NotYetImplementedError(`Proxy mode is not yet implemented for OpenAI assistants`);
|
|
11161
|
+
}
|
|
11162
|
+
super(options);
|
|
11163
|
+
this.isCreatingNewAssistantsAllowed = false;
|
|
11164
|
+
this.assistantId = options.assistantId;
|
|
11165
|
+
this.isCreatingNewAssistantsAllowed = (_a = options.isCreatingNewAssistantsAllowed) !== null && _a !== void 0 ? _a : false;
|
|
11166
|
+
if (this.assistantId === null && !this.isCreatingNewAssistantsAllowed) {
|
|
11167
|
+
throw new NotAllowed(`Assistant ID is null and creating new assistants is not allowed - this configuration does not make sense`);
|
|
11168
|
+
}
|
|
11169
|
+
// <- TODO: !!! `OpenAiAssistantExecutionToolsOptions` - Allow `assistantId: null` together with `isCreatingNewAssistantsAllowed: true`
|
|
11170
|
+
// TODO: [👱] Make limiter same as in `OpenAiExecutionTools`
|
|
11171
|
+
}
|
|
11172
|
+
get title() {
|
|
11173
|
+
return 'OpenAI Assistant';
|
|
11174
|
+
}
|
|
11175
|
+
get description() {
|
|
11176
|
+
return 'Use single assistant provided by OpenAI';
|
|
11177
|
+
}
|
|
11178
|
+
/**
|
|
11179
|
+
* Calls OpenAI API to use a chat model.
|
|
11180
|
+
*/
|
|
11181
|
+
async callChatModel(prompt) {
|
|
11182
|
+
return this.callChatModelStream(prompt, () => { });
|
|
11183
|
+
}
|
|
11184
|
+
/**
|
|
11185
|
+
* Calls OpenAI API to use a chat model with streaming.
|
|
11186
|
+
*/
|
|
11187
|
+
async callChatModelStream(prompt, onProgress) {
|
|
11188
|
+
var _a, _b, _c, _d, _e, _f;
|
|
11189
|
+
if (this.options.isVerbose) {
|
|
11190
|
+
console.info('💬 OpenAI callChatModel call', { prompt });
|
|
11191
|
+
}
|
|
11192
|
+
const { content, parameters, modelRequirements /*, format*/ } = prompt;
|
|
11193
|
+
const client = await this.getClient();
|
|
11194
|
+
// TODO: [☂] Use here more modelRequirements
|
|
11195
|
+
if (modelRequirements.modelVariant !== 'CHAT') {
|
|
11196
|
+
throw new PipelineExecutionError('Use callChatModel only for CHAT variant');
|
|
11197
|
+
}
|
|
11198
|
+
// TODO: [👨👨👧👧] Remove:
|
|
11199
|
+
for (const key of ['maxTokens', 'modelName', 'seed', 'temperature']) {
|
|
11200
|
+
if (modelRequirements[key] !== undefined) {
|
|
11201
|
+
throw new NotYetImplementedError(`In \`OpenAiAssistantExecutionTools\` you cannot specify \`${key}\``);
|
|
11202
|
+
}
|
|
11203
|
+
}
|
|
11204
|
+
/*
|
|
11205
|
+
TODO: [👨👨👧👧] Implement all of this for Assistants
|
|
11206
|
+
const modelName = modelRequirements.modelName || this.getDefaultChatModel().modelName;
|
|
11207
|
+
const modelSettings = {
|
|
11208
|
+
model: modelName,
|
|
11209
|
+
|
|
11210
|
+
temperature: modelRequirements.temperature,
|
|
11211
|
+
|
|
11212
|
+
// <- TODO: [🈁] Use `seed` here AND/OR use is `isDeterministic` for entire execution tools
|
|
11213
|
+
// <- Note: [🧆]
|
|
11214
|
+
} as OpenAI.Chat.Completions.CompletionCreateParamsNonStreaming; // <- TODO: Guard here types better
|
|
11215
|
+
|
|
11216
|
+
if (format === 'JSON') {
|
|
11217
|
+
modelSettings.response_format = {
|
|
11218
|
+
type: 'json_object',
|
|
11219
|
+
};
|
|
11220
|
+
}
|
|
11221
|
+
*/
|
|
11222
|
+
// <- TODO: [🚸] Not all models are compatible with JSON mode
|
|
11223
|
+
// > 'response_format' of type 'json_object' is not supported with this model.
|
|
11224
|
+
const rawPromptContent = templateParameters(content, {
|
|
11225
|
+
...parameters,
|
|
11226
|
+
modelName: 'assistant',
|
|
11227
|
+
// <- [🧠] What is the best value here
|
|
11228
|
+
});
|
|
11229
|
+
// Build thread messages: include previous thread messages + current user message
|
|
11230
|
+
const threadMessages = [];
|
|
11231
|
+
// TODO: [🈹] Maybe this should not be here but in other place, look at commit 39d705e75e5bcf7a818c3af36bc13e1c8475c30c
|
|
11232
|
+
// Add previous messages from thread (if any)
|
|
11233
|
+
if ('thread' in prompt && Array.isArray(prompt.thread)) {
|
|
11234
|
+
const previousMessages = prompt.thread.map((msg) => ({
|
|
11235
|
+
role: (msg.sender === 'assistant' ? 'assistant' : 'user'),
|
|
11236
|
+
content: msg.content,
|
|
11237
|
+
}));
|
|
10265
11238
|
threadMessages.push(...previousMessages);
|
|
10266
11239
|
}
|
|
10267
11240
|
// Always add the current user message
|
|
@@ -10304,8 +11277,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
10304
11277
|
console.info(colors.bgWhite('rawRequest (non-streaming with tools)'), JSON.stringify(rawRequest, null, 4));
|
|
10305
11278
|
}
|
|
10306
11279
|
// Create thread and run
|
|
10307
|
-
|
|
10308
|
-
let run = threadAndRun;
|
|
11280
|
+
let run = (await client.beta.threads.createAndRun(rawRequest));
|
|
10309
11281
|
const completedToolCalls = [];
|
|
10310
11282
|
const toolCallStartedAt = new Map();
|
|
10311
11283
|
// Poll until run completes or requires action
|
|
@@ -10400,14 +11372,14 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
10400
11372
|
}
|
|
10401
11373
|
}
|
|
10402
11374
|
// Submit tool outputs
|
|
10403
|
-
run = await client.beta.threads.runs.submitToolOutputs(run.thread_id, run.id, {
|
|
11375
|
+
run = (await client.beta.threads.runs.submitToolOutputs(run.thread_id, run.id, {
|
|
10404
11376
|
tool_outputs: toolOutputs,
|
|
10405
|
-
});
|
|
11377
|
+
}));
|
|
10406
11378
|
}
|
|
10407
11379
|
else {
|
|
10408
11380
|
// Wait a bit before polling again
|
|
10409
11381
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
10410
|
-
run = await client.beta.threads.runs.retrieve(run.thread_id, run.id);
|
|
11382
|
+
run = (await client.beta.threads.runs.retrieve(run.thread_id, run.id));
|
|
10411
11383
|
}
|
|
10412
11384
|
}
|
|
10413
11385
|
if (run.status !== 'completed') {
|
|
@@ -10606,6 +11578,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
10606
11578
|
getAssistant(assistantId) {
|
|
10607
11579
|
return new OpenAiAssistantExecutionTools({
|
|
10608
11580
|
...this.options,
|
|
11581
|
+
isCreatingNewAssistantsAllowed: this.isCreatingNewAssistantsAllowed,
|
|
10609
11582
|
assistantId,
|
|
10610
11583
|
});
|
|
10611
11584
|
}
|
|
@@ -10631,88 +11604,13 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
10631
11604
|
let vectorStoreId;
|
|
10632
11605
|
// If knowledge sources are provided, create a vector store with them
|
|
10633
11606
|
if (knowledgeSources && knowledgeSources.length > 0) {
|
|
10634
|
-
|
|
10635
|
-
|
|
10636
|
-
|
|
10637
|
-
|
|
10638
|
-
|
|
10639
|
-
}
|
|
10640
|
-
// Create a vector store
|
|
10641
|
-
const vectorStore = await client.beta.vectorStores.create({
|
|
10642
|
-
name: `${name} Knowledge Base`,
|
|
11607
|
+
const vectorStoreResult = await this.createVectorStoreWithKnowledgeSources({
|
|
11608
|
+
client,
|
|
11609
|
+
name,
|
|
11610
|
+
knowledgeSources,
|
|
11611
|
+
logLabel: 'assistant creation',
|
|
10643
11612
|
});
|
|
10644
|
-
vectorStoreId =
|
|
10645
|
-
if (this.options.isVerbose) {
|
|
10646
|
-
console.info('[🤰]', 'Vector store created', {
|
|
10647
|
-
vectorStoreId,
|
|
10648
|
-
});
|
|
10649
|
-
}
|
|
10650
|
-
// Upload files from knowledge sources to the vector store
|
|
10651
|
-
const fileStreams = [];
|
|
10652
|
-
for (const [index, source] of knowledgeSources.entries()) {
|
|
10653
|
-
try {
|
|
10654
|
-
if (this.options.isVerbose) {
|
|
10655
|
-
console.info('[🤰]', 'Processing knowledge source', {
|
|
10656
|
-
index: index + 1,
|
|
10657
|
-
total: knowledgeSources.length,
|
|
10658
|
-
source,
|
|
10659
|
-
sourceType: source.startsWith('http') || source.startsWith('https') ? 'url' : 'file',
|
|
10660
|
-
});
|
|
10661
|
-
}
|
|
10662
|
-
// Check if it's a URL
|
|
10663
|
-
if (source.startsWith('http://') || source.startsWith('https://')) {
|
|
10664
|
-
// Download the file
|
|
10665
|
-
const response = await fetch(source);
|
|
10666
|
-
if (!response.ok) {
|
|
10667
|
-
console.error(`Failed to download ${source}: ${response.statusText}`);
|
|
10668
|
-
continue;
|
|
10669
|
-
}
|
|
10670
|
-
const buffer = await response.arrayBuffer();
|
|
10671
|
-
let filename = source.split('/').pop() || 'downloaded-file';
|
|
10672
|
-
try {
|
|
10673
|
-
const url = new URL(source);
|
|
10674
|
-
filename = url.pathname.split('/').pop() || filename;
|
|
10675
|
-
}
|
|
10676
|
-
catch (error) {
|
|
10677
|
-
// Keep default filename
|
|
10678
|
-
}
|
|
10679
|
-
const blob = new Blob([buffer]);
|
|
10680
|
-
const file = new File([blob], filename);
|
|
10681
|
-
fileStreams.push(file);
|
|
10682
|
-
}
|
|
10683
|
-
else {
|
|
10684
|
-
/*
|
|
10685
|
-
TODO: [🐱🚀] Resolve problem with browser environment
|
|
10686
|
-
// Assume it's a local file path
|
|
10687
|
-
// Note: This will work in Node.js environment
|
|
10688
|
-
// For browser environments, this would need different handling
|
|
10689
|
-
const fs = await import('fs');
|
|
10690
|
-
const fileStream = fs.createReadStream(source);
|
|
10691
|
-
fileStreams.push(fileStream);
|
|
10692
|
-
*/
|
|
10693
|
-
}
|
|
10694
|
-
}
|
|
10695
|
-
catch (error) {
|
|
10696
|
-
console.error(`Error processing knowledge source ${source}:`, error);
|
|
10697
|
-
}
|
|
10698
|
-
}
|
|
10699
|
-
// Batch upload files to the vector store
|
|
10700
|
-
if (fileStreams.length > 0) {
|
|
10701
|
-
try {
|
|
10702
|
-
await client.beta.vectorStores.fileBatches.uploadAndPoll(vectorStoreId, {
|
|
10703
|
-
files: fileStreams,
|
|
10704
|
-
});
|
|
10705
|
-
if (this.options.isVerbose) {
|
|
10706
|
-
console.info('[🤰]', 'Uploaded files to vector store', {
|
|
10707
|
-
vectorStoreId,
|
|
10708
|
-
fileCount: fileStreams.length,
|
|
10709
|
-
});
|
|
10710
|
-
}
|
|
10711
|
-
}
|
|
10712
|
-
catch (error) {
|
|
10713
|
-
console.error('Error uploading files to vector store:', error);
|
|
10714
|
-
}
|
|
10715
|
-
}
|
|
11613
|
+
vectorStoreId = vectorStoreResult.vectorStoreId;
|
|
10716
11614
|
}
|
|
10717
11615
|
// Create assistant with vector store attached
|
|
10718
11616
|
const assistantConfig = {
|
|
@@ -10779,91 +11677,14 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
10779
11677
|
const client = await this.getClient();
|
|
10780
11678
|
let vectorStoreId;
|
|
10781
11679
|
// If knowledge sources are provided, create a vector store with them
|
|
10782
|
-
// TODO: [🧠] Reuse vector store creation logic from createNewAssistant
|
|
10783
11680
|
if (knowledgeSources && knowledgeSources.length > 0) {
|
|
10784
|
-
|
|
10785
|
-
|
|
10786
|
-
|
|
10787
|
-
|
|
10788
|
-
|
|
10789
|
-
});
|
|
10790
|
-
}
|
|
10791
|
-
// Create a vector store
|
|
10792
|
-
const vectorStore = await client.beta.vectorStores.create({
|
|
10793
|
-
name: `${name} Knowledge Base`,
|
|
11681
|
+
const vectorStoreResult = await this.createVectorStoreWithKnowledgeSources({
|
|
11682
|
+
client,
|
|
11683
|
+
name: name !== null && name !== void 0 ? name : assistantId,
|
|
11684
|
+
knowledgeSources,
|
|
11685
|
+
logLabel: 'assistant update',
|
|
10794
11686
|
});
|
|
10795
|
-
vectorStoreId =
|
|
10796
|
-
if (this.options.isVerbose) {
|
|
10797
|
-
console.info('[🤰]', 'Vector store created for assistant update', {
|
|
10798
|
-
vectorStoreId,
|
|
10799
|
-
});
|
|
10800
|
-
}
|
|
10801
|
-
// Upload files from knowledge sources to the vector store
|
|
10802
|
-
const fileStreams = [];
|
|
10803
|
-
for (const [index, source] of knowledgeSources.entries()) {
|
|
10804
|
-
try {
|
|
10805
|
-
if (this.options.isVerbose) {
|
|
10806
|
-
console.info('[🤰]', 'Processing knowledge source for update', {
|
|
10807
|
-
index: index + 1,
|
|
10808
|
-
total: knowledgeSources.length,
|
|
10809
|
-
source,
|
|
10810
|
-
sourceType: source.startsWith('http') || source.startsWith('https') ? 'url' : 'file',
|
|
10811
|
-
});
|
|
10812
|
-
}
|
|
10813
|
-
// Check if it's a URL
|
|
10814
|
-
if (source.startsWith('http://') || source.startsWith('https://')) {
|
|
10815
|
-
// Download the file
|
|
10816
|
-
const response = await fetch(source);
|
|
10817
|
-
if (!response.ok) {
|
|
10818
|
-
console.error(`Failed to download ${source}: ${response.statusText}`);
|
|
10819
|
-
continue;
|
|
10820
|
-
}
|
|
10821
|
-
const buffer = await response.arrayBuffer();
|
|
10822
|
-
let filename = source.split('/').pop() || 'downloaded-file';
|
|
10823
|
-
try {
|
|
10824
|
-
const url = new URL(source);
|
|
10825
|
-
filename = url.pathname.split('/').pop() || filename;
|
|
10826
|
-
}
|
|
10827
|
-
catch (error) {
|
|
10828
|
-
// Keep default filename
|
|
10829
|
-
}
|
|
10830
|
-
const blob = new Blob([buffer]);
|
|
10831
|
-
const file = new File([blob], filename);
|
|
10832
|
-
fileStreams.push(file);
|
|
10833
|
-
}
|
|
10834
|
-
else {
|
|
10835
|
-
/*
|
|
10836
|
-
TODO: [🐱🚀] Resolve problem with browser environment
|
|
10837
|
-
// Assume it's a local file path
|
|
10838
|
-
// Note: This will work in Node.js environment
|
|
10839
|
-
// For browser environments, this would need different handling
|
|
10840
|
-
const fs = await import('fs');
|
|
10841
|
-
const fileStream = fs.createReadStream(source);
|
|
10842
|
-
fileStreams.push(fileStream);
|
|
10843
|
-
*/
|
|
10844
|
-
}
|
|
10845
|
-
}
|
|
10846
|
-
catch (error) {
|
|
10847
|
-
console.error(`Error processing knowledge source ${source}:`, error);
|
|
10848
|
-
}
|
|
10849
|
-
}
|
|
10850
|
-
// Batch upload files to the vector store
|
|
10851
|
-
if (fileStreams.length > 0) {
|
|
10852
|
-
try {
|
|
10853
|
-
await client.beta.vectorStores.fileBatches.uploadAndPoll(vectorStoreId, {
|
|
10854
|
-
files: fileStreams,
|
|
10855
|
-
});
|
|
10856
|
-
if (this.options.isVerbose) {
|
|
10857
|
-
console.info('[🤰]', 'Uploaded files to vector store for update', {
|
|
10858
|
-
vectorStoreId,
|
|
10859
|
-
fileCount: fileStreams.length,
|
|
10860
|
-
});
|
|
10861
|
-
}
|
|
10862
|
-
}
|
|
10863
|
-
catch (error) {
|
|
10864
|
-
console.error('Error uploading files to vector store:', error);
|
|
10865
|
-
}
|
|
10866
|
-
}
|
|
11687
|
+
vectorStoreId = vectorStoreResult.vectorStoreId;
|
|
10867
11688
|
}
|
|
10868
11689
|
const assistantUpdate = {
|
|
10869
11690
|
name,
|
|
@@ -10906,7 +11727,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
10906
11727
|
* Discriminant for type guards
|
|
10907
11728
|
*/
|
|
10908
11729
|
get discriminant() {
|
|
10909
|
-
return DISCRIMINANT;
|
|
11730
|
+
return DISCRIMINANT$1;
|
|
10910
11731
|
}
|
|
10911
11732
|
/**
|
|
10912
11733
|
* Type guard to check if given `LlmExecutionTools` are instanceof `OpenAiAssistantExecutionTools`
|
|
@@ -10914,7 +11735,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
10914
11735
|
* Note: This is useful when you can possibly have multiple versions of `@promptbook/openai` installed
|
|
10915
11736
|
*/
|
|
10916
11737
|
static isOpenAiAssistantExecutionTools(llmExecutionTools) {
|
|
10917
|
-
return llmExecutionTools.discriminant === DISCRIMINANT;
|
|
11738
|
+
return llmExecutionTools.discriminant === DISCRIMINANT$1;
|
|
10918
11739
|
}
|
|
10919
11740
|
}
|
|
10920
11741
|
/**
|
|
@@ -10922,7 +11743,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
10922
11743
|
*
|
|
10923
11744
|
* @private const of `OpenAiAssistantExecutionTools`
|
|
10924
11745
|
*/
|
|
10925
|
-
const DISCRIMINANT = 'OPEN_AI_ASSISTANT_V1';
|
|
11746
|
+
const DISCRIMINANT$1 = 'OPEN_AI_ASSISTANT_V1';
|
|
10926
11747
|
/**
|
|
10927
11748
|
* TODO: !!!!! [✨🥚] Knowledge should work both with and without scrapers
|
|
10928
11749
|
* TODO: [🙎] In `OpenAiAssistantExecutionTools` Allow to create abstract assistants with `isCreatingNewAssistantsAllowed`
|
|
@@ -16594,11 +17415,14 @@ const _FormattedBookInMarkdownTranspilerRegistration = $bookTranspilersRegister.
|
|
|
16594
17415
|
function createEmptyAgentModelRequirements() {
|
|
16595
17416
|
return {
|
|
16596
17417
|
systemMessage: '',
|
|
17418
|
+
promptSuffix: '',
|
|
16597
17419
|
// modelName: 'gpt-5',
|
|
16598
17420
|
modelName: 'gemini-2.5-flash-lite',
|
|
16599
17421
|
temperature: 0.7,
|
|
16600
17422
|
topP: 0.9,
|
|
16601
17423
|
topK: 50,
|
|
17424
|
+
parentAgentUrl: null,
|
|
17425
|
+
isClosed: false,
|
|
16602
17426
|
};
|
|
16603
17427
|
}
|
|
16604
17428
|
/**
|
|
@@ -16715,6 +17539,28 @@ class BaseCommitmentDefinition {
|
|
|
16715
17539
|
return currentMessage + separator + content;
|
|
16716
17540
|
});
|
|
16717
17541
|
}
|
|
17542
|
+
/**
|
|
17543
|
+
* Helper method to create a new requirements object with updated prompt suffix
|
|
17544
|
+
*/
|
|
17545
|
+
updatePromptSuffix(requirements, contentUpdate) {
|
|
17546
|
+
const newSuffix = typeof contentUpdate === 'string' ? contentUpdate : contentUpdate(requirements.promptSuffix);
|
|
17547
|
+
return {
|
|
17548
|
+
...requirements,
|
|
17549
|
+
promptSuffix: newSuffix,
|
|
17550
|
+
};
|
|
17551
|
+
}
|
|
17552
|
+
/**
|
|
17553
|
+
* Helper method to append content to the prompt suffix
|
|
17554
|
+
* Default separator is a single newline for bullet lists.
|
|
17555
|
+
*/
|
|
17556
|
+
appendToPromptSuffix(requirements, content, separator = '\n') {
|
|
17557
|
+
return this.updatePromptSuffix(requirements, (currentSuffix) => {
|
|
17558
|
+
if (!currentSuffix.trim()) {
|
|
17559
|
+
return content;
|
|
17560
|
+
}
|
|
17561
|
+
return `${currentSuffix}${separator}${content}`;
|
|
17562
|
+
});
|
|
17563
|
+
}
|
|
16718
17564
|
/**
|
|
16719
17565
|
* Helper method to add a comment section to the system message
|
|
16720
17566
|
* Comments are lines starting with # that will be removed from the final system message
|
|
@@ -16892,13 +17738,9 @@ class ClosedCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
16892
17738
|
`);
|
|
16893
17739
|
}
|
|
16894
17740
|
applyToAgentModelRequirements(requirements, _content) {
|
|
16895
|
-
const updatedMetadata = {
|
|
16896
|
-
...requirements.metadata,
|
|
16897
|
-
isClosed: true,
|
|
16898
|
-
};
|
|
16899
17741
|
return {
|
|
16900
17742
|
...requirements,
|
|
16901
|
-
|
|
17743
|
+
isClosed: true,
|
|
16902
17744
|
};
|
|
16903
17745
|
}
|
|
16904
17746
|
}
|
|
@@ -17176,12 +18018,12 @@ class DictionaryCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
17176
18018
|
return requirements;
|
|
17177
18019
|
}
|
|
17178
18020
|
// Get existing dictionary entries from metadata
|
|
17179
|
-
const existingDictionary = ((_a = requirements.
|
|
18021
|
+
const existingDictionary = ((_a = requirements._metadata) === null || _a === void 0 ? void 0 : _a.DICTIONARY) || '';
|
|
17180
18022
|
// Merge the new dictionary entry with existing entries
|
|
17181
18023
|
const mergedDictionary = existingDictionary ? `${existingDictionary}\n${trimmedContent}` : trimmedContent;
|
|
17182
18024
|
// Store the merged dictionary in metadata for debugging and inspection
|
|
17183
18025
|
const updatedMetadata = {
|
|
17184
|
-
...requirements.
|
|
18026
|
+
...requirements._metadata,
|
|
17185
18027
|
DICTIONARY: mergedDictionary,
|
|
17186
18028
|
};
|
|
17187
18029
|
// Create the dictionary section for the system message
|
|
@@ -17189,7 +18031,7 @@ class DictionaryCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
17189
18031
|
const dictionarySection = `# DICTIONARY\n${mergedDictionary}`;
|
|
17190
18032
|
return {
|
|
17191
18033
|
...this.appendToSystemMessage(requirements, dictionarySection),
|
|
17192
|
-
|
|
18034
|
+
_metadata: updatedMetadata,
|
|
17193
18035
|
};
|
|
17194
18036
|
}
|
|
17195
18037
|
}
|
|
@@ -17329,10 +18171,7 @@ class FromCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
17329
18171
|
applyToAgentModelRequirements(requirements, content) {
|
|
17330
18172
|
const trimmedContent = content.trim();
|
|
17331
18173
|
if (!trimmedContent) {
|
|
17332
|
-
return
|
|
17333
|
-
...requirements,
|
|
17334
|
-
parentAgentUrl: undefined,
|
|
17335
|
-
};
|
|
18174
|
+
return requirements;
|
|
17336
18175
|
}
|
|
17337
18176
|
if (trimmedContent.toUpperCase() === 'VOID' ||
|
|
17338
18177
|
trimmedContent.toUpperCase() === 'NULL' ||
|
|
@@ -17644,9 +18483,13 @@ class KnowledgeCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
17644
18483
|
return this.appendToSystemMessage(updatedRequirements, knowledgeInfo, '\n\n');
|
|
17645
18484
|
}
|
|
17646
18485
|
else {
|
|
17647
|
-
|
|
17648
|
-
const
|
|
17649
|
-
|
|
18486
|
+
const inlineSource = createInlineKnowledgeSourceFile(trimmedContent);
|
|
18487
|
+
const updatedRequirements = {
|
|
18488
|
+
...requirements,
|
|
18489
|
+
knowledgeSources: [...(requirements.knowledgeSources || []), inlineSource.url],
|
|
18490
|
+
};
|
|
18491
|
+
const knowledgeInfo = `Knowledge Source Inline: ${inlineSource.filename} (derived from inline content and processed for retrieval during chat)`;
|
|
18492
|
+
return this.appendToSystemMessage(updatedRequirements, knowledgeInfo, '\n\n');
|
|
17650
18493
|
}
|
|
17651
18494
|
}
|
|
17652
18495
|
}
|
|
@@ -17893,16 +18736,16 @@ class AgentMessageCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
17893
18736
|
// and typically doesn't need to be added to the system prompt or model requirements directly.
|
|
17894
18737
|
// It is extracted separately for the chat interface.
|
|
17895
18738
|
var _a;
|
|
17896
|
-
const pendingUserMessage = (_a = requirements.
|
|
18739
|
+
const pendingUserMessage = (_a = requirements._metadata) === null || _a === void 0 ? void 0 : _a.pendingUserMessage;
|
|
17897
18740
|
if (pendingUserMessage) {
|
|
17898
18741
|
const newSample = { question: pendingUserMessage, answer: content };
|
|
17899
18742
|
const newSamples = [...(requirements.samples || []), newSample];
|
|
17900
|
-
const newMetadata = { ...requirements.
|
|
18743
|
+
const newMetadata = { ...requirements._metadata };
|
|
17901
18744
|
delete newMetadata.pendingUserMessage;
|
|
17902
18745
|
return {
|
|
17903
18746
|
...requirements,
|
|
17904
18747
|
samples: newSamples,
|
|
17905
|
-
|
|
18748
|
+
_metadata: newMetadata,
|
|
17906
18749
|
};
|
|
17907
18750
|
}
|
|
17908
18751
|
return requirements;
|
|
@@ -18150,8 +18993,8 @@ class UserMessageCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
18150
18993
|
applyToAgentModelRequirements(requirements, content) {
|
|
18151
18994
|
return {
|
|
18152
18995
|
...requirements,
|
|
18153
|
-
|
|
18154
|
-
...requirements.
|
|
18996
|
+
_metadata: {
|
|
18997
|
+
...requirements._metadata,
|
|
18155
18998
|
pendingUserMessage: content,
|
|
18156
18999
|
},
|
|
18157
19000
|
};
|
|
@@ -19009,11 +19852,7 @@ class NoteCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
19009
19852
|
if (trimmedContent === '') {
|
|
19010
19853
|
return requirements;
|
|
19011
19854
|
}
|
|
19012
|
-
|
|
19013
|
-
return {
|
|
19014
|
-
...requirements,
|
|
19015
|
-
notes: [...(requirements.notes || []), trimmedContent],
|
|
19016
|
-
};
|
|
19855
|
+
return requirements;
|
|
19017
19856
|
}
|
|
19018
19857
|
}
|
|
19019
19858
|
/**
|
|
@@ -19075,12 +19914,12 @@ class OpenCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
19075
19914
|
// Since OPEN is default, we can just ensure isClosed is false
|
|
19076
19915
|
// But to be explicit we can set it
|
|
19077
19916
|
const updatedMetadata = {
|
|
19078
|
-
...requirements.
|
|
19917
|
+
...requirements._metadata,
|
|
19079
19918
|
isClosed: false,
|
|
19080
19919
|
};
|
|
19081
19920
|
return {
|
|
19082
19921
|
...requirements,
|
|
19083
|
-
|
|
19922
|
+
_metadata: updatedMetadata,
|
|
19084
19923
|
};
|
|
19085
19924
|
}
|
|
19086
19925
|
}
|
|
@@ -19161,7 +20000,7 @@ class PersonaCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
19161
20000
|
return requirements;
|
|
19162
20001
|
}
|
|
19163
20002
|
// Get existing persona content from metadata
|
|
19164
|
-
const existingPersonaContent = ((_a = requirements.
|
|
20003
|
+
const existingPersonaContent = ((_a = requirements._metadata) === null || _a === void 0 ? void 0 : _a.PERSONA) || '';
|
|
19165
20004
|
// Merge the new content with existing persona content
|
|
19166
20005
|
// When multiple PERSONA commitments exist, they are merged into one
|
|
19167
20006
|
const mergedPersonaContent = existingPersonaContent
|
|
@@ -19169,12 +20008,12 @@ class PersonaCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
19169
20008
|
: trimmedContent;
|
|
19170
20009
|
// Store the merged persona content in metadata for debugging and inspection
|
|
19171
20010
|
const updatedMetadata = {
|
|
19172
|
-
...requirements.
|
|
20011
|
+
...requirements._metadata,
|
|
19173
20012
|
PERSONA: mergedPersonaContent,
|
|
19174
20013
|
};
|
|
19175
20014
|
// Get the agent name from metadata (which should contain the first line of agent source)
|
|
19176
20015
|
// If not available, extract from current system message as fallback
|
|
19177
|
-
let agentName = (_b = requirements.
|
|
20016
|
+
let agentName = (_b = requirements._metadata) === null || _b === void 0 ? void 0 : _b.agentName;
|
|
19178
20017
|
if (!agentName) {
|
|
19179
20018
|
// Fallback: extract from current system message
|
|
19180
20019
|
const currentMessage = requirements.systemMessage.trim();
|
|
@@ -19221,7 +20060,7 @@ class PersonaCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
19221
20060
|
return {
|
|
19222
20061
|
...requirements,
|
|
19223
20062
|
systemMessage: newSystemMessage,
|
|
19224
|
-
|
|
20063
|
+
_metadata: updatedMetadata,
|
|
19225
20064
|
};
|
|
19226
20065
|
}
|
|
19227
20066
|
}
|
|
@@ -19304,7 +20143,16 @@ class RuleCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
19304
20143
|
}
|
|
19305
20144
|
// Add rule to the system message
|
|
19306
20145
|
const ruleSection = `Rule: ${trimmedContent}`;
|
|
19307
|
-
|
|
20146
|
+
const requirementsWithRule = this.appendToSystemMessage(requirements, ruleSection, '\n\n');
|
|
20147
|
+
const ruleLines = trimmedContent
|
|
20148
|
+
.split(/\r?\n/)
|
|
20149
|
+
.map((line) => line.trim())
|
|
20150
|
+
.filter(Boolean)
|
|
20151
|
+
.map((line) => `- ${line}`);
|
|
20152
|
+
if (ruleLines.length === 0) {
|
|
20153
|
+
return requirementsWithRule;
|
|
20154
|
+
}
|
|
20155
|
+
return this.appendToPromptSuffix(requirementsWithRule, ruleLines.join('\n'));
|
|
19308
20156
|
}
|
|
19309
20157
|
}
|
|
19310
20158
|
/**
|
|
@@ -19810,7 +20658,7 @@ class TeamCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
19810
20658
|
if (teammates.length === 0) {
|
|
19811
20659
|
return requirements;
|
|
19812
20660
|
}
|
|
19813
|
-
const agentName = ((_a = requirements.
|
|
20661
|
+
const agentName = ((_a = requirements._metadata) === null || _a === void 0 ? void 0 : _a.agentName) || 'Agent';
|
|
19814
20662
|
const teamEntries = teammates.map((teammate) => ({
|
|
19815
20663
|
toolName: createTeamToolName(teammate.url),
|
|
19816
20664
|
teammate,
|
|
@@ -19850,7 +20698,7 @@ class TeamCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
19850
20698
|
},
|
|
19851
20699
|
});
|
|
19852
20700
|
}
|
|
19853
|
-
const existingTeammates = ((_b = requirements.
|
|
20701
|
+
const existingTeammates = ((_b = requirements._metadata) === null || _b === void 0 ? void 0 : _b.teammates) || [];
|
|
19854
20702
|
const updatedTeammates = [...existingTeammates];
|
|
19855
20703
|
for (const entry of teamEntries) {
|
|
19856
20704
|
if (updatedTeammates.some((existing) => existing.url === entry.teammate.url)) {
|
|
@@ -19879,8 +20727,8 @@ class TeamCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
19879
20727
|
return this.appendToSystemMessage({
|
|
19880
20728
|
...requirements,
|
|
19881
20729
|
tools: updatedTools,
|
|
19882
|
-
|
|
19883
|
-
...requirements.
|
|
20730
|
+
_metadata: {
|
|
20731
|
+
...requirements._metadata,
|
|
19884
20732
|
teammates: updatedTeammates,
|
|
19885
20733
|
},
|
|
19886
20734
|
}, teamSystemMessage);
|
|
@@ -19980,11 +20828,16 @@ function createTeamToolFunction(entry) {
|
|
|
19980
20828
|
const request = buildTeammateRequest(message, args.context);
|
|
19981
20829
|
let response = '';
|
|
19982
20830
|
let error = null;
|
|
20831
|
+
let toolCalls;
|
|
19983
20832
|
try {
|
|
19984
20833
|
const remoteAgent = await getRemoteTeammateAgent(entry.teammate.url);
|
|
19985
20834
|
const prompt = buildTeammatePrompt(request);
|
|
19986
20835
|
const teammateResult = await remoteAgent.callChatModel(prompt);
|
|
19987
20836
|
response = teammateResult.content || '';
|
|
20837
|
+
toolCalls =
|
|
20838
|
+
'toolCalls' in teammateResult && Array.isArray(teammateResult.toolCalls)
|
|
20839
|
+
? teammateResult.toolCalls
|
|
20840
|
+
: undefined;
|
|
19988
20841
|
}
|
|
19989
20842
|
catch (err) {
|
|
19990
20843
|
error = err instanceof Error ? err.message : String(err);
|
|
@@ -19994,6 +20847,7 @@ function createTeamToolFunction(entry) {
|
|
|
19994
20847
|
teammate: teammateMetadata,
|
|
19995
20848
|
request,
|
|
19996
20849
|
response: teammateReply,
|
|
20850
|
+
toolCalls: toolCalls && toolCalls.length > 0 ? toolCalls : undefined,
|
|
19997
20851
|
error,
|
|
19998
20852
|
conversation: [
|
|
19999
20853
|
{
|
|
@@ -20106,7 +20960,7 @@ class TemplateCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
20106
20960
|
if (!trimmedContent) {
|
|
20107
20961
|
// Store template mode flag in metadata
|
|
20108
20962
|
const updatedMetadata = {
|
|
20109
|
-
...requirements.
|
|
20963
|
+
...requirements._metadata,
|
|
20110
20964
|
templateMode: true,
|
|
20111
20965
|
};
|
|
20112
20966
|
// Add a general instruction about using structured templates
|
|
@@ -20116,21 +20970,21 @@ class TemplateCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
20116
20970
|
`);
|
|
20117
20971
|
return {
|
|
20118
20972
|
...this.appendToSystemMessage(requirements, templateModeInstruction, '\n\n'),
|
|
20119
|
-
|
|
20973
|
+
_metadata: updatedMetadata,
|
|
20120
20974
|
};
|
|
20121
20975
|
}
|
|
20122
20976
|
// If content is provided, add the specific template instructions
|
|
20123
20977
|
const templateSection = `Response Template: ${trimmedContent}`;
|
|
20124
20978
|
// Store the template in metadata for potential programmatic access
|
|
20125
|
-
const existingTemplates = ((_a = requirements.
|
|
20979
|
+
const existingTemplates = ((_a = requirements._metadata) === null || _a === void 0 ? void 0 : _a.templates) || [];
|
|
20126
20980
|
const updatedMetadata = {
|
|
20127
|
-
...requirements.
|
|
20981
|
+
...requirements._metadata,
|
|
20128
20982
|
templates: [...existingTemplates, trimmedContent],
|
|
20129
20983
|
templateMode: true,
|
|
20130
20984
|
};
|
|
20131
20985
|
return {
|
|
20132
20986
|
...this.appendToSystemMessage(requirements, templateSection, '\n\n'),
|
|
20133
|
-
|
|
20987
|
+
_metadata: updatedMetadata,
|
|
20134
20988
|
};
|
|
20135
20989
|
}
|
|
20136
20990
|
}
|
|
@@ -20467,8 +21321,8 @@ class UseBrowserCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
20467
21321
|
return this.appendToSystemMessage({
|
|
20468
21322
|
...requirements,
|
|
20469
21323
|
tools: updatedTools,
|
|
20470
|
-
|
|
20471
|
-
...requirements.
|
|
21324
|
+
_metadata: {
|
|
21325
|
+
...requirements._metadata,
|
|
20472
21326
|
useBrowser: true,
|
|
20473
21327
|
},
|
|
20474
21328
|
}, spaceTrim$1(`
|
|
@@ -20697,8 +21551,8 @@ class UseEmailCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
20697
21551
|
return this.appendToSystemMessage({
|
|
20698
21552
|
...requirements,
|
|
20699
21553
|
tools: updatedTools,
|
|
20700
|
-
|
|
20701
|
-
...requirements.
|
|
21554
|
+
_metadata: {
|
|
21555
|
+
...requirements._metadata,
|
|
20702
21556
|
useEmail: content || true,
|
|
20703
21557
|
},
|
|
20704
21558
|
}, spaceTrim$1((block) => `
|
|
@@ -20833,8 +21687,8 @@ class UseImageGeneratorCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
20833
21687
|
return this.appendToSystemMessage({
|
|
20834
21688
|
...requirements,
|
|
20835
21689
|
tools: updatedTools,
|
|
20836
|
-
|
|
20837
|
-
...requirements.
|
|
21690
|
+
_metadata: {
|
|
21691
|
+
...requirements._metadata,
|
|
20838
21692
|
useImageGenerator: content || true,
|
|
20839
21693
|
},
|
|
20840
21694
|
}, spaceTrim$1(`
|
|
@@ -21125,8 +21979,8 @@ class UseSearchEngineCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
21125
21979
|
return this.appendToSystemMessage({
|
|
21126
21980
|
...requirements,
|
|
21127
21981
|
tools: updatedTools,
|
|
21128
|
-
|
|
21129
|
-
...requirements.
|
|
21982
|
+
_metadata: {
|
|
21983
|
+
...requirements._metadata,
|
|
21130
21984
|
useSearchEngine: content || true,
|
|
21131
21985
|
},
|
|
21132
21986
|
}, spaceTrim$1((block) => `
|
|
@@ -21274,8 +22128,8 @@ class UseTimeCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
21274
22128
|
return this.appendToSystemMessage({
|
|
21275
22129
|
...requirements,
|
|
21276
22130
|
tools: updatedTools,
|
|
21277
|
-
|
|
21278
|
-
...requirements.
|
|
22131
|
+
_metadata: {
|
|
22132
|
+
...requirements._metadata,
|
|
21279
22133
|
},
|
|
21280
22134
|
}, spaceTrim$1((block) => `
|
|
21281
22135
|
Time and date context:
|
|
@@ -21859,14 +22713,26 @@ function removeCommentsFromSystemMessage(systemMessage) {
|
|
|
21859
22713
|
}
|
|
21860
22714
|
|
|
21861
22715
|
/**
|
|
21862
|
-
* Creates agent model requirements using the new commitment system
|
|
22716
|
+
* Creates agent model requirements using the new commitment system.
|
|
22717
|
+
*
|
|
21863
22718
|
* This function uses a reduce-like pattern where each commitment applies its changes
|
|
21864
|
-
* to build the final requirements starting from a basic empty model
|
|
22719
|
+
* to build the final requirements starting from a basic empty model.
|
|
21865
22720
|
*
|
|
21866
|
-
* @
|
|
22721
|
+
* @param agentSource - Agent source book to parse.
|
|
22722
|
+
* @param modelName - Optional override for the agent model name.
|
|
22723
|
+
* @param options - Additional options such as the agent reference resolver.
|
|
22724
|
+
*
|
|
22725
|
+
* @private @@@
|
|
22726
|
+
*/
|
|
22727
|
+
const COMMITMENTS_WITH_AGENT_REFERENCES = new Set(['FROM', 'IMPORT', 'IMPORTS', 'TEAM']);
|
|
22728
|
+
/**
|
|
22729
|
+
* @@@
|
|
22730
|
+
*
|
|
22731
|
+
* @private @@@
|
|
21867
22732
|
*/
|
|
21868
|
-
async function createAgentModelRequirementsWithCommitments(agentSource, modelName) {
|
|
22733
|
+
async function createAgentModelRequirementsWithCommitments(agentSource, modelName, options) {
|
|
21869
22734
|
var _a;
|
|
22735
|
+
const agentReferenceResolver = options === null || options === void 0 ? void 0 : options.agentReferenceResolver;
|
|
21870
22736
|
// Parse the agent source to extract commitments
|
|
21871
22737
|
const parseResult = parseAgentSourceWithCommitments(agentSource);
|
|
21872
22738
|
// Apply DELETE filtering: remove prior commitments tagged by parameters targeted by DELETE/CANCEL/DISCARD/REMOVE
|
|
@@ -21903,8 +22769,8 @@ async function createAgentModelRequirementsWithCommitments(agentSource, modelNam
|
|
|
21903
22769
|
// Store the agent name in metadata so commitments can access it
|
|
21904
22770
|
requirements = {
|
|
21905
22771
|
...requirements,
|
|
21906
|
-
|
|
21907
|
-
...requirements.
|
|
22772
|
+
_metadata: {
|
|
22773
|
+
...requirements._metadata,
|
|
21908
22774
|
agentName: parseResult.agentName,
|
|
21909
22775
|
},
|
|
21910
22776
|
};
|
|
@@ -21918,6 +22784,11 @@ async function createAgentModelRequirementsWithCommitments(agentSource, modelNam
|
|
|
21918
22784
|
// Apply each commitment in order using reduce-like pattern
|
|
21919
22785
|
for (let i = 0; i < filteredCommitments.length; i++) {
|
|
21920
22786
|
const commitment = filteredCommitments[i];
|
|
22787
|
+
const isReferenceCommitment = Boolean(agentReferenceResolver && COMMITMENTS_WITH_AGENT_REFERENCES.has(commitment.type));
|
|
22788
|
+
let commitmentContent = commitment.content;
|
|
22789
|
+
if (isReferenceCommitment && agentReferenceResolver) {
|
|
22790
|
+
commitmentContent = await agentReferenceResolver.resolveCommitmentContent(commitment.type, commitment.content);
|
|
22791
|
+
}
|
|
21921
22792
|
// CLOSED commitment should work only if its the last commitment in the book
|
|
21922
22793
|
if (commitment.type === 'CLOSED' && i !== filteredCommitments.length - 1) {
|
|
21923
22794
|
continue;
|
|
@@ -21925,7 +22796,7 @@ async function createAgentModelRequirementsWithCommitments(agentSource, modelNam
|
|
|
21925
22796
|
const definition = getCommitmentDefinition(commitment.type);
|
|
21926
22797
|
if (definition) {
|
|
21927
22798
|
try {
|
|
21928
|
-
requirements = definition.applyToAgentModelRequirements(requirements,
|
|
22799
|
+
requirements = definition.applyToAgentModelRequirements(requirements, commitmentContent);
|
|
21929
22800
|
}
|
|
21930
22801
|
catch (error) {
|
|
21931
22802
|
console.warn(`Failed to apply commitment ${commitment.type}:`, error);
|
|
@@ -22384,23 +23255,28 @@ function normalizeSeparator(content) {
|
|
|
22384
23255
|
*/
|
|
22385
23256
|
|
|
22386
23257
|
/**
|
|
22387
|
-
* Creates model requirements for an agent based on its source
|
|
23258
|
+
* Creates model requirements for an agent based on its source.
|
|
22388
23259
|
*
|
|
22389
23260
|
* There are 2 similar functions:
|
|
22390
23261
|
* - `parseAgentSource` which is a lightweight parser for agent source, it parses basic information and its purpose is to be quick and synchronous. The commitments there are hardcoded.
|
|
22391
23262
|
* - `createAgentModelRequirements` which is an asynchronous function that creates model requirements it applies each commitment one by one and works asynchronous.
|
|
22392
23263
|
*
|
|
23264
|
+
* @param agentSource - Book describing the agent.
|
|
23265
|
+
* @param modelName - Optional override for the agent's model.
|
|
23266
|
+
* @param availableModels - Models that could fulfill the agent.
|
|
23267
|
+
* @param llmTools - Execution tools used when selecting a best model.
|
|
23268
|
+
* @param options - Optional hooks such as the agent reference resolver.
|
|
22393
23269
|
* @public exported from `@promptbook/core`
|
|
22394
23270
|
*/
|
|
22395
|
-
async function createAgentModelRequirements(agentSource, modelName, availableModels, llmTools) {
|
|
23271
|
+
async function createAgentModelRequirements(agentSource, modelName, availableModels, llmTools, options) {
|
|
22396
23272
|
// If availableModels are provided and no specific modelName is given,
|
|
22397
23273
|
// use preparePersona to select the best model
|
|
22398
23274
|
if (availableModels && !modelName && llmTools) {
|
|
22399
23275
|
const selectedModelName = await selectBestModelUsingPersona(agentSource, llmTools);
|
|
22400
|
-
return createAgentModelRequirementsWithCommitments(agentSource, selectedModelName);
|
|
23276
|
+
return createAgentModelRequirementsWithCommitments(agentSource, selectedModelName, options);
|
|
22401
23277
|
}
|
|
22402
23278
|
// Use the new commitment-based system with provided or default model
|
|
22403
|
-
return createAgentModelRequirementsWithCommitments(agentSource, modelName);
|
|
23279
|
+
return createAgentModelRequirementsWithCommitments(agentSource, modelName, options);
|
|
22404
23280
|
}
|
|
22405
23281
|
/**
|
|
22406
23282
|
* Selects the best model using the preparePersona function
|
|
@@ -28697,6 +29573,40 @@ function isAssistantPreparationToolCall(toolCall) {
|
|
|
28697
29573
|
return toolCall.name === ASSISTANT_PREPARATION_TOOL_CALL_NAME;
|
|
28698
29574
|
}
|
|
28699
29575
|
|
|
29576
|
+
/**
|
|
29577
|
+
* Builds a stable identity string for tool calls across partial updates.
|
|
29578
|
+
*
|
|
29579
|
+
* @param toolCall - Tool call entry to identify.
|
|
29580
|
+
* @returns Stable identity string for deduplication.
|
|
29581
|
+
*
|
|
29582
|
+
* @private function of <Chat/>
|
|
29583
|
+
*/
|
|
29584
|
+
function getToolCallIdentity(toolCall) {
|
|
29585
|
+
const rawToolCall = toolCall.rawToolCall;
|
|
29586
|
+
const rawId = (rawToolCall === null || rawToolCall === void 0 ? void 0 : rawToolCall.id) || (rawToolCall === null || rawToolCall === void 0 ? void 0 : rawToolCall.callId) || (rawToolCall === null || rawToolCall === void 0 ? void 0 : rawToolCall.call_id);
|
|
29587
|
+
if (rawId) {
|
|
29588
|
+
return `id:${rawId}`;
|
|
29589
|
+
}
|
|
29590
|
+
if (toolCall.createdAt) {
|
|
29591
|
+
return `time:${toolCall.createdAt}:${toolCall.name}`;
|
|
29592
|
+
}
|
|
29593
|
+
const argsKey = (() => {
|
|
29594
|
+
if (typeof toolCall.arguments === 'string') {
|
|
29595
|
+
return toolCall.arguments;
|
|
29596
|
+
}
|
|
29597
|
+
if (!toolCall.arguments) {
|
|
29598
|
+
return '';
|
|
29599
|
+
}
|
|
29600
|
+
try {
|
|
29601
|
+
return JSON.stringify(toolCall.arguments);
|
|
29602
|
+
}
|
|
29603
|
+
catch (_a) {
|
|
29604
|
+
return '';
|
|
29605
|
+
}
|
|
29606
|
+
})();
|
|
29607
|
+
return `fallback:${toolCall.name}:${argsKey}`;
|
|
29608
|
+
}
|
|
29609
|
+
|
|
28700
29610
|
/*! *****************************************************************************
|
|
28701
29611
|
Copyright (c) Microsoft Corporation.
|
|
28702
29612
|
|
|
@@ -28918,206 +29828,490 @@ function promptbookifyAiText(text) {
|
|
|
28918
29828
|
* TODO: [🧠][✌️] Make some Promptbook-native token system
|
|
28919
29829
|
*/
|
|
28920
29830
|
|
|
29831
|
+
const DEFAULT_AGENT_KIT_MODEL_NAME = 'gpt-5.2';
|
|
29832
|
+
const DEFAULT_JSON_SCHEMA_NAME = 'StructuredOutput';
|
|
29833
|
+
/*
|
|
29834
|
+
TODO: Use or remove
|
|
29835
|
+
const EMPTY_JSON_SCHEMA: JsonSchemaDefinition['schema'] = {
|
|
29836
|
+
type: 'object',
|
|
29837
|
+
properties: {},
|
|
29838
|
+
required: [],
|
|
29839
|
+
additionalProperties: true,
|
|
29840
|
+
};
|
|
29841
|
+
*/
|
|
29842
|
+
function buildJsonSchemaDefinition(jsonSchema) {
|
|
29843
|
+
var _a, _b, _c;
|
|
29844
|
+
const schema = (_a = jsonSchema === null || jsonSchema === void 0 ? void 0 : jsonSchema.schema) !== null && _a !== void 0 ? _a : {};
|
|
29845
|
+
return {
|
|
29846
|
+
type: 'json_schema',
|
|
29847
|
+
name: (_b = jsonSchema === null || jsonSchema === void 0 ? void 0 : jsonSchema.name) !== null && _b !== void 0 ? _b : DEFAULT_JSON_SCHEMA_NAME,
|
|
29848
|
+
strict: Boolean(jsonSchema === null || jsonSchema === void 0 ? void 0 : jsonSchema.strict),
|
|
29849
|
+
schema: {
|
|
29850
|
+
type: 'object',
|
|
29851
|
+
properties: ((_c = schema.properties) !== null && _c !== void 0 ? _c : {}),
|
|
29852
|
+
required: Array.isArray(schema.required) ? schema.required : [],
|
|
29853
|
+
additionalProperties: schema.additionalProperties === undefined ? true : Boolean(schema.additionalProperties),
|
|
29854
|
+
description: schema.description,
|
|
29855
|
+
},
|
|
29856
|
+
};
|
|
29857
|
+
}
|
|
29858
|
+
/**
|
|
29859
|
+
* Maps OpenAI `response_format` payloads to AgentKit output types so the runner can forward
|
|
29860
|
+
* structured-output preferences to OpenAI while still reusing the same AgentKit agent instance.
|
|
29861
|
+
*
|
|
29862
|
+
* @param responseFormat - The OpenAI `response_format` payload from the user request.
|
|
29863
|
+
* @returns An Agent output type compatible with the requested schema or `undefined` when no impact is required.
|
|
29864
|
+
* @private utility of Open AI
|
|
29865
|
+
*/
|
|
29866
|
+
function mapResponseFormatToAgentOutputType(responseFormat) {
|
|
29867
|
+
if (!responseFormat) {
|
|
29868
|
+
return undefined;
|
|
29869
|
+
}
|
|
29870
|
+
if (typeof responseFormat === 'string') {
|
|
29871
|
+
if (responseFormat === 'text') {
|
|
29872
|
+
return 'text';
|
|
29873
|
+
}
|
|
29874
|
+
if (responseFormat === 'json_schema' || responseFormat === 'json_object') {
|
|
29875
|
+
return buildJsonSchemaDefinition();
|
|
29876
|
+
}
|
|
29877
|
+
return 'text';
|
|
29878
|
+
}
|
|
29879
|
+
switch (responseFormat.type) {
|
|
29880
|
+
case 'text':
|
|
29881
|
+
return 'text';
|
|
29882
|
+
case 'json_schema':
|
|
29883
|
+
return buildJsonSchemaDefinition(responseFormat.json_schema);
|
|
29884
|
+
case 'json_object':
|
|
29885
|
+
return buildJsonSchemaDefinition();
|
|
29886
|
+
default:
|
|
29887
|
+
return undefined;
|
|
29888
|
+
}
|
|
29889
|
+
}
|
|
28921
29890
|
/**
|
|
28922
|
-
* Execution
|
|
29891
|
+
* Execution tools for OpenAI AgentKit (Agents SDK).
|
|
28923
29892
|
*
|
|
28924
29893
|
* @public exported from `@promptbook/openai`
|
|
28925
29894
|
*/
|
|
28926
|
-
class
|
|
29895
|
+
class OpenAiAgentKitExecutionTools extends OpenAiVectorStoreHandler {
|
|
29896
|
+
/**
|
|
29897
|
+
* Creates OpenAI AgentKit execution tools.
|
|
29898
|
+
*/
|
|
28927
29899
|
constructor(options) {
|
|
29900
|
+
var _a;
|
|
29901
|
+
if (options.isProxied) {
|
|
29902
|
+
throw new NotYetImplementedError(`Proxy mode is not yet implemented for OpenAI AgentKit`);
|
|
29903
|
+
}
|
|
28928
29904
|
super(options);
|
|
28929
|
-
this.
|
|
29905
|
+
this.preparedAgentKitAgent = null;
|
|
29906
|
+
this.agentKitModelName = (_a = options.agentKitModelName) !== null && _a !== void 0 ? _a : DEFAULT_AGENT_KIT_MODEL_NAME;
|
|
28930
29907
|
}
|
|
28931
29908
|
get title() {
|
|
28932
|
-
return 'OpenAI
|
|
29909
|
+
return 'OpenAI AgentKit';
|
|
29910
|
+
}
|
|
29911
|
+
get description() {
|
|
29912
|
+
return 'Use OpenAI AgentKit for agent-style chat with tools and knowledge';
|
|
29913
|
+
}
|
|
29914
|
+
/**
|
|
29915
|
+
* Calls OpenAI AgentKit with a chat prompt (non-streaming).
|
|
29916
|
+
*/
|
|
29917
|
+
async callChatModel(prompt) {
|
|
29918
|
+
return this.callChatModelStream(prompt, () => { });
|
|
29919
|
+
}
|
|
29920
|
+
/**
|
|
29921
|
+
* Calls OpenAI AgentKit with a chat prompt (streaming).
|
|
29922
|
+
*/
|
|
29923
|
+
async callChatModelStream(prompt, onProgress) {
|
|
29924
|
+
const { content, parameters, modelRequirements } = prompt;
|
|
29925
|
+
if (modelRequirements.modelVariant !== 'CHAT') {
|
|
29926
|
+
throw new PipelineExecutionError('Use callChatModel only for CHAT variant');
|
|
29927
|
+
}
|
|
29928
|
+
for (const key of ['maxTokens', 'modelName', 'seed', 'temperature']) {
|
|
29929
|
+
if (modelRequirements[key] !== undefined) {
|
|
29930
|
+
throw new NotYetImplementedError(`In \`OpenAiAgentKitExecutionTools\` you cannot specify \`${key}\``);
|
|
29931
|
+
}
|
|
29932
|
+
}
|
|
29933
|
+
const rawPromptContent = templateParameters(content, {
|
|
29934
|
+
...parameters,
|
|
29935
|
+
modelName: this.agentKitModelName,
|
|
29936
|
+
});
|
|
29937
|
+
const responseFormatOutputType = mapResponseFormatToAgentOutputType(modelRequirements.responseFormat);
|
|
29938
|
+
const preparedAgentKitAgent = await this.prepareAgentKitAgent({
|
|
29939
|
+
name: (prompt.title || 'Agent'),
|
|
29940
|
+
instructions: modelRequirements.systemMessage || '',
|
|
29941
|
+
knowledgeSources: modelRequirements.knowledgeSources,
|
|
29942
|
+
tools: 'tools' in prompt && Array.isArray(prompt.tools) ? prompt.tools : modelRequirements.tools,
|
|
29943
|
+
});
|
|
29944
|
+
return this.callChatModelStreamWithPreparedAgent({
|
|
29945
|
+
openAiAgentKitAgent: preparedAgentKitAgent.agent,
|
|
29946
|
+
prompt,
|
|
29947
|
+
rawPromptContent,
|
|
29948
|
+
onProgress,
|
|
29949
|
+
responseFormatOutputType,
|
|
29950
|
+
});
|
|
29951
|
+
}
|
|
29952
|
+
/**
|
|
29953
|
+
* Returns a prepared AgentKit agent when the server wants to manage caching externally.
|
|
29954
|
+
*/
|
|
29955
|
+
getPreparedAgentKitAgent() {
|
|
29956
|
+
return this.preparedAgentKitAgent;
|
|
29957
|
+
}
|
|
29958
|
+
/**
|
|
29959
|
+
* Stores a prepared AgentKit agent for later reuse by external cache managers.
|
|
29960
|
+
*/
|
|
29961
|
+
setPreparedAgentKitAgent(preparedAgent) {
|
|
29962
|
+
this.preparedAgentKitAgent = preparedAgent;
|
|
28933
29963
|
}
|
|
28934
|
-
|
|
28935
|
-
|
|
29964
|
+
/**
|
|
29965
|
+
* Creates a new tools instance bound to a prepared AgentKit agent.
|
|
29966
|
+
*/
|
|
29967
|
+
getPreparedAgentTools(preparedAgent) {
|
|
29968
|
+
const tools = new OpenAiAgentKitExecutionTools(this.agentKitOptions);
|
|
29969
|
+
tools.setPreparedAgentKitAgent(preparedAgent);
|
|
29970
|
+
return tools;
|
|
28936
29971
|
}
|
|
28937
29972
|
/**
|
|
28938
|
-
*
|
|
29973
|
+
* Prepares an AgentKit agent with optional knowledge sources and tool definitions.
|
|
28939
29974
|
*/
|
|
28940
|
-
async
|
|
29975
|
+
async prepareAgentKitAgent(options) {
|
|
29976
|
+
var _a, _b;
|
|
29977
|
+
const { name, instructions, knowledgeSources, tools, vectorStoreId: cachedVectorStoreId, storeAsPrepared, } = options;
|
|
29978
|
+
await this.ensureAgentKitDefaults();
|
|
28941
29979
|
if (this.options.isVerbose) {
|
|
28942
|
-
console.info('
|
|
29980
|
+
console.info('[🤰]', 'Preparing OpenAI AgentKit agent', {
|
|
29981
|
+
name,
|
|
29982
|
+
instructionsLength: instructions.length,
|
|
29983
|
+
knowledgeSourcesCount: (_a = knowledgeSources === null || knowledgeSources === void 0 ? void 0 : knowledgeSources.length) !== null && _a !== void 0 ? _a : 0,
|
|
29984
|
+
toolsCount: (_b = tools === null || tools === void 0 ? void 0 : tools.length) !== null && _b !== void 0 ? _b : 0,
|
|
29985
|
+
});
|
|
28943
29986
|
}
|
|
28944
|
-
|
|
28945
|
-
|
|
28946
|
-
|
|
28947
|
-
|
|
29987
|
+
let vectorStoreId = cachedVectorStoreId;
|
|
29988
|
+
if (!vectorStoreId && knowledgeSources && knowledgeSources.length > 0) {
|
|
29989
|
+
const vectorStoreResult = await this.createVectorStoreWithKnowledgeSources({
|
|
29990
|
+
client: await this.getClient(),
|
|
29991
|
+
name,
|
|
29992
|
+
knowledgeSources,
|
|
29993
|
+
logLabel: 'agentkit preparation',
|
|
29994
|
+
});
|
|
29995
|
+
vectorStoreId = vectorStoreResult.vectorStoreId;
|
|
28948
29996
|
}
|
|
28949
|
-
|
|
28950
|
-
|
|
28951
|
-
|
|
28952
|
-
|
|
28953
|
-
|
|
28954
|
-
const input = []; // TODO: Type properly when OpenAI types are updated
|
|
28955
|
-
// Add previous messages from thread (if any)
|
|
28956
|
-
if ('thread' in prompt && Array.isArray(prompt.thread)) {
|
|
28957
|
-
const previousMessages = prompt.thread.map((msg) => ({
|
|
28958
|
-
role: msg.sender === 'assistant' ? 'assistant' : 'user',
|
|
28959
|
-
content: msg.content,
|
|
28960
|
-
}));
|
|
28961
|
-
input.push(...previousMessages);
|
|
29997
|
+
else if (vectorStoreId && this.options.isVerbose) {
|
|
29998
|
+
console.info('[🤰]', 'Using cached vector store for AgentKit agent', {
|
|
29999
|
+
name,
|
|
30000
|
+
vectorStoreId,
|
|
30001
|
+
});
|
|
28962
30002
|
}
|
|
28963
|
-
|
|
28964
|
-
|
|
28965
|
-
|
|
28966
|
-
|
|
30003
|
+
const agentKitTools = this.buildAgentKitTools({ tools, vectorStoreId });
|
|
30004
|
+
const openAiAgentKitAgent = new Agent$1({
|
|
30005
|
+
name,
|
|
30006
|
+
model: this.agentKitModelName,
|
|
30007
|
+
instructions: instructions || 'You are a helpful assistant.',
|
|
30008
|
+
tools: agentKitTools,
|
|
28967
30009
|
});
|
|
28968
|
-
|
|
28969
|
-
|
|
28970
|
-
|
|
28971
|
-
const agentTools = tools ? [...tools] : [];
|
|
28972
|
-
let toolResources = undefined;
|
|
28973
|
-
if (this.vectorStoreId) {
|
|
28974
|
-
agentTools.push({ type: 'file_search' });
|
|
28975
|
-
toolResources = {
|
|
28976
|
-
file_search: {
|
|
28977
|
-
vector_store_ids: [this.vectorStoreId],
|
|
28978
|
-
},
|
|
28979
|
-
};
|
|
28980
|
-
}
|
|
28981
|
-
// Add file_search also if knowledgeSources are present in the prompt (passed via AgentLlmExecutionTools)
|
|
28982
|
-
if (modelRequirements.knowledgeSources &&
|
|
28983
|
-
modelRequirements.knowledgeSources.length > 0 &&
|
|
28984
|
-
!this.vectorStoreId) {
|
|
28985
|
-
// Note: Vector store should have been created by AgentLlmExecutionTools and passed via options.
|
|
28986
|
-
// If we are here, it means we have knowledge sources but no vector store ID.
|
|
28987
|
-
// We can't easily create one here without persisting it.
|
|
28988
|
-
console.warn('Knowledge sources provided but no vector store ID. Creating temporary vector store is not implemented in callChatModelStream.');
|
|
28989
|
-
}
|
|
28990
|
-
const start = $getCurrentDate();
|
|
28991
|
-
// Construct the request
|
|
28992
|
-
const rawRequest = {
|
|
28993
|
-
// TODO: Type properly as OpenAI.Responses.CreateResponseParams
|
|
28994
|
-
model: modelRequirements.modelName || 'gpt-4o',
|
|
28995
|
-
input,
|
|
28996
|
-
instructions: modelRequirements.systemMessage,
|
|
28997
|
-
tools: agentTools.length > 0 ? agentTools : undefined,
|
|
28998
|
-
tool_resources: toolResources,
|
|
28999
|
-
store: false, // Stateless by default as we pass full history
|
|
30010
|
+
const preparedAgent = {
|
|
30011
|
+
agent: openAiAgentKitAgent,
|
|
30012
|
+
vectorStoreId,
|
|
29000
30013
|
};
|
|
29001
|
-
if (
|
|
29002
|
-
|
|
30014
|
+
if (storeAsPrepared) {
|
|
30015
|
+
this.setPreparedAgentKitAgent(preparedAgent);
|
|
29003
30016
|
}
|
|
29004
|
-
// Call Responses API
|
|
29005
|
-
// Note: Using any cast because types might not be updated yet
|
|
29006
|
-
const response = await client.responses.create(rawRequest);
|
|
29007
30017
|
if (this.options.isVerbose) {
|
|
29008
|
-
console.info(
|
|
30018
|
+
console.info('[🤰]', 'OpenAI AgentKit agent ready', {
|
|
30019
|
+
name,
|
|
30020
|
+
model: this.agentKitModelName,
|
|
30021
|
+
toolCount: agentKitTools.length,
|
|
30022
|
+
hasVectorStore: Boolean(vectorStoreId),
|
|
30023
|
+
});
|
|
29009
30024
|
}
|
|
29010
|
-
|
|
29011
|
-
|
|
29012
|
-
|
|
29013
|
-
|
|
29014
|
-
|
|
29015
|
-
|
|
29016
|
-
|
|
29017
|
-
|
|
29018
|
-
|
|
29019
|
-
|
|
29020
|
-
|
|
30025
|
+
return preparedAgent;
|
|
30026
|
+
}
|
|
30027
|
+
/**
|
|
30028
|
+
* Ensures the AgentKit SDK is wired to the OpenAI client and API key.
|
|
30029
|
+
*/
|
|
30030
|
+
async ensureAgentKitDefaults() {
|
|
30031
|
+
const client = await this.getClient();
|
|
30032
|
+
setDefaultOpenAIClient(client);
|
|
30033
|
+
const apiKey = this.agentKitOptions.apiKey;
|
|
30034
|
+
if (apiKey && typeof apiKey === 'string') {
|
|
30035
|
+
setDefaultOpenAIKey(apiKey);
|
|
30036
|
+
}
|
|
30037
|
+
}
|
|
30038
|
+
/**
|
|
30039
|
+
* Builds the tool list for AgentKit, including hosted file search when applicable.
|
|
30040
|
+
*/
|
|
30041
|
+
buildAgentKitTools(options) {
|
|
30042
|
+
var _a;
|
|
30043
|
+
const { tools, vectorStoreId } = options;
|
|
30044
|
+
const agentKitTools = [];
|
|
30045
|
+
if (vectorStoreId) {
|
|
30046
|
+
agentKitTools.push(fileSearchTool(vectorStoreId));
|
|
30047
|
+
}
|
|
30048
|
+
if (tools && tools.length > 0) {
|
|
30049
|
+
const scriptTools = this.resolveScriptTools();
|
|
30050
|
+
for (const toolDefinition of tools) {
|
|
30051
|
+
agentKitTools.push(tool({
|
|
30052
|
+
name: toolDefinition.name,
|
|
30053
|
+
description: toolDefinition.description,
|
|
30054
|
+
parameters: toolDefinition.parameters
|
|
30055
|
+
? {
|
|
30056
|
+
...toolDefinition.parameters,
|
|
30057
|
+
additionalProperties: false,
|
|
30058
|
+
required: (_a = toolDefinition.parameters.required) !== null && _a !== void 0 ? _a : [],
|
|
30059
|
+
}
|
|
30060
|
+
: undefined,
|
|
30061
|
+
strict: false,
|
|
30062
|
+
execute: async (input, runContext, details) => {
|
|
30063
|
+
var _a, _b, _c;
|
|
30064
|
+
const scriptTool = scriptTools[0];
|
|
30065
|
+
const functionName = toolDefinition.name;
|
|
30066
|
+
const calledAt = $getCurrentDate();
|
|
30067
|
+
const callId = (_a = details === null || details === void 0 ? void 0 : details.toolCall) === null || _a === void 0 ? void 0 : _a.callId;
|
|
30068
|
+
const functionArgs = input !== null && input !== void 0 ? input : {};
|
|
30069
|
+
if (this.options.isVerbose) {
|
|
30070
|
+
console.info('[🤰]', 'Executing AgentKit tool', {
|
|
30071
|
+
functionName,
|
|
30072
|
+
callId,
|
|
30073
|
+
calledAt,
|
|
30074
|
+
});
|
|
30075
|
+
}
|
|
30076
|
+
try {
|
|
30077
|
+
return await scriptTool.execute({
|
|
30078
|
+
scriptLanguage: 'javascript',
|
|
30079
|
+
script: `
|
|
30080
|
+
const args = ${JSON.stringify(functionArgs)};
|
|
30081
|
+
return await ${functionName}(args);
|
|
30082
|
+
`,
|
|
30083
|
+
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 : {},
|
|
30084
|
+
});
|
|
29021
30085
|
}
|
|
29022
|
-
|
|
29023
|
-
|
|
30086
|
+
catch (error) {
|
|
30087
|
+
assertsError(error);
|
|
30088
|
+
const serializedError = serializeError(error);
|
|
30089
|
+
const errorMessage = spaceTrim$2((block) => `
|
|
30090
|
+
|
|
30091
|
+
The invoked tool \`${functionName}\` failed with error:
|
|
30092
|
+
|
|
30093
|
+
\`\`\`json
|
|
30094
|
+
${block(JSON.stringify(serializedError, null, 4))}
|
|
30095
|
+
\`\`\`
|
|
30096
|
+
|
|
30097
|
+
`);
|
|
30098
|
+
console.error('[🤰]', 'AgentKit tool execution failed', {
|
|
30099
|
+
functionName,
|
|
30100
|
+
callId,
|
|
30101
|
+
error: serializedError,
|
|
30102
|
+
});
|
|
30103
|
+
return errorMessage;
|
|
29024
30104
|
}
|
|
30105
|
+
},
|
|
30106
|
+
}));
|
|
30107
|
+
}
|
|
30108
|
+
}
|
|
30109
|
+
return agentKitTools;
|
|
30110
|
+
}
|
|
30111
|
+
/**
|
|
30112
|
+
* Resolves the configured script tools for tool execution.
|
|
30113
|
+
*/
|
|
30114
|
+
resolveScriptTools() {
|
|
30115
|
+
const executionTools = this.options.executionTools;
|
|
30116
|
+
if (!executionTools || !executionTools.script) {
|
|
30117
|
+
throw new PipelineExecutionError(`Model requested tools but no executionTools.script were provided in OpenAiAgentKitExecutionTools options`);
|
|
30118
|
+
}
|
|
30119
|
+
return Array.isArray(executionTools.script) ? executionTools.script : [executionTools.script];
|
|
30120
|
+
}
|
|
30121
|
+
/**
|
|
30122
|
+
* Runs a prepared AgentKit agent and streams results back to the caller.
|
|
30123
|
+
*/
|
|
30124
|
+
async callChatModelStreamWithPreparedAgent(options) {
|
|
30125
|
+
var _a, _b, _c, _d;
|
|
30126
|
+
const { openAiAgentKitAgent, prompt, onProgress } = options;
|
|
30127
|
+
const rawPromptContent = (_a = options.rawPromptContent) !== null && _a !== void 0 ? _a : templateParameters(prompt.content, {
|
|
30128
|
+
...prompt.parameters,
|
|
30129
|
+
modelName: this.agentKitModelName,
|
|
30130
|
+
});
|
|
30131
|
+
const agentForRun = options.responseFormatOutputType !== undefined
|
|
30132
|
+
? openAiAgentKitAgent.clone({
|
|
30133
|
+
outputType: options.responseFormatOutputType,
|
|
30134
|
+
})
|
|
30135
|
+
: openAiAgentKitAgent;
|
|
30136
|
+
const start = $getCurrentDate();
|
|
30137
|
+
let latestContent = '';
|
|
30138
|
+
const toolCalls = [];
|
|
30139
|
+
const toolCallIndexById = new Map();
|
|
30140
|
+
const inputItems = await this.buildAgentKitInputItems(prompt, rawPromptContent);
|
|
30141
|
+
const rawRequest = {
|
|
30142
|
+
agentName: agentForRun.name,
|
|
30143
|
+
input: inputItems,
|
|
30144
|
+
};
|
|
30145
|
+
const streamResult = await run(agentForRun, inputItems, {
|
|
30146
|
+
stream: true,
|
|
30147
|
+
context: { parameters: prompt.parameters },
|
|
30148
|
+
});
|
|
30149
|
+
for await (const event of streamResult) {
|
|
30150
|
+
if (event.type === 'raw_model_stream_event' && ((_b = event.data) === null || _b === void 0 ? void 0 : _b.type) === 'output_text_delta') {
|
|
30151
|
+
latestContent += event.data.delta;
|
|
30152
|
+
onProgress({
|
|
30153
|
+
content: latestContent,
|
|
30154
|
+
modelName: this.agentKitModelName,
|
|
30155
|
+
timing: { start, complete: $getCurrentDate() },
|
|
30156
|
+
usage: UNCERTAIN_USAGE,
|
|
30157
|
+
rawPromptContent: rawPromptContent,
|
|
30158
|
+
rawRequest: null,
|
|
30159
|
+
rawResponse: {},
|
|
30160
|
+
});
|
|
30161
|
+
continue;
|
|
30162
|
+
}
|
|
30163
|
+
if (event.type === 'run_item_stream_event') {
|
|
30164
|
+
const rawItem = (_c = event.item) === null || _c === void 0 ? void 0 : _c.rawItem;
|
|
30165
|
+
if (event.name === 'tool_called' && (rawItem === null || rawItem === void 0 ? void 0 : rawItem.type) === 'function_call') {
|
|
30166
|
+
const toolCall = {
|
|
30167
|
+
name: rawItem.name,
|
|
30168
|
+
arguments: rawItem.arguments,
|
|
30169
|
+
rawToolCall: rawItem,
|
|
30170
|
+
createdAt: $getCurrentDate(),
|
|
30171
|
+
};
|
|
30172
|
+
toolCallIndexById.set(rawItem.callId, toolCalls.length);
|
|
30173
|
+
toolCalls.push(toolCall);
|
|
30174
|
+
onProgress({
|
|
30175
|
+
content: latestContent,
|
|
30176
|
+
modelName: this.agentKitModelName,
|
|
30177
|
+
timing: { start, complete: $getCurrentDate() },
|
|
30178
|
+
usage: UNCERTAIN_USAGE,
|
|
30179
|
+
rawPromptContent: rawPromptContent,
|
|
30180
|
+
rawRequest: null,
|
|
30181
|
+
rawResponse: {},
|
|
30182
|
+
toolCalls: [toolCall],
|
|
30183
|
+
});
|
|
30184
|
+
}
|
|
30185
|
+
if (event.name === 'tool_output' && (rawItem === null || rawItem === void 0 ? void 0 : rawItem.type) === 'function_call_result') {
|
|
30186
|
+
const index = toolCallIndexById.get(rawItem.callId);
|
|
30187
|
+
const result = this.formatAgentKitToolOutput(rawItem.output);
|
|
30188
|
+
if (index !== undefined) {
|
|
30189
|
+
const existingToolCall = toolCalls[index];
|
|
30190
|
+
const completedToolCall = {
|
|
30191
|
+
...existingToolCall,
|
|
30192
|
+
result,
|
|
30193
|
+
rawToolCall: rawItem,
|
|
30194
|
+
};
|
|
30195
|
+
toolCalls[index] = completedToolCall;
|
|
30196
|
+
onProgress({
|
|
30197
|
+
content: latestContent,
|
|
30198
|
+
modelName: this.agentKitModelName,
|
|
30199
|
+
timing: { start, complete: $getCurrentDate() },
|
|
30200
|
+
usage: UNCERTAIN_USAGE,
|
|
30201
|
+
rawPromptContent: rawPromptContent,
|
|
30202
|
+
rawRequest: null,
|
|
30203
|
+
rawResponse: {},
|
|
30204
|
+
toolCalls: [completedToolCall],
|
|
30205
|
+
});
|
|
29025
30206
|
}
|
|
29026
30207
|
}
|
|
29027
|
-
else if (item.type === 'function_call') ;
|
|
29028
30208
|
}
|
|
29029
30209
|
}
|
|
29030
|
-
|
|
29031
|
-
|
|
29032
|
-
|
|
29033
|
-
|
|
29034
|
-
|
|
29035
|
-
|
|
29036
|
-
content: resultContent,
|
|
29037
|
-
modelName: response.model || 'agent',
|
|
30210
|
+
await streamResult.completed;
|
|
30211
|
+
const complete = $getCurrentDate();
|
|
30212
|
+
const finalContent = ((_d = streamResult.finalOutput) !== null && _d !== void 0 ? _d : latestContent);
|
|
30213
|
+
const finalResult = {
|
|
30214
|
+
content: finalContent,
|
|
30215
|
+
modelName: this.agentKitModelName,
|
|
29038
30216
|
timing: { start, complete },
|
|
29039
30217
|
usage: UNCERTAIN_USAGE,
|
|
29040
|
-
rawPromptContent,
|
|
30218
|
+
rawPromptContent: rawPromptContent,
|
|
29041
30219
|
rawRequest,
|
|
29042
|
-
rawResponse:
|
|
29043
|
-
|
|
29044
|
-
|
|
29045
|
-
|
|
29046
|
-
|
|
29047
|
-
order: [],
|
|
29048
|
-
value: {
|
|
29049
|
-
content: resultContent,
|
|
29050
|
-
modelName: response.model || 'agent',
|
|
29051
|
-
timing: { start, complete },
|
|
29052
|
-
usage: UNCERTAIN_USAGE,
|
|
29053
|
-
rawPromptContent,
|
|
29054
|
-
rawRequest,
|
|
29055
|
-
rawResponse: response,
|
|
29056
|
-
toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
29057
|
-
},
|
|
29058
|
-
});
|
|
30220
|
+
rawResponse: { runResult: streamResult },
|
|
30221
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
30222
|
+
};
|
|
30223
|
+
onProgress(finalResult);
|
|
30224
|
+
return finalResult;
|
|
29059
30225
|
}
|
|
29060
30226
|
/**
|
|
29061
|
-
*
|
|
30227
|
+
* Builds AgentKit input items from the prompt and optional thread.
|
|
29062
30228
|
*/
|
|
29063
|
-
|
|
29064
|
-
|
|
29065
|
-
const
|
|
29066
|
-
|
|
29067
|
-
|
|
29068
|
-
|
|
29069
|
-
|
|
29070
|
-
|
|
29071
|
-
|
|
29072
|
-
|
|
29073
|
-
|
|
29074
|
-
|
|
29075
|
-
|
|
29076
|
-
const response = await fetch(source);
|
|
29077
|
-
if (!response.ok) {
|
|
29078
|
-
console.error(`Failed to download ${source}: ${response.statusText}`);
|
|
29079
|
-
continue;
|
|
29080
|
-
}
|
|
29081
|
-
const buffer = await response.arrayBuffer();
|
|
29082
|
-
const filename = source.split('/').pop() || 'downloaded-file';
|
|
29083
|
-
const blob = new Blob([buffer]);
|
|
29084
|
-
const file = new File([blob], filename);
|
|
29085
|
-
fileStreams.push(file);
|
|
30229
|
+
async buildAgentKitInputItems(prompt, rawPromptContent) {
|
|
30230
|
+
var _a;
|
|
30231
|
+
const inputItems = [];
|
|
30232
|
+
if ('thread' in prompt && Array.isArray(prompt.thread)) {
|
|
30233
|
+
for (const message of prompt.thread) {
|
|
30234
|
+
const sender = message.sender;
|
|
30235
|
+
const content = (_a = message.content) !== null && _a !== void 0 ? _a : '';
|
|
30236
|
+
if (sender === 'assistant' || sender === 'agent') {
|
|
30237
|
+
inputItems.push({
|
|
30238
|
+
role: 'assistant',
|
|
30239
|
+
status: 'completed',
|
|
30240
|
+
content: [{ type: 'output_text', text: content }],
|
|
30241
|
+
});
|
|
29086
30242
|
}
|
|
29087
30243
|
else {
|
|
29088
|
-
|
|
30244
|
+
inputItems.push({
|
|
30245
|
+
role: 'user',
|
|
30246
|
+
content,
|
|
30247
|
+
});
|
|
29089
30248
|
}
|
|
29090
30249
|
}
|
|
29091
|
-
catch (error) {
|
|
29092
|
-
console.error(`Error processing knowledge source ${source}:`, error);
|
|
29093
|
-
}
|
|
29094
30250
|
}
|
|
29095
|
-
|
|
29096
|
-
|
|
29097
|
-
|
|
29098
|
-
|
|
29099
|
-
|
|
29100
|
-
|
|
29101
|
-
|
|
29102
|
-
|
|
29103
|
-
|
|
30251
|
+
const userContent = await this.buildAgentKitUserContent(prompt, rawPromptContent);
|
|
30252
|
+
inputItems.push({
|
|
30253
|
+
role: 'user',
|
|
30254
|
+
content: userContent,
|
|
30255
|
+
});
|
|
30256
|
+
return inputItems;
|
|
30257
|
+
}
|
|
30258
|
+
/**
|
|
30259
|
+
* Builds the user message content for AgentKit runs, including file inputs when provided.
|
|
30260
|
+
*/
|
|
30261
|
+
async buildAgentKitUserContent(prompt, rawPromptContent) {
|
|
30262
|
+
if ('files' in prompt && Array.isArray(prompt.files) && prompt.files.length > 0) {
|
|
30263
|
+
const fileItems = await Promise.all(prompt.files.map(async (file) => {
|
|
30264
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
30265
|
+
const base64 = Buffer.from(arrayBuffer).toString('base64');
|
|
30266
|
+
return {
|
|
30267
|
+
type: 'input_image',
|
|
30268
|
+
image: `data:${file.type};base64,${base64}`,
|
|
30269
|
+
};
|
|
30270
|
+
}));
|
|
30271
|
+
return [{ type: 'input_text', text: rawPromptContent }, ...fileItems];
|
|
30272
|
+
}
|
|
30273
|
+
return rawPromptContent;
|
|
30274
|
+
}
|
|
30275
|
+
/**
|
|
30276
|
+
* Normalizes AgentKit tool outputs into a string for Promptbook tool call results.
|
|
30277
|
+
*/
|
|
30278
|
+
formatAgentKitToolOutput(output) {
|
|
30279
|
+
if (typeof output === 'string') {
|
|
30280
|
+
return output;
|
|
30281
|
+
}
|
|
30282
|
+
if (output && typeof output === 'object') {
|
|
30283
|
+
const textOutput = output;
|
|
30284
|
+
if (textOutput.type === 'text' && typeof textOutput.text === 'string') {
|
|
30285
|
+
return textOutput.text;
|
|
29104
30286
|
}
|
|
29105
30287
|
}
|
|
29106
|
-
return
|
|
30288
|
+
return JSON.stringify(output !== null && output !== void 0 ? output : null);
|
|
29107
30289
|
}
|
|
29108
30290
|
/**
|
|
29109
|
-
*
|
|
30291
|
+
* Returns AgentKit-specific options.
|
|
30292
|
+
*/
|
|
30293
|
+
get agentKitOptions() {
|
|
30294
|
+
return this.options;
|
|
30295
|
+
}
|
|
30296
|
+
/**
|
|
30297
|
+
* Discriminant for type guards.
|
|
29110
30298
|
*/
|
|
29111
30299
|
get discriminant() {
|
|
29112
|
-
return
|
|
30300
|
+
return DISCRIMINANT;
|
|
29113
30301
|
}
|
|
29114
30302
|
/**
|
|
29115
|
-
* Type guard to check if given `LlmExecutionTools` are instanceof `
|
|
30303
|
+
* Type guard to check if given `LlmExecutionTools` are instanceof `OpenAiAgentKitExecutionTools`.
|
|
29116
30304
|
*/
|
|
29117
|
-
static
|
|
29118
|
-
return llmExecutionTools.discriminant ===
|
|
30305
|
+
static isOpenAiAgentKitExecutionTools(llmExecutionTools) {
|
|
30306
|
+
return llmExecutionTools.discriminant === DISCRIMINANT;
|
|
29119
30307
|
}
|
|
29120
30308
|
}
|
|
30309
|
+
/**
|
|
30310
|
+
* Discriminant for type guards.
|
|
30311
|
+
*
|
|
30312
|
+
* @private const of `OpenAiAgentKitExecutionTools`
|
|
30313
|
+
*/
|
|
30314
|
+
const DISCRIMINANT = 'OPEN_AI_AGENT_KIT_V1';
|
|
29121
30315
|
|
|
29122
30316
|
/**
|
|
29123
30317
|
* Emits a progress update to signal assistant preparation before long setup work.
|
|
@@ -29154,8 +30348,8 @@ function emitAssistantPreparationProgress(options) {
|
|
|
29154
30348
|
* - `Agent` - which represents an AI Agent with its source, memories, actions, etc. Agent is a higher-level abstraction which is internally using:
|
|
29155
30349
|
* - `LlmExecutionTools` - which wraps one or more LLM models and provides an interface to execute them
|
|
29156
30350
|
* - `AgentLlmExecutionTools` - which is a specific implementation of `LlmExecutionTools` that wraps another LlmExecutionTools and applies agent-specific system prompts and requirements
|
|
29157
|
-
* - `OpenAiAgentExecutionTools` - which is a specific implementation of `LlmExecutionTools` for OpenAI models with agent capabilities (using Responses API), recommended for usage in `Agent` or `AgentLlmExecutionTools`
|
|
29158
30351
|
* - `OpenAiAssistantExecutionTools` - (Deprecated) which is a specific implementation of `LlmExecutionTools` for OpenAI models with assistant capabilities
|
|
30352
|
+
* - `OpenAiAgentKitExecutionTools` - which is a specific implementation of `LlmExecutionTools` backed by OpenAI AgentKit
|
|
29159
30353
|
* - `RemoteAgent` - which is an `Agent` that connects to a Promptbook Agents Server
|
|
29160
30354
|
*
|
|
29161
30355
|
* @public exported from `@promptbook/core`
|
|
@@ -29290,97 +30484,129 @@ class AgentLlmExecutionTools {
|
|
|
29290
30484
|
* Calls the chat model with agent-specific system prompt and requirements with streaming
|
|
29291
30485
|
*/
|
|
29292
30486
|
async callChatModelStream(prompt, onProgress) {
|
|
30487
|
+
var _a, _b;
|
|
29293
30488
|
// Ensure we're working with a chat prompt
|
|
29294
30489
|
if (prompt.modelRequirements.modelVariant !== 'CHAT') {
|
|
29295
30490
|
throw new Error('AgentLlmExecutionTools only supports chat prompts');
|
|
29296
30491
|
}
|
|
29297
30492
|
const modelRequirements = await this.getModelRequirements();
|
|
30493
|
+
const { _metadata, promptSuffix, ...sanitizedRequirements } = modelRequirements;
|
|
29298
30494
|
const chatPrompt = prompt;
|
|
29299
30495
|
let underlyingLlmResult;
|
|
29300
|
-
|
|
30496
|
+
const chatPromptContentWithSuffix = promptSuffix
|
|
30497
|
+
? `${chatPrompt.content}\n\n${promptSuffix}`
|
|
30498
|
+
: chatPrompt.content;
|
|
29301
30499
|
const promptWithAgentModelRequirements = {
|
|
29302
30500
|
...chatPrompt,
|
|
30501
|
+
content: chatPromptContentWithSuffix,
|
|
29303
30502
|
modelRequirements: {
|
|
29304
30503
|
...chatPrompt.modelRequirements,
|
|
29305
|
-
...
|
|
30504
|
+
...sanitizedRequirements,
|
|
29306
30505
|
// Spread tools to convert readonly array to mutable
|
|
29307
|
-
tools:
|
|
30506
|
+
tools: sanitizedRequirements.tools
|
|
30507
|
+
? [...sanitizedRequirements.tools]
|
|
30508
|
+
: chatPrompt.modelRequirements.tools,
|
|
29308
30509
|
// Spread knowledgeSources to convert readonly array to mutable
|
|
29309
|
-
knowledgeSources:
|
|
29310
|
-
? [...
|
|
30510
|
+
knowledgeSources: sanitizedRequirements.knowledgeSources
|
|
30511
|
+
? [...sanitizedRequirements.knowledgeSources]
|
|
29311
30512
|
: undefined,
|
|
29312
30513
|
// Prepend agent system message to existing system message
|
|
29313
|
-
systemMessage:
|
|
30514
|
+
systemMessage: sanitizedRequirements.systemMessage +
|
|
29314
30515
|
(chatPrompt.modelRequirements.systemMessage
|
|
29315
30516
|
? `\n\n${chatPrompt.modelRequirements.systemMessage}`
|
|
29316
30517
|
: ''),
|
|
29317
30518
|
}, // Cast to avoid readonly mismatch from spread
|
|
29318
30519
|
};
|
|
29319
30520
|
console.log('!!!! promptWithAgentModelRequirements:', promptWithAgentModelRequirements);
|
|
29320
|
-
if (
|
|
29321
|
-
const requirementsHash = SHA256(JSON.stringify(
|
|
29322
|
-
const
|
|
29323
|
-
|
|
29324
|
-
|
|
30521
|
+
if (OpenAiAgentKitExecutionTools.isOpenAiAgentKitExecutionTools(this.options.llmTools)) {
|
|
30522
|
+
const requirementsHash = SHA256(JSON.stringify(sanitizedRequirements)).toString();
|
|
30523
|
+
const vectorStoreHash = SHA256(JSON.stringify((_a = sanitizedRequirements.knowledgeSources) !== null && _a !== void 0 ? _a : [])).toString();
|
|
30524
|
+
const cachedVectorStore = AgentLlmExecutionTools.vectorStoreCache.get(this.title);
|
|
30525
|
+
const cachedAgentKit = AgentLlmExecutionTools.agentKitAgentCache.get(this.title);
|
|
30526
|
+
let preparedAgentKit = this.options.assistantPreparationMode === 'external'
|
|
30527
|
+
? this.options.llmTools.getPreparedAgentKitAgent()
|
|
30528
|
+
: null;
|
|
30529
|
+
const vectorStoreId = (preparedAgentKit === null || preparedAgentKit === void 0 ? void 0 : preparedAgentKit.vectorStoreId) ||
|
|
30530
|
+
(cachedVectorStore && cachedVectorStore.requirementsHash === vectorStoreHash
|
|
30531
|
+
? cachedVectorStore.vectorStoreId
|
|
30532
|
+
: undefined);
|
|
30533
|
+
if (!preparedAgentKit && cachedAgentKit && cachedAgentKit.requirementsHash === requirementsHash) {
|
|
29325
30534
|
if (this.options.isVerbose) {
|
|
29326
|
-
console.
|
|
30535
|
+
console.info('[🤰]', 'Using cached OpenAI AgentKit agent', {
|
|
30536
|
+
agent: this.title,
|
|
30537
|
+
});
|
|
29327
30538
|
}
|
|
29328
|
-
|
|
29329
|
-
|
|
29330
|
-
|
|
29331
|
-
|
|
29332
|
-
// We can cast to access options if they were public, or use a method to clone.
|
|
29333
|
-
// OpenAiAgentExecutionTools doesn't have a clone method.
|
|
29334
|
-
// However, we can just assume the passed tool *might* not have the vector store yet, or we are replacing it.
|
|
29335
|
-
// Actually, if the passed tool IS OpenAiAgentExecutionTools, we should use it as a base.
|
|
29336
|
-
// TODO: [🧠] This is a bit hacky, accessing protected options or recreating tools.
|
|
29337
|
-
// Ideally OpenAiAgentExecutionTools should have a method `withVectorStoreId`.
|
|
29338
|
-
agentTools = new OpenAiAgentExecutionTools({
|
|
29339
|
-
...this.options.llmTools.options,
|
|
29340
|
-
vectorStoreId: cached.vectorStoreId,
|
|
29341
|
-
});
|
|
30539
|
+
preparedAgentKit = {
|
|
30540
|
+
agent: cachedAgentKit.agent,
|
|
30541
|
+
vectorStoreId: cachedAgentKit.vectorStoreId,
|
|
30542
|
+
};
|
|
29342
30543
|
}
|
|
29343
|
-
|
|
30544
|
+
if (!preparedAgentKit) {
|
|
29344
30545
|
if (this.options.isVerbose) {
|
|
29345
|
-
console.
|
|
29346
|
-
|
|
29347
|
-
|
|
29348
|
-
if (modelRequirements.knowledgeSources && modelRequirements.knowledgeSources.length > 0) {
|
|
29349
|
-
const client = await this.options.llmTools.getClient();
|
|
29350
|
-
vectorStoreId = await OpenAiAgentExecutionTools.createVectorStore(client, this.title, modelRequirements.knowledgeSources);
|
|
30546
|
+
console.info('[🤰]', 'Preparing OpenAI AgentKit agent', {
|
|
30547
|
+
agent: this.title,
|
|
30548
|
+
});
|
|
29351
30549
|
}
|
|
29352
|
-
if (vectorStoreId) {
|
|
29353
|
-
|
|
29354
|
-
|
|
29355
|
-
|
|
30550
|
+
if (!vectorStoreId && ((_b = sanitizedRequirements.knowledgeSources) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
30551
|
+
emitAssistantPreparationProgress({
|
|
30552
|
+
onProgress,
|
|
30553
|
+
prompt,
|
|
30554
|
+
modelName: this.modelName,
|
|
30555
|
+
phase: 'Creating knowledge base',
|
|
29356
30556
|
});
|
|
29357
30557
|
}
|
|
29358
|
-
|
|
29359
|
-
|
|
30558
|
+
emitAssistantPreparationProgress({
|
|
30559
|
+
onProgress,
|
|
30560
|
+
prompt,
|
|
30561
|
+
modelName: this.modelName,
|
|
30562
|
+
phase: 'Preparing AgentKit agent',
|
|
30563
|
+
});
|
|
30564
|
+
preparedAgentKit = await this.options.llmTools.prepareAgentKitAgent({
|
|
30565
|
+
name: this.title,
|
|
30566
|
+
instructions: sanitizedRequirements.systemMessage || '',
|
|
30567
|
+
knowledgeSources: sanitizedRequirements.knowledgeSources,
|
|
30568
|
+
tools: sanitizedRequirements.tools ? [...sanitizedRequirements.tools] : undefined,
|
|
29360
30569
|
vectorStoreId,
|
|
29361
30570
|
});
|
|
29362
30571
|
}
|
|
29363
|
-
|
|
29364
|
-
|
|
29365
|
-
|
|
29366
|
-
|
|
29367
|
-
|
|
29368
|
-
|
|
29369
|
-
|
|
29370
|
-
|
|
29371
|
-
|
|
29372
|
-
|
|
29373
|
-
|
|
29374
|
-
|
|
29375
|
-
|
|
29376
|
-
|
|
30572
|
+
if (preparedAgentKit.vectorStoreId) {
|
|
30573
|
+
AgentLlmExecutionTools.vectorStoreCache.set(this.title, {
|
|
30574
|
+
vectorStoreId: preparedAgentKit.vectorStoreId,
|
|
30575
|
+
requirementsHash: vectorStoreHash,
|
|
30576
|
+
});
|
|
30577
|
+
}
|
|
30578
|
+
AgentLlmExecutionTools.agentKitAgentCache.set(this.title, {
|
|
30579
|
+
agent: preparedAgentKit.agent,
|
|
30580
|
+
requirementsHash,
|
|
30581
|
+
vectorStoreId: preparedAgentKit.vectorStoreId,
|
|
30582
|
+
});
|
|
30583
|
+
const responseFormatOutputType = mapResponseFormatToAgentOutputType(promptWithAgentModelRequirements.modelRequirements.responseFormat);
|
|
30584
|
+
underlyingLlmResult = await this.options.llmTools.callChatModelStreamWithPreparedAgent({
|
|
30585
|
+
openAiAgentKitAgent: preparedAgentKit.agent,
|
|
30586
|
+
prompt: promptWithAgentModelRequirements,
|
|
30587
|
+
onProgress,
|
|
30588
|
+
responseFormatOutputType,
|
|
30589
|
+
});
|
|
29377
30590
|
}
|
|
29378
30591
|
else if (OpenAiAssistantExecutionTools.isOpenAiAssistantExecutionTools(this.options.llmTools)) {
|
|
29379
30592
|
// ... deprecated path ...
|
|
29380
|
-
const requirementsHash = SHA256(JSON.stringify(
|
|
30593
|
+
const requirementsHash = SHA256(JSON.stringify(sanitizedRequirements)).toString();
|
|
29381
30594
|
const cached = AgentLlmExecutionTools.assistantCache.get(this.title);
|
|
29382
30595
|
let assistant;
|
|
29383
|
-
if (
|
|
30596
|
+
if (this.options.assistantPreparationMode === 'external') {
|
|
30597
|
+
assistant = this.options.llmTools;
|
|
30598
|
+
if (this.options.isVerbose) {
|
|
30599
|
+
console.info('[🤰]', 'Using externally managed OpenAI Assistant', {
|
|
30600
|
+
agent: this.title,
|
|
30601
|
+
assistantId: assistant.assistantId,
|
|
30602
|
+
});
|
|
30603
|
+
}
|
|
30604
|
+
AgentLlmExecutionTools.assistantCache.set(this.title, {
|
|
30605
|
+
assistantId: assistant.assistantId,
|
|
30606
|
+
requirementsHash,
|
|
30607
|
+
});
|
|
30608
|
+
}
|
|
30609
|
+
else if (cached) {
|
|
29384
30610
|
if (cached.requirementsHash === requirementsHash) {
|
|
29385
30611
|
if (this.options.isVerbose) {
|
|
29386
30612
|
console.info('[🤰]', 'Using cached OpenAI Assistant', {
|
|
@@ -29406,9 +30632,9 @@ class AgentLlmExecutionTools {
|
|
|
29406
30632
|
assistant = await this.options.llmTools.updateAssistant({
|
|
29407
30633
|
assistantId: cached.assistantId,
|
|
29408
30634
|
name: this.title,
|
|
29409
|
-
instructions:
|
|
29410
|
-
knowledgeSources:
|
|
29411
|
-
tools:
|
|
30635
|
+
instructions: sanitizedRequirements.systemMessage,
|
|
30636
|
+
knowledgeSources: sanitizedRequirements.knowledgeSources,
|
|
30637
|
+
tools: sanitizedRequirements.tools ? [...sanitizedRequirements.tools] : undefined,
|
|
29412
30638
|
});
|
|
29413
30639
|
AgentLlmExecutionTools.assistantCache.set(this.title, {
|
|
29414
30640
|
assistantId: assistant.assistantId,
|
|
@@ -29431,9 +30657,9 @@ class AgentLlmExecutionTools {
|
|
|
29431
30657
|
});
|
|
29432
30658
|
assistant = await this.options.llmTools.createNewAssistant({
|
|
29433
30659
|
name: this.title,
|
|
29434
|
-
instructions:
|
|
29435
|
-
knowledgeSources:
|
|
29436
|
-
tools:
|
|
30660
|
+
instructions: sanitizedRequirements.systemMessage,
|
|
30661
|
+
knowledgeSources: sanitizedRequirements.knowledgeSources,
|
|
30662
|
+
tools: sanitizedRequirements.tools ? [...sanitizedRequirements.tools] : undefined,
|
|
29437
30663
|
/*
|
|
29438
30664
|
!!!
|
|
29439
30665
|
metadata: {
|
|
@@ -29475,18 +30701,28 @@ class AgentLlmExecutionTools {
|
|
|
29475
30701
|
}
|
|
29476
30702
|
}
|
|
29477
30703
|
let content = underlyingLlmResult.content;
|
|
29478
|
-
|
|
29479
|
-
|
|
29480
|
-
|
|
29481
|
-
|
|
30704
|
+
if (typeof content === 'string') {
|
|
30705
|
+
// Note: Cleanup the AI artifacts from the content
|
|
30706
|
+
content = humanizeAiText(content);
|
|
30707
|
+
// Note: Make sure the content is Promptbook-like
|
|
30708
|
+
content = promptbookifyAiText(content);
|
|
30709
|
+
}
|
|
30710
|
+
else {
|
|
30711
|
+
// TODO: Maybe deep `humanizeAiText` + `promptbookifyAiText` inside of the object
|
|
30712
|
+
content = JSON.stringify(content);
|
|
30713
|
+
}
|
|
29482
30714
|
const agentResult = {
|
|
29483
30715
|
...underlyingLlmResult,
|
|
29484
|
-
content,
|
|
30716
|
+
content: content,
|
|
29485
30717
|
modelName: this.modelName,
|
|
29486
30718
|
};
|
|
29487
30719
|
return agentResult;
|
|
29488
30720
|
}
|
|
29489
30721
|
}
|
|
30722
|
+
/**
|
|
30723
|
+
* Cached AgentKit agents to avoid rebuilding identical instances.
|
|
30724
|
+
*/
|
|
30725
|
+
AgentLlmExecutionTools.agentKitAgentCache = new Map();
|
|
29490
30726
|
/**
|
|
29491
30727
|
* Cache of OpenAI assistants to avoid creating duplicates
|
|
29492
30728
|
*/
|
|
@@ -29567,8 +30803,8 @@ function buildTeacherSummary(commitments, used) {
|
|
|
29567
30803
|
* - `Agent` - which represents an AI Agent with its source, memories, actions, etc. Agent is a higher-level abstraction which is internally using:
|
|
29568
30804
|
* - `LlmExecutionTools` - which wraps one or more LLM models and provides an interface to execute them
|
|
29569
30805
|
* - `AgentLlmExecutionTools` - which is a specific implementation of `LlmExecutionTools` that wraps another LlmExecutionTools and applies agent-specific system prompts and requirements
|
|
29570
|
-
* - `OpenAiAgentExecutionTools` - which is a specific implementation of `LlmExecutionTools` for OpenAI models with agent capabilities (using Responses API), recommended for usage in `Agent` or `AgentLlmExecutionTools`
|
|
29571
30806
|
* - `OpenAiAssistantExecutionTools` - (Deprecated) which is a specific implementation of `LlmExecutionTools` for OpenAI models with assistant capabilities
|
|
30807
|
+
* - `OpenAiAgentKitExecutionTools` - which is a specific implementation of `LlmExecutionTools` backed by OpenAI AgentKit
|
|
29572
30808
|
* - `RemoteAgent` - which is an `Agent` that connects to a Promptbook Agents Server
|
|
29573
30809
|
*
|
|
29574
30810
|
* @public exported from `@promptbook/core`
|
|
@@ -29599,6 +30835,7 @@ class Agent extends AgentLlmExecutionTools {
|
|
|
29599
30835
|
super({
|
|
29600
30836
|
isVerbose: options.isVerbose,
|
|
29601
30837
|
llmTools: getSingleLlmExecutionTools(options.executionTools.llm),
|
|
30838
|
+
assistantPreparationMode: options.assistantPreparationMode,
|
|
29602
30839
|
agentSource: agentSource.value, // <- TODO: [🐱🚀] Allow to pass BehaviorSubject<string_book> OR refresh llmExecutionTools.callChat on agentSource change
|
|
29603
30840
|
});
|
|
29604
30841
|
_Agent_instances.add(this);
|
|
@@ -29665,7 +30902,6 @@ class Agent extends AgentLlmExecutionTools {
|
|
|
29665
30902
|
* Note: This method also implements the learning mechanism
|
|
29666
30903
|
*/
|
|
29667
30904
|
async callChatModelStream(prompt, onProgress) {
|
|
29668
|
-
var _a;
|
|
29669
30905
|
// [1] Check if the user is asking the same thing as in the samples
|
|
29670
30906
|
const modelRequirements = await this.getModelRequirements();
|
|
29671
30907
|
if (modelRequirements.samples) {
|
|
@@ -29713,7 +30949,7 @@ class Agent extends AgentLlmExecutionTools {
|
|
|
29713
30949
|
if (result.rawResponse && 'sample' in result.rawResponse) {
|
|
29714
30950
|
return result;
|
|
29715
30951
|
}
|
|
29716
|
-
if (
|
|
30952
|
+
if (modelRequirements.isClosed) {
|
|
29717
30953
|
return result;
|
|
29718
30954
|
}
|
|
29719
30955
|
// Note: [0] Notify start of self-learning
|
|
@@ -29874,6 +31110,63 @@ async function _Agent_selfLearnTeacher(prompt, result) {
|
|
|
29874
31110
|
* TODO: [🧠][😰]Agent is not working with the parameters, should it be?
|
|
29875
31111
|
*/
|
|
29876
31112
|
|
|
31113
|
+
/**
|
|
31114
|
+
* Resolve a remote META IMAGE value into an absolute URL when possible.
|
|
31115
|
+
*/
|
|
31116
|
+
function resolveRemoteImageUrl(imageUrl, agentUrl) {
|
|
31117
|
+
if (!imageUrl) {
|
|
31118
|
+
return undefined;
|
|
31119
|
+
}
|
|
31120
|
+
if (imageUrl.startsWith('http://') ||
|
|
31121
|
+
imageUrl.startsWith('https://') ||
|
|
31122
|
+
imageUrl.startsWith('data:') ||
|
|
31123
|
+
imageUrl.startsWith('blob:')) {
|
|
31124
|
+
return imageUrl;
|
|
31125
|
+
}
|
|
31126
|
+
try {
|
|
31127
|
+
return new URL(imageUrl, agentUrl).href;
|
|
31128
|
+
}
|
|
31129
|
+
catch (_a) {
|
|
31130
|
+
return imageUrl;
|
|
31131
|
+
}
|
|
31132
|
+
}
|
|
31133
|
+
/**
|
|
31134
|
+
* Format a META commitment line when the value is provided.
|
|
31135
|
+
*/
|
|
31136
|
+
function formatMetaLine(label, value) {
|
|
31137
|
+
if (!value) {
|
|
31138
|
+
return null;
|
|
31139
|
+
}
|
|
31140
|
+
return `META ${label} ${value}`;
|
|
31141
|
+
}
|
|
31142
|
+
/**
|
|
31143
|
+
* Build a minimal agent source snapshot for remote agents.
|
|
31144
|
+
*/
|
|
31145
|
+
function buildRemoteAgentSource(profile, meta) {
|
|
31146
|
+
const metaLines = [
|
|
31147
|
+
formatMetaLine('FULLNAME', meta === null || meta === void 0 ? void 0 : meta.fullname),
|
|
31148
|
+
formatMetaLine('IMAGE', meta === null || meta === void 0 ? void 0 : meta.image),
|
|
31149
|
+
formatMetaLine('DESCRIPTION', meta === null || meta === void 0 ? void 0 : meta.description),
|
|
31150
|
+
formatMetaLine('COLOR', meta === null || meta === void 0 ? void 0 : meta.color),
|
|
31151
|
+
formatMetaLine('FONT', meta === null || meta === void 0 ? void 0 : meta.font),
|
|
31152
|
+
formatMetaLine('LINK', meta === null || meta === void 0 ? void 0 : meta.link),
|
|
31153
|
+
]
|
|
31154
|
+
.filter((line) => Boolean(line))
|
|
31155
|
+
.join('\n');
|
|
31156
|
+
const personaBlock = profile.personaDescription
|
|
31157
|
+
? spaceTrim$2((block) => `
|
|
31158
|
+
PERSONA
|
|
31159
|
+
${block(profile.personaDescription || '')}
|
|
31160
|
+
`)
|
|
31161
|
+
: '';
|
|
31162
|
+
return book `
|
|
31163
|
+
${profile.agentName}
|
|
31164
|
+
|
|
31165
|
+
${metaLines}
|
|
31166
|
+
|
|
31167
|
+
${personaBlock}
|
|
31168
|
+
`;
|
|
31169
|
+
}
|
|
29877
31170
|
/**
|
|
29878
31171
|
* Represents one AI Agent
|
|
29879
31172
|
*
|
|
@@ -29881,13 +31174,15 @@ async function _Agent_selfLearnTeacher(prompt, result) {
|
|
|
29881
31174
|
* - `Agent` - which represents an AI Agent with its source, memories, actions, etc. Agent is a higher-level abstraction which is internally using:
|
|
29882
31175
|
* - `LlmExecutionTools` - which wraps one or more LLM models and provides an interface to execute them
|
|
29883
31176
|
* - `AgentLlmExecutionTools` - which is a specific implementation of `LlmExecutionTools` that wraps another LlmExecutionTools and applies agent-specific system prompts and requirements
|
|
29884
|
-
* - `OpenAiAssistantExecutionTools` - which is a specific implementation of `LlmExecutionTools` for OpenAI models with assistant capabilities
|
|
31177
|
+
* - `OpenAiAssistantExecutionTools` - (Deprecated) which is a specific implementation of `LlmExecutionTools` for OpenAI models with assistant capabilities
|
|
31178
|
+
* - `OpenAiAgentKitExecutionTools` - which is a specific implementation of `LlmExecutionTools` backed by OpenAI AgentKit
|
|
29885
31179
|
* - `RemoteAgent` - which is an `Agent` that connects to a Promptbook Agents Server
|
|
29886
31180
|
*
|
|
29887
31181
|
* @public exported from `@promptbook/core`
|
|
29888
31182
|
*/
|
|
29889
31183
|
class RemoteAgent extends Agent {
|
|
29890
31184
|
static async connect(options) {
|
|
31185
|
+
var _a, _b, _c;
|
|
29891
31186
|
const agentProfileUrl = `${options.agentUrl}/api/profile`;
|
|
29892
31187
|
const profileResponse = await fetch(agentProfileUrl);
|
|
29893
31188
|
// <- TODO: [🐱🚀] What about closed-source agents?
|
|
@@ -29907,14 +31202,14 @@ class RemoteAgent extends Agent {
|
|
|
29907
31202
|
|
|
29908
31203
|
`));
|
|
29909
31204
|
}
|
|
29910
|
-
const profile = await profileResponse.json();
|
|
31205
|
+
const profile = (await profileResponse.json());
|
|
31206
|
+
const resolvedMeta = {
|
|
31207
|
+
...(profile.meta || {}),
|
|
31208
|
+
image: resolveRemoteImageUrl((_a = profile.meta) === null || _a === void 0 ? void 0 : _a.image, options.agentUrl),
|
|
31209
|
+
};
|
|
29911
31210
|
// Note: We are creating dummy agent source because we don't have the source from the remote agent
|
|
29912
31211
|
// But we populate the metadata from the profile
|
|
29913
|
-
const agentSource = new BehaviorSubject(
|
|
29914
|
-
${profile.agentName}
|
|
29915
|
-
|
|
29916
|
-
${profile.personaDescription}
|
|
29917
|
-
`);
|
|
31212
|
+
const agentSource = new BehaviorSubject(buildRemoteAgentSource(profile, resolvedMeta));
|
|
29918
31213
|
// <- TODO: [🐱🚀] createBookFromProfile
|
|
29919
31214
|
// <- TODO: [🐱🚀] Support updating and self-updating
|
|
29920
31215
|
const remoteAgent = new RemoteAgent({
|
|
@@ -29937,10 +31232,10 @@ class RemoteAgent extends Agent {
|
|
|
29937
31232
|
});
|
|
29938
31233
|
remoteAgent._remoteAgentName = profile.agentName;
|
|
29939
31234
|
remoteAgent._remoteAgentHash = profile.agentHash;
|
|
29940
|
-
remoteAgent.personaDescription = profile.personaDescription;
|
|
29941
|
-
remoteAgent.initialMessage = profile.initialMessage;
|
|
29942
|
-
remoteAgent.links = profile.links;
|
|
29943
|
-
remoteAgent.meta =
|
|
31235
|
+
remoteAgent.personaDescription = (_b = profile.personaDescription) !== null && _b !== void 0 ? _b : null;
|
|
31236
|
+
remoteAgent.initialMessage = (_c = profile.initialMessage) !== null && _c !== void 0 ? _c : null;
|
|
31237
|
+
remoteAgent.links = profile.links || [];
|
|
31238
|
+
remoteAgent.meta = resolvedMeta;
|
|
29944
31239
|
remoteAgent.capabilities = profile.capabilities || [];
|
|
29945
31240
|
remoteAgent.samples = profile.samples || [];
|
|
29946
31241
|
remoteAgent.toolTitles = profile.toolTitles || {};
|
|
@@ -30044,26 +31339,7 @@ class RemoteAgent extends Agent {
|
|
|
30044
31339
|
};
|
|
30045
31340
|
};
|
|
30046
31341
|
const getToolCallKey = (toolCall) => {
|
|
30047
|
-
|
|
30048
|
-
const rawId = (_a = toolCall.rawToolCall) === null || _a === void 0 ? void 0 : _a.id;
|
|
30049
|
-
if (rawId) {
|
|
30050
|
-
return `id:${rawId}`;
|
|
30051
|
-
}
|
|
30052
|
-
const argsKey = (() => {
|
|
30053
|
-
if (typeof toolCall.arguments === 'string') {
|
|
30054
|
-
return toolCall.arguments;
|
|
30055
|
-
}
|
|
30056
|
-
if (!toolCall.arguments) {
|
|
30057
|
-
return '';
|
|
30058
|
-
}
|
|
30059
|
-
try {
|
|
30060
|
-
return JSON.stringify(toolCall.arguments);
|
|
30061
|
-
}
|
|
30062
|
-
catch (_a) {
|
|
30063
|
-
return '';
|
|
30064
|
-
}
|
|
30065
|
-
})();
|
|
30066
|
-
return `${toolCall.name}:${toolCall.createdAt || ''}:${argsKey}`;
|
|
31342
|
+
return getToolCallIdentity(toolCall);
|
|
30067
31343
|
};
|
|
30068
31344
|
const mergeToolCall = (existing, incoming) => {
|
|
30069
31345
|
const incomingResult = incoming.result;
|