@prompty/core 0.1.2
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/README.md +2 -0
- package/dist/index.d.mts +84 -0
- package/dist/index.d.ts +84 -0
- package/dist/index.js +354 -0
- package/dist/index.mjs +316 -0
- package/package.json +42 -0
package/README.md
ADDED
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
declare class PropertySettings {
|
|
2
|
+
type: string;
|
|
3
|
+
default: any;
|
|
4
|
+
description: string;
|
|
5
|
+
}
|
|
6
|
+
interface OpenAIModel {
|
|
7
|
+
type: "openai";
|
|
8
|
+
name: string;
|
|
9
|
+
organization?: string;
|
|
10
|
+
api_key: string;
|
|
11
|
+
base_url?: string;
|
|
12
|
+
}
|
|
13
|
+
interface AzureOpenAIModel {
|
|
14
|
+
type: "azure_openai";
|
|
15
|
+
api_version: string;
|
|
16
|
+
azure_deployment: string;
|
|
17
|
+
azure_endpoint: string;
|
|
18
|
+
api_key?: string;
|
|
19
|
+
}
|
|
20
|
+
interface MaasModel {
|
|
21
|
+
type: "serverless";
|
|
22
|
+
endpoint: string;
|
|
23
|
+
model: string;
|
|
24
|
+
api_key?: string;
|
|
25
|
+
}
|
|
26
|
+
type ModelConfiguration = OpenAIModel | AzureOpenAIModel | MaasModel;
|
|
27
|
+
declare class ModelSettings {
|
|
28
|
+
api: string;
|
|
29
|
+
configuration: ModelConfiguration;
|
|
30
|
+
parameters: any;
|
|
31
|
+
response: any;
|
|
32
|
+
}
|
|
33
|
+
declare class TemplateSettings {
|
|
34
|
+
type: string;
|
|
35
|
+
parser: string;
|
|
36
|
+
}
|
|
37
|
+
declare class Prompty {
|
|
38
|
+
name: string;
|
|
39
|
+
description: string;
|
|
40
|
+
authors: string[];
|
|
41
|
+
tags: string[];
|
|
42
|
+
version: string;
|
|
43
|
+
base: string;
|
|
44
|
+
basePrompty: Prompty;
|
|
45
|
+
model: ModelSettings;
|
|
46
|
+
sample: any;
|
|
47
|
+
input: {
|
|
48
|
+
[key: string]: PropertySettings;
|
|
49
|
+
};
|
|
50
|
+
output: {
|
|
51
|
+
[key: string]: PropertySettings;
|
|
52
|
+
};
|
|
53
|
+
template: TemplateSettings;
|
|
54
|
+
file: string;
|
|
55
|
+
content: string;
|
|
56
|
+
constructor(content: string);
|
|
57
|
+
static prepare(prompt: Prompty, inputs?: any): Promise<any>;
|
|
58
|
+
static load(filePath: string): Promise<any>;
|
|
59
|
+
static export(prompt: Prompty): string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
declare abstract class Invoker {
|
|
63
|
+
prompty: Prompty;
|
|
64
|
+
constructor(prompty?: Prompty);
|
|
65
|
+
abstract invoke(data: any): Promise<any>;
|
|
66
|
+
abstract invokeSync(data: any): any;
|
|
67
|
+
call(data: any): Promise<any>;
|
|
68
|
+
callSync(data: any): any;
|
|
69
|
+
}
|
|
70
|
+
type InvokerConstructor = new (prompty: Prompty) => Invoker;
|
|
71
|
+
type InvokerType = "renderer" | "parser" | "executor" | "processor";
|
|
72
|
+
declare class InvokerFactory {
|
|
73
|
+
private static _instance;
|
|
74
|
+
private _invokers;
|
|
75
|
+
register(type: InvokerType, name: string, invokerClass: InvokerConstructor): void;
|
|
76
|
+
create(type: InvokerType, name: string, prompty: Prompty): Invoker;
|
|
77
|
+
static getInstance(): InvokerFactory;
|
|
78
|
+
call(type: InvokerType, name: string, prompty: Prompty, data: any): Promise<any>;
|
|
79
|
+
callSync(type: InvokerType, name: string, prompty: Prompty, data: any): any;
|
|
80
|
+
toDict(): Record<string, Record<string, string>>;
|
|
81
|
+
toJson(): string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export { Invoker, InvokerFactory, type MaasModel, type ModelConfiguration, Prompty };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
declare class PropertySettings {
|
|
2
|
+
type: string;
|
|
3
|
+
default: any;
|
|
4
|
+
description: string;
|
|
5
|
+
}
|
|
6
|
+
interface OpenAIModel {
|
|
7
|
+
type: "openai";
|
|
8
|
+
name: string;
|
|
9
|
+
organization?: string;
|
|
10
|
+
api_key: string;
|
|
11
|
+
base_url?: string;
|
|
12
|
+
}
|
|
13
|
+
interface AzureOpenAIModel {
|
|
14
|
+
type: "azure_openai";
|
|
15
|
+
api_version: string;
|
|
16
|
+
azure_deployment: string;
|
|
17
|
+
azure_endpoint: string;
|
|
18
|
+
api_key?: string;
|
|
19
|
+
}
|
|
20
|
+
interface MaasModel {
|
|
21
|
+
type: "serverless";
|
|
22
|
+
endpoint: string;
|
|
23
|
+
model: string;
|
|
24
|
+
api_key?: string;
|
|
25
|
+
}
|
|
26
|
+
type ModelConfiguration = OpenAIModel | AzureOpenAIModel | MaasModel;
|
|
27
|
+
declare class ModelSettings {
|
|
28
|
+
api: string;
|
|
29
|
+
configuration: ModelConfiguration;
|
|
30
|
+
parameters: any;
|
|
31
|
+
response: any;
|
|
32
|
+
}
|
|
33
|
+
declare class TemplateSettings {
|
|
34
|
+
type: string;
|
|
35
|
+
parser: string;
|
|
36
|
+
}
|
|
37
|
+
declare class Prompty {
|
|
38
|
+
name: string;
|
|
39
|
+
description: string;
|
|
40
|
+
authors: string[];
|
|
41
|
+
tags: string[];
|
|
42
|
+
version: string;
|
|
43
|
+
base: string;
|
|
44
|
+
basePrompty: Prompty;
|
|
45
|
+
model: ModelSettings;
|
|
46
|
+
sample: any;
|
|
47
|
+
input: {
|
|
48
|
+
[key: string]: PropertySettings;
|
|
49
|
+
};
|
|
50
|
+
output: {
|
|
51
|
+
[key: string]: PropertySettings;
|
|
52
|
+
};
|
|
53
|
+
template: TemplateSettings;
|
|
54
|
+
file: string;
|
|
55
|
+
content: string;
|
|
56
|
+
constructor(content: string);
|
|
57
|
+
static prepare(prompt: Prompty, inputs?: any): Promise<any>;
|
|
58
|
+
static load(filePath: string): Promise<any>;
|
|
59
|
+
static export(prompt: Prompty): string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
declare abstract class Invoker {
|
|
63
|
+
prompty: Prompty;
|
|
64
|
+
constructor(prompty?: Prompty);
|
|
65
|
+
abstract invoke(data: any): Promise<any>;
|
|
66
|
+
abstract invokeSync(data: any): any;
|
|
67
|
+
call(data: any): Promise<any>;
|
|
68
|
+
callSync(data: any): any;
|
|
69
|
+
}
|
|
70
|
+
type InvokerConstructor = new (prompty: Prompty) => Invoker;
|
|
71
|
+
type InvokerType = "renderer" | "parser" | "executor" | "processor";
|
|
72
|
+
declare class InvokerFactory {
|
|
73
|
+
private static _instance;
|
|
74
|
+
private _invokers;
|
|
75
|
+
register(type: InvokerType, name: string, invokerClass: InvokerConstructor): void;
|
|
76
|
+
create(type: InvokerType, name: string, prompty: Prompty): Invoker;
|
|
77
|
+
static getInstance(): InvokerFactory;
|
|
78
|
+
call(type: InvokerType, name: string, prompty: Prompty, data: any): Promise<any>;
|
|
79
|
+
callSync(type: InvokerType, name: string, prompty: Prompty, data: any): any;
|
|
80
|
+
toDict(): Record<string, Record<string, string>>;
|
|
81
|
+
toJson(): string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export { Invoker, InvokerFactory, type MaasModel, type ModelConfiguration, Prompty };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
|
|
29
|
+
// src/index.ts
|
|
30
|
+
var src_exports = {};
|
|
31
|
+
__export(src_exports, {
|
|
32
|
+
Invoker: () => Invoker,
|
|
33
|
+
InvokerFactory: () => InvokerFactory,
|
|
34
|
+
Prompty: () => Prompty
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(src_exports);
|
|
37
|
+
|
|
38
|
+
// src/core.ts
|
|
39
|
+
var import_gray_matter = __toESM(require("gray-matter"));
|
|
40
|
+
|
|
41
|
+
// src/utils.ts
|
|
42
|
+
var fs = __toESM(require("fs/promises"));
|
|
43
|
+
var _utils = class _utils {
|
|
44
|
+
static async readFileSafe(filePath, encoding = "utf-8") {
|
|
45
|
+
if (_utils.isNode) {
|
|
46
|
+
const data = await fs.readFile(filePath, encoding);
|
|
47
|
+
return data;
|
|
48
|
+
} else {
|
|
49
|
+
throw new Error("Load from file not supported in browser");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
static paramHoisting(top, bottom, topKey = null) {
|
|
53
|
+
let newDict = {};
|
|
54
|
+
if (topKey) {
|
|
55
|
+
newDict = topKey in top ? { ...top[topKey] } : {};
|
|
56
|
+
} else {
|
|
57
|
+
newDict = { ...top };
|
|
58
|
+
}
|
|
59
|
+
for (const key in bottom) {
|
|
60
|
+
if (!(key in newDict)) {
|
|
61
|
+
newDict[key] = bottom[key];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return newDict;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
_utils.isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
|
|
68
|
+
var utils = _utils;
|
|
69
|
+
|
|
70
|
+
// src/invokerFactory.ts
|
|
71
|
+
var Invoker = class {
|
|
72
|
+
constructor(prompty) {
|
|
73
|
+
this.prompty = prompty;
|
|
74
|
+
}
|
|
75
|
+
async call(data) {
|
|
76
|
+
return await this.invoke(data);
|
|
77
|
+
}
|
|
78
|
+
callSync(data) {
|
|
79
|
+
return this.invokeSync(data);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
var NoOpInvoker = class extends Invoker {
|
|
83
|
+
async invoke(data) {
|
|
84
|
+
return Promise.resolve(data);
|
|
85
|
+
}
|
|
86
|
+
invokeSync(data) {
|
|
87
|
+
return data;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
var InvokerFactory = class _InvokerFactory {
|
|
91
|
+
constructor() {
|
|
92
|
+
this._invokers = {
|
|
93
|
+
renderer: { ["NOOP"]: NoOpInvoker },
|
|
94
|
+
parser: { ["NOOP"]: NoOpInvoker },
|
|
95
|
+
executor: { ["NOOP"]: NoOpInvoker },
|
|
96
|
+
processor: { ["NOOP"]: NoOpInvoker }
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
register(type, name, invokerClass) {
|
|
100
|
+
if (!this._invokers[type]) {
|
|
101
|
+
throw new Error(`Invalid invoker type: ${type}`);
|
|
102
|
+
}
|
|
103
|
+
this._invokers[type][name] = invokerClass;
|
|
104
|
+
}
|
|
105
|
+
create(type, name, prompty) {
|
|
106
|
+
const invokerClass = this._invokers[type][name];
|
|
107
|
+
if (!invokerClass) {
|
|
108
|
+
throw new Error(`No registered ${type} for name: ${name}`);
|
|
109
|
+
}
|
|
110
|
+
return new invokerClass(prompty);
|
|
111
|
+
}
|
|
112
|
+
static getInstance() {
|
|
113
|
+
if (!this._instance) {
|
|
114
|
+
this._instance = new _InvokerFactory();
|
|
115
|
+
}
|
|
116
|
+
return this._instance;
|
|
117
|
+
}
|
|
118
|
+
async call(type, name, prompty, data) {
|
|
119
|
+
return await this.create(type, name, prompty).call(data);
|
|
120
|
+
}
|
|
121
|
+
callSync(type, name, prompty, data) {
|
|
122
|
+
return this.create(type, name, prompty).callSync(data);
|
|
123
|
+
}
|
|
124
|
+
toDict() {
|
|
125
|
+
const dict = {};
|
|
126
|
+
for (const [type, invokers] of Object.entries(this._invokers)) {
|
|
127
|
+
dict[type] = Object.fromEntries(
|
|
128
|
+
Object.entries(invokers).map(([key, value]) => [key, value.name])
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
return dict;
|
|
132
|
+
}
|
|
133
|
+
toJson() {
|
|
134
|
+
return JSON.stringify(this.toDict());
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// src/parsers.ts
|
|
139
|
+
var path = __toESM(require("path"));
|
|
140
|
+
var PromptyChatParser = class extends Invoker {
|
|
141
|
+
constructor(prompty) {
|
|
142
|
+
super(prompty);
|
|
143
|
+
this.roles = ["assistant", "function", "system", "user"];
|
|
144
|
+
}
|
|
145
|
+
async inlineImage(imageItem) {
|
|
146
|
+
if (imageItem.startsWith("http") || imageItem.startsWith("data")) {
|
|
147
|
+
return imageItem;
|
|
148
|
+
} else {
|
|
149
|
+
if (utils.isNode) {
|
|
150
|
+
const imagePath = path.join(path.dirname(this.prompty.file), imageItem);
|
|
151
|
+
const fileContent = await utils.readFileSafe(imagePath, "base64");
|
|
152
|
+
const extension = path.extname(imagePath).toLowerCase();
|
|
153
|
+
switch (extension) {
|
|
154
|
+
case ".png":
|
|
155
|
+
return `data:image/png;base64,${fileContent}`;
|
|
156
|
+
case ".jpg":
|
|
157
|
+
case ".jpeg":
|
|
158
|
+
return `data:image/jpeg;base64,${fileContent}`;
|
|
159
|
+
default:
|
|
160
|
+
throw new Error(`Invalid image format ${extension} - currently only .png and .jpg/.jpeg are supported.`);
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
throw new Error("Load from file not supported in browser");
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async parseContent(content, role) {
|
|
168
|
+
const imageRegex = /!\[(.*?)\]\((.*?)\)/gm;
|
|
169
|
+
let matches;
|
|
170
|
+
let contentItems = [];
|
|
171
|
+
let contentChunks = content.split(imageRegex);
|
|
172
|
+
for (let index = 0; index < contentChunks.length; index++) {
|
|
173
|
+
const chunk = contentChunks[index];
|
|
174
|
+
if (index % 3 === 0 && chunk.trim()) {
|
|
175
|
+
contentItems.push({ type: "text", text: chunk.trim() });
|
|
176
|
+
} else if (index % 3 === 2) {
|
|
177
|
+
const base64Str = await this.inlineImage(chunk.split(" ")[0].trim());
|
|
178
|
+
let msg = {
|
|
179
|
+
type: "image_url",
|
|
180
|
+
image_url: { url: base64Str }
|
|
181
|
+
};
|
|
182
|
+
contentItems.push(msg);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return contentItems;
|
|
186
|
+
}
|
|
187
|
+
invokeSync(data) {
|
|
188
|
+
throw new Error("Not Supported");
|
|
189
|
+
}
|
|
190
|
+
async invoke(data) {
|
|
191
|
+
let messages = [];
|
|
192
|
+
const separator = new RegExp(`\\s*#?\\s*(${this.roles.join("|")})\\s*:\\s*\\n`, "im");
|
|
193
|
+
let chunks = data.split(separator).filter((chunk) => chunk.trim());
|
|
194
|
+
if (!this.roles.includes(chunks[0].trim().toLowerCase())) {
|
|
195
|
+
chunks.unshift("system");
|
|
196
|
+
}
|
|
197
|
+
if (this.roles.includes(chunks[chunks.length - 1].trim().toLowerCase())) {
|
|
198
|
+
chunks.pop();
|
|
199
|
+
}
|
|
200
|
+
if (chunks.length % 2 !== 0) {
|
|
201
|
+
throw new Error("Invalid prompt format");
|
|
202
|
+
}
|
|
203
|
+
for (let i = 0; i < chunks.length; i += 2) {
|
|
204
|
+
const role = chunks[i].trim().toLowerCase();
|
|
205
|
+
const content = chunks[i + 1].trim();
|
|
206
|
+
const parsedContent = await this.parseContent(content, role);
|
|
207
|
+
messages.push({ role, content: parsedContent });
|
|
208
|
+
}
|
|
209
|
+
return messages;
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
var factory = InvokerFactory.getInstance();
|
|
213
|
+
factory.register("parser", "prompty.chat", PromptyChatParser);
|
|
214
|
+
factory.register("parser", "prompty.embedding", NoOpInvoker);
|
|
215
|
+
factory.register("parser", "prompty.image", NoOpInvoker);
|
|
216
|
+
factory.register("parser", "prompty.completion", NoOpInvoker);
|
|
217
|
+
|
|
218
|
+
// src/renderers.ts
|
|
219
|
+
var nunjucks = __toESM(require("nunjucks"));
|
|
220
|
+
var mustache = __toESM(require("mustache"));
|
|
221
|
+
var NunjucksRenderer = class extends Invoker {
|
|
222
|
+
constructor() {
|
|
223
|
+
super(...arguments);
|
|
224
|
+
this.templates = {};
|
|
225
|
+
}
|
|
226
|
+
async invoke(data) {
|
|
227
|
+
return Promise.resolve(this.invokeSync(data));
|
|
228
|
+
}
|
|
229
|
+
invokeSync(data) {
|
|
230
|
+
return nunjucks.renderString(this.prompty.content, data);
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
var MustacheRenderer = class extends Invoker {
|
|
234
|
+
constructor() {
|
|
235
|
+
super(...arguments);
|
|
236
|
+
this.templates = {};
|
|
237
|
+
}
|
|
238
|
+
async invoke(data) {
|
|
239
|
+
return Promise.resolve(this.invokeSync(data));
|
|
240
|
+
}
|
|
241
|
+
invokeSync(data) {
|
|
242
|
+
return mustache.render(this.prompty.content, data);
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
var factory2 = InvokerFactory.getInstance();
|
|
246
|
+
factory2.register("renderer", "jinja2", NunjucksRenderer);
|
|
247
|
+
factory2.register("renderer", "mustache", MustacheRenderer);
|
|
248
|
+
|
|
249
|
+
// src/core.ts
|
|
250
|
+
var yaml = __toESM(require("js-yaml"));
|
|
251
|
+
var ModelSettings = class {
|
|
252
|
+
constructor() {
|
|
253
|
+
this.api = "chat";
|
|
254
|
+
this.configuration = {};
|
|
255
|
+
this.parameters = {};
|
|
256
|
+
this.response = {};
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
var TemplateSettings = class {
|
|
260
|
+
constructor() {
|
|
261
|
+
this.type = "jinja2";
|
|
262
|
+
this.parser = "prompty";
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
var Prompty = class _Prompty {
|
|
266
|
+
constructor(content) {
|
|
267
|
+
// metadata
|
|
268
|
+
this.name = "";
|
|
269
|
+
this.description = "";
|
|
270
|
+
this.authors = [];
|
|
271
|
+
this.tags = [];
|
|
272
|
+
this.version = "";
|
|
273
|
+
this.base = "";
|
|
274
|
+
this.basePrompty = null;
|
|
275
|
+
// model
|
|
276
|
+
this.model = new ModelSettings();
|
|
277
|
+
// sample
|
|
278
|
+
this.sample = {};
|
|
279
|
+
// input / output
|
|
280
|
+
this.input = {};
|
|
281
|
+
this.output = {};
|
|
282
|
+
// template
|
|
283
|
+
this.template = new TemplateSettings();
|
|
284
|
+
// misc
|
|
285
|
+
this.file = "";
|
|
286
|
+
this.content = "";
|
|
287
|
+
var _a, _b, _c, _d, _e, _f;
|
|
288
|
+
const items = (0, import_gray_matter.default)(content);
|
|
289
|
+
this.name = items.data.name || "";
|
|
290
|
+
this.description = items.data.description || "";
|
|
291
|
+
this.authors = items.data.authors || [];
|
|
292
|
+
this.tags = items.data.tags || [];
|
|
293
|
+
this.version = items.data.version || "";
|
|
294
|
+
this.base = items.data.base || "";
|
|
295
|
+
this.model.api = ((_a = items.data.model) == null ? void 0 : _a.api) || "chat";
|
|
296
|
+
this.model.configuration = ((_b = items.data.model) == null ? void 0 : _b.configuration) || {};
|
|
297
|
+
this.model.parameters = ((_c = items.data.model) == null ? void 0 : _c.parameters) || {};
|
|
298
|
+
this.model.response = ((_d = items.data.model) == null ? void 0 : _d.response) || {};
|
|
299
|
+
this.sample = items.data.sample || {};
|
|
300
|
+
this.input = items.data.input || {};
|
|
301
|
+
this.output = items.data.output || {};
|
|
302
|
+
if (items.data.template && typeof items.data.template === "string") {
|
|
303
|
+
this.template.type = items.data.template || this.template.type;
|
|
304
|
+
} else {
|
|
305
|
+
this.template.type = ((_e = items.data.template) == null ? void 0 : _e.type) || this.template.type;
|
|
306
|
+
this.template.parser = ((_f = items.data.template) == null ? void 0 : _f.parser) || this.template.parser;
|
|
307
|
+
}
|
|
308
|
+
this.file = content;
|
|
309
|
+
this.content = items.content;
|
|
310
|
+
}
|
|
311
|
+
static async prepare(prompt, inputs = {}) {
|
|
312
|
+
const invoker = InvokerFactory.getInstance();
|
|
313
|
+
inputs = utils.paramHoisting(inputs, prompt.sample);
|
|
314
|
+
let render2;
|
|
315
|
+
if (prompt.template.type === "NOOP") {
|
|
316
|
+
render2 = prompt.content;
|
|
317
|
+
} else {
|
|
318
|
+
render2 = await invoker.call("renderer", prompt.template.type, prompt, inputs);
|
|
319
|
+
}
|
|
320
|
+
let result;
|
|
321
|
+
if (prompt.template.parser === "NOOP") {
|
|
322
|
+
result = render2;
|
|
323
|
+
} else {
|
|
324
|
+
result = await invoker.call("parser", `${prompt.template.parser}.${prompt.model.api}`, prompt, render2);
|
|
325
|
+
}
|
|
326
|
+
return result;
|
|
327
|
+
}
|
|
328
|
+
static async load(filePath) {
|
|
329
|
+
return new _Prompty(await utils.readFileSafe(filePath));
|
|
330
|
+
}
|
|
331
|
+
static export(prompt) {
|
|
332
|
+
const front_matter = {
|
|
333
|
+
name: prompt.name,
|
|
334
|
+
description: prompt.description,
|
|
335
|
+
authors: prompt.authors,
|
|
336
|
+
tags: prompt.tags,
|
|
337
|
+
version: prompt.version,
|
|
338
|
+
base: prompt.base,
|
|
339
|
+
model: prompt.model,
|
|
340
|
+
sample: prompt.sample,
|
|
341
|
+
input: prompt.input,
|
|
342
|
+
output: prompt.output,
|
|
343
|
+
template: prompt.template
|
|
344
|
+
};
|
|
345
|
+
const yaml_str = "---\r\n" + yaml.dump(front_matter) + "---\r\n" + prompt.content;
|
|
346
|
+
return yaml_str;
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
350
|
+
0 && (module.exports = {
|
|
351
|
+
Invoker,
|
|
352
|
+
InvokerFactory,
|
|
353
|
+
Prompty
|
|
354
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
// src/core.ts
|
|
2
|
+
import matter from "gray-matter";
|
|
3
|
+
|
|
4
|
+
// src/utils.ts
|
|
5
|
+
import * as fs from "fs/promises";
|
|
6
|
+
var _utils = class _utils {
|
|
7
|
+
static async readFileSafe(filePath, encoding = "utf-8") {
|
|
8
|
+
if (_utils.isNode) {
|
|
9
|
+
const data = await fs.readFile(filePath, encoding);
|
|
10
|
+
return data;
|
|
11
|
+
} else {
|
|
12
|
+
throw new Error("Load from file not supported in browser");
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
static paramHoisting(top, bottom, topKey = null) {
|
|
16
|
+
let newDict = {};
|
|
17
|
+
if (topKey) {
|
|
18
|
+
newDict = topKey in top ? { ...top[topKey] } : {};
|
|
19
|
+
} else {
|
|
20
|
+
newDict = { ...top };
|
|
21
|
+
}
|
|
22
|
+
for (const key in bottom) {
|
|
23
|
+
if (!(key in newDict)) {
|
|
24
|
+
newDict[key] = bottom[key];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return newDict;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
_utils.isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null;
|
|
31
|
+
var utils = _utils;
|
|
32
|
+
|
|
33
|
+
// src/invokerFactory.ts
|
|
34
|
+
var Invoker = class {
|
|
35
|
+
constructor(prompty) {
|
|
36
|
+
this.prompty = prompty;
|
|
37
|
+
}
|
|
38
|
+
async call(data) {
|
|
39
|
+
return await this.invoke(data);
|
|
40
|
+
}
|
|
41
|
+
callSync(data) {
|
|
42
|
+
return this.invokeSync(data);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
var NoOpInvoker = class extends Invoker {
|
|
46
|
+
async invoke(data) {
|
|
47
|
+
return Promise.resolve(data);
|
|
48
|
+
}
|
|
49
|
+
invokeSync(data) {
|
|
50
|
+
return data;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
var InvokerFactory = class _InvokerFactory {
|
|
54
|
+
constructor() {
|
|
55
|
+
this._invokers = {
|
|
56
|
+
renderer: { ["NOOP"]: NoOpInvoker },
|
|
57
|
+
parser: { ["NOOP"]: NoOpInvoker },
|
|
58
|
+
executor: { ["NOOP"]: NoOpInvoker },
|
|
59
|
+
processor: { ["NOOP"]: NoOpInvoker }
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
register(type, name, invokerClass) {
|
|
63
|
+
if (!this._invokers[type]) {
|
|
64
|
+
throw new Error(`Invalid invoker type: ${type}`);
|
|
65
|
+
}
|
|
66
|
+
this._invokers[type][name] = invokerClass;
|
|
67
|
+
}
|
|
68
|
+
create(type, name, prompty) {
|
|
69
|
+
const invokerClass = this._invokers[type][name];
|
|
70
|
+
if (!invokerClass) {
|
|
71
|
+
throw new Error(`No registered ${type} for name: ${name}`);
|
|
72
|
+
}
|
|
73
|
+
return new invokerClass(prompty);
|
|
74
|
+
}
|
|
75
|
+
static getInstance() {
|
|
76
|
+
if (!this._instance) {
|
|
77
|
+
this._instance = new _InvokerFactory();
|
|
78
|
+
}
|
|
79
|
+
return this._instance;
|
|
80
|
+
}
|
|
81
|
+
async call(type, name, prompty, data) {
|
|
82
|
+
return await this.create(type, name, prompty).call(data);
|
|
83
|
+
}
|
|
84
|
+
callSync(type, name, prompty, data) {
|
|
85
|
+
return this.create(type, name, prompty).callSync(data);
|
|
86
|
+
}
|
|
87
|
+
toDict() {
|
|
88
|
+
const dict = {};
|
|
89
|
+
for (const [type, invokers] of Object.entries(this._invokers)) {
|
|
90
|
+
dict[type] = Object.fromEntries(
|
|
91
|
+
Object.entries(invokers).map(([key, value]) => [key, value.name])
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
return dict;
|
|
95
|
+
}
|
|
96
|
+
toJson() {
|
|
97
|
+
return JSON.stringify(this.toDict());
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// src/parsers.ts
|
|
102
|
+
import * as path from "path";
|
|
103
|
+
var PromptyChatParser = class extends Invoker {
|
|
104
|
+
constructor(prompty) {
|
|
105
|
+
super(prompty);
|
|
106
|
+
this.roles = ["assistant", "function", "system", "user"];
|
|
107
|
+
}
|
|
108
|
+
async inlineImage(imageItem) {
|
|
109
|
+
if (imageItem.startsWith("http") || imageItem.startsWith("data")) {
|
|
110
|
+
return imageItem;
|
|
111
|
+
} else {
|
|
112
|
+
if (utils.isNode) {
|
|
113
|
+
const imagePath = path.join(path.dirname(this.prompty.file), imageItem);
|
|
114
|
+
const fileContent = await utils.readFileSafe(imagePath, "base64");
|
|
115
|
+
const extension = path.extname(imagePath).toLowerCase();
|
|
116
|
+
switch (extension) {
|
|
117
|
+
case ".png":
|
|
118
|
+
return `data:image/png;base64,${fileContent}`;
|
|
119
|
+
case ".jpg":
|
|
120
|
+
case ".jpeg":
|
|
121
|
+
return `data:image/jpeg;base64,${fileContent}`;
|
|
122
|
+
default:
|
|
123
|
+
throw new Error(`Invalid image format ${extension} - currently only .png and .jpg/.jpeg are supported.`);
|
|
124
|
+
}
|
|
125
|
+
} else {
|
|
126
|
+
throw new Error("Load from file not supported in browser");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async parseContent(content, role) {
|
|
131
|
+
const imageRegex = /!\[(.*?)\]\((.*?)\)/gm;
|
|
132
|
+
let matches;
|
|
133
|
+
let contentItems = [];
|
|
134
|
+
let contentChunks = content.split(imageRegex);
|
|
135
|
+
for (let index = 0; index < contentChunks.length; index++) {
|
|
136
|
+
const chunk = contentChunks[index];
|
|
137
|
+
if (index % 3 === 0 && chunk.trim()) {
|
|
138
|
+
contentItems.push({ type: "text", text: chunk.trim() });
|
|
139
|
+
} else if (index % 3 === 2) {
|
|
140
|
+
const base64Str = await this.inlineImage(chunk.split(" ")[0].trim());
|
|
141
|
+
let msg = {
|
|
142
|
+
type: "image_url",
|
|
143
|
+
image_url: { url: base64Str }
|
|
144
|
+
};
|
|
145
|
+
contentItems.push(msg);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return contentItems;
|
|
149
|
+
}
|
|
150
|
+
invokeSync(data) {
|
|
151
|
+
throw new Error("Not Supported");
|
|
152
|
+
}
|
|
153
|
+
async invoke(data) {
|
|
154
|
+
let messages = [];
|
|
155
|
+
const separator = new RegExp(`\\s*#?\\s*(${this.roles.join("|")})\\s*:\\s*\\n`, "im");
|
|
156
|
+
let chunks = data.split(separator).filter((chunk) => chunk.trim());
|
|
157
|
+
if (!this.roles.includes(chunks[0].trim().toLowerCase())) {
|
|
158
|
+
chunks.unshift("system");
|
|
159
|
+
}
|
|
160
|
+
if (this.roles.includes(chunks[chunks.length - 1].trim().toLowerCase())) {
|
|
161
|
+
chunks.pop();
|
|
162
|
+
}
|
|
163
|
+
if (chunks.length % 2 !== 0) {
|
|
164
|
+
throw new Error("Invalid prompt format");
|
|
165
|
+
}
|
|
166
|
+
for (let i = 0; i < chunks.length; i += 2) {
|
|
167
|
+
const role = chunks[i].trim().toLowerCase();
|
|
168
|
+
const content = chunks[i + 1].trim();
|
|
169
|
+
const parsedContent = await this.parseContent(content, role);
|
|
170
|
+
messages.push({ role, content: parsedContent });
|
|
171
|
+
}
|
|
172
|
+
return messages;
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
var factory = InvokerFactory.getInstance();
|
|
176
|
+
factory.register("parser", "prompty.chat", PromptyChatParser);
|
|
177
|
+
factory.register("parser", "prompty.embedding", NoOpInvoker);
|
|
178
|
+
factory.register("parser", "prompty.image", NoOpInvoker);
|
|
179
|
+
factory.register("parser", "prompty.completion", NoOpInvoker);
|
|
180
|
+
|
|
181
|
+
// src/renderers.ts
|
|
182
|
+
import * as nunjucks from "nunjucks";
|
|
183
|
+
import * as mustache from "mustache";
|
|
184
|
+
var NunjucksRenderer = class extends Invoker {
|
|
185
|
+
constructor() {
|
|
186
|
+
super(...arguments);
|
|
187
|
+
this.templates = {};
|
|
188
|
+
}
|
|
189
|
+
async invoke(data) {
|
|
190
|
+
return Promise.resolve(this.invokeSync(data));
|
|
191
|
+
}
|
|
192
|
+
invokeSync(data) {
|
|
193
|
+
return nunjucks.renderString(this.prompty.content, data);
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
var MustacheRenderer = class extends Invoker {
|
|
197
|
+
constructor() {
|
|
198
|
+
super(...arguments);
|
|
199
|
+
this.templates = {};
|
|
200
|
+
}
|
|
201
|
+
async invoke(data) {
|
|
202
|
+
return Promise.resolve(this.invokeSync(data));
|
|
203
|
+
}
|
|
204
|
+
invokeSync(data) {
|
|
205
|
+
return mustache.render(this.prompty.content, data);
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
var factory2 = InvokerFactory.getInstance();
|
|
209
|
+
factory2.register("renderer", "jinja2", NunjucksRenderer);
|
|
210
|
+
factory2.register("renderer", "mustache", MustacheRenderer);
|
|
211
|
+
|
|
212
|
+
// src/core.ts
|
|
213
|
+
import * as yaml from "js-yaml";
|
|
214
|
+
var ModelSettings = class {
|
|
215
|
+
constructor() {
|
|
216
|
+
this.api = "chat";
|
|
217
|
+
this.configuration = {};
|
|
218
|
+
this.parameters = {};
|
|
219
|
+
this.response = {};
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
var TemplateSettings = class {
|
|
223
|
+
constructor() {
|
|
224
|
+
this.type = "jinja2";
|
|
225
|
+
this.parser = "prompty";
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
var Prompty = class _Prompty {
|
|
229
|
+
constructor(content) {
|
|
230
|
+
// metadata
|
|
231
|
+
this.name = "";
|
|
232
|
+
this.description = "";
|
|
233
|
+
this.authors = [];
|
|
234
|
+
this.tags = [];
|
|
235
|
+
this.version = "";
|
|
236
|
+
this.base = "";
|
|
237
|
+
this.basePrompty = null;
|
|
238
|
+
// model
|
|
239
|
+
this.model = new ModelSettings();
|
|
240
|
+
// sample
|
|
241
|
+
this.sample = {};
|
|
242
|
+
// input / output
|
|
243
|
+
this.input = {};
|
|
244
|
+
this.output = {};
|
|
245
|
+
// template
|
|
246
|
+
this.template = new TemplateSettings();
|
|
247
|
+
// misc
|
|
248
|
+
this.file = "";
|
|
249
|
+
this.content = "";
|
|
250
|
+
var _a, _b, _c, _d, _e, _f;
|
|
251
|
+
const items = matter(content);
|
|
252
|
+
this.name = items.data.name || "";
|
|
253
|
+
this.description = items.data.description || "";
|
|
254
|
+
this.authors = items.data.authors || [];
|
|
255
|
+
this.tags = items.data.tags || [];
|
|
256
|
+
this.version = items.data.version || "";
|
|
257
|
+
this.base = items.data.base || "";
|
|
258
|
+
this.model.api = ((_a = items.data.model) == null ? void 0 : _a.api) || "chat";
|
|
259
|
+
this.model.configuration = ((_b = items.data.model) == null ? void 0 : _b.configuration) || {};
|
|
260
|
+
this.model.parameters = ((_c = items.data.model) == null ? void 0 : _c.parameters) || {};
|
|
261
|
+
this.model.response = ((_d = items.data.model) == null ? void 0 : _d.response) || {};
|
|
262
|
+
this.sample = items.data.sample || {};
|
|
263
|
+
this.input = items.data.input || {};
|
|
264
|
+
this.output = items.data.output || {};
|
|
265
|
+
if (items.data.template && typeof items.data.template === "string") {
|
|
266
|
+
this.template.type = items.data.template || this.template.type;
|
|
267
|
+
} else {
|
|
268
|
+
this.template.type = ((_e = items.data.template) == null ? void 0 : _e.type) || this.template.type;
|
|
269
|
+
this.template.parser = ((_f = items.data.template) == null ? void 0 : _f.parser) || this.template.parser;
|
|
270
|
+
}
|
|
271
|
+
this.file = content;
|
|
272
|
+
this.content = items.content;
|
|
273
|
+
}
|
|
274
|
+
static async prepare(prompt, inputs = {}) {
|
|
275
|
+
const invoker = InvokerFactory.getInstance();
|
|
276
|
+
inputs = utils.paramHoisting(inputs, prompt.sample);
|
|
277
|
+
let render2;
|
|
278
|
+
if (prompt.template.type === "NOOP") {
|
|
279
|
+
render2 = prompt.content;
|
|
280
|
+
} else {
|
|
281
|
+
render2 = await invoker.call("renderer", prompt.template.type, prompt, inputs);
|
|
282
|
+
}
|
|
283
|
+
let result;
|
|
284
|
+
if (prompt.template.parser === "NOOP") {
|
|
285
|
+
result = render2;
|
|
286
|
+
} else {
|
|
287
|
+
result = await invoker.call("parser", `${prompt.template.parser}.${prompt.model.api}`, prompt, render2);
|
|
288
|
+
}
|
|
289
|
+
return result;
|
|
290
|
+
}
|
|
291
|
+
static async load(filePath) {
|
|
292
|
+
return new _Prompty(await utils.readFileSafe(filePath));
|
|
293
|
+
}
|
|
294
|
+
static export(prompt) {
|
|
295
|
+
const front_matter = {
|
|
296
|
+
name: prompt.name,
|
|
297
|
+
description: prompt.description,
|
|
298
|
+
authors: prompt.authors,
|
|
299
|
+
tags: prompt.tags,
|
|
300
|
+
version: prompt.version,
|
|
301
|
+
base: prompt.base,
|
|
302
|
+
model: prompt.model,
|
|
303
|
+
sample: prompt.sample,
|
|
304
|
+
input: prompt.input,
|
|
305
|
+
output: prompt.output,
|
|
306
|
+
template: prompt.template
|
|
307
|
+
};
|
|
308
|
+
const yaml_str = "---\r\n" + yaml.dump(front_matter) + "---\r\n" + prompt.content;
|
|
309
|
+
return yaml_str;
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
export {
|
|
313
|
+
Invoker,
|
|
314
|
+
InvokerFactory,
|
|
315
|
+
Prompty
|
|
316
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@prompty/core",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Prompty core package",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"/dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"test": "jest",
|
|
13
|
+
"test:watch": "jest --watch",
|
|
14
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
15
|
+
"dev": "npm run build -- --watch",
|
|
16
|
+
"publish-packages": "turbo run build lint test && changeset version && changeset publish --access public"
|
|
17
|
+
},
|
|
18
|
+
"author": "",
|
|
19
|
+
"license": "ISC",
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@changesets/cli": "^2.27.1",
|
|
22
|
+
"@types/base-64": "^1.0.2",
|
|
23
|
+
"@types/jest": "^29.5.12",
|
|
24
|
+
"@types/js-yaml": "^4.0.9",
|
|
25
|
+
"@types/node": "^20.11.24",
|
|
26
|
+
"@types/nunjucks": "^3.2.6",
|
|
27
|
+
"jest": "^29.7.0",
|
|
28
|
+
"puppeteer": "^22.6.4",
|
|
29
|
+
"ts-jest": "^29.1.2",
|
|
30
|
+
"tsup": "^8.0.2",
|
|
31
|
+
"typescript": "5.2.2"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@types/mustache": "^4.2.5",
|
|
35
|
+
"base-64": "^1.0.0",
|
|
36
|
+
"gray-matter": "^4.0.3",
|
|
37
|
+
"js-yaml": "^4.1.0",
|
|
38
|
+
"mustache": "^4.2.0",
|
|
39
|
+
"nunjucks": "^3.2.4",
|
|
40
|
+
"openai": "^4.33.0"
|
|
41
|
+
}
|
|
42
|
+
}
|