@senpi/runtime 3.0.9-dev.feat-strategy-compos.20260722011437 → 3.0.9-dev.feat-strategy-compos.20260722213012

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.
@@ -427,6 +427,22 @@ def _pos_num(v) -> Optional[float]:
427
427
  return None
428
428
 
429
429
 
430
+ def unwrap_positions_envelope(doc: Any) -> Any:
431
+ """Descend into a ``{success, data}`` MCP envelope BEFORE shape-parsing. The gateway wraps
432
+ ``strategy_get_clearinghouse_state`` as ``{success: true, data: {main, xyz}, meta: {...}}`` and
433
+ ``default_mcp_call`` returns that whole document, so the per-DEX buckets live one level down under
434
+ ``.data``. This mirrors the TS call path (client.ts::fetchClearingHouseStateOnce unwraps via
435
+ ``unwrapEnvelope`` at client.ts:791 BEFORE clearingHouseStateLooksParsable /
436
+ openPositionsFromClearingHouseState run) — those TS helpers never had the bug because their caller
437
+ unwraps first. Non-envelope shapes (an already-unwrapped flat list or top-level ``{main, xyz}``)
438
+ have no boolean ``success`` key and are returned unchanged, so existing shapes keep parsing."""
439
+ if not isinstance(doc, dict):
440
+ return doc
441
+ if not isinstance(doc.get("success"), bool) or "data" not in doc:
442
+ return doc
443
+ return doc.get("data")
444
+
445
+
430
446
  def clearinghouse_looks_parsable(state: dict) -> bool:
431
447
  """True if ``state`` is a recognizable strategy_get_clearinghouse_state response — either a
432
448
  flat ``positions``/``positionsList`` list, or per-DEX buckets carrying ``assetPositions`` /
@@ -506,6 +522,7 @@ def default_read_positions(wallet: str, mcp_fn: McpFn = default_mcp_call) -> Pos
506
522
  return PositionsResult(False, [], reason=f"MCP error reading positions ({e})")
507
523
  except Exception as e: # noqa: BLE001 — a surprise transport fault must not crash the verb
508
524
  return PositionsResult(False, [], reason=f"could not read positions ({e})")
509
- if not isinstance(raw, dict) or not clearinghouse_looks_parsable(raw):
525
+ state = unwrap_positions_envelope(raw)
526
+ if not isinstance(state, dict) or not clearinghouse_looks_parsable(state):
510
527
  return PositionsResult(False, [], reason="clearinghouse response shape not recognized")
511
- return PositionsResult(True, parse_open_positions(raw))
528
+ return PositionsResult(True, parse_open_positions(state))
@@ -14,6 +14,11 @@
14
14
  "senpi"
15
15
  ]
16
16
  },
17
+ "contracts": {
18
+ "tools": [
19
+ "senpi_strategy"
20
+ ]
21
+ },
17
22
  "configSchema": {
18
23
  "type": "object",
19
24
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@senpi/runtime",
3
- "version": "3.0.9-dev.feat-strategy-compos.20260722011437",
3
+ "version": "3.0.9-dev.feat-strategy-compos.20260722213012",
4
4
  "description": "Senpi runtime plugin for OpenClaw",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",