cdsa-harness 0.22.4 → 0.22.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.
- package/package.json +1 -1
- package/src/builtins.js +1 -1
- package/src/cli.js +23 -5
- package/src/llm.js +9 -0
- package/src/ui.js +1 -0
package/package.json
CHANGED
package/src/builtins.js
CHANGED
package/src/cli.js
CHANGED
|
@@ -81,14 +81,27 @@ function printTeach(ev, stream) {
|
|
|
81
81
|
return;
|
|
82
82
|
|
|
83
83
|
case Step.MODEL_CALL: {
|
|
84
|
+
// 실제 값은 흰색, 초보자용 설명(←)은 노란색으로 구분해 가독성을 높인다.
|
|
85
|
+
const why = (t) => c.yellow(`← ${t}`);
|
|
86
|
+
const ROLE_DESC = {
|
|
87
|
+
system: "하네스가 자동으로 넣는 규칙·정체성·작업폴더 안내문",
|
|
88
|
+
user: "내가 입력한 메시지",
|
|
89
|
+
assistant: "모델(AI)이 이전에 한 답변",
|
|
90
|
+
tool: "도구 실행 결과 — 모델에게 되돌려주는 값",
|
|
91
|
+
};
|
|
84
92
|
const lines = [];
|
|
85
|
-
lines.push(`${c.grey("provider/model")} ${c.bold(`${d.provider} · ${d.model}`)}`);
|
|
86
|
-
lines.push(c.
|
|
93
|
+
lines.push(`${c.grey("provider/model")} ${c.white(c.bold(`${d.provider} · ${d.model}`))} ${why("어느 회사의 어떤 모델을 호출하는지")}`);
|
|
94
|
+
lines.push(`${c.white(`모델에 보내는 메시지 ${d.messages?.length || 0}개 · 추정 ${d.estTokens} 토큰 · ${d.totalChars}자`)}`);
|
|
95
|
+
lines.push(` ${why("모델은 기억이 없어서, 지금까지의 대화 전체를 매번 처음부터 다시 보냅니다")}`);
|
|
87
96
|
for (const m of d.messages || []) {
|
|
88
97
|
const roleColor = m.role === "system" ? c.magenta : m.role === "user" ? c.cyan : m.role === "assistant" ? c.green : c.yellow;
|
|
89
|
-
|
|
98
|
+
const desc = ROLE_DESC[m.role]
|
|
99
|
+
? ` ${why(ROLE_DESC[m.role] + (m.extra && m.role === "assistant" ? " (도구를 써달라는 요청 포함)" : ""))}`
|
|
100
|
+
: "";
|
|
101
|
+
lines.push(` ${roleColor(m.role.padEnd(9))} ${c.white(`${m.chars}자${m.extra || ""}`)}${desc}`);
|
|
90
102
|
}
|
|
91
|
-
lines.push(c.
|
|
103
|
+
lines.push(`${c.white(`제공 도구(${d.tools?.length || 0})`)}${c.grey(`: ${(d.tools || []).join(", ")}`)}`);
|
|
104
|
+
lines.push(` ${why("모델이 쓸 수 있는 '손'(함수) 목록 — 모델이 이름과 인자로 요청하면 하네스가 대신 실행")}`);
|
|
92
105
|
console.log(panel(lines, { title: `${d.sub ? "┆ " : ""}🧠 ② LLM 호출 — 반복 ${d.iteration}`, color: "magenta" }));
|
|
93
106
|
if (d.systemPrompt && !d.sub) {
|
|
94
107
|
console.log(panel(clip(d.systemPrompt, 600).split("\n"), {
|
|
@@ -297,7 +310,12 @@ async function fetchProviderModels(cfg, query = "") {
|
|
|
297
310
|
try {
|
|
298
311
|
if (cfg.provider === "openrouter") {
|
|
299
312
|
const r = await fetchJson("https://openrouter.ai/api/v1/models");
|
|
300
|
-
|
|
313
|
+
// 하네스는 항상 도구(tools)를 함께 보내므로, 도구를 지원하지 않는 모델은 어차피
|
|
314
|
+
// "No endpoints found that support tool use" 로 실패한다 — 목록에서 미리 제외.
|
|
315
|
+
let ids = (r.data || [])
|
|
316
|
+
.filter((m) => !Array.isArray(m.supported_parameters) || m.supported_parameters.includes("tools"))
|
|
317
|
+
.map((m) => m.id)
|
|
318
|
+
.sort();
|
|
301
319
|
if (q) ids = ids.filter((id) => id.toLowerCase().includes(q));
|
|
302
320
|
return { list: ids, live: true };
|
|
303
321
|
}
|
package/src/llm.js
CHANGED
|
@@ -346,6 +346,15 @@ function safeParse(jsonStr) {
|
|
|
346
346
|
|
|
347
347
|
function httpErrorMessage(status, text) {
|
|
348
348
|
let msg = `API 오류 ${status}: ${trim(text)}`;
|
|
349
|
+
// 도구(tool use) 미지원 모델/엔드포인트 — 모델명 오타 힌트는 오답이므로 여기서 끝낸다.
|
|
350
|
+
if (/tool[ _]use|support tools?/i.test(text)) {
|
|
351
|
+
msg +=
|
|
352
|
+
"\n ↳ 이 모델(또는 이 모델의 제공 엔드포인트)이 도구 호출(tool use)을 지원하지 않아요. " +
|
|
353
|
+
"에이전트 하네스는 파일 도구가 필수라 도구 지원 모델이 필요합니다." +
|
|
354
|
+
"\n ↳ /models 로 다른 모델을 고르세요 — OpenRouter 목록은 도구 지원 모델만 표시됩니다 " +
|
|
355
|
+
"(예: anthropic/claude-sonnet-4.5, openai/gpt-4o-mini).";
|
|
356
|
+
return msg;
|
|
357
|
+
}
|
|
349
358
|
if (status === 404) {
|
|
350
359
|
msg += "\n ↳ 모델 이름을 확인하세요. /model 로 변경 가능. " +
|
|
351
360
|
"OpenRouter 는 'provider/model' 형식이어야 합니다 (예: openai/gpt-4o-mini, anthropic/claude-3.7-sonnet).";
|