@parall/parall 1.62.0 → 1.63.0

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.
@@ -52323,6 +52323,13 @@ function browserViewerRequestOptions(command, opts) {
52323
52323
  };
52324
52324
  }
52325
52325
 
52326
+ // ../sdk/dist/clip-connection-endpoints.js
52327
+ var clipConnectionEndpoints = {
52328
+ CLIP_CONNECTIONS: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/connections`,
52329
+ CLIP_CONNECTION_ACCESS: (orgId, connId) => `/api/v1/orgs/${orgId}/clip-connections/${connId}/access`,
52330
+ CLIP_CONNECTION: (orgId, connId) => `/api/v1/orgs/${orgId}/clip-connections/${connId}`
52331
+ };
52332
+
52326
52333
  // ../sdk/dist/attachment-endpoints.js
52327
52334
  function attachmentEndpoints(apiBase) {
52328
52335
  return {
@@ -52336,6 +52343,7 @@ function attachmentEndpoints(apiBase) {
52336
52343
  // ../sdk/dist/edge-endpoints.js
52337
52344
  var API_BASE = "/api/v1";
52338
52345
  var edgeEndpoints = {
52346
+ ORG_EDGE_PROFILE_ACCESS: (orgId, edgeId, profileName) => `${API_BASE}/orgs/${orgId}/edge/${edgeId}/profiles/${encodeURIComponent(profileName)}/access`,
52339
52347
  ORG_EDGE: (orgId) => `${API_BASE}/orgs/${orgId}/edge`,
52340
52348
  ORG_EDGE_CONNECT: (orgId) => `${API_BASE}/orgs/${orgId}/edge/connect`,
52341
52349
  ORG_EDGE_DEVICES: (orgId) => `${API_BASE}/orgs/${orgId}/edge/devices`,
@@ -52527,6 +52535,7 @@ var ENDPOINTS = {
52527
52535
  MACHINES_ME_AGENTS: `${API_BASE2}/machines/me/agents`,
52528
52536
  MACHINES_ME_HEALTH: `${API_BASE2}/machines/me/health`,
52529
52537
  MACHINES_ME_RUNTIME_REPORT: `${API_BASE2}/machines/me/runtime-report`,
52538
+ MACHINES_ME_DIAGNOSTICS: `${API_BASE2}/machines/me/diagnostics`,
52530
52539
  MACHINES_ME_CLIPS: `${API_BASE2}/machines/me/clips`,
52531
52540
  MACHINES_ME_BROWSER_PROFILES: `${API_BASE2}/machines/me/browser-profiles`,
52532
52541
  MACHINES_ME_BROWSER_PROFILE_STATUS: (profileId) => `${API_BASE2}/machines/me/browser-profiles/${profileId}/status`,
@@ -52713,6 +52722,7 @@ var ENDPOINTS = {
52713
52722
  // Wiki History (commits, file commits, blame)
52714
52723
  WIKI_COMMITS: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/commits`,
52715
52724
  WIKI_FILE_COMMITS: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/file-commits`,
52725
+ WIKI_PATH_ACTIVITY: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/path-activity`,
52716
52726
  WIKI_BLAME: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/blame`,
52717
52727
  // Wiki Operations (audit log)
52718
52728
  WIKI_OPERATIONS: (orgId, wikiId) => `${WIKI_BASE}/orgs/${orgId}/wikis/${wikiId}/operations`,
@@ -52848,8 +52858,7 @@ var ENDPOINTS = {
52848
52858
  // Same request/reply shape as the v2 browser-profile viewer, on the v3 edge
52849
52859
  // pipe. Additive: does NOT replace BROWSER_PROFILE_VIEWER_COMMAND.
52850
52860
  ORG_EDGE_VIEWER_COMMAND: (orgId, edgeId) => `/api/v1/orgs/${orgId}/edge/${edgeId}/viewer/command`,
52851
- CLIP_CONNECTIONS: (orgId, clipId) => `/api/v1/orgs/${orgId}/clip-registry/${clipId}/connections`,
52852
- CLIP_CONNECTION: (orgId, connId) => `/api/v1/orgs/${orgId}/clip-connections/${connId}`,
52861
+ ...clipConnectionEndpoints,
52853
52862
  // Clip registry (v3, org-scoped, served by api-server — `crg_` entries)
52854
52863
  ORG_CLIP_REGISTRY: (orgId) => `/api/v1/orgs/${orgId}/clip-registry`,
52855
52864
  ORG_CLIP_REGISTRY_RESOLVE: (orgId) => `/api/v1/orgs/${orgId}/clip-registry/resolve`,
@@ -53363,6 +53372,39 @@ var ChannelConversationClient = class extends SlackFilesClient {
53363
53372
  }
53364
53373
  };
53365
53374
 
53375
+ // ../sdk/dist/clip-connection-client.js
53376
+ var ClipConnectionClient = class extends ChannelConversationClient {
53377
+ // ---- Clip connections ----
53378
+ async listClipConnections(orgId, clipId) {
53379
+ return this.request("GET", ENDPOINTS.CLIP_CONNECTIONS(orgId, clipId));
53380
+ }
53381
+ async createClipConnection(orgId, clipId, input) {
53382
+ return this.request("POST", ENDPOINTS.CLIP_CONNECTIONS(orgId, clipId), input);
53383
+ }
53384
+ async deleteClipConnection(orgId, connId) {
53385
+ return this.request("DELETE", ENDPOINTS.CLIP_CONNECTION(orgId, connId));
53386
+ }
53387
+ /** Organization members may read; personal connections are owner-only. */
53388
+ async getClipConnectionAccess(orgId, connId) {
53389
+ return this.request("GET", ENDPOINTS.CLIP_CONNECTION_ACCESS(orgId, connId));
53390
+ }
53391
+ /** Human org owner/admin; accepts JWT or personal key. */
53392
+ async putClipConnectionAccess(orgId, connId, input) {
53393
+ return this.request("PUT", ENDPOINTS.CLIP_CONNECTION_ACCESS(orgId, connId), input);
53394
+ }
53395
+ };
53396
+
53397
+ // ../sdk/dist/browser-profile-client.js
53398
+ var BrowserProfileClient = class extends ClipConnectionClient {
53399
+ async getBrowserProfileAccess(orgId, edgeId, profileName) {
53400
+ return this.request("GET", ENDPOINTS.ORG_EDGE_PROFILE_ACCESS(orgId, edgeId, profileName));
53401
+ }
53402
+ /** Replace the complete access policy; requires a human org owner/admin. */
53403
+ async putBrowserProfileAccess(orgId, edgeId, profileName, access) {
53404
+ return this.request("PUT", ENDPOINTS.ORG_EDGE_PROFILE_ACCESS(orgId, edgeId, profileName), access);
53405
+ }
53406
+ };
53407
+
53366
53408
  // ../sdk/dist/wiki-upload.js
53367
53409
  function createWikiUploadFormData(params) {
53368
53410
  const form = new FormData();
@@ -53499,7 +53541,7 @@ function legacyHeartbeatFromReport(report) {
53499
53541
  detectedRuntimes
53500
53542
  };
53501
53543
  }
53502
- var ParallClient = class _ParallClient extends ChannelConversationClient {
53544
+ var ParallClient = class _ParallClient extends BrowserProfileClient {
53503
53545
  baseUrl;
53504
53546
  wikiBaseUrl;
53505
53547
  token;
@@ -54533,6 +54575,17 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
54533
54575
  await this.postMachineHeartbeat(legacyHeartbeatFromReport(report));
54534
54576
  return "legacy";
54535
54577
  }
54578
+ /**
54579
+ * Upload a diagnostics bundle from the machine itself (`mck_` bearer):
54580
+ * a gzip body the daemon assembled and redacted locally. Multipart so the
54581
+ * meta travels beside the file; the server indexes it for platform staff.
54582
+ */
54583
+ async uploadMachineDiagnostics(bundle, meta2 = {}) {
54584
+ const form = new FormData();
54585
+ form.append("meta", JSON.stringify(meta2));
54586
+ form.append("bundle", new Blob([new Uint8Array(bundle)], { type: "application/gzip" }), "diagnostics.json.gz");
54587
+ return this.multipartRequest("POST", ENDPOINTS.MACHINES_ME_DIAGNOSTICS, form, false, { timeoutMs: 2 * 60 * 1e3 });
54588
+ }
54536
54589
  /**
54537
54590
  * @deprecated Legacy form of `putMachineRuntimeReport`, kept for servers
54538
54591
  * that predate it. `POST /machines/me/health` — report daemon state. All
@@ -55314,6 +55367,10 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
55314
55367
  ...params
55315
55368
  });
55316
55369
  }
55370
+ /** Bounded, ACL-safe activity for one Wiki file path. */
55371
+ async getWikiPathActivity(orgId, wikiId, path11, opts) {
55372
+ return this.request("GET", ENDPOINTS.WIKI_PATH_ACTIVITY(orgId, wikiId), void 0, { path: path11 }, false, opts);
55373
+ }
55317
55374
  async getWikiBlame(orgId, wikiId, path11, ref) {
55318
55375
  return this.request("GET", ENDPOINTS.WIKI_BLAME(orgId, wikiId), void 0, { path: path11, ref });
55319
55376
  }
@@ -55744,7 +55801,7 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
55744
55801
  /**
55745
55802
  * Read a clip's per-org exec access (by user id — humans and agents alike).
55746
55803
  * Org-member readable, so a denied caller can learn why exec answered
55747
- * `CLIP_NOT_ALLOWED` / `CLIP_CONNECTION_NOT_ALLOWED` (agents:
55804
+ * `CONNECTION_NOT_ALLOWED` (retired: `CLIP_NOT_ALLOWED` / `CLIP_CONNECTION_NOT_ALLOWED`) (agents:
55748
55805
  * `CLIP_AGENT_NOT_ALLOWED` / `CLIP_AGENT_CONNECTION_NOT_ALLOWED`). Writing
55749
55806
  * it (`putClipAgentExecAccess`) is an org owner/admin's act.
55750
55807
  */
@@ -55784,6 +55841,19 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
55784
55841
  async deleteEdgeDevice(orgId, edgeId) {
55785
55842
  return this.request("DELETE", ENDPOINTS.ORG_EDGE_DEVICE(orgId, edgeId));
55786
55843
  }
55844
+ /** Move the human caller's OWN BYOC device between the org layer and their
55845
+ * personal layer (ADR-020). `member` takes the device — and every clip
55846
+ * connection bound to it — out of the org's sight and into the owner's sole
55847
+ * custody; `org` shares it back, after which an org admin binds clips to it
55848
+ * and the clip's access list governs exec. Idempotent. Refused for hosted
55849
+ * profiles (`EDGE_NOT_PERSONALIZABLE`), for anyone but the owner
55850
+ * (`FORBIDDEN`; someone else's personal device is `NOT_FOUND`), and for
55851
+ * agents. */
55852
+ async setEdgeManagedBy(orgId, edgeId, managedBy) {
55853
+ return this.request("PATCH", ENDPOINTS.ORG_EDGE_DEVICE(orgId, edgeId), {
55854
+ managed_by: managedBy
55855
+ });
55856
+ }
55787
55857
  /** Idempotently remove the human caller's own offline BYOC registration.
55788
55858
  * A live connection returns `EDGE_ONLINE`. */
55789
55859
  async unregisterEdgeDevice(orgId, edgeId) {
@@ -55866,7 +55936,7 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
55866
55936
  return this.request("GET", ENDPOINTS.ORG_BROWSER_ALIAS_EXECUTION(orgId, requestId));
55867
55937
  }
55868
55938
  /** Accept one idempotent Browser Use operation for an explicit Profile.
55869
- * The Server resolves Profile→Edge; callers never select an Edge directly. */
55939
+ * JWT, personal, agent and managed keys use profile access. The Server resolves Profile→Edge. */
55870
55940
  async createBrowserUseOperation(orgId, request3) {
55871
55941
  return this.request("POST", ENDPOINTS.ORG_BROWSER_USE_OPERATIONS(orgId), request3);
55872
55942
  }
@@ -55983,9 +56053,9 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
55983
56053
  * - `EDGE_DEADLINE_EXCEEDED` 504 — arrived late, provably NOT executed.
55984
56054
  * - `EDGE_HOSTED_DISABLED_FOR_ORG` 403, `EDGE_REPAIR` 503 (operator-held),
55985
56055
  * `EDGE_RUNTIME_UNAVAILABLE` 503 (deployment has no hosted runtime).
55986
- * - Access errors (decided before any side effect): `CLIP_NOT_ALLOWED`
55987
- * (no grant for this clip), `CLIP_CONNECTION_NOT_ALLOWED` (grant does
55988
- * not cover this connection) — agent principals receive the historical
56056
+ * - Access errors (before side effects): human `CONNECTION_NOT_ALLOWED`.
56057
+ * `CLIP_NOT_ALLOWED` / `CLIP_CONNECTION_NOT_ALLOWED` are retired.
56058
+ * Agent principals receive the historical
55989
56059
  * `CLIP_AGENT_NOT_ALLOWED` / `CLIP_AGENT_CONNECTION_NOT_ALLOWED` for one
55990
56060
  * release. An org owner/admin can widen access in the clip's settings.
55991
56061
  * - Routing errors: `CONNECTION_REQUIRED`, `CONNECTION_NOT_FOUND`,
@@ -56007,16 +56077,6 @@ var ParallClient = class _ParallClient extends ChannelConversationClient {
56007
56077
  throw err;
56008
56078
  }
56009
56079
  }
56010
- // ---- Clip connections ----
56011
- async listClipConnections(orgId, clipId) {
56012
- return this.request("GET", ENDPOINTS.CLIP_CONNECTIONS(orgId, clipId));
56013
- }
56014
- async createClipConnection(orgId, clipId, input) {
56015
- return this.request("POST", ENDPOINTS.CLIP_CONNECTIONS(orgId, clipId), input);
56016
- }
56017
- async deleteClipConnection(orgId, connId) {
56018
- return this.request("DELETE", ENDPOINTS.CLIP_CONNECTION(orgId, connId));
56019
- }
56020
56080
  // ---- MCP clip server config (same-org or reviewed Official OAuth) ----
56021
56081
  /**
56022
56082
  * Read the redacted MCP config. 404 NOT_FOUND when the clip has none yet —
@@ -56664,12 +56724,15 @@ function createActiveForkState(fork, targetId, continuationPrefix) {
56664
56724
 
56665
56725
  // ../agent-core/dist/redact.js
56666
56726
  function redactSecrets(s, knownValues = []) {
56727
+ return maskKnownValues(s, knownValues).replace(/\b(agk|mck|cpk)_[A-Za-z0-9_-]+/g, "$1_***").replace(/\b(sk|pk|rk)-[A-Za-z0-9_-]{8,}/g, "$1-***").replace(/\bAKIA[0-9A-Z]{16}\b/g, "AKIA***").replace(/\b((?:bearer|basic)\s+)[A-Za-z0-9._~+/=-]+/gi, "$1***").replace(/(\b(?:[\w-]*[_-])?(?:api[_-]?key|key|token|secret|password|passwd|authorization)["']?\s*[=:]\s*)(?:"(?:\\.|[^"\\\r\n])*"|'(?:\\.|[^'\\\r\n])*'|[^\s&;,}\]"']+)/gi, "$1***").replace(/[A-Za-z0-9_-]{32,}/g, "***");
56728
+ }
56729
+ function maskKnownValues(s, knownValues) {
56667
56730
  let out = s;
56668
56731
  for (const v of knownValues) {
56669
56732
  if (typeof v === "string" && v.length >= 6)
56670
56733
  out = out.split(v).join("***");
56671
56734
  }
56672
- return out.replace(/\b(agk|mck|cpk)_[A-Za-z0-9_-]+/g, "$1_***").replace(/\b(sk|pk|rk)-[A-Za-z0-9_-]{8,}/g, "$1-***").replace(/\bAKIA[0-9A-Z]{16}\b/g, "AKIA***").replace(/\b(bearer\s+)[A-Za-z0-9._~+/=-]{8,}/gi, "$1***").replace(/[A-Za-z0-9_-]{32,}/g, "***");
56735
+ return out;
56673
56736
  }
56674
56737
  function redactTurnOutcome(event, knownValues) {
56675
56738
  const redacted = { ...event };
@@ -56690,6 +56753,16 @@ function describeTurnOutcomeFailure(outcome) {
56690
56753
  stepMessage: `LLM turn ${outcome.outcome}${retryNote}${outcome.detail ? `: ${outcome.detail}` : ""}`
56691
56754
  };
56692
56755
  }
56756
+ function redactLogger(log, knownValues) {
56757
+ if (!log)
56758
+ return void 0;
56759
+ return {
56760
+ info: (message) => log.info(redactSecrets(message, knownValues)),
56761
+ warn: (message) => log.warn(redactSecrets(message, knownValues)),
56762
+ error: (message) => log.error(redactSecrets(message, knownValues)),
56763
+ ...log.child ? { child: (name) => redactLogger(log.child(name), knownValues) } : {}
56764
+ };
56765
+ }
56693
56766
 
56694
56767
  // ../agent-core/dist/lane-ledger.js
56695
56768
  import * as fs2 from "node:fs";
@@ -57024,10 +57097,10 @@ ${frame}` : frame;
57024
57097
  return {
57025
57098
  deliveryKey: dispatchEventIds.join(","),
57026
57099
  dispatchEventIds,
57027
- update: explicit ? (state) => this.updateInputState(lane, dispatchEventIds, state) : async () => void 0
57100
+ update: explicit ? (state, failure) => this.updateInputState(lane, dispatchEventIds, state, failure) : async () => void 0
57028
57101
  };
57029
57102
  }
