@zhongqian97-code/ecode 0.3.4 → 0.3.6

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 (2) hide show
  1. package/dist/index.js +55 -8
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -94,7 +94,14 @@ function loadConfig() {
94
94
  logDir: process.env.ECODE_LOG_DIR ?? fileConfig.logDir ?? DEFAULTS.logDir,
95
95
  // contextLimit 仅支持配置文件配置:数值类型在文件中更直观,
96
96
  // 环境变量还需要 parseInt 转换,增加出错风险
97
- contextLimit: fileConfig.contextLimit
97
+ contextLimit: fileConfig.contextLimit,
98
+ // ECODE_SYSTEM_PROMPT 环境变量优先;未设时从配置文件读取;
99
+ // 两者均未设时保持 undefined(由 resolveSystemPrompt 决定使用内置默认值)。
100
+ // 注意:空字符串 "" 是有效值(表示禁用),?? 不会跳过空字符串。
101
+ systemPrompt: process.env.ECODE_SYSTEM_PROMPT ?? fileConfig.systemPrompt,
102
+ // providers/defaultProvider 仅支持配置文件配置,不支持环境变量注入
103
+ providers: fileConfig.providers,
104
+ defaultProvider: fileConfig.defaultProvider
98
105
  };
99
106
  }
100
107
 
@@ -102,14 +109,23 @@ function loadConfig() {
102
109
  import { useState as useState3, useCallback, useRef as useRef2, useEffect as useEffect3, useMemo } from "react";
103
110
  import { Box as Box6, useInput as useInput2, useStdout, useStdin } from "ink";
104
111
 
105
- // src/llm.ts
112
+ // src/providers/openai.ts
106
113
  import OpenAI from "openai";
107
- function createLLMClient(config2) {
114
+ function createOpenAIProvider(profile) {
108
115
  const openai = new OpenAI({
109
- baseURL: config2.baseUrl,
110
- apiKey: config2.apiKey
116
+ baseURL: profile.baseUrl,
117
+ apiKey: profile.apiKey
111
118
  });
119
+ const capabilities = Object.freeze(
120
+ Object.defineProperties({}, {
121
+ supportsTools: { value: true, writable: false, enumerable: true, configurable: false },
122
+ supportsReasoningStream: { value: true, writable: false, enumerable: true, configurable: false },
123
+ supportsImages: { value: false, writable: false, enumerable: true, configurable: false },
124
+ supportsJsonSchema: { value: true, writable: false, enumerable: true, configurable: false }
125
+ })
126
+ );
112
127
  return {
128
+ capabilities,
113
129
  /**
114
130
  * stream 方法向 LLM 发起一次流式对话请求,返回异步可迭代的 chunk 序列。
115
131
  *
@@ -123,12 +139,13 @@ function createLLMClient(config2) {
123
139
  *
124
140
  * @param messages 完整的对话历史,包含 user/assistant/tool 所有轮次
125
141
  * @param tools 可选的工具列表,不传或传空数组时不附加 tools 字段
142
+ * @param signal 可选的 AbortSignal,用于取消请求
126
143
  */
127
144
  stream(messages, tools, signal) {
128
145
  return {
129
146
  [Symbol.asyncIterator]: async function* () {
130
147
  const requestParams = {
131
- model: config2.model,
148
+ model: profile.model,
132
149
  messages,
133
150
  stream: true,
134
151
  stream_options: { include_usage: true }
@@ -196,6 +213,36 @@ function createLLMClient(config2) {
196
213
  };
197
214
  }
198
215
 
216
+ // src/providers/index.ts
217
+ function createProvider(profile) {
218
+ return createOpenAIProvider(profile);
219
+ }
220
+ function resolveActiveProfile(config2, providerName) {
221
+ if (providerName !== void 0) {
222
+ const profile = config2.providers?.[providerName];
223
+ if (!profile) {
224
+ throw new Error(`Provider '${providerName}' not found`);
225
+ }
226
+ return profile;
227
+ }
228
+ if (config2.defaultProvider) {
229
+ const profile = config2.providers?.[config2.defaultProvider];
230
+ if (profile) return profile;
231
+ }
232
+ if (config2.providers) {
233
+ if (config2.providers["default"]) {
234
+ return config2.providers["default"];
235
+ }
236
+ const first = Object.values(config2.providers)[0];
237
+ if (first) return first;
238
+ }
239
+ return {
240
+ baseUrl: config2.baseUrl,
241
+ apiKey: config2.apiKey,
242
+ model: config2.model
243
+ };
244
+ }
245
+
199
246
  // src/repl.ts
200
247
  import * as readline from "readline/promises";
201
248
 
@@ -1993,7 +2040,7 @@ function App({ config: config2, version: version2, autoMode: autoMode2 = false,
1993
2040
  totalLinesRef.current = totalLines;
1994
2041
  const pendingConfirmRef = useRef2(null);
1995
2042
  const abortControllerRef = useRef2(null);
1996
- const llmRef = useRef2(llmClient ?? createLLMClient(config2));
2043
+ const llmRef = useRef2(llmClient ?? createProvider(resolveActiveProfile(config2)));
1997
2044
  const inputRef = useRef2(null);
1998
2045
  const [skillTools, setSkillTools] = useState3([]);
1999
2046
  const skillToolsRef = useRef2([]);
@@ -2677,7 +2724,7 @@ for (const dir of [builtinSkillsDir, userSkillsDir, projectSkillsDir]) {
2677
2724
  var trustedSkillDirs = [builtinSkillsDir, userSkillsDir, projectSkillsDir];
2678
2725
  if (pipeMode) {
2679
2726
  const prompt = await readStdin();
2680
- const llm = createLLMClient(finalConfig);
2727
+ const llm = createProvider(resolveActiveProfile(finalConfig));
2681
2728
  await runPipe(prompt, llm);
2682
2729
  process.exit(0);
2683
2730
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhongqian97-code/ecode",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "A minimal Claude Code clone with REPL interface and bash tool calling",
5
5
  "type": "module",
6
6
  "author": "zhongqian97-code",