@acnlabs/acn-cli 1.0.9 → 1.0.11

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 +96 -42
  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: "1.0.9",
34
+ version: "1.0.11",
35
35
  description: "Official CLI for ACN (Agent Collaboration Network) \u2014 zero-integration agent access",
36
36
  main: "dist/index.js",
37
37
  bin: {
@@ -1764,6 +1764,8 @@ function canCompleteOfficialHop(opts) {
1764
1764
 
1765
1765
  // src/commands/chat-writeback.ts
1766
1766
  var DEFAULT_COMPLETE_TIMEOUT_MS = 12e4;
1767
+ var DEFAULT_OFFICIAL_COMPLETE_TIMEOUT_MS = 28e3;
1768
+ var JWT_MINT_ATTEMPTS = 3;
1767
1769
  var DEFAULT_WRITEBACK_TIMEOUT_MS = 3e4;
1768
1770
  var DEFAULT_CHAT_JWT_AUDIENCE = "https://api.agentplanet.org";
1769
1771
  var cachedJwt = null;
@@ -1911,41 +1913,50 @@ async function mintAgentJwt(opts, fetchFn = fetch) {
1911
1913
  return { ok: true, token: cachedJwt.token };
1912
1914
  }
1913
1915
  const url = `${opts.acnBaseUrl.replace(/\/+$/, "")}/oauth/token`;
1914
- try {
1915
- const res = await fetchFn(url, {
1916
- method: "POST",
1917
- headers: { "content-type": "application/json" },
1918
- body: JSON.stringify({
1919
- grant_type: "client_credentials",
1920
- client_id: opts.agentId,
1921
- client_secret: opts.apiKey,
1922
- audience: opts.audience
1923
- })
1924
- });
1925
- const text = await res.text();
1926
- if (res.status < 200 || res.status >= 300) {
1927
- return { ok: false, reason: `oauth_http_${res.status}` };
1928
- }
1929
- let parsed;
1916
+ let lastReason = "oauth_failed";
1917
+ for (let attempt = 1; attempt <= JWT_MINT_ATTEMPTS; attempt++) {
1930
1918
  try {
1931
- parsed = JSON.parse(text);
1932
- } catch {
1933
- return { ok: false, reason: "oauth_invalid_json" };
1934
- }
1935
- const rec = asRecord2(parsed);
1936
- const token = typeof rec?.access_token === "string" ? rec.access_token.trim() : "";
1937
- if (!token) return { ok: false, reason: "oauth_missing_access_token" };
1938
- const expiresIn = typeof rec?.expires_in === "number" && rec.expires_in > 0 ? rec.expires_in : 1800;
1939
- cachedJwt = {
1940
- token,
1941
- agentId: opts.agentId,
1942
- expEpochSec: now + expiresIn
1943
- };
1944
- return { ok: true, token };
1945
- } catch (err) {
1946
- const msg = err instanceof Error ? err.message : String(err);
1947
- return { ok: false, reason: msg.slice(0, 200) };
1919
+ const res = await fetchFn(url, {
1920
+ method: "POST",
1921
+ headers: { "content-type": "application/json" },
1922
+ body: JSON.stringify({
1923
+ grant_type: "client_credentials",
1924
+ client_id: opts.agentId,
1925
+ client_secret: opts.apiKey,
1926
+ audience: opts.audience
1927
+ })
1928
+ });
1929
+ const text = await res.text();
1930
+ if (res.status < 200 || res.status >= 300) {
1931
+ lastReason = `oauth_http_${res.status}`;
1932
+ } else {
1933
+ let parsed;
1934
+ try {
1935
+ parsed = JSON.parse(text);
1936
+ } catch {
1937
+ lastReason = "oauth_invalid_json";
1938
+ continue;
1939
+ }
1940
+ const rec = asRecord2(parsed);
1941
+ const token = typeof rec?.access_token === "string" ? rec.access_token.trim() : "";
1942
+ if (!token) {
1943
+ lastReason = "oauth_missing_access_token";
1944
+ continue;
1945
+ }
1946
+ const expiresIn = typeof rec?.expires_in === "number" && rec.expires_in > 0 ? rec.expires_in : 1800;
1947
+ cachedJwt = {
1948
+ token,
1949
+ agentId: opts.agentId,
1950
+ expEpochSec: now + expiresIn
1951
+ };
1952
+ return { ok: true, token };
1953
+ }
1954
+ } catch (err) {
1955
+ const msg = err instanceof Error ? err.message : String(err);
1956
+ lastReason = msg.slice(0, 200);
1957
+ }
1948
1958
  }
1959
+ return { ok: false, reason: lastReason };
1949
1960
  }
1950
1961
  function clearAgentJwtCache() {
1951
1962
  cachedJwt = null;
@@ -2059,6 +2070,23 @@ function spawnCompleteExec(event, opts, deps, jwt, door) {
2059
2070
  child.stdin?.end(body);
2060
2071
  });
2061
2072
  }
2073
+ var OFFICIAL_V0_O_SERIES = /(^|\/)o[134](?:$|[-/:])/;
2074
+ function officialV0SupportsModel(modelId) {
2075
+ const id = (modelId || "").trim().toLowerCase();
2076
+ if (!id) return true;
2077
+ if (id.includes("-think") || id.includes(":thinking") || id.includes("reasoning")) {
2078
+ return false;
2079
+ }
2080
+ if (id.includes("deepseek-r1")) return false;
2081
+ return !OFFICIAL_V0_O_SERIES.test(id);
2082
+ }
2083
+ function officialCompleteFailureContent(reason, model) {
2084
+ const mid = (model || "").trim();
2085
+ if (mid && !officialV0SupportsModel(mid)) {
2086
+ return `Official v0 is a single completion and cannot run thinking/reasoning models (${mid}). Switch to a chat model such as kimi-k2.5.`;
2087
+ }
2088
+ return `Official hop failed (${reason}). Try kimi or another chat model.`;
2089
+ }
2062
2090
  async function completeOfficialViaHost(event, opts, deps, jwt) {
2063
2091
  const chat = event.chat;
2064
2092
  if (!chat) return { ok: false, reason: "no_chat_envelope" };
@@ -2073,13 +2101,16 @@ async function completeOfficialViaHost(event, opts, deps, jwt) {
2073
2101
  const model = chat.requested_model?.trim();
2074
2102
  const text = chat.user_text?.trim();
2075
2103
  if (!model) return { ok: false, reason: "official_complete_missing_model" };
2104
+ if (!officialV0SupportsModel(model)) {
2105
+ return { ok: false, reason: "official_complete_unsupported_model" };
2106
+ }
2076
2107
  if (!text) return { ok: false, reason: "official_complete_missing_text" };
2077
2108
  const logFn = deps.logFn ?? ((line) => console.error(line));
2078
2109
  logFn(
2079
2110
  `[acn listen] official_complete chat_id=${chat.chat_id} model=${model}`
2080
2111
  );
2081
2112
  const fetchFn = deps.fetchFn ?? fetch;
2082
- const timeoutMs = opts.completeTimeoutMs ?? DEFAULT_COMPLETE_TIMEOUT_MS;
2113
+ const timeoutMs = opts.completeTimeoutMs ?? DEFAULT_OFFICIAL_COMPLETE_TIMEOUT_MS;
2083
2114
  const controller = new AbortController();
2084
2115
  const timer = setTimeout(() => controller.abort(), timeoutMs);
2085
2116
  try {
@@ -2250,6 +2281,18 @@ async function handleChatWriteback(event, opts, deps = {}) {
2250
2281
  logFn(
2251
2282
  `[acn listen] official_jwt_failed chat_id=${event.chat.chat_id} reason=${minted.reason}`
2252
2283
  );
2284
+ const written2 = await postWriteback(
2285
+ event,
2286
+ { content: officialCompleteFailureContent(minted.reason, event.chat.requested_model) },
2287
+ opts,
2288
+ deps
2289
+ );
2290
+ if (written2.ok) {
2291
+ logFn(
2292
+ `[acn listen] official_fail_writeback_ok chat_id=${event.chat.chat_id} message_id=${event.message_id} reason=${minted.reason}`
2293
+ );
2294
+ return written2;
2295
+ }
2253
2296
  return { ok: false, reason: minted.reason };
2254
2297
  }
2255
2298
  jwt = minted.token;
@@ -2268,6 +2311,20 @@ async function handleChatWriteback(event, opts, deps = {}) {
2268
2311
  logFn(
2269
2312
  `[acn listen] chat_complete_failed chat_id=${event.chat.chat_id} message_id=${event.message_id} reason=${completed.reason}`
2270
2313
  );
2314
+ if (event.chat.inference_path === "official") {
2315
+ const written2 = await postWriteback(
2316
+ event,
2317
+ { content: officialCompleteFailureContent(completed.reason, event.chat.requested_model) },
2318
+ opts,
2319
+ deps
2320
+ );
2321
+ if (written2.ok) {
2322
+ logFn(
2323
+ `[acn listen] official_fail_writeback_ok chat_id=${event.chat.chat_id} message_id=${event.message_id} reason=${completed.reason}`
2324
+ );
2325
+ return written2;
2326
+ }
2327
+ }
2271
2328
  return { ok: false, reason: completed.reason };
2272
2329
  }
2273
2330
  const written = await postWriteback(event, completed.result, opts, deps);
@@ -2840,8 +2897,7 @@ function listenCommand() {
2840
2897
  'BYO only (optional if official-only): stdin event \u2192 stdout {"content"}. Official hops complete via Host.'
2841
2898
  ).option(
2842
2899
  "--chat-complete-timeout <ms>",
2843
- `Host complete timeout in ms (default ${DEFAULT_COMPLETE_TIMEOUT_MS})`,
2844
- String(DEFAULT_COMPLETE_TIMEOUT_MS)
2900
+ `Complete timeout in ms (official default ${DEFAULT_OFFICIAL_COMPLETE_TIMEOUT_MS}; BYO default ${DEFAULT_COMPLETE_TIMEOUT_MS})`
2845
2901
  ).option("-i, --agent-id <id>", "Agent ID (defaults to config)").option(
2846
2902
  "-m, --model <modelId>",
2847
2903
  "Declare runtime model (Host Catalog id) on connect + every 15m via REST heartbeat (self-reported; env: ACN_PREFERRED_MODEL)"
@@ -2914,10 +2970,8 @@ function listenCommand() {
2914
2970
  }
2915
2971
  const wakeTimeoutMs = Number.parseInt(opts.wakeTimeout ?? "", 10);
2916
2972
  const dedupeTtlSec = Number.parseInt(opts.dedupeTtl ?? "", 10);
2917
- const chatCompleteTimeoutMs = Number.parseInt(
2918
- opts.chatCompleteTimeout ?? "",
2919
- 10
2920
- );
2973
+ const rawCompleteTimeout = opts.chatCompleteTimeout?.trim();
2974
+ const chatCompleteTimeoutMs = rawCompleteTimeout ? Number.parseInt(rawCompleteTimeout, 10) : void 0;
2921
2975
  if (opts.runtime && (!Number.isFinite(wakeTimeoutMs) || wakeTimeoutMs <= 0)) {
2922
2976
  console.error("--wake-timeout must be a positive integer (ms).");
2923
2977
  process.exit(1);
@@ -2926,7 +2980,7 @@ function listenCommand() {
2926
2980
  console.error("--dedupe-ttl must be a positive integer (seconds).");
2927
2981
  process.exit(1);
2928
2982
  }
2929
- if (opts.chatWriteback && (!Number.isFinite(chatCompleteTimeoutMs) || chatCompleteTimeoutMs <= 0)) {
2983
+ if (opts.chatWriteback && rawCompleteTimeout && (!Number.isFinite(chatCompleteTimeoutMs) || (chatCompleteTimeoutMs ?? 0) <= 0)) {
2930
2984
  console.error("--chat-complete-timeout must be a positive integer (ms).");
2931
2985
  process.exit(1);
2932
2986
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acnlabs/acn-cli",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "Official CLI for ACN (Agent Collaboration Network) \u2014 zero-integration agent access",
5
5
  "main": "dist/index.js",
6
6
  "bin": {