opencode-feishu 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +396 -362
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11587,7 +11587,7 @@ var require_object_inspect = __commonJS({
|
|
|
11587
11587
|
"double": /(["\\])/g,
|
|
11588
11588
|
single: /(['\\])/g
|
|
11589
11589
|
};
|
|
11590
|
-
module2.exports = function inspect_(obj, options, depth,
|
|
11590
|
+
module2.exports = function inspect_(obj, options, depth, seen) {
|
|
11591
11591
|
var opts = options || {};
|
|
11592
11592
|
if (has(opts, "quoteStyle") && !has(quotes, opts.quoteStyle)) {
|
|
11593
11593
|
throw new TypeError('option "quoteStyle" must be "single" or "double"');
|
|
@@ -11637,15 +11637,15 @@ var require_object_inspect = __commonJS({
|
|
|
11637
11637
|
return isArray2(obj) ? "[Array]" : "[Object]";
|
|
11638
11638
|
}
|
|
11639
11639
|
var indent = getIndent(opts, depth);
|
|
11640
|
-
if (typeof
|
|
11641
|
-
|
|
11642
|
-
} else if (indexOf(
|
|
11640
|
+
if (typeof seen === "undefined") {
|
|
11641
|
+
seen = [];
|
|
11642
|
+
} else if (indexOf(seen, obj) >= 0) {
|
|
11643
11643
|
return "[Circular]";
|
|
11644
11644
|
}
|
|
11645
11645
|
function inspect(value, from, noIndent) {
|
|
11646
11646
|
if (from) {
|
|
11647
|
-
|
|
11648
|
-
|
|
11647
|
+
seen = $arrSlice.call(seen);
|
|
11648
|
+
seen.push(from);
|
|
11649
11649
|
}
|
|
11650
11650
|
if (noIndent) {
|
|
11651
11651
|
var newOpts = {
|
|
@@ -11654,9 +11654,9 @@ var require_object_inspect = __commonJS({
|
|
|
11654
11654
|
if (has(opts, "quoteStyle")) {
|
|
11655
11655
|
newOpts.quoteStyle = opts.quoteStyle;
|
|
11656
11656
|
}
|
|
11657
|
-
return inspect_(value, newOpts, depth + 1,
|
|
11657
|
+
return inspect_(value, newOpts, depth + 1, seen);
|
|
11658
11658
|
}
|
|
11659
|
-
return inspect_(value, opts, depth + 1,
|
|
11659
|
+
return inspect_(value, opts, depth + 1, seen);
|
|
11660
11660
|
}
|
|
11661
11661
|
if (typeof obj === "function" && !isRegExp2(obj)) {
|
|
11662
11662
|
var name = nameOf(obj);
|
|
@@ -13718,7 +13718,7 @@ var require_lodash2 = __commonJS({
|
|
|
13718
13718
|
if (stacked && stack.get(other)) {
|
|
13719
13719
|
return stacked == other;
|
|
13720
13720
|
}
|
|
13721
|
-
var index = -1, result = true,
|
|
13721
|
+
var index = -1, result = true, seen = bitmask & UNORDERED_COMPARE_FLAG ? new SetCache() : void 0;
|
|
13722
13722
|
stack.set(array2, other);
|
|
13723
13723
|
stack.set(other, array2);
|
|
13724
13724
|
while (++index < arrLength) {
|
|
@@ -13733,10 +13733,10 @@ var require_lodash2 = __commonJS({
|
|
|
13733
13733
|
result = false;
|
|
13734
13734
|
break;
|
|
13735
13735
|
}
|
|
13736
|
-
if (
|
|
13736
|
+
if (seen) {
|
|
13737
13737
|
if (!arraySome(other, function(othValue2, othIndex) {
|
|
13738
|
-
if (!
|
|
13739
|
-
return
|
|
13738
|
+
if (!seen.has(othIndex) && (arrValue === othValue2 || equalFunc(arrValue, othValue2, customizer, bitmask, stack))) {
|
|
13739
|
+
return seen.add(othIndex);
|
|
13740
13740
|
}
|
|
13741
13741
|
})) {
|
|
13742
13742
|
result = false;
|
|
@@ -109648,14 +109648,14 @@ function initializeContext(params) {
|
|
|
109648
109648
|
function process2(schema, ctx, _params = { path: [], schemaPath: [] }) {
|
|
109649
109649
|
var _a2;
|
|
109650
109650
|
const def = schema._zod.def;
|
|
109651
|
-
const
|
|
109652
|
-
if (
|
|
109653
|
-
|
|
109651
|
+
const seen = ctx.seen.get(schema);
|
|
109652
|
+
if (seen) {
|
|
109653
|
+
seen.count++;
|
|
109654
109654
|
const isCycle = _params.schemaPath.includes(schema);
|
|
109655
109655
|
if (isCycle) {
|
|
109656
|
-
|
|
109656
|
+
seen.cycle = _params.path;
|
|
109657
109657
|
}
|
|
109658
|
-
return
|
|
109658
|
+
return seen.schema;
|
|
109659
109659
|
}
|
|
109660
109660
|
const result = { schema: {}, count: 1, cycle: void 0, path: _params.path };
|
|
109661
109661
|
ctx.seen.set(schema, result);
|
|
@@ -109738,12 +109738,12 @@ function extractDefs(ctx, schema) {
|
|
|
109738
109738
|
if (entry[1].schema.$ref) {
|
|
109739
109739
|
return;
|
|
109740
109740
|
}
|
|
109741
|
-
const
|
|
109741
|
+
const seen = entry[1];
|
|
109742
109742
|
const { ref, defId } = makeURI(entry);
|
|
109743
|
-
|
|
109743
|
+
seen.def = { ...seen.schema };
|
|
109744
109744
|
if (defId)
|
|
109745
|
-
|
|
109746
|
-
const schema2 =
|
|
109745
|
+
seen.defId = defId;
|
|
109746
|
+
const schema2 = seen.schema;
|
|
109747
109747
|
for (const key in schema2) {
|
|
109748
109748
|
delete schema2[key];
|
|
109749
109749
|
}
|
|
@@ -109751,16 +109751,16 @@ function extractDefs(ctx, schema) {
|
|
|
109751
109751
|
};
|
|
109752
109752
|
if (ctx.cycles === "throw") {
|
|
109753
109753
|
for (const entry of ctx.seen.entries()) {
|
|
109754
|
-
const
|
|
109755
|
-
if (
|
|
109756
|
-
throw new Error(`Cycle detected: #/${
|
|
109754
|
+
const seen = entry[1];
|
|
109755
|
+
if (seen.cycle) {
|
|
109756
|
+
throw new Error(`Cycle detected: #/${seen.cycle?.join("/")}/<root>
|
|
109757
109757
|
|
|
109758
109758
|
Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.`);
|
|
109759
109759
|
}
|
|
109760
109760
|
}
|
|
109761
109761
|
}
|
|
109762
109762
|
for (const entry of ctx.seen.entries()) {
|
|
109763
|
-
const
|
|
109763
|
+
const seen = entry[1];
|
|
109764
109764
|
if (schema === entry[0]) {
|
|
109765
109765
|
extractToDef(entry);
|
|
109766
109766
|
continue;
|
|
@@ -109777,11 +109777,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
109777
109777
|
extractToDef(entry);
|
|
109778
109778
|
continue;
|
|
109779
109779
|
}
|
|
109780
|
-
if (
|
|
109780
|
+
if (seen.cycle) {
|
|
109781
109781
|
extractToDef(entry);
|
|
109782
109782
|
continue;
|
|
109783
109783
|
}
|
|
109784
|
-
if (
|
|
109784
|
+
if (seen.count > 1) {
|
|
109785
109785
|
if (ctx.reused === "ref") {
|
|
109786
109786
|
extractToDef(entry);
|
|
109787
109787
|
continue;
|
|
@@ -109794,13 +109794,13 @@ function finalize(ctx, schema) {
|
|
|
109794
109794
|
if (!root)
|
|
109795
109795
|
throw new Error("Unprocessed schema. This is a bug in Zod.");
|
|
109796
109796
|
const flattenRef = (zodSchema) => {
|
|
109797
|
-
const
|
|
109798
|
-
if (
|
|
109797
|
+
const seen = ctx.seen.get(zodSchema);
|
|
109798
|
+
if (seen.ref === null)
|
|
109799
109799
|
return;
|
|
109800
|
-
const schema2 =
|
|
109800
|
+
const schema2 = seen.def ?? seen.schema;
|
|
109801
109801
|
const _cached = { ...schema2 };
|
|
109802
|
-
const ref =
|
|
109803
|
-
|
|
109802
|
+
const ref = seen.ref;
|
|
109803
|
+
seen.ref = null;
|
|
109804
109804
|
if (ref) {
|
|
109805
109805
|
flattenRef(ref);
|
|
109806
109806
|
const refSeen = ctx.seen.get(ref);
|
|
@@ -109852,7 +109852,7 @@ function finalize(ctx, schema) {
|
|
|
109852
109852
|
ctx.override({
|
|
109853
109853
|
zodSchema,
|
|
109854
109854
|
jsonSchema: schema2,
|
|
109855
|
-
path:
|
|
109855
|
+
path: seen.path ?? []
|
|
109856
109856
|
});
|
|
109857
109857
|
};
|
|
109858
109858
|
for (const entry of [...ctx.seen.entries()].reverse()) {
|
|
@@ -109875,9 +109875,9 @@ function finalize(ctx, schema) {
|
|
|
109875
109875
|
Object.assign(result, root.def ?? root.schema);
|
|
109876
109876
|
const defs = ctx.external?.defs ?? {};
|
|
109877
109877
|
for (const entry of ctx.seen.entries()) {
|
|
109878
|
-
const
|
|
109879
|
-
if (
|
|
109880
|
-
defs[
|
|
109878
|
+
const seen = entry[1];
|
|
109879
|
+
if (seen.def && seen.defId) {
|
|
109880
|
+
defs[seen.defId] = seen.def;
|
|
109881
109881
|
}
|
|
109882
109882
|
}
|
|
109883
109883
|
if (ctx.external) ; else {
|
|
@@ -110371,9 +110371,9 @@ var recordProcessor = (schema, ctx, _json, params) => {
|
|
|
110371
110371
|
var nullableProcessor = (schema, ctx, json2, params) => {
|
|
110372
110372
|
const def = schema._zod.def;
|
|
110373
110373
|
const inner = process2(def.innerType, ctx, params);
|
|
110374
|
-
const
|
|
110374
|
+
const seen = ctx.seen.get(schema);
|
|
110375
110375
|
if (ctx.target === "openapi-3.0") {
|
|
110376
|
-
|
|
110376
|
+
seen.ref = def.innerType;
|
|
110377
110377
|
json2.nullable = true;
|
|
110378
110378
|
} else {
|
|
110379
110379
|
json2.anyOf = [inner, { type: "null" }];
|
|
@@ -110382,29 +110382,29 @@ var nullableProcessor = (schema, ctx, json2, params) => {
|
|
|
110382
110382
|
var nonoptionalProcessor = (schema, ctx, _json, params) => {
|
|
110383
110383
|
const def = schema._zod.def;
|
|
110384
110384
|
process2(def.innerType, ctx, params);
|
|
110385
|
-
const
|
|
110386
|
-
|
|
110385
|
+
const seen = ctx.seen.get(schema);
|
|
110386
|
+
seen.ref = def.innerType;
|
|
110387
110387
|
};
|
|
110388
110388
|
var defaultProcessor = (schema, ctx, json2, params) => {
|
|
110389
110389
|
const def = schema._zod.def;
|
|
110390
110390
|
process2(def.innerType, ctx, params);
|
|
110391
|
-
const
|
|
110392
|
-
|
|
110391
|
+
const seen = ctx.seen.get(schema);
|
|
110392
|
+
seen.ref = def.innerType;
|
|
110393
110393
|
json2.default = JSON.parse(JSON.stringify(def.defaultValue));
|
|
110394
110394
|
};
|
|
110395
110395
|
var prefaultProcessor = (schema, ctx, json2, params) => {
|
|
110396
110396
|
const def = schema._zod.def;
|
|
110397
110397
|
process2(def.innerType, ctx, params);
|
|
110398
|
-
const
|
|
110399
|
-
|
|
110398
|
+
const seen = ctx.seen.get(schema);
|
|
110399
|
+
seen.ref = def.innerType;
|
|
110400
110400
|
if (ctx.io === "input")
|
|
110401
110401
|
json2._prefault = JSON.parse(JSON.stringify(def.defaultValue));
|
|
110402
110402
|
};
|
|
110403
110403
|
var catchProcessor = (schema, ctx, json2, params) => {
|
|
110404
110404
|
const def = schema._zod.def;
|
|
110405
110405
|
process2(def.innerType, ctx, params);
|
|
110406
|
-
const
|
|
110407
|
-
|
|
110406
|
+
const seen = ctx.seen.get(schema);
|
|
110407
|
+
seen.ref = def.innerType;
|
|
110408
110408
|
let catchValue;
|
|
110409
110409
|
try {
|
|
110410
110410
|
catchValue = def.catchValue(void 0);
|
|
@@ -110417,33 +110417,33 @@ var pipeProcessor = (schema, ctx, _json, params) => {
|
|
|
110417
110417
|
const def = schema._zod.def;
|
|
110418
110418
|
const innerType = ctx.io === "input" ? def.in._zod.def.type === "transform" ? def.out : def.in : def.out;
|
|
110419
110419
|
process2(innerType, ctx, params);
|
|
110420
|
-
const
|
|
110421
|
-
|
|
110420
|
+
const seen = ctx.seen.get(schema);
|
|
110421
|
+
seen.ref = innerType;
|
|
110422
110422
|
};
|
|
110423
110423
|
var readonlyProcessor = (schema, ctx, json2, params) => {
|
|
110424
110424
|
const def = schema._zod.def;
|
|
110425
110425
|
process2(def.innerType, ctx, params);
|
|
110426
|
-
const
|
|
110427
|
-
|
|
110426
|
+
const seen = ctx.seen.get(schema);
|
|
110427
|
+
seen.ref = def.innerType;
|
|
110428
110428
|
json2.readOnly = true;
|
|
110429
110429
|
};
|
|
110430
110430
|
var promiseProcessor = (schema, ctx, _json, params) => {
|
|
110431
110431
|
const def = schema._zod.def;
|
|
110432
110432
|
process2(def.innerType, ctx, params);
|
|
110433
|
-
const
|
|
110434
|
-
|
|
110433
|
+
const seen = ctx.seen.get(schema);
|
|
110434
|
+
seen.ref = def.innerType;
|
|
110435
110435
|
};
|
|
110436
110436
|
var optionalProcessor = (schema, ctx, _json, params) => {
|
|
110437
110437
|
const def = schema._zod.def;
|
|
110438
110438
|
process2(def.innerType, ctx, params);
|
|
110439
|
-
const
|
|
110440
|
-
|
|
110439
|
+
const seen = ctx.seen.get(schema);
|
|
110440
|
+
seen.ref = def.innerType;
|
|
110441
110441
|
};
|
|
110442
110442
|
var lazyProcessor = (schema, ctx, _json, params) => {
|
|
110443
110443
|
const innerType = schema._zod.innerType;
|
|
110444
110444
|
process2(innerType, ctx, params);
|
|
110445
|
-
const
|
|
110446
|
-
|
|
110445
|
+
const seen = ctx.seen.get(schema);
|
|
110446
|
+
seen.ref = innerType;
|
|
110447
110447
|
};
|
|
110448
110448
|
var allProcessors = {
|
|
110449
110449
|
string: stringProcessor,
|
|
@@ -112507,8 +112507,8 @@ config(en_default());
|
|
|
112507
112507
|
// src/types.ts
|
|
112508
112508
|
var AutoPromptSchema = external_exports.object({
|
|
112509
112509
|
enabled: external_exports.boolean().default(false),
|
|
112510
|
-
intervalSeconds: external_exports.number().int().positive().default(30),
|
|
112511
|
-
maxIterations: external_exports.number().int().positive().default(10),
|
|
112510
|
+
intervalSeconds: external_exports.number().int().positive().max(300).default(30),
|
|
112511
|
+
maxIterations: external_exports.number().int().positive().max(100).default(10),
|
|
112512
112512
|
message: external_exports.string().min(1).default("\u8BF7\u540C\u6B65\u5F53\u524D\u8FDB\u5EA6\uFF0C\u5982\u9700\u5E2E\u52A9\u8BF7\u8BF4\u660E"),
|
|
112513
112513
|
idleThreshold: external_exports.number().int().min(1).default(2),
|
|
112514
112514
|
idleMaxLength: external_exports.number().int().min(10).default(50)
|
|
@@ -112516,10 +112516,10 @@ var AutoPromptSchema = external_exports.object({
|
|
|
112516
112516
|
var FeishuConfigSchema = external_exports.object({
|
|
112517
112517
|
appId: external_exports.string().min(1, "appId \u4E0D\u80FD\u4E3A\u7A7A"),
|
|
112518
112518
|
appSecret: external_exports.string().min(1, "appSecret \u4E0D\u80FD\u4E3A\u7A7A"),
|
|
112519
|
-
timeout: external_exports.number().int().positive().default(12e4),
|
|
112519
|
+
timeout: external_exports.number().int().positive().max(6e5).default(12e4),
|
|
112520
112520
|
thinkingDelay: external_exports.number().int().nonnegative().default(2500),
|
|
112521
112521
|
logLevel: external_exports.enum(["fatal", "error", "warn", "info", "debug", "trace"]).default("info"),
|
|
112522
|
-
maxHistoryMessages: external_exports.number().int().positive().default(200),
|
|
112522
|
+
maxHistoryMessages: external_exports.number().int().positive().max(500).default(200),
|
|
112523
112523
|
pollInterval: external_exports.number().int().positive().default(1e3),
|
|
112524
112524
|
stablePolls: external_exports.number().int().positive().default(3),
|
|
112525
112525
|
dedupTtl: external_exports.number().int().positive().default(10 * 60 * 1e3),
|
|
@@ -112714,37 +112714,40 @@ function buildQuestionCard(request) {
|
|
|
112714
112714
|
}
|
|
112715
112715
|
|
|
112716
112716
|
// src/feishu/sender.ts
|
|
112717
|
+
async function wrapSendCall(fn, idExtractor = (res) => res?.data?.message_id ?? "") {
|
|
112718
|
+
try {
|
|
112719
|
+
const res = await fn();
|
|
112720
|
+
return { ok: true, messageId: idExtractor(res) };
|
|
112721
|
+
} catch (err) {
|
|
112722
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
112723
|
+
}
|
|
112724
|
+
}
|
|
112717
112725
|
async function sendTextMessage(client, chatId, text) {
|
|
112718
112726
|
if (!chatId?.trim()) {
|
|
112719
112727
|
return { ok: false, error: "No chat_id provided" };
|
|
112720
112728
|
}
|
|
112721
|
-
|
|
112722
|
-
|
|
112729
|
+
return wrapSendCall(
|
|
112730
|
+
() => client.im.message.create({
|
|
112723
112731
|
params: { receive_id_type: "chat_id" },
|
|
112724
112732
|
data: {
|
|
112725
112733
|
receive_id: chatId.trim(),
|
|
112726
112734
|
msg_type: "text",
|
|
112727
112735
|
content: JSON.stringify({ text })
|
|
112728
112736
|
}
|
|
112729
|
-
})
|
|
112730
|
-
|
|
112731
|
-
} catch (err) {
|
|
112732
|
-
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
112733
|
-
}
|
|
112737
|
+
})
|
|
112738
|
+
);
|
|
112734
112739
|
}
|
|
112735
112740
|
async function updateMessage(client, messageId, text) {
|
|
112736
|
-
|
|
112737
|
-
|
|
112741
|
+
return wrapSendCall(
|
|
112742
|
+
() => client.im.message.update({
|
|
112738
112743
|
path: { message_id: messageId },
|
|
112739
112744
|
data: {
|
|
112740
112745
|
msg_type: "text",
|
|
112741
112746
|
content: JSON.stringify({ text })
|
|
112742
112747
|
}
|
|
112743
|
-
})
|
|
112744
|
-
|
|
112745
|
-
|
|
112746
|
-
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
112747
|
-
}
|
|
112748
|
+
}),
|
|
112749
|
+
() => messageId
|
|
112750
|
+
);
|
|
112748
112751
|
}
|
|
112749
112752
|
async function deleteMessage(client, messageId) {
|
|
112750
112753
|
try {
|
|
@@ -112756,49 +112759,71 @@ async function sendInteractiveCard(client, chatId, card) {
|
|
|
112756
112759
|
if (!chatId?.trim()) {
|
|
112757
112760
|
return { ok: false, error: "No chat_id provided" };
|
|
112758
112761
|
}
|
|
112759
|
-
|
|
112760
|
-
|
|
112762
|
+
return wrapSendCall(
|
|
112763
|
+
() => client.im.message.create({
|
|
112761
112764
|
params: { receive_id_type: "chat_id" },
|
|
112762
112765
|
data: {
|
|
112763
112766
|
receive_id: chatId.trim(),
|
|
112764
112767
|
msg_type: "interactive",
|
|
112765
112768
|
content: JSON.stringify(card)
|
|
112766
112769
|
}
|
|
112767
|
-
})
|
|
112768
|
-
|
|
112769
|
-
} catch (err) {
|
|
112770
|
-
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
112771
|
-
}
|
|
112770
|
+
})
|
|
112771
|
+
);
|
|
112772
112772
|
}
|
|
112773
112773
|
async function sendCardMessage(client, chatId, cardId) {
|
|
112774
112774
|
if (!chatId?.trim()) {
|
|
112775
112775
|
return { ok: false, error: "No chat_id provided" };
|
|
112776
112776
|
}
|
|
112777
|
-
|
|
112778
|
-
|
|
112777
|
+
return wrapSendCall(
|
|
112778
|
+
() => client.im.message.create({
|
|
112779
112779
|
params: { receive_id_type: "chat_id" },
|
|
112780
112780
|
data: {
|
|
112781
112781
|
receive_id: chatId.trim(),
|
|
112782
112782
|
msg_type: "interactive",
|
|
112783
112783
|
content: JSON.stringify({ type: "card_kit", data: { card_id: cardId } })
|
|
112784
112784
|
}
|
|
112785
|
-
})
|
|
112786
|
-
|
|
112787
|
-
} catch (err) {
|
|
112788
|
-
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
112789
|
-
}
|
|
112785
|
+
})
|
|
112786
|
+
);
|
|
112790
112787
|
}
|
|
112791
112788
|
|
|
112789
|
+
// src/utils/ttl-map.ts
|
|
112790
|
+
var TtlMap = class {
|
|
112791
|
+
constructor(defaultTtlMs) {
|
|
112792
|
+
this.defaultTtlMs = defaultTtlMs;
|
|
112793
|
+
}
|
|
112794
|
+
data = /* @__PURE__ */ new Map();
|
|
112795
|
+
timers = /* @__PURE__ */ new Map();
|
|
112796
|
+
get(key) {
|
|
112797
|
+
return this.data.get(key);
|
|
112798
|
+
}
|
|
112799
|
+
has(key) {
|
|
112800
|
+
return this.data.has(key);
|
|
112801
|
+
}
|
|
112802
|
+
set(key, value, ttlMs) {
|
|
112803
|
+
this.delete(key);
|
|
112804
|
+
this.data.set(key, value);
|
|
112805
|
+
const timer = setTimeout(() => {
|
|
112806
|
+
this.data.delete(key);
|
|
112807
|
+
this.timers.delete(key);
|
|
112808
|
+
}, ttlMs ?? this.defaultTtlMs);
|
|
112809
|
+
timer.unref();
|
|
112810
|
+
this.timers.set(key, timer);
|
|
112811
|
+
}
|
|
112812
|
+
delete(key) {
|
|
112813
|
+
const timer = this.timers.get(key);
|
|
112814
|
+
if (timer) {
|
|
112815
|
+
clearTimeout(timer);
|
|
112816
|
+
this.timers.delete(key);
|
|
112817
|
+
}
|
|
112818
|
+
this.data.delete(key);
|
|
112819
|
+
}
|
|
112820
|
+
};
|
|
112821
|
+
|
|
112792
112822
|
// src/handler/interactive.ts
|
|
112793
|
-
var
|
|
112794
|
-
var seenRequestIds = /* @__PURE__ */ new Map();
|
|
112823
|
+
var seenIds = new TtlMap(10 * 60 * 1e3);
|
|
112795
112824
|
function markSeen(requestId) {
|
|
112796
|
-
|
|
112797
|
-
|
|
112798
|
-
if (now - ts > SEEN_TTL_MS) seenRequestIds.delete(id);
|
|
112799
|
-
}
|
|
112800
|
-
if (seenRequestIds.has(requestId)) return false;
|
|
112801
|
-
seenRequestIds.set(requestId, now);
|
|
112825
|
+
if (seenIds.has(requestId)) return false;
|
|
112826
|
+
seenIds.set(requestId, true);
|
|
112802
112827
|
return true;
|
|
112803
112828
|
}
|
|
112804
112829
|
function handlePermissionRequested(request, chatId, deps) {
|
|
@@ -112866,19 +112891,14 @@ function buildCallbackResponse(action) {
|
|
|
112866
112891
|
}
|
|
112867
112892
|
|
|
112868
112893
|
// src/feishu/dedup.ts
|
|
112869
|
-
var
|
|
112870
|
-
var seen = /* @__PURE__ */ new Map();
|
|
112894
|
+
var dedup = new TtlMap(10 * 60 * 1e3);
|
|
112871
112895
|
function initDedup(ttl) {
|
|
112872
|
-
|
|
112896
|
+
dedup = new TtlMap(ttl);
|
|
112873
112897
|
}
|
|
112874
112898
|
function isDuplicate(messageId) {
|
|
112875
|
-
const now = Date.now();
|
|
112876
|
-
for (const [k, ts] of seen) {
|
|
112877
|
-
if (now - ts > seenTtlMs) seen.delete(k);
|
|
112878
|
-
}
|
|
112879
112899
|
if (!messageId) return false;
|
|
112880
|
-
if (
|
|
112881
|
-
|
|
112900
|
+
if (dedup.has(messageId)) return true;
|
|
112901
|
+
dedup.set(messageId, true);
|
|
112882
112902
|
return false;
|
|
112883
112903
|
}
|
|
112884
112904
|
|
|
@@ -113316,57 +113336,24 @@ function emit(sessionId, action) {
|
|
|
113316
113336
|
|
|
113317
113337
|
// src/handler/event.ts
|
|
113318
113338
|
var pendingBySession = /* @__PURE__ */ new Map();
|
|
113319
|
-
var sessionErrors =
|
|
113320
|
-
var
|
|
113321
|
-
var SESSION_ERROR_TTL_MS = 3e4;
|
|
113322
|
-
var retryAttempts = /* @__PURE__ */ new Map();
|
|
113323
|
-
var retryAttemptTimeouts = /* @__PURE__ */ new Map();
|
|
113339
|
+
var sessionErrors = new TtlMap(3e4);
|
|
113340
|
+
var retryAttempts = new TtlMap(36e5);
|
|
113324
113341
|
var MAX_RETRY_ATTEMPTS = 2;
|
|
113325
|
-
var RETRY_ATTEMPTS_TTL_MS = 36e5;
|
|
113326
113342
|
function clearRetryAttempts(sessionKey) {
|
|
113327
113343
|
retryAttempts.delete(sessionKey);
|
|
113328
|
-
const timer = retryAttemptTimeouts.get(sessionKey);
|
|
113329
|
-
if (timer) {
|
|
113330
|
-
clearTimeout(timer);
|
|
113331
|
-
retryAttemptTimeouts.delete(sessionKey);
|
|
113332
|
-
}
|
|
113333
113344
|
}
|
|
113334
113345
|
function getRetryAttempts(sessionKey) {
|
|
113335
113346
|
return retryAttempts.get(sessionKey) ?? 0;
|
|
113336
113347
|
}
|
|
113337
113348
|
function setRetryAttempts(sessionKey, count) {
|
|
113338
113349
|
retryAttempts.set(sessionKey, count);
|
|
113339
|
-
const existing = retryAttemptTimeouts.get(sessionKey);
|
|
113340
|
-
if (existing) clearTimeout(existing);
|
|
113341
|
-
const timeoutId = setTimeout(() => {
|
|
113342
|
-
retryAttempts.delete(sessionKey);
|
|
113343
|
-
retryAttemptTimeouts.delete(sessionKey);
|
|
113344
|
-
}, RETRY_ATTEMPTS_TTL_MS);
|
|
113345
|
-
retryAttemptTimeouts.set(sessionKey, timeoutId);
|
|
113346
113350
|
}
|
|
113347
113351
|
function getSessionError(sessionId) {
|
|
113348
113352
|
return sessionErrors.get(sessionId);
|
|
113349
113353
|
}
|
|
113350
113354
|
function clearSessionError(sessionId) {
|
|
113351
|
-
const timer = sessionErrorTimeouts.get(sessionId);
|
|
113352
|
-
if (timer) {
|
|
113353
|
-
clearTimeout(timer);
|
|
113354
|
-
sessionErrorTimeouts.delete(sessionId);
|
|
113355
|
-
}
|
|
113356
113355
|
sessionErrors.delete(sessionId);
|
|
113357
113356
|
}
|
|
113358
|
-
function setSessionError(sessionId, message, fields) {
|
|
113359
|
-
const existing = sessionErrorTimeouts.get(sessionId);
|
|
113360
|
-
if (existing) {
|
|
113361
|
-
clearTimeout(existing);
|
|
113362
|
-
}
|
|
113363
|
-
sessionErrors.set(sessionId, { message, fields });
|
|
113364
|
-
const timeoutId = setTimeout(() => {
|
|
113365
|
-
sessionErrors.delete(sessionId);
|
|
113366
|
-
sessionErrorTimeouts.delete(sessionId);
|
|
113367
|
-
}, SESSION_ERROR_TTL_MS);
|
|
113368
|
-
sessionErrorTimeouts.set(sessionId, timeoutId);
|
|
113369
|
-
}
|
|
113370
113357
|
function registerPending(sessionId, payload) {
|
|
113371
113358
|
pendingBySession.set(sessionId, { ...payload, textBuffer: "", expectedMessageId: void 0 });
|
|
113372
113359
|
}
|
|
@@ -113417,111 +113404,115 @@ async function handleEvent(event, deps) {
|
|
|
113417
113404
|
switch (event.type) {
|
|
113418
113405
|
case "message.part.updated": {
|
|
113419
113406
|
const part = event.properties.part;
|
|
113420
|
-
if (!part) break;
|
|
113421
|
-
const
|
|
113422
|
-
if (!sessionId) break;
|
|
113423
|
-
const payload = pendingBySession.get(sessionId);
|
|
113407
|
+
if (!part?.sessionID) break;
|
|
113408
|
+
const payload = pendingBySession.get(part.sessionID);
|
|
113424
113409
|
if (!payload) break;
|
|
113425
|
-
|
|
113426
|
-
if (messageId) {
|
|
113427
|
-
if (!payload.expectedMessageId) {
|
|
113428
|
-
payload.expectedMessageId = messageId;
|
|
113429
|
-
} else if (payload.expectedMessageId !== messageId) {
|
|
113430
|
-
break;
|
|
113431
|
-
}
|
|
113432
|
-
} else if (payload.expectedMessageId) {
|
|
113433
|
-
break;
|
|
113434
|
-
}
|
|
113435
|
-
const partSessionId = part.sessionID;
|
|
113436
|
-
if (part.type === "tool") {
|
|
113437
|
-
const p = part;
|
|
113438
|
-
const toolName = String(p.toolName ?? p.name ?? "unknown");
|
|
113439
|
-
const callID = String(p.toolCallID ?? p.id ?? "");
|
|
113440
|
-
const hasError = p.error !== void 0 && p.error !== null;
|
|
113441
|
-
const rawState = p.state != null ? String(p.state) : hasError ? "error" : "running";
|
|
113442
|
-
const toolState = rawState === "completed" || rawState === "error" ? rawState : "running";
|
|
113443
|
-
if (partSessionId) {
|
|
113444
|
-
emit(partSessionId, {
|
|
113445
|
-
type: "tool-state-changed",
|
|
113446
|
-
sessionId: partSessionId,
|
|
113447
|
-
callID,
|
|
113448
|
-
tool: toolName,
|
|
113449
|
-
state: toolState
|
|
113450
|
-
});
|
|
113451
|
-
}
|
|
113452
|
-
break;
|
|
113453
|
-
}
|
|
113454
|
-
const delta = event.properties.delta;
|
|
113455
|
-
if (delta) {
|
|
113456
|
-
payload.textBuffer += delta;
|
|
113457
|
-
} else {
|
|
113458
|
-
const fullText = extractPartText(part);
|
|
113459
|
-
if (fullText) {
|
|
113460
|
-
payload.textBuffer = fullText;
|
|
113461
|
-
}
|
|
113462
|
-
}
|
|
113463
|
-
if (payload.textBuffer) {
|
|
113464
|
-
const res = await updateMessage(payload.feishuClient, payload.placeholderId, payload.textBuffer.trim());
|
|
113465
|
-
if (!res.ok) ;
|
|
113466
|
-
}
|
|
113467
|
-
if (partSessionId) {
|
|
113468
|
-
emit(partSessionId, {
|
|
113469
|
-
type: "text-updated",
|
|
113470
|
-
sessionId: partSessionId,
|
|
113471
|
-
messageId: part.messageID,
|
|
113472
|
-
delta: delta ?? void 0,
|
|
113473
|
-
fullText: payload.textBuffer
|
|
113474
|
-
});
|
|
113475
|
-
}
|
|
113410
|
+
await handleMessagePartUpdated(event, part, payload);
|
|
113476
113411
|
break;
|
|
113477
113412
|
}
|
|
113478
|
-
case "session.error":
|
|
113479
|
-
|
|
113480
|
-
const sessionId = props.sessionID;
|
|
113481
|
-
if (!sessionId) break;
|
|
113482
|
-
const error48 = props.error;
|
|
113483
|
-
let errMsg;
|
|
113484
|
-
if (typeof error48 === "string") {
|
|
113485
|
-
errMsg = error48;
|
|
113486
|
-
} else if (error48 && typeof error48 === "object") {
|
|
113487
|
-
const e = error48;
|
|
113488
|
-
const rawDataMsg = e.data && typeof e.data === "object" && "message" in e.data ? e.data.message : void 0;
|
|
113489
|
-
const dataMsg = rawDataMsg != null ? String(rawDataMsg) : void 0;
|
|
113490
|
-
errMsg = String(e.message ?? dataMsg ?? e.type ?? e.name ?? "An unexpected error occurred");
|
|
113491
|
-
} else {
|
|
113492
|
-
errMsg = String(error48);
|
|
113493
|
-
}
|
|
113494
|
-
const fields = extractErrorFields(error48);
|
|
113495
|
-
deps.log("warn", "\u6536\u5230 session.error \u4E8B\u4EF6", { sessionId, errMsg });
|
|
113496
|
-
setSessionError(sessionId, errMsg, fields);
|
|
113413
|
+
case "session.error":
|
|
113414
|
+
handleSessionErrorEvent(event, deps);
|
|
113497
113415
|
break;
|
|
113498
|
-
|
|
113499
|
-
|
|
113500
|
-
const evtType = event.type;
|
|
113501
|
-
const evtProps = event.properties ?? {};
|
|
113502
|
-
const evtSessionId = evtProps.sessionID;
|
|
113503
|
-
if (evtType === "permission.asked" && evtSessionId) {
|
|
113504
|
-
emit(evtSessionId, {
|
|
113505
|
-
type: "permission-requested",
|
|
113506
|
-
sessionId: evtSessionId,
|
|
113507
|
-
request: evtProps
|
|
113508
|
-
});
|
|
113509
|
-
deps.log("info", "permission.asked \u4E8B\u4EF6\u5DF2\u5206\u53D1", { sessionId: evtSessionId });
|
|
113510
|
-
} else if (evtType === "question.asked" && evtSessionId) {
|
|
113511
|
-
emit(evtSessionId, {
|
|
113512
|
-
type: "question-requested",
|
|
113513
|
-
sessionId: evtSessionId,
|
|
113514
|
-
request: evtProps
|
|
113515
|
-
});
|
|
113516
|
-
deps.log("info", "question.asked \u4E8B\u4EF6\u5DF2\u5206\u53D1", { sessionId: evtSessionId });
|
|
113517
|
-
} else if (evtType === "session.idle" && evtSessionId) {
|
|
113518
|
-
emit(evtSessionId, {
|
|
113519
|
-
type: "session-idle",
|
|
113520
|
-
sessionId: evtSessionId
|
|
113521
|
-
});
|
|
113522
|
-
}
|
|
113416
|
+
default:
|
|
113417
|
+
handleV2Event(event, deps);
|
|
113523
113418
|
break;
|
|
113419
|
+
}
|
|
113420
|
+
}
|
|
113421
|
+
async function handleMessagePartUpdated(event, part, payload) {
|
|
113422
|
+
const messageId = part.messageID;
|
|
113423
|
+
if (messageId) {
|
|
113424
|
+
if (!payload.expectedMessageId) {
|
|
113425
|
+
payload.expectedMessageId = messageId;
|
|
113426
|
+
} else if (payload.expectedMessageId !== messageId) {
|
|
113427
|
+
return;
|
|
113524
113428
|
}
|
|
113429
|
+
} else if (payload.expectedMessageId) {
|
|
113430
|
+
return;
|
|
113431
|
+
}
|
|
113432
|
+
const partSessionId = part.sessionID;
|
|
113433
|
+
if (part.type === "tool") {
|
|
113434
|
+
const p = part;
|
|
113435
|
+
const toolName = String(p.toolName ?? p.name ?? "unknown");
|
|
113436
|
+
const callID = String(p.toolCallID ?? p.id ?? "");
|
|
113437
|
+
const hasError = p.error !== void 0 && p.error !== null;
|
|
113438
|
+
const rawState = p.state != null ? String(p.state) : hasError ? "error" : "running";
|
|
113439
|
+
const toolState = rawState === "completed" || rawState === "error" ? rawState : "running";
|
|
113440
|
+
if (partSessionId) {
|
|
113441
|
+
emit(partSessionId, {
|
|
113442
|
+
type: "tool-state-changed",
|
|
113443
|
+
sessionId: partSessionId,
|
|
113444
|
+
callID,
|
|
113445
|
+
tool: toolName,
|
|
113446
|
+
state: toolState
|
|
113447
|
+
});
|
|
113448
|
+
}
|
|
113449
|
+
return;
|
|
113450
|
+
}
|
|
113451
|
+
const delta = event.properties.delta;
|
|
113452
|
+
if (delta) {
|
|
113453
|
+
payload.textBuffer += delta;
|
|
113454
|
+
} else {
|
|
113455
|
+
const fullText = extractPartText(part);
|
|
113456
|
+
if (fullText) {
|
|
113457
|
+
payload.textBuffer = fullText;
|
|
113458
|
+
}
|
|
113459
|
+
}
|
|
113460
|
+
if (payload.textBuffer) {
|
|
113461
|
+
await updateMessage(payload.feishuClient, payload.placeholderId, payload.textBuffer.trim());
|
|
113462
|
+
}
|
|
113463
|
+
if (partSessionId) {
|
|
113464
|
+
emit(partSessionId, {
|
|
113465
|
+
type: "text-updated",
|
|
113466
|
+
sessionId: partSessionId,
|
|
113467
|
+
messageId: part.messageID,
|
|
113468
|
+
delta: delta ?? void 0,
|
|
113469
|
+
fullText: payload.textBuffer
|
|
113470
|
+
});
|
|
113471
|
+
}
|
|
113472
|
+
}
|
|
113473
|
+
function handleSessionErrorEvent(event, deps) {
|
|
113474
|
+
const props = event.properties;
|
|
113475
|
+
const sessionId = props.sessionID;
|
|
113476
|
+
if (!sessionId) return;
|
|
113477
|
+
const error48 = props.error;
|
|
113478
|
+
let errMsg;
|
|
113479
|
+
if (typeof error48 === "string") {
|
|
113480
|
+
errMsg = error48;
|
|
113481
|
+
} else if (error48 && typeof error48 === "object") {
|
|
113482
|
+
const e = error48;
|
|
113483
|
+
const asStr = (v) => typeof v === "string" && v.trim().length > 0 ? v : void 0;
|
|
113484
|
+
const rawDataMsg = e.data && typeof e.data === "object" && "message" in e.data ? e.data.message : void 0;
|
|
113485
|
+
errMsg = asStr(e.message) ?? asStr(rawDataMsg) ?? asStr(e.type) ?? asStr(e.name) ?? "An unexpected error occurred";
|
|
113486
|
+
} else {
|
|
113487
|
+
errMsg = String(error48);
|
|
113488
|
+
}
|
|
113489
|
+
const fields = extractErrorFields(error48);
|
|
113490
|
+
deps.log("warn", "\u6536\u5230 session.error \u4E8B\u4EF6", { sessionId, errMsg });
|
|
113491
|
+
sessionErrors.set(sessionId, { message: errMsg, fields });
|
|
113492
|
+
}
|
|
113493
|
+
function handleV2Event(event, deps) {
|
|
113494
|
+
const evtType = event.type;
|
|
113495
|
+
const evtProps = event.properties ?? {};
|
|
113496
|
+
const evtSessionId = evtProps.sessionID;
|
|
113497
|
+
if (evtType === "permission.asked" && evtSessionId) {
|
|
113498
|
+
emit(evtSessionId, {
|
|
113499
|
+
type: "permission-requested",
|
|
113500
|
+
sessionId: evtSessionId,
|
|
113501
|
+
request: evtProps
|
|
113502
|
+
});
|
|
113503
|
+
deps.log("info", "permission.asked \u4E8B\u4EF6\u5DF2\u5206\u53D1", { sessionId: evtSessionId });
|
|
113504
|
+
} else if (evtType === "question.asked" && evtSessionId) {
|
|
113505
|
+
emit(evtSessionId, {
|
|
113506
|
+
type: "question-requested",
|
|
113507
|
+
sessionId: evtSessionId,
|
|
113508
|
+
request: evtProps
|
|
113509
|
+
});
|
|
113510
|
+
deps.log("info", "question.asked \u4E8B\u4EF6\u5DF2\u5206\u53D1", { sessionId: evtSessionId });
|
|
113511
|
+
} else if (evtType === "session.idle" && evtSessionId) {
|
|
113512
|
+
emit(evtSessionId, {
|
|
113513
|
+
type: "session-idle",
|
|
113514
|
+
sessionId: evtSessionId
|
|
113515
|
+
});
|
|
113525
113516
|
}
|
|
113526
113517
|
}
|
|
113527
113518
|
function extractPartText(part) {
|
|
@@ -113532,6 +113523,128 @@ function extractPartText(part) {
|
|
|
113532
113523
|
return "";
|
|
113533
113524
|
}
|
|
113534
113525
|
|
|
113526
|
+
// src/handler/error-recovery.ts
|
|
113527
|
+
var SessionErrorDetected = class extends Error {
|
|
113528
|
+
constructor(sessionError) {
|
|
113529
|
+
super(sessionError.message);
|
|
113530
|
+
this.sessionError = sessionError;
|
|
113531
|
+
this.name = "SessionErrorDetected";
|
|
113532
|
+
}
|
|
113533
|
+
};
|
|
113534
|
+
async function getGlobalDefaultModel(client, directory) {
|
|
113535
|
+
const query = directory ? { directory } : void 0;
|
|
113536
|
+
const { data: config2 } = await client.config.get({ query });
|
|
113537
|
+
const model = config2?.model;
|
|
113538
|
+
if (!model || !model.includes("/")) return void 0;
|
|
113539
|
+
const slash = model.indexOf("/");
|
|
113540
|
+
const providerID = model.slice(0, slash).trim();
|
|
113541
|
+
const modelID = model.slice(slash + 1).trim();
|
|
113542
|
+
if (!providerID || !modelID) return void 0;
|
|
113543
|
+
return { providerID, modelID };
|
|
113544
|
+
}
|
|
113545
|
+
function extractSessionError(err, sessionId) {
|
|
113546
|
+
const result = err instanceof SessionErrorDetected ? err.sessionError : getSessionError(sessionId);
|
|
113547
|
+
clearSessionError(sessionId);
|
|
113548
|
+
return result;
|
|
113549
|
+
}
|
|
113550
|
+
async function tryModelRecovery(params) {
|
|
113551
|
+
const {
|
|
113552
|
+
sessionError,
|
|
113553
|
+
sessionId,
|
|
113554
|
+
sessionKey,
|
|
113555
|
+
client,
|
|
113556
|
+
directory,
|
|
113557
|
+
parts,
|
|
113558
|
+
timeout,
|
|
113559
|
+
pollInterval,
|
|
113560
|
+
stablePolls,
|
|
113561
|
+
query,
|
|
113562
|
+
signal,
|
|
113563
|
+
log,
|
|
113564
|
+
poll
|
|
113565
|
+
} = params;
|
|
113566
|
+
log("info", "\u9519\u8BEF\u5B57\u6BB5\u68C0\u67E5", {
|
|
113567
|
+
sessionKey,
|
|
113568
|
+
fields: sessionError.fields,
|
|
113569
|
+
isModel: isModelError(sessionError.fields)
|
|
113570
|
+
});
|
|
113571
|
+
if (!isModelError(sessionError.fields)) {
|
|
113572
|
+
return { recovered: false, sessionError };
|
|
113573
|
+
}
|
|
113574
|
+
const attempts = getRetryAttempts(sessionKey);
|
|
113575
|
+
if (attempts >= MAX_RETRY_ATTEMPTS) {
|
|
113576
|
+
log("warn", "\u5DF2\u8FBE\u91CD\u8BD5\u4E0A\u9650\uFF0C\u653E\u5F03\u6062\u590D", { sessionKey, attempts });
|
|
113577
|
+
return { recovered: false, sessionError };
|
|
113578
|
+
}
|
|
113579
|
+
try {
|
|
113580
|
+
let modelOverride;
|
|
113581
|
+
try {
|
|
113582
|
+
modelOverride = await getGlobalDefaultModel(client, directory);
|
|
113583
|
+
} catch (configErr) {
|
|
113584
|
+
log("warn", "\u8BFB\u53D6\u5168\u5C40\u6A21\u578B\u914D\u7F6E\u5931\u8D25", {
|
|
113585
|
+
sessionKey,
|
|
113586
|
+
error: configErr instanceof Error ? configErr.message : String(configErr)
|
|
113587
|
+
});
|
|
113588
|
+
}
|
|
113589
|
+
if (!modelOverride) {
|
|
113590
|
+
log("warn", "\u5168\u5C40\u9ED8\u8BA4\u6A21\u578B\u672A\u914D\u7F6E\uFF0C\u653E\u5F03\u6062\u590D", { sessionKey });
|
|
113591
|
+
return { recovered: false, sessionError };
|
|
113592
|
+
}
|
|
113593
|
+
setRetryAttempts(sessionKey, attempts + 1);
|
|
113594
|
+
log("info", "\u4F7F\u7528\u5168\u5C40\u9ED8\u8BA4\u6A21\u578B\u6062\u590D", {
|
|
113595
|
+
sessionKey,
|
|
113596
|
+
providerID: modelOverride.providerID,
|
|
113597
|
+
modelID: modelOverride.modelID
|
|
113598
|
+
});
|
|
113599
|
+
clearSessionError(sessionId);
|
|
113600
|
+
await client.session.promptAsync({
|
|
113601
|
+
path: { id: sessionId },
|
|
113602
|
+
query,
|
|
113603
|
+
body: { parts: [...parts], model: modelOverride }
|
|
113604
|
+
});
|
|
113605
|
+
const finalText = await poll(client, sessionId, {
|
|
113606
|
+
timeout,
|
|
113607
|
+
pollInterval,
|
|
113608
|
+
stablePolls,
|
|
113609
|
+
query,
|
|
113610
|
+
signal
|
|
113611
|
+
});
|
|
113612
|
+
log("info", "\u6A21\u578B\u6062\u590D\u540E\u54CD\u5E94\u5B8C\u6210", {
|
|
113613
|
+
sessionKey,
|
|
113614
|
+
sessionId,
|
|
113615
|
+
output: finalText || "(empty)"
|
|
113616
|
+
});
|
|
113617
|
+
clearRetryAttempts(sessionKey);
|
|
113618
|
+
log("info", "\u6A21\u578B\u4E0D\u517C\u5BB9\u6062\u590D\u6210\u529F", {
|
|
113619
|
+
sessionId,
|
|
113620
|
+
sessionKey,
|
|
113621
|
+
model: `${modelOverride.providerID}/${modelOverride.modelID}`,
|
|
113622
|
+
attempt: attempts + 1
|
|
113623
|
+
});
|
|
113624
|
+
return { recovered: true, text: finalText };
|
|
113625
|
+
} catch (recoveryErr) {
|
|
113626
|
+
if (recoveryErr instanceof Error && recoveryErr.name === "AbortError") {
|
|
113627
|
+
throw recoveryErr;
|
|
113628
|
+
}
|
|
113629
|
+
const errMsg = recoveryErr instanceof Error ? recoveryErr.message : String(recoveryErr);
|
|
113630
|
+
let updatedError;
|
|
113631
|
+
if (recoveryErr instanceof SessionErrorDetected) {
|
|
113632
|
+
updatedError = recoveryErr.sessionError;
|
|
113633
|
+
clearSessionError(sessionId);
|
|
113634
|
+
} else {
|
|
113635
|
+
const sseError = getSessionError(sessionId);
|
|
113636
|
+
if (sseError) {
|
|
113637
|
+
updatedError = sseError;
|
|
113638
|
+
clearSessionError(sessionId);
|
|
113639
|
+
} else {
|
|
113640
|
+
updatedError = { message: errMsg, fields: [] };
|
|
113641
|
+
}
|
|
113642
|
+
}
|
|
113643
|
+
log("error", "\u6A21\u578B\u6062\u590D\u5931\u8D25", { sessionId, sessionKey, error: errMsg });
|
|
113644
|
+
return { recovered: false, sessionError: updatedError };
|
|
113645
|
+
}
|
|
113646
|
+
}
|
|
113647
|
+
|
|
113535
113648
|
// src/session.ts
|
|
113536
113649
|
var SESSION_KEY_PREFIX = "feishu";
|
|
113537
113650
|
var TITLE_PREFIX = "Feishu";
|
|
@@ -113907,108 +114020,50 @@ async function handleChat(ctx, deps, signal) {
|
|
|
113907
114020
|
await abortCleanup(streamingCard, feishuClient, placeholderId);
|
|
113908
114021
|
return void 0;
|
|
113909
114022
|
}
|
|
113910
|
-
|
|
113911
|
-
|
|
113912
|
-
sessionError = err.sessionError;
|
|
113913
|
-
clearSessionError(session.id);
|
|
113914
|
-
} else {
|
|
113915
|
-
sessionError = getSessionError(session.id);
|
|
113916
|
-
clearSessionError(session.id);
|
|
113917
|
-
}
|
|
114023
|
+
const sessionError = extractSessionError(err, session.id);
|
|
114024
|
+
let displayError = sessionError;
|
|
113918
114025
|
if (sessionError) {
|
|
113919
|
-
|
|
113920
|
-
|
|
113921
|
-
|
|
113922
|
-
|
|
113923
|
-
});
|
|
113924
|
-
}
|
|
113925
|
-
if (sessionError && isModelError(sessionError.fields)) {
|
|
113926
|
-
const attempts = getRetryAttempts(sessionKey);
|
|
113927
|
-
if (attempts < MAX_RETRY_ATTEMPTS) {
|
|
113928
|
-
try {
|
|
113929
|
-
let modelOverride;
|
|
113930
|
-
try {
|
|
113931
|
-
modelOverride = await getGlobalDefaultModel(client, directory);
|
|
113932
|
-
} catch (configErr) {
|
|
113933
|
-
log("warn", "\u8BFB\u53D6\u5168\u5C40\u6A21\u578B\u914D\u7F6E\u5931\u8D25", {
|
|
113934
|
-
sessionKey,
|
|
113935
|
-
error: configErr instanceof Error ? configErr.message : String(configErr)
|
|
113936
|
-
});
|
|
113937
|
-
}
|
|
113938
|
-
if (!modelOverride) {
|
|
113939
|
-
log("warn", "\u5168\u5C40\u9ED8\u8BA4\u6A21\u578B\u672A\u914D\u7F6E\uFF0C\u653E\u5F03\u6062\u590D", { sessionKey });
|
|
113940
|
-
} else {
|
|
113941
|
-
setRetryAttempts(sessionKey, attempts + 1);
|
|
113942
|
-
log("info", "\u4F7F\u7528\u5168\u5C40\u9ED8\u8BA4\u6A21\u578B\u6062\u590D", {
|
|
113943
|
-
sessionKey,
|
|
113944
|
-
providerID: modelOverride.providerID,
|
|
113945
|
-
modelID: modelOverride.modelID
|
|
113946
|
-
});
|
|
113947
|
-
clearSessionError(session.id);
|
|
113948
|
-
await client.session.promptAsync({
|
|
113949
|
-
path: { id: session.id },
|
|
113950
|
-
query,
|
|
113951
|
-
body: { ...baseBody, model: modelOverride }
|
|
113952
|
-
});
|
|
113953
|
-
const finalText = await pollForResponse(client, session.id, { timeout, pollInterval, stablePolls, query, signal });
|
|
113954
|
-
log("info", "\u6A21\u578B\u6062\u590D\u540E\u54CD\u5E94\u5B8C\u6210", {
|
|
113955
|
-
sessionKey,
|
|
113956
|
-
sessionId: session.id,
|
|
113957
|
-
output: finalText || "(empty)"
|
|
113958
|
-
});
|
|
113959
|
-
clearRetryAttempts(sessionKey);
|
|
113960
|
-
await finalizeReply(streamingCard, feishuClient, chatId, placeholderId, finalText || "\u26A0\uFE0F \u54CD\u5E94\u8D85\u65F6");
|
|
113961
|
-
log("info", "\u6A21\u578B\u4E0D\u517C\u5BB9\u6062\u590D\u6210\u529F", {
|
|
113962
|
-
sessionId: session.id,
|
|
113963
|
-
sessionKey,
|
|
113964
|
-
model: `${modelOverride.providerID}/${modelOverride.modelID}`,
|
|
113965
|
-
attempt: attempts + 1
|
|
113966
|
-
});
|
|
113967
|
-
if (config2.autoPrompt.enabled && shouldReply) {
|
|
113968
|
-
return { sessionId: session.id, sessionKey, chatId, deps };
|
|
113969
|
-
}
|
|
113970
|
-
return void 0;
|
|
113971
|
-
}
|
|
113972
|
-
} catch (recoveryErr) {
|
|
113973
|
-
if (recoveryErr instanceof Error && recoveryErr.name === "AbortError") {
|
|
113974
|
-
log("info", "\u6A21\u578B\u6062\u590D\u88AB\u4E2D\u65AD", { sessionKey });
|
|
113975
|
-
await abortCleanup(streamingCard, feishuClient, placeholderId);
|
|
113976
|
-
return void 0;
|
|
113977
|
-
}
|
|
113978
|
-
const errMsg = recoveryErr instanceof Error ? recoveryErr.message : String(recoveryErr);
|
|
113979
|
-
if (recoveryErr instanceof SessionErrorDetected) {
|
|
113980
|
-
sessionError = recoveryErr.sessionError;
|
|
113981
|
-
clearSessionError(session.id);
|
|
113982
|
-
} else {
|
|
113983
|
-
const sseError = getSessionError(session.id);
|
|
113984
|
-
if (sseError) {
|
|
113985
|
-
sessionError = sseError;
|
|
113986
|
-
clearSessionError(session.id);
|
|
113987
|
-
} else {
|
|
113988
|
-
sessionError = { message: errMsg, fields: [] };
|
|
113989
|
-
}
|
|
113990
|
-
}
|
|
113991
|
-
log("error", "\u6A21\u578B\u6062\u590D\u5931\u8D25", {
|
|
113992
|
-
sessionId: session.id,
|
|
113993
|
-
sessionKey,
|
|
113994
|
-
error: errMsg
|
|
113995
|
-
});
|
|
113996
|
-
}
|
|
113997
|
-
} else {
|
|
113998
|
-
log("warn", "\u5DF2\u8FBE\u91CD\u8BD5\u4E0A\u9650\uFF0C\u653E\u5F03\u6062\u590D", {
|
|
114026
|
+
try {
|
|
114027
|
+
const recovery = await tryModelRecovery({
|
|
114028
|
+
sessionError,
|
|
114029
|
+
sessionId: session.id,
|
|
113999
114030
|
sessionKey,
|
|
114000
|
-
|
|
114031
|
+
client,
|
|
114032
|
+
directory,
|
|
114033
|
+
parts,
|
|
114034
|
+
timeout,
|
|
114035
|
+
pollInterval,
|
|
114036
|
+
stablePolls,
|
|
114037
|
+
query,
|
|
114038
|
+
signal,
|
|
114039
|
+
log,
|
|
114040
|
+
poll: pollForResponse
|
|
114001
114041
|
});
|
|
114042
|
+
if (recovery.recovered) {
|
|
114043
|
+
await finalizeReply(streamingCard, feishuClient, chatId, placeholderId, recovery.text || "\u26A0\uFE0F \u54CD\u5E94\u8D85\u65F6");
|
|
114044
|
+
if (config2.autoPrompt.enabled && shouldReply) {
|
|
114045
|
+
return { sessionId: session.id, sessionKey, chatId, deps };
|
|
114046
|
+
}
|
|
114047
|
+
return void 0;
|
|
114048
|
+
}
|
|
114049
|
+
displayError = recovery.sessionError;
|
|
114050
|
+
} catch (abortErr) {
|
|
114051
|
+
if (abortErr instanceof Error && abortErr.name === "AbortError") {
|
|
114052
|
+
log("info", "\u6A21\u578B\u6062\u590D\u88AB\u4E2D\u65AD", { sessionKey });
|
|
114053
|
+
await abortCleanup(streamingCard, feishuClient, placeholderId);
|
|
114054
|
+
return void 0;
|
|
114055
|
+
}
|
|
114056
|
+
throw abortErr;
|
|
114002
114057
|
}
|
|
114003
114058
|
}
|
|
114004
114059
|
const thrownError = err instanceof Error ? err.message : String(err);
|
|
114005
|
-
const errorMessage =
|
|
114060
|
+
const errorMessage = displayError?.message || thrownError;
|
|
114006
114061
|
log("error", "\u5BF9\u8BDD\u5904\u7406\u5931\u8D25", {
|
|
114007
114062
|
sessionId: session.id,
|
|
114008
114063
|
sessionKey,
|
|
114009
114064
|
chatType,
|
|
114010
114065
|
error: thrownError,
|
|
114011
|
-
...
|
|
114066
|
+
...displayError ? { sessionError: displayError.message } : {}
|
|
114012
114067
|
});
|
|
114013
114068
|
await finalizeReply(streamingCard, feishuClient, chatId, placeholderId, "\u274C " + errorMessage);
|
|
114014
114069
|
} finally {
|
|
@@ -114018,17 +114073,6 @@ async function handleChat(ctx, deps, signal) {
|
|
|
114018
114073
|
unregisterPending(activeSessionId);
|
|
114019
114074
|
}
|
|
114020
114075
|
}
|
|
114021
|
-
async function getGlobalDefaultModel(client, directory) {
|
|
114022
|
-
const query = directory ? { directory } : void 0;
|
|
114023
|
-
const { data: config2 } = await client.config.get({ query });
|
|
114024
|
-
const model = config2?.model;
|
|
114025
|
-
if (!model || !model.includes("/")) return void 0;
|
|
114026
|
-
const slash = model.indexOf("/");
|
|
114027
|
-
const providerID = model.slice(0, slash).trim();
|
|
114028
|
-
const modelID = model.slice(slash + 1).trim();
|
|
114029
|
-
if (!providerID || !modelID) return void 0;
|
|
114030
|
-
return { providerID, modelID };
|
|
114031
|
-
}
|
|
114032
114076
|
async function buildPromptParts(feishuClient, messageId, messageType, rawContent, textContent, chatType, senderId, log) {
|
|
114033
114077
|
if (messageType === "text") {
|
|
114034
114078
|
let promptText = textContent;
|
|
@@ -114043,13 +114087,6 @@ async function buildPromptParts(feishuClient, messageId, messageType, rawContent
|
|
|
114043
114087
|
}
|
|
114044
114088
|
return parts;
|
|
114045
114089
|
}
|
|
114046
|
-
var SessionErrorDetected = class extends Error {
|
|
114047
|
-
constructor(sessionError) {
|
|
114048
|
-
super(sessionError.message);
|
|
114049
|
-
this.sessionError = sessionError;
|
|
114050
|
-
this.name = "SessionErrorDetected";
|
|
114051
|
-
}
|
|
114052
|
-
};
|
|
114053
114090
|
async function pollForResponse(client, sessionId, opts) {
|
|
114054
114091
|
const { timeout, pollInterval, stablePolls, query, signal } = opts;
|
|
114055
114092
|
const start = Date.now();
|
|
@@ -114170,6 +114207,7 @@ function extractLastAssistantText(messages) {
|
|
|
114170
114207
|
}
|
|
114171
114208
|
|
|
114172
114209
|
// src/handler/session-queue.ts
|
|
114210
|
+
var QUEUE_MONITOR_INTERVAL_MS = 200;
|
|
114173
114211
|
var states = /* @__PURE__ */ new Map();
|
|
114174
114212
|
function getOrCreateState(sessionKey) {
|
|
114175
114213
|
const existing = states.get(sessionKey);
|
|
@@ -114317,7 +114355,7 @@ async function drainLoop(sessionKey, state) {
|
|
|
114317
114355
|
const autoPromptController = new AbortController();
|
|
114318
114356
|
const monitor = setInterval(() => {
|
|
114319
114357
|
if (state.queue.length > 0) autoPromptController.abort();
|
|
114320
|
-
},
|
|
114358
|
+
}, QUEUE_MONITOR_INTERVAL_MS);
|
|
114321
114359
|
try {
|
|
114322
114360
|
const result = await runOneAutoPromptIteration(
|
|
114323
114361
|
autoPromptCtx,
|
|
@@ -114480,21 +114518,9 @@ var FeishuPlugin = async (ctx) => {
|
|
|
114480
114518
|
});
|
|
114481
114519
|
};
|
|
114482
114520
|
const configPath = join(homedir(), ".config", "opencode", "plugins", "feishu.json");
|
|
114483
|
-
if (!existsSync(configPath)) {
|
|
114484
|
-
throw new Error(
|
|
114485
|
-
`\u7F3A\u5C11\u98DE\u4E66\u914D\u7F6E\u6587\u4EF6\uFF1A\u8BF7\u521B\u5EFA ${configPath}\uFF0C\u5185\u5BB9\u4E3A {"appId":"cli_xxx","appSecret":"xxx"}`
|
|
114486
|
-
);
|
|
114487
|
-
}
|
|
114488
114521
|
let resolvedConfig;
|
|
114489
114522
|
try {
|
|
114490
|
-
|
|
114491
|
-
JSON.parse(readFileSync(configPath, "utf-8"))
|
|
114492
|
-
);
|
|
114493
|
-
const parsed = FeishuConfigSchema.parse(raw);
|
|
114494
|
-
resolvedConfig = {
|
|
114495
|
-
...parsed,
|
|
114496
|
-
directory: expandDirectoryPath(parsed.directory ?? ctx.directory ?? "")
|
|
114497
|
-
};
|
|
114523
|
+
resolvedConfig = loadAndValidateConfig(configPath, ctx.directory ?? "");
|
|
114498
114524
|
} catch (e) {
|
|
114499
114525
|
if (e instanceof external_exports.ZodError) {
|
|
114500
114526
|
const details = e.issues.map((i) => ` - ${i.path.join(".")}: ${i.message}`).join("\n");
|
|
@@ -114573,6 +114599,14 @@ ${details}`);
|
|
|
114573
114599
|
};
|
|
114574
114600
|
return hooks;
|
|
114575
114601
|
};
|
|
114602
|
+
function loadAndValidateConfig(configPath, ctxDirectory) {
|
|
114603
|
+
if (!existsSync(configPath)) {
|
|
114604
|
+
throw new Error(`\u7F3A\u5C11\u98DE\u4E66\u914D\u7F6E\u6587\u4EF6\uFF1A\u8BF7\u521B\u5EFA ${configPath}\uFF0C\u5185\u5BB9\u4E3A {"appId":"cli_xxx","appSecret":"xxx"}`);
|
|
114605
|
+
}
|
|
114606
|
+
const raw = resolveEnvPlaceholders(JSON.parse(readFileSync(configPath, "utf-8")));
|
|
114607
|
+
const parsed = FeishuConfigSchema.parse(raw);
|
|
114608
|
+
return { ...parsed, directory: expandDirectoryPath(parsed.directory ?? ctxDirectory ?? "") };
|
|
114609
|
+
}
|
|
114576
114610
|
function expandDirectoryPath(dir) {
|
|
114577
114611
|
if (!dir) return dir;
|
|
114578
114612
|
if (dir.startsWith("~")) {
|