larkway 0.3.19 → 0.3.21
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 +1 -1
- package/README.zh.md +1 -1
- package/dist/cli/index.js +45 -23
- package/dist/main.js +295 -48
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
You @ the bot in a Feishu thread. It runs on your machine — reading your real codebase, executing commands, opening MRs — and posts the result back. You define what the agent knows and what it can do. Larkway just carries the messages.
|
|
10
10
|
|
|
11
|
-
**Current release: v0.3.
|
|
11
|
+
**Current release: v0.3.21**
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
package/README.zh.md
CHANGED
package/dist/cli/index.js
CHANGED
|
@@ -111269,6 +111269,20 @@ var init_channelPostClient = __esm({
|
|
|
111269
111269
|
}
|
|
111270
111270
|
return { messageId };
|
|
111271
111271
|
}
|
|
111272
|
+
async updatePost(messageId, content) {
|
|
111273
|
+
const res = await withPostRetry(
|
|
111274
|
+
"updatePost",
|
|
111275
|
+
() => this.channel().rawClient.im.v1.message.update({
|
|
111276
|
+
path: { message_id: messageId },
|
|
111277
|
+
data: {
|
|
111278
|
+
content,
|
|
111279
|
+
msg_type: "post"
|
|
111280
|
+
}
|
|
111281
|
+
}),
|
|
111282
|
+
{ maxAttempts: this.maxAttempts, baseDelayMs: this.baseDelayMs }
|
|
111283
|
+
);
|
|
111284
|
+
return { messageId: res.data?.message_id ?? messageId };
|
|
111285
|
+
}
|
|
111272
111286
|
};
|
|
111273
111287
|
}
|
|
111274
111288
|
});
|
|
@@ -123677,12 +123691,13 @@ import path from "node:path";
|
|
|
123677
123691
|
var NonEmptyString = external_exports.string().trim().min(1);
|
|
123678
123692
|
function defaultResponseSurfacePrototypeConfig() {
|
|
123679
123693
|
return {
|
|
123680
|
-
enabled:
|
|
123694
|
+
enabled: true,
|
|
123681
123695
|
allowed_chats: [],
|
|
123682
123696
|
allowed_threads: [],
|
|
123683
|
-
lazy_card_creation:
|
|
123697
|
+
lazy_card_creation: true,
|
|
123684
123698
|
kill_switch: false,
|
|
123685
|
-
post_outbound_enabled:
|
|
123699
|
+
post_outbound_enabled: true,
|
|
123700
|
+
allow_agent_mentions: true,
|
|
123686
123701
|
allowed_mention_open_ids: [],
|
|
123687
123702
|
max_posts_per_turn: 1,
|
|
123688
123703
|
max_posts_per_window: 4,
|
|
@@ -123693,12 +123708,13 @@ function defaultResponseSurfacePrototypeConfig() {
|
|
|
123693
123708
|
}
|
|
123694
123709
|
var DEFAULT_RESPONSE_SURFACE_PROTOTYPE = defaultResponseSurfacePrototypeConfig();
|
|
123695
123710
|
var responseSurfacePrototypeConfigDefaults = () => ({
|
|
123696
|
-
enabled:
|
|
123711
|
+
enabled: true,
|
|
123697
123712
|
allowed_chats: [],
|
|
123698
123713
|
allowed_threads: [],
|
|
123699
|
-
lazy_card_creation:
|
|
123714
|
+
lazy_card_creation: true,
|
|
123700
123715
|
kill_switch: false,
|
|
123701
|
-
post_outbound_enabled:
|
|
123716
|
+
post_outbound_enabled: true,
|
|
123717
|
+
allow_agent_mentions: true,
|
|
123702
123718
|
allowed_mention_open_ids: [],
|
|
123703
123719
|
max_posts_per_turn: 1,
|
|
123704
123720
|
max_posts_per_window: 4,
|
|
@@ -123747,40 +123763,46 @@ var ResponseSurfaceStateSchema = external_exports.preprocess((value) => {
|
|
|
123747
123763
|
}, StrictResponseSurfaceStateSchema.optional());
|
|
123748
123764
|
var ResponseSurfacePrototypeConfigSchema = external_exports.object({
|
|
123749
123765
|
/**
|
|
123750
|
-
* Master gate. Default
|
|
123766
|
+
* Master gate. Default true makes response surfaces available unless the
|
|
123767
|
+
* runtime kill switch disables them.
|
|
123751
123768
|
*/
|
|
123752
|
-
enabled: external_exports.boolean().default(
|
|
123769
|
+
enabled: external_exports.boolean().default(true),
|
|
123753
123770
|
/**
|
|
123754
|
-
* Optional chat allowlist for
|
|
123755
|
-
*
|
|
123771
|
+
* Optional chat allowlist for staged rollout. Empty means all chats are
|
|
123772
|
+
* allowed by this gate.
|
|
123756
123773
|
*/
|
|
123757
123774
|
allowed_chats: external_exports.array(external_exports.string().min(1)).default([]),
|
|
123758
123775
|
/**
|
|
123759
|
-
* Optional Larkway session/thread allowlist for
|
|
123760
|
-
*
|
|
123776
|
+
* Optional Larkway session/thread allowlist for staged rollout. Empty means
|
|
123777
|
+
* all threads are allowed by this gate.
|
|
123761
123778
|
*/
|
|
123762
123779
|
allowed_threads: external_exports.array(external_exports.string().min(1)).default([]),
|
|
123763
123780
|
/**
|
|
123764
|
-
*
|
|
123765
|
-
* the
|
|
123766
|
-
*
|
|
123781
|
+
* Post-first gate. Default true means the bridge starts a lightweight post
|
|
123782
|
+
* as the live main surface when post outbound is available, and creates a
|
|
123783
|
+
* card only for fallback or card-only capabilities.
|
|
123767
123784
|
*/
|
|
123768
|
-
lazy_card_creation: external_exports.boolean().default(
|
|
123785
|
+
lazy_card_creation: external_exports.boolean().default(true),
|
|
123769
123786
|
/**
|
|
123770
123787
|
* Runtime kill switch for emergency rollback. When true, every response
|
|
123771
123788
|
* surface post path is treated as disabled even if enabled/allowlists are
|
|
123772
|
-
* otherwise configured.
|
|
123789
|
+
* otherwise configured.
|
|
123773
123790
|
*/
|
|
123774
123791
|
kill_switch: external_exports.boolean().default(false),
|
|
123775
123792
|
/**
|
|
123776
|
-
*
|
|
123777
|
-
*
|
|
123793
|
+
* Gate for real post outbound. Defaults on, but the runtime still requires
|
|
123794
|
+
* an injected post client and all safety gates before any post path.
|
|
123795
|
+
*/
|
|
123796
|
+
post_outbound_enabled: external_exports.boolean().default(true),
|
|
123797
|
+
/**
|
|
123798
|
+
* Allows Agent-authored post mentions. This powers handoff to peer bots.
|
|
123799
|
+
* Keep this false only when the operator wants to suppress every real @.
|
|
123778
123800
|
*/
|
|
123779
|
-
|
|
123801
|
+
allow_agent_mentions: external_exports.boolean().default(true),
|
|
123780
123802
|
/**
|
|
123781
|
-
*
|
|
123782
|
-
*
|
|
123783
|
-
* in public docs/tests.
|
|
123803
|
+
* Optional target allowlist for real post @ mentions. Empty means the Agent
|
|
123804
|
+
* may choose mention targets; non-empty narrows mentions to this exact set.
|
|
123805
|
+
* Keep real IDs in private bot config, never in public docs/tests.
|
|
123784
123806
|
*/
|
|
123785
123807
|
allowed_mention_open_ids: external_exports.array(external_exports.string().min(1)).default([]),
|
|
123786
123808
|
/**
|
package/dist/main.js
CHANGED
|
@@ -115497,6 +115497,20 @@ var ChannelPostClient = class {
|
|
|
115497
115497
|
}
|
|
115498
115498
|
return { messageId };
|
|
115499
115499
|
}
|
|
115500
|
+
async updatePost(messageId, content) {
|
|
115501
|
+
const res = await withPostRetry(
|
|
115502
|
+
"updatePost",
|
|
115503
|
+
() => this.channel().rawClient.im.v1.message.update({
|
|
115504
|
+
path: { message_id: messageId },
|
|
115505
|
+
data: {
|
|
115506
|
+
content,
|
|
115507
|
+
msg_type: "post"
|
|
115508
|
+
}
|
|
115509
|
+
}),
|
|
115510
|
+
{ maxAttempts: this.maxAttempts, baseDelayMs: this.baseDelayMs }
|
|
115511
|
+
);
|
|
115512
|
+
return { messageId: res.data?.message_id ?? messageId };
|
|
115513
|
+
}
|
|
115500
115514
|
};
|
|
115501
115515
|
|
|
115502
115516
|
// src/lark/channelClient.ts
|
|
@@ -117434,10 +117448,12 @@ function renderStateContract(stateFilePath) {
|
|
|
117434
117448
|
const stateTarget = stateFilePath ? `\u6307\u5B9A\u8DEF\u5F84 \`${stateFilePath}\`` : "\u5DE5\u4F5C\u76EE\u5F55\u91CC\u7684 `.larkway/state.json`";
|
|
117435
117449
|
return [
|
|
117436
117450
|
"<state-contract>",
|
|
117437
|
-
"\u4F60\u548C\u8FD0\u8425\u4E4B\u95F4\u7684\u754C\u9762\u662F\u98DE\u4E66\u8BDD\u9898\u91CC\u7684
|
|
117438
|
-
"-
|
|
117439
|
-
"- \
|
|
117440
|
-
|
|
117451
|
+
"\u4F60\u548C\u8FD0\u8425\u4E4B\u95F4\u7684\u754C\u9762\u662F\u98DE\u4E66\u8BDD\u9898\u91CC\u7684 response surface,\u8FD9\u662F\u4E00\u4E2A thin-channel \u5916\u58F3:",
|
|
117452
|
+
"- \u9ED8\u8BA4\u4E3B\u56DE\u590D\u9762\u662F post/RichText:bridge \u8D77\u624B\u53D1\u4E00\u6761\u8F7B\u91CF\u201C\u6B63\u5728\u5904\u7406\u2026\u201Dpost,\u6267\u884C\u4E2D\u7528\u5206\u5757\u7EA7\u539F\u5730\u7F16\u8F91\u6A21\u62DF\u6D41\u5F0F\u8F93\u51FA,\u7ED3\u675F\u65F6\u7F16\u8F91\u6210\u5E72\u51C0\u7EC8\u7A3F\u3002",
|
|
117453
|
+
"- \u5361\u7247\u662F\u4F8B\u5916\u8865\u5145\u9762,\u53EA\u5728\u9700\u8981\u79BB\u6563\u9009\u62E9/\u6309\u94AE(`choices`)\u6216 post \u8868\u8FBE\u4E0D\u4E86\u7684\u7ED3\u6784\u5316\u5185\u5BB9(`content_blocks`/`image_blocks`,\u4F8B\u5982\u56FE\u7247\u7EC4\u3001\u9A8C\u6536\u6E05\u5355\u3001dev \u9884\u89C8)\u65F6\u624D\u8865\u4E00\u5F20\u3002",
|
|
117454
|
+
"- bridge \u8D1F\u8D23\u521B\u5EFA/\u7F16\u8F91 post\u3001\u5FC5\u8981\u65F6\u521B\u5EFA/\u66F4\u65B0\u98DE\u4E66\u5361\u7247\u3001\u8282\u6D41\u3001\u6E32\u67D3\u6B63\u6587\u3001\u628A choices \u8F6C\u6210\u6309\u94AE\u5E76\u628A\u70B9\u51FB\u503C\u56DE\u4F20\u7ED9\u4F60\u3002",
|
|
117455
|
+
"- \u4F60\u8D1F\u8D23\u628A\u6700\u7EC8\u7ED9\u8FD0\u8425\u770B\u7684\u6B63\u6587\u3001\u72B6\u6001\u3001\u4E0B\u4E00\u6B65\u95EE\u9898\u3001\u662F\u5426\u9700\u8981 choices/\u7ED3\u6784\u5316\u5361\u7247\u5199\u8FDB state.json\u3002",
|
|
117456
|
+
`\u4F60\u4E0D\u76F4\u63A5\u53D1/\u7F16\u8F91 bridge \u7BA1\u7406\u7684 post \u6216\u5361\u7247;\u4F60\u53EA\u5199 ${stateTarget},bridge \u8BFB\u5B83\u6765\u505A\u5B89\u5168\u6E32\u67D3\u3002`,
|
|
117441
117457
|
"**\u5B8C\u6210\u672C\u6B21\u54CD\u5E94\u524D\u5FC5\u987B**\u6839\u636E\u5F53\u524D\u5B9E\u9645\u72B6\u6001\u66F4\u65B0\u8FD9\u4E2A\u6587\u4EF6(\u539F\u5B50\u5199:\u5199 .tmp \u518D mv)\u3002",
|
|
117442
117458
|
"",
|
|
117443
117459
|
"\u4F60\u80FD\u5199\u7684\u5B57\u6BB5:",
|
|
@@ -117448,18 +117464,19 @@ function renderStateContract(stateFilePath) {
|
|
|
117448
117464
|
"- card_color: \u5361\u7247\u914D\u8272(\u53EF\u9009,success/failure/neutral,\u4E5F\u53EF\u76F4\u63A5\u5199 green/red/grey)",
|
|
117449
117465
|
"- image_blocks: \u53EF\u9009\u56FE\u7247\u9884\u89C8\u5757\u6570\u7EC4,\u6700\u591A 4 \u4E2A\u3002\u6BCF\u9879 `{img_key, alt?, title?, mode?, preview?}`; `img_key` \u5FC5\u987B\u662F\u5DF2\u4E0A\u4F20/\u53EF\u7528\u4E8E\u5361\u7247\u7684 Feishu \u56FE\u7247 key,`alt` \u7701\u7565\u65F6 bridge \u9ED8\u8BA4\u201C\u56FE\u7247\u9884\u89C8\u201D,`mode` \u53EA\u5141\u8BB8 `crop_center`/`fit_horizontal` \u5E76\u6620\u5C04\u5230 Card JSON 2.0 `scale_type`,`preview` \u9ED8\u8BA4 true\u3002bridge \u4E0D\u8D1F\u8D23\u4E0B\u8F7D/\u4E0A\u4F20/\u9009\u62E9\u56FE\u7247;\u8FD9\u4E9B\u7531\u4F60\u7528 lark-cli \u7B49\u5DE5\u5177\u5148\u5B8C\u6210\u3002",
|
|
117450
117466
|
'- content_blocks: \u53EF\u9009\u6709\u5E8F\u6B63\u6587\u5757\u6570\u7EC4,\u6700\u591A 12 \u4E2A block\u3001\u6700\u591A 4 \u4E2A image block\u3002\u53EA\u652F\u6301\u7A84 union:`{type:"markdown", content}` \u548C `{type:"image", img_key, alt?, title?, mode?, preview?}`;\u4E0D\u652F\u6301 raw card JSON\u3002\u7528\u4E8E\u6B63\u6587\u4E0E\u56FE\u7247\u4EA4\u9519\u6392\u7248,\u4F8B\u5982 markdown -> image -> markdown -> image\u3002\u82E5 `content_blocks` \u975E\u7A7A,bridge \u4EE5\u5B83\u4F5C\u4E3A\u4E3B\u6B63\u6587\u5E76\u5FFD\u7565 `last_message` + `image_blocks` \u7684\u6B63\u6587\u6E32\u67D3,\u907F\u514D\u91CD\u590D;\u82E5\u7701\u7565\u5219\u4FDD\u6301\u65E7 `last_message` + `image_blocks` \u884C\u4E3A\u3002',
|
|
117451
|
-
'- response_surface: \u53EF\u9009\
|
|
117467
|
+
'- response_surface: \u53EF\u9009\u8986\u76D6\u5B57\u6BB5,\u5F62\u5982 `{mode:"card"|"post"|"hybrid", primary?:"card"|"post", post?:{mentions:[{user_id,label?}]}, card?:{compact?:boolean, capabilities?:[...]}}`\u3002\u9ED8\u8BA4\u53EF\u4E0D\u5199;\u65E0\u663E\u5F0F card \u610F\u56FE\u65F6 bridge \u6309 post-first \u5904\u7406\u3002\u9700\u8981\u771F\u5B9E @ \u65F6\u628A\u76EE\u6807\u5199\u5165 `post.mentions`;\u4E0D\u8981\u5199 raw Feishu post/card JSON\u3002',
|
|
117452
117468
|
"- scheduled reply / daily social ops review card \u7B49\u9700\u8981\u201C\u5E73\u53F0\u6B63\u6587 + \u5339\u914D\u56FE\u7247\u201D\u540C\u6BB5\u76F8\u90BB\u5C55\u793A\u7684\u573A\u666F,\u5E94\u5148\u53D6\u5F97\u5404\u56FE\u7247 `img_key`,\u518D\u5199 `content_blocks` \u4E3A `\u5E73\u53F0 markdown -> \u5BF9\u5E94 image -> \u4E0B\u4E2A\u5E73\u53F0 markdown -> \u5BF9\u5E94 image`;\u4E0D\u8981\u7528\u5355\u72EC\u8BDD\u9898\u56FE\u7247\u6D88\u606F\u6216\u5C3E\u90E8 `image_blocks` \u4EE3\u66FF\u9A8C\u6536\u9762\u3002",
|
|
117453
117469
|
"- dev_url / mr_url / \u5176\u4F59\u4E1A\u52A1\u5B57\u6BB5:\u81EA\u7531\u5199\u5165,bridge \u4E0D\u611F\u77E5\u5176\u4E1A\u52A1\u542B\u4E49;\u8981\u8BA9\u8FD0\u8425\u770B\u5230,\u8BF7\u5199\u8FDB last_message",
|
|
117454
117470
|
"- updated_at: ISO 8601 timestamp",
|
|
117455
117471
|
"",
|
|
117456
|
-
"**\u7EDD\u4E0D\u81EA\u5DF1 `lark-cli api PATCH .../im/v1/messages/...` \u6539\
|
|
117457
|
-
"\u81EA\u5DF1
|
|
117458
|
-
"\u5199\u5B8C state.json \u5C31**\u5E72\u51C0\u7ED3\u675F\u672C\u8F6E**(\u4F60\u7684\u8FDB\u7A0B\u9000\u51FA \u2192 bridge \u624D
|
|
117459
|
-
"\u6302\u7740\u4E0D\u9000\u51FA = \
|
|
117472
|
+
"**\u7EDD\u4E0D\u81EA\u5DF1 `lark-cli api PATCH/PUT .../im/v1/messages/...` \u6539 bridge \u7BA1\u7406\u7684 post/card** \u2014\u2014 \u90A3\u662F bridge \u7684\u6D3B;",
|
|
117473
|
+
"\u81EA\u5DF1\u53D1/\u6539\u4E3B\u56DE\u590D\u9762\u4F1A\u548C bridge \u7684 post \u7F16\u8F91\u3001\u5361\u7247 finalize\u3001\u6309\u94AE\u56DE\u4F20\u3001\u5D29\u6E83\u6062\u590D\u51B2\u7A81\u3002\u4F60\u53EA\u5199 state.json,\u7F51\u7EDC\u66F4\u65B0\u4EA4\u7ED9 bridge\u3002",
|
|
117474
|
+
"\u5199\u5B8C state.json \u5C31**\u5E72\u51C0\u7ED3\u675F\u672C\u8F6E**(\u4F60\u7684\u8FDB\u7A0B\u9000\u51FA \u2192 bridge \u624D\u628A post/card \u6536\u655B\u6210\u7EC8\u6001;",
|
|
117475
|
+
"\u6302\u7740\u4E0D\u9000\u51FA = \u8BDD\u9898\u6C38\u8FDC\u5361\u5728\u300C\u6B63\u5728\u5904\u7406\u2026\u300D)\u3002",
|
|
117460
117476
|
"",
|
|
117461
117477
|
"\u5361\u7247\u5C55\u793A\u539F\u5219:",
|
|
117462
|
-
"-
|
|
117478
|
+
"- \u8FD0\u884C\u4E2D\u4E3B\u9762\u662F post,bridge \u901A\u8FC7\u6574\u6761\u5BCC\u6587\u672C\u66FF\u6362\u505A\u5206\u5757\u5237\u65B0;\u5B83\u4E0D\u662F\u9010\u5B57 token streaming,\u4E0D\u8981\u4F9D\u8D56\u5DE5\u5177\u6D41/\u65E5\u5FD7\u8868\u8FBE\u4E1A\u52A1\u9636\u6BB5\u3002",
|
|
117479
|
+
"- \u6700\u7EC8 post \u4EE5\u4F60\u7684 `last_message` \u4E3A\u4E3B;\u82E5\u5199\u4E86 `choices`\u3001`content_blocks` \u6216 `image_blocks`,bridge \u4F1A\u5728 post \u4E4B\u540E\u8865\u5361\u7247\u627F\u8F7D\u8FD9\u4E9B\u80FD\u529B\u3002",
|
|
117463
117480
|
"- \u4E0D\u8981\u4F9D\u8D56 bridge \u4ECE\u8F93\u51FA\u91CC\u89E3\u6790\u4E1A\u52A1\u9636\u6BB5\u3001MR\u3001\u9884\u89C8\u5730\u5740\u6216\u4E0B\u4E00\u6B65\u52A8\u4F5C;\u9700\u8981\u5C55\u793A\u7684\u5185\u5BB9\u4F60\u81EA\u5DF1\u5199\u8FDB last_message\u3002",
|
|
117464
117481
|
"- \u4E0D\u8981\u6C42\u56FA\u5B9A\u683C\u5F0F\u3002\u6839\u636E\u4EFB\u52A1\u9009\u62E9\u6700\u6E05\u695A\u7684\u8868\u8FBE:\u77ED\u7ED3\u8BBA\u3001\u5206\u70B9\u3001\u8868\u683C\u3001\u94FE\u63A5\u3001\u4E0B\u4E00\u6B65\u95EE\u9898\u90FD\u53EF\u4EE5\u3002",
|
|
117465
117482
|
"- \u5982\u679C\u672C\u8F6E\u6D89\u53CA repo / \u4EE3\u7801 / \u6587\u6863\u4FEE\u6539,last_message \u5E94\u5305\u542B\u8DB3\u591F\u8BA9\u8FD0\u8425\u9A8C\u6536\u7684\u8BC1\u636E,\u4F8B\u5982\u4F60\u5B9E\u9645\u4F7F\u7528\u7684 workspace/repo\u3001\u5173\u952E diff \u6216\u94FE\u63A5\u3001\u8FD0\u884C\u8FC7\u7684\u6D4B\u8BD5/\u68C0\u67E5\u547D\u4EE4\u548C\u7ED3\u679C\u3002\u5177\u4F53\u8BC1\u636E\u7531\u4EFB\u52A1\u51B3\u5B9A;dogfood E2E \u7684\u4E25\u683C\u6E05\u5355\u53EA\u5728 dogfood guide \u4E2D\u8981\u6C42\u3002",
|
|
@@ -118256,12 +118273,13 @@ import path6 from "node:path";
|
|
|
118256
118273
|
var NonEmptyString = external_exports.string().trim().min(1);
|
|
118257
118274
|
function defaultResponseSurfacePrototypeConfig() {
|
|
118258
118275
|
return {
|
|
118259
|
-
enabled:
|
|
118276
|
+
enabled: true,
|
|
118260
118277
|
allowed_chats: [],
|
|
118261
118278
|
allowed_threads: [],
|
|
118262
|
-
lazy_card_creation:
|
|
118279
|
+
lazy_card_creation: true,
|
|
118263
118280
|
kill_switch: false,
|
|
118264
|
-
post_outbound_enabled:
|
|
118281
|
+
post_outbound_enabled: true,
|
|
118282
|
+
allow_agent_mentions: true,
|
|
118265
118283
|
allowed_mention_open_ids: [],
|
|
118266
118284
|
max_posts_per_turn: 1,
|
|
118267
118285
|
max_posts_per_window: 4,
|
|
@@ -118272,12 +118290,13 @@ function defaultResponseSurfacePrototypeConfig() {
|
|
|
118272
118290
|
}
|
|
118273
118291
|
var DEFAULT_RESPONSE_SURFACE_PROTOTYPE = defaultResponseSurfacePrototypeConfig();
|
|
118274
118292
|
var responseSurfacePrototypeConfigDefaults = () => ({
|
|
118275
|
-
enabled:
|
|
118293
|
+
enabled: true,
|
|
118276
118294
|
allowed_chats: [],
|
|
118277
118295
|
allowed_threads: [],
|
|
118278
|
-
lazy_card_creation:
|
|
118296
|
+
lazy_card_creation: true,
|
|
118279
118297
|
kill_switch: false,
|
|
118280
|
-
post_outbound_enabled:
|
|
118298
|
+
post_outbound_enabled: true,
|
|
118299
|
+
allow_agent_mentions: true,
|
|
118281
118300
|
allowed_mention_open_ids: [],
|
|
118282
118301
|
max_posts_per_turn: 1,
|
|
118283
118302
|
max_posts_per_window: 4,
|
|
@@ -118326,40 +118345,46 @@ var ResponseSurfaceStateSchema = external_exports.preprocess((value) => {
|
|
|
118326
118345
|
}, StrictResponseSurfaceStateSchema.optional());
|
|
118327
118346
|
var ResponseSurfacePrototypeConfigSchema = external_exports.object({
|
|
118328
118347
|
/**
|
|
118329
|
-
* Master gate. Default
|
|
118348
|
+
* Master gate. Default true makes response surfaces available unless the
|
|
118349
|
+
* runtime kill switch disables them.
|
|
118330
118350
|
*/
|
|
118331
|
-
enabled: external_exports.boolean().default(
|
|
118351
|
+
enabled: external_exports.boolean().default(true),
|
|
118332
118352
|
/**
|
|
118333
|
-
* Optional chat allowlist for
|
|
118334
|
-
*
|
|
118353
|
+
* Optional chat allowlist for staged rollout. Empty means all chats are
|
|
118354
|
+
* allowed by this gate.
|
|
118335
118355
|
*/
|
|
118336
118356
|
allowed_chats: external_exports.array(external_exports.string().min(1)).default([]),
|
|
118337
118357
|
/**
|
|
118338
|
-
* Optional Larkway session/thread allowlist for
|
|
118339
|
-
*
|
|
118358
|
+
* Optional Larkway session/thread allowlist for staged rollout. Empty means
|
|
118359
|
+
* all threads are allowed by this gate.
|
|
118340
118360
|
*/
|
|
118341
118361
|
allowed_threads: external_exports.array(external_exports.string().min(1)).default([]),
|
|
118342
118362
|
/**
|
|
118343
|
-
*
|
|
118344
|
-
* the
|
|
118345
|
-
*
|
|
118363
|
+
* Post-first gate. Default true means the bridge starts a lightweight post
|
|
118364
|
+
* as the live main surface when post outbound is available, and creates a
|
|
118365
|
+
* card only for fallback or card-only capabilities.
|
|
118346
118366
|
*/
|
|
118347
|
-
lazy_card_creation: external_exports.boolean().default(
|
|
118367
|
+
lazy_card_creation: external_exports.boolean().default(true),
|
|
118348
118368
|
/**
|
|
118349
118369
|
* Runtime kill switch for emergency rollback. When true, every response
|
|
118350
118370
|
* surface post path is treated as disabled even if enabled/allowlists are
|
|
118351
|
-
* otherwise configured.
|
|
118371
|
+
* otherwise configured.
|
|
118352
118372
|
*/
|
|
118353
118373
|
kill_switch: external_exports.boolean().default(false),
|
|
118354
118374
|
/**
|
|
118355
|
-
*
|
|
118356
|
-
*
|
|
118375
|
+
* Gate for real post outbound. Defaults on, but the runtime still requires
|
|
118376
|
+
* an injected post client and all safety gates before any post path.
|
|
118357
118377
|
*/
|
|
118358
|
-
post_outbound_enabled: external_exports.boolean().default(
|
|
118378
|
+
post_outbound_enabled: external_exports.boolean().default(true),
|
|
118359
118379
|
/**
|
|
118360
|
-
*
|
|
118361
|
-
*
|
|
118362
|
-
|
|
118380
|
+
* Allows Agent-authored post mentions. This powers handoff to peer bots.
|
|
118381
|
+
* Keep this false only when the operator wants to suppress every real @.
|
|
118382
|
+
*/
|
|
118383
|
+
allow_agent_mentions: external_exports.boolean().default(true),
|
|
118384
|
+
/**
|
|
118385
|
+
* Optional target allowlist for real post @ mentions. Empty means the Agent
|
|
118386
|
+
* may choose mention targets; non-empty narrows mentions to this exact set.
|
|
118387
|
+
* Keep real IDs in private bot config, never in public docs/tests.
|
|
118363
118388
|
*/
|
|
118364
118389
|
allowed_mention_open_ids: external_exports.array(external_exports.string().min(1)).default([]),
|
|
118365
118390
|
/**
|
|
@@ -118391,12 +118416,21 @@ var ResponseSurfacePrototypeConfigSchema = external_exports.object({
|
|
|
118391
118416
|
function isResponseSurfacePrototypeAllowlisted(config, facts) {
|
|
118392
118417
|
if (!config?.enabled) return false;
|
|
118393
118418
|
if (config.kill_switch) return false;
|
|
118419
|
+
const hasScopedAllowlist = config.allowed_chats.length > 0 || config.allowed_threads.length > 0;
|
|
118420
|
+
if (!hasScopedAllowlist) return true;
|
|
118394
118421
|
const chatAllowed = config.allowed_chats.length > 0 && config.allowed_chats.includes(facts.chatId);
|
|
118395
118422
|
const threadAllowed = config.allowed_threads.length > 0 && config.allowed_threads.includes(facts.threadId);
|
|
118396
118423
|
return chatAllowed || threadAllowed;
|
|
118397
118424
|
}
|
|
118425
|
+
function isResponseSurfaceMentionAllowed(config, userId) {
|
|
118426
|
+
if (!config?.allow_agent_mentions) return false;
|
|
118427
|
+
const normalized = userId.trim().toLowerCase();
|
|
118428
|
+
if (normalized === "all" || normalized === "@all") return false;
|
|
118429
|
+
if (config.allowed_mention_open_ids.length === 0) return true;
|
|
118430
|
+
return config.allowed_mention_open_ids.includes(userId);
|
|
118431
|
+
}
|
|
118398
118432
|
function shouldProvideResponseSurfacePostClient(config) {
|
|
118399
|
-
return !!(config?.enabled && !config.kill_switch && config.post_outbound_enabled && config.max_posts_per_turn >= 1 && config.max_posts_per_window >= 1
|
|
118433
|
+
return !!(config?.enabled && !config.kill_switch && config.post_outbound_enabled && config.max_posts_per_turn >= 1 && config.max_posts_per_window >= 1);
|
|
118400
118434
|
}
|
|
118401
118435
|
function isResponseSurfacePostOutboundAvailable(config, facts, opts) {
|
|
118402
118436
|
return !!(opts.postClientAvailable && shouldProvideResponseSurfacePostClient(config) && isResponseSurfacePrototypeAllowlisted(config, facts));
|
|
@@ -119202,6 +119236,9 @@ function fullCard(input, reason) {
|
|
|
119202
119236
|
function hasCardOnlyPayload(state) {
|
|
119203
119237
|
return !!(state?.choices?.length || state?.image_blocks?.length || state?.content_blocks?.length);
|
|
119204
119238
|
}
|
|
119239
|
+
function hasCardOnlyPayloadIn(input) {
|
|
119240
|
+
return !!(hasCardOnlyPayload(input.state) || input.baseCard.choices?.length || input.baseCard.imageBlocks?.length || input.baseCard.contentBlocks?.length);
|
|
119241
|
+
}
|
|
119205
119242
|
function compactAuditCard(input, post) {
|
|
119206
119243
|
const status = input.state?.status ?? (input.baseCard.success ? "ready" : "failed");
|
|
119207
119244
|
const title = input.baseCard.titleOverride ?? "Post \u5DF2\u53D1\u9001";
|
|
@@ -119228,7 +119265,7 @@ function policyBlockedCard(input) {
|
|
|
119228
119265
|
return {
|
|
119229
119266
|
...input.baseCard,
|
|
119230
119267
|
success: false,
|
|
119231
|
-
failureReason: "response_surface post mention target is
|
|
119268
|
+
failureReason: "response_surface post mention target is blocked by policy; visible card fallback used"
|
|
119232
119269
|
};
|
|
119233
119270
|
}
|
|
119234
119271
|
function postText(input) {
|
|
@@ -119271,10 +119308,18 @@ async function existingLedgerEntry(input, idempotencyKey) {
|
|
|
119271
119308
|
return ledger?.posts.find((post) => post.idempotencyKey === idempotencyKey) ?? null;
|
|
119272
119309
|
}
|
|
119273
119310
|
function sentResult(input, surface, post, reason) {
|
|
119311
|
+
if (hasCardOnlyPayloadIn(input)) {
|
|
119312
|
+
return {
|
|
119313
|
+
card: input.baseCard,
|
|
119314
|
+
reason: "post-sent-card-capability-required",
|
|
119315
|
+
visible: true,
|
|
119316
|
+
post
|
|
119317
|
+
};
|
|
119318
|
+
}
|
|
119274
119319
|
if (surface.mode === "hybrid" || input.cardStarted) {
|
|
119275
119320
|
return {
|
|
119276
119321
|
card: compactAuditCard(input, post),
|
|
119277
|
-
reason: reason === "post-ledger-already-sent" ? "post-ledger-already-sent" : surface.mode === "hybrid" ? "hybrid-post-sent-compact-card" :
|
|
119322
|
+
reason: reason === "post-ledger-already-sent" ? "post-ledger-already-sent" : surface.mode === "hybrid" ? "hybrid-post-sent-compact-card" : reason,
|
|
119278
119323
|
visible: true,
|
|
119279
119324
|
post
|
|
119280
119325
|
};
|
|
@@ -119317,10 +119362,11 @@ function emitSurfaceObservation(input) {
|
|
|
119317
119362
|
);
|
|
119318
119363
|
}
|
|
119319
119364
|
async function dispatchResponseSurfaceInner(input) {
|
|
119320
|
-
const
|
|
119321
|
-
if (
|
|
119365
|
+
const declaredSurface = input.state?.response_surface;
|
|
119366
|
+
if (declaredSurface?.mode === "card" || declaredSurface?.primary === "card") {
|
|
119322
119367
|
return fullCard(input, "legacy-card-mode");
|
|
119323
119368
|
}
|
|
119369
|
+
const surface = declaredSurface ?? { mode: "post", primary: "post" };
|
|
119324
119370
|
const cfg = input.prototypeConfig;
|
|
119325
119371
|
if (!cfg?.enabled) return fullCard(input, "prototype-disabled");
|
|
119326
119372
|
if (cfg.kill_switch) return fullCard(input, "kill-switch-active");
|
|
@@ -119339,15 +119385,12 @@ async function dispatchResponseSurfaceInner(input) {
|
|
|
119339
119385
|
if (!input.visibleFallbackAvailable) {
|
|
119340
119386
|
return fullCard(input, "visible-fallback-unavailable");
|
|
119341
119387
|
}
|
|
119342
|
-
if (hasCardOnlyPayload(input.state)) {
|
|
119343
|
-
return fullCard(input, "card-capability-required");
|
|
119344
|
-
}
|
|
119345
119388
|
if (!input.postLedgerAvailable || !input.worktreePath) {
|
|
119346
119389
|
return fullCard(input, "post-ledger-unavailable");
|
|
119347
119390
|
}
|
|
119348
119391
|
const mentions = surface.post?.mentions ?? [];
|
|
119349
119392
|
const blockedMention = mentions.find(
|
|
119350
|
-
(mention) => !cfg
|
|
119393
|
+
(mention) => !isResponseSurfaceMentionAllowed(cfg, mention.user_id)
|
|
119351
119394
|
);
|
|
119352
119395
|
const text = postText(input);
|
|
119353
119396
|
const policyDigest = digestPostContent(text);
|
|
@@ -119363,7 +119406,17 @@ async function dispatchResponseSurfaceInner(input) {
|
|
|
119363
119406
|
});
|
|
119364
119407
|
const now = input.now?.() ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
119365
119408
|
if (blockedMention) {
|
|
119366
|
-
const policyError = `mention target is not allowed: ${blockedMention.user_id}`;
|
|
119409
|
+
const policyError = `mention target is not allowed by response surface policy: ${blockedMention.user_id}`;
|
|
119410
|
+
if (input.livePost) {
|
|
119411
|
+
try {
|
|
119412
|
+
await input.postClient.updatePost(input.livePost.messageId, buildPostContent({ text }));
|
|
119413
|
+
} catch (err) {
|
|
119414
|
+
console.warn(
|
|
119415
|
+
"[surface_dispatch] live post policy-blocked cleanup update failed:",
|
|
119416
|
+
err
|
|
119417
|
+
);
|
|
119418
|
+
}
|
|
119419
|
+
}
|
|
119367
119420
|
await writeLedger(
|
|
119368
119421
|
input,
|
|
119369
119422
|
newLedgerEntry({
|
|
@@ -119398,7 +119451,7 @@ async function dispatchResponseSurfaceInner(input) {
|
|
|
119398
119451
|
}))
|
|
119399
119452
|
});
|
|
119400
119453
|
const contentDigest = digestPostContent(content);
|
|
119401
|
-
const idempotencyKey = derivePostIdempotencyKey({
|
|
119454
|
+
const idempotencyKey = input.livePost?.idempotencyKey ?? derivePostIdempotencyKey({
|
|
119402
119455
|
botId: input.facts.botId,
|
|
119403
119456
|
threadId: input.facts.threadId,
|
|
119404
119457
|
triggerMessageId: input.facts.triggerMessageId,
|
|
@@ -119451,7 +119504,7 @@ async function dispatchResponseSurfaceInner(input) {
|
|
|
119451
119504
|
}
|
|
119452
119505
|
};
|
|
119453
119506
|
}
|
|
119454
|
-
const budget = input.postBudget?.reserve();
|
|
119507
|
+
const budget = input.livePost ? void 0 : input.postBudget?.reserve();
|
|
119455
119508
|
if (budget && !budget.allowed) {
|
|
119456
119509
|
return {
|
|
119457
119510
|
...fullCard(input, "post-rate-limit-exhausted"),
|
|
@@ -119485,7 +119538,7 @@ async function dispatchResponseSurfaceInner(input) {
|
|
|
119485
119538
|
})
|
|
119486
119539
|
);
|
|
119487
119540
|
try {
|
|
119488
|
-
const sent = await input.postClient.createPostReply(input.facts.replyToMessageId, content, {
|
|
119541
|
+
const sent = input.livePost ? await input.postClient.updatePost(input.livePost.messageId, content) : await input.postClient.createPostReply(input.facts.replyToMessageId, content, {
|
|
119489
119542
|
replyInThread: input.facts.replyInThread,
|
|
119490
119543
|
idempotencyKey
|
|
119491
119544
|
});
|
|
@@ -119511,7 +119564,10 @@ async function dispatchResponseSurfaceInner(input) {
|
|
|
119511
119564
|
})
|
|
119512
119565
|
);
|
|
119513
119566
|
const post = { idempotencyKey, messageId: sent.messageId, role };
|
|
119514
|
-
return {
|
|
119567
|
+
return {
|
|
119568
|
+
...sentResult(input, surface, post, input.livePost ? "post-updated" : "post-sent"),
|
|
119569
|
+
budget
|
|
119570
|
+
};
|
|
119515
119571
|
} catch (err) {
|
|
119516
119572
|
const failedAt = input.now?.() ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
119517
119573
|
const error = err instanceof Error ? err.message : String(err);
|
|
@@ -119564,6 +119620,122 @@ async function dispatchResponseSurface(input) {
|
|
|
119564
119620
|
return result;
|
|
119565
119621
|
}
|
|
119566
119622
|
|
|
119623
|
+
// src/bridge/postProgress.ts
|
|
119624
|
+
var DEFAULT_PLACEHOLDER_TEXT = "\u6B63\u5728\u5904\u7406\u2026";
|
|
119625
|
+
var DEFAULT_PATCH_INTERVAL_MS = 1500;
|
|
119626
|
+
var DEFAULT_MAX_PROGRESS_EDITS = 16;
|
|
119627
|
+
function normalizeText2(text) {
|
|
119628
|
+
return text.replace(/\r\n/g, "\n").trim();
|
|
119629
|
+
}
|
|
119630
|
+
function progressText(raw, fallback) {
|
|
119631
|
+
const text = normalizeText2(raw);
|
|
119632
|
+
if (!text) return fallback;
|
|
119633
|
+
return text.length > 3500 ? `${text.slice(0, 3500)}
|
|
119634
|
+
|
|
119635
|
+
_\u5904\u7406\u4E2D\u5185\u5BB9\u8F83\u957F\uFF0C\u7EC8\u7A3F\u4F1A\u6536\u655B\u3002_` : text;
|
|
119636
|
+
}
|
|
119637
|
+
var LivePostProgressHandle = class {
|
|
119638
|
+
messageId;
|
|
119639
|
+
idempotencyKey;
|
|
119640
|
+
role = "primary";
|
|
119641
|
+
postClient;
|
|
119642
|
+
patchIntervalMs;
|
|
119643
|
+
maxProgressEdits;
|
|
119644
|
+
initialText;
|
|
119645
|
+
textBuffer = "";
|
|
119646
|
+
lastPatchedText = "";
|
|
119647
|
+
progressEdits = 0;
|
|
119648
|
+
pendingPatch = null;
|
|
119649
|
+
inFlight = Promise.resolve();
|
|
119650
|
+
closed = false;
|
|
119651
|
+
constructor(opts) {
|
|
119652
|
+
this.postClient = opts.postClient;
|
|
119653
|
+
this.messageId = opts.messageId;
|
|
119654
|
+
this.idempotencyKey = opts.idempotencyKey;
|
|
119655
|
+
this.initialText = opts.initialText;
|
|
119656
|
+
this.lastPatchedText = opts.initialText;
|
|
119657
|
+
this.patchIntervalMs = opts.patchIntervalMs;
|
|
119658
|
+
this.maxProgressEdits = opts.maxProgressEdits;
|
|
119659
|
+
}
|
|
119660
|
+
handle(event) {
|
|
119661
|
+
if (this.closed) return;
|
|
119662
|
+
if (event.type !== "text_delta") return;
|
|
119663
|
+
this.textBuffer += event.text;
|
|
119664
|
+
this.schedulePatch();
|
|
119665
|
+
}
|
|
119666
|
+
async finalize(opts) {
|
|
119667
|
+
await this.drain();
|
|
119668
|
+
const finalText = normalizeText2(opts.text) || this.initialText;
|
|
119669
|
+
await this.update(finalText, opts.mentions);
|
|
119670
|
+
}
|
|
119671
|
+
async drain() {
|
|
119672
|
+
this.closed = true;
|
|
119673
|
+
if (this.pendingPatch) {
|
|
119674
|
+
clearTimeout(this.pendingPatch);
|
|
119675
|
+
this.pendingPatch = null;
|
|
119676
|
+
}
|
|
119677
|
+
await this.inFlight;
|
|
119678
|
+
}
|
|
119679
|
+
close() {
|
|
119680
|
+
this.closed = true;
|
|
119681
|
+
if (this.pendingPatch) {
|
|
119682
|
+
clearTimeout(this.pendingPatch);
|
|
119683
|
+
this.pendingPatch = null;
|
|
119684
|
+
}
|
|
119685
|
+
}
|
|
119686
|
+
schedulePatch() {
|
|
119687
|
+
if (this.pendingPatch || this.progressEdits >= this.maxProgressEdits) return;
|
|
119688
|
+
this.pendingPatch = setTimeout(() => {
|
|
119689
|
+
this.pendingPatch = null;
|
|
119690
|
+
void this.patchProgress();
|
|
119691
|
+
}, this.patchIntervalMs);
|
|
119692
|
+
this.pendingPatch.unref?.();
|
|
119693
|
+
}
|
|
119694
|
+
async patchProgress() {
|
|
119695
|
+
if (this.closed || this.progressEdits >= this.maxProgressEdits) return;
|
|
119696
|
+
const nextText = progressText(this.textBuffer, this.initialText);
|
|
119697
|
+
if (nextText === this.lastPatchedText) return;
|
|
119698
|
+
this.progressEdits += 1;
|
|
119699
|
+
this.inFlight = this.inFlight.then(() => this.update(nextText)).catch((err) => {
|
|
119700
|
+
console.warn("[post_progress] progress update failed (continuing):", err);
|
|
119701
|
+
});
|
|
119702
|
+
await this.inFlight;
|
|
119703
|
+
}
|
|
119704
|
+
async update(text, mentions = []) {
|
|
119705
|
+
const content = buildPostContent({ text, mentions });
|
|
119706
|
+
await this.postClient.updatePost(this.messageId, content);
|
|
119707
|
+
this.lastPatchedText = text;
|
|
119708
|
+
}
|
|
119709
|
+
};
|
|
119710
|
+
async function createPostProgressHandle(opts) {
|
|
119711
|
+
const role = "primary";
|
|
119712
|
+
const initialText = normalizeText2(opts.initialText ?? DEFAULT_PLACEHOLDER_TEXT);
|
|
119713
|
+
const idempotencyKey = derivePostIdempotencyKey({
|
|
119714
|
+
botId: opts.facts.botId,
|
|
119715
|
+
threadId: opts.facts.threadId,
|
|
119716
|
+
triggerMessageId: opts.facts.triggerMessageId,
|
|
119717
|
+
role,
|
|
119718
|
+
logicalIndex: 0,
|
|
119719
|
+
contentDigest: digestPostContent("live-progress-placeholder")
|
|
119720
|
+
});
|
|
119721
|
+
const sent = await opts.postClient.createPostReply(
|
|
119722
|
+
opts.replyToMessageId,
|
|
119723
|
+
buildPostContent({ text: initialText }),
|
|
119724
|
+
{
|
|
119725
|
+
replyInThread: opts.replyInThread,
|
|
119726
|
+
idempotencyKey
|
|
119727
|
+
}
|
|
119728
|
+
);
|
|
119729
|
+
return new LivePostProgressHandle({
|
|
119730
|
+
postClient: opts.postClient,
|
|
119731
|
+
messageId: sent.messageId,
|
|
119732
|
+
idempotencyKey,
|
|
119733
|
+
initialText,
|
|
119734
|
+
patchIntervalMs: opts.patchIntervalMs ?? DEFAULT_PATCH_INTERVAL_MS,
|
|
119735
|
+
maxProgressEdits: opts.maxProgressEdits ?? DEFAULT_MAX_PROGRESS_EDITS
|
|
119736
|
+
});
|
|
119737
|
+
}
|
|
119738
|
+
|
|
119567
119739
|
// src/bridge/postBudget.ts
|
|
119568
119740
|
function scopeKey(scope) {
|
|
119569
119741
|
return `${scope.botId}\0${scope.chatId}\0${scope.threadId}`;
|
|
@@ -119945,6 +120117,8 @@ var BridgeHandler = class {
|
|
|
119945
120117
|
visibleFallbackAvailable: true
|
|
119946
120118
|
});
|
|
119947
120119
|
let card;
|
|
120120
|
+
let progressPost;
|
|
120121
|
+
let progressPostStartFailed = false;
|
|
119948
120122
|
if (surfaceController.shouldStartCardImmediately()) {
|
|
119949
120123
|
try {
|
|
119950
120124
|
card = await this.deps.cardRenderer.start(messageId, { replyInThread, threadId });
|
|
@@ -120108,6 +120282,55 @@ var BridgeHandler = class {
|
|
|
120108
120282
|
} catch (err) {
|
|
120109
120283
|
console.warn("[bridge.handler] ensureStateFile failed (continuing):", err);
|
|
120110
120284
|
}
|
|
120285
|
+
if (!card && postOutboundAvailable && this.deps.postClient) {
|
|
120286
|
+
const budget = prototypeConfig ? this.responseSurfacePostBudget.reserve({
|
|
120287
|
+
scope: {
|
|
120288
|
+
botId: this.deps.botConfig?.id ?? "v1-default",
|
|
120289
|
+
chatId: parsed.chatId,
|
|
120290
|
+
threadId
|
|
120291
|
+
},
|
|
120292
|
+
maxPosts: prototypeConfig.max_posts_per_window,
|
|
120293
|
+
windowMs: prototypeConfig.post_window_ms
|
|
120294
|
+
}) : void 0;
|
|
120295
|
+
if (budget?.allowed === false) {
|
|
120296
|
+
console.warn("[bridge.handler] post progress budget exhausted; using card fallback");
|
|
120297
|
+
progressPostStartFailed = true;
|
|
120298
|
+
} else {
|
|
120299
|
+
try {
|
|
120300
|
+
progressPost = await createPostProgressHandle({
|
|
120301
|
+
postClient: this.deps.postClient,
|
|
120302
|
+
replyToMessageId: messageId,
|
|
120303
|
+
replyInThread,
|
|
120304
|
+
facts: {
|
|
120305
|
+
botId: this.deps.botConfig?.id ?? "v1-default",
|
|
120306
|
+
threadId,
|
|
120307
|
+
triggerMessageId: messageId
|
|
120308
|
+
},
|
|
120309
|
+
initialText: "\u6B63\u5728\u5904\u7406\u2026"
|
|
120310
|
+
});
|
|
120311
|
+
await this.deps.client.removeProcessingReaction?.(messageId);
|
|
120312
|
+
await recordEvent({
|
|
120313
|
+
status: "running",
|
|
120314
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
120315
|
+
appendPath: "\u5DF2\u521B\u5EFA post",
|
|
120316
|
+
reason: "response surface \u4F7F\u7528 post \u4F5C\u4E3A\u672C\u8F6E\u4E3B\u56DE\u590D\u9762\u3002"
|
|
120317
|
+
});
|
|
120318
|
+
} catch (err) {
|
|
120319
|
+
progressPostStartFailed = true;
|
|
120320
|
+
console.warn("[bridge.handler] create progress post failed; using card fallback:", err);
|
|
120321
|
+
}
|
|
120322
|
+
}
|
|
120323
|
+
}
|
|
120324
|
+
if (!card && progressPostStartFailed) {
|
|
120325
|
+
card = await this.deps.cardRenderer.start(messageId, { replyInThread, threadId });
|
|
120326
|
+
await this.deps.client.removeProcessingReaction?.(messageId);
|
|
120327
|
+
await recordEvent({
|
|
120328
|
+
status: "running",
|
|
120329
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
120330
|
+
appendPath: "post \u5931\u8D25\uFF0C\u5DF2\u521B\u5EFA\u5361\u7247",
|
|
120331
|
+
reason: "post \u4E3B\u9762\u521B\u5EFA\u5931\u8D25\uFF0Cbridge \u4F7F\u7528\u53EF\u89C1\u5361\u7247\u515C\u5E95\u3002"
|
|
120332
|
+
});
|
|
120333
|
+
}
|
|
120111
120334
|
if (card) {
|
|
120112
120335
|
try {
|
|
120113
120336
|
await writeCardFile(worktreePath, {
|
|
@@ -120182,6 +120405,7 @@ var BridgeHandler = class {
|
|
|
120182
120405
|
try {
|
|
120183
120406
|
for await (const ev of handle.events) {
|
|
120184
120407
|
if (card) card.handle(ev);
|
|
120408
|
+
else progressPost?.handle(ev);
|
|
120185
120409
|
if (ev.type === "system_init") {
|
|
120186
120410
|
sessionId = ev.sessionId;
|
|
120187
120411
|
}
|
|
@@ -120249,6 +120473,7 @@ var BridgeHandler = class {
|
|
|
120249
120473
|
imageBlocks: reportedState?.image_blocks,
|
|
120250
120474
|
contentBlocks: reportedState?.content_blocks
|
|
120251
120475
|
};
|
|
120476
|
+
await progressPost?.drain();
|
|
120252
120477
|
const surfaceDispatch = await dispatchResponseSurface({
|
|
120253
120478
|
state: reportedState,
|
|
120254
120479
|
prototypeConfig,
|
|
@@ -120263,10 +120488,15 @@ var BridgeHandler = class {
|
|
|
120263
120488
|
worktreePath,
|
|
120264
120489
|
baseCard: baseCardPayload,
|
|
120265
120490
|
cardStarted: !!card,
|
|
120266
|
-
postOutboundAvailable,
|
|
120491
|
+
postOutboundAvailable: postOutboundAvailable && !progressPostStartFailed,
|
|
120267
120492
|
postLedgerAvailable: true,
|
|
120268
120493
|
visibleFallbackAvailable: true,
|
|
120269
120494
|
postClient: this.deps.postClient,
|
|
120495
|
+
livePost: progressPost ? {
|
|
120496
|
+
messageId: progressPost.messageId,
|
|
120497
|
+
idempotencyKey: progressPost.idempotencyKey,
|
|
120498
|
+
role: progressPost.role
|
|
120499
|
+
} : void 0,
|
|
120270
120500
|
postBudget: prototypeConfig ? {
|
|
120271
120501
|
reserve: () => this.responseSurfacePostBudget.reserve({
|
|
120272
120502
|
scope: {
|
|
@@ -120370,6 +120600,23 @@ var BridgeHandler = class {
|
|
|
120370
120600
|
reason: String(err)
|
|
120371
120601
|
});
|
|
120372
120602
|
settle(false);
|
|
120603
|
+
if (!card && progressPost) {
|
|
120604
|
+
try {
|
|
120605
|
+
await progressPost.finalize({
|
|
120606
|
+
text: `\u6267\u884C\u5931\u8D25: ${String(err)}`
|
|
120607
|
+
});
|
|
120608
|
+
} catch (postFinalizeErr) {
|
|
120609
|
+
console.error(
|
|
120610
|
+
"[bridge.handler] progress post failure update failed; creating card fallback:",
|
|
120611
|
+
postFinalizeErr
|
|
120612
|
+
);
|
|
120613
|
+
try {
|
|
120614
|
+
card = await this.deps.cardRenderer.start(messageId, { replyInThread, threadId });
|
|
120615
|
+
} catch (cardStartErr) {
|
|
120616
|
+
console.error("[bridge.handler] failure card start also failed:", cardStartErr);
|
|
120617
|
+
}
|
|
120618
|
+
}
|
|
120619
|
+
}
|
|
120373
120620
|
if (card) {
|
|
120374
120621
|
try {
|
|
120375
120622
|
await card.finalize({
|