@howlil/ez-agents 3.1.0 → 3.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 (110) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +288 -718
  3. package/bin/install.js +438 -71
  4. package/commands/ez/auth.md +87 -0
  5. package/commands/ez/join-discord.md +18 -18
  6. package/ez-agents/bin/ez-tools.cjs +120 -2
  7. package/ez-agents/bin/lib/assistant-adapter.cjs +264 -205
  8. package/ez-agents/bin/lib/audit-exec.cjs +26 -9
  9. package/ez-agents/bin/lib/auth.cjs +2 -1
  10. package/ez-agents/bin/lib/circuit-breaker.cjs +118 -118
  11. package/ez-agents/bin/lib/commands.cjs +42 -23
  12. package/ez-agents/bin/lib/config.cjs +190 -183
  13. package/ez-agents/bin/lib/core.cjs +42 -25
  14. package/ez-agents/bin/lib/file-lock.cjs +236 -236
  15. package/ez-agents/bin/lib/frontmatter.cjs +299 -299
  16. package/ez-agents/bin/lib/fs-utils.cjs +153 -153
  17. package/ez-agents/bin/lib/git-utils.cjs +203 -203
  18. package/ez-agents/bin/lib/health-check.cjs +2 -3
  19. package/ez-agents/bin/lib/index.cjs +113 -113
  20. package/ez-agents/bin/lib/init.cjs +757 -710
  21. package/ez-agents/bin/lib/logger.cjs +52 -15
  22. package/ez-agents/bin/lib/milestone.cjs +241 -241
  23. package/ez-agents/bin/lib/model-provider.cjs +241 -146
  24. package/ez-agents/bin/lib/phase.cjs +925 -908
  25. package/ez-agents/bin/lib/planning-write.cjs +107 -0
  26. package/ez-agents/bin/lib/retry.cjs +119 -119
  27. package/ez-agents/bin/lib/roadmap.cjs +306 -305
  28. package/ez-agents/bin/lib/safe-exec.cjs +91 -5
  29. package/ez-agents/bin/lib/safe-path.cjs +130 -130
  30. package/ez-agents/bin/lib/state.cjs +736 -721
  31. package/ez-agents/bin/lib/temp-file.cjs +239 -239
  32. package/ez-agents/bin/lib/template.cjs +223 -222
  33. package/ez-agents/bin/lib/test-file-lock.cjs +112 -112
  34. package/ez-agents/bin/lib/test-graceful.cjs +93 -93
  35. package/ez-agents/bin/lib/test-logger.cjs +60 -60
  36. package/ez-agents/bin/lib/test-safe-exec.cjs +38 -38
  37. package/ez-agents/bin/lib/test-safe-path.cjs +33 -33
  38. package/ez-agents/bin/lib/test-temp-file.cjs +125 -125
  39. package/ez-agents/bin/lib/timeout-exec.cjs +63 -62
  40. package/ez-agents/bin/lib/verify.cjs +69 -26
  41. package/ez-agents/references/checkpoints.md +776 -776
  42. package/ez-agents/references/continuation-format.md +249 -249
  43. package/ez-agents/references/questioning.md +162 -162
  44. package/ez-agents/references/tdd.md +263 -263
  45. package/ez-agents/templates/codebase/concerns.md +310 -310
  46. package/ez-agents/templates/codebase/conventions.md +307 -307
  47. package/ez-agents/templates/codebase/integrations.md +280 -280
  48. package/ez-agents/templates/codebase/stack.md +186 -186
  49. package/ez-agents/templates/codebase/testing.md +480 -480
  50. package/ez-agents/templates/config.json +37 -37
  51. package/ez-agents/templates/continue-here.md +78 -78
  52. package/ez-agents/templates/milestone-archive.md +123 -123
  53. package/ez-agents/templates/milestone.md +115 -115
  54. package/ez-agents/templates/requirements.md +231 -231
  55. package/ez-agents/templates/research-project/ARCHITECTURE.md +204 -204
  56. package/ez-agents/templates/research-project/FEATURES.md +147 -147
  57. package/ez-agents/templates/research-project/PITFALLS.md +200 -200
  58. package/ez-agents/templates/research-project/STACK.md +120 -120
  59. package/ez-agents/templates/research-project/SUMMARY.md +170 -170
  60. package/ez-agents/templates/retrospective.md +54 -54
  61. package/ez-agents/templates/roadmap.md +202 -202
  62. package/ez-agents/templates/summary-minimal.md +41 -41
  63. package/ez-agents/templates/summary-standard.md +48 -48
  64. package/ez-agents/templates/summary.md +248 -248
  65. package/ez-agents/templates/user-setup.md +311 -311
  66. package/ez-agents/templates/verification-report.md +322 -322
  67. package/ez-agents/workflows/add-phase.md +112 -112
  68. package/ez-agents/workflows/add-tests.md +351 -351
  69. package/ez-agents/workflows/add-todo.md +158 -158
  70. package/ez-agents/workflows/audit-milestone.md +332 -332
  71. package/ez-agents/workflows/autonomous.md +743 -743
  72. package/ez-agents/workflows/check-todos.md +177 -177
  73. package/ez-agents/workflows/cleanup.md +152 -152
  74. package/ez-agents/workflows/complete-milestone.md +766 -766
  75. package/ez-agents/workflows/diagnose-issues.md +219 -219
  76. package/ez-agents/workflows/discovery-phase.md +289 -289
  77. package/ez-agents/workflows/discuss-phase.md +762 -762
  78. package/ez-agents/workflows/execute-phase.md +468 -468
  79. package/ez-agents/workflows/execute-plan.md +483 -483
  80. package/ez-agents/workflows/health.md +159 -159
  81. package/ez-agents/workflows/help.md +492 -492
  82. package/ez-agents/workflows/insert-phase.md +130 -130
  83. package/ez-agents/workflows/list-phase-assumptions.md +178 -178
  84. package/ez-agents/workflows/map-codebase.md +316 -316
  85. package/ez-agents/workflows/new-milestone.md +384 -384
  86. package/ez-agents/workflows/new-project.md +1113 -1111
  87. package/ez-agents/workflows/node-repair.md +92 -92
  88. package/ez-agents/workflows/pause-work.md +122 -122
  89. package/ez-agents/workflows/plan-milestone-gaps.md +274 -274
  90. package/ez-agents/workflows/plan-phase.md +651 -651
  91. package/ez-agents/workflows/progress.md +382 -382
  92. package/ez-agents/workflows/quick.md +610 -610
  93. package/ez-agents/workflows/remove-phase.md +155 -155
  94. package/ez-agents/workflows/research-phase.md +74 -74
  95. package/ez-agents/workflows/resume-project.md +307 -307
  96. package/ez-agents/workflows/set-profile.md +81 -81
  97. package/ez-agents/workflows/settings.md +242 -242
  98. package/ez-agents/workflows/stats.md +57 -57
  99. package/ez-agents/workflows/transition.md +544 -544
  100. package/ez-agents/workflows/ui-phase.md +290 -290
  101. package/ez-agents/workflows/ui-review.md +157 -157
  102. package/ez-agents/workflows/update.md +320 -320
  103. package/ez-agents/workflows/validate-phase.md +167 -167
  104. package/ez-agents/workflows/verify-phase.md +243 -243
  105. package/ez-agents/workflows/verify-work.md +584 -584
  106. package/package.json +2 -3
  107. package/scripts/build-hooks.js +43 -43
  108. package/scripts/fix-qwen-installation.js +144 -0
  109. package/scripts/run-tests.cjs +29 -29
  110. package/README.zh-CN.md +0 -702
@@ -1,205 +1,264 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * GSD Assistant Adapters — Unified interface for AI coding assistants
5
- *
6
- * Adapters for: Claude Code, OpenCode, Gemini CLI, Codex
7
- *
8
- * Usage:
9
- * const { createAdapter } = require('./assistant-adapter.cjs');
10
- * const adapter = createAdapter('claude-code');
11
- * await adapter.spawnAgent('planner', { prompt: '...' });
12
- */
13
-
14
- const Logger = require('./logger.cjs');
15
- const logger = new Logger();
16
-
17
- /**
18
- * Base adapter interface
19
- */
20
- class AssistantAdapter {
21
- constructor(name) {
22
- if (new.target === AssistantAdapter) {
23
- throw new Error('AssistantAdapter is abstract - use a concrete subclass');
24
- }
25
- this.name = name;
26
- }
27
-
28
- /**
29
- * Spawn a subagent
30
- * @param {string} type - Agent type
31
- * @param {Object} options - Agent options
32
- * @returns {Promise<Object>} - Agent result
33
- */
34
- async spawnAgent(type, options) {
35
- throw new Error('spawnAgent must be implemented');
36
- }
37
-
38
- /**
39
- * Call a tool/function
40
- * @param {string} tool - Tool name
41
- * @param {Object} params - Tool parameters
42
- * @returns {Promise<any>} - Tool result
43
- */
44
- async callTool(tool, params) {
45
- throw new Error('callTool must be implemented');
46
- }
47
-
48
- /**
49
- * Select model for task
50
- * @param {string} taskType - Task type (planning, execution, verification)
51
- * @returns {string} - Model name
52
- */
53
- selectModel(taskType) {
54
- throw new Error('selectModel must be implemented');
55
- }
56
-
57
- /**
58
- * Get adapter info
59
- * @returns {Object} - Adapter information
60
- */
61
- getInfo() {
62
- return {
63
- name: this.name,
64
- type: this.constructor.name
65
- };
66
- }
67
- }
68
-
69
- /**
70
- * Claude Code adapter
71
- */
72
- class ClaudeCodeAdapter extends AssistantAdapter {
73
- constructor() {
74
- super('claude-code');
75
- }
76
-
77
- async spawnAgent(type, options) {
78
- logger.info('Claude Code: spawning agent', { type });
79
- // Would use Claude Code's Task tool in production
80
- return { type, status: 'completed', result: '[Claude Code agent result]' };
81
- }
82
-
83
- async callTool(tool, params) {
84
- logger.info('Claude Code: calling tool', { tool });
85
- // Would use Claude Code's tool system
86
- return { tool, status: 'success' };
87
- }
88
-
89
- selectModel(taskType) {
90
- const models = {
91
- planning: 'claude-3-opus',
92
- execution: 'claude-3-sonnet',
93
- verification: 'claude-3-sonnet'
94
- };
95
- return models[taskType] || models.execution;
96
- }
97
- }
98
-
99
- /**
100
- * OpenCode adapter
101
- */
102
- class OpenCodeAdapter extends AssistantAdapter {
103
- constructor() {
104
- super('opencode');
105
- }
106
-
107
- async spawnAgent(type, options) {
108
- logger.info('OpenCode: spawning agent', { type });
109
- return { type, status: 'completed', result: '[OpenCode agent result]' };
110
- }
111
-
112
- async callTool(tool, params) {
113
- logger.info('OpenCode: calling tool', { tool });
114
- return { tool, status: 'success' };
115
- }
116
-
117
- selectModel(taskType) {
118
- return 'gpt-4-turbo';
119
- }
120
- }
121
-
122
- /**
123
- * Gemini CLI adapter
124
- */
125
- class GeminiAdapter extends AssistantAdapter {
126
- constructor() {
127
- super('gemini');
128
- }
129
-
130
- async spawnAgent(type, options) {
131
- logger.info('Gemini: spawning agent', { type });
132
- return { type, status: 'completed', result: '[Gemini agent result]' };
133
- }
134
-
135
- async callTool(tool, params) {
136
- logger.info('Gemini: calling tool', { tool });
137
- return { tool, status: 'success' };
138
- }
139
-
140
- selectModel(taskType) {
141
- return 'gemini-pro';
142
- }
143
- }
144
-
145
- /**
146
- * Codex adapter
147
- */
148
- class CodexAdapter extends AssistantAdapter {
149
- constructor() {
150
- super('codex');
151
- }
152
-
153
- async spawnAgent(type, options) {
154
- logger.info('Codex: spawning agent', { type });
155
- return { type, status: 'completed', result: '[Codex agent result]' };
156
- }
157
-
158
- async callTool(tool, params) {
159
- logger.info('Codex: calling tool', { tool });
160
- return { tool, status: 'success' };
161
- }
162
-
163
- selectModel(taskType) {
164
- return 'codex-latest';
165
- }
166
- }
167
-
168
- /**
169
- * Factory function to create adapter
170
- * @param {string} type - Adapter type
171
- * @returns {AssistantAdapter} - Adapter instance
172
- */
173
- function createAdapter(type) {
174
- const adapters = {
175
- 'claude-code': ClaudeCodeAdapter,
176
- 'opencode': OpenCodeAdapter,
177
- 'gemini': GeminiAdapter,
178
- 'codex': CodexAdapter
179
- };
180
-
181
- const AdapterClass = adapters[type];
182
- if (!AdapterClass) {
183
- throw new Error(`Unknown adapter type: ${type}. Available: ${Object.keys(adapters).join(', ')}`);
184
- }
185
-
186
- return new AdapterClass();
187
- }
188
-
189
- /**
190
- * Get available adapters
191
- * @returns {string[]} - List of adapter names
192
- */
193
- function getAvailableAdapters() {
194
- return ['claude-code', 'opencode', 'gemini', 'codex'];
195
- }
196
-
197
- module.exports = {
198
- AssistantAdapter,
199
- ClaudeCodeAdapter,
200
- OpenCodeAdapter,
201
- GeminiAdapter,
202
- CodexAdapter,
203
- createAdapter,
204
- getAvailableAdapters
205
- };
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * EZ Assistant Adapters — Unified interface for AI coding assistants
5
+ *
6
+ * Adapters for: Claude Code, OpenCode, Gemini CLI, Codex
7
+ *
8
+ * Usage:
9
+ * const { createAdapter } = require('./assistant-adapter.cjs');
10
+ * const adapter = createAdapter('claude-code');
11
+ * await adapter.spawnAgent('planner', { prompt: '...' });
12
+ */
13
+
14
+ const Logger = require('./logger.cjs');
15
+ const logger = new Logger();
16
+
17
+ /**
18
+ * Base adapter interface
19
+ */
20
+ class AssistantAdapter {
21
+ constructor(name) {
22
+ if (new.target === AssistantAdapter) {
23
+ throw new Error('AssistantAdapter is abstract - use a concrete subclass');
24
+ }
25
+ this.name = name;
26
+ }
27
+
28
+ /**
29
+ * Spawn a subagent
30
+ * @param {string} type - Agent type
31
+ * @param {Object} options - Agent options
32
+ * @returns {Promise<Object>} - Agent result
33
+ */
34
+ async spawnAgent(type, options) {
35
+ throw new Error('spawnAgent must be implemented');
36
+ }
37
+
38
+ /**
39
+ * Call a tool/function
40
+ * @param {string} tool - Tool name
41
+ * @param {Object} params - Tool parameters
42
+ * @returns {Promise<any>} - Tool result
43
+ */
44
+ async callTool(tool, params) {
45
+ throw new Error('callTool must be implemented');
46
+ }
47
+
48
+ /**
49
+ * Select model for task
50
+ * @param {string} taskType - Task type (planning, execution, verification)
51
+ * @returns {string} - Model name
52
+ */
53
+ selectModel(taskType) {
54
+ throw new Error('selectModel must be implemented');
55
+ }
56
+
57
+ /**
58
+ * Get adapter info
59
+ * @returns {Object} - Adapter information
60
+ */
61
+ getInfo() {
62
+ return {
63
+ name: this.name,
64
+ type: this.constructor.name
65
+ };
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Claude Code adapter
71
+ */
72
+ class ClaudeCodeAdapter extends AssistantAdapter {
73
+ constructor() {
74
+ super('claude-code');
75
+ }
76
+
77
+ async spawnAgent(type, options) {
78
+ logger.info('Claude Code: spawning agent', { type });
79
+ // Would use Claude Code's Task tool in production
80
+ return { type, status: 'completed', result: '[Claude Code agent result]' };
81
+ }
82
+
83
+ async callTool(tool, params) {
84
+ logger.info('Claude Code: calling tool', { tool });
85
+ // Would use Claude Code's tool system
86
+ return { tool, status: 'success' };
87
+ }
88
+
89
+ selectModel(taskType) {
90
+ const models = {
91
+ planning: 'claude-3-opus',
92
+ execution: 'claude-3-sonnet',
93
+ verification: 'claude-3-sonnet'
94
+ };
95
+ return models[taskType] || models.execution;
96
+ }
97
+ }
98
+
99
+ /**
100
+ * OpenCode adapter
101
+ */
102
+ class OpenCodeAdapter extends AssistantAdapter {
103
+ constructor() {
104
+ super('opencode');
105
+ }
106
+
107
+ async spawnAgent(type, options) {
108
+ logger.info('OpenCode: spawning agent', { type });
109
+ return { type, status: 'completed', result: '[OpenCode agent result]' };
110
+ }
111
+
112
+ async callTool(tool, params) {
113
+ logger.info('OpenCode: calling tool', { tool });
114
+ return { tool, status: 'success' };
115
+ }
116
+
117
+ selectModel(taskType) {
118
+ return 'gpt-4-turbo';
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Gemini CLI adapter
124
+ */
125
+ class GeminiAdapter extends AssistantAdapter {
126
+ constructor() {
127
+ super('gemini');
128
+ }
129
+
130
+ async spawnAgent(type, options) {
131
+ logger.info('Gemini: spawning agent', { type });
132
+ return { type, status: 'completed', result: '[Gemini agent result]' };
133
+ }
134
+
135
+ async callTool(tool, params) {
136
+ logger.info('Gemini: calling tool', { tool });
137
+ return { tool, status: 'success' };
138
+ }
139
+
140
+ selectModel(taskType) {
141
+ return 'gemini-pro';
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Codex adapter
147
+ */
148
+ class CodexAdapter extends AssistantAdapter {
149
+ constructor() {
150
+ super('codex');
151
+ }
152
+
153
+ async spawnAgent(type, options) {
154
+ logger.info('Codex: spawning agent', { type });
155
+ return { type, status: 'completed', result: '[Codex agent result]' };
156
+ }
157
+
158
+ async callTool(tool, params) {
159
+ logger.info('Codex: calling tool', { tool });
160
+ return { tool, status: 'success' };
161
+ }
162
+
163
+ selectModel(taskType) {
164
+ return 'codex-latest';
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Qwen Code adapter
170
+ */
171
+ class QwenAdapter extends AssistantAdapter {
172
+ constructor() {
173
+ super('qwen');
174
+ }
175
+
176
+ async spawnAgent(type, options) {
177
+ logger.info('Qwen Code: spawning agent', { type });
178
+ // Qwen Code uses its own agent system
179
+ return { type, status: 'completed', result: '[Qwen Code agent result]' };
180
+ }
181
+
182
+ async callTool(tool, params) {
183
+ logger.info('Qwen Code: calling tool', { tool });
184
+ return { tool, status: 'success' };
185
+ }
186
+
187
+ selectModel(taskType) {
188
+ const models = {
189
+ planning: 'qwen-max',
190
+ execution: 'qwen-plus',
191
+ verification: 'qwen-plus'
192
+ };
193
+ return models[taskType] || models.execution;
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Kimi Code adapter
199
+ */
200
+ class KimiAdapter extends AssistantAdapter {
201
+ constructor() {
202
+ super('kimi');
203
+ }
204
+
205
+ async spawnAgent(type, options) {
206
+ logger.info('Kimi Code: spawning agent', { type });
207
+ return { type, status: 'completed', result: '[Kimi Code agent result]' };
208
+ }
209
+
210
+ async callTool(tool, params) {
211
+ logger.info('Kimi Code: calling tool', { tool });
212
+ return { tool, status: 'success' };
213
+ }
214
+
215
+ selectModel(taskType) {
216
+ const models = {
217
+ planning: 'moonshot-v1-32k',
218
+ execution: 'moonshot-v1-8k',
219
+ verification: 'moonshot-v1-8k'
220
+ };
221
+ return models[taskType] || models.execution;
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Factory function to create adapter
227
+ * @param {string} type - Adapter type
228
+ * @returns {AssistantAdapter} - Adapter instance
229
+ */
230
+ function createAdapter(type) {
231
+ const adapters = {
232
+ 'claude-code': ClaudeCodeAdapter,
233
+ 'opencode': OpenCodeAdapter,
234
+ 'gemini': GeminiAdapter,
235
+ 'codex': CodexAdapter,
236
+ 'qwen': QwenAdapter,
237
+ 'kimi': KimiAdapter
238
+ };
239
+
240
+ const AdapterClass = adapters[type];
241
+ if (!AdapterClass) {
242
+ throw new Error(`Unknown adapter type: ${type}. Available: ${Object.keys(adapters).join(', ')}`);
243
+ }
244
+
245
+ return new AdapterClass();
246
+ }
247
+
248
+ /**
249
+ * Get available adapters
250
+ * @returns {string[]} - List of adapter names
251
+ */
252
+ function getAvailableAdapters() {
253
+ return ['claude-code', 'opencode', 'gemini', 'codex', 'qwen', 'kimi'];
254
+ }
255
+
256
+ module.exports = {
257
+ AssistantAdapter,
258
+ ClaudeCodeAdapter,
259
+ OpenCodeAdapter,
260
+ GeminiAdapter,
261
+ CodexAdapter,
262
+ createAdapter,
263
+ getAvailableAdapters
264
+ };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * GSD Audit Exec — Command execution with full audit logging
4
+ * EZ Audit Exec — Command execution with full audit logging
5
5
  *
6
6
  * Logs all command executions to audit file for security review:
7
7
  * - Timestamp, command, arguments, context
@@ -22,13 +22,25 @@ const logger = new Logger();
22
22
 
23
23
  const execFileAsync = promisify(execFile);
24
24
 
25
- // Audit log file path
26
- const AUDIT_DIR = join('.planning', 'logs');
27
- const AUDIT_FILE = join(AUDIT_DIR, `audit-${new Date().toISOString().split('T')[0]}.jsonl`);
25
+ // Audit log file path - lazy init
26
+ let _AUDIT_DIR;
27
+ let _AUDIT_FILE;
28
28
 
29
- // Ensure audit directory exists
30
- if (!existsSync(AUDIT_DIR)) {
31
- mkdirSync(AUDIT_DIR, { recursive: true });
29
+ function getAuditDir() {
30
+ if (!_AUDIT_DIR) {
31
+ _AUDIT_DIR = join('.planning', 'logs');
32
+ if (!existsSync(_AUDIT_DIR)) {
33
+ mkdirSync(_AUDIT_DIR, { recursive: true });
34
+ }
35
+ }
36
+ return _AUDIT_DIR;
37
+ }
38
+
39
+ function getAuditFile() {
40
+ if (!_AUDIT_FILE) {
41
+ _AUDIT_FILE = join(getAuditDir(), `audit-${new Date().toISOString().split('T')[0]}.jsonl`);
42
+ }
43
+ return _AUDIT_FILE;
32
44
  }
33
45
 
34
46
  /**
@@ -36,8 +48,13 @@ if (!existsSync(AUDIT_DIR)) {
36
48
  * @param {Object} entry - Audit entry
37
49
  */
38
50
  function writeAudit(entry) {
39
- const line = JSON.stringify(entry) + '\n';
40
- appendFileSync(AUDIT_FILE, line, 'utf-8');
51
+ try {
52
+ const line = JSON.stringify(entry) + '\n';
53
+ appendFileSync(getAuditFile(), line, 'utf-8');
54
+ } catch (err) {
55
+ // Silently ignore audit write failures - logging is best-effort
56
+ // This can happen in temp test directories or when .planning doesn't exist
57
+ }
41
58
  }
42
59
 
43
60
  /**
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * GSD Auth — Secure credential storage using system keychain
4
+ * EZ Auth — Secure credential storage using system keychain
5
5
  *
6
6
  * Stores API keys securely using:
7
7
  * - keytar for system keychain (Windows Credential Manager, macOS Keychain, libsecret)
@@ -25,6 +25,7 @@ const PROVIDERS = {
25
25
  ANTHROPIC: 'anthropic',
26
26
  MOONSHOT: 'moonshot',
27
27
  ALIBABA: 'alibaba',
28
+ QWEN: 'qwen',
28
29
  OPENAI: 'openai'
29
30
  };
30
31