@algolia/wizard 0.66.0 → 0.68.0
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/main.js +387 -58
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -48,7 +48,7 @@ function runAlgoliaCli(args, { onOutput, redact } = {}) {
|
|
|
48
48
|
const store = useWizard.getState();
|
|
49
49
|
const command = mask(args.join(" "), redact);
|
|
50
50
|
const logId = store.logStart("tool", `algolia ${command}`);
|
|
51
|
-
return new Promise((
|
|
51
|
+
return new Promise((resolve5, reject) => {
|
|
52
52
|
const child = spawn("npx", npxArgs(args), { shell });
|
|
53
53
|
let stdout = "";
|
|
54
54
|
let stderr = "";
|
|
@@ -71,7 +71,7 @@ function runAlgoliaCli(args, { onOutput, redact } = {}) {
|
|
|
71
71
|
splitters.stdout.flush();
|
|
72
72
|
splitters.stderr.flush();
|
|
73
73
|
if (code === 0) {
|
|
74
|
-
|
|
74
|
+
resolve5(stdout);
|
|
75
75
|
} else {
|
|
76
76
|
const failed = stderr.trim();
|
|
77
77
|
let detail = "";
|
|
@@ -275,15 +275,15 @@ var useWizard = create((set, get) => ({
|
|
|
275
275
|
),
|
|
276
276
|
openLearnMore: () => set({ homeScreen: "learnMore" }),
|
|
277
277
|
backToHome: () => set({ homeScreen: "home" }),
|
|
278
|
-
waitForStart: () => new Promise((
|
|
278
|
+
waitForStart: () => new Promise((resolve5) => {
|
|
279
279
|
if (get().phase !== "idle") {
|
|
280
|
-
|
|
280
|
+
resolve5();
|
|
281
281
|
return;
|
|
282
282
|
}
|
|
283
283
|
const unsubscribe = useWizard.subscribe((s) => {
|
|
284
284
|
if (s.phase !== "idle") {
|
|
285
285
|
unsubscribe();
|
|
286
|
-
|
|
286
|
+
resolve5();
|
|
287
287
|
}
|
|
288
288
|
});
|
|
289
289
|
}),
|
|
@@ -385,11 +385,11 @@ var useWizard = create((set, get) => ({
|
|
|
385
385
|
(t) => t.id === id ? { ...t, status, durationMs: Date.now() - t.startedAt } : t
|
|
386
386
|
)
|
|
387
387
|
})),
|
|
388
|
-
requestUserInput: (req) => new Promise((
|
|
388
|
+
requestUserInput: (req) => new Promise((resolve5) => {
|
|
389
389
|
set({
|
|
390
390
|
phase: "awaitingInput",
|
|
391
391
|
inputReq: req,
|
|
392
|
-
_resolve:
|
|
392
|
+
_resolve: resolve5
|
|
393
393
|
});
|
|
394
394
|
}),
|
|
395
395
|
submitInput: async (value) => {
|
|
@@ -1490,7 +1490,106 @@ async function clearWorkflowState(workflowId) {
|
|
|
1490
1490
|
await rm(stateFile(workflowId), { force: true });
|
|
1491
1491
|
}
|
|
1492
1492
|
|
|
1493
|
+
// src/lib/modelProfiles.ts
|
|
1494
|
+
var TOKENS_PER_MILLION = 1e6;
|
|
1495
|
+
var INITIAL_MODEL_ATTEMPT = 1;
|
|
1496
|
+
var NO_TOKENS = 0;
|
|
1497
|
+
var QUICK_MAX_OUTPUT_TOKENS = 8192;
|
|
1498
|
+
var QUICK_MAX_STEPS = 16;
|
|
1499
|
+
var ANALYSIS_MAX_OUTPUT_TOKENS = 8192;
|
|
1500
|
+
var ANALYSIS_MAX_STEPS = 24;
|
|
1501
|
+
var IMPLEMENTATION_MAX_OUTPUT_TOKENS = 65536;
|
|
1502
|
+
var IMPLEMENTATION_MAX_STEPS = 48;
|
|
1503
|
+
var VALIDATION_MAX_OUTPUT_TOKENS = 8192;
|
|
1504
|
+
var VALIDATION_MAX_STEPS = 24;
|
|
1505
|
+
var HAIKU_4_5_PRICES = {
|
|
1506
|
+
input: 1,
|
|
1507
|
+
output: 5,
|
|
1508
|
+
cacheRead: 0.1,
|
|
1509
|
+
cacheWrite: 1.25
|
|
1510
|
+
};
|
|
1511
|
+
var SONNET_5_PRICES = {
|
|
1512
|
+
input: 2,
|
|
1513
|
+
output: 10,
|
|
1514
|
+
cacheRead: 0.2,
|
|
1515
|
+
cacheWrite: 2.5
|
|
1516
|
+
};
|
|
1517
|
+
var MODEL_PROFILES = {
|
|
1518
|
+
quick: {
|
|
1519
|
+
model: "claude-haiku-4-5",
|
|
1520
|
+
thinking: "disabled",
|
|
1521
|
+
maxOutputTokens: QUICK_MAX_OUTPUT_TOKENS,
|
|
1522
|
+
maxSteps: QUICK_MAX_STEPS,
|
|
1523
|
+
prices: HAIKU_4_5_PRICES
|
|
1524
|
+
},
|
|
1525
|
+
analysis: {
|
|
1526
|
+
model: "claude-sonnet-5",
|
|
1527
|
+
thinking: "adaptive",
|
|
1528
|
+
effort: "low",
|
|
1529
|
+
maxOutputTokens: ANALYSIS_MAX_OUTPUT_TOKENS,
|
|
1530
|
+
maxSteps: ANALYSIS_MAX_STEPS,
|
|
1531
|
+
prices: SONNET_5_PRICES
|
|
1532
|
+
},
|
|
1533
|
+
implementation: {
|
|
1534
|
+
model: "claude-sonnet-5",
|
|
1535
|
+
thinking: "adaptive",
|
|
1536
|
+
effort: "medium",
|
|
1537
|
+
maxOutputTokens: IMPLEMENTATION_MAX_OUTPUT_TOKENS,
|
|
1538
|
+
maxSteps: IMPLEMENTATION_MAX_STEPS,
|
|
1539
|
+
prices: SONNET_5_PRICES
|
|
1540
|
+
},
|
|
1541
|
+
implementationRetry: {
|
|
1542
|
+
model: "claude-sonnet-5",
|
|
1543
|
+
thinking: "adaptive",
|
|
1544
|
+
effort: "high",
|
|
1545
|
+
maxOutputTokens: IMPLEMENTATION_MAX_OUTPUT_TOKENS,
|
|
1546
|
+
maxSteps: IMPLEMENTATION_MAX_STEPS,
|
|
1547
|
+
prices: SONNET_5_PRICES
|
|
1548
|
+
},
|
|
1549
|
+
validation: {
|
|
1550
|
+
model: "claude-sonnet-5",
|
|
1551
|
+
thinking: "adaptive",
|
|
1552
|
+
effort: "low",
|
|
1553
|
+
maxOutputTokens: VALIDATION_MAX_OUTPUT_TOKENS,
|
|
1554
|
+
maxSteps: VALIDATION_MAX_STEPS,
|
|
1555
|
+
prices: SONNET_5_PRICES
|
|
1556
|
+
}
|
|
1557
|
+
};
|
|
1558
|
+
function getModelProfile(profileName) {
|
|
1559
|
+
return MODEL_PROFILES[profileName];
|
|
1560
|
+
}
|
|
1561
|
+
function providerOptionsForProfile(profileName) {
|
|
1562
|
+
const profile = getModelProfile(profileName);
|
|
1563
|
+
return {
|
|
1564
|
+
thinking: { type: profile.thinking },
|
|
1565
|
+
...profile.effort !== void 0 && { effort: profile.effort }
|
|
1566
|
+
};
|
|
1567
|
+
}
|
|
1568
|
+
function tokenCount(value = NO_TOKENS) {
|
|
1569
|
+
return value;
|
|
1570
|
+
}
|
|
1571
|
+
function estimateModelCost(profileName, usage) {
|
|
1572
|
+
const { prices } = getModelProfile(profileName);
|
|
1573
|
+
const inputDetails = Object.assign({}, usage.inputTokenDetails);
|
|
1574
|
+
const cacheRead = tokenCount(inputDetails.cacheReadTokens);
|
|
1575
|
+
const cacheWrite = tokenCount(inputDetails.cacheWriteTokens);
|
|
1576
|
+
const input = Math.max(
|
|
1577
|
+
NO_TOKENS,
|
|
1578
|
+
tokenCount(usage.inputTokens) - cacheRead - cacheWrite
|
|
1579
|
+
);
|
|
1580
|
+
const output = tokenCount(usage.outputTokens);
|
|
1581
|
+
return (input * prices.input + cacheRead * prices.cacheRead + cacheWrite * prices.cacheWrite + output * prices.output) / TOKENS_PER_MILLION;
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1493
1584
|
// src/lib/telemetry.ts
|
|
1585
|
+
var COUNT_METRIC = 1;
|
|
1586
|
+
var GAUGE_METRIC = 3;
|
|
1587
|
+
var FIRST_ATTEMPT = 1;
|
|
1588
|
+
var NO_TOKENS2 = 0;
|
|
1589
|
+
var AGENT_TELEMETRY_CONTEXT = {
|
|
1590
|
+
appId: void 0,
|
|
1591
|
+
workflowId: void 0
|
|
1592
|
+
};
|
|
1494
1593
|
function isTelemetryOptedOut() {
|
|
1495
1594
|
return process.env.WIZARD_TELEMETRY === "false";
|
|
1496
1595
|
}
|
|
@@ -1537,6 +1636,110 @@ function sendMetric(name, value, type, tags = []) {
|
|
|
1537
1636
|
function metricTags(workflowId, actionId) {
|
|
1538
1637
|
return actionId ? [`workflow:${workflowId}`, `action:${actionId}`] : [`workflow:${workflowId}`];
|
|
1539
1638
|
}
|
|
1639
|
+
function agentMetricTags(event, workflowId) {
|
|
1640
|
+
const profile = getModelProfile(event.profile);
|
|
1641
|
+
return [
|
|
1642
|
+
...workflowId ? [`workflow:${workflowId}`] : [],
|
|
1643
|
+
`operation:${event.operation}`,
|
|
1644
|
+
`profile:${event.profile}`,
|
|
1645
|
+
`model:${profile.model}`,
|
|
1646
|
+
`effort:${profile.effort ?? "none"}`,
|
|
1647
|
+
`thinking:${profile.thinking}`
|
|
1648
|
+
];
|
|
1649
|
+
}
|
|
1650
|
+
function agentRunValues(event) {
|
|
1651
|
+
const usage = Object.assign({}, event.usage);
|
|
1652
|
+
const inputTokenDetails = Object.assign({}, usage.inputTokenDetails);
|
|
1653
|
+
return {
|
|
1654
|
+
inputTokens: usage.inputTokens ?? NO_TOKENS2,
|
|
1655
|
+
outputTokens: usage.outputTokens ?? NO_TOKENS2,
|
|
1656
|
+
cacheReadTokens: inputTokenDetails.cacheReadTokens ?? NO_TOKENS2,
|
|
1657
|
+
cacheWriteTokens: inputTokenDetails.cacheWriteTokens ?? NO_TOKENS2,
|
|
1658
|
+
estimatedCostUsd: estimateModelCost(event.profile, usage)
|
|
1659
|
+
};
|
|
1660
|
+
}
|
|
1661
|
+
function agentRunMetrics(event, values, tags) {
|
|
1662
|
+
const runTags = [...tags];
|
|
1663
|
+
return [
|
|
1664
|
+
{
|
|
1665
|
+
name: "wizard.agent.duration_ms",
|
|
1666
|
+
value: event.durationMs,
|
|
1667
|
+
type: GAUGE_METRIC,
|
|
1668
|
+
tags: runTags
|
|
1669
|
+
},
|
|
1670
|
+
{
|
|
1671
|
+
name: "wizard.agent.input_tokens",
|
|
1672
|
+
value: values.inputTokens,
|
|
1673
|
+
type: COUNT_METRIC,
|
|
1674
|
+
tags: runTags
|
|
1675
|
+
},
|
|
1676
|
+
{
|
|
1677
|
+
name: "wizard.agent.output_tokens",
|
|
1678
|
+
value: values.outputTokens,
|
|
1679
|
+
type: COUNT_METRIC,
|
|
1680
|
+
tags: runTags
|
|
1681
|
+
},
|
|
1682
|
+
{
|
|
1683
|
+
name: "wizard.agent.cache_read_tokens",
|
|
1684
|
+
value: values.cacheReadTokens,
|
|
1685
|
+
type: COUNT_METRIC,
|
|
1686
|
+
tags: runTags
|
|
1687
|
+
},
|
|
1688
|
+
{
|
|
1689
|
+
name: "wizard.agent.cache_write_tokens",
|
|
1690
|
+
value: values.cacheWriteTokens,
|
|
1691
|
+
type: COUNT_METRIC,
|
|
1692
|
+
tags: runTags
|
|
1693
|
+
},
|
|
1694
|
+
{
|
|
1695
|
+
name: "wizard.agent.estimated_cost_usd",
|
|
1696
|
+
value: values.estimatedCostUsd,
|
|
1697
|
+
type: COUNT_METRIC,
|
|
1698
|
+
tags: runTags
|
|
1699
|
+
},
|
|
1700
|
+
{
|
|
1701
|
+
name: "wizard.agent.retry",
|
|
1702
|
+
value: Number(event.attempt > FIRST_ATTEMPT),
|
|
1703
|
+
type: COUNT_METRIC,
|
|
1704
|
+
tags: runTags
|
|
1705
|
+
}
|
|
1706
|
+
];
|
|
1707
|
+
}
|
|
1708
|
+
function trackAgentRun(event) {
|
|
1709
|
+
const profile = getModelProfile(event.profile);
|
|
1710
|
+
const values = agentRunValues(event);
|
|
1711
|
+
const tagsForMetrics = agentMetricTags(
|
|
1712
|
+
event,
|
|
1713
|
+
AGENT_TELEMETRY_CONTEXT.workflowId
|
|
1714
|
+
);
|
|
1715
|
+
const tags = [
|
|
1716
|
+
...tagsForMetrics,
|
|
1717
|
+
...AGENT_TELEMETRY_CONTEXT.appId ? [`app_id:${AGENT_TELEMETRY_CONTEXT.appId}`] : []
|
|
1718
|
+
];
|
|
1719
|
+
sendTelemetry({
|
|
1720
|
+
logs: [
|
|
1721
|
+
{
|
|
1722
|
+
status: "info",
|
|
1723
|
+
message: "wizard agent completed",
|
|
1724
|
+
attributes: {
|
|
1725
|
+
event: "wizard.agent.complete",
|
|
1726
|
+
operation: event.operation,
|
|
1727
|
+
profile: event.profile,
|
|
1728
|
+
model: profile.model,
|
|
1729
|
+
effort: profile.effort ?? "none",
|
|
1730
|
+
thinking: profile.thinking,
|
|
1731
|
+
attempt: event.attempt,
|
|
1732
|
+
durationMs: event.durationMs,
|
|
1733
|
+
workflow_id: AGENT_TELEMETRY_CONTEXT.workflowId,
|
|
1734
|
+
app_id: AGENT_TELEMETRY_CONTEXT.appId,
|
|
1735
|
+
...values
|
|
1736
|
+
},
|
|
1737
|
+
tags
|
|
1738
|
+
}
|
|
1739
|
+
],
|
|
1740
|
+
metrics: agentRunMetrics(event, values, tagsForMetrics)
|
|
1741
|
+
});
|
|
1742
|
+
}
|
|
1540
1743
|
function logTags(workflowId, actionId, appId) {
|
|
1541
1744
|
return [
|
|
1542
1745
|
...metricTags(workflowId, actionId),
|
|
@@ -1552,6 +1755,8 @@ function emitTelemetryLog(level, message, attributes, tags) {
|
|
|
1552
1755
|
sendLog(level, message, attributes, tags);
|
|
1553
1756
|
}
|
|
1554
1757
|
function trackWorkflowStart(ctx) {
|
|
1758
|
+
AGENT_TELEMETRY_CONTEXT.appId = ctx.appId;
|
|
1759
|
+
AGENT_TELEMETRY_CONTEXT.workflowId = ctx.workflowId;
|
|
1555
1760
|
const attributes = {
|
|
1556
1761
|
event: "wizard.workflow.start",
|
|
1557
1762
|
workflow_id: ctx.workflowId,
|
|
@@ -1677,6 +1882,8 @@ function trackWizardComplete(event) {
|
|
|
1677
1882
|
attributes,
|
|
1678
1883
|
logTags(event.workflowId, void 0, event.appId)
|
|
1679
1884
|
);
|
|
1885
|
+
AGENT_TELEMETRY_CONTEXT.appId = void 0;
|
|
1886
|
+
AGENT_TELEMETRY_CONTEXT.workflowId = void 0;
|
|
1680
1887
|
}
|
|
1681
1888
|
function trackWorkflowError(ctx) {
|
|
1682
1889
|
const attributes = {
|
|
@@ -1693,6 +1900,8 @@ function trackWorkflowError(ctx) {
|
|
|
1693
1900
|
attributes,
|
|
1694
1901
|
logTags(ctx.workflowId, ctx.actionId, ctx.appId)
|
|
1695
1902
|
);
|
|
1903
|
+
AGENT_TELEMETRY_CONTEXT.appId = void 0;
|
|
1904
|
+
AGENT_TELEMETRY_CONTEXT.workflowId = void 0;
|
|
1696
1905
|
}
|
|
1697
1906
|
|
|
1698
1907
|
// src/lib/events.ts
|
|
@@ -1760,7 +1969,7 @@ function identify(traits) {
|
|
|
1760
1969
|
// package.json
|
|
1761
1970
|
var package_default = {
|
|
1762
1971
|
name: "@algolia/wizard",
|
|
1763
|
-
version: "0.
|
|
1972
|
+
version: "0.68.0",
|
|
1764
1973
|
description: "Magically implement Algolia functionality in your codebase",
|
|
1765
1974
|
type: "module",
|
|
1766
1975
|
engines: {
|
|
@@ -2306,7 +2515,8 @@ import {
|
|
|
2306
2515
|
hasToolCall,
|
|
2307
2516
|
Output as Output3,
|
|
2308
2517
|
APICallError,
|
|
2309
|
-
NoOutputGeneratedError
|
|
2518
|
+
NoOutputGeneratedError,
|
|
2519
|
+
stepCountIs
|
|
2310
2520
|
} from "ai";
|
|
2311
2521
|
import { createAnthropic as createAnthropic3 } from "@ai-sdk/anthropic";
|
|
2312
2522
|
import "zod";
|
|
@@ -2806,10 +3016,10 @@ var GIT_ENV_OVERRIDES = [
|
|
|
2806
3016
|
function gitSucceeds(root, args) {
|
|
2807
3017
|
const env = { ...process.env };
|
|
2808
3018
|
for (const key of GIT_ENV_OVERRIDES) delete env[key];
|
|
2809
|
-
return new Promise((
|
|
3019
|
+
return new Promise((resolve5) => {
|
|
2810
3020
|
execFile("git", ["-C", root, ...args], { env }, (err) => {
|
|
2811
|
-
if (!err) return
|
|
2812
|
-
|
|
3021
|
+
if (!err) return resolve5(true);
|
|
3022
|
+
resolve5(
|
|
2813
3023
|
err.code === 1 ? false : void 0
|
|
2814
3024
|
);
|
|
2815
3025
|
});
|
|
@@ -3256,7 +3466,7 @@ var SIGKILL_DELAY_MS = 5e3;
|
|
|
3256
3466
|
function runShell(command, opts) {
|
|
3257
3467
|
const timeoutMs = opts.timeoutMs ?? DEFAULT_SHELL_TIMEOUT_MS;
|
|
3258
3468
|
const startedAt = Date.now();
|
|
3259
|
-
return new Promise((
|
|
3469
|
+
return new Promise((resolve5) => {
|
|
3260
3470
|
let output = "";
|
|
3261
3471
|
let timedOut = false;
|
|
3262
3472
|
let settled = false;
|
|
@@ -3271,7 +3481,7 @@ function runShell(command, opts) {
|
|
|
3271
3481
|
settled = true;
|
|
3272
3482
|
clearTimeout(timer);
|
|
3273
3483
|
clearTimeout(killTimer);
|
|
3274
|
-
|
|
3484
|
+
resolve5({
|
|
3275
3485
|
exitCode,
|
|
3276
3486
|
output: truncateText(output.trim()),
|
|
3277
3487
|
timedOut,
|
|
@@ -3297,6 +3507,7 @@ function runShell(command, opts) {
|
|
|
3297
3507
|
}
|
|
3298
3508
|
|
|
3299
3509
|
// src/lib/tools/runShell.ts
|
|
3510
|
+
var CLASSIFIER_MAX_OUTPUT_TOKENS = 512;
|
|
3300
3511
|
function storeApproval(root) {
|
|
3301
3512
|
return async (req) => {
|
|
3302
3513
|
const store = useWizard.getState();
|
|
@@ -3510,7 +3721,6 @@ function fastPathSafety(command) {
|
|
|
3510
3721
|
if (results.every((r) => r === true)) return true;
|
|
3511
3722
|
return void 0;
|
|
3512
3723
|
}
|
|
3513
|
-
var CLASSIFIER_MODEL = "claude-haiku-4-5";
|
|
3514
3724
|
var commandSafetySchema = z16.object({
|
|
3515
3725
|
safe: z16.boolean(),
|
|
3516
3726
|
reason: z16.string().describe("One short sentence explaining the verdict.")
|
|
@@ -3528,16 +3738,28 @@ function defaultCreateModel() {
|
|
|
3528
3738
|
}
|
|
3529
3739
|
function approvedCommandHistory(approvedCommands) {
|
|
3530
3740
|
return Array.from(approvedCommands).map((entry) => {
|
|
3531
|
-
const
|
|
3532
|
-
return { cwd: entry.slice(0,
|
|
3741
|
+
const sep3 = entry.indexOf("\0");
|
|
3742
|
+
return { cwd: entry.slice(0, sep3), command: entry.slice(sep3 + 1) };
|
|
3533
3743
|
});
|
|
3534
3744
|
}
|
|
3535
3745
|
async function classifyCommandSafety(createModel, command, cwd, explanation, approvedHistory) {
|
|
3536
3746
|
try {
|
|
3537
3747
|
const anthropic = createModel();
|
|
3538
|
-
const
|
|
3539
|
-
|
|
3748
|
+
const profile = getModelProfile("quick" /* quick */);
|
|
3749
|
+
const modelOptions = providerOptionsForProfile("quick" /* quick */);
|
|
3750
|
+
const startedAt = Date.now();
|
|
3751
|
+
const { output, usage } = await generateText({
|
|
3752
|
+
model: anthropic(profile.model),
|
|
3753
|
+
maxOutputTokens: CLASSIFIER_MAX_OUTPUT_TOKENS,
|
|
3540
3754
|
temperature: 0,
|
|
3755
|
+
providerOptions: {
|
|
3756
|
+
anthropic: {
|
|
3757
|
+
thinking: modelOptions.thinking,
|
|
3758
|
+
...modelOptions.effort !== void 0 && {
|
|
3759
|
+
effort: modelOptions.effort
|
|
3760
|
+
}
|
|
3761
|
+
}
|
|
3762
|
+
},
|
|
3541
3763
|
output: Output.object({ schema: commandSafetySchema }),
|
|
3542
3764
|
prompt: [
|
|
3543
3765
|
"A coding agent wants to run this shell command in a user's project without asking for approval first. The command may be in any programming language or ecosystem.",
|
|
@@ -3558,6 +3780,13 @@ async function classifyCommandSafety(createModel, command, cwd, explanation, app
|
|
|
3558
3780
|
`Stated purpose: ${explanation}`
|
|
3559
3781
|
].join("\n")
|
|
3560
3782
|
});
|
|
3783
|
+
trackAgentRun({
|
|
3784
|
+
operation: "shell-safety-classifier",
|
|
3785
|
+
profile: "quick" /* quick */,
|
|
3786
|
+
attempt: INITIAL_MODEL_ATTEMPT,
|
|
3787
|
+
durationMs: Date.now() - startedAt,
|
|
3788
|
+
usage
|
|
3789
|
+
});
|
|
3561
3790
|
if (!output.safe) {
|
|
3562
3791
|
logger.info(
|
|
3563
3792
|
{ command, reason: output.reason },
|
|
@@ -3702,7 +3931,6 @@ import { createAnthropic as createAnthropic2 } from "@ai-sdk/anthropic";
|
|
|
3702
3931
|
import { nanoid as nanoid2 } from "nanoid";
|
|
3703
3932
|
import z17 from "zod";
|
|
3704
3933
|
var DATA_DIR = ".algolia-wizard/data";
|
|
3705
|
-
var RECORD_MODEL = "claude-haiku-4-5";
|
|
3706
3934
|
var MAX_RECORDS = 100;
|
|
3707
3935
|
var BATCH_SIZE = 10;
|
|
3708
3936
|
var MAX_BATCH_ATTEMPTS = 3;
|
|
@@ -3737,9 +3965,21 @@ function generateRecordTool(ctx, createModel = defaultCreateModel2) {
|
|
|
3737
3965
|
const generateBatch = async (batchCount) => {
|
|
3738
3966
|
let lastError;
|
|
3739
3967
|
for (let attempt = 1; attempt <= MAX_BATCH_ATTEMPTS; attempt++) {
|
|
3968
|
+
const profile = getModelProfile("quick" /* quick */);
|
|
3969
|
+
const modelOptions = providerOptionsForProfile("quick" /* quick */);
|
|
3970
|
+
const startedAt = Date.now();
|
|
3740
3971
|
try {
|
|
3741
|
-
const { output } = await generateText2({
|
|
3742
|
-
model: anthropic(
|
|
3972
|
+
const { output, usage } = await generateText2({
|
|
3973
|
+
model: anthropic(profile.model),
|
|
3974
|
+
maxOutputTokens: profile.maxOutputTokens,
|
|
3975
|
+
providerOptions: {
|
|
3976
|
+
anthropic: {
|
|
3977
|
+
thinking: modelOptions.thinking,
|
|
3978
|
+
...modelOptions.effort !== void 0 && {
|
|
3979
|
+
effort: modelOptions.effort
|
|
3980
|
+
}
|
|
3981
|
+
}
|
|
3982
|
+
},
|
|
3743
3983
|
output: Output2.object({
|
|
3744
3984
|
schema: z17.object({
|
|
3745
3985
|
records: z17.array(recordSchema2).length(batchCount)
|
|
@@ -3751,9 +3991,23 @@ function generateRecordTool(ctx, createModel = defaultCreateModel2) {
|
|
|
3751
3991
|
`Variety seed: ${nanoid2()}. Use it to diversify values.`
|
|
3752
3992
|
].filter(Boolean).join("\n")
|
|
3753
3993
|
});
|
|
3994
|
+
trackAgentRun({
|
|
3995
|
+
operation: "sample-record-generation",
|
|
3996
|
+
profile: "quick" /* quick */,
|
|
3997
|
+
attempt,
|
|
3998
|
+
durationMs: Date.now() - startedAt,
|
|
3999
|
+
usage
|
|
4000
|
+
});
|
|
3754
4001
|
return output.records;
|
|
3755
4002
|
} catch (err) {
|
|
3756
4003
|
if (!NoObjectGeneratedError.isInstance(err)) throw err;
|
|
4004
|
+
trackAgentRun({
|
|
4005
|
+
operation: "sample-record-generation",
|
|
4006
|
+
profile: "quick" /* quick */,
|
|
4007
|
+
attempt,
|
|
4008
|
+
durationMs: Date.now() - startedAt,
|
|
4009
|
+
usage: err.usage
|
|
4010
|
+
});
|
|
3757
4011
|
lastError = err;
|
|
3758
4012
|
logger.warn(
|
|
3759
4013
|
{ entityName, batchCount, attempt, err },
|
|
@@ -3867,14 +4121,10 @@ var FS_READ_TOOLS = [
|
|
|
3867
4121
|
];
|
|
3868
4122
|
|
|
3869
4123
|
// src/lib/agent.ts
|
|
3870
|
-
var MODEL_BY_SIZE = {
|
|
3871
|
-
small: "claude-haiku-4-5",
|
|
3872
|
-
medium: "claude-sonnet-4-6",
|
|
3873
|
-
large: "claude-opus-4-8"
|
|
3874
|
-
};
|
|
3875
4124
|
var MISSING_REPORT_STATUS_ERROR_MESSAGE = "Agent finished without calling reportStatus";
|
|
3876
4125
|
var MISSING_REPORT_USER_MESSAGE = "This step ran into a problem finishing. Run the wizard again to retry it.";
|
|
3877
4126
|
var REPORT_STATUS_RETRIES = 2;
|
|
4127
|
+
var ATTEMPT_NUMBER_OFFSET = 1;
|
|
3878
4128
|
var PROVIDER_ERROR_USER_MESSAGE = "The AI service had trouble responding. Run the wizard again to retry this step.";
|
|
3879
4129
|
function retryKind(err) {
|
|
3880
4130
|
if (err instanceof Error && err.message === MISSING_REPORT_STATUS_ERROR_MESSAGE) {
|
|
@@ -3907,7 +4157,20 @@ async function runAgent(req) {
|
|
|
3907
4157
|
}
|
|
3908
4158
|
async function runAgentAttempt(req, attempt) {
|
|
3909
4159
|
const start = Date.now();
|
|
3910
|
-
|
|
4160
|
+
const profileName = req.modelProfile ?? "implementation" /* implementation */;
|
|
4161
|
+
const profile = getModelProfile(profileName);
|
|
4162
|
+
const modelOptions = providerOptionsForProfile(profileName);
|
|
4163
|
+
logger.info(
|
|
4164
|
+
{
|
|
4165
|
+
startedAt: new Date(start).toISOString(),
|
|
4166
|
+
operation: req.operation,
|
|
4167
|
+
profile: profileName,
|
|
4168
|
+
model: profile.model,
|
|
4169
|
+
effort: profile.effort,
|
|
4170
|
+
thinking: profile.thinking
|
|
4171
|
+
},
|
|
4172
|
+
"runAgent started"
|
|
4173
|
+
);
|
|
3911
4174
|
const token = getAuthToken();
|
|
3912
4175
|
if (!token) {
|
|
3913
4176
|
throw new Error("Not authenticated: no user token available");
|
|
@@ -3934,7 +4197,16 @@ async function runAgentAttempt(req, attempt) {
|
|
|
3934
4197
|
] : []
|
|
3935
4198
|
];
|
|
3936
4199
|
const agent = new ToolLoopAgent({
|
|
3937
|
-
model: anthropic(
|
|
4200
|
+
model: anthropic(profile.model),
|
|
4201
|
+
maxOutputTokens: profile.maxOutputTokens,
|
|
4202
|
+
providerOptions: {
|
|
4203
|
+
anthropic: {
|
|
4204
|
+
thinking: modelOptions.thinking,
|
|
4205
|
+
...modelOptions.effort !== void 0 && {
|
|
4206
|
+
effort: modelOptions.effort
|
|
4207
|
+
}
|
|
4208
|
+
}
|
|
4209
|
+
},
|
|
3938
4210
|
// Cache tools + system on the last system block. Tools render before
|
|
3939
4211
|
// system, so one breakpoint here caches both, reused on every loop turn
|
|
3940
4212
|
// after the first.
|
|
@@ -3955,7 +4227,10 @@ async function runAgentAttempt(req, attempt) {
|
|
|
3955
4227
|
tools: req.tools
|
|
3956
4228
|
}),
|
|
3957
4229
|
toolChoice: "required",
|
|
3958
|
-
stopWhen: [
|
|
4230
|
+
stopWhen: [
|
|
4231
|
+
hasToolCall("reportStatus"),
|
|
4232
|
+
stepCountIs(profile.maxSteps)
|
|
4233
|
+
]
|
|
3959
4234
|
});
|
|
3960
4235
|
const stream = await agent.stream({
|
|
3961
4236
|
prompt: "Follow system instructions"
|
|
@@ -3986,13 +4261,20 @@ async function runAgentAttempt(req, attempt) {
|
|
|
3986
4261
|
}
|
|
3987
4262
|
const end = Date.now();
|
|
3988
4263
|
const usage = await stream.totalUsage;
|
|
4264
|
+
trackAgentRun({
|
|
4265
|
+
operation: req.operation,
|
|
4266
|
+
profile: profileName,
|
|
4267
|
+
attempt: attempt + ATTEMPT_NUMBER_OFFSET,
|
|
4268
|
+
durationMs: end - start,
|
|
4269
|
+
usage
|
|
4270
|
+
});
|
|
3989
4271
|
logger.info(
|
|
3990
4272
|
{
|
|
3991
4273
|
finishedAt: new Date(end).toISOString(),
|
|
3992
4274
|
durationMs: end - start,
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
4275
|
+
operation: req.operation,
|
|
4276
|
+
profile: profileName,
|
|
4277
|
+
model: profile.model,
|
|
3996
4278
|
usage
|
|
3997
4279
|
},
|
|
3998
4280
|
"runAgent finished"
|
|
@@ -4073,6 +4355,7 @@ function prioritizeFrontendFrameworks(result) {
|
|
|
4073
4355
|
}
|
|
4074
4356
|
var detectLanguage = async () => {
|
|
4075
4357
|
const result = await runAgent({
|
|
4358
|
+
operation: "language-detection",
|
|
4076
4359
|
instructions: [
|
|
4077
4360
|
"Analyze the codebase and determine the programming languages and frameworks used",
|
|
4078
4361
|
"If a superset language is found, exclude the subset language (e.g. TypeScript over JavaScript).",
|
|
@@ -4088,7 +4371,7 @@ var detectLanguage = async () => {
|
|
|
4088
4371
|
],
|
|
4089
4372
|
tools: ["listFiles", "changeDirectory", "readFile", "searchFiles"],
|
|
4090
4373
|
outputSchema: detectLanguageSchema,
|
|
4091
|
-
|
|
4374
|
+
modelProfile: "quick" /* quick */
|
|
4092
4375
|
});
|
|
4093
4376
|
return prioritizeFrontendFrameworks(result);
|
|
4094
4377
|
};
|
|
@@ -4164,9 +4447,11 @@ var MODE_CONFIG = {
|
|
|
4164
4447
|
function runMode(mode, extraInstructions = []) {
|
|
4165
4448
|
const { instructions, outputSchema } = MODE_CONFIG[mode];
|
|
4166
4449
|
return runAgent({
|
|
4450
|
+
operation: `code-analysis-${mode}`,
|
|
4167
4451
|
instructions: [...instructions, ...extraInstructions],
|
|
4168
4452
|
tools: READONLY_TOOLS,
|
|
4169
|
-
outputSchema
|
|
4453
|
+
outputSchema,
|
|
4454
|
+
modelProfile: "analysis" /* analysis */
|
|
4170
4455
|
});
|
|
4171
4456
|
}
|
|
4172
4457
|
async function runAnalysis(mode, extraInstructions = []) {
|
|
@@ -4544,6 +4829,7 @@ ${JSON.stringify(s.output, null, 2)}`
|
|
|
4544
4829
|
}
|
|
4545
4830
|
var reviewStep = async (ctx, options) => {
|
|
4546
4831
|
const result = await runAgent({
|
|
4832
|
+
operation: "workflow-review",
|
|
4547
4833
|
instructions: [
|
|
4548
4834
|
"Summarize what was accomplished in the workflow, leaving out verbose details.",
|
|
4549
4835
|
"Base your summary only on the step outputs provided \u2014 do not read the repository.",
|
|
@@ -4558,7 +4844,7 @@ ${formatCompletedSteps(ctx.completedSteps)}`,
|
|
|
4558
4844
|
],
|
|
4559
4845
|
tools: [],
|
|
4560
4846
|
outputSchema: reviewSchema,
|
|
4561
|
-
|
|
4847
|
+
modelProfile: "quick" /* quick */
|
|
4562
4848
|
});
|
|
4563
4849
|
ctx.clearNotices();
|
|
4564
4850
|
useWizard.getState().setReview(result);
|
|
@@ -4568,7 +4854,7 @@ ${formatCompletedSteps(ctx.completedSteps)}`,
|
|
|
4568
4854
|
// src/actions/implement.ts
|
|
4569
4855
|
import z28 from "zod";
|
|
4570
4856
|
import { access, mkdir as mkdir5, readFile as readFile8 } from "node:fs/promises";
|
|
4571
|
-
import { join as join10, relative as relative6 } from "node:path";
|
|
4857
|
+
import { dirname as dirname5, isAbsolute as isAbsolute3, join as join10, relative as relative6, resolve as resolve4, sep as sep2 } from "node:path";
|
|
4572
4858
|
|
|
4573
4859
|
// src/lib/git.ts
|
|
4574
4860
|
import { execFile as execFile2 } from "node:child_process";
|
|
@@ -4576,7 +4862,7 @@ import { copyFile, mkdir as mkdir4, stat as stat3 } from "node:fs/promises";
|
|
|
4576
4862
|
import { basename as basename2, dirname as dirname3, isAbsolute as isAbsolute2, join as join8, resolve as resolve3 } from "node:path";
|
|
4577
4863
|
var MAX_BUFFER = 32 * 1024 * 1024;
|
|
4578
4864
|
function git(args) {
|
|
4579
|
-
return new Promise((
|
|
4865
|
+
return new Promise((resolve5, reject) => {
|
|
4580
4866
|
execFile2("git", args, { maxBuffer: MAX_BUFFER }, (err, stdout, stderr) => {
|
|
4581
4867
|
if (err)
|
|
4582
4868
|
return reject(
|
|
@@ -4584,7 +4870,7 @@ function git(args) {
|
|
|
4584
4870
|
`git ${args.join(" ")} failed: ${stderr.toString().trim() || err.message}`
|
|
4585
4871
|
)
|
|
4586
4872
|
);
|
|
4587
|
-
|
|
4873
|
+
resolve5(stdout.toString());
|
|
4588
4874
|
});
|
|
4589
4875
|
});
|
|
4590
4876
|
}
|
|
@@ -4739,6 +5025,7 @@ var validationOutputSchema = z28.object({
|
|
|
4739
5025
|
unrelatedFailure: z28.string().optional()
|
|
4740
5026
|
});
|
|
4741
5027
|
var MAX_IMPLEMENT_VALIDATION_ATTEMPTS = 3;
|
|
5028
|
+
var FIRST_IMPLEMENTATION_ATTEMPT = 1;
|
|
4742
5029
|
var DEFAULT_IMPLEMENT_USE_CASES = ["ingestion", "search"];
|
|
4743
5030
|
var INGEST_DIR = ".algolia-wizard";
|
|
4744
5031
|
var INGESTION_SOURCE_PROMPT = "What data do you want to index?";
|
|
@@ -4846,12 +5133,22 @@ function searchInstructions(input) {
|
|
|
4846
5133
|
const entity = input.findings.confirmedEntities ? input.findings.confirmedEntities[0].name : null;
|
|
4847
5134
|
const attributes = input.findings.confirmedEntities ? input.findings.confirmedEntities[0].attributes : null;
|
|
4848
5135
|
const entitySchemaMessage = entity && attributes ? `The following entity schema should be used to build the UI: ${JSON.stringify({ entity, attributes })}` : null;
|
|
4849
|
-
const
|
|
5136
|
+
const packageManagedInstructions = input.frontendHasPackageJson ? packageSearchInstructions(input) : cdnSearchInstructions(input);
|
|
4850
5137
|
return [
|
|
4851
5138
|
"Implement an in-app Algolia search experience.",
|
|
4852
5139
|
entitySchemaMessage ?? "",
|
|
4853
5140
|
`Build the search UI for ${input.searchUiTarget}.`,
|
|
4854
5141
|
"Create search UI only. Do not create or modify ingestion scripts, rake/manage/CLI tasks, migrations, seeders, or other data-loading code, even if the data looks incomplete.",
|
|
5142
|
+
...packageManagedInstructions,
|
|
5143
|
+
"Meet WCAG AA contrast (4.5:1 body text, 3:1 large text/icons) between the panel's text and its own background, and give the input and the active result a focus indicator visible against whatever sits behind it. Style the panel through the widget's class and CSS-variable overrides (or, when hand-built, the app's existing theme tokens) \u2014 never assume a light surface or reuse the surrounding page's colors unchanged inside the panel.",
|
|
5144
|
+
"The panel takes its width from the input by default, so a small input makes it unreadably narrow: give it a min-width of 320px independent of the input, anchored to the input edge it opens from so widening does not push it off-screen.",
|
|
5145
|
+
"Match the styles of the application as closely as possible.",
|
|
5146
|
+
"The summary should be extremely concise; do not mention manual testing steps."
|
|
5147
|
+
];
|
|
5148
|
+
}
|
|
5149
|
+
function packageSearchInstructions(input) {
|
|
5150
|
+
const doc = getFrameworkSpecificDoc(frameworksForDoc(input.language));
|
|
5151
|
+
return [
|
|
4855
5152
|
...doc ? [
|
|
4856
5153
|
"Follow the Algolia SDK reference below for client setup, search UI wiring, and Insights instrumentation \u2014 Insights is required, not optional; prefer the reference over prior knowledge:",
|
|
4857
5154
|
doc
|
|
@@ -4862,16 +5159,22 @@ function searchInstructions(input) {
|
|
|
4862
5159
|
`Import and render the new component in ${input.searchLocation ? `"${input.searchLocation}"` : "the best, always-rendered layout location (e.g. a header/nav component)"} so it is reachable across the app \u2014 at least a working search input and results panel against the target index.`,
|
|
4863
5160
|
"If a search box already exists, replace its usage with an import and render of your new component; remove the old implementation.",
|
|
4864
5161
|
"When rendering results with an existing shared component (e.g. a card), import and reuse that component rather than inlining its markup \u2014 inlining silently drops the styles and behavior its own file provides.",
|
|
4865
|
-
"Meet WCAG AA contrast (4.5:1 body text, 3:1 large text/icons) between the panel's text and its own background, and give the input and the active result a focus indicator visible against whatever sits behind it. Style the panel through the widget's class and CSS-variable overrides (or, when hand-built, the app's existing theme tokens) \u2014 never assume a light surface or reuse the surrounding page's colors unchanged inside the panel.",
|
|
4866
5162
|
"Vendor theme CSS, and any CSS you write against vendor class names, must be global: import the theme from the component's own script module or the app's global stylesheet, and put overrides in a global block (Astro <style is:global>, an unscoped Vue block, a plain global CSS file). Never a framework-scoped style block or a CSS Module \u2014 scoping rewrites the vendor selectors and the widget's runtime DOM carries no scope attribute, so not one rule matches: styling silently does nothing and the build still passes.",
|
|
4867
|
-
"The panel takes its width from the input by default, so a small input makes it unreadably narrow: give it a min-width of 320px independent of the input, anchored to the input edge it opens from so widening does not push it off-screen.",
|
|
4868
5163
|
`Define ${SEARCH_CONFIG_APP_ID}, ${SEARCH_CONFIG_SEARCH_KEY}, and ${SEARCH_CONFIG_INDEX_NAME} as exported constants in a module that fits this project's existing conventions for shared client-side config \u2014 reuse an existing one if it already holds config like this, or add a small new one otherwise. These are PUBLIC values, safe to commit and expose client-side: never read them from an environment variable or a .env* file, and never hardcode them anywhere except in that one module (import them wherever the search client needs them).`,
|
|
4869
5164
|
`Set ${SEARCH_CONFIG_APP_ID} to "${input.appId}" and ${SEARCH_CONFIG_INDEX_NAME} to "${input.targetIndex}".`,
|
|
4870
5165
|
input.searchKey ? `Set ${SEARCH_CONFIG_SEARCH_KEY} to "${input.searchKey}".` : `A real search-only key could not be provisioned${input.searchKeyError ? ` (${input.searchKeyError})` : ""} \u2014 set ${SEARCH_CONFIG_SEARCH_KEY} to the placeholder "${SEARCH_KEY_PLACEHOLDER}" and add a prominent TODO for the developer to fill in a real one.`,
|
|
4871
5166
|
'Report the repo-relative path of that module as "searchConfigFile" in your final status.',
|
|
4872
|
-
"Install any Algolia packages you import with the project's own package manager via runShell, and declare them in the project's dependency manifest."
|
|
4873
|
-
|
|
4874
|
-
|
|
5167
|
+
"Install any Algolia packages you import with the project's own package manager via runShell, and declare them in the project's dependency manifest."
|
|
5168
|
+
];
|
|
5169
|
+
}
|
|
5170
|
+
function cdnSearchInstructions(input) {
|
|
5171
|
+
return [
|
|
5172
|
+
`The target frontend has no package.json. Add the search container to its existing HTML or template, create separate classic config and search scripts, define window.${SEARCH_CONFIG_APP_ID}, window.${SEARCH_CONFIG_SEARCH_KEY}, and window.${SEARCH_CONFIG_INDEX_NAME} in the config script, and report that script as "searchConfigFile". Never create package.json, create a component, use imports or exports, or run npm, pnpm, yarn, or bun.`,
|
|
5173
|
+
`Set window.${SEARCH_CONFIG_APP_ID} to "${input.appId}" and window.${SEARCH_CONFIG_INDEX_NAME} to "${input.targetIndex}".`,
|
|
5174
|
+
input.searchKey ? `Set window.${SEARCH_CONFIG_SEARCH_KEY} to "${input.searchKey}".` : `A real search-only key could not be provisioned${input.searchKeyError ? ` (${input.searchKeyError})` : ""} \u2014 set window.${SEARCH_CONFIG_SEARCH_KEY} to the placeholder "${SEARCH_KEY_PLACEHOLDER}" and add a prominent TODO for the developer to fill in a real one.`,
|
|
5175
|
+
'Load these exact pinned tags in order before the config and search scripts: <script src="https://cdn.jsdelivr.net/npm/algoliasearch@5.59.0/dist/lite/builds/browser.umd.js" integrity="sha256-pduQHl1jn0IaN/BIpSotQm7Y5THdpKcX3Bw6xdRteRw=" crossorigin="anonymous"></script> then <script src="https://cdn.jsdelivr.net/npm/instantsearch.js@4.117.0/dist/instantsearch.production.min.js" integrity="sha256-5zhKxAGeH7ThWfnmdD4pS1gsmafE2b8aWRsq8set/dc=" crossorigin="anonymous"></script>.',
|
|
5176
|
+
'When using the InstantSearch theme, load this exact tag before the application styles: <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/instantsearch.css@8.22.1/themes/satellite-min.css" integrity="sha256-5/eHPZl63VYJSDVOKrOgGe/5+owUkX3uPAW6+XYeLNc=" crossorigin="anonymous">. Never use an unversioned or differently versioned theme URL, and never omit its integrity attribute.',
|
|
5177
|
+
`In that classic search script, use window['algoliasearch/lite'].liteClient and window.instantsearch. Add window.instantsearch.widgets.autocomplete as the only search widget. Configure it with container '#autocomplete', placeholder 'Search...', and an indices array containing one object whose indexName is window.${SEARCH_CONFIG_INDEX_NAME}; put item and noResults functions in its templates option, implement getURL only for an existing route, and match the item template to the entity schema. Keep insights: true and call search.start(). Do not substitute searchBox or hits, omit indices, use imports or exports, or use type="module".`
|
|
4875
5178
|
];
|
|
4876
5179
|
}
|
|
4877
5180
|
function validationInstructions(input) {
|
|
@@ -4883,6 +5186,9 @@ function validationInstructions(input) {
|
|
|
4883
5186
|
"Do not run the test suite or any test command.",
|
|
4884
5187
|
"Do not modify files. Report each implementation issue as a concrete instruction for the next implementation pass.",
|
|
4885
5188
|
`Available type-check and lint tools: ${JSON.stringify(input.findings.verification ?? [])}.`,
|
|
5189
|
+
...!input.frontendHasPackageJson ? [
|
|
5190
|
+
"The frontend has no package.json: never create one or run npm, pnpm, yarn, or bun. Validate the CDN implementation by inspecting its HTML or template and classic scripts for the search container, Algolia \u2192 InstantSearch \u2192 config \u2192 search load order, browser globals, autocomplete widget configuration, search.start(), and exact pinned CDN URLs and integrity attributes for every Algolia script or stylesheet. Source inspection is required even when the project has no automated checks. window.instantsearch.widgets.autocomplete is a real widget in the pinned InstantSearch build; do not report its use as an error, and do not fetch a remote bundle or URL to verify it."
|
|
5191
|
+
] : [],
|
|
4886
5192
|
"Always call reportStatus with status=success after validation, even when sufficient=false.",
|
|
4887
5193
|
"Set sufficient=true only when the search bar is unique, correctly placed, and structurally complete.",
|
|
4888
5194
|
"Set sufficient=false for an implementation issue. Include concrete additionalInstructions for the next pass.",
|
|
@@ -5038,11 +5344,25 @@ async function pathExists(path) {
|
|
|
5038
5344
|
return false;
|
|
5039
5345
|
}
|
|
5040
5346
|
}
|
|
5347
|
+
async function frontendHasPackageJson(repoRoot, searchLocation) {
|
|
5348
|
+
let directory = repoRoot;
|
|
5349
|
+
if (searchLocation) {
|
|
5350
|
+
const candidate = dirname5(resolve4(repoRoot, searchLocation));
|
|
5351
|
+
const candidateRelative = relative6(repoRoot, candidate);
|
|
5352
|
+
const outsideRoot = candidateRelative === ".." || candidateRelative.startsWith(`..${sep2}`) || isAbsolute3(candidateRelative);
|
|
5353
|
+
if (!outsideRoot) directory = candidate;
|
|
5354
|
+
}
|
|
5355
|
+
for (; ; ) {
|
|
5356
|
+
if (await pathExists(join10(directory, "package.json"))) return true;
|
|
5357
|
+
if (directory === repoRoot) return false;
|
|
5358
|
+
directory = dirname5(directory);
|
|
5359
|
+
}
|
|
5360
|
+
}
|
|
5041
5361
|
async function resolveBuildCheckPlan(ctx, repoRoot, input) {
|
|
5042
5362
|
if (!input.findings.verification?.length) {
|
|
5043
5363
|
return { run: false, installDependencies: false };
|
|
5044
5364
|
}
|
|
5045
|
-
const installDependencies = isJsProject(input.language) && !await pathExists(join10(repoRoot, "node_modules"));
|
|
5365
|
+
const installDependencies = input.frontendHasPackageJson && isJsProject(input.language) && !await pathExists(join10(repoRoot, "node_modules"));
|
|
5046
5366
|
const accepted = Boolean(
|
|
5047
5367
|
await ctx.requestUserInput({
|
|
5048
5368
|
prompt: installDependencies ? MISSING_DEPENDENCIES_PROMPT : BUILD_CHECK_PROMPT,
|
|
@@ -5220,7 +5540,11 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
|
|
|
5220
5540
|
ingestDir: INGEST_DIR,
|
|
5221
5541
|
ingestionSource,
|
|
5222
5542
|
uploadFilePath,
|
|
5223
|
-
searchUiTarget: searchUiTarget(language)
|
|
5543
|
+
searchUiTarget: searchUiTarget(language),
|
|
5544
|
+
frontendHasPackageJson: await frontendHasPackageJson(
|
|
5545
|
+
repoRoot,
|
|
5546
|
+
searchLocation
|
|
5547
|
+
)
|
|
5224
5548
|
};
|
|
5225
5549
|
let agentRuns = 0;
|
|
5226
5550
|
let ingestCommand;
|
|
@@ -5235,10 +5559,11 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
|
|
|
5235
5559
|
[INDEX_NAME_VAR]: targetIndex
|
|
5236
5560
|
})) : void 0;
|
|
5237
5561
|
const searchTools = makeToolContext(repoRoot);
|
|
5238
|
-
async function runImplementationUseCase(currentUseCase, extraInstructions = []) {
|
|
5562
|
+
async function runImplementationUseCase(currentUseCase, extraInstructions = [], isRetry = false) {
|
|
5239
5563
|
if (agentRuns > 0) ctx.recordStepExecution();
|
|
5240
5564
|
agentRuns += 1;
|
|
5241
5565
|
return runAgent({
|
|
5566
|
+
operation: `${currentUseCase}-implementation`,
|
|
5242
5567
|
instructions: buildAgentInstructions(
|
|
5243
5568
|
currentUseCase,
|
|
5244
5569
|
input,
|
|
@@ -5246,6 +5571,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
|
|
|
5246
5571
|
),
|
|
5247
5572
|
tools: toolsForUseCase(currentUseCase, input.ingestionSource),
|
|
5248
5573
|
outputSchema: implementationOutputSchema,
|
|
5574
|
+
modelProfile: isRetry ? "implementationRetry" /* implementationRetry */ : "implementation" /* implementation */,
|
|
5249
5575
|
toolContext: currentUseCase === "ingestion" ? ingestionTools ?? searchTools : searchTools
|
|
5250
5576
|
});
|
|
5251
5577
|
}
|
|
@@ -5253,6 +5579,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
|
|
|
5253
5579
|
if (agentRuns > 0) ctx.recordStepExecution();
|
|
5254
5580
|
agentRuns += 1;
|
|
5255
5581
|
return runAgent({
|
|
5582
|
+
operation: "search-validation",
|
|
5256
5583
|
instructions: buildAgentInstructions(
|
|
5257
5584
|
"validation",
|
|
5258
5585
|
input,
|
|
@@ -5260,6 +5587,7 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
|
|
|
5260
5587
|
),
|
|
5261
5588
|
tools: toolsForUseCase("validation"),
|
|
5262
5589
|
outputSchema: validationOutputSchema,
|
|
5590
|
+
modelProfile: "validation" /* validation */,
|
|
5263
5591
|
toolContext: searchTools
|
|
5264
5592
|
});
|
|
5265
5593
|
}
|
|
@@ -5393,8 +5721,8 @@ ${detail}` : ""}`
|
|
|
5393
5721
|
});
|
|
5394
5722
|
};
|
|
5395
5723
|
useWizard.getState().clearWrittenFiles();
|
|
5396
|
-
for (let attempt =
|
|
5397
|
-
if (attempt >
|
|
5724
|
+
for (let attempt = FIRST_IMPLEMENTATION_ATTEMPT; attempt <= MAX_IMPLEMENT_VALIDATION_ATTEMPTS; attempt++) {
|
|
5725
|
+
if (attempt > FIRST_IMPLEMENTATION_ATTEMPT) {
|
|
5398
5726
|
logger.info(
|
|
5399
5727
|
{
|
|
5400
5728
|
attempt,
|
|
@@ -5406,7 +5734,8 @@ ${detail}` : ""}`
|
|
|
5406
5734
|
}
|
|
5407
5735
|
const searchResult = await runImplementationUseCase(
|
|
5408
5736
|
"search",
|
|
5409
|
-
extraInstructions
|
|
5737
|
+
extraInstructions,
|
|
5738
|
+
attempt > FIRST_IMPLEMENTATION_ATTEMPT
|
|
5410
5739
|
);
|
|
5411
5740
|
summaries.push(formatSummary("search", searchResult.summary));
|
|
5412
5741
|
if (searchResult.searchConfigFile) {
|
|
@@ -5800,7 +6129,7 @@ function getWorkflow(id) {
|
|
|
5800
6129
|
}
|
|
5801
6130
|
|
|
5802
6131
|
// src/ui/Welcome.tsx
|
|
5803
|
-
import { dirname as
|
|
6132
|
+
import { dirname as dirname6, join as join11 } from "node:path";
|
|
5804
6133
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
5805
6134
|
import { useState as useState10 } from "react";
|
|
5806
6135
|
import { Box as Box11, Spacer, Text as Text12, useInput as useInput6, useWindowSize as useWindowSize5 } from "ink";
|
|
@@ -5832,7 +6161,7 @@ var sidebarItems = [
|
|
|
5832
6161
|
// src/ui/Welcome.tsx
|
|
5833
6162
|
import Image, { TerminalInfoContext, defaultTerminalInfo } from "ink-picture";
|
|
5834
6163
|
import { jsx as jsx10, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
5835
|
-
var IMAGE_PATH = join11(
|
|
6164
|
+
var IMAGE_PATH = join11(dirname6(fileURLToPath2(import.meta.url)), "algolia.png");
|
|
5836
6165
|
var TERMINAL_INFO = {
|
|
5837
6166
|
...defaultTerminalInfo,
|
|
5838
6167
|
supportsUnicode: true,
|
|
@@ -7150,11 +7479,11 @@ async function requestTerminalSize(stdout = process.stdout, {
|
|
|
7150
7479
|
stdout.write("\x1B[2J\x1B[H");
|
|
7151
7480
|
}
|
|
7152
7481
|
function waitForResize(stdout, timeoutMs) {
|
|
7153
|
-
return new Promise((
|
|
7482
|
+
return new Promise((resolve5) => {
|
|
7154
7483
|
const finish = (didResize) => () => {
|
|
7155
7484
|
clearTimeout(timer);
|
|
7156
7485
|
stdout.off("resize", onResize);
|
|
7157
|
-
|
|
7486
|
+
resolve5(didResize);
|
|
7158
7487
|
};
|
|
7159
7488
|
const onResize = finish(true);
|
|
7160
7489
|
const timer = setTimeout(finish(false), timeoutMs);
|
|
@@ -7162,15 +7491,15 @@ function waitForResize(stdout, timeoutMs) {
|
|
|
7162
7491
|
});
|
|
7163
7492
|
}
|
|
7164
7493
|
function delay(ms) {
|
|
7165
|
-
return new Promise((
|
|
7166
|
-
setTimeout(
|
|
7494
|
+
return new Promise((resolve5) => {
|
|
7495
|
+
setTimeout(resolve5, ms);
|
|
7167
7496
|
});
|
|
7168
7497
|
}
|
|
7169
7498
|
|
|
7170
7499
|
// package.json with { type: 'json' }
|
|
7171
7500
|
var package_default2 = {
|
|
7172
7501
|
name: "@algolia/wizard",
|
|
7173
|
-
version: "0.
|
|
7502
|
+
version: "0.68.0",
|
|
7174
7503
|
description: "Magically implement Algolia functionality in your codebase",
|
|
7175
7504
|
type: "module",
|
|
7176
7505
|
engines: {
|