@axiom-lattice/core 2.1.73 → 2.1.74

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.mjs CHANGED
@@ -3059,6 +3059,168 @@ var PostgresDatabase = class {
3059
3059
  }
3060
3060
  }
3061
3061
  };
3062
+ var MysqlDatabase = class {
3063
+ constructor(config) {
3064
+ // mysql2.Pool
3065
+ this.connected = false;
3066
+ this.config = config;
3067
+ }
3068
+ async connect() {
3069
+ if (this.connected && this.pool) return;
3070
+ try {
3071
+ const mysql = await import("mysql2/promise");
3072
+ const poolConfig = this.config.connectionString ? { uri: this.config.connectionString } : {
3073
+ host: this.config.host || "localhost",
3074
+ port: this.config.port || 3306,
3075
+ database: this.config.database,
3076
+ user: this.config.user,
3077
+ password: this.config.password,
3078
+ ssl: this.config.ssl ? { rejectUnauthorized: false } : void 0
3079
+ };
3080
+ this.pool = mysql.createPool({
3081
+ ...poolConfig,
3082
+ waitForConnections: true,
3083
+ connectionLimit: 10,
3084
+ maxIdle: 10,
3085
+ idleTimeout: 6e4,
3086
+ queueLimit: 0,
3087
+ enableKeepAlive: true,
3088
+ keepAliveInitialDelay: 0
3089
+ });
3090
+ const connection = await this.pool.getConnection();
3091
+ try {
3092
+ await connection.query("SELECT 1");
3093
+ } finally {
3094
+ connection.release();
3095
+ }
3096
+ this.connected = true;
3097
+ } catch (error) {
3098
+ this.connected = false;
3099
+ throw new Error(`Failed to connect to MySQL: ${error}`);
3100
+ }
3101
+ }
3102
+ async disconnect() {
3103
+ if (this.pool) {
3104
+ try {
3105
+ await this.pool.end();
3106
+ } catch (error) {
3107
+ console.warn("Warning: Error closing MySQL pool:", error);
3108
+ } finally {
3109
+ this.pool = null;
3110
+ this.connected = false;
3111
+ }
3112
+ }
3113
+ }
3114
+ async listTables() {
3115
+ await this.ensureConnected();
3116
+ const query = `
3117
+ SELECT TABLE_NAME, TABLE_SCHEMA
3118
+ FROM information_schema.TABLES
3119
+ WHERE TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
3120
+ AND TABLE_SCHEMA = DATABASE()
3121
+ AND TABLE_TYPE = 'BASE TABLE'
3122
+ ORDER BY TABLE_SCHEMA, TABLE_NAME
3123
+ `;
3124
+ const [rows] = await this.pool.query(query);
3125
+ return rows.map((row) => ({
3126
+ name: row.TABLE_NAME,
3127
+ schema: row.TABLE_SCHEMA
3128
+ }));
3129
+ }
3130
+ async getTableInfo(tables) {
3131
+ await this.ensureConnected();
3132
+ const schemas = [];
3133
+ for (const tableName of tables) {
3134
+ const rawName = tableName.includes(".") ? tableName.split(".").pop() : tableName;
3135
+ const columnQuery = `
3136
+ SELECT
3137
+ c.COLUMN_NAME,
3138
+ c.DATA_TYPE,
3139
+ c.IS_NULLABLE,
3140
+ c.COLUMN_DEFAULT
3141
+ FROM information_schema.COLUMNS c
3142
+ WHERE c.TABLE_NAME = ?
3143
+ AND c.TABLE_SCHEMA = DATABASE()
3144
+ ORDER BY c.ORDINAL_POSITION
3145
+ `;
3146
+ const pkQuery = `
3147
+ SELECT k.COLUMN_NAME
3148
+ FROM information_schema.TABLE_CONSTRAINTS t
3149
+ JOIN information_schema.KEY_COLUMN_USAGE k
3150
+ ON t.CONSTRAINT_NAME = k.CONSTRAINT_NAME
3151
+ AND t.TABLE_SCHEMA = k.TABLE_SCHEMA
3152
+ AND t.TABLE_NAME = k.TABLE_NAME
3153
+ WHERE t.CONSTRAINT_TYPE = 'PRIMARY KEY'
3154
+ AND t.TABLE_NAME = ?
3155
+ AND t.TABLE_SCHEMA = DATABASE()
3156
+ `;
3157
+ const fkQuery = `
3158
+ SELECT
3159
+ k.COLUMN_NAME,
3160
+ k.REFERENCED_TABLE_NAME,
3161
+ k.REFERENCED_COLUMN_NAME
3162
+ FROM information_schema.KEY_COLUMN_USAGE k
3163
+ WHERE k.TABLE_NAME = ?
3164
+ AND k.TABLE_SCHEMA = DATABASE()
3165
+ AND k.REFERENCED_TABLE_NAME IS NOT NULL
3166
+ `;
3167
+ const [columnRows] = await this.pool.query(columnQuery, [rawName]);
3168
+ const [pkRows] = await this.pool.query(pkQuery, [rawName]);
3169
+ const [fkRows] = await this.pool.query(fkQuery, [rawName]);
3170
+ const pkColumns = new Set(pkRows.map((r) => r.COLUMN_NAME));
3171
+ const fkMap = /* @__PURE__ */ new Map();
3172
+ for (const row of fkRows) {
3173
+ fkMap.set(row.COLUMN_NAME, {
3174
+ foreignTable: row.REFERENCED_TABLE_NAME,
3175
+ foreignColumn: row.REFERENCED_COLUMN_NAME
3176
+ });
3177
+ }
3178
+ const columns = columnRows.map((row) => {
3179
+ const fkRef = fkMap.get(row.COLUMN_NAME);
3180
+ return {
3181
+ name: row.COLUMN_NAME,
3182
+ type: row.DATA_TYPE,
3183
+ nullable: row.IS_NULLABLE === "YES",
3184
+ default: row.COLUMN_DEFAULT,
3185
+ isPrimaryKey: pkColumns.has(row.COLUMN_NAME),
3186
+ isForeignKey: fkRef !== void 0,
3187
+ foreignKeyRef: fkRef ? `${fkRef.foreignTable}.${fkRef.foreignColumn}` : void 0
3188
+ };
3189
+ });
3190
+ let sampleRows = [];
3191
+ try {
3192
+ const sampleQuery = `SELECT * FROM \`${rawName}\` LIMIT 3`;
3193
+ const [sampleResult] = await this.pool.query(sampleQuery);
3194
+ sampleRows = sampleResult;
3195
+ } catch {
3196
+ }
3197
+ schemas.push({
3198
+ tableName,
3199
+ columns,
3200
+ sampleRows
3201
+ });
3202
+ }
3203
+ return schemas;
3204
+ }
3205
+ async executeQuery(query) {
3206
+ await this.ensureConnected();
3207
+ const [rows, fields] = await this.pool.query(query);
3208
+ const isSelectResult = Array.isArray(rows);
3209
+ return {
3210
+ rows: isSelectResult ? rows : [],
3211
+ rowCount: isSelectResult ? rows.length : rows.affectedRows || 0,
3212
+ fields: fields?.map((f) => f.name)
3213
+ };
3214
+ }
3215
+ getDatabaseType() {
3216
+ return "mysql";
3217
+ }
3218
+ async ensureConnected() {
3219
+ if (!this.connected) {
3220
+ await this.connect();
3221
+ }
3222
+ }
3223
+ };
3062
3224
  var SqlDatabaseManager = class _SqlDatabaseManager {
3063
3225
  constructor() {
3064
3226
  this.databases = /* @__PURE__ */ new Map();
@@ -3098,7 +3260,8 @@ var SqlDatabaseManager = class _SqlDatabaseManager {
3098
3260
  database = new PostgresDatabase(config);
3099
3261
  break;
3100
3262
  case "mysql":
3101
- throw new Error("MySQL support not yet implemented");
3263
+ database = new MysqlDatabase(config);
3264
+ break;
3102
3265
  case "sqlite":
3103
3266
  throw new Error("SQLite support not yet implemented");
3104
3267
  default:
@@ -5633,7 +5796,7 @@ var SandboxLatticeManager = class _SandboxLatticeManager extends BaseLatticeMana
5633
5796
  const tenantId = config.tenantId ?? "default";
5634
5797
  const mapping = this._resolveVolumeForPath(config, tenantId, filePath);
5635
5798
  if (!mapping) return null;
5636
- const client = provider.createVolumeFsClient(mapping.volumeName);
5799
+ const client = provider.createVolumeFsClient(mapping.volumeName, mapping.pathPrefix);
5637
5800
  return new VolumeFilesystem(stripPrefixClient(client, mapping.pathPrefix), mapping.pathPrefix);
5638
5801
  }
5639
5802
  _resolveVolumeForPath(config, tenantId, filePath) {
@@ -21299,7 +21462,7 @@ var MicrosandboxRemoteProvider = class {
21299
21462
  this.instances.delete(name);
21300
21463
  await this.client.deleteSandbox(name);
21301
21464
  }
21302
- createVolumeFsClient(volumeName) {
21465
+ createVolumeFsClient(volumeName, _pathPrefix) {
21303
21466
  return {
21304
21467
  read: (path3) => this.client.volumeFsRead(volumeName, path3),
21305
21468
  write: (path3, content) => this.client.volumeFsWrite(volumeName, path3, content),
@@ -21356,50 +21519,84 @@ var MicrosandboxRemoteProvider = class {
21356
21519
  import { SandboxClient as SandboxClient23 } from "@agent-infra/sandbox";
21357
21520
 
21358
21521
  // src/sandbox_lattice/RemoteSandboxInstance.ts
21522
+ function extractFetcherError(error) {
21523
+ if (typeof error === "string") {
21524
+ return error;
21525
+ }
21526
+ if (error && typeof error === "object") {
21527
+ const e = error;
21528
+ if (typeof e.reason === "string") {
21529
+ switch (e.reason) {
21530
+ case "status-code":
21531
+ return `HTTP ${e.statusCode}: ${JSON.stringify(e.body)}`;
21532
+ case "non-json":
21533
+ return `HTTP ${e.statusCode}: ${e.rawBody}`;
21534
+ case "timeout":
21535
+ return "Request timed out";
21536
+ case "unknown":
21537
+ return typeof e.errorMessage === "string" ? e.errorMessage : "Unknown error";
21538
+ }
21539
+ }
21540
+ if (typeof e.message === "string") {
21541
+ return e.message;
21542
+ }
21543
+ if (typeof e.error === "string") {
21544
+ return e.error;
21545
+ }
21546
+ return JSON.stringify(error);
21547
+ }
21548
+ return String(error);
21549
+ }
21359
21550
  var RemoteSandboxInstance = class {
21360
- constructor(name, client) {
21551
+ constructor(name, client, workspace) {
21361
21552
  this.client = client;
21553
+ this.workspace = workspace;
21362
21554
  this.file = {
21363
21555
  readFile: async (file) => {
21364
- const result = await this.client.file.readFile({ file });
21556
+ const resolved = this.resolvePath(file);
21557
+ const result = await this.client.file.readFile({ file: resolved });
21365
21558
  if (!result.ok) {
21366
- throw new Error(String(result.error));
21559
+ throw new Error(`readFile failed: ${extractFetcherError(result.error)}`);
21367
21560
  }
21368
21561
  return { content: result.body.data?.content ?? "" };
21369
21562
  },
21370
21563
  writeFile: async (file, content) => {
21371
- const result = await this.client.file.writeFile({ file, content });
21564
+ const resolved = this.resolvePath(file);
21565
+ const result = await this.client.file.writeFile({ file: resolved, content });
21372
21566
  if (!result.ok) {
21373
- throw new Error(String(result.error));
21567
+ throw new Error(`writeFile failed: ${extractFetcherError(result.error)}`);
21374
21568
  }
21375
21569
  },
21376
21570
  listPath: async (path3, options) => {
21571
+ const resolved = this.resolvePath(path3);
21377
21572
  const result = await this.client.file.listPath({
21378
- path: path3,
21573
+ path: resolved,
21379
21574
  recursive: options?.recursive ?? false
21380
21575
  });
21381
21576
  if (!result.ok) {
21382
- throw new Error(String(result.error));
21577
+ throw new Error(`listPath failed: ${extractFetcherError(result.error)}`);
21383
21578
  }
21384
21579
  const files = (result.body.data?.files || []).map((f) => ({
21385
21580
  path: f.path,
21386
- is_dir: f.is_dir ?? false,
21387
- size: f.size,
21581
+ is_dir: f.is_dir === true || f.size === null,
21582
+ size: f.size ?? void 0,
21388
21583
  modified_at: f.modified_at
21389
21584
  }));
21390
21585
  return { files };
21391
21586
  },
21392
21587
  findFiles: async (path3, glob) => {
21393
- const result = await this.client.file.findFiles({ path: path3, glob });
21588
+ const resolved = this.resolvePath(path3);
21589
+ const result = await this.client.file.findFiles({ path: resolved, glob });
21394
21590
  if (!result.ok) {
21395
- throw new Error(String(result.error));
21591
+ throw new Error(`findFiles failed: ${extractFetcherError(result.error)}`);
21396
21592
  }
21397
21593
  return { files: result.body.data?.files || [] };
21398
21594
  },
21399
21595
  searchInFile: async (file, regex) => {
21400
- const result = await this.client.file.searchInFile({ file, regex });
21596
+ const resolved = this.resolvePath(file);
21597
+ const result = await this.client.file.searchInFile({ file: resolved, regex });
21401
21598
  if (!result.ok) {
21402
- throw new Error(String(result.error));
21599
+ throw new Error(`searchInFile failed: ${extractFetcherError(result.error)}`);
21403
21600
  }
21404
21601
  return {
21405
21602
  matches: result.body.data?.matches || [],
@@ -21407,30 +21604,33 @@ var RemoteSandboxInstance = class {
21407
21604
  };
21408
21605
  },
21409
21606
  strReplaceEditor: async (params) => {
21607
+ const resolved = this.resolvePath(params.path);
21410
21608
  const result = await this.client.file.strReplaceEditor({
21411
21609
  command: params.command,
21412
- path: params.path,
21610
+ path: resolved,
21413
21611
  old_str: params.old_str,
21414
21612
  new_str: params.new_str,
21415
21613
  replace_mode: params.replace_mode
21416
21614
  });
21417
21615
  if (!result.ok) {
21418
- throw new Error(String(result.error));
21616
+ throw new Error(`strReplaceEditor failed: ${extractFetcherError(result.error)}`);
21419
21617
  }
21420
21618
  },
21421
21619
  uploadFile: async (params) => {
21620
+ const resolved = this.resolvePath(params.file);
21422
21621
  const result = await this.client.file.uploadFile({
21423
21622
  file: params.data,
21424
- path: params.file
21623
+ path: resolved
21425
21624
  });
21426
21625
  if (!result.ok) {
21427
- throw new Error(String(result.error));
21626
+ throw new Error(`uploadFile failed: ${extractFetcherError(result.error)}`);
21428
21627
  }
21429
21628
  },
21430
21629
  downloadFile: async (params) => {
21431
- const result = await this.client.file.downloadFile({ path: params.file });
21630
+ const resolved = this.resolvePath(params.file);
21631
+ const result = await this.client.file.downloadFile({ path: resolved });
21432
21632
  if (!result.ok) {
21433
- throw new Error(String(result.error));
21633
+ throw new Error(`downloadFile failed: ${extractFetcherError(result.error)}`);
21434
21634
  }
21435
21635
  const buffer2 = await result.body.arrayBuffer();
21436
21636
  return Buffer.from(buffer2);
@@ -21440,11 +21640,11 @@ var RemoteSandboxInstance = class {
21440
21640
  execCommand: async (params) => {
21441
21641
  const result = await this.client.shell.execCommand({
21442
21642
  command: params.command,
21443
- exec_dir: params.exec_dir,
21643
+ exec_dir: params.exec_dir ? this.resolvePath(params.exec_dir) : void 0,
21444
21644
  timeout: params.timeout
21445
21645
  });
21446
21646
  if (!result.ok) {
21447
- throw new Error(String(result.error));
21647
+ throw new Error(`execCommand failed: ${extractFetcherError(result.error)}`);
21448
21648
  }
21449
21649
  return {
21450
21650
  output: result.body.data?.output ?? "",
@@ -21454,6 +21654,15 @@ var RemoteSandboxInstance = class {
21454
21654
  };
21455
21655
  this.name = name;
21456
21656
  }
21657
+ resolvePath(file) {
21658
+ if (file.startsWith(this.workspace)) {
21659
+ return file;
21660
+ }
21661
+ if (!file.startsWith("/")) {
21662
+ return `${this.workspace}/${file}`;
21663
+ }
21664
+ return `${this.workspace}${file}`;
21665
+ }
21457
21666
  async start() {
21458
21667
  }
21459
21668
  async stop() {
@@ -21474,23 +21683,58 @@ var RemoteSandboxInstance = class {
21474
21683
  };
21475
21684
 
21476
21685
  // src/sandbox_lattice/providers/RemoteSandboxProvider.ts
21686
+ var DEFAULT_WORKSPACE = "/home/gem";
21477
21687
  var RemoteSandboxProvider = class {
21478
21688
  constructor(config) {
21479
21689
  this.config = config;
21480
21690
  this.instances = /* @__PURE__ */ new Map();
21691
+ this.creating = /* @__PURE__ */ new Map();
21692
+ this.workspace = DEFAULT_WORKSPACE;
21693
+ this.workspaceResolved = false;
21481
21694
  this.client = new SandboxClient23({
21482
21695
  baseUrl: config.baseURL,
21483
21696
  environment: ""
21484
21697
  });
21485
21698
  }
21699
+ async resolveWorkspace() {
21700
+ if (this.workspaceResolved) {
21701
+ return this.workspace;
21702
+ }
21703
+ try {
21704
+ const result = await this.client.sandbox.getContext();
21705
+ if (result.ok && result.body.home_dir) {
21706
+ this.workspace = result.body.home_dir;
21707
+ }
21708
+ } catch {
21709
+ }
21710
+ this.workspaceResolved = true;
21711
+ return this.workspace;
21712
+ }
21486
21713
  async createSandbox(name, _config) {
21487
21714
  const existing = this.instances.get(name);
21488
21715
  if (existing) {
21489
21716
  return existing;
21490
21717
  }
21491
- const instance = new RemoteSandboxInstance(name, this.client);
21492
- this.instances.set(name, instance);
21493
- return instance;
21718
+ const inFlight = this.creating.get(name);
21719
+ if (inFlight) {
21720
+ return inFlight;
21721
+ }
21722
+ const creation = (async () => {
21723
+ const workspace = await this.resolveWorkspace();
21724
+ const instance = new RemoteSandboxInstance(name, this.client, workspace);
21725
+ this.instances.set(name, instance);
21726
+ return instance;
21727
+ })();
21728
+ this.creating.set(name, creation);
21729
+ creation.then(
21730
+ () => {
21731
+ this.creating.delete(name);
21732
+ },
21733
+ () => {
21734
+ this.creating.delete(name);
21735
+ }
21736
+ );
21737
+ return creation;
21494
21738
  }
21495
21739
  async getSandbox(name) {
21496
21740
  const instance = this.instances.get(name);
@@ -21500,9 +21744,7 @@ var RemoteSandboxProvider = class {
21500
21744
  return instance;
21501
21745
  }
21502
21746
  async stopSandbox(name) {
21503
- const instance = this.instances.get(name);
21504
- if (instance) {
21505
- }
21747
+ this.instances.delete(name);
21506
21748
  }
21507
21749
  async deleteSandbox(name) {
21508
21750
  this.instances.delete(name);
@@ -21510,6 +21752,82 @@ var RemoteSandboxProvider = class {
21510
21752
  async listSandboxes() {
21511
21753
  return Array.from(this.instances.values());
21512
21754
  }
21755
+ createVolumeFsClient(_volumeName, pathPrefix) {
21756
+ const workspace = this.workspace;
21757
+ const resolve3 = (p) => {
21758
+ if (!p || p === "/") {
21759
+ if (pathPrefix) {
21760
+ return `${workspace}${pathPrefix}`;
21761
+ }
21762
+ return workspace;
21763
+ }
21764
+ if (p.startsWith(workspace)) {
21765
+ return p;
21766
+ }
21767
+ if (p.startsWith("/")) {
21768
+ return `${workspace}${p}`;
21769
+ }
21770
+ if (pathPrefix) {
21771
+ const mountDir = pathPrefix.replace(/^\//, "");
21772
+ return `${workspace}/${mountDir}/${p}`;
21773
+ }
21774
+ return `${workspace}/${p}`;
21775
+ };
21776
+ return {
21777
+ read: async (path3) => {
21778
+ const resolved = resolve3(path3);
21779
+ const result = await this.client.file.readFile({ file: resolved });
21780
+ if (!result.ok) {
21781
+ throw new Error(`Volume read failed: ${extractFetcherError(result.error)}`);
21782
+ }
21783
+ return result.body.data?.content ?? "";
21784
+ },
21785
+ write: async (path3, content) => {
21786
+ const resolved = resolve3(path3);
21787
+ const result = await this.client.file.writeFile({ file: resolved, content });
21788
+ if (!result.ok) {
21789
+ throw new Error(`Volume write failed: ${extractFetcherError(result.error)}`);
21790
+ }
21791
+ },
21792
+ list: async (path3) => {
21793
+ const resolved = resolve3(path3);
21794
+ const result = await this.client.file.listPath({
21795
+ path: resolved,
21796
+ recursive: false
21797
+ });
21798
+ if (!result.ok) {
21799
+ throw new Error(`Volume list failed: ${extractFetcherError(result.error)}`);
21800
+ }
21801
+ const entries = (result.body.data?.files || []).map((f) => ({
21802
+ path: f.path.startsWith(workspace) ? f.path.slice(workspace.length) : f.path,
21803
+ kind: f.is_dir === true || f.size === null ? "directory" : "file",
21804
+ size: f.size ?? 0,
21805
+ mode: 0,
21806
+ modified: f.modified_at ?? null
21807
+ }));
21808
+ return entries;
21809
+ },
21810
+ readRaw: async (path3) => {
21811
+ const resolved = resolve3(path3);
21812
+ const result = await this.client.file.downloadFile({ path: resolved });
21813
+ if (!result.ok) {
21814
+ throw new Error(`Volume download failed: ${extractFetcherError(result.error)}`);
21815
+ }
21816
+ const buffer2 = await result.body.arrayBuffer();
21817
+ return Buffer.from(buffer2);
21818
+ },
21819
+ writeRaw: async (path3, data) => {
21820
+ const resolved = resolve3(path3);
21821
+ const result = await this.client.file.uploadFile({
21822
+ file: data,
21823
+ path: resolved
21824
+ });
21825
+ if (!result.ok) {
21826
+ throw new Error(`Volume upload failed: ${extractFetcherError(result.error)}`);
21827
+ }
21828
+ }
21829
+ };
21830
+ }
21513
21831
  };
21514
21832
 
21515
21833
  // src/sandbox_lattice/providers/E2BProvider.ts
@@ -22150,6 +22468,7 @@ export {
22150
22468
  MicrosandboxRemoteProvider,
22151
22469
  MicrosandboxServiceClient,
22152
22470
  ModelLatticeManager,
22471
+ MysqlDatabase,
22153
22472
  PinoLoggerClient,
22154
22473
  PostgresDatabase,
22155
22474
  PrometheusClient,
@@ -22214,6 +22533,7 @@ export {
22214
22533
  ensureBuiltinAgentsForTenant,
22215
22534
  eventBus,
22216
22535
  event_bus_default as eventBusDefault,
22536
+ extractFetcherError,
22217
22537
  fileDataToString,
22218
22538
  formatContentWithLineNumbers,
22219
22539
  formatGrepMatches,