@altimateai/altimate-code 0.8.6 → 0.8.9
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/CHANGELOG.md +63 -0
- package/dbt-tools/dist/index.js +137 -53
- package/package.json +10 -10
- package/skills/query-optimize/SKILL.md +9 -9
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,69 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.8.9] - 2026-06-19
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **The non-interactive `run` guard no longer mis-handles a blank env var.** A blank/whitespace `ALTIMATE_NON_INTERACTIVE=` is now treated as unset, so it can't silently reintroduce the headless `run` hang that #937 fixed. (#937 follow-up)
|
|
13
|
+
- **Session transcript boolean query flags accept the common falsey strings.** `thinking`, `toolDetails`, and `assistantMetadata` now treat `false`/`0`/`no`/`off` (case-insensitive) as false, not just the literal `"false"`. (#941 follow-up)
|
|
14
|
+
- **Writing an MCP server entry refuses to clobber an unparseable config** (detected via `parse()` with an error sink, not the error-tolerant `parseTree()`), and `updatedAt` is preserved through config normalization so the datamate reconnect signal survives. (#893 follow-up)
|
|
15
|
+
- **dbt error bubbling strips the full ANSI escape family** (cursor/erase sequences from progress spinners), not just SGR color codes. (#933 follow-up)
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- **The headless `serve` startup upgrade check is jittered** (base + random, ~1–6s) so a fleet restarting together doesn't stampede the unauthenticated GitHub releases API in the same instant. (#940 follow-up)
|
|
20
|
+
|
|
21
|
+
### Internal
|
|
22
|
+
|
|
23
|
+
- **Diverged upstream constants are wrapped in `altimate_change` markers** (`DEFAULT_CHUNK_TIMEOUT`, the question-tool `output` field) so they survive upstream merges. (#844, #937)
|
|
24
|
+
- **Added a v0.8.9 adversarial test suite** covering the shipping code and the review fixes under hostile input (question-tool env matrix, MCP config parse-guard, startup-upgrade fail-safety + jitter).
|
|
25
|
+
|
|
26
|
+
## [0.8.8] - 2026-06-19
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- **Windows now has a one-line PowerShell installer.** `irm https://www.altimate.sh/install.ps1 | iex` downloads the standalone binary from GitHub releases (AVX2-aware, with a baseline fallback), adds it to your user `PATH`, and supports `-Version`, `-NoPathUpdate`, and `-ForceBaseline`. `altimate upgrade` uses the same path on Windows. (#930)
|
|
31
|
+
- **IDE-aware datamate transport, MCP enabled-state persistence, and a `/mcps` command.** The active IDE's `mcp.json` datamate entry/URL is mirrored into `altimate-code.json` and reconnected when it changes; enabled/disabled state for MCP servers now persists to disk; `/mcps` lists and toggles servers; project `mcp.json` files are discovered recursively (project-scoped servers are discovered disabled, never auto-connected). (#893)
|
|
32
|
+
- **Session transcript REST endpoint for the datamates extension.** `GET /session/:id/transcript` returns the full conversation as formatted Markdown, with `thinking`, `toolDetails`, and `assistantMetadata` query flags. (#941)
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- **Headless `serve` now checks for and applies updates on startup.** When `autoupdate` is unset (the default) and a supported install method is present, `serve` performs a one-shot, best-effort self-upgrade shortly after start. It never restarts the running process and can never crash `serve` (errors are swallowed). Opt out with `autoupdate: false` or `"notify"` in config, or `OPENCODE_DISABLE_AUTOUPDATE=1`. (#940)
|
|
37
|
+
- **The per-chunk streaming watchdog timeout was raised from 2 minutes to 5 minutes** so slow warehouse/LLM streams are not aborted prematurely. (#844)
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
- **`dbt show`/`compile` failures now surface the real dbt error** instead of a generic "Could not parse", with inline SQL redacted from the message so secrets/PII don't leak into logs. (#933)
|
|
42
|
+
- **The question tool no longer hangs in non-interactive contexts.** `altimate run` is detected as headless and returns "Unanswered" (letting the agent decide) rather than blocking forever; `ALTIMATE_AUTO_ANSWER=first|last|<label>` can pre-answer. (#937)
|
|
43
|
+
- **Windows release archives are verified by checksum in both installers** before extraction, and latest-version resolution is more resilient to transient fetch failures. (#942, #946)
|
|
44
|
+
|
|
45
|
+
### Internal
|
|
46
|
+
|
|
47
|
+
- **`serve` logs the trace directory on startup** so operators can find session traces. (#929)
|
|
48
|
+
- **Added a release-validation regression suite** covering the merged PRs. (#952)
|
|
49
|
+
|
|
50
|
+
## [0.8.7] - 2026-06-10
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
|
|
54
|
+
- **Verified query optimization — `altimate_core_rewrite` now proves a rewrite is safe before suggesting it.** A new `verify_equivalence` mode composes the rewrite engine with the equivalence checker: a candidate rewrite is labeled **VERIFIED** only when the engine affirmatively returns `equivalent === true`; everything else (including the no-schema case) is still returned but labeled "review before applying." This is the gated core for one-click verified query optimization, so an optimization that silently changes results is never presented as safe. (#918)
|
|
55
|
+
- **Per-turn tool retrieval trims the tool-definition context flood.** Three flag-gated, default-off agent-loop reliability features: a per-turn tool subset (always-on core tools + lexical top-k, never dropping a tool referenced mid-trajectory) that cuts the ~78-tool definition payload sent each turn; grammar/JSON-Schema constrained decoding for local models (vLLM/LM Studio/llama.cpp); and a pluggable pre-execution critic gate for side-effecting tools. All default off, so the existing agent path is unchanged unless explicitly enabled. (#858)
|
|
56
|
+
|
|
57
|
+
### Changed
|
|
58
|
+
|
|
59
|
+
- **Upgraded the SQL engine `@altimateai/altimate-core` `0.4.0` → `0.5.1` and wired its new equivalence capabilities into the dbt PR reviewer.** The reviewer now forwards the project's SQL **dialect** hint to the equivalence engine, so dialect-specific compiled warehouse SQL (e.g. Snowflake semi-structured `col:field`) parses and the comparison is decided instead of abstaining on a syntax error, and it honors the engine's new authoritative **`decidable`** flag — abstaining when the engine itself says it could not decide, rather than guessing. An empty/auto-detect dialect is coerced to "no hint" so the engine is never handed an unknown dialect. (#925, #928)
|
|
60
|
+
|
|
61
|
+
### Fixed
|
|
62
|
+
|
|
63
|
+
- **The dbt PR reviewer is more reliable and less noisy.** Demo-parity hardening: tighter PII-review precision, reduced safe-refactor review noise, schema YAML catalog rules now run in review, and added DuckDB data-diff end-to-end coverage. (#919)
|
|
64
|
+
- **dbt review no longer misclassifies YAML files.** Schema/property YAML files are classified correctly so the right rules apply to them. (#920)
|
|
65
|
+
- **The `release-v0.8.5` adversarial test gate is pinned to a constant version** so it stops breaking on every subsequent release. (#923)
|
|
66
|
+
|
|
67
|
+
### Internal
|
|
68
|
+
|
|
69
|
+
- **Centralized code-review dispatch on PR ready.** A gated loop dispatches a centralized OCR/Gemini review when a pull request is marked ready for review. (#914)
|
|
70
|
+
|
|
8
71
|
## [0.8.6] - 2026-06-08
|
|
9
72
|
|
|
10
73
|
### Added
|
package/dbt-tools/dist/index.js
CHANGED
|
@@ -321,16 +321,25 @@ function getDbt() {
|
|
|
321
321
|
}
|
|
322
322
|
return resolvedDbt;
|
|
323
323
|
}
|
|
324
|
+
function toExecFileError(e) {
|
|
325
|
+
if (e instanceof Error)
|
|
326
|
+
return e;
|
|
327
|
+
return new Error(String(e));
|
|
328
|
+
}
|
|
324
329
|
function run2(args) {
|
|
325
330
|
const dbt2 = getDbt();
|
|
326
331
|
const env = buildDbtEnv(dbt2);
|
|
327
332
|
const cwd = globalOptions.projectRoot ?? process.cwd();
|
|
328
333
|
return new Promise((resolve4, reject2) => {
|
|
329
334
|
execFile(dbt2.path, args, { timeout: 120000, maxBuffer: 10 * 1024 * 1024, env, cwd }, (err, stdout, stderr) => {
|
|
330
|
-
if (err)
|
|
331
|
-
|
|
332
|
-
|
|
335
|
+
if (err) {
|
|
336
|
+
const execErr = err;
|
|
337
|
+
execErr.stdout = stdout;
|
|
338
|
+
execErr.stderr = stderr;
|
|
339
|
+
reject2(execErr);
|
|
340
|
+
} else {
|
|
333
341
|
resolve4({ stdout, stderr });
|
|
342
|
+
}
|
|
334
343
|
});
|
|
335
344
|
});
|
|
336
345
|
}
|
|
@@ -392,7 +401,7 @@ function looksLikeRowData(val) {
|
|
|
392
401
|
}
|
|
393
402
|
}
|
|
394
403
|
function stripAnsi(text) {
|
|
395
|
-
return text.replace(/\x1b\[[0-9
|
|
404
|
+
return text.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, "");
|
|
396
405
|
}
|
|
397
406
|
function parseAsciiTable(text) {
|
|
398
407
|
const cleaned = stripAnsi(text);
|
|
@@ -439,41 +448,43 @@ async function execDbtShow(sql, limit) {
|
|
|
439
448
|
const args = ["show", "--inline", sql, "--output", "json", "--log-format", "json"];
|
|
440
449
|
if (limit !== undefined)
|
|
441
450
|
args.push("--limit", String(limit));
|
|
442
|
-
let
|
|
451
|
+
let primaryRunError;
|
|
452
|
+
let lines = [];
|
|
443
453
|
try {
|
|
444
454
|
const { stdout } = await run2(args);
|
|
445
455
|
lines = parseJsonLines(stdout);
|
|
446
|
-
} catch {
|
|
447
|
-
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
rows = parsed;
|
|
456
|
+
} catch (e) {
|
|
457
|
+
primaryRunError = toExecFileError(e);
|
|
458
|
+
}
|
|
459
|
+
if (!primaryRunError) {
|
|
460
|
+
const previewLine = lines.find((l) => l.data?.preview) ?? lines.find((l) => l.data?.rows) ?? lines.find((l) => l.result?.preview) ?? lines.find((l) => l.result?.rows);
|
|
461
|
+
const sqlLine = lines.find((l) => l.data?.sql) ?? lines.find((l) => l.data?.compiled_sql) ?? lines.find((l) => l.result?.sql);
|
|
462
|
+
if (previewLine) {
|
|
463
|
+
const preview = previewLine.data?.preview ?? previewLine.data?.rows ?? previewLine.result?.preview ?? previewLine.result?.rows;
|
|
464
|
+
let rows;
|
|
465
|
+
if (typeof preview === "string") {
|
|
466
|
+
const parsed = safeJsonParse(preview);
|
|
467
|
+
rows = Array.isArray(parsed) ? parsed : [];
|
|
468
|
+
} else if (Array.isArray(preview)) {
|
|
469
|
+
rows = preview;
|
|
458
470
|
} else {
|
|
459
471
|
rows = [];
|
|
460
472
|
}
|
|
461
|
-
} else {
|
|
462
|
-
rows = preview;
|
|
463
|
-
}
|
|
464
|
-
const columnNames = rows.length > 0 && rows[0] ? Object.keys(rows[0]) : [];
|
|
465
|
-
const compiledSql = sqlLine?.data?.sql ?? sqlLine?.data?.compiled_sql ?? sqlLine?.result?.sql ?? sql;
|
|
466
|
-
return { columnNames, columnTypes: columnNames.map(() => "string"), data: rows, rawSql: sql, compiledSql };
|
|
467
|
-
}
|
|
468
|
-
for (const line of lines) {
|
|
469
|
-
const found = deepFind(line, (val) => looksLikeRowData(val));
|
|
470
|
-
if (found) {
|
|
471
|
-
const rows = typeof found === "string" ? JSON.parse(found) : found;
|
|
472
473
|
const columnNames = rows.length > 0 && rows[0] ? Object.keys(rows[0]) : [];
|
|
473
|
-
const compiledSql =
|
|
474
|
+
const compiledSql = sqlLine?.data?.sql ?? sqlLine?.data?.compiled_sql ?? sqlLine?.result?.sql ?? sql;
|
|
474
475
|
return { columnNames, columnTypes: columnNames.map(() => "string"), data: rows, rawSql: sql, compiledSql };
|
|
475
476
|
}
|
|
477
|
+
for (const line of lines) {
|
|
478
|
+
const found = deepFind(line, (val) => looksLikeRowData(val));
|
|
479
|
+
if (found) {
|
|
480
|
+
const rows = typeof found === "string" ? JSON.parse(found) : found;
|
|
481
|
+
const columnNames = rows.length > 0 && rows[0] ? Object.keys(rows[0]) : [];
|
|
482
|
+
const compiledSql = deepFind(line, (val) => looksLikeSql(val)) ?? sql;
|
|
483
|
+
return { columnNames, columnTypes: columnNames.map(() => "string"), data: rows, rawSql: sql, compiledSql };
|
|
484
|
+
}
|
|
485
|
+
}
|
|
476
486
|
}
|
|
487
|
+
let plainRunError;
|
|
477
488
|
try {
|
|
478
489
|
const plainArgs = ["show", "--inline", sql];
|
|
479
490
|
if (limit !== undefined)
|
|
@@ -489,62 +500,135 @@ async function execDbtShow(sql, limit) {
|
|
|
489
500
|
compiledSql: sql
|
|
490
501
|
};
|
|
491
502
|
}
|
|
492
|
-
} catch {
|
|
503
|
+
} catch (e) {
|
|
504
|
+
plainRunError = toExecFileError(e);
|
|
505
|
+
}
|
|
506
|
+
if (primaryRunError) {
|
|
507
|
+
const errorLogLines = parseJsonLines(primaryRunError.stdout?.toString() ?? "");
|
|
508
|
+
const realError = extractDbtError(errorLogLines, primaryRunError, plainRunError);
|
|
509
|
+
if (realError) {
|
|
510
|
+
const hasDbtCategoryPrefix = /^(Compilation|Database|Runtime|Parsing|Validation|Dependency)\s+Error\b/.test(realError);
|
|
511
|
+
throw new Error(hasDbtCategoryPrefix ? realError : `dbt show failed: ${realError}`);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
if (plainRunError) {
|
|
515
|
+
const fallback = extractDbtError([], undefined, plainRunError) ?? fallbackExitMessage(undefined, plainRunError) ?? "unknown error";
|
|
516
|
+
throw new Error(`Could not parse dbt show JSON output, and plain-text fallback failed: ${fallback}`);
|
|
517
|
+
}
|
|
493
518
|
throw new Error("Could not parse dbt show output in any format (JSON, heuristic, or plain text). " + `Got ${lines.length} JSON lines.`);
|
|
494
519
|
}
|
|
520
|
+
function extractDbtError(lines, primary, plain) {
|
|
521
|
+
if (!primary && !plain)
|
|
522
|
+
return;
|
|
523
|
+
const errorMessages = lines.map((l) => {
|
|
524
|
+
const line = l;
|
|
525
|
+
const isError = line.info?.level === "error" || line.level === "error";
|
|
526
|
+
if (!isError)
|
|
527
|
+
return;
|
|
528
|
+
return line.info?.msg ?? line.msg;
|
|
529
|
+
}).filter((m) => typeof m === "string" && m.trim().length > 0);
|
|
530
|
+
const structuredMsg = errorMessages.at(-1);
|
|
531
|
+
const primaryStderr = primary?.stderr?.toString().trim();
|
|
532
|
+
const plainStderr = plain?.stderr?.toString().trim();
|
|
533
|
+
const chosen = (structuredMsg && structuredMsg.length > 0 ? structuredMsg : undefined) ?? (primaryStderr && primaryStderr.length > 0 ? primaryStderr : undefined) ?? (plainStderr && plainStderr.length > 0 ? plainStderr : undefined) ?? fallbackExitMessage(primary, plain);
|
|
534
|
+
return chosen ? stripAnsi(chosen) : undefined;
|
|
535
|
+
}
|
|
536
|
+
function fallbackExitMessage(primary, plain) {
|
|
537
|
+
const err = primary ?? plain;
|
|
538
|
+
if (!err)
|
|
539
|
+
return;
|
|
540
|
+
const looksLikeCommandFailed = typeof err.message === "string" && err.message.startsWith("Command failed:");
|
|
541
|
+
if (!looksLikeCommandFailed)
|
|
542
|
+
return err.message;
|
|
543
|
+
if (typeof err.code === "number")
|
|
544
|
+
return `dbt exited with status ${err.code}`;
|
|
545
|
+
if (err.signal)
|
|
546
|
+
return `dbt killed by signal ${err.signal}`;
|
|
547
|
+
if (typeof err.code === "string")
|
|
548
|
+
return `dbt failed: ${err.code}`;
|
|
549
|
+
return "dbt failed (no exit code reported)";
|
|
550
|
+
}
|
|
551
|
+
function bubbleDbtError(label, primary, plain) {
|
|
552
|
+
const errorLogLines = primary?.stdout ? parseJsonLines(primary.stdout.toString()) : [];
|
|
553
|
+
const real = extractDbtError(errorLogLines, primary, plain);
|
|
554
|
+
if (real) {
|
|
555
|
+
const hasDbtCategoryPrefix = /^(Compilation|Database|Runtime|Parsing|Validation|Dependency)\s+Error\b/.test(real);
|
|
556
|
+
return hasDbtCategoryPrefix ? real : `${label}: ${real}`;
|
|
557
|
+
}
|
|
558
|
+
return `${label}: ${fallbackExitMessage(primary, plain) ?? "unknown error"}`;
|
|
559
|
+
}
|
|
495
560
|
async function execDbtCompile(model) {
|
|
496
561
|
const args = ["compile", "--select", model, "--output", "json", "--log-format", "json"];
|
|
497
|
-
let lines;
|
|
562
|
+
let lines = [];
|
|
563
|
+
let primaryRunError;
|
|
498
564
|
try {
|
|
499
565
|
const { stdout } = await run2(args);
|
|
500
566
|
lines = parseJsonLines(stdout);
|
|
501
|
-
} catch {
|
|
502
|
-
|
|
567
|
+
} catch (e) {
|
|
568
|
+
primaryRunError = toExecFileError(e);
|
|
503
569
|
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
const
|
|
509
|
-
|
|
510
|
-
|
|
570
|
+
if (!primaryRunError) {
|
|
571
|
+
const sql = findCompiledSql(lines);
|
|
572
|
+
if (sql)
|
|
573
|
+
return { sql };
|
|
574
|
+
for (const line of lines) {
|
|
575
|
+
const found = deepFind(line, (val) => looksLikeSql(val));
|
|
576
|
+
if (found)
|
|
577
|
+
return { sql: found };
|
|
578
|
+
}
|
|
511
579
|
}
|
|
580
|
+
let manifestRunError;
|
|
512
581
|
try {
|
|
513
582
|
await run2(["compile", "--select", model]);
|
|
514
|
-
} catch {
|
|
583
|
+
} catch (e) {
|
|
584
|
+
manifestRunError = toExecFileError(e);
|
|
585
|
+
}
|
|
515
586
|
const fromManifest = readCompiledFromManifest(model);
|
|
516
587
|
if (fromManifest)
|
|
517
588
|
return { sql: fromManifest };
|
|
589
|
+
let plainRunError;
|
|
518
590
|
try {
|
|
519
591
|
const { stdout: plainOut } = await run2(["compile", "--select", model]);
|
|
520
592
|
return { sql: plainOut.trim() };
|
|
521
593
|
} catch (e) {
|
|
522
|
-
|
|
594
|
+
plainRunError = toExecFileError(e);
|
|
595
|
+
}
|
|
596
|
+
if (primaryRunError || plainRunError || manifestRunError) {
|
|
597
|
+
throw new Error(bubbleDbtError("dbt compile failed", primaryRunError, plainRunError ?? manifestRunError));
|
|
523
598
|
}
|
|
599
|
+
throw new Error(`Could not compile model '${model}' in any format (JSON, heuristic, or manifest).`);
|
|
524
600
|
}
|
|
525
601
|
async function execDbtCompileInline(sql, _model) {
|
|
526
602
|
const args = ["compile", "--inline", sql, "--output", "json", "--log-format", "json"];
|
|
527
|
-
let lines;
|
|
603
|
+
let lines = [];
|
|
604
|
+
let primaryRunError;
|
|
528
605
|
try {
|
|
529
606
|
const { stdout } = await run2(args);
|
|
530
607
|
lines = parseJsonLines(stdout);
|
|
531
|
-
} catch {
|
|
532
|
-
|
|
608
|
+
} catch (e) {
|
|
609
|
+
primaryRunError = toExecFileError(e);
|
|
533
610
|
}
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
const
|
|
539
|
-
|
|
540
|
-
|
|
611
|
+
if (!primaryRunError) {
|
|
612
|
+
const compiled = findCompiledSql(lines);
|
|
613
|
+
if (compiled)
|
|
614
|
+
return { sql: compiled };
|
|
615
|
+
for (const line of lines) {
|
|
616
|
+
const found = deepFind(line, (val) => looksLikeSql(val));
|
|
617
|
+
if (found)
|
|
618
|
+
return { sql: found };
|
|
619
|
+
}
|
|
541
620
|
}
|
|
621
|
+
let plainRunError;
|
|
542
622
|
try {
|
|
543
623
|
const { stdout: plainOut } = await run2(["compile", "--inline", sql]);
|
|
544
624
|
return { sql: plainOut.trim() };
|
|
545
625
|
} catch (e) {
|
|
546
|
-
|
|
626
|
+
plainRunError = toExecFileError(e);
|
|
627
|
+
}
|
|
628
|
+
if (primaryRunError || plainRunError) {
|
|
629
|
+
throw new Error(bubbleDbtError("dbt compile inline failed", primaryRunError, plainRunError));
|
|
547
630
|
}
|
|
631
|
+
throw new Error("Could not compile inline SQL in any format (JSON, heuristic, or plain text).");
|
|
548
632
|
}
|
|
549
633
|
function findCompiledSql(lines) {
|
|
550
634
|
const compiledLine = lines.find((l) => l.data?.compiled) ?? lines.find((l) => l.data?.compiled_code) ?? lines.find((l) => l.result?.node?.compiled_code) ?? lines.find((l) => l.result?.compiled_code) ?? lines.find((l) => l.data?.compiled_sql);
|
package/package.json
CHANGED
|
@@ -7,20 +7,20 @@
|
|
|
7
7
|
"scripts": {
|
|
8
8
|
"postinstall": "bun ./postinstall.mjs || node ./postinstall.mjs"
|
|
9
9
|
},
|
|
10
|
-
"version": "0.8.
|
|
10
|
+
"version": "0.8.9",
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@altimateai/altimate-core": "0.
|
|
13
|
+
"@altimateai/altimate-core": "0.5.1"
|
|
14
14
|
},
|
|
15
15
|
"optionalDependencies": {
|
|
16
|
-
"@altimateai/altimate-code-linux-
|
|
17
|
-
"@altimateai/altimate-code-
|
|
18
|
-
"@altimateai/altimate-code-linux-x64
|
|
19
|
-
"@altimateai/altimate-code-darwin-x64
|
|
20
|
-
"@altimateai/altimate-code-
|
|
21
|
-
"@altimateai/altimate-code-darwin-
|
|
22
|
-
"@altimateai/altimate-code-windows-x64": "0.8.
|
|
23
|
-
"@altimateai/altimate-code-linux-
|
|
16
|
+
"@altimateai/altimate-code-linux-x64-baseline": "0.8.9",
|
|
17
|
+
"@altimateai/altimate-code-windows-x64": "0.8.9",
|
|
18
|
+
"@altimateai/altimate-code-linux-x64": "0.8.9",
|
|
19
|
+
"@altimateai/altimate-code-darwin-x64": "0.8.9",
|
|
20
|
+
"@altimateai/altimate-code-darwin-x64-baseline": "0.8.9",
|
|
21
|
+
"@altimateai/altimate-code-darwin-arm64": "0.8.9",
|
|
22
|
+
"@altimateai/altimate-code-windows-x64-baseline": "0.8.9",
|
|
23
|
+
"@altimateai/altimate-code-linux-arm64": "0.8.9"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
26
|
"pg": ">=8",
|
|
@@ -7,7 +7,7 @@ description: Analyze and optimize SQL queries for better performance
|
|
|
7
7
|
|
|
8
8
|
## Requirements
|
|
9
9
|
**Agent:** any (read-only analysis)
|
|
10
|
-
**Tools used:**
|
|
10
|
+
**Tools used:** altimate_core_rewrite (with `verify_equivalence: true`), sql_analyze, sql_explain, read, glob, schema_inspect, warehouse_list
|
|
11
11
|
|
|
12
12
|
Analyze SQL queries for performance issues and suggest concrete optimizations including rewritten SQL.
|
|
13
13
|
|
|
@@ -20,9 +20,9 @@ Analyze SQL queries for performance issues and suggest concrete optimizations in
|
|
|
20
20
|
|
|
21
21
|
2. **Determine the dialect** -- Default to `snowflake`. If the user specifies a dialect (postgres, bigquery, duckdb, etc.), use that instead. Check the project for warehouse connections using `warehouse_list` if unsure.
|
|
22
22
|
|
|
23
|
-
3. **Run the optimizer**:
|
|
24
|
-
-
|
|
25
|
-
-
|
|
23
|
+
3. **Run the verified optimizer**:
|
|
24
|
+
- If the user has a warehouse connection, first call `schema_inspect` on the relevant tables to build schema context (needed both for better rewrites — e.g. SELECT * expansion — and to verify equivalence)
|
|
25
|
+
- Call `altimate_core_rewrite` with the SQL, schema context, and **`verify_equivalence: true`**. This proposes rewrites AND proves each one returns the same results as the original in a single step. The result is partitioned into **verified-equivalent** rewrites (safe to apply) and **unverified** rewrites (review before applying), so you never recommend a rewrite that silently changes semantics.
|
|
26
26
|
|
|
27
27
|
4. **Run detailed analysis**:
|
|
28
28
|
- Call `sql_analyze` with the same SQL and dialect to get the full anti-pattern breakdown with recommendations
|
|
@@ -32,10 +32,10 @@ Analyze SQL queries for performance issues and suggest concrete optimizations in
|
|
|
32
32
|
- Look for: full table scans, sort operations on large datasets, inefficient join strategies, missing partition pruning
|
|
33
33
|
- Include key findings in the report under "Execution Plan Insights"
|
|
34
34
|
|
|
35
|
-
6. **
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
35
|
+
6. **Equivalence verification is built into step 3** (`verify_equivalence: true`):
|
|
36
|
+
- Present the **verified-equivalent** rewrites as safe to apply.
|
|
37
|
+
- Present **unverified** rewrites separately with their reason ("review before applying") — do not recommend applying these without manual review.
|
|
38
|
+
- If no schema was available, all rewrites come back unverified; say so and recommend supplying a schema (or a warehouse connection) to enable verification.
|
|
39
39
|
|
|
40
40
|
7. **Present findings** in a structured format:
|
|
41
41
|
|
|
@@ -83,4 +83,4 @@ The user invokes this skill with SQL or a file path:
|
|
|
83
83
|
- `/query-optimize models/staging/stg_orders.sql` -- Optimize SQL from a file
|
|
84
84
|
- `/query-optimize` -- Optimize the most recently discussed SQL in the conversation
|
|
85
85
|
|
|
86
|
-
Use the tools: `
|
|
86
|
+
Use the tools: `altimate_core_rewrite` with `verify_equivalence: true` (proposes rewrites AND proves they preserve results in one step), `sql_analyze`, `sql_explain` (execution plans), `read` (for file-based SQL), `glob` (to find SQL files), `schema_inspect` (for schema context), `warehouse_list` (to check connections).
|