@acnlabs/acn-cli 0.14.2 → 1.0.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.
Files changed (2) hide show
  1. package/dist/index.js +54 -15
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -31,7 +31,7 @@ var require_package = __commonJS({
31
31
  "package.json"(exports2, module2) {
32
32
  module2.exports = {
33
33
  name: "@acnlabs/acn-cli",
34
- version: "0.14.2",
34
+ version: "1.0.0",
35
35
  description: "Official CLI for ACN (Agent Collaboration Network) \u2014 zero-integration agent access",
36
36
  main: "dist/index.js",
37
37
  bin: {
@@ -1560,7 +1560,7 @@ function validateChatWritebackOptions(opts) {
1560
1560
  const hasUrl = Boolean(opts.chatCompleteUrl?.trim());
1561
1561
  const hasExec = Boolean(opts.chatCompleteExec?.trim());
1562
1562
  if (hasUrl === hasExec) {
1563
- return '--chat-writeback requires exactly one of --chat-complete-url or --chat-complete-exec (host returns JSON {"content":"..."}).';
1563
+ return '--chat-writeback requires exactly one of --chat-complete-url or --chat-complete-exec (host returns JSON {"content":"..."} and optional usage).';
1564
1564
  }
1565
1565
  return null;
1566
1566
  }
@@ -1594,6 +1594,39 @@ function extractContent(payload) {
1594
1594
  }
1595
1595
  return null;
1596
1596
  }
1597
+ function asNonNegInt(v) {
1598
+ if (typeof v === "number" && Number.isFinite(v) && v >= 0) {
1599
+ return Math.floor(v);
1600
+ }
1601
+ if (typeof v === "string" && v.trim() !== "") {
1602
+ const n = Number(v);
1603
+ if (Number.isFinite(n) && n >= 0) return Math.floor(n);
1604
+ }
1605
+ return null;
1606
+ }
1607
+ function extractUsage(payload) {
1608
+ const rec = asRecord2(payload);
1609
+ if (!rec) return void 0;
1610
+ const usageRec = asRecord2(rec.usage) ?? rec;
1611
+ const input = asNonNegInt(usageRec.input_tokens) ?? asNonNegInt(usageRec.prompt_tokens);
1612
+ const output2 = asNonNegInt(usageRec.output_tokens) ?? asNonNegInt(usageRec.completion_tokens);
1613
+ if (input === null && output2 === null) return void 0;
1614
+ const out = {
1615
+ input_tokens: input ?? 0,
1616
+ output_tokens: output2 ?? 0
1617
+ };
1618
+ const ms = usageRec.meter_source;
1619
+ if (ms === "peer_self" || ms === "gateway" || ms === "runtime_attested" || ms === "protocol") {
1620
+ out.meter_source = ms;
1621
+ }
1622
+ return out;
1623
+ }
1624
+ function parseCompletePayload(payload) {
1625
+ const content = extractContent(payload);
1626
+ if (!content) return { ok: false, reason: "complete_missing_content" };
1627
+ const usage = extractUsage(payload);
1628
+ return { ok: true, result: usage ? { content, usage } : { content } };
1629
+ }
1597
1630
  async function mintAgentJwt(opts, fetchFn = fetch) {
1598
1631
  const now = Math.floor(Date.now() / 1e3);
1599
1632
  if (cachedJwt && cachedJwt.agentId === opts.agentId && cachedJwt.expEpochSec > now + 60) {
@@ -1661,9 +1694,7 @@ async function completeViaHttp(event, opts, deps) {
1661
1694
  } catch {
1662
1695
  return { ok: false, reason: "complete_invalid_json" };
1663
1696
  }
1664
- const content = extractContent(parsed);
1665
- if (!content) return { ok: false, reason: "complete_missing_content" };
1666
- return { ok: true, content };
1697
+ return parseCompletePayload(parsed);
1667
1698
  } catch (err) {
1668
1699
  const msg = err instanceof Error ? err.message : String(err);
1669
1700
  if (controller.signal.aborted || /abort|timeout/i.test(msg)) {
@@ -1711,12 +1742,7 @@ function completeViaExec(event, opts, deps) {
1711
1742
  const text = Buffer.concat(stdout).toString("utf-8").trim();
1712
1743
  try {
1713
1744
  const parsed = JSON.parse(text);
1714
- const content = extractContent(parsed);
1715
- if (!content) {
1716
- finish({ ok: false, reason: "complete_missing_content" });
1717
- return;
1718
- }
1719
- finish({ ok: true, content });
1745
+ finish(parseCompletePayload(parsed));
1720
1746
  } catch {
1721
1747
  finish({ ok: false, reason: "complete_invalid_json" });
1722
1748
  }
@@ -1724,7 +1750,7 @@ function completeViaExec(event, opts, deps) {
1724
1750
  child.stdin?.end(body);
1725
1751
  });
1726
1752
  }
1727
- async function postWriteback(event, content, opts, deps) {
1753
+ async function postWriteback(event, complete, opts, deps) {
1728
1754
  const chat = event.chat;
1729
1755
  if (!chat) return { ok: false, reason: "no_chat_envelope" };
1730
1756
  if (!isAllowedChatReplyPath(chat.chat_id, chat.reply_path)) {
@@ -1747,6 +1773,18 @@ async function postWriteback(event, content, opts, deps) {
1747
1773
  return { ok: false, reason: "reply_url_origin_mismatch" };
1748
1774
  }
1749
1775
  const timeoutMs = opts.writebackTimeoutMs ?? DEFAULT_WRITEBACK_TIMEOUT_MS;
1776
+ const replyToId = chat.gateway_message_id ?? event.message_id;
1777
+ const body = {
1778
+ content: complete.content,
1779
+ reply_to_id: replyToId
1780
+ };
1781
+ if (complete.usage) {
1782
+ body.usage = {
1783
+ input_tokens: complete.usage.input_tokens,
1784
+ output_tokens: complete.usage.output_tokens,
1785
+ meter_source: complete.usage.meter_source ?? "peer_self"
1786
+ };
1787
+ }
1750
1788
  const postOnce = async (token) => {
1751
1789
  const controller = new AbortController();
1752
1790
  const timer = setTimeout(() => controller.abort(), timeoutMs);
@@ -1757,7 +1795,7 @@ async function postWriteback(event, content, opts, deps) {
1757
1795
  "content-type": "application/json",
1758
1796
  Authorization: `Bearer ${token}`
1759
1797
  },
1760
- body: JSON.stringify({ content }),
1798
+ body: JSON.stringify(body),
1761
1799
  signal: controller.signal
1762
1800
  });
1763
1801
  if (res.status === 200 || res.status === 201) {
@@ -1813,15 +1851,16 @@ async function handleChatWriteback(event, opts, deps = {}) {
1813
1851
  );
1814
1852
  return { ok: false, reason: completed.reason };
1815
1853
  }
1816
- const written = await postWriteback(event, completed.content, opts, deps);
1854
+ const written = await postWriteback(event, completed.result, opts, deps);
1817
1855
  if (!written.ok) {
1818
1856
  logFn(
1819
1857
  `[acn listen] chat_writeback_failed chat_id=${event.chat.chat_id} message_id=${event.message_id} reason=${written.reason}`
1820
1858
  );
1821
1859
  return written;
1822
1860
  }
1861
+ const usageNote = completed.result.usage ? ` usage_in=${completed.result.usage.input_tokens} usage_out=${completed.result.usage.output_tokens}` : "";
1823
1862
  logFn(
1824
- `[acn listen] chat_writeback_ok chat_id=${event.chat.chat_id} message_id=${event.message_id} http=${written.httpStatus}`
1863
+ `[acn listen] chat_writeback_ok chat_id=${event.chat.chat_id} message_id=${event.message_id} http=${written.httpStatus}${usageNote}`
1825
1864
  );
1826
1865
  return written;
1827
1866
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acnlabs/acn-cli",
3
- "version": "0.14.2",
3
+ "version": "1.0.0",
4
4
  "description": "Official CLI for ACN (Agent Collaboration Network) — zero-integration agent access",
5
5
  "main": "dist/index.js",
6
6
  "bin": {