connectbase-client 3.39.0 → 3.41.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/CHANGELOG.md +66 -0
- package/dist/cli.js +58 -5
- package/dist/index.d.mts +15 -3
- package/dist/index.d.ts +15 -3
- package/dist/index.js +4 -3
- package/dist/index.mjs +4 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,72 @@
|
|
|
3
3
|
본 SDK 의 모든 주요 변경사항을 [Keep a Changelog](https://keepachangelog.com/ko/1.1.0/) 형식으로 기록합니다.
|
|
4
4
|
버전은 [Semantic Versioning](https://semver.org/lang/ko/) 을 따릅니다.
|
|
5
5
|
|
|
6
|
+
## [3.41.0] - 2026-07-02
|
|
7
|
+
|
|
8
|
+
### Added — 웹 배포 파일당 크기 한도 사전 검증 (fail-fast)
|
|
9
|
+
|
|
10
|
+
`connectbase deploy` 가 파일을 수집한 직후, 서버로 업로드하기 **전에** 각 파일이 웹 스토리지
|
|
11
|
+
파일당 크기 한도를 넘는지 검사한다(플랫폼 이슈 019f221b). 기존에는 전량 수집·업로드를 마친
|
|
12
|
+
뒤에야 서버에서 원시 DB 오류(`Error 8025 (HY000): entry too large`)로 실패해 원인 파악이
|
|
13
|
+
어려웠다.
|
|
14
|
+
|
|
15
|
+
- 초과 파일이 있으면 **어떤 파일이 얼마나 큰지**(바이너리는 원본→base64 크기까지) 나열하고,
|
|
16
|
+
파일 스토리지(`cb.storage`) 사용을 안내한 뒤 업로드 없이 즉시 종료한다.
|
|
17
|
+
- 검사 기준: 파일 내용은 DB(TiDB Text 컬럼)에 저장되며 단일 엔트리 한도 6 MiB 를 넘을 수 없다.
|
|
18
|
+
바이너리는 base64(약 1.33x)로 저장되므로 원본 기준 실질 상한은 약 4.5 MB.
|
|
19
|
+
- 텍스트 파일은 UTF-8 바이트 기준으로 정확히 계산(멀티바이트 문자 포함).
|
|
20
|
+
|
|
21
|
+
## [3.40.0] - 2026-06-28
|
|
22
|
+
|
|
23
|
+
### Added — KB 하이브리드(시맨틱) 검색 지원
|
|
24
|
+
|
|
25
|
+
지식베이스 검색에 BM25 키워드 + 벡터 의미 검색을 RRF(Reciprocal Rank Fusion)로 융합하는
|
|
26
|
+
하이브리드 검색을 추가했다. 콘솔 > **AI** 에서 임베딩을 켠 앱(gemini / openai BYOK)에서
|
|
27
|
+
동작하며, 오타·동의어·의역에 강하다.
|
|
28
|
+
|
|
29
|
+
- **\`KnowledgeSearchRequest.hybrid?: boolean\`** — \`cb.knowledge.search()\` 에 hybrid 옵션 추가.
|
|
30
|
+
미설정(기본)이면 임베딩을 켠 앱에서 자동 적용, \`false\` 면 키워드 전용 검색을 강제.
|
|
31
|
+
- **\`AIChatRequest.hybrid?: boolean\`** — \`cb.ai.chat()\` / \`cb.ai.chatStream()\` 의 RAG 검색에도
|
|
32
|
+
동일 옵션 적용. 미설정이면 임베딩을 켠 앱에서 자동 적용된다.
|
|
33
|
+
- 임베딩 미설정 앱에서는 무시되며 기존 BM25 검색으로 동작한다(하위호환, 회귀 없음).
|
|
34
|
+
|
|
35
|
+
## [3.39.2] - 2026-06-26
|
|
36
|
+
|
|
37
|
+
### Performance — 터널 프록시 응답 지연 제거 (TCP_NODELAY / keep-alive)
|
|
38
|
+
|
|
39
|
+
`connectbase tunnel` 프록시 경유가 직접 호출 대비 **~2.4초 고정 지연**을 추가하던 문제를
|
|
40
|
+
수정했다(플랫폼 이슈 019f01c3 — 실시간 TTS 음성에서 "첫 음성까지 ~3.5초"). 원인은 응답
|
|
41
|
+
본문을 tunnel-server 로 되돌리는 영구 WebSocket 소켓에 Nagle 알고리즘이 켜져 있던 것이다.
|
|
42
|
+
|
|
43
|
+
- **TCP_NODELAY (핵심)**: tunnel-server 로의 영구 WS 소켓에 `setNoDelay(true)` 적용. 프록시
|
|
44
|
+
응답 본문은 CLI→tunnel-server 방향으로 CLI 가 송신하는데, 업스트림(사이드카)이 본문을
|
|
45
|
+
여러 작은 청크로 흘리면 각 WS 프레임 write 가 직전 세그먼트의 ACK 를 기다리며 묶였다.
|
|
46
|
+
tunnel-server 가 지리적으로 먼 경우(예: 한국↔싱가포르 ~45ms RTT) 이 Nagle×delayed-ACK
|
|
47
|
+
상호작용이 프레임당 수십 ms 스톨을 만들고, 청크 수에 비례해 고정 수초로 누적됐다.
|
|
48
|
+
- **로컬 keep-alive**: 사이드카(로컬 업스트림) HTTP 호출에 keep-alive Agent 적용 — 요청마다
|
|
49
|
+
TCP 핸드셰이크를 새로 맺지 않고 소켓을 재사용한다(순차 호출 시 이득).
|
|
50
|
+
- **로컬·업스트림 WS 소켓 NoDelay**: 사이드카 HTTP/WS 소켓에도 `setNoDelay(true)` 적용
|
|
51
|
+
(인터랙티브 WS — noVNC·실시간 프레임 — 프레임당 지연 감소).
|
|
52
|
+
|
|
53
|
+
연계: core-server 도 프록시 forward 를 공개 도메인(`tunnel.connectbase.world`, 클러스터
|
|
54
|
+
밖 ingress 헤어핀)이 아니라 tunnel-server 내부 ClusterIP 로 직결하도록 함께 수정됐다.
|
|
55
|
+
|
|
56
|
+
## [3.39.1] - 2026-06-26
|
|
57
|
+
|
|
58
|
+
### Fixed — 터널 인증 4xx 를 재시도하지 않고 즉시 원인 표시
|
|
59
|
+
|
|
60
|
+
`connectbase tunnel` 이 인증 단계에서 받은 **클라이언트 오류(4xx)** 를 일시 장애처럼 10회
|
|
61
|
+
재시도하던 것을 수정했다. 서버가 4xx 로 명확히 거부하면 재시도 없이 즉시 원인을 출력하고 종료한다.
|
|
62
|
+
|
|
63
|
+
- **403 (앱 접근 거부)**: `app_id` 오설정(공개키 UUID·storageId 입력)이 대부분 — 서버 메시지와
|
|
64
|
+
함께 "`app_id` 가 콘솔의 앱/프로젝트 ID 인지 확인" 안내를 출력하고 즉시 종료.
|
|
65
|
+
- **그 외 4xx (400/404 등)**: 설정 문제라 재시도해도 동일하게 실패 → 즉시 종료.
|
|
66
|
+
- **5xx · 429 · 네트워크 오류**: 기존대로 지수 백오프 재시도(일시적 장애).
|
|
67
|
+
- 서버 응답 본문의 `{"error":"..."}` 메시지를 파싱해 표시.
|
|
68
|
+
|
|
69
|
+
연계: tunnel-server 가 core 인증 4xx(403/401)를 503 "auth service unavailable" 로 뭉개던
|
|
70
|
+
서버측 문제도 함께 수정됐다(설정 오류가 서비스 장애로 오진단되던 것 해소).
|
|
71
|
+
|
|
6
72
|
## [3.39.0] - 2026-06-25
|
|
7
73
|
|
|
8
74
|
### Removed (BREAKING) — 게스트/익명 로그인 제거
|
package/dist/cli.js
CHANGED
|
@@ -215,6 +215,7 @@ var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
215
215
|
".zip",
|
|
216
216
|
".wasm"
|
|
217
217
|
]);
|
|
218
|
+
var WEB_FILE_MAX_STORED_BYTES = 6 * 1024 * 1024 - 64 * 1024;
|
|
218
219
|
function sha256Hex(value) {
|
|
219
220
|
return crypto.createHash("sha256").update(value, "utf8").digest("hex");
|
|
220
221
|
}
|
|
@@ -281,6 +282,29 @@ function collectFiles(dir, baseDir = dir) {
|
|
|
281
282
|
}
|
|
282
283
|
return files;
|
|
283
284
|
}
|
|
285
|
+
function formatSize(bytes) {
|
|
286
|
+
if (bytes >= 1024 * 1024) return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
|
|
287
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
288
|
+
}
|
|
289
|
+
function validateFileSizes(files) {
|
|
290
|
+
const oversized = files.map((f) => {
|
|
291
|
+
const storedBytes = Buffer.byteLength(f.content, "utf8");
|
|
292
|
+
const originalBytes = f.isBinary ? Math.round(f.content.length * 3 / 4) : storedBytes;
|
|
293
|
+
return { path: f.path, isBinary: f.isBinary, storedBytes, originalBytes };
|
|
294
|
+
}).filter((f) => f.storedBytes > WEB_FILE_MAX_STORED_BYTES);
|
|
295
|
+
if (oversized.length === 0) return;
|
|
296
|
+
error(`\uC6F9 \uC2A4\uD1A0\uB9AC\uC9C0 \uD30C\uC77C\uB2F9 \uD06C\uAE30 \uD55C\uB3C4(\uC57D ${formatSize(WEB_FILE_MAX_STORED_BYTES)})\uB97C \uCD08\uACFC\uD55C \uD30C\uC77C\uC774 \uC788\uC5B4 \uBC30\uD3EC\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4:`);
|
|
297
|
+
for (const f of oversized) {
|
|
298
|
+
const detail = f.isBinary ? `${formatSize(f.originalBytes)} \u2192 base64 ${formatSize(f.storedBytes)}` : formatSize(f.storedBytes);
|
|
299
|
+
error(` \u2022 ${f.path} (${detail})`);
|
|
300
|
+
}
|
|
301
|
+
log("");
|
|
302
|
+
warn("\uC815\uC801 \uD638\uC2A4\uD305 \uD30C\uC77C\uC740 DB \uB2E8\uC77C \uC5D4\uD2B8\uB9AC(6 MiB)\uC5D0 \uC800\uC7A5\uB418\uBA70, \uBC14\uC774\uB108\uB9AC\uB294 base64(\uC57D 1.33x)\uB85C");
|
|
303
|
+
warn("\uBD80\uD480\uC5B4 \uC6D0\uBCF8 \uAE30\uC900 \uC57D 4.5 MB \uAC00 \uC2E4\uC9C8 \uC0C1\uD55C\uC785\uB2C8\uB2E4.");
|
|
304
|
+
warn(`\uB300\uC6A9\uB7C9 \uC5D0\uC14B(3D \uBAA8\uB378\xB7\uB3D9\uC601\uC0C1\xB7\uD070 \uD3F0\uD2B8 \uB4F1)\uC740 \uD30C\uC77C \uC2A4\uD1A0\uB9AC\uC9C0(${colors.cyan}cb.storage${colors.reset}, presigned URL)\uC5D0`);
|
|
305
|
+
warn("\uC62C\uB9AC\uACE0 URL \uB85C \uCC38\uC870\uD558\uC138\uC694. \uD30C\uC77C \uC2A4\uD1A0\uB9AC\uC9C0\uB294 \uD30C\uC77C\uB2F9 \uACE0\uC815 \uC0C1\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
306
|
+
process.exit(1);
|
|
307
|
+
}
|
|
284
308
|
var DEFAULT_REQUEST_TIMEOUT_MS = 6e4;
|
|
285
309
|
async function makeRequest(url, method, headers, body, reqOpts = {}) {
|
|
286
310
|
return new Promise((resolve2, reject) => {
|
|
@@ -378,6 +402,7 @@ async function deploy(directory, config, isDev = false, deployOpts = {}) {
|
|
|
378
402
|
error("\uBC30\uD3EC\uD560 \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
379
403
|
process.exit(1);
|
|
380
404
|
}
|
|
405
|
+
validateFileSizes(files);
|
|
381
406
|
const totalSize = files.reduce((sum, f) => sum + f.content.length, 0);
|
|
382
407
|
const sizeKB = (totalSize / 1024).toFixed(1);
|
|
383
408
|
log(`${colors.green}\u2713${colors.reset} ${files.length}\uAC1C \uD30C\uC77C \uBC1C\uACAC (${sizeKB} KB)`);
|
|
@@ -1933,6 +1958,7 @@ ${colors.cyan}ConnectBase Tunnel${colors.reset}`);
|
|
|
1933
1958
|
req.on("upgrade", (_res, sock, _head) => {
|
|
1934
1959
|
socket = sock;
|
|
1935
1960
|
reconnectAttempts = 0;
|
|
1961
|
+
sock.setNoDelay(true);
|
|
1936
1962
|
const parser = new WsFrameParser({
|
|
1937
1963
|
onMessage: (data) => {
|
|
1938
1964
|
try {
|
|
@@ -1988,16 +2014,32 @@ ${colors.cyan}ConnectBase Tunnel${colors.reset}`);
|
|
|
1988
2014
|
let body = "";
|
|
1989
2015
|
res.on("data", (chunk) => body += chunk.toString());
|
|
1990
2016
|
res.on("end", () => {
|
|
1991
|
-
|
|
1992
|
-
|
|
2017
|
+
const status = res.statusCode ?? 0;
|
|
2018
|
+
let serverMsg = body;
|
|
2019
|
+
try {
|
|
2020
|
+
const j = JSON.parse(body);
|
|
2021
|
+
if (j && typeof j.error === "string") serverMsg = j.error;
|
|
2022
|
+
} catch {
|
|
2023
|
+
}
|
|
2024
|
+
if (status === 401) {
|
|
2025
|
+
error("\uC778\uC99D \uC2E4\uD328: Secret Key\uAC00 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
1993
2026
|
shouldReconnect = false;
|
|
1994
2027
|
process.exit(1);
|
|
1995
|
-
} else if (
|
|
2028
|
+
} else if (status === 402) {
|
|
1996
2029
|
error("\uD560\uB2F9\uB7C9 \uCD08\uACFC: \uD50C\uB79C\uC744 \uC5C5\uADF8\uB808\uC774\uB4DC\uD558\uC138\uC694");
|
|
1997
2030
|
shouldReconnect = false;
|
|
1998
2031
|
process.exit(1);
|
|
2032
|
+
} else if (status === 403) {
|
|
2033
|
+
error(`\uC811\uADFC \uAC70\uBD80: ${serverMsg}`);
|
|
2034
|
+
error("\u2192 app_id \uAC00 \uCF58\uC194\uC758 \uC571/\uD504\uB85C\uC81D\uD2B8 ID \uC778\uC9C0 \uD655\uC778\uD558\uC138\uC694 (\uACF5\uAC1C\uD0A4 UUID \uB098 storageId \uAC00 \uC544\uB2D9\uB2C8\uB2E4).");
|
|
2035
|
+
shouldReconnect = false;
|
|
2036
|
+
process.exit(1);
|
|
2037
|
+
} else if (status >= 400 && status < 500 && status !== 429) {
|
|
2038
|
+
error(`\uD130\uB110 \uC5F0\uACB0 \uAC70\uBD80 (${status}): ${serverMsg}`);
|
|
2039
|
+
shouldReconnect = false;
|
|
2040
|
+
process.exit(1);
|
|
1999
2041
|
} else {
|
|
2000
|
-
error(`\uD130\uB110 \uC11C\uBC84 \uC751\uB2F5 \uC624\uB958 (${
|
|
2042
|
+
error(`\uD130\uB110 \uC11C\uBC84 \uC751\uB2F5 \uC624\uB958 (${status}): ${serverMsg}`);
|
|
2001
2043
|
if (shouldReconnect) {
|
|
2002
2044
|
scheduleReconnect();
|
|
2003
2045
|
}
|
|
@@ -2017,6 +2059,7 @@ ${colors.cyan}ConnectBase Tunnel${colors.reset}`);
|
|
|
2017
2059
|
setTimeout(connect, delay);
|
|
2018
2060
|
}
|
|
2019
2061
|
const streams = /* @__PURE__ */ new Map();
|
|
2062
|
+
const localAgent = new http.Agent({ keepAlive: true, maxSockets: 64 });
|
|
2020
2063
|
function routeStreamData(streamId, payload) {
|
|
2021
2064
|
const f = streams.get(streamId);
|
|
2022
2065
|
if (!f) return;
|
|
@@ -2050,7 +2093,7 @@ ${colors.cyan}ConnectBase Tunnel${colors.reset}`);
|
|
|
2050
2093
|
let started = false;
|
|
2051
2094
|
let cancelled = false;
|
|
2052
2095
|
const localReq = http.request(
|
|
2053
|
-
{ hostname: "127.0.0.1", port: localPort, path: fullPath, method, headers: localHeaders },
|
|
2096
|
+
{ hostname: "127.0.0.1", port: localPort, path: fullPath, method, headers: localHeaders, agent: localAgent },
|
|
2054
2097
|
(res) => {
|
|
2055
2098
|
const respHeaders = {};
|
|
2056
2099
|
for (const [k, v] of Object.entries(res.headers)) {
|
|
@@ -2082,6 +2125,12 @@ ${colors.cyan}ConnectBase Tunnel${colors.reset}`);
|
|
|
2082
2125
|
});
|
|
2083
2126
|
}
|
|
2084
2127
|
);
|
|
2128
|
+
localReq.on("socket", (s) => {
|
|
2129
|
+
try {
|
|
2130
|
+
s.setNoDelay(true);
|
|
2131
|
+
} catch {
|
|
2132
|
+
}
|
|
2133
|
+
});
|
|
2085
2134
|
localReq.on("error", (err) => {
|
|
2086
2135
|
warn(`\uB85C\uCEEC \uC11C\uBC84 \uC5F0\uACB0 \uC2E4\uD328 (${method} ${reqPath}): ${err.message}`);
|
|
2087
2136
|
if (!started) {
|
|
@@ -2140,6 +2189,10 @@ ${colors.cyan}ConnectBase Tunnel${colors.reset}`);
|
|
|
2140
2189
|
});
|
|
2141
2190
|
req.on("upgrade", (res, sk) => {
|
|
2142
2191
|
upstream = sk;
|
|
2192
|
+
try {
|
|
2193
|
+
upstream.setNoDelay(true);
|
|
2194
|
+
} catch {
|
|
2195
|
+
}
|
|
2143
2196
|
const respHeaders = {};
|
|
2144
2197
|
for (const [k, v] of Object.entries(res.headers)) {
|
|
2145
2198
|
if (v == null) continue;
|
package/dist/index.d.mts
CHANGED
|
@@ -2402,14 +2402,15 @@ declare class StorageAPI {
|
|
|
2402
2402
|
* 파일 목록 조회
|
|
2403
2403
|
*
|
|
2404
2404
|
* @param storageId - 파일 스토리지 ID
|
|
2405
|
-
* @param parentId - 부모 폴더 ID
|
|
2405
|
+
* @param parentId - 부모 폴더 ID. 지정 시 해당 폴더의 **직계 자식만** 반환한다.
|
|
2406
|
+
* 미지정 시 스토리지 **전체 파일 트리**를 flat 배열로 반환한다.
|
|
2406
2407
|
*
|
|
2407
2408
|
* @example
|
|
2408
2409
|
* ```ts
|
|
2409
|
-
* //
|
|
2410
|
+
* // 스토리지 전체 파일 목록 (flat 트리)
|
|
2410
2411
|
* const files = await cb.storage.getFiles('storage-id')
|
|
2411
2412
|
*
|
|
2412
|
-
* // 특정 폴더의
|
|
2413
|
+
* // 특정 폴더의 직계 자식만 (대용량 버킷에서 전체 트리 전송 회피)
|
|
2413
2414
|
* const subFiles = await cb.storage.getFiles('storage-id', 'folder-id')
|
|
2414
2415
|
* ```
|
|
2415
2416
|
*/
|
|
@@ -7370,6 +7371,12 @@ interface KnowledgeSearchRequest {
|
|
|
7370
7371
|
top_k?: number;
|
|
7371
7372
|
/** Agentic Search 활성화 — AI 가 쿼리를 자동 생성하여 다중 검색 수행 */
|
|
7372
7373
|
agentic?: boolean;
|
|
7374
|
+
/**
|
|
7375
|
+
* Hybrid 검색 — BM25 키워드 + 벡터 시맨틱 검색을 RRF 로 융합.
|
|
7376
|
+
* 미설정(기본): 콘솔 > AI 에서 embedding 을 켠 앱은 자동 적용.
|
|
7377
|
+
* `false`: 키워드 전용 검색 강제. embedding 미설정 앱에서는 무시(BM25 only).
|
|
7378
|
+
*/
|
|
7379
|
+
hybrid?: boolean;
|
|
7373
7380
|
/**
|
|
7374
7381
|
* metadata 기반 필터 (옵셔널). 키 형식 `metadata.<path>` 또는 raw key.
|
|
7375
7382
|
* 값에 `AUTH_MEMBER_ID_TOKEN` 사용 시 서버가 인증된 AppMember ID 로 치환.
|
|
@@ -7655,6 +7662,11 @@ interface AIChatRequest {
|
|
|
7655
7662
|
knowledgeBaseId?: string;
|
|
7656
7663
|
topK?: number;
|
|
7657
7664
|
agentic?: boolean;
|
|
7665
|
+
/**
|
|
7666
|
+
* KB 검색 hybrid(BM25 + 벡터 시맨틱, RRF 융합) 제어. 미설정(기본)이면 콘솔 > AI 에서
|
|
7667
|
+
* embedding 을 켠 앱은 자동 적용, `false` 면 키워드 전용 검색 강제.
|
|
7668
|
+
*/
|
|
7669
|
+
hybrid?: boolean;
|
|
7658
7670
|
toolGroupId?: string;
|
|
7659
7671
|
/**
|
|
7660
7672
|
* 0 보다 크면, 서버측 도구 그룹 실행(`toolGroupId` 사용 시)에서 각 도구 결과를 모델에
|
package/dist/index.d.ts
CHANGED
|
@@ -2402,14 +2402,15 @@ declare class StorageAPI {
|
|
|
2402
2402
|
* 파일 목록 조회
|
|
2403
2403
|
*
|
|
2404
2404
|
* @param storageId - 파일 스토리지 ID
|
|
2405
|
-
* @param parentId - 부모 폴더 ID
|
|
2405
|
+
* @param parentId - 부모 폴더 ID. 지정 시 해당 폴더의 **직계 자식만** 반환한다.
|
|
2406
|
+
* 미지정 시 스토리지 **전체 파일 트리**를 flat 배열로 반환한다.
|
|
2406
2407
|
*
|
|
2407
2408
|
* @example
|
|
2408
2409
|
* ```ts
|
|
2409
|
-
* //
|
|
2410
|
+
* // 스토리지 전체 파일 목록 (flat 트리)
|
|
2410
2411
|
* const files = await cb.storage.getFiles('storage-id')
|
|
2411
2412
|
*
|
|
2412
|
-
* // 특정 폴더의
|
|
2413
|
+
* // 특정 폴더의 직계 자식만 (대용량 버킷에서 전체 트리 전송 회피)
|
|
2413
2414
|
* const subFiles = await cb.storage.getFiles('storage-id', 'folder-id')
|
|
2414
2415
|
* ```
|
|
2415
2416
|
*/
|
|
@@ -7370,6 +7371,12 @@ interface KnowledgeSearchRequest {
|
|
|
7370
7371
|
top_k?: number;
|
|
7371
7372
|
/** Agentic Search 활성화 — AI 가 쿼리를 자동 생성하여 다중 검색 수행 */
|
|
7372
7373
|
agentic?: boolean;
|
|
7374
|
+
/**
|
|
7375
|
+
* Hybrid 검색 — BM25 키워드 + 벡터 시맨틱 검색을 RRF 로 융합.
|
|
7376
|
+
* 미설정(기본): 콘솔 > AI 에서 embedding 을 켠 앱은 자동 적용.
|
|
7377
|
+
* `false`: 키워드 전용 검색 강제. embedding 미설정 앱에서는 무시(BM25 only).
|
|
7378
|
+
*/
|
|
7379
|
+
hybrid?: boolean;
|
|
7373
7380
|
/**
|
|
7374
7381
|
* metadata 기반 필터 (옵셔널). 키 형식 `metadata.<path>` 또는 raw key.
|
|
7375
7382
|
* 값에 `AUTH_MEMBER_ID_TOKEN` 사용 시 서버가 인증된 AppMember ID 로 치환.
|
|
@@ -7655,6 +7662,11 @@ interface AIChatRequest {
|
|
|
7655
7662
|
knowledgeBaseId?: string;
|
|
7656
7663
|
topK?: number;
|
|
7657
7664
|
agentic?: boolean;
|
|
7665
|
+
/**
|
|
7666
|
+
* KB 검색 hybrid(BM25 + 벡터 시맨틱, RRF 융합) 제어. 미설정(기본)이면 콘솔 > AI 에서
|
|
7667
|
+
* embedding 을 켠 앱은 자동 적용, `false` 면 키워드 전용 검색 강제.
|
|
7668
|
+
*/
|
|
7669
|
+
hybrid?: boolean;
|
|
7658
7670
|
toolGroupId?: string;
|
|
7659
7671
|
/**
|
|
7660
7672
|
* 0 보다 크면, 서버측 도구 그룹 실행(`toolGroupId` 사용 시)에서 각 도구 결과를 모델에
|
package/dist/index.js
CHANGED
|
@@ -2279,14 +2279,15 @@ var StorageAPI = class {
|
|
|
2279
2279
|
* 파일 목록 조회
|
|
2280
2280
|
*
|
|
2281
2281
|
* @param storageId - 파일 스토리지 ID
|
|
2282
|
-
* @param parentId - 부모 폴더 ID
|
|
2282
|
+
* @param parentId - 부모 폴더 ID. 지정 시 해당 폴더의 **직계 자식만** 반환한다.
|
|
2283
|
+
* 미지정 시 스토리지 **전체 파일 트리**를 flat 배열로 반환한다.
|
|
2283
2284
|
*
|
|
2284
2285
|
* @example
|
|
2285
2286
|
* ```ts
|
|
2286
|
-
* //
|
|
2287
|
+
* // 스토리지 전체 파일 목록 (flat 트리)
|
|
2287
2288
|
* const files = await cb.storage.getFiles('storage-id')
|
|
2288
2289
|
*
|
|
2289
|
-
* // 특정 폴더의
|
|
2290
|
+
* // 특정 폴더의 직계 자식만 (대용량 버킷에서 전체 트리 전송 회피)
|
|
2290
2291
|
* const subFiles = await cb.storage.getFiles('storage-id', 'folder-id')
|
|
2291
2292
|
* ```
|
|
2292
2293
|
*/
|
package/dist/index.mjs
CHANGED
|
@@ -2234,14 +2234,15 @@ var StorageAPI = class {
|
|
|
2234
2234
|
* 파일 목록 조회
|
|
2235
2235
|
*
|
|
2236
2236
|
* @param storageId - 파일 스토리지 ID
|
|
2237
|
-
* @param parentId - 부모 폴더 ID
|
|
2237
|
+
* @param parentId - 부모 폴더 ID. 지정 시 해당 폴더의 **직계 자식만** 반환한다.
|
|
2238
|
+
* 미지정 시 스토리지 **전체 파일 트리**를 flat 배열로 반환한다.
|
|
2238
2239
|
*
|
|
2239
2240
|
* @example
|
|
2240
2241
|
* ```ts
|
|
2241
|
-
* //
|
|
2242
|
+
* // 스토리지 전체 파일 목록 (flat 트리)
|
|
2242
2243
|
* const files = await cb.storage.getFiles('storage-id')
|
|
2243
2244
|
*
|
|
2244
|
-
* // 특정 폴더의
|
|
2245
|
+
* // 특정 폴더의 직계 자식만 (대용량 버킷에서 전체 트리 전송 회피)
|
|
2245
2246
|
* const subFiles = await cb.storage.getFiles('storage-id', 'folder-id')
|
|
2246
2247
|
* ```
|
|
2247
2248
|
*/
|