@botconnector/bccli 0.3.0-beta.3 → 0.4.0-beta.10
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.md +75 -2
- package/dist/args-AWLROI65.js +12 -0
- package/dist/{chunk-Z5JM76EL.js → chunk-2MGINW4O.js} +4 -1
- package/dist/{chunk-5C6NQFSI.js → chunk-7S6JXQCH.js} +1 -1
- package/dist/{chunk-XQLXE666.js → chunk-BFZXRKW5.js} +1 -1
- package/dist/{chunk-RDQ7HPWS.js → chunk-BJ337ABK.js} +18 -4
- package/dist/chunk-CLN4Z5E3.js +60 -0
- package/dist/{chunk-TV6LEHOH.js → chunk-DX7CZTBB.js} +1 -1
- package/dist/{chunk-5XN44Q55.js → chunk-ELML4KVQ.js} +7 -1
- package/dist/{chunk-R37QWDTL.js → chunk-IOWDWOXS.js} +2 -2
- package/dist/chunk-KV27KTOX.js +254 -0
- package/dist/{chunk-5ISYVAXI.js → chunk-U7GK73CK.js} +90 -15
- package/dist/cli.js +328 -135
- package/dist/{config-XPWPGNZJ.js → config-YUNKPCNB.js} +2 -2
- package/dist/integrationCli-GEIMUL3M.js +347 -0
- package/dist/{login-WJMGVDRM.js → login-4C262MEI.js} +1 -1
- package/dist/{mcpCli-BV3IGR47.js → mcpCli-DZWQPTOS.js} +3 -3
- package/dist/providerCli-Q7LRM2NP.js +12 -0
- package/dist/ui-6GTQUJOE.js +1415 -0
- package/package.json +2 -1
- package/dist/args-EVIFNGPQ.js +0 -11
- package/dist/chunk-TBPPXOOZ.js +0 -165
- package/dist/providerCli-SJRCBSRE.js +0 -11
- package/dist/ui-HAW5NMFA.js +0 -867
|
@@ -4,13 +4,64 @@ import {
|
|
|
4
4
|
providerName,
|
|
5
5
|
removeGlobalProvider,
|
|
6
6
|
writeGlobalConfig
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-7S6JXQCH.js";
|
|
8
|
+
import {
|
|
9
|
+
reasoningPayload
|
|
10
|
+
} from "./chunk-CLN4Z5E3.js";
|
|
8
11
|
import {
|
|
9
12
|
PRESETS,
|
|
10
13
|
loadConfig,
|
|
11
14
|
readCredentials,
|
|
12
15
|
saveCredential
|
|
13
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-2MGINW4O.js";
|
|
17
|
+
|
|
18
|
+
// src/thinking.ts
|
|
19
|
+
var OPEN = "<think>";
|
|
20
|
+
var CLOSE = "</think>";
|
|
21
|
+
function partialTag(text, tag) {
|
|
22
|
+
for (let n = Math.min(tag.length - 1, text.length); n > 0; n--) if (tag.startsWith(text.slice(-n))) return n;
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
25
|
+
var ThinkSplitter = class {
|
|
26
|
+
inside = false;
|
|
27
|
+
held = "";
|
|
28
|
+
push(delta) {
|
|
29
|
+
let rest = this.held + delta;
|
|
30
|
+
this.held = "";
|
|
31
|
+
let text = "";
|
|
32
|
+
let thinking = "";
|
|
33
|
+
while (rest) {
|
|
34
|
+
const tag = this.inside ? CLOSE : OPEN;
|
|
35
|
+
const at = rest.indexOf(tag);
|
|
36
|
+
if (at >= 0) {
|
|
37
|
+
if (this.inside) thinking += rest.slice(0, at);
|
|
38
|
+
else text += rest.slice(0, at);
|
|
39
|
+
rest = rest.slice(at + tag.length);
|
|
40
|
+
this.inside = !this.inside;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const keep = partialTag(rest, tag);
|
|
44
|
+
const out = rest.slice(0, rest.length - keep);
|
|
45
|
+
if (this.inside) thinking += out;
|
|
46
|
+
else text += out;
|
|
47
|
+
this.held = rest.slice(rest.length - keep);
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
return { text, thinking };
|
|
51
|
+
}
|
|
52
|
+
/** Whatever was held back as a possible tag start is plain text after all. */
|
|
53
|
+
flush() {
|
|
54
|
+
const held = this.held;
|
|
55
|
+
this.held = "";
|
|
56
|
+
return this.inside ? { text: "", thinking: held } : { text: held, thinking: "" };
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
function splitThinking(text) {
|
|
60
|
+
const s = new ThinkSplitter();
|
|
61
|
+
const a = s.push(text);
|
|
62
|
+
const b = s.flush();
|
|
63
|
+
return { text: a.text + b.text, thinking: a.thinking + b.thinking };
|
|
64
|
+
}
|
|
14
65
|
|
|
15
66
|
// src/provider.ts
|
|
16
67
|
var ProviderError = class extends Error {
|
|
@@ -58,8 +109,21 @@ function errorMessage(body) {
|
|
|
58
109
|
}
|
|
59
110
|
}
|
|
60
111
|
var toUsage = (u) => u ? { inputTokens: u.prompt_tokens ?? 0, outputTokens: u.completion_tokens ?? 0 } : void 0;
|
|
61
|
-
async function readStream(res, onText) {
|
|
112
|
+
async function readStream(res, onText, onThinking) {
|
|
62
113
|
let text = "";
|
|
114
|
+
let thinking = "";
|
|
115
|
+
const splitter = new ThinkSplitter();
|
|
116
|
+
const emit = (part) => {
|
|
117
|
+
if (part.thinking) {
|
|
118
|
+
thinking += part.thinking;
|
|
119
|
+
onThinking?.(part.thinking);
|
|
120
|
+
}
|
|
121
|
+
if (part.text) {
|
|
122
|
+
text += part.text;
|
|
123
|
+
onText?.(part.text);
|
|
124
|
+
if (loopAt < 0) loopAt = detectRepetition(text);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
63
127
|
let usage;
|
|
64
128
|
let finishReason;
|
|
65
129
|
const calls = [];
|
|
@@ -84,11 +148,9 @@ async function readStream(res, onText) {
|
|
|
84
148
|
if (!choice) return;
|
|
85
149
|
if (choice.finish_reason) finishReason = choice.finish_reason;
|
|
86
150
|
const delta = choice.delta ?? {};
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if (loopAt < 0) loopAt = detectRepetition(text);
|
|
91
|
-
}
|
|
151
|
+
const reasoning = delta.reasoning_content || delta.reasoning;
|
|
152
|
+
if (reasoning) emit({ text: "", thinking: reasoning });
|
|
153
|
+
if (delta.content) emit(splitter.push(delta.content));
|
|
92
154
|
for (const tc of delta.tool_calls ?? []) {
|
|
93
155
|
let target = tc.index !== void 0 ? byIndex.get(tc.index) : current;
|
|
94
156
|
if (!target || tc.index === void 0 && tc.id && target.id && target.id !== tc.id) {
|
|
@@ -110,11 +172,12 @@ async function readStream(res, onText) {
|
|
|
110
172
|
buffer = buffer.slice(newline + 1);
|
|
111
173
|
newline = buffer.indexOf("\n");
|
|
112
174
|
}
|
|
113
|
-
if (loopAt >= 0) return { text: text.slice(0, loopAt), toolCalls: [], usage, finishReason: "repetition" };
|
|
175
|
+
if (loopAt >= 0) return { text: text.slice(0, loopAt), toolCalls: [], thinking: thinking || void 0, usage, finishReason: "repetition" };
|
|
114
176
|
}
|
|
115
177
|
handle(buffer.trim());
|
|
178
|
+
emit(splitter.flush());
|
|
116
179
|
const toolCalls = calls.map((call, index) => ({ ...call, id: call.id || `call_${index}` }));
|
|
117
|
-
return { text, toolCalls, usage, finishReason };
|
|
180
|
+
return { text, toolCalls, thinking: thinking || void 0, usage, finishReason };
|
|
118
181
|
}
|
|
119
182
|
async function readJson(res) {
|
|
120
183
|
const body = await res.json();
|
|
@@ -124,11 +187,17 @@ async function readJson(res) {
|
|
|
124
187
|
name: tc.function?.name ?? "",
|
|
125
188
|
arguments: tc.function?.arguments ?? ""
|
|
126
189
|
}));
|
|
127
|
-
|
|
190
|
+
const split = splitThinking(choice?.message?.content ?? "");
|
|
191
|
+
const thinking = (choice?.message?.reasoning_content || choice?.message?.reasoning || "") + split.thinking;
|
|
192
|
+
return { text: split.text, toolCalls, thinking: thinking || void 0, usage: toUsage(body.usage), finishReason: choice?.finish_reason };
|
|
128
193
|
}
|
|
129
|
-
function createProvider({ baseURL, apiKey, model, fetch: doFetch = fetch, retryDelayMs = 1e3 }) {
|
|
194
|
+
function createProvider({ baseURL, apiKey, model, providerId, fetch: doFetch = fetch, retryDelayMs = 1e3 }) {
|
|
130
195
|
const headers = { "content-type": "application/json" };
|
|
131
196
|
if (apiKey) headers.authorization = `Bearer ${apiKey}`;
|
|
197
|
+
if (/^https:\/\/api\.botconnector\.id\/v1\/?$/.test(baseURL) && apiKey?.startsWith("bc_live_")) {
|
|
198
|
+
headers["x-botconnector-client"] = "bccli";
|
|
199
|
+
headers["x-botconnector-client-version"] = "0.4.0";
|
|
200
|
+
}
|
|
132
201
|
async function post(path, body, signal) {
|
|
133
202
|
let lastError;
|
|
134
203
|
for (let attempt = 0; attempt < 4; attempt++) {
|
|
@@ -149,15 +218,21 @@ function createProvider({ baseURL, apiKey, model, fetch: doFetch = fetch, retryD
|
|
|
149
218
|
throw lastError ?? new ProviderError("Permintaan gagal");
|
|
150
219
|
}
|
|
151
220
|
return {
|
|
152
|
-
async chat({ messages, tools, signal, onText }) {
|
|
221
|
+
async chat({ messages, tools, signal, onText, onThinking, reasoning = "auto" }) {
|
|
222
|
+
let reasoningOverride;
|
|
223
|
+
try {
|
|
224
|
+
reasoningOverride = reasoningPayload(providerId, reasoning);
|
|
225
|
+
} catch (error) {
|
|
226
|
+
throw new ProviderError(error.message);
|
|
227
|
+
}
|
|
153
228
|
const res = await post(
|
|
154
229
|
"/chat/completions",
|
|
155
|
-
{ model, messages, stream: true, stream_options: { include_usage: true }, ...tools?.length ? { tools } : {} },
|
|
230
|
+
{ model, messages, stream: true, stream_options: { include_usage: true }, ...tools?.length ? { tools } : {}, ...reasoningOverride },
|
|
156
231
|
signal
|
|
157
232
|
);
|
|
158
233
|
if ((res.headers.get("content-type") ?? "").includes("application/json")) return readJson(res);
|
|
159
234
|
if (!res.body) throw new ProviderError("Respons provider kosong");
|
|
160
|
-
return readStream(res, onText);
|
|
235
|
+
return readStream(res, onText, onThinking);
|
|
161
236
|
},
|
|
162
237
|
async listModels() {
|
|
163
238
|
const res = await doFetch(`${baseURL}/models`, { headers });
|