homegraph 1.1.1 → 1.1.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.
@@ -11,12 +11,17 @@
11
11
  *
12
12
  * Config file resolution (per DevEco Code docs):
13
13
  * - local: `.deveco/deveco.jsonc` → `deveco.jsonc` (defaults to `.deveco/`)
14
- * - global: `~/.config/deveco/deveco.jsonc` (XDG-style;
15
- * `%APPDATA%/deveco/deveco.jsonc` on Windows)
14
+ * - global: `~/.config/deveco/deveco.jsonc` (XDG-style on EVERY platform,
15
+ * Windows included — DevEco uses the same `xdg-basedir` resolution
16
+ * as opencode, not `%APPDATA%`)
16
17
  *
17
18
  * Like Cursor, DevEco Code may launch MCP servers with a cwd that
18
19
  * isn't the workspace root, so we inject `--path` into the command
19
20
  * array.
21
+ *
22
+ * Early homegraph installs wrote the global entry to `%APPDATA%/deveco` on
23
+ * Windows; DevEco never reads it. install/uninstall sweep stale entries
24
+ * from that legacy location.
20
25
  */
21
26
  import { AgentTarget } from './types';
22
27
  export declare const devecoTarget: AgentTarget;
@@ -1 +1 @@
1
- {"version":3,"file":"deveco.d.ts","sourceRoot":"","sources":["../../../src/installer/targets/deveco.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,OAAO,EACL,WAAW,EAKZ,MAAM,SAAS,CAAC;AA2LjB,eAAO,MAAM,YAAY,EAAE,WAAgC,CAAC"}
1
+ {"version":3,"file":"deveco.d.ts","sourceRoot":"","sources":["../../../src/installer/targets/deveco.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAMH,OAAO,EACL,WAAW,EAKZ,MAAM,SAAS,CAAC;AAgNjB,eAAO,MAAM,YAAY,EAAE,WAAgC,CAAC"}
@@ -12,12 +12,17 @@
12
12
  *
13
13
  * Config file resolution (per DevEco Code docs):
14
14
  * - local: `.deveco/deveco.jsonc` → `deveco.jsonc` (defaults to `.deveco/`)
15
- * - global: `~/.config/deveco/deveco.jsonc` (XDG-style;
16
- * `%APPDATA%/deveco/deveco.jsonc` on Windows)
15
+ * - global: `~/.config/deveco/deveco.jsonc` (XDG-style on EVERY platform,
16
+ * Windows included — DevEco uses the same `xdg-basedir` resolution
17
+ * as opencode, not `%APPDATA%`)
17
18
  *
18
19
  * Like Cursor, DevEco Code may launch MCP servers with a cwd that
19
20
  * isn't the workspace root, so we inject `--path` into the command
20
21
  * array.
22
+ *
23
+ * Early homegraph installs wrote the global entry to `%APPDATA%/deveco` on
24
+ * Windows; DevEco never reads it. install/uninstall sweep stale entries
25
+ * from that legacy location.
21
26
  */
22
27
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
23
28
  if (k2 === undefined) k2 = k;
@@ -61,15 +66,23 @@ const jsonc_parser_1 = require("jsonc-parser");
61
66
  const shared_1 = require("./shared");
62
67
  const instructions_template_1 = require("../instructions-template");
63
68
  function globalConfigDir() {
64
- if (process.platform === 'win32') {
65
- const appData = process.env.APPDATA ?? path.join(os.homedir(), 'AppData', 'Roaming');
66
- return path.join(appData, 'deveco');
67
- }
68
69
  const xdg = process.env.XDG_CONFIG_HOME && process.env.XDG_CONFIG_HOME.trim().length > 0
69
70
  ? process.env.XDG_CONFIG_HOME
70
71
  : path.join(os.homedir(), '.config');
71
72
  return path.join(xdg, 'deveco');
72
73
  }
74
+ /**
75
+ * Early installs wrote the global entry to `%APPDATA%/deveco` on Windows — a
76
+ * dir DevEco never reads. Returns that legacy dir when it could hold stale
77
+ * state (APPDATA set and resolving somewhere other than the real config dir).
78
+ */
79
+ function legacyWindowsConfigDir() {
80
+ const appData = process.env.APPDATA;
81
+ if (!appData || !appData.trim())
82
+ return null;
83
+ const legacy = path.join(appData, 'deveco');
84
+ return path.resolve(legacy) === path.resolve(globalConfigDir()) ? null : legacy;
85
+ }
73
86
  function configBaseDir(loc) {
74
87
  return loc === 'global' ? globalConfigDir() : process.cwd();
75
88
  }
@@ -123,8 +136,9 @@ class DevecoTarget {
123
136
  const file = configPath(loc);
124
137
  const config = parseConfig(readConfigText(file));
125
138
  const alreadyConfigured = !!config.mcp?.homegraph;
139
+ const legacy = legacyWindowsConfigDir();
126
140
  const installed = loc === 'global'
127
- ? fs.existsSync(globalConfigDir())
141
+ ? fs.existsSync(globalConfigDir()) || (!!legacy && fs.existsSync(legacy))
128
142
  : fs.existsSync(path.join(process.cwd(), '.deveco'))
129
143
  || fs.existsSync(path.join(process.cwd(), 'deveco.jsonc'));
130
144
  return { installed, alreadyConfigured, configPath: file };
@@ -135,6 +149,8 @@ class DevecoTarget {
135
149
  const instrCleanup = removeInstructionsEntry(loc);
136
150
  if (instrCleanup.action === 'removed')
137
151
  files.push(instrCleanup);
152
+ if (loc === 'global')
153
+ files.push(...cleanupLegacyWindowsState());
138
154
  return {
139
155
  files,
140
156
  notes: ['Restart DevEco Code for MCP changes to take effect.'],
@@ -142,32 +158,10 @@ class DevecoTarget {
142
158
  }
143
159
  uninstall(loc) {
144
160
  const files = [];
145
- const file = configPath(loc);
146
- if (!fs.existsSync(file)) {
147
- files.push({ path: file, action: 'not-found' });
148
- }
149
- else {
150
- const text = readConfigText(file);
151
- const config = parseConfig(text);
152
- if (!config.mcp?.homegraph) {
153
- files.push({ path: file, action: 'not-found' });
154
- }
155
- else {
156
- let edits = (0, jsonc_parser_1.modify)(text, ['mcp', 'homegraph'], undefined, {
157
- formattingOptions: FORMATTING,
158
- });
159
- let updated = (0, jsonc_parser_1.applyEdits)(text, edits);
160
- const afterParsed = parseConfig(updated);
161
- if (afterParsed.mcp && typeof afterParsed.mcp === 'object' &&
162
- Object.keys(afterParsed.mcp).length === 0) {
163
- edits = (0, jsonc_parser_1.modify)(updated, ['mcp'], undefined, { formattingOptions: FORMATTING });
164
- updated = (0, jsonc_parser_1.applyEdits)(updated, edits);
165
- }
166
- (0, shared_1.atomicWriteFileSync)(file, updated);
167
- files.push({ path: file, action: 'removed' });
168
- }
169
- }
161
+ files.push(removeMcpEntryAt(configPath(loc)));
170
162
  files.push(removeInstructionsEntry(loc));
163
+ if (loc === 'global')
164
+ files.push(...cleanupLegacyWindowsState());
171
165
  return { files };
172
166
  }
173
167
  printConfig(loc) {
@@ -208,6 +202,42 @@ function writeMcpEntry(loc) {
208
202
  (0, shared_1.atomicWriteFileSync)(file, updated);
209
203
  return { path: file, action: existed ? 'updated' : 'created' };
210
204
  }
205
+ function removeMcpEntryAt(file) {
206
+ if (!fs.existsSync(file))
207
+ return { path: file, action: 'not-found' };
208
+ const text = readConfigText(file);
209
+ const config = parseConfig(text);
210
+ if (!config.mcp?.homegraph)
211
+ return { path: file, action: 'not-found' };
212
+ let edits = (0, jsonc_parser_1.modify)(text, ['mcp', 'homegraph'], undefined, {
213
+ formattingOptions: FORMATTING,
214
+ });
215
+ let updated = (0, jsonc_parser_1.applyEdits)(text, edits);
216
+ const afterParsed = parseConfig(updated);
217
+ if (afterParsed.mcp && typeof afterParsed.mcp === 'object' &&
218
+ Object.keys(afterParsed.mcp).length === 0) {
219
+ edits = (0, jsonc_parser_1.modify)(updated, ['mcp'], undefined, { formattingOptions: FORMATTING });
220
+ updated = (0, jsonc_parser_1.applyEdits)(updated, edits);
221
+ }
222
+ (0, shared_1.atomicWriteFileSync)(file, updated);
223
+ return { path: file, action: 'removed' };
224
+ }
225
+ function cleanupLegacyWindowsState() {
226
+ const dir = legacyWindowsConfigDir();
227
+ if (!dir || !fs.existsSync(dir))
228
+ return [];
229
+ const out = [];
230
+ for (const name of ['deveco.jsonc', 'deveco.json']) {
231
+ const res = removeMcpEntryAt(path.join(dir, name));
232
+ if (res.action === 'removed')
233
+ out.push(res);
234
+ }
235
+ const agents = path.join(dir, 'AGENTS.md');
236
+ const action = (0, shared_1.removeMarkedSection)(agents, instructions_template_1.HOMEGRAPH_SECTION_START, instructions_template_1.HOMEGRAPH_SECTION_END);
237
+ if (action === 'removed')
238
+ out.push({ path: agents, action });
239
+ return out;
240
+ }
211
241
  function removeInstructionsEntry(loc) {
212
242
  const file = instructionsPath(loc);
213
243
  const action = (0, shared_1.removeMarkedSection)(file, instructions_template_1.HOMEGRAPH_SECTION_START, instructions_template_1.HOMEGRAPH_SECTION_END);
@@ -1 +1 @@
1
- {"version":3,"file":"deveco.js","sourceRoot":"","sources":["../../../src/installer/targets/deveco.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deveco.js","sourceRoot":"","sources":["../../../src/installer/targets/deveco.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homegraph",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "Supercharge AI coding agents with semantic code intelligence — surgical context, fewer tool calls, faster answers. 100% local.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -88,15 +88,17 @@ python scripts/qa_eval/run_pipeline.py ab -r /path/to/your/repo
88
88
 
89
89
  **注意**:`--provider zhipu` 只影响 **builtin Agent** 和 **Judge**;`deveco-code` / `claude-code` 使用各自 CLI 的账号与凭证,不会读取 `ZHIPU_API_KEY`。
90
90
 
91
- DevEco 首次使用或换机后需配置模型:
91
+ DevEco 首次使用需配置模型(凭证保存在用户目录,**不是** DEVECO_HOME):
92
92
 
93
93
  ```bash
94
- deveco providers reset # 若报 credentials cannot be decrypted
95
- deveco # 打开 TUI,在设置里添加智谱等 provider
96
- # 或
97
- deveco providers login
94
+ deveco providers login # Zhipu AI,输入 API Key
95
+ # 凭证目录(Windows): C:\Users\<你>\.config\deveco
98
96
  ```
99
97
 
98
+ TUI 若提示 **DEVECO_HOME**,那是 DevEco **Studio** 安装路径(需 6.1+),仅编译/推包需要;**跑 qa_eval 可跳过**。你当前 Studio 为 5.1,填 `C:\Program Files\Huawei\DevEco Studio` 会校验失败,属正常。
99
+
100
+ homegraph MCP 写在**被测仓库**的 `.deveco/deveco.jsonc`;智谱 Key 仍读 `~/.config/deveco`。
101
+
100
102
  **Judge 打分**(Stage 2)三种宿主共用,仍需 `ZHIPU_API_KEY` 或 `DASHSCOPE_API_KEY`(与 `--provider` 一致)。
101
103
 
102
104
  #### 怎么跑
@@ -121,6 +123,8 @@ where deveco
121
123
  deveco providers reset # 仅凭证损坏/换机时需要
122
124
  deveco # TUI 里配置智谱等模型后再跑评测
123
125
  python scripts/qa_eval/run_pipeline.py ab -r /path/to/your/repo --provider zhipu --agent-host deveco-code
126
+ # 指定 DevEco 模型(可选,格式 provider/model):
127
+ # python scripts/qa_eval/run_pipeline.py ab -r /path/to/your/repo --provider zhipu --agent-host deveco-code --deveco-model zhipuai/glm-4.5-flash
124
128
  # → report-deveco.txt
125
129
 
126
130
  # ④ 三种依次跑(各写各的报告,不会互相覆盖)
@@ -380,7 +384,7 @@ python scripts/qa_eval/run_pipeline.py score \
380
384
  | 现象 | 处理 |
381
385
  |------|------|
382
386
  | Claude 准确率全 < 0.1 / `Not logged in` | Agent 未登录:`claude login` 后重跑;pipeline 现会在首题探测并 fail-fast |
383
- | `deveco ... exit 1` / `credentials cannot be decrypted` | DevEco 凭证无效:`deveco providers reset` 后在 TUI 重新配置 provider;与 `ZHIPU_API_KEY` 无关 |
387
+ | `deveco-code` exit 1 / `Model not found: glm-4-flash` | `--provider zhipu` 的模型只给 Judge/builtin;deveco `deveco models` 里的 `zhipuai/...` 名,或加 `--deveco-model zhipuai/glm-4.5-flash` |
384
388
  | `401` / Judge 全失败 | 检查 API Key:`DASHSCOPE_API_KEY`(DashScope)或 `ZHIPU_API_KEY`(智谱,格式 `id.secret`);智谱请加 `--provider zhipu`,勿把智谱 Key 设到 `DASHSCOPE_API_KEY` |
385
389
  | `Cannot find module 'arkanalyzer'` | `npm run build`,用 `node dist/bin/homegraph.js sync` |
386
390
  | `rg not found on PATH` | `sudo apt install ripgrep`(without 臂需要) |
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env python3
2
+ """One-off probe: parser + single run_deveco_query. Run from repo root."""
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ sys.path.insert(0, str(Path(__file__).resolve().parent))
7
+ from external_agent import DEFAULT_DEVECO_MODEL, parse_opencode_json_events, run_deveco_query
8
+
9
+ SAMPLE = (
10
+ '{"type":"step_start","part":{"type":"step-start"}}\n'
11
+ '{"type":"text","part":{"type":"text","text":"\\nOK"}}\n'
12
+ )
13
+
14
+ def main() -> int:
15
+ parsed = parse_opencode_json_events(SAMPLE)
16
+ assert parsed["agent_status"] == "success" and "OK" in parsed["output_answer"], parsed
17
+ print("parser OK:", parsed["output_answer"])
18
+
19
+ repo = Path(r"D:\code\benchmark")
20
+ if not repo.is_dir():
21
+ print("skip run: benchmark repo missing")
22
+ return 0
23
+
24
+ print(f"probing run_deveco_query (model={DEFAULT_DEVECO_MODEL}, timeout=90s)...")
25
+ r = run_deveco_query(
26
+ repo,
27
+ "reply OK only",
28
+ arm="with",
29
+ hg_bin=None,
30
+ log_file=None,
31
+ task_id=0,
32
+ timeout_sec=90,
33
+ )
34
+ print("status:", r.get("agent_status"))
35
+ print("error:", r.get("agent_error"))
36
+ print("answer:", (r.get("output_answer") or "")[:200])
37
+ return 0 if r.get("agent_status") == "success" else 1
38
+
39
+
40
+ if __name__ == "__main__":
41
+ raise SystemExit(main())
@@ -29,8 +29,35 @@ def _strip_ansi(text: str) -> str:
29
29
  return re.sub(r"\x1b\[[0-9;]*m", "", text or "")
30
30
 
31
31
 
32
+ def _extract_deveco_json_errors(text: str) -> str | None:
33
+ """Parse deveco --format json error lines into a short message."""
34
+ messages: list[str] = []
35
+ for line in _strip_ansi(text).splitlines():
36
+ line = line.strip()
37
+ if not line.startswith("{"):
38
+ continue
39
+ try:
40
+ ev = json.loads(line)
41
+ except json.JSONDecodeError:
42
+ continue
43
+ if ev.get("type") != "error":
44
+ continue
45
+ err = ev.get("error") or {}
46
+ data = err.get("data") or {}
47
+ msg = data.get("message") or err.get("message") or err.get("name")
48
+ if msg and msg not in messages:
49
+ messages.append(str(msg))
50
+ if not messages:
51
+ return None
52
+ return "; ".join(messages)
53
+
54
+
32
55
  def _cli_error_summary(stderr: str, stdout: str, *, max_len: int = 400) -> str:
33
56
  """Pick a short user-facing error from CLI stderr/stdout."""
57
+ for raw in (stderr, stdout):
58
+ deveco_err = _extract_deveco_json_errors(raw)
59
+ if deveco_err:
60
+ return deveco_err[:max_len]
34
61
  for raw in (stderr, stdout):
35
62
  clean = _strip_ansi(raw).strip()
36
63
  if not clean:
@@ -63,7 +90,11 @@ def auth_failure_reason(text: str) -> str | None:
63
90
  "DevEco Code 未配置或凭证无效。请运行: deveco providers reset,"
64
91
  "然后重新登录/配置 provider"
65
92
  )
66
- if "invalid api key" in t or "incorrect api key" in t:
93
+ if "model not found" in t:
94
+ return (
95
+ "DevEco 模型名无效。deveco 需要 provider/model 格式(如 zhipuai/glm-4.5-flash),"
96
+ "可用 `deveco models` 查看;勿把 Judge 的 --model 直接传给 deveco"
97
+ )
67
98
  return "API Key 无效"
68
99
  if "authentication required" in t or "unauthorized" in t:
69
100
  return "未授权,请检查登录或 API Key"
@@ -104,6 +135,19 @@ def find_deveco_cli() -> str:
104
135
  )
105
136
 
106
137
 
138
+ def _popen_capture(cmd: list[str], *, cwd: str) -> subprocess.Popen:
139
+ """Run CLI with UTF-8 stdout/stderr (Windows default locale is often GBK)."""
140
+ return subprocess.Popen(
141
+ cmd,
142
+ cwd=cwd,
143
+ stdout=subprocess.PIPE,
144
+ stderr=subprocess.PIPE,
145
+ text=True,
146
+ encoding="utf-8",
147
+ errors="replace",
148
+ )
149
+
150
+
107
151
  def write_mcp_config(path: Path, *, hg_command: str, hg_args: list[str]) -> None:
108
152
  path.write_text(
109
153
  json.dumps({"mcpServers": {"homegraph": {"command": hg_command, "args": hg_args}}}, indent=2)
@@ -188,6 +232,7 @@ def parse_opencode_json_events(raw: str) -> dict[str, Any]:
188
232
  total_tokens = 0
189
233
  max_turn = 0
190
234
  duration_ms = 0
235
+ stream_errors: list[str] = []
191
236
 
192
237
  for line in raw.splitlines():
193
238
  line = line.strip()
@@ -199,7 +244,37 @@ def parse_opencode_json_events(raw: str) -> dict[str, Any]:
199
244
  continue
200
245
 
201
246
  ev_type = ev.get("type") or ev.get("event")
202
- if ev_type in ("message", "assistant", "text"):
247
+ part = ev.get("part") if isinstance(ev.get("part"), dict) else {}
248
+
249
+ if ev_type == "error":
250
+ err = ev.get("error") or {}
251
+ data = err.get("data") or {}
252
+ msg = data.get("message") or err.get("message") or err.get("name")
253
+ if msg:
254
+ stream_errors.append(str(msg))
255
+
256
+ # DevEco / opencode stream-json: {type:"text", part:{type:"text", text:"..."}}
257
+ if ev_type == "text" and part.get("text"):
258
+ text = str(part["text"]).strip()
259
+ if text:
260
+ answer_parts.append(text)
261
+ max_turn += 1
262
+
263
+ part_type = part.get("type") or ""
264
+ if ev_type in ("tool", "tool_call", "tool_use") or part_type in (
265
+ "tool",
266
+ "tool-invocation",
267
+ "tool_use",
268
+ "tool-call",
269
+ ):
270
+ max_turn += 1
271
+ name = part.get("tool") or part.get("name") or ev.get("tool") or "?"
272
+ inp = part.get("input") or part.get("args") or part.get("state") or ev.get("input") or {}
273
+ tool_trace.append(
274
+ f"---\n{name}\nargs: {json.dumps(inp, ensure_ascii=False)[:500]}\n---"
275
+ )
276
+
277
+ if ev_type in ("message", "assistant"):
203
278
  content = ev.get("content") or ev.get("text") or ev.get("message")
204
279
  if isinstance(content, str) and content.strip():
205
280
  answer_parts.append(content.strip())
@@ -225,6 +300,10 @@ def parse_opencode_json_events(raw: str) -> dict[str, Any]:
225
300
  if ev.get("duration_ms"):
226
301
  duration_ms = max(duration_ms, int(ev["duration_ms"]))
227
302
 
303
+ part_time = part.get("time") if isinstance(part.get("time"), dict) else {}
304
+ if part_time.get("start") and part_time.get("end"):
305
+ duration_ms = max(duration_ms, int(part_time["end"]) - int(part_time["start"]))
306
+
228
307
  answer = "\n".join(answer_parts).strip()
229
308
  output = "\n\n".join(tool_trace + ([answer] if answer else []))
230
309
  auth_err = auth_failure_reason(answer) or auth_failure_reason(raw)
@@ -237,9 +316,19 @@ def parse_opencode_json_events(raw: str) -> dict[str, Any]:
237
316
  "agent_duration_ms": duration_ms,
238
317
  "agent_usage": {"total_tokens": total_tokens} if total_tokens else {},
239
318
  }
319
+ if stream_errors and not answer:
320
+ return {
321
+ "output_answer": output,
322
+ "agent_status": "error",
323
+ "agent_error": "; ".join(stream_errors),
324
+ "agent_turns": max_turn,
325
+ "agent_duration_ms": duration_ms,
326
+ "agent_usage": {"total_tokens": total_tokens} if total_tokens else {},
327
+ }
240
328
  return {
241
329
  "output_answer": output,
242
330
  "agent_status": "success" if answer else "error",
331
+ "agent_error": None if answer else "deveco 未返回可解析的文本回答",
243
332
  "agent_turns": max_turn,
244
333
  "agent_duration_ms": duration_ms,
245
334
  "agent_usage": {"total_tokens": total_tokens} if total_tokens else {},
@@ -305,13 +394,7 @@ def run_claude_query(
305
394
  _log_line(log_file, "the 1 turn")
306
395
  t0 = time.time()
307
396
 
308
- proc = subprocess.Popen(
309
- cmd,
310
- cwd=str(repo),
311
- stdout=subprocess.PIPE,
312
- stderr=subprocess.PIPE,
313
- text=True,
314
- )
397
+ proc = _popen_capture(cmd, cwd=str(repo))
315
398
  with sample_memory(proc.pid) as sampler:
316
399
  try:
317
400
  stdout, stderr = proc.communicate(timeout=timeout_sec)
@@ -329,7 +412,7 @@ def run_claude_query(
329
412
  }
330
413
  mem = sampler.last_stats
331
414
 
332
- if proc.returncode != 0 and not stdout.strip():
415
+ if proc.returncode != 0 and not (stdout or "").strip():
333
416
  _log_memory(log_file, mem)
334
417
  return {
335
418
  "output_answer": (stderr or "")[:2000],
@@ -352,7 +435,7 @@ def run_claude_query(
352
435
  "agent_host": HOST_CLAUDE,
353
436
  "agent_memory_mb": mem,
354
437
  }
355
- parsed = parse_claude_stream_json(stdout)
438
+ parsed = parse_claude_stream_json(stdout or "")
356
439
  tokens = (parsed.get("agent_usage") or {}).get("total_tokens") or 0
357
440
  if tokens:
358
441
  _log_line(log_file, f"totalTokenCount = {tokens}")
@@ -369,6 +452,41 @@ def run_claude_query(
369
452
  }
370
453
 
371
454
 
455
+ def _deveco_project_config_dir(repo: Path) -> Path:
456
+ """Project-level deveco config (read before ~/.config/deveco/deveco.jsonc)."""
457
+ return repo / ".deveco"
458
+
459
+
460
+ def _write_deveco_project_mcp(repo: Path, *, arm: str, hg_bin: str) -> Path:
461
+ """Write repo/.deveco/deveco.jsonc for MCP only; credentials stay in ~/.config/deveco."""
462
+ config_dir = _deveco_project_config_dir(repo)
463
+ config_dir.mkdir(parents=True, exist_ok=True)
464
+ config_path = config_dir / "deveco.jsonc"
465
+ if arm == "with":
466
+ if not hg_bin:
467
+ from agent_runner import find_homegraph_bin
468
+
469
+ hg_bin = find_homegraph_bin(None)
470
+ cmd, base_args = _split_hg_bin(hg_bin)
471
+ body = {
472
+ "$schema": "https://opencode.ai/config.json",
473
+ "mcp": {
474
+ "homegraph": {
475
+ "type": "local",
476
+ "command": [cmd, *base_args, "--path", str(repo.resolve())],
477
+ "enabled": True,
478
+ }
479
+ },
480
+ }
481
+ else:
482
+ body = {"$schema": "https://opencode.ai/config.json", "mcp": {}}
483
+ config_path.write_text(json.dumps(body, indent=2) + "\n", encoding="utf-8")
484
+ return config_path
485
+
486
+
487
+ DEFAULT_DEVECO_MODEL = "zhipuai/glm-4.5-flash"
488
+
489
+
372
490
  def run_deveco_query(
373
491
  repo: Path,
374
492
  query: str,
@@ -383,33 +501,7 @@ def run_deveco_query(
383
501
  cli = find_deveco_cli()
384
502
  backend = f"deveco-code-{'with' if arm == 'with' else 'without'}-homegraph"
385
503
 
386
- config_dir = repo / ".qa_eval_deveco"
387
- config_dir.mkdir(exist_ok=True)
388
- config_path = config_dir / "opencode.jsonc"
389
- if arm == "with":
390
- cmd, base_args = _split_hg_bin(hg_bin)
391
- config_path.write_text(
392
- json.dumps(
393
- {
394
- "$schema": "https://opencode.ai/config.json",
395
- "mcp": {
396
- "homegraph": {
397
- "type": "local",
398
- "command": [cmd, *base_args, "--path", str(repo.resolve())],
399
- "enabled": True,
400
- }
401
- },
402
- },
403
- indent=2,
404
- )
405
- + "\n",
406
- encoding="utf-8",
407
- )
408
- else:
409
- config_path.write_text(
410
- '{"$schema":"https://opencode.ai/config.json","mcp":{}}\n',
411
- encoding="utf-8",
412
- )
504
+ _write_deveco_project_mcp(repo, arm=arm, hg_bin=hg_bin)
413
505
 
414
506
  run_cmd = [
415
507
  cli,
@@ -423,19 +515,14 @@ def run_deveco_query(
423
515
  ]
424
516
  if model:
425
517
  run_cmd.extend(["--model", model])
518
+ else:
519
+ run_cmd.extend(["--model", DEFAULT_DEVECO_MODEL])
426
520
 
427
521
  _log_line(log_file, f"Evaluate {task_id}:")
428
522
  _log_line(log_file, "the 1 turn")
429
523
  t0 = time.time()
430
524
 
431
- proc = subprocess.Popen(
432
- run_cmd,
433
- cwd=str(repo),
434
- stdout=subprocess.PIPE,
435
- stderr=subprocess.PIPE,
436
- text=True,
437
- env={**os.environ, "XDG_CONFIG_HOME": str(config_dir)},
438
- )
525
+ proc = _popen_capture(run_cmd, cwd=str(repo))
439
526
  with sample_memory(proc.pid) as sampler:
440
527
  try:
441
528
  stdout, stderr = proc.communicate(timeout=timeout_sec)
@@ -469,14 +556,16 @@ def run_deveco_query(
469
556
  }
470
557
 
471
558
  _log_line(log_file, "first token")
472
- parsed = parse_opencode_json_events(stdout if stdout.strip() else stderr)
559
+ out = (stdout or "").strip()
560
+ err = (stderr or "").strip()
561
+ parsed = parse_opencode_json_events(out if out else err)
473
562
  tokens = (parsed.get("agent_usage") or {}).get("total_tokens") or 0
474
563
  if tokens:
475
564
  _log_line(log_file, f"totalTokenCount = {tokens}")
476
565
  _log_memory(log_file, mem)
477
566
 
478
567
  duration_ms = parsed.get("agent_duration_ms") or int((time.time() - t0) * 1000)
479
- return {
568
+ result = {
480
569
  **parsed,
481
570
  "agent_duration_ms": duration_ms,
482
571
  "agent_backend": backend,
@@ -484,6 +573,9 @@ def run_deveco_query(
484
573
  "ab_arm": "with-homegraph" if arm == "with" else "without-homegraph",
485
574
  "agent_memory_mb": mem,
486
575
  }
576
+ if result.get("agent_status") != "success" and not result.get("agent_error"):
577
+ result["agent_error"] = _extract_deveco_json_errors(combined) or "deveco 未返回可解析的文本回答"
578
+ return result
487
579
 
488
580
 
489
581
  def run_external_dataset(
@@ -569,6 +661,8 @@ def run_external_dataset(
569
661
  if i == 1 and meta.get("agent_error") and (
570
662
  "未登录" in str(meta["agent_error"])
571
663
  or "DevEco Code" in str(meta["agent_error"])
664
+ or "DevEco 模型" in str(meta["agent_error"])
665
+ or "Model not found" in str(meta["agent_error"])
572
666
  ):
573
667
  auth_abort = str(meta["agent_error"])
574
668
  print(f"\n ✗ {auth_abort} — 后续题目跳过", flush=True)
@@ -396,6 +396,7 @@ def run_agent_stage(
396
396
  llm,
397
397
  hg_bin: str | None,
398
398
  max_turns: int,
399
+ deveco_model: str | None = None,
399
400
  ) -> None:
400
401
  if agent_host == HOST_CLAUDE:
401
402
  verify_claude_login()
@@ -428,7 +429,7 @@ def run_agent_stage(
428
429
  output=out,
429
430
  log_file=log,
430
431
  hg_bin=hg_bin or "",
431
- model=llm.model if agent_host == HOST_DEVECO else None,
432
+ model=deveco_model if agent_host == HOST_DEVECO else None,
432
433
  )
433
434
 
434
435
 
@@ -497,6 +498,7 @@ def cmd_ab(args: argparse.Namespace) -> int:
497
498
  llm=llm,
498
499
  hg_bin=args.homegraph_bin,
499
500
  max_turns=args.max_turns,
501
+ deveco_model=getattr(args, "deveco_model", None),
500
502
  )
501
503
 
502
504
  if not args.no_judge:
@@ -605,6 +607,7 @@ def cmd_hosts(args: argparse.Namespace) -> int:
605
607
  no_judge=args.no_judge,
606
608
  report=None,
607
609
  agent_host=host,
610
+ deveco_model=getattr(args, "deveco_model", None),
608
611
  )
609
612
  if cmd_ab(host_args) != 0:
610
613
  rc = 1
@@ -653,6 +656,11 @@ def main() -> int:
653
656
  p_ab.add_argument("--base-url", default=None, help="OpenAI 兼容 API 端点(默认随 provider)")
654
657
  p_ab.add_argument("--homegraph-bin", default=None)
655
658
  p_ab.add_argument("--max-turns", type=int, default=8, help="Agent 最多工具轮次")
659
+ p_ab.add_argument(
660
+ "--deveco-model",
661
+ default=None,
662
+ help="DevEco Agent 模型(provider/model,如 zhipuai/glm-4.5-flash);默认用 DevEco 自身配置,不用 --model",
663
+ )
656
664
  p_ab.add_argument("--no-agent", action="store_true", help="不跑 Agent,沿用已有 JSONL")
657
665
  p_ab.add_argument("--no-judge", action="store_true", help="不跑 Judge,沿用已有 scored")
658
666
  p_ab.add_argument(
@@ -676,6 +684,7 @@ def main() -> int:
676
684
  p_hosts.add_argument("--base-url", default=None)
677
685
  p_hosts.add_argument("--homegraph-bin", default=None)
678
686
  p_hosts.add_argument("--max-turns", type=int, default=8)
687
+ p_hosts.add_argument("--deveco-model", default=None)
679
688
  p_hosts.add_argument("--no-agent", action="store_true")
680
689
  p_hosts.add_argument("--no-judge", action="store_true")
681
690
  p_hosts.add_argument(