@gholl-studio/pier-connector 0.7.5 → 0.7.7
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/inbound.d.ts +9 -2
- package/dist/inbound.js +39 -92
- package/dist/inbound.js.map +1 -1
- package/package.json +2 -2
- package/src/inbound.ts +47 -102
package/dist/inbound.d.ts
CHANGED
|
@@ -3,5 +3,12 @@
|
|
|
3
3
|
* @description Manages inbound message processing, agent routing resolution, and session context propagation.
|
|
4
4
|
*/
|
|
5
5
|
import type { InboundMessage } from './types.js';
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
import type { PierRobot } from './robot.js';
|
|
7
|
+
/**
|
|
8
|
+
* Handle incoming messages from NATS (Core or JetStream).
|
|
9
|
+
* @param ctx The plugin runtime context
|
|
10
|
+
* @param inbound The normalized inbound message payload
|
|
11
|
+
* @param jobId The associated Job or Group ID
|
|
12
|
+
* @param robot The active PierRobot instance
|
|
13
|
+
*/
|
|
14
|
+
export declare function handleInbound(ctx: any, inbound: InboundMessage, jobId: string, robot: PierRobot, plugin: any): Promise<void>;
|
package/dist/inbound.js
CHANGED
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
* @file inbound.ts
|
|
3
3
|
* @description Manages inbound message processing, agent routing resolution, and session context propagation.
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Handle incoming messages from NATS (Core or JetStream).
|
|
7
|
+
* @param ctx The plugin runtime context
|
|
8
|
+
* @param inbound The normalized inbound message payload
|
|
9
|
+
* @param jobId The associated Job or Group ID
|
|
10
|
+
* @param robot The active PierRobot instance
|
|
11
|
+
*/
|
|
12
|
+
export async function handleInbound(ctx, inbound, jobId, robot, plugin) {
|
|
7
13
|
const logger = ctx.log || console;
|
|
8
14
|
const channelRuntime = ctx.channelRuntime;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return;
|
|
12
|
-
}
|
|
13
|
-
// 1. Resolve Account-Scoped Configuration
|
|
14
|
-
// 使用原始完整配置,不覆盖 channels.pier,确保 bindings 和 defaultAgent 完整可用。
|
|
15
|
-
// resolveAgentRoute 需要完整配置中的 bindings 才能正确匹配 channel+accountId 路由规则。
|
|
15
|
+
// 1. Prepare Scoped Config
|
|
16
|
+
// resolveAgentRoute needs bindings in full config to match channel+accountId routing rules.
|
|
16
17
|
const rootConfig = ctx.cfg || {};
|
|
17
18
|
const accountScopedCfg = rootConfig;
|
|
18
19
|
// 2. Resolve Agent Route
|
|
@@ -31,17 +32,25 @@ inbound, jobId, robot, pierPlugin) {
|
|
|
31
32
|
const dynamicSessionKey = route.sessionKey;
|
|
32
33
|
const metadata = robot.activeNodeJobs.get(jobId);
|
|
33
34
|
let injectedPrompt = "";
|
|
34
|
-
// Dynamic Whiteboard Context Injection (
|
|
35
|
+
// --- Dynamic Whiteboard Context Injection (Autonomous Intelligence) ---
|
|
35
36
|
let boardIndex = "[Empty]";
|
|
37
|
+
let missionGoal = "[Not Defined]";
|
|
36
38
|
if (isWorkspace) {
|
|
37
39
|
try {
|
|
38
40
|
const kv = await robot.client.nats.getWorkspaceKV(jobId);
|
|
41
|
+
// A. Fetch Index (Awareness)
|
|
39
42
|
const keysIter = await kv.keys();
|
|
40
43
|
const keys = [];
|
|
41
44
|
for await (const k of keysIter)
|
|
42
45
|
keys.push(k);
|
|
43
46
|
if (keys.length > 0)
|
|
44
47
|
boardIndex = keys.join(", ");
|
|
48
|
+
// B. Proactively read 'mission.goal' (Long-term Memory)
|
|
49
|
+
// This ensures the agent NEVER forgets the objective regardless of chat length.
|
|
50
|
+
const goalEntry = await kv.get('mission.goal') || await kv.get('goal');
|
|
51
|
+
if (goalEntry) {
|
|
52
|
+
missionGoal = new TextDecoder().decode(goalEntry.value);
|
|
53
|
+
}
|
|
45
54
|
}
|
|
46
55
|
catch (e) { }
|
|
47
56
|
}
|
|
@@ -65,12 +74,18 @@ inbound, jobId, robot, pierPlugin) {
|
|
|
65
74
|
"=========================================",
|
|
66
75
|
"You are an autonomous AI worker on Pier.",
|
|
67
76
|
isWorkspace ? `CURRENT WORKSPACE ID (groupId): ${jobId}` : "",
|
|
68
|
-
isWorkspace ? `
|
|
69
|
-
isWorkspace ?
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
"
|
|
73
|
-
"
|
|
77
|
+
isWorkspace ? `PRIMARY MISSION GOAL: ${missionGoal}` : "",
|
|
78
|
+
isWorkspace ? `BOARD INDEX: ${boardIndex}` : "",
|
|
79
|
+
"-----------------------------------------",
|
|
80
|
+
isWorkspace ? "AUTONOMY & MEMORY PROTOCOL:" : "",
|
|
81
|
+
isWorkspace ? "1. The 'PRIMARY MISSION GOAL' is your source of truth and long-term memory. It defines your purpose in this workspace." : "",
|
|
82
|
+
isWorkspace ? "2. Use `pier_read_board_item` to fetch technical details for any key listed in the BOARD INDEX." : "",
|
|
83
|
+
isWorkspace ? "3. PROACTIVE ACTION: If you see a plan or task assigned to you on the board, proceed with implementation. Report progress via `pier_chat`." : "",
|
|
84
|
+
isWorkspace ? "4. Use the groupId exactly as provided. DO NOT add 'pierWorkspace:' prefixes." : "",
|
|
85
|
+
"-----------------------------------------",
|
|
86
|
+
"5. You MUST USE the `pier_finish_task` tool to submit the final result when the mission objectives are fully met.",
|
|
87
|
+
"6. If requirements are unclear, use `pier_chat` to consult the employer.",
|
|
88
|
+
"7. Do not remain idle if the goal is clear. Act, update the board, and coordinate."
|
|
74
89
|
].filter(Boolean).join('\n');
|
|
75
90
|
}
|
|
76
91
|
// 3. Finalize Context
|
|
@@ -85,89 +100,21 @@ inbound, jobId, robot, pierPlugin) {
|
|
|
85
100
|
ChatType: chatType,
|
|
86
101
|
SenderId: inbound.senderId,
|
|
87
102
|
SenderName: inbound.senderId,
|
|
88
|
-
Provider: 'pier',
|
|
89
|
-
Surface: 'pier',
|
|
90
|
-
OriginatingChannel: 'pier',
|
|
91
|
-
OriginatingTo: `chat:${jobId}`,
|
|
92
103
|
WasMentioned: inbound.WasMentioned ?? true,
|
|
93
|
-
|
|
94
|
-
SystemPrompt: injectedPrompt,
|
|
95
|
-
MessageId: inbound.messageId,
|
|
96
|
-
MessageSid: inbound.messageId,
|
|
104
|
+
InjectedSystemPrompt: injectedPrompt,
|
|
97
105
|
Metadata: {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
routingSource: routingSource
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
// 4. Create Dispatcher
|
|
106
|
-
// 必须从 createReplyDispatcherWithTyping 获取 replyOptions,
|
|
107
|
-
// 它包含 SDK 内部生命周期钉子(onReplyStart / onTypingController / onTypingCleanup),
|
|
108
|
-
// 必须传入 dispatchReplyFromConfig 才能正确启动和终止 typing controller。
|
|
109
|
-
const { dispatcher, replyOptions, markDispatchIdle, markRunComplete } = channelRuntime.reply.createReplyDispatcherWithTyping({
|
|
110
|
-
deliver: async (payload, info) => {
|
|
111
|
-
const currentMeta = robot.activeNodeJobs.get(jobId);
|
|
112
|
-
const resAgent = payload.agentId || finalAgentId;
|
|
113
|
-
logger.info(`[pier-connector:trace] Outbound delivery for ${jobId}. Responder: ${resAgent}.`);
|
|
114
|
-
if (payload.text && payload.text.length > 0) {
|
|
115
|
-
await pierPlugin.outbound.sendText({
|
|
116
|
-
text: payload.text,
|
|
117
|
-
to: `pier:${jobId}`,
|
|
118
|
-
accountId: robot.accountId,
|
|
119
|
-
metadata: {
|
|
120
|
-
...currentMeta,
|
|
121
|
-
accountId: robot.accountId,
|
|
122
|
-
pierJobId: jobId,
|
|
123
|
-
respondingAgentId: resAgent,
|
|
124
|
-
workspace: isWorkspace
|
|
125
|
-
},
|
|
126
|
-
});
|
|
127
|
-
}
|
|
106
|
+
jobId: jobId,
|
|
107
|
+
pierJobId: metadata?.pierJobId,
|
|
108
|
+
workspace: isWorkspace,
|
|
109
|
+
boardKeys: boardIndex
|
|
128
110
|
}
|
|
129
111
|
});
|
|
130
|
-
//
|
|
131
|
-
if (channelRuntime.session?.recordSessionMetaFromInbound) {
|
|
132
|
-
try {
|
|
133
|
-
const storePath = channelRuntime.session.resolveStorePath(dynamicSessionKey);
|
|
134
|
-
await channelRuntime.session.recordSessionMetaFromInbound({
|
|
135
|
-
storePath, sessionKey: dynamicSessionKey, ctx: ctxPayload
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
catch (err) {
|
|
139
|
-
logger.error(`[pier-connector] ✖ Failed to record session metadata: ${err.message}`);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
// 6. Dispatch
|
|
112
|
+
// 4. Dispatch to Agent
|
|
143
113
|
try {
|
|
144
|
-
|
|
145
|
-
ctx: ctxPayload,
|
|
146
|
-
cfg: accountScopedCfg,
|
|
147
|
-
dispatcher,
|
|
148
|
-
replyOptions: {
|
|
149
|
-
// 必须展开 replyOptions,否则 typing controller 永远不会被启动/停止
|
|
150
|
-
// 上一条消息的会话状态就会游跍,导致 SDK 拒绝处理下一条消息
|
|
151
|
-
...replyOptions,
|
|
152
|
-
onModelSelected: (mCtx) => {
|
|
153
|
-
logger.info(`[pier-connector:debug] Model selected for ${jobId}: ${mCtx.provider}/${mCtx.model}`);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
// 等待所有已入队的 deliver() 调用完成(参照飞书插件 dispatch.ts L128)
|
|
158
|
-
// 不调用此方法, dispatchReplyFromConfig 可能在 deliver 永远未执行的情况下返回
|
|
159
|
-
await dispatcher.waitForIdle();
|
|
160
|
-
logger.info(`[pier-connector] Dispatch complete for ${jobId}. queuedFinal=${queuedFinal}, counts=${JSON.stringify(counts)}`);
|
|
114
|
+
await channelRuntime.reply.dispatchInbound(ctxPayload);
|
|
161
115
|
}
|
|
162
116
|
catch (err) {
|
|
163
|
-
logger.error(`[pier-connector]
|
|
164
|
-
}
|
|
165
|
-
finally {
|
|
166
|
-
// markRunComplete 通知 typing controller 运行已结束。
|
|
167
|
-
// markDispatchIdle 通知 dispatcher 空闲。
|
|
168
|
-
// 必须在 finally 块不调用不等待下一条消息。
|
|
169
|
-
markRunComplete?.();
|
|
170
|
-
markDispatchIdle?.();
|
|
117
|
+
logger.error(`[pier-connector] Dispatch failed: ${err.message}`);
|
|
171
118
|
}
|
|
172
119
|
}
|
|
173
120
|
//# sourceMappingURL=inbound.js.map
|
package/dist/inbound.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inbound.js","sourceRoot":"","sources":["../src/inbound.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"inbound.js","sourceRoot":"","sources":["../src/inbound.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gholl-studio/pier-connector",
|
|
3
3
|
"author": "gholl",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.7",
|
|
5
5
|
"description": "OpenClaw plugin that connects to the Pier job marketplace. Automatically fetches, executes, and reports distributed tasks for rewards.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
],
|
|
42
42
|
"license": "MIT",
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@gholl-studio/pier-sdk": "^1.4.
|
|
44
|
+
"@gholl-studio/pier-sdk": "^1.4.8",
|
|
45
45
|
"@nats-io/jetstream": "^3.3.1",
|
|
46
46
|
"@nats-io/transport-node": "^3.0.0",
|
|
47
47
|
"ethers": "^6.16.0",
|
package/src/inbound.ts
CHANGED
|
@@ -5,25 +5,27 @@
|
|
|
5
5
|
|
|
6
6
|
import type { InboundMessage } from './types.js';
|
|
7
7
|
import { truncate } from './job-handler.js';
|
|
8
|
+
import type { PierRobot } from './robot.js';
|
|
8
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Handle incoming messages from NATS (Core or JetStream).
|
|
12
|
+
* @param ctx The plugin runtime context
|
|
13
|
+
* @param inbound The normalized inbound message payload
|
|
14
|
+
* @param jobId The associated Job or Group ID
|
|
15
|
+
* @param robot The active PierRobot instance
|
|
16
|
+
*/
|
|
9
17
|
export async function handleInbound(
|
|
10
|
-
ctx: any,
|
|
11
|
-
inbound: InboundMessage,
|
|
12
|
-
jobId: string,
|
|
13
|
-
robot:
|
|
14
|
-
|
|
18
|
+
ctx: any,
|
|
19
|
+
inbound: InboundMessage,
|
|
20
|
+
jobId: string,
|
|
21
|
+
robot: PierRobot,
|
|
22
|
+
plugin: any
|
|
15
23
|
) {
|
|
16
24
|
const logger = ctx.log || console;
|
|
17
25
|
const channelRuntime = ctx.channelRuntime;
|
|
18
|
-
|
|
19
|
-
if (!channelRuntime?.reply) {
|
|
20
|
-
console.error(`[pier-connector][${robot.accountId}] SDK Error: channelRuntime.reply is not available.`);
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
26
|
|
|
24
|
-
// 1.
|
|
25
|
-
//
|
|
26
|
-
// resolveAgentRoute 需要完整配置中的 bindings 才能正确匹配 channel+accountId 路由规则。
|
|
27
|
+
// 1. Prepare Scoped Config
|
|
28
|
+
// resolveAgentRoute needs bindings in full config to match channel+accountId routing rules.
|
|
27
29
|
const rootConfig = ctx.cfg || {};
|
|
28
30
|
const accountScopedCfg = rootConfig;
|
|
29
31
|
|
|
@@ -48,15 +50,25 @@ export async function handleInbound(
|
|
|
48
50
|
const metadata = robot.activeNodeJobs.get(jobId);
|
|
49
51
|
let injectedPrompt = "";
|
|
50
52
|
|
|
51
|
-
// Dynamic Whiteboard Context Injection (
|
|
53
|
+
// --- Dynamic Whiteboard Context Injection (Autonomous Intelligence) ---
|
|
52
54
|
let boardIndex = "[Empty]";
|
|
55
|
+
let missionGoal = "[Not Defined]";
|
|
53
56
|
if (isWorkspace) {
|
|
54
57
|
try {
|
|
55
58
|
const kv = await robot.client.nats.getWorkspaceKV(jobId);
|
|
59
|
+
|
|
60
|
+
// A. Fetch Index (Awareness)
|
|
56
61
|
const keysIter = await kv.keys();
|
|
57
62
|
const keys = [];
|
|
58
63
|
for await (const k of keysIter) keys.push(k);
|
|
59
64
|
if (keys.length > 0) boardIndex = keys.join(", ");
|
|
65
|
+
|
|
66
|
+
// B. Proactively read 'mission.goal' (Long-term Memory)
|
|
67
|
+
// This ensures the agent NEVER forgets the objective regardless of chat length.
|
|
68
|
+
const goalEntry = await kv.get('mission.goal') || await kv.get('goal');
|
|
69
|
+
if (goalEntry) {
|
|
70
|
+
missionGoal = new TextDecoder().decode(goalEntry.value);
|
|
71
|
+
}
|
|
60
72
|
} catch (e) {}
|
|
61
73
|
}
|
|
62
74
|
|
|
@@ -79,12 +91,18 @@ export async function handleInbound(
|
|
|
79
91
|
"=========================================",
|
|
80
92
|
"You are an autonomous AI worker on Pier.",
|
|
81
93
|
isWorkspace ? `CURRENT WORKSPACE ID (groupId): ${jobId}` : "",
|
|
82
|
-
isWorkspace ? `
|
|
83
|
-
isWorkspace ?
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
"
|
|
87
|
-
"
|
|
94
|
+
isWorkspace ? `PRIMARY MISSION GOAL: ${missionGoal}` : "",
|
|
95
|
+
isWorkspace ? `BOARD INDEX: ${boardIndex}` : "",
|
|
96
|
+
"-----------------------------------------",
|
|
97
|
+
isWorkspace ? "AUTONOMY & MEMORY PROTOCOL:" : "",
|
|
98
|
+
isWorkspace ? "1. The 'PRIMARY MISSION GOAL' is your source of truth and long-term memory. It defines your purpose in this workspace." : "",
|
|
99
|
+
isWorkspace ? "2. Use `pier_read_board_item` to fetch technical details for any key listed in the BOARD INDEX." : "",
|
|
100
|
+
isWorkspace ? "3. PROACTIVE ACTION: If you see a plan or task assigned to you on the board, proceed with implementation. Report progress via `pier_chat`." : "",
|
|
101
|
+
isWorkspace ? "4. Use the groupId exactly as provided. DO NOT add 'pierWorkspace:' prefixes." : "",
|
|
102
|
+
"-----------------------------------------",
|
|
103
|
+
"5. You MUST USE the `pier_finish_task` tool to submit the final result when the mission objectives are fully met.",
|
|
104
|
+
"6. If requirements are unclear, use `pier_chat` to consult the employer.",
|
|
105
|
+
"7. Do not remain idle if the goal is clear. Act, update the board, and coordinate."
|
|
88
106
|
].filter(Boolean).join('\n');
|
|
89
107
|
}
|
|
90
108
|
|
|
@@ -100,93 +118,20 @@ export async function handleInbound(
|
|
|
100
118
|
ChatType: chatType as any,
|
|
101
119
|
SenderId: inbound.senderId,
|
|
102
120
|
SenderName: inbound.senderId,
|
|
103
|
-
Provider: 'pier',
|
|
104
|
-
Surface: 'pier',
|
|
105
|
-
OriginatingChannel: 'pier',
|
|
106
|
-
OriginatingTo: `chat:${jobId}`,
|
|
107
121
|
WasMentioned: inbound.WasMentioned ?? true,
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
accountId: robot.accountId,
|
|
115
|
-
agentId: finalAgentId,
|
|
116
|
-
pierJobId: jobId,
|
|
117
|
-
routingSource: routingSource
|
|
122
|
+
InjectedSystemPrompt: injectedPrompt,
|
|
123
|
+
Metadata: {
|
|
124
|
+
jobId: jobId,
|
|
125
|
+
pierJobId: metadata?.pierJobId,
|
|
126
|
+
workspace: isWorkspace,
|
|
127
|
+
boardKeys: boardIndex
|
|
118
128
|
}
|
|
119
129
|
});
|
|
120
130
|
|
|
121
|
-
// 4.
|
|
122
|
-
// 必须从 createReplyDispatcherWithTyping 获取 replyOptions,
|
|
123
|
-
// 它包含 SDK 内部生命周期钉子(onReplyStart / onTypingController / onTypingCleanup),
|
|
124
|
-
// 必须传入 dispatchReplyFromConfig 才能正确启动和终止 typing controller。
|
|
125
|
-
const { dispatcher, replyOptions, markDispatchIdle, markRunComplete } = channelRuntime.reply.createReplyDispatcherWithTyping({
|
|
126
|
-
deliver: async (payload: any, info: any) => {
|
|
127
|
-
const currentMeta = robot.activeNodeJobs.get(jobId);
|
|
128
|
-
const resAgent = payload.agentId || finalAgentId;
|
|
129
|
-
|
|
130
|
-
logger.info(`[pier-connector:trace] Outbound delivery for ${jobId}. Responder: ${resAgent}.`);
|
|
131
|
-
|
|
132
|
-
if (payload.text && payload.text.length > 0) {
|
|
133
|
-
await pierPlugin.outbound.sendText({
|
|
134
|
-
text: payload.text,
|
|
135
|
-
to: `pier:${jobId}`,
|
|
136
|
-
accountId: robot.accountId,
|
|
137
|
-
metadata: {
|
|
138
|
-
...currentMeta,
|
|
139
|
-
accountId: robot.accountId,
|
|
140
|
-
pierJobId: jobId,
|
|
141
|
-
respondingAgentId: resAgent,
|
|
142
|
-
workspace: isWorkspace
|
|
143
|
-
},
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
// 5. Session Recording
|
|
150
|
-
if (channelRuntime.session?.recordSessionMetaFromInbound) {
|
|
151
|
-
try {
|
|
152
|
-
const storePath = channelRuntime.session.resolveStorePath(dynamicSessionKey);
|
|
153
|
-
await channelRuntime.session.recordSessionMetaFromInbound({
|
|
154
|
-
storePath, sessionKey: dynamicSessionKey, ctx: ctxPayload
|
|
155
|
-
});
|
|
156
|
-
} catch (err: any) {
|
|
157
|
-
logger.error(`[pier-connector] ✖ Failed to record session metadata: ${err.message}`);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// 6. Dispatch
|
|
131
|
+
// 4. Dispatch to Agent
|
|
162
132
|
try {
|
|
163
|
-
|
|
164
|
-
ctx: ctxPayload,
|
|
165
|
-
cfg: accountScopedCfg,
|
|
166
|
-
dispatcher,
|
|
167
|
-
replyOptions: {
|
|
168
|
-
// 必须展开 replyOptions,否则 typing controller 永远不会被启动/停止
|
|
169
|
-
// 上一条消息的会话状态就会游跍,导致 SDK 拒绝处理下一条消息
|
|
170
|
-
...replyOptions,
|
|
171
|
-
onModelSelected: (mCtx: any) => {
|
|
172
|
-
logger.info(`[pier-connector:debug] Model selected for ${jobId}: ${mCtx.provider}/${mCtx.model}`);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
// 等待所有已入队的 deliver() 调用完成(参照飞书插件 dispatch.ts L128)
|
|
178
|
-
// 不调用此方法, dispatchReplyFromConfig 可能在 deliver 永远未执行的情况下返回
|
|
179
|
-
await dispatcher.waitForIdle();
|
|
180
|
-
|
|
181
|
-
logger.info(`[pier-connector] Dispatch complete for ${jobId}. queuedFinal=${queuedFinal}, counts=${JSON.stringify(counts)}`);
|
|
133
|
+
await channelRuntime.reply.dispatchInbound(ctxPayload);
|
|
182
134
|
} catch (err: any) {
|
|
183
|
-
logger.error(`[pier-connector]
|
|
184
|
-
} finally {
|
|
185
|
-
// markRunComplete 通知 typing controller 运行已结束。
|
|
186
|
-
// markDispatchIdle 通知 dispatcher 空闲。
|
|
187
|
-
// 必须在 finally 块不调用不等待下一条消息。
|
|
188
|
-
markRunComplete?.();
|
|
189
|
-
markDispatchIdle?.();
|
|
135
|
+
logger.error(`[pier-connector] Dispatch failed: ${err.message}`);
|
|
190
136
|
}
|
|
191
137
|
}
|
|
192
|
-
|