57030
- async updateInputState(lane, dispatchEventIds, state) {
57103
+ async updateInputState(lane, dispatchEventIds, state, failure) {
57031
57104
  const failed = new Set(state === "failed" ? dispatchEventIds : []);
57032
57105
  const failedSourceIds = [...lane.folded].filter(([, dispatchEventId]) => failed.has(dispatchEventId)).map(([sourceId]) => sourceId);
57033
57106
  const restoreLocalClaims = failedSourceIds.length > 0 ? this.opts.releaseLocalClaims?.(failedSourceIds) : void 0;
@@ -57037,7 +57110,11 @@ ${frame}` : frame;
57037
57110
  target_uri: lane.targetUri,
57038
57111
  thread_root_id: lane.threadRootId,
57039
57112
  dispatch_event_ids: dispatchEventIds,
57040
- state
57113
+ state,
57114
+ ...state === "failed" && failure ? {
57115
+ outcome_class: errorWireClass(failure.outcomeClass),
57116
+ detail: failure.detail ? redactSecrets(failure.detail, this.opts.knownSecrets).slice(0, 500) : void 0
57117
+ } : {}
57041
57118
  });
57042
57119
  if (result.recognized !== dispatchEventIds.length) {
57043
57120
  throw new Error(`input lifecycle ${state} recognized ${result.recognized}/${dispatchEventIds.length} WorkItems`);
@@ -57058,19 +57135,7 @@ ${frame}` : frame;
57058
57135
  }
57059
57136
  return { retry: state === "failed" };
57060
57137
  }
