@letta-ai/letta-agent-sdk 0.2.4 → 0.2.5

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.js CHANGED
@@ -1354,6 +1354,249 @@ ${stderr}` : "";
1354
1354
  }
1355
1355
  }
1356
1356
 
1357
+ // src/repositories.ts
1358
+ var DEFAULT_CLOUD_API_BASE_URL = "https://api.letta.com";
1359
+ function getDefaultApiKey() {
1360
+ const env = globalThis.process?.env;
1361
+ return env?.LETTA_API_KEY ?? env?.LETTA_CLOUD_API_KEY;
1362
+ }
1363
+ function bearerTokenFromHeaders(headers) {
1364
+ const authorization = headers?.Authorization ?? headers?.authorization;
1365
+ if (!authorization)
1366
+ return;
1367
+ const match = /^Bearer\s+(.+)$/i.exec(authorization);
1368
+ return match?.[1];
1369
+ }
1370
+ function getCloudApiKey(options) {
1371
+ return options.apiKey ?? bearerTokenFromHeaders(options.headers) ?? getDefaultApiKey();
1372
+ }
1373
+ function getFetch(fetchOverride) {
1374
+ const resolved = fetchOverride ?? globalThis.fetch;
1375
+ if (!resolved)
1376
+ throw new Error("No fetch implementation available for cloud backend.");
1377
+ return resolved.bind(globalThis);
1378
+ }
1379
+ function normalizeCloudApiBaseUrl(url) {
1380
+ const parsed = new URL(url ?? DEFAULT_CLOUD_API_BASE_URL);
1381
+ parsed.pathname = parsed.pathname.replace(/\/+$/, "");
1382
+ parsed.search = "";
1383
+ parsed.hash = "";
1384
+ return parsed.toString().replace(/\/$/, "");
1385
+ }
1386
+ function cloudHeaders(options) {
1387
+ const headers = {
1388
+ "Content-Type": "application/json",
1389
+ ...options.headers ?? {}
1390
+ };
1391
+ const apiKey = getCloudApiKey(options);
1392
+ if (apiKey && !headers.Authorization && !headers.authorization) {
1393
+ headers.Authorization = `Bearer ${apiKey}`;
1394
+ }
1395
+ return headers;
1396
+ }
1397
+ async function parseJsonResponse(response) {
1398
+ const text = await response.text();
1399
+ if (!text)
1400
+ return null;
1401
+ try {
1402
+ return JSON.parse(text);
1403
+ } catch {
1404
+ return text;
1405
+ }
1406
+ }
1407
+ function responseErrorMessage(body, fallback) {
1408
+ if (body && typeof body === "object") {
1409
+ const record = body;
1410
+ const message = record.message ?? record.error ?? record.detail;
1411
+ const reasonText = record.reason_text;
1412
+ const pieces = [message, reasonText].filter((value) => typeof value === "string" && value.length > 0);
1413
+ if (pieces.length > 0)
1414
+ return pieces.join(": ");
1415
+ }
1416
+ return fallback;
1417
+ }
1418
+ function assertOkResponse(response, body, action) {
1419
+ if (!response.ok) {
1420
+ throw new Error(responseErrorMessage(body, `${action} failed with HTTP ${response.status}`));
1421
+ }
1422
+ }
1423
+ function optionalString(value) {
1424
+ return typeof value === "string" ? value : undefined;
1425
+ }
1426
+ function requireString(value, name) {
1427
+ if (typeof value !== "string")
1428
+ throw new Error(`Cloud repositories response missing ${name}.`);
1429
+ return value;
1430
+ }
1431
+ function toRepository(body) {
1432
+ if (!body || typeof body !== "object") {
1433
+ throw new Error("Cloud repositories response did not include a repository.");
1434
+ }
1435
+ const record = body;
1436
+ return {
1437
+ id: requireString(record.id, "id"),
1438
+ name: requireString(record.name, "name"),
1439
+ createdAt: requireString(record.created_at, "created_at"),
1440
+ updatedAt: requireString(record.updated_at, "updated_at")
1441
+ };
1442
+ }
1443
+ function toFileMutation(body) {
1444
+ if (!body || typeof body !== "object") {
1445
+ throw new Error("Cloud repositories file response did not include file details.");
1446
+ }
1447
+ const record = body;
1448
+ return {
1449
+ path: requireString(record.path, "path"),
1450
+ contentSha256: requireString(record.content_sha256, "content_sha256"),
1451
+ commitSha: requireString(record.commit_sha, "commit_sha")
1452
+ };
1453
+ }
1454
+ function addOptionalSearchParam(url, key, value) {
1455
+ if (value !== undefined)
1456
+ url.searchParams.set(key, String(value));
1457
+ }
1458
+
1459
+ class RepositoriesClient {
1460
+ options;
1461
+ constructor(options) {
1462
+ this.options = options;
1463
+ }
1464
+ async create(params) {
1465
+ return toRepository(await this.request("/v1/repositories", "POST", { name: params.name }, "Cloud create repository"));
1466
+ }
1467
+ async list(params = {}) {
1468
+ const url = this.url("/v1/repositories");
1469
+ addOptionalSearchParam(url, "limit", params.limit);
1470
+ addOptionalSearchParam(url, "offset", params.offset);
1471
+ const body = await this.requestUrl(url, "GET", undefined, "Cloud list repositories");
1472
+ if (!body || typeof body !== "object") {
1473
+ throw new Error("Cloud list repositories response did not include repositories.");
1474
+ }
1475
+ const record = body;
1476
+ const repositories = Array.isArray(record.repositories) ? record.repositories.map(toRepository) : [];
1477
+ return {
1478
+ repositories,
1479
+ hasNextPage: record.has_next_page === true
1480
+ };
1481
+ }
1482
+ async get(repositoryId) {
1483
+ return toRepository(await this.request(`/v1/repositories/${encodeURIComponent(repositoryId)}`, "GET", undefined, "Cloud get repository"));
1484
+ }
1485
+ async delete(repositoryId) {
1486
+ await this.request(`/v1/repositories/${encodeURIComponent(repositoryId)}`, "DELETE", undefined, "Cloud delete repository");
1487
+ }
1488
+ files = {
1489
+ list: async (repositoryId, params = {}) => {
1490
+ const url = this.url(`/v1/repositories/${encodeURIComponent(repositoryId)}/files`);
1491
+ addOptionalSearchParam(url, "path_prefix", params.pathPrefix);
1492
+ addOptionalSearchParam(url, "depth", params.depth);
1493
+ addOptionalSearchParam(url, "ref", params.ref);
1494
+ const body = await this.requestUrl(url, "GET", undefined, "Cloud list repository files");
1495
+ if (!body || typeof body !== "object") {
1496
+ throw new Error("Cloud list repository files response did not include files.");
1497
+ }
1498
+ const record = body;
1499
+ const files = Array.isArray(record.files) ? record.files.map((entry) => {
1500
+ if (!entry || typeof entry !== "object") {
1501
+ throw new Error("Cloud list repository files response included an invalid file entry.");
1502
+ }
1503
+ const file = entry;
1504
+ const type = file.type;
1505
+ if (type !== "file" && type !== "directory") {
1506
+ throw new Error("Cloud list repository files response included an invalid file type.");
1507
+ }
1508
+ return { path: requireString(file.path, "path"), type };
1509
+ }) : [];
1510
+ return { files, ref: requireString(record.ref, "ref") };
1511
+ },
1512
+ create: async (repositoryId, params) => toFileMutation(await this.request(`/v1/repositories/${encodeURIComponent(repositoryId)}/files`, "POST", { path: params.path, content: params.content }, "Cloud create repository file")),
1513
+ read: async (repositoryId, params) => {
1514
+ const url = this.url(`/v1/repositories/${encodeURIComponent(repositoryId)}/files/content`);
1515
+ url.searchParams.set("path", params.path);
1516
+ addOptionalSearchParam(url, "ref", params.ref);
1517
+ const body = await this.requestUrl(url, "GET", undefined, "Cloud read repository file");
1518
+ if (!body || typeof body !== "object") {
1519
+ throw new Error("Cloud read repository file response did not include file content.");
1520
+ }
1521
+ const record = body;
1522
+ return {
1523
+ path: requireString(record.path, "path"),
1524
+ content: requireString(record.content, "content"),
1525
+ contentSha256: requireString(record.content_sha256, "content_sha256"),
1526
+ ref: optionalString(record.ref)
1527
+ };
1528
+ },
1529
+ update: async (repositoryId, params) => toFileMutation(await this.request(`/v1/repositories/${encodeURIComponent(repositoryId)}/files/content`, "POST", {
1530
+ path: params.path,
1531
+ ...params.content !== undefined ? { content: params.content } : {},
1532
+ ...params.newPath !== undefined ? { new_path: params.newPath } : {},
1533
+ ...params.precondition !== undefined ? {
1534
+ precondition: {
1535
+ type: "content_sha256",
1536
+ content_sha256: params.precondition.contentSha256
1537
+ }
1538
+ } : {}
1539
+ }, "Cloud update repository file")),
1540
+ delete: async (repositoryId, params) => {
1541
+ const body = await this.request(`/v1/repositories/${encodeURIComponent(repositoryId)}/files/content`, "DELETE", { path: params.path }, "Cloud delete repository file");
1542
+ if (!body || typeof body !== "object") {
1543
+ throw new Error("Cloud delete repository file response did not include delete details.");
1544
+ }
1545
+ const record = body;
1546
+ return { success: record.success === true, commitSha: requireString(record.commit_sha, "commit_sha") };
1547
+ }
1548
+ };
1549
+ versions = {
1550
+ list: async (repositoryId, params = {}) => {
1551
+ const url = this.url(`/v1/repositories/${encodeURIComponent(repositoryId)}/versions`);
1552
+ addOptionalSearchParam(url, "path", params.path);
1553
+ addOptionalSearchParam(url, "limit", params.limit);
1554
+ const body = await this.requestUrl(url, "GET", undefined, "Cloud list repository versions");
1555
+ if (Array.isArray(body))
1556
+ return body;
1557
+ if (body && typeof body === "object") {
1558
+ const record = body;
1559
+ if (Array.isArray(record.commits))
1560
+ return record.commits;
1561
+ if (Array.isArray(record.versions))
1562
+ return record.versions;
1563
+ }
1564
+ return [];
1565
+ },
1566
+ get: async (repositoryId, sha, params) => {
1567
+ const url = this.url(`/v1/repositories/${encodeURIComponent(repositoryId)}/versions/${encodeURIComponent(sha)}`);
1568
+ url.searchParams.set("path", params.path);
1569
+ const body = await this.requestUrl(url, "GET", undefined, "Cloud get repository version");
1570
+ if (!body || typeof body !== "object") {
1571
+ throw new Error("Cloud get repository version response did not include file content.");
1572
+ }
1573
+ const record = body;
1574
+ return {
1575
+ path: requireString(record.path, "path"),
1576
+ content: requireString(record.content, "content"),
1577
+ contentSha256: requireString(record.content_sha256, "content_sha256"),
1578
+ ref: requireString(record.sha, "sha")
1579
+ };
1580
+ }
1581
+ };
1582
+ url(path) {
1583
+ return new URL(`${normalizeCloudApiBaseUrl(this.options.apiBaseUrl)}${path}`);
1584
+ }
1585
+ async request(path, method, body, action) {
1586
+ return this.requestUrl(this.url(path), method, body, action);
1587
+ }
1588
+ async requestUrl(url, method, body, action) {
1589
+ const response = await getFetch(this.options.fetch)(url, {
1590
+ method,
1591
+ headers: cloudHeaders(this.options),
1592
+ ...body !== undefined ? { body: JSON.stringify(body) } : {}
1593
+ });
1594
+ const parsed = await parseJsonResponse(response);
1595
+ assertOkResponse(response, parsed, action);
1596
+ return parsed;
1597
+ }
1598
+ }
1599
+
1357
1600
  // node_modules/@letta-ai/letta-code/dist/app-server-client.js
1358
1601
  var DEFAULT_REQUEST_TIMEOUT_MS = 30000;
1359
1602
  var WEBSOCKET_OPEN_STATE = 1;
@@ -3479,20 +3722,20 @@ class AppServerSession extends RemoteClientSessionCore {
3479
3722
  }
3480
3723
 
3481
3724
  // src/remote.ts
3482
- function getDefaultApiKey() {
3725
+ function getDefaultApiKey2() {
3483
3726
  if (typeof process === "undefined") {
3484
3727
  return;
3485
3728
  }
3486
3729
  return process.env.LETTA_API_KEY;
3487
3730
  }
3488
3731
  function createHeaders(options) {
3489
- const apiKey = options.apiKey ?? getDefaultApiKey();
3732
+ const apiKey = options.apiKey ?? getDefaultApiKey2();
3490
3733
  return {
3491
3734
  ...apiKey ? { Authorization: `Bearer ${apiKey}` } : {},
3492
3735
  ...options.headers ?? {}
3493
3736
  };
3494
3737
  }
3495
- function getFetch(options) {
3738
+ function getFetch2(options) {
3496
3739
  const fetchImpl = options.fetch ?? globalThis.fetch;
3497
3740
  if (!fetchImpl) {
3498
3741
  throw new Error("Remote environments require a fetch implementation");
@@ -3513,7 +3756,7 @@ function ensureOnline(environment, target) {
3513
3756
  target
3514
3757
  };
3515
3758
  }
3516
- async function parseJsonResponse(response) {
3759
+ async function parseJsonResponse2(response) {
3517
3760
  const text = await response.text();
3518
3761
  const body = text ? JSON.parse(text) : null;
3519
3762
  if (!response.ok) {
@@ -3530,18 +3773,18 @@ class RemoteEnvironmentClient {
3530
3773
  constructor(options = {}) {
3531
3774
  this.options = options;
3532
3775
  this.baseUrl = normalizeBaseUrl2(options.baseUrl);
3533
- this.fetchImpl = getFetch(options);
3776
+ this.fetchImpl = getFetch2(options);
3534
3777
  }
3535
3778
  async listEnvironments() {
3536
3779
  const url = new URL(`${this.baseUrl}/v1/environments`);
3537
3780
  const response = await this.fetchImpl(url, {
3538
3781
  headers: createHeaders(this.options)
3539
3782
  });
3540
- return parseJsonResponse(response);
3783
+ return parseJsonResponse2(response);
3541
3784
  }
3542
3785
  async getEnvironmentByDeviceId(deviceId) {
3543
3786
  const response = await this.fetchImpl(`${this.baseUrl}/v1/environments/${encodeURIComponent(deviceId)}`, { headers: createHeaders(this.options) });
3544
- return parseJsonResponse(response);
3787
+ return parseJsonResponse2(response);
3545
3788
  }
3546
3789
  async resolveEnvironment(target) {
3547
3790
  if ("connectionId" in target) {
@@ -3574,7 +3817,7 @@ class RemoteEnvironmentClient {
3574
3817
  }
3575
3818
 
3576
3819
  // src/cloud-session.ts
3577
- var DEFAULT_CLOUD_API_BASE_URL = "https://api.letta.com";
3820
+ var DEFAULT_CLOUD_API_BASE_URL2 = "https://api.letta.com";
3578
3821
  var DEFAULT_TURN_TIMEOUT_MS = 120000;
3579
3822
  var DEFAULT_PING_INTERVAL_MS = 30000;
3580
3823
  var DEFAULT_SANDBOX_TTL_MINUTES = 5;
@@ -3582,25 +3825,27 @@ var MIN_SANDBOX_TTL_MINUTES = 1;
3582
3825
  var MAX_SANDBOX_TTL_MINUTES = 60;
3583
3826
  var DEFAULT_SANDBOX_READY_TIMEOUT_MS = 120000;
3584
3827
  var DEFAULT_SANDBOX_READY_POLL_INTERVAL_MS = 1000;
3828
+ var DEFAULT_REPOSITORY_ATTACH_TIMEOUT_MS = 1e4;
3829
+ var DEFAULT_REPOSITORY_ATTACH_POLL_INTERVAL_MS = 250;
3585
3830
  var SDK_AGENT_ORIGIN = "@letta-ai/letta-agent-sdk";
3586
3831
 
3587
3832
  class CloudManagedSandboxOwnershipError extends Error {
3588
3833
  }
3589
- function getDefaultApiKey2() {
3834
+ function getDefaultApiKey3() {
3590
3835
  const env = globalThis.process?.env;
3591
3836
  return env?.LETTA_API_KEY ?? env?.LETTA_CLOUD_API_KEY;
3592
3837
  }
3593
- function bearerTokenFromHeaders(headers) {
3838
+ function bearerTokenFromHeaders2(headers) {
3594
3839
  const authorization = headers?.Authorization ?? headers?.authorization;
3595
3840
  if (!authorization)
3596
3841
  return;
3597
3842
  const match = /^Bearer\s+(.+)$/i.exec(authorization);
3598
3843
  return match?.[1];
3599
3844
  }
3600
- function getCloudApiKey(options) {
3601
- return options.apiKey ?? bearerTokenFromHeaders(options.headers) ?? getDefaultApiKey2();
3845
+ function getCloudApiKey2(options) {
3846
+ return options.apiKey ?? bearerTokenFromHeaders2(options.headers) ?? getDefaultApiKey3();
3602
3847
  }
3603
- function getFetch2(fetchOverride) {
3848
+ function getFetch3(fetchOverride) {
3604
3849
  const resolved = fetchOverride ?? globalThis.fetch;
3605
3850
  if (!resolved) {
3606
3851
  throw new Error("No fetch implementation available for cloud backend.");
@@ -3614,19 +3859,19 @@ function getWebSocketConstructor(websocketOverride) {
3614
3859
  }
3615
3860
  return resolved;
3616
3861
  }
3617
- function normalizeCloudApiBaseUrl(url) {
3618
- const parsed = new URL(url ?? DEFAULT_CLOUD_API_BASE_URL);
3862
+ function normalizeCloudApiBaseUrl2(url) {
3863
+ const parsed = new URL(url ?? DEFAULT_CLOUD_API_BASE_URL2);
3619
3864
  parsed.pathname = parsed.pathname.replace(/\/+$/, "");
3620
3865
  parsed.search = "";
3621
3866
  parsed.hash = "";
3622
3867
  return parsed.toString().replace(/\/$/, "");
3623
3868
  }
3624
- function cloudHeaders(options) {
3869
+ function cloudHeaders2(options) {
3625
3870
  const headers = {
3626
3871
  "Content-Type": "application/json",
3627
3872
  ...options.headers ?? {}
3628
3873
  };
3629
- const apiKey = getCloudApiKey(options);
3874
+ const apiKey = getCloudApiKey2(options);
3630
3875
  if (apiKey && !headers.Authorization && !headers.authorization) {
3631
3876
  headers.Authorization = `Bearer ${apiKey}`;
3632
3877
  }
@@ -3636,12 +3881,12 @@ function cloudWebSocketHeaders(options) {
3636
3881
  const headers = { ...options.headers ?? {} };
3637
3882
  delete headers.authorization;
3638
3883
  delete headers.Authorization;
3639
- const apiKey = getCloudApiKey(options);
3884
+ const apiKey = getCloudApiKey2(options);
3640
3885
  if (apiKey)
3641
3886
  headers.Authorization = `Bearer ${apiKey}`;
3642
3887
  return Object.keys(headers).length > 0 ? headers : undefined;
3643
3888
  }
3644
- async function parseJsonResponse2(response) {
3889
+ async function parseJsonResponse3(response) {
3645
3890
  const text = await response.text();
3646
3891
  if (!text)
3647
3892
  return null;
@@ -3651,7 +3896,7 @@ async function parseJsonResponse2(response) {
3651
3896
  return text;
3652
3897
  }
3653
3898
  }
3654
- function responseErrorMessage(body, fallback) {
3899
+ function responseErrorMessage2(body, fallback) {
3655
3900
  if (body && typeof body === "object") {
3656
3901
  const record = body;
3657
3902
  const message = record.message ?? record.error ?? record.detail;
@@ -3662,9 +3907,9 @@ function responseErrorMessage(body, fallback) {
3662
3907
  }
3663
3908
  return fallback;
3664
3909
  }
3665
- function assertOkResponse(response, body, action) {
3910
+ function assertOkResponse2(response, body, action) {
3666
3911
  if (!response.ok) {
3667
- throw new Error(responseErrorMessage(body, `${action} failed with HTTP ${response.status}`));
3912
+ throw new Error(responseErrorMessage2(body, `${action} failed with HTTP ${response.status}`));
3668
3913
  }
3669
3914
  }
3670
3915
  function validatePositiveInteger(value, name) {
@@ -3724,7 +3969,7 @@ function environmentToRemoteTarget(environment) {
3724
3969
  throw new Error("Unknown cloud environment selector.");
3725
3970
  }
3726
3971
  function buildCloudStatusWebSocketUrl(params) {
3727
- const base = new URL(normalizeCloudApiBaseUrl(params.apiBaseUrl));
3972
+ const base = new URL(normalizeCloudApiBaseUrl2(params.apiBaseUrl));
3728
3973
  if (base.protocol === "http:") {
3729
3974
  base.protocol = "ws:";
3730
3975
  } else if (base.protocol === "https:") {
@@ -3771,7 +4016,7 @@ function messageEventData(event) {
3771
4016
  function createCloudStatusWebSocketConstructor(params) {
3772
4017
  const WebSocketCtor = getWebSocketConstructor(params.cloudOptions.WebSocket);
3773
4018
  const authMode = params.cloudOptions.webSocketAuth ?? "header";
3774
- const cloudHeaders2 = authMode === "header" ? cloudWebSocketHeaders(params.cloudOptions) : undefined;
4019
+ const cloudHeaders3 = authMode === "header" ? cloudWebSocketHeaders(params.cloudOptions) : undefined;
3775
4020
  const pingIntervalMs = params.cloudOptions.pingIntervalMs ?? DEFAULT_PING_INTERVAL_MS;
3776
4021
  const state = {
3777
4022
  runtime: params.runtime,
@@ -3791,7 +4036,7 @@ function createCloudStatusWebSocketConstructor(params) {
3791
4036
  this.channel = new URL(url).searchParams.get("channel");
3792
4037
  const mergedHeaders = authMode === "header" ? {
3793
4038
  ...options?.headers ?? {},
3794
- ...cloudHeaders2 ?? {}
4039
+ ...cloudHeaders3 ?? {}
3795
4040
  } : undefined;
3796
4041
  const socketOptions = mergedHeaders && Object.keys(mergedHeaders).length > 0 ? { headers: mergedHeaders } : undefined;
3797
4042
  this.socket = new WebSocketCtor(url, socketOptions);
@@ -3951,10 +4196,10 @@ function externalToolsByName(tools) {
3951
4196
  }
3952
4197
  function cloudHarnessAppServerOptions(clientOptions) {
3953
4198
  const appServer = clientOptions.appServer;
3954
- const apiKey = getCloudApiKey(clientOptions);
4199
+ const apiKey = getCloudApiKey2(clientOptions);
3955
4200
  const localEnv = {
3956
4201
  ...apiKey ? { LETTA_API_KEY: apiKey } : {},
3957
- ...clientOptions.apiBaseUrl ? { LETTA_BASE_URL: normalizeCloudApiBaseUrl(clientOptions.apiBaseUrl) } : {}
4202
+ ...clientOptions.apiBaseUrl ? { LETTA_BASE_URL: normalizeCloudApiBaseUrl2(clientOptions.apiBaseUrl) } : {}
3958
4203
  };
3959
4204
  return {
3960
4205
  local: appServer?.url === undefined,
@@ -4013,6 +4258,7 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
4013
4258
  managedSandbox = null;
4014
4259
  sandboxRefreshTimer = null;
4015
4260
  sandboxRefreshInFlight = null;
4261
+ attachedRepositoryIds = new Set;
4016
4262
  cloudMode;
4017
4263
  constructor(cloudOptions, mode) {
4018
4264
  super(mode, {
@@ -4028,7 +4274,7 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
4028
4274
  const resolved = await this.resolveRuntime();
4029
4275
  const connection = await this.resolveConnectionForRuntime(resolved.runtime);
4030
4276
  this.connectionId = connection.connectionId;
4031
- const apiKey = getCloudApiKey(this.cloudOptions);
4277
+ const apiKey = getCloudApiKey2(this.cloudOptions);
4032
4278
  const url = buildCloudStatusWebSocketUrl({
4033
4279
  apiBaseUrl: this.cloudOptions.apiBaseUrl,
4034
4280
  connectionId: connection.connectionId,
@@ -4076,6 +4322,7 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
4076
4322
  this.removeControlRequestHandler = null;
4077
4323
  client.close();
4078
4324
  await this.cleanupManagedSandbox();
4325
+ await this.cleanupSessionRepositories(resolved.runtime.agent_id);
4079
4326
  throw error;
4080
4327
  }
4081
4328
  }
@@ -4123,16 +4370,12 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
4123
4370
  this.removeControlRequestHandler?.();
4124
4371
  this.removeControlRequestHandler = null;
4125
4372
  this.cleanupManagedSandbox();
4373
+ if (this.runtime?.agent_id)
4374
+ this.cleanupSessionRepositories(this.runtime.agent_id);
4126
4375
  }
4127
4376
  async resolveRuntime() {
4128
4377
  let agentId = this.cloudMode.agentId;
4129
4378
  let conversationId = this.cloudMode.conversationId;
4130
- if (agentId && this.cloudMode.newConversation) {
4131
- const conversation = await this.createConversation(agentId);
4132
- conversationId = conversation.id;
4133
- } else if (agentId && this.cloudMode.defaultConversation) {
4134
- conversationId = "default";
4135
- }
4136
4379
  if (!agentId && conversationId) {
4137
4380
  const conversation = await this.retrieveConversation(conversationId);
4138
4381
  if (!conversation.agent_id) {
@@ -4140,34 +4383,134 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
4140
4383
  }
4141
4384
  agentId = conversation.agent_id;
4142
4385
  }
4143
- if (!agentId || !conversationId) {
4386
+ if (!agentId) {
4387
+ throw new Error("Constellation createSession()/resumeSession() requires an agent id or conversation id.");
4388
+ }
4389
+ await this.attachSessionRepositories(agentId);
4390
+ if (this.cloudMode.newConversation) {
4391
+ const conversation = await this.createConversation(agentId);
4392
+ conversationId = conversation.id;
4393
+ } else if (this.cloudMode.defaultConversation) {
4394
+ conversationId = "default";
4395
+ }
4396
+ if (!conversationId) {
4144
4397
  throw new Error("Constellation createSession()/resumeSession() requires an agent id or conversation id.");
4145
4398
  }
4146
4399
  return { runtime: { agent_id: agentId, conversation_id: conversationId } };
4147
4400
  }
4401
+ async attachSessionRepositories(agentId) {
4402
+ const resources = this.repositoryResources();
4403
+ if (resources.length === 0)
4404
+ return;
4405
+ const existing = await this.listAgentRepositories(agentId);
4406
+ const existingIds = new Set(existing.map((repository) => repository.id));
4407
+ try {
4408
+ for (const resource of resources) {
4409
+ if (existingIds.has(resource.repositoryId) || this.attachedRepositoryIds.has(resource.repositoryId)) {
4410
+ continue;
4411
+ }
4412
+ await this.linkAgentRepository(agentId, resource.repositoryId);
4413
+ await this.waitForAgentRepository(agentId, resource.repositoryId);
4414
+ this.attachedRepositoryIds.add(resource.repositoryId);
4415
+ }
4416
+ } catch (error) {
4417
+ await this.cleanupSessionRepositories(agentId);
4418
+ throw error;
4419
+ }
4420
+ }
4421
+ async cleanupSessionRepositories(agentId) {
4422
+ const repositoryIds = [...this.attachedRepositoryIds];
4423
+ this.attachedRepositoryIds.clear();
4424
+ await Promise.all(repositoryIds.map(async (repositoryId) => {
4425
+ try {
4426
+ await this.unlinkAgentRepository(agentId, repositoryId);
4427
+ } catch {}
4428
+ }));
4429
+ }
4430
+ repositoryResources() {
4431
+ const resources = this.cloudMode.options.resources ?? [];
4432
+ const seen = new Set;
4433
+ const result = [];
4434
+ for (const resource of resources) {
4435
+ if (resource.type !== "repository") {
4436
+ throw new Error(`Unsupported Cloud session resource type: ${String(resource.type)}`);
4437
+ }
4438
+ if (typeof resource.repositoryId !== "string" || resource.repositoryId.length === 0) {
4439
+ throw new Error("Cloud session repository resources require repositoryId.");
4440
+ }
4441
+ if (seen.has(resource.repositoryId))
4442
+ continue;
4443
+ seen.add(resource.repositoryId);
4444
+ result.push(resource);
4445
+ }
4446
+ return result;
4447
+ }
4448
+ async listAgentRepositories(agentId) {
4449
+ const fetchImpl = getFetch3(this.cloudOptions.fetch);
4450
+ const baseUrl = normalizeCloudApiBaseUrl2(this.cloudOptions.apiBaseUrl);
4451
+ const response = await fetchImpl(`${baseUrl}/v1/agents/${encodeURIComponent(agentId)}/repositories`, { headers: cloudHeaders2(this.cloudOptions) });
4452
+ const body = await parseJsonResponse3(response);
4453
+ assertOkResponse2(response, body, "Cloud list agent repositories");
4454
+ if (!body || typeof body !== "object")
4455
+ return [];
4456
+ const repositories = body.repositories;
4457
+ return Array.isArray(repositories) ? repositories.filter((repository) => repository !== null && typeof repository === "object" && typeof repository.id === "string") : [];
4458
+ }
4459
+ async waitForAgentRepository(agentId, repositoryId) {
4460
+ const deadline = Date.now() + DEFAULT_REPOSITORY_ATTACH_TIMEOUT_MS;
4461
+ while (true) {
4462
+ const repositories = await this.listAgentRepositories(agentId);
4463
+ if (repositories.some((repository) => repository.id === repositoryId))
4464
+ return;
4465
+ if (Date.now() >= deadline) {
4466
+ throw new Error(`Cloud attach agent repository did not become visible for ${agentId}: ${repositoryId}`);
4467
+ }
4468
+ await sleep(DEFAULT_REPOSITORY_ATTACH_POLL_INTERVAL_MS);
4469
+ }
4470
+ }
4471
+ async linkAgentRepository(agentId, repositoryId) {
4472
+ const fetchImpl = getFetch3(this.cloudOptions.fetch);
4473
+ const baseUrl = normalizeCloudApiBaseUrl2(this.cloudOptions.apiBaseUrl);
4474
+ const response = await fetchImpl(`${baseUrl}/v1/agents/${encodeURIComponent(agentId)}/repositories`, {
4475
+ method: "POST",
4476
+ headers: cloudHeaders2(this.cloudOptions),
4477
+ body: JSON.stringify({ repository_id: repositoryId })
4478
+ });
4479
+ const body = await parseJsonResponse3(response);
4480
+ assertOkResponse2(response, body, "Cloud attach agent repository");
4481
+ }
4482
+ async unlinkAgentRepository(agentId, repositoryId) {
4483
+ const fetchImpl = getFetch3(this.cloudOptions.fetch);
4484
+ const baseUrl = normalizeCloudApiBaseUrl2(this.cloudOptions.apiBaseUrl);
4485
+ const response = await fetchImpl(`${baseUrl}/v1/agents/${encodeURIComponent(agentId)}/repositories/${encodeURIComponent(repositoryId)}`, { method: "DELETE", headers: cloudHeaders2(this.cloudOptions) });
4486
+ const body = await parseJsonResponse3(response);
4487
+ if (response.status === 404)
4488
+ return;
4489
+ assertOkResponse2(response, body, "Cloud detach agent repository");
4490
+ }
4148
4491
  async createConversation(agentId) {
4149
- const fetchImpl = getFetch2(this.cloudOptions.fetch);
4150
- const baseUrl = normalizeCloudApiBaseUrl(this.cloudOptions.apiBaseUrl);
4492
+ const fetchImpl = getFetch3(this.cloudOptions.fetch);
4493
+ const baseUrl = normalizeCloudApiBaseUrl2(this.cloudOptions.apiBaseUrl);
4151
4494
  const url = new URL(`${baseUrl}/v1/conversations/`);
4152
4495
  url.searchParams.set("agent_id", agentId);
4153
4496
  const response = await fetchImpl(url, {
4154
4497
  method: "POST",
4155
- headers: cloudHeaders(this.cloudOptions),
4498
+ headers: cloudHeaders2(this.cloudOptions),
4156
4499
  body: JSON.stringify({})
4157
4500
  });
4158
- const body = await parseJsonResponse2(response);
4159
- assertOkResponse(response, body, "Cloud createSession()");
4501
+ const body = await parseJsonResponse3(response);
4502
+ assertOkResponse2(response, body, "Cloud createSession()");
4160
4503
  if (!isCloudConversation(body)) {
4161
4504
  throw new Error("Cloud createSession() response did not include a conversation id.");
4162
4505
  }
4163
4506
  return { id: body.id, agent_id: body.agent_id };
4164
4507
  }
4165
4508
  async retrieveConversation(conversationId) {
4166
- const fetchImpl = getFetch2(this.cloudOptions.fetch);
4167
- const baseUrl = normalizeCloudApiBaseUrl(this.cloudOptions.apiBaseUrl);
4168
- const response = await fetchImpl(`${baseUrl}/v1/conversations/${encodeURIComponent(conversationId)}`, { headers: cloudHeaders(this.cloudOptions) });
4169
- const body = await parseJsonResponse2(response);
4170
- assertOkResponse(response, body, "Cloud resumeSession()");
4509
+ const fetchImpl = getFetch3(this.cloudOptions.fetch);
4510
+ const baseUrl = normalizeCloudApiBaseUrl2(this.cloudOptions.apiBaseUrl);
4511
+ const response = await fetchImpl(`${baseUrl}/v1/conversations/${encodeURIComponent(conversationId)}`, { headers: cloudHeaders2(this.cloudOptions) });
4512
+ const body = await parseJsonResponse3(response);
4513
+ assertOkResponse2(response, body, "Cloud resumeSession()");
4171
4514
  if (!isCloudConversation(body)) {
4172
4515
  throw new Error(`Cloud resumeSession() could not retrieve conversation ${conversationId}.`);
4173
4516
  }
@@ -4203,15 +4546,15 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
4203
4546
  }
4204
4547
  }
4205
4548
  async createManagedSandbox(agentId) {
4206
- const fetchImpl = getFetch2(this.cloudOptions.fetch);
4207
- const baseUrl = normalizeCloudApiBaseUrl(this.cloudOptions.apiBaseUrl);
4549
+ const fetchImpl = getFetch3(this.cloudOptions.fetch);
4550
+ const baseUrl = normalizeCloudApiBaseUrl2(this.cloudOptions.apiBaseUrl);
4208
4551
  const response = await fetchImpl(`${baseUrl}/v1/agents/${encodeURIComponent(agentId)}/sandboxes`, {
4209
4552
  method: "POST",
4210
- headers: cloudHeaders(this.cloudOptions),
4553
+ headers: cloudHeaders2(this.cloudOptions),
4211
4554
  body: JSON.stringify({})
4212
4555
  });
4213
- const body = await parseJsonResponse2(response);
4214
- assertOkResponse(response, body, "Cloud create managed sandbox");
4556
+ const body = await parseJsonResponse3(response);
4557
+ assertOkResponse2(response, body, "Cloud create managed sandbox");
4215
4558
  if (!isCloudAgentSandbox(body)) {
4216
4559
  throw new Error("Cloud create managed sandbox response did not include sandbox connection details.");
4217
4560
  }
@@ -4245,15 +4588,15 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
4245
4588
  }
4246
4589
  }
4247
4590
  async refreshManagedSandboxOnce(sandbox) {
4248
- const fetchImpl = getFetch2(this.cloudOptions.fetch);
4249
- const baseUrl = normalizeCloudApiBaseUrl(this.cloudOptions.apiBaseUrl);
4591
+ const fetchImpl = getFetch3(this.cloudOptions.fetch);
4592
+ const baseUrl = normalizeCloudApiBaseUrl2(this.cloudOptions.apiBaseUrl);
4250
4593
  const response = await fetchImpl(`${baseUrl}/v1/agents/${encodeURIComponent(sandbox.agentId)}/sandboxes/refresh`, {
4251
4594
  method: "POST",
4252
- headers: cloudHeaders(this.cloudOptions),
4595
+ headers: cloudHeaders2(this.cloudOptions),
4253
4596
  body: JSON.stringify({ ttlMinutes: sandbox.ttlMinutes })
4254
4597
  });
4255
- const body = await parseJsonResponse2(response);
4256
- assertOkResponse(response, body, "Cloud refresh managed sandbox");
4598
+ const body = await parseJsonResponse3(response);
4599
+ assertOkResponse2(response, body, "Cloud refresh managed sandbox");
4257
4600
  if (!isCloudAgentSandboxRefresh(body) || !body.success) {
4258
4601
  throw new Error("Cloud refresh managed sandbox response did not confirm refresh.");
4259
4602
  }
@@ -4263,16 +4606,16 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
4263
4606
  }
4264
4607
  async terminateManagedSandbox(sandbox) {
4265
4608
  await this.refreshManagedSandbox(sandbox);
4266
- const fetchImpl = getFetch2(this.cloudOptions.fetch);
4267
- const baseUrl = normalizeCloudApiBaseUrl(this.cloudOptions.apiBaseUrl);
4609
+ const fetchImpl = getFetch3(this.cloudOptions.fetch);
4610
+ const baseUrl = normalizeCloudApiBaseUrl2(this.cloudOptions.apiBaseUrl);
4268
4611
  const response = await fetchImpl(`${baseUrl}/v1/agents/${encodeURIComponent(sandbox.agentId)}/sandboxes`, {
4269
4612
  method: "DELETE",
4270
- headers: cloudHeaders(this.cloudOptions)
4613
+ headers: cloudHeaders2(this.cloudOptions)
4271
4614
  });
4272
- const body = await parseJsonResponse2(response);
4615
+ const body = await parseJsonResponse3(response);
4273
4616
  if (response.status === 404)
4274
4617
  return;
4275
- assertOkResponse(response, body, "Cloud terminate managed sandbox");
4618
+ assertOkResponse2(response, body, "Cloud terminate managed sandbox");
4276
4619
  }
4277
4620
  async waitForManagedSandboxConnection(sandbox) {
4278
4621
  const deadline = Date.now() + sandbox.readyTimeoutMs;
@@ -4325,7 +4668,7 @@ class CloudEnvironmentSession extends RemoteClientSessionCore {
4325
4668
  remoteEnvironmentClient() {
4326
4669
  return new RemoteEnvironmentClient({
4327
4670
  baseUrl: this.cloudOptions.apiBaseUrl,
4328
- apiKey: getCloudApiKey(this.cloudOptions),
4671
+ apiKey: getCloudApiKey2(this.cloudOptions),
4329
4672
  headers: this.cloudOptions.headers,
4330
4673
  fetch: this.cloudOptions.fetch
4331
4674
  });
@@ -4486,6 +4829,9 @@ function stripCloudExecutionOptions(options) {
4486
4829
  delete sessionOptions.sandbox;
4487
4830
  return sessionOptions;
4488
4831
  }
4832
+ function hasRepositoryResources(options) {
4833
+ return options.resources !== undefined && options.resources.length > 0;
4834
+ }
4489
4835
  function hasCreateAgentEnvironment(options) {
4490
4836
  return "environment" in options;
4491
4837
  }
@@ -4500,6 +4846,7 @@ class LettaAgentClient {
4500
4846
  backend;
4501
4847
  environment;
4502
4848
  options;
4849
+ repositoriesClient = null;
4503
4850
  constructor(options = {}) {
4504
4851
  const backend = options.backend ?? "local";
4505
4852
  if (!isLettaCodeBackend(backend)) {
@@ -4543,6 +4890,9 @@ class LettaAgentClient {
4543
4890
  validateCloudClientOptions(options);
4544
4891
  }
4545
4892
  }
4893
+ get repositories() {
4894
+ return this.getRepositoriesClient();
4895
+ }
4546
4896
  async createAgent(options = {}) {
4547
4897
  if (hasCreateAgentEnvironment(options)) {
4548
4898
  throw new Error("createAgent() does not accept environment. Set a client default or pass environment to resumeSession()/createSession().");
@@ -4700,6 +5050,9 @@ class LettaAgentClient {
4700
5050
  if (options.sandbox !== undefined) {
4701
5051
  throw new Error(`${action}() sandbox options are only valid with backend: "cloud".`);
4702
5052
  }
5053
+ if (hasRepositoryResources(options)) {
5054
+ throw new Error(`${action}() repository resources are only valid with backend: "cloud".`);
5055
+ }
4703
5056
  if (!this.useLegacyLocalStdio()) {
4704
5057
  assertRemoteSessionOptionsSupported(action, options);
4705
5058
  }
@@ -4712,6 +5065,9 @@ class LettaAgentClient {
4712
5065
  if (options.sandbox !== undefined) {
4713
5066
  throw new Error(`${action}() sandbox options are only valid with backend: "cloud"; remote url selects the app-server runtime.`);
4714
5067
  }
5068
+ if (hasRepositoryResources(options)) {
5069
+ throw new Error(`${action}() repository resources are only valid with backend: "cloud".`);
5070
+ }
4715
5071
  assertRemoteSessionOptionsSupported(action, options);
4716
5072
  return;
4717
5073
  }
@@ -4750,6 +5106,13 @@ class LettaAgentClient {
4750
5106
  }
4751
5107
  return this.options;
4752
5108
  }
5109
+ getRepositoriesClient() {
5110
+ if (this.backend !== "cloud") {
5111
+ throw new Error('client.repositories is only available with backend: "cloud".');
5112
+ }
5113
+ this.repositoriesClient ??= new RepositoriesClient(this.cloudOptions());
5114
+ return this.repositoriesClient;
5115
+ }
4753
5116
  cloudOptions() {
4754
5117
  if (this.backend !== "cloud") {
4755
5118
  throw new Error('Constellation options requested for non-"cloud" backend.');
@@ -4995,7 +5358,8 @@ export {
4995
5358
  createSession,
4996
5359
  createAgent,
4997
5360
  Session,
5361
+ RepositoriesClient,
4998
5362
  LettaAgentClient
4999
5363
  };
5000
5364
 
5001
- //# debugId=380F2F63E2AF857764756E2164756E21
5365
+ //# debugId=7B3400A69740F48F64756E2164756E21