@gholl-studio/pier-connector 0.2.50 → 0.2.52

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.
Files changed (2) hide show
  1. package/package.json +5 -3
  2. package/src/index.js +72 -48
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gholl-studio/pier-connector",
3
3
  "author": "gholl",
4
- "version": "0.2.50",
4
+ "version": "0.2.52",
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": "src/index.js",
@@ -50,6 +50,8 @@
50
50
  }
51
51
  },
52
52
  "devDependencies": {
53
- "dotenv": "^17.3.1"
53
+ "dotenv": "^17.3.1",
54
+ "openclaw": ">=2.0.0",
55
+ "typescript": "^5.0.0"
54
56
  }
55
- }
57
+ }
package/src/index.js CHANGED
@@ -8,6 +8,7 @@
8
8
  * 4. A command ("/pier") for checking connection status
9
9
  */
10
10
 
11
+ import { definePluginEntry } from 'openclaw/plugin-sdk/plugin-entry';
11
12
  import { PierClient, protocol } from '@gholl-studio/pier-sdk';
12
13
  const { createRequestPayload, createResultPayload, createErrorPayload } = protocol;
13
14
  import { parseJob, safeRespond, truncate } from './job-handler.js';
@@ -22,7 +23,7 @@ import path from 'path';
22
23
  *
23
24
  * @param {object} api – OpenClaw plugin API
24
25
  */
25
- export default function register(api) {
26
+ const register = (api) => {
26
27
  const logger = api.logger;
27
28
 
28
29
  // ── shared state (Instances) ───────────────────────────────────
@@ -38,11 +39,15 @@ export default function register(api) {
38
39
  // ── resolve plugin config ──────────────────────────────────────────
39
40
 
40
41
  function resolveConfigs() {
41
- const globalAccounts = api.runtime?.config?.channels?.['pier']?.accounts || {};
42
- const pluginAccounts = api.config?.channels?.['pier']?.accounts || {};
42
+ // api.config is the full global OpenClaw configuration
43
+ const globalAccounts = api.config?.channels?.['pier']?.accounts || {};
44
+
45
+ // api.pluginConfig is the scoped config for THIS plugin
46
+ const pluginAccounts = api.pluginConfig?.accounts || {};
47
+
43
48
  const rawAccounts = { ...globalAccounts, ...pluginAccounts };
44
49
 
45
- const legacyCfg = api.config?.plugins?.entries?.['pier-connector']?.config || api.config || {};
50
+ const legacyCfg = api.pluginConfig || {};
46
51
 
47
52
  // If no accounts defined at all, fallback to 'default' using legacy/env config
48
53
  if (Object.keys(rawAccounts).length === 0) {
@@ -165,11 +170,22 @@ export default function register(api) {
165
170
  return;
166
171
  }
167
172
 
168
- logger.info(`[pier-connector:trace] receiveIncoming triggered. inbound.accountId='${inbound.accountId}', inbound.senderId='${inbound.senderId}'`);
173
+ logger.info(`[pier-connector:trace] receiveIncoming triggered for jobId=${jobId}. accountId='${inbound.accountId}', senderId='${inbound.senderId}'`);
174
+
175
+ // 1. Resolve Global Configuration
176
+ // In OpenClaw V2, we use api.config for the full global state.
177
+ const rootConfig = api.config || {};
178
+
179
+ // Diagnostic logging
180
+ const b = rootConfig.bindings;
181
+ const bindingsCount = Array.isArray(b) ? b.length : (b ? Object.keys(b).length : 0);
182
+ const agentsCount = rootConfig.agents?.list ? (Array.isArray(rootConfig.agents.list) ? rootConfig.agents.list.length : Object.keys(rootConfig.agents.list).length) : 0;
183
+
184
+ logger.info(`[pier-connector:trace] Diagnostic: rootConfig source=api.config, bindings=${bindingsCount}, agents=${agentsCount}`);
169
185
 
170
- const globalConfig = api.runtime?.config || {};
186
+ // 2. Resolve Agent Route via SDK
171
187
  const route = api.runtime.channel.routing.resolveAgentRoute({
172
- cfg: globalConfig,
188
+ cfg: rootConfig,
173
189
  channel: 'pier',
174
190
  account: inbound.accountId,
175
191
  peer: { kind: 'direct', id: jobId }
@@ -177,57 +193,55 @@ export default function register(api) {
177
193
 
178
194
  logger.info(`[pier-connector:trace] resolveAgentRoute returned: route.agentId='${route?.agentId}', route.accountId='${route?.accountId}'`);
179
195
 
180
- // 1. Explicit account-level agentId from plugin config (if still used)
181
- let finalAgentId = this.config.agentId;
182
- let routingSource = 'account-config';
196
+ // 3. Robust Routing Decision Tree
197
+ let finalAgentId = null;
198
+ let routingSource = 'unresolved';
183
199
 
184
- // 2. Robust manual parse (safeguard against OpenClaw core parsing bugs)
185
- if (!finalAgentId) {
186
- const cfg = globalConfig;
187
- const bs = Array.isArray(cfg.bindings) ? cfg.bindings : [];
188
- const al = Array.isArray(cfg.agents?.list) ? cfg.agents.list : [];
189
-
190
- logger.info(`[pier-connector:trace] Manual debug: bindings_count=${bs.length}, agents_count=${al.length}`);
200
+ // A. Check explicit account-level binding in plugin local config (this.config)
201
+ if (this.config.agentId && this.config.agentId !== 'main' && this.config.agentId !== 'default') {
202
+ finalAgentId = this.config.agentId;
203
+ routingSource = 'plugin-local-config';
204
+ }
191
205
 
192
- // Check bindings
193
- const manualBinding = bs.find(b =>
194
- b.match?.channel === 'pier' &&
195
- (b.match?.accountId === inbound.accountId || b.match?.account === inbound.accountId)
206
+ // B. Check Global Bindings (Manual Scan of rootConfig.bindings)
207
+ if (!finalAgentId) {
208
+ const bindings = Array.isArray(rootConfig.bindings) ? rootConfig.bindings : [];
209
+ const binding = bindings.find(bi =>
210
+ bi.match?.channel === 'pier' &&
211
+ (bi.match?.accountId === inbound.accountId || bi.match?.account === inbound.accountId)
196
212
  );
197
-
198
- if (manualBinding && manualBinding.agentId && manualBinding.agentId !== 'main') {
199
- finalAgentId = manualBinding.agentId;
200
- routingSource = 'manual-global-bindings';
201
- }
202
-
203
- // Check agent list for name match (account ID == agent ID)
204
- if (!finalAgentId) {
205
- const nameMatch = al.find(a => a.id === inbound.accountId);
206
- if (nameMatch) {
207
- finalAgentId = inbound.accountId;
208
- routingSource = 'manual-name-match';
209
- }
213
+ if (binding?.agentId && binding.agentId !== 'main') {
214
+ finalAgentId = binding.agentId;
215
+ routingSource = 'manual-global-bindings-match';
210
216
  }
211
217
  }
212
218
 
213
- // 3. Fallback to OpenClaw's resolveAgentRoute (only if still unresolved and not 'main')
219
+ // C. SDK Routing Result (if it actually found something non-default)
214
220
  if (!finalAgentId && route.agentId && route.agentId !== 'main' && route.agentId !== 'default') {
215
221
  finalAgentId = route.agentId;
216
222
  routingSource = 'sdk-global-bindings';
217
223
  }
218
224
 
219
- // 4. Ultimate/Aggressive default
220
- if (!finalAgentId) {
221
- if (inbound.accountId && inbound.accountId !== 'default' && inbound.accountId !== 'main') {
222
- // Critical fallback: if the account has a custom name, assume the user wants that specific agent
225
+ // D. Name-Matching Fallback (CRITICAL: account name == agent ID)
226
+ // If we see account 'sunwukong', and we have an agent 'sunwukong', route there!
227
+ if (!finalAgentId && inbound.accountId && inbound.accountId !== 'default' && inbound.accountId !== 'main') {
228
+ // Check if such an agent exists in rootConfig
229
+ const agents = rootConfig.agents?.list || {};
230
+ const agentExists = Array.isArray(agents) ? agents.some(a => a.id === inbound.accountId) : !!agents[inbound.accountId];
231
+
232
+ if (agentExists) {
223
233
  finalAgentId = inbound.accountId;
224
- routingSource = 'aggressive-account-name-match';
225
- } else {
226
- finalAgentId = route.agentId || 'main'; // Ultimate fallback
227
- routingSource = route.agentId ? 'global-bindings-fallback' : 'default-routing';
234
+ routingSource = 'account-agent-name-match';
228
235
  }
229
236
  }
230
237
 
238
+
239
+ // E. Ultimate Fallback
240
+ if (!finalAgentId) {
241
+ finalAgentId = route.agentId || 'main'; // Use SDK result or hard default 'main'
242
+ routingSource = route.agentId ? 'sdk-default-fallback' : 'hardcoded-main-fallback';
243
+ }
244
+
231
245
  logger.info(`[pier-connector] Routing account '${inbound.accountId}' -> agent '${finalAgentId}' (Source: ${routingSource})`);
232
246
 
233
247
  const dynamicSessionKey = `pier-job-${jobId}`;
@@ -241,7 +255,7 @@ export default function register(api) {
241
255
  "=========================================",
242
256
  "You are an autonomous AI worker on Pier. This job currently has NO assigned worker.",
243
257
  "1. DO NOT directly solve the user's task or output the final answer right now.",
244
- "2. You MUST USE the `pier_bid_task` tool to send a pitch/bid to the employer explaining why you are best equipped to solve this, and state your price.",
258
+ "2. You MUST USE the \`pier_bid_task\` tool to send a pitch/bid to the employer explaining why you are best equipped to solve this.",
245
259
  "3. Stop executing after submitting the bid.",
246
260
  "4. You MUST use the Job ID provided below when calling the tool.",
247
261
  `Job ID: ${jobId}`,
@@ -260,8 +274,9 @@ export default function register(api) {
260
274
  ].join('\n');
261
275
  }
262
276
 
277
+ // MsgContext uses PascalCase for keys in OpenClaw V2 SDK
263
278
  const ctxPayload = api.runtime.channel.reply.finalizeInboundContext({
264
- agentId: finalAgentId, // Lowercase agentId is the standard target identifier
279
+ agentId: finalAgentId, // Keep lowercase here as it's the target system ID
265
280
  Body: inbound.text,
266
281
  BodyForAgent: inbound.text,
267
282
  RawBody: inbound.text,
@@ -282,12 +297,13 @@ export default function register(api) {
282
297
  Metadata: {
283
298
  ...metadata,
284
299
  accountId: this.accountId,
285
- pierJobId: jobId
300
+ pierJobId: jobId,
301
+ routingSource: routingSource
286
302
  }
287
303
  });
288
304
 
289
305
  const { dispatcher, markDispatchIdle } = api.runtime.channel.reply.createReplyDispatcherWithTyping({
290
- cfg: api.runtime.config,
306
+ cfg: api.config,
291
307
  agentId: finalAgentId,
292
308
  deliver: async (payload) => {
293
309
  const currentMeta = this.activeNodeJobs.get(jobId);
@@ -314,7 +330,7 @@ export default function register(api) {
314
330
 
315
331
  try {
316
332
  await api.runtime.channel.reply.dispatchReplyFromConfig({
317
- ctx: ctxPayload, cfg: api.runtime.config, dispatcher
333
+ ctx: ctxPayload, cfg: api.config, dispatcher
318
334
  });
319
335
  } finally {
320
336
  markDispatchIdle();
@@ -1210,3 +1226,11 @@ export default function register(api) {
1210
1226
 
1211
1227
  logger.info('[pier-connector] Plugin registered');
1212
1228
  }
1229
+
1230
+ export default definePluginEntry({
1231
+ id: 'pier-connector',
1232
+ name: 'Pier Connector',
1233
+ description: 'Connects OpenClaw to the Pier job marketplace.',
1234
+ register
1235
+ });
1236
+