@promptbook/cli 0.110.0-5 → 0.110.0-7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/index.es.js +1114 -573
- package/esm/index.es.js.map +1 -1
- package/esm/typings/src/_packages/openai.index.d.ts +8 -0
- package/esm/typings/src/_packages/types.index.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/execution/LlmExecutionTools.d.ts +2 -1
- package/esm/typings/src/llm-providers/agent/Agent.d.ts +1 -0
- package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +5 -0
- package/esm/typings/src/llm-providers/agent/AgentOptions.d.ts +4 -3
- package/esm/typings/src/llm-providers/agent/CreateAgentLlmExecutionToolsOptions.d.ts +7 -5
- package/esm/typings/src/llm-providers/agent/RemoteAgent.d.ts +2 -1
- package/esm/typings/src/llm-providers/openai/OpenAiAgentKitExecutionTools.d.ts +111 -0
- package/esm/typings/src/llm-providers/openai/OpenAiAgentKitExecutionToolsOptions.d.ts +15 -0
- package/esm/typings/src/llm-providers/openai/OpenAiAssistantExecutionTools.d.ts +3 -42
- package/esm/typings/src/llm-providers/openai/OpenAiAssistantExecutionToolsOptions.d.ts +2 -33
- 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/version.d.ts +1 -1
- package/package.json +6 -2
- package/umd/index.umd.js +1117 -577
- package/umd/index.umd.js.map +1 -1
package/esm/index.es.js
CHANGED
|
@@ -31,6 +31,7 @@ import { OpenAIClient, AzureKeyCredential } from '@azure/openai';
|
|
|
31
31
|
import { Subject, BehaviorSubject } from 'rxjs';
|
|
32
32
|
import { lookup, extension } from 'mime-types';
|
|
33
33
|
import { parse, unparse } from 'papaparse';
|
|
34
|
+
import { Agent as Agent$1, setDefaultOpenAIClient, setDefaultOpenAIKey, fileSearchTool, tool, run } from '@openai/agents';
|
|
34
35
|
import OpenAI from 'openai';
|
|
35
36
|
|
|
36
37
|
// ⚠️ WARNING: This code has been generated so that any manual changes will be overwritten
|
|
@@ -47,7 +48,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
47
48
|
* @generated
|
|
48
49
|
* @see https://github.com/webgptorg/promptbook
|
|
49
50
|
*/
|
|
50
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.110.0-
|
|
51
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.110.0-7';
|
|
51
52
|
/**
|
|
52
53
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
53
54
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -27028,16 +27029,11 @@ class OpenAiCompatibleExecutionTools {
|
|
|
27028
27029
|
const openAiOptions = { ...this.options };
|
|
27029
27030
|
delete openAiOptions.isVerbose;
|
|
27030
27031
|
delete openAiOptions.userId;
|
|
27031
|
-
// Enhanced configuration
|
|
27032
|
+
// Enhanced configuration with retries and timeouts.
|
|
27032
27033
|
const enhancedOptions = {
|
|
27033
27034
|
...openAiOptions,
|
|
27034
27035
|
timeout: API_REQUEST_TIMEOUT,
|
|
27035
27036
|
maxRetries: CONNECTION_RETRIES_LIMIT,
|
|
27036
|
-
defaultHeaders: {
|
|
27037
|
-
Connection: 'keep-alive',
|
|
27038
|
-
'Keep-Alive': 'timeout=30, max=100',
|
|
27039
|
-
...openAiOptions.defaultHeaders,
|
|
27040
|
-
},
|
|
27041
27037
|
};
|
|
27042
27038
|
this.client = new OpenAI(enhancedOptions);
|
|
27043
27039
|
}
|
|
@@ -28457,521 +28453,68 @@ class OpenAiExecutionTools extends OpenAiCompatibleExecutionTools {
|
|
|
28457
28453
|
}
|
|
28458
28454
|
}
|
|
28459
28455
|
|
|
28460
|
-
/**
|
|
28461
|
-
* Uploads files to OpenAI and returns their IDs
|
|
28462
|
-
*
|
|
28463
|
-
* @private utility for `OpenAiAssistantExecutionTools` and `OpenAiCompatibleExecutionTools`
|
|
28464
|
-
*/
|
|
28465
|
-
async function uploadFilesToOpenAi(client, files) {
|
|
28466
|
-
const fileIds = [];
|
|
28467
|
-
for (const file of files) {
|
|
28468
|
-
// Note: OpenAI API expects a File object or a ReadStream
|
|
28469
|
-
// In browser environment, we can pass the File object directly
|
|
28470
|
-
// In Node.js environment, we might need to convert it or use a different approach
|
|
28471
|
-
// But since `Prompt.files` already contains `File` objects, we try to pass them directly
|
|
28472
|
-
const uploadedFile = await client.files.create({
|
|
28473
|
-
file: file,
|
|
28474
|
-
purpose: 'assistants',
|
|
28475
|
-
});
|
|
28476
|
-
fileIds.push(uploadedFile.id);
|
|
28477
|
-
}
|
|
28478
|
-
return fileIds;
|
|
28479
|
-
}
|
|
28480
|
-
|
|
28481
28456
|
const DEFAULT_KNOWLEDGE_SOURCE_DOWNLOAD_TIMEOUT_MS = 30000;
|
|
28482
28457
|
const DEFAULT_KNOWLEDGE_SOURCE_UPLOAD_TIMEOUT_MS = 900000;
|
|
28483
28458
|
const VECTOR_STORE_PROGRESS_LOG_INTERVAL_MIN_MS = 15000;
|
|
28484
28459
|
const VECTOR_STORE_STALL_LOG_THRESHOLD_MS = 30000;
|
|
28485
28460
|
/**
|
|
28486
|
-
*
|
|
28487
|
-
*
|
|
28488
|
-
* This is useful for calling OpenAI API with a single assistant, for more wide usage use `OpenAiExecutionTools`.
|
|
28489
|
-
*
|
|
28490
|
-
* Note: [🦖] There are several different things in Promptbook:
|
|
28491
|
-
* - `Agent` - which represents an AI Agent with its source, memories, actions, etc. Agent is a higher-level abstraction which is internally using:
|
|
28492
|
-
* - `LlmExecutionTools` - which wraps one or more LLM models and provides an interface to execute them
|
|
28493
|
-
* - `AgentLlmExecutionTools` - which is a specific implementation of `LlmExecutionTools` that wraps another LlmExecutionTools and applies agent-specific system prompts and requirements
|
|
28494
|
-
* - `OpenAiAssistantExecutionTools` - which is a specific implementation of `LlmExecutionTools` for OpenAI models with assistant capabilities, recommended for usage in `Agent` or `AgentLlmExecutionTools`
|
|
28495
|
-
* - `RemoteAgent` - which is an `Agent` that connects to a Promptbook Agents Server
|
|
28461
|
+
* Base class for OpenAI execution tools that need hosted vector stores.
|
|
28496
28462
|
*
|
|
28497
28463
|
* @public exported from `@promptbook/openai`
|
|
28498
28464
|
*/
|
|
28499
|
-
class
|
|
28500
|
-
/**
|
|
28501
|
-
* Creates OpenAI Execution Tools.
|
|
28502
|
-
*
|
|
28503
|
-
* @param options which are relevant are directly passed to the OpenAI client
|
|
28504
|
-
*/
|
|
28505
|
-
constructor(options) {
|
|
28506
|
-
var _a;
|
|
28507
|
-
if (options.isProxied) {
|
|
28508
|
-
throw new NotYetImplementedError(`Proxy mode is not yet implemented for OpenAI assistants`);
|
|
28509
|
-
}
|
|
28510
|
-
super(options);
|
|
28511
|
-
this.isCreatingNewAssistantsAllowed = false;
|
|
28512
|
-
this.assistantId = options.assistantId;
|
|
28513
|
-
this.isCreatingNewAssistantsAllowed = (_a = options.isCreatingNewAssistantsAllowed) !== null && _a !== void 0 ? _a : false;
|
|
28514
|
-
if (this.assistantId === null && !this.isCreatingNewAssistantsAllowed) {
|
|
28515
|
-
throw new NotAllowed(`Assistant ID is null and creating new assistants is not allowed - this configuration does not make sense`);
|
|
28516
|
-
}
|
|
28517
|
-
// <- TODO: !!! `OpenAiAssistantExecutionToolsOptions` - Allow `assistantId: null` together with `isCreatingNewAssistantsAllowed: true`
|
|
28518
|
-
// TODO: [👱] Make limiter same as in `OpenAiExecutionTools`
|
|
28519
|
-
}
|
|
28520
|
-
get title() {
|
|
28521
|
-
return 'OpenAI Assistant';
|
|
28522
|
-
}
|
|
28523
|
-
get description() {
|
|
28524
|
-
return 'Use single assistant provided by OpenAI';
|
|
28525
|
-
}
|
|
28526
|
-
/**
|
|
28527
|
-
* Calls OpenAI API to use a chat model.
|
|
28528
|
-
*/
|
|
28529
|
-
async callChatModel(prompt) {
|
|
28530
|
-
return this.callChatModelStream(prompt, () => { });
|
|
28531
|
-
}
|
|
28532
|
-
/**
|
|
28533
|
-
* Calls OpenAI API to use a chat model with streaming.
|
|
28534
|
-
*/
|
|
28535
|
-
async callChatModelStream(prompt, onProgress) {
|
|
28536
|
-
var _a, _b, _c, _d, _e, _f;
|
|
28537
|
-
if (this.options.isVerbose) {
|
|
28538
|
-
console.info('💬 OpenAI callChatModel call', { prompt });
|
|
28539
|
-
}
|
|
28540
|
-
const { content, parameters, modelRequirements /*, format*/ } = prompt;
|
|
28541
|
-
const client = await this.getClient();
|
|
28542
|
-
// TODO: [☂] Use here more modelRequirements
|
|
28543
|
-
if (modelRequirements.modelVariant !== 'CHAT') {
|
|
28544
|
-
throw new PipelineExecutionError('Use callChatModel only for CHAT variant');
|
|
28545
|
-
}
|
|
28546
|
-
// TODO: [👨👨👧👧] Remove:
|
|
28547
|
-
for (const key of ['maxTokens', 'modelName', 'seed', 'temperature']) {
|
|
28548
|
-
if (modelRequirements[key] !== undefined) {
|
|
28549
|
-
throw new NotYetImplementedError(`In \`OpenAiAssistantExecutionTools\` you cannot specify \`${key}\``);
|
|
28550
|
-
}
|
|
28551
|
-
}
|
|
28552
|
-
/*
|
|
28553
|
-
TODO: [👨👨👧👧] Implement all of this for Assistants
|
|
28554
|
-
const modelName = modelRequirements.modelName || this.getDefaultChatModel().modelName;
|
|
28555
|
-
const modelSettings = {
|
|
28556
|
-
model: modelName,
|
|
28557
|
-
|
|
28558
|
-
temperature: modelRequirements.temperature,
|
|
28559
|
-
|
|
28560
|
-
// <- TODO: [🈁] Use `seed` here AND/OR use is `isDeterministic` for entire execution tools
|
|
28561
|
-
// <- Note: [🧆]
|
|
28562
|
-
} as OpenAI.Chat.Completions.CompletionCreateParamsNonStreaming; // <- TODO: Guard here types better
|
|
28563
|
-
|
|
28564
|
-
if (format === 'JSON') {
|
|
28565
|
-
modelSettings.response_format = {
|
|
28566
|
-
type: 'json_object',
|
|
28567
|
-
};
|
|
28568
|
-
}
|
|
28569
|
-
*/
|
|
28570
|
-
// <- TODO: [🚸] Not all models are compatible with JSON mode
|
|
28571
|
-
// > 'response_format' of type 'json_object' is not supported with this model.
|
|
28572
|
-
const rawPromptContent = templateParameters(content, {
|
|
28573
|
-
...parameters,
|
|
28574
|
-
modelName: 'assistant',
|
|
28575
|
-
// <- [🧠] What is the best value here
|
|
28576
|
-
});
|
|
28577
|
-
// Build thread messages: include previous thread messages + current user message
|
|
28578
|
-
const threadMessages = [];
|
|
28579
|
-
// TODO: [🈹] Maybe this should not be here but in other place, look at commit 39d705e75e5bcf7a818c3af36bc13e1c8475c30c
|
|
28580
|
-
// Add previous messages from thread (if any)
|
|
28581
|
-
if ('thread' in prompt && Array.isArray(prompt.thread)) {
|
|
28582
|
-
const previousMessages = prompt.thread.map((msg) => ({
|
|
28583
|
-
role: (msg.sender === 'assistant' ? 'assistant' : 'user'),
|
|
28584
|
-
content: msg.content,
|
|
28585
|
-
}));
|
|
28586
|
-
threadMessages.push(...previousMessages);
|
|
28587
|
-
}
|
|
28588
|
-
// Always add the current user message
|
|
28589
|
-
const currentUserMessage = {
|
|
28590
|
-
role: 'user',
|
|
28591
|
-
content: rawPromptContent,
|
|
28592
|
-
};
|
|
28593
|
-
if ('files' in prompt && Array.isArray(prompt.files) && prompt.files.length > 0) {
|
|
28594
|
-
const fileIds = await uploadFilesToOpenAi(client, prompt.files);
|
|
28595
|
-
currentUserMessage.attachments = fileIds.map((fileId) => ({
|
|
28596
|
-
file_id: fileId,
|
|
28597
|
-
tools: [{ type: 'file_search' }, { type: 'code_interpreter' }],
|
|
28598
|
-
}));
|
|
28599
|
-
}
|
|
28600
|
-
threadMessages.push(currentUserMessage);
|
|
28601
|
-
// Check if tools are being used - if so, use non-streaming mode
|
|
28602
|
-
const hasTools = modelRequirements.tools !== undefined && modelRequirements.tools.length > 0;
|
|
28603
|
-
const start = $getCurrentDate();
|
|
28604
|
-
let complete;
|
|
28605
|
-
// [🐱🚀] When tools are present, we need to use the non-streaming Runs API
|
|
28606
|
-
// because streaming doesn't support tool execution flow properly
|
|
28607
|
-
if (hasTools) {
|
|
28608
|
-
onProgress({
|
|
28609
|
-
content: '',
|
|
28610
|
-
modelName: 'assistant',
|
|
28611
|
-
timing: { start, complete: $getCurrentDate() },
|
|
28612
|
-
usage: UNCERTAIN_USAGE,
|
|
28613
|
-
rawPromptContent,
|
|
28614
|
-
rawRequest: null,
|
|
28615
|
-
rawResponse: null,
|
|
28616
|
-
});
|
|
28617
|
-
const rawRequest = {
|
|
28618
|
-
assistant_id: this.assistantId,
|
|
28619
|
-
thread: {
|
|
28620
|
-
messages: threadMessages,
|
|
28621
|
-
},
|
|
28622
|
-
tools: mapToolsToOpenAi(modelRequirements.tools),
|
|
28623
|
-
};
|
|
28624
|
-
if (this.options.isVerbose) {
|
|
28625
|
-
console.info(colors.bgWhite('rawRequest (non-streaming with tools)'), JSON.stringify(rawRequest, null, 4));
|
|
28626
|
-
}
|
|
28627
|
-
// Create thread and run
|
|
28628
|
-
const threadAndRun = await client.beta.threads.createAndRun(rawRequest);
|
|
28629
|
-
let run = threadAndRun;
|
|
28630
|
-
const completedToolCalls = [];
|
|
28631
|
-
const toolCallStartedAt = new Map();
|
|
28632
|
-
// Poll until run completes or requires action
|
|
28633
|
-
while (run.status === 'queued' || run.status === 'in_progress' || run.status === 'requires_action') {
|
|
28634
|
-
if (run.status === 'requires_action' && ((_a = run.required_action) === null || _a === void 0 ? void 0 : _a.type) === 'submit_tool_outputs') {
|
|
28635
|
-
// Execute tools
|
|
28636
|
-
const toolCalls = run.required_action.submit_tool_outputs.tool_calls;
|
|
28637
|
-
const toolOutputs = [];
|
|
28638
|
-
for (const toolCall of toolCalls) {
|
|
28639
|
-
if (toolCall.type === 'function') {
|
|
28640
|
-
const functionName = toolCall.function.name;
|
|
28641
|
-
const functionArgs = JSON.parse(toolCall.function.arguments);
|
|
28642
|
-
const calledAt = $getCurrentDate();
|
|
28643
|
-
if (toolCall.id) {
|
|
28644
|
-
toolCallStartedAt.set(toolCall.id, calledAt);
|
|
28645
|
-
}
|
|
28646
|
-
onProgress({
|
|
28647
|
-
content: '',
|
|
28648
|
-
modelName: 'assistant',
|
|
28649
|
-
timing: { start, complete: $getCurrentDate() },
|
|
28650
|
-
usage: UNCERTAIN_USAGE,
|
|
28651
|
-
rawPromptContent,
|
|
28652
|
-
rawRequest: null,
|
|
28653
|
-
rawResponse: null,
|
|
28654
|
-
toolCalls: [
|
|
28655
|
-
{
|
|
28656
|
-
name: functionName,
|
|
28657
|
-
arguments: toolCall.function.arguments,
|
|
28658
|
-
result: '',
|
|
28659
|
-
rawToolCall: toolCall,
|
|
28660
|
-
createdAt: calledAt,
|
|
28661
|
-
},
|
|
28662
|
-
],
|
|
28663
|
-
});
|
|
28664
|
-
if (this.options.isVerbose) {
|
|
28665
|
-
console.info(`🔧 Executing tool: ${functionName}`, functionArgs);
|
|
28666
|
-
}
|
|
28667
|
-
// Get execution tools for script execution
|
|
28668
|
-
const executionTools = this.options
|
|
28669
|
-
.executionTools;
|
|
28670
|
-
if (!executionTools || !executionTools.script) {
|
|
28671
|
-
throw new PipelineExecutionError(`Model requested tool '${functionName}' but no executionTools.script were provided in OpenAiAssistantExecutionTools options`);
|
|
28672
|
-
}
|
|
28673
|
-
// TODO: [DRY] Use some common tool caller (similar to OpenAiCompatibleExecutionTools)
|
|
28674
|
-
const scriptTools = Array.isArray(executionTools.script)
|
|
28675
|
-
? executionTools.script
|
|
28676
|
-
: [executionTools.script];
|
|
28677
|
-
let functionResponse;
|
|
28678
|
-
let errors;
|
|
28679
|
-
try {
|
|
28680
|
-
const scriptTool = scriptTools[0]; // <- TODO: [🧠] Which script tool to use?
|
|
28681
|
-
functionResponse = await scriptTool.execute({
|
|
28682
|
-
scriptLanguage: 'javascript',
|
|
28683
|
-
script: `
|
|
28684
|
-
const args = ${JSON.stringify(functionArgs)};
|
|
28685
|
-
return await ${functionName}(args);
|
|
28686
|
-
`,
|
|
28687
|
-
parameters: prompt.parameters,
|
|
28688
|
-
});
|
|
28689
|
-
if (this.options.isVerbose) {
|
|
28690
|
-
console.info(`✅ Tool ${functionName} executed:`, functionResponse);
|
|
28691
|
-
}
|
|
28692
|
-
}
|
|
28693
|
-
catch (error) {
|
|
28694
|
-
assertsError(error);
|
|
28695
|
-
const serializedError = serializeError(error);
|
|
28696
|
-
errors = [serializedError];
|
|
28697
|
-
functionResponse = spaceTrim$2((block) => `
|
|
28698
|
-
|
|
28699
|
-
The invoked tool \`${functionName}\` failed with error:
|
|
28700
|
-
|
|
28701
|
-
\`\`\`json
|
|
28702
|
-
${block(JSON.stringify(serializedError, null, 4))}
|
|
28703
|
-
\`\`\`
|
|
28704
|
-
|
|
28705
|
-
`);
|
|
28706
|
-
console.error(colors.bgRed(`❌ Error executing tool ${functionName}:`));
|
|
28707
|
-
console.error(error);
|
|
28708
|
-
}
|
|
28709
|
-
toolOutputs.push({
|
|
28710
|
-
tool_call_id: toolCall.id,
|
|
28711
|
-
output: functionResponse,
|
|
28712
|
-
});
|
|
28713
|
-
completedToolCalls.push({
|
|
28714
|
-
name: functionName,
|
|
28715
|
-
arguments: toolCall.function.arguments,
|
|
28716
|
-
result: functionResponse,
|
|
28717
|
-
rawToolCall: toolCall,
|
|
28718
|
-
createdAt: toolCall.id ? toolCallStartedAt.get(toolCall.id) || calledAt : calledAt,
|
|
28719
|
-
errors,
|
|
28720
|
-
});
|
|
28721
|
-
}
|
|
28722
|
-
}
|
|
28723
|
-
// Submit tool outputs
|
|
28724
|
-
run = await client.beta.threads.runs.submitToolOutputs(run.thread_id, run.id, {
|
|
28725
|
-
tool_outputs: toolOutputs,
|
|
28726
|
-
});
|
|
28727
|
-
}
|
|
28728
|
-
else {
|
|
28729
|
-
// Wait a bit before polling again
|
|
28730
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
28731
|
-
run = await client.beta.threads.runs.retrieve(run.thread_id, run.id);
|
|
28732
|
-
}
|
|
28733
|
-
}
|
|
28734
|
-
if (run.status !== 'completed') {
|
|
28735
|
-
throw new PipelineExecutionError(`Assistant run failed with status: ${run.status}`);
|
|
28736
|
-
}
|
|
28737
|
-
// Get messages from the thread
|
|
28738
|
-
const messages = await client.beta.threads.messages.list(run.thread_id);
|
|
28739
|
-
const assistantMessages = messages.data.filter((msg) => msg.role === 'assistant');
|
|
28740
|
-
if (assistantMessages.length === 0) {
|
|
28741
|
-
throw new PipelineExecutionError('No assistant messages found after run completion');
|
|
28742
|
-
}
|
|
28743
|
-
const lastMessage = assistantMessages[0];
|
|
28744
|
-
const textContent = lastMessage.content.find((c) => c.type === 'text');
|
|
28745
|
-
if (!textContent || textContent.type !== 'text') {
|
|
28746
|
-
throw new PipelineExecutionError('No text content in assistant response');
|
|
28747
|
-
}
|
|
28748
|
-
complete = $getCurrentDate();
|
|
28749
|
-
const resultContent = textContent.text.value;
|
|
28750
|
-
const usage = UNCERTAIN_USAGE;
|
|
28751
|
-
// Progress callback with final result
|
|
28752
|
-
const finalChunk = {
|
|
28753
|
-
content: resultContent,
|
|
28754
|
-
modelName: 'assistant',
|
|
28755
|
-
timing: { start, complete },
|
|
28756
|
-
usage,
|
|
28757
|
-
rawPromptContent,
|
|
28758
|
-
rawRequest,
|
|
28759
|
-
rawResponse: { run, messages: messages.data },
|
|
28760
|
-
toolCalls: completedToolCalls.length > 0 ? completedToolCalls : undefined,
|
|
28761
|
-
};
|
|
28762
|
-
onProgress(finalChunk);
|
|
28763
|
-
return exportJson({
|
|
28764
|
-
name: 'promptResult',
|
|
28765
|
-
message: `Result of \`OpenAiAssistantExecutionTools.callChatModelStream\` (with tools)`,
|
|
28766
|
-
order: [],
|
|
28767
|
-
value: finalChunk,
|
|
28768
|
-
});
|
|
28769
|
-
}
|
|
28770
|
-
// Streaming mode (without tools)
|
|
28771
|
-
const rawRequest = {
|
|
28772
|
-
// TODO: [👨👨👧👧] ...modelSettings,
|
|
28773
|
-
// TODO: [👨👨👧👧][🧠] What about system message for assistants, does it make sense - combination of OpenAI assistants with Promptbook Personas
|
|
28774
|
-
assistant_id: this.assistantId,
|
|
28775
|
-
thread: {
|
|
28776
|
-
messages: threadMessages,
|
|
28777
|
-
},
|
|
28778
|
-
tools: modelRequirements.tools === undefined ? undefined : mapToolsToOpenAi(modelRequirements.tools),
|
|
28779
|
-
// <- TODO: Add user identification here> user: this.options.user,
|
|
28780
|
-
};
|
|
28781
|
-
if (this.options.isVerbose) {
|
|
28782
|
-
console.info(colors.bgWhite('rawRequest (streaming)'), JSON.stringify(rawRequest, null, 4));
|
|
28783
|
-
}
|
|
28784
|
-
const stream = await client.beta.threads.createAndRunStream(rawRequest);
|
|
28785
|
-
stream.on('connect', () => {
|
|
28786
|
-
if (this.options.isVerbose) {
|
|
28787
|
-
console.info('connect', stream.currentEvent);
|
|
28788
|
-
}
|
|
28789
|
-
});
|
|
28790
|
-
stream.on('textDelta', (textDelta, snapshot) => {
|
|
28791
|
-
if (this.options.isVerbose && textDelta.value) {
|
|
28792
|
-
console.info('textDelta', textDelta.value);
|
|
28793
|
-
}
|
|
28794
|
-
const chunk = {
|
|
28795
|
-
content: snapshot.value,
|
|
28796
|
-
modelName: 'assistant',
|
|
28797
|
-
timing: {
|
|
28798
|
-
start,
|
|
28799
|
-
complete: $getCurrentDate(),
|
|
28800
|
-
},
|
|
28801
|
-
usage: UNCERTAIN_USAGE,
|
|
28802
|
-
rawPromptContent,
|
|
28803
|
-
rawRequest,
|
|
28804
|
-
rawResponse: snapshot,
|
|
28805
|
-
};
|
|
28806
|
-
onProgress(chunk);
|
|
28807
|
-
});
|
|
28808
|
-
stream.on('messageCreated', (message) => {
|
|
28809
|
-
if (this.options.isVerbose) {
|
|
28810
|
-
console.info('messageCreated', message);
|
|
28811
|
-
}
|
|
28812
|
-
});
|
|
28813
|
-
stream.on('messageDone', (message) => {
|
|
28814
|
-
if (this.options.isVerbose) {
|
|
28815
|
-
console.info('messageDone', message);
|
|
28816
|
-
}
|
|
28817
|
-
});
|
|
28818
|
-
// TODO: [🐱🚀] Handle tool calls in assistants
|
|
28819
|
-
// Note: OpenAI Assistant streaming with tool calls requires special handling.
|
|
28820
|
-
// The stream will pause when a tool call is needed, and we need to:
|
|
28821
|
-
// 1. Wait for the run to reach 'requires_action' status
|
|
28822
|
-
// 2. Execute the tool calls
|
|
28823
|
-
// 3. Submit tool outputs via a separate API call (not on the stream)
|
|
28824
|
-
// 4. Continue the run
|
|
28825
|
-
// This requires switching to non-streaming mode or using the Runs API directly.
|
|
28826
|
-
// For now, tools with assistants should use the non-streaming chat completions API instead.
|
|
28827
|
-
const rawResponse = await stream.finalMessages();
|
|
28828
|
-
if (this.options.isVerbose) {
|
|
28829
|
-
console.info(colors.bgWhite('rawResponse'), JSON.stringify(rawResponse, null, 4));
|
|
28830
|
-
}
|
|
28831
|
-
if (rawResponse.length !== 1) {
|
|
28832
|
-
throw new PipelineExecutionError(`There is NOT 1 BUT ${rawResponse.length} finalMessages from OpenAI`);
|
|
28833
|
-
}
|
|
28834
|
-
if (rawResponse[0].content.length !== 1) {
|
|
28835
|
-
throw new PipelineExecutionError(`There is NOT 1 BUT ${rawResponse[0].content.length} finalMessages content from OpenAI`);
|
|
28836
|
-
}
|
|
28837
|
-
if (((_b = rawResponse[0].content[0]) === null || _b === void 0 ? void 0 : _b.type) !== 'text') {
|
|
28838
|
-
throw new PipelineExecutionError(`There is NOT 'text' BUT ${(_c = rawResponse[0].content[0]) === null || _c === void 0 ? void 0 : _c.type} finalMessages content type from OpenAI`);
|
|
28839
|
-
}
|
|
28840
|
-
let resultContent = (_d = rawResponse[0].content[0]) === null || _d === void 0 ? void 0 : _d.text.value;
|
|
28841
|
-
// Process annotations to replace file IDs with filenames
|
|
28842
|
-
if ((_e = rawResponse[0].content[0]) === null || _e === void 0 ? void 0 : _e.text.annotations) {
|
|
28843
|
-
const annotations = (_f = rawResponse[0].content[0]) === null || _f === void 0 ? void 0 : _f.text.annotations;
|
|
28844
|
-
// Map to store file ID -> filename to avoid duplicate requests
|
|
28845
|
-
const fileIdToName = new Map();
|
|
28846
|
-
for (const annotation of annotations) {
|
|
28847
|
-
if (annotation.type === 'file_citation') {
|
|
28848
|
-
const fileId = annotation.file_citation.file_id;
|
|
28849
|
-
let filename = fileIdToName.get(fileId);
|
|
28850
|
-
if (!filename) {
|
|
28851
|
-
try {
|
|
28852
|
-
const file = await client.files.retrieve(fileId);
|
|
28853
|
-
filename = file.filename;
|
|
28854
|
-
fileIdToName.set(fileId, filename);
|
|
28855
|
-
}
|
|
28856
|
-
catch (error) {
|
|
28857
|
-
console.error(`Failed to retrieve file info for ${fileId}`, error);
|
|
28858
|
-
// Fallback to "Source" or keep original if fetch fails
|
|
28859
|
-
filename = 'Source';
|
|
28860
|
-
}
|
|
28861
|
-
}
|
|
28862
|
-
if (filename && resultContent) {
|
|
28863
|
-
// Replace the citation marker with filename
|
|
28864
|
-
// Regex to match the second part of the citation: 【id†source】 -> 【id†filename】
|
|
28865
|
-
// Note: annotation.text contains the exact marker like 【4:0†source】
|
|
28866
|
-
const newText = annotation.text.replace(/†.*?】/, `†${filename}】`);
|
|
28867
|
-
resultContent = resultContent.replace(annotation.text, newText);
|
|
28868
|
-
}
|
|
28869
|
-
}
|
|
28870
|
-
}
|
|
28871
|
-
}
|
|
28872
|
-
// eslint-disable-next-line prefer-const
|
|
28873
|
-
complete = $getCurrentDate();
|
|
28874
|
-
const usage = UNCERTAIN_USAGE;
|
|
28875
|
-
// <- TODO: [🥘] Compute real usage for assistant
|
|
28876
|
-
// ?> const usage = computeOpenAiUsage(content, resultContent || '', rawResponse);
|
|
28877
|
-
if (resultContent === null) {
|
|
28878
|
-
throw new PipelineExecutionError('No response message from OpenAI');
|
|
28879
|
-
}
|
|
28880
|
-
return exportJson({
|
|
28881
|
-
name: 'promptResult',
|
|
28882
|
-
message: `Result of \`OpenAiAssistantExecutionTools.callChatModelStream\``,
|
|
28883
|
-
order: [],
|
|
28884
|
-
value: {
|
|
28885
|
-
content: resultContent,
|
|
28886
|
-
modelName: 'assistant',
|
|
28887
|
-
// <- TODO: [🥘] Detect used model in assistant
|
|
28888
|
-
// ?> model: rawResponse.model || modelName,
|
|
28889
|
-
timing: {
|
|
28890
|
-
start,
|
|
28891
|
-
complete,
|
|
28892
|
-
},
|
|
28893
|
-
usage,
|
|
28894
|
-
rawPromptContent,
|
|
28895
|
-
rawRequest,
|
|
28896
|
-
rawResponse,
|
|
28897
|
-
// <- [🗯]
|
|
28898
|
-
},
|
|
28899
|
-
});
|
|
28900
|
-
}
|
|
28901
|
-
/*
|
|
28902
|
-
public async playground() {
|
|
28903
|
-
const client = await this.getClient();
|
|
28904
|
-
|
|
28905
|
-
// List all assistants
|
|
28906
|
-
const assistants = await client.beta.assistants.list();
|
|
28907
|
-
|
|
28908
|
-
// Get details of a specific assistant
|
|
28909
|
-
const assistantId = 'asst_MO8fhZf4dGloCfXSHeLcIik0';
|
|
28910
|
-
const assistant = await client.beta.assistants.retrieve(assistantId);
|
|
28911
|
-
|
|
28912
|
-
// Update an assistant
|
|
28913
|
-
const updatedAssistant = await client.beta.assistants.update(assistantId, {
|
|
28914
|
-
name: assistant.name + '(M)',
|
|
28915
|
-
description: 'Updated description via Promptbook',
|
|
28916
|
-
metadata: {
|
|
28917
|
-
[Math.random().toString(36).substring(2, 15)]: new Date().toISOString(),
|
|
28918
|
-
},
|
|
28919
|
-
});
|
|
28920
|
-
|
|
28921
|
-
await forEver();
|
|
28922
|
-
}
|
|
28923
|
-
*/
|
|
28924
|
-
/**
|
|
28925
|
-
* Get an existing assistant tool wrapper
|
|
28926
|
-
*/
|
|
28927
|
-
getAssistant(assistantId) {
|
|
28928
|
-
return new OpenAiAssistantExecutionTools({
|
|
28929
|
-
...this.options,
|
|
28930
|
-
isCreatingNewAssistantsAllowed: this.isCreatingNewAssistantsAllowed,
|
|
28931
|
-
assistantId,
|
|
28932
|
-
});
|
|
28933
|
-
}
|
|
28465
|
+
class OpenAiVectorStoreHandler extends OpenAiExecutionTools {
|
|
28934
28466
|
/**
|
|
28935
28467
|
* Returns the per-knowledge-source download timeout in milliseconds.
|
|
28936
28468
|
*/
|
|
28937
28469
|
getKnowledgeSourceDownloadTimeoutMs() {
|
|
28938
28470
|
var _a;
|
|
28939
|
-
return (_a = this.
|
|
28471
|
+
return (_a = this.vectorStoreOptions.knowledgeSourceDownloadTimeoutMs) !== null && _a !== void 0 ? _a : DEFAULT_KNOWLEDGE_SOURCE_DOWNLOAD_TIMEOUT_MS;
|
|
28940
28472
|
}
|
|
28941
28473
|
/**
|
|
28942
28474
|
* Returns the max concurrency for knowledge source uploads.
|
|
28943
28475
|
*/
|
|
28944
28476
|
getKnowledgeSourceUploadMaxConcurrency() {
|
|
28945
28477
|
var _a;
|
|
28946
|
-
return (_a = this.
|
|
28478
|
+
return (_a = this.vectorStoreOptions.knowledgeSourceUploadMaxConcurrency) !== null && _a !== void 0 ? _a : 5;
|
|
28947
28479
|
}
|
|
28948
28480
|
/**
|
|
28949
28481
|
* Returns the polling interval in milliseconds for vector store uploads.
|
|
28950
28482
|
*/
|
|
28951
28483
|
getKnowledgeSourceUploadPollIntervalMs() {
|
|
28952
28484
|
var _a;
|
|
28953
|
-
return (_a = this.
|
|
28485
|
+
return (_a = this.vectorStoreOptions.knowledgeSourceUploadPollIntervalMs) !== null && _a !== void 0 ? _a : 5000;
|
|
28954
28486
|
}
|
|
28955
28487
|
/**
|
|
28956
28488
|
* Returns the overall upload timeout in milliseconds for vector store uploads.
|
|
28957
28489
|
*/
|
|
28958
28490
|
getKnowledgeSourceUploadTimeoutMs() {
|
|
28959
28491
|
var _a;
|
|
28960
|
-
return (_a = this.
|
|
28492
|
+
return (_a = this.vectorStoreOptions.knowledgeSourceUploadTimeoutMs) !== null && _a !== void 0 ? _a : DEFAULT_KNOWLEDGE_SOURCE_UPLOAD_TIMEOUT_MS;
|
|
28961
28493
|
}
|
|
28962
28494
|
/**
|
|
28963
28495
|
* Returns true if we should continue even if vector store ingestion stalls.
|
|
28964
28496
|
*/
|
|
28965
28497
|
shouldContinueOnVectorStoreStall() {
|
|
28966
28498
|
var _a;
|
|
28967
|
-
return (_a = this.
|
|
28499
|
+
return (_a = this.vectorStoreOptions.shouldContinueOnVectorStoreStall) !== null && _a !== void 0 ? _a : true;
|
|
28968
28500
|
}
|
|
28969
28501
|
/**
|
|
28970
|
-
* Returns
|
|
28502
|
+
* Returns vector-store-specific options with extended settings.
|
|
28971
28503
|
*/
|
|
28972
|
-
get
|
|
28504
|
+
get vectorStoreOptions() {
|
|
28973
28505
|
return this.options;
|
|
28974
28506
|
}
|
|
28507
|
+
/**
|
|
28508
|
+
* Returns the OpenAI vector stores API surface, supporting stable and beta SDKs.
|
|
28509
|
+
*/
|
|
28510
|
+
getVectorStoresApi(client) {
|
|
28511
|
+
var _a, _b;
|
|
28512
|
+
const vectorStores = (_a = client.vectorStores) !== null && _a !== void 0 ? _a : (_b = client.beta) === null || _b === void 0 ? void 0 : _b.vectorStores;
|
|
28513
|
+
if (!vectorStores) {
|
|
28514
|
+
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.');
|
|
28515
|
+
}
|
|
28516
|
+
return vectorStores;
|
|
28517
|
+
}
|
|
28975
28518
|
/**
|
|
28976
28519
|
* Downloads a knowledge source URL into a File for vector store upload.
|
|
28977
28520
|
*/
|
|
@@ -29044,7 +28587,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
29044
28587
|
* Logs vector store file batch diagnostics to help trace ingestion stalls or failures.
|
|
29045
28588
|
*/
|
|
29046
28589
|
async logVectorStoreFileBatchDiagnostics(options) {
|
|
29047
|
-
var _a, _b;
|
|
28590
|
+
var _a, _b, _c, _d, _e;
|
|
29048
28591
|
const { client, vectorStoreId, batchId, uploadedFiles, logLabel, reason } = options;
|
|
29049
28592
|
if (reason === 'stalled' && !this.options.isVerbose) {
|
|
29050
28593
|
return;
|
|
@@ -29063,8 +28606,10 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
29063
28606
|
fileIdToMetadata.set(file.fileId, file);
|
|
29064
28607
|
}
|
|
29065
28608
|
try {
|
|
28609
|
+
const vectorStores = this.getVectorStoresApi(client);
|
|
29066
28610
|
const limit = Math.min(100, Math.max(10, uploadedFiles.length));
|
|
29067
|
-
const batchFilesPage = await
|
|
28611
|
+
const batchFilesPage = await vectorStores.fileBatches.listFiles(batchId, {
|
|
28612
|
+
vector_store_id: vectorStoreId,
|
|
29068
28613
|
limit,
|
|
29069
28614
|
});
|
|
29070
28615
|
const batchFiles = (_a = batchFilesPage.data) !== null && _a !== void 0 ? _a : [];
|
|
@@ -29078,23 +28623,27 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
29078
28623
|
const inProgressSamples = [];
|
|
29079
28624
|
const batchFileIds = new Set();
|
|
29080
28625
|
for (const file of batchFiles) {
|
|
29081
|
-
|
|
29082
|
-
statusCounts[
|
|
29083
|
-
const
|
|
29084
|
-
|
|
28626
|
+
const status = (_b = file.status) !== null && _b !== void 0 ? _b : 'unknown';
|
|
28627
|
+
statusCounts[status] = ((_c = statusCounts[status]) !== null && _c !== void 0 ? _c : 0) + 1;
|
|
28628
|
+
const vectorStoreFileId = file.id;
|
|
28629
|
+
const uploadedFileId = (_d = file.file_id) !== null && _d !== void 0 ? _d : file.fileId;
|
|
28630
|
+
const fileId = uploadedFileId !== null && uploadedFileId !== void 0 ? uploadedFileId : vectorStoreFileId;
|
|
28631
|
+
batchFileIds.add(fileId);
|
|
28632
|
+
const metadata = fileIdToMetadata.get(fileId);
|
|
28633
|
+
if (status === 'failed') {
|
|
29085
28634
|
errorSamples.push({
|
|
29086
|
-
fileId
|
|
28635
|
+
fileId,
|
|
28636
|
+
status,
|
|
28637
|
+
error: (_e = file.last_error) === null || _e === void 0 ? void 0 : _e.message,
|
|
29087
28638
|
filename: metadata === null || metadata === void 0 ? void 0 : metadata.filename,
|
|
29088
|
-
|
|
29089
|
-
status: file.status,
|
|
29090
|
-
lastError: file.last_error,
|
|
28639
|
+
vectorStoreFileId: uploadedFileId ? vectorStoreFileId : undefined,
|
|
29091
28640
|
});
|
|
29092
28641
|
}
|
|
29093
|
-
|
|
28642
|
+
if (status === 'in_progress') {
|
|
29094
28643
|
inProgressSamples.push({
|
|
29095
|
-
fileId
|
|
28644
|
+
fileId,
|
|
29096
28645
|
filename: metadata === null || metadata === void 0 ? void 0 : metadata.filename,
|
|
29097
|
-
|
|
28646
|
+
vectorStoreFileId: uploadedFileId ? vectorStoreFileId : undefined,
|
|
29098
28647
|
});
|
|
29099
28648
|
}
|
|
29100
28649
|
}
|
|
@@ -29106,7 +28655,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
29106
28655
|
filename: file.filename,
|
|
29107
28656
|
sizeBytes: file.sizeBytes,
|
|
29108
28657
|
}));
|
|
29109
|
-
const vectorStore = await
|
|
28658
|
+
const vectorStore = await vectorStores.retrieve(vectorStoreId);
|
|
29110
28659
|
const logPayload = {
|
|
29111
28660
|
vectorStoreId,
|
|
29112
28661
|
batchId,
|
|
@@ -29140,8 +28689,9 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
29140
28689
|
* Uploads knowledge source files to the vector store and polls until processing completes.
|
|
29141
28690
|
*/
|
|
29142
28691
|
async uploadKnowledgeSourceFilesToVectorStore(options) {
|
|
29143
|
-
var _a, _b, _c, _d;
|
|
28692
|
+
var _a, _b, _c, _d, _e, _f;
|
|
29144
28693
|
const { client, vectorStoreId, files, totalBytes, logLabel } = options;
|
|
28694
|
+
const vectorStores = this.getVectorStoresApi(client);
|
|
29145
28695
|
const uploadStartedAtMs = Date.now();
|
|
29146
28696
|
const maxConcurrency = Math.max(1, this.getKnowledgeSourceUploadMaxConcurrency());
|
|
29147
28697
|
const pollIntervalMs = Math.max(1000, this.getKnowledgeSourceUploadPollIntervalMs());
|
|
@@ -29260,7 +28810,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
29260
28810
|
});
|
|
29261
28811
|
return null;
|
|
29262
28812
|
}
|
|
29263
|
-
const batch = await
|
|
28813
|
+
const batch = await vectorStores.fileBatches.create(vectorStoreId, {
|
|
29264
28814
|
file_ids: fileIds,
|
|
29265
28815
|
});
|
|
29266
28816
|
const expectedBatchId = batch.id;
|
|
@@ -29292,7 +28842,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
29292
28842
|
const pollStartedAtMs = Date.now();
|
|
29293
28843
|
const progressLogIntervalMs = Math.max(VECTOR_STORE_PROGRESS_LOG_INTERVAL_MIN_MS, pollIntervalMs);
|
|
29294
28844
|
const diagnosticsIntervalMs = Math.max(60000, pollIntervalMs * 5);
|
|
29295
|
-
let lastStatus;
|
|
28845
|
+
// let lastStatus: string | undefined;
|
|
29296
28846
|
let lastCountsKey = '';
|
|
29297
28847
|
let lastProgressKey = '';
|
|
29298
28848
|
let lastLogAtMs = 0;
|
|
@@ -29300,118 +28850,139 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
29300
28850
|
let lastDiagnosticsAtMs = pollStartedAtMs;
|
|
29301
28851
|
let latestBatch = batch;
|
|
29302
28852
|
let loggedBatchIdMismatch = false;
|
|
28853
|
+
let loggedBatchIdFallback = false;
|
|
28854
|
+
let loggedBatchIdInvalid = false;
|
|
29303
28855
|
let shouldPoll = true;
|
|
29304
28856
|
while (shouldPoll) {
|
|
29305
|
-
latestBatch = await client.beta.vectorStores.fileBatches.retrieve(vectorStoreId, expectedBatchId);
|
|
29306
|
-
const counts = latestBatch.file_counts;
|
|
29307
|
-
const countsKey = `${counts.completed}/${counts.failed}/${counts.in_progress}/${counts.cancelled}/${counts.total}`;
|
|
29308
28857
|
const nowMs = Date.now();
|
|
29309
|
-
const returnedBatchId = latestBatch.id;
|
|
29310
28858
|
// [🤰] Note: Sometimes OpenAI returns Vector Store object instead of Batch object, or IDs get swapped.
|
|
29311
|
-
|
|
29312
|
-
const
|
|
29313
|
-
|
|
29314
|
-
|
|
29315
|
-
|
|
29316
|
-
|
|
29317
|
-
|
|
28859
|
+
const rawBatchId = typeof latestBatch.id === 'string' ? latestBatch.id : '';
|
|
28860
|
+
const rawVectorStoreId = latestBatch.vector_store_id;
|
|
28861
|
+
let returnedBatchId = rawBatchId;
|
|
28862
|
+
let returnedBatchIdValid = typeof returnedBatchId === 'string' && returnedBatchId.startsWith('vsfb_');
|
|
28863
|
+
if (!returnedBatchIdValid && expectedBatchIdValid) {
|
|
28864
|
+
if (!loggedBatchIdFallback) {
|
|
28865
|
+
console.error('[🤰]', 'Vector store file batch id missing from response; falling back to expected', {
|
|
28866
|
+
vectorStoreId,
|
|
28867
|
+
expectedBatchId,
|
|
28868
|
+
returnedBatchId,
|
|
28869
|
+
rawVectorStoreId,
|
|
28870
|
+
logLabel,
|
|
28871
|
+
});
|
|
28872
|
+
loggedBatchIdFallback = true;
|
|
28873
|
+
}
|
|
28874
|
+
returnedBatchId = expectedBatchId;
|
|
28875
|
+
returnedBatchIdValid = true;
|
|
28876
|
+
}
|
|
28877
|
+
if (!returnedBatchIdValid && !loggedBatchIdInvalid) {
|
|
28878
|
+
console.error('[🤰]', 'Vector store file batch id is invalid; stopping polling', {
|
|
28879
|
+
vectorStoreId,
|
|
28880
|
+
expectedBatchId,
|
|
28881
|
+
returnedBatchId,
|
|
28882
|
+
rawVectorStoreId,
|
|
28883
|
+
logLabel,
|
|
28884
|
+
});
|
|
28885
|
+
loggedBatchIdInvalid = true;
|
|
28886
|
+
}
|
|
28887
|
+
const batchIdMismatch = expectedBatchIdValid && returnedBatchIdValid && returnedBatchId !== expectedBatchId;
|
|
29318
28888
|
if (batchIdMismatch && !loggedBatchIdMismatch) {
|
|
29319
28889
|
console.error('[🤰]', 'Vector store file batch id mismatch', {
|
|
29320
28890
|
vectorStoreId,
|
|
29321
28891
|
expectedBatchId,
|
|
29322
28892
|
returnedBatchId,
|
|
29323
|
-
status: latestBatch.status,
|
|
29324
|
-
fileCounts: counts,
|
|
29325
28893
|
logLabel,
|
|
29326
28894
|
});
|
|
29327
28895
|
loggedBatchIdMismatch = true;
|
|
29328
28896
|
}
|
|
29329
|
-
if (
|
|
29330
|
-
|
|
28897
|
+
if (returnedBatchIdValid) {
|
|
28898
|
+
latestBatch = await vectorStores.fileBatches.retrieve(returnedBatchId, {
|
|
28899
|
+
vector_store_id: vectorStoreId,
|
|
28900
|
+
});
|
|
28901
|
+
}
|
|
28902
|
+
else {
|
|
28903
|
+
shouldPoll = false;
|
|
28904
|
+
continue;
|
|
28905
|
+
}
|
|
28906
|
+
const status = (_e = latestBatch.status) !== null && _e !== void 0 ? _e : 'unknown';
|
|
28907
|
+
const fileCounts = (_f = latestBatch.file_counts) !== null && _f !== void 0 ? _f : {};
|
|
28908
|
+
const progressKey = JSON.stringify(fileCounts);
|
|
28909
|
+
const statusCountsKey = `${status}-${progressKey}`;
|
|
28910
|
+
const isProgressing = progressKey !== lastProgressKey;
|
|
28911
|
+
if (isProgressing) {
|
|
29331
28912
|
lastProgressAtMs = nowMs;
|
|
28913
|
+
lastProgressKey = progressKey;
|
|
29332
28914
|
}
|
|
29333
|
-
if (
|
|
28915
|
+
if (this.options.isVerbose &&
|
|
28916
|
+
(statusCountsKey !== lastCountsKey || nowMs - lastLogAtMs >= progressLogIntervalMs)) {
|
|
29334
28917
|
console.info('[🤰]', 'Vector store file batch status', {
|
|
29335
28918
|
vectorStoreId,
|
|
29336
|
-
batchId:
|
|
29337
|
-
|
|
29338
|
-
|
|
29339
|
-
fileCounts: counts,
|
|
28919
|
+
batchId: returnedBatchId,
|
|
28920
|
+
status,
|
|
28921
|
+
fileCounts,
|
|
29340
28922
|
elapsedMs: nowMs - pollStartedAtMs,
|
|
29341
28923
|
logLabel,
|
|
29342
28924
|
});
|
|
29343
|
-
|
|
29344
|
-
if (counts.in_progress > 0 && nowMs - lastProgressAtMs > VECTOR_STORE_STALL_LOG_THRESHOLD_MS) {
|
|
29345
|
-
await this.logVectorStoreFileBatchDiagnostics({
|
|
29346
|
-
client,
|
|
29347
|
-
vectorStoreId,
|
|
29348
|
-
batchId: diagnosticsBatchId,
|
|
29349
|
-
uploadedFiles,
|
|
29350
|
-
logLabel,
|
|
29351
|
-
reason: 'stalled',
|
|
29352
|
-
});
|
|
29353
|
-
}
|
|
29354
|
-
lastStatus = latestBatch.status;
|
|
29355
|
-
lastCountsKey = countsKey;
|
|
28925
|
+
lastCountsKey = statusCountsKey;
|
|
29356
28926
|
lastLogAtMs = nowMs;
|
|
29357
28927
|
}
|
|
29358
|
-
if (
|
|
28928
|
+
if (status === 'in_progress' &&
|
|
28929
|
+
nowMs - lastProgressAtMs >= VECTOR_STORE_STALL_LOG_THRESHOLD_MS &&
|
|
29359
28930
|
nowMs - lastDiagnosticsAtMs >= diagnosticsIntervalMs) {
|
|
29360
28931
|
lastDiagnosticsAtMs = nowMs;
|
|
29361
28932
|
await this.logVectorStoreFileBatchDiagnostics({
|
|
29362
28933
|
client,
|
|
29363
28934
|
vectorStoreId,
|
|
29364
|
-
batchId:
|
|
28935
|
+
batchId: returnedBatchId,
|
|
29365
28936
|
uploadedFiles,
|
|
29366
28937
|
logLabel,
|
|
29367
28938
|
reason: 'stalled',
|
|
29368
28939
|
});
|
|
29369
28940
|
}
|
|
29370
|
-
if (
|
|
28941
|
+
if (status === 'completed') {
|
|
29371
28942
|
if (this.options.isVerbose) {
|
|
29372
28943
|
console.info('[🤰]', 'Vector store file batch completed', {
|
|
29373
28944
|
vectorStoreId,
|
|
29374
|
-
batchId:
|
|
29375
|
-
|
|
29376
|
-
|
|
29377
|
-
elapsedMs: Date.now() - uploadStartedAtMs,
|
|
29378
|
-
logLabel,
|
|
29379
|
-
});
|
|
29380
|
-
}
|
|
29381
|
-
if (latestBatch.file_counts.failed > 0) {
|
|
29382
|
-
console.error('[🤰]', 'Vector store file batch completed with failures', {
|
|
29383
|
-
vectorStoreId,
|
|
29384
|
-
batchId: expectedBatchId,
|
|
29385
|
-
...(batchIdMismatch ? { returnedBatchId } : {}),
|
|
29386
|
-
fileCounts: latestBatch.file_counts,
|
|
29387
|
-
logLabel,
|
|
29388
|
-
});
|
|
29389
|
-
await this.logVectorStoreFileBatchDiagnostics({
|
|
29390
|
-
client,
|
|
29391
|
-
vectorStoreId,
|
|
29392
|
-
batchId: diagnosticsBatchId,
|
|
29393
|
-
uploadedFiles,
|
|
28945
|
+
batchId: returnedBatchId,
|
|
28946
|
+
fileCounts,
|
|
28947
|
+
elapsedMs: nowMs - pollStartedAtMs,
|
|
29394
28948
|
logLabel,
|
|
29395
|
-
reason: 'failed',
|
|
29396
28949
|
});
|
|
29397
28950
|
}
|
|
29398
28951
|
shouldPoll = false;
|
|
29399
28952
|
continue;
|
|
29400
28953
|
}
|
|
29401
|
-
if (
|
|
28954
|
+
if (status === 'failed') {
|
|
28955
|
+
console.error('[🤰]', 'Vector store file batch completed with failures', {
|
|
28956
|
+
vectorStoreId,
|
|
28957
|
+
batchId: returnedBatchId,
|
|
28958
|
+
fileCounts,
|
|
28959
|
+
elapsedMs: nowMs - pollStartedAtMs,
|
|
28960
|
+
logLabel,
|
|
28961
|
+
});
|
|
28962
|
+
await this.logVectorStoreFileBatchDiagnostics({
|
|
28963
|
+
client,
|
|
28964
|
+
vectorStoreId,
|
|
28965
|
+
batchId: returnedBatchId,
|
|
28966
|
+
uploadedFiles,
|
|
28967
|
+
logLabel,
|
|
28968
|
+
reason: 'failed',
|
|
28969
|
+
});
|
|
28970
|
+
shouldPoll = false;
|
|
28971
|
+
continue;
|
|
28972
|
+
}
|
|
28973
|
+
if (status === 'cancelled') {
|
|
29402
28974
|
console.error('[🤰]', 'Vector store file batch did not complete', {
|
|
29403
28975
|
vectorStoreId,
|
|
29404
|
-
batchId:
|
|
29405
|
-
|
|
29406
|
-
|
|
29407
|
-
|
|
29408
|
-
elapsedMs: Date.now() - uploadStartedAtMs,
|
|
28976
|
+
batchId: returnedBatchId,
|
|
28977
|
+
status,
|
|
28978
|
+
fileCounts,
|
|
28979
|
+
elapsedMs: nowMs - pollStartedAtMs,
|
|
29409
28980
|
logLabel,
|
|
29410
28981
|
});
|
|
29411
28982
|
await this.logVectorStoreFileBatchDiagnostics({
|
|
29412
28983
|
client,
|
|
29413
28984
|
vectorStoreId,
|
|
29414
|
-
batchId:
|
|
28985
|
+
batchId: returnedBatchId,
|
|
29415
28986
|
uploadedFiles,
|
|
29416
28987
|
logLabel,
|
|
29417
28988
|
reason: 'failed',
|
|
@@ -29422,9 +28993,8 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
29422
28993
|
if (nowMs - pollStartedAtMs >= uploadTimeoutMs) {
|
|
29423
28994
|
console.error('[🤰]', 'Timed out waiting for vector store file batch', {
|
|
29424
28995
|
vectorStoreId,
|
|
29425
|
-
batchId:
|
|
29426
|
-
|
|
29427
|
-
fileCounts: latestBatch.file_counts,
|
|
28996
|
+
batchId: returnedBatchId,
|
|
28997
|
+
fileCounts,
|
|
29428
28998
|
elapsedMs: nowMs - pollStartedAtMs,
|
|
29429
28999
|
uploadTimeoutMs,
|
|
29430
29000
|
logLabel,
|
|
@@ -29432,7 +29002,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
29432
29002
|
await this.logVectorStoreFileBatchDiagnostics({
|
|
29433
29003
|
client,
|
|
29434
29004
|
vectorStoreId,
|
|
29435
|
-
batchId:
|
|
29005
|
+
batchId: returnedBatchId,
|
|
29436
29006
|
uploadedFiles,
|
|
29437
29007
|
logLabel,
|
|
29438
29008
|
reason: 'timeout',
|
|
@@ -29455,7 +29025,9 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
29455
29025
|
});
|
|
29456
29026
|
}
|
|
29457
29027
|
else {
|
|
29458
|
-
await
|
|
29028
|
+
await vectorStores.fileBatches.cancel(cancelBatchId, {
|
|
29029
|
+
vector_store_id: vectorStoreId,
|
|
29030
|
+
});
|
|
29459
29031
|
}
|
|
29460
29032
|
if (this.options.isVerbose) {
|
|
29461
29033
|
console.info('[🤰]', 'Cancelled vector store file batch after timeout', {
|
|
@@ -29490,6 +29062,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
29490
29062
|
*/
|
|
29491
29063
|
async createVectorStoreWithKnowledgeSources(options) {
|
|
29492
29064
|
const { client, name, knowledgeSources, logLabel } = options;
|
|
29065
|
+
const vectorStores = this.getVectorStoresApi(client);
|
|
29493
29066
|
const knowledgeSourcesCount = knowledgeSources.length;
|
|
29494
29067
|
const downloadTimeoutMs = this.getKnowledgeSourceDownloadTimeoutMs();
|
|
29495
29068
|
if (this.options.isVerbose) {
|
|
@@ -29500,7 +29073,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
29500
29073
|
logLabel,
|
|
29501
29074
|
});
|
|
29502
29075
|
}
|
|
29503
|
-
const vectorStore = await
|
|
29076
|
+
const vectorStore = await vectorStores.create({
|
|
29504
29077
|
name: `${name} Knowledge Base`,
|
|
29505
29078
|
});
|
|
29506
29079
|
const vectorStoreId = vectorStore.id;
|
|
@@ -29551,7 +29124,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
29551
29124
|
});
|
|
29552
29125
|
}
|
|
29553
29126
|
/*
|
|
29554
|
-
TODO: [
|
|
29127
|
+
TODO: [🤰] Resolve problem with browser environment
|
|
29555
29128
|
// Assume it's a local file path
|
|
29556
29129
|
// Note: This will work in Node.js environment
|
|
29557
29130
|
// For browser environments, this would need different handling
|
|
@@ -29626,6 +29199,478 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
29626
29199
|
totalBytes,
|
|
29627
29200
|
};
|
|
29628
29201
|
}
|
|
29202
|
+
}
|
|
29203
|
+
|
|
29204
|
+
/**
|
|
29205
|
+
* Uploads files to OpenAI and returns their IDs
|
|
29206
|
+
*
|
|
29207
|
+
* @private utility for `OpenAiAssistantExecutionTools` and `OpenAiCompatibleExecutionTools`
|
|
29208
|
+
*/
|
|
29209
|
+
async function uploadFilesToOpenAi(client, files) {
|
|
29210
|
+
const fileIds = [];
|
|
29211
|
+
for (const file of files) {
|
|
29212
|
+
// Note: OpenAI API expects a File object or a ReadStream
|
|
29213
|
+
// In browser environment, we can pass the File object directly
|
|
29214
|
+
// In Node.js environment, we might need to convert it or use a different approach
|
|
29215
|
+
// But since `Prompt.files` already contains `File` objects, we try to pass them directly
|
|
29216
|
+
const uploadedFile = await client.files.create({
|
|
29217
|
+
file: file,
|
|
29218
|
+
purpose: 'assistants',
|
|
29219
|
+
});
|
|
29220
|
+
fileIds.push(uploadedFile.id);
|
|
29221
|
+
}
|
|
29222
|
+
return fileIds;
|
|
29223
|
+
}
|
|
29224
|
+
|
|
29225
|
+
/**
|
|
29226
|
+
* Execution Tools for calling OpenAI API Assistants
|
|
29227
|
+
*
|
|
29228
|
+
* This is useful for calling OpenAI API with a single assistant, for more wide usage use `OpenAiExecutionTools`.
|
|
29229
|
+
*
|
|
29230
|
+
* Note: [🦖] There are several different things in Promptbook:
|
|
29231
|
+
* - `Agent` - which represents an AI Agent with its source, memories, actions, etc. Agent is a higher-level abstraction which is internally using:
|
|
29232
|
+
* - `LlmExecutionTools` - which wraps one or more LLM models and provides an interface to execute them
|
|
29233
|
+
* - `AgentLlmExecutionTools` - which is a specific implementation of `LlmExecutionTools` that wraps another LlmExecutionTools and applies agent-specific system prompts and requirements
|
|
29234
|
+
* - `OpenAiAssistantExecutionTools` - which is a specific implementation of `LlmExecutionTools` for OpenAI models with assistant capabilities, recommended for usage in `Agent` or `AgentLlmExecutionTools`
|
|
29235
|
+
* - `RemoteAgent` - which is an `Agent` that connects to a Promptbook Agents Server
|
|
29236
|
+
*
|
|
29237
|
+
* @deprecated Use `OpenAiAgentKitExecutionTools` instead.
|
|
29238
|
+
* @public exported from `@promptbook/openai`
|
|
29239
|
+
*/
|
|
29240
|
+
class OpenAiAssistantExecutionTools extends OpenAiVectorStoreHandler {
|
|
29241
|
+
/**
|
|
29242
|
+
* Creates OpenAI Execution Tools.
|
|
29243
|
+
*
|
|
29244
|
+
* @param options which are relevant are directly passed to the OpenAI client
|
|
29245
|
+
*/
|
|
29246
|
+
constructor(options) {
|
|
29247
|
+
var _a;
|
|
29248
|
+
if (options.isProxied) {
|
|
29249
|
+
throw new NotYetImplementedError(`Proxy mode is not yet implemented for OpenAI assistants`);
|
|
29250
|
+
}
|
|
29251
|
+
super(options);
|
|
29252
|
+
this.isCreatingNewAssistantsAllowed = false;
|
|
29253
|
+
this.assistantId = options.assistantId;
|
|
29254
|
+
this.isCreatingNewAssistantsAllowed = (_a = options.isCreatingNewAssistantsAllowed) !== null && _a !== void 0 ? _a : false;
|
|
29255
|
+
if (this.assistantId === null && !this.isCreatingNewAssistantsAllowed) {
|
|
29256
|
+
throw new NotAllowed(`Assistant ID is null and creating new assistants is not allowed - this configuration does not make sense`);
|
|
29257
|
+
}
|
|
29258
|
+
// <- TODO: !!! `OpenAiAssistantExecutionToolsOptions` - Allow `assistantId: null` together with `isCreatingNewAssistantsAllowed: true`
|
|
29259
|
+
// TODO: [👱] Make limiter same as in `OpenAiExecutionTools`
|
|
29260
|
+
}
|
|
29261
|
+
get title() {
|
|
29262
|
+
return 'OpenAI Assistant';
|
|
29263
|
+
}
|
|
29264
|
+
get description() {
|
|
29265
|
+
return 'Use single assistant provided by OpenAI';
|
|
29266
|
+
}
|
|
29267
|
+
/**
|
|
29268
|
+
* Calls OpenAI API to use a chat model.
|
|
29269
|
+
*/
|
|
29270
|
+
async callChatModel(prompt) {
|
|
29271
|
+
return this.callChatModelStream(prompt, () => { });
|
|
29272
|
+
}
|
|
29273
|
+
/**
|
|
29274
|
+
* Calls OpenAI API to use a chat model with streaming.
|
|
29275
|
+
*/
|
|
29276
|
+
async callChatModelStream(prompt, onProgress) {
|
|
29277
|
+
var _a, _b, _c, _d, _e, _f;
|
|
29278
|
+
if (this.options.isVerbose) {
|
|
29279
|
+
console.info('💬 OpenAI callChatModel call', { prompt });
|
|
29280
|
+
}
|
|
29281
|
+
const { content, parameters, modelRequirements /*, format*/ } = prompt;
|
|
29282
|
+
const client = await this.getClient();
|
|
29283
|
+
// TODO: [☂] Use here more modelRequirements
|
|
29284
|
+
if (modelRequirements.modelVariant !== 'CHAT') {
|
|
29285
|
+
throw new PipelineExecutionError('Use callChatModel only for CHAT variant');
|
|
29286
|
+
}
|
|
29287
|
+
// TODO: [👨👨👧👧] Remove:
|
|
29288
|
+
for (const key of ['maxTokens', 'modelName', 'seed', 'temperature']) {
|
|
29289
|
+
if (modelRequirements[key] !== undefined) {
|
|
29290
|
+
throw new NotYetImplementedError(`In \`OpenAiAssistantExecutionTools\` you cannot specify \`${key}\``);
|
|
29291
|
+
}
|
|
29292
|
+
}
|
|
29293
|
+
/*
|
|
29294
|
+
TODO: [👨👨👧👧] Implement all of this for Assistants
|
|
29295
|
+
const modelName = modelRequirements.modelName || this.getDefaultChatModel().modelName;
|
|
29296
|
+
const modelSettings = {
|
|
29297
|
+
model: modelName,
|
|
29298
|
+
|
|
29299
|
+
temperature: modelRequirements.temperature,
|
|
29300
|
+
|
|
29301
|
+
// <- TODO: [🈁] Use `seed` here AND/OR use is `isDeterministic` for entire execution tools
|
|
29302
|
+
// <- Note: [🧆]
|
|
29303
|
+
} as OpenAI.Chat.Completions.CompletionCreateParamsNonStreaming; // <- TODO: Guard here types better
|
|
29304
|
+
|
|
29305
|
+
if (format === 'JSON') {
|
|
29306
|
+
modelSettings.response_format = {
|
|
29307
|
+
type: 'json_object',
|
|
29308
|
+
};
|
|
29309
|
+
}
|
|
29310
|
+
*/
|
|
29311
|
+
// <- TODO: [🚸] Not all models are compatible with JSON mode
|
|
29312
|
+
// > 'response_format' of type 'json_object' is not supported with this model.
|
|
29313
|
+
const rawPromptContent = templateParameters(content, {
|
|
29314
|
+
...parameters,
|
|
29315
|
+
modelName: 'assistant',
|
|
29316
|
+
// <- [🧠] What is the best value here
|
|
29317
|
+
});
|
|
29318
|
+
// Build thread messages: include previous thread messages + current user message
|
|
29319
|
+
const threadMessages = [];
|
|
29320
|
+
// TODO: [🈹] Maybe this should not be here but in other place, look at commit 39d705e75e5bcf7a818c3af36bc13e1c8475c30c
|
|
29321
|
+
// Add previous messages from thread (if any)
|
|
29322
|
+
if ('thread' in prompt && Array.isArray(prompt.thread)) {
|
|
29323
|
+
const previousMessages = prompt.thread.map((msg) => ({
|
|
29324
|
+
role: (msg.sender === 'assistant' ? 'assistant' : 'user'),
|
|
29325
|
+
content: msg.content,
|
|
29326
|
+
}));
|
|
29327
|
+
threadMessages.push(...previousMessages);
|
|
29328
|
+
}
|
|
29329
|
+
// Always add the current user message
|
|
29330
|
+
const currentUserMessage = {
|
|
29331
|
+
role: 'user',
|
|
29332
|
+
content: rawPromptContent,
|
|
29333
|
+
};
|
|
29334
|
+
if ('files' in prompt && Array.isArray(prompt.files) && prompt.files.length > 0) {
|
|
29335
|
+
const fileIds = await uploadFilesToOpenAi(client, prompt.files);
|
|
29336
|
+
currentUserMessage.attachments = fileIds.map((fileId) => ({
|
|
29337
|
+
file_id: fileId,
|
|
29338
|
+
tools: [{ type: 'file_search' }, { type: 'code_interpreter' }],
|
|
29339
|
+
}));
|
|
29340
|
+
}
|
|
29341
|
+
threadMessages.push(currentUserMessage);
|
|
29342
|
+
// Check if tools are being used - if so, use non-streaming mode
|
|
29343
|
+
const hasTools = modelRequirements.tools !== undefined && modelRequirements.tools.length > 0;
|
|
29344
|
+
const start = $getCurrentDate();
|
|
29345
|
+
let complete;
|
|
29346
|
+
// [🐱🚀] When tools are present, we need to use the non-streaming Runs API
|
|
29347
|
+
// because streaming doesn't support tool execution flow properly
|
|
29348
|
+
if (hasTools) {
|
|
29349
|
+
onProgress({
|
|
29350
|
+
content: '',
|
|
29351
|
+
modelName: 'assistant',
|
|
29352
|
+
timing: { start, complete: $getCurrentDate() },
|
|
29353
|
+
usage: UNCERTAIN_USAGE,
|
|
29354
|
+
rawPromptContent,
|
|
29355
|
+
rawRequest: null,
|
|
29356
|
+
rawResponse: null,
|
|
29357
|
+
});
|
|
29358
|
+
const rawRequest = {
|
|
29359
|
+
assistant_id: this.assistantId,
|
|
29360
|
+
thread: {
|
|
29361
|
+
messages: threadMessages,
|
|
29362
|
+
},
|
|
29363
|
+
tools: mapToolsToOpenAi(modelRequirements.tools),
|
|
29364
|
+
};
|
|
29365
|
+
if (this.options.isVerbose) {
|
|
29366
|
+
console.info(colors.bgWhite('rawRequest (non-streaming with tools)'), JSON.stringify(rawRequest, null, 4));
|
|
29367
|
+
}
|
|
29368
|
+
// Create thread and run
|
|
29369
|
+
let run = (await client.beta.threads.createAndRun(rawRequest));
|
|
29370
|
+
const completedToolCalls = [];
|
|
29371
|
+
const toolCallStartedAt = new Map();
|
|
29372
|
+
// Poll until run completes or requires action
|
|
29373
|
+
while (run.status === 'queued' || run.status === 'in_progress' || run.status === 'requires_action') {
|
|
29374
|
+
if (run.status === 'requires_action' && ((_a = run.required_action) === null || _a === void 0 ? void 0 : _a.type) === 'submit_tool_outputs') {
|
|
29375
|
+
// Execute tools
|
|
29376
|
+
const toolCalls = run.required_action.submit_tool_outputs.tool_calls;
|
|
29377
|
+
const toolOutputs = [];
|
|
29378
|
+
for (const toolCall of toolCalls) {
|
|
29379
|
+
if (toolCall.type === 'function') {
|
|
29380
|
+
const functionName = toolCall.function.name;
|
|
29381
|
+
const functionArgs = JSON.parse(toolCall.function.arguments);
|
|
29382
|
+
const calledAt = $getCurrentDate();
|
|
29383
|
+
if (toolCall.id) {
|
|
29384
|
+
toolCallStartedAt.set(toolCall.id, calledAt);
|
|
29385
|
+
}
|
|
29386
|
+
onProgress({
|
|
29387
|
+
content: '',
|
|
29388
|
+
modelName: 'assistant',
|
|
29389
|
+
timing: { start, complete: $getCurrentDate() },
|
|
29390
|
+
usage: UNCERTAIN_USAGE,
|
|
29391
|
+
rawPromptContent,
|
|
29392
|
+
rawRequest: null,
|
|
29393
|
+
rawResponse: null,
|
|
29394
|
+
toolCalls: [
|
|
29395
|
+
{
|
|
29396
|
+
name: functionName,
|
|
29397
|
+
arguments: toolCall.function.arguments,
|
|
29398
|
+
result: '',
|
|
29399
|
+
rawToolCall: toolCall,
|
|
29400
|
+
createdAt: calledAt,
|
|
29401
|
+
},
|
|
29402
|
+
],
|
|
29403
|
+
});
|
|
29404
|
+
if (this.options.isVerbose) {
|
|
29405
|
+
console.info(`🔧 Executing tool: ${functionName}`, functionArgs);
|
|
29406
|
+
}
|
|
29407
|
+
// Get execution tools for script execution
|
|
29408
|
+
const executionTools = this.options
|
|
29409
|
+
.executionTools;
|
|
29410
|
+
if (!executionTools || !executionTools.script) {
|
|
29411
|
+
throw new PipelineExecutionError(`Model requested tool '${functionName}' but no executionTools.script were provided in OpenAiAssistantExecutionTools options`);
|
|
29412
|
+
}
|
|
29413
|
+
// TODO: [DRY] Use some common tool caller (similar to OpenAiCompatibleExecutionTools)
|
|
29414
|
+
const scriptTools = Array.isArray(executionTools.script)
|
|
29415
|
+
? executionTools.script
|
|
29416
|
+
: [executionTools.script];
|
|
29417
|
+
let functionResponse;
|
|
29418
|
+
let errors;
|
|
29419
|
+
try {
|
|
29420
|
+
const scriptTool = scriptTools[0]; // <- TODO: [🧠] Which script tool to use?
|
|
29421
|
+
functionResponse = await scriptTool.execute({
|
|
29422
|
+
scriptLanguage: 'javascript',
|
|
29423
|
+
script: `
|
|
29424
|
+
const args = ${JSON.stringify(functionArgs)};
|
|
29425
|
+
return await ${functionName}(args);
|
|
29426
|
+
`,
|
|
29427
|
+
parameters: prompt.parameters,
|
|
29428
|
+
});
|
|
29429
|
+
if (this.options.isVerbose) {
|
|
29430
|
+
console.info(`✅ Tool ${functionName} executed:`, functionResponse);
|
|
29431
|
+
}
|
|
29432
|
+
}
|
|
29433
|
+
catch (error) {
|
|
29434
|
+
assertsError(error);
|
|
29435
|
+
const serializedError = serializeError(error);
|
|
29436
|
+
errors = [serializedError];
|
|
29437
|
+
functionResponse = spaceTrim$2((block) => `
|
|
29438
|
+
|
|
29439
|
+
The invoked tool \`${functionName}\` failed with error:
|
|
29440
|
+
|
|
29441
|
+
\`\`\`json
|
|
29442
|
+
${block(JSON.stringify(serializedError, null, 4))}
|
|
29443
|
+
\`\`\`
|
|
29444
|
+
|
|
29445
|
+
`);
|
|
29446
|
+
console.error(colors.bgRed(`❌ Error executing tool ${functionName}:`));
|
|
29447
|
+
console.error(error);
|
|
29448
|
+
}
|
|
29449
|
+
toolOutputs.push({
|
|
29450
|
+
tool_call_id: toolCall.id,
|
|
29451
|
+
output: functionResponse,
|
|
29452
|
+
});
|
|
29453
|
+
completedToolCalls.push({
|
|
29454
|
+
name: functionName,
|
|
29455
|
+
arguments: toolCall.function.arguments,
|
|
29456
|
+
result: functionResponse,
|
|
29457
|
+
rawToolCall: toolCall,
|
|
29458
|
+
createdAt: toolCall.id ? toolCallStartedAt.get(toolCall.id) || calledAt : calledAt,
|
|
29459
|
+
errors,
|
|
29460
|
+
});
|
|
29461
|
+
}
|
|
29462
|
+
}
|
|
29463
|
+
// Submit tool outputs
|
|
29464
|
+
run = (await client.beta.threads.runs.submitToolOutputs(run.thread_id, run.id, {
|
|
29465
|
+
tool_outputs: toolOutputs,
|
|
29466
|
+
}));
|
|
29467
|
+
}
|
|
29468
|
+
else {
|
|
29469
|
+
// Wait a bit before polling again
|
|
29470
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
29471
|
+
run = (await client.beta.threads.runs.retrieve(run.thread_id, run.id));
|
|
29472
|
+
}
|
|
29473
|
+
}
|
|
29474
|
+
if (run.status !== 'completed') {
|
|
29475
|
+
throw new PipelineExecutionError(`Assistant run failed with status: ${run.status}`);
|
|
29476
|
+
}
|
|
29477
|
+
// Get messages from the thread
|
|
29478
|
+
const messages = await client.beta.threads.messages.list(run.thread_id);
|
|
29479
|
+
const assistantMessages = messages.data.filter((msg) => msg.role === 'assistant');
|
|
29480
|
+
if (assistantMessages.length === 0) {
|
|
29481
|
+
throw new PipelineExecutionError('No assistant messages found after run completion');
|
|
29482
|
+
}
|
|
29483
|
+
const lastMessage = assistantMessages[0];
|
|
29484
|
+
const textContent = lastMessage.content.find((c) => c.type === 'text');
|
|
29485
|
+
if (!textContent || textContent.type !== 'text') {
|
|
29486
|
+
throw new PipelineExecutionError('No text content in assistant response');
|
|
29487
|
+
}
|
|
29488
|
+
complete = $getCurrentDate();
|
|
29489
|
+
const resultContent = textContent.text.value;
|
|
29490
|
+
const usage = UNCERTAIN_USAGE;
|
|
29491
|
+
// Progress callback with final result
|
|
29492
|
+
const finalChunk = {
|
|
29493
|
+
content: resultContent,
|
|
29494
|
+
modelName: 'assistant',
|
|
29495
|
+
timing: { start, complete },
|
|
29496
|
+
usage,
|
|
29497
|
+
rawPromptContent,
|
|
29498
|
+
rawRequest,
|
|
29499
|
+
rawResponse: { run, messages: messages.data },
|
|
29500
|
+
toolCalls: completedToolCalls.length > 0 ? completedToolCalls : undefined,
|
|
29501
|
+
};
|
|
29502
|
+
onProgress(finalChunk);
|
|
29503
|
+
return exportJson({
|
|
29504
|
+
name: 'promptResult',
|
|
29505
|
+
message: `Result of \`OpenAiAssistantExecutionTools.callChatModelStream\` (with tools)`,
|
|
29506
|
+
order: [],
|
|
29507
|
+
value: finalChunk,
|
|
29508
|
+
});
|
|
29509
|
+
}
|
|
29510
|
+
// Streaming mode (without tools)
|
|
29511
|
+
const rawRequest = {
|
|
29512
|
+
// TODO: [👨👨👧👧] ...modelSettings,
|
|
29513
|
+
// TODO: [👨👨👧👧][🧠] What about system message for assistants, does it make sense - combination of OpenAI assistants with Promptbook Personas
|
|
29514
|
+
assistant_id: this.assistantId,
|
|
29515
|
+
thread: {
|
|
29516
|
+
messages: threadMessages,
|
|
29517
|
+
},
|
|
29518
|
+
tools: modelRequirements.tools === undefined ? undefined : mapToolsToOpenAi(modelRequirements.tools),
|
|
29519
|
+
// <- TODO: Add user identification here> user: this.options.user,
|
|
29520
|
+
};
|
|
29521
|
+
if (this.options.isVerbose) {
|
|
29522
|
+
console.info(colors.bgWhite('rawRequest (streaming)'), JSON.stringify(rawRequest, null, 4));
|
|
29523
|
+
}
|
|
29524
|
+
const stream = await client.beta.threads.createAndRunStream(rawRequest);
|
|
29525
|
+
stream.on('connect', () => {
|
|
29526
|
+
if (this.options.isVerbose) {
|
|
29527
|
+
console.info('connect', stream.currentEvent);
|
|
29528
|
+
}
|
|
29529
|
+
});
|
|
29530
|
+
stream.on('textDelta', (textDelta, snapshot) => {
|
|
29531
|
+
if (this.options.isVerbose && textDelta.value) {
|
|
29532
|
+
console.info('textDelta', textDelta.value);
|
|
29533
|
+
}
|
|
29534
|
+
const chunk = {
|
|
29535
|
+
content: snapshot.value,
|
|
29536
|
+
modelName: 'assistant',
|
|
29537
|
+
timing: {
|
|
29538
|
+
start,
|
|
29539
|
+
complete: $getCurrentDate(),
|
|
29540
|
+
},
|
|
29541
|
+
usage: UNCERTAIN_USAGE,
|
|
29542
|
+
rawPromptContent,
|
|
29543
|
+
rawRequest,
|
|
29544
|
+
rawResponse: snapshot,
|
|
29545
|
+
};
|
|
29546
|
+
onProgress(chunk);
|
|
29547
|
+
});
|
|
29548
|
+
stream.on('messageCreated', (message) => {
|
|
29549
|
+
if (this.options.isVerbose) {
|
|
29550
|
+
console.info('messageCreated', message);
|
|
29551
|
+
}
|
|
29552
|
+
});
|
|
29553
|
+
stream.on('messageDone', (message) => {
|
|
29554
|
+
if (this.options.isVerbose) {
|
|
29555
|
+
console.info('messageDone', message);
|
|
29556
|
+
}
|
|
29557
|
+
});
|
|
29558
|
+
// TODO: [🐱🚀] Handle tool calls in assistants
|
|
29559
|
+
// Note: OpenAI Assistant streaming with tool calls requires special handling.
|
|
29560
|
+
// The stream will pause when a tool call is needed, and we need to:
|
|
29561
|
+
// 1. Wait for the run to reach 'requires_action' status
|
|
29562
|
+
// 2. Execute the tool calls
|
|
29563
|
+
// 3. Submit tool outputs via a separate API call (not on the stream)
|
|
29564
|
+
// 4. Continue the run
|
|
29565
|
+
// This requires switching to non-streaming mode or using the Runs API directly.
|
|
29566
|
+
// For now, tools with assistants should use the non-streaming chat completions API instead.
|
|
29567
|
+
const rawResponse = await stream.finalMessages();
|
|
29568
|
+
if (this.options.isVerbose) {
|
|
29569
|
+
console.info(colors.bgWhite('rawResponse'), JSON.stringify(rawResponse, null, 4));
|
|
29570
|
+
}
|
|
29571
|
+
if (rawResponse.length !== 1) {
|
|
29572
|
+
throw new PipelineExecutionError(`There is NOT 1 BUT ${rawResponse.length} finalMessages from OpenAI`);
|
|
29573
|
+
}
|
|
29574
|
+
if (rawResponse[0].content.length !== 1) {
|
|
29575
|
+
throw new PipelineExecutionError(`There is NOT 1 BUT ${rawResponse[0].content.length} finalMessages content from OpenAI`);
|
|
29576
|
+
}
|
|
29577
|
+
if (((_b = rawResponse[0].content[0]) === null || _b === void 0 ? void 0 : _b.type) !== 'text') {
|
|
29578
|
+
throw new PipelineExecutionError(`There is NOT 'text' BUT ${(_c = rawResponse[0].content[0]) === null || _c === void 0 ? void 0 : _c.type} finalMessages content type from OpenAI`);
|
|
29579
|
+
}
|
|
29580
|
+
let resultContent = (_d = rawResponse[0].content[0]) === null || _d === void 0 ? void 0 : _d.text.value;
|
|
29581
|
+
// Process annotations to replace file IDs with filenames
|
|
29582
|
+
if ((_e = rawResponse[0].content[0]) === null || _e === void 0 ? void 0 : _e.text.annotations) {
|
|
29583
|
+
const annotations = (_f = rawResponse[0].content[0]) === null || _f === void 0 ? void 0 : _f.text.annotations;
|
|
29584
|
+
// Map to store file ID -> filename to avoid duplicate requests
|
|
29585
|
+
const fileIdToName = new Map();
|
|
29586
|
+
for (const annotation of annotations) {
|
|
29587
|
+
if (annotation.type === 'file_citation') {
|
|
29588
|
+
const fileId = annotation.file_citation.file_id;
|
|
29589
|
+
let filename = fileIdToName.get(fileId);
|
|
29590
|
+
if (!filename) {
|
|
29591
|
+
try {
|
|
29592
|
+
const file = await client.files.retrieve(fileId);
|
|
29593
|
+
filename = file.filename;
|
|
29594
|
+
fileIdToName.set(fileId, filename);
|
|
29595
|
+
}
|
|
29596
|
+
catch (error) {
|
|
29597
|
+
console.error(`Failed to retrieve file info for ${fileId}`, error);
|
|
29598
|
+
// Fallback to "Source" or keep original if fetch fails
|
|
29599
|
+
filename = 'Source';
|
|
29600
|
+
}
|
|
29601
|
+
}
|
|
29602
|
+
if (filename && resultContent) {
|
|
29603
|
+
// Replace the citation marker with filename
|
|
29604
|
+
// Regex to match the second part of the citation: 【id†source】 -> 【id†filename】
|
|
29605
|
+
// Note: annotation.text contains the exact marker like 【4:0†source】
|
|
29606
|
+
const newText = annotation.text.replace(/†.*?】/, `†${filename}】`);
|
|
29607
|
+
resultContent = resultContent.replace(annotation.text, newText);
|
|
29608
|
+
}
|
|
29609
|
+
}
|
|
29610
|
+
}
|
|
29611
|
+
}
|
|
29612
|
+
// eslint-disable-next-line prefer-const
|
|
29613
|
+
complete = $getCurrentDate();
|
|
29614
|
+
const usage = UNCERTAIN_USAGE;
|
|
29615
|
+
// <- TODO: [🥘] Compute real usage for assistant
|
|
29616
|
+
// ?> const usage = computeOpenAiUsage(content, resultContent || '', rawResponse);
|
|
29617
|
+
if (resultContent === null) {
|
|
29618
|
+
throw new PipelineExecutionError('No response message from OpenAI');
|
|
29619
|
+
}
|
|
29620
|
+
return exportJson({
|
|
29621
|
+
name: 'promptResult',
|
|
29622
|
+
message: `Result of \`OpenAiAssistantExecutionTools.callChatModelStream\``,
|
|
29623
|
+
order: [],
|
|
29624
|
+
value: {
|
|
29625
|
+
content: resultContent,
|
|
29626
|
+
modelName: 'assistant',
|
|
29627
|
+
// <- TODO: [🥘] Detect used model in assistant
|
|
29628
|
+
// ?> model: rawResponse.model || modelName,
|
|
29629
|
+
timing: {
|
|
29630
|
+
start,
|
|
29631
|
+
complete,
|
|
29632
|
+
},
|
|
29633
|
+
usage,
|
|
29634
|
+
rawPromptContent,
|
|
29635
|
+
rawRequest,
|
|
29636
|
+
rawResponse,
|
|
29637
|
+
// <- [🗯]
|
|
29638
|
+
},
|
|
29639
|
+
});
|
|
29640
|
+
}
|
|
29641
|
+
/*
|
|
29642
|
+
public async playground() {
|
|
29643
|
+
const client = await this.getClient();
|
|
29644
|
+
|
|
29645
|
+
// List all assistants
|
|
29646
|
+
const assistants = await client.beta.assistants.list();
|
|
29647
|
+
|
|
29648
|
+
// Get details of a specific assistant
|
|
29649
|
+
const assistantId = 'asst_MO8fhZf4dGloCfXSHeLcIik0';
|
|
29650
|
+
const assistant = await client.beta.assistants.retrieve(assistantId);
|
|
29651
|
+
|
|
29652
|
+
// Update an assistant
|
|
29653
|
+
const updatedAssistant = await client.beta.assistants.update(assistantId, {
|
|
29654
|
+
name: assistant.name + '(M)',
|
|
29655
|
+
description: 'Updated description via Promptbook',
|
|
29656
|
+
metadata: {
|
|
29657
|
+
[Math.random().toString(36).substring(2, 15)]: new Date().toISOString(),
|
|
29658
|
+
},
|
|
29659
|
+
});
|
|
29660
|
+
|
|
29661
|
+
await forEver();
|
|
29662
|
+
}
|
|
29663
|
+
*/
|
|
29664
|
+
/**
|
|
29665
|
+
* Get an existing assistant tool wrapper
|
|
29666
|
+
*/
|
|
29667
|
+
getAssistant(assistantId) {
|
|
29668
|
+
return new OpenAiAssistantExecutionTools({
|
|
29669
|
+
...this.options,
|
|
29670
|
+
isCreatingNewAssistantsAllowed: this.isCreatingNewAssistantsAllowed,
|
|
29671
|
+
assistantId,
|
|
29672
|
+
});
|
|
29673
|
+
}
|
|
29629
29674
|
async createNewAssistant(options) {
|
|
29630
29675
|
var _a, _b, _c;
|
|
29631
29676
|
if (!this.isCreatingNewAssistantsAllowed) {
|
|
@@ -29771,7 +29816,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
29771
29816
|
* Discriminant for type guards
|
|
29772
29817
|
*/
|
|
29773
29818
|
get discriminant() {
|
|
29774
|
-
return DISCRIMINANT;
|
|
29819
|
+
return DISCRIMINANT$1;
|
|
29775
29820
|
}
|
|
29776
29821
|
/**
|
|
29777
29822
|
* Type guard to check if given `LlmExecutionTools` are instanceof `OpenAiAssistantExecutionTools`
|
|
@@ -29779,7 +29824,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
29779
29824
|
* Note: This is useful when you can possibly have multiple versions of `@promptbook/openai` installed
|
|
29780
29825
|
*/
|
|
29781
29826
|
static isOpenAiAssistantExecutionTools(llmExecutionTools) {
|
|
29782
|
-
return llmExecutionTools.discriminant === DISCRIMINANT;
|
|
29827
|
+
return llmExecutionTools.discriminant === DISCRIMINANT$1;
|
|
29783
29828
|
}
|
|
29784
29829
|
}
|
|
29785
29830
|
/**
|
|
@@ -29787,7 +29832,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
|
|
|
29787
29832
|
*
|
|
29788
29833
|
* @private const of `OpenAiAssistantExecutionTools`
|
|
29789
29834
|
*/
|
|
29790
|
-
const DISCRIMINANT = 'OPEN_AI_ASSISTANT_V1';
|
|
29835
|
+
const DISCRIMINANT$1 = 'OPEN_AI_ASSISTANT_V1';
|
|
29791
29836
|
/**
|
|
29792
29837
|
* TODO: !!!!! [✨🥚] Knowledge should work both with and without scrapers
|
|
29793
29838
|
* TODO: [🙎] In `OpenAiAssistantExecutionTools` Allow to create abstract assistants with `isCreatingNewAssistantsAllowed`
|
|
@@ -32594,6 +32639,426 @@ function promptbookifyAiText(text) {
|
|
|
32594
32639
|
* TODO: [🧠][✌️] Make some Promptbook-native token system
|
|
32595
32640
|
*/
|
|
32596
32641
|
|
|
32642
|
+
const DEFAULT_AGENT_KIT_MODEL_NAME = 'gpt-5.2';
|
|
32643
|
+
/**
|
|
32644
|
+
* Execution tools for OpenAI AgentKit (Agents SDK).
|
|
32645
|
+
*
|
|
32646
|
+
* @public exported from `@promptbook/openai`
|
|
32647
|
+
*/
|
|
32648
|
+
class OpenAiAgentKitExecutionTools extends OpenAiVectorStoreHandler {
|
|
32649
|
+
/**
|
|
32650
|
+
* Creates OpenAI AgentKit execution tools.
|
|
32651
|
+
*/
|
|
32652
|
+
constructor(options) {
|
|
32653
|
+
var _a;
|
|
32654
|
+
if (options.isProxied) {
|
|
32655
|
+
throw new NotYetImplementedError(`Proxy mode is not yet implemented for OpenAI AgentKit`);
|
|
32656
|
+
}
|
|
32657
|
+
super(options);
|
|
32658
|
+
this.preparedAgentKitAgent = null;
|
|
32659
|
+
this.agentKitModelName = (_a = options.agentKitModelName) !== null && _a !== void 0 ? _a : DEFAULT_AGENT_KIT_MODEL_NAME;
|
|
32660
|
+
}
|
|
32661
|
+
get title() {
|
|
32662
|
+
return 'OpenAI AgentKit';
|
|
32663
|
+
}
|
|
32664
|
+
get description() {
|
|
32665
|
+
return 'Use OpenAI AgentKit for agent-style chat with tools and knowledge';
|
|
32666
|
+
}
|
|
32667
|
+
/**
|
|
32668
|
+
* Calls OpenAI AgentKit with a chat prompt (non-streaming).
|
|
32669
|
+
*/
|
|
32670
|
+
async callChatModel(prompt) {
|
|
32671
|
+
return this.callChatModelStream(prompt, () => { });
|
|
32672
|
+
}
|
|
32673
|
+
/**
|
|
32674
|
+
* Calls OpenAI AgentKit with a chat prompt (streaming).
|
|
32675
|
+
*/
|
|
32676
|
+
async callChatModelStream(prompt, onProgress) {
|
|
32677
|
+
const { content, parameters, modelRequirements } = prompt;
|
|
32678
|
+
if (modelRequirements.modelVariant !== 'CHAT') {
|
|
32679
|
+
throw new PipelineExecutionError('Use callChatModel only for CHAT variant');
|
|
32680
|
+
}
|
|
32681
|
+
for (const key of ['maxTokens', 'modelName', 'seed', 'temperature']) {
|
|
32682
|
+
if (modelRequirements[key] !== undefined) {
|
|
32683
|
+
throw new NotYetImplementedError(`In \`OpenAiAgentKitExecutionTools\` you cannot specify \`${key}\``);
|
|
32684
|
+
}
|
|
32685
|
+
}
|
|
32686
|
+
const rawPromptContent = templateParameters(content, {
|
|
32687
|
+
...parameters,
|
|
32688
|
+
modelName: this.agentKitModelName,
|
|
32689
|
+
});
|
|
32690
|
+
const preparedAgentKitAgent = await this.prepareAgentKitAgent({
|
|
32691
|
+
name: (prompt.title || 'Agent'),
|
|
32692
|
+
instructions: modelRequirements.systemMessage || '',
|
|
32693
|
+
knowledgeSources: modelRequirements.knowledgeSources,
|
|
32694
|
+
tools: 'tools' in prompt && Array.isArray(prompt.tools) ? prompt.tools : modelRequirements.tools,
|
|
32695
|
+
});
|
|
32696
|
+
return this.callChatModelStreamWithPreparedAgent({
|
|
32697
|
+
openAiAgentKitAgent: preparedAgentKitAgent.agent,
|
|
32698
|
+
prompt,
|
|
32699
|
+
rawPromptContent,
|
|
32700
|
+
onProgress,
|
|
32701
|
+
});
|
|
32702
|
+
}
|
|
32703
|
+
/**
|
|
32704
|
+
* Returns a prepared AgentKit agent when the server wants to manage caching externally.
|
|
32705
|
+
*/
|
|
32706
|
+
getPreparedAgentKitAgent() {
|
|
32707
|
+
return this.preparedAgentKitAgent;
|
|
32708
|
+
}
|
|
32709
|
+
/**
|
|
32710
|
+
* Stores a prepared AgentKit agent for later reuse by external cache managers.
|
|
32711
|
+
*/
|
|
32712
|
+
setPreparedAgentKitAgent(preparedAgent) {
|
|
32713
|
+
this.preparedAgentKitAgent = preparedAgent;
|
|
32714
|
+
}
|
|
32715
|
+
/**
|
|
32716
|
+
* Creates a new tools instance bound to a prepared AgentKit agent.
|
|
32717
|
+
*/
|
|
32718
|
+
getPreparedAgentTools(preparedAgent) {
|
|
32719
|
+
const tools = new OpenAiAgentKitExecutionTools(this.agentKitOptions);
|
|
32720
|
+
tools.setPreparedAgentKitAgent(preparedAgent);
|
|
32721
|
+
return tools;
|
|
32722
|
+
}
|
|
32723
|
+
/**
|
|
32724
|
+
* Prepares an AgentKit agent with optional knowledge sources and tool definitions.
|
|
32725
|
+
*/
|
|
32726
|
+
async prepareAgentKitAgent(options) {
|
|
32727
|
+
var _a, _b;
|
|
32728
|
+
const { name, instructions, knowledgeSources, tools, vectorStoreId: cachedVectorStoreId, storeAsPrepared, } = options;
|
|
32729
|
+
await this.ensureAgentKitDefaults();
|
|
32730
|
+
if (this.options.isVerbose) {
|
|
32731
|
+
console.info('[🤰]', 'Preparing OpenAI AgentKit agent', {
|
|
32732
|
+
name,
|
|
32733
|
+
instructionsLength: instructions.length,
|
|
32734
|
+
knowledgeSourcesCount: (_a = knowledgeSources === null || knowledgeSources === void 0 ? void 0 : knowledgeSources.length) !== null && _a !== void 0 ? _a : 0,
|
|
32735
|
+
toolsCount: (_b = tools === null || tools === void 0 ? void 0 : tools.length) !== null && _b !== void 0 ? _b : 0,
|
|
32736
|
+
});
|
|
32737
|
+
}
|
|
32738
|
+
let vectorStoreId = cachedVectorStoreId;
|
|
32739
|
+
if (!vectorStoreId && knowledgeSources && knowledgeSources.length > 0) {
|
|
32740
|
+
const vectorStoreResult = await this.createVectorStoreWithKnowledgeSources({
|
|
32741
|
+
client: await this.getClient(),
|
|
32742
|
+
name,
|
|
32743
|
+
knowledgeSources,
|
|
32744
|
+
logLabel: 'agentkit preparation',
|
|
32745
|
+
});
|
|
32746
|
+
vectorStoreId = vectorStoreResult.vectorStoreId;
|
|
32747
|
+
}
|
|
32748
|
+
else if (vectorStoreId && this.options.isVerbose) {
|
|
32749
|
+
console.info('[🤰]', 'Using cached vector store for AgentKit agent', {
|
|
32750
|
+
name,
|
|
32751
|
+
vectorStoreId,
|
|
32752
|
+
});
|
|
32753
|
+
}
|
|
32754
|
+
const agentKitTools = this.buildAgentKitTools({ tools, vectorStoreId });
|
|
32755
|
+
const openAiAgentKitAgent = new Agent$1({
|
|
32756
|
+
name,
|
|
32757
|
+
model: this.agentKitModelName,
|
|
32758
|
+
instructions: instructions || 'You are a helpful assistant.',
|
|
32759
|
+
tools: agentKitTools,
|
|
32760
|
+
});
|
|
32761
|
+
const preparedAgent = {
|
|
32762
|
+
agent: openAiAgentKitAgent,
|
|
32763
|
+
vectorStoreId,
|
|
32764
|
+
};
|
|
32765
|
+
if (storeAsPrepared) {
|
|
32766
|
+
this.setPreparedAgentKitAgent(preparedAgent);
|
|
32767
|
+
}
|
|
32768
|
+
if (this.options.isVerbose) {
|
|
32769
|
+
console.info('[🤰]', 'OpenAI AgentKit agent ready', {
|
|
32770
|
+
name,
|
|
32771
|
+
model: this.agentKitModelName,
|
|
32772
|
+
toolCount: agentKitTools.length,
|
|
32773
|
+
hasVectorStore: Boolean(vectorStoreId),
|
|
32774
|
+
});
|
|
32775
|
+
}
|
|
32776
|
+
return preparedAgent;
|
|
32777
|
+
}
|
|
32778
|
+
/**
|
|
32779
|
+
* Ensures the AgentKit SDK is wired to the OpenAI client and API key.
|
|
32780
|
+
*/
|
|
32781
|
+
async ensureAgentKitDefaults() {
|
|
32782
|
+
const client = await this.getClient();
|
|
32783
|
+
setDefaultOpenAIClient(client);
|
|
32784
|
+
const apiKey = this.agentKitOptions.apiKey;
|
|
32785
|
+
if (apiKey && typeof apiKey === 'string') {
|
|
32786
|
+
setDefaultOpenAIKey(apiKey);
|
|
32787
|
+
}
|
|
32788
|
+
}
|
|
32789
|
+
/**
|
|
32790
|
+
* Builds the tool list for AgentKit, including hosted file search when applicable.
|
|
32791
|
+
*/
|
|
32792
|
+
buildAgentKitTools(options) {
|
|
32793
|
+
var _a;
|
|
32794
|
+
const { tools, vectorStoreId } = options;
|
|
32795
|
+
const agentKitTools = [];
|
|
32796
|
+
if (vectorStoreId) {
|
|
32797
|
+
agentKitTools.push(fileSearchTool(vectorStoreId));
|
|
32798
|
+
}
|
|
32799
|
+
if (tools && tools.length > 0) {
|
|
32800
|
+
const scriptTools = this.resolveScriptTools();
|
|
32801
|
+
for (const toolDefinition of tools) {
|
|
32802
|
+
agentKitTools.push(tool({
|
|
32803
|
+
name: toolDefinition.name,
|
|
32804
|
+
description: toolDefinition.description,
|
|
32805
|
+
parameters: toolDefinition.parameters
|
|
32806
|
+
? {
|
|
32807
|
+
...toolDefinition.parameters,
|
|
32808
|
+
additionalProperties: false,
|
|
32809
|
+
required: (_a = toolDefinition.parameters.required) !== null && _a !== void 0 ? _a : [],
|
|
32810
|
+
}
|
|
32811
|
+
: undefined,
|
|
32812
|
+
strict: false,
|
|
32813
|
+
execute: async (input, runContext, details) => {
|
|
32814
|
+
var _a, _b, _c;
|
|
32815
|
+
const scriptTool = scriptTools[0];
|
|
32816
|
+
const functionName = toolDefinition.name;
|
|
32817
|
+
const calledAt = $getCurrentDate();
|
|
32818
|
+
const callId = (_a = details === null || details === void 0 ? void 0 : details.toolCall) === null || _a === void 0 ? void 0 : _a.callId;
|
|
32819
|
+
const functionArgs = input !== null && input !== void 0 ? input : {};
|
|
32820
|
+
if (this.options.isVerbose) {
|
|
32821
|
+
console.info('[🤰]', 'Executing AgentKit tool', {
|
|
32822
|
+
functionName,
|
|
32823
|
+
callId,
|
|
32824
|
+
calledAt,
|
|
32825
|
+
});
|
|
32826
|
+
}
|
|
32827
|
+
try {
|
|
32828
|
+
return await scriptTool.execute({
|
|
32829
|
+
scriptLanguage: 'javascript',
|
|
32830
|
+
script: `
|
|
32831
|
+
const args = ${JSON.stringify(functionArgs)};
|
|
32832
|
+
return await ${functionName}(args);
|
|
32833
|
+
`,
|
|
32834
|
+
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 : {},
|
|
32835
|
+
});
|
|
32836
|
+
}
|
|
32837
|
+
catch (error) {
|
|
32838
|
+
assertsError(error);
|
|
32839
|
+
const serializedError = serializeError(error);
|
|
32840
|
+
const errorMessage = spaceTrim$2((block) => `
|
|
32841
|
+
|
|
32842
|
+
The invoked tool \`${functionName}\` failed with error:
|
|
32843
|
+
|
|
32844
|
+
\`\`\`json
|
|
32845
|
+
${block(JSON.stringify(serializedError, null, 4))}
|
|
32846
|
+
\`\`\`
|
|
32847
|
+
|
|
32848
|
+
`);
|
|
32849
|
+
console.error('[🤰]', 'AgentKit tool execution failed', {
|
|
32850
|
+
functionName,
|
|
32851
|
+
callId,
|
|
32852
|
+
error: serializedError,
|
|
32853
|
+
});
|
|
32854
|
+
return errorMessage;
|
|
32855
|
+
}
|
|
32856
|
+
},
|
|
32857
|
+
}));
|
|
32858
|
+
}
|
|
32859
|
+
}
|
|
32860
|
+
return agentKitTools;
|
|
32861
|
+
}
|
|
32862
|
+
/**
|
|
32863
|
+
* Resolves the configured script tools for tool execution.
|
|
32864
|
+
*/
|
|
32865
|
+
resolveScriptTools() {
|
|
32866
|
+
const executionTools = this.options.executionTools;
|
|
32867
|
+
if (!executionTools || !executionTools.script) {
|
|
32868
|
+
throw new PipelineExecutionError(`Model requested tools but no executionTools.script were provided in OpenAiAgentKitExecutionTools options`);
|
|
32869
|
+
}
|
|
32870
|
+
return Array.isArray(executionTools.script) ? executionTools.script : [executionTools.script];
|
|
32871
|
+
}
|
|
32872
|
+
/**
|
|
32873
|
+
* Runs a prepared AgentKit agent and streams results back to the caller.
|
|
32874
|
+
*/
|
|
32875
|
+
async callChatModelStreamWithPreparedAgent(options) {
|
|
32876
|
+
var _a, _b, _c, _d;
|
|
32877
|
+
const { openAiAgentKitAgent, prompt, onProgress } = options;
|
|
32878
|
+
const rawPromptContent = (_a = options.rawPromptContent) !== null && _a !== void 0 ? _a : templateParameters(prompt.content, {
|
|
32879
|
+
...prompt.parameters,
|
|
32880
|
+
modelName: this.agentKitModelName,
|
|
32881
|
+
});
|
|
32882
|
+
const start = $getCurrentDate();
|
|
32883
|
+
let latestContent = '';
|
|
32884
|
+
const toolCalls = [];
|
|
32885
|
+
const toolCallIndexById = new Map();
|
|
32886
|
+
const inputItems = await this.buildAgentKitInputItems(prompt, rawPromptContent);
|
|
32887
|
+
const rawRequest = {
|
|
32888
|
+
agentName: openAiAgentKitAgent.name,
|
|
32889
|
+
input: inputItems,
|
|
32890
|
+
};
|
|
32891
|
+
const streamResult = await run(openAiAgentKitAgent, inputItems, {
|
|
32892
|
+
stream: true,
|
|
32893
|
+
context: { parameters: prompt.parameters },
|
|
32894
|
+
});
|
|
32895
|
+
for await (const event of streamResult) {
|
|
32896
|
+
if (event.type === 'raw_model_stream_event' && ((_b = event.data) === null || _b === void 0 ? void 0 : _b.type) === 'output_text_delta') {
|
|
32897
|
+
latestContent += event.data.delta;
|
|
32898
|
+
onProgress({
|
|
32899
|
+
content: latestContent,
|
|
32900
|
+
modelName: this.agentKitModelName,
|
|
32901
|
+
timing: { start, complete: $getCurrentDate() },
|
|
32902
|
+
usage: UNCERTAIN_USAGE,
|
|
32903
|
+
rawPromptContent: rawPromptContent,
|
|
32904
|
+
rawRequest: null,
|
|
32905
|
+
rawResponse: {},
|
|
32906
|
+
});
|
|
32907
|
+
continue;
|
|
32908
|
+
}
|
|
32909
|
+
if (event.type === 'run_item_stream_event') {
|
|
32910
|
+
const rawItem = (_c = event.item) === null || _c === void 0 ? void 0 : _c.rawItem;
|
|
32911
|
+
if (event.name === 'tool_called' && (rawItem === null || rawItem === void 0 ? void 0 : rawItem.type) === 'function_call') {
|
|
32912
|
+
const toolCall = {
|
|
32913
|
+
name: rawItem.name,
|
|
32914
|
+
arguments: rawItem.arguments,
|
|
32915
|
+
rawToolCall: rawItem,
|
|
32916
|
+
createdAt: $getCurrentDate(),
|
|
32917
|
+
};
|
|
32918
|
+
toolCallIndexById.set(rawItem.callId, toolCalls.length);
|
|
32919
|
+
toolCalls.push(toolCall);
|
|
32920
|
+
onProgress({
|
|
32921
|
+
content: latestContent,
|
|
32922
|
+
modelName: this.agentKitModelName,
|
|
32923
|
+
timing: { start, complete: $getCurrentDate() },
|
|
32924
|
+
usage: UNCERTAIN_USAGE,
|
|
32925
|
+
rawPromptContent: rawPromptContent,
|
|
32926
|
+
rawRequest: null,
|
|
32927
|
+
rawResponse: {},
|
|
32928
|
+
toolCalls: [toolCall],
|
|
32929
|
+
});
|
|
32930
|
+
}
|
|
32931
|
+
if (event.name === 'tool_output' && (rawItem === null || rawItem === void 0 ? void 0 : rawItem.type) === 'function_call_result') {
|
|
32932
|
+
const index = toolCallIndexById.get(rawItem.callId);
|
|
32933
|
+
const result = this.formatAgentKitToolOutput(rawItem.output);
|
|
32934
|
+
if (index !== undefined) {
|
|
32935
|
+
const existingToolCall = toolCalls[index];
|
|
32936
|
+
const completedToolCall = {
|
|
32937
|
+
...existingToolCall,
|
|
32938
|
+
result,
|
|
32939
|
+
rawToolCall: rawItem,
|
|
32940
|
+
};
|
|
32941
|
+
toolCalls[index] = completedToolCall;
|
|
32942
|
+
onProgress({
|
|
32943
|
+
content: latestContent,
|
|
32944
|
+
modelName: this.agentKitModelName,
|
|
32945
|
+
timing: { start, complete: $getCurrentDate() },
|
|
32946
|
+
usage: UNCERTAIN_USAGE,
|
|
32947
|
+
rawPromptContent: rawPromptContent,
|
|
32948
|
+
rawRequest: null,
|
|
32949
|
+
rawResponse: {},
|
|
32950
|
+
toolCalls: [completedToolCall],
|
|
32951
|
+
});
|
|
32952
|
+
}
|
|
32953
|
+
}
|
|
32954
|
+
}
|
|
32955
|
+
}
|
|
32956
|
+
await streamResult.completed;
|
|
32957
|
+
const complete = $getCurrentDate();
|
|
32958
|
+
const finalContent = ((_d = streamResult.finalOutput) !== null && _d !== void 0 ? _d : latestContent);
|
|
32959
|
+
const finalResult = {
|
|
32960
|
+
content: finalContent,
|
|
32961
|
+
modelName: this.agentKitModelName,
|
|
32962
|
+
timing: { start, complete },
|
|
32963
|
+
usage: UNCERTAIN_USAGE,
|
|
32964
|
+
rawPromptContent: rawPromptContent,
|
|
32965
|
+
rawRequest,
|
|
32966
|
+
rawResponse: { runResult: streamResult },
|
|
32967
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
32968
|
+
};
|
|
32969
|
+
onProgress(finalResult);
|
|
32970
|
+
return finalResult;
|
|
32971
|
+
}
|
|
32972
|
+
/**
|
|
32973
|
+
* Builds AgentKit input items from the prompt and optional thread.
|
|
32974
|
+
*/
|
|
32975
|
+
async buildAgentKitInputItems(prompt, rawPromptContent) {
|
|
32976
|
+
var _a;
|
|
32977
|
+
const inputItems = [];
|
|
32978
|
+
if ('thread' in prompt && Array.isArray(prompt.thread)) {
|
|
32979
|
+
for (const message of prompt.thread) {
|
|
32980
|
+
const sender = message.sender;
|
|
32981
|
+
const content = (_a = message.content) !== null && _a !== void 0 ? _a : '';
|
|
32982
|
+
if (sender === 'assistant' || sender === 'agent') {
|
|
32983
|
+
inputItems.push({
|
|
32984
|
+
role: 'assistant',
|
|
32985
|
+
status: 'completed',
|
|
32986
|
+
content: [{ type: 'output_text', text: content }],
|
|
32987
|
+
});
|
|
32988
|
+
}
|
|
32989
|
+
else {
|
|
32990
|
+
inputItems.push({
|
|
32991
|
+
role: 'user',
|
|
32992
|
+
content,
|
|
32993
|
+
});
|
|
32994
|
+
}
|
|
32995
|
+
}
|
|
32996
|
+
}
|
|
32997
|
+
const userContent = await this.buildAgentKitUserContent(prompt, rawPromptContent);
|
|
32998
|
+
inputItems.push({
|
|
32999
|
+
role: 'user',
|
|
33000
|
+
content: userContent,
|
|
33001
|
+
});
|
|
33002
|
+
return inputItems;
|
|
33003
|
+
}
|
|
33004
|
+
/**
|
|
33005
|
+
* Builds the user message content for AgentKit runs, including file inputs when provided.
|
|
33006
|
+
*/
|
|
33007
|
+
async buildAgentKitUserContent(prompt, rawPromptContent) {
|
|
33008
|
+
if ('files' in prompt && Array.isArray(prompt.files) && prompt.files.length > 0) {
|
|
33009
|
+
const fileItems = await Promise.all(prompt.files.map(async (file) => {
|
|
33010
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
33011
|
+
const base64 = Buffer.from(arrayBuffer).toString('base64');
|
|
33012
|
+
return {
|
|
33013
|
+
type: 'input_image',
|
|
33014
|
+
image: `data:${file.type};base64,${base64}`,
|
|
33015
|
+
};
|
|
33016
|
+
}));
|
|
33017
|
+
return [{ type: 'input_text', text: rawPromptContent }, ...fileItems];
|
|
33018
|
+
}
|
|
33019
|
+
return rawPromptContent;
|
|
33020
|
+
}
|
|
33021
|
+
/**
|
|
33022
|
+
* Normalizes AgentKit tool outputs into a string for Promptbook tool call results.
|
|
33023
|
+
*/
|
|
33024
|
+
formatAgentKitToolOutput(output) {
|
|
33025
|
+
if (typeof output === 'string') {
|
|
33026
|
+
return output;
|
|
33027
|
+
}
|
|
33028
|
+
if (output && typeof output === 'object') {
|
|
33029
|
+
const textOutput = output;
|
|
33030
|
+
if (textOutput.type === 'text' && typeof textOutput.text === 'string') {
|
|
33031
|
+
return textOutput.text;
|
|
33032
|
+
}
|
|
33033
|
+
}
|
|
33034
|
+
return JSON.stringify(output !== null && output !== void 0 ? output : null);
|
|
33035
|
+
}
|
|
33036
|
+
/**
|
|
33037
|
+
* Returns AgentKit-specific options.
|
|
33038
|
+
*/
|
|
33039
|
+
get agentKitOptions() {
|
|
33040
|
+
return this.options;
|
|
33041
|
+
}
|
|
33042
|
+
/**
|
|
33043
|
+
* Discriminant for type guards.
|
|
33044
|
+
*/
|
|
33045
|
+
get discriminant() {
|
|
33046
|
+
return DISCRIMINANT;
|
|
33047
|
+
}
|
|
33048
|
+
/**
|
|
33049
|
+
* Type guard to check if given `LlmExecutionTools` are instanceof `OpenAiAgentKitExecutionTools`.
|
|
33050
|
+
*/
|
|
33051
|
+
static isOpenAiAgentKitExecutionTools(llmExecutionTools) {
|
|
33052
|
+
return llmExecutionTools.discriminant === DISCRIMINANT;
|
|
33053
|
+
}
|
|
33054
|
+
}
|
|
33055
|
+
/**
|
|
33056
|
+
* Discriminant for type guards.
|
|
33057
|
+
*
|
|
33058
|
+
* @private const of `OpenAiAgentKitExecutionTools`
|
|
33059
|
+
*/
|
|
33060
|
+
const DISCRIMINANT = 'OPEN_AI_AGENT_KIT_V1';
|
|
33061
|
+
|
|
32597
33062
|
/**
|
|
32598
33063
|
* Emits a progress update to signal assistant preparation before long setup work.
|
|
32599
33064
|
*/
|
|
@@ -32630,6 +33095,7 @@ function emitAssistantPreparationProgress(options) {
|
|
|
32630
33095
|
* - `LlmExecutionTools` - which wraps one or more LLM models and provides an interface to execute them
|
|
32631
33096
|
* - `AgentLlmExecutionTools` - which is a specific implementation of `LlmExecutionTools` that wraps another LlmExecutionTools and applies agent-specific system prompts and requirements
|
|
32632
33097
|
* - `OpenAiAssistantExecutionTools` - (Deprecated) which is a specific implementation of `LlmExecutionTools` for OpenAI models with assistant capabilities
|
|
33098
|
+
* - `OpenAiAgentKitExecutionTools` - which is a specific implementation of `LlmExecutionTools` backed by OpenAI AgentKit
|
|
32633
33099
|
* - `RemoteAgent` - which is an `Agent` that connects to a Promptbook Agents Server
|
|
32634
33100
|
*
|
|
32635
33101
|
* @public exported from `@promptbook/core`
|
|
@@ -32764,6 +33230,7 @@ class AgentLlmExecutionTools {
|
|
|
32764
33230
|
* Calls the chat model with agent-specific system prompt and requirements with streaming
|
|
32765
33231
|
*/
|
|
32766
33232
|
async callChatModelStream(prompt, onProgress) {
|
|
33233
|
+
var _a, _b;
|
|
32767
33234
|
// Ensure we're working with a chat prompt
|
|
32768
33235
|
if (prompt.modelRequirements.modelVariant !== 'CHAT') {
|
|
32769
33236
|
throw new Error('AgentLlmExecutionTools only supports chat prompts');
|
|
@@ -32791,7 +33258,75 @@ class AgentLlmExecutionTools {
|
|
|
32791
33258
|
}, // Cast to avoid readonly mismatch from spread
|
|
32792
33259
|
};
|
|
32793
33260
|
console.log('!!!! promptWithAgentModelRequirements:', promptWithAgentModelRequirements);
|
|
32794
|
-
if (
|
|
33261
|
+
if (OpenAiAgentKitExecutionTools.isOpenAiAgentKitExecutionTools(this.options.llmTools)) {
|
|
33262
|
+
const requirementsHash = SHA256(JSON.stringify(modelRequirements)).toString();
|
|
33263
|
+
const vectorStoreHash = SHA256(JSON.stringify((_a = modelRequirements.knowledgeSources) !== null && _a !== void 0 ? _a : [])).toString();
|
|
33264
|
+
const cachedVectorStore = AgentLlmExecutionTools.vectorStoreCache.get(this.title);
|
|
33265
|
+
const cachedAgentKit = AgentLlmExecutionTools.agentKitAgentCache.get(this.title);
|
|
33266
|
+
let preparedAgentKit = this.options.assistantPreparationMode === 'external'
|
|
33267
|
+
? this.options.llmTools.getPreparedAgentKitAgent()
|
|
33268
|
+
: null;
|
|
33269
|
+
const vectorStoreId = (preparedAgentKit === null || preparedAgentKit === void 0 ? void 0 : preparedAgentKit.vectorStoreId) ||
|
|
33270
|
+
(cachedVectorStore && cachedVectorStore.requirementsHash === vectorStoreHash
|
|
33271
|
+
? cachedVectorStore.vectorStoreId
|
|
33272
|
+
: undefined);
|
|
33273
|
+
if (!preparedAgentKit && cachedAgentKit && cachedAgentKit.requirementsHash === requirementsHash) {
|
|
33274
|
+
if (this.options.isVerbose) {
|
|
33275
|
+
console.info('[🤰]', 'Using cached OpenAI AgentKit agent', {
|
|
33276
|
+
agent: this.title,
|
|
33277
|
+
});
|
|
33278
|
+
}
|
|
33279
|
+
preparedAgentKit = {
|
|
33280
|
+
agent: cachedAgentKit.agent,
|
|
33281
|
+
vectorStoreId: cachedAgentKit.vectorStoreId,
|
|
33282
|
+
};
|
|
33283
|
+
}
|
|
33284
|
+
if (!preparedAgentKit) {
|
|
33285
|
+
if (this.options.isVerbose) {
|
|
33286
|
+
console.info('[🤰]', 'Preparing OpenAI AgentKit agent', {
|
|
33287
|
+
agent: this.title,
|
|
33288
|
+
});
|
|
33289
|
+
}
|
|
33290
|
+
if (!vectorStoreId && ((_b = modelRequirements.knowledgeSources) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
33291
|
+
emitAssistantPreparationProgress({
|
|
33292
|
+
onProgress,
|
|
33293
|
+
prompt,
|
|
33294
|
+
modelName: this.modelName,
|
|
33295
|
+
phase: 'Creating knowledge base',
|
|
33296
|
+
});
|
|
33297
|
+
}
|
|
33298
|
+
emitAssistantPreparationProgress({
|
|
33299
|
+
onProgress,
|
|
33300
|
+
prompt,
|
|
33301
|
+
modelName: this.modelName,
|
|
33302
|
+
phase: 'Preparing AgentKit agent',
|
|
33303
|
+
});
|
|
33304
|
+
preparedAgentKit = await this.options.llmTools.prepareAgentKitAgent({
|
|
33305
|
+
name: this.title,
|
|
33306
|
+
instructions: modelRequirements.systemMessage || '',
|
|
33307
|
+
knowledgeSources: modelRequirements.knowledgeSources,
|
|
33308
|
+
tools: modelRequirements.tools ? [...modelRequirements.tools] : undefined,
|
|
33309
|
+
vectorStoreId,
|
|
33310
|
+
});
|
|
33311
|
+
}
|
|
33312
|
+
if (preparedAgentKit.vectorStoreId) {
|
|
33313
|
+
AgentLlmExecutionTools.vectorStoreCache.set(this.title, {
|
|
33314
|
+
vectorStoreId: preparedAgentKit.vectorStoreId,
|
|
33315
|
+
requirementsHash: vectorStoreHash,
|
|
33316
|
+
});
|
|
33317
|
+
}
|
|
33318
|
+
AgentLlmExecutionTools.agentKitAgentCache.set(this.title, {
|
|
33319
|
+
agent: preparedAgentKit.agent,
|
|
33320
|
+
requirementsHash,
|
|
33321
|
+
vectorStoreId: preparedAgentKit.vectorStoreId,
|
|
33322
|
+
});
|
|
33323
|
+
underlyingLlmResult = await this.options.llmTools.callChatModelStreamWithPreparedAgent({
|
|
33324
|
+
openAiAgentKitAgent: preparedAgentKit.agent,
|
|
33325
|
+
prompt: promptWithAgentModelRequirements,
|
|
33326
|
+
onProgress,
|
|
33327
|
+
});
|
|
33328
|
+
}
|
|
33329
|
+
else if (OpenAiAssistantExecutionTools.isOpenAiAssistantExecutionTools(this.options.llmTools)) {
|
|
32795
33330
|
// ... deprecated path ...
|
|
32796
33331
|
const requirementsHash = SHA256(JSON.stringify(modelRequirements)).toString();
|
|
32797
33332
|
const cached = AgentLlmExecutionTools.assistantCache.get(this.title);
|
|
@@ -32916,6 +33451,10 @@ class AgentLlmExecutionTools {
|
|
|
32916
33451
|
return agentResult;
|
|
32917
33452
|
}
|
|
32918
33453
|
}
|
|
33454
|
+
/**
|
|
33455
|
+
* Cached AgentKit agents to avoid rebuilding identical instances.
|
|
33456
|
+
*/
|
|
33457
|
+
AgentLlmExecutionTools.agentKitAgentCache = new Map();
|
|
32919
33458
|
/**
|
|
32920
33459
|
* Cache of OpenAI assistants to avoid creating duplicates
|
|
32921
33460
|
*/
|
|
@@ -32997,6 +33536,7 @@ function buildTeacherSummary(commitments, used) {
|
|
|
32997
33536
|
* - `LlmExecutionTools` - which wraps one or more LLM models and provides an interface to execute them
|
|
32998
33537
|
* - `AgentLlmExecutionTools` - which is a specific implementation of `LlmExecutionTools` that wraps another LlmExecutionTools and applies agent-specific system prompts and requirements
|
|
32999
33538
|
* - `OpenAiAssistantExecutionTools` - (Deprecated) which is a specific implementation of `LlmExecutionTools` for OpenAI models with assistant capabilities
|
|
33539
|
+
* - `OpenAiAgentKitExecutionTools` - which is a specific implementation of `LlmExecutionTools` backed by OpenAI AgentKit
|
|
33000
33540
|
* - `RemoteAgent` - which is an `Agent` that connects to a Promptbook Agents Server
|
|
33001
33541
|
*
|
|
33002
33542
|
* @public exported from `@promptbook/core`
|
|
@@ -33367,7 +33907,8 @@ function buildRemoteAgentSource(profile, meta) {
|
|
|
33367
33907
|
* - `Agent` - which represents an AI Agent with its source, memories, actions, etc. Agent is a higher-level abstraction which is internally using:
|
|
33368
33908
|
* - `LlmExecutionTools` - which wraps one or more LLM models and provides an interface to execute them
|
|
33369
33909
|
* - `AgentLlmExecutionTools` - which is a specific implementation of `LlmExecutionTools` that wraps another LlmExecutionTools and applies agent-specific system prompts and requirements
|
|
33370
|
-
* - `OpenAiAssistantExecutionTools` - which is a specific implementation of `LlmExecutionTools` for OpenAI models with assistant capabilities
|
|
33910
|
+
* - `OpenAiAssistantExecutionTools` - (Deprecated) which is a specific implementation of `LlmExecutionTools` for OpenAI models with assistant capabilities
|
|
33911
|
+
* - `OpenAiAgentKitExecutionTools` - which is a specific implementation of `LlmExecutionTools` backed by OpenAI AgentKit
|
|
33371
33912
|
* - `RemoteAgent` - which is an `Agent` that connects to a Promptbook Agents Server
|
|
33372
33913
|
*
|
|
33373
33914
|
* @public exported from `@promptbook/core`
|