@covia/covia-sdk 1.8.0 → 1.9.1
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/README.md +98 -33
- package/dist/index.d.mts +203 -60
- package/dist/index.d.ts +203 -60
- package/dist/index.js +516 -156
- package/dist/index.mjs +513 -157
- package/package.json +9 -4
package/dist/index.js
CHANGED
|
@@ -45,6 +45,15 @@ var GridError = class extends CoviaError {
|
|
|
45
45
|
this.responseBody = responseBody;
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
|
+
var UnsupportedVenueFeatureError = class extends CoviaError {
|
|
49
|
+
constructor(feature) {
|
|
50
|
+
super(
|
|
51
|
+
`The connected venue cannot serve ${feature} without creating a job. Invoke the corresponding operation explicitly if creating a persisted job is intended.`
|
|
52
|
+
);
|
|
53
|
+
this.feature = feature;
|
|
54
|
+
this.name = "UnsupportedVenueFeatureError";
|
|
55
|
+
}
|
|
56
|
+
};
|
|
48
57
|
var CoviaConnectionError = class extends CoviaError {
|
|
49
58
|
constructor(message, options = {}) {
|
|
50
59
|
super(message);
|
|
@@ -114,6 +123,14 @@ var JobNotFoundError = class extends NotFoundError {
|
|
|
114
123
|
this.jobId = jobId;
|
|
115
124
|
}
|
|
116
125
|
};
|
|
126
|
+
var AgentSessionNotFoundError = class extends CoviaError {
|
|
127
|
+
constructor(agentId, sessionId) {
|
|
128
|
+
super(`Agent session not found: ${agentId}/${sessionId}`, 404);
|
|
129
|
+
this.agentId = agentId;
|
|
130
|
+
this.sessionId = sessionId;
|
|
131
|
+
this.name = "AgentSessionNotFoundError";
|
|
132
|
+
}
|
|
133
|
+
};
|
|
117
134
|
|
|
118
135
|
// node_modules/.pnpm/@noble+ed25519@3.1.0/node_modules/@noble/ed25519/index.js
|
|
119
136
|
var ed25519_CURVE = Object.freeze({
|
|
@@ -1033,9 +1050,13 @@ function privateKeyToHex(key) {
|
|
|
1033
1050
|
return Array.from(key).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1034
1051
|
}
|
|
1035
1052
|
function hexToPrivateKey(hex) {
|
|
1036
|
-
const
|
|
1053
|
+
const cleaned = hex.startsWith("0x") || hex.startsWith("0X") ? hex.slice(2) : hex;
|
|
1054
|
+
if (!/^[0-9a-fA-F]{64}$/.test(cleaned)) {
|
|
1055
|
+
throw new Error("Invalid Ed25519 private key: expected 64 hex characters (32 bytes)");
|
|
1056
|
+
}
|
|
1057
|
+
const bytes = new Uint8Array(32);
|
|
1037
1058
|
for (let i = 0; i < bytes.length; i++) {
|
|
1038
|
-
bytes[i] = parseInt(
|
|
1059
|
+
bytes[i] = parseInt(cleaned.substring(i * 2, i * 2 + 2), 16);
|
|
1039
1060
|
}
|
|
1040
1061
|
return bytes;
|
|
1041
1062
|
}
|
|
@@ -1149,6 +1170,14 @@ function createEdDSAJWT(privateKey, lifetimeSeconds = 300, audience) {
|
|
|
1149
1170
|
}
|
|
1150
1171
|
|
|
1151
1172
|
// src/Credentials.ts
|
|
1173
|
+
function base64Encode(text) {
|
|
1174
|
+
const bytes = new TextEncoder().encode(text);
|
|
1175
|
+
let binary = "";
|
|
1176
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
1177
|
+
binary += String.fromCharCode(bytes[i]);
|
|
1178
|
+
}
|
|
1179
|
+
return btoa(binary);
|
|
1180
|
+
}
|
|
1152
1181
|
var Auth = class {
|
|
1153
1182
|
};
|
|
1154
1183
|
var NoAuth = class extends Auth {
|
|
@@ -1171,7 +1200,7 @@ var BasicAuth = class extends Auth {
|
|
|
1171
1200
|
this._password = password;
|
|
1172
1201
|
}
|
|
1173
1202
|
apply(headers, _audience) {
|
|
1174
|
-
const credentials =
|
|
1203
|
+
const credentials = base64Encode(`${this._username}:${this._password}`);
|
|
1175
1204
|
headers["Authorization"] = `Basic ${credentials}`;
|
|
1176
1205
|
}
|
|
1177
1206
|
};
|
|
@@ -1188,8 +1217,30 @@ var Ed25519Auth = class _Ed25519Auth extends Auth {
|
|
|
1188
1217
|
this._lifetime = tokenLifetimeSeconds;
|
|
1189
1218
|
}
|
|
1190
1219
|
apply(headers, audience) {
|
|
1191
|
-
|
|
1192
|
-
|
|
1220
|
+
headers["Authorization"] = `Bearer ${this.identityToken(audience)}`;
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Mint a bearer-usable identity JWT for this key — the same token
|
|
1224
|
+
* {@link apply} attaches to every request, exposed for callers that need
|
|
1225
|
+
* to present this identity elsewhere (CLI tools, curl, another client:
|
|
1226
|
+
* `Authorization: Bearer <token>`).
|
|
1227
|
+
*
|
|
1228
|
+
* An explicitly-pinned {@link audience} wins; otherwise the JWT `aud` is
|
|
1229
|
+
* bound to the venue DID given here. A token with no `aud` is replayable
|
|
1230
|
+
* at any venue that accepts the caller's DID, so minting one is refused
|
|
1231
|
+
* rather than silently weakened.
|
|
1232
|
+
*
|
|
1233
|
+
* @param audience - The venue DID the token is bound to (`aud` claim).
|
|
1234
|
+
* @param lifetimeSeconds - Token lifetime; defaults to this instance's.
|
|
1235
|
+
*/
|
|
1236
|
+
identityToken(audience, lifetimeSeconds) {
|
|
1237
|
+
const aud = this._audience ?? (audience || void 0);
|
|
1238
|
+
if (!aud) {
|
|
1239
|
+
throw new CoviaError(
|
|
1240
|
+
"Ed25519Auth requires a venue audience to bind the token to: connect via Grid.connect()/Venue.connect() so the venue DID is known, or pin auth.audience explicitly."
|
|
1241
|
+
);
|
|
1242
|
+
}
|
|
1243
|
+
return createEdDSAJWT(this._privateKey, lifetimeSeconds ?? this._lifetime, aud);
|
|
1193
1244
|
}
|
|
1194
1245
|
/** The caller's DID derived from the public key. */
|
|
1195
1246
|
getDID() {
|
|
@@ -1302,17 +1353,24 @@ async function parseErrorBody(response) {
|
|
|
1302
1353
|
let body = null;
|
|
1303
1354
|
let message = `Request failed with status ${response.status}`;
|
|
1304
1355
|
try {
|
|
1305
|
-
|
|
1356
|
+
if (typeof response.text === "function") {
|
|
1357
|
+
const text = await response.text();
|
|
1358
|
+
if (text) {
|
|
1359
|
+
try {
|
|
1360
|
+
body = JSON.parse(text);
|
|
1361
|
+
} catch {
|
|
1362
|
+
body = text;
|
|
1363
|
+
message = text;
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
} else {
|
|
1367
|
+
body = await response.json();
|
|
1368
|
+
}
|
|
1306
1369
|
if (body && typeof body === "object" && "error" in body) {
|
|
1307
1370
|
const err2 = body.error;
|
|
1308
1371
|
if (typeof err2 === "string") message = err2;
|
|
1309
1372
|
}
|
|
1310
1373
|
} catch {
|
|
1311
|
-
try {
|
|
1312
|
-
const text = await response.text();
|
|
1313
|
-
if (text) message = text;
|
|
1314
|
-
} catch {
|
|
1315
|
-
}
|
|
1316
1374
|
}
|
|
1317
1375
|
return { message, body };
|
|
1318
1376
|
}
|
|
@@ -1606,13 +1664,82 @@ var AdapterManager = class {
|
|
|
1606
1664
|
}
|
|
1607
1665
|
};
|
|
1608
1666
|
|
|
1609
|
-
// src/
|
|
1667
|
+
// src/VenueTransport.ts
|
|
1668
|
+
function requestOptions(venue, options) {
|
|
1669
|
+
const {
|
|
1670
|
+
contentType,
|
|
1671
|
+
headers: suppliedHeaders = {},
|
|
1672
|
+
...request
|
|
1673
|
+
} = options;
|
|
1674
|
+
const headers = { ...suppliedHeaders };
|
|
1675
|
+
const effectiveContentType = contentType !== void 0 ? contentType : request.body != null ? "application/json" : null;
|
|
1676
|
+
if (effectiveContentType && headers["Content-Type"] === void 0) {
|
|
1677
|
+
headers["Content-Type"] = effectiveContentType;
|
|
1678
|
+
}
|
|
1679
|
+
venue.auth.apply(headers, venue.venueId);
|
|
1680
|
+
return { ...request, headers };
|
|
1681
|
+
}
|
|
1682
|
+
function venueJson(venue, path, options = {}) {
|
|
1683
|
+
return fetchWithError(
|
|
1684
|
+
`${venue.baseUrl}${path}`,
|
|
1685
|
+
requestOptions(venue, options)
|
|
1686
|
+
);
|
|
1687
|
+
}
|
|
1688
|
+
function venueStream(venue, path, options = {}) {
|
|
1689
|
+
return fetchStreamWithError(
|
|
1690
|
+
`${venue.baseUrl}${path}`,
|
|
1691
|
+
requestOptions(venue, options)
|
|
1692
|
+
);
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
// src/venue-features.ts
|
|
1610
1696
|
function versionAtLeast(version, major, minor) {
|
|
1611
1697
|
const m = version?.match(/^(\d+)\.(\d+)/);
|
|
1612
1698
|
if (!m) return true;
|
|
1613
1699
|
const [maj, min] = [Number(m[1]), Number(m[2])];
|
|
1614
1700
|
return maj > major || maj === major && min >= minor;
|
|
1615
1701
|
}
|
|
1702
|
+
var ROUTE_MISSING_404 = /\bEndpoint (GET|POST|PUT|DELETE|PATCH|HEAD) /;
|
|
1703
|
+
|
|
1704
|
+
// src/values-util.ts
|
|
1705
|
+
function record(value) {
|
|
1706
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
1707
|
+
}
|
|
1708
|
+
var SLICE_PAGE_SIZE = 200;
|
|
1709
|
+
async function sliceAll(workspace, path, pageSize = SLICE_PAGE_SIZE) {
|
|
1710
|
+
const items = [];
|
|
1711
|
+
let offset = 0;
|
|
1712
|
+
for (; ; ) {
|
|
1713
|
+
const page = await workspace.slice(path, offset, pageSize);
|
|
1714
|
+
if (!page.exists) {
|
|
1715
|
+
if (items.length === 0) return items;
|
|
1716
|
+
throw new CoviaError(`Sliceable value at ${path} disappeared mid-read`);
|
|
1717
|
+
}
|
|
1718
|
+
const values = page.values ?? [];
|
|
1719
|
+
items.push(...values);
|
|
1720
|
+
const nextOffset = (page.offset ?? offset) + values.length;
|
|
1721
|
+
const done = page.count !== void 0 ? nextOffset >= page.count : values.length < pageSize;
|
|
1722
|
+
if (values.length === 0 || done) break;
|
|
1723
|
+
if (nextOffset <= offset) {
|
|
1724
|
+
throw new CoviaError(`Venue returned a slice of ${path} that did not advance`);
|
|
1725
|
+
}
|
|
1726
|
+
offset = nextOffset;
|
|
1727
|
+
}
|
|
1728
|
+
return items;
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
// src/AgentManager.ts
|
|
1732
|
+
function sessionRecord(sessionId, value) {
|
|
1733
|
+
const session = record(value) ?? {};
|
|
1734
|
+
const meta = record(session.meta);
|
|
1735
|
+
return {
|
|
1736
|
+
id: sessionId,
|
|
1737
|
+
metadata: meta ?? {},
|
|
1738
|
+
pending: Array.isArray(session.pending) ? session.pending : [],
|
|
1739
|
+
frames: Array.isArray(session.frames) ? session.frames : [],
|
|
1740
|
+
wakeTime: typeof session.wakeTime === "number" ? session.wakeTime : void 0
|
|
1741
|
+
};
|
|
1742
|
+
}
|
|
1616
1743
|
var AgentManager = class {
|
|
1617
1744
|
constructor(venue) {
|
|
1618
1745
|
this.venue = venue;
|
|
@@ -1620,11 +1747,6 @@ var AgentManager = class {
|
|
|
1620
1747
|
// pre-0.4 venues pay the probe once, not one failed GET per read (covia#180).
|
|
1621
1748
|
this.agentsGetSupported = true;
|
|
1622
1749
|
}
|
|
1623
|
-
_headers() {
|
|
1624
|
-
const headers = { "Content-Type": "application/json" };
|
|
1625
|
-
this.venue.auth.apply(headers, this.venue.venueId);
|
|
1626
|
-
return headers;
|
|
1627
|
-
}
|
|
1628
1750
|
/** Whether the venue serves `GET /api/v1/agents`: no if a probe already
|
|
1629
1751
|
* 404'd, or if the venue's last known status identifies it as pre-0.4. */
|
|
1630
1752
|
supportsAgentsGet() {
|
|
@@ -1635,25 +1757,25 @@ var AgentManager = class {
|
|
|
1635
1757
|
}
|
|
1636
1758
|
return this.agentsGetSupported;
|
|
1637
1759
|
}
|
|
1638
|
-
/** A job-free agents GET
|
|
1639
|
-
async
|
|
1760
|
+
/** A job-free agents GET that rejects when the endpoint is unavailable. */
|
|
1761
|
+
async agentsGet(path, params) {
|
|
1640
1762
|
if (this.supportsAgentsGet()) {
|
|
1641
1763
|
try {
|
|
1642
1764
|
const qs = new URLSearchParams();
|
|
1643
1765
|
for (const [k, v] of Object.entries(params)) if (v !== void 0) qs.set(k, String(v));
|
|
1644
1766
|
const q = qs.toString();
|
|
1645
|
-
return await
|
|
1646
|
-
|
|
1647
|
-
{
|
|
1767
|
+
return await venueJson(
|
|
1768
|
+
this.venue,
|
|
1769
|
+
`/api/v1/agents${path}${q ? `?${q}` : ""}`
|
|
1648
1770
|
);
|
|
1649
1771
|
} catch (e) {
|
|
1650
1772
|
if (!(e instanceof NotFoundError)) throw e;
|
|
1651
|
-
const routeMissing = path === "" ||
|
|
1773
|
+
const routeMissing = path === "" || ROUTE_MISSING_404.test(e.message);
|
|
1652
1774
|
if (!routeMissing) throw e;
|
|
1653
1775
|
this.agentsGetSupported = false;
|
|
1654
1776
|
}
|
|
1655
1777
|
}
|
|
1656
|
-
|
|
1778
|
+
throw new UnsupportedVenueFeatureError("agent reads");
|
|
1657
1779
|
}
|
|
1658
1780
|
async create(input) {
|
|
1659
1781
|
return this.venue.operations.run("v/ops/agent/create", input);
|
|
@@ -1698,10 +1820,10 @@ var AgentManager = class {
|
|
|
1698
1820
|
/**
|
|
1699
1821
|
* List the caller's agents. **Job-free** on covia ≥ 0.4: goes through
|
|
1700
1822
|
* `GET /api/v1/agents` (covia#180) — synchronous, no Job persisted. Older
|
|
1701
|
-
* venues
|
|
1823
|
+
* venues reject rather than silently creating a persisted Job.
|
|
1702
1824
|
*/
|
|
1703
1825
|
async list(includeTerminated) {
|
|
1704
|
-
const result = await this.
|
|
1826
|
+
const result = await this.agentsGet("", { includeTerminated });
|
|
1705
1827
|
const raw = result?.agents ?? [];
|
|
1706
1828
|
const agents = raw.map((a) => typeof a === "string" ? { agentId: a } : a);
|
|
1707
1829
|
return { agents };
|
|
@@ -1722,9 +1844,61 @@ var AgentManager = class {
|
|
|
1722
1844
|
return this.venue.operations.run("v/ops/agent/cancel-task", { agentId, taskId });
|
|
1723
1845
|
}
|
|
1724
1846
|
/** Agent info. **Job-free** on covia ≥ 0.4 (`GET /api/v1/agents/{id}`,
|
|
1725
|
-
* covia#180); older venues
|
|
1847
|
+
* covia#180); older venues require an explicit compatibility opt-in. */
|
|
1726
1848
|
async info(agentId) {
|
|
1727
|
-
return this.
|
|
1849
|
+
return this.agentsGet(`/${encodeURIComponent(agentId)}`, {});
|
|
1850
|
+
}
|
|
1851
|
+
/**
|
|
1852
|
+
* Page an agent's sessions directly from `g/<agentId>/sessions`.
|
|
1853
|
+
* This is a job-free Values read; session adapter-specific fields remain
|
|
1854
|
+
* available on each record's `value` while common runtime fields are typed.
|
|
1855
|
+
*/
|
|
1856
|
+
async listSessions(agentId, options = {}) {
|
|
1857
|
+
const result = await this.venue.workspace.slice(
|
|
1858
|
+
`g/${agentId}/sessions`,
|
|
1859
|
+
options.offset,
|
|
1860
|
+
options.limit
|
|
1861
|
+
);
|
|
1862
|
+
const sessions = (result.values ?? []).flatMap((entry) => {
|
|
1863
|
+
const pair = record(entry);
|
|
1864
|
+
if (!pair || typeof pair.key !== "string") return [];
|
|
1865
|
+
return [sessionRecord(pair.key, pair.value)];
|
|
1866
|
+
});
|
|
1867
|
+
return {
|
|
1868
|
+
items: sessions,
|
|
1869
|
+
total: result.count ?? sessions.length,
|
|
1870
|
+
offset: result.offset ?? options.offset ?? 0,
|
|
1871
|
+
limit: options.limit ?? sessions.length
|
|
1872
|
+
};
|
|
1873
|
+
}
|
|
1874
|
+
/** Read one agent session directly from the workspace Values surface. */
|
|
1875
|
+
async getSession(agentId, sessionId) {
|
|
1876
|
+
const path = `g/${agentId}/sessions/${sessionId}`;
|
|
1877
|
+
const result = await this.venue.workspace.read(path);
|
|
1878
|
+
if (!result.exists) {
|
|
1879
|
+
throw new AgentSessionNotFoundError(agentId, sessionId);
|
|
1880
|
+
}
|
|
1881
|
+
if (result.truncated) {
|
|
1882
|
+
return this._readLargeSession(path, sessionId);
|
|
1883
|
+
}
|
|
1884
|
+
if (result.value === void 0 || result.value === null) {
|
|
1885
|
+
throw new AgentSessionNotFoundError(agentId, sessionId);
|
|
1886
|
+
}
|
|
1887
|
+
return sessionRecord(sessionId, result.value);
|
|
1888
|
+
}
|
|
1889
|
+
async _readLargeSession(path, sessionId) {
|
|
1890
|
+
const [meta, wakeTime, pending, frames] = await Promise.all([
|
|
1891
|
+
this.venue.workspace.read(`${path}/meta`),
|
|
1892
|
+
this.venue.workspace.read(`${path}/wakeTime`),
|
|
1893
|
+
sliceAll(this.venue.workspace, `${path}/pending`),
|
|
1894
|
+
sliceAll(this.venue.workspace, `${path}/frames`)
|
|
1895
|
+
]);
|
|
1896
|
+
return sessionRecord(sessionId, {
|
|
1897
|
+
meta: meta.exists ? meta.value : void 0,
|
|
1898
|
+
wakeTime: wakeTime.exists ? wakeTime.value : void 0,
|
|
1899
|
+
pending,
|
|
1900
|
+
frames
|
|
1901
|
+
});
|
|
1728
1902
|
}
|
|
1729
1903
|
async fork(input) {
|
|
1730
1904
|
return this.venue.operations.run("v/ops/agent/fork", input);
|
|
@@ -1886,23 +2060,50 @@ var Job = class {
|
|
|
1886
2060
|
};
|
|
1887
2061
|
|
|
1888
2062
|
// src/JobManager.ts
|
|
2063
|
+
function jobPage(value) {
|
|
2064
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
2065
|
+
throw new CoviaError("Venue returned an invalid jobs listing");
|
|
2066
|
+
}
|
|
2067
|
+
const page = value;
|
|
2068
|
+
if (!Array.isArray(page.items) || !page.items.every((item) => typeof item === "string") || !Number.isInteger(page.total) || (page.total ?? -1) < 0 || !Number.isInteger(page.offset) || (page.offset ?? -1) < 0 || !Number.isInteger(page.limit) || (page.limit ?? -1) < 0) {
|
|
2069
|
+
throw new CoviaError("Venue returned an invalid jobs page");
|
|
2070
|
+
}
|
|
2071
|
+
return page;
|
|
2072
|
+
}
|
|
1889
2073
|
var JobManager = class {
|
|
1890
2074
|
constructor(venue) {
|
|
1891
2075
|
this.venue = venue;
|
|
1892
2076
|
}
|
|
1893
2077
|
async list() {
|
|
1894
|
-
const
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
2078
|
+
const items = [];
|
|
2079
|
+
let offset = 0;
|
|
2080
|
+
let targetTotal;
|
|
2081
|
+
while (targetTotal === void 0 || items.length < targetTotal) {
|
|
2082
|
+
const body = await venueJson(
|
|
2083
|
+
this.venue,
|
|
2084
|
+
`/api/v1/jobs?offset=${offset}&limit=1000`
|
|
2085
|
+
);
|
|
2086
|
+
if (Array.isArray(body)) {
|
|
2087
|
+
if (!body.every((item) => typeof item === "string")) {
|
|
2088
|
+
throw new CoviaError("Venue returned an invalid jobs listing");
|
|
2089
|
+
}
|
|
2090
|
+
return body;
|
|
2091
|
+
}
|
|
2092
|
+
const page = jobPage(body);
|
|
2093
|
+
targetTotal ?? (targetTotal = page.total);
|
|
2094
|
+
items.push(...page.items);
|
|
2095
|
+
if (page.items.length === 0) break;
|
|
2096
|
+
const nextOffset = page.offset + page.items.length;
|
|
2097
|
+
if (nextOffset <= offset) {
|
|
2098
|
+
throw new CoviaError("Venue returned a jobs page that did not advance");
|
|
2099
|
+
}
|
|
2100
|
+
offset = nextOffset;
|
|
2101
|
+
}
|
|
2102
|
+
return items;
|
|
1900
2103
|
}
|
|
1901
2104
|
async get(jobId) {
|
|
1902
2105
|
try {
|
|
1903
|
-
const data = await
|
|
1904
|
-
headers: this._buildHeaders()
|
|
1905
|
-
});
|
|
2106
|
+
const data = await venueJson(this.venue, `/api/v1/jobs/${jobId}`);
|
|
1906
2107
|
return new Job(jobId, this.venue, data);
|
|
1907
2108
|
} catch (error) {
|
|
1908
2109
|
if (error instanceof NotFoundError) {
|
|
@@ -1913,9 +2114,8 @@ var JobManager = class {
|
|
|
1913
2114
|
}
|
|
1914
2115
|
async cancel(jobId) {
|
|
1915
2116
|
try {
|
|
1916
|
-
return await
|
|
1917
|
-
method: "PUT"
|
|
1918
|
-
headers: this._buildHeaders()
|
|
2117
|
+
return await venueJson(this.venue, `/api/v1/jobs/${jobId}/cancel`, {
|
|
2118
|
+
method: "PUT"
|
|
1919
2119
|
});
|
|
1920
2120
|
} catch (error) {
|
|
1921
2121
|
if (error instanceof NotFoundError) {
|
|
@@ -1926,9 +2126,8 @@ var JobManager = class {
|
|
|
1926
2126
|
}
|
|
1927
2127
|
async delete(jobId) {
|
|
1928
2128
|
try {
|
|
1929
|
-
await
|
|
1930
|
-
method: "PUT"
|
|
1931
|
-
headers: this._buildHeaders()
|
|
2129
|
+
await venueStream(this.venue, `/api/v1/jobs/${jobId}/delete`, {
|
|
2130
|
+
method: "PUT"
|
|
1932
2131
|
});
|
|
1933
2132
|
} catch (error) {
|
|
1934
2133
|
if (error instanceof NotFoundError) {
|
|
@@ -1939,9 +2138,8 @@ var JobManager = class {
|
|
|
1939
2138
|
}
|
|
1940
2139
|
async pause(jobId) {
|
|
1941
2140
|
try {
|
|
1942
|
-
return await
|
|
1943
|
-
method: "PUT"
|
|
1944
|
-
headers: this._buildHeaders()
|
|
2141
|
+
return await venueJson(this.venue, `/api/v1/jobs/${jobId}/pause`, {
|
|
2142
|
+
method: "PUT"
|
|
1945
2143
|
});
|
|
1946
2144
|
} catch (error) {
|
|
1947
2145
|
if (error instanceof NotFoundError) {
|
|
@@ -1952,9 +2150,8 @@ var JobManager = class {
|
|
|
1952
2150
|
}
|
|
1953
2151
|
async resume(jobId) {
|
|
1954
2152
|
try {
|
|
1955
|
-
return await
|
|
1956
|
-
method: "PUT"
|
|
1957
|
-
headers: this._buildHeaders()
|
|
2153
|
+
return await venueJson(this.venue, `/api/v1/jobs/${jobId}/resume`, {
|
|
2154
|
+
method: "PUT"
|
|
1958
2155
|
});
|
|
1959
2156
|
} catch (error) {
|
|
1960
2157
|
if (error instanceof NotFoundError) {
|
|
@@ -1965,9 +2162,8 @@ var JobManager = class {
|
|
|
1965
2162
|
}
|
|
1966
2163
|
async sendMessage(jobId, message) {
|
|
1967
2164
|
try {
|
|
1968
|
-
return await
|
|
2165
|
+
return await venueJson(this.venue, `/api/v1/jobs/${jobId}`, {
|
|
1969
2166
|
method: "POST",
|
|
1970
|
-
headers: this._buildHeaders(),
|
|
1971
2167
|
body: JSON.stringify(message)
|
|
1972
2168
|
});
|
|
1973
2169
|
} catch (error) {
|
|
@@ -1978,16 +2174,11 @@ var JobManager = class {
|
|
|
1978
2174
|
}
|
|
1979
2175
|
}
|
|
1980
2176
|
async *stream(jobId) {
|
|
1981
|
-
const response = await
|
|
1982
|
-
headers: {
|
|
2177
|
+
const response = await venueStream(this.venue, `/api/v1/jobs/${jobId}/sse`, {
|
|
2178
|
+
headers: { "Accept": "text/event-stream" }
|
|
1983
2179
|
});
|
|
1984
2180
|
yield* parseSSEStream(response);
|
|
1985
2181
|
}
|
|
1986
|
-
_buildHeaders() {
|
|
1987
|
-
const headers = { "Content-Type": "application/json" };
|
|
1988
|
-
this.venue.auth.apply(headers, this.venue.venueId);
|
|
1989
|
-
return headers;
|
|
1990
|
-
}
|
|
1991
2182
|
};
|
|
1992
2183
|
|
|
1993
2184
|
// src/Asset.ts
|
|
@@ -2067,10 +2258,12 @@ var DataAsset = class extends Asset {
|
|
|
2067
2258
|
};
|
|
2068
2259
|
|
|
2069
2260
|
// src/AssetManager.ts
|
|
2070
|
-
var cache = /* @__PURE__ */ new Map();
|
|
2071
2261
|
var AssetManager = class {
|
|
2072
2262
|
constructor(venue) {
|
|
2073
2263
|
this.venue = venue;
|
|
2264
|
+
// Memory cache is manager/venue-local. Content-addressed metadata may still
|
|
2265
|
+
// be shared deliberately through the configured persistent metadata store.
|
|
2266
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
2074
2267
|
}
|
|
2075
2268
|
/**
|
|
2076
2269
|
* Get an asset by lattice address.
|
|
@@ -2083,23 +2276,25 @@ var AssetManager = class {
|
|
|
2083
2276
|
* @returns Returns either an Operation or DataAsset based on the asset's metadata
|
|
2084
2277
|
*/
|
|
2085
2278
|
async get(assetId) {
|
|
2086
|
-
if (cache.has(assetId)) {
|
|
2087
|
-
return this._wrap(assetId, cache.get(assetId));
|
|
2279
|
+
if (this.cache.has(assetId)) {
|
|
2280
|
+
return this._wrap(assetId, this.cache.get(assetId));
|
|
2088
2281
|
}
|
|
2089
2282
|
const hash = assetHash(assetId);
|
|
2090
2283
|
if (hash) {
|
|
2091
2284
|
const persisted = getAssetMetadataStore()?.get(normaliseHash(hash));
|
|
2092
2285
|
if (persisted) {
|
|
2093
|
-
cache.set(assetId, persisted);
|
|
2286
|
+
this.cache.set(assetId, persisted);
|
|
2094
2287
|
return this._wrap(assetId, persisted);
|
|
2095
2288
|
}
|
|
2096
2289
|
}
|
|
2097
2290
|
try {
|
|
2098
|
-
const data = await
|
|
2099
|
-
|
|
2100
|
-
|
|
2291
|
+
const data = await venueJson(
|
|
2292
|
+
this.venue,
|
|
2293
|
+
`/api/v1/assets/${assetId}`,
|
|
2294
|
+
{ contentType: null }
|
|
2295
|
+
);
|
|
2101
2296
|
if (hash) {
|
|
2102
|
-
cache.set(assetId, data);
|
|
2297
|
+
this.cache.set(assetId, data);
|
|
2103
2298
|
getAssetMetadataStore()?.put(normaliseHash(hash), data);
|
|
2104
2299
|
}
|
|
2105
2300
|
return this._wrap(assetId, data);
|
|
@@ -2126,18 +2321,19 @@ var AssetManager = class {
|
|
|
2126
2321
|
if (options.limit !== void 0) {
|
|
2127
2322
|
params.set("limit", String(options.limit));
|
|
2128
2323
|
}
|
|
2129
|
-
return
|
|
2130
|
-
|
|
2131
|
-
|
|
2324
|
+
return venueJson(
|
|
2325
|
+
this.venue,
|
|
2326
|
+
`/api/v1/assets?${params.toString()}`,
|
|
2327
|
+
{ contentType: null }
|
|
2328
|
+
);
|
|
2132
2329
|
}
|
|
2133
2330
|
/**
|
|
2134
2331
|
* Register a new asset
|
|
2135
2332
|
* @param assetData - Asset configuration
|
|
2136
2333
|
*/
|
|
2137
2334
|
async register(assetData) {
|
|
2138
|
-
return
|
|
2335
|
+
return venueJson(this.venue, "/api/v1/assets", {
|
|
2139
2336
|
method: "POST",
|
|
2140
|
-
headers: this._buildHeaders(),
|
|
2141
2337
|
body: JSON.stringify(assetData)
|
|
2142
2338
|
}).then((response) => this.get(response));
|
|
2143
2339
|
}
|
|
@@ -2147,9 +2343,11 @@ var AssetManager = class {
|
|
|
2147
2343
|
*/
|
|
2148
2344
|
async getMetadata(assetId) {
|
|
2149
2345
|
try {
|
|
2150
|
-
return await
|
|
2151
|
-
|
|
2152
|
-
|
|
2346
|
+
return await venueJson(
|
|
2347
|
+
this.venue,
|
|
2348
|
+
`/api/v1/assets/${assetId}`,
|
|
2349
|
+
{ contentType: null }
|
|
2350
|
+
);
|
|
2153
2351
|
} catch (error) {
|
|
2154
2352
|
if (error instanceof NotFoundError) {
|
|
2155
2353
|
throw new AssetNotFoundError(assetId);
|
|
@@ -2165,9 +2363,9 @@ var AssetManager = class {
|
|
|
2165
2363
|
*/
|
|
2166
2364
|
async putContent(assetId, content) {
|
|
2167
2365
|
try {
|
|
2168
|
-
return await
|
|
2366
|
+
return await venueJson(this.venue, `/api/v1/assets/${assetId}/content`, {
|
|
2169
2367
|
method: "PUT",
|
|
2170
|
-
|
|
2368
|
+
contentType: null,
|
|
2171
2369
|
body: content
|
|
2172
2370
|
});
|
|
2173
2371
|
} catch (error) {
|
|
@@ -2183,9 +2381,11 @@ var AssetManager = class {
|
|
|
2183
2381
|
*/
|
|
2184
2382
|
async getContent(assetId) {
|
|
2185
2383
|
try {
|
|
2186
|
-
const response = await
|
|
2187
|
-
|
|
2188
|
-
|
|
2384
|
+
const response = await venueStream(
|
|
2385
|
+
this.venue,
|
|
2386
|
+
`/api/v1/assets/${assetId}/content`,
|
|
2387
|
+
{ contentType: null }
|
|
2388
|
+
);
|
|
2189
2389
|
return response.body;
|
|
2190
2390
|
} catch (error) {
|
|
2191
2391
|
if (error instanceof NotFoundError) {
|
|
@@ -2206,17 +2406,11 @@ var AssetManager = class {
|
|
|
2206
2406
|
* Clear the asset cache.
|
|
2207
2407
|
*/
|
|
2208
2408
|
clearCache() {
|
|
2209
|
-
cache.clear();
|
|
2210
|
-
getAssetMetadataStore()?.clear();
|
|
2409
|
+
this.cache.clear();
|
|
2211
2410
|
}
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
_buildHeaders(contentType = "application/json") {
|
|
2216
|
-
const headers = {};
|
|
2217
|
-
if (contentType) headers["Content-Type"] = contentType;
|
|
2218
|
-
this.venue.auth.apply(headers, this.venue.venueId);
|
|
2219
|
-
return headers;
|
|
2411
|
+
/** Clear the explicitly configured cross-session metadata store. */
|
|
2412
|
+
clearPersistentCache() {
|
|
2413
|
+
getAssetMetadataStore()?.clear();
|
|
2220
2414
|
}
|
|
2221
2415
|
};
|
|
2222
2416
|
|
|
@@ -2229,23 +2423,23 @@ var OperationManager = class {
|
|
|
2229
2423
|
* List all named operations available on this venue
|
|
2230
2424
|
*/
|
|
2231
2425
|
async list() {
|
|
2232
|
-
return
|
|
2426
|
+
return venueJson(this.venue, "/api/v1/operations");
|
|
2233
2427
|
}
|
|
2234
2428
|
/**
|
|
2235
2429
|
* Get details of a named operation
|
|
2236
2430
|
* @param name - Operation name (e.g., "v/ops/schema/infer")
|
|
2237
2431
|
*/
|
|
2238
2432
|
async get(name) {
|
|
2239
|
-
return
|
|
2433
|
+
return venueJson(this.venue, `/api/v1/operations/${name}`);
|
|
2240
2434
|
}
|
|
2241
2435
|
/**
|
|
2242
2436
|
* Execute an operation and wait for the result
|
|
2243
2437
|
* @param assetId - Operation asset ID or named operation
|
|
2244
2438
|
* @param input - Operation input parameters
|
|
2245
|
-
* @param options -
|
|
2439
|
+
* @param options - Execution options (e.g., ucans or private execution)
|
|
2246
2440
|
*/
|
|
2247
2441
|
async run(assetId, input, options) {
|
|
2248
|
-
if (this.venue.privateJobs) {
|
|
2442
|
+
if (options?.private ?? this.venue.privateJobs) {
|
|
2249
2443
|
return this._runPrivate(assetId, input, options);
|
|
2250
2444
|
}
|
|
2251
2445
|
const job = await this.invoke(assetId, input, options);
|
|
@@ -2267,9 +2461,8 @@ var OperationManager = class {
|
|
|
2267
2461
|
wait: true
|
|
2268
2462
|
};
|
|
2269
2463
|
if (options?.ucans) payload.ucans = options.ucans;
|
|
2270
|
-
const rec = await
|
|
2464
|
+
const rec = await venueJson(this.venue, "/api/v1/invoke", {
|
|
2271
2465
|
method: "POST",
|
|
2272
|
-
headers: this._buildHeaders(),
|
|
2273
2466
|
body: JSON.stringify(payload)
|
|
2274
2467
|
});
|
|
2275
2468
|
const status = rec.status;
|
|
@@ -2281,6 +2474,7 @@ var OperationManager = class {
|
|
|
2281
2474
|
const job = new Job(rec.id ?? "", this.venue, rec);
|
|
2282
2475
|
return await job.result();
|
|
2283
2476
|
} catch (e) {
|
|
2477
|
+
if (!(e instanceof NotFoundError)) throw e;
|
|
2284
2478
|
throw new CoviaError(
|
|
2285
2479
|
`Private job completed while unobserved \u2014 its record is already forgotten, so the result could not be collected. Private jobs that outlive the venue wait window cannot be reliably collected; consider a non-private run for long operations. (${e.message})`
|
|
2286
2480
|
);
|
|
@@ -2293,7 +2487,7 @@ var OperationManager = class {
|
|
|
2293
2487
|
* @param options - Invoke options (e.g., ucans)
|
|
2294
2488
|
*/
|
|
2295
2489
|
async invoke(assetId, input, options) {
|
|
2296
|
-
if (this.venue.privateJobs) {
|
|
2490
|
+
if (options?.private ?? this.venue.privateJobs) {
|
|
2297
2491
|
throw new CoviaError(
|
|
2298
2492
|
"Private-jobs mode requires run(): a completed private job is immediately forgotten by the venue, so a poll-style Job cannot collect its result."
|
|
2299
2493
|
);
|
|
@@ -2305,27 +2499,15 @@ var OperationManager = class {
|
|
|
2305
2499
|
if (options?.ucans) {
|
|
2306
2500
|
payload.ucans = options.ucans;
|
|
2307
2501
|
}
|
|
2308
|
-
const response = await
|
|
2502
|
+
const response = await venueJson(this.venue, "/api/v1/invoke", {
|
|
2309
2503
|
method: "POST",
|
|
2310
|
-
headers: this._buildHeaders(),
|
|
2311
2504
|
body: JSON.stringify(payload)
|
|
2312
2505
|
});
|
|
2313
2506
|
return new Job(response.id ?? "", this.venue, response);
|
|
2314
2507
|
}
|
|
2315
|
-
_buildHeaders() {
|
|
2316
|
-
const headers = { "Content-Type": "application/json" };
|
|
2317
|
-
this.venue.auth.apply(headers, this.venue.venueId);
|
|
2318
|
-
return headers;
|
|
2319
|
-
}
|
|
2320
2508
|
};
|
|
2321
2509
|
|
|
2322
2510
|
// src/WorkspaceManager.ts
|
|
2323
|
-
function versionAtLeast2(version, major, minor) {
|
|
2324
|
-
const m = version?.match(/^(\d+)\.(\d+)/);
|
|
2325
|
-
if (!m) return true;
|
|
2326
|
-
const [maj, min] = [Number(m[1]), Number(m[2])];
|
|
2327
|
-
return maj > major || maj === major && min >= minor;
|
|
2328
|
-
}
|
|
2329
2511
|
var WorkspaceManager = class {
|
|
2330
2512
|
constructor(venue) {
|
|
2331
2513
|
this.venue = venue;
|
|
@@ -2333,16 +2515,11 @@ var WorkspaceManager = class {
|
|
|
2333
2515
|
// so pre-0.3 venues pay the probe once, not one failed GET per read.
|
|
2334
2516
|
this.valuesSupported = true;
|
|
2335
2517
|
}
|
|
2336
|
-
_headers() {
|
|
2337
|
-
const headers = { "Content-Type": "application/json" };
|
|
2338
|
-
this.venue.auth.apply(headers, this.venue.venueId);
|
|
2339
|
-
return headers;
|
|
2340
|
-
}
|
|
2341
2518
|
/** GET a job-free `/api/v1/values/{op}` read; omit undefined params. */
|
|
2342
2519
|
_values(op, params) {
|
|
2343
2520
|
const qs = new URLSearchParams();
|
|
2344
2521
|
for (const [k, v] of Object.entries(params)) if (v !== void 0) qs.set(k, String(v));
|
|
2345
|
-
return
|
|
2522
|
+
return venueJson(this.venue, `/api/v1/values/${op}?${qs.toString()}`);
|
|
2346
2523
|
}
|
|
2347
2524
|
/**
|
|
2348
2525
|
* Whether the venue serves `GET /api/v1/values/*`: no if a probe already
|
|
@@ -2353,40 +2530,46 @@ var WorkspaceManager = class {
|
|
|
2353
2530
|
supportsValues() {
|
|
2354
2531
|
if (!this.valuesSupported) return false;
|
|
2355
2532
|
const status = this.venue.lastKnownStatus;
|
|
2356
|
-
if (status && (!status.version || !
|
|
2533
|
+
if (status && (!status.version || !versionAtLeast(status.version, 0, 3))) {
|
|
2357
2534
|
this.valuesSupported = false;
|
|
2358
2535
|
}
|
|
2359
2536
|
return this.valuesSupported;
|
|
2360
2537
|
}
|
|
2361
|
-
|
|
2362
|
-
|
|
2538
|
+
unsupported(feature) {
|
|
2539
|
+
throw new UnsupportedVenueFeatureError(feature);
|
|
2540
|
+
}
|
|
2541
|
+
/** A job-free Values read that rejects when the endpoint is unavailable. */
|
|
2542
|
+
async valuesRead(op, params) {
|
|
2363
2543
|
if (this.supportsValues()) {
|
|
2364
2544
|
try {
|
|
2365
2545
|
return await this._values(op, params);
|
|
2366
2546
|
} catch (e) {
|
|
2367
2547
|
if (!(e instanceof NotFoundError)) throw e;
|
|
2548
|
+
if (!ROUTE_MISSING_404.test(e.message)) throw e;
|
|
2368
2549
|
this.valuesSupported = false;
|
|
2369
2550
|
}
|
|
2370
2551
|
}
|
|
2371
|
-
return
|
|
2552
|
+
return this.unsupported(`workspace ${op} reads`);
|
|
2372
2553
|
}
|
|
2373
2554
|
// ── job-free reads (#177) ───────────────────────────────────────────────────
|
|
2374
2555
|
async read(path, maxSize, ucans) {
|
|
2375
|
-
if (ucans?.length) return this.
|
|
2376
|
-
return this.
|
|
2556
|
+
if (ucans?.length) return this.unsupported("UCAN-authorised workspace reads");
|
|
2557
|
+
return this.valuesRead("read", { path, maxSize });
|
|
2377
2558
|
}
|
|
2378
2559
|
async list(path, limit, offset, ucans) {
|
|
2379
2560
|
path = path || "/";
|
|
2380
|
-
if (ucans?.length) return this.
|
|
2381
|
-
return this.
|
|
2561
|
+
if (ucans?.length) return this.unsupported("UCAN-authorised workspace listings");
|
|
2562
|
+
return this.valuesRead("list", { path, limit, offset });
|
|
2382
2563
|
}
|
|
2383
2564
|
async slice(path, offset, limit, ucans) {
|
|
2384
|
-
if (ucans?.length) return this.
|
|
2385
|
-
return this.
|
|
2565
|
+
if (ucans?.length) return this.unsupported("UCAN-authorised workspace slices");
|
|
2566
|
+
return this.valuesRead("slice", { path, offset, limit });
|
|
2386
2567
|
}
|
|
2387
2568
|
async inspect(paths, budget, compact, ucans) {
|
|
2388
|
-
if (ucans?.length || Array.isArray(paths)) return this.
|
|
2389
|
-
|
|
2569
|
+
if (ucans?.length || Array.isArray(paths)) return this.unsupported(
|
|
2570
|
+
Array.isArray(paths) ? "multi-path workspace inspection" : "UCAN-authorised workspace inspection"
|
|
2571
|
+
);
|
|
2572
|
+
return this.valuesRead("inspect", { path: paths, budget, compact });
|
|
2390
2573
|
}
|
|
2391
2574
|
/**
|
|
2392
2575
|
* Count entries at a depth below `path` — a job-free server-side tally, so the
|
|
@@ -2398,8 +2581,8 @@ var WorkspaceManager = class {
|
|
|
2398
2581
|
*/
|
|
2399
2582
|
async count(path, opts = {}) {
|
|
2400
2583
|
const { depth, ucans } = opts;
|
|
2401
|
-
if (ucans?.length) return this.
|
|
2402
|
-
return this.
|
|
2584
|
+
if (ucans?.length) return this.unsupported("UCAN-authorised workspace counts");
|
|
2585
|
+
return this.valuesRead("count", { path, depth });
|
|
2403
2586
|
}
|
|
2404
2587
|
/**
|
|
2405
2588
|
* Count entries at a depth below `path`, optionally partitioned by a field —
|
|
@@ -2411,8 +2594,8 @@ var WorkspaceManager = class {
|
|
|
2411
2594
|
*/
|
|
2412
2595
|
async aggregate(path, opts = {}) {
|
|
2413
2596
|
const { depth, groupBy, ucans } = opts;
|
|
2414
|
-
if (ucans?.length) return this.
|
|
2415
|
-
return this.
|
|
2597
|
+
if (ucans?.length) return this.unsupported("UCAN-authorised workspace aggregation");
|
|
2598
|
+
return this.valuesRead("aggregate", { path, depth, groupBy });
|
|
2416
2599
|
}
|
|
2417
2600
|
// ── writes stay on the job path (they should leave an audit record) ─────────
|
|
2418
2601
|
async write(path, value, ucans) {
|
|
@@ -2473,6 +2656,121 @@ var SecretManager = class {
|
|
|
2473
2656
|
}
|
|
2474
2657
|
};
|
|
2475
2658
|
|
|
2659
|
+
// src/SkillManager.ts
|
|
2660
|
+
var PAGE_SIZE = 100;
|
|
2661
|
+
var SkillManager = class {
|
|
2662
|
+
constructor(venue) {
|
|
2663
|
+
this.venue = venue;
|
|
2664
|
+
}
|
|
2665
|
+
/** Return every skill asset directly contained at `path`. */
|
|
2666
|
+
async list(path) {
|
|
2667
|
+
const location = path.replace(/\/+$/, "");
|
|
2668
|
+
const skills = [];
|
|
2669
|
+
let offset = 0;
|
|
2670
|
+
for (; ; ) {
|
|
2671
|
+
const page = await this.venue.workspace.list(location, PAGE_SIZE, offset);
|
|
2672
|
+
if (!page.exists) {
|
|
2673
|
+
if (skills.length === 0) return [];
|
|
2674
|
+
throw new CoviaError(`Skill listing at ${location} disappeared mid-listing`);
|
|
2675
|
+
}
|
|
2676
|
+
const keys = page.keys ?? [];
|
|
2677
|
+
const assets = await Promise.all(
|
|
2678
|
+
keys.map((key) => this.get(`${location}/${key}`))
|
|
2679
|
+
);
|
|
2680
|
+
skills.push(...assets);
|
|
2681
|
+
const nextOffset = (page.offset ?? offset) + keys.length;
|
|
2682
|
+
if (keys.length === 0 || nextOffset >= (page.count ?? nextOffset)) break;
|
|
2683
|
+
if (nextOffset <= offset) {
|
|
2684
|
+
throw new CoviaError("Venue returned a skills page that did not advance");
|
|
2685
|
+
}
|
|
2686
|
+
offset = nextOffset;
|
|
2687
|
+
}
|
|
2688
|
+
return skills;
|
|
2689
|
+
}
|
|
2690
|
+
/** Return the ordinary asset at exactly `path`, with typed skill metadata. */
|
|
2691
|
+
async get(path) {
|
|
2692
|
+
return this.venue.assets.get(path);
|
|
2693
|
+
}
|
|
2694
|
+
};
|
|
2695
|
+
|
|
2696
|
+
// src/MemoryManager.ts
|
|
2697
|
+
var DEFAULT_MEMORY_PATH = "w/memory";
|
|
2698
|
+
function memoryChange(value) {
|
|
2699
|
+
const result = record(value);
|
|
2700
|
+
if (typeof result?.n !== "number" || typeof result.count !== "number") {
|
|
2701
|
+
throw new CoviaError("Venue returned an invalid memory mutation result");
|
|
2702
|
+
}
|
|
2703
|
+
return { number: result.n, count: result.count };
|
|
2704
|
+
}
|
|
2705
|
+
var MemoryManager = class {
|
|
2706
|
+
constructor(venue) {
|
|
2707
|
+
this.venue = venue;
|
|
2708
|
+
}
|
|
2709
|
+
/**
|
|
2710
|
+
* Read memory directly from the workspace Values surface. This is job-free;
|
|
2711
|
+
* unlike `v/ops/memory {command:'recall'}`, it returns structured entries
|
|
2712
|
+
* rather than an LLM-oriented numbered text block.
|
|
2713
|
+
*/
|
|
2714
|
+
async list(path = DEFAULT_MEMORY_PATH) {
|
|
2715
|
+
const result = await this.venue.workspace.read(path);
|
|
2716
|
+
if (!result.exists) {
|
|
2717
|
+
return [];
|
|
2718
|
+
}
|
|
2719
|
+
let raw;
|
|
2720
|
+
if (result.truncated) {
|
|
2721
|
+
raw = await sliceAll(this.venue.workspace, path);
|
|
2722
|
+
} else if (result.value === void 0 || result.value === null) {
|
|
2723
|
+
return [];
|
|
2724
|
+
} else if (Array.isArray(result.value)) {
|
|
2725
|
+
raw = result.value;
|
|
2726
|
+
} else {
|
|
2727
|
+
throw new CoviaError(`Memory at ${path} is not a flat list`);
|
|
2728
|
+
}
|
|
2729
|
+
const entries = raw.map((value, index) => {
|
|
2730
|
+
const item = record(value);
|
|
2731
|
+
const text = typeof value === "string" ? value : typeof item?.text === "string" ? item.text : void 0;
|
|
2732
|
+
if (text === void 0) {
|
|
2733
|
+
throw new CoviaError(`Memory entry ${index + 1} at ${path} has no text`);
|
|
2734
|
+
}
|
|
2735
|
+
return {
|
|
2736
|
+
number: index + 1,
|
|
2737
|
+
text,
|
|
2738
|
+
createdAt: typeof item?.ts === "number" ? item.ts : void 0,
|
|
2739
|
+
updatedAt: typeof item?.updated === "number" ? item.updated : void 0
|
|
2740
|
+
};
|
|
2741
|
+
});
|
|
2742
|
+
return entries;
|
|
2743
|
+
}
|
|
2744
|
+
/** Append a memory entry. Mutations intentionally remain audited Jobs. */
|
|
2745
|
+
async remember(text, path = DEFAULT_MEMORY_PATH) {
|
|
2746
|
+
const result = await this.venue.operations.run("v/ops/memory", {
|
|
2747
|
+
command: "remember",
|
|
2748
|
+
text,
|
|
2749
|
+
path
|
|
2750
|
+
});
|
|
2751
|
+
return memoryChange(result);
|
|
2752
|
+
}
|
|
2753
|
+
/** Replace a 1-based memory entry. Mutations intentionally remain audited Jobs. */
|
|
2754
|
+
async update(number, text, path = DEFAULT_MEMORY_PATH) {
|
|
2755
|
+
const result = await this.venue.operations.run("v/ops/memory", {
|
|
2756
|
+
command: "update",
|
|
2757
|
+
n: number,
|
|
2758
|
+
text,
|
|
2759
|
+
path
|
|
2760
|
+
});
|
|
2761
|
+
return memoryChange(result);
|
|
2762
|
+
}
|
|
2763
|
+
/** Remove a 1-based memory entry. Mutations intentionally remain audited Jobs. */
|
|
2764
|
+
async forget(number, path = DEFAULT_MEMORY_PATH) {
|
|
2765
|
+
const result = await this.venue.operations.run("v/ops/memory", {
|
|
2766
|
+
command: "forget",
|
|
2767
|
+
n: number,
|
|
2768
|
+
path
|
|
2769
|
+
});
|
|
2770
|
+
return memoryChange(result);
|
|
2771
|
+
}
|
|
2772
|
+
};
|
|
2773
|
+
|
|
2476
2774
|
// src/Agent.ts
|
|
2477
2775
|
var Agent = class _Agent {
|
|
2478
2776
|
constructor(id, venue) {
|
|
@@ -2514,6 +2812,14 @@ var Agent = class _Agent {
|
|
|
2514
2812
|
async info() {
|
|
2515
2813
|
return this._agents.info(this.id);
|
|
2516
2814
|
}
|
|
2815
|
+
/** Page this agent's sessions through the job-free workspace Values API. */
|
|
2816
|
+
async listSessions(options) {
|
|
2817
|
+
return this._agents.listSessions(this.id, options);
|
|
2818
|
+
}
|
|
2819
|
+
/** Read one session through the job-free workspace Values API. */
|
|
2820
|
+
async getSession(sessionId) {
|
|
2821
|
+
return this._agents.getSession(this.id, sessionId);
|
|
2822
|
+
}
|
|
2517
2823
|
/**
|
|
2518
2824
|
* Fork this agent into a new agent.
|
|
2519
2825
|
* @param agentId - ID for the new forked agent
|
|
@@ -2598,7 +2904,11 @@ function connectionFailureMessage(venueId, attempts) {
|
|
|
2598
2904
|
}
|
|
2599
2905
|
var Venue = class _Venue {
|
|
2600
2906
|
constructor(options = {}) {
|
|
2601
|
-
|
|
2907
|
+
this._closed = false;
|
|
2908
|
+
/**
|
|
2909
|
+
* Connection-level private-jobs mode — see {@link setPrivate}.
|
|
2910
|
+
* @deprecated Pass `{ private: true }` to `operations.run()` instead.
|
|
2911
|
+
*/
|
|
2602
2912
|
this.privateJobs = false;
|
|
2603
2913
|
this.baseUrl = options.baseUrl || "";
|
|
2604
2914
|
this.venueId = options.venueId || "";
|
|
@@ -2609,6 +2919,10 @@ var Venue = class _Venue {
|
|
|
2609
2919
|
description: options.description || ""
|
|
2610
2920
|
};
|
|
2611
2921
|
}
|
|
2922
|
+
/** Whether this handle has been closed and should not be reused by Grid. */
|
|
2923
|
+
get closed() {
|
|
2924
|
+
return this._closed;
|
|
2925
|
+
}
|
|
2612
2926
|
/**
|
|
2613
2927
|
* Puts this connection in **private-jobs mode**: every subsequent
|
|
2614
2928
|
* `operations.run(...)` executes as a memory-only job (covia #192) — never
|
|
@@ -2617,7 +2931,10 @@ var Venue = class _Venue {
|
|
|
2617
2931
|
*
|
|
2618
2932
|
* Because a completed private job is immediately forgotten, results are
|
|
2619
2933
|
* collected through the invoke `wait` window rather than polling — so
|
|
2620
|
-
|
|
2934
|
+
* private mode works with `run()`; a poll-style `invoke()` throws.
|
|
2935
|
+
*
|
|
2936
|
+
* @deprecated Pass `{ private: true }` to `operations.run()` instead. The
|
|
2937
|
+
* per-call option avoids mutable connection-wide execution state.
|
|
2621
2938
|
*/
|
|
2622
2939
|
setPrivate(enabled) {
|
|
2623
2940
|
this.privateJobs = enabled;
|
|
@@ -2646,6 +2963,12 @@ var Venue = class _Venue {
|
|
|
2646
2963
|
get secrets() {
|
|
2647
2964
|
return this._secrets ?? (this._secrets = new SecretManager(this));
|
|
2648
2965
|
}
|
|
2966
|
+
get skills() {
|
|
2967
|
+
return this._skills ?? (this._skills = new SkillManager(this));
|
|
2968
|
+
}
|
|
2969
|
+
get memory() {
|
|
2970
|
+
return this._memory ?? (this._memory = new MemoryManager(this));
|
|
2971
|
+
}
|
|
2649
2972
|
/**
|
|
2650
2973
|
* Connect to a venue, validating it with `GET {base}/api/v1/status`. If the
|
|
2651
2974
|
* venue is auth-gated (status answers 401/403 — public access disabled), the
|
|
@@ -2675,7 +2998,7 @@ var Venue = class _Venue {
|
|
|
2675
2998
|
baseUrl: venueId.baseUrl,
|
|
2676
2999
|
venueId: venueId.venueId,
|
|
2677
3000
|
name: venueId.metadata.name,
|
|
2678
|
-
auth,
|
|
3001
|
+
auth: auth ?? venueId.auth,
|
|
2679
3002
|
status: venueId.lastKnownStatus
|
|
2680
3003
|
});
|
|
2681
3004
|
await connected.status();
|
|
@@ -2694,7 +3017,7 @@ var Venue = class _Venue {
|
|
|
2694
3017
|
if (typeof endpoint !== "string") {
|
|
2695
3018
|
throw new CoviaError("No (string) endpoint found for DID");
|
|
2696
3019
|
}
|
|
2697
|
-
candidates = [endpoint.replace(/\/api\/v1
|
|
3020
|
+
candidates = [stripTrailingSlash(endpoint).replace(/\/api\/v1$/, "")];
|
|
2698
3021
|
} else {
|
|
2699
3022
|
candidates = venueBaseUrlCandidates(venueId);
|
|
2700
3023
|
}
|
|
@@ -2702,7 +3025,11 @@ var Venue = class _Venue {
|
|
|
2702
3025
|
for (const baseUrl of candidates) {
|
|
2703
3026
|
const statusUrl = baseUrl + "/api/v1/status";
|
|
2704
3027
|
try {
|
|
2705
|
-
const data = await
|
|
3028
|
+
const data = await venueJson({
|
|
3029
|
+
baseUrl,
|
|
3030
|
+
venueId: expectedDid ?? "",
|
|
3031
|
+
auth: new NoAuth()
|
|
3032
|
+
}, "/api/v1/status");
|
|
2706
3033
|
if (!data.did) {
|
|
2707
3034
|
throw new CoviaError(`Venue status at ${statusUrl} did not include a DID`);
|
|
2708
3035
|
}
|
|
@@ -2787,9 +3114,10 @@ var Venue = class _Venue {
|
|
|
2787
3114
|
* @returns {Promise<string[]>}
|
|
2788
3115
|
*/
|
|
2789
3116
|
async listSecrets() {
|
|
2790
|
-
const result = await
|
|
2791
|
-
|
|
2792
|
-
|
|
3117
|
+
const result = await venueJson(
|
|
3118
|
+
this,
|
|
3119
|
+
"/api/v1/secrets"
|
|
3120
|
+
);
|
|
2793
3121
|
return Array.isArray(result.items) ? result.items : [];
|
|
2794
3122
|
}
|
|
2795
3123
|
/**
|
|
@@ -2797,9 +3125,8 @@ var Venue = class _Venue {
|
|
|
2797
3125
|
* @param name - Secret name
|
|
2798
3126
|
*/
|
|
2799
3127
|
async deleteSecret(name) {
|
|
2800
|
-
await
|
|
2801
|
-
method: "DELETE"
|
|
2802
|
-
headers: this._buildHeaders()
|
|
3128
|
+
await venueStream(this, `/api/v1/secrets/${encodeURIComponent(name)}`, {
|
|
3129
|
+
method: "DELETE"
|
|
2803
3130
|
});
|
|
2804
3131
|
}
|
|
2805
3132
|
/**
|
|
@@ -2808,7 +3135,7 @@ var Venue = class _Venue {
|
|
|
2808
3135
|
* @throws {VenueIdentityChangedError} If this address reports a different known DID.
|
|
2809
3136
|
*/
|
|
2810
3137
|
async status() {
|
|
2811
|
-
const data = await
|
|
3138
|
+
const data = await venueJson(this, "/api/v1/status");
|
|
2812
3139
|
if (data.did) {
|
|
2813
3140
|
if (this.venueId) {
|
|
2814
3141
|
assertVenueIdentity(this.venueId, data.did, this.baseUrl);
|
|
@@ -2876,7 +3203,8 @@ var Venue = class _Venue {
|
|
|
2876
3203
|
* Clears cached asset data for this venue.
|
|
2877
3204
|
*/
|
|
2878
3205
|
close() {
|
|
2879
|
-
this.
|
|
3206
|
+
this._closed = true;
|
|
3207
|
+
this._assets?.clearCache();
|
|
2880
3208
|
}
|
|
2881
3209
|
/**
|
|
2882
3210
|
* Disposable support — allows `using venue = await Grid.connect(...)` in TS 5.2+.
|
|
@@ -2884,15 +3212,28 @@ var Venue = class _Venue {
|
|
|
2884
3212
|
[Symbol.dispose]() {
|
|
2885
3213
|
this.close();
|
|
2886
3214
|
}
|
|
2887
|
-
_buildHeaders() {
|
|
2888
|
-
const headers = { "Content-Type": "application/json" };
|
|
2889
|
-
this.auth.apply(headers, this.venueId);
|
|
2890
|
-
return headers;
|
|
2891
|
-
}
|
|
2892
3215
|
};
|
|
2893
3216
|
|
|
2894
3217
|
// src/Grid.ts
|
|
2895
|
-
var
|
|
3218
|
+
var anonymousConnections = /* @__PURE__ */ new Map();
|
|
3219
|
+
var authenticatedConnections = /* @__PURE__ */ new WeakMap();
|
|
3220
|
+
function connectionsFor(auth) {
|
|
3221
|
+
if (!auth) return anonymousConnections;
|
|
3222
|
+
let connections = authenticatedConnections.get(auth);
|
|
3223
|
+
if (!connections) {
|
|
3224
|
+
connections = /* @__PURE__ */ new Map();
|
|
3225
|
+
authenticatedConnections.set(auth, connections);
|
|
3226
|
+
}
|
|
3227
|
+
return connections;
|
|
3228
|
+
}
|
|
3229
|
+
function normaliseKey(venueId) {
|
|
3230
|
+
return venueId.replace(/\/+$/, "");
|
|
3231
|
+
}
|
|
3232
|
+
function removeEntry(cache, entry) {
|
|
3233
|
+
for (const [key, candidate] of cache) {
|
|
3234
|
+
if (candidate === entry) cache.delete(key);
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
2896
3237
|
var Grid = class {
|
|
2897
3238
|
/**
|
|
2898
3239
|
* Static method to connect to a venue
|
|
@@ -2901,12 +3242,27 @@ var Grid = class {
|
|
|
2901
3242
|
* @returns {Promise<Venue>} A new Venue instance configured appropriately
|
|
2902
3243
|
*/
|
|
2903
3244
|
static async connect(venueId, auth) {
|
|
2904
|
-
const
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
3245
|
+
const cache = connectionsFor(auth);
|
|
3246
|
+
const key = normaliseKey(venueId);
|
|
3247
|
+
const cached = cache.get(key);
|
|
3248
|
+
if (cached) {
|
|
3249
|
+
if (!cached.venue?.closed) return cached.promise;
|
|
3250
|
+
removeEntry(cache, cached);
|
|
3251
|
+
}
|
|
3252
|
+
const entry = {};
|
|
3253
|
+
entry.promise = Venue.connect(venueId, auth).then((venue) => {
|
|
3254
|
+
entry.venue = venue;
|
|
3255
|
+
cache.set(normaliseKey(venue.baseUrl), entry);
|
|
3256
|
+
if (key.startsWith("did:")) {
|
|
3257
|
+
cache.set(normaliseKey(venue.venueId), entry);
|
|
3258
|
+
}
|
|
3259
|
+
return venue;
|
|
3260
|
+
}).catch((error) => {
|
|
3261
|
+
removeEntry(cache, entry);
|
|
3262
|
+
throw error;
|
|
3263
|
+
});
|
|
3264
|
+
cache.set(key, entry);
|
|
3265
|
+
return entry.promise;
|
|
2910
3266
|
}
|
|
2911
3267
|
};
|
|
2912
3268
|
|
|
@@ -2952,6 +3308,7 @@ function relayDelegation(privateKey, venueDID, lifetimeSeconds, caps = []) {
|
|
|
2952
3308
|
exports.AdapterManager = AdapterManager;
|
|
2953
3309
|
exports.Agent = Agent;
|
|
2954
3310
|
exports.AgentManager = AgentManager;
|
|
3311
|
+
exports.AgentSessionNotFoundError = AgentSessionNotFoundError;
|
|
2955
3312
|
exports.AgentStatus = AgentStatus;
|
|
2956
3313
|
exports.Asset = Asset;
|
|
2957
3314
|
exports.AssetManager = AssetManager;
|
|
@@ -2974,6 +3331,7 @@ exports.JobManager = JobManager;
|
|
|
2974
3331
|
exports.JobNotFoundError = JobNotFoundError;
|
|
2975
3332
|
exports.JobStatus = JobStatus;
|
|
2976
3333
|
exports.KeyPairAuth = KeyPairAuth;
|
|
3334
|
+
exports.MemoryManager = MemoryManager;
|
|
2977
3335
|
exports.Namespace = Namespace;
|
|
2978
3336
|
exports.NoAuth = NoAuth;
|
|
2979
3337
|
exports.NotFoundError = NotFoundError;
|
|
@@ -2982,7 +3340,9 @@ exports.OperationManager = OperationManager;
|
|
|
2982
3340
|
exports.RateLimitError = RateLimitError;
|
|
2983
3341
|
exports.RunStatus = RunStatus;
|
|
2984
3342
|
exports.SecretManager = SecretManager;
|
|
3343
|
+
exports.SkillManager = SkillManager;
|
|
2985
3344
|
exports.UCANManager = UCANManager;
|
|
3345
|
+
exports.UnsupportedVenueFeatureError = UnsupportedVenueFeatureError;
|
|
2986
3346
|
exports.VENUE_RELAY = VENUE_RELAY;
|
|
2987
3347
|
exports.Venue = Venue;
|
|
2988
3348
|
exports.VenueIdentityChangedError = VenueIdentityChangedError;
|