@perkos/perkos-a2a 0.12.57 → 0.12.58

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/README.md CHANGED
@@ -130,6 +130,31 @@ curl -s -X POST http://localhost:5050/a2a/jsonrpc \
130
130
  -d '{"jsonrpc":"2.0","method":"tasks/list","id":1,"params":{}}' | python3 -m json.tool
131
131
  ```
132
132
 
133
+ ## Which one do you need: plugin or standalone bridge?
134
+
135
+ This package ships **two different entry points**, and picking the wrong one is
136
+ the most common way to end up with an agent that looks connected but never does
137
+ any work.
138
+
139
+ | | In-runtime plugin (`index.ts`) | Standalone bridge (`bridge-agent.ts`) |
140
+ |---|---|---|
141
+ | How it runs | Loaded inside the OpenClaw gateway process | Its own process (`perkos-a2a-agent`) |
142
+ | Chat + A2A peer tasks | Yes | Yes |
143
+ | **PerkOS job-board work** | **No** | **Yes** |
144
+ | Reads the dispatcher's board scope | No | Yes |
145
+ | Reply sent back to the caller | Synthesized by the bridge | The runtime's real answer |
146
+ | Board MCP tools (`updateTaskStatus`, …) | Not hosted | Hosted on loopback |
147
+
148
+ **If the agent has to pick up tasks from a PerkOS board, you need the standalone
149
+ bridge.** This is true for **both** runtimes: it is not a Hermes-only concern.
150
+ The in-runtime plugin ignores the board scope the dispatcher attaches to a task
151
+ and completes the A2A task with a reply it synthesizes itself, so the board
152
+ never advances and the dispatcher burns its retries against a plausible-looking
153
+ answer.
154
+
155
+ Run **one** of them, never both against the same agent: two listeners will both
156
+ answer the same inbound task.
157
+
133
158
  ## Quick Start
134
159
 
135
160
  ```bash
@@ -161,6 +186,12 @@ pairing flow. Do not share one global relay key across production agents.
161
186
 
162
187
  ### OpenClaw agent
163
188
 
189
+ > **Board work needs the standalone bridge, not this plugin.** Installing the
190
+ > plugin gives an OpenClaw agent chat and peer-to-peer A2A. It does **not** let
191
+ > it work a PerkOS job board. See
192
+ > [Which one do you need](#which-one-do-you-need-plugin-or-standalone-bridge)
193
+ > and [PerkOS board tools](#perkos-board-tools-job-board-over-mcp).
194
+
164
195
  OpenClaw agents install `@perkos/perkos-a2a` as an OpenClaw plugin:
165
196
 
166
197
  ```bash
@@ -510,7 +541,10 @@ OpenClaw uses `enqueueSystemEvent` + `requestHeartbeatNow` when available.
510
541
 
511
542
  Hermes delivery uses the supported Hermes API Server HTTP surface. By default the bridge posts to `/v1/responses`; `/v1/runs` is available when you want observable run state/events, and `/v1/chat/completions` is available for OpenAI-compatible chat payloads. Validate the local Hermes API Server with `GET /health` and `GET /v1/capabilities`. Do not use UI/workspace endpoints such as `/api/session-send` or `/api/sessions/send`; those are not the stable Hermes runtime delivery interface.
512
543
 
513
- Hermes does not load OpenClaw plugins, so run the standalone bridge next to Hermes with API Server enabled:
544
+ Hermes does not load OpenClaw plugins, so a Hermes agent always runs the standalone
545
+ bridge. Note this is not the only reason to run it: an **OpenClaw** agent that has to
546
+ work a PerkOS board needs the standalone bridge too (point `HERMES_API_URL` at the
547
+ OpenClaw gateway and set `A2A_RUNTIME=openclaw`). Run it with API Server enabled:
514
548
 
515
549
  ```bash
516
550
  A2A_AGENT_NAME=hermes-agent \
@@ -672,6 +706,60 @@ When the plugin is active, three tools are available to the agent:
672
706
  | `perkos_a2a_send` | Send a task to a named peer (direct HTTP → relay fallback) |
673
707
  | `perkos_a2a_status` | Check the status of a previously sent task by ID |
674
708
 
709
+ These three are the plugin's **entire** tool surface. Job-board tools are not
710
+ here: they are served over MCP by the standalone bridge, below.
711
+
712
+ ## PerkOS board tools (job board over MCP)
713
+
714
+ To let an agent actually work a PerkOS job board (claim a task, move it to
715
+ Done, post to the project chat), the **standalone bridge** hosts a local MCP
716
+ server exposing the board tools natively. The model calls them like any other
717
+ tool: no shell, no `execute_code`, no approval gate. It works for **both**
718
+ runtimes, Hermes and OpenClaw.
719
+
720
+ The bridge mints a wallet-scoped, short-lived JWT per call using
721
+ `A2A_TOOLS_JWT_SECRET`, which never leaves the bridge process. The model never
722
+ supplies a wallet, only board arguments such as `projectId`.
723
+
724
+ Tools exposed: `createTask`, `updateTaskStatus`, `listProjectTasks`,
725
+ `postProjectMessage`, `listDocs`, `createDoc`, `readDoc`, `upsertPlanGroup`,
726
+ `upsertPlanTask`, `proposePlan`, `postDocMessage`.
727
+
728
+ ### Enabling it
729
+
730
+ All three of these must be set on the **bridge** process, or the board MCP
731
+ server silently does not start:
732
+
733
+ | Variable | Required | Notes |
734
+ |---|---|---|
735
+ | `A2A_TOOLS_JWT_SECRET` | yes | Must be **>=32 characters**, or the listener is disabled. Must equal the Tools API's `JWT_SHARED_SECRET`. |
736
+ | `A2A_TOOLS_API_URL` | yes | e.g. `https://api.perkos.xyz/tools` |
737
+ | `PERKOS_OWNER_WALLET` | yes | The board owner's wallet. **Without it the board MCP server is disabled** and the agent has no way to move a task. |
738
+ | `A2A_BOARD_MCP_PORT` | no | Defaults to `5071`. |
739
+ | `A2A_TOOLS_TOKEN_TTL_SECONDS` | no | Defaults to `60`. |
740
+
741
+ Startup is logged. If you see this line, the agent can receive board tasks but
742
+ can never complete them:
743
+
744
+ ```
745
+ [board-mcp] PERKOS_OWNER_WALLET unset — board MCP server disabled (set it to enable native job-board tools)
746
+ ```
747
+
748
+ Then point the runtime's MCP client at `http://127.0.0.1:5071` (transport:
749
+ MCP streamable-http). The server binds loopback only.
750
+
751
+ ### Symptom checklist
752
+
753
+ An agent that is assigned board tasks but never moves them usually has one of:
754
+
755
+ 1. It is running the **in-runtime plugin** instead of the standalone bridge, so
756
+ the board scope never reaches it and the reply is synthesized. Check for a
757
+ separate `perkos-a2a-agent` / `bridge-agent.js` process; if there is none,
758
+ this is your problem.
759
+ 2. `PERKOS_OWNER_WALLET` is unset, so the board tools were never served.
760
+ 3. `A2A_TOOLS_JWT_SECRET` is shorter than 32 characters, or does not match the
761
+ Tools API secret.
762
+
675
763
  ## CLI Commands
676
764
 
677
765
  ```bash
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAkBH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,EAGV,WAAW,EAEZ,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,cAAc,YAAY,CAAC;AA0C3B,kEAAkE;AAClE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAItF;AAED,KAAK,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAoFpD;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,OAAO,EACd,oBAAoB,EAAE,MAAM,GAC3B,OAAO,CA2BT;AAED;;;;GAIG;AACH,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,OAAO,EACd,QAAQ,CAAC,EAAE,MAAM,EACjB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAsCT;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,oBAAoB,EAC3B,eAAe,CAAC,EAAE,MAAM,GACvB,oBAAoB,CA+BtB;AAED,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,eAAe,EACvB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;CAAE,GAClF,OAAO,CAAC,IAAI,CAAC,CAsBf;AA+BD,KAAK,qBAAqB,GAAG;IAC3B,QAAQ,CAAC,EAAE,KAAK,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,YAAY,CAAC,EAAE,OAAO,CAAC;KACxB,CAAC,CAAC;IACH,IAAI,CAAC,EAAE;QACL,yBAAyB,CAAC,EAAE,MAAM,CAAC;QACnC,qBAAqB,CAAC,EAAE,MAAM,CAAC;KAChC,CAAC;CACH,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,GAAG,IAAI,CAYrF;AAED,6EAA6E;AAC7E,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,MAAM,CAGR;AAQD,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,iBAAiB,GAAG,eAAe,GAAG,iBAAiB,CAAC;CACjE,CAAC;AAkBF;;;;;;GAMG;AACH,wBAAgB,gCAAgC,CAC9C,aAAa,EAAE,OAAO,EACtB,OAAO,EAAE,MAAM,EACf,sBAAsB,CAAC,EAAE,MAAM,GAC9B,yBAAyB,GAAG,IAAI,CAqBlC;AAED,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,eAAe,EACvB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,MAAM,EACxB,MAAM,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;CAAE,GAClF,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAgHxB;AAkBD,oFAAoF;AACpF,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,WAAW,EAAE,EACvB,gBAAgB,EAAE,MAAM,GACvB,MAAM,CAWR;AA4CD,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAe/D;AAMD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAc7E;AAED,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,GAAG,QAu0BxC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -27782,6 +27782,22 @@ import { readFileSync as readFileSync5 } from "node:fs";
27782
27782
  import { dirname as dirname3, resolve as resolve3 } from "node:path";
27783
27783
  import { fileURLToPath as fileURLToPath2 } from "node:url";
27784
27784
 
27785
+ // src/task-context.ts
27786
+ function perkosTaskContext(task, trustedDispatcher = process.env.PERKOS_DISPATCHER_AGENT_NAME || "perkos-ci-probe-dispatcher") {
27787
+ const metadata = task.metadata;
27788
+ if (metadata?.fromAgent !== trustedDispatcher) return void 0;
27789
+ const raw = metadata.perkosBoard;
27790
+ if (!raw || typeof raw !== "object") return void 0;
27791
+ const value = raw;
27792
+ if (typeof value.wallet !== "string" || typeof value.convId !== "string") {
27793
+ return void 0;
27794
+ }
27795
+ const wallet = value.wallet.trim().toLowerCase();
27796
+ const convId = value.convId.trim();
27797
+ if (!/^0x[0-9a-f]{40}$/.test(wallet) || !convId) return void 0;
27798
+ return { wallet, convId };
27799
+ }
27800
+
27785
27801
  // src/agentic-actions.ts
27786
27802
  var FALLBACK_AGENT_ALIASES = [
27787
27803
  ["Perkos-Claw-Tester", ["perkos-claw-tester", "openclaw", "open claw", "claw"]],
@@ -29654,6 +29670,7 @@ function isWebhookEvent(msg) {
29654
29670
  }
29655
29671
 
29656
29672
  // src/index.ts
29673
+ var warnedBoardTaskUnsupported = false;
29657
29674
  function loadedPluginVersion() {
29658
29675
  try {
29659
29676
  const manifest = JSON.parse(readFileSync5(new URL("../openclaw.plugin.json", import.meta.url), "utf8"));
@@ -30158,6 +30175,12 @@ function register(api) {
30158
30175
  });
30159
30176
  return;
30160
30177
  }
30178
+ if (!warnedBoardTaskUnsupported && perkosTaskContext(task)) {
30179
+ warnedBoardTaskUnsupported = true;
30180
+ logger.error(
30181
+ '[perkos-a2a] This is a PerkOS BOARD task, and the in-runtime plugin cannot work a board. It will be answered with a synthesized reply and the task will never move. Run the standalone bridge (perkos-a2a-agent) for this agent instead, with A2A_TOOLS_JWT_SECRET, A2A_TOOLS_API_URL and PERKOS_OWNER_WALLET set, then disable this plugin so both do not answer the same task. See the README section "Which one do you need: plugin or standalone bridge?".'
30182
+ );
30183
+ }
30161
30184
  task.artifacts.push({
30162
30185
  kind: "artifact",
30163
30186
  artifactId: randomUUID7(),