deel-local-cli 1.20.12 → 2.0.0
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/README.ko.md +96 -77
- package/README.md +119 -80
- package/bin/deel.js +398 -32
- package/package.json +2 -1
- package/src/acp/jsonrpc.js +87 -7
- package/src/acp/map.js +62 -13
- package/src/acp/serve.js +338 -30
- package/src/agent/agents.js +110 -12
- package/src/agent/askcheck.js +50 -6
- package/src/agent/asks.js +59 -5
- package/src/agent/budget.js +9 -2
- package/src/agent/card.js +8 -2
- package/src/agent/commit.js +168 -16
- package/src/agent/compact.js +93 -21
- package/src/agent/{/354/213/240/353/242/260/353/217/204.js → confidence.js} +1 -1
- package/src/agent/effort.js +85 -15
- package/src/agent/evidence.js +63 -7
- package/src/agent/evolve.js +132 -24
- package/src/agent/grade.js +12 -3
- package/src/agent/loop.js +408 -81
- package/src/agent/memory.js +176 -29
- package/src/agent/mention.js +22 -5
- package/src/agent/models.js +31 -7
- package/src/agent/modes.js +25 -10
- package/src/agent/outschema.js +381 -56
- package/src/agent/pins.js +33 -2
- package/src/agent/project.js +73 -8
- package/src/agent/recall.js +40 -9
- package/src/agent/{/354/204/261/355/225/234/352/270/260/353/241/235.js → recordshape.js} +19 -8
- package/src/agent/review.js +143 -13
- package/src/agent/route.js +506 -32
- package/src/agent/salvage.js +2 -1
- package/src/agent/session.js +457 -31
- package/src/agent/store.js +232 -22
- package/src/agent/threads.js +52 -3
- package/src/backend/adapter.js +508 -85
- package/src/backend/azure.js +12 -1
- package/src/backend/cachemark.js +31 -5
- package/src/backend/clientcert.js +23 -1
- package/src/backend/ctxsize.js +56 -9
- package/src/backend/detect.js +252 -19
- package/src/backend/http.js +383 -42
- package/src/backend/learn.js +101 -11
- package/src/backend/mcp.js +333 -24
- package/src/backend/price.js +61 -13
- package/src/backend/probe.js +188 -36
- package/src/backend/proxy.js +108 -14
- package/src/backend/quota.js +226 -30
- package/src/backend/retry.js +46 -3
- package/src/backend/scan.js +47 -10
- package/src/backend/scanui.js +57 -7
- package/src/backend/toolfit.js +204 -22
- package/src/backend/vision.js +14 -1
- package/src/backend/wire.js +58 -10
- package/src/cmdnames.js +16 -0
- package/src/commands/common.js +70 -0
- package/src/commands/extend.js +300 -0
- package/src/commands/model.js +852 -0
- package/src/commands/view.js +328 -0
- package/src/commands/work.js +823 -0
- package/src/commands.js +193 -2082
- package/src/completion.js +45 -3
- package/src/config.js +452 -39
- package/src/configexplain.js +125 -14
- package/src/doctor.js +164 -26
- package/src/i18n/en.js +22 -0
- package/src/i18n/index.js +31 -1
- package/src/i18n/ja.js +25 -1
- package/src/i18n/ko.js +25 -2
- package/src/i18n/zh.js +25 -1
- package/src/lsp/client.js +111 -9
- package/src/lsp/servers.js +86 -22
- package/src/oneshot.js +325 -65
- package/src/pack/sbom.js +28 -5
- package/src/pack/selfpack.js +54 -5
- package/src/pack/sheet.en.js +24 -3
- package/src/pack/tar.js +45 -8
- package/src/pack/zip.js +103 -8
- package/src/plugins/manage.js +165 -14
- package/src/preview/serve.js +239 -23
- package/src/providers/bedrock.js +30 -5
- package/src/providers/gemini.js +8 -0
- package/src/providers/index.js +17 -1
- package/src/repl.js +254 -61
- package/src/report.js +7 -2
- package/src/reset.js +151 -25
- package/src/safety/audit.js +108 -8
- package/src/safety/authcmd.js +75 -5
- package/src/safety/guard.js +507 -15
- package/src/safety/hooks.js +172 -20
- package/src/safety/keystore.js +178 -18
- package/src/safety/network.js +209 -6
- package/src/safety/policy.js +377 -36
- package/src/safety/runmode.js +9 -2
- package/src/safety/secrets.js +243 -17
- package/src/safety/shellenv.js +64 -3
- package/src/safety/trust.js +298 -32
- package/src/safety/undo.js +409 -17
- package/src/setup.js +175 -17
- package/src/skills/discover.js +122 -19
- package/src/stats.js +57 -16
- package/src/tools/{/355/231/225/354/235/270/353/262/225.js → checkmethods.js} +26 -1
- package/src/tools/clipboard.js +53 -20
- package/src/tools/convert.js +118 -37
- package/src/tools/desc.en.js +48 -5
- package/src/tools/doc2md.js +11 -1
- package/src/tools/docs.js +94 -18
- package/src/tools/edit-match.js +212 -13
- package/src/tools/encoding.js +525 -28
- package/src/tools/excel-com.js +63 -15
- package/src/tools/excel.js +12 -7
- package/src/tools/fastgrep.js +444 -36
- package/src/tools/fig.js +40 -9
- package/src/tools/fsutil.js +235 -21
- package/src/tools/hwpxwrite.js +80 -19
- package/src/tools/ignore.js +55 -7
- package/src/tools/index.js +1029 -145
- package/src/tools/jobs.js +325 -50
- package/src/tools/kiwi.js +50 -5
- package/src/tools/lsp.js +164 -32
- package/src/tools/outline.js +52 -12
- package/src/tools/pdf.js +366 -56
- package/src/tools/shell.js +12 -4
- package/src/tools/spawn.js +203 -18
- package/src/tools/todo.js +73 -4
- package/src/tools/verify.js +312 -43
- package/src/tools/webfetch.js +184 -25
- package/src/tools/xlsx.js +232 -31
- package/src/ui/ansi.js +209 -15
- package/src/ui/banner.js +2 -1
- package/src/ui/complete.js +46 -4
- package/src/ui/diff.js +4 -2
- package/src/ui/export.js +91 -17
- package/src/ui/inputbox.js +58 -18
- package/src/ui/intro.js +9 -2
- package/src/ui/level.js +32 -7
- package/src/ui/md.js +101 -15
- package/src/ui/motion.js +5 -2
- package/src/ui/notify.js +7 -1
- package/src/ui/office.js +37 -5
- package/src/ui/pastechip.js +3 -2
- package/src/ui/pick.js +85 -12
- package/src/ui/prompt.js +176 -13
- package/src/ui/screen.js +2 -1
- package/src/ui/spinner.js +6 -1
- package/src/ui/status.js +80 -12
- package/src/ui/wrap.js +23 -37
- /package/src/agent/{/353/213/250/352/263/204.js" → phase.js} +0 -0
- /package/src/skills/builtin/{/352/271/212/354/235/264/354/236/210/352/262/214-/353/247/214/353/223/244/352/270/260/SKILL.md" → build-deep/SKILL.md} +0 -0
- /package/src/skills/builtin/{/354/260/250/352/267/274/354/260/250/352/267/274-/353/224/224/353/262/204/352/271/205/SKILL.md" → debug-step-by-step/SKILL.md} +0 -0
- /package/src/skills/builtin/{/353/201/235/352/271/214/354/247/200-/355/225/230/352/270/260/SKILL.md" → finish-all/SKILL.md} +0 -0
- /package/src/skills/builtin/{/354/212/244/354/212/244/353/241/234-/352/262/200/355/206/240/SKILL.md" → self-review/SKILL.md} +0 -0
- /package/src/skills/builtin/{/354/275/224/353/223/234-/354/244/204/354/235/264/352/270/260/SKILL.md" → simplify-code/SKILL.md} +0 -0
- /package/src/skills/builtin/{/354/260/224/353/237/254/353/263/264/352/270/260/SKILL.md" → spike/SKILL.md} +0 -0
- /package/src/skills/builtin/{/352/262/200/354/202/254-/353/250/274/354/240/200/SKILL.md" → test-first/SKILL.md} +0 -0
package/src/acp/jsonrpc.js
CHANGED
|
@@ -80,8 +80,19 @@ export function 줄나누기(한줄) {
|
|
|
80
80
|
*/
|
|
81
81
|
let 자리;
|
|
82
82
|
while ((자리 = 남은것.indexOf('\n')) >= 0) {
|
|
83
|
-
|
|
83
|
+
let 줄 = 남은것.slice(0, 자리).replace(/\r$/, '');
|
|
84
84
|
남은것 = 남은것.slice(자리 + 1);
|
|
85
|
+
/*
|
|
86
|
+
* ── 줄 앞의 BOM 을 뗀다 (사냥5 H5-9) ──────────────────────────────────
|
|
87
|
+
*
|
|
88
|
+
* .NET 의 `StreamWriter(Encoding.UTF8)` 처럼 첫 바이트에 BOM(U+FEFF) 을 붙여
|
|
89
|
+
* 쓰는 클라이언트가 있다. 그 글자는 JSON 이 받지 않아서 **첫 줄 = initialize**
|
|
90
|
+
* 가 -32700 · id null 로 떨어졌고, 저쪽은 initialize 답을 영영 기다렸다 —
|
|
91
|
+
* 붙자마자 멈추는데 우리 로그에는 「읽을 수 없는 JSON」 한 줄뿐이다.
|
|
92
|
+
* 줄마다 보는 것은, 메시지마다 새 writer 를 여는 클라이언트면 BOM 이 매 줄 앞에
|
|
93
|
+
* 오기 때문이다. 글자는 번호로 비교한다 — 소스에 보이지 않는 글자를 안 둔다.
|
|
94
|
+
*/
|
|
95
|
+
if (줄.charCodeAt(0) === 0xfeff) 줄 = 줄.slice(1);
|
|
85
96
|
if (줄.trim()) 한줄(줄); // 빈 줄은 그냥 넘긴다. 오류로 칠 것이 아니다
|
|
86
97
|
}
|
|
87
98
|
};
|
|
@@ -117,12 +128,34 @@ export class 연결 {
|
|
|
117
128
|
this.보내기줄(JSON.stringify(덩이) + '\n');
|
|
118
129
|
}
|
|
119
130
|
|
|
120
|
-
/**
|
|
121
|
-
|
|
131
|
+
/**
|
|
132
|
+
* 저쪽에 요청을 걸고 답을 기다린다.
|
|
133
|
+
*
|
|
134
|
+
* ── 기다림에도 끊는 줄이 있어야 한다 (사냥5 H5-3) ───────────────────────
|
|
135
|
+
*
|
|
136
|
+
* 승인 창을 띄워 두고 사람이 안 누른 채 턴을 취소하면, 여기 기다림은 끊기는 줄을
|
|
137
|
+
* 몰라서 **답이 올 때까지** 서 있었다. 그 턴은 취소된 뒤에도 살아 있고, 한참 뒤에
|
|
138
|
+
* 옛 창의 「이번만 실행」 이 닿으면 그대로 도구를 돌렸다. signal 을 주면 끊기는
|
|
139
|
+
* 순간 기다림을 거둔다 — 표에서도 지우므로 늦게 온 답은 「이미 포기한 것」 으로
|
|
140
|
+
* 조용히 버려진다.
|
|
141
|
+
*
|
|
142
|
+
* @param {object} [o]
|
|
143
|
+
* @param {AbortSignal|null} [o.signal] 끊기면 기다림을 거두고 `거둠: true` 오류로 깬다
|
|
144
|
+
*/
|
|
145
|
+
요청(방법, 인자, { signal = null } = {}) {
|
|
122
146
|
const id = this.다음번호++;
|
|
123
147
|
return new Promise((풀기, 깨기) => {
|
|
124
148
|
if (this.닫혔나) { 깨기(new Error('관이 닫혔습니다')); return; }
|
|
125
|
-
|
|
149
|
+
const 거둔오류 = () => Object.assign(new Error('기다리던 요청을 거뒀습니다 — 턴이 끊겼습니다'), { 거둠: true });
|
|
150
|
+
// 이미 끊긴 턴의 물음은 내보내지도 않는다. 에디터에 답할 수 없는 창만 남는다.
|
|
151
|
+
if (signal?.aborted) { 깨기(거둔오류()); return; }
|
|
152
|
+
const 거두기 = () => { if (this.기다리는것.delete(id)) 깨기(거둔오류()); };
|
|
153
|
+
signal?.addEventListener?.('abort', 거두기, { once: true });
|
|
154
|
+
const 떼기 = () => signal?.removeEventListener?.('abort', 거두기);
|
|
155
|
+
this.기다리는것.set(id, {
|
|
156
|
+
풀기: (값) => { 떼기(); 풀기(값); },
|
|
157
|
+
깨기: (오류) => { 떼기(); 깨기(오류); },
|
|
158
|
+
});
|
|
126
159
|
this.#쓰기({ jsonrpc: '2.0', id, method: 방법, params: 인자 ?? {} });
|
|
127
160
|
});
|
|
128
161
|
}
|
|
@@ -148,6 +181,18 @@ export class 연결 {
|
|
|
148
181
|
this.#쓰기({ jsonrpc: '2.0', id: null, error: { code: 오류번호.파싱, message: '읽을 수 없는 JSON 입니다' } });
|
|
149
182
|
return;
|
|
150
183
|
}
|
|
184
|
+
/*
|
|
185
|
+
* 묶음(batch) — `[{…}, {…}]` 한 줄.
|
|
186
|
+
*
|
|
187
|
+
* 배열도 typeof 로는 'object' 라 바로 아래 갈래를 지나쳤다. 그 뒤로는 method 도
|
|
188
|
+
* id 도 없는 것으로 읽혀 **답이 한 줄도 안 나갔다** — 저쪽은 영영 기다린다.
|
|
189
|
+
* ACP 는 묶음을 쓰지 않고 우리도 안 받는다. 안 받는다고 답한다. 안에 든 id 를
|
|
190
|
+
* 골라 답하지 않는 것은, 받지 않은 요청에 답이 붙으면 저쪽이 된 줄 알기 때문이다.
|
|
191
|
+
*/
|
|
192
|
+
if (Array.isArray(온것)) {
|
|
193
|
+
this.#쓰기({ jsonrpc: '2.0', id: null, error: { code: 오류번호.잘못된요청, message: '묶음(batch)은 받지 않습니다 — 한 줄에 요청 하나씩 보내 주세요' } });
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
151
196
|
if (!온것 || typeof 온것 !== 'object') {
|
|
152
197
|
this.#쓰기({ jsonrpc: '2.0', id: null, error: { code: 오류번호.잘못된요청, message: '객체가 아닙니다' } });
|
|
153
198
|
return;
|
|
@@ -157,7 +202,18 @@ export class 연결 {
|
|
|
157
202
|
//
|
|
158
203
|
// 'id' in 온것 으로 본다. id 가 0 일 수 있기 때문이다 — ACP 클라이언트는
|
|
159
204
|
// 실제로 0번부터 센다. 여기서 truthy 로 보면 첫 요청의 답을 통째로 잃는다.
|
|
160
|
-
|
|
205
|
+
//
|
|
206
|
+
// method 도 **칸이 있나**로 본다 (사냥5 H5-10). `!온것.method` 는 빈 글도 거짓으로
|
|
207
|
+
// 쳐서 `{"id":77,"method":""}` 가 이 답 갈래로 왔다 — 77번에는 아무 답도 안 나가
|
|
208
|
+
// 저쪽이 영영 기다렸고, 같은 번호의 우리 요청이 있으면 그게 엉뚱하게 풀렸다.
|
|
209
|
+
// id 와 method 가 같이 있으면 요청이다. 빈 method 는 아래에서 -32600 으로 답한다.
|
|
210
|
+
//
|
|
211
|
+
// 그리고 **result·error 칸이 있어야** 답이다 (8회차 ACP-3). method 칸이 아예
|
|
212
|
+
// 없는 줄은 위 빈 method 검사에 안 걸려 그대로 답 갈래로 갔고, result 가 없으니
|
|
213
|
+
// 기다리던 우리 요청이 `풀기(undefined)` 로 풀렸다 — 승인 묻기가 이 길로 오므로
|
|
214
|
+
// 답이 아닌 줄 하나가 승인 결과를 「아무것도 안 고름」 으로 만든다. 그 id 에는
|
|
215
|
+
// 답도 안 나가 저쪽도 영영 기다렸다. 무엇이 답인가는 규격이 정해 두었다.
|
|
216
|
+
if ('id' in 온것 && !('method' in 온것) && ('result' in 온것 || 'error' in 온것)) {
|
|
161
217
|
const 기다림 = this.기다리는것.get(온것.id);
|
|
162
218
|
if (!기다림) return; // 이미 포기한 것. 늦게 온 답은 조용히 버린다
|
|
163
219
|
this.기다리는것.delete(온것.id);
|
|
@@ -172,14 +228,38 @@ export class 연결 {
|
|
|
172
228
|
return;
|
|
173
229
|
}
|
|
174
230
|
|
|
175
|
-
if (typeof 온것.method !== 'string') {
|
|
231
|
+
if (typeof 온것.method !== 'string' || !온것.method) {
|
|
232
|
+
/*
|
|
233
|
+
* ── 우리 기다림을 **영영 매달아 두지 않는다** (사냥6 막판-뒷단) ───────
|
|
234
|
+
*
|
|
235
|
+
* 위 ACP-3 고침이 「result·error 가 없으면 답이 아니다」 로 막으면서, 그런 줄이
|
|
236
|
+
* 여기로 굴러떨어지게 됐다. 그런데 여기서는 저쪽에만 -32600 을 답하고 끝난다 —
|
|
237
|
+
* 그 번호를 기다리던 **우리** 요청은 아무도 안 깨운다. 요청() 에는 시계가 없어서
|
|
238
|
+
* 턴을 사람이 취소하기 전까지 서 있는다(재 봤다: pending 인 채로 남는다).
|
|
239
|
+
* 승인 묻기가 이 길로 오므로, 규격을 어긴 줄 하나에 화면이 말없이 멎는다 —
|
|
240
|
+
* 바로 위 문단이 「저쪽도 영영 기다렸다」 고 적어 둔 것의 우리 쪽 판이다.
|
|
241
|
+
*
|
|
242
|
+
* 깨뜨리면 serve.js 의 승인묻기 가 받아 「못 물어봐서 거부했습니다」 를 로그에
|
|
243
|
+
* 적고 안 한다. 못 물어본 것을 못 물어봤다고 말하는 것이 이 프로그램의 자세다.
|
|
244
|
+
* 깨뜨리는 것은 **method 칸이 아예 없는** 줄뿐이다. 빈 method 는 H5-10 이 정한
|
|
245
|
+
* 대로 「요청」 이라, 저쪽이 빈 글자 하나로 우리 승인 물음을 마음대로 끊게 된다 —
|
|
246
|
+
* 끊긴 물음의 답은 거부라 위험하진 않지만, 남이 끊을 수 있는 자리를 열어 줄 까닭이
|
|
247
|
+
* 없다. 칸째 없는 줄만 답이 깨진 것으로 본다.
|
|
248
|
+
*/
|
|
176
249
|
if ('id' in 온것) {
|
|
250
|
+
const 기다림 = 'method' in 온것 ? null : this.기다리는것.get(온것.id);
|
|
251
|
+
if (기다림) {
|
|
252
|
+
this.기다리는것.delete(온것.id);
|
|
253
|
+
try { 기다림.깨기(new Error('저쪽 답에 result·error 가 없습니다 — 규격에 맞는 답이 아닙니다')); } catch { /* 이미 정리된 것 */ }
|
|
254
|
+
}
|
|
177
255
|
this.#쓰기({ jsonrpc: '2.0', id: 온것.id, error: { code: 오류번호.잘못된요청, message: 'method 가 없습니다' } });
|
|
178
256
|
}
|
|
179
257
|
return;
|
|
180
258
|
}
|
|
181
259
|
|
|
182
|
-
|
|
260
|
+
// 알림은 id **칸이 없는** 요청이다(JSON-RPC 2.0). id 가 null 이어도 요청이라 답한다 —
|
|
261
|
+
// null 을 알림으로 쳤더니 답이 한 줄도 안 나가 저쪽이 영영 기다렸다 (6회차 규약6ai-b J2).
|
|
262
|
+
const 알림인가 = !('id' in 온것);
|
|
183
263
|
|
|
184
264
|
Promise.resolve()
|
|
185
265
|
.then(() => this.다루기(온것.method, 온것.params ?? {}))
|
package/src/acp/map.js
CHANGED
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
//
|
|
26
26
|
// 읽기만 하는 순수 함수를 들여오는 것은 순수함을 안 깬다. 규격을 읽는 규칙은
|
|
27
27
|
// backend/adapter.js 한 곳에만 있어야 한다 (집안 규칙: 자는 한 벌).
|
|
28
|
+
import { isAbsolute, resolve } from 'node:path';
|
|
29
|
+
|
|
28
30
|
import { 부른것들, 결과들, 본문글 } from '../backend/adapter.js';
|
|
29
31
|
import { 첫이름 } from '../tools/label.js';
|
|
30
32
|
|
|
@@ -40,9 +42,12 @@ const 갈래표 = {
|
|
|
40
42
|
Write: 'edit',
|
|
41
43
|
Append: 'edit',
|
|
42
44
|
Edit: 'edit',
|
|
45
|
+
Move: 'move',
|
|
43
46
|
Glob: 'search',
|
|
44
47
|
Grep: 'search',
|
|
45
48
|
Recall: 'search',
|
|
49
|
+
Def: 'search',
|
|
50
|
+
Refs: 'search',
|
|
46
51
|
Bash: 'execute',
|
|
47
52
|
Jobs: 'execute',
|
|
48
53
|
Verify: 'execute',
|
|
@@ -50,6 +55,7 @@ const 갈래표 = {
|
|
|
50
55
|
Task: 'think',
|
|
51
56
|
TodoWrite: 'think',
|
|
52
57
|
Skill: 'think',
|
|
58
|
+
Ask: 'other',
|
|
53
59
|
Remember: 'other',
|
|
54
60
|
};
|
|
55
61
|
|
|
@@ -77,8 +83,15 @@ export function 도구이름표(이름, 인자) {
|
|
|
77
83
|
: null)
|
|
78
84
|
?? (Array.isArray(a.paths) && a.paths.length ? `${a.paths.length}개` : null)
|
|
79
85
|
?? (Array.isArray(a.todos) ? `${a.todos.length}건` : null);
|
|
80
|
-
|
|
81
|
-
|
|
86
|
+
/*
|
|
87
|
+
* 이름표는 에디터의 **한 줄** 머리다. 본문 줄이는 자르기() 를 쓰면 그 끝에
|
|
88
|
+
* `\n… (N자 줄임)` 이 붙어서 머리가 두 줄이 되고, 한 줄을 미리 정해 둔
|
|
89
|
+
* 자리라 그 줄이 깨진다. 긴 명령 하나면 바로 그렇게 된다.
|
|
90
|
+
*/
|
|
91
|
+
const 안 = 첫 == null ? '' : 한줄로(String(첫), 80);
|
|
92
|
+
// 이름이 없으면 「도구」 다. 앞칸만 채우면 화면에 `undefined(a.js)` 가 뜬다.
|
|
93
|
+
const 이름글 = String(이름 ?? '').trim() || '도구';
|
|
94
|
+
return 안 ? `${이름글}(${안})` : 이름글;
|
|
82
95
|
}
|
|
83
96
|
|
|
84
97
|
/**
|
|
@@ -88,11 +101,21 @@ export function 도구이름표(이름, 인자) {
|
|
|
88
101
|
* 있는데, 에디터는 절대 경로라야 연다. 인자만 보고 넘기면 눌러도 안 열리는
|
|
89
102
|
* 링크가 되고, 그건 없느니만 못하다.
|
|
90
103
|
*/
|
|
91
|
-
export function 도구자리(이름, 인자,
|
|
104
|
+
export function 도구자리(이름, 인자, 결과, { 뿌리 = null } = {}) {
|
|
92
105
|
const 모은것 = [];
|
|
93
106
|
const 넣기 = (p) => {
|
|
94
107
|
const s = typeof p === 'string' ? p.trim() : '';
|
|
95
|
-
if (s
|
|
108
|
+
if (!s) return;
|
|
109
|
+
/*
|
|
110
|
+
* 상대 경로는 **여기서** 절대 경로로 편다.
|
|
111
|
+
*
|
|
112
|
+
* 에디터는 절대 경로라야 연다. 상대 경로를 그대로 주면 눌러도 아무 일이
|
|
113
|
+
* 안 일어나는데, 화면에는 멀쩡한 링크로 보인다 — 없느니만 못하다.
|
|
114
|
+
* 도는 중(tool_call)에는 결과가 아직 없어서 인자에 적힌 상대 경로뿐이라,
|
|
115
|
+
* 이 자리를 안 펴면 도구가 도는 내내 링크가 다 죽어 있다.
|
|
116
|
+
*/
|
|
117
|
+
const 편것 = 뿌리 && !isAbsolute(s) ? resolve(뿌리, s) : s;
|
|
118
|
+
if (!모은것.includes(편것)) 모은것.push(편것);
|
|
96
119
|
};
|
|
97
120
|
|
|
98
121
|
넣기(결과?.changed);
|
|
@@ -141,7 +164,7 @@ export function 도구내용(결과, 최대 = 2000) {
|
|
|
141
164
|
* @param {string} 아이디 이 세션 안에서 유일한 번호
|
|
142
165
|
* @param {object} ev loop.js 가 흘린 `tool` 이벤트
|
|
143
166
|
*/
|
|
144
|
-
export function 도구끝남(아이디, ev) {
|
|
167
|
+
export function 도구끝남(아이디, ev, { 뿌리 = null } = {}) {
|
|
145
168
|
return {
|
|
146
169
|
sessionUpdate: 'tool_call_update',
|
|
147
170
|
toolCallId: 아이디,
|
|
@@ -149,12 +172,12 @@ export function 도구끝남(아이디, ev) {
|
|
|
149
172
|
kind: 도구갈래(ev?.name),
|
|
150
173
|
status: 도구탈났나(ev?.result) ? 'failed' : 'completed',
|
|
151
174
|
content: 도구내용(ev?.result),
|
|
152
|
-
locations: 도구자리(ev?.name, ev?.args, ev?.result),
|
|
175
|
+
locations: 도구자리(ev?.name, ev?.args, ev?.result, { 뿌리 }),
|
|
153
176
|
};
|
|
154
177
|
}
|
|
155
178
|
|
|
156
179
|
/** 이제 막 시작한 도구 호출. */
|
|
157
|
-
export function 도구시작(아이디, 이름,
|
|
180
|
+
export function 도구시작(아이디, 이름, 인자, { 뿌리 = null } = {}) {
|
|
158
181
|
return {
|
|
159
182
|
sessionUpdate: 'tool_call',
|
|
160
183
|
toolCallId: 아이디,
|
|
@@ -162,7 +185,7 @@ export function 도구시작(아이디, 이름, 인자) {
|
|
|
162
185
|
kind: 도구갈래(이름),
|
|
163
186
|
status: 'in_progress',
|
|
164
187
|
content: [],
|
|
165
|
-
locations: 도구자리(이름, 인자, null),
|
|
188
|
+
locations: 도구자리(이름, 인자, null, { 뿌리 }),
|
|
166
189
|
};
|
|
167
190
|
}
|
|
168
191
|
|
|
@@ -227,7 +250,7 @@ function 인자풀기(x) {
|
|
|
227
250
|
* @param {object[]} messages store.js 가 읽어 온 대화
|
|
228
251
|
* @returns {object[]} session/update 의 update 자리에 그대로 넣을 것들
|
|
229
252
|
*/
|
|
230
|
-
export function 되살린것(messages, { 최대내용 = 2000 } = {}) {
|
|
253
|
+
export function 되살린것(messages, { 최대내용 = 2000, 뿌리 = null } = {}) {
|
|
231
254
|
const 줄 = Array.isArray(messages) ? messages : [];
|
|
232
255
|
|
|
233
256
|
/*
|
|
@@ -290,8 +313,20 @@ export function 되살린것(messages, { 최대내용 = 2000 } = {}) {
|
|
|
290
313
|
const 이름 = String(tc.name ?? '도구');
|
|
291
314
|
const 인자 = 인자풀기(tc.args);
|
|
292
315
|
|
|
316
|
+
/*
|
|
317
|
+
* id 가 붙은 부름은 **id 로만** 찾는다.
|
|
318
|
+
*
|
|
319
|
+
* 못 찾으면 이름 큐로 한 번 더 찾았다. 그 큐에 든 것은 id 를 안 주는 규격의
|
|
320
|
+
* 답이거나 **같은 이름을 쓰는 다른 부름의 답**이다. 그래서 제 답이 안 남은
|
|
321
|
+
* 부름이 남의 답을 뺏어 달고 completed 로 그려졌다 — 바로 아래 머리말이
|
|
322
|
+
* 「성공으로 그리면 안 된다」 고 적어 둔 그 자리다. 게다가 뺏긴 쪽은 큐가
|
|
323
|
+
* 비어 실패로 밀린다. 한 줄 어긋난 것이 아니라 둘 다 틀린 것이다.
|
|
324
|
+
*
|
|
325
|
+
* id 를 주는 규격은 답에도 id 를 적는다(adapter.js 의 toolMessage). 이름으로
|
|
326
|
+
* 짝짓는 것은 id 가 아예 없는 규격(ollama)뿐이고, 그쪽은 부름에도 id 가 없다.
|
|
327
|
+
*/
|
|
293
328
|
let 답;
|
|
294
|
-
if (tc?.id != null
|
|
329
|
+
if (tc?.id != null) 답 = id로.get(tc.id);
|
|
295
330
|
else {
|
|
296
331
|
const q = 이름으로.get(이름);
|
|
297
332
|
if (q?.length) 답 = q.shift();
|
|
@@ -315,7 +350,7 @@ export function 되살린것(messages, { 최대내용 = 2000 } = {}) {
|
|
|
315
350
|
content: 없음
|
|
316
351
|
? [{ type: 'content', content: { type: 'text', text: '결과가 안 남았습니다 — 이 도구가 도는 중에 끊겼습니다.' } }]
|
|
317
352
|
: [{ type: 'content', content: { type: 'text', text: 자르기(String(답), 최대내용) } }],
|
|
318
|
-
locations: 도구자리(이름, 인자, null),
|
|
353
|
+
locations: 도구자리(이름, 인자, null, { 뿌리 }),
|
|
319
354
|
});
|
|
320
355
|
}
|
|
321
356
|
}
|
|
@@ -340,8 +375,16 @@ export function 프롬프트글(덩이들) {
|
|
|
340
375
|
break;
|
|
341
376
|
case 'resource': {
|
|
342
377
|
const r = b.resource ?? {};
|
|
343
|
-
|
|
344
|
-
|
|
378
|
+
/*
|
|
379
|
+
* 빈 글도 **읽은 것**이다.
|
|
380
|
+
*
|
|
381
|
+
* `&& r.text` 로 보던 때는 빈 파일이 알맹이가 아예 안 실려 온 붙임과 같은
|
|
382
|
+
* 갈래로 떨어져 「글이 아니라 못 읽었습니다」 가 붙었다. 모델은 그걸 읽기
|
|
383
|
+
* 실패로 알아듣고 같은 파일을 Read 로 또 연다 — 그리고 또 빈 파일을 본다.
|
|
384
|
+
* 빈 것과 못 읽은 것은 다음에 할 일이 다르다.
|
|
385
|
+
*/
|
|
386
|
+
if (typeof r.text === 'string') {
|
|
387
|
+
조각.push(`--- ${r.uri ?? '붙임'} ---\n${r.text || '(빈 파일입니다)'}`);
|
|
345
388
|
} else if (r.uri) {
|
|
346
389
|
조각.push(`(붙임: ${r.uri} — 글이 아니라 못 읽었습니다)`);
|
|
347
390
|
}
|
|
@@ -365,3 +408,9 @@ function 자르기(s, n) {
|
|
|
365
408
|
const t = String(s ?? '');
|
|
366
409
|
return t.length > n ? `${t.slice(0, n)}\n… (${t.length - n}자 줄임)` : t;
|
|
367
410
|
}
|
|
411
|
+
|
|
412
|
+
/** 한 줄짜리 자리(이름표)에 쓴다. 줄바꿈을 빈칸으로 눕히고 말줄임만 붙인다. */
|
|
413
|
+
function 한줄로(s, n) {
|
|
414
|
+
const t = String(s ?? '').replace(/\s+/g, ' ').trim();
|
|
415
|
+
return t.length > n ? `${t.slice(0, n)}…` : t;
|
|
416
|
+
}
|