@corvio/cli 0.1.0-beta.10 → 0.1.0-beta.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.
- package/dist/cli.js +77 -6
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
agentCredentialPath,
|
|
40
40
|
} from "./core.js";
|
|
41
41
|
|
|
42
|
-
const VERSION = "0.1.0-beta.
|
|
42
|
+
const VERSION = "0.1.0-beta.11";
|
|
43
43
|
const DEFAULT_API_BASE = "https://api.corvio.ai/v1";
|
|
44
44
|
const DEFAULT_APP_BASE = "https://corvio.ai";
|
|
45
45
|
const USER_AGENT = `corvio-cli/${VERSION}`;
|
|
@@ -1628,6 +1628,43 @@ async function startAgentLeaseHeartbeat(api, event, leaseToken, leaseSeconds) {
|
|
|
1628
1628
|
};
|
|
1629
1629
|
}
|
|
1630
1630
|
|
|
1631
|
+
const FATAL_AGENT_LISTENER_ERROR_CODES = new Set([
|
|
1632
|
+
"agent_auth_required",
|
|
1633
|
+
"invalid_agent_key",
|
|
1634
|
+
"agent_credential_store_invalid",
|
|
1635
|
+
"agent_routing_ambiguous",
|
|
1636
|
+
"agent_runtime_device_invalid",
|
|
1637
|
+
"agent_runtime_provider_mismatch",
|
|
1638
|
+
"agent_project_binding_required",
|
|
1639
|
+
"agent_provider_unavailable",
|
|
1640
|
+
"agent_provider_not_ready",
|
|
1641
|
+
"agent_handler_required",
|
|
1642
|
+
"agent_handler_failed",
|
|
1643
|
+
"agent_handler_result_invalid",
|
|
1644
|
+
]);
|
|
1645
|
+
|
|
1646
|
+
function classifyAgentListenerFailure(error) {
|
|
1647
|
+
const code = String(error?.code || "agent_event_processing_failed").trim();
|
|
1648
|
+
const status = Number(error?.status || 0);
|
|
1649
|
+
const fatalListener = error?.exitCode === EXIT.AUTH
|
|
1650
|
+
|| status === 401
|
|
1651
|
+
|| status === 403
|
|
1652
|
+
|| FATAL_AGENT_LISTENER_ERROR_CODES.has(code);
|
|
1653
|
+
const retryable = !fatalListener
|
|
1654
|
+
&& (!(status >= 400 && status < 500) || [408, 429].includes(status));
|
|
1655
|
+
return { code, status: status || null, fatalListener, retryable };
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
function attachAgentEventFailure(error, failure) {
|
|
1659
|
+
if (error && typeof error === "object") {
|
|
1660
|
+
error.agentEventFailure = failure;
|
|
1661
|
+
return error;
|
|
1662
|
+
}
|
|
1663
|
+
const wrapped = new CliError(String(error), { code: "agent_event_processing_failed" });
|
|
1664
|
+
wrapped.agentEventFailure = failure;
|
|
1665
|
+
return wrapped;
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1631
1668
|
async function processClaimedAgentEvent(api, event, options) {
|
|
1632
1669
|
const leaseToken = String(event?.delivery?.lease_token || "");
|
|
1633
1670
|
if (!event?.id || !leaseToken) throw new CliError("Claimed event is missing its lease receipt.", { code: "agent_event_invalid" });
|
|
@@ -1751,15 +1788,37 @@ async function processClaimedAgentEvent(api, event, options) {
|
|
|
1751
1788
|
// The original execution error remains the failure authority.
|
|
1752
1789
|
}
|
|
1753
1790
|
}
|
|
1791
|
+
const disposition = classifyAgentListenerFailure(error);
|
|
1792
|
+
let failedEvent = null;
|
|
1793
|
+
let failError = null;
|
|
1754
1794
|
try {
|
|
1755
|
-
await api.request(`/agent-events/${resourcePath(event.id)}:fail`, {
|
|
1795
|
+
failedEvent = await api.request(`/agent-events/${resourcePath(event.id)}:fail`, {
|
|
1756
1796
|
method: "POST",
|
|
1757
|
-
body: {
|
|
1797
|
+
body: {
|
|
1798
|
+
lease_token: leaseToken,
|
|
1799
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1800
|
+
retryable: disposition.retryable,
|
|
1801
|
+
},
|
|
1758
1802
|
});
|
|
1759
|
-
} catch {
|
|
1803
|
+
} catch (failure) {
|
|
1804
|
+
failError = failure;
|
|
1760
1805
|
// Preserve the original execution failure; the expired lease remains reclaimable.
|
|
1761
1806
|
}
|
|
1762
|
-
|
|
1807
|
+
const finalError = failError && classifyAgentListenerFailure(failError).fatalListener
|
|
1808
|
+
? failError
|
|
1809
|
+
: error;
|
|
1810
|
+
throw attachAgentEventFailure(finalError, {
|
|
1811
|
+
event_id: String(event.id),
|
|
1812
|
+
event: failedEvent,
|
|
1813
|
+
retryable: disposition.retryable,
|
|
1814
|
+
fatal_listener: disposition.fatalListener
|
|
1815
|
+
|| Boolean(failError && classifyAgentListenerFailure(failError).fatalListener),
|
|
1816
|
+
error: {
|
|
1817
|
+
code: disposition.code,
|
|
1818
|
+
message: error instanceof Error ? error.message : String(error),
|
|
1819
|
+
...(disposition.status ? { status: disposition.status } : {}),
|
|
1820
|
+
},
|
|
1821
|
+
});
|
|
1763
1822
|
}
|
|
1764
1823
|
}
|
|
1765
1824
|
|
|
@@ -1773,9 +1832,21 @@ async function runAgent(options) {
|
|
|
1773
1832
|
const claimed = await claimAgentEvent(api, options, options.once ? 0 : 30);
|
|
1774
1833
|
if (!claimed.event) {
|
|
1775
1834
|
if (options.once) return writeResult({ processed: false, reason: "no_event", retry_after_seconds: claimed.retry_after_seconds }, { json: options.json });
|
|
1835
|
+
const retryAfterSeconds = Number(claimed.retry_after_seconds || 0);
|
|
1836
|
+
if (Number.isFinite(retryAfterSeconds) && retryAfterSeconds > 0) {
|
|
1837
|
+
await sleep(Math.min(30_000, Math.max(50, retryAfterSeconds * 1_000)));
|
|
1838
|
+
}
|
|
1839
|
+
continue;
|
|
1840
|
+
}
|
|
1841
|
+
let receipt;
|
|
1842
|
+
try {
|
|
1843
|
+
receipt = await processClaimedAgentEvent(api, claimed.event, options);
|
|
1844
|
+
} catch (error) {
|
|
1845
|
+
const failure = error?.agentEventFailure;
|
|
1846
|
+
if (options.once || !failure || failure.fatal_listener) throw error;
|
|
1847
|
+
process.stdout.write(`${JSON.stringify({ processed: false, ...failure })}\n`);
|
|
1776
1848
|
continue;
|
|
1777
1849
|
}
|
|
1778
|
-
const receipt = await processClaimedAgentEvent(api, claimed.event, options);
|
|
1779
1850
|
if (options.once) return writeResult({ processed: true, ...receipt }, { json: options.json });
|
|
1780
1851
|
process.stdout.write(`${JSON.stringify({ processed: true, ...receipt })}\n`);
|
|
1781
1852
|
}
|