cloving 0.3.17 → 0.3.19

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 (102) hide show
  1. package/.DS_Store +0 -0
  2. package/.aider.chat.history.md +16978 -0
  3. package/.aider.input.history +15 -0
  4. package/.aider.tags.cache.v3/cache.db +0 -0
  5. package/.aider.tags.cache.v3/cache.db-shm +0 -0
  6. package/.aider.tags.cache.v3/cache.db-wal +0 -0
  7. package/.cursorrules +77 -0
  8. package/.github/workflows/auto-release.yml +83 -0
  9. package/.github/workflows/ci.yml +32 -0
  10. package/.github/workflows/npm-publish.yml +34 -0
  11. package/.gitignore +67 -0
  12. package/.husky/_/.gitignore +1 -0
  13. package/.husky/_/applypatch-msg +2 -0
  14. package/.husky/_/commit-msg +2 -0
  15. package/.husky/_/h +22 -0
  16. package/.husky/_/husky.sh +9 -0
  17. package/.husky/_/post-applypatch +2 -0
  18. package/.husky/_/post-checkout +2 -0
  19. package/.husky/_/post-commit +2 -0
  20. package/.husky/_/post-merge +2 -0
  21. package/.husky/_/post-rewrite +2 -0
  22. package/.husky/_/pre-applypatch +2 -0
  23. package/.husky/_/pre-auto-gc +2 -0
  24. package/.husky/_/pre-commit +2 -0
  25. package/.husky/_/pre-merge-commit +2 -0
  26. package/.husky/_/pre-push +2 -0
  27. package/.husky/_/pre-rebase +2 -0
  28. package/.husky/_/prepare-commit-msg +2 -0
  29. package/.husky/pre-commit +1 -0
  30. package/.husky/pre-push +1 -0
  31. package/.prettierrc.json +7 -0
  32. package/.tool-versions +2 -0
  33. package/SECURITY.md +15 -0
  34. package/cloving.json +67 -0
  35. package/dist/cloving_gpt/adapters/openai.js +2 -0
  36. package/dist/commands/generate/context.js +1 -1
  37. package/dist/commands/tokens.js +1 -1
  38. package/dist/managers/CommitManager.js +8 -2
  39. package/dist/managers/ProxyManager.js +9 -2
  40. package/dist/managers/StreamManager.js +1 -1
  41. package/dist/package.json +26 -26
  42. package/dist/utils/config_utils.js +21 -4
  43. package/dist/utils/git_utils.js +109 -7
  44. package/dist/utils/prompt_utils.js +3 -3
  45. package/jest.config.js +11 -0
  46. package/package.json +23 -23
  47. package/src/cloving_gpt/adapters/azureopenai.ts +83 -0
  48. package/src/cloving_gpt/adapters/claude.ts +140 -0
  49. package/src/cloving_gpt/adapters/gemini.ts +146 -0
  50. package/src/cloving_gpt/adapters/index.ts +43 -0
  51. package/src/cloving_gpt/adapters/mistral.ts +142 -0
  52. package/src/cloving_gpt/adapters/ollama.ts +136 -0
  53. package/src/cloving_gpt/adapters/openai.ts +113 -0
  54. package/src/cloving_gpt/index.ts +229 -0
  55. package/src/commands/chat.ts +12 -0
  56. package/src/commands/config.ts +192 -0
  57. package/src/commands/generate/code.ts +18 -0
  58. package/src/commands/generate/commit.ts +9 -0
  59. package/src/commands/generate/context.ts +93 -0
  60. package/src/commands/generate/docs.ts +9 -0
  61. package/src/commands/generate/review.ts +9 -0
  62. package/src/commands/generate/shell.ts +9 -0
  63. package/src/commands/generate/unit_tests.ts +9 -0
  64. package/src/commands/init.ts +9 -0
  65. package/src/commands/models.ts +21 -0
  66. package/src/commands/proxy.ts +9 -0
  67. package/src/commands/tokens.ts +82 -0
  68. package/src/index.ts +197 -0
  69. package/src/managers/BlockManager.ts +126 -0
  70. package/src/managers/ChatManager.ts +755 -0
  71. package/src/managers/ChunkManager.ts +31 -0
  72. package/src/managers/CodeManager.ts +226 -0
  73. package/src/managers/CommitManager.ts +71 -0
  74. package/src/managers/DocsManager.ts +101 -0
  75. package/src/managers/InitManager.ts +263 -0
  76. package/src/managers/ProxyManager.ts +240 -0
  77. package/src/managers/ReviewManager.ts +154 -0
  78. package/src/managers/ShellManager.ts +172 -0
  79. package/src/managers/StreamManager.ts +353 -0
  80. package/src/managers/UnitTestManager.ts +293 -0
  81. package/src/utils/config_utils.ts +271 -0
  82. package/src/utils/git_utils.ts +230 -0
  83. package/src/utils/model_utils.ts +3 -0
  84. package/src/utils/prompt_utils.ts +375 -0
  85. package/src/utils/prompts/CODEGEN_COULDNT_APPLY.md +5 -0
  86. package/src/utils/prompts/CODEGEN_EXAMPLES.md +82 -0
  87. package/src/utils/prompts/CODEGEN_INSTRUCTIONS.md +43 -0
  88. package/src/utils/prompts/DOCS_INSTRUCTIONS.md +9 -0
  89. package/src/utils/prompts/INIT_INSTRUCTIONS.md +132 -0
  90. package/src/utils/prompts/REVIEW_INSTRUCTIONS.md +49 -0
  91. package/src/utils/prompts/SHELL_INSTRUCTIONS.md +15 -0
  92. package/src/utils/prompts/SPECIAL_FILES.md +66 -0
  93. package/src/utils/prompts/index.ts +37 -0
  94. package/src/utils/string_utils.ts +552 -0
  95. package/src/utils/types.ts +127 -0
  96. package/tests/commands/generate/unit_tests.test.ts +27 -0
  97. package/tests/utils/git_utils.test.ts +116 -0
  98. package/tests/utils/model_utils.test.ts +27 -0
  99. package/tests/utils/prompt_utils.test.ts +33 -0
  100. package/tests/utils/string_utils.test.ts +560 -0
  101. package/tsconfig.json +14 -0
  102. package/yarn.lock +5823 -0
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloving",
3
- "version": "0.3.15",
3
+ "version": "0.3.19",
4
4
  "packageManager": "yarn@1.22.22",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -39,43 +39,43 @@
39
39
  }
40
40
  },
41
41
  "dependencies": {
42
- "@inquirer/prompts": "^5.3.8",
43
- "axios": "^1.7.3",
42
+ "@inquirer/prompts": "^7.3.2",
43
+ "axios": "^1.7.9",
44
44
  "cli-highlight": "^2.1.11",
45
45
  "colors": "^1.4.0",
46
- "commander": "^12.1.0",
46
+ "commander": "^13.1.0",
47
47
  "copy-paste": "^1.5.3",
48
- "eslint": "^8.57.0",
49
- "eslint-config-prettier": "^9.1.0",
48
+ "eslint": "^9.20.1",
49
+ "eslint-config-prettier": "^10.0.1",
50
50
  "eslint-config-raine": "^0.5.0",
51
51
  "eslint-config-standard": "^17.1.0",
52
- "eslint-plugin-import": "^2.29.1",
53
- "eslint-plugin-jsdoc": "^50.1.0",
54
- "eslint-plugin-n": "^16.6.2",
55
- "eslint-plugin-promise": "^6.6.0",
56
- "express": "^4.19.2",
57
- "ignore": "^5.3.2",
58
- "ini": "^4.1.3",
59
- "isbinaryfile": "^5.0.2",
60
- "nock": "^13.5.4",
61
- "vite": "^5.4.0",
62
- "vite-node": "^2.0.5"
52
+ "eslint-plugin-import": "^2.31.0",
53
+ "eslint-plugin-jsdoc": "^50.6.3",
54
+ "eslint-plugin-n": "^17.15.1",
55
+ "eslint-plugin-promise": "^7.2.1",
56
+ "express": "^4.21.2",
57
+ "ignore": "^7.0.3",
58
+ "ini": "^5.0.0",
59
+ "isbinaryfile": "^5.0.4",
60
+ "nock": "^14.0.1",
61
+ "vite": "^6.1.1",
62
+ "vite-node": "^3.0.6"
63
63
  },
64
64
  "devDependencies": {
65
65
  "@types/body-parser": "^1.19.5",
66
66
  "@types/copy-paste": "^1.1.33",
67
- "@types/express": "^4.17.21",
67
+ "@types/express": "^5.0.0",
68
68
  "@types/ini": "^4.1.1",
69
69
  "@types/inquirer": "^9.0.7",
70
- "@types/jest": "^29.5.12",
71
- "@types/node": "^22.2.0",
72
- "husky": "^9.1.4",
70
+ "@types/jest": "^29.5.14",
71
+ "@types/node": "^22.13.4",
72
+ "husky": "^9.1.7",
73
73
  "jest": "^29.7.0",
74
- "lint-prepush": "^2.2.2",
75
- "lint-staged": "^15.2.9",
76
- "prettier": "^3.2.5",
77
- "ts-jest": "^29.2.4",
78
- "typescript": "^5.5.4"
74
+ "lint-prepush": "^3.0.2",
75
+ "lint-staged": "^15.4.3",
76
+ "prettier": "^3.5.1",
77
+ "ts-jest": "^29.2.5",
78
+ "typescript": "^5.7.3"
79
79
  },
80
80
  "resolutions": {
81
81
  "eslint": "8.57.0",
@@ -7,7 +7,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
7
7
  return (mod && mod.__esModule) ? mod : { "default": mod };
8
8
  };
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.getTestingDirectory = exports.getAllFiles = exports.removeProjectConfig = exports.saveProjectConfig = exports.getProjectConfig = exports.getPrimaryModel = exports.saveConfig = exports.getClovingConfig = exports.getConfig = exports.CLOVINGPROJECT_PATH = exports.CLOVINGFILE_PATH = exports.CLOVING_CONFIG_PATH = void 0;
10
+ exports.getTestingDirectory = exports.getAllFiles = exports.removeProjectConfig = exports.saveProjectConfig = exports.getProjectConfig = exports.getPrimaryModel = exports.saveConfig = exports.getNearestClovingConfig = exports.getClovingConfig = exports.getConfig = exports.CLOVINGPROJECT_PATH = exports.CLOVINGFILE_PATH = exports.CLOVING_CONFIG_PATH = void 0;
11
11
  const os_1 = __importDefault(require("os"));
12
12
  const path_1 = __importDefault(require("path"));
13
13
  const fs_1 = __importDefault(require("fs"));
@@ -86,8 +86,7 @@ const getClovingConfig = () => {
86
86
  return clovingConfig;
87
87
  }
88
88
  else if (fs_1.default.existsSync(exports.CLOVINGFILE_PATH)) {
89
- const configFile = fs_1.default.readFileSync(exports.CLOVINGFILE_PATH, 'utf-8');
90
- clovingConfig = JSON.parse(configFile);
89
+ clovingConfig = getClovingConfigAtPath(exports.CLOVINGFILE_PATH);
91
90
  return clovingConfig;
92
91
  }
93
92
  else {
@@ -96,6 +95,24 @@ const getClovingConfig = () => {
96
95
  }
97
96
  };
98
97
  exports.getClovingConfig = getClovingConfig;
98
+ const getClovingConfigAtPath = (fullPath) => {
99
+ const configFile = fs_1.default.readFileSync(fullPath, 'utf-8');
100
+ return JSON.parse(configFile);
101
+ };
102
+ const getNearestClovingConfig = () => {
103
+ let runPath = process.cwd();
104
+ const parts = runPath.split(path_1.default.sep);
105
+ while (parts.length > 0) {
106
+ const configPath = path_1.default.join(parts.join(path_1.default.sep), exports.CLOVINGFILE_PATH);
107
+ if (fs_1.default.existsSync(configPath)) {
108
+ clovingConfig = getClovingConfigAtPath(configPath);
109
+ return { config: clovingConfig, path: configPath };
110
+ }
111
+ parts.pop();
112
+ }
113
+ throw new Error(`No ${exports.CLOVINGFILE_PATH} file found in ${runPath} or any parent directory`);
114
+ };
115
+ exports.getNearestClovingConfig = getNearestClovingConfig;
99
116
  /**
100
117
  * Saves the Cloving configuration to the config file
101
118
  * @param {ClovingConfig} config - The configuration to save
@@ -199,7 +216,7 @@ Please provide instructions on how to set up testing for this project.`;
199
216
  const getAllFiles = async (options, forTesting) => {
200
217
  const gpt = new cloving_gpt_1.default(options);
201
218
  // Read the cloving.json file
202
- const config = (0, exports.getClovingConfig)();
219
+ const { config } = (0, exports.getNearestClovingConfig)();
203
220
  const testingDirectory = (0, exports.getTestingDirectory)();
204
221
  let allSrcFiles = [];
205
222
  if (forTesting && !testingDirectory) {
@@ -7,9 +7,27 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
7
7
  return (mod && mod.__esModule) ? mod : { "default": mod };
8
8
  };
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.generateCommitMessagePrompt = exports.getCurrentBranchName = exports.getDefaultBranchName = exports.getGitDiff = void 0;
10
+ exports.generateCommitMessagePrompt = exports.readCommitlintConfig = exports.findCommitlintConfig = exports.getCurrentBranchName = exports.getDefaultBranchName = exports.getGitDiff = void 0;
11
11
  const child_process_1 = require("child_process");
12
12
  const readline_1 = __importDefault(require("readline"));
13
+ const fs_1 = __importDefault(require("fs"));
14
+ const path_1 = __importDefault(require("path"));
15
+ const COMMITLINT_CONFIG_FILES = [
16
+ '.commitlintrc',
17
+ '.commitlintrc.json',
18
+ '.commitlintrc.yaml',
19
+ '.commitlintrc.yml',
20
+ '.commitlintrc.js',
21
+ '.commitlintrc.cjs',
22
+ '.commitlintrc.mjs',
23
+ '.commitlintrc.ts',
24
+ '.commitlintrc.cts',
25
+ 'commitlint.config.js',
26
+ 'commitlint.config.cjs',
27
+ 'commitlint.config.mjs',
28
+ 'commitlint.config.ts',
29
+ 'commitlint.config.cts',
30
+ ];
13
31
  /**
14
32
  * Prompts the user with a question and returns their answer.
15
33
  * @param {string} question - The question to ask the user.
@@ -88,24 +106,108 @@ const getCurrentBranchName = () => {
88
106
  }
89
107
  };
90
108
  exports.getCurrentBranchName = getCurrentBranchName;
109
+ /**
110
+ * Checks if a commitlint configuration file exists in the project.
111
+ * @returns {string | null} The path to the commitlint config file if found, null otherwise.
112
+ */
113
+ const findCommitlintConfig = () => {
114
+ for (const configFile of COMMITLINT_CONFIG_FILES) {
115
+ if (fs_1.default.existsSync(configFile)) {
116
+ return configFile;
117
+ }
118
+ }
119
+ return null;
120
+ };
121
+ exports.findCommitlintConfig = findCommitlintConfig;
122
+ /**
123
+ * Reads and parses the commitlint configuration file.
124
+ * @param {string} configPath - Path to the commitlint config file.
125
+ * @returns {object | null} The parsed configuration object or null if unable to parse.
126
+ */
127
+ const readCommitlintConfig = (configPath) => {
128
+ try {
129
+ const ext = path_1.default.extname(configPath);
130
+ if (['.js', '.cjs', '.mjs', '.ts', '.cts'].includes(ext)) {
131
+ // For JavaScript/TypeScript config files, we can't safely require them
132
+ // as they might have dependencies or complex configurations
133
+ return null;
134
+ }
135
+ if (['.json', '', '.yaml', '.yml'].includes(ext)) {
136
+ const content = fs_1.default.readFileSync(configPath, 'utf-8');
137
+ if (ext === '.json' || ext === '') {
138
+ return JSON.parse(content);
139
+ }
140
+ // For YAML files, we'll just return the raw content as a string
141
+ return { config: content };
142
+ }
143
+ return null;
144
+ }
145
+ catch (error) {
146
+ console.error('Error reading commitlint config:', error.message);
147
+ return null;
148
+ }
149
+ };
150
+ exports.readCommitlintConfig = readCommitlintConfig;
91
151
  /**
92
152
  * Generates a prompt for creating a commit message based on a Git diff.
93
153
  * @param {string} diff - The Git diff to base the commit message on.
94
154
  * @returns {string} A prompt string for generating a commit message.
95
155
  */
96
156
  const generateCommitMessagePrompt = (diff) => {
97
- return `Generate a concise and meaningful commit message based on a diff.
157
+ // Check if commitlint is configured
158
+ const commitlintConfig = (0, exports.findCommitlintConfig)();
159
+ let configInfo = '';
160
+ if (commitlintConfig) {
161
+ const config = (0, exports.readCommitlintConfig)(commitlintConfig);
162
+ if (config) {
163
+ configInfo = `\nFound commitlint configuration at ${commitlintConfig}:
164
+ \`\`\`json
165
+ ${JSON.stringify(config, null, 2)}
166
+ \`\`\`
167
+ Please ensure the commit message follows any additional rules specified in this configuration.
168
+ `;
169
+ }
170
+ }
171
+ return `Generate a conventional commit message following the Conventional Commits specification (www.conventionalcommits.org).${configInfo}
172
+
173
+ The commit message should follow this format:
174
+ <type>[optional scope]: <description>
175
+
176
+ [optional body]
177
+
178
+ [optional footer(s)]
179
+
180
+ Types must be one of:
181
+ 1. revert: Reverts a previous commit
182
+ 2. feat: A new feature
183
+ 3. fix: A bug fix
184
+ 4. refactor: A code change that neither fixes a bug nor adds a feature
185
+ 5. perf: A code change that improves performance
186
+ 6. build: Changes that affect the build system or external dependencies or updates to versions of dependencies or version bumps
187
+ 7. test: Adding missing tests or correcting existing tests
188
+ 8. docs: Documentation only changes
189
+ 9. style: Changes that do not affect the meaning of the code
190
+ 10. ci: Changes to our CI configuration files and scripts
191
+ 11. chore: Other changes that don't modify src or test files
192
+
193
+ Use the order of types as an order of precedence for the commit message if there are multiple types in one commit.
194
+
195
+ The scope should be the part of the codebase affected.
196
+ The description should be imperative, present tense, and not capitalized.
197
+ Breaking changes should be indicated by "!" before the ":" or by "BREAKING CHANGE:" in the footer.
98
198
 
99
199
  Do not add any commentary or context to the message other than the commit message itself.
100
200
 
101
- An example of the output for this should look like the following:
201
+ Here is an example of a valid conventional commit message:
102
202
 
103
203
  \`\`\`plaintext
104
- Update dependencies and package versions
204
+ feat(api): add new endpoint for user authentication
205
+
206
+ - Implement JWT token generation
207
+ - Add password hashing with bcrypt
208
+ - Create user validation middleware
105
209
 
106
- - Upgrade Ruby gems including aws-sdk, honeybadger, irb, and rubocop
107
- - Update Node.js packages including esbuild, tinymce, and trix
108
- - Bump TypeScript and ESLint related packages to latest versions
210
+ BREAKING CHANGE: 'auth' endpoint now requires API key in headers
109
211
  \`\`\`
110
212
 
111
213
  Here is the diff to help you write the commit message:
@@ -56,7 +56,7 @@ const generateCodegenPrompt = (contextFilesContent) => {
56
56
  ## Description of App
57
57
 
58
58
  \`\`\`json
59
- ${JSON.stringify((0, config_utils_1.getClovingConfig)(), null, 2)}
59
+ ${JSON.stringify((0, config_utils_1.getNearestClovingConfig)().config, null, 2)}
60
60
  \`\`\`
61
61
 
62
62
  ## Special Files
@@ -99,7 +99,7 @@ ${prompts_1.CODEGEN_EXAMPLES}
99
99
  ## Description of App
100
100
 
101
101
  \`\`\`json
102
- ${JSON.stringify((0, config_utils_1.getClovingConfig)(), null, 2)}
102
+ ${JSON.stringify((0, config_utils_1.getNearestClovingConfig)().config, null, 2)}
103
103
  \`\`\`
104
104
 
105
105
  ## Special Files
@@ -136,7 +136,7 @@ const generateReviewPrompt = (options, contextFiles) => {
136
136
  .join('\n');
137
137
  prompt += `### Description of App
138
138
 
139
- ${JSON.stringify((0, config_utils_1.getClovingConfig)(), null, 2)}
139
+ ${JSON.stringify((0, config_utils_1.getNearestClovingConfig)().config, null, 2)}
140
140
 
141
141
  ${contextFileContents}
142
142
 
package/jest.config.js ADDED
@@ -0,0 +1,11 @@
1
+ /** @type {import('ts-jest').JestConfigWithTsJest} */
2
+ module.exports = {
3
+ preset: 'ts-jest',
4
+ testEnvironment: 'node',
5
+ testMatch: ['**/tests/**/*.test.ts'],
6
+ moduleFileExtensions: ['ts', 'js'],
7
+ transform: {
8
+ '^.+\\.ts$': 'ts-jest',
9
+ },
10
+ }
11
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloving",
3
- "version": "0.3.17",
3
+ "version": "0.3.19",
4
4
  "packageManager": "yarn@1.22.22",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -39,27 +39,27 @@
39
39
  }
40
40
  },
41
41
  "dependencies": {
42
- "@inquirer/prompts": "^5.3.8",
43
- "axios": "^1.7.7",
42
+ "@inquirer/prompts": "^7.3.2",
43
+ "axios": "^1.7.9",
44
44
  "cli-highlight": "^2.1.11",
45
45
  "colors": "^1.4.0",
46
- "commander": "^12.1.0",
46
+ "commander": "^13.1.0",
47
47
  "copy-paste": "^1.5.3",
48
- "eslint": "^8.57.0",
49
- "eslint-config-prettier": "^9.1.0",
48
+ "eslint": "^9.20.1",
49
+ "eslint-config-prettier": "^10.0.1",
50
50
  "eslint-config-raine": "^0.5.0",
51
51
  "eslint-config-standard": "^17.1.0",
52
52
  "eslint-plugin-import": "^2.31.0",
53
- "eslint-plugin-jsdoc": "^50.3.1",
54
- "eslint-plugin-n": "^16.6.2",
55
- "eslint-plugin-promise": "^6.6.0",
56
- "express": "^4.21.1",
57
- "ignore": "^5.3.2",
58
- "ini": "^4.1.3",
59
- "isbinaryfile": "^5.0.2",
60
- "nock": "^13.5.5",
61
- "vite": "^5.4.8",
62
- "vite-node": "^2.1.2"
53
+ "eslint-plugin-jsdoc": "^50.6.3",
54
+ "eslint-plugin-n": "^17.15.1",
55
+ "eslint-plugin-promise": "^7.2.1",
56
+ "express": "^4.21.2",
57
+ "ignore": "^7.0.3",
58
+ "ini": "^5.0.0",
59
+ "isbinaryfile": "^5.0.4",
60
+ "nock": "^14.0.1",
61
+ "vite": "^6.1.1",
62
+ "vite-node": "^3.0.6"
63
63
  },
64
64
  "devDependencies": {
65
65
  "@types/body-parser": "^1.19.5",
@@ -67,15 +67,15 @@
67
67
  "@types/express": "^5.0.0",
68
68
  "@types/ini": "^4.1.1",
69
69
  "@types/inquirer": "^9.0.7",
70
- "@types/jest": "^29.5.13",
71
- "@types/node": "^22.7.5",
72
- "husky": "^9.1.6",
70
+ "@types/jest": "^29.5.14",
71
+ "@types/node": "^22.13.4",
72
+ "husky": "^9.1.7",
73
73
  "jest": "^29.7.0",
74
- "lint-prepush": "^2.2.2",
75
- "lint-staged": "^15.2.10",
76
- "prettier": "^3.3.3",
74
+ "lint-prepush": "^3.0.2",
75
+ "lint-staged": "^15.4.3",
76
+ "prettier": "^3.5.1",
77
77
  "ts-jest": "^29.2.5",
78
- "typescript": "^5.6.3"
78
+ "typescript": "^5.7.3"
79
79
  },
80
80
  "resolutions": {
81
81
  "eslint": "8.57.0",
@@ -0,0 +1,83 @@
1
+ import { Adapter } from '.'
2
+ import type { GPTRequest, OpenAIStreamChunk } from '../../utils/types'
3
+
4
+ export class AzureOpenAIAdapter implements Adapter {
5
+ private model: string
6
+ private endpoint: string
7
+
8
+ static supportedModels: string[] = [
9
+ 'azureopenai:gpt:4o-2024-08-06',
10
+ 'azureopenai:gpt:4o',
11
+ 'azureopenai:gpt:4o-mini',
12
+ 'azureopenai:gpt:4-turbo',
13
+ 'azureopenai:gpt:3.5-turbo',
14
+ // Add more supported models as needed
15
+ ]
16
+
17
+ static listSupportedModels(): void {
18
+ AzureOpenAIAdapter.supportedModels.forEach((model) => {
19
+ console.log(model)
20
+ })
21
+ }
22
+
23
+ constructor(model: string, endpoint: string) {
24
+ this.model = model
25
+ this.endpoint = endpoint
26
+ }
27
+
28
+ getEndpoint(): string {
29
+ return this.endpoint
30
+ }
31
+
32
+ getHeaders(apiKey: string): Record<string, string> {
33
+ return {
34
+ Authorization: `Bearer ${apiKey}`,
35
+ 'Content-Type': 'application/json',
36
+ }
37
+ }
38
+
39
+ getPayload(request: GPTRequest, stream: boolean = false): Record<string, any> {
40
+ return {
41
+ model: this.model.replace('azureopenai:', '').replace(':', '-'),
42
+ messages:
43
+ request.messages && request.messages.length > 0
44
+ ? request.messages
45
+ : [{ role: 'user', content: request.prompt }],
46
+ max_tokens: request.maxTokens,
47
+ temperature: request.temperature || 0.2,
48
+ stream,
49
+ }
50
+ }
51
+
52
+ extractResponse(data: any): string {
53
+ return data.choices[0].message.content
54
+ }
55
+
56
+ convertStream(data: string): OpenAIStreamChunk | null {
57
+ let beginningChar = 0
58
+ let lastChar = 0
59
+
60
+ while (lastChar < data.length) {
61
+ try {
62
+ let remainingString = data.slice(beginningChar, lastChar)
63
+
64
+ const firstBraceIndex = remainingString.indexOf('{')
65
+ if (firstBraceIndex > -1) {
66
+ remainingString = remainingString.slice(firstBraceIndex)
67
+ }
68
+
69
+ const parsedObject = JSON.parse(remainingString)
70
+ const output = parsedObject?.choices[0]?.delta?.content || ''
71
+
72
+ return {
73
+ output,
74
+ lastChar,
75
+ }
76
+ } catch (error) {
77
+ lastChar += 1
78
+ }
79
+ }
80
+
81
+ return null
82
+ }
83
+ }
@@ -0,0 +1,140 @@
1
+ import { Adapter } from '.'
2
+ import type { GPTRequest, OpenAIStreamChunk } from '../../utils/types'
3
+
4
+ /**
5
+ * ClaudeAdapter class implements the Adapter interface for Claude AI models.
6
+ */
7
+ export class ClaudeAdapter implements Adapter {
8
+ private model: string
9
+ private anthropicVersion: string
10
+
11
+ /**
12
+ * Array of supported Claude model identifiers.
13
+ */
14
+ static supportedModels: string[] = [
15
+ 'claude:claude-3-5:sonnet-20240620',
16
+ 'claude:claude-3:opus-20240229',
17
+ 'claude:claude-3:sonnet-20240229',
18
+ 'claude:claude-3:haiku-20240307',
19
+ // Add more supported models here as needed
20
+ ]
21
+
22
+ /**
23
+ * Initializes a new ClaudeAdapter instance.
24
+ * @param model - The Claude model identifier.
25
+ */
26
+ constructor(model: string) {
27
+ this.model = model
28
+ this.anthropicVersion = '2023-06-01'
29
+ }
30
+
31
+ /**
32
+ * Logs all supported Claude models to the console.
33
+ */
34
+ static listSupportedModels(): void {
35
+ ClaudeAdapter.supportedModels.forEach((model) => {
36
+ console.log(model)
37
+ })
38
+ }
39
+
40
+ /**
41
+ * Returns the API endpoint for Claude.
42
+ * @returns The API endpoint URL.
43
+ */
44
+ getEndpoint(): string {
45
+ return `https://api.anthropic.com/v1/messages`
46
+ }
47
+
48
+ /**
49
+ * Generates headers for API requests.
50
+ * @param apiKey - The API key for authentication.
51
+ * @returns An object containing the required headers.
52
+ */
53
+ getHeaders(apiKey: string): Record<string, string> {
54
+ return {
55
+ 'x-api-key': apiKey,
56
+ 'Content-Type': 'application/json',
57
+ 'anthropic-version': this.anthropicVersion,
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Prepares the payload for API requests.
63
+ * @param request - The GPTRequest object containing request details.
64
+ * @param stream - Whether to enable streaming (default: false).
65
+ * @returns An object containing the prepared payload.
66
+ */
67
+ getPayload(request: GPTRequest, stream: boolean = false): Record<string, any> {
68
+ let system = 'You are a computer programmer giving advice on how to write better code.'
69
+ if (request.messages && request.messages.length > 0 && request.messages[0].role === 'system') {
70
+ system = request.messages[0].content
71
+ request = { ...request, messages: request.messages.slice(1) }
72
+ }
73
+ return {
74
+ model: this.model.replace(':', '-'),
75
+ system,
76
+ messages:
77
+ request.messages && request.messages.length > 0
78
+ ? request.messages
79
+ : [{ role: 'user', content: request.prompt }],
80
+ max_tokens: request.maxTokens || 4096,
81
+ temperature: request.temperature || 0.2,
82
+ stream,
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Extracts the response text from the API response data.
88
+ * @param data - The API response data.
89
+ * @returns The extracted response text.
90
+ * @throws Error if the response structure is invalid.
91
+ */
92
+ extractResponse(data: any): string {
93
+ try {
94
+ if (data && data.content && Array.isArray(data.content) && data.content.length > 0) {
95
+ return data.content.map((item: any) => item.text).join('\n')
96
+ } else {
97
+ console.error('Unexpected response structure:', data)
98
+ throw new Error('Invalid response structure')
99
+ }
100
+ } catch (error) {
101
+ console.error('Error extracting response:', error)
102
+ throw error
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Converts streaming data to OpenAIStreamChunk format.
108
+ * @param data - The streaming data string.
109
+ * @returns An OpenAIStreamChunk object or null if parsing fails.
110
+ */
111
+ convertStream(data: string): OpenAIStreamChunk | null {
112
+ let beginningChar = 0
113
+ let lastChar = 0
114
+
115
+ while (lastChar < data.length) {
116
+ try {
117
+ let remainingString = data.slice(beginningChar, lastChar)
118
+
119
+ // Strip any leading characters until we encounter the first '{' in this block
120
+ const firstBraceIndex = remainingString.indexOf('{')
121
+ if (firstBraceIndex > -1) {
122
+ remainingString = remainingString.slice(firstBraceIndex)
123
+ }
124
+
125
+ const parsedObject = JSON.parse(remainingString)
126
+ const output = parsedObject?.delta?.text || ''
127
+
128
+ return {
129
+ output,
130
+ lastChar,
131
+ }
132
+ } catch (error) {
133
+ // Incrementally increase the size of the JSON string to parse
134
+ lastChar += 1
135
+ }
136
+ }
137
+
138
+ return null
139
+ }
140
+ }