@promptbook/cli 0.104.0-3 → 0.104.0-4
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/apps/agents-server/src/database/migrate.ts +34 -1
- package/apps/agents-server/src/database/migrations/2025-12-0402-message-table.sql +42 -0
- package/apps/agents-server/src/message-providers/email/_common/Email.ts +73 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/TODO.txt +1 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddress.test.ts.todo +108 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddress.ts +62 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddresses.test.ts.todo +117 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/parseEmailAddresses.ts +19 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddress.test.ts.todo +119 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddress.ts +19 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddresses.test.ts.todo +74 -0
- package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddresses.ts +14 -0
- package/apps/agents-server/src/message-providers/email/sendgrid/SendgridMessageProvider.ts +44 -0
- package/apps/agents-server/src/message-providers/email/zeptomail/ZeptomailMessageProvider.ts +43 -0
- package/apps/agents-server/src/message-providers/index.ts +13 -0
- package/apps/agents-server/src/message-providers/interfaces/MessageProvider.ts +11 -0
- package/apps/agents-server/src/utils/messages/sendMessage.ts +91 -0
- package/apps/agents-server/src/utils/normalization/filenameToPrompt.test.ts +36 -0
- package/apps/agents-server/src/utils/normalization/filenameToPrompt.ts +6 -2
- package/esm/index.es.js +32 -2
- package/esm/index.es.js.map +1 -1
- package/esm/typings/src/llm-providers/_multiple/MultipleLlmExecutionTools.d.ts +6 -2
- package/esm/typings/src/llm-providers/remote/RemoteLlmExecutionTools.d.ts +1 -0
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +32 -2
- package/umd/index.umd.js.map +1 -1
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { describe, expect, it } from '@jest/globals';
|
|
2
|
+
import { stringifyEmailAddresses } from './stringifyEmailAddresses';
|
|
3
|
+
|
|
4
|
+
describe('how stringifyEmailAddresses works', () => {
|
|
5
|
+
it('should work with single email', () => {
|
|
6
|
+
expect(
|
|
7
|
+
stringifyEmailAddresses([
|
|
8
|
+
{
|
|
9
|
+
fullName: null,
|
|
10
|
+
baseEmail: 'pavol@webgpt.cz',
|
|
11
|
+
fullEmail: 'pavol@webgpt.cz',
|
|
12
|
+
plus: [],
|
|
13
|
+
},
|
|
14
|
+
]),
|
|
15
|
+
).toEqual('pavol@webgpt.cz');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should work with simple emails', () => {
|
|
19
|
+
expect(
|
|
20
|
+
stringifyEmailAddresses([
|
|
21
|
+
{
|
|
22
|
+
fullName: null,
|
|
23
|
+
baseEmail: 'pavol@webgpt.cz',
|
|
24
|
+
fullEmail: 'pavol@webgpt.cz',
|
|
25
|
+
plus: [],
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
fullName: null,
|
|
29
|
+
baseEmail: 'jirka@webgpt.cz',
|
|
30
|
+
fullEmail: 'jirka@webgpt.cz',
|
|
31
|
+
plus: [],
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
fullName: null,
|
|
35
|
+
baseEmail: 'tomas@webgpt.cz',
|
|
36
|
+
fullEmail: 'tomas@webgpt.cz',
|
|
37
|
+
plus: [],
|
|
38
|
+
},
|
|
39
|
+
]),
|
|
40
|
+
).toEqual('pavol@webgpt.cz, jirka@webgpt.cz, tomas@webgpt.cz');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should work with fullname', () => {
|
|
44
|
+
expect(
|
|
45
|
+
stringifyEmailAddresses([
|
|
46
|
+
{
|
|
47
|
+
fullName: 'Pavol Hejný',
|
|
48
|
+
baseEmail: 'pavol@webgpt.cz',
|
|
49
|
+
fullEmail: 'pavol@webgpt.cz',
|
|
50
|
+
plus: [],
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
fullName: 'Jiří Jahn',
|
|
54
|
+
baseEmail: 'jirka@webgpt.cz',
|
|
55
|
+
fullEmail: 'jirka@webgpt.cz',
|
|
56
|
+
plus: [],
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
fullName: 'Tomáš Studeník',
|
|
60
|
+
baseEmail: 'tomas@webgpt.cz',
|
|
61
|
+
fullEmail: 'tomas@webgpt.cz',
|
|
62
|
+
plus: [],
|
|
63
|
+
},
|
|
64
|
+
]),
|
|
65
|
+
).toEqual('"Pavol Hejný" <pavol@webgpt.cz>, "Jiří Jahn" <jirka@webgpt.cz>, "Tomáš Studeník" <tomas@webgpt.cz>');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// TODO: [🎾] Implement and test here escaping
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* TODO: [🐫] This test fails because of aliased imports `import type { string_emails } from '@promptbook-local/types';`, fix it
|
|
74
|
+
*/
|
package/apps/agents-server/src/message-providers/email/_common/utils/stringifyEmailAddresses.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { string_emails } from '@promptbook-local/types';
|
|
2
|
+
import type { EmailAddress } from '../Email';
|
|
3
|
+
import { stringifyEmailAddress } from './stringifyEmailAddress';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Makes string email from multiple EmailAddress
|
|
7
|
+
*/
|
|
8
|
+
export function stringifyEmailAddresses(emailAddresses: Array<EmailAddress>): string_emails {
|
|
9
|
+
return emailAddresses.map((emailAddress) => stringifyEmailAddress(emailAddress)).join(', ');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* TODO: [🎾] Implement and test here escaping
|
|
14
|
+
*/
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { removeMarkdownFormatting } from '@promptbook-local/markdown-utils';
|
|
2
|
+
import type { really_any } from '@promptbook-local/types';
|
|
3
|
+
import sendgridEmailClient from '@sendgrid/mail';
|
|
4
|
+
import { marked } from 'marked';
|
|
5
|
+
import { MessageProvider } from '../../interfaces/MessageProvider';
|
|
6
|
+
import { OutboundEmail } from '../_common/Email';
|
|
7
|
+
import { parseEmailAddress } from '../_common/utils/parseEmailAddress';
|
|
8
|
+
|
|
9
|
+
export class SendgridMessageProvider implements MessageProvider {
|
|
10
|
+
constructor(private readonly apiKey: string) {
|
|
11
|
+
sendgridEmailClient.setApiKey(this.apiKey);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public async send(message: OutboundEmail): Promise<really_any> {
|
|
15
|
+
const sender = message.sender;
|
|
16
|
+
const recipients = (Array.isArray(message.recipients) ? message.recipients : [message.recipients]).filter(
|
|
17
|
+
Boolean,
|
|
18
|
+
) as really_any[];
|
|
19
|
+
|
|
20
|
+
const text = removeMarkdownFormatting(message.content);
|
|
21
|
+
const html = await marked.parse(message.content);
|
|
22
|
+
|
|
23
|
+
const { fullEmail, fullName } = parseEmailAddress(sender);
|
|
24
|
+
|
|
25
|
+
const response = await sendgridEmailClient.send({
|
|
26
|
+
from: {
|
|
27
|
+
email: fullEmail,
|
|
28
|
+
name: fullName || undefined,
|
|
29
|
+
},
|
|
30
|
+
to: recipients.map((r) => {
|
|
31
|
+
const { fullEmail, fullName } = parseEmailAddress(r.email || r.baseEmail || r);
|
|
32
|
+
return {
|
|
33
|
+
email: fullEmail,
|
|
34
|
+
name: r.name || fullName || undefined,
|
|
35
|
+
};
|
|
36
|
+
}),
|
|
37
|
+
subject: message.metadata?.subject || 'No Subject',
|
|
38
|
+
text,
|
|
39
|
+
html,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return response;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { removeMarkdownFormatting } from '@promptbook-local/markdown-utils';
|
|
2
|
+
import type { really_any } from '@promptbook-local/types';
|
|
3
|
+
import { marked } from 'marked';
|
|
4
|
+
// @ts-expect-error: Zeptomail types are not resolving correctly
|
|
5
|
+
import { SendMailClient } from 'zeptomail';
|
|
6
|
+
import { MessageProvider } from '../../interfaces/MessageProvider';
|
|
7
|
+
import { OutboundEmail } from '../_common/Email';
|
|
8
|
+
|
|
9
|
+
export class ZeptomailMessageProvider implements MessageProvider {
|
|
10
|
+
constructor(private readonly apiKey: string) {}
|
|
11
|
+
|
|
12
|
+
public async send(message: OutboundEmail): Promise<really_any> {
|
|
13
|
+
const client = new SendMailClient({ url: 'api.zeptomail.com/', token: this.apiKey });
|
|
14
|
+
|
|
15
|
+
const sender = message.sender as really_any;
|
|
16
|
+
const recipients = (Array.isArray(message.recipients) ? message.recipients : [message.recipients]).filter(
|
|
17
|
+
Boolean,
|
|
18
|
+
) as really_any[];
|
|
19
|
+
|
|
20
|
+
const textbody = removeMarkdownFormatting(message.content);
|
|
21
|
+
const htmlbody = await marked.parse(message.content);
|
|
22
|
+
|
|
23
|
+
const response = await client.sendMail({
|
|
24
|
+
from: {
|
|
25
|
+
address: sender.email || sender.baseEmail || sender,
|
|
26
|
+
name: sender.name || sender.fullName || undefined,
|
|
27
|
+
},
|
|
28
|
+
to: recipients.map((r) => ({
|
|
29
|
+
email_address: {
|
|
30
|
+
address: r.email || r.baseEmail || r,
|
|
31
|
+
name: r.name || r.fullName || undefined,
|
|
32
|
+
},
|
|
33
|
+
})),
|
|
34
|
+
subject: message.metadata?.subject || 'No Subject',
|
|
35
|
+
textbody,
|
|
36
|
+
htmlbody,
|
|
37
|
+
track_clicks: true,
|
|
38
|
+
track_opens: true,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return response;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { SendgridMessageProvider } from './email/sendgrid/SendgridMessageProvider';
|
|
2
|
+
import { ZeptomailMessageProvider } from './email/zeptomail/ZeptomailMessageProvider';
|
|
3
|
+
import { MessageProvider } from './interfaces/MessageProvider';
|
|
4
|
+
|
|
5
|
+
export const EMAIL_PROVIDERS: Record<string, MessageProvider> = {};
|
|
6
|
+
|
|
7
|
+
if (process.env.ZEPTOMAIL_API_KEY) {
|
|
8
|
+
EMAIL_PROVIDERS['ZEPTOMAIL'] = new ZeptomailMessageProvider(process.env.ZEPTOMAIL_API_KEY);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (process.env.SENDGRID_API_KEY) {
|
|
12
|
+
EMAIL_PROVIDERS['SENDGRID'] = new SendgridMessageProvider(process.env.SENDGRID_API_KEY);
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Message, really_any, string_email } from '@promptbook-local/types';
|
|
2
|
+
|
|
3
|
+
export type MessageProvider = {
|
|
4
|
+
/**
|
|
5
|
+
* Sends a message through the provider
|
|
6
|
+
*
|
|
7
|
+
* @param message The message to send
|
|
8
|
+
* @returns Raw response from the provider
|
|
9
|
+
*/
|
|
10
|
+
send(message: Message<string_email>): Promise<really_any>;
|
|
11
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { really_any } from '@promptbook-local/types';
|
|
2
|
+
import { $getTableName } from '../../database/$getTableName';
|
|
3
|
+
import { $provideSupabaseForServer } from '../../database/$provideSupabaseForServer';
|
|
4
|
+
import { EMAIL_PROVIDERS } from '../../message-providers';
|
|
5
|
+
import { OutboundEmail } from '../../message-providers/email/_common/Email';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Sends a message
|
|
9
|
+
*/
|
|
10
|
+
export async function sendMessage(message: OutboundEmail): Promise<void> {
|
|
11
|
+
const supabase = await $provideSupabaseForServer();
|
|
12
|
+
// @ts-expect-error: Tables are not yet in types
|
|
13
|
+
const messageTable = await $getTableName('Message');
|
|
14
|
+
// @ts-expect-error: Tables are not yet in types
|
|
15
|
+
const messageSendAttemptTable = await $getTableName('MessageSendAttempt');
|
|
16
|
+
|
|
17
|
+
// 1. Insert message
|
|
18
|
+
const { data: insertedMessage, error: insertError } = await supabase
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
.from(messageTable as any)
|
|
21
|
+
.insert({
|
|
22
|
+
channel: message.channel || 'UNKNOWN',
|
|
23
|
+
direction: message.direction || 'OUTBOUND',
|
|
24
|
+
sender: message.sender,
|
|
25
|
+
recipients: message.recipients,
|
|
26
|
+
content: message.content,
|
|
27
|
+
threadId: message.threadId,
|
|
28
|
+
metadata: message.metadata,
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
+
} as any)
|
|
31
|
+
.select()
|
|
32
|
+
.single();
|
|
33
|
+
|
|
34
|
+
if (insertError) {
|
|
35
|
+
throw new Error(`Failed to insert message: ${insertError.message}`);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!insertedMessage) {
|
|
39
|
+
throw new Error('Failed to insert message: No data returned');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 2. If outbound and email, try to send
|
|
43
|
+
if (message.direction === 'OUTBOUND' && message.channel === 'EMAIL') {
|
|
44
|
+
const providers = Object.keys(EMAIL_PROVIDERS);
|
|
45
|
+
|
|
46
|
+
if (providers.length === 0) {
|
|
47
|
+
console.warn('No email providers configured');
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let isSent = false;
|
|
52
|
+
|
|
53
|
+
for (const providerName of providers) {
|
|
54
|
+
const provider = EMAIL_PROVIDERS[providerName];
|
|
55
|
+
let isSuccessful = false;
|
|
56
|
+
let raw: really_any = null;
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
raw = await provider.send(message);
|
|
60
|
+
isSuccessful = true;
|
|
61
|
+
isSent = true;
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.error(`Failed to send email via ${providerName}`, error);
|
|
64
|
+
raw = { error: error instanceof Error ? error.message : String(error) };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 3. Log attempt
|
|
68
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
69
|
+
await supabase.from(messageSendAttemptTable as any).insert({
|
|
70
|
+
// @ts-expect-error: insertedMessage is any
|
|
71
|
+
messageId: insertedMessage.id,
|
|
72
|
+
providerName,
|
|
73
|
+
isSuccessful,
|
|
74
|
+
raw,
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
76
|
+
} as any);
|
|
77
|
+
|
|
78
|
+
if (isSuccessful) {
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!isSent) {
|
|
84
|
+
throw new Error('Failed to send email via any provider');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* TODO: !!!! Move to `message-providers` and rename `message-providers` -> `messages`
|
|
91
|
+
*/
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { describe, expect, it } from '@jest/globals';
|
|
2
|
+
import { filenameToPrompt } from './filenameToPrompt';
|
|
3
|
+
|
|
4
|
+
describe('how filenameToPrompt works', () => {
|
|
5
|
+
it('will convert filename with dashes', () => {
|
|
6
|
+
expect(filenameToPrompt('cat-sitting-on-keyboard.png')).toEqual('Cat sitting on keyboard');
|
|
7
|
+
expect(filenameToPrompt('hello-world.jpg')).toEqual('Hello world');
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('will convert filename with underscores', () => {
|
|
11
|
+
expect(filenameToPrompt('cat_sitting_on_keyboard.png')).toEqual('Cat sitting on keyboard');
|
|
12
|
+
expect(filenameToPrompt('hello_world.jpg')).toEqual('Hello world');
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('will convert filename with mixed separators', () => {
|
|
16
|
+
expect(filenameToPrompt('cat-sitting_on-keyboard.png')).toEqual('Cat sitting on keyboard');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('will handle single word filename', () => {
|
|
20
|
+
expect(filenameToPrompt('cat.png')).toEqual('Cat');
|
|
21
|
+
expect(filenameToPrompt('HELLO.jpg')).toEqual('HELLO');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('will handle filename without extension', () => {
|
|
25
|
+
expect(filenameToPrompt('cat-sitting-on-keyboard')).toEqual('Cat sitting on keyboard');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('will handle filename with multiple dots', () => {
|
|
29
|
+
expect(filenameToPrompt('cat.sitting.on.keyboard.png')).toEqual('Cat.sitting.on.keyboard');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('will handle capitalized words after first word', () => {
|
|
33
|
+
expect(filenameToPrompt('Cat-Sitting-On-Keyboard.png')).toEqual('Cat sitting on keyboard');
|
|
34
|
+
expect(filenameToPrompt('HELLO-WORLD.png')).toEqual('HELLO world');
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { capitalize } from '
|
|
1
|
+
import { capitalize } from '@promptbook/utils';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Converts a filename like "cat-sitting-on-keyboard.png" to a prompt like "Cat sitting on keyboard"
|
|
@@ -15,7 +15,11 @@ export function filenameToPrompt(filename: string): string {
|
|
|
15
15
|
|
|
16
16
|
// Capitalize each word
|
|
17
17
|
const words = withSpaces.split(' ');
|
|
18
|
-
const capitalizedWords = words.map(word => capitalize(word));
|
|
18
|
+
const capitalizedWords = words.map((word, index) => (index === 0 ? capitalize(word) : word.toLowerCase()));
|
|
19
19
|
|
|
20
20
|
return capitalizedWords.join(' ');
|
|
21
21
|
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* TODO: [🧠][🏰] Make standard normalization function exported from `@promptbook/utils`
|
|
25
|
+
*/
|
package/esm/index.es.js
CHANGED
|
@@ -47,7 +47,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
47
47
|
* @generated
|
|
48
48
|
* @see https://github.com/webgptorg/promptbook
|
|
49
49
|
*/
|
|
50
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.104.0-
|
|
50
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.104.0-4';
|
|
51
51
|
/**
|
|
52
52
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
53
53
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -3721,6 +3721,7 @@ class RemoteLlmExecutionTools {
|
|
|
3721
3721
|
}
|
|
3722
3722
|
}
|
|
3723
3723
|
/**
|
|
3724
|
+
* TODO: !!!! Deprecate pipeline server and all of its components
|
|
3724
3725
|
* TODO: Maybe use `$exportJson`
|
|
3725
3726
|
* TODO: [🧠][🛍] Maybe not `isAnonymous: boolean` BUT `mode: 'ANONYMOUS'|'COLLECTION'`
|
|
3726
3727
|
* TODO: [🍓] Allow to list compatible models with each variant
|
|
@@ -4249,6 +4250,9 @@ function cacheLlmTools(llmTools, options = {}) {
|
|
|
4249
4250
|
case 'EMBEDDING':
|
|
4250
4251
|
promptResult = await llmTools.callEmbeddingModel(prompt);
|
|
4251
4252
|
break variant;
|
|
4253
|
+
case 'IMAGE_GENERATION':
|
|
4254
|
+
promptResult = await llmTools.callImageGenerationModel(prompt);
|
|
4255
|
+
break variant;
|
|
4252
4256
|
// <- case [🤖]:
|
|
4253
4257
|
default:
|
|
4254
4258
|
throw new PipelineExecutionError(`Unknown model variant "${prompt.modelRequirements.modelVariant}"`);
|
|
@@ -4336,6 +4340,11 @@ function cacheLlmTools(llmTools, options = {}) {
|
|
|
4336
4340
|
return /* not await */ callCommonModel(prompt);
|
|
4337
4341
|
};
|
|
4338
4342
|
}
|
|
4343
|
+
if (llmTools.callImageGenerationModel !== undefined) {
|
|
4344
|
+
proxyTools.callImageGenerationModel = async (prompt) => {
|
|
4345
|
+
return /* not await */ callCommonModel(prompt);
|
|
4346
|
+
};
|
|
4347
|
+
}
|
|
4339
4348
|
// <- Note: [🤖]
|
|
4340
4349
|
return proxyTools;
|
|
4341
4350
|
}
|
|
@@ -4524,6 +4533,15 @@ function countUsage(llmTools) {
|
|
|
4524
4533
|
return promptResult;
|
|
4525
4534
|
};
|
|
4526
4535
|
}
|
|
4536
|
+
if (llmTools.callImageGenerationModel !== undefined) {
|
|
4537
|
+
proxyTools.callImageGenerationModel = async (prompt) => {
|
|
4538
|
+
// console.info('[🚕] callImageGenerationModel through countTotalUsage');
|
|
4539
|
+
const promptResult = await llmTools.callImageGenerationModel(prompt);
|
|
4540
|
+
totalUsage = addUsage(totalUsage, promptResult.usage);
|
|
4541
|
+
spending.next(promptResult.usage);
|
|
4542
|
+
return promptResult;
|
|
4543
|
+
};
|
|
4544
|
+
}
|
|
4527
4545
|
// <- Note: [🤖]
|
|
4528
4546
|
return proxyTools;
|
|
4529
4547
|
}
|
|
@@ -4646,6 +4664,12 @@ class MultipleLlmExecutionTools {
|
|
|
4646
4664
|
callEmbeddingModel(prompt) {
|
|
4647
4665
|
return this.callCommonModel(prompt);
|
|
4648
4666
|
}
|
|
4667
|
+
/**
|
|
4668
|
+
* Calls the best available embedding model
|
|
4669
|
+
*/
|
|
4670
|
+
callImageGenerationModel(prompt) {
|
|
4671
|
+
return this.callCommonModel(prompt);
|
|
4672
|
+
}
|
|
4649
4673
|
// <- Note: [🤖]
|
|
4650
4674
|
/**
|
|
4651
4675
|
* Calls the best available model
|
|
@@ -4672,6 +4696,11 @@ class MultipleLlmExecutionTools {
|
|
|
4672
4696
|
continue llm;
|
|
4673
4697
|
}
|
|
4674
4698
|
return await llmExecutionTools.callEmbeddingModel(prompt);
|
|
4699
|
+
case 'IMAGE_GENERATION':
|
|
4700
|
+
if (llmExecutionTools.callImageGenerationModel === undefined) {
|
|
4701
|
+
continue llm;
|
|
4702
|
+
}
|
|
4703
|
+
return await llmExecutionTools.callImageGenerationModel(prompt);
|
|
4675
4704
|
// <- case [🤖]:
|
|
4676
4705
|
default:
|
|
4677
4706
|
throw new UnexpectedError(`Unknown model variant "${prompt.modelRequirements.modelVariant}" in ${llmExecutionTools.title}`);
|
|
@@ -7594,8 +7623,9 @@ async function executeAttempts(options) {
|
|
|
7594
7623
|
$ongoingTaskResult.$resultString = $ongoingTaskResult.$completionResult.content;
|
|
7595
7624
|
break variant;
|
|
7596
7625
|
case 'EMBEDDING':
|
|
7626
|
+
case 'IMAGE_GENERATION':
|
|
7597
7627
|
throw new PipelineExecutionError(spaceTrim$1((block) => `
|
|
7598
|
-
|
|
7628
|
+
${modelRequirements.modelVariant} model can not be used in pipeline
|
|
7599
7629
|
|
|
7600
7630
|
This should be catched during parsing
|
|
7601
7631
|
|