@radaros/transport 0.3.32 → 0.3.33

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.cjs CHANGED
@@ -1606,6 +1606,99 @@ function createAgentRouter(opts) {
1606
1606
  router.get("/registry", (_req, res) => {
1607
1607
  res.json(reg.list());
1608
1608
  });
1609
+ router.get("/agents/:name/card", (req, res) => {
1610
+ const r = reg;
1611
+ if (typeof r.getAgentCard !== "function") return res.status(501).json({ error: "Discovery cards not available" });
1612
+ const card = r.getAgentCard(req.params.name);
1613
+ if (!card) return res.status(404).json({ error: `Agent "${req.params.name}" not found` });
1614
+ res.json(card);
1615
+ });
1616
+ router.get("/.well-known/agent-cards.json", (_req, res) => {
1617
+ const r = reg;
1618
+ if (typeof r.getAllAgentCards !== "function") return res.json([]);
1619
+ res.json(r.getAllAgentCards());
1620
+ });
1621
+ router.get("/approvals/pending", (_req, res) => {
1622
+ const pending = [];
1623
+ for (const agent of reg.agents.values()) {
1624
+ const mgr = agent.approvalManager;
1625
+ if (mgr && typeof mgr.listPending === "function") {
1626
+ pending.push(...mgr.listPending());
1627
+ }
1628
+ }
1629
+ res.json(pending);
1630
+ });
1631
+ router.post("/approvals/:requestId/approve", (req, res) => {
1632
+ const { requestId } = req.params;
1633
+ const { reason } = req.body ?? {};
1634
+ for (const agent of reg.agents.values()) {
1635
+ const mgr = agent.approvalManager;
1636
+ if (mgr && typeof mgr.approve === "function") {
1637
+ mgr.approve(requestId, reason);
1638
+ }
1639
+ }
1640
+ res.json({ status: "approved", requestId });
1641
+ });
1642
+ router.post("/approvals/:requestId/deny", (req, res) => {
1643
+ const { requestId } = req.params;
1644
+ const { reason } = req.body ?? {};
1645
+ for (const agent of reg.agents.values()) {
1646
+ const mgr = agent.approvalManager;
1647
+ if (mgr && typeof mgr.deny === "function") {
1648
+ mgr.deny(requestId, reason);
1649
+ }
1650
+ }
1651
+ res.json({ status: "denied", requestId });
1652
+ });
1653
+ router.get("/agents/:name/checkpoints", async (req, res) => {
1654
+ const agent = reg.getAgent(req.params.name);
1655
+ if (!agent) return res.status(404).json({ error: `Agent "${req.params.name}" not found` });
1656
+ const config = agent.config;
1657
+ const checkpointMgr = config?._checkpointManager;
1658
+ if (!checkpointMgr) return res.json([]);
1659
+ const runId = req.query.runId;
1660
+ if (!runId) return res.status(400).json({ error: "runId query param required" });
1661
+ try {
1662
+ const checkpoints = await checkpointMgr.list(runId);
1663
+ res.json(checkpoints);
1664
+ } catch (err) {
1665
+ res.status(500).json({ error: err.message });
1666
+ }
1667
+ });
1668
+ router.post("/agents/:name/rollback/:checkpointId", async (req, res) => {
1669
+ const agent = reg.getAgent(req.params.name);
1670
+ if (!agent) return res.status(404).json({ error: `Agent "${req.params.name}" not found` });
1671
+ const config = agent.config;
1672
+ const checkpointMgr = config?._checkpointManager;
1673
+ if (!checkpointMgr) return res.status(400).json({ error: "Checkpointing not enabled for this agent" });
1674
+ try {
1675
+ const checkpoint = await checkpointMgr.rollback(req.params.checkpointId);
1676
+ if (!checkpoint) return res.status(404).json({ error: "Checkpoint not found" });
1677
+ res.json(checkpoint);
1678
+ } catch (err) {
1679
+ res.status(500).json({ error: err.message });
1680
+ }
1681
+ });
1682
+ router.get("/approvals/stream", (req, res) => {
1683
+ res.writeHead(200, {
1684
+ "Content-Type": "text/event-stream",
1685
+ "Cache-Control": "no-cache",
1686
+ Connection: "keep-alive"
1687
+ });
1688
+ const listener = (data) => {
1689
+ res.write(`data: ${JSON.stringify(data)}
1690
+
1691
+ `);
1692
+ };
1693
+ for (const agent of reg.agents.values()) {
1694
+ agent.eventBus.on("tool.approval.request", listener);
1695
+ }
1696
+ req.on("close", () => {
1697
+ for (const agent of reg.agents.values()) {
1698
+ agent.eventBus.off("tool.approval.request", listener);
1699
+ }
1700
+ });
1701
+ });
1609
1702
  }
1610
1703
  if (opts.scheduler) {
1611
1704
  const queue = opts.scheduler;
@@ -1636,6 +1729,38 @@ function createAgentRouter(opts) {
1636
1729
  }
1637
1730
  });
1638
1731
  }
1732
+ if (opts.metricsExporter) {
1733
+ const exporter = opts.metricsExporter;
1734
+ router.get("/metrics", (_req, res) => {
1735
+ res.set("Content-Type", "text/plain; version=0.0.4; charset=utf-8");
1736
+ res.send(exporter.toPrometheus());
1737
+ });
1738
+ router.get("/metrics/json", (req, res) => {
1739
+ const agent = req.query.agent;
1740
+ if (agent) {
1741
+ res.json(exporter.getMetrics(agent));
1742
+ } else {
1743
+ res.json(exporter.toJSON());
1744
+ }
1745
+ });
1746
+ router.get("/metrics/stream", (req, res) => {
1747
+ res.writeHead(200, {
1748
+ "Content-Type": "text/event-stream",
1749
+ "Cache-Control": "no-cache",
1750
+ Connection: "keep-alive"
1751
+ });
1752
+ const handler = (event) => {
1753
+ res.write(`data: ${JSON.stringify(event)}
1754
+
1755
+ `);
1756
+ };
1757
+ const subscribers = exporter.subscribers;
1758
+ subscribers.add(handler);
1759
+ req.on("close", () => {
1760
+ subscribers.delete(handler);
1761
+ });
1762
+ });
1763
+ }
1639
1764
  if (opts.admin) {
1640
1765
  const adminOpts = typeof opts.admin === "object" ? opts.admin : {};
1641
1766
  const { router: adminRouter } = createAdminRouter({
package/dist/index.d.cts CHANGED
@@ -206,6 +206,10 @@ interface RouterOptions {
206
206
  * Pass an AgentQueue instance from `@radaros/queue`.
207
207
  */
208
208
  scheduler?: any;
209
+ /**
210
+ * MetricsExporter instance from `@radaros/observability` for `/metrics` endpoints.
211
+ */
212
+ metricsExporter?: any;
209
213
  }
210
214
 
211
215
  declare function createAgentRouter(opts: RouterOptions): any;
package/dist/index.d.ts CHANGED
@@ -206,6 +206,10 @@ interface RouterOptions {
206
206
  * Pass an AgentQueue instance from `@radaros/queue`.
207
207
  */
208
208
  scheduler?: any;
209
+ /**
210
+ * MetricsExporter instance from `@radaros/observability` for `/metrics` endpoints.
211
+ */
212
+ metricsExporter?: any;
209
213
  }
210
214
 
211
215
  declare function createAgentRouter(opts: RouterOptions): any;
package/dist/index.js CHANGED
@@ -1563,6 +1563,99 @@ function createAgentRouter(opts) {
1563
1563
  router.get("/registry", (_req, res) => {
1564
1564
  res.json(reg.list());
1565
1565
  });
1566
+ router.get("/agents/:name/card", (req, res) => {
1567
+ const r = reg;
1568
+ if (typeof r.getAgentCard !== "function") return res.status(501).json({ error: "Discovery cards not available" });
1569
+ const card = r.getAgentCard(req.params.name);
1570
+ if (!card) return res.status(404).json({ error: `Agent "${req.params.name}" not found` });
1571
+ res.json(card);
1572
+ });
1573
+ router.get("/.well-known/agent-cards.json", (_req, res) => {
1574
+ const r = reg;
1575
+ if (typeof r.getAllAgentCards !== "function") return res.json([]);
1576
+ res.json(r.getAllAgentCards());
1577
+ });
1578
+ router.get("/approvals/pending", (_req, res) => {
1579
+ const pending = [];
1580
+ for (const agent of reg.agents.values()) {
1581
+ const mgr = agent.approvalManager;
1582
+ if (mgr && typeof mgr.listPending === "function") {
1583
+ pending.push(...mgr.listPending());
1584
+ }
1585
+ }
1586
+ res.json(pending);
1587
+ });
1588
+ router.post("/approvals/:requestId/approve", (req, res) => {
1589
+ const { requestId } = req.params;
1590
+ const { reason } = req.body ?? {};
1591
+ for (const agent of reg.agents.values()) {
1592
+ const mgr = agent.approvalManager;
1593
+ if (mgr && typeof mgr.approve === "function") {
1594
+ mgr.approve(requestId, reason);
1595
+ }
1596
+ }
1597
+ res.json({ status: "approved", requestId });
1598
+ });
1599
+ router.post("/approvals/:requestId/deny", (req, res) => {
1600
+ const { requestId } = req.params;
1601
+ const { reason } = req.body ?? {};
1602
+ for (const agent of reg.agents.values()) {
1603
+ const mgr = agent.approvalManager;
1604
+ if (mgr && typeof mgr.deny === "function") {
1605
+ mgr.deny(requestId, reason);
1606
+ }
1607
+ }
1608
+ res.json({ status: "denied", requestId });
1609
+ });
1610
+ router.get("/agents/:name/checkpoints", async (req, res) => {
1611
+ const agent = reg.getAgent(req.params.name);
1612
+ if (!agent) return res.status(404).json({ error: `Agent "${req.params.name}" not found` });
1613
+ const config = agent.config;
1614
+ const checkpointMgr = config?._checkpointManager;
1615
+ if (!checkpointMgr) return res.json([]);
1616
+ const runId = req.query.runId;
1617
+ if (!runId) return res.status(400).json({ error: "runId query param required" });
1618
+ try {
1619
+ const checkpoints = await checkpointMgr.list(runId);
1620
+ res.json(checkpoints);
1621
+ } catch (err) {
1622
+ res.status(500).json({ error: err.message });
1623
+ }
1624
+ });
1625
+ router.post("/agents/:name/rollback/:checkpointId", async (req, res) => {
1626
+ const agent = reg.getAgent(req.params.name);
1627
+ if (!agent) return res.status(404).json({ error: `Agent "${req.params.name}" not found` });
1628
+ const config = agent.config;
1629
+ const checkpointMgr = config?._checkpointManager;
1630
+ if (!checkpointMgr) return res.status(400).json({ error: "Checkpointing not enabled for this agent" });
1631
+ try {
1632
+ const checkpoint = await checkpointMgr.rollback(req.params.checkpointId);
1633
+ if (!checkpoint) return res.status(404).json({ error: "Checkpoint not found" });
1634
+ res.json(checkpoint);
1635
+ } catch (err) {
1636
+ res.status(500).json({ error: err.message });
1637
+ }
1638
+ });
1639
+ router.get("/approvals/stream", (req, res) => {
1640
+ res.writeHead(200, {
1641
+ "Content-Type": "text/event-stream",
1642
+ "Cache-Control": "no-cache",
1643
+ Connection: "keep-alive"
1644
+ });
1645
+ const listener = (data) => {
1646
+ res.write(`data: ${JSON.stringify(data)}
1647
+
1648
+ `);
1649
+ };
1650
+ for (const agent of reg.agents.values()) {
1651
+ agent.eventBus.on("tool.approval.request", listener);
1652
+ }
1653
+ req.on("close", () => {
1654
+ for (const agent of reg.agents.values()) {
1655
+ agent.eventBus.off("tool.approval.request", listener);
1656
+ }
1657
+ });
1658
+ });
1566
1659
  }
1567
1660
  if (opts.scheduler) {
1568
1661
  const queue = opts.scheduler;
@@ -1593,6 +1686,38 @@ function createAgentRouter(opts) {
1593
1686
  }
1594
1687
  });
1595
1688
  }
1689
+ if (opts.metricsExporter) {
1690
+ const exporter = opts.metricsExporter;
1691
+ router.get("/metrics", (_req, res) => {
1692
+ res.set("Content-Type", "text/plain; version=0.0.4; charset=utf-8");
1693
+ res.send(exporter.toPrometheus());
1694
+ });
1695
+ router.get("/metrics/json", (req, res) => {
1696
+ const agent = req.query.agent;
1697
+ if (agent) {
1698
+ res.json(exporter.getMetrics(agent));
1699
+ } else {
1700
+ res.json(exporter.toJSON());
1701
+ }
1702
+ });
1703
+ router.get("/metrics/stream", (req, res) => {
1704
+ res.writeHead(200, {
1705
+ "Content-Type": "text/event-stream",
1706
+ "Cache-Control": "no-cache",
1707
+ Connection: "keep-alive"
1708
+ });
1709
+ const handler = (event) => {
1710
+ res.write(`data: ${JSON.stringify(event)}
1711
+
1712
+ `);
1713
+ };
1714
+ const subscribers = exporter.subscribers;
1715
+ subscribers.add(handler);
1716
+ req.on("close", () => {
1717
+ subscribers.delete(handler);
1718
+ });
1719
+ });
1720
+ }
1596
1721
  if (opts.admin) {
1597
1722
  const adminOpts = typeof opts.admin === "object" ? opts.admin : {};
1598
1723
  const { router: adminRouter } = createAdminRouter({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@radaros/transport",
3
- "version": "0.3.32",
3
+ "version": "0.3.33",
4
4
  "description": "HTTP and WebSocket transport layer for RadarOS agents",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -42,7 +42,7 @@
42
42
  "typescript": "^5.6.0"
43
43
  },
44
44
  "peerDependencies": {
45
- "@radaros/core": "^0.3.32",
45
+ "@radaros/core": "^0.3.33",
46
46
  "@types/express": "^4.0.0 || ^5.0.0",
47
47
  "express": "^4.0.0 || ^5.0.0",
48
48
  "multer": ">=2.0.0",