@gholl-studio/pier-connector 0.3.17 → 0.3.19

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gholl-studio/pier-connector",
3
3
  "author": "gholl",
4
- "version": "0.3.17",
4
+ "version": "0.3.19",
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.ts",
package/src/inbound.ts CHANGED
@@ -3,35 +3,25 @@
3
3
  * @description Manages inbound message processing, agent routing resolution, and session context propagation.
4
4
  */
5
5
 
6
- import type { PierPluginApi, InboundMessage } from './types.js';
6
+ import type { InboundMessage } from './types.js';
7
7
  import { truncate } from './job-handler.js';
8
8
 
9
9
  export async function handleInbound(
10
- api: PierPluginApi,
10
+ runtime: any, // Using context-aware runtime from gateway
11
11
  inbound: InboundMessage,
12
12
  jobId: string,
13
- robot: any, // Avoiding circular dependency with type PierRobot
14
- pierChannel: any
13
+ robot: any,
14
+ pierPlugin: any
15
15
  ) {
16
- const logger = api.logger;
17
- if (!api.runtime?.channel?.reply) {
18
- logger.error(`[pier-connector][${robot.accountId}] SDK Error: api.runtime.channel.reply is not available.`);
16
+ const logger = runtime.log || console;
17
+
18
+ if (!runtime.reply) {
19
+ console.error(`[pier-connector][${robot.accountId}] SDK Error: runtime.reply is not available.`);
19
20
  return;
20
21
  }
21
22
 
22
- // 0. Log Online/Configured Agents
23
- const agentsList = (api.config as any)?.agents?.list || [];
24
- const agentIds = Array.isArray(agentsList) ? agentsList.map((a: any) => a.id) : Object.keys(agentsList);
25
- logger.info(`[pier-connector][${robot.accountId}] Available agents in OpenClaw: ${JSON.stringify(agentIds)}`);
26
-
27
- // 1. Resolve Account-Scoped Configuration (Flat Structure for SDK)
28
- /**
29
- * ★ Multi-Account Configuration Isolation:
30
- * SDK helpers like resolveAgentRoute expect the channel config at the top level
31
- * of cfg.channels.<channelName>. Replacing it with the robot's merged config
32
- * ensures the SDK sees the correct agentId/dmPolicy for this specific account.
33
- */
34
- const rootConfig = api.config || {};
23
+ // 1. Resolve Account-Scoped Configuration
24
+ const rootConfig = runtime.cfg || {};
35
25
  const accountScopedCfg = {
36
26
  ...rootConfig,
37
27
  channels: {
@@ -40,8 +30,8 @@ export async function handleInbound(
40
30
  }
41
31
  };
42
32
 
43
- // 2. Resolve Agent Route via SDK with Scoped Config
44
- const route = api.runtime.channel.routing.resolveAgentRoute({
33
+ // 2. Resolve Agent Route
34
+ const route = runtime.routing.resolveAgentRoute({
45
35
  cfg: accountScopedCfg,
46
36
  channel: 'pier',
47
37
  accountId: robot.accountId,
@@ -53,14 +43,6 @@ export async function handleInbound(
53
43
 
54
44
  logger.info(`[pier-connector] Routing account '${robot.accountId}' -> agent '${finalAgentId}' (Source: ${routingSource})`);
55
45
 
56
- // Debug: Check Agent Identity (Correct Signature: resolveAgentIdentity(cfg, agentId))
57
- try {
58
- const identity = (api.runtime as any).agent.resolveAgentIdentity(accountScopedCfg, finalAgentId);
59
- logger.info(`[pier-connector:debug] Identity resolution for ${finalAgentId}: ${JSON.stringify(identity)}`);
60
- } catch (err: any) {
61
- logger.warn(`[pier-connector:debug] Identity resolution failed for ${finalAgentId}: ${err.message}`);
62
- }
63
-
64
46
  const dynamicSessionKey = `pier-job-${jobId}`;
65
47
  const metadata = robot.activeNodeJobs.get(jobId);
66
48
  let injectedPrompt = "";
@@ -89,19 +71,18 @@ export async function handleInbound(
89
71
  ].join('\n');
90
72
  }
91
73
 
92
- logger.info(`[pier-connector:trace] Finalized inbound context for job ${jobId}. Target Agent: ${finalAgentId}, Session: ${dynamicSessionKey}`);
93
-
94
- const ctxPayload = api.runtime.channel.reply.finalizeInboundContext({
74
+ // 3. Finalize Context
75
+ const ctxPayload = runtime.reply.finalizeInboundContext({
95
76
  Body: inbound.body,
96
77
  BodyForAgent: inbound.body,
97
78
  RawBody: inbound.body,
98
- From: `pier:${inbound.senderId}`,
79
+ From: inbound.senderId,
99
80
  To: `chat:${jobId}`,
100
81
  SessionKey: dynamicSessionKey,
101
82
  AccountId: robot.accountId,
102
83
  ChatType: 'direct',
103
84
  SenderId: inbound.senderId,
104
- SenderName: inbound.senderId, // Use senderId as name if unknown
85
+ SenderName: inbound.senderId,
105
86
  Provider: 'pier',
106
87
  Surface: 'pier',
107
88
  OriginatingChannel: 'pier',
@@ -114,41 +95,41 @@ export async function handleInbound(
114
95
  Metadata: {
115
96
  ...metadata,
116
97
  accountId: robot.accountId,
98
+ agentId: finalAgentId,
117
99
  pierJobId: jobId,
118
100
  routingSource: routingSource
119
101
  }
120
102
  });
121
103
 
122
- logger.info(`[pier-connector:trace] FULL DISPATCH CONTEXT for job ${jobId}: ${JSON.stringify(ctxPayload)}`);
123
-
124
- const { dispatcher, markDispatchIdle } = api.runtime.channel.reply.createReplyDispatcherWithTyping({
104
+ // 4. Create Dispatcher
105
+ const { dispatcher, markDispatchIdle } = runtime.reply.createReplyDispatcherWithTyping({
125
106
  deliver: async (payload: any, info: any) => {
126
107
  const currentMeta = robot.activeNodeJobs.get(jobId);
127
- const respondingAgent = payload.agentId || payload.btw?.agentId || payload.channelData?.agentId || finalAgentId;
108
+ const resAgent = payload.agentId || finalAgentId;
128
109
 
129
- logger.info(`[pier-connector:trace] Outbound delivery triggered for job ${jobId}. Type: ${info?.kind}. Responding Agent: ${respondingAgent}.`);
130
- logger.info(`[pier-connector:debug] FULL PAYLOAD: ${JSON.stringify(payload)}`);
110
+ logger.info(`[pier-connector:trace] Outbound delivery for ${jobId}. Responder: ${resAgent}.`);
131
111
 
132
112
  if (payload.text && payload.text.length > 0) {
133
- await pierChannel.outbound.sendText({
113
+ await pierPlugin.outbound.sendText({
134
114
  text: payload.text,
135
115
  to: `pier:${jobId}`,
116
+ accountId: robot.accountId,
136
117
  metadata: {
137
118
  ...currentMeta,
138
119
  accountId: robot.accountId,
139
120
  pierJobId: jobId,
140
- respondingAgentId: respondingAgent
121
+ respondingAgentId: resAgent
141
122
  },
142
123
  });
143
124
  }
144
125
  }
145
126
  });
146
127
 
147
- if (api.runtime.channel.session?.recordSessionMetaFromInbound) {
128
+ // 5. Session Recording
129
+ if (runtime.session?.recordSessionMetaFromInbound) {
148
130
  try {
149
- const storePath = api.runtime.channel.session.resolveStorePath(dynamicSessionKey);
150
- logger.info(`[pier-connector:trace] Recording session metadata at ${storePath}`);
151
- await api.runtime.channel.session.recordSessionMetaFromInbound({
131
+ const storePath = runtime.session.resolveStorePath(dynamicSessionKey);
132
+ await runtime.session.recordSessionMetaFromInbound({
152
133
  storePath, sessionKey: dynamicSessionKey, ctx: ctxPayload
153
134
  });
154
135
  } catch (err: any) {
@@ -156,22 +137,22 @@ export async function handleInbound(
156
137
  }
157
138
  }
158
139
 
140
+ // 6. Dispatch
159
141
  try {
160
- logger.info(`[pier-connector:trace] Dispatching reply to agent ${finalAgentId}...`);
161
- await api.runtime.channel.reply.dispatchReplyFromConfig({
142
+ await runtime.reply.dispatchReplyFromConfig({
162
143
  ctx: ctxPayload,
163
144
  cfg: accountScopedCfg,
164
145
  dispatcher,
165
146
  replyOptions: {
166
147
  onModelSelected: (mCtx: any) => {
167
- logger.info(`[pier-connector:debug] Model selected for ${jobId}: ${mCtx.provider}/${mCtx.model} (Think: ${mCtx.thinkLevel})`);
148
+ logger.info(`[pier-connector:debug] Model selected for ${jobId}: ${mCtx.provider}/${mCtx.model}`);
168
149
  }
169
150
  }
170
- } as any);
171
- logger.info(`[pier-connector:trace] dispatchReplyFromConfig completed for job ${jobId}`);
151
+ });
172
152
  } catch (err: any) {
173
153
  logger.error(`[pier-connector] ✖ Dispatch error for job ${jobId}: ${err.message}`);
174
154
  } finally {
175
- markDispatchIdle();
155
+ markDispatchIdle?.();
176
156
  }
177
157
  }
158
+
package/src/index.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  /**
2
2
  * @file index.ts
3
- * @description Main entry point for the Pier Connector plugin. Orchestrates robots, tools, and channel registration.
3
+ * @description Main entry point for the Pier Connector plugin.
4
+ * Implements the standard OpenClaw ChannelPlugin interface for native multi-account support.
4
5
  */
5
6
 
6
7
  import { definePluginEntry } from 'openclaw/plugin-sdk/plugin-entry';
8
+ import type { ChannelPlugin, OpenClawConfig, PluginRuntime } from 'openclaw/plugin-sdk';
7
9
  import { protocol } from '@gholl-studio/pier-sdk';
8
10
  const { createRequestPayload } = protocol;
9
11
  import { DEFAULTS } from './config.js';
@@ -12,99 +14,174 @@ import { handleInbound } from './inbound.js';
12
14
  import { registerCli } from './cli.js';
13
15
  import type { PierAccountConfig, PierPluginApi } from './types.js';
14
16
 
15
- const register = (api: PierPluginApi) => {
16
- const logger = api.logger;
17
- const instances = new Map<string, PierRobot>();
18
- const globalStats = { received: 0, completed: 0, failed: 0 };
19
-
20
- function mergedCfgFrom(legacy: any, account: any): PierAccountConfig {
21
- const merged = { ...legacy, ...account };
22
- return {
23
- accountId: account.accountId || 'default',
24
- pierApiUrl: merged.pierApiUrl || DEFAULTS.PIER_API_URL,
25
- nodeId: merged.nodeId || DEFAULTS.NODE_ID,
26
- secretKey: merged.secretKey || DEFAULTS.SECRET_KEY,
27
- privateKey: merged.privateKey || process.env.PIER_PRIVATE_KEY || DEFAULTS.PRIVATE_KEY,
28
- natsUrl: merged.natsUrl || DEFAULTS.NATS_URL,
29
- subject: merged.subject || DEFAULTS.SUBJECT,
30
- publishSubject: merged.publishSubject || DEFAULTS.PUBLISH_SUBJECT,
31
- queueGroup: merged.queueGroup || DEFAULTS.QUEUE_GROUP,
32
- agentId: merged.agentId || DEFAULTS.AGENT_ID,
33
- walletAddress: merged.walletAddress || DEFAULTS.WALLET_ADDRESS,
34
- capabilities: merged.capabilities || ['translation', 'code-execution', 'reasoning', 'vision'],
35
- };
36
- }
17
+ // Global instances map to track active robots by account ID
18
+ const instances = new Map<string, PierRobot>();
37
19
 
38
- function resolveConfigs(): PierAccountConfig[] {
39
- const globalAccounts = (api.config as any)?.channels?.['pier']?.accounts || {};
40
- const pluginAccounts = (api.pluginConfig as any)?.accounts || {};
41
- const rawAccounts = { ...globalAccounts, ...pluginAccounts };
42
- const legacyCfg = api.pluginConfig || {};
20
+ /**
21
+ * Merges global/legacy config with account-specific overrides.
22
+ */
23
+ function mergedCfgFrom(legacy: any, account: any): PierAccountConfig {
24
+ const merged = { ...legacy, ...account };
25
+ return {
26
+ accountId: account.accountId || 'default',
27
+ pierApiUrl: merged.pierApiUrl || DEFAULTS.PIER_API_URL,
28
+ nodeId: merged.nodeId || DEFAULTS.NODE_ID,
29
+ secretKey: merged.secretKey || DEFAULTS.SECRET_KEY,
30
+ privateKey: merged.privateKey || process.env.PIER_PRIVATE_KEY || DEFAULTS.PRIVATE_KEY,
31
+ natsUrl: merged.natsUrl || DEFAULTS.NATS_URL,
32
+ subject: merged.subject || DEFAULTS.SUBJECT,
33
+ publishSubject: merged.publishSubject || DEFAULTS.PUBLISH_SUBJECT,
34
+ queueGroup: merged.queueGroup || DEFAULTS.QUEUE_GROUP,
35
+ agentId: merged.agentId || DEFAULTS.AGENT_ID,
36
+ walletAddress: merged.walletAddress || DEFAULTS.WALLET_ADDRESS,
37
+ capabilities: merged.capabilities || ['translation', 'code-execution', 'reasoning', 'vision'],
38
+ };
39
+ }
43
40
 
44
- if (Object.keys(rawAccounts).length === 0) {
45
- return [mergedCfgFrom(legacyCfg, { accountId: 'default' })];
46
- }
41
+ /**
42
+ * Resolves all configured accounts for the Pier channel.
43
+ */
44
+ function getAccountConfigs(cfg: OpenClawConfig, pluginConfig: any): PierAccountConfig[] {
45
+ const globalAccounts = (cfg as any)?.channels?.['pier']?.accounts || {};
46
+ const pluginAccounts = pluginConfig?.accounts || {};
47
+ const rawAccounts = { ...globalAccounts, ...pluginAccounts };
48
+ const legacyCfg = pluginConfig || {};
47
49
 
48
- return Object.entries(rawAccounts).map(([id, account]: [string, any]) =>
49
- mergedCfgFrom(legacyCfg, { ...account, accountId: id })
50
- );
50
+ if (Object.keys(rawAccounts).length === 0) {
51
+ return [mergedCfgFrom(legacyCfg, { accountId: 'default' })];
51
52
  }
52
53
 
53
- const pierChannel = {
54
+ return Object.entries(rawAccounts).map(([id, account]: [string, any]) =>
55
+ mergedCfgFrom(legacyCfg, { ...account, accountId: id })
56
+ );
57
+ }
58
+
59
+ const pierPlugin: ChannelPlugin<PierAccountConfig> = {
60
+ id: 'pier',
61
+
62
+ meta: {
54
63
  id: 'pier',
55
- meta: {
56
- id: 'pier',
57
- label: 'Pier',
58
- selectionLabel: 'Pier (NATS Job Marketplace)',
59
- blurb: 'Connect to the Pier distributed job marketplace.'
64
+ label: 'Pier',
65
+ selectionLabel: 'Pier (NATS Job Marketplace)',
66
+ docsPath: '/channels/pier',
67
+ blurb: 'Connect to the Pier distributed job marketplace.',
68
+ },
69
+
70
+ capabilities: {
71
+ chatTypes: ['direct'],
72
+ media: false,
73
+ reactions: false,
74
+ threads: false,
75
+ nativeCommands: true,
76
+ blockStreaming: true,
77
+ },
78
+
79
+ // -------------------------------------------------------------------------
80
+ // Config Adapter
81
+ // -------------------------------------------------------------------------
82
+ config: {
83
+ listAccountIds: (cfg) => {
84
+ const accounts = (cfg as any)?.channels?.['pier']?.accounts || {};
85
+ const ids = Object.keys(accounts);
86
+ return ids.length > 0 ? ids : ['default'];
60
87
  },
61
- outbound: {
62
- sendText: async (params: any) => {
63
- const robot = instances.get(params.metadata?.accountId || 'default') || instances.values().next().value;
64
- if (!robot || !robot.js) return;
65
-
66
- const jobId = params.metadata?.pierJobId || params.to.replace(/^pier:/, '');
67
- const subject = `chat.${jobId}`;
68
-
69
- const payload = {
70
- id: crypto.randomUUID ? crypto.randomUUID() : (Math.random().toString(36).substring(2)),
71
- job_id: jobId,
72
- sender_id: robot.config.nodeId,
73
- sender_name: robot.accountId,
74
- sender_type: 'node',
75
- content: params.text,
76
- created_at: new Date().toISOString(),
77
- auth_token: robot.config.secretKey
78
- };
88
+ resolveAccount: (cfg, accountId) => {
89
+ const accounts = (cfg as any)?.channels?.['pier']?.accounts || {};
90
+ const account = accounts[accountId || 'default'] || {};
91
+ return mergedCfgFrom((cfg as any)?.channels?.['pier'] || {}, { ...account, accountId: accountId || 'default' });
92
+ },
93
+ defaultAccountId: () => 'default'
94
+ },
79
95
 
80
- await robot.js.publish(subject, new TextEncoder().encode(JSON.stringify(payload)));
81
- }
96
+ // -------------------------------------------------------------------------
97
+ // Pairing Adapter
98
+ // -------------------------------------------------------------------------
99
+ pairing: {
100
+ idLabel: 'pierJobId',
101
+ normalizeAllowEntry: (entry) => entry.replace(/^(pier|job):/i, ''),
102
+ notifyApproval: async ({ cfg, id, accountId }) => {
103
+ // Signal received when 'openclaw pairing approve pier <id>' is run.
104
+ // Useful if we want to trigger specific onboarding or status updates.
105
+ console.log(`[pier-connector] Pairing approved for Job ${id} on account ${accountId}`);
82
106
  }
83
- };
107
+ },
84
108
 
85
- api.registerChannel(pierChannel as any);
86
-
87
- api.registerService({
88
- id: 'pier-connector',
89
- start: async () => {
90
- const configs = resolveConfigs();
91
- for (const config of configs) {
92
- const robot = new PierRobot(config, api, async (inbound, jobId) => {
93
- await handleInbound(api, inbound, jobId, robot, pierChannel);
94
- globalStats.received++;
95
- });
96
- instances.set(config.accountId, robot);
97
- await robot.start();
109
+ // -------------------------------------------------------------------------
110
+ // Outbound Adapter
111
+ // -------------------------------------------------------------------------
112
+ outbound: {
113
+ deliveryMode: 'direct',
114
+ sendText: async (ctx) => {
115
+ const robot = instances.get(ctx.accountId || 'default') || instances.values().next().value;
116
+ if (!robot || !robot.js) {
117
+ throw new Error('Robot not connected');
98
118
  }
119
+
120
+ const jobId = ctx.to.replace(/^pier:/, '');
121
+ const subject = `chat.${jobId}`;
122
+
123
+ const payload = {
124
+ id: (globalThis.crypto as any).randomUUID ? (globalThis.crypto as any).randomUUID() : (Math.random().toString(36).substring(2)),
125
+ job_id: jobId,
126
+ sender_id: robot.config.nodeId,
127
+ sender_name: robot.accountId,
128
+ sender_type: 'node',
129
+ content: ctx.text,
130
+ created_at: new Date().toISOString(),
131
+ auth_token: robot.config.secretKey
132
+ };
133
+
134
+ await robot.js.publish(subject, new TextEncoder().encode(JSON.stringify(payload)));
135
+
136
+ return {
137
+ channel: 'pier',
138
+ messageId: payload.id,
139
+ conversationId: jobId
140
+ };
141
+ }
142
+ },
143
+
144
+ // -------------------------------------------------------------------------
145
+ // Gateway Adapter
146
+ // -------------------------------------------------------------------------
147
+ gateway: {
148
+ startAccount: async (ctx) => {
149
+ const config = ctx.account;
150
+ const robot = new PierRobot(config, (ctx.runtime as any), async (inbound, jobId) => {
151
+ // Pass the context-aware runtime and the plugin instance
152
+ await handleInbound((ctx.runtime as any), inbound, jobId, robot, pierPlugin);
153
+ });
154
+ instances.set(ctx.accountId, robot);
155
+ await robot.start();
156
+ ctx.setStatus({
157
+ ...ctx.getStatus(),
158
+ running: true,
159
+ lastStartAt: new Date().toISOString()
160
+ } as any);
99
161
  },
100
- stop: async () => {
101
- for (const robot of instances.values()) {
162
+ stopAccount: async (ctx) => {
163
+ const robot = instances.get(ctx.accountId);
164
+ if (robot) {
102
165
  await robot.stop();
166
+ instances.delete(ctx.accountId);
103
167
  }
104
- instances.clear();
168
+ ctx.setStatus({
169
+ ...ctx.getStatus(),
170
+ running: false,
171
+ lastStopAt: new Date().toISOString()
172
+ } as any);
105
173
  }
106
- });
174
+ }
175
+ };
176
+
177
+ const register = (api: PierPluginApi) => {
178
+ const logger = api.logger;
179
+ const globalStats = { received: 0, completed: 0, failed: 0 };
180
+
181
+ // Register our new ChannelPlugin
182
+ api.registerChannel({ plugin: pierPlugin as any });
107
183
 
184
+ // Tools and CLI registration
108
185
  api.registerTool({
109
186
  name: 'pier_publish',
110
187
  label: 'Publish to Pier',
@@ -193,6 +270,7 @@ const register = (api: PierPluginApi) => {
193
270
  { optional: true }
194
271
  );
195
272
 
273
+ // Helper to register marketplace action tools
196
274
  const registerSystemActionTool = (name: string, label: string, description: string, action: string, extraParams: any, userRole = 'node') => {
197
275
  api.registerTool({
198
276
  name,
@@ -215,7 +293,6 @@ const register = (api: PierPluginApi) => {
215
293
  }
216
294
 
217
295
  try {
218
- const subject = `chat.${params.jobId}`;
219
296
  const { jobId: j, accountId: _, ...p } = params;
220
297
 
221
298
  if (!robot.js) {
@@ -234,7 +311,7 @@ const register = (api: PierPluginApi) => {
234
311
  action: action
235
312
  };
236
313
 
237
- await robot.js.publish(subject, new TextEncoder().encode(JSON.stringify(msgData)));
314
+ await robot.js.publish(`chat.${params.jobId}`, new TextEncoder().encode(JSON.stringify(msgData)));
238
315
  return { content: [{ type: 'text', text: `${action} executed successfully` }], details: {} };
239
316
  } catch (err: any) {
240
317
  return { content: [{ type: 'text', text: `Error: ${err.message}` }], details: {} };
@@ -279,7 +356,7 @@ const register = (api: PierPluginApi) => {
279
356
  }
280
357
  }, { optional: true });
281
358
 
282
- // Register simple status command
359
+ // Status Command
283
360
  api.registerCommand({
284
361
  name: 'pier',
285
362
  description: 'Show Pier status',
@@ -302,3 +379,4 @@ export default definePluginEntry({
302
379
  description: 'Connects OpenClaw to the Pier job marketplace.',
303
380
  register
304
381
  });
382
+
package/src/robot.ts CHANGED
@@ -25,20 +25,20 @@ export class PierRobot {
25
25
  public connectionStatus: 'disconnected' | 'connecting' | 'connected' | 'error' = 'disconnected';
26
26
  public stats = { received: 0, completed: 0, failed: 0 };
27
27
 
28
- private api: PierPluginApi;
28
+ private runtime: any;
29
29
  private logger: any;
30
30
  private heartbeatTimer: NodeJS.Timeout | null = null;
31
31
  private onInbound: (inbound: InboundMessage, jobId: string) => Promise<void>;
32
32
 
33
33
  constructor(
34
34
  config: PierAccountConfig,
35
- api: PierPluginApi,
35
+ runtime: any,
36
36
  onInbound: (inbound: InboundMessage, jobId: string) => Promise<void>
37
37
  ) {
38
38
  this.config = config;
39
39
  this.accountId = config.accountId;
40
- this.api = api;
41
- this.logger = api.logger;
40
+ this.runtime = runtime;
41
+ this.logger = runtime.log || console;
42
42
  this.onInbound = onInbound;
43
43
  this.client = new PierClient({
44
44
  apiUrl: config.pierApiUrl,
@@ -264,7 +264,7 @@ export class PierRobot {
264
264
 
265
265
  async autoRegister() {
266
266
  if (!this.config.privateKey) return;
267
- const hostName = `${(this.api as any).getRuntimeInfo?.()?.hostname ?? 'Auto'}-${this.accountId}`;
267
+ const hostName = `${this.runtime?.hostname ?? 'Auto'}-${this.accountId}`;
268
268
  const { nodeId, secretKey } = await this.client.autoRegister(this.config.privateKey, hostName);
269
269
  this.config.nodeId = nodeId;
270
270
  this.config.secretKey = secretKey;