@bedrockio/ai 0.2.1 → 0.4.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.
Files changed (63) hide show
  1. package/.claude/settings.local.json +11 -0
  2. package/CHANGELOG.md +34 -0
  3. package/README.md +59 -17
  4. package/__mocks__/@anthropic-ai/sdk.js +16 -22
  5. package/__mocks__/@google/generative-ai.js +1 -1
  6. package/__mocks__/openai.js +33 -28
  7. package/dist/cjs/BaseClient.js +242 -126
  8. package/dist/cjs/anthropic.js +115 -93
  9. package/dist/cjs/google.js +74 -86
  10. package/dist/cjs/index.js +24 -25
  11. package/dist/cjs/openai.js +114 -69
  12. package/dist/cjs/package.json +1 -0
  13. package/dist/cjs/utils/code.js +11 -0
  14. package/dist/cjs/utils/json.js +53 -0
  15. package/dist/cjs/utils/templates.js +83 -0
  16. package/dist/cjs/xai.js +14 -0
  17. package/dist/esm/BaseClient.js +243 -0
  18. package/dist/esm/anthropic.js +116 -0
  19. package/dist/esm/google.js +75 -0
  20. package/dist/esm/index.js +25 -0
  21. package/dist/esm/openai.js +113 -0
  22. package/dist/esm/utils/code.js +8 -0
  23. package/dist/esm/utils/json.js +50 -0
  24. package/dist/esm/utils/templates.js +76 -0
  25. package/dist/esm/xai.js +10 -0
  26. package/eslint.config.js +2 -0
  27. package/package.json +18 -17
  28. package/src/BaseClient.js +239 -89
  29. package/src/anthropic.js +96 -56
  30. package/src/google.js +6 -12
  31. package/src/index.js +20 -16
  32. package/src/openai.js +97 -31
  33. package/src/utils/code.js +9 -0
  34. package/src/utils/json.js +58 -0
  35. package/src/utils/templates.js +87 -0
  36. package/src/xai.js +12 -0
  37. package/tsconfig.cjs.json +8 -0
  38. package/tsconfig.esm.json +8 -0
  39. package/tsconfig.types.json +9 -0
  40. package/types/BaseClient.d.ts +68 -26
  41. package/types/BaseClient.d.ts.map +1 -1
  42. package/types/anthropic.d.ts +26 -2
  43. package/types/anthropic.d.ts.map +1 -1
  44. package/types/google.d.ts.map +1 -1
  45. package/types/index.d.ts +4 -3
  46. package/types/index.d.ts.map +1 -1
  47. package/types/openai.d.ts +45 -2
  48. package/types/openai.d.ts.map +1 -1
  49. package/types/util.d.ts +1 -1
  50. package/types/util.d.ts.map +1 -1
  51. package/types/utils/code.d.ts +2 -0
  52. package/types/utils/code.d.ts.map +1 -0
  53. package/types/utils/json.d.ts +2 -0
  54. package/types/utils/json.d.ts.map +1 -0
  55. package/types/utils/templates.d.ts +3 -0
  56. package/types/utils/templates.d.ts.map +1 -0
  57. package/types/utils.d.ts +4 -0
  58. package/types/utils.d.ts.map +1 -0
  59. package/types/xai.d.ts +4 -0
  60. package/types/xai.d.ts.map +1 -0
  61. package/vitest.config.js +10 -0
  62. package/dist/cjs/util.js +0 -47
  63. package/src/util.js +0 -42
@@ -1,94 +1,82 @@
1
1
  "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.GoogleClient = void 0;
7
- var _generativeAi = require("@google/generative-ai");
8
- var _BaseClient = _interopRequireDefault(require("./BaseClient.js"));
9
- var _util = require("./util.js");
10
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
7
+ const generative_ai_1 = require("@google/generative-ai");
8
+ const BaseClient_js_1 = __importDefault(require("./BaseClient.js"));
11
9
  const DEFAULT_MODEL = 'models/gemini-2.0-flash-exp';
12
- class GoogleClient extends _BaseClient.default {
13
- constructor(options) {
14
- super(options);
15
- const {
16
- apiKey
17
- } = options;
18
- this.client = new _generativeAi.GoogleGenerativeAI(apiKey);
19
- }
20
-
21
- /**
22
- * Lists available models.
23
- * {@link https://ai.google.dev/gemini-api/docs/models/gemini#gemini-2.0-flashl Documentation}
24
- */
25
- async models() {
26
- return ['gemini-2.0-flash-exp', 'gemini-1.5-flash', 'gemini-1.5-flash-8b', 'gemini-1.5-pro'];
27
- }
28
- async getCompletion(options) {
29
- const {
30
- model = DEFAULT_MODEL,
31
- output = 'text',
32
- stream = false
33
- } = options;
34
- const {
35
- client
36
- } = this;
37
- const generator = client.getGenerativeModel({
38
- model
39
- });
40
- const messages = await this.getMessages(options);
41
- const prompts = messages.map(message => {
42
- return message.content;
43
- });
44
- let response;
45
- if (stream) {
46
- response = await generator.generateContentStream(prompts);
47
- } else {
48
- response = await generator.generateContent(prompts);
10
+ class GoogleClient extends BaseClient_js_1.default {
11
+ constructor(options) {
12
+ super(options);
13
+ const { apiKey } = options;
14
+ this.client = new generative_ai_1.GoogleGenerativeAI(apiKey);
49
15
  }
50
- // const response = await client.chat.completions.create({
51
- // model,
52
- // messages,
53
- // stream,
54
- // });
55
-
56
- if (output === 'raw') {
57
- return response;
16
+ /**
17
+ * Lists available models.
18
+ * {@link https://ai.google.dev/gemini-api/docs/models/gemini#gemini-2.0-flashl Documentation}
19
+ */
20
+ async models() {
21
+ return [
22
+ 'gemini-2.0-flash-exp',
23
+ 'gemini-1.5-flash',
24
+ 'gemini-1.5-flash-8b',
25
+ 'gemini-1.5-pro',
26
+ ];
58
27
  }
59
-
60
- // @ts-ignore
61
- const parts = response.response.candidates.flatMap(candidate => {
62
- return candidate.content.parts;
63
- });
64
- const [message] = parts;
65
- return (0, _util.transformResponse)({
66
- ...options,
67
- messages,
68
- message
69
- });
70
- }
71
- async getStream(options) {
72
- const response = await super.getStream(options);
73
- // @ts-ignore
74
- return response.stream;
75
- }
76
- getStreamedChunk(chunk, started) {
77
- const [candidate] = chunk.candidates;
78
- let type;
79
- if (!started) {
80
- type = 'start';
81
- } else if (candidate.finishReason === 'STOP') {
82
- type = 'stop';
83
- } else {
84
- type = 'chunk';
28
+ async getCompletion(options) {
29
+ const { model = DEFAULT_MODEL, output = 'text', stream = false } = options;
30
+ const { client } = this;
31
+ const generator = client.getGenerativeModel({
32
+ model,
33
+ });
34
+ // @ts-ignore
35
+ const messages = await this.getMessages(options);
36
+ const prompts = messages.map((message) => {
37
+ return message.content;
38
+ });
39
+ let response;
40
+ if (stream) {
41
+ response = await generator.generateContentStream(prompts);
42
+ }
43
+ else {
44
+ response = await generator.generateContent(prompts);
45
+ }
46
+ if (output === 'raw') {
47
+ return response;
48
+ }
49
+ // @ts-ignore
50
+ const parts = response.response.candidates.flatMap((candidate) => {
51
+ return candidate.content.parts;
52
+ });
53
+ const [message] = parts;
54
+ return message;
85
55
  }
86
- if (type) {
87
- return {
88
- type,
89
- text: candidate.content.parts[0].text || ''
90
- };
56
+ async getStream(options) {
57
+ // @ts-ignore
58
+ const response = await super.getStream(options);
59
+ // @ts-ignore
60
+ return response.stream;
61
+ }
62
+ getStreamedChunk(chunk, started) {
63
+ const [candidate] = chunk.candidates;
64
+ let type;
65
+ if (!started) {
66
+ type = 'start';
67
+ }
68
+ else if (candidate.finishReason === 'STOP') {
69
+ type = 'stop';
70
+ }
71
+ else {
72
+ type = 'chunk';
73
+ }
74
+ if (type) {
75
+ return {
76
+ type,
77
+ text: candidate.content.parts[0].text || '',
78
+ };
79
+ }
91
80
  }
92
- }
93
81
  }
94
- exports.GoogleClient = GoogleClient;
82
+ exports.GoogleClient = GoogleClient;
package/dist/cjs/index.js CHANGED
@@ -1,29 +1,28 @@
1
1
  "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.Client = void 0;
7
- var _openai = require("./openai.js");
8
- var _google = require("./google.js");
9
- var _anthropic = require("./anthropic.js");
10
- class Client {
11
- constructor(options) {
12
- const {
13
- platform,
14
- ...rest
15
- } = options;
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createClient = createClient;
4
+ const anthropic_js_1 = require("./anthropic.js");
5
+ const google_js_1 = require("./google.js");
6
+ const openai_js_1 = require("./openai.js");
7
+ const xai_js_1 = require("./xai.js");
8
+ function createClient(options = {}) {
9
+ const { platform } = options;
10
+ if (!platform) {
11
+ throw new Error('No platform specified.');
12
+ }
16
13
  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.');
14
+ return new openai_js_1.OpenAiClient(options);
15
+ }
16
+ else if (platform === 'google' || platform === 'gemini') {
17
+ return new google_js_1.GoogleClient(options);
18
+ }
19
+ else if (platform === 'anthropic' || platform === 'claude') {
20
+ return new anthropic_js_1.AnthropicClient(options);
21
+ }
22
+ else if (platform === 'xai' || platform === 'grok') {
23
+ return new xai_js_1.XAiClient(options);
24
+ }
25
+ else if (platform) {
26
+ throw new Error(`Unknown platform "${platform}".`);
26
27
  }
27
- }
28
28
  }
29
- exports.Client = Client;
@@ -1,75 +1,120 @@
1
1
  "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.OpenAiClient = void 0;
7
- var _openai = _interopRequireDefault(require("openai"));
8
- var _BaseClient = _interopRequireDefault(require("./BaseClient.js"));
9
- var _util = require("./util.js");
10
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
- const DEFAULT_MODEL = 'gpt-4o';
12
- class OpenAiClient extends _BaseClient.default {
13
- constructor(options) {
14
- super(options);
15
- this.client = new _openai.default({
16
- ...options
17
- });
18
- }
19
-
20
- /**
21
- * Lists available models.
22
- * {@link https://platform.openai.com/docs/models Documentation}
23
- */
24
- async models() {
25
- const {
26
- data
27
- } = await this.client.models.list();
28
- return data.map(o => o.id);
29
- }
30
- async getCompletion(options) {
31
- const {
32
- model = DEFAULT_MODEL,
33
- output = 'text',
34
- stream = false
35
- } = options;
36
- const {
37
- client
38
- } = this;
39
- const messages = await this.getMessages(options);
40
- const response = await client.chat.completions.create({
41
- model,
42
- messages,
43
- stream
44
- });
45
- if (output === 'raw') {
46
- return response;
7
+ const openai_1 = __importDefault(require("openai"));
8
+ const BaseClient_js_1 = __importDefault(require("./BaseClient.js"));
9
+ class OpenAiClient extends BaseClient_js_1.default {
10
+ static DEFAULT_MODEL = 'gpt-5-nano';
11
+ constructor(options) {
12
+ super(options);
13
+ this.client = new openai_1.default(options);
47
14
  }
48
- const {
49
- message
50
- } = response.choices[0];
51
- return (0, _util.transformResponse)({
52
- ...options,
53
- messages,
54
- message
55
- });
56
- }
57
- getStreamedChunk(chunk, started) {
58
- const [choice] = chunk.choices;
59
- let type;
60
- if (!started) {
61
- type = 'start';
62
- } else if (choice.finish_reason === 'stop') {
63
- type = 'stop';
64
- } else {
65
- type = 'chunk';
15
+ /**
16
+ * Lists available models.
17
+ * {@link https://platform.openai.com/docs/models Documentation}
18
+ */
19
+ async models() {
20
+ const { data } = await this.client.models.list();
21
+ return data.map((o) => o.id);
66
22
  }
67
- if (type) {
68
- return {
69
- type,
70
- text: choice.delta.content || ''
71
- };
23
+ async runPrompt(options) {
24
+ const { input, model, tools, verbosity, temperature, instructions, prevResponseId, stream = false, } = options;
25
+ const params = {
26
+ model,
27
+ input,
28
+ tools,
29
+ stream,
30
+ temperature,
31
+ instructions,
32
+ previous_response_id: prevResponseId,
33
+ text: {
34
+ format: this.getOutputFormat(options),
35
+ verbosity,
36
+ },
37
+ };
38
+ this.debug('Params:', params);
39
+ // @ts-ignore
40
+ return await this.client.responses.create(params);
41
+ }
42
+ async runStream(options) {
43
+ return await this.runPrompt({
44
+ ...options,
45
+ stream: true,
46
+ });
47
+ }
48
+ getTextResponse(response) {
49
+ return response.output_text;
50
+ }
51
+ getStructuredResponse(response) {
52
+ return JSON.parse(response.output_text);
53
+ }
54
+ getMessagesResponse(input, response) {
55
+ return {
56
+ messages: [
57
+ ...input,
58
+ {
59
+ role: 'assistant',
60
+ content: response.output_text,
61
+ },
62
+ ],
63
+ // Note that this ability currently only
64
+ // exists for OpenAI compatible providers.
65
+ prevResponseId: response.id,
66
+ };
67
+ }
68
+ // Private
69
+ getOutputFormat(options) {
70
+ let { output, schema } = options;
71
+ if (output === 'json') {
72
+ return {
73
+ type: 'json_object',
74
+ };
75
+ }
76
+ else if (schema) {
77
+ return {
78
+ type: 'json_schema',
79
+ // Name is required but arbitrary.
80
+ name: 'schema',
81
+ strict: true,
82
+ schema,
83
+ };
84
+ }
85
+ else {
86
+ return {
87
+ type: 'text',
88
+ };
89
+ }
90
+ }
91
+ normalizeStreamEvent(event) {
92
+ const { type } = event;
93
+ if (type === 'response.created') {
94
+ return {
95
+ type: 'start',
96
+ id: event.response.id,
97
+ };
98
+ }
99
+ else if (type === 'response.completed') {
100
+ return {
101
+ type: 'stop',
102
+ id: event.response.id,
103
+ usage: event.response.usage,
104
+ };
105
+ }
106
+ else if (type === 'response.output_text.delta') {
107
+ return {
108
+ type: 'delta',
109
+ delta: event.delta,
110
+ };
111
+ }
112
+ else if (type === 'response.output_text.done') {
113
+ return {
114
+ type: 'done',
115
+ text: event.text,
116
+ };
117
+ }
72
118
  }
73
- }
74
119
  }
75
- exports.OpenAiClient = OpenAiClient;
120
+ exports.OpenAiClient = OpenAiClient;
@@ -0,0 +1 @@
1
+ { "type": "commonjs" }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseCode = parseCode;
4
+ const CODE_REG = /^```\w*(.+)```/s;
5
+ function parseCode(content) {
6
+ const match = content.trim().match(CODE_REG);
7
+ if (match) {
8
+ content = match[1].trim();
9
+ }
10
+ return content;
11
+ }
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createMessageExtractor = createMessageExtractor;
4
+ const partial_json_1 = require("partial-json");
5
+ function createMessageExtractor(keys) {
6
+ let buffer = '';
7
+ const extractors = keys.map((key) => {
8
+ return createExtractor(key);
9
+ });
10
+ return (delta) => {
11
+ buffer += delta;
12
+ return extractors
13
+ .map((extractor) => {
14
+ return extractor(buffer);
15
+ })
16
+ .filter((extracted) => {
17
+ return extracted;
18
+ });
19
+ };
20
+ }
21
+ function createExtractor(key) {
22
+ let lastText = '';
23
+ let done = false;
24
+ return (buffer) => {
25
+ if (done) {
26
+ return;
27
+ }
28
+ const text = extractText(buffer, key);
29
+ if (!text) {
30
+ return;
31
+ }
32
+ // Don't finish while the buffer has whitespace as it
33
+ // may be in the middle of trying to extract.
34
+ if (text === lastText && !buffer.endsWith(' ')) {
35
+ done = true;
36
+ }
37
+ const delta = text.slice(lastText.length);
38
+ lastText = text;
39
+ return {
40
+ key,
41
+ text,
42
+ delta,
43
+ done,
44
+ };
45
+ };
46
+ }
47
+ function extractText(input, key) {
48
+ if (!input) {
49
+ return;
50
+ }
51
+ const parsed = (0, partial_json_1.parse)(input, partial_json_1.STR | partial_json_1.OBJ);
52
+ return parsed?.[key] || '';
53
+ }
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadTemplates = loadTemplates;
7
+ exports.renderTemplate = renderTemplate;
8
+ const promises_1 = __importDefault(require("fs/promises"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const glob_1 = require("glob");
11
+ const mustache_1 = __importDefault(require("mustache"));
12
+ async function loadTemplates(dir) {
13
+ const result = {};
14
+ const files = await (0, glob_1.glob)(path_1.default.join(dir, '*.md'));
15
+ if (!files.length) {
16
+ throw new Error(`No templates found in: ${dir}.`);
17
+ }
18
+ for (let file of files) {
19
+ const base = path_1.default.basename(file, '.md');
20
+ result[base] = await loadTemplate(file);
21
+ }
22
+ return result;
23
+ }
24
+ function renderTemplate(template, options) {
25
+ let params = {
26
+ ...options,
27
+ ...options.params,
28
+ };
29
+ params = mapObjects(params);
30
+ params = wrapProxy(params);
31
+ return mustache_1.default.render(template, params);
32
+ }
33
+ // Utils
34
+ async function loadTemplate(file) {
35
+ return await promises_1.default.readFile(file, 'utf-8');
36
+ }
37
+ // Transform arrays and object to versions
38
+ // that are more understandable in the context
39
+ // of a template that may have meaningful whitespace.
40
+ function mapObjects(params) {
41
+ const result = {};
42
+ for (let [key, value] of Object.entries(params)) {
43
+ if (Array.isArray(value)) {
44
+ value = mapArray(value);
45
+ }
46
+ else if (typeof value === 'object') {
47
+ value = JSON.stringify(value, null, 2);
48
+ }
49
+ result[key] = value;
50
+ }
51
+ return result;
52
+ }
53
+ function mapArray(arr) {
54
+ // Only map simple arrays of primitives.
55
+ if (typeof arr[0] === 'string') {
56
+ arr = arr
57
+ .map((el) => {
58
+ return `- ${el}`;
59
+ })
60
+ .join('\n');
61
+ }
62
+ return arr;
63
+ }
64
+ // Wrap params with a proxy object that reports
65
+ // as having all properties. If one is accessed
66
+ // that does not exist then return the original
67
+ // token. This way templates can be partially
68
+ // interpolated and re-interpolated later.
69
+ function wrapProxy(params) {
70
+ return new Proxy(params, {
71
+ has() {
72
+ return true;
73
+ },
74
+ get(target, prop) {
75
+ if (prop in target) {
76
+ return target[prop];
77
+ }
78
+ else {
79
+ return `{{{${prop.toString()}}}}`;
80
+ }
81
+ },
82
+ });
83
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.XAiClient = void 0;
4
+ const openai_js_1 = require("./openai.js");
5
+ class XAiClient extends openai_js_1.OpenAiClient {
6
+ static DEFAULT_MODEL = 'grok-4-fast';
7
+ constructor(options) {
8
+ super({
9
+ ...options,
10
+ baseURL: 'https://api.x.ai/v1',
11
+ });
12
+ }
13
+ }
14
+ exports.XAiClient = XAiClient;