57061
- /**
57062
- * Complete the lane when no local work remains for it: the server sweeps
57063
- * still-leased members as no_action, releases the occupancy row, and
57064
- * re-drives any same-target pending work. A STALE_LANE answer means a
57065
- * takeover already owns the resource — local state is dropped either way.
57066
- */
57067
- /**
57068
- * Record that the turn on this lane surfaced a runtime error. The flow
57069
- * settles an errored lane immediately (dispatchLaneGroup returns 'failed'
57070
- * after a forced complete), so the bit normally lives for one turn only —
57071
- * it is the transport between the gateway's per-session error signal and
57072
- * this lane's complete request.
57073
- */
57138
+ /** Carry the runtime error into the lane's forced completion. */
57074
57139
  markTurnError(laneKey, info = {}) {
57075
57140
  const lane = this.lanes.get(laneKey);
57076
57141
  if (lane)
@@ -58460,6 +58525,9 @@ async function consumeTypedDispatch(host, ref, run, hooks) {
58460
58525
  }
58461
58526
  }
58462
58527
  }
58528
+ } catch (err) {
58529
+ ledger.markTurnError(claimed.laneKey, releaseErrorInfo(err, [host.opts.config.api_key]));
58530
+ throw err;
58463
58531
  } finally {
58464
58532
  settle(resolved);
58465
58533
  span.setAttribute("dispatch.lane_result", resolved ? "dispatched" : "released");
@@ -60007,12 +60075,14 @@ var ParallAgentGateway = class {
60007
60075
  DISPATCH_DEADLINE_MS;
60008
60076
  constructor(opts) {
60009
60077
  this.opts = opts;
60078
+ opts = this.opts = { ...opts, log: redactLogger(opts.log, [opts.config.api_key]) };
60010
60079
  if (opts.dispatchContextDir) {
60011
60080
  this.laneLedger = new LaneLedger({
60012
60081
  client: opts.client,
60013
60082
  orgId: opts.config.org_id,
60014
60083
  contextDir: opts.dispatchContextDir,
60015
60084
  log: opts.log,
60085
+ knownSecrets: [opts.config.api_key],
60016
60086
  coverageMode: opts.dispatchAdapter.inputLifecycleMode ?? "implicit",
60017
60087
  releaseLocalClaims: (sourceIds) => releaseLocalMessageClaims(this.dispatchedMessages, sourceIds)
60018
60088
  });
@@ -60183,12 +60253,6 @@ var ParallAgentGateway = class {
60183
60253
  * this safe: every bridge emits its error events before the turn-boundary
60184
60254
  * turn_outcome.
60185
60255
  */
60186
- /**
60187
- * Redaction for every runtime-error text that gets persisted or shown: the
60188
- * turn-outcome detail, the runtime error step and the dispatch-failure
60189
- * step all surface in the product, and a runtime error can echo the agent
60190
- * key or a provider credential.
60191
- */
60192
60256
  redactRuntimeText(text) {
60193
60257
  return redactSecrets(text, [this.opts.config.api_key]).slice(0, 2e3);
60194
60258
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parall/parall",
3
- "version": "1.62.0",
3
+ "version": "1.63.0",
4
4
  "description": "OpenClaw channel plugin for Parall IM",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -16,8 +16,8 @@
16
16
  "openclaw.plugin.json"
17
17
  ],
18
18
  "dependencies": {
19
- "@parall/agent-core": "1.62.0",
20
- "@parall/sdk": "1.62.0"
19
+ "@parall/agent-core": "1.63.0",
20
+ "@parall/sdk": "1.63.0"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@types/node": "^22.0.0",
@@ -18,12 +18,16 @@ parall clip tools <clip> # MCP clips only: live tool schemas
18
18
  ```
19
19
 
20
20
  `clip list` answers both discovery questions at once: WHICH clip (name,
21
- description, version) and WHERE it can run — every connection with its
22
- `ccn_…` id, alias, and target kind:
21
+ description, version) and WHERE it could run — every connection you can SEE
22
+ (public org-layer rows or those the clip's access list admits you to, plus rows on your
23
+ own personal device; an admin's list is a management view of the whole org
24
+ layer and does not by itself grant exec) with its `ccn_…` id, alias, and
25
+ target kind:
23
26
 
24
27
  - `cloud` — an org-shared cloud profile (a maintainer's signed-in browser)
25
28
  - `desktop` — a member's device: org-shared (`layer: org` — an org admin
26
- binds it, the clip's access list decides, same as cloud and MCP) or
29
+ binds it; public connections admit everyone, otherwise the clip's access
30
+ list decides, same as cloud and MCP) or
27
31
  personal (`layer: personal` — its owner alone, nobody else sees it)
28
32
  - `mcp` — a remote MCP tool server
29
33
  - `device` — a device whose placement could not be resolved just now (the
@@ -63,6 +67,8 @@ bound to the clip, and the connection is what your access is granted on.
63
67
 
64
68
  - Without a connection the server answers `AGENT_CONNECTION_REQUIRED`; the
65
69
  fix is to discover the clip's connections and name one, never to retry.
70
+ - human 调用返回 `CONNECTION_NOT_ALLOWED` 时,请 org admin 公开该 connection
71
+ 或把调用者加入 Clip 名单;agent 本版仍返回下述两个错误码。
66
72
  - `CLIP_AGENT_NOT_ALLOWED` / `CLIP_AGENT_CONNECTION_NOT_ALLOWED` mean a
67
73
  human has restricted who may run this clip (or through which account);
68
74
  ask them to widen access — you cannot grant it to yourself.
@@ -112,10 +118,20 @@ parall clip exec <clip> <tool> [json-args] --connection <ccn_|alias>
112
118
  - `OUTCOME_UNKNOWN` follows the rule below: dispatched and MAY HAVE
113
119
  EXECUTED — never auto-retry.
114
120
 
121
+ ## Browser Use
122
+
123
+ Browser Use 接受 personal key 和 agent key,无需 managed key;权限按调用者
124
+ 在目标设备 profile 上的授权裁决。`PROFILE_NOT_ALLOWED` 表示未获授权,
125
+ 请 org admin 调整该 profile 的公开状态或名单,不要重试或改用其他 key 绕过。
126
+ profile 公开只授予 browser.read / browser.interact,browser.advanced 仍需显式授权。
127
+ Clip exec 的 connection 是另一种目标:agent 调用仍必须带 connection,缺失会返回
128
+ `AGENT_CONNECTION_REQUIRED`,先发现 connection 再调用。
129
+
115
130
  ## Behavior rules
116
131
 
117
132
  - An authorization error (`CLIP_AGENT_NOT_ALLOWED`,
118
- `CLIP_AGENT_CONNECTION_NOT_ALLOWED`, `FORBIDDEN`) is a fail-fast: ask
133
+ `CLIP_AGENT_CONNECTION_NOT_ALLOWED`, `CONNECTION_NOT_ALLOWED`,
134
+ `PROFILE_NOT_ALLOWED`, `FORBIDDEN`) is a fail-fast: ask
119
135
  an org admin to grant the clip or the connection — do not retry or work
120
136
  around it.
121
137
  - If the target device is offline or the call times out, report that