@minipi/mini-pi 1.0.1 → 1.0.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.
- package/README.md +44 -10
- package/bin/mini-pi-cli.cjs +1199 -629
- package/package.json +3 -3
package/bin/mini-pi-cli.cjs
CHANGED
|
@@ -85,7 +85,7 @@ var init_tslib = __esm({
|
|
|
85
85
|
});
|
|
86
86
|
|
|
87
87
|
// node_modules/.pnpm/@anthropic-ai+sdk@0.125.0/node_modules/@anthropic-ai/sdk/internal/errors.mjs
|
|
88
|
-
function
|
|
88
|
+
function isAbortError3(err) {
|
|
89
89
|
return typeof err === "object" && err !== null && // Spec-compliant fetch implementations
|
|
90
90
|
("name" in err && err.name === "AbortError" || // Expo fetch
|
|
91
91
|
"message" in err && String(err.message).includes("FetchRequestCanceledException"));
|
|
@@ -279,10 +279,10 @@ var init_values = __esm({
|
|
|
279
279
|
});
|
|
280
280
|
|
|
281
281
|
// node_modules/.pnpm/@anthropic-ai+sdk@0.125.0/node_modules/@anthropic-ai/sdk/internal/utils/sleep.mjs
|
|
282
|
-
var
|
|
282
|
+
var sleep3;
|
|
283
283
|
var init_sleep = __esm({
|
|
284
284
|
"node_modules/.pnpm/@anthropic-ai+sdk@0.125.0/node_modules/@anthropic-ai/sdk/internal/utils/sleep.mjs"() {
|
|
285
|
-
|
|
285
|
+
sleep3 = (ms, signal) => new Promise((resolve6) => {
|
|
286
286
|
if (signal?.aborted)
|
|
287
287
|
return resolve6();
|
|
288
288
|
const onAbort = () => {
|
|
@@ -964,18 +964,18 @@ __export(node_exports, {
|
|
|
964
964
|
child_process: () => child_process,
|
|
965
965
|
crypto: () => crypto2,
|
|
966
966
|
fs: () => fs,
|
|
967
|
-
os: () =>
|
|
967
|
+
os: () => os2,
|
|
968
968
|
path: () => path2,
|
|
969
969
|
stream: () => stream,
|
|
970
970
|
util: () => util
|
|
971
971
|
});
|
|
972
|
-
var child_process, crypto2, fs,
|
|
972
|
+
var child_process, crypto2, fs, os2, path2, stream, util;
|
|
973
973
|
var init_node = __esm({
|
|
974
974
|
"node_modules/.pnpm/@anthropic-ai+sdk@0.125.0/node_modules/@anthropic-ai/sdk/internal/node.mjs"() {
|
|
975
975
|
child_process = __toESM(require("node:child_process"), 1);
|
|
976
976
|
crypto2 = __toESM(require("node:crypto"), 1);
|
|
977
977
|
fs = __toESM(require("node:fs"), 1);
|
|
978
|
-
|
|
978
|
+
os2 = __toESM(require("node:os"), 1);
|
|
979
979
|
path2 = __toESM(require("node:path"), 1);
|
|
980
980
|
stream = __toESM(require("node:stream"), 1);
|
|
981
981
|
util = __toESM(require("node:util"), 1);
|
|
@@ -1361,11 +1361,11 @@ function defaultLogger() {
|
|
|
1361
1361
|
const envLevel = readEnv2("ANTHROPIC_LOG");
|
|
1362
1362
|
if (!cachedDefaultLogger || envLevel !== lastEnvLevel) {
|
|
1363
1363
|
lastEnvLevel = envLevel;
|
|
1364
|
-
cachedDefaultLogger = filterLogger(console,
|
|
1364
|
+
cachedDefaultLogger = filterLogger(console, parseLogLevel3(envLevel, "process.env['ANTHROPIC_LOG']", filterLogger(console, defaultLogLevel)) ?? defaultLogLevel);
|
|
1365
1365
|
}
|
|
1366
1366
|
return cachedDefaultLogger;
|
|
1367
1367
|
}
|
|
1368
|
-
var defaultLogLevel, levelNumbers2,
|
|
1368
|
+
var defaultLogLevel, levelNumbers2, parseLogLevel3, noopLogger2, cachedLoggers2, lastEnvLevel, cachedDefaultLogger, formatRequestDetails2;
|
|
1369
1369
|
var init_log = __esm({
|
|
1370
1370
|
"node_modules/.pnpm/@anthropic-ai+sdk@0.125.0/node_modules/@anthropic-ai/sdk/internal/utils/log.mjs"() {
|
|
1371
1371
|
init_values();
|
|
@@ -1378,7 +1378,7 @@ var init_log = __esm({
|
|
|
1378
1378
|
info: 400,
|
|
1379
1379
|
debug: 500
|
|
1380
1380
|
};
|
|
1381
|
-
|
|
1381
|
+
parseLogLevel3 = (maybeLevel, sourceName, logger2) => {
|
|
1382
1382
|
if (!maybeLevel) {
|
|
1383
1383
|
return void 0;
|
|
1384
1384
|
}
|
|
@@ -2155,7 +2155,7 @@ var init_streaming = __esm({
|
|
|
2155
2155
|
}
|
|
2156
2156
|
done = true;
|
|
2157
2157
|
} catch (e) {
|
|
2158
|
-
if (
|
|
2158
|
+
if (isAbortError3(e))
|
|
2159
2159
|
return;
|
|
2160
2160
|
throw e;
|
|
2161
2161
|
} finally {
|
|
@@ -2199,7 +2199,7 @@ var init_streaming = __esm({
|
|
|
2199
2199
|
}
|
|
2200
2200
|
done = true;
|
|
2201
2201
|
} catch (e) {
|
|
2202
|
-
if (
|
|
2202
|
+
if (isAbortError3(e))
|
|
2203
2203
|
return;
|
|
2204
2204
|
throw e;
|
|
2205
2205
|
} finally {
|
|
@@ -2371,11 +2371,11 @@ var init_parse = __esm({
|
|
|
2371
2371
|
function isFetchOriginError(err) {
|
|
2372
2372
|
return typeof err === "object" && err !== null && fetchOriginErrors.has(err);
|
|
2373
2373
|
}
|
|
2374
|
-
function
|
|
2374
|
+
function isRetryableError2(err) {
|
|
2375
2375
|
const seen = /* @__PURE__ */ new Set();
|
|
2376
2376
|
while (typeof err === "object" && err !== null && !seen.has(err)) {
|
|
2377
2377
|
seen.add(err);
|
|
2378
|
-
if (isFetchOriginError(err) ||
|
|
2378
|
+
if (isFetchOriginError(err) || isAbortError3(err) || err instanceof APIConnectionError2 || err instanceof RetryableError) {
|
|
2379
2379
|
return true;
|
|
2380
2380
|
}
|
|
2381
2381
|
err = err.cause;
|
|
@@ -5004,7 +5004,7 @@ var init_poller = __esm({
|
|
|
5004
5004
|
const wait = applyJitter(backoff2(attempt));
|
|
5005
5005
|
log.warn("poll failed, backing off", { error: String(e), backoff_ms: wait });
|
|
5006
5006
|
attempt++;
|
|
5007
|
-
await
|
|
5007
|
+
await sleep3(wait, __classPrivateFieldGet2(this, _WorkPoller_controller, "f").signal);
|
|
5008
5008
|
continue;
|
|
5009
5009
|
}
|
|
5010
5010
|
attempt = 0;
|
|
@@ -5012,7 +5012,7 @@ var init_poller = __esm({
|
|
|
5012
5012
|
if (__classPrivateFieldGet2(this, _WorkPoller_drain, "f"))
|
|
5013
5013
|
return;
|
|
5014
5014
|
idle.onEmptyPoll();
|
|
5015
|
-
await
|
|
5015
|
+
await sleep3(jitter(1e3, 3e3), __classPrivateFieldGet2(this, _WorkPoller_controller, "f").signal);
|
|
5016
5016
|
continue;
|
|
5017
5017
|
}
|
|
5018
5018
|
idle.onClaim();
|
|
@@ -5444,7 +5444,7 @@ var init_SessionToolRunner = __esm({
|
|
|
5444
5444
|
});
|
|
5445
5445
|
}
|
|
5446
5446
|
ctrl.signal.throwIfAborted();
|
|
5447
|
-
await
|
|
5447
|
+
await sleep3(backoff3, ctrl.signal);
|
|
5448
5448
|
backoff3 = Math.min(backoff3 * 2, STREAM_BACKOFF_CAP_MS);
|
|
5449
5449
|
}
|
|
5450
5450
|
}, _SessionToolRunner_reconcile = /**
|
|
@@ -5696,7 +5696,7 @@ var init_SessionToolRunner = __esm({
|
|
|
5696
5696
|
backoff_ms: waitMs,
|
|
5697
5697
|
error: String(e)
|
|
5698
5698
|
});
|
|
5699
|
-
await
|
|
5699
|
+
await sleep3(waitMs, ctrl.signal);
|
|
5700
5700
|
}
|
|
5701
5701
|
}
|
|
5702
5702
|
__classPrivateFieldGet2(this, _SessionToolRunner_logger, "f").error("failed to send tool result", {
|
|
@@ -5709,7 +5709,7 @@ var init_SessionToolRunner = __esm({
|
|
|
5709
5709
|
async function _SessionToolRunner_drain2() {
|
|
5710
5710
|
if (__classPrivateFieldGet2(this, _SessionToolRunner_inFlightCount, "f") === 0)
|
|
5711
5711
|
return;
|
|
5712
|
-
await Promise.race([new Promise((r) => __classPrivateFieldSet2(this, _SessionToolRunner_onIdle, r, "f")),
|
|
5712
|
+
await Promise.race([new Promise((r) => __classPrivateFieldSet2(this, _SessionToolRunner_onIdle, r, "f")), sleep3(DRAIN_TIMEOUT_MS)]);
|
|
5713
5713
|
__classPrivateFieldSet2(this, _SessionToolRunner_onIdle, null, "f");
|
|
5714
5714
|
if (__classPrivateFieldGet2(this, _SessionToolRunner_inFlightCount, "f") > 0) {
|
|
5715
5715
|
__classPrivateFieldGet2(this, _SessionToolRunner_logger, "f").warn("drain timeout exceeded");
|
|
@@ -8087,7 +8087,7 @@ async function heartbeatLoop(client, work, lease, logger2, requestOptions, onLea
|
|
|
8087
8087
|
};
|
|
8088
8088
|
await beat();
|
|
8089
8089
|
while (!lease.signal.aborted) {
|
|
8090
|
-
await
|
|
8090
|
+
await sleep3(intervalMs, lease.signal);
|
|
8091
8091
|
lease.signal.throwIfAborted();
|
|
8092
8092
|
await beat();
|
|
8093
8093
|
}
|
|
@@ -9887,7 +9887,7 @@ var init_BetaMessageStream = __esm({
|
|
|
9887
9887
|
_BetaMessageStream_logger.set(this, void 0);
|
|
9888
9888
|
_BetaMessageStream_handleError.set(this, (error) => {
|
|
9889
9889
|
__classPrivateFieldSet2(this, _BetaMessageStream_errored, true, "f");
|
|
9890
|
-
if (
|
|
9890
|
+
if (isAbortError3(error)) {
|
|
9891
9891
|
error = new APIUserAbortError2();
|
|
9892
9892
|
}
|
|
9893
9893
|
if (error instanceof APIUserAbortError2) {
|
|
@@ -14725,7 +14725,7 @@ var init_MessageStream = __esm({
|
|
|
14725
14725
|
_MessageStream_logger.set(this, void 0);
|
|
14726
14726
|
_MessageStream_handleError.set(this, (error) => {
|
|
14727
14727
|
__classPrivateFieldSet2(this, _MessageStream_errored, true, "f");
|
|
14728
|
-
if (
|
|
14728
|
+
if (isAbortError3(error)) {
|
|
14729
14729
|
error = new APIUserAbortError2();
|
|
14730
14730
|
}
|
|
14731
14731
|
if (error instanceof APIUserAbortError2) {
|
|
@@ -15973,7 +15973,7 @@ var init_client = __esm({
|
|
|
15973
15973
|
this.timeout = options.timeout ?? _a5.DEFAULT_TIMEOUT;
|
|
15974
15974
|
this.logger = options.logger ?? console;
|
|
15975
15975
|
this.logLevel = defaultLogLevel;
|
|
15976
|
-
this.logLevel =
|
|
15976
|
+
this.logLevel = parseLogLevel3(options.logLevel, "ClientOptions.logLevel", loggerFor2(this)) ?? parseLogLevel3(readEnv2("ANTHROPIC_LOG"), "process.env['ANTHROPIC_LOG']", loggerFor2(this)) ?? defaultLogLevel;
|
|
15977
15977
|
this.fetchOptions = options.fetchOptions;
|
|
15978
15978
|
this.maxRetries = validatePositiveInteger2("maxRetries", options.maxRetries ?? 2);
|
|
15979
15979
|
this.fetch = options.fetch ?? getDefaultFetch2();
|
|
@@ -16352,9 +16352,9 @@ var init_client = __esm({
|
|
|
16352
16352
|
if (options.signal?.aborted) {
|
|
16353
16353
|
throw new APIUserAbortError2();
|
|
16354
16354
|
}
|
|
16355
|
-
const isTimeout =
|
|
16355
|
+
const isTimeout = isAbortError3(response) || /timed? ?out/i.test(String(response) + ("cause" in response ? String(response.cause) : ""));
|
|
16356
16356
|
const hasMiddleware = this.middleware.length > 0 || !!options.middleware?.length || this.backendMiddleware().length > 0;
|
|
16357
|
-
if (hasMiddleware && !isTimeout && !
|
|
16357
|
+
if (hasMiddleware && !isTimeout && !isRetryableError2(response)) {
|
|
16358
16358
|
loggerFor2(this).info(`[${requestLogID}] middleware error (not retryable)`);
|
|
16359
16359
|
loggerFor2(this).debug(`[${requestLogID}] middleware error (not retryable)`, formatRequestDetails2({
|
|
16360
16360
|
retryOfRequestLogID,
|
|
@@ -16532,7 +16532,7 @@ var init_client = __esm({
|
|
|
16532
16532
|
const maxRetries = options.maxRetries ?? this.maxRetries;
|
|
16533
16533
|
timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);
|
|
16534
16534
|
}
|
|
16535
|
-
await
|
|
16535
|
+
await sleep3(timeoutMillis);
|
|
16536
16536
|
return this.makeRequest(options, retriesRemaining - 1, requestLogID);
|
|
16537
16537
|
}
|
|
16538
16538
|
calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {
|
|
@@ -16696,6 +16696,432 @@ var init_sdk = __esm({
|
|
|
16696
16696
|
}
|
|
16697
16697
|
});
|
|
16698
16698
|
|
|
16699
|
+
// src/agent/model/config.ts
|
|
16700
|
+
var REQUEST_TIMEOUT_MS = 12e4;
|
|
16701
|
+
var STREAM_IDLE_TIMEOUT_MS = 12e4;
|
|
16702
|
+
var DEFAULT_MAX_TOKENS = 8192;
|
|
16703
|
+
function resolveMaxTokens(value) {
|
|
16704
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 1 ? Math.floor(value) : DEFAULT_MAX_TOKENS;
|
|
16705
|
+
}
|
|
16706
|
+
function resolveStreamIdleTimeout(value) {
|
|
16707
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : STREAM_IDLE_TIMEOUT_MS;
|
|
16708
|
+
}
|
|
16709
|
+
|
|
16710
|
+
// src/agent/model/errors.ts
|
|
16711
|
+
var STREAM_IDLE_TIMEOUT_ERROR_NAME = "StreamIdleTimeoutError";
|
|
16712
|
+
var PARTIAL_STREAM_ERROR_NAME = "PartialStreamInterruptedError";
|
|
16713
|
+
var ERROR_CAUSE_MAX_DEPTH = 5;
|
|
16714
|
+
function describeError(error) {
|
|
16715
|
+
return error instanceof Error ? error.message : String(error);
|
|
16716
|
+
}
|
|
16717
|
+
function findInErrorChain(error, read) {
|
|
16718
|
+
let current = error;
|
|
16719
|
+
for (let depth = 0; current && typeof current === "object" && depth < ERROR_CAUSE_MAX_DEPTH; depth += 1) {
|
|
16720
|
+
const candidate = current;
|
|
16721
|
+
const value = read(candidate);
|
|
16722
|
+
if (value !== void 0) {
|
|
16723
|
+
return value;
|
|
16724
|
+
}
|
|
16725
|
+
current = candidate.cause;
|
|
16726
|
+
}
|
|
16727
|
+
return void 0;
|
|
16728
|
+
}
|
|
16729
|
+
function nameInErrorChain(error, name) {
|
|
16730
|
+
let current = error;
|
|
16731
|
+
for (let depth = 0; current && typeof current === "object" && depth < ERROR_CAUSE_MAX_DEPTH; depth += 1) {
|
|
16732
|
+
const candidate = current;
|
|
16733
|
+
if (candidate.name === name) {
|
|
16734
|
+
return true;
|
|
16735
|
+
}
|
|
16736
|
+
current = candidate.cause;
|
|
16737
|
+
}
|
|
16738
|
+
return false;
|
|
16739
|
+
}
|
|
16740
|
+
var ABORT_ERROR_PATTERNS = [/^AbortError$/i, /APIUserAbortError/i];
|
|
16741
|
+
function isAbortError(error) {
|
|
16742
|
+
let current = error;
|
|
16743
|
+
for (let depth = 0; current && typeof current === "object" && depth < ERROR_CAUSE_MAX_DEPTH; depth += 1) {
|
|
16744
|
+
const candidate = current;
|
|
16745
|
+
for (const value of [candidate.name, candidate.constructor?.name]) {
|
|
16746
|
+
if (typeof value === "string" && ABORT_ERROR_PATTERNS.some((pattern) => pattern.test(value))) {
|
|
16747
|
+
return true;
|
|
16748
|
+
}
|
|
16749
|
+
}
|
|
16750
|
+
current = candidate.cause;
|
|
16751
|
+
}
|
|
16752
|
+
return false;
|
|
16753
|
+
}
|
|
16754
|
+
var StreamIdleTimeoutError = class extends Error {
|
|
16755
|
+
constructor(idleMs) {
|
|
16756
|
+
super(`\u6D41\u5F0F\u54CD\u5E94 ${idleMs}ms \u5185\u6CA1\u6709\u6536\u5230\u4EFB\u4F55\u6570\u636E\uFF0C\u5DF2\u4E2D\u6B62\u672C\u6B21\u8BF7\u6C42`);
|
|
16757
|
+
this.name = STREAM_IDLE_TIMEOUT_ERROR_NAME;
|
|
16758
|
+
}
|
|
16759
|
+
};
|
|
16760
|
+
function isStreamIdleTimeoutError(error) {
|
|
16761
|
+
return nameInErrorChain(error, STREAM_IDLE_TIMEOUT_ERROR_NAME);
|
|
16762
|
+
}
|
|
16763
|
+
var PartialStreamInterruptedError = class extends Error {
|
|
16764
|
+
constructor(cause) {
|
|
16765
|
+
super(
|
|
16766
|
+
`\u6D41\u5F0F\u54CD\u5E94\u5728\u5DF2\u8F93\u51FA\u90E8\u5206\u5185\u5BB9\u540E\u4E2D\u65AD\uFF0C\u672A\u81EA\u52A8\u91CD\u8BD5\uFF08\u907F\u514D\u91CD\u590D\u8F93\u51FA\u4E0E\u91CD\u590D\u8BA1\u8D39\uFF09\uFF1A${describeError(cause)}`
|
|
16767
|
+
);
|
|
16768
|
+
this.name = PARTIAL_STREAM_ERROR_NAME;
|
|
16769
|
+
this.cause = cause;
|
|
16770
|
+
}
|
|
16771
|
+
};
|
|
16772
|
+
function isPartialStreamInterrupted(error) {
|
|
16773
|
+
return nameInErrorChain(error, PARTIAL_STREAM_ERROR_NAME);
|
|
16774
|
+
}
|
|
16775
|
+
function toNonRetryableIfPartialStream(error, emittedContent) {
|
|
16776
|
+
if (emittedContent && isRetryableError(error)) {
|
|
16777
|
+
return new PartialStreamInterruptedError(error);
|
|
16778
|
+
}
|
|
16779
|
+
return error;
|
|
16780
|
+
}
|
|
16781
|
+
var RETRYABLE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
16782
|
+
"ETIMEDOUT",
|
|
16783
|
+
"ECONNRESET",
|
|
16784
|
+
"ECONNREFUSED",
|
|
16785
|
+
"EPIPE",
|
|
16786
|
+
"ENOTFOUND",
|
|
16787
|
+
"EAI_AGAIN",
|
|
16788
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
16789
|
+
"UND_ERR_SOCKET"
|
|
16790
|
+
]);
|
|
16791
|
+
var RETRYABLE_ERROR_NAME_PATTERNS = [
|
|
16792
|
+
/^APIConnectionError$/,
|
|
16793
|
+
/^APIConnectionTimeoutError$/,
|
|
16794
|
+
/^APIConnectionTimeoutError\d*$/
|
|
16795
|
+
];
|
|
16796
|
+
function isRetryableError(error) {
|
|
16797
|
+
if (!error || typeof error !== "object") {
|
|
16798
|
+
return false;
|
|
16799
|
+
}
|
|
16800
|
+
if (isPartialStreamInterrupted(error)) {
|
|
16801
|
+
return false;
|
|
16802
|
+
}
|
|
16803
|
+
if (isStreamIdleTimeoutError(error)) {
|
|
16804
|
+
return true;
|
|
16805
|
+
}
|
|
16806
|
+
const name = findInErrorChain(
|
|
16807
|
+
error,
|
|
16808
|
+
(candidate) => typeof candidate.name === "string" ? candidate.name : void 0
|
|
16809
|
+
);
|
|
16810
|
+
if (name && RETRYABLE_ERROR_NAME_PATTERNS.some((pattern) => pattern.test(name))) {
|
|
16811
|
+
return true;
|
|
16812
|
+
}
|
|
16813
|
+
const status = findInErrorChain(
|
|
16814
|
+
error,
|
|
16815
|
+
(candidate) => typeof candidate.status === "number" ? candidate.status : void 0
|
|
16816
|
+
);
|
|
16817
|
+
if (status !== void 0) {
|
|
16818
|
+
return status === 429 || status === 408 || status >= 500;
|
|
16819
|
+
}
|
|
16820
|
+
const code = findInErrorChain(
|
|
16821
|
+
error,
|
|
16822
|
+
(candidate) => typeof candidate.code === "string" ? candidate.code : void 0
|
|
16823
|
+
);
|
|
16824
|
+
if (code !== void 0 && RETRYABLE_ERROR_CODES.has(code)) {
|
|
16825
|
+
return true;
|
|
16826
|
+
}
|
|
16827
|
+
return false;
|
|
16828
|
+
}
|
|
16829
|
+
|
|
16830
|
+
// src/agent/model/retry.ts
|
|
16831
|
+
var MAX_REQUEST_ATTEMPTS = 3;
|
|
16832
|
+
var RETRY_BASE_DELAY_MS = 1e3;
|
|
16833
|
+
var RETRY_JITTER_RATIO = 0.2;
|
|
16834
|
+
function applyRetryJitter(delayMs, random = Math.random) {
|
|
16835
|
+
const factor = 1 - RETRY_JITTER_RATIO + random() * RETRY_JITTER_RATIO * 2;
|
|
16836
|
+
return Math.max(0, Math.round(delayMs * factor));
|
|
16837
|
+
}
|
|
16838
|
+
function readHeader(headers, name) {
|
|
16839
|
+
if (!headers || typeof headers !== "object") {
|
|
16840
|
+
return null;
|
|
16841
|
+
}
|
|
16842
|
+
const getter = headers.get;
|
|
16843
|
+
if (typeof getter === "function") {
|
|
16844
|
+
const value = getter.call(headers, name);
|
|
16845
|
+
return typeof value === "string" ? value : null;
|
|
16846
|
+
}
|
|
16847
|
+
const record = headers;
|
|
16848
|
+
for (const key of [name, name.toLowerCase(), name.toUpperCase()]) {
|
|
16849
|
+
const value = record[key];
|
|
16850
|
+
if (typeof value === "string") {
|
|
16851
|
+
return value;
|
|
16852
|
+
}
|
|
16853
|
+
}
|
|
16854
|
+
return null;
|
|
16855
|
+
}
|
|
16856
|
+
function findHeaders(error) {
|
|
16857
|
+
let current = error;
|
|
16858
|
+
for (let depth = 0; current && typeof current === "object" && depth < 5; depth += 1) {
|
|
16859
|
+
const candidate = current;
|
|
16860
|
+
if (candidate.headers && typeof candidate.headers === "object") {
|
|
16861
|
+
return candidate.headers;
|
|
16862
|
+
}
|
|
16863
|
+
current = candidate.cause;
|
|
16864
|
+
}
|
|
16865
|
+
return void 0;
|
|
16866
|
+
}
|
|
16867
|
+
function retryAfterMsFromError(error, now = Date.now()) {
|
|
16868
|
+
const headers = findHeaders(error);
|
|
16869
|
+
if (!headers) {
|
|
16870
|
+
return void 0;
|
|
16871
|
+
}
|
|
16872
|
+
const ms = readHeader(headers, "retry-after-ms");
|
|
16873
|
+
if (ms !== null && ms.trim() !== "") {
|
|
16874
|
+
const parsed = Number(ms);
|
|
16875
|
+
if (Number.isFinite(parsed) && parsed >= 0) {
|
|
16876
|
+
return parsed;
|
|
16877
|
+
}
|
|
16878
|
+
}
|
|
16879
|
+
const raw = readHeader(headers, "retry-after");
|
|
16880
|
+
if (raw !== null && raw.trim() !== "") {
|
|
16881
|
+
const seconds = Number(raw);
|
|
16882
|
+
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
16883
|
+
return seconds * 1e3;
|
|
16884
|
+
}
|
|
16885
|
+
const date = Date.parse(raw);
|
|
16886
|
+
if (Number.isFinite(date)) {
|
|
16887
|
+
return Math.max(0, date - now);
|
|
16888
|
+
}
|
|
16889
|
+
}
|
|
16890
|
+
return void 0;
|
|
16891
|
+
}
|
|
16892
|
+
function resolveRetryDelayMs(error, backoffMs, now = Date.now(), random = Math.random) {
|
|
16893
|
+
const serverMs = retryAfterMsFromError(error, now);
|
|
16894
|
+
const base = serverMs === void 0 ? backoffMs : Math.max(serverMs, backoffMs);
|
|
16895
|
+
return applyRetryJitter(base, random);
|
|
16896
|
+
}
|
|
16897
|
+
function sleep(ms, signal) {
|
|
16898
|
+
return new Promise((resolve6, reject) => {
|
|
16899
|
+
if (signal?.aborted) {
|
|
16900
|
+
reject(new Error("aborted"));
|
|
16901
|
+
return;
|
|
16902
|
+
}
|
|
16903
|
+
const timer = setTimeout(() => {
|
|
16904
|
+
signal?.removeEventListener("abort", onAbort);
|
|
16905
|
+
resolve6();
|
|
16906
|
+
}, ms);
|
|
16907
|
+
const onAbort = () => {
|
|
16908
|
+
clearTimeout(timer);
|
|
16909
|
+
reject(new Error("aborted"));
|
|
16910
|
+
};
|
|
16911
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
16912
|
+
});
|
|
16913
|
+
}
|
|
16914
|
+
async function withRetry(operation, options = {}) {
|
|
16915
|
+
const attempts = Math.max(1, options.attempts ?? MAX_REQUEST_ATTEMPTS);
|
|
16916
|
+
const baseDelayMs = options.baseDelayMs ?? RETRY_BASE_DELAY_MS;
|
|
16917
|
+
const wait = options.wait ?? sleep;
|
|
16918
|
+
const random = options.random ?? Math.random;
|
|
16919
|
+
const now = options.now ?? Date.now;
|
|
16920
|
+
for (let attempt = 1; ; attempt += 1) {
|
|
16921
|
+
try {
|
|
16922
|
+
return await operation();
|
|
16923
|
+
} catch (error) {
|
|
16924
|
+
const cancelled = options.signal?.aborted === true || isAbortError(error);
|
|
16925
|
+
if (cancelled || attempt >= attempts || !isRetryableError(error)) {
|
|
16926
|
+
throw error;
|
|
16927
|
+
}
|
|
16928
|
+
const backoffMs = baseDelayMs * 2 ** (attempt - 1);
|
|
16929
|
+
const delayMs = resolveRetryDelayMs(error, backoffMs, now(), random);
|
|
16930
|
+
options.onRetry?.(attempt, error, delayMs);
|
|
16931
|
+
await wait(delayMs, options.signal);
|
|
16932
|
+
}
|
|
16933
|
+
}
|
|
16934
|
+
}
|
|
16935
|
+
|
|
16936
|
+
// src/agent/message.ts
|
|
16937
|
+
function createTextContent(value) {
|
|
16938
|
+
return {
|
|
16939
|
+
type: "text",
|
|
16940
|
+
text: value
|
|
16941
|
+
};
|
|
16942
|
+
}
|
|
16943
|
+
function createUserMessage(input) {
|
|
16944
|
+
return {
|
|
16945
|
+
role: "user",
|
|
16946
|
+
content: [createTextContent(input)],
|
|
16947
|
+
timestamp: Date.now()
|
|
16948
|
+
};
|
|
16949
|
+
}
|
|
16950
|
+
function messageText(message) {
|
|
16951
|
+
return message.content.filter((block) => block.type === "text").map((block) => block.text).join("\n");
|
|
16952
|
+
}
|
|
16953
|
+
function isTextContent(block) {
|
|
16954
|
+
return block.type === "text";
|
|
16955
|
+
}
|
|
16956
|
+
|
|
16957
|
+
// src/agent/model/stream.ts
|
|
16958
|
+
function createStreamIdleWatchdog(parent, idleMs = STREAM_IDLE_TIMEOUT_MS) {
|
|
16959
|
+
const controller = new AbortController();
|
|
16960
|
+
let timedOut = false;
|
|
16961
|
+
let timer = null;
|
|
16962
|
+
let disposed = false;
|
|
16963
|
+
const clear = () => {
|
|
16964
|
+
if (timer) {
|
|
16965
|
+
clearTimeout(timer);
|
|
16966
|
+
timer = null;
|
|
16967
|
+
}
|
|
16968
|
+
};
|
|
16969
|
+
const arm = () => {
|
|
16970
|
+
clear();
|
|
16971
|
+
if (disposed || controller.signal.aborted) {
|
|
16972
|
+
return;
|
|
16973
|
+
}
|
|
16974
|
+
timer = setTimeout(() => {
|
|
16975
|
+
timedOut = true;
|
|
16976
|
+
controller.abort();
|
|
16977
|
+
}, idleMs);
|
|
16978
|
+
};
|
|
16979
|
+
const onParentAbort = () => {
|
|
16980
|
+
clear();
|
|
16981
|
+
controller.abort();
|
|
16982
|
+
};
|
|
16983
|
+
if (parent?.aborted) {
|
|
16984
|
+
controller.abort();
|
|
16985
|
+
} else {
|
|
16986
|
+
parent?.addEventListener("abort", onParentAbort, { once: true });
|
|
16987
|
+
arm();
|
|
16988
|
+
}
|
|
16989
|
+
return {
|
|
16990
|
+
signal: controller.signal,
|
|
16991
|
+
touch: arm,
|
|
16992
|
+
timedOut: () => timedOut,
|
|
16993
|
+
dispose: () => {
|
|
16994
|
+
disposed = true;
|
|
16995
|
+
clear();
|
|
16996
|
+
parent?.removeEventListener("abort", onParentAbort);
|
|
16997
|
+
}
|
|
16998
|
+
};
|
|
16999
|
+
}
|
|
17000
|
+
function classifyStreamFailure(error, watchdog, signal, idleMs = STREAM_IDLE_TIMEOUT_MS) {
|
|
17001
|
+
if (watchdog.timedOut() && signal?.aborted !== true) {
|
|
17002
|
+
return new StreamIdleTimeoutError(idleMs);
|
|
17003
|
+
}
|
|
17004
|
+
return error;
|
|
17005
|
+
}
|
|
17006
|
+
function assertStreamNotIdleTimedOut(watchdog, idleMs, signal) {
|
|
17007
|
+
if (watchdog.timedOut() && signal?.aborted !== true) {
|
|
17008
|
+
throw new StreamIdleTimeoutError(idleMs);
|
|
17009
|
+
}
|
|
17010
|
+
}
|
|
17011
|
+
function createDeltaEmitter(onDelta) {
|
|
17012
|
+
let any = false;
|
|
17013
|
+
return {
|
|
17014
|
+
onDelta: onDelta ? (delta) => {
|
|
17015
|
+
any = true;
|
|
17016
|
+
onDelta(delta);
|
|
17017
|
+
} : void 0,
|
|
17018
|
+
emittedAny: () => any
|
|
17019
|
+
};
|
|
17020
|
+
}
|
|
17021
|
+
function mapFinishReason(reason) {
|
|
17022
|
+
if (reason === "tool_calls" || reason === "function_call") {
|
|
17023
|
+
return "toolUse";
|
|
17024
|
+
}
|
|
17025
|
+
if (reason === "length") {
|
|
17026
|
+
return "length";
|
|
17027
|
+
}
|
|
17028
|
+
if (reason === "content_filter") {
|
|
17029
|
+
return "error";
|
|
17030
|
+
}
|
|
17031
|
+
return "stop";
|
|
17032
|
+
}
|
|
17033
|
+
async function collectOpenAIStream(chunks, onDelta, onChunk) {
|
|
17034
|
+
let text = "";
|
|
17035
|
+
let finishReason = null;
|
|
17036
|
+
let usage = null;
|
|
17037
|
+
const toolCalls = /* @__PURE__ */ new Map();
|
|
17038
|
+
for await (const chunk of chunks) {
|
|
17039
|
+
onChunk?.();
|
|
17040
|
+
if (chunk.usage) {
|
|
17041
|
+
usage = chunk.usage;
|
|
17042
|
+
}
|
|
17043
|
+
const choice = chunk.choices?.[0];
|
|
17044
|
+
if (!choice) {
|
|
17045
|
+
continue;
|
|
17046
|
+
}
|
|
17047
|
+
const delta = choice.delta;
|
|
17048
|
+
if (delta?.content) {
|
|
17049
|
+
text += delta.content;
|
|
17050
|
+
onDelta?.(delta.content);
|
|
17051
|
+
}
|
|
17052
|
+
for (const call of delta?.tool_calls ?? []) {
|
|
17053
|
+
const index = call.index ?? 0;
|
|
17054
|
+
const entry = toolCalls.get(index) ?? { id: "", name: "", args: "" };
|
|
17055
|
+
if (call.id) {
|
|
17056
|
+
entry.id = call.id;
|
|
17057
|
+
}
|
|
17058
|
+
if (call.function?.name) {
|
|
17059
|
+
entry.name += call.function.name;
|
|
17060
|
+
}
|
|
17061
|
+
if (call.function?.arguments) {
|
|
17062
|
+
entry.args += call.function.arguments;
|
|
17063
|
+
}
|
|
17064
|
+
toolCalls.set(index, entry);
|
|
17065
|
+
}
|
|
17066
|
+
if (choice.finish_reason) {
|
|
17067
|
+
finishReason = choice.finish_reason;
|
|
17068
|
+
}
|
|
17069
|
+
}
|
|
17070
|
+
const content = [];
|
|
17071
|
+
if (text) {
|
|
17072
|
+
content.push(createTextContent(text));
|
|
17073
|
+
}
|
|
17074
|
+
for (const [index, call] of [...toolCalls.entries()].sort((a, b) => a[0] - b[0])) {
|
|
17075
|
+
let args = {};
|
|
17076
|
+
if (call.args) {
|
|
17077
|
+
try {
|
|
17078
|
+
args = JSON.parse(call.args);
|
|
17079
|
+
} catch {
|
|
17080
|
+
args = {};
|
|
17081
|
+
}
|
|
17082
|
+
}
|
|
17083
|
+
content.push({
|
|
17084
|
+
type: "toolCall",
|
|
17085
|
+
id: call.id || `call_${index}`,
|
|
17086
|
+
name: call.name,
|
|
17087
|
+
arguments: args
|
|
17088
|
+
});
|
|
17089
|
+
}
|
|
17090
|
+
return {
|
|
17091
|
+
role: "assistant",
|
|
17092
|
+
content,
|
|
17093
|
+
stopReason: mapFinishReason(finishReason),
|
|
17094
|
+
usage: {
|
|
17095
|
+
input: usage?.prompt_tokens ?? 0,
|
|
17096
|
+
output: usage?.completion_tokens ?? 0,
|
|
17097
|
+
totalTokens: usage?.total_tokens ?? 0
|
|
17098
|
+
},
|
|
17099
|
+
timestamp: Date.now()
|
|
17100
|
+
};
|
|
17101
|
+
}
|
|
17102
|
+
|
|
17103
|
+
// src/agent/model/response.ts
|
|
17104
|
+
function createErrorResponse(error, signal, label = "\u6A21\u578B\u8C03\u7528") {
|
|
17105
|
+
if (signal?.aborted || isAbortError(error)) {
|
|
17106
|
+
return {
|
|
17107
|
+
role: "assistant",
|
|
17108
|
+
content: [createTextContent(`${label}\u5DF2\u53D6\u6D88`)],
|
|
17109
|
+
stopReason: "aborted",
|
|
17110
|
+
usage: { input: 0, output: 0, totalTokens: 0 },
|
|
17111
|
+
errorMessage: "aborted",
|
|
17112
|
+
timestamp: Date.now()
|
|
17113
|
+
};
|
|
17114
|
+
}
|
|
17115
|
+
return {
|
|
17116
|
+
role: "assistant",
|
|
17117
|
+
content: [createTextContent(`${label}\u5931\u8D25\uFF1A${describeError(error)}`)],
|
|
17118
|
+
stopReason: "error",
|
|
17119
|
+
usage: { input: 0, output: 0, totalTokens: 0 },
|
|
17120
|
+
errorMessage: describeError(error),
|
|
17121
|
+
timestamp: Date.now()
|
|
17122
|
+
};
|
|
17123
|
+
}
|
|
17124
|
+
|
|
16699
17125
|
// node_modules/.pnpm/openai@7.15.0/node_modules/openai/internal/tslib.mjs
|
|
16700
17126
|
function __classPrivateFieldSet(receiver, state2, value, kind, f) {
|
|
16701
17127
|
if (kind === "m")
|
|
@@ -16727,7 +17153,7 @@ var uuid4 = function() {
|
|
|
16727
17153
|
};
|
|
16728
17154
|
|
|
16729
17155
|
// node_modules/.pnpm/openai@7.15.0/node_modules/openai/internal/errors.mjs
|
|
16730
|
-
function
|
|
17156
|
+
function isAbortError2(err) {
|
|
16731
17157
|
return typeof err === "object" && err !== null && // Spec-compliant fetch implementations
|
|
16732
17158
|
("name" in err && err.name === "AbortError" || // Expo fetch
|
|
16733
17159
|
"message" in err && String(err.message).includes("FetchRequestCanceledException"));
|
|
@@ -16936,7 +17362,7 @@ var safeJSON = (text) => {
|
|
|
16936
17362
|
};
|
|
16937
17363
|
|
|
16938
17364
|
// node_modules/.pnpm/openai@7.15.0/node_modules/openai/internal/utils/sleep.mjs
|
|
16939
|
-
var
|
|
17365
|
+
var sleep2 = (ms) => new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
16940
17366
|
|
|
16941
17367
|
// node_modules/.pnpm/openai@7.15.0/node_modules/openai/internal/shims.mjs
|
|
16942
17368
|
function getDefaultFetch() {
|
|
@@ -17321,7 +17747,7 @@ var _Stream_client;
|
|
|
17321
17747
|
var _Stream_isTeeBranch;
|
|
17322
17748
|
var _Stream_cancelIterator;
|
|
17323
17749
|
function isTransportAbortError(error) {
|
|
17324
|
-
return !(error instanceof APIError) &&
|
|
17750
|
+
return !(error instanceof APIError) && isAbortError2(error);
|
|
17325
17751
|
}
|
|
17326
17752
|
function createStreamTeeQueue() {
|
|
17327
17753
|
let entries = [];
|
|
@@ -17522,7 +17948,7 @@ var Stream = class _Stream {
|
|
|
17522
17948
|
}
|
|
17523
17949
|
done = true;
|
|
17524
17950
|
} catch (e) {
|
|
17525
|
-
if (controller.signal.aborted ||
|
|
17951
|
+
if (controller.signal.aborted || isAbortError2(e)) {
|
|
17526
17952
|
return;
|
|
17527
17953
|
}
|
|
17528
17954
|
throw e;
|
|
@@ -17674,7 +18100,7 @@ function createAbortableSSESource(body, signal) {
|
|
|
17674
18100
|
}
|
|
17675
18101
|
return { value: result.value, done: false };
|
|
17676
18102
|
} catch (error) {
|
|
17677
|
-
if (signal.aborted && (
|
|
18103
|
+
if (signal.aborted && (isAbortError2(error) || error === signal.reason)) {
|
|
17678
18104
|
return ended;
|
|
17679
18105
|
}
|
|
17680
18106
|
throw error;
|
|
@@ -17781,7 +18207,7 @@ async function* _iterSSEMessages(response, controller) {
|
|
|
17781
18207
|
}
|
|
17782
18208
|
} catch (error) {
|
|
17783
18209
|
failed = true;
|
|
17784
|
-
if (!signal.aborted || !
|
|
18210
|
+
if (!signal.aborted || !isAbortError2(error) && error !== signal.reason) {
|
|
17785
18211
|
throw error;
|
|
17786
18212
|
}
|
|
17787
18213
|
} finally {
|
|
@@ -17930,7 +18356,7 @@ async function defaultParseResponse(client, props) {
|
|
|
17930
18356
|
return body;
|
|
17931
18357
|
}
|
|
17932
18358
|
function asAbortError(error, signal) {
|
|
17933
|
-
if (!signal.aborted || error !== signal.reason ||
|
|
18359
|
+
if (!signal.aborted || error !== signal.reason || isAbortError2(error)) {
|
|
17934
18360
|
return error;
|
|
17935
18361
|
}
|
|
17936
18362
|
const message = "This operation was aborted";
|
|
@@ -29873,7 +30299,7 @@ async function pollWithResponse(retrieve, intermediateStatuses, terminalStatuses
|
|
|
29873
30299
|
}
|
|
29874
30300
|
}
|
|
29875
30301
|
const signal = options && Object.prototype.propertyIsEnumerable.call(options, "signal") ? options.signal : void 0;
|
|
29876
|
-
await (signal ? sleepUntilAborted(sleepInterval, signal) :
|
|
30302
|
+
await (signal ? sleepUntilAborted(sleepInterval, signal) : sleep2(sleepInterval));
|
|
29877
30303
|
} else if (terminalStatuses.includes(status)) {
|
|
29878
30304
|
return data;
|
|
29879
30305
|
}
|
|
@@ -30534,7 +30960,7 @@ async function waitForFileProcessing(resource, id, pollInterval, maxWait) {
|
|
|
30534
30960
|
const start = performance.now();
|
|
30535
30961
|
let file = await resource.retrieve(id);
|
|
30536
30962
|
while (!file.status || !terminalStates.has(file.status)) {
|
|
30537
|
-
await
|
|
30963
|
+
await sleep2(pollInterval);
|
|
30538
30964
|
file = await resource.retrieve(id);
|
|
30539
30965
|
if (performance.now() - start > maxWait) {
|
|
30540
30966
|
throw new APIConnectionTimeoutError({
|
|
@@ -34299,7 +34725,7 @@ var OpenAI = class {
|
|
|
34299
34725
|
if (callerSignal?.aborted || req.signal?.aborted) {
|
|
34300
34726
|
throw this._makeUserAbortError(callerSignal?.aborted ? callerSignal : req.signal);
|
|
34301
34727
|
}
|
|
34302
|
-
const isTimeout =
|
|
34728
|
+
const isTimeout = isAbortError2(response) || /timed? ?out/i.test(String(response) + ("cause" in response ? String(response.cause) : ""));
|
|
34303
34729
|
if (retriesRemaining && !hasStreamingBody && (!x509Authentication || isTransientX509ConnectionError2(response))) {
|
|
34304
34730
|
loggerFor(this).info(`[${requestLogID}] connection ${isTimeout ? "timed out" : "failed"} - ${retryMessage}`);
|
|
34305
34731
|
loggerFor(this).debug(`[${requestLogID}] connection ${isTimeout ? "timed out" : "failed"} (${retryMessage})`, formatRequestDetails({
|
|
@@ -34526,7 +34952,7 @@ var OpenAI = class {
|
|
|
34526
34952
|
if (x509Authentication) {
|
|
34527
34953
|
await x509Authentication.waitForRetry(timeoutMillis, x509Authentication.effectiveSignal());
|
|
34528
34954
|
} else {
|
|
34529
|
-
await
|
|
34955
|
+
await sleep2(timeoutMillis);
|
|
34530
34956
|
}
|
|
34531
34957
|
return this.makeRequest(options, retriesRemaining - 1, requestLogID);
|
|
34532
34958
|
}
|
|
@@ -34773,30 +35199,6 @@ var brand_privateBedrockClient = Symbol.for("openai.privateBedrockClient");
|
|
|
34773
35199
|
var _a4;
|
|
34774
35200
|
_a4 = brand_privateBedrockClient;
|
|
34775
35201
|
|
|
34776
|
-
// src/agent/model.ts
|
|
34777
|
-
init_sdk();
|
|
34778
|
-
|
|
34779
|
-
// src/agent/message.ts
|
|
34780
|
-
function createTextContent(value) {
|
|
34781
|
-
return {
|
|
34782
|
-
type: "text",
|
|
34783
|
-
text: value
|
|
34784
|
-
};
|
|
34785
|
-
}
|
|
34786
|
-
function createUserMessage(input) {
|
|
34787
|
-
return {
|
|
34788
|
-
role: "user",
|
|
34789
|
-
content: [createTextContent(input)],
|
|
34790
|
-
timestamp: Date.now()
|
|
34791
|
-
};
|
|
34792
|
-
}
|
|
34793
|
-
function messageText(message) {
|
|
34794
|
-
return message.content.filter((block) => block.type === "text").map((block) => block.text).join("\n");
|
|
34795
|
-
}
|
|
34796
|
-
function isTextContent(block) {
|
|
34797
|
-
return block.type === "text";
|
|
34798
|
-
}
|
|
34799
|
-
|
|
34800
35202
|
// node_modules/.pnpm/chalk@6.0.0/node_modules/chalk/source/utilities.js
|
|
34801
35203
|
function stringReplaceAll(string, substring, postfix) {
|
|
34802
35204
|
let index = string.indexOf(substring);
|
|
@@ -35369,7 +35771,7 @@ var LEVEL_WEIGHT = {
|
|
|
35369
35771
|
};
|
|
35370
35772
|
var DEFAULT_LOG_LEVEL = "info";
|
|
35371
35773
|
var LOG_LEVEL_ENV = "MINI_PI_LOG_LEVEL";
|
|
35372
|
-
function
|
|
35774
|
+
function parseLogLevel2(value) {
|
|
35373
35775
|
if (typeof value !== "string") {
|
|
35374
35776
|
return void 0;
|
|
35375
35777
|
}
|
|
@@ -35407,7 +35809,7 @@ var defaultLogSink = (entry) => {
|
|
|
35407
35809
|
process.stderr.write(`${paint(entry.level, LEVEL_LABEL[entry.level])}${scope} ${body}
|
|
35408
35810
|
`);
|
|
35409
35811
|
};
|
|
35410
|
-
var currentLevel =
|
|
35812
|
+
var currentLevel = parseLogLevel2(process.env[LOG_LEVEL_ENV]) ?? DEFAULT_LOG_LEVEL;
|
|
35411
35813
|
var currentSink = defaultLogSink;
|
|
35412
35814
|
function createLogger(scope) {
|
|
35413
35815
|
const emit = (level) => (message, ...args) => {
|
|
@@ -35426,10 +35828,7 @@ function createLogger(scope) {
|
|
|
35426
35828
|
}
|
|
35427
35829
|
var logger = createLogger();
|
|
35428
35830
|
|
|
35429
|
-
// src/agent/model.ts
|
|
35430
|
-
var REQUEST_TIMEOUT_MS = 12e4;
|
|
35431
|
-
var STREAM_IDLE_TIMEOUT_MS = 12e4;
|
|
35432
|
-
var DEFAULT_MAX_TOKENS = 8192;
|
|
35831
|
+
// src/agent/model/openai.ts
|
|
35433
35832
|
var REASONING_MODEL_PATTERN = /^o\d/i;
|
|
35434
35833
|
function buildOpenAIRequest(params) {
|
|
35435
35834
|
const payload = {
|
|
@@ -35463,378 +35862,10 @@ function isUnsupportedMaxTokensError(error) {
|
|
|
35463
35862
|
message
|
|
35464
35863
|
);
|
|
35465
35864
|
}
|
|
35466
|
-
function buildAnthropicRequest(params) {
|
|
35467
|
-
return {
|
|
35468
|
-
model: params.model,
|
|
35469
|
-
max_tokens: Math.max(1, Math.floor(params.maxTokens ?? DEFAULT_MAX_TOKENS)),
|
|
35470
|
-
system: params.system,
|
|
35471
|
-
messages: params.messages,
|
|
35472
|
-
tools: params.tools.length > 0 ? params.tools : void 0
|
|
35473
|
-
};
|
|
35474
|
-
}
|
|
35475
|
-
var MAX_REQUEST_ATTEMPTS = 3;
|
|
35476
|
-
var RETRY_BASE_DELAY_MS = 1e3;
|
|
35477
|
-
var STREAM_IDLE_TIMEOUT_ERROR_NAME = "StreamIdleTimeoutError";
|
|
35478
|
-
var StreamIdleTimeoutError = class extends Error {
|
|
35479
|
-
constructor(idleMs) {
|
|
35480
|
-
super(`\u6D41\u5F0F\u54CD\u5E94 ${idleMs}ms \u5185\u6CA1\u6709\u6536\u5230\u4EFB\u4F55\u6570\u636E\uFF0C\u5DF2\u4E2D\u6B62\u672C\u6B21\u8BF7\u6C42`);
|
|
35481
|
-
this.name = STREAM_IDLE_TIMEOUT_ERROR_NAME;
|
|
35482
|
-
}
|
|
35483
|
-
};
|
|
35484
|
-
function isStreamIdleTimeoutError(error) {
|
|
35485
|
-
let current = error;
|
|
35486
|
-
for (let depth = 0; current && typeof current === "object" && depth < 5; depth += 1) {
|
|
35487
|
-
const candidate = current;
|
|
35488
|
-
if (candidate.name === STREAM_IDLE_TIMEOUT_ERROR_NAME) {
|
|
35489
|
-
return true;
|
|
35490
|
-
}
|
|
35491
|
-
current = candidate.cause;
|
|
35492
|
-
}
|
|
35493
|
-
return false;
|
|
35494
|
-
}
|
|
35495
|
-
function createStreamIdleWatchdog(parent, idleMs = STREAM_IDLE_TIMEOUT_MS) {
|
|
35496
|
-
const controller = new AbortController();
|
|
35497
|
-
let timedOut = false;
|
|
35498
|
-
let timer = null;
|
|
35499
|
-
let disposed = false;
|
|
35500
|
-
const clear = () => {
|
|
35501
|
-
if (timer) {
|
|
35502
|
-
clearTimeout(timer);
|
|
35503
|
-
timer = null;
|
|
35504
|
-
}
|
|
35505
|
-
};
|
|
35506
|
-
const arm = () => {
|
|
35507
|
-
clear();
|
|
35508
|
-
if (disposed || controller.signal.aborted) {
|
|
35509
|
-
return;
|
|
35510
|
-
}
|
|
35511
|
-
timer = setTimeout(() => {
|
|
35512
|
-
timedOut = true;
|
|
35513
|
-
controller.abort();
|
|
35514
|
-
}, idleMs);
|
|
35515
|
-
};
|
|
35516
|
-
const onParentAbort = () => {
|
|
35517
|
-
clear();
|
|
35518
|
-
controller.abort();
|
|
35519
|
-
};
|
|
35520
|
-
if (parent?.aborted) {
|
|
35521
|
-
controller.abort();
|
|
35522
|
-
} else {
|
|
35523
|
-
parent?.addEventListener("abort", onParentAbort, { once: true });
|
|
35524
|
-
arm();
|
|
35525
|
-
}
|
|
35526
|
-
return {
|
|
35527
|
-
signal: controller.signal,
|
|
35528
|
-
touch: arm,
|
|
35529
|
-
timedOut: () => timedOut,
|
|
35530
|
-
dispose: () => {
|
|
35531
|
-
disposed = true;
|
|
35532
|
-
clear();
|
|
35533
|
-
parent?.removeEventListener("abort", onParentAbort);
|
|
35534
|
-
}
|
|
35535
|
-
};
|
|
35536
|
-
}
|
|
35537
|
-
function resolveMaxTokens(value) {
|
|
35538
|
-
return typeof value === "number" && Number.isFinite(value) && value >= 1 ? Math.floor(value) : DEFAULT_MAX_TOKENS;
|
|
35539
|
-
}
|
|
35540
|
-
function resolveStreamIdleTimeout(value) {
|
|
35541
|
-
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : STREAM_IDLE_TIMEOUT_MS;
|
|
35542
|
-
}
|
|
35543
|
-
function classifyStreamFailure(error, watchdog, signal, idleMs = STREAM_IDLE_TIMEOUT_MS) {
|
|
35544
|
-
if (watchdog.timedOut() && signal?.aborted !== true) {
|
|
35545
|
-
return new StreamIdleTimeoutError(idleMs);
|
|
35546
|
-
}
|
|
35547
|
-
return error;
|
|
35548
|
-
}
|
|
35549
|
-
function assertStreamNotIdleTimedOut(watchdog, idleMs, signal) {
|
|
35550
|
-
if (watchdog.timedOut() && signal?.aborted !== true) {
|
|
35551
|
-
throw new StreamIdleTimeoutError(idleMs);
|
|
35552
|
-
}
|
|
35553
|
-
}
|
|
35554
|
-
var PARTIAL_STREAM_ERROR_NAME = "PartialStreamInterruptedError";
|
|
35555
|
-
var PartialStreamInterruptedError = class extends Error {
|
|
35556
|
-
constructor(cause) {
|
|
35557
|
-
super(
|
|
35558
|
-
`\u6D41\u5F0F\u54CD\u5E94\u5728\u5DF2\u8F93\u51FA\u90E8\u5206\u5185\u5BB9\u540E\u4E2D\u65AD\uFF0C\u672A\u81EA\u52A8\u91CD\u8BD5\uFF08\u907F\u514D\u91CD\u590D\u8F93\u51FA\u4E0E\u91CD\u590D\u8BA1\u8D39\uFF09\uFF1A${describeError(cause)}`
|
|
35559
|
-
);
|
|
35560
|
-
this.name = PARTIAL_STREAM_ERROR_NAME;
|
|
35561
|
-
this.cause = cause;
|
|
35562
|
-
}
|
|
35563
|
-
};
|
|
35564
|
-
function isPartialStreamInterrupted(error) {
|
|
35565
|
-
let current = error;
|
|
35566
|
-
for (let depth = 0; current && typeof current === "object" && depth < 5; depth += 1) {
|
|
35567
|
-
const candidate = current;
|
|
35568
|
-
if (candidate.name === PARTIAL_STREAM_ERROR_NAME) {
|
|
35569
|
-
return true;
|
|
35570
|
-
}
|
|
35571
|
-
current = candidate.cause;
|
|
35572
|
-
}
|
|
35573
|
-
return false;
|
|
35574
|
-
}
|
|
35575
|
-
function toNonRetryableIfPartialStream(error, emittedContent) {
|
|
35576
|
-
if (emittedContent && isRetryableError2(error)) {
|
|
35577
|
-
return new PartialStreamInterruptedError(error);
|
|
35578
|
-
}
|
|
35579
|
-
return error;
|
|
35580
|
-
}
|
|
35581
|
-
var RETRYABLE_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
35582
|
-
"ETIMEDOUT",
|
|
35583
|
-
"ECONNRESET",
|
|
35584
|
-
"ECONNREFUSED",
|
|
35585
|
-
"EPIPE",
|
|
35586
|
-
"ENOTFOUND",
|
|
35587
|
-
"EAI_AGAIN",
|
|
35588
|
-
"UND_ERR_CONNECT_TIMEOUT",
|
|
35589
|
-
"UND_ERR_SOCKET"
|
|
35590
|
-
]);
|
|
35591
|
-
var RETRYABLE_ERROR_NAME_PATTERNS = [
|
|
35592
|
-
/^APIConnectionError$/,
|
|
35593
|
-
/^APIConnectionTimeoutError$/,
|
|
35594
|
-
/^APIConnectionTimeoutError\d*$/
|
|
35595
|
-
];
|
|
35596
|
-
var ERROR_CAUSE_MAX_DEPTH = 5;
|
|
35597
|
-
function findInErrorChain(error, read) {
|
|
35598
|
-
let current = error;
|
|
35599
|
-
for (let depth = 0; current && typeof current === "object" && depth < ERROR_CAUSE_MAX_DEPTH; depth += 1) {
|
|
35600
|
-
const candidate = current;
|
|
35601
|
-
const value = read(candidate);
|
|
35602
|
-
if (value !== void 0) {
|
|
35603
|
-
return value;
|
|
35604
|
-
}
|
|
35605
|
-
current = candidate.cause;
|
|
35606
|
-
}
|
|
35607
|
-
return void 0;
|
|
35608
|
-
}
|
|
35609
|
-
function isRetryableError2(error) {
|
|
35610
|
-
if (!error || typeof error !== "object") {
|
|
35611
|
-
return false;
|
|
35612
|
-
}
|
|
35613
|
-
if (isPartialStreamInterrupted(error)) {
|
|
35614
|
-
return false;
|
|
35615
|
-
}
|
|
35616
|
-
if (isStreamIdleTimeoutError(error)) {
|
|
35617
|
-
return true;
|
|
35618
|
-
}
|
|
35619
|
-
const name = findInErrorChain(
|
|
35620
|
-
error,
|
|
35621
|
-
(candidate) => typeof candidate.name === "string" ? candidate.name : void 0
|
|
35622
|
-
);
|
|
35623
|
-
if (name && RETRYABLE_ERROR_NAME_PATTERNS.some((pattern) => pattern.test(name))) {
|
|
35624
|
-
return true;
|
|
35625
|
-
}
|
|
35626
|
-
const status = findInErrorChain(
|
|
35627
|
-
error,
|
|
35628
|
-
(candidate) => typeof candidate.status === "number" ? candidate.status : void 0
|
|
35629
|
-
);
|
|
35630
|
-
if (status !== void 0) {
|
|
35631
|
-
return status === 429 || status === 408 || status >= 500;
|
|
35632
|
-
}
|
|
35633
|
-
const code = findInErrorChain(
|
|
35634
|
-
error,
|
|
35635
|
-
(candidate) => typeof candidate.code === "string" ? candidate.code : void 0
|
|
35636
|
-
);
|
|
35637
|
-
if (code !== void 0 && RETRYABLE_ERROR_CODES.has(code)) {
|
|
35638
|
-
return true;
|
|
35639
|
-
}
|
|
35640
|
-
return false;
|
|
35641
|
-
}
|
|
35642
|
-
var RETRY_JITTER_RATIO = 0.2;
|
|
35643
|
-
function applyRetryJitter(delayMs, random = Math.random) {
|
|
35644
|
-
const factor = 1 - RETRY_JITTER_RATIO + random() * RETRY_JITTER_RATIO * 2;
|
|
35645
|
-
return Math.max(0, Math.round(delayMs * factor));
|
|
35646
|
-
}
|
|
35647
|
-
function readHeader(headers, name) {
|
|
35648
|
-
if (!headers || typeof headers !== "object") {
|
|
35649
|
-
return null;
|
|
35650
|
-
}
|
|
35651
|
-
const getter = headers.get;
|
|
35652
|
-
if (typeof getter === "function") {
|
|
35653
|
-
const value = getter.call(headers, name);
|
|
35654
|
-
return typeof value === "string" ? value : null;
|
|
35655
|
-
}
|
|
35656
|
-
const record = headers;
|
|
35657
|
-
for (const key of [name, name.toLowerCase(), name.toUpperCase()]) {
|
|
35658
|
-
const value = record[key];
|
|
35659
|
-
if (typeof value === "string") {
|
|
35660
|
-
return value;
|
|
35661
|
-
}
|
|
35662
|
-
}
|
|
35663
|
-
return null;
|
|
35664
|
-
}
|
|
35665
|
-
function retryAfterMsFromError(error, now = Date.now()) {
|
|
35666
|
-
const headers = findInErrorChain(
|
|
35667
|
-
error,
|
|
35668
|
-
(candidate) => candidate.headers && typeof candidate.headers === "object" ? candidate.headers : void 0
|
|
35669
|
-
);
|
|
35670
|
-
if (!headers) {
|
|
35671
|
-
return void 0;
|
|
35672
|
-
}
|
|
35673
|
-
const ms = readHeader(headers, "retry-after-ms");
|
|
35674
|
-
if (ms !== null && ms.trim() !== "") {
|
|
35675
|
-
const parsed = Number(ms);
|
|
35676
|
-
if (Number.isFinite(parsed) && parsed >= 0) {
|
|
35677
|
-
return parsed;
|
|
35678
|
-
}
|
|
35679
|
-
}
|
|
35680
|
-
const raw = readHeader(headers, "retry-after");
|
|
35681
|
-
if (raw !== null && raw.trim() !== "") {
|
|
35682
|
-
const seconds = Number(raw);
|
|
35683
|
-
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
35684
|
-
return seconds * 1e3;
|
|
35685
|
-
}
|
|
35686
|
-
const date = Date.parse(raw);
|
|
35687
|
-
if (Number.isFinite(date)) {
|
|
35688
|
-
return Math.max(0, date - now);
|
|
35689
|
-
}
|
|
35690
|
-
}
|
|
35691
|
-
return void 0;
|
|
35692
|
-
}
|
|
35693
|
-
function resolveRetryDelayMs(error, backoffMs, now = Date.now(), random = Math.random) {
|
|
35694
|
-
const serverMs = retryAfterMsFromError(error, now);
|
|
35695
|
-
const base = serverMs === void 0 ? backoffMs : Math.max(serverMs, backoffMs);
|
|
35696
|
-
return applyRetryJitter(base, random);
|
|
35697
|
-
}
|
|
35698
|
-
function sleep3(ms, signal) {
|
|
35699
|
-
return new Promise((resolve6, reject) => {
|
|
35700
|
-
if (signal?.aborted) {
|
|
35701
|
-
reject(new Error("aborted"));
|
|
35702
|
-
return;
|
|
35703
|
-
}
|
|
35704
|
-
const timer = setTimeout(() => {
|
|
35705
|
-
signal?.removeEventListener("abort", onAbort);
|
|
35706
|
-
resolve6();
|
|
35707
|
-
}, ms);
|
|
35708
|
-
const onAbort = () => {
|
|
35709
|
-
clearTimeout(timer);
|
|
35710
|
-
reject(new Error("aborted"));
|
|
35711
|
-
};
|
|
35712
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
35713
|
-
});
|
|
35714
|
-
}
|
|
35715
|
-
async function withRetry(operation, options = {}) {
|
|
35716
|
-
const attempts = Math.max(1, options.attempts ?? MAX_REQUEST_ATTEMPTS);
|
|
35717
|
-
const baseDelayMs = options.baseDelayMs ?? RETRY_BASE_DELAY_MS;
|
|
35718
|
-
const wait = options.wait ?? sleep3;
|
|
35719
|
-
const random = options.random ?? Math.random;
|
|
35720
|
-
const now = options.now ?? Date.now;
|
|
35721
|
-
for (let attempt = 1; ; attempt += 1) {
|
|
35722
|
-
try {
|
|
35723
|
-
return await operation();
|
|
35724
|
-
} catch (error) {
|
|
35725
|
-
const cancelled = options.signal?.aborted === true || isAbortError3(error);
|
|
35726
|
-
if (cancelled || attempt >= attempts || !isRetryableError2(error)) {
|
|
35727
|
-
throw error;
|
|
35728
|
-
}
|
|
35729
|
-
const backoffMs = baseDelayMs * 2 ** (attempt - 1);
|
|
35730
|
-
const delayMs = resolveRetryDelayMs(error, backoffMs, now(), random);
|
|
35731
|
-
options.onRetry?.(attempt, error, delayMs);
|
|
35732
|
-
await wait(delayMs, options.signal);
|
|
35733
|
-
}
|
|
35734
|
-
}
|
|
35735
|
-
}
|
|
35736
|
-
var ABORT_ERROR_PATTERNS = [/^AbortError$/i, /APIUserAbortError/i];
|
|
35737
|
-
function isAbortError3(error) {
|
|
35738
|
-
let current = error;
|
|
35739
|
-
for (let depth = 0; current && typeof current === "object" && depth < 5; depth += 1) {
|
|
35740
|
-
const candidate = current;
|
|
35741
|
-
for (const value of [candidate.name, candidate.constructor?.name]) {
|
|
35742
|
-
if (typeof value === "string" && ABORT_ERROR_PATTERNS.some((pattern) => pattern.test(value))) {
|
|
35743
|
-
return true;
|
|
35744
|
-
}
|
|
35745
|
-
}
|
|
35746
|
-
current = candidate.cause;
|
|
35747
|
-
}
|
|
35748
|
-
return false;
|
|
35749
|
-
}
|
|
35750
|
-
function describeError(error) {
|
|
35751
|
-
return error instanceof Error ? error.message : String(error);
|
|
35752
|
-
}
|
|
35753
35865
|
function isUnsupportedStreamOptionsError(error) {
|
|
35754
35866
|
const message = error instanceof Error ? error.message : String(error);
|
|
35755
35867
|
return /stream_options/i.test(message);
|
|
35756
35868
|
}
|
|
35757
|
-
function mapFinishReason(reason) {
|
|
35758
|
-
if (reason === "tool_calls" || reason === "function_call") {
|
|
35759
|
-
return "toolUse";
|
|
35760
|
-
}
|
|
35761
|
-
if (reason === "length") {
|
|
35762
|
-
return "length";
|
|
35763
|
-
}
|
|
35764
|
-
if (reason === "content_filter") {
|
|
35765
|
-
return "error";
|
|
35766
|
-
}
|
|
35767
|
-
return "stop";
|
|
35768
|
-
}
|
|
35769
|
-
async function collectOpenAIStream(chunks, onDelta, onChunk) {
|
|
35770
|
-
let text = "";
|
|
35771
|
-
let finishReason = null;
|
|
35772
|
-
let usage = null;
|
|
35773
|
-
const toolCalls = /* @__PURE__ */ new Map();
|
|
35774
|
-
for await (const chunk of chunks) {
|
|
35775
|
-
onChunk?.();
|
|
35776
|
-
if (chunk.usage) {
|
|
35777
|
-
usage = chunk.usage;
|
|
35778
|
-
}
|
|
35779
|
-
const choice = chunk.choices?.[0];
|
|
35780
|
-
if (!choice) {
|
|
35781
|
-
continue;
|
|
35782
|
-
}
|
|
35783
|
-
const delta = choice.delta;
|
|
35784
|
-
if (delta?.content) {
|
|
35785
|
-
text += delta.content;
|
|
35786
|
-
onDelta?.(delta.content);
|
|
35787
|
-
}
|
|
35788
|
-
for (const call of delta?.tool_calls ?? []) {
|
|
35789
|
-
const index = call.index ?? 0;
|
|
35790
|
-
const entry = toolCalls.get(index) ?? { id: "", name: "", args: "" };
|
|
35791
|
-
if (call.id) {
|
|
35792
|
-
entry.id = call.id;
|
|
35793
|
-
}
|
|
35794
|
-
if (call.function?.name) {
|
|
35795
|
-
entry.name += call.function.name;
|
|
35796
|
-
}
|
|
35797
|
-
if (call.function?.arguments) {
|
|
35798
|
-
entry.args += call.function.arguments;
|
|
35799
|
-
}
|
|
35800
|
-
toolCalls.set(index, entry);
|
|
35801
|
-
}
|
|
35802
|
-
if (choice.finish_reason) {
|
|
35803
|
-
finishReason = choice.finish_reason;
|
|
35804
|
-
}
|
|
35805
|
-
}
|
|
35806
|
-
const content = [];
|
|
35807
|
-
if (text) {
|
|
35808
|
-
content.push(createTextContent(text));
|
|
35809
|
-
}
|
|
35810
|
-
for (const [index, call] of [...toolCalls.entries()].sort((a, b) => a[0] - b[0])) {
|
|
35811
|
-
let args = {};
|
|
35812
|
-
if (call.args) {
|
|
35813
|
-
try {
|
|
35814
|
-
args = JSON.parse(call.args);
|
|
35815
|
-
} catch {
|
|
35816
|
-
args = {};
|
|
35817
|
-
}
|
|
35818
|
-
}
|
|
35819
|
-
content.push({
|
|
35820
|
-
type: "toolCall",
|
|
35821
|
-
id: call.id || `call_${index}`,
|
|
35822
|
-
name: call.name,
|
|
35823
|
-
arguments: args
|
|
35824
|
-
});
|
|
35825
|
-
}
|
|
35826
|
-
return {
|
|
35827
|
-
role: "assistant",
|
|
35828
|
-
content,
|
|
35829
|
-
stopReason: mapFinishReason(finishReason),
|
|
35830
|
-
usage: {
|
|
35831
|
-
input: usage?.prompt_tokens ?? 0,
|
|
35832
|
-
output: usage?.completion_tokens ?? 0,
|
|
35833
|
-
totalTokens: usage?.total_tokens ?? 0
|
|
35834
|
-
},
|
|
35835
|
-
timestamp: Date.now()
|
|
35836
|
-
};
|
|
35837
|
-
}
|
|
35838
35869
|
var OpenAIModel = class {
|
|
35839
35870
|
client;
|
|
35840
35871
|
model;
|
|
@@ -35867,10 +35898,10 @@ var OpenAIModel = class {
|
|
|
35867
35898
|
try {
|
|
35868
35899
|
return await this.requestWithFallbacks(input, messages, tools);
|
|
35869
35900
|
} catch (error) {
|
|
35870
|
-
if (!
|
|
35901
|
+
if (!isAbortError(error) && !input.signal?.aborted) {
|
|
35871
35902
|
logger.error("OpenAI API error:", error);
|
|
35872
35903
|
}
|
|
35873
|
-
return
|
|
35904
|
+
return createErrorResponse(error, input.signal);
|
|
35874
35905
|
}
|
|
35875
35906
|
}
|
|
35876
35907
|
/**
|
|
@@ -35913,12 +35944,11 @@ var OpenAIModel = class {
|
|
|
35913
35944
|
}
|
|
35914
35945
|
/** 流式请求:逐段回调 onDelta,最终拼装成完整消息 */
|
|
35915
35946
|
async streamCompletion(input, messages, tools) {
|
|
35916
|
-
const watchdog = createStreamIdleWatchdog(
|
|
35917
|
-
|
|
35918
|
-
|
|
35919
|
-
|
|
35920
|
-
|
|
35921
|
-
} : void 0;
|
|
35947
|
+
const watchdog = createStreamIdleWatchdog(
|
|
35948
|
+
input.signal,
|
|
35949
|
+
this.streamIdleTimeoutMs
|
|
35950
|
+
);
|
|
35951
|
+
const emitter = createDeltaEmitter(input.onDelta);
|
|
35922
35952
|
try {
|
|
35923
35953
|
const stream2 = await this.client.chat.completions.create(
|
|
35924
35954
|
buildOpenAIRequest({
|
|
@@ -35931,7 +35961,7 @@ var OpenAIModel = class {
|
|
|
35931
35961
|
}),
|
|
35932
35962
|
{ signal: watchdog.signal, timeout: REQUEST_TIMEOUT_MS }
|
|
35933
35963
|
);
|
|
35934
|
-
const message = await collectOpenAIStream(stream2, onDelta, watchdog.touch);
|
|
35964
|
+
const message = await collectOpenAIStream(stream2, emitter.onDelta, watchdog.touch);
|
|
35935
35965
|
assertStreamNotIdleTimedOut(watchdog, this.streamIdleTimeoutMs, input.signal);
|
|
35936
35966
|
return message;
|
|
35937
35967
|
} catch (error) {
|
|
@@ -35941,31 +35971,11 @@ var OpenAIModel = class {
|
|
|
35941
35971
|
input.signal,
|
|
35942
35972
|
this.streamIdleTimeoutMs
|
|
35943
35973
|
);
|
|
35944
|
-
throw toNonRetryableIfPartialStream(failure,
|
|
35974
|
+
throw toNonRetryableIfPartialStream(failure, emitter.emittedAny());
|
|
35945
35975
|
} finally {
|
|
35946
35976
|
watchdog.dispose();
|
|
35947
35977
|
}
|
|
35948
35978
|
}
|
|
35949
|
-
createErrorResponse(error, signal) {
|
|
35950
|
-
if (signal?.aborted || isAbortError3(error)) {
|
|
35951
|
-
return {
|
|
35952
|
-
role: "assistant",
|
|
35953
|
-
content: [createTextContent("\u6A21\u578B\u8C03\u7528\u5DF2\u53D6\u6D88")],
|
|
35954
|
-
stopReason: "aborted",
|
|
35955
|
-
usage: { input: 0, output: 0, totalTokens: 0 },
|
|
35956
|
-
errorMessage: "aborted",
|
|
35957
|
-
timestamp: Date.now()
|
|
35958
|
-
};
|
|
35959
|
-
}
|
|
35960
|
-
return {
|
|
35961
|
-
role: "assistant",
|
|
35962
|
-
content: [createTextContent(`\u6A21\u578B\u8C03\u7528\u5931\u8D25\uFF1A${describeError(error)}`)],
|
|
35963
|
-
stopReason: "error",
|
|
35964
|
-
usage: { input: 0, output: 0, totalTokens: 0 },
|
|
35965
|
-
errorMessage: describeError(error),
|
|
35966
|
-
timestamp: Date.now()
|
|
35967
|
-
};
|
|
35968
|
-
}
|
|
35969
35979
|
convertMessages(systemPrompt, messages) {
|
|
35970
35980
|
const result = [];
|
|
35971
35981
|
result.push({
|
|
@@ -36021,6 +36031,18 @@ var OpenAIModel = class {
|
|
|
36021
36031
|
function createOpenAIModel(config) {
|
|
36022
36032
|
return new OpenAIModel(config);
|
|
36023
36033
|
}
|
|
36034
|
+
|
|
36035
|
+
// src/agent/model/anthropic.ts
|
|
36036
|
+
init_sdk();
|
|
36037
|
+
function buildAnthropicRequest(params) {
|
|
36038
|
+
return {
|
|
36039
|
+
model: params.model,
|
|
36040
|
+
max_tokens: Math.max(1, Math.floor(params.maxTokens ?? DEFAULT_MAX_TOKENS)),
|
|
36041
|
+
system: params.system,
|
|
36042
|
+
messages: params.messages,
|
|
36043
|
+
tools: params.tools.length > 0 ? params.tools : void 0
|
|
36044
|
+
};
|
|
36045
|
+
}
|
|
36024
36046
|
var AnthropicModel = class {
|
|
36025
36047
|
client;
|
|
36026
36048
|
model;
|
|
@@ -36056,16 +36078,19 @@ var AnthropicModel = class {
|
|
|
36056
36078
|
);
|
|
36057
36079
|
return this.convertResponse(response);
|
|
36058
36080
|
} catch (error) {
|
|
36059
|
-
if (!
|
|
36081
|
+
if (!isAbortError(error) && !input.signal?.aborted) {
|
|
36060
36082
|
logger.error("Anthropic API error:", error);
|
|
36061
36083
|
}
|
|
36062
|
-
return
|
|
36084
|
+
return createErrorResponse(error, input.signal, "Anthropic \u6A21\u578B\u8C03\u7528");
|
|
36063
36085
|
}
|
|
36064
36086
|
}
|
|
36065
36087
|
/** 流式请求:经 stream 事件逐段回调 onDelta,最终取回完整消息 */
|
|
36066
36088
|
async streamCompletion(input, system, messages, tools) {
|
|
36067
|
-
const watchdog = createStreamIdleWatchdog(
|
|
36068
|
-
|
|
36089
|
+
const watchdog = createStreamIdleWatchdog(
|
|
36090
|
+
input.signal,
|
|
36091
|
+
this.streamIdleTimeoutMs
|
|
36092
|
+
);
|
|
36093
|
+
const emitter = createDeltaEmitter(input.onDelta);
|
|
36069
36094
|
try {
|
|
36070
36095
|
const stream2 = this.client.messages.stream(
|
|
36071
36096
|
buildAnthropicRequest({
|
|
@@ -36077,10 +36102,9 @@ var AnthropicModel = class {
|
|
|
36077
36102
|
}),
|
|
36078
36103
|
{ signal: watchdog.signal, timeout: REQUEST_TIMEOUT_MS }
|
|
36079
36104
|
);
|
|
36080
|
-
if (
|
|
36105
|
+
if (emitter.onDelta) {
|
|
36081
36106
|
stream2.on("text", (delta) => {
|
|
36082
|
-
|
|
36083
|
-
input.onDelta?.(delta);
|
|
36107
|
+
emitter.onDelta?.(delta);
|
|
36084
36108
|
});
|
|
36085
36109
|
}
|
|
36086
36110
|
stream2.on("streamEvent", () => watchdog.touch());
|
|
@@ -36094,7 +36118,7 @@ var AnthropicModel = class {
|
|
|
36094
36118
|
input.signal,
|
|
36095
36119
|
this.streamIdleTimeoutMs
|
|
36096
36120
|
);
|
|
36097
|
-
throw toNonRetryableIfPartialStream(failure,
|
|
36121
|
+
throw toNonRetryableIfPartialStream(failure, emitter.emittedAny());
|
|
36098
36122
|
} finally {
|
|
36099
36123
|
watchdog.dispose();
|
|
36100
36124
|
}
|
|
@@ -36175,54 +36199,37 @@ var AnthropicModel = class {
|
|
|
36175
36199
|
});
|
|
36176
36200
|
}
|
|
36177
36201
|
}
|
|
36178
|
-
let stopReason = "stop";
|
|
36179
|
-
if (response.stop_reason === "tool_use") {
|
|
36180
|
-
stopReason = "toolUse";
|
|
36181
|
-
} else if (response.stop_reason === "max_tokens") {
|
|
36182
|
-
stopReason = "length";
|
|
36183
|
-
} else if (response.stop_reason === "end_turn") {
|
|
36184
|
-
stopReason = "stop";
|
|
36185
|
-
} else {
|
|
36186
|
-
stopReason = "error";
|
|
36187
|
-
}
|
|
36188
|
-
const usage = {
|
|
36189
|
-
input: response.usage.input_tokens,
|
|
36190
|
-
output: response.usage.output_tokens,
|
|
36191
|
-
totalTokens: response.usage.input_tokens + response.usage.output_tokens
|
|
36192
|
-
};
|
|
36193
36202
|
return {
|
|
36194
36203
|
role: "assistant",
|
|
36195
36204
|
content,
|
|
36196
|
-
stopReason,
|
|
36197
|
-
usage
|
|
36205
|
+
stopReason: mapStopReason(response.stop_reason),
|
|
36206
|
+
usage: {
|
|
36207
|
+
input: response.usage.input_tokens,
|
|
36208
|
+
output: response.usage.output_tokens,
|
|
36209
|
+
totalTokens: response.usage.input_tokens + response.usage.output_tokens
|
|
36210
|
+
},
|
|
36198
36211
|
timestamp: Date.now()
|
|
36199
36212
|
};
|
|
36200
36213
|
}
|
|
36201
|
-
createErrorResponse(error, signal) {
|
|
36202
|
-
if (signal?.aborted || isAbortError3(error)) {
|
|
36203
|
-
return {
|
|
36204
|
-
role: "assistant",
|
|
36205
|
-
content: [createTextContent("\u6A21\u578B\u8C03\u7528\u5DF2\u53D6\u6D88")],
|
|
36206
|
-
stopReason: "aborted",
|
|
36207
|
-
usage: { input: 0, output: 0, totalTokens: 0 },
|
|
36208
|
-
errorMessage: "aborted",
|
|
36209
|
-
timestamp: Date.now()
|
|
36210
|
-
};
|
|
36211
|
-
}
|
|
36212
|
-
return {
|
|
36213
|
-
role: "assistant",
|
|
36214
|
-
content: [createTextContent(`Anthropic \u6A21\u578B\u8C03\u7528\u5931\u8D25\uFF1A${describeError(error)}`)],
|
|
36215
|
-
stopReason: "error",
|
|
36216
|
-
usage: { input: 0, output: 0, totalTokens: 0 },
|
|
36217
|
-
timestamp: Date.now(),
|
|
36218
|
-
errorMessage: describeError(error)
|
|
36219
|
-
};
|
|
36220
|
-
}
|
|
36221
36214
|
};
|
|
36215
|
+
function mapStopReason(reason) {
|
|
36216
|
+
if (reason === "tool_use") {
|
|
36217
|
+
return "toolUse";
|
|
36218
|
+
}
|
|
36219
|
+
if (reason === "max_tokens") {
|
|
36220
|
+
return "length";
|
|
36221
|
+
}
|
|
36222
|
+
if (reason === "end_turn") {
|
|
36223
|
+
return "stop";
|
|
36224
|
+
}
|
|
36225
|
+
return "error";
|
|
36226
|
+
}
|
|
36222
36227
|
function createAnthropicModel(config) {
|
|
36223
36228
|
return new AnthropicModel(config);
|
|
36224
36229
|
}
|
|
36225
|
-
|
|
36230
|
+
|
|
36231
|
+
// src/agent/model/factory.ts
|
|
36232
|
+
function createModelFromProvider(config) {
|
|
36226
36233
|
switch (config.sdkType) {
|
|
36227
36234
|
case "OpenAI":
|
|
36228
36235
|
return createOpenAIModel({
|
|
@@ -37316,12 +37323,62 @@ async function readSearchableFile(absolutePath2) {
|
|
|
37316
37323
|
}
|
|
37317
37324
|
}
|
|
37318
37325
|
|
|
37326
|
+
// src/agent/tools/skill.ts
|
|
37327
|
+
var emptySkillSource = {
|
|
37328
|
+
loadSkill: () => null,
|
|
37329
|
+
loadAllMetadata: () => []
|
|
37330
|
+
};
|
|
37331
|
+
function loadSkillTool(source) {
|
|
37332
|
+
return {
|
|
37333
|
+
name: "load_skill",
|
|
37334
|
+
description: `Load the full content of a skill by its exact name. Skills are listed in the system prompt under "\u53EF\u7528 Skills" (name + description). Call this when the user's request matches a skill, then follow its instructions. Only names from that list are accepted; paths are not.`,
|
|
37335
|
+
parameters: {
|
|
37336
|
+
type: "object",
|
|
37337
|
+
properties: {
|
|
37338
|
+
name: {
|
|
37339
|
+
type: "string",
|
|
37340
|
+
description: 'Exact skill name from the "\u53EF\u7528 Skills" list, e.g. "cli-output-presentation".'
|
|
37341
|
+
}
|
|
37342
|
+
},
|
|
37343
|
+
required: ["name"]
|
|
37344
|
+
},
|
|
37345
|
+
async execute(args) {
|
|
37346
|
+
const name = stringArg(args.name, "").trim();
|
|
37347
|
+
if (!name) {
|
|
37348
|
+
return {
|
|
37349
|
+
content: [createTextContent("\u7F3A\u5C11 skill \u540D\u79F0\uFF1A\u8BF7\u63D0\u4F9B name \u53C2\u6570")],
|
|
37350
|
+
isError: true
|
|
37351
|
+
};
|
|
37352
|
+
}
|
|
37353
|
+
const skill = source.loadSkill(name);
|
|
37354
|
+
if (!skill) {
|
|
37355
|
+
const available = source.loadAllMetadata().map((s) => s.name);
|
|
37356
|
+
return {
|
|
37357
|
+
content: [
|
|
37358
|
+
createTextContent(
|
|
37359
|
+
`\u672A\u627E\u5230 skill: ${name}
|
|
37360
|
+
\u53EF\u7528\u7684 skill\uFF1A${available.length > 0 ? available.join("\u3001") : "\uFF08\u5F53\u524D\u6CA1\u6709\u53EF\u7528 skill\uFF09"}`
|
|
37361
|
+
)
|
|
37362
|
+
],
|
|
37363
|
+
isError: true,
|
|
37364
|
+
details: { skill: name, available }
|
|
37365
|
+
};
|
|
37366
|
+
}
|
|
37367
|
+
return {
|
|
37368
|
+
content: [createTextContent(skill.content)],
|
|
37369
|
+
details: { skill: skill.name, chars: skill.content.length }
|
|
37370
|
+
};
|
|
37371
|
+
}
|
|
37372
|
+
};
|
|
37373
|
+
}
|
|
37374
|
+
|
|
37319
37375
|
// src/agent/tools/registry.ts
|
|
37320
37376
|
var READ_ONLY_TOOL_NAMES = [
|
|
37321
37377
|
"list_files",
|
|
37322
37378
|
"glob",
|
|
37323
37379
|
"grep",
|
|
37324
|
-
"read_file"
|
|
37380
|
+
"read_file",
|
|
37381
|
+
"load_skill"
|
|
37325
37382
|
];
|
|
37326
37383
|
var READ_ONLY_TOOLS = new Set(READ_ONLY_TOOL_NAMES);
|
|
37327
37384
|
var ToolRegistry = class _ToolRegistry {
|
|
@@ -37409,6 +37466,7 @@ function createToolRegistry(workspaceRoot, options) {
|
|
|
37409
37466
|
globTool(workspaceRoot),
|
|
37410
37467
|
grepTool(workspaceRoot),
|
|
37411
37468
|
readFileTool(workspaceRoot),
|
|
37469
|
+
loadSkillTool(options?.skillLoader ?? emptySkillSource),
|
|
37412
37470
|
writeFileTool(workspaceRoot),
|
|
37413
37471
|
editFileTool(workspaceRoot),
|
|
37414
37472
|
bashTool(workspaceRoot)
|
|
@@ -38263,10 +38321,11 @@ var GENERAL_INSTRUCTIONS = [
|
|
|
38263
38321
|
"\u6240\u4EE5\u5FC5\u8981\u7684\u4E0A\u4E0B\u6587\uFF08\u8DEF\u5F84\u3001\u7B26\u53F7\u540D\u3001\u5173\u952E\u6570\u5B57\uFF09\u5FC5\u987B\u5199\u8FDB\u6765\u3002",
|
|
38264
38322
|
"\u505A\u5B8C\u7684\u90E8\u5206\u548C\u6CA1\u505A\u5B8C\u7684\u90E8\u5206\u8981\u5206\u5F00\u8BF4\u6E05\u695A\uFF0C\u4E0D\u8981\u628A\u534A\u622A\u7ED3\u8BBA\u8BF4\u6210\u5DF2\u5B8C\u6210\u3002"
|
|
38265
38323
|
].join("\n");
|
|
38324
|
+
var DELEGATABLE_READ_ONLY_TOOLS = READ_ONLY_TOOL_NAMES.filter((name) => name !== "load_skill");
|
|
38266
38325
|
var SUBAGENT_ROLE_PRESETS = {
|
|
38267
38326
|
explore: {
|
|
38268
38327
|
label: "explore",
|
|
38269
|
-
tools:
|
|
38328
|
+
tools: DELEGATABLE_READ_ONLY_TOOLS,
|
|
38270
38329
|
maxTurns: 20,
|
|
38271
38330
|
// 纯读取,最容易被大范围检索拖长:给得比 implement 短
|
|
38272
38331
|
timeoutMs: 12e4,
|
|
@@ -38275,7 +38334,7 @@ var SUBAGENT_ROLE_PRESETS = {
|
|
|
38275
38334
|
},
|
|
38276
38335
|
implement: {
|
|
38277
38336
|
label: "implement",
|
|
38278
|
-
tools: [...
|
|
38337
|
+
tools: [...DELEGATABLE_READ_ONLY_TOOLS, "write_file", "edit_file"],
|
|
38279
38338
|
maxTurns: 40,
|
|
38280
38339
|
// 要改文件还要自述验证(通常含一次测试/构建),最慢
|
|
38281
38340
|
timeoutMs: 3e5,
|
|
@@ -38285,7 +38344,7 @@ var SUBAGENT_ROLE_PRESETS = {
|
|
|
38285
38344
|
},
|
|
38286
38345
|
review: {
|
|
38287
38346
|
label: "review",
|
|
38288
|
-
tools:
|
|
38347
|
+
tools: DELEGATABLE_READ_ONLY_TOOLS,
|
|
38289
38348
|
maxTurns: 10,
|
|
38290
38349
|
timeoutMs: 6e4,
|
|
38291
38350
|
canEscalate: false,
|
|
@@ -38293,7 +38352,7 @@ var SUBAGENT_ROLE_PRESETS = {
|
|
|
38293
38352
|
},
|
|
38294
38353
|
general: {
|
|
38295
38354
|
label: "general",
|
|
38296
|
-
tools:
|
|
38355
|
+
tools: DELEGATABLE_READ_ONLY_TOOLS,
|
|
38297
38356
|
maxTurns: 30,
|
|
38298
38357
|
timeoutMs: 18e4,
|
|
38299
38358
|
canEscalate: true,
|
|
@@ -39688,6 +39747,26 @@ var SettingsStore = class {
|
|
|
39688
39747
|
this.settings.subagentTrace = enabled;
|
|
39689
39748
|
await this.persist();
|
|
39690
39749
|
}
|
|
39750
|
+
/**
|
|
39751
|
+
* 启动时是否检测新版本(`/update` 开关)。
|
|
39752
|
+
*
|
|
39753
|
+
* **默认开启**:与委派不同,更新检测的代价是"每天最多一次带超时的
|
|
39754
|
+
* 请求",而收益(不永远用旧版本)对每个用户都成立。想安静的人
|
|
39755
|
+
* `/update off` 一次即可,也不必先知道 settings.json 有这个字段。
|
|
39756
|
+
*/
|
|
39757
|
+
async getUpdateCheckEnabled() {
|
|
39758
|
+
await this.initialize();
|
|
39759
|
+
return this.settings.updateCheck !== false;
|
|
39760
|
+
}
|
|
39761
|
+
/**
|
|
39762
|
+
* 开关启动时的版本更新检测。
|
|
39763
|
+
* @throws settings.json 处于损坏状态时拒绝写入
|
|
39764
|
+
*/
|
|
39765
|
+
async setUpdateCheckEnabled(enabled) {
|
|
39766
|
+
await this.initialize();
|
|
39767
|
+
this.settings.updateCheck = enabled;
|
|
39768
|
+
await this.persist();
|
|
39769
|
+
}
|
|
39691
39770
|
/**
|
|
39692
39771
|
* 获取所有设置
|
|
39693
39772
|
*/
|
|
@@ -40156,6 +40235,10 @@ var COMMANDS = [
|
|
|
40156
40235
|
usage: "/subagent [on|off|trace on|trace off]",
|
|
40157
40236
|
description: "\u5F00\u5173\u5B50 Agent \u59D4\u6D3E\uFF08\u9ED8\u8BA4\u5173\u95ED\uFF09\uFF1Btrace \u5B50\u9879\u5F00\u5173\u59D4\u6D3E\u6392\u969C\u843D\u76D8"
|
|
40158
40237
|
},
|
|
40238
|
+
{
|
|
40239
|
+
usage: "/update [on|off]",
|
|
40240
|
+
description: "\u68C0\u67E5\u662F\u5426\u6709\u65B0\u7248\u672C\uFF08\u4E0D\u5E26\u53C2\u6570\u7ACB\u5373\u68C0\u67E5\uFF09\uFF1Bon/off \u5F00\u5173\u542F\u52A8\u68C0\u6D4B"
|
|
40241
|
+
},
|
|
40159
40242
|
{ usage: "/status", description: "\u67E5\u770B\u6A21\u578B\u3001\u4F1A\u8BDD\u6587\u4EF6\u3001\u4E0A\u4E0B\u6587\u4E0E token \u7528\u91CF\u3001\u786E\u8BA4\u6A21\u5F0F" },
|
|
40160
40243
|
{ usage: "/sessions", description: "\u5217\u51FA\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u7684\u4F1A\u8BDD" },
|
|
40161
40244
|
{ usage: "/switch <n>", description: "\u5207\u6362\u5230\u6307\u5B9A\u4F1A\u8BDD\uFF08\u6062\u590D\u5176\u5386\u53F2\u4E0A\u4E0B\u6587\uFF09" },
|
|
@@ -40195,7 +40278,7 @@ function printHelp() {
|
|
|
40195
40278
|
console.log(source_default.dim(" - \u76F4\u63A5\u8F93\u5165\u95EE\u9898\u5373\u53EF\u5F00\u59CB\u5BF9\u8BDD"));
|
|
40196
40279
|
console.log(source_default.dim(" - \u652F\u6301\u591A\u8F6E\u5BF9\u8BDD\uFF0C\u4E0A\u4E0B\u6587\u4F1A\u81EA\u52A8\u4FDD\u6301"));
|
|
40197
40280
|
console.log(source_default.dim(" - \u8F93\u5165\u7F16\u7A0B\u95EE\u9898\u6216\u6587\u4EF6\u64CD\u4F5C\u8BF7\u6C42"));
|
|
40198
|
-
console.log(source_default.dim(" - \
|
|
40281
|
+
console.log(source_default.dim(" - \u9700\u8981\u67D0\u4E2A skill \u65F6\u6A21\u578B\u4F1A\u81EA\u884C\u52A0\u8F7D\uFF0C\u4E5F\u53EF\u7528 /load \u624B\u52A8\u52A0\u8F7D"));
|
|
40199
40282
|
console.log("");
|
|
40200
40283
|
}
|
|
40201
40284
|
|
|
@@ -41280,6 +41363,7 @@ var ASCII_ICONS = {
|
|
|
41280
41363
|
glob: "[glob]",
|
|
41281
41364
|
grep: "[grep]",
|
|
41282
41365
|
read_file: "[read]",
|
|
41366
|
+
load_skill: "[skill]",
|
|
41283
41367
|
write_file: "[write]",
|
|
41284
41368
|
edit_file: "[edit]",
|
|
41285
41369
|
bash: "[bash]"
|
|
@@ -41289,6 +41373,7 @@ var EMOJI_ICONS = {
|
|
|
41289
41373
|
glob: "\u{1F50E}",
|
|
41290
41374
|
grep: "\u{1F50D}",
|
|
41291
41375
|
read_file: "\u{1F4D6}",
|
|
41376
|
+
load_skill: "\u{1F4DA}",
|
|
41292
41377
|
write_file: "\u270F\uFE0F",
|
|
41293
41378
|
edit_file: "\u{1F527}",
|
|
41294
41379
|
bash: "\u{1F4BB}"
|
|
@@ -41298,6 +41383,7 @@ var TOOL_COLORS = {
|
|
|
41298
41383
|
glob: "cyan",
|
|
41299
41384
|
grep: "cyan",
|
|
41300
41385
|
read_file: "cyan",
|
|
41386
|
+
load_skill: "cyan",
|
|
41301
41387
|
write_file: "magenta",
|
|
41302
41388
|
edit_file: "yellow",
|
|
41303
41389
|
bash: "green"
|
|
@@ -42121,6 +42207,7 @@ function handleSkills(sessionManager) {
|
|
|
42121
42207
|
console.log(source_default.red("\n\u274C SessionManager \u672A\u521D\u59CB\u5316\n"));
|
|
42122
42208
|
return;
|
|
42123
42209
|
}
|
|
42210
|
+
sessionManager.getSkillLoader().clearCache();
|
|
42124
42211
|
const metadata = sessionManager.loadSkillMetadata();
|
|
42125
42212
|
if (metadata.length === 0) {
|
|
42126
42213
|
console.log(source_default.dim("\n\u{1F4ED} \u6CA1\u6709\u627E\u5230\u4EFB\u4F55 skill\n"));
|
|
@@ -42159,11 +42246,32 @@ function handleSkills(sessionManager) {
|
|
|
42159
42246
|
console.log(source_default.dim("\u4F7F\u7528 /load <name> \u52A0\u8F7D skill \u5B8C\u6574\u5185\u5BB9"));
|
|
42160
42247
|
console.log("");
|
|
42161
42248
|
}
|
|
42249
|
+
function composeLoadedSkillSections(sessionManager, names) {
|
|
42250
|
+
const sections = [];
|
|
42251
|
+
for (const name of names) {
|
|
42252
|
+
const content = sessionManager.loadSkillContent(name);
|
|
42253
|
+
if (content) {
|
|
42254
|
+
sections.push(`## \u5DF2\u52A0\u8F7D Skill: ${name}
|
|
42255
|
+
|
|
42256
|
+
${content}`);
|
|
42257
|
+
}
|
|
42258
|
+
}
|
|
42259
|
+
return sections.length > 0 ? `
|
|
42260
|
+
|
|
42261
|
+
${sections.join("\n\n")}` : "";
|
|
42262
|
+
}
|
|
42162
42263
|
async function handleLoadSkill(sessionManager, skillName, options) {
|
|
42163
42264
|
if (!sessionManager) {
|
|
42164
42265
|
console.log(source_default.red("\n\u274C SessionManager \u672A\u521D\u59CB\u5316\n"));
|
|
42165
42266
|
return;
|
|
42166
42267
|
}
|
|
42268
|
+
const names = options.loadedSkillNames ?? (options.loadedSkillNames = []);
|
|
42269
|
+
if (names.includes(skillName)) {
|
|
42270
|
+
console.log(source_default.dim(`
|
|
42271
|
+
\u2139\uFE0F skill ${skillName} \u5DF2\u52A0\u8F7D\uFF0C\u4E0D\u91CD\u590D\u6CE8\u5165
|
|
42272
|
+
`));
|
|
42273
|
+
return;
|
|
42274
|
+
}
|
|
42167
42275
|
const skillContent = sessionManager.loadSkillContent(skillName);
|
|
42168
42276
|
if (!skillContent) {
|
|
42169
42277
|
console.log(source_default.red(`
|
|
@@ -42172,32 +42280,15 @@ async function handleLoadSkill(sessionManager, skillName, options) {
|
|
|
42172
42280
|
console.log(source_default.dim("\u4F7F\u7528 /skills \u67E5\u770B\u6240\u6709\u53EF\u7528\u7684 skills\n"));
|
|
42173
42281
|
return;
|
|
42174
42282
|
}
|
|
42175
|
-
|
|
42176
|
-
|
|
42177
|
-
|
|
42178
|
-
|
|
42179
|
-
${skillContent}`;
|
|
42180
|
-
options.systemPrompt = options.systemPrompt + skillSection;
|
|
42283
|
+
names.push(skillName);
|
|
42284
|
+
const base = options.baseSystemPrompt ?? options.systemPrompt;
|
|
42285
|
+
options.baseSystemPrompt = base;
|
|
42286
|
+
options.systemPrompt = base + composeLoadedSkillSections(sessionManager, names);
|
|
42181
42287
|
console.log(source_default.green(`
|
|
42182
42288
|
\u2705 \u5DF2\u52A0\u8F7D skill: ${skillName}
|
|
42183
42289
|
`));
|
|
42184
42290
|
console.log(source_default.dim("\u8BE5 skill \u7684\u5185\u5BB9\u5DF2\u6CE8\u5165\u5230\u4E0A\u4E0B\u6587\u4E2D\uFF0C\u540E\u7EED\u5BF9\u8BDD\u5C06\u53C2\u8003\u6B64 skill\u3002\n"));
|
|
42185
42291
|
}
|
|
42186
|
-
function checkSkillMatch(sessionManager, userInput) {
|
|
42187
|
-
if (!sessionManager) return;
|
|
42188
|
-
const matches = sessionManager.findMatchingSkills(userInput);
|
|
42189
|
-
if (matches.length > 0) {
|
|
42190
|
-
const topMatches = matches.slice(0, 3);
|
|
42191
|
-
console.log("");
|
|
42192
|
-
console.log(source_default.cyan("\u{1F4A1} \u53D1\u73B0\u5339\u914D\u7684 Skills:"));
|
|
42193
|
-
for (const skill of topMatches) {
|
|
42194
|
-
console.log(source_default.white(` - ${skill.name}`) + source_default.dim(`: ${skill.description}`));
|
|
42195
|
-
}
|
|
42196
|
-
console.log(source_default.dim(`
|
|
42197
|
-
\u4F7F\u7528 /load <name> \u52A0\u8F7D skill \u83B7\u53D6\u66F4\u4E13\u4E1A\u7684\u5E2E\u52A9`));
|
|
42198
|
-
console.log("");
|
|
42199
|
-
}
|
|
42200
|
-
}
|
|
42201
42292
|
|
|
42202
42293
|
// src/cli/subagentCommand.ts
|
|
42203
42294
|
var SUBAGENT_ON_WORDS = ["on", "\u5F00", "\u5F00\u542F", "\u6253\u5F00", "true", "enable"];
|
|
@@ -42300,6 +42391,446 @@ function printSubAgentCommandResult(outcome, previous) {
|
|
|
42300
42391
|
}
|
|
42301
42392
|
}
|
|
42302
42393
|
|
|
42394
|
+
// src/cli/updateCheck.ts
|
|
42395
|
+
var import_promises7 = require("node:fs/promises");
|
|
42396
|
+
var import_node_os4 = require("node:os");
|
|
42397
|
+
var import_node_path10 = require("node:path");
|
|
42398
|
+
|
|
42399
|
+
// package.json
|
|
42400
|
+
var package_default = {
|
|
42401
|
+
name: "@minipi/mini-pi",
|
|
42402
|
+
version: "1.0.2",
|
|
42403
|
+
description: "Mini Pi Code Agent - AI\u7F16\u7A0B\u52A9\u624B",
|
|
42404
|
+
bin: {
|
|
42405
|
+
"mini-pi": "./bin/mini-pi-cli.cjs"
|
|
42406
|
+
},
|
|
42407
|
+
files: [
|
|
42408
|
+
"bin/mini-pi-cli.cjs",
|
|
42409
|
+
"README.md"
|
|
42410
|
+
],
|
|
42411
|
+
engines: {
|
|
42412
|
+
node: ">=22"
|
|
42413
|
+
},
|
|
42414
|
+
publishConfig: {
|
|
42415
|
+
access: "public"
|
|
42416
|
+
},
|
|
42417
|
+
repository: {
|
|
42418
|
+
type: "git",
|
|
42419
|
+
url: "git+https://github.com/arixse/mini-pi.git"
|
|
42420
|
+
},
|
|
42421
|
+
bugs: {
|
|
42422
|
+
url: "https://github.com/arixse/mini-pi/issues"
|
|
42423
|
+
},
|
|
42424
|
+
homepage: "https://github.com/arixse/mini-pi#readme",
|
|
42425
|
+
scripts: {
|
|
42426
|
+
dev: "tsx watch src/cli/entry.ts",
|
|
42427
|
+
"dev:cli": "tsx src/cli/entry.ts",
|
|
42428
|
+
"build:cli": "esbuild src/cli/entry.ts --bundle --platform=node --outfile=bin/mini-pi-cli.cjs --format=cjs --external:react --external:react-dom --external:lucide-react --external:vite",
|
|
42429
|
+
prepare: "npm run build:cli",
|
|
42430
|
+
"link:cli": "npm link",
|
|
42431
|
+
typecheck: "tsc --noEmit",
|
|
42432
|
+
test: 'tsx --test --test-concurrency=4 "src/**/*.test.ts"',
|
|
42433
|
+
"test:coverage": 'tsx --test --test-concurrency=4 --experimental-test-coverage --test-coverage-exclude="**/*.test.ts" --test-coverage-exclude="**/shim/*.cjs" --test-coverage-lines=85 --test-coverage-branches=85 --test-coverage-functions=90 "src/**/*.test.ts"',
|
|
42434
|
+
check: "npm run typecheck && npm run test:coverage"
|
|
42435
|
+
},
|
|
42436
|
+
keywords: [],
|
|
42437
|
+
author: "",
|
|
42438
|
+
license: "ISC",
|
|
42439
|
+
packageManager: "pnpm@10.17.0",
|
|
42440
|
+
type: "module",
|
|
42441
|
+
dependencies: {
|
|
42442
|
+
"@anthropic-ai/sdk": "^0.125.0",
|
|
42443
|
+
"@vitejs/plugin-react": "^6.1.0",
|
|
42444
|
+
chalk: "^6.0.0",
|
|
42445
|
+
concurrently: "^10.0.5",
|
|
42446
|
+
dotenv: "^17.4.2",
|
|
42447
|
+
express: "^5.2.1",
|
|
42448
|
+
"lucide-react": "^1.34.0",
|
|
42449
|
+
openai: "^7.15.0",
|
|
42450
|
+
react: "^19.2.8",
|
|
42451
|
+
"react-dom": "^19.2.8",
|
|
42452
|
+
tsx: "^4.23.12",
|
|
42453
|
+
vite: "^8.2.2"
|
|
42454
|
+
},
|
|
42455
|
+
devDependencies: {
|
|
42456
|
+
"@types/express": "^5.0.6",
|
|
42457
|
+
"@types/node": "^26.3.0",
|
|
42458
|
+
"@types/react": "^19.2.18",
|
|
42459
|
+
"@types/react-dom": "^19.2.5",
|
|
42460
|
+
esbuild: "^0.25.2",
|
|
42461
|
+
typescript: "^7.0.2"
|
|
42462
|
+
}
|
|
42463
|
+
};
|
|
42464
|
+
|
|
42465
|
+
// src/cli/version.ts
|
|
42466
|
+
var FALLBACK_VERSION = "0.0.0";
|
|
42467
|
+
var FALLBACK_PACKAGE_NAME = "mini-pi";
|
|
42468
|
+
var declared = package_default.version;
|
|
42469
|
+
var APP_VERSION = typeof declared === "string" && declared.length > 0 ? declared : FALLBACK_VERSION;
|
|
42470
|
+
var declaredName = package_default.name;
|
|
42471
|
+
var PACKAGE_NAME = typeof declaredName === "string" && declaredName.length > 0 ? declaredName : FALLBACK_PACKAGE_NAME;
|
|
42472
|
+
function formatVersion(version = APP_VERSION) {
|
|
42473
|
+
return `v${version}`;
|
|
42474
|
+
}
|
|
42475
|
+
function wantsVersion(argv) {
|
|
42476
|
+
return argv.includes("--version") || argv.includes("-v");
|
|
42477
|
+
}
|
|
42478
|
+
|
|
42479
|
+
// src/cli/versionCompare.ts
|
|
42480
|
+
var SEMVER_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
42481
|
+
function isSemver(version) {
|
|
42482
|
+
return SEMVER_PATTERN.test(version.trim());
|
|
42483
|
+
}
|
|
42484
|
+
function parseVersion(raw) {
|
|
42485
|
+
const withoutPrefix = raw.trim().replace(/^[vV=]+/, "");
|
|
42486
|
+
const [coreAndPre] = withoutPrefix.split("+");
|
|
42487
|
+
const [corePart, ...preParts] = coreAndPre.split("-");
|
|
42488
|
+
const core = corePart.split(".").map((part) => {
|
|
42489
|
+
const value = Number.parseInt(part, 10);
|
|
42490
|
+
return Number.isFinite(value) && value >= 0 ? value : 0;
|
|
42491
|
+
});
|
|
42492
|
+
while (core.length < 3) {
|
|
42493
|
+
core.push(0);
|
|
42494
|
+
}
|
|
42495
|
+
return {
|
|
42496
|
+
core: [core[0] ?? 0, core[1] ?? 0, core[2] ?? 0],
|
|
42497
|
+
prerelease: preParts.length > 0 ? preParts.join("-").split(".").filter(Boolean) : []
|
|
42498
|
+
};
|
|
42499
|
+
}
|
|
42500
|
+
function comparePrerelease(left, right) {
|
|
42501
|
+
if (left.length === 0 && right.length === 0) {
|
|
42502
|
+
return 0;
|
|
42503
|
+
}
|
|
42504
|
+
if (left.length === 0) {
|
|
42505
|
+
return 1;
|
|
42506
|
+
}
|
|
42507
|
+
if (right.length === 0) {
|
|
42508
|
+
return -1;
|
|
42509
|
+
}
|
|
42510
|
+
const length = Math.max(left.length, right.length);
|
|
42511
|
+
for (let index = 0; index < length; index += 1) {
|
|
42512
|
+
const a = left[index];
|
|
42513
|
+
const b = right[index];
|
|
42514
|
+
if (a === void 0) {
|
|
42515
|
+
return -1;
|
|
42516
|
+
}
|
|
42517
|
+
if (b === void 0) {
|
|
42518
|
+
return 1;
|
|
42519
|
+
}
|
|
42520
|
+
const aNumeric = /^\d+$/.test(a);
|
|
42521
|
+
const bNumeric = /^\d+$/.test(b);
|
|
42522
|
+
if (aNumeric && bNumeric) {
|
|
42523
|
+
const diff = Number(a) - Number(b);
|
|
42524
|
+
if (diff !== 0) {
|
|
42525
|
+
return diff < 0 ? -1 : 1;
|
|
42526
|
+
}
|
|
42527
|
+
continue;
|
|
42528
|
+
}
|
|
42529
|
+
if (aNumeric !== bNumeric) {
|
|
42530
|
+
return aNumeric ? -1 : 1;
|
|
42531
|
+
}
|
|
42532
|
+
if (a !== b) {
|
|
42533
|
+
return a < b ? -1 : 1;
|
|
42534
|
+
}
|
|
42535
|
+
}
|
|
42536
|
+
return 0;
|
|
42537
|
+
}
|
|
42538
|
+
function compareVersions(a, b) {
|
|
42539
|
+
const left = parseVersion(a);
|
|
42540
|
+
const right = parseVersion(b);
|
|
42541
|
+
for (let index = 0; index < 3; index += 1) {
|
|
42542
|
+
if (left.core[index] !== right.core[index]) {
|
|
42543
|
+
return left.core[index] < right.core[index] ? -1 : 1;
|
|
42544
|
+
}
|
|
42545
|
+
}
|
|
42546
|
+
return comparePrerelease(left.prerelease, right.prerelease);
|
|
42547
|
+
}
|
|
42548
|
+
function isNewerVersion(latest, current) {
|
|
42549
|
+
if (!isSemver(latest) || !isSemver(current)) {
|
|
42550
|
+
return false;
|
|
42551
|
+
}
|
|
42552
|
+
return compareVersions(latest, current) > 0;
|
|
42553
|
+
}
|
|
42554
|
+
function parseLatestVersion(payload) {
|
|
42555
|
+
if (payload === null || typeof payload !== "object") {
|
|
42556
|
+
return null;
|
|
42557
|
+
}
|
|
42558
|
+
const record = payload;
|
|
42559
|
+
for (const candidate of [record.version, record["dist-tags"]?.latest]) {
|
|
42560
|
+
if (typeof candidate === "string" && isSemver(candidate)) {
|
|
42561
|
+
return candidate.trim();
|
|
42562
|
+
}
|
|
42563
|
+
}
|
|
42564
|
+
return null;
|
|
42565
|
+
}
|
|
42566
|
+
|
|
42567
|
+
// src/cli/updateCheck.ts
|
|
42568
|
+
var DEFAULT_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
42569
|
+
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
42570
|
+
var DEFAULT_REGISTRY_URL = "https://registry.npmjs.org";
|
|
42571
|
+
var UPDATE_CHECK_CACHE_FILE = "update-check.json";
|
|
42572
|
+
var SKIP_UPDATE_CHECK_ENV = "MINI_PI_SKIP_UPDATE_CHECK";
|
|
42573
|
+
function isCacheFresh(checkedAt, now, maxAgeMs) {
|
|
42574
|
+
if (!Number.isFinite(checkedAt) || !Number.isFinite(now)) {
|
|
42575
|
+
return false;
|
|
42576
|
+
}
|
|
42577
|
+
if (checkedAt > now) {
|
|
42578
|
+
return false;
|
|
42579
|
+
}
|
|
42580
|
+
return now - checkedAt < maxAgeMs;
|
|
42581
|
+
}
|
|
42582
|
+
async function checkForUpdate(input) {
|
|
42583
|
+
const { current } = input;
|
|
42584
|
+
if (!input.enabled) {
|
|
42585
|
+
return { status: "disabled" };
|
|
42586
|
+
}
|
|
42587
|
+
const now = (input.now ?? Date.now)();
|
|
42588
|
+
const maxAgeMs = input.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
|
|
42589
|
+
let latest = null;
|
|
42590
|
+
if (!input.force) {
|
|
42591
|
+
const cache = await input.readCache();
|
|
42592
|
+
if (cache && isCacheFresh(cache.checkedAt, now, maxAgeMs)) {
|
|
42593
|
+
latest = cache.latestVersion;
|
|
42594
|
+
}
|
|
42595
|
+
}
|
|
42596
|
+
if (latest === null) {
|
|
42597
|
+
latest = await input.fetchLatest();
|
|
42598
|
+
if (latest !== null) {
|
|
42599
|
+
try {
|
|
42600
|
+
await input.writeCache({ checkedAt: now, latestVersion: latest });
|
|
42601
|
+
} catch {
|
|
42602
|
+
}
|
|
42603
|
+
}
|
|
42604
|
+
}
|
|
42605
|
+
if (latest === null) {
|
|
42606
|
+
return {
|
|
42607
|
+
status: "check-failed",
|
|
42608
|
+
current,
|
|
42609
|
+
reason: "\u65E0\u6CD5\u83B7\u53D6\u6700\u65B0\u7248\u672C\u53F7\uFF08\u7F51\u7EDC\u4E0D\u53EF\u8FBE\u6216\u8BF7\u6C42\u8D85\u65F6\uFF09"
|
|
42610
|
+
};
|
|
42611
|
+
}
|
|
42612
|
+
return isNewerVersion(latest, current) ? { status: "update-available", current, latest } : { status: "up-to-date", current, latest };
|
|
42613
|
+
}
|
|
42614
|
+
async function readCacheFile(cachePath) {
|
|
42615
|
+
try {
|
|
42616
|
+
const content = await (0, import_promises7.readFile)(cachePath, "utf-8");
|
|
42617
|
+
const data = JSON.parse(content);
|
|
42618
|
+
if (data === null || typeof data !== "object") {
|
|
42619
|
+
return null;
|
|
42620
|
+
}
|
|
42621
|
+
const record = data;
|
|
42622
|
+
if (typeof record.checkedAt !== "number" || !Number.isFinite(record.checkedAt) || typeof record.latestVersion !== "string" || record.latestVersion.length === 0) {
|
|
42623
|
+
return null;
|
|
42624
|
+
}
|
|
42625
|
+
return { checkedAt: record.checkedAt, latestVersion: record.latestVersion };
|
|
42626
|
+
} catch {
|
|
42627
|
+
return null;
|
|
42628
|
+
}
|
|
42629
|
+
}
|
|
42630
|
+
async function writeCacheFile(cachePath, cache) {
|
|
42631
|
+
try {
|
|
42632
|
+
await (0, import_promises7.mkdir)((0, import_node_path10.join)(cachePath, ".."), { recursive: true });
|
|
42633
|
+
await (0, import_promises7.writeFile)(cachePath, JSON.stringify(cache), "utf-8");
|
|
42634
|
+
} catch {
|
|
42635
|
+
}
|
|
42636
|
+
}
|
|
42637
|
+
function createRegistryFetcher(input) {
|
|
42638
|
+
const url = `${input.registryUrl.replace(/\/+$/, "")}/${input.packageName}/latest`;
|
|
42639
|
+
return async () => {
|
|
42640
|
+
try {
|
|
42641
|
+
const response = await input.fetchImpl(url, {
|
|
42642
|
+
signal: AbortSignal.timeout(input.timeoutMs)
|
|
42643
|
+
});
|
|
42644
|
+
if (!response.ok) {
|
|
42645
|
+
return null;
|
|
42646
|
+
}
|
|
42647
|
+
return parseLatestVersion(await response.json());
|
|
42648
|
+
} catch {
|
|
42649
|
+
return null;
|
|
42650
|
+
}
|
|
42651
|
+
};
|
|
42652
|
+
}
|
|
42653
|
+
function createUpdateChecker(overrides = {}) {
|
|
42654
|
+
const current = overrides.current ?? APP_VERSION;
|
|
42655
|
+
const packageName = overrides.packageName ?? PACKAGE_NAME;
|
|
42656
|
+
const cachePath = overrides.cachePath ?? (0, import_node_path10.join)((0, import_node_os4.homedir)(), ".mini-pi", UPDATE_CHECK_CACHE_FILE);
|
|
42657
|
+
const registryUrl = overrides.registryUrl ?? overrides.env?.npm_config_registry ?? DEFAULT_REGISTRY_URL;
|
|
42658
|
+
const timeoutMs = overrides.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
42659
|
+
const maxAgeMs = overrides.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
|
|
42660
|
+
const fetchImpl = overrides.fetchImpl ?? ((url, init) => fetch(url, init));
|
|
42661
|
+
const now = overrides.now ?? Date.now;
|
|
42662
|
+
const isInteractive = overrides.isInteractive ?? Boolean(process.stdout.isTTY);
|
|
42663
|
+
const env2 = overrides.env ?? process.env;
|
|
42664
|
+
const settingsStore = overrides.settingsStore;
|
|
42665
|
+
const fetchLatest = createRegistryFetcher({
|
|
42666
|
+
registryUrl,
|
|
42667
|
+
packageName,
|
|
42668
|
+
timeoutMs,
|
|
42669
|
+
fetchImpl
|
|
42670
|
+
});
|
|
42671
|
+
const readCache = () => readCacheFile(cachePath);
|
|
42672
|
+
const writeCache = (cache) => writeCacheFile(cachePath, cache);
|
|
42673
|
+
const runCheck = (force) => checkForUpdate({
|
|
42674
|
+
current,
|
|
42675
|
+
// 开关判定在 checkOnStartup 里做;走到这里必然是"该查"
|
|
42676
|
+
enabled: true,
|
|
42677
|
+
force,
|
|
42678
|
+
fetchLatest,
|
|
42679
|
+
readCache,
|
|
42680
|
+
writeCache,
|
|
42681
|
+
now,
|
|
42682
|
+
maxAgeMs
|
|
42683
|
+
});
|
|
42684
|
+
return {
|
|
42685
|
+
async checkOnStartup() {
|
|
42686
|
+
if (!isInteractive) {
|
|
42687
|
+
return { status: "skipped" };
|
|
42688
|
+
}
|
|
42689
|
+
if (env2[SKIP_UPDATE_CHECK_ENV]) {
|
|
42690
|
+
return { status: "disabled" };
|
|
42691
|
+
}
|
|
42692
|
+
if (settingsStore && !await settingsStore.getUpdateCheckEnabled()) {
|
|
42693
|
+
return { status: "disabled" };
|
|
42694
|
+
}
|
|
42695
|
+
return runCheck(false);
|
|
42696
|
+
},
|
|
42697
|
+
checkNow: () => runCheck(true),
|
|
42698
|
+
async isEnabled() {
|
|
42699
|
+
if (env2[SKIP_UPDATE_CHECK_ENV]) {
|
|
42700
|
+
return false;
|
|
42701
|
+
}
|
|
42702
|
+
if (!settingsStore) {
|
|
42703
|
+
return true;
|
|
42704
|
+
}
|
|
42705
|
+
return settingsStore.getUpdateCheckEnabled();
|
|
42706
|
+
},
|
|
42707
|
+
async setEnabled(enabled) {
|
|
42708
|
+
if (!settingsStore) {
|
|
42709
|
+
throw new Error("settings \u672A\u914D\u7F6E\uFF0C\u65E0\u6CD5\u6301\u4E45\u5316\u66F4\u65B0\u68C0\u6D4B\u5F00\u5173");
|
|
42710
|
+
}
|
|
42711
|
+
await settingsStore.setUpdateCheckEnabled(enabled);
|
|
42712
|
+
}
|
|
42713
|
+
};
|
|
42714
|
+
}
|
|
42715
|
+
function updateNoticeLines(current, latest, packageName = PACKAGE_NAME) {
|
|
42716
|
+
return [
|
|
42717
|
+
`\u2B06\uFE0F \u53D1\u73B0\u65B0\u7248\u672C ${formatVersion(latest)}\uFF08\u5F53\u524D ${formatVersion(current)}\uFF09`,
|
|
42718
|
+
` \u66F4\u65B0\u547D\u4EE4\uFF1Anpm install -g ${packageName}`
|
|
42719
|
+
];
|
|
42720
|
+
}
|
|
42721
|
+
function printCheckResult(result) {
|
|
42722
|
+
switch (result.status) {
|
|
42723
|
+
case "update-available": {
|
|
42724
|
+
const [headline, command] = updateNoticeLines(
|
|
42725
|
+
result.current,
|
|
42726
|
+
result.latest,
|
|
42727
|
+
PACKAGE_NAME
|
|
42728
|
+
);
|
|
42729
|
+
console.log();
|
|
42730
|
+
console.log(source_default.yellow(headline));
|
|
42731
|
+
console.log(source_default.dim(command));
|
|
42732
|
+
console.log();
|
|
42733
|
+
return;
|
|
42734
|
+
}
|
|
42735
|
+
case "up-to-date":
|
|
42736
|
+
console.log(
|
|
42737
|
+
source_default.green(`
|
|
42738
|
+
\u2705 \u5DF2\u662F\u6700\u65B0\u7248\u672C\uFF08${formatVersion(result.current)}\uFF09
|
|
42739
|
+
`)
|
|
42740
|
+
);
|
|
42741
|
+
return;
|
|
42742
|
+
case "check-failed":
|
|
42743
|
+
console.log(source_default.yellow(`
|
|
42744
|
+
\u26A0\uFE0F \u68C0\u67E5\u5931\u8D25\uFF1A${result.reason}
|
|
42745
|
+
`));
|
|
42746
|
+
return;
|
|
42747
|
+
case "disabled":
|
|
42748
|
+
console.log(source_default.dim("\n\u{1F6AB} \u542F\u52A8\u68C0\u6D4B\u5DF2\u5173\u95ED\uFF08/update on \u91CD\u65B0\u5F00\u542F\uFF09\n"));
|
|
42749
|
+
return;
|
|
42750
|
+
case "skipped":
|
|
42751
|
+
console.log(source_default.dim("\n\u2139\uFE0F \u975E\u4EA4\u4E92\u7EC8\u7AEF\uFF0C\u8DF3\u8FC7\u66F4\u65B0\u68C0\u6D4B\n"));
|
|
42752
|
+
return;
|
|
42753
|
+
}
|
|
42754
|
+
}
|
|
42755
|
+
function printUpdateNotice(result) {
|
|
42756
|
+
if (result.status !== "update-available") {
|
|
42757
|
+
return;
|
|
42758
|
+
}
|
|
42759
|
+
printCheckResult(result);
|
|
42760
|
+
}
|
|
42761
|
+
var UPDATE_ON_WORDS = ["on", "\u5F00", "\u5F00\u542F", "\u6253\u5F00", "true", "enable"];
|
|
42762
|
+
var UPDATE_OFF_WORDS = ["off", "\u5173", "\u5173\u95ED", "false", "disable"];
|
|
42763
|
+
function parseUpdateCommand(argument) {
|
|
42764
|
+
const raw = argument.trim();
|
|
42765
|
+
if (!raw) {
|
|
42766
|
+
return { kind: "check" };
|
|
42767
|
+
}
|
|
42768
|
+
const word = raw.toLowerCase();
|
|
42769
|
+
if (UPDATE_ON_WORDS.includes(word)) {
|
|
42770
|
+
return { kind: "set", enabled: true };
|
|
42771
|
+
}
|
|
42772
|
+
if (UPDATE_OFF_WORDS.includes(word)) {
|
|
42773
|
+
return { kind: "set", enabled: false };
|
|
42774
|
+
}
|
|
42775
|
+
return { kind: "unknown", raw };
|
|
42776
|
+
}
|
|
42777
|
+
async function applyUpdateCommand(input) {
|
|
42778
|
+
const command = parseUpdateCommand(input.argument);
|
|
42779
|
+
if (command.kind === "unknown") {
|
|
42780
|
+
return {
|
|
42781
|
+
kind: "error",
|
|
42782
|
+
message: `\u65E0\u6CD5\u8BC6\u522B\u7684\u53C2\u6570\uFF1A${command.raw}\u3002\u7528\u6CD5\uFF1A/update [on|off]\uFF08\u4E0D\u5E26\u53C2\u6570\u5219\u7ACB\u5373\u68C0\u67E5\uFF09`
|
|
42783
|
+
};
|
|
42784
|
+
}
|
|
42785
|
+
if (command.kind === "set") {
|
|
42786
|
+
if (!input.persist) {
|
|
42787
|
+
return { kind: "error", message: "\u66F4\u65B0\u68C0\u6D4B\u672A\u914D\u7F6E\uFF0C\u65E0\u6CD5\u6301\u4E45\u5316\u5F00\u5173" };
|
|
42788
|
+
}
|
|
42789
|
+
try {
|
|
42790
|
+
await input.persist(command.enabled);
|
|
42791
|
+
} catch {
|
|
42792
|
+
return { kind: "toggle", enabled: command.enabled, persistFailed: true };
|
|
42793
|
+
}
|
|
42794
|
+
return { kind: "toggle", enabled: command.enabled };
|
|
42795
|
+
}
|
|
42796
|
+
if (!input.check) {
|
|
42797
|
+
return { kind: "error", message: "\u66F4\u65B0\u68C0\u6D4B\u672A\u914D\u7F6E" };
|
|
42798
|
+
}
|
|
42799
|
+
return { kind: "check", result: await input.check() };
|
|
42800
|
+
}
|
|
42801
|
+
function printUpdateOutcome(outcome, previous) {
|
|
42802
|
+
if (outcome.kind === "error") {
|
|
42803
|
+
console.log(source_default.red(`
|
|
42804
|
+
\u274C ${outcome.message}
|
|
42805
|
+
`));
|
|
42806
|
+
return;
|
|
42807
|
+
}
|
|
42808
|
+
if (outcome.kind === "toggle") {
|
|
42809
|
+
if (outcome.enabled === previous) {
|
|
42810
|
+
console.log(
|
|
42811
|
+
source_default.dim(
|
|
42812
|
+
outcome.enabled ? "\n\u{1F91D} \u542F\u52A8\u68C0\u6D4B\u5DF2\u7ECF\u662F\u5F00\u542F\u72B6\u6001\n" : "\n\u{1F91D} \u542F\u52A8\u68C0\u6D4B\u5DF2\u7ECF\u662F\u5173\u95ED\u72B6\u6001\n"
|
|
42813
|
+
)
|
|
42814
|
+
);
|
|
42815
|
+
} else {
|
|
42816
|
+
console.log(
|
|
42817
|
+
outcome.enabled ? source_default.green("\n\u2705 \u5DF2\u5F00\u542F\u542F\u52A8\u65F6\u7684\u7248\u672C\u66F4\u65B0\u68C0\u6D4B\n") : source_default.yellow(
|
|
42818
|
+
"\n\u{1F6AB} \u5DF2\u5173\u95ED\u542F\u52A8\u65F6\u7684\u7248\u672C\u66F4\u65B0\u68C0\u6D4B\uFF08/update on \u91CD\u65B0\u5F00\u542F\uFF09\n"
|
|
42819
|
+
)
|
|
42820
|
+
);
|
|
42821
|
+
}
|
|
42822
|
+
if (outcome.persistFailed) {
|
|
42823
|
+
console.log(
|
|
42824
|
+
source_default.red(
|
|
42825
|
+
"\u26A0\uFE0F \u5F00\u5173\u672A\u80FD\u5199\u5165 settings.json\uFF08\u6587\u4EF6\u4E0D\u53EF\u5199\uFF09\uFF0C\u91CD\u542F\u540E\u6062\u590D\u9ED8\u8BA4\n"
|
|
42826
|
+
)
|
|
42827
|
+
);
|
|
42828
|
+
}
|
|
42829
|
+
return;
|
|
42830
|
+
}
|
|
42831
|
+
printCheckResult(outcome.result);
|
|
42832
|
+
}
|
|
42833
|
+
|
|
42303
42834
|
// src/cli/dispatch.ts
|
|
42304
42835
|
async function handleSlashCommand(input, ctx) {
|
|
42305
42836
|
const { options, rl } = ctx;
|
|
@@ -42393,9 +42924,12 @@ async function handleSlashCommand(input, ctx) {
|
|
|
42393
42924
|
if (input === "/reload") {
|
|
42394
42925
|
if (options.onReload) {
|
|
42395
42926
|
try {
|
|
42396
|
-
const { model, systemPrompt, contextWindow, contextWindowSource } = await options.onReload();
|
|
42927
|
+
const { model, systemPrompt, baseSystemPrompt, contextWindow, contextWindowSource } = await options.onReload();
|
|
42397
42928
|
options.model = model;
|
|
42398
42929
|
options.systemPrompt = systemPrompt;
|
|
42930
|
+
if (baseSystemPrompt !== void 0) {
|
|
42931
|
+
options.baseSystemPrompt = baseSystemPrompt;
|
|
42932
|
+
}
|
|
42399
42933
|
if (contextWindow !== void 0) {
|
|
42400
42934
|
options.contextWindow = contextWindow;
|
|
42401
42935
|
options.contextWindowSource = contextWindowSource ?? "configured";
|
|
@@ -42441,6 +42975,19 @@ async function handleSlashCommand(input, ctx) {
|
|
|
42441
42975
|
}
|
|
42442
42976
|
return true;
|
|
42443
42977
|
}
|
|
42978
|
+
if (input === "/update" || input.startsWith("/update ")) {
|
|
42979
|
+
const checker = ctx.options.updateChecker;
|
|
42980
|
+
const enabled = checker ? await checker.isEnabled() : false;
|
|
42981
|
+
const outcome = await applyUpdateCommand({
|
|
42982
|
+
argument: input.slice("/update".length).trim(),
|
|
42983
|
+
enabled,
|
|
42984
|
+
persist: checker ? (value) => checker.setEnabled(value) : void 0,
|
|
42985
|
+
// 手动检查忽略开关与缓存:用户显式敲了命令,就没有"已关闭"可言
|
|
42986
|
+
check: checker ? () => checker.checkNow() : void 0
|
|
42987
|
+
});
|
|
42988
|
+
printUpdateOutcome(outcome, enabled);
|
|
42989
|
+
return true;
|
|
42990
|
+
}
|
|
42444
42991
|
return false;
|
|
42445
42992
|
}
|
|
42446
42993
|
|
|
@@ -42520,15 +43067,21 @@ var LOGO_LINES = [
|
|
|
42520
43067
|
" \u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551",
|
|
42521
43068
|
" \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D"
|
|
42522
43069
|
];
|
|
42523
|
-
function printLogo(width = process.stdout.columns ?? DEFAULT_TERMINAL_WIDTH) {
|
|
43070
|
+
function printLogo(width = process.stdout.columns ?? DEFAULT_TERMINAL_WIDTH, version = APP_VERSION) {
|
|
43071
|
+
const stamp = source_default.dim(` ${formatVersion(version)}`);
|
|
42524
43072
|
if (width < MIN_LOGO_WIDTH) {
|
|
42525
43073
|
console.log(source_default.cyan(" mini-pi"));
|
|
43074
|
+
console.log(stamp);
|
|
42526
43075
|
return;
|
|
42527
43076
|
}
|
|
42528
43077
|
console.log("");
|
|
42529
43078
|
for (const line of LOGO_LINES) {
|
|
42530
43079
|
console.log(source_default.cyan(line));
|
|
42531
43080
|
}
|
|
43081
|
+
console.log(stamp);
|
|
43082
|
+
}
|
|
43083
|
+
function printVersion(version = APP_VERSION) {
|
|
43084
|
+
console.log(`mini-pi ${formatVersion(version)}`);
|
|
42532
43085
|
}
|
|
42533
43086
|
function printWelcome(providerName, modelName, contextWindow) {
|
|
42534
43087
|
const rule = () => printSeparator();
|
|
@@ -42855,7 +43408,6 @@ async function startRepl(options) {
|
|
|
42855
43408
|
rl.prompt();
|
|
42856
43409
|
return;
|
|
42857
43410
|
}
|
|
42858
|
-
checkSkillMatch(options.sessionManager, input);
|
|
42859
43411
|
if (!options.model) {
|
|
42860
43412
|
console.log(source_default.yellow("\u26A0\uFE0F \u5C1A\u672A\u914D\u7F6E\u6A21\u578B\uFF0C\u8BF7\u4F7F\u7528 /login \u548C /model \u547D\u4EE4\u8FDB\u884C\u914D\u7F6E"));
|
|
42861
43413
|
rl.prompt();
|
|
@@ -42993,7 +43545,7 @@ ${projectStack}` : "",
|
|
|
42993
43545
|
|
|
42994
43546
|
// src/cli/projectStack.ts
|
|
42995
43547
|
var import_node_fs7 = require("node:fs");
|
|
42996
|
-
var
|
|
43548
|
+
var import_node_path11 = require("node:path");
|
|
42997
43549
|
function emptyStack() {
|
|
42998
43550
|
return { frameworks: [], commands: [] };
|
|
42999
43551
|
}
|
|
@@ -43052,26 +43604,26 @@ function detectPackageManager(root, pkg) {
|
|
|
43052
43604
|
["package-lock.json", "npm"]
|
|
43053
43605
|
];
|
|
43054
43606
|
for (const [file, manager] of locks) {
|
|
43055
|
-
if ((0, import_node_fs7.existsSync)((0,
|
|
43607
|
+
if ((0, import_node_fs7.existsSync)((0, import_node_path11.join)(root, file))) {
|
|
43056
43608
|
return manager;
|
|
43057
43609
|
}
|
|
43058
43610
|
}
|
|
43059
|
-
const
|
|
43060
|
-
if (!
|
|
43611
|
+
const declared2 = str(pkg, "packageManager");
|
|
43612
|
+
if (!declared2) {
|
|
43061
43613
|
return void 0;
|
|
43062
43614
|
}
|
|
43063
|
-
const at =
|
|
43064
|
-
const name = at > 0 ?
|
|
43615
|
+
const at = declared2.indexOf("@");
|
|
43616
|
+
const name = at > 0 ? declared2.slice(0, at) : declared2;
|
|
43065
43617
|
return name === "" ? void 0 : name;
|
|
43066
43618
|
}
|
|
43067
43619
|
function detectProjectStack(workspaceRoot) {
|
|
43068
|
-
const pkg = readJson((0,
|
|
43620
|
+
const pkg = readJson((0, import_node_path11.join)(workspaceRoot, "package.json"));
|
|
43069
43621
|
if (pkg) {
|
|
43070
43622
|
const dependencies = [...keys(pkg, "dependencies"), ...keys(pkg, "devDependencies")];
|
|
43071
43623
|
const packageManager = detectPackageManager(workspaceRoot, pkg);
|
|
43072
43624
|
const runPrefix = packageManager && packageManager !== "npm" ? packageManager : "npm run";
|
|
43073
43625
|
const scripts = keys(pkg, "scripts");
|
|
43074
|
-
const typescript = (0, import_node_fs7.existsSync)((0,
|
|
43626
|
+
const typescript = (0, import_node_fs7.existsSync)((0, import_node_path11.join)(workspaceRoot, "tsconfig.json")) || dependencies.includes("typescript");
|
|
43075
43627
|
const nodeRange = str(pkg["engines"], "node");
|
|
43076
43628
|
return {
|
|
43077
43629
|
...str(pkg, "name") ? { name: str(pkg, "name") } : {},
|
|
@@ -43080,7 +43632,7 @@ function detectProjectStack(workspaceRoot) {
|
|
|
43080
43632
|
...packageManager ? { packageManager } : {},
|
|
43081
43633
|
...nodeRange ? { runtime: `node ${nodeRange}` } : {},
|
|
43082
43634
|
typescript,
|
|
43083
|
-
git: (0, import_node_fs7.existsSync)((0,
|
|
43635
|
+
git: (0, import_node_fs7.existsSync)((0, import_node_path11.join)(workspaceRoot, ".git")),
|
|
43084
43636
|
frameworks: FRAMEWORK_HINTS.filter(([dep]) => dependencies.includes(dep)).map(
|
|
43085
43637
|
([, label]) => label
|
|
43086
43638
|
),
|
|
@@ -43096,8 +43648,8 @@ function detectProjectStack(workspaceRoot) {
|
|
|
43096
43648
|
["Cargo.toml", "Rust", ["cargo build", "cargo test"]]
|
|
43097
43649
|
];
|
|
43098
43650
|
for (const [file, language, commands] of otherLanguages) {
|
|
43099
|
-
if ((0, import_node_fs7.existsSync)((0,
|
|
43100
|
-
return { ...emptyStack(), language, commands, git: (0, import_node_fs7.existsSync)((0,
|
|
43651
|
+
if ((0, import_node_fs7.existsSync)((0, import_node_path11.join)(workspaceRoot, file))) {
|
|
43652
|
+
return { ...emptyStack(), language, commands, git: (0, import_node_fs7.existsSync)((0, import_node_path11.join)(workspaceRoot, ".git")) };
|
|
43101
43653
|
}
|
|
43102
43654
|
}
|
|
43103
43655
|
return emptyStack();
|
|
@@ -43143,29 +43695,62 @@ function formatProjectStack(stack) {
|
|
|
43143
43695
|
// src/agent/sessionManager.ts
|
|
43144
43696
|
var import_node_crypto2 = require("node:crypto");
|
|
43145
43697
|
var import_node_fs9 = require("node:fs");
|
|
43146
|
-
var
|
|
43147
|
-
var
|
|
43698
|
+
var import_node_path13 = require("node:path");
|
|
43699
|
+
var import_node_os6 = require("node:os");
|
|
43148
43700
|
|
|
43149
43701
|
// src/agent/skillLoader.ts
|
|
43150
43702
|
var import_node_fs8 = require("node:fs");
|
|
43151
|
-
var
|
|
43152
|
-
var
|
|
43703
|
+
var import_node_path12 = require("node:path");
|
|
43704
|
+
var import_node_os5 = require("node:os");
|
|
43705
|
+
|
|
43706
|
+
// src/agent/skillFrontmatter.ts
|
|
43707
|
+
var FRONTMATTER_RE = /^\uFEFF?---\s*\r?\n([\s\S]*?)\r?\n---/;
|
|
43153
43708
|
function parseFrontmatter(content) {
|
|
43154
|
-
const
|
|
43155
|
-
if (!
|
|
43709
|
+
const match = FRONTMATTER_RE.exec(content);
|
|
43710
|
+
if (!match) {
|
|
43156
43711
|
return null;
|
|
43157
43712
|
}
|
|
43158
|
-
const
|
|
43159
|
-
|
|
43160
|
-
const descMatch = frontmatter.match(/^description:\s*(.+)$/m);
|
|
43161
|
-
if (!nameMatch) {
|
|
43713
|
+
const name = readField(match[1], "name");
|
|
43714
|
+
if (!name) {
|
|
43162
43715
|
return null;
|
|
43163
43716
|
}
|
|
43164
43717
|
return {
|
|
43165
|
-
name
|
|
43166
|
-
description:
|
|
43718
|
+
name,
|
|
43719
|
+
description: readField(match[1], "description") ?? ""
|
|
43167
43720
|
};
|
|
43168
43721
|
}
|
|
43722
|
+
function readField(block, key) {
|
|
43723
|
+
const lines = block.split(/\r?\n/);
|
|
43724
|
+
const keyPattern = new RegExp(`^${key}\\s*:`);
|
|
43725
|
+
const start = lines.findIndex((line) => keyPattern.test(line));
|
|
43726
|
+
if (start < 0) {
|
|
43727
|
+
return null;
|
|
43728
|
+
}
|
|
43729
|
+
const rawValue = lines[start].slice(lines[start].indexOf(":") + 1).trim();
|
|
43730
|
+
const isBlockScalar = /^[>|]/.test(rawValue);
|
|
43731
|
+
const parts = isBlockScalar ? [] : [rawValue];
|
|
43732
|
+
for (let i = start + 1; i < lines.length; i++) {
|
|
43733
|
+
const line = lines[i];
|
|
43734
|
+
if (!/^\s+\S/.test(line)) break;
|
|
43735
|
+
if (/^\s*[\w.-]+\s*:/.test(line)) break;
|
|
43736
|
+
parts.push(line.trim());
|
|
43737
|
+
}
|
|
43738
|
+
const value = parts.join(" ").trim();
|
|
43739
|
+
return value === "" ? null : stripQuotes(value);
|
|
43740
|
+
}
|
|
43741
|
+
function stripQuotes(value) {
|
|
43742
|
+
if (value.length < 2) {
|
|
43743
|
+
return value;
|
|
43744
|
+
}
|
|
43745
|
+
const first = value[0];
|
|
43746
|
+
const last = value[value.length - 1];
|
|
43747
|
+
if (first === '"' && last === '"' || first === "'" && last === "'") {
|
|
43748
|
+
return value.slice(1, -1);
|
|
43749
|
+
}
|
|
43750
|
+
return value;
|
|
43751
|
+
}
|
|
43752
|
+
|
|
43753
|
+
// src/agent/skillLoader.ts
|
|
43169
43754
|
var SkillLoader = class {
|
|
43170
43755
|
skillDirs;
|
|
43171
43756
|
metadataCache = null;
|
|
@@ -43180,11 +43765,11 @@ var SkillLoader = class {
|
|
|
43180
43765
|
this.skillDirs = customDirs;
|
|
43181
43766
|
} else {
|
|
43182
43767
|
this.skillDirs = [
|
|
43183
|
-
{ path: (0,
|
|
43184
|
-
{ path: (0,
|
|
43185
|
-
{ path: (0,
|
|
43186
|
-
{ path: (0,
|
|
43187
|
-
{ path: (0,
|
|
43768
|
+
{ path: (0, import_node_path12.join)((0, import_node_os5.homedir)(), ".agents", "skills"), source: "global-agents" },
|
|
43769
|
+
{ path: (0, import_node_path12.join)((0, import_node_os5.homedir)(), ".mini-pi", "skills"), source: "global-mini-pi" },
|
|
43770
|
+
{ path: (0, import_node_path12.join)(workspaceRoot, ".mini-pi", "skills"), source: "project" },
|
|
43771
|
+
{ path: (0, import_node_path12.join)(workspaceRoot, ".pi", "skills"), source: "project" },
|
|
43772
|
+
{ path: (0, import_node_path12.join)(workspaceRoot, ".agents", "skills"), source: "project" }
|
|
43188
43773
|
];
|
|
43189
43774
|
}
|
|
43190
43775
|
}
|
|
@@ -43206,8 +43791,8 @@ var SkillLoader = class {
|
|
|
43206
43791
|
const entries = (0, import_node_fs8.readdirSync)(dirPath, { withFileTypes: true });
|
|
43207
43792
|
for (const entry of entries) {
|
|
43208
43793
|
if (!entry.isDirectory()) continue;
|
|
43209
|
-
const skillDir = (0,
|
|
43210
|
-
const skillFile = (0,
|
|
43794
|
+
const skillDir = (0, import_node_path12.join)(dirPath, entry.name);
|
|
43795
|
+
const skillFile = (0, import_node_path12.join)(skillDir, "SKILL.md");
|
|
43211
43796
|
if (!(0, import_node_fs8.existsSync)(skillFile)) continue;
|
|
43212
43797
|
try {
|
|
43213
43798
|
const content = (0, import_node_fs8.readFileSync)(skillFile, "utf8");
|
|
@@ -43220,6 +43805,10 @@ var SkillLoader = class {
|
|
|
43220
43805
|
skillFile,
|
|
43221
43806
|
source
|
|
43222
43807
|
});
|
|
43808
|
+
} else {
|
|
43809
|
+
logger.warn(
|
|
43810
|
+
`\u8DF3\u8FC7\u65E0\u6CD5\u89E3\u6790\u7684 skill\uFF1A${skillFile}\uFF08\u7F3A\u5C11 name \u5B57\u6BB5\u6216 frontmatter \u683C\u5F0F\u4E0D\u53D7\u652F\u6301\uFF09`
|
|
43811
|
+
);
|
|
43223
43812
|
}
|
|
43224
43813
|
} catch (error) {
|
|
43225
43814
|
logger.warn(`Failed to read skill ${skillFile}:`, error);
|
|
@@ -43274,37 +43863,6 @@ var SkillLoader = class {
|
|
|
43274
43863
|
return null;
|
|
43275
43864
|
}
|
|
43276
43865
|
}
|
|
43277
|
-
/**
|
|
43278
|
-
* 检查用户输入是否匹配某个 skill
|
|
43279
|
-
* 基于 skill 名称和描述中的关键词进行匹配
|
|
43280
|
-
*/
|
|
43281
|
-
findMatchingSkills(userInput) {
|
|
43282
|
-
const metadata = this.loadAllMetadata();
|
|
43283
|
-
const inputLower = userInput.toLowerCase();
|
|
43284
|
-
const matches = [];
|
|
43285
|
-
for (const skill of metadata) {
|
|
43286
|
-
let score = 0;
|
|
43287
|
-
if (inputLower.includes(skill.name.toLowerCase())) {
|
|
43288
|
-
score += 100;
|
|
43289
|
-
}
|
|
43290
|
-
const nameWords = skill.name.toLowerCase().split(/[-_\s]+/);
|
|
43291
|
-
for (const word of nameWords) {
|
|
43292
|
-
if (word.length > 2 && inputLower.includes(word)) {
|
|
43293
|
-
score += 30;
|
|
43294
|
-
}
|
|
43295
|
-
}
|
|
43296
|
-
const descWords = skill.description.toLowerCase().split(/\s+/);
|
|
43297
|
-
for (const word of descWords) {
|
|
43298
|
-
if (word.length > 3 && inputLower.includes(word)) {
|
|
43299
|
-
score += 5;
|
|
43300
|
-
}
|
|
43301
|
-
}
|
|
43302
|
-
if (score > 0) {
|
|
43303
|
-
matches.push({ skill, score });
|
|
43304
|
-
}
|
|
43305
|
-
}
|
|
43306
|
-
return matches.sort((a, b) => b.score - a.score).map((m) => m.skill);
|
|
43307
|
-
}
|
|
43308
43866
|
/**
|
|
43309
43867
|
* 清除缓存(用于重新加载)
|
|
43310
43868
|
*/
|
|
@@ -43314,7 +43872,9 @@ var SkillLoader = class {
|
|
|
43314
43872
|
}
|
|
43315
43873
|
/**
|
|
43316
43874
|
* 生成 skill 摘要列表(用于注入 system prompt)
|
|
43317
|
-
*
|
|
43875
|
+
*
|
|
43876
|
+
* 渐进式披露:系统提示词里只放轻量元数据,全文由模型通过 `load_skill`
|
|
43877
|
+
* 工具按需取用——每次请求的固定开销就只有这一份清单。
|
|
43318
43878
|
*/
|
|
43319
43879
|
generateSkillSummary() {
|
|
43320
43880
|
const metadata = this.loadAllMetadata();
|
|
@@ -43324,7 +43884,7 @@ var SkillLoader = class {
|
|
|
43324
43884
|
const lines = [
|
|
43325
43885
|
"## \u53EF\u7528 Skills",
|
|
43326
43886
|
"",
|
|
43327
|
-
"\u4EE5\u4E0B\u662F\u4F60\u53EF\u7528\u7684 skills\u3002\u5F53\u7528\u6237\u7684\u8BF7\u6C42\
|
|
43887
|
+
"\u4EE5\u4E0B\u662F\u4F60\u53EF\u7528\u7684 skills\u3002\u5F53\u7528\u6237\u7684\u8BF7\u6C42\u4E0E\u67D0\u4E2A skill \u76F8\u5173\u65F6\uFF0C\u4F60\u5E94\u8BE5\u52A0\u8F7D\u5E76\u53C2\u8003\u8BE5 skill \u7684\u5B8C\u6574\u5185\u5BB9\u6765\u6307\u5BFC\u4F60\u7684\u56DE\u7B54\u3002",
|
|
43328
43888
|
""
|
|
43329
43889
|
];
|
|
43330
43890
|
const bySource = /* @__PURE__ */ new Map();
|
|
@@ -43350,7 +43910,9 @@ var SkillLoader = class {
|
|
|
43350
43910
|
lines.push("");
|
|
43351
43911
|
}
|
|
43352
43912
|
lines.push("---");
|
|
43353
|
-
lines.push(
|
|
43913
|
+
lines.push(
|
|
43914
|
+
"\u5F53\u7528\u6237\u7684\u8BF7\u6C42\u4E0E\u67D0\u4E2A skill \u76F8\u5173\u65F6\uFF0C\u8C03\u7528 load_skill \u5DE5\u5177\u52A0\u8F7D\u5B83\u7684\u5B8C\u6574\u5185\u5BB9\uFF0C\u7136\u540E\u6309\u5176\u4E2D\u7684\u89C4\u5219\u6267\u884C\uFF1B\u4E0D\u8981\u8BE2\u95EE\u7528\u6237\uFF0C\u76F4\u63A5\u52A0\u8F7D\u3002"
|
|
43915
|
+
);
|
|
43354
43916
|
return lines.join("\n");
|
|
43355
43917
|
}
|
|
43356
43918
|
};
|
|
@@ -43360,14 +43922,14 @@ var WORKSPACE_MARKER = ".workspace-key";
|
|
|
43360
43922
|
var MAX_DIR_NAME_LENGTH = 120;
|
|
43361
43923
|
function absolutePath(workspaceRoot) {
|
|
43362
43924
|
try {
|
|
43363
|
-
return (0, import_node_fs9.realpathSync)((0,
|
|
43925
|
+
return (0, import_node_fs9.realpathSync)((0, import_node_path13.resolve)(workspaceRoot));
|
|
43364
43926
|
} catch {
|
|
43365
|
-
return (0,
|
|
43927
|
+
return (0, import_node_path13.resolve)(workspaceRoot);
|
|
43366
43928
|
}
|
|
43367
43929
|
}
|
|
43368
43930
|
function normalizeWorkspaceKey(workspaceRoot) {
|
|
43369
43931
|
const absolute = absolutePath(workspaceRoot);
|
|
43370
|
-
return (0,
|
|
43932
|
+
return (0, import_node_os6.platform)() === "win32" ? absolute.toLowerCase() : absolute;
|
|
43371
43933
|
}
|
|
43372
43934
|
function workspaceKeyHash(workspaceRoot) {
|
|
43373
43935
|
return (0, import_node_crypto2.createHash)("sha256").update(normalizeWorkspaceKey(workspaceRoot)).digest("hex").slice(0, 8);
|
|
@@ -43380,12 +43942,12 @@ function workspaceSessionDirName(workspaceRoot) {
|
|
|
43380
43942
|
var SessionManager = class {
|
|
43381
43943
|
constructor(workspaceRoot, options) {
|
|
43382
43944
|
this.workspaceRoot = workspaceRoot;
|
|
43383
|
-
this.sessionsDir = options?.sessionsDir ?? (0,
|
|
43945
|
+
this.sessionsDir = options?.sessionsDir ?? (0, import_node_path13.join)((0, import_node_os6.homedir)(), ".mini-pi", "sessions");
|
|
43384
43946
|
this.workspaceKey = normalizeWorkspaceKey(workspaceRoot);
|
|
43385
43947
|
this.projectSessionsDir = this.resolveProjectSessionsDir();
|
|
43386
|
-
this.globalAgentsPath = options?.globalAgentsPath ?? (0,
|
|
43387
|
-
this.projectAgentsPath = (0,
|
|
43388
|
-
this.skillLoader = new SkillLoader(workspaceRoot, options?.customSkillDirs);
|
|
43948
|
+
this.globalAgentsPath = options?.globalAgentsPath ?? (0, import_node_path13.join)((0, import_node_os6.homedir)(), ".mini-pi", "AGENTS.md");
|
|
43949
|
+
this.projectAgentsPath = (0, import_node_path13.join)(workspaceRoot, "AGENTS.md");
|
|
43950
|
+
this.skillLoader = options?.skillLoader ?? new SkillLoader(workspaceRoot, options?.customSkillDirs);
|
|
43389
43951
|
this.ensureSessionsDir();
|
|
43390
43952
|
}
|
|
43391
43953
|
sessionsDir;
|
|
@@ -43408,10 +43970,10 @@ var SessionManager = class {
|
|
|
43408
43970
|
*/
|
|
43409
43971
|
resolveProjectSessionsDir() {
|
|
43410
43972
|
const name = workspaceSessionDirName(this.workspaceRoot);
|
|
43411
|
-
const candidate = (0,
|
|
43973
|
+
const candidate = (0, import_node_path13.join)(this.sessionsDir, name);
|
|
43412
43974
|
const owner = this.readWorkspaceMarker(candidate);
|
|
43413
43975
|
if (owner !== null && owner !== this.workspaceKey) {
|
|
43414
|
-
return (0,
|
|
43976
|
+
return (0, import_node_path13.join)(
|
|
43415
43977
|
this.sessionsDir,
|
|
43416
43978
|
`${name}-${workspaceKeyHash(this.workspaceRoot)}`
|
|
43417
43979
|
);
|
|
@@ -43421,7 +43983,7 @@ var SessionManager = class {
|
|
|
43421
43983
|
/** 读目录下的归属标记;不存在或读不出时返回 null(视为"无人认领") */
|
|
43422
43984
|
readWorkspaceMarker(dir) {
|
|
43423
43985
|
try {
|
|
43424
|
-
const raw = (0, import_node_fs9.readFileSync)((0,
|
|
43986
|
+
const raw = (0, import_node_fs9.readFileSync)((0, import_node_path13.join)(dir, WORKSPACE_MARKER), "utf8").trim();
|
|
43425
43987
|
return raw.length > 0 ? raw : null;
|
|
43426
43988
|
} catch {
|
|
43427
43989
|
return null;
|
|
@@ -43454,7 +44016,7 @@ var SessionManager = class {
|
|
|
43454
44016
|
if (!(0, import_node_fs9.existsSync)(this.projectSessionsDir)) {
|
|
43455
44017
|
(0, import_node_fs9.mkdirSync)(this.projectSessionsDir, { recursive: true });
|
|
43456
44018
|
}
|
|
43457
|
-
const marker = (0,
|
|
44019
|
+
const marker = (0, import_node_path13.join)(this.projectSessionsDir, WORKSPACE_MARKER);
|
|
43458
44020
|
if (!(0, import_node_fs9.existsSync)(marker)) {
|
|
43459
44021
|
try {
|
|
43460
44022
|
(0, import_node_fs9.writeFileSync)(marker, `${this.workspaceKey}
|
|
@@ -43525,14 +44087,6 @@ ${parts.join("\n\n---\n\n")}`;
|
|
|
43525
44087
|
const skill = this.skillLoader.loadSkill(skillName);
|
|
43526
44088
|
return skill ? skill.content : null;
|
|
43527
44089
|
}
|
|
43528
|
-
/**
|
|
43529
|
-
* 根据用户输入查找匹配的 skills
|
|
43530
|
-
* @param userInput 用户输入
|
|
43531
|
-
* @returns 匹配的 skill 列表
|
|
43532
|
-
*/
|
|
43533
|
-
findMatchingSkills(userInput) {
|
|
43534
|
-
return this.skillLoader.findMatchingSkills(userInput);
|
|
43535
|
-
}
|
|
43536
44090
|
/**
|
|
43537
44091
|
* 生成 skill 摘要(用于注入 system prompt)
|
|
43538
44092
|
*/
|
|
@@ -43559,11 +44113,11 @@ ${parts.join("\n\n---\n\n")}`;
|
|
|
43559
44113
|
*/
|
|
43560
44114
|
allocateSessionPath() {
|
|
43561
44115
|
const timestamp = this.generateTimestamp();
|
|
43562
|
-
let path5 = (0,
|
|
44116
|
+
let path5 = (0, import_node_path13.join)(this.projectSessionsDir, `${timestamp}.jsonl`);
|
|
43563
44117
|
let suffix = 1;
|
|
43564
44118
|
while ((0, import_node_fs9.existsSync)(path5)) {
|
|
43565
44119
|
suffix += 1;
|
|
43566
|
-
path5 = (0,
|
|
44120
|
+
path5 = (0, import_node_path13.join)(this.projectSessionsDir, `${timestamp}-${suffix}.jsonl`);
|
|
43567
44121
|
}
|
|
43568
44122
|
return path5;
|
|
43569
44123
|
}
|
|
@@ -43615,7 +44169,7 @@ ${parts.join("\n\n---\n\n")}`;
|
|
|
43615
44169
|
return [];
|
|
43616
44170
|
}
|
|
43617
44171
|
return files.map((fileName) => {
|
|
43618
|
-
const filePath = (0,
|
|
44172
|
+
const filePath = (0, import_node_path13.join)(this.projectSessionsDir, fileName);
|
|
43619
44173
|
let sizeBytes = 0;
|
|
43620
44174
|
try {
|
|
43621
44175
|
sizeBytes = (0, import_node_fs9.statSync)(filePath).size;
|
|
@@ -43742,13 +44296,20 @@ async function tryCreateDefaultSettings(providerService, settingsStore) {
|
|
|
43742
44296
|
}
|
|
43743
44297
|
return void 0;
|
|
43744
44298
|
}
|
|
43745
|
-
async function main() {
|
|
44299
|
+
async function main(argv = process.argv.slice(2)) {
|
|
44300
|
+
if (wantsVersion(argv)) {
|
|
44301
|
+
printVersion();
|
|
44302
|
+
return;
|
|
44303
|
+
}
|
|
43746
44304
|
const workspaceRoot = process.cwd();
|
|
43747
44305
|
const providerService = new ModelProviderService();
|
|
43748
44306
|
const settingsStore = new SettingsStore();
|
|
44307
|
+
const updateChecker = createUpdateChecker({ settingsStore });
|
|
43749
44308
|
const { model, providerName, modelName } = await createModelFromSettings(providerService, settingsStore);
|
|
44309
|
+
const skillLoader = new SkillLoader(workspaceRoot);
|
|
43750
44310
|
const subAgentRuntime = new SubAgentRuntimeProvider();
|
|
43751
44311
|
const toolRegistry = createToolRegistry(workspaceRoot, {
|
|
44312
|
+
skillLoader,
|
|
43752
44313
|
extraTools: [
|
|
43753
44314
|
createSubAgentTool({
|
|
43754
44315
|
workspaceRoot,
|
|
@@ -43767,7 +44328,7 @@ async function main() {
|
|
|
43767
44328
|
const { window: contextWindow, source: contextWindowSource } = await resolveContextWindowFromSettings(settingsStore, modelName);
|
|
43768
44329
|
const subAgentEnabled = await settingsStore.getSubagentEnabled();
|
|
43769
44330
|
const subAgentTrace = await settingsStore.getSubagentTrace();
|
|
43770
|
-
const sessionManager = new SessionManager(workspaceRoot);
|
|
44331
|
+
const sessionManager = new SessionManager(workspaceRoot, { skillLoader });
|
|
43771
44332
|
if (model) {
|
|
43772
44333
|
sessionManager.setModel(model);
|
|
43773
44334
|
}
|
|
@@ -43777,6 +44338,7 @@ async function main() {
|
|
|
43777
44338
|
console.log(source_default.dim(`[Skills]
|
|
43778
44339
|
${skills.length > 0 ? skills.map((skill) => skill.name).join(",") : ""}`));
|
|
43779
44340
|
}
|
|
44341
|
+
const loadedSkillNames = [];
|
|
43780
44342
|
const buildPrompt = () => buildSystemPrompt({
|
|
43781
44343
|
workspaceRoot,
|
|
43782
44344
|
fixedContext: sessionManager.getFixedContext(),
|
|
@@ -43799,6 +44361,8 @@ async function main() {
|
|
|
43799
44361
|
);
|
|
43800
44362
|
console.log();
|
|
43801
44363
|
}
|
|
44364
|
+
const updateResult = await updateChecker.checkOnStartup();
|
|
44365
|
+
printUpdateNotice(updateResult);
|
|
43802
44366
|
const onNewSession = () => {
|
|
43803
44367
|
return sessionManager.createNewSession();
|
|
43804
44368
|
};
|
|
@@ -43810,7 +44374,9 @@ async function main() {
|
|
|
43810
44374
|
if (newModel) {
|
|
43811
44375
|
sessionManager.setModel(newModel);
|
|
43812
44376
|
}
|
|
43813
|
-
|
|
44377
|
+
sessionManager.getSkillLoader().clearCache();
|
|
44378
|
+
const newBasePrompt = buildPrompt();
|
|
44379
|
+
const newSystemPrompt = newBasePrompt + composeLoadedSkillSections(sessionManager, loadedSkillNames);
|
|
43814
44380
|
const resolved = await resolveContextWindowFromSettings(
|
|
43815
44381
|
settingsStore,
|
|
43816
44382
|
newModelName
|
|
@@ -43820,6 +44386,7 @@ async function main() {
|
|
|
43820
44386
|
return {
|
|
43821
44387
|
model: newModel,
|
|
43822
44388
|
systemPrompt: newSystemPrompt,
|
|
44389
|
+
baseSystemPrompt: newBasePrompt,
|
|
43823
44390
|
contextWindow: resolved.window,
|
|
43824
44391
|
contextWindowSource: resolved.source
|
|
43825
44392
|
};
|
|
@@ -43844,6 +44411,8 @@ async function main() {
|
|
|
43844
44411
|
await startRepl({
|
|
43845
44412
|
prompt: "You: ",
|
|
43846
44413
|
systemPrompt,
|
|
44414
|
+
baseSystemPrompt: systemPrompt,
|
|
44415
|
+
loadedSkillNames,
|
|
43847
44416
|
messages,
|
|
43848
44417
|
model,
|
|
43849
44418
|
toolRegistry,
|
|
@@ -43853,6 +44422,7 @@ async function main() {
|
|
|
43853
44422
|
workspaceRoot,
|
|
43854
44423
|
providerService,
|
|
43855
44424
|
settingsStore,
|
|
44425
|
+
updateChecker,
|
|
43856
44426
|
sessionStore,
|
|
43857
44427
|
sessionManager,
|
|
43858
44428
|
contextWindow,
|