@dhf-openclaw/grix 0.4.10 → 0.4.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -90,6 +90,17 @@ function resolveWsUrl(merged, agentId) {
90
90
  }
91
91
  return `ws://127.0.0.1:27189/v1/agent-api/ws?agent_id=${encodeURIComponent(agentId)}`;
92
92
  }
93
+ function resolveAgentAPIBaseUrl(merged) {
94
+ const cfgBase = normalizeNonEmpty(merged.apiBaseUrl);
95
+ if (cfgBase) {
96
+ return cfgBase;
97
+ }
98
+ if (normalizeNonEmpty(merged.wsUrl)) {
99
+ return "";
100
+ }
101
+ const envBase = normalizeNonEmpty(process.env.GRIX_AGENT_API_BASE);
102
+ return envBase;
103
+ }
93
104
  function redactAibotWsUrl(wsUrl) {
94
105
  if (!wsUrl) {
95
106
  return "";
@@ -113,6 +124,7 @@ function resolveAibotAccount(params) {
113
124
  const agentId = normalizeAgentId(merged.agentId || process.env.GRIX_AGENT_ID);
114
125
  const apiKey = normalizeNonEmpty(merged.apiKey || process.env.GRIX_API_KEY);
115
126
  const wsUrl = resolveWsUrl(merged, agentId);
127
+ const apiBaseUrl = resolveAgentAPIBaseUrl(merged);
116
128
  const configured = Boolean(wsUrl && agentId && apiKey);
117
129
  return {
118
130
  accountId,
@@ -120,6 +132,7 @@ function resolveAibotAccount(params) {
120
132
  enabled,
121
133
  configured,
122
134
  wsUrl,
135
+ apiBaseUrl,
123
136
  agentId,
124
137
  apiKey,
125
138
  config: merged
@@ -467,6 +480,9 @@ var AibotWsClient = class {
467
480
  `reconnect scheduled in ${params.delayMs}ms attempt=${params.attempt} stable=${params.stable} authRejected=${params.authRejected} penaltyFloor=${params.penaltyFloor} suppressed=${suppressed}`
468
481
  );
469
482
  }
483
+ shouldLogInboundPacket(cmd) {
484
+ return cmd !== "ping" && cmd !== "pong" && cmd !== "send_ack";
485
+ }
470
486
  getStatus() {
471
487
  return { ...this.status };
472
488
  }
@@ -542,9 +558,6 @@ var AibotWsClient = class {
542
558
  if (!normalizedChannel || !normalizedAccountID || !normalizedRouteSessionKey || !normalizedSessionID) {
543
559
  throw new Error("grix session_route_bind requires channel/account_id/route_session_key/session_id");
544
560
  }
545
- this.logInfo(
546
- `session_route_bind request channel=${normalizedChannel} accountId=${normalizedAccountID} routeSessionKey=${normalizedRouteSessionKey} sessionId=${normalizedSessionID}`
547
- );
548
561
  const packet = await this.request(
549
562
  "session_route_bind",
550
563
  {
@@ -564,9 +577,6 @@ var AibotWsClient = class {
564
577
  );
565
578
  throw this.packetError(packet);
566
579
  }
567
- this.logInfo(
568
- `session_route_bind ack channel=${normalizedChannel} accountId=${normalizedAccountID} routeSessionKey=${normalizedRouteSessionKey} sessionId=${normalizedSessionID}`
569
- );
570
580
  return packet.payload;
571
581
  }
572
582
  async resolveSessionRoute(channel, accountId, routeSessionKey, opts = {}) {
@@ -577,9 +587,6 @@ var AibotWsClient = class {
577
587
  if (!normalizedChannel || !normalizedAccountID || !normalizedRouteSessionKey) {
578
588
  throw new Error("grix session_route_resolve requires channel/account_id/route_session_key");
579
589
  }
580
- this.logInfo(
581
- `session_route_resolve request channel=${normalizedChannel} accountId=${normalizedAccountID} routeSessionKey=${normalizedRouteSessionKey}`
582
- );
583
590
  const packet = await this.request(
584
591
  "session_route_resolve",
585
592
  {
@@ -603,9 +610,6 @@ var AibotWsClient = class {
603
610
  if (!normalizedSessionID) {
604
611
  throw new Error("grix session_route_resolve ack missing session_id");
605
612
  }
606
- this.logInfo(
607
- `session_route_resolve ack channel=${normalizedChannel} accountId=${normalizedAccountID} routeSessionKey=${normalizedRouteSessionKey} sessionId=${normalizedSessionID}`
608
- );
609
613
  return {
610
614
  ...payload,
611
615
  channel: String(payload.channel ?? normalizedChannel),
@@ -1058,7 +1062,7 @@ var AibotWsClient = class {
1058
1062
  }
1059
1063
  const cmd = String(packet.cmd ?? "").trim();
1060
1064
  const seq = Number(packet.seq ?? 0);
1061
- if (cmd !== "ping") {
1065
+ if (this.shouldLogInboundPacket(cmd)) {
1062
1066
  this.logInfo(
1063
1067
  `inbound packet conn=${resolvedConnSerial} cmd=${cmd || "-"} seq=${seq} bytes=${text.length}`
1064
1068
  );
@@ -3656,9 +3660,6 @@ async function deliverAibotStreamBlock(params) {
3656
3660
  messageSid: params.messageSid,
3657
3661
  clientMsgId: params.clientMsgId
3658
3662
  });
3659
- params.runtime.log(
3660
- `[grix:${params.account.accountId}] stream block split into ${chunks.length} chunk(s) ${context} textLen=${params.text.length} chunkDelayMs=${chunkDelayMs}`
3661
- );
3662
3663
  for (let index = 0; index < chunks.length; index++) {
3663
3664
  if (params.abortSignal?.aborted) {
3664
3665
  params.runtime.log(
@@ -3671,9 +3672,6 @@ async function deliverAibotStreamBlock(params) {
3671
3672
  if (!normalized) {
3672
3673
  continue;
3673
3674
  }
3674
- params.runtime.log(
3675
- `[grix:${params.account.accountId}] stream chunk send ${context} chunkIndex=${index + 1}/${chunks.length} deltaLen=${normalized.length}`
3676
- );
3677
3675
  await params.client.sendStreamChunk(params.sessionId, normalized, {
3678
3676
  eventId: params.eventId,
3679
3677
  clientMsgId: params.clientMsgId,
@@ -3726,9 +3724,6 @@ async function bindSessionRouteMapping(params) {
3726
3724
  return;
3727
3725
  }
3728
3726
  try {
3729
- params.runtime.log(
3730
- `[grix:${params.account.accountId}] session route bind begin routeSessionKey=${routeSessionKey} sessionId=${sessionId}`
3731
- );
3732
3727
  await params.client.bindSessionRoute(
3733
3728
  "grix",
3734
3729
  params.account.accountId,
@@ -3958,9 +3953,6 @@ async function processEvent(params) {
3958
3953
  sessionId,
3959
3954
  controller: runAbortController
3960
3955
  });
3961
- runtime2.log(
3962
- `[grix:${account.accountId}] active reply run registered eventId=${eventId || `${sessionId}:${messageSid}`} sessionId=${sessionId} messageSid=${messageSid} activeRun=${activeRun ? "true" : "false"}`
3963
- );
3964
3956
  try {
3965
3957
  const route = core.channel.routing.resolveAgentRoute({
3966
3958
  cfg: config,
@@ -4186,22 +4178,10 @@ async function processEvent(params) {
4186
4178
  }
4187
4179
  hasSentBlock = false;
4188
4180
  try {
4189
- const finishContext = buildEventLogContext({
4190
- eventId,
4191
- sessionId,
4192
- messageSid,
4193
- clientMsgId: streamClientMsgId
4194
- });
4195
4181
  const finishDelayMs = resolveStreamFinishDelayMs(account);
4196
4182
  if (finishDelayMs > 0) {
4197
- runtime2.log(
4198
- `[grix:${account.accountId}] stream finish delay ${finishContext} delayMs=${finishDelayMs}`
4199
- );
4200
4183
  await sleep2(finishDelayMs);
4201
4184
  }
4202
- runtime2.log(
4203
- `[grix:${account.accountId}] stream finish ${finishContext}`
4204
- );
4205
4185
  await client.sendStreamChunk(sessionId, "", {
4206
4186
  eventId,
4207
4187
  clientMsgId: streamClientMsgId,
@@ -4235,9 +4215,12 @@ async function processEvent(params) {
4235
4215
  clientMsgId: info.kind === "block" ? streamClientMsgId : `reply_${messageSid}_${outboundCounter}`,
4236
4216
  outboundCounter
4237
4217
  });
4238
- runtime2.log(
4239
- `[grix:${account.accountId}] deliver ${deliverContext} kind=${info.kind} textLen=${text.length} hasMedia=${hasMedia} streamedBefore=${streamedTextAlreadyVisible}`
4240
- );
4218
+ const isStreamBlock = info.kind === "block" && !guardedText && !hasMedia && text.length > 0;
4219
+ if (!isStreamBlock) {
4220
+ runtime2.log(
4221
+ `[grix:${account.accountId}] deliver ${deliverContext} kind=${info.kind} textLen=${text.length} hasMedia=${hasMedia} streamedBefore=${streamedTextAlreadyVisible}`
4222
+ );
4223
+ }
4241
4224
  if (guardedText) {
4242
4225
  runtime2.error(
4243
4226
  `[grix:${account.accountId}] rewrite internal reply text ${deliverContext} code=${guardedText.code} raw=${JSON.stringify(guardedText.rawText)}`
@@ -4256,7 +4239,7 @@ async function processEvent(params) {
4256
4239
  );
4257
4240
  return;
4258
4241
  }
4259
- if (info.kind === "block" && !guardedText && !hasMedia && text) {
4242
+ if (isStreamBlock) {
4260
4243
  const didSendBlock = await deliverAibotStreamBlock({
4261
4244
  text,
4262
4245
  client,
@@ -4407,7 +4390,7 @@ async function processEvent(params) {
4407
4390
  }
4408
4391
  } finally {
4409
4392
  runtime2.log(
4410
- `[grix:${account.accountId}] active reply run clearing eventId=${activeRun?.eventId || "-"} sessionId=${activeRun?.sessionId || sessionId} stopRequested=${activeRun?.stopRequested === true} abortReason=${activeRun ? resolveAbortReason(activeRun.controller.signal) : "-"} visibleOutputSent=${visibleOutputSent}`
4393
+ `[grix:${account.accountId}] active reply run clearing eventId=${activeRun?.eventId || "-"} stopRequested=${activeRun?.stopRequested === true} abortReason=${activeRun ? resolveAbortReason(activeRun.controller.signal) : "-"} visibleOutputSent=${visibleOutputSent}`
4411
4394
  );
4412
4395
  clearActiveReplyRun(activeRun);
4413
4396
  if (!inboundEventAccepted) {
@@ -4602,7 +4585,7 @@ var meta = {
4602
4585
  label: "Grix",
4603
4586
  selectionLabel: "Grix",
4604
4587
  docsPath: "/channels/grix",
4605
- blurb: "Connect OpenClaw to grix.dhf.pub for OpenClaw website management with mobile PWA support.",
4588
+ blurb: "Connect OpenClaw to a Grix deployment for website management with mobile PWA support.",
4606
4589
  aliases: ["gr"],
4607
4590
  order: 90
4608
4591
  };
@@ -4715,6 +4698,7 @@ var aibotPlugin = {
4715
4698
  clearBaseFields: [
4716
4699
  "name",
4717
4700
  "wsUrl",
4701
+ "apiBaseUrl",
4718
4702
  "agentId",
4719
4703
  "apiKey",
4720
4704
  "reconnectMs",
@@ -5309,6 +5293,17 @@ function buildGroupMemberAddRequest(params) {
5309
5293
  body
5310
5294
  };
5311
5295
  }
5296
+ function buildGroupLeaveSelfRequest(params) {
5297
+ const sessionID = readRequiredStringParam(params, "sessionId");
5298
+ return {
5299
+ actionName: "group_leave_self",
5300
+ method: "POST",
5301
+ path: "/sessions/leave",
5302
+ body: {
5303
+ session_id: sessionID
5304
+ }
5305
+ };
5306
+ }
5312
5307
  function buildGroupMemberRemoveRequest(params) {
5313
5308
  const sessionID = readRequiredStringParam(params, "sessionId");
5314
5309
  const memberIDs = readNumericIDArray(params, "memberIds", true);
@@ -5516,6 +5511,8 @@ function buildAgentHTTPRequest(action, params) {
5516
5511
  return buildMessageHistoryRequest(params);
5517
5512
  case "group_create":
5518
5513
  return buildGroupCreateRequest(params);
5514
+ case "group_leave_self":
5515
+ return buildGroupLeaveSelfRequest(params);
5519
5516
  case "group_member_add":
5520
5517
  return buildGroupMemberAddRequest(params);
5521
5518
  case "group_member_remove":
@@ -5539,13 +5536,19 @@ function buildAgentHTTPRequest(action, params) {
5539
5536
 
5540
5537
  // src/admin/agent-api-http.ts
5541
5538
  var DEFAULT_HTTP_TIMEOUT_MS = 15e3;
5539
+ var MAX_LOG_KEYS = 8;
5540
+ var MAX_LOG_PAYLOAD_CHARS = 1200;
5542
5541
  function trimTrailingSlash(value) {
5543
5542
  return value.replace(/\/+$/, "");
5544
5543
  }
5544
+ function logAgentAPIInfo(message) {
5545
+ console.info(`[grix:agent-api] ${message}`);
5546
+ }
5547
+ function logAgentAPIError(message) {
5548
+ console.error(`[grix:agent-api] ${message}`);
5549
+ }
5545
5550
  function resolveExplicitAgentAPIBase() {
5546
- const base = String(
5547
- process.env.GRIX_AGENT_API_BASE ?? process.env.AIBOT_AGENT_API_BASE ?? ""
5548
- ).trim();
5551
+ const base = String(process.env.GRIX_AGENT_API_BASE ?? "").trim();
5549
5552
  if (!base) {
5550
5553
  return "";
5551
5554
  }
@@ -5595,16 +5598,39 @@ function deriveLocalAgentAPIBaseFromWsUrl(wsUrl) {
5595
5598
  const protocol = parsed.protocol === "wss:" ? "https:" : "http:";
5596
5599
  return trimTrailingSlash(`${protocol}//${parsed.hostname}:${apiPort}`) + "/v1/agent-api";
5597
5600
  }
5598
- function resolveAgentAPIBase(account) {
5599
- const explicit = resolveExplicitAgentAPIBase();
5600
- if (explicit) {
5601
- return explicit;
5601
+ function resolveAgentAPIBaseInfo(account) {
5602
+ const accountBase = trimTrailingSlash(String(account.apiBaseUrl ?? "").trim());
5603
+ if (accountBase) {
5604
+ return {
5605
+ base: accountBase,
5606
+ source: "account_api_base_url"
5607
+ };
5602
5608
  }
5603
- const local = deriveLocalAgentAPIBaseFromWsUrl(account.wsUrl);
5609
+ const normalizedWsUrl = String(account.wsUrl ?? "").trim();
5610
+ const local = deriveLocalAgentAPIBaseFromWsUrl(normalizedWsUrl);
5604
5611
  if (local) {
5605
- return local;
5612
+ return {
5613
+ base: local,
5614
+ source: "local_ws_url"
5615
+ };
5616
+ }
5617
+ if (normalizedWsUrl) {
5618
+ return {
5619
+ base: deriveAgentAPIBaseFromWsUrl(normalizedWsUrl),
5620
+ source: "derived_from_ws_url"
5621
+ };
5622
+ }
5623
+ const explicit = resolveExplicitAgentAPIBase();
5624
+ if (explicit) {
5625
+ return {
5626
+ base: explicit,
5627
+ source: "env_grix_agent_api_base"
5628
+ };
5606
5629
  }
5607
- return deriveAgentAPIBaseFromWsUrl(account.wsUrl);
5630
+ return {
5631
+ base: deriveAgentAPIBaseFromWsUrl(normalizedWsUrl),
5632
+ source: "derived_from_ws_url"
5633
+ };
5608
5634
  }
5609
5635
  function buildRequestURL(base, path, query) {
5610
5636
  const normalizedPath = path.startsWith("/") ? path : `/${path}`;
@@ -5647,10 +5673,105 @@ function extractNetworkErrorMessage(error) {
5647
5673
  }
5648
5674
  return String(error);
5649
5675
  }
5676
+ function buildAPIKeyState(apiKey) {
5677
+ const normalized = String(apiKey ?? "").trim();
5678
+ if (!normalized) {
5679
+ return "empty";
5680
+ }
5681
+ return "present";
5682
+ }
5683
+ function summarizePayloadKeys(payload) {
5684
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
5685
+ return "none";
5686
+ }
5687
+ const keys = Object.keys(payload).map((k) => String(k).trim()).filter(Boolean).sort();
5688
+ if (!keys.length) {
5689
+ return "none";
5690
+ }
5691
+ const limited = keys.slice(0, MAX_LOG_KEYS);
5692
+ if (keys.length <= MAX_LOG_KEYS) {
5693
+ return limited.join(",");
5694
+ }
5695
+ return `${limited.join(",")}...(total=${keys.length})`;
5696
+ }
5697
+ function summarizePayloadBytes(payload) {
5698
+ try {
5699
+ return String(Buffer.byteLength(JSON.stringify(payload ?? {}), "utf8"));
5700
+ } catch {
5701
+ return "unknown";
5702
+ }
5703
+ }
5704
+ function isSensitiveLogKey(key) {
5705
+ const normalized = String(key ?? "").trim().toLowerCase();
5706
+ return normalized.includes("api_key") || normalized.includes("apikey") || normalized.includes("token") || normalized.includes("authorization") || normalized.includes("password") || normalized.includes("secret");
5707
+ }
5708
+ function sanitizePayloadForLog(payload, depth = 0) {
5709
+ if (depth >= 5) {
5710
+ return "[max-depth]";
5711
+ }
5712
+ if (payload == null) {
5713
+ return payload;
5714
+ }
5715
+ if (typeof payload === "string" || typeof payload === "number" || typeof payload === "boolean") {
5716
+ return payload;
5717
+ }
5718
+ if (Array.isArray(payload)) {
5719
+ return payload.map((item) => sanitizePayloadForLog(item, depth + 1));
5720
+ }
5721
+ if (typeof payload === "object") {
5722
+ const raw = payload;
5723
+ const sanitized = {};
5724
+ for (const [key, value] of Object.entries(raw)) {
5725
+ sanitized[key] = isSensitiveLogKey(key) ? "<redacted>" : sanitizePayloadForLog(value, depth + 1);
5726
+ }
5727
+ return sanitized;
5728
+ }
5729
+ return String(payload);
5730
+ }
5731
+ function stringifyPayloadForLog(payload) {
5732
+ let json = "";
5733
+ try {
5734
+ json = JSON.stringify(sanitizePayloadForLog(payload));
5735
+ } catch {
5736
+ return '"[unserializable]"';
5737
+ }
5738
+ if (!json) {
5739
+ return "{}";
5740
+ }
5741
+ if (json.length <= MAX_LOG_PAYLOAD_CHARS) {
5742
+ return json;
5743
+ }
5744
+ return `${json.slice(0, MAX_LOG_PAYLOAD_CHARS)}...(truncated,len=${json.length})`;
5745
+ }
5746
+ function buildRequestLogContext(params, context) {
5747
+ const queryPayload = params.query ?? {};
5748
+ const bodyPayload = params.method === "POST" ? params.body ?? {} : {};
5749
+ return [
5750
+ `action=${params.actionName}`,
5751
+ `account=${params.account.accountId}`,
5752
+ `agent=${params.account.agentId}`,
5753
+ `method=${params.method}`,
5754
+ `source=${context.resolvedBase.source}`,
5755
+ `url=${context.url}`,
5756
+ `timeout_ms=${context.timeoutMs}`,
5757
+ `api_key=${buildAPIKeyState(params.account.apiKey)}`,
5758
+ `query_keys=${summarizePayloadKeys(queryPayload)}`,
5759
+ `query_payload=${JSON.stringify(stringifyPayloadForLog(queryPayload))}`,
5760
+ `body_keys=${summarizePayloadKeys(bodyPayload)}`,
5761
+ `body_payload=${JSON.stringify(stringifyPayloadForLog(bodyPayload))}`,
5762
+ `body_bytes=${summarizePayloadBytes(bodyPayload)}`
5763
+ ].join(" ");
5764
+ }
5650
5765
  async function callAgentAPI(params) {
5651
- const base = resolveAgentAPIBase(params.account);
5652
- const url = buildRequestURL(base, params.path, params.query);
5766
+ const resolvedBase = resolveAgentAPIBaseInfo(params.account);
5767
+ const url = buildRequestURL(resolvedBase.base, params.path, params.query);
5653
5768
  const timeoutMs = Number.isFinite(params.timeoutMs) ? Math.max(1e3, Math.floor(params.timeoutMs)) : DEFAULT_HTTP_TIMEOUT_MS;
5769
+ const requestLogContext = buildRequestLogContext(params, {
5770
+ resolvedBase,
5771
+ url,
5772
+ timeoutMs
5773
+ });
5774
+ logAgentAPIInfo(`request ${requestLogContext}`);
5654
5775
  const controller = new AbortController();
5655
5776
  const timer = setTimeout(() => controller.abort(), timeoutMs);
5656
5777
  let resp;
@@ -5666,6 +5787,9 @@ async function callAgentAPI(params) {
5666
5787
  });
5667
5788
  } catch (error) {
5668
5789
  clearTimeout(timer);
5790
+ logAgentAPIError(
5791
+ `network_error ${requestLogContext} error=${JSON.stringify(extractNetworkErrorMessage(error))}`
5792
+ );
5669
5793
  throw new Error(
5670
5794
  `Grix ${params.actionName} network error: ${extractNetworkErrorMessage(error)}`
5671
5795
  );
@@ -5677,6 +5801,9 @@ async function callAgentAPI(params) {
5677
5801
  try {
5678
5802
  envelope = JSON.parse(rawBody);
5679
5803
  } catch {
5804
+ logAgentAPIError(
5805
+ `invalid_response ${requestLogContext} status=${status} raw_len=${rawBody.length}`
5806
+ );
5680
5807
  throw new Error(
5681
5808
  `Grix ${params.actionName} invalid response: status=${status} body=${rawBody.slice(0, 256)}`
5682
5809
  );
@@ -5684,13 +5811,41 @@ async function callAgentAPI(params) {
5684
5811
  const bizCode = normalizeBizCode(envelope.code);
5685
5812
  if (!resp.ok || bizCode !== 0) {
5686
5813
  const message = normalizeMessage(envelope.msg);
5814
+ logAgentAPIError(
5815
+ `failed ${requestLogContext} status=${status} code=${bizCode} msg=${message} has_data=${envelope.data == null ? "false" : "true"}`
5816
+ );
5687
5817
  throw new Error(
5688
5818
  `Grix ${params.actionName} failed: status=${status} code=${bizCode} msg=${message}`
5689
5819
  );
5690
5820
  }
5821
+ logAgentAPIInfo(`success ${requestLogContext} status=${status}`);
5691
5822
  return envelope.data;
5692
5823
  }
5693
5824
 
5825
+ // src/admin/account-binding.ts
5826
+ function normalizeNonEmpty2(value) {
5827
+ const normalized = String(value ?? "").trim();
5828
+ return normalized || void 0;
5829
+ }
5830
+ function resolveStrictToolAccountId(params) {
5831
+ const toolAccountId = normalizeNonEmpty2(params.toolAccountId);
5832
+ const contextAccountId = normalizeNonEmpty2(params.contextAccountId);
5833
+ console.info(
5834
+ `[grix:account-binding] tool=${params.toolName} request_account=${toolAccountId ?? "-"} context_account=${contextAccountId ?? "-"}`
5835
+ );
5836
+ if (!toolAccountId) {
5837
+ throw new Error(
5838
+ `[${params.toolName}] accountId is required. Pass the exact accountId of the current connection.`
5839
+ );
5840
+ }
5841
+ if (contextAccountId && toolAccountId !== contextAccountId) {
5842
+ throw new Error(
5843
+ `[${params.toolName}] accountId mismatch. request=${toolAccountId}, context=${contextAccountId}. Refusing cross-account execution.`
5844
+ );
5845
+ }
5846
+ return toolAccountId;
5847
+ }
5848
+
5694
5849
  // src/admin/accounts.ts
5695
5850
  var DEFAULT_ACCOUNT_ID2 = "default";
5696
5851
  function normalizeAccountId2(value) {
@@ -5711,9 +5866,24 @@ function listConfiguredAccountIds2(cfg) {
5711
5866
  }
5712
5867
  return Object.keys(accounts).filter(Boolean);
5713
5868
  }
5714
- function normalizeNonEmpty2(value) {
5869
+ function normalizeNonEmpty3(value) {
5715
5870
  return String(value ?? "").trim();
5716
5871
  }
5872
+ function trimTrailingSlash2(value) {
5873
+ return value.replace(/\/+$/, "");
5874
+ }
5875
+ function summarizeEndpoint(value) {
5876
+ const normalized = normalizeNonEmpty3(value);
5877
+ if (!normalized) {
5878
+ return "-";
5879
+ }
5880
+ try {
5881
+ const parsed = new URL(normalized);
5882
+ return `${parsed.protocol}//${parsed.host}`;
5883
+ } catch {
5884
+ return normalized.slice(0, 128);
5885
+ }
5886
+ }
5717
5887
  function appendAgentIdToWsUrl2(rawWsUrl, agentId) {
5718
5888
  if (!rawWsUrl) {
5719
5889
  return "";
@@ -5736,8 +5906,8 @@ function appendAgentIdToWsUrl2(rawWsUrl, agentId) {
5736
5906
  }
5737
5907
  }
5738
5908
  function resolveWsUrl2(merged, agentId) {
5739
- const envWs = normalizeNonEmpty2(process.env.GRIX_WS_URL);
5740
- const cfgWs = normalizeNonEmpty2(merged.wsUrl);
5909
+ const envWs = normalizeNonEmpty3(process.env.GRIX_WS_URL);
5910
+ const cfgWs = normalizeNonEmpty3(merged.wsUrl);
5741
5911
  const ws = cfgWs || envWs;
5742
5912
  if (ws) {
5743
5913
  return appendAgentIdToWsUrl2(ws, agentId);
@@ -5747,6 +5917,44 @@ function resolveWsUrl2(merged, agentId) {
5747
5917
  }
5748
5918
  return `ws://127.0.0.1:27189/v1/agent-api/ws?agent_id=${encodeURIComponent(agentId)}`;
5749
5919
  }
5920
+ function resolveAgentAPIBaseUrl2(merged) {
5921
+ const cfgBase = trimTrailingSlash2(normalizeNonEmpty3(merged.apiBaseUrl));
5922
+ if (cfgBase) {
5923
+ return cfgBase;
5924
+ }
5925
+ if (normalizeNonEmpty3(merged.wsUrl)) {
5926
+ return "";
5927
+ }
5928
+ const envBase = trimTrailingSlash2(normalizeNonEmpty3(process.env.GRIX_AGENT_API_BASE));
5929
+ const webBase = trimTrailingSlash2(normalizeNonEmpty3(process.env.GRIX_WEB_BASE_URL));
5930
+ return envBase || webBase;
5931
+ }
5932
+ function resolveStrictAccountConfig(cfg, accountId) {
5933
+ const grixCfg = rawGrixConfig(cfg);
5934
+ const accounts = grixCfg.accounts;
5935
+ if (!accounts || typeof accounts !== "object") {
5936
+ console.error(
5937
+ `[grix:account] strict lookup failed account=${accountId} reason=accounts_map_missing`
5938
+ );
5939
+ throw new Error(
5940
+ `Grix account "${accountId}" is not configured under channels.grix.accounts.`
5941
+ );
5942
+ }
5943
+ const configuredIds = Object.keys(accounts).filter(Boolean).sort();
5944
+ const account = accounts[accountId];
5945
+ if (!account || typeof account !== "object") {
5946
+ console.error(
5947
+ `[grix:account] strict lookup failed account=${accountId} reason=account_missing configured_accounts=${configuredIds.join(",") || "none"}`
5948
+ );
5949
+ throw new Error(
5950
+ `Grix account "${accountId}" is missing under channels.grix.accounts.${accountId}.`
5951
+ );
5952
+ }
5953
+ console.info(
5954
+ `[grix:account] strict lookup account=${accountId} configured_accounts=${configuredIds.join(",") || "none"} has_ws=${normalizeNonEmpty3(account.wsUrl) ? "yes" : "no"} has_api_base=${normalizeNonEmpty3(account.apiBaseUrl) ? "yes" : "no"} has_agent_id=${normalizeNonEmpty3(account.agentId) ? "yes" : "no"} has_api_key=${normalizeNonEmpty3(account.apiKey) ? "yes" : "no"}`
5955
+ );
5956
+ return account;
5957
+ }
5750
5958
  function resolveMergedAccountConfig(cfg, accountId) {
5751
5959
  const grixCfg = rawGrixConfig(cfg);
5752
5960
  const { accounts: _ignoredAccounts, defaultAccount: _ignoredDefault, ...base } = grixCfg;
@@ -5776,21 +5984,29 @@ function resolveDefaultGrixAccountId(cfg) {
5776
5984
  return ids[0] ?? DEFAULT_ACCOUNT_ID2;
5777
5985
  }
5778
5986
  function resolveGrixAccount(params) {
5987
+ const strictScope = Boolean(params.strictAccountScope);
5779
5988
  const accountId = params.accountId == null || String(params.accountId).trim() === "" ? resolveDefaultGrixAccountId(params.cfg) : normalizeAccountId2(params.accountId);
5780
- const merged = resolveMergedAccountConfig(params.cfg, accountId);
5989
+ const merged = strictScope ? resolveStrictAccountConfig(params.cfg, accountId) : resolveMergedAccountConfig(params.cfg, accountId);
5781
5990
  const baseEnabled = rawGrixConfig(params.cfg).enabled !== false;
5782
5991
  const accountEnabled = merged.enabled !== false;
5783
5992
  const enabled = baseEnabled && accountEnabled;
5784
- const agentId = normalizeNonEmpty2(merged.agentId || process.env.GRIX_AGENT_ID);
5785
- const apiKey = normalizeNonEmpty2(merged.apiKey || process.env.GRIX_API_KEY);
5786
- const wsUrl = resolveWsUrl2(merged, agentId);
5993
+ const agentId = strictScope ? normalizeNonEmpty3(merged.agentId) : normalizeNonEmpty3(merged.agentId || process.env.GRIX_AGENT_ID);
5994
+ const apiKey = strictScope ? normalizeNonEmpty3(merged.apiKey) : normalizeNonEmpty3(merged.apiKey || process.env.GRIX_API_KEY);
5995
+ const wsUrl = strictScope ? appendAgentIdToWsUrl2(normalizeNonEmpty3(merged.wsUrl), agentId) : resolveWsUrl2(merged, agentId);
5996
+ const apiBaseUrl = strictScope ? trimTrailingSlash2(normalizeNonEmpty3(merged.apiBaseUrl)) : resolveAgentAPIBaseUrl2(merged);
5787
5997
  const configured = Boolean(wsUrl && agentId && apiKey);
5998
+ if (strictScope) {
5999
+ console.info(
6000
+ `[grix:account] strict resolved account=${accountId} enabled=${enabled} configured=${configured} ws_endpoint=${summarizeEndpoint(wsUrl)} api_base_endpoint=${summarizeEndpoint(apiBaseUrl)} agent_id=${agentId || "-"} api_key=${apiKey ? "present" : "empty"}`
6001
+ );
6002
+ }
5788
6003
  return {
5789
6004
  accountId,
5790
- name: normalizeNonEmpty2(merged.name) || void 0,
6005
+ name: normalizeNonEmpty3(merged.name) || void 0,
5791
6006
  enabled,
5792
6007
  configured,
5793
6008
  wsUrl,
6009
+ apiBaseUrl,
5794
6010
  agentId,
5795
6011
  apiKey,
5796
6012
  config: merged
@@ -5805,6 +6021,7 @@ function summarizeGrixAccounts(cfg) {
5805
6021
  enabled: account.enabled,
5806
6022
  configured: account.configured,
5807
6023
  wsUrl: account.wsUrl || null,
6024
+ apiBaseUrl: account.apiBaseUrl || null,
5808
6025
  agentId: account.agentId || null
5809
6026
  };
5810
6027
  });
@@ -5842,9 +6059,15 @@ function sanitizeCreatedAgentData(data) {
5842
6059
  return payload;
5843
6060
  }
5844
6061
  async function createGrixApiAgent(params) {
6062
+ const accountId = resolveStrictToolAccountId({
6063
+ toolName: "grix_agent_admin",
6064
+ toolAccountId: params.toolParams.accountId,
6065
+ contextAccountId: params.contextAccountId
6066
+ });
5845
6067
  const account = resolveGrixAccount({
5846
6068
  cfg: params.cfg,
5847
- accountId: params.toolParams.accountId
6069
+ accountId,
6070
+ strictAccountScope: true
5848
6071
  });
5849
6072
  if (!account.enabled) {
5850
6073
  throw new Error(`Grix account "${account.accountId}" is disabled.`);
@@ -5968,9 +6191,10 @@ var GrixAgentAdminToolSchema = {
5968
6191
  required: ["actions"]
5969
6192
  }
5970
6193
  },
5971
- required: ["agentName", "describeMessageTool"]
6194
+ required: ["accountId", "agentName", "describeMessageTool"]
5972
6195
  };
5973
- function createGrixAgentAdminTool(api) {
6196
+ function createGrixAgentAdminTool(api, ctx) {
6197
+ const contextAccountId = ctx?.agentAccountId;
5974
6198
  return {
5975
6199
  name: "grix_agent_admin",
5976
6200
  label: "Grix Agent Admin",
@@ -5981,7 +6205,8 @@ function createGrixAgentAdminTool(api) {
5981
6205
  return jsonToolResult(
5982
6206
  await createGrixApiAgent({
5983
6207
  cfg: api.config,
5984
- toolParams: params
6208
+ toolParams: params,
6209
+ contextAccountId
5985
6210
  })
5986
6211
  );
5987
6212
  } catch (err) {
@@ -6000,6 +6225,8 @@ function mapGroupActionToRequestAction(action) {
6000
6225
  return "group_create";
6001
6226
  case "detail":
6002
6227
  return "group_detail_read";
6228
+ case "leave":
6229
+ return "group_leave_self";
6003
6230
  case "add_members":
6004
6231
  return "group_member_add";
6005
6232
  case "remove_members":
@@ -6018,9 +6245,15 @@ function mapGroupActionToRequestAction(action) {
6018
6245
  }
6019
6246
  }
6020
6247
  async function runGrixGroupAction(params) {
6248
+ const accountId = resolveStrictToolAccountId({
6249
+ toolName: "grix_group",
6250
+ toolAccountId: params.toolParams.accountId,
6251
+ contextAccountId: params.contextAccountId
6252
+ });
6021
6253
  const account = resolveGrixAccount({
6022
6254
  cfg: params.cfg,
6023
- accountId: params.toolParams.accountId
6255
+ accountId,
6256
+ strictAccountScope: true
6024
6257
  });
6025
6258
  if (!account.enabled) {
6026
6259
  throw new Error(`Grix account "${account.accountId}" is disabled.`);
@@ -6038,6 +6271,13 @@ async function runGrixGroupAction(params) {
6038
6271
  query: request.query,
6039
6272
  body: request.body
6040
6273
  });
6274
+ if (params.toolParams.action === "leave") {
6275
+ const d = data;
6276
+ const left = d != null && typeof d === "object" ? d["left"] : void 0;
6277
+ console.info(
6278
+ `[grix:group] leave result account=${account.accountId} agent=${account.agentId} session=${String(params.toolParams.sessionId ?? "")} left=${left}`
6279
+ );
6280
+ }
6041
6281
  return {
6042
6282
  ok: true,
6043
6283
  accountId: account.accountId,
@@ -6063,7 +6303,7 @@ var GrixGroupToolSchema = {
6063
6303
  memberIds: { type: "array", items: numericIdSchema },
6064
6304
  memberTypes: { type: "array", items: { type: "integer", enum: [1, 2] } }
6065
6305
  },
6066
- required: ["action", "name"]
6306
+ required: ["action", "accountId", "name"]
6067
6307
  },
6068
6308
  {
6069
6309
  type: "object",
@@ -6073,7 +6313,17 @@ var GrixGroupToolSchema = {
6073
6313
  accountId: { type: "string", minLength: 1 },
6074
6314
  sessionId: { type: "string", minLength: 1 }
6075
6315
  },
6076
- required: ["action", "sessionId"]
6316
+ required: ["action", "accountId", "sessionId"]
6317
+ },
6318
+ {
6319
+ type: "object",
6320
+ additionalProperties: false,
6321
+ properties: {
6322
+ action: { const: "leave" },
6323
+ accountId: { type: "string", minLength: 1 },
6324
+ sessionId: { type: "string", minLength: 1 }
6325
+ },
6326
+ required: ["action", "accountId", "sessionId"]
6077
6327
  },
6078
6328
  {
6079
6329
  type: "object",
@@ -6085,7 +6335,7 @@ var GrixGroupToolSchema = {
6085
6335
  memberIds: { type: "array", items: numericIdSchema, minItems: 1 },
6086
6336
  memberTypes: { type: "array", items: { type: "integer", enum: [1, 2] } }
6087
6337
  },
6088
- required: ["action", "sessionId", "memberIds"]
6338
+ required: ["action", "accountId", "sessionId", "memberIds"]
6089
6339
  },
6090
6340
  {
6091
6341
  type: "object",
@@ -6097,7 +6347,7 @@ var GrixGroupToolSchema = {
6097
6347
  memberIds: { type: "array", items: numericIdSchema, minItems: 1 },
6098
6348
  memberTypes: { type: "array", items: { type: "integer", enum: [1, 2] } }
6099
6349
  },
6100
- required: ["action", "sessionId", "memberIds"]
6350
+ required: ["action", "accountId", "sessionId", "memberIds"]
6101
6351
  },
6102
6352
  {
6103
6353
  type: "object",
@@ -6110,7 +6360,7 @@ var GrixGroupToolSchema = {
6110
6360
  memberType: { type: "integer", enum: [1] },
6111
6361
  role: { type: "integer", enum: [1, 2] }
6112
6362
  },
6113
- required: ["action", "sessionId", "memberId", "role"]
6363
+ required: ["action", "accountId", "sessionId", "memberId", "role"]
6114
6364
  },
6115
6365
  {
6116
6366
  type: "object",
@@ -6121,7 +6371,7 @@ var GrixGroupToolSchema = {
6121
6371
  sessionId: { type: "string", minLength: 1 },
6122
6372
  allMembersMuted: { type: "boolean" }
6123
6373
  },
6124
- required: ["action", "sessionId", "allMembersMuted"]
6374
+ required: ["action", "accountId", "sessionId", "allMembersMuted"]
6125
6375
  },
6126
6376
  {
6127
6377
  type: "object",
@@ -6135,7 +6385,7 @@ var GrixGroupToolSchema = {
6135
6385
  isSpeakMuted: { type: "boolean" },
6136
6386
  canSpeakWhenAllMuted: { type: "boolean" }
6137
6387
  },
6138
- required: ["action", "sessionId", "memberId"],
6388
+ required: ["action", "accountId", "sessionId", "memberId"],
6139
6389
  anyOf: [
6140
6390
  { required: ["isSpeakMuted"] },
6141
6391
  { required: ["canSpeakWhenAllMuted"] }
@@ -6149,11 +6399,12 @@ var GrixGroupToolSchema = {
6149
6399
  accountId: { type: "string", minLength: 1 },
6150
6400
  sessionId: { type: "string", minLength: 1 }
6151
6401
  },
6152
- required: ["action", "sessionId"]
6402
+ required: ["action", "accountId", "sessionId"]
6153
6403
  }
6154
6404
  ]
6155
6405
  };
6156
- function createGrixGroupTool(api) {
6406
+ function createGrixGroupTool(api, ctx) {
6407
+ const contextAccountId = ctx?.agentAccountId;
6157
6408
  return {
6158
6409
  name: "grix_group",
6159
6410
  label: "Grix Group",
@@ -6164,7 +6415,8 @@ function createGrixGroupTool(api) {
6164
6415
  return jsonToolResult(
6165
6416
  await runGrixGroupAction({
6166
6417
  cfg: api.config,
6167
- toolParams: params
6418
+ toolParams: params,
6419
+ contextAccountId
6168
6420
  })
6169
6421
  );
6170
6422
  } catch (err) {
@@ -6191,9 +6443,15 @@ function mapQueryActionToRequestAction(action) {
6191
6443
  }
6192
6444
  }
6193
6445
  async function runGrixQueryAction(params) {
6446
+ const accountId = resolveStrictToolAccountId({
6447
+ toolName: "grix_query",
6448
+ toolAccountId: params.toolParams.accountId,
6449
+ contextAccountId: params.contextAccountId
6450
+ });
6194
6451
  const account = resolveGrixAccount({
6195
6452
  cfg: params.cfg,
6196
- accountId: params.toolParams.accountId
6453
+ accountId,
6454
+ strictAccountScope: true
6197
6455
  });
6198
6456
  if (!account.enabled) {
6199
6457
  throw new Error(`Grix account "${account.accountId}" is disabled.`);
@@ -6232,7 +6490,7 @@ var GrixQueryToolSchema = {
6232
6490
  limit: { type: "integer", minimum: 1 },
6233
6491
  offset: { type: "integer", minimum: 0 }
6234
6492
  },
6235
- required: ["action", "id"]
6493
+ required: ["action", "accountId", "id"]
6236
6494
  },
6237
6495
  {
6238
6496
  type: "object",
@@ -6244,7 +6502,7 @@ var GrixQueryToolSchema = {
6244
6502
  limit: { type: "integer", minimum: 1 },
6245
6503
  offset: { type: "integer", minimum: 0 }
6246
6504
  },
6247
- required: ["action", "id"]
6505
+ required: ["action", "accountId", "id"]
6248
6506
  },
6249
6507
  {
6250
6508
  type: "object",
@@ -6256,11 +6514,12 @@ var GrixQueryToolSchema = {
6256
6514
  beforeId: { type: "string", pattern: "^[0-9]+$" },
6257
6515
  limit: { type: "integer", minimum: 1 }
6258
6516
  },
6259
- required: ["action", "sessionId"]
6517
+ required: ["action", "accountId", "sessionId"]
6260
6518
  }
6261
6519
  ]
6262
6520
  };
6263
- function createGrixQueryTool(api) {
6521
+ function createGrixQueryTool(api, ctx) {
6522
+ const contextAccountId = ctx?.agentAccountId;
6264
6523
  return {
6265
6524
  name: "grix_query",
6266
6525
  label: "Grix Query",
@@ -6271,7 +6530,8 @@ function createGrixQueryTool(api) {
6271
6530
  return jsonToolResult(
6272
6531
  await runGrixQueryAction({
6273
6532
  cfg: api.config,
6274
- toolParams: params
6533
+ toolParams: params,
6534
+ contextAccountId
6275
6535
  })
6276
6536
  );
6277
6537
  } catch (err) {
@@ -6364,9 +6624,9 @@ var plugin = {
6364
6624
  register(api) {
6365
6625
  setAibotRuntime(api.runtime);
6366
6626
  api.registerChannel({ plugin: aibotPlugin });
6367
- api.registerTool(createGrixQueryTool(api), { optional: true });
6368
- api.registerTool(createGrixGroupTool(api), { optional: true });
6369
- api.registerTool(createGrixAgentAdminTool(api), { optional: true });
6627
+ api.registerTool((ctx) => createGrixQueryTool(api, ctx), { optional: true });
6628
+ api.registerTool((ctx) => createGrixGroupTool(api, ctx), { optional: true });
6629
+ api.registerTool((ctx) => createGrixAgentAdminTool(api, ctx), { optional: true });
6370
6630
  api.registerCli(({ program }) => registerGrixAdminCli({ api, program }), {
6371
6631
  commands: ["grix"]
6372
6632
  });