@bedrockio/ai 0.2.0 → 0.3.0

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/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ## 0.3.0
2
+
3
+ - Added MultiClient.
4
+ - Allow partial template interpolation.
5
+ - Changed default openai model to `gpt-4o-mini`.
6
+ - Allow passing in specific `params` object.
7
+ - Allow passing in complex arrays.
8
+
9
+ ## 0.2.1
10
+
11
+ - Better error handling for entry.
12
+ - Allow parsing of unknown code.
13
+
1
14
  ## 0.2.0
2
15
 
3
16
  - Added Gemini
package/README.md CHANGED
@@ -96,6 +96,7 @@ Currently supported platforms:
96
96
  - OpenAI (ChatGPT)
97
97
  - Anthropic (Claude)
98
98
  - Google (Gemini).
99
+ - xAi (Grok).
99
100
 
100
101
  ## Models
101
102
 
@@ -58,23 +58,39 @@ class BaseClient {
58
58
  }
59
59
  }
60
60
  async getMessages(options) {
61
+ const {
62
+ text
63
+ } = options;
61
64
  const template = await this.resolveTemplate(options);
62
- const raw = _mustache.default.render(template, transformParams(options));
63
- const messages = [];
64
- for (let match of raw.matchAll(MESSAGES_REG)) {
65
- const [, role, content] = match;
66
- messages.push({
67
- role: role.toLowerCase(),
68
- content: content.trim()
69
- });
70
- }
71
- if (!messages.length) {
72
- messages.push({
65
+ if (template) {
66
+ const raw = render(template, options);
67
+ const messages = [];
68
+ for (let match of raw.matchAll(MESSAGES_REG)) {
69
+ const [, role, content] = match;
70
+ messages.push({
71
+ role: role.toLowerCase(),
72
+ content: content.trim()
73
+ });
74
+ }
75
+ if (!messages.length) {
76
+ messages.push({
77
+ role: 'user',
78
+ content: raw.trim()
79
+ });
80
+ }
81
+ return messages;
82
+ } else if (text) {
83
+ return [{
73
84
  role: 'user',
74
- content: raw.trim()
75
- });
85
+ content: text
86
+ }];
87
+ } else {
88
+ throw new Error('No input provided.');
76
89
  }
77
- return messages;
90
+ }
91
+ async buildTemplate(options) {
92
+ const template = await this.resolveTemplate(options);
93
+ return render(template, options);
78
94
  }
79
95
  async loadTemplates() {
80
96
  const {
@@ -83,18 +99,18 @@ class BaseClient {
83
99
  this.templates ||= await (0, _util.loadTemplates)(templates);
84
100
  }
85
101
  async resolveTemplate(options) {
86
- await this.loadTemplates();
87
- let {
88
- file,
89
- template
102
+ const {
103
+ template,
104
+ file
90
105
  } = options;
91
- if (!template && file) {
92
- template = this.templates[file];
93
- }
94
- if (!template) {
95
- throw new Error('No template provided.');
106
+ if (template) {
107
+ return template;
108
+ } else if (file?.endsWith('.md')) {
109
+ return await (0, _util.loadTemplate)(file);
110
+ } else if (file) {
111
+ await this.loadTemplates();
112
+ return this.templates[file];
96
113
  }
97
- return template;
98
114
  }
99
115
  async getStream(options) {
100
116
  return await this.prompt({
@@ -114,17 +130,57 @@ class BaseClient {
114
130
  }
115
131
  }
116
132
  exports.default = BaseClient;
117
- function transformParams(params) {
133
+ function render(template, options) {
134
+ let params = {
135
+ ...options,
136
+ ...options.params
137
+ };
138
+ params = mapObjects(params);
139
+ params = wrapProxy(params);
140
+ return _mustache.default.render(template, params);
141
+ }
142
+
143
+ // Transform arrays and object to versions
144
+ // that are more understandable in the context
145
+ // of a template that may have meaningful whitespace.
146
+ function mapObjects(params) {
118
147
  const result = {};
119
148
  for (let [key, value] of Object.entries(params)) {
120
149
  if (Array.isArray(value)) {
121
- value = value.map(el => {
122
- return `- ${el}`;
123
- }).join('\n');
150
+ value = mapArray(value);
124
151
  } else if (typeof value === 'object') {
125
152
  value = JSON.stringify(value, null, 2);
126
153
  }
127
154
  result[key] = value;
128
155
  }
129
156
  return result;
157
+ }
158
+ function mapArray(arr) {
159
+ // Only map simple arrays of primitives.
160
+ if (typeof arr[0] === 'string') {
161
+ arr = arr.map(el => {
162
+ return `- ${el}`;
163
+ }).join('\n');
164
+ }
165
+ return arr;
166
+ }
167
+
168
+ // Wrap params with a proxy object that reports
169
+ // as having all properties. If one is accessed
170
+ // that does not exist then return the original
171
+ // token. This way templates can be partially
172
+ // interpolated and re-interpolated later.
173
+ function wrapProxy(params) {
174
+ return new Proxy(params, {
175
+ has() {
176
+ return true;
177
+ },
178
+ get(target, prop) {
179
+ if (prop in target) {
180
+ return target[prop];
181
+ } else {
182
+ return `{{{${prop.toString()}}}}`;
183
+ }
184
+ }
185
+ });
130
186
  }
@@ -47,12 +47,6 @@ class GoogleClient extends _BaseClient.default {
47
47
  } else {
48
48
  response = await generator.generateContent(prompts);
49
49
  }
50
- // const response = await client.chat.completions.create({
51
- // model,
52
- // messages,
53
- // stream,
54
- // });
55
-
56
50
  if (output === 'raw') {
57
51
  return response;
58
52
  }
package/dist/cjs/index.js CHANGED
@@ -3,27 +3,78 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.Client = void 0;
6
+ exports.MultiClient = exports.Client = void 0;
7
7
  var _openai = require("./openai.js");
8
8
  var _google = require("./google.js");
9
9
  var _anthropic = require("./anthropic.js");
10
+ var _xai = require("./xai.js");
10
11
  class Client {
12
+ constructor(options = {}) {
13
+ if (!options.platform) {
14
+ throw new Error('No platform specified.');
15
+ } else if (!options.templates) {
16
+ throw new Error('No templates directory specified.');
17
+ } else if (!options.apiKey) {
18
+ throw new Error('No API key specified.');
19
+ }
20
+ return getClientForPlatform(options);
21
+ }
22
+ }
23
+ exports.Client = Client;
24
+ class MultiClient {
11
25
  constructor(options) {
12
26
  const {
13
- platform,
14
- ...rest
27
+ platforms
15
28
  } = options;
16
- if (platform === 'openai' || platform === 'gpt') {
17
- return new _openai.OpenAiClient(rest);
18
- } else if (platform === 'google' || platform === 'gemini') {
19
- return new _google.GoogleClient(rest);
20
- } else if (platform === 'anthropic' || platform === 'claude') {
21
- return new _anthropic.AnthropicClient(rest);
22
- } else if (platform) {
23
- throw new Error(`Unknown platform "${platform}".`);
24
- } else {
25
- throw new Error('Platform required.');
29
+ this.clients = {};
30
+ for (let platform of platforms) {
31
+ const {
32
+ name,
33
+ apiKey
34
+ } = platform;
35
+ const client = getClientForPlatform({
36
+ ...options,
37
+ platform: name,
38
+ apiKey
39
+ });
40
+ this.clients[name] = client;
41
+ this.clients[undefined] ||= client;
26
42
  }
27
43
  }
44
+ prompt(options) {
45
+ return this.getClient(options).prompt(options);
46
+ }
47
+ stream(options) {
48
+ return this.getClient(options).stream(options);
49
+ }
50
+ buildTemplate(options) {
51
+ return this.getClient(options).buildTemplate(options);
52
+ }
53
+ getClient(options) {
54
+ const {
55
+ platform
56
+ } = options;
57
+ const client = this.clients[platform];
58
+ if (!client) {
59
+ throw new Error(`Platform "${platform}" not found.`);
60
+ }
61
+ return client;
62
+ }
28
63
  }
29
- exports.Client = Client;
64
+ exports.MultiClient = MultiClient;
65
+ function getClientForPlatform(options) {
66
+ const {
67
+ platform
68
+ } = options;
69
+ if (platform === 'openai' || platform === 'gpt') {
70
+ return new _openai.OpenAiClient(options);
71
+ } else if (platform === 'google' || platform === 'gemini') {
72
+ return new _google.GoogleClient(options);
73
+ } else if (platform === 'anthropic' || platform === 'claude') {
74
+ return new _anthropic.AnthropicClient(options);
75
+ } else if (platform === 'xai' || platform === 'grok') {
76
+ return new _xai.XAiClient(options);
77
+ } else if (platform) {
78
+ throw new Error(`Unknown platform "${platform}".`);
79
+ }
80
+ }
@@ -8,7 +8,7 @@ var _openai = _interopRequireDefault(require("openai"));
8
8
  var _BaseClient = _interopRequireDefault(require("./BaseClient.js"));
9
9
  var _util = require("./util.js");
10
10
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
- const DEFAULT_MODEL = 'gpt-4o';
11
+ const DEFAULT_MODEL = 'gpt-4o-mini';
12
12
  class OpenAiClient extends _BaseClient.default {
13
13
  constructor(options) {
14
14
  super(options);
@@ -40,7 +40,10 @@ class OpenAiClient extends _BaseClient.default {
40
40
  const response = await client.chat.completions.create({
41
41
  model,
42
42
  messages,
43
- stream
43
+ stream,
44
+ response_format: {
45
+ type: output === 'json' ? 'json_object' : 'text'
46
+ }
44
47
  });
45
48
  if (output === 'raw') {
46
49
  return response;
package/dist/cjs/util.js CHANGED
@@ -3,30 +3,29 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.loadTemplate = loadTemplate;
6
7
  exports.loadTemplates = loadTemplates;
7
- exports.parse = parse;
8
8
  exports.transformResponse = transformResponse;
9
9
  var _promises = _interopRequireDefault(require("fs/promises"));
10
10
  var _path = _interopRequireDefault(require("path"));
11
11
  var _glob = require("glob");
12
12
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
+ const CODE_REG = /^```\w*$(.+)```/ms;
13
14
  const JSON_REG = /([{[].+[}\]])/s;
14
15
  async function loadTemplates(dir) {
15
16
  const result = {};
16
17
  const files = await (0, _glob.glob)(_path.default.join(dir, '*.md'));
18
+ if (!files.length) {
19
+ throw new Error(`No templates found in: ${dir}.`);
20
+ }
17
21
  for (let file of files) {
18
22
  const base = _path.default.basename(file, '.md');
19
- result[base] = await _promises.default.readFile(file, 'utf-8');
23
+ result[base] = await loadTemplate(file);
20
24
  }
21
25
  return result;
22
26
  }
23
- function parse(content) {
24
- try {
25
- const match = content.match(JSON_REG);
26
- return JSON.parse(match[1]);
27
- } catch (error) {
28
- throw new Error('Unable to derive JSON object in response.');
29
- }
27
+ async function loadTemplate(file) {
28
+ return await _promises.default.readFile(file, 'utf-8');
30
29
  }
31
30
  function transformResponse(options) {
32
31
  const {
@@ -40,8 +39,24 @@ function transformResponse(options) {
40
39
  } else if (output === 'messages') {
41
40
  return [...messages, message];
42
41
  } else if (output === 'json') {
43
- return parse(content);
42
+ return parseJson(content);
43
+ } else if (output === 'code') {
44
+ return parseCode(content);
44
45
  } else {
45
- throw new Error(`Unknown output type "${output}".`);
46
+ throw new Error(`No output type provided.`);
47
+ }
48
+ }
49
+ function parseJson(content) {
50
+ try {
51
+ return JSON.parse(content.match(JSON_REG)[0]);
52
+ } catch (error) {
53
+ throw new Error(`Unable to derive JSON from response:\n\n${content}`);
54
+ }
55
+ }
56
+ function parseCode(content) {
57
+ try {
58
+ return content.match(CODE_REG)[1].trim();
59
+ } catch (error) {
60
+ throw new Error(`Unable to derive code from response:\n\n${content}`);
46
61
  }
47
62
  }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.XAiClient = void 0;
7
+ var _openai = require("./openai.js");
8
+ const DEFAULT_MODEL = 'grok-2-1212';
9
+ class XAiClient extends _openai.OpenAiClient {
10
+ constructor(options) {
11
+ super({
12
+ ...options,
13
+ baseURL: 'https://api.x.ai/v1'
14
+ });
15
+ }
16
+ async getCompletion(options) {
17
+ return super.getCompletion({
18
+ model: DEFAULT_MODEL,
19
+ ...options
20
+ });
21
+ }
22
+ }
23
+ exports.XAiClient = XAiClient;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bedrockio/ai",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Bedrock wrapper for common AI chatbots.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -11,8 +11,14 @@
11
11
  "eject": "scripts/eject",
12
12
  "prepublish": "yarn build && yarn types"
13
13
  },
14
- "main": "./dist/cjs/index.js",
15
14
  "types": "types/index.d.ts",
15
+ "main": "./dist/cjs/index.js",
16
+ "exports": {
17
+ ".": {
18
+ "import": "./src/index.js",
19
+ "require": "./dist/cjs/index.js"
20
+ }
21
+ },
16
22
  "contributors": [
17
23
  {
18
24
  "name": "Andrew Plummer",
@@ -25,11 +31,11 @@
25
31
  "url": "https://github.com/bedrockio/router"
26
32
  },
27
33
  "dependencies": {
28
- "@anthropic-ai/sdk": "^0.33.1",
34
+ "@anthropic-ai/sdk": "^0.36.3",
29
35
  "@google/generative-ai": "^0.21.0",
30
36
  "glob": "^11.0.1",
31
37
  "mustache": "^4.2.0",
32
- "openai": "^4.79.1"
38
+ "openai": "^4.83.0"
33
39
  },
34
40
  "devDependencies": {
35
41
  "@babel/cli": "^7.26.4",
package/src/BaseClient.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import Mustache from 'mustache';
2
2
 
3
- import { loadTemplates } from './util.js';
3
+ import { loadTemplates, loadTemplate } from './util.js';
4
4
 
5
5
  const MESSAGES_REG = /(?:^|\n)-{3,}\s*(\w+)\s*-{3,}(.*?)(?=\n-{3,}|$)/gs;
6
6
 
@@ -57,26 +57,44 @@ export default class BaseClient {
57
57
  }
58
58
 
59
59
  async getMessages(options) {
60
+ const { text } = options;
60
61
  const template = await this.resolveTemplate(options);
61
- const raw = Mustache.render(template, transformParams(options));
62
-
63
- const messages = [];
64
- for (let match of raw.matchAll(MESSAGES_REG)) {
65
- const [, role, content] = match;
66
- messages.push({
67
- role: role.toLowerCase(),
68
- content: content.trim(),
69
- });
70
- }
71
62
 
72
- if (!messages.length) {
73
- messages.push({
74
- role: 'user',
75
- content: raw.trim(),
76
- });
63
+ if (template) {
64
+ const raw = render(template, options);
65
+
66
+ const messages = [];
67
+ for (let match of raw.matchAll(MESSAGES_REG)) {
68
+ const [, role, content] = match;
69
+ messages.push({
70
+ role: role.toLowerCase(),
71
+ content: content.trim(),
72
+ });
73
+ }
74
+
75
+ if (!messages.length) {
76
+ messages.push({
77
+ role: 'user',
78
+ content: raw.trim(),
79
+ });
80
+ }
81
+
82
+ return messages;
83
+ } else if (text) {
84
+ return [
85
+ {
86
+ role: 'user',
87
+ content: text,
88
+ },
89
+ ];
90
+ } else {
91
+ throw new Error('No input provided.');
77
92
  }
93
+ }
78
94
 
79
- return messages;
95
+ async buildTemplate(options) {
96
+ const template = await this.resolveTemplate(options);
97
+ return render(template, options);
80
98
  }
81
99
 
82
100
  async loadTemplates() {
@@ -85,19 +103,15 @@ export default class BaseClient {
85
103
  }
86
104
 
87
105
  async resolveTemplate(options) {
88
- await this.loadTemplates();
89
-
90
- let { file, template } = options;
91
-
92
- if (!template && file) {
93
- template = this.templates[file];
94
- }
95
-
96
- if (!template) {
97
- throw new Error('No template provided.');
106
+ const { template, file } = options;
107
+ if (template) {
108
+ return template;
109
+ } else if (file?.endsWith('.md')) {
110
+ return await loadTemplate(file);
111
+ } else if (file) {
112
+ await this.loadTemplates();
113
+ return this.templates[file];
98
114
  }
99
-
100
- return template;
101
115
  }
102
116
 
103
117
  async getStream(options) {
@@ -120,15 +134,25 @@ export default class BaseClient {
120
134
  }
121
135
  }
122
136
 
123
- function transformParams(params) {
137
+ function render(template, options) {
138
+ let params = {
139
+ ...options,
140
+ ...options.params,
141
+ };
142
+
143
+ params = mapObjects(params);
144
+ params = wrapProxy(params);
145
+ return Mustache.render(template, params);
146
+ }
147
+
148
+ // Transform arrays and object to versions
149
+ // that are more understandable in the context
150
+ // of a template that may have meaningful whitespace.
151
+ function mapObjects(params) {
124
152
  const result = {};
125
153
  for (let [key, value] of Object.entries(params)) {
126
154
  if (Array.isArray(value)) {
127
- value = value
128
- .map((el) => {
129
- return `- ${el}`;
130
- })
131
- .join('\n');
155
+ value = mapArray(value);
132
156
  } else if (typeof value === 'object') {
133
157
  value = JSON.stringify(value, null, 2);
134
158
  }
@@ -136,3 +160,36 @@ function transformParams(params) {
136
160
  }
137
161
  return result;
138
162
  }
163
+
164
+ function mapArray(arr) {
165
+ // Only map simple arrays of primitives.
166
+ if (typeof arr[0] === 'string') {
167
+ arr = arr
168
+ .map((el) => {
169
+ return `- ${el}`;
170
+ })
171
+ .join('\n');
172
+ }
173
+ return arr;
174
+ }
175
+
176
+ // Wrap params with a proxy object that reports
177
+ // as having all properties. If one is accessed
178
+ // that does not exist then return the original
179
+ // token. This way templates can be partially
180
+ // interpolated and re-interpolated later.
181
+ function wrapProxy(params) {
182
+ return new Proxy(params, {
183
+ has() {
184
+ return true;
185
+ },
186
+
187
+ get(target, prop) {
188
+ if (prop in target) {
189
+ return target[prop];
190
+ } else {
191
+ return `{{{${prop.toString()}}}}`;
192
+ }
193
+ },
194
+ });
195
+ }
package/src/google.js CHANGED
@@ -29,7 +29,9 @@ export class GoogleClient extends BaseClient {
29
29
  const { model = DEFAULT_MODEL, output = 'text', stream = false } = options;
30
30
  const { client } = this;
31
31
 
32
- const generator = client.getGenerativeModel({ model });
32
+ const generator = client.getGenerativeModel({
33
+ model,
34
+ });
33
35
 
34
36
  const messages = await this.getMessages(options);
35
37
 
@@ -44,11 +46,6 @@ export class GoogleClient extends BaseClient {
44
46
  } else {
45
47
  response = await generator.generateContent(prompts);
46
48
  }
47
- // const response = await client.chat.completions.create({
48
- // model,
49
- // messages,
50
- // stream,
51
- // });
52
49
 
53
50
  if (output === 'raw') {
54
51
  return response;
package/src/index.js CHANGED
@@ -1,20 +1,72 @@
1
1
  import { OpenAiClient } from './openai.js';
2
2
  import { GoogleClient } from './google.js';
3
3
  import { AnthropicClient } from './anthropic.js';
4
+ import { XAiClient } from './xai.js';
4
5
 
5
6
  export class Client {
7
+ constructor(options = {}) {
8
+ if (!options.platform) {
9
+ throw new Error('No platform specified.');
10
+ } else if (!options.templates) {
11
+ throw new Error('No templates directory specified.');
12
+ } else if (!options.apiKey) {
13
+ throw new Error('No API key specified.');
14
+ }
15
+ return getClientForPlatform(options);
16
+ }
17
+ }
18
+
19
+ export class MultiClient {
6
20
  constructor(options) {
7
- const { platform, ...rest } = options;
8
- if (platform === 'openai' || platform === 'gpt') {
9
- return new OpenAiClient(rest);
10
- } else if (platform === 'google' || platform === 'gemini') {
11
- return new GoogleClient(rest);
12
- } else if (platform === 'anthropic' || platform === 'claude') {
13
- return new AnthropicClient(rest);
14
- } else if (platform) {
15
- throw new Error(`Unknown platform "${platform}".`);
16
- } else {
17
- throw new Error('Platform required.');
21
+ const { platforms } = options;
22
+
23
+ this.clients = {};
24
+
25
+ for (let platform of platforms) {
26
+ const { name, apiKey } = platform;
27
+ const client = getClientForPlatform({
28
+ ...options,
29
+ platform: name,
30
+ apiKey,
31
+ });
32
+ this.clients[name] = client;
33
+ this.clients[undefined] ||= client;
34
+ }
35
+ }
36
+
37
+ prompt(options) {
38
+ return this.getClient(options).prompt(options);
39
+ }
40
+
41
+ stream(options) {
42
+ return this.getClient(options).stream(options);
43
+ }
44
+
45
+ buildTemplate(options) {
46
+ return this.getClient(options).buildTemplate(options);
47
+ }
48
+
49
+ getClient(options) {
50
+ const { platform } = options;
51
+ const client = this.clients[platform];
52
+ if (!client) {
53
+ throw new Error(`Platform "${platform}" not found.`);
18
54
  }
55
+ return client;
56
+ }
57
+ }
58
+
59
+ function getClientForPlatform(options) {
60
+ const { platform } = options;
61
+ if (platform === 'openai' || platform === 'gpt') {
62
+ return new OpenAiClient(options);
63
+ } else if (platform === 'google' || platform === 'gemini') {
64
+ return new GoogleClient(options);
65
+ } else if (platform === 'anthropic' || platform === 'claude') {
66
+ return new AnthropicClient(options);
67
+ } else if (platform === 'xai' || platform === 'grok') {
68
+ return new XAiClient(options);
69
+ } else if (platform) {
70
+ throw new Error(`Unknown platform "${platform}".`);
19
71
  }
20
72
  }
package/src/openai.js CHANGED
@@ -3,7 +3,7 @@ import OpenAI from 'openai';
3
3
  import BaseClient from './BaseClient.js';
4
4
  import { transformResponse } from './util.js';
5
5
 
6
- const DEFAULT_MODEL = 'gpt-4o';
6
+ const DEFAULT_MODEL = 'gpt-4o-mini';
7
7
 
8
8
  export class OpenAiClient extends BaseClient {
9
9
  constructor(options) {
@@ -31,6 +31,9 @@ export class OpenAiClient extends BaseClient {
31
31
  model,
32
32
  messages,
33
33
  stream,
34
+ response_format: {
35
+ type: output === 'json' ? 'json_object' : 'text',
36
+ },
34
37
  });
35
38
 
36
39
  if (output === 'raw') {
package/src/util.js CHANGED
@@ -4,27 +4,27 @@ import path from 'path';
4
4
 
5
5
  import { glob } from 'glob';
6
6
 
7
+ const CODE_REG = /^```\w*$(.+)```/ms;
7
8
  const JSON_REG = /([{[].+[}\]])/s;
8
9
 
9
10
  export async function loadTemplates(dir) {
10
11
  const result = {};
11
12
  const files = await glob(path.join(dir, '*.md'));
12
13
 
14
+ if (!files.length) {
15
+ throw new Error(`No templates found in: ${dir}.`);
16
+ }
17
+
13
18
  for (let file of files) {
14
19
  const base = path.basename(file, '.md');
15
- result[base] = await fs.readFile(file, 'utf-8');
20
+ result[base] = await loadTemplate(file);
16
21
  }
17
22
 
18
23
  return result;
19
24
  }
20
25
 
21
- export function parse(content) {
22
- try {
23
- const match = content.match(JSON_REG);
24
- return JSON.parse(match[1]);
25
- } catch (error) {
26
- throw new Error('Unable to derive JSON object in response.');
27
- }
26
+ export async function loadTemplate(file) {
27
+ return await fs.readFile(file, 'utf-8');
28
28
  }
29
29
 
30
30
  export function transformResponse(options) {
@@ -35,8 +35,26 @@ export function transformResponse(options) {
35
35
  } else if (output === 'messages') {
36
36
  return [...messages, message];
37
37
  } else if (output === 'json') {
38
- return parse(content);
38
+ return parseJson(content);
39
+ } else if (output === 'code') {
40
+ return parseCode(content);
39
41
  } else {
40
- throw new Error(`Unknown output type "${output}".`);
42
+ throw new Error(`No output type provided.`);
43
+ }
44
+ }
45
+
46
+ function parseJson(content) {
47
+ try {
48
+ return JSON.parse(content.match(JSON_REG)[0]);
49
+ } catch (error) {
50
+ throw new Error(`Unable to derive JSON from response:\n\n${content}`);
51
+ }
52
+ }
53
+
54
+ function parseCode(content) {
55
+ try {
56
+ return content.match(CODE_REG)[1].trim();
57
+ } catch (error) {
58
+ throw new Error(`Unable to derive code from response:\n\n${content}`);
41
59
  }
42
60
  }
package/src/xai.js ADDED
@@ -0,0 +1,19 @@
1
+ import { OpenAiClient } from './openai.js';
2
+
3
+ const DEFAULT_MODEL = 'grok-2-1212';
4
+
5
+ export class XAiClient extends OpenAiClient {
6
+ constructor(options) {
7
+ super({
8
+ ...options,
9
+ baseURL: 'https://api.x.ai/v1',
10
+ });
11
+ }
12
+
13
+ async getCompletion(options) {
14
+ return super.getCompletion({
15
+ model: DEFAULT_MODEL,
16
+ ...options,
17
+ });
18
+ }
19
+ }
@@ -30,6 +30,7 @@ export default class BaseClient {
30
30
  role: any;
31
31
  content: any;
32
32
  }[]>;
33
+ buildTemplate(options: any): Promise<any>;
33
34
  loadTemplates(): Promise<void>;
34
35
  resolveTemplate(options: any): Promise<any>;
35
36
  getStream(options: any): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"BaseClient.d.ts","sourceRoot":"","sources":["../src/BaseClient.js"],"names":[],"mappings":"AAMA;IACE,0BAGC;IAFC,aAAsB;IACtB,eAAqB;IAGvB;;;;;;;;;;;OAWG;IACH,gBALG;QAAwB,KAAK,EAArB,MAAM;QACyC,MAAM,GAArD,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU;QACL,KAAK,GAApC;gBAAQ,MAAM,GAAE,GAAG;SAAC;KAE9B,iBAYA;IAED;;;OAGG;IACH,mDAeC;IAED;;;SAqBC;IAED,+BAGC;IAED,4CAcC;IAED,uCAMC;IAED,kCAGC;IAED,iDAIC;CACF"}
1
+ {"version":3,"file":"BaseClient.d.ts","sourceRoot":"","sources":["../src/BaseClient.js"],"names":[],"mappings":"AAMA;IACE,0BAGC;IAFC,aAAsB;IACtB,eAAqB;IAGvB;;;;;;;;;;;OAWG;IACH,gBALG;QAAwB,KAAK,EAArB,MAAM;QACyC,MAAM,GAArD,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU;QACL,KAAK,GAApC;gBAAQ,MAAM,GAAE,GAAG;SAAC;KAE9B,iBAYA;IAED;;;OAGG;IACH,mDAeC;IAED;;;SAkCC;IAED,0CAGC;IAED,+BAGC;IAED,4CAUC;IAED,uCAMC;IAED,kCAGC;IAED,iDAIC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../src/google.js"],"names":[],"mappings":"AAOA;IAII,2BAA4C;IAG9C;;;OAGG;IACH,4BAOC;IAED,0CAwCC;IACD,sCAIC;IAED;;;MAkBC;CACF;uBA3FsB,iBAAiB;mCAFL,uBAAuB"}
1
+ {"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../src/google.js"],"names":[],"mappings":"AAOA;IAII,2BAA4C;IAG9C;;;OAGG;IACH,4BAOC;IAED,0CAqCC;IACD,sCAIC;IAED;;;MAkBC;CACF;uBAxFsB,iBAAiB;mCAFL,uBAAuB"}
package/types/index.d.ts CHANGED
@@ -1,4 +1,12 @@
1
1
  export class Client {
2
+ constructor(options?: {});
3
+ }
4
+ export class MultiClient {
2
5
  constructor(options: any);
6
+ clients: {};
7
+ prompt(options: any): any;
8
+ stream(options: any): any;
9
+ buildTemplate(options: any): any;
10
+ getClient(options: any): any;
3
11
  }
4
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"AAIA;IACE,0BAaC;CACF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.js"],"names":[],"mappings":"AAKA;IACE,0BASC;CACF;AAED;IACE,0BAeC;IAZC,YAAiB;IAcnB,0BAEC;IAED,0BAEC;IAED,iCAEC;IAED,6BAOC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../src/openai.js"],"names":[],"mappings":"AAOA;IAGI,eAEE;IAGJ;;;OAGG;IACH,4BAGC;IAED,0CAsBC;IAED;;;MAkBC;CACF;uBAjEsB,iBAAiB;mBAFrB,QAAQ"}
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../src/openai.js"],"names":[],"mappings":"AAOA;IAGI,eAEE;IAGJ;;;OAGG;IACH,4BAGC;IAED,0CAyBC;IAED;;;MAkBC;CACF;uBApEsB,iBAAiB;mBAFrB,QAAQ"}
package/types/util.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export function loadTemplates(dir: any): Promise<{}>;
2
- export function parse(content: any): any;
2
+ export function loadTemplate(file: any): Promise<string>;
3
3
  export function transformResponse(options: any): any;
4
4
  //# sourceMappingURL=util.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.js"],"names":[],"mappings":"AAQA,qDAUC;AAED,yCAOC;AAED,qDAYC"}
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.js"],"names":[],"mappings":"AASA,qDAcC;AAED,yDAEC;AAED,qDAcC"}
package/types/xai.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export class XAiClient extends OpenAiClient {
2
+ }
3
+ import { OpenAiClient } from './openai.js';
4
+ //# sourceMappingURL=xai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xai.d.ts","sourceRoot":"","sources":["../src/xai.js"],"names":[],"mappings":"AAIA;CAcC;6BAlB4B,aAAa"}