@posthog/wizard 2.74.0 → 2.75.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/README.md +41 -27
- package/dist/README.md +10 -0
- package/dist/{add-mcp-server-to-clients-BtWwRG7O.js → add-mcp-server-to-clients-CjfnPMbO.js} +5 -5
- package/dist/{add-mcp-server-to-clients-BtWwRG7O.js.map → add-mcp-server-to-clients-CjfnPMbO.js.map} +1 -1
- package/dist/{agent-interface-CK6pmvkF.js → agent-interface-BKLTDSyN.js} +144 -338
- package/dist/agent-interface-BKLTDSyN.js.map +1 -0
- package/dist/{agent-prompt-loader-CPCNMvGh.js → agent-prompt-loader-DAagxT3p.js} +5 -5
- package/dist/{agent-prompt-loader-CPCNMvGh.js.map → agent-prompt-loader-DAagxT3p.js.map} +1 -1
- package/dist/{agent-runner-jz4yiJfh.js → agent-runner-BkQontri.js} +136 -46
- package/dist/agent-runner-BkQontri.js.map +1 -0
- package/dist/{analytics-DZNb3aRN.js → analytics-DSK0GXg1.js} +6 -4
- package/dist/analytics-DSK0GXg1.js.map +1 -0
- package/dist/analytics-yurAACt5.js +2 -0
- package/dist/{api-DXGaiK94.js → api-CwNulLDK.js} +3 -3
- package/dist/{api-DXGaiK94.js.map → api-CwNulLDK.js.map} +1 -1
- package/dist/bin.js +125 -4072
- package/dist/bin.js.map +1 -1
- package/dist/{bounded-fs-CErPpkN2.js → bounded-fs-D85Tk3nS.js} +3 -3
- package/dist/{bounded-fs-CErPpkN2.js.map → bounded-fs-D85Tk3nS.js.map} +1 -1
- package/dist/{ci-install-CzWzi_qu.js → ci-install-CQLi_a-r.js} +4 -4
- package/dist/{ci-install-CzWzi_qu.js.map → ci-install-CQLi_a-r.js.map} +1 -1
- package/dist/{debug-D4y9vVWt.js → debug-CBmI5YUF.js} +1 -1
- package/dist/{debug-ECdmmlDM.js → debug-DUmMVUHn.js} +14 -335
- package/dist/debug-DUmMVUHn.js.map +1 -0
- package/dist/{defaults-DI642M3n.js → defaults-DDDwYTN5.js} +1 -1
- package/dist/{defaults-DI642M3n.js.map → defaults-DDDwYTN5.js.map} +1 -1
- package/dist/{env-api-key-g5w775Ve.js → env-api-key-CGC1Bqwq.js} +2 -2
- package/dist/{env-api-key-g5w775Ve.js.map → env-api-key-CGC1Bqwq.js.map} +1 -1
- package/dist/{environment-DDkdsWUr.js → environment-DC4RDnzR.js} +4 -4
- package/dist/{environment-DDkdsWUr.js.map → environment-DC4RDnzR.js.map} +1 -1
- package/dist/{file-watcher-BNdFPlI8.js → file-watcher-hafFFQib.js} +2 -2
- package/dist/{file-watcher-BNdFPlI8.js.map → file-watcher-hafFFQib.js.map} +1 -1
- package/dist/gateway-session-Ctc2xaz7.js +271 -0
- package/dist/gateway-session-Ctc2xaz7.js.map +1 -0
- package/dist/gateway-session-zwwZAyTt.js +2 -0
- package/dist/{headless-ui-DBZCl4CG.js → headless-ui-CQ46FOTh.js} +2 -2
- package/dist/{headless-ui-DBZCl4CG.js.map → headless-ui-CQ46FOTh.js.map} +1 -1
- package/dist/{interactive-BKxXUB0T.js → interactive-5O4XQf59.js} +2 -2
- package/dist/{interactive-BKxXUB0T.js.map → interactive-5O4XQf59.js.map} +1 -1
- package/dist/{mcp-CwM45_Kp.js → mcp-D0Dni4tL.js} +2 -2
- package/dist/{mcp-CwM45_Kp.js.map → mcp-D0Dni4tL.js.map} +1 -1
- package/dist/{mcp-prompt-streaming-R8H7uhuO.js → mcp-prompt-streaming-DNCDeU51.js} +6 -5
- package/dist/{mcp-prompt-streaming-R8H7uhuO.js.map → mcp-prompt-streaming-DNCDeU51.js.map} +1 -1
- package/dist/mint-failure-CQqypC_v.js +5718 -0
- package/dist/mint-failure-CQqypC_v.js.map +1 -0
- package/dist/{non-interactive-DxzBwNxJ.js → non-interactive-D5-lCBy6.js} +2 -2
- package/dist/{non-interactive-DxzBwNxJ.js.map → non-interactive-D5-lCBy6.js.map} +1 -1
- package/dist/{orchestrator-tools-CTpKnk5-.js → orchestrator-tools-D8ZQS2DM.js} +5 -5
- package/dist/orchestrator-tools-D8ZQS2DM.js.map +1 -0
- package/dist/{package-manager-Bi6gaPa4.js → package-manager-hyP-CPSZ.js} +2 -2
- package/dist/{package-manager-Bi6gaPa4.js.map → package-manager-hyP-CPSZ.js.map} +1 -1
- package/dist/{pi-DpWFwz5u.js → pi-DARAk2I_.js} +35 -24
- package/dist/pi-DARAk2I_.js.map +1 -0
- package/dist/{playground-BtTCVaSD.js → playground-Djabnagq.js} +13 -65
- package/dist/playground-Djabnagq.js.map +1 -0
- package/dist/{posthog-B99H8Zyk.js → posthog-C3Sncfan.js} +2 -2
- package/dist/{posthog-B99H8Zyk.js.map → posthog-C3Sncfan.js.map} +1 -1
- package/dist/{provisioning-BewSEuFX.js → provisioning-B74q1uSQ.js} +3 -3
- package/dist/{provisioning-BewSEuFX.js.map → provisioning-B74q1uSQ.js.map} +1 -1
- package/dist/{queue-tools-CbRM-OET.js → queue-tools-FLMG8hcB.js} +34 -9
- package/dist/queue-tools-FLMG8hcB.js.map +1 -0
- package/dist/{registry-Bt2Mc4vC.js → registry-DZoReEU3.js} +5 -5
- package/dist/{registry-Bt2Mc4vC.js.map → registry-DZoReEU3.js.map} +1 -1
- package/dist/{security-Cmxb64bz.js → security-DiBFYwh7.js} +5 -5
- package/dist/{security-Cmxb64bz.js.map → security-DiBFYwh7.js.map} +1 -1
- package/dist/{setup-utils-CCphwDIz.js → setup-utils-C3tsa6D6.js} +48 -9
- package/dist/setup-utils-C3tsa6D6.js.map +1 -0
- package/dist/smoke-test-ci.sh +9 -14
- package/dist/{start-tui-BRwZzlWb.js → start-tui-BXjJGNx2.js} +849 -115
- package/dist/start-tui-BXjJGNx2.js.map +1 -0
- package/dist/{steps-CJrx1t72.js → steps-CeFanezY.js} +7 -7
- package/dist/{steps-CJrx1t72.js.map → steps-CeFanezY.js.map} +1 -1
- package/dist/{store-BhcCTIn4.js → store-DN_6FaoQ.js} +66 -28
- package/dist/store-DN_6FaoQ.js.map +1 -0
- package/dist/{subagent-BeMPBF5r.js → subagent-BzhCH9c3.js} +2 -2
- package/dist/{subagent-BeMPBF5r.js.map → subagent-BzhCH9c3.js.map} +1 -1
- package/dist/{task-DX3eZgBL.js → task-DZKmaWYF.js} +19 -22
- package/dist/task-DZKmaWYF.js.map +1 -0
- package/dist/{task-stream-BW7BG70C.js → task-stream-h-b1nWdM.js} +5 -5
- package/dist/{task-stream-BW7BG70C.js.map → task-stream-h-b1nWdM.js.map} +1 -1
- package/dist/{tasks-Did1AR7v.js → tasks-0Rb5AXpz.js} +2 -2
- package/dist/{tasks-Did1AR7v.js.map → tasks-0Rb5AXpz.js.map} +1 -1
- package/dist/{telemetry-CPWHrsXK.js → telemetry-QpeVhVtU.js} +3 -3
- package/dist/{telemetry-CPWHrsXK.js.map → telemetry-QpeVhVtU.js.map} +1 -1
- package/dist/{terminal-CpVFsbGu.js → terminal-dLoYiXsd.js} +24 -65
- package/dist/terminal-dLoYiXsd.js.map +1 -0
- package/dist/{tools-DjiwCd53.js → tools-DmwO0eBZ.js} +22 -16
- package/dist/tools-DmwO0eBZ.js.map +1 -0
- package/dist/{wizard-abort-RUnY1Dax.js → wizard-abort-B0c5VDie.js} +4 -4
- package/dist/{wizard-abort-RUnY1Dax.js.map → wizard-abort-B0c5VDie.js.map} +1 -1
- package/dist/{wizard-abort-DjJ-6y6S.js → wizard-abort-C9Jbm-m7.js} +1 -1
- package/dist/{wizard-session-BWAQoi9q.js → wizard-session-CYvyYnti.js} +1 -1
- package/dist/{wizard-session-GdDN_aMS.js → wizard-session-FSJCkTcP.js} +9 -2
- package/dist/wizard-session-FSJCkTcP.js.map +1 -0
- package/dist/yara-hooks-B7prW1Ng.js +2 -0
- package/dist/{yara-hooks-jBqAkgxw.js → yara-hooks-uCiAIcqU.js} +4 -4
- package/dist/{yara-hooks-jBqAkgxw.js.map → yara-hooks-uCiAIcqU.js.map} +1 -1
- package/package.json +1 -1
- package/dist/agent-interface-CK6pmvkF.js.map +0 -1
- package/dist/agent-runner-jz4yiJfh.js.map +0 -1
- package/dist/analytics-CfadnLFG.js +0 -2
- package/dist/analytics-DZNb3aRN.js.map +0 -1
- package/dist/debug-ECdmmlDM.js.map +0 -1
- package/dist/orchestrator-tools-CTpKnk5-.js.map +0 -1
- package/dist/pi-DpWFwz5u.js.map +0 -1
- package/dist/playground-BtTCVaSD.js.map +0 -1
- package/dist/posthog-integration-CxvkKY1j.js +0 -1475
- package/dist/posthog-integration-CxvkKY1j.js.map +0 -1
- package/dist/queue-tools-CbRM-OET.js.map +0 -1
- package/dist/setup-utils-CCphwDIz.js.map +0 -1
- package/dist/start-tui-BRwZzlWb.js.map +0 -1
- package/dist/store-BhcCTIn4.js.map +0 -1
- package/dist/task-DX3eZgBL.js.map +0 -1
- package/dist/terminal-CpVFsbGu.js.map +0 -1
- package/dist/tools-DjiwCd53.js.map +0 -1
- package/dist/wizard-session-GdDN_aMS.js.map +0 -1
- package/dist/yara-hooks-CBMSmD9F.js +0 -2
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { n as __require } from "./rolldown-runtime-B_-DWIq7.js";
|
|
2
|
-
import { c as RESUME_INSTRUCTION,
|
|
3
|
-
import {
|
|
4
|
-
import { n as ADDITIONAL_FEATURE_PROMPTS } from "./wizard-session-
|
|
5
|
-
import { n as analytics } from "./analytics-
|
|
6
|
-
import { a as safeReadFile, i as readProjectFile, o as walkProjectFiles } from "./bounded-fs-
|
|
7
|
-
import { i as wizardAbort, n as registerCleanup, t as WizardError } from "./wizard-abort-
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
2
|
+
import { c as RESUME_INSTRUCTION, l as classifyAuthFailure, o as AgentSignals, s as REMARK_INSTRUCTION } from "./errors--OqLxmWR.js";
|
|
3
|
+
import { E as AWS_SKILLS_BASE_URL, O as CONTEXT_MILL_URL, a as getLogFilePath, bt as runtimeEnv, f as getUI, mt as wizardUserAgentForProgram, o as initLogFile, r as debug, s as logToFile, ut as WIZARD_REMARK_EVENT_NAME } from "./debug-DUmMVUHn.js";
|
|
4
|
+
import { n as ADDITIONAL_FEATURE_PROMPTS } from "./wizard-session-FSJCkTcP.js";
|
|
5
|
+
import { n as analytics } from "./analytics-DSK0GXg1.js";
|
|
6
|
+
import { a as safeReadFile, i as readProjectFile, o as walkProjectFiles } from "./bounded-fs-D85Tk3nS.js";
|
|
7
|
+
import { i as wizardAbort, n as registerCleanup, t as WizardError } from "./wizard-abort-B0c5VDie.js";
|
|
8
|
+
import { o as gatewayAuth, r as buildWizardPropertiesBlob, s as isPastRefresh } from "./gateway-session-Ctc2xaz7.js";
|
|
9
|
+
import { b as coerceAuditChecks, g as AUDIT_CHECKS_FILE, l as prewarmYaraScanner, n as createPostToolUseYaraHooks, p as scanInstalledSkill, r as createPreToolUseYaraHooks } from "./yara-hooks-uCiAIcqU.js";
|
|
10
|
+
import { C as writeJsonAtomic, S as makeMutex, l as buildOrchestratorTools, x as triageModelFor, y as modelCapabilities } from "./queue-tools-FLMG8hcB.js";
|
|
10
11
|
import { createRequire } from "node:module";
|
|
11
12
|
import * as fs$1 from "fs";
|
|
12
13
|
import fs from "fs";
|
|
@@ -191,302 +192,6 @@ function createCustomHeaders() {
|
|
|
191
192
|
};
|
|
192
193
|
}
|
|
193
194
|
//#endregion
|
|
194
|
-
//#region src/lib/legacy-gateway.ts
|
|
195
|
-
let enabled = false;
|
|
196
|
-
/** Only the `--ci` runner turns this on. */
|
|
197
|
-
function setLegacyGatewayFallback(on) {
|
|
198
|
-
enabled = on;
|
|
199
|
-
}
|
|
200
|
-
/** Legacy auth when the fallback is on and the mint cannot serve this credential (401, or 404 without the endpoint). */
|
|
201
|
-
function legacyGatewayAuth(host, accessToken, mintStatus) {
|
|
202
|
-
if (!enabled || mintStatus !== 401 && mintStatus !== 404) return void 0;
|
|
203
|
-
return {
|
|
204
|
-
gatewayUrl: legacyGatewayUrl(host),
|
|
205
|
-
token: accessToken,
|
|
206
|
-
legacy: true,
|
|
207
|
-
refreshAtMs: Number.POSITIVE_INFINITY
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
function legacyGatewayUrl(host) {
|
|
211
|
-
const { hostname } = new URL(host.apiHost);
|
|
212
|
-
if (hostname === "host.docker.internal") return "http://host.docker.internal:3308/wizard";
|
|
213
|
-
if (hostname === "localhost" || hostname === "127.0.0.1") return "http://localhost:3308/wizard";
|
|
214
|
-
return `https://gateway.${host.region}.posthog.com/wizard`;
|
|
215
|
-
}
|
|
216
|
-
/** The legacy gateway reads per-key metadata and flag headers and needs an explicit Bedrock opt-in. */
|
|
217
|
-
function legacyGatewayHeaders(wizardMetadata, wizardFlags) {
|
|
218
|
-
const headers = { "x-posthog-use-bedrock-fallback": "true" };
|
|
219
|
-
for (const [key, value] of Object.entries(wizardMetadata)) headers[key.startsWith("X-POSTHOG-PROPERTY-") ? key : `X-POSTHOG-PROPERTY-${key}`] = value;
|
|
220
|
-
for (const [flagKey, variant] of Object.entries(wizardFlags)) {
|
|
221
|
-
if (!flagKey.toLowerCase().startsWith("wizard")) continue;
|
|
222
|
-
headers[`X-POSTHOG-FLAG-${flagKey.toUpperCase()}`] = variant;
|
|
223
|
-
}
|
|
224
|
-
return headers;
|
|
225
|
-
}
|
|
226
|
-
//#endregion
|
|
227
|
-
//#region src/lib/gateway-session.ts
|
|
228
|
-
/**
|
|
229
|
-
* Gateway auth for a wizard run: a `phe_` scoped token the backend mints, with
|
|
230
|
-
* pinned attribution, a spend cap and an expiry.
|
|
231
|
-
*
|
|
232
|
-
* Every mint failure throws, since a silent downgrade would spend uncapped,
|
|
233
|
-
* unattributed money to hide an outage. The CI-only exception lives in
|
|
234
|
-
* legacy-gateway.ts.
|
|
235
|
-
*/
|
|
236
|
-
let cached = null;
|
|
237
|
-
/**
|
|
238
|
-
* Shared so concurrent callers mint once. The orchestrator starts every runnable
|
|
239
|
-
* task at once, and each would otherwise take its own token and its own cap.
|
|
240
|
-
*/
|
|
241
|
-
let inFlight = null;
|
|
242
|
-
/**
|
|
243
|
-
* Adoption floor. The anthropic subprocess holds its credential until a 401
|
|
244
|
-
* forces a re-mint, so a token below this would churn mints.
|
|
245
|
-
*/
|
|
246
|
-
const MIN_USABLE_TTL_MS = 120 * 1e3;
|
|
247
|
-
/** Re-resolve at this fraction of the token's life, leaving a usable remainder. */
|
|
248
|
-
const REFRESH_AT_FRACTION = .8;
|
|
249
|
-
const MINT_TIMEOUT_MS = 2e4;
|
|
250
|
-
/** Longer than any refusal the mint writes; a body past this is not a message. */
|
|
251
|
-
const MAX_REFUSAL_DETAIL_LENGTH = 500;
|
|
252
|
-
/** Outcomes are short snake_case labels; anything longer is not one. */
|
|
253
|
-
const MAX_REFUSAL_OUTCOME_LENGTH = 64;
|
|
254
|
-
/** Resolve this run's gateway auth, minting and re-minting near expiry. */
|
|
255
|
-
async function gatewayAuth(host, accessToken, program) {
|
|
256
|
-
const key = `${host.apiHost}\n${accessToken}\n${program ?? ""}`;
|
|
257
|
-
if (cached && cached.key === key && Date.now() < cached.staleAtMs) return cached.auth;
|
|
258
|
-
if (inFlight && inFlight.key === key) return inFlight.promise;
|
|
259
|
-
const promise = resolveGatewayAuth(host, accessToken, key, program);
|
|
260
|
-
inFlight = {
|
|
261
|
-
key,
|
|
262
|
-
promise
|
|
263
|
-
};
|
|
264
|
-
try {
|
|
265
|
-
return await promise;
|
|
266
|
-
} finally {
|
|
267
|
-
if (inFlight?.promise === promise) inFlight = null;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
async function resolveGatewayAuth(host, accessToken, key, program) {
|
|
271
|
-
if (!program) {
|
|
272
|
-
logToFile("[gateway] run has no program id; failing the run");
|
|
273
|
-
throw new GatewayMintFailed("this run has no program to attribute its spend to");
|
|
274
|
-
}
|
|
275
|
-
let minted;
|
|
276
|
-
try {
|
|
277
|
-
minted = await mintGatewayToken(host, accessToken, program);
|
|
278
|
-
} catch (e) {
|
|
279
|
-
if (!(e instanceof GatewayMintRefused)) throw e;
|
|
280
|
-
const legacy = legacyGatewayAuth(host, accessToken, e.status);
|
|
281
|
-
if (!legacy) throw e;
|
|
282
|
-
logToFile(`[gateway] mint refused this credential (HTTP ${e.status}); CI run staying on the legacy gateway`);
|
|
283
|
-
cached = {
|
|
284
|
-
key,
|
|
285
|
-
auth: legacy,
|
|
286
|
-
staleAtMs: legacy.refreshAtMs
|
|
287
|
-
};
|
|
288
|
-
return legacy;
|
|
289
|
-
}
|
|
290
|
-
const expiresAtMs = Date.parse(minted.expiresAt);
|
|
291
|
-
const ttlMs = expiresAtMs - Date.now();
|
|
292
|
-
if (!Number.isFinite(expiresAtMs) || ttlMs < MIN_USABLE_TTL_MS) {
|
|
293
|
-
logToFile(`[gateway] mint returned a token with ${ttlMs}ms of life; failing the run`);
|
|
294
|
-
throw new GatewayMintFailed(`the PostHog gateway issued a token with ${ttlMs}ms of life`);
|
|
295
|
-
}
|
|
296
|
-
const staleAtMs = Date.now() + ttlMs * REFRESH_AT_FRACTION;
|
|
297
|
-
logToFile(`[gateway] minted a scoped token: program=${program} team=${minted.teamId ?? "unknown"} ttl=${Math.round(ttlMs / 1e3)}s url=${minted.gatewayUrl}`);
|
|
298
|
-
const auth = {
|
|
299
|
-
gatewayUrl: minted.gatewayUrl,
|
|
300
|
-
token: minted.token,
|
|
301
|
-
teamId: minted.teamId,
|
|
302
|
-
refreshAtMs: staleAtMs
|
|
303
|
-
};
|
|
304
|
-
cached = {
|
|
305
|
-
key,
|
|
306
|
-
auth,
|
|
307
|
-
staleAtMs
|
|
308
|
-
};
|
|
309
|
-
return auth;
|
|
310
|
-
}
|
|
311
|
-
/** Whether a 401 on this bearer may be age (past its refresh instant) rather than a bad credential. */
|
|
312
|
-
function isPastRefresh(auth, now = Date.now()) {
|
|
313
|
-
return now >= auth.refreshAtMs;
|
|
314
|
-
}
|
|
315
|
-
/**
|
|
316
|
-
* Whether a server-supplied origin may receive a bearer and prompt content:
|
|
317
|
-
* https (loopback excepted), and either a posthog.com host or the one the run
|
|
318
|
-
* authenticated against.
|
|
319
|
-
*/
|
|
320
|
-
function isTrustedGatewayUrl(value, apiHost) {
|
|
321
|
-
let url;
|
|
322
|
-
try {
|
|
323
|
-
url = new URL(value);
|
|
324
|
-
} catch {
|
|
325
|
-
return false;
|
|
326
|
-
}
|
|
327
|
-
if (url.pathname !== "/" || url.search || url.hash || url.username || url.password) return false;
|
|
328
|
-
if (url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "host.docker.internal") return true;
|
|
329
|
-
if (url.protocol !== "https:") return false;
|
|
330
|
-
if (url.hostname.endsWith(".posthog.com")) return true;
|
|
331
|
-
try {
|
|
332
|
-
return url.hostname === new URL(apiHost).hostname;
|
|
333
|
-
} catch {
|
|
334
|
-
return false;
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
/**
|
|
338
|
-
* A deliberate refusal from the mint endpoint, as opposed to the mint being
|
|
339
|
-
* unavailable. Thrown so the run stops instead of proceeding without the
|
|
340
|
-
* controls the refusal was enforcing. A WizardError, so the runners print its
|
|
341
|
-
* message as-is and `wizardAbort` resolves its code.
|
|
342
|
-
*/
|
|
343
|
-
var GatewayMintRefused = class extends WizardError {
|
|
344
|
-
status;
|
|
345
|
-
/** The backend's refusal outcome (`blocked`, `throttled`, ...), when it sent one. */
|
|
346
|
-
outcome;
|
|
347
|
-
constructor(status, message, outcome) {
|
|
348
|
-
super(message, {
|
|
349
|
-
status,
|
|
350
|
-
outcome
|
|
351
|
-
}, ErrorCodes.GatewayMintRefused);
|
|
352
|
-
this.name = "GatewayMintRefused";
|
|
353
|
-
this.status = status;
|
|
354
|
-
this.outcome = outcome;
|
|
355
|
-
}
|
|
356
|
-
};
|
|
357
|
-
/**
|
|
358
|
-
* The mint could not produce a usable credential: unreachable, a 5xx, or a
|
|
359
|
-
* response the client cannot use.
|
|
360
|
-
*/
|
|
361
|
-
var GatewayMintFailed = class extends WizardError {
|
|
362
|
-
constructor(message) {
|
|
363
|
-
super(message, void 0, ErrorCodes.GatewayMintFailed);
|
|
364
|
-
this.name = "GatewayMintFailed";
|
|
365
|
-
}
|
|
366
|
-
};
|
|
367
|
-
/**
|
|
368
|
-
* Whether a mint status means "refused this run" rather than "not available".
|
|
369
|
-
* 429 the daily run limit, 403 revoked project access, 400 a login covering
|
|
370
|
-
* more than one project, 401 a credential the mint does not accept, 404 an
|
|
371
|
-
* instance without the mint endpoint.
|
|
372
|
-
*/
|
|
373
|
-
function isMintRefusal(status) {
|
|
374
|
-
return status === 400 || status === 401 || status === 403 || status === 404 || status === 429;
|
|
375
|
-
}
|
|
376
|
-
/**
|
|
377
|
-
* The server's own reason for a refusal, when it sent one. DRF answers every
|
|
378
|
-
* refusal as `{"detail": "...", "code": "<outcome>"}`; the blocklist's detail
|
|
379
|
-
* names the contact address, which the fixed messages below cannot. `code` is
|
|
380
|
-
* the backend's own label for the refusal (`outcome` on older backends) and
|
|
381
|
-
* rides the client event.
|
|
382
|
-
*/
|
|
383
|
-
function cleanRefusalText(value) {
|
|
384
|
-
if (typeof value !== "string") return "";
|
|
385
|
-
return value.replace(/[\u0000-\u001f\u007f-\u009f]/g, " ").trim();
|
|
386
|
-
}
|
|
387
|
-
async function readRefusal(resp) {
|
|
388
|
-
try {
|
|
389
|
-
const body = await resp.json();
|
|
390
|
-
const detail = cleanRefusalText(body?.detail);
|
|
391
|
-
const outcome = cleanRefusalText(body?.code) || cleanRefusalText(body?.outcome);
|
|
392
|
-
return {
|
|
393
|
-
detail: detail.length > 0 && detail.length <= MAX_REFUSAL_DETAIL_LENGTH ? detail : void 0,
|
|
394
|
-
outcome: outcome.length > 0 && outcome.length <= MAX_REFUSAL_OUTCOME_LENGTH ? outcome : void 0
|
|
395
|
-
};
|
|
396
|
-
} catch {
|
|
397
|
-
return {};
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
function mintRefusalMessage(status, detail) {
|
|
401
|
-
if (detail) return detail;
|
|
402
|
-
switch (status) {
|
|
403
|
-
case 429: return "This wizard program has used its daily run limit. Try again tomorrow.";
|
|
404
|
-
case 403: return "Your access to this project has changed. Re-authenticate and try again.";
|
|
405
|
-
case 400: return "Your PostHog login must cover exactly one project. Re-authenticate and try again.";
|
|
406
|
-
case 401: return "PostHog did not accept this login. Re-authenticate with `npx @posthog/wizard@latest`.";
|
|
407
|
-
case 404: return "This PostHog instance does not issue gateway tokens. Upgrade with `npx @posthog/wizard@latest` and try again.";
|
|
408
|
-
default: return "The PostHog gateway refused this run.";
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
async function mintGatewayToken(host, accessToken, program) {
|
|
412
|
-
try {
|
|
413
|
-
const resp = await fetch(`${host.apiHost}/api/wizard/gateway_token/`, {
|
|
414
|
-
method: "POST",
|
|
415
|
-
headers: {
|
|
416
|
-
Authorization: `Bearer ${accessToken}`,
|
|
417
|
-
"Content-Type": "application/json"
|
|
418
|
-
},
|
|
419
|
-
body: JSON.stringify({
|
|
420
|
-
program,
|
|
421
|
-
reads_refusal_reason: true
|
|
422
|
-
}),
|
|
423
|
-
signal: AbortSignal.timeout(MINT_TIMEOUT_MS)
|
|
424
|
-
});
|
|
425
|
-
if (!resp.ok) {
|
|
426
|
-
if (isMintRefusal(resp.status)) {
|
|
427
|
-
const refusal = await readRefusal(resp);
|
|
428
|
-
logToFile(`[gateway] mint refused with HTTP ${resp.status} (${refusal.outcome ?? "no outcome"}); failing the run`);
|
|
429
|
-
analytics.wizardCapture("gateway mint refused", {
|
|
430
|
-
status: resp.status,
|
|
431
|
-
outcome: refusal.outcome,
|
|
432
|
-
program
|
|
433
|
-
});
|
|
434
|
-
throw new GatewayMintRefused(resp.status, mintRefusalMessage(resp.status, refusal.detail), refusal.outcome);
|
|
435
|
-
}
|
|
436
|
-
logToFile(`[gateway] mint failed with HTTP ${resp.status}; failing the run`);
|
|
437
|
-
throw new GatewayMintFailed(`the PostHog gateway could not issue a token (HTTP ${resp.status})`);
|
|
438
|
-
}
|
|
439
|
-
const body = await resp.json();
|
|
440
|
-
if (!body.token) {
|
|
441
|
-
logToFile("[gateway] mint response omitted token; failing the run");
|
|
442
|
-
throw new GatewayMintFailed("mint response omitted token");
|
|
443
|
-
}
|
|
444
|
-
if (!body.expires_at) {
|
|
445
|
-
logToFile("[gateway] mint response omitted expires_at; failing the run");
|
|
446
|
-
throw new GatewayMintFailed("mint response omitted expires_at");
|
|
447
|
-
}
|
|
448
|
-
if (!body.gateway_url) {
|
|
449
|
-
logToFile("[gateway] mint response omitted gateway_url; failing the run");
|
|
450
|
-
throw new GatewayMintFailed("mint response omitted gateway_url");
|
|
451
|
-
}
|
|
452
|
-
if (!isTrustedGatewayUrl(body.gateway_url, host.apiHost)) {
|
|
453
|
-
logToFile("[gateway] mint returned an untrusted gateway url; failing the run");
|
|
454
|
-
throw new GatewayMintFailed("mint returned an untrusted gateway url");
|
|
455
|
-
}
|
|
456
|
-
return {
|
|
457
|
-
token: body.token,
|
|
458
|
-
expiresAt: body.expires_at,
|
|
459
|
-
gatewayUrl: body.gateway_url.replace(/\/+$/, ""),
|
|
460
|
-
teamId: body.team_id
|
|
461
|
-
};
|
|
462
|
-
} catch (e) {
|
|
463
|
-
if (e instanceof GatewayMintRefused || e instanceof GatewayMintFailed) throw e;
|
|
464
|
-
logToFile(`[gateway] mint transport failure (${String(e)}); failing the run`);
|
|
465
|
-
throw new GatewayMintFailed(`could not reach the PostHog gateway (${String(e)})`);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
/**
|
|
469
|
-
* The v2 run-metadata carrier: one JSON blob for the `X-PostHog-Properties`
|
|
470
|
-
* header. Plain keys only, since the gateway strips `$`-prefixed keys as reserved,
|
|
471
|
-
* so feature-flag variants land as `wizard_flag_<key>` instead of the legacy
|
|
472
|
-
* `$feature/<key>` (dashboards keying on `$feature/wizard-*` read the new key
|
|
473
|
-
* post-cutover).
|
|
474
|
-
*/
|
|
475
|
-
function buildWizardPropertiesBlob(wizardMetadata, wizardFlags, teamId) {
|
|
476
|
-
const props = { ai_product: "wizard" };
|
|
477
|
-
if (teamId !== void 0) props.team_id = teamId;
|
|
478
|
-
for (const [key, value] of Object.entries(wizardMetadata)) props[stripPropertyPrefix(key)] = value;
|
|
479
|
-
for (const [flagKey, variant] of Object.entries(wizardFlags)) {
|
|
480
|
-
if (!flagKey.toLowerCase().startsWith("wizard")) continue;
|
|
481
|
-
props[`wizard_flag_${flagKey.toLowerCase()}`] = variant;
|
|
482
|
-
}
|
|
483
|
-
return JSON.stringify(props);
|
|
484
|
-
}
|
|
485
|
-
const LEGACY_PROPERTY_PREFIX = "X-POSTHOG-PROPERTY-";
|
|
486
|
-
function stripPropertyPrefix(key) {
|
|
487
|
-
return key.toUpperCase().startsWith(LEGACY_PROPERTY_PREFIX) ? key.slice(19).toLowerCase() : key;
|
|
488
|
-
}
|
|
489
|
-
//#endregion
|
|
490
195
|
//#region src/lib/safe-tools.ts
|
|
491
196
|
const LINTING_TOOLS = [
|
|
492
197
|
"codespell",
|
|
@@ -998,6 +703,13 @@ function evaluateBashCommand(rawCommand) {
|
|
|
998
703
|
*/
|
|
999
704
|
/** Sentinel returned for unanswered fields on cancellation or timeout. */
|
|
1000
705
|
const CANCELLED_SENTINEL = "__cancelled__";
|
|
706
|
+
/**
|
|
707
|
+
* The longer per-question timeout, for asks that send the user on an errand —
|
|
708
|
+
* open a database console, mint a restricted API key. The default above is
|
|
709
|
+
* sized for a question answerable from memory and expires long before an
|
|
710
|
+
* errand is done.
|
|
711
|
+
*/
|
|
712
|
+
const LONGER_ASK_TIMEOUT_MS = 1200 * 1e3;
|
|
1001
713
|
function buildCancelledAnswers(questions) {
|
|
1002
714
|
const out = {};
|
|
1003
715
|
for (const q of questions) out[q.id] = CANCELLED_SENTINEL;
|
|
@@ -1020,8 +732,10 @@ function createWizardAskBridge(opts) {
|
|
|
1020
732
|
};
|
|
1021
733
|
const startedAt = Date.now();
|
|
1022
734
|
let timer;
|
|
735
|
+
let timedOut = false;
|
|
1023
736
|
const timeoutPromise = new Promise((resolve) => {
|
|
1024
737
|
timer = setTimeout(() => {
|
|
738
|
+
timedOut = true;
|
|
1025
739
|
opts.cancelQuestion?.();
|
|
1026
740
|
resolve(buildCancelledAnswers(questions));
|
|
1027
741
|
}, timeoutMs);
|
|
@@ -1034,7 +748,7 @@ function createWizardAskBridge(opts) {
|
|
|
1034
748
|
subject,
|
|
1035
749
|
question_count: questions.length,
|
|
1036
750
|
duration_ms: durationMs,
|
|
1037
|
-
timed_out:
|
|
751
|
+
timed_out: timedOut
|
|
1038
752
|
});
|
|
1039
753
|
else analytics.wizardCapture("wizard_ask answered", {
|
|
1040
754
|
source: pending.source,
|
|
@@ -1042,7 +756,10 @@ function createWizardAskBridge(opts) {
|
|
|
1042
756
|
question_count: questions.length,
|
|
1043
757
|
duration_ms: durationMs
|
|
1044
758
|
});
|
|
1045
|
-
return
|
|
759
|
+
return {
|
|
760
|
+
answers,
|
|
761
|
+
timedOut
|
|
762
|
+
};
|
|
1046
763
|
} finally {
|
|
1047
764
|
if (timer) clearTimeout(timer);
|
|
1048
765
|
}
|
|
@@ -1326,6 +1043,31 @@ function normaliseAskSubject(subject) {
|
|
|
1326
1043
|
return trimmed.slice(0, ASK_SUBJECT_MAX_LENGTH);
|
|
1327
1044
|
}
|
|
1328
1045
|
/**
|
|
1046
|
+
* The `wizard_ask` `kind` field description, shared by both harness facades so
|
|
1047
|
+
* the inferred default cannot drift between them.
|
|
1048
|
+
*/
|
|
1049
|
+
const WIZARD_ASK_KIND_DESCRIPTION = "'single' = pick one option, 'multi' = pick any, 'text' = free-form single-line answer. Optional: omit it and the kind follows the question — 'single' when you pass options, 'text' when you do not, which is what a credential question wants.";
|
|
1050
|
+
/**
|
|
1051
|
+
* Fill in the `kind` of every question that arrived without one.
|
|
1052
|
+
*
|
|
1053
|
+
* The field used to be required, and both harnesses validate a call before this
|
|
1054
|
+
* handler sees it — pi against the typebox schema, the MCP SDK against the zod
|
|
1055
|
+
* one — so a call that omitted it was rejected upstream and the agent spent a
|
|
1056
|
+
* turn recovering from a validation error rather than asking its question.
|
|
1057
|
+
* Accepting the omission costs nothing, because `options` already says which
|
|
1058
|
+
* kind was meant, and a question carrying none is free text — which is what a
|
|
1059
|
+
* credential question wants, and the case an agent is most likely to send bare.
|
|
1060
|
+
*
|
|
1061
|
+
* Options imply `single`, never `multi`: omitting `kind` expresses no intent to
|
|
1062
|
+
* accept more than one answer.
|
|
1063
|
+
*/
|
|
1064
|
+
function resolveAskQuestionKinds(questions) {
|
|
1065
|
+
return questions.map((q) => ({
|
|
1066
|
+
...q,
|
|
1067
|
+
kind: q.kind ?? (q.options && q.options.length > 0 ? "single" : "text")
|
|
1068
|
+
}));
|
|
1069
|
+
}
|
|
1070
|
+
/**
|
|
1329
1071
|
* The `wizard_ask` `sensitive` field description, shared by both harness facades
|
|
1330
1072
|
* (the zod schema in `./mcp` and the typebox mirror in `harness/pi/tools.ts`) so
|
|
1331
1073
|
* the secret-handling guidance cannot drift between them — the same discipline
|
|
@@ -1354,7 +1096,43 @@ const WIZARD_ASK_SUBJECT_DESCRIPTION = "Short, stable tag naming what this call
|
|
|
1354
1096
|
* server in `./mcp` and the pi-native mirror in `harness/pi/tools.ts`) so the
|
|
1355
1097
|
* batching and cancellation contract reads identically in both harnesses.
|
|
1356
1098
|
*/
|
|
1357
|
-
const WIZARD_ASK_TOOL_DESCRIPTION = "Ask the user one or more structured questions and wait for their answers. Use this whenever you would otherwise inline a question in your text output. Batch every question about one subject into a single call (up to 8) rather than asking one at a time, and tag the call with `subject`. Walking a list — one call per data-warehouse source, one call per integration step — is expected and is never blocked, because the batching guard counts consecutive calls per subject. A fully cancelled or timed-out response does NOT count against the per-run cap
|
|
1099
|
+
const WIZARD_ASK_TOOL_DESCRIPTION = "Ask the user one or more structured questions and wait for their answers. Use this whenever you would otherwise inline a question in your text output. Batch every question about one subject into a single call (up to 8) rather than asking one at a time, and tag the call with `subject`. Walking a list — one call per data-warehouse source, one call per integration step — is expected and is never blocked, because the batching guard counts consecutive calls per subject. A fully cancelled or timed-out response does NOT count against the per-run cap, so nothing is wasted. When a field is not collected the result carries a `cancelled` object naming those question ids, whether the user dismissed the prompt or it timed out, and what to do next: read that instead of inspecting the answer values, and fall back gracefully (e.g. hand over a deep link) rather than re-asking.";
|
|
1100
|
+
/**
|
|
1101
|
+
* Guidance returned with a `wizard_ask` result when the user dismissed the
|
|
1102
|
+
* prompt. Shared by both harness facades, like the descriptions above.
|
|
1103
|
+
*
|
|
1104
|
+
* Deliberately says nothing about how the caller reports its own outcome:
|
|
1105
|
+
* `wizard_ask` serves programs with no task queue as well as the orchestrator's
|
|
1106
|
+
* seeded ones, so the note covers the ask and only the ask.
|
|
1107
|
+
*/
|
|
1108
|
+
const ASK_CANCELLED_NOTE = "The user dismissed this prompt, so none of these fields were collected. Read it as a decline for this subject: do not re-ask the same questions. Fall back to a route that needs no answer from them (for example, hand them a link to finish it themselves) and carry on with the rest of your work. Asking about a different subject is still fine.";
|
|
1109
|
+
/**
|
|
1110
|
+
* Guidance returned with a `wizard_ask` result when the prompt timed out.
|
|
1111
|
+
*
|
|
1112
|
+
* A timeout is not one decline: it says nobody is reading the terminal, and
|
|
1113
|
+
* every later prompt in the run will end the same way after the same wait.
|
|
1114
|
+
* Naming that is the difference between falling back once and stopping the run
|
|
1115
|
+
* behind one unattended prompt per remaining item.
|
|
1116
|
+
*/
|
|
1117
|
+
const ASK_TIMED_OUT_NOTE = "This prompt timed out with no answer, so the user is most likely away from the terminal. Read it as a decline, and expect any further prompt in this run to time out the same way after the same wait: stop asking and finish without them — hand over links for everything still outstanding — rather than opening another prompt.";
|
|
1118
|
+
/**
|
|
1119
|
+
* Describe an ask's cancelled fields, or `undefined` when every question was
|
|
1120
|
+
* answered. `timedOut` comes from the ask bridge — it is the only thing that
|
|
1121
|
+
* tells a dismissed prompt from an unattended one.
|
|
1122
|
+
*/
|
|
1123
|
+
function describeAskCancellation(answers, timedOut) {
|
|
1124
|
+
const questionIds = Object.entries(answers).filter(([, value]) => value === CANCELLED_SENTINEL).map(([id]) => id);
|
|
1125
|
+
if (questionIds.length === 0) return void 0;
|
|
1126
|
+
return timedOut ? {
|
|
1127
|
+
reason: "timed-out",
|
|
1128
|
+
questionIds,
|
|
1129
|
+
note: ASK_TIMED_OUT_NOTE
|
|
1130
|
+
} : {
|
|
1131
|
+
reason: "user-cancelled",
|
|
1132
|
+
questionIds,
|
|
1133
|
+
note: ASK_CANCELLED_NOTE
|
|
1134
|
+
};
|
|
1135
|
+
}
|
|
1358
1136
|
/**
|
|
1359
1137
|
* Pure decision function for the wizard_ask caps. Returns whether the
|
|
1360
1138
|
* upcoming call should proceed and, if not, the message to surface to the
|
|
@@ -1537,6 +1315,34 @@ function templateEnvWriteRefusal(resolvedPath) {
|
|
|
1537
1315
|
if (!isTemplateEnvFileName(name)) return null;
|
|
1538
1316
|
return `Error: "${name}" is a committed template that documents key names, so it is not a valid target for set_env_values — a credential written there would be published with the repository. Write to .env or .env.local instead (it is created if missing). If you only mean to document the key name, edit the template directly.`;
|
|
1539
1317
|
}
|
|
1318
|
+
/** Whole-word, so `NEXT_PUBLIC_POSTHOG_KEY` (`_` is a word character) does not count. */
|
|
1319
|
+
const LEGACY_KEY_USE = /\bPOSTHOG_KEY\b/;
|
|
1320
|
+
/** Files where a project reads or defines an env var: source, config, env, shell and build files. */
|
|
1321
|
+
const LEGACY_KEY_SCAN_FILE = /^(\.env.*|Dockerfile.*|Makefile|Procfile|package\.json|app\.json|eas\.json|.*\.[cm]?[jt]sx?|.*\.(vue|svelte|astro|py|rb|php|go|rs|exs?|java|kts?|swift|dart|cs|ya?ml|toml|sh|bash|gradle|properties|xcconfig|plist))$/;
|
|
1322
|
+
function projectReadsLegacyKey(workingDirectory) {
|
|
1323
|
+
let found = false;
|
|
1324
|
+
walkProjectFiles(workingDirectory, (name, fullPath) => {
|
|
1325
|
+
if (found || !LEGACY_KEY_SCAN_FILE.test(name)) return;
|
|
1326
|
+
const content = readProjectFile(fullPath);
|
|
1327
|
+
if (content !== null && LEGACY_KEY_USE.test(content)) found = true;
|
|
1328
|
+
}, 6);
|
|
1329
|
+
return found;
|
|
1330
|
+
}
|
|
1331
|
+
/**
|
|
1332
|
+
* `set_env_values`' refusal for the legacy `POSTHOG_KEY` name, or null. Shared
|
|
1333
|
+
* by both facades so the two cannot disagree about it.
|
|
1334
|
+
*
|
|
1335
|
+
* `POSTHOG_KEY` is the old name for the project token, so a new project gets
|
|
1336
|
+
* the canonical one (e.g. NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN). A project whose
|
|
1337
|
+
* code already reads `POSTHOG_KEY` keeps it: refusing there forces a rename of
|
|
1338
|
+
* working code, and every deploy step and CI secret that still passes the old
|
|
1339
|
+
* name then starts the app with an empty token.
|
|
1340
|
+
*/
|
|
1341
|
+
function legacyKeyNameRefusal(workingDirectory, keys) {
|
|
1342
|
+
const key = keys.find((k) => k.toUpperCase() === "POSTHOG_KEY");
|
|
1343
|
+
if (!key || projectReadsLegacyKey(workingDirectory)) return null;
|
|
1344
|
+
return `Error: "${key}" is not a valid PostHog env var name. Use the key name from your framework's integration guide (e.g. NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN). POSTHOG_KEY is accepted only when the project already reads it.`;
|
|
1345
|
+
}
|
|
1540
1346
|
/**
|
|
1541
1347
|
* Escape a key before it is interpolated into the match regex below. The key
|
|
1542
1348
|
* comes from the agent, and a stray metacharacter would otherwise build a
|
|
@@ -1934,11 +1740,11 @@ async function createWizardToolsServer(options) {
|
|
|
1934
1740
|
filePath: z.string().describe(ENV_FILE_PATH_DESCRIPTION),
|
|
1935
1741
|
values: z.record(z.string(), z.union([z.string(), z.object({ secretRef: z.string() })])).describe("Key → (literal string OR { secretRef } pointing to a vaulted secret)")
|
|
1936
1742
|
}, (args) => {
|
|
1937
|
-
const
|
|
1938
|
-
if (
|
|
1743
|
+
const keyRefusal = legacyKeyNameRefusal(workingDirectory, Object.keys(args.values));
|
|
1744
|
+
if (keyRefusal) return {
|
|
1939
1745
|
content: [{
|
|
1940
1746
|
type: "text",
|
|
1941
|
-
text:
|
|
1747
|
+
text: keyRefusal
|
|
1942
1748
|
}],
|
|
1943
1749
|
isError: true
|
|
1944
1750
|
};
|
|
@@ -2109,7 +1915,7 @@ async function createWizardToolsServer(options) {
|
|
|
2109
1915
|
"single",
|
|
2110
1916
|
"multi",
|
|
2111
1917
|
"text"
|
|
2112
|
-
]).describe(
|
|
1918
|
+
]).optional().describe(WIZARD_ASK_KIND_DESCRIPTION),
|
|
2113
1919
|
options: z.array(z.object({
|
|
2114
1920
|
label: z.string(),
|
|
2115
1921
|
value: z.string(),
|
|
@@ -2158,7 +1964,8 @@ async function createWizardToolsServer(options) {
|
|
|
2158
1964
|
isError: capDecision.reason !== "adjacency"
|
|
2159
1965
|
};
|
|
2160
1966
|
}
|
|
2161
|
-
|
|
1967
|
+
const questions = resolveAskQuestionKinds(args.questions);
|
|
1968
|
+
for (const q of questions) {
|
|
2162
1969
|
if ((q.kind === "single" || q.kind === "multi") && (!q.options || q.options.length === 0)) return {
|
|
2163
1970
|
content: [{
|
|
2164
1971
|
type: "text",
|
|
@@ -2175,7 +1982,7 @@ async function createWizardToolsServer(options) {
|
|
|
2175
1982
|
};
|
|
2176
1983
|
}
|
|
2177
1984
|
const ids = /* @__PURE__ */ new Set();
|
|
2178
|
-
for (const q of
|
|
1985
|
+
for (const q of questions) {
|
|
2179
1986
|
if (ids.has(q.id)) return {
|
|
2180
1987
|
content: [{
|
|
2181
1988
|
type: "text",
|
|
@@ -2187,16 +1994,20 @@ async function createWizardToolsServer(options) {
|
|
|
2187
1994
|
}
|
|
2188
1995
|
askAccounting.record(args.subject);
|
|
2189
1996
|
try {
|
|
2190
|
-
const answers = await askBridge.request({
|
|
2191
|
-
questions
|
|
1997
|
+
const { answers, timedOut } = await askBridge.request({
|
|
1998
|
+
questions,
|
|
2192
1999
|
subject: normaliseAskSubject(args.subject)
|
|
2193
2000
|
});
|
|
2194
2001
|
if (isFullyCancelled(answers)) askAccounting.refund(args.subject);
|
|
2195
|
-
const sanitised = vaultSensitiveAnswers(
|
|
2196
|
-
|
|
2002
|
+
const sanitised = vaultSensitiveAnswers(questions, answers, secretVault);
|
|
2003
|
+
const cancelled = describeAskCancellation(sanitised, timedOut);
|
|
2004
|
+
logToFile(`wizard_ask: resolved ${Object.keys(answers).length} answer(s) for ${args.questions.length} question(s)${cancelled ? `, cancelled: ${cancelled.reason}` : ""}`);
|
|
2197
2005
|
return { content: [{
|
|
2198
2006
|
type: "text",
|
|
2199
|
-
text: JSON.stringify({
|
|
2007
|
+
text: JSON.stringify({
|
|
2008
|
+
answers: sanitised,
|
|
2009
|
+
...cancelled ? { cancelled } : {}
|
|
2010
|
+
}, null, 2)
|
|
2200
2011
|
}] };
|
|
2201
2012
|
} catch (err) {
|
|
2202
2013
|
askAccounting.refund(args.subject);
|
|
@@ -2246,9 +2057,8 @@ const GATEWAY_PROVIDER = "posthog-gateway";
|
|
|
2246
2057
|
* OpenAI models take the Responses API because OpenAI rejects function tools
|
|
2247
2058
|
* combined with `reasoning_effort` on chat completions and every task sends both.
|
|
2248
2059
|
*/
|
|
2249
|
-
function gatewayApiFor(modelId
|
|
2250
|
-
|
|
2251
|
-
return legacy ? "openai-completions" : "openai-responses";
|
|
2060
|
+
function gatewayApiFor(modelId) {
|
|
2061
|
+
return modelId.startsWith("openai/") ? "openai-responses" : "anthropic-messages";
|
|
2252
2062
|
}
|
|
2253
2063
|
/**
|
|
2254
2064
|
* Gateway HTTP headers, mirroring `buildAgentEnv` on the anthropic path: one
|
|
@@ -2256,10 +2066,10 @@ function gatewayApiFor(modelId, legacy) {
|
|
|
2256
2066
|
* plus the 1M context beta, since pi otherwise runs at 200k and overflows on
|
|
2257
2067
|
* larger projects (the post-run compaction failures).
|
|
2258
2068
|
*/
|
|
2259
|
-
function buildGatewayHeaders(wizardMetadata, wizardFlags, teamId
|
|
2069
|
+
function buildGatewayHeaders(wizardMetadata, wizardFlags, teamId) {
|
|
2260
2070
|
return {
|
|
2261
2071
|
"anthropic-beta": "context-1m-2025-08-07",
|
|
2262
|
-
|
|
2072
|
+
"X-PostHog-Properties": buildWizardPropertiesBlob(wizardMetadata, wizardFlags, teamId)
|
|
2263
2073
|
};
|
|
2264
2074
|
}
|
|
2265
2075
|
/**
|
|
@@ -2268,8 +2078,8 @@ function buildGatewayHeaders(wizardMetadata, wizardFlags, teamId, legacy) {
|
|
|
2268
2078
|
* callers (scan triage) hand it straight to `completeSimple`.
|
|
2269
2079
|
*/
|
|
2270
2080
|
function buildGatewayModel(inputs) {
|
|
2271
|
-
const { gatewayUrl, wizardMetadata, wizardFlags, modelId, teamId
|
|
2272
|
-
const api = gatewayApiFor(modelId
|
|
2081
|
+
const { gatewayUrl, wizardMetadata, wizardFlags, modelId, teamId } = inputs;
|
|
2082
|
+
const api = gatewayApiFor(modelId);
|
|
2273
2083
|
return {
|
|
2274
2084
|
id: modelId,
|
|
2275
2085
|
name: `${modelId} (PostHog Gateway)`,
|
|
@@ -2286,7 +2096,7 @@ function buildGatewayModel(inputs) {
|
|
|
2286
2096
|
},
|
|
2287
2097
|
contextWindow: 1e6,
|
|
2288
2098
|
maxTokens: 64e3,
|
|
2289
|
-
headers: buildGatewayHeaders(wizardMetadata, wizardFlags, teamId
|
|
2099
|
+
headers: buildGatewayHeaders(wizardMetadata, wizardFlags, teamId)
|
|
2290
2100
|
};
|
|
2291
2101
|
}
|
|
2292
2102
|
/**
|
|
@@ -2294,8 +2104,8 @@ function buildGatewayModel(inputs) {
|
|
|
2294
2104
|
* plus the derived traits the session setup needs (`caps.thinkingLevel`).
|
|
2295
2105
|
*/
|
|
2296
2106
|
function buildGatewayProvider(inputs) {
|
|
2297
|
-
const { gatewayUrl, accessToken, modelId, effort
|
|
2298
|
-
const api = gatewayApiFor(modelId
|
|
2107
|
+
const { gatewayUrl, accessToken, modelId, effort } = inputs;
|
|
2108
|
+
const api = gatewayApiFor(modelId);
|
|
2299
2109
|
const tableCaps = modelCapabilities(modelId);
|
|
2300
2110
|
const caps = effort && effort !== "off" && tableCaps.reasoning ? modelCapabilities(modelId, effort) : effort === "off" && tableCaps.reasoning ? {
|
|
2301
2111
|
...tableCaps,
|
|
@@ -2390,7 +2200,6 @@ function createTriageLLMProvider(auth, harness) {
|
|
|
2390
2200
|
gatewayUrl: current.baseURL,
|
|
2391
2201
|
accessToken: authToken,
|
|
2392
2202
|
teamId: current.teamId,
|
|
2393
|
-
legacy: current.legacy,
|
|
2394
2203
|
wizardMetadata: current.wizardMetadata ?? {},
|
|
2395
2204
|
wizardFlags: current.wizardFlags ?? {},
|
|
2396
2205
|
modelId
|
|
@@ -3259,13 +3068,11 @@ function isWarlockDisabled() {
|
|
|
3259
3068
|
/**
|
|
3260
3069
|
* Build ANTHROPIC_CUSTOM_HEADERS for the SDK subprocess: the run's metadata and
|
|
3261
3070
|
* flags as one `X-PostHog-Properties` JSON blob. Bedrock fallback is native to
|
|
3262
|
-
* the gateway, so there is no opt-in header.
|
|
3263
|
-
* gateway's shape instead.
|
|
3071
|
+
* the gateway, so there is no opt-in header.
|
|
3264
3072
|
*/
|
|
3265
|
-
function buildAgentEnv(wizardMetadata, wizardFlags,
|
|
3073
|
+
function buildAgentEnv(wizardMetadata, wizardFlags, teamId) {
|
|
3266
3074
|
const headers = createCustomHeaders();
|
|
3267
|
-
|
|
3268
|
-
for (const [key, value] of Object.entries(shaped)) headers.add(key, value);
|
|
3075
|
+
headers.add("X-PostHog-Properties", buildWizardPropertiesBlob(wizardMetadata, wizardFlags, teamId));
|
|
3269
3076
|
const encoded = headers.encode();
|
|
3270
3077
|
logToFile("ANTHROPIC_CUSTOM_HEADERS", encoded);
|
|
3271
3078
|
return encoded;
|
|
@@ -3375,7 +3182,6 @@ async function initializeAgent(config, options) {
|
|
|
3375
3182
|
baseURL: current.gatewayUrl,
|
|
3376
3183
|
authToken: current.token,
|
|
3377
3184
|
teamId: current.teamId,
|
|
3378
|
-
legacy: current.legacy,
|
|
3379
3185
|
wizardMetadata: triageMetadata,
|
|
3380
3186
|
wizardFlags: config.wizardFlags ?? {}
|
|
3381
3187
|
};
|
|
@@ -3621,7 +3427,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3621
3427
|
CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS: "true",
|
|
3622
3428
|
POSTHOG_MCP_TOKEN: agentConfig.posthogApiKey,
|
|
3623
3429
|
MCP_CONNECTION_NONBLOCKING: "0",
|
|
3624
|
-
ANTHROPIC_CUSTOM_HEADERS: buildAgentEnv(agentConfig.wizardMetadata ?? {}, agentConfig.wizardFlags ?? {}, agentConfig.gatewayAuth)
|
|
3430
|
+
ANTHROPIC_CUSTOM_HEADERS: buildAgentEnv(agentConfig.wizardMetadata ?? {}, agentConfig.wizardFlags ?? {}, agentConfig.gatewayAuth.teamId)
|
|
3625
3431
|
},
|
|
3626
3432
|
canUseTool: (toolName, input) => {
|
|
3627
3433
|
logToFile("canUseTool called:", {
|
|
@@ -4145,6 +3951,6 @@ function handleSDKMessage(message, options, spinner, signals, receivedSuccessRes
|
|
|
4145
3951
|
}
|
|
4146
3952
|
}
|
|
4147
3953
|
//#endregion
|
|
4148
|
-
export {
|
|
3954
|
+
export { parseEnvKeyNames as $, WIZARD_ASK_TOOL_DESCRIPTION as A, mergeEnvValues as B, publishHandoff as C, WIZARD_ASK_KIND_DESCRIPTION as D, ENV_FILE_PATH_DESCRIPTION as E, downloadSkill as F, templateEnvWriteRefusal as G, resolveAskQuestionKinds as H, ensureGitignoreCoverage as I, LONGER_ASK_TIMEOUT_MS as J, vaultSensitiveAnswers as K, fetchSkillMenu as L, checkEnvKeys as M, createAskAccounting as N, WIZARD_ASK_SENSITIVE_DESCRIPTION as O, describeAskCancellation as P, isEnvFileName as Q, installSkillById as R, PUBLISH_HANDOFF_TOOL_NAME as S, CHECK_ENV_KEYS_FILE_PATH_DESCRIPTION as T, resolveEnvPath as U, normaliseAskSubject as V, resolveEnvSecretRefs as W, isFullyCancelled as X, createWizardAskBridge as Y, MAX_ENV_KEY_SET as Z, buildGatewayProvider as _, wizardCanUseTool as a, PUBLISH_HANDOFF_CONTENT_DESCRIPTION as b, checkAllSettingsConflicts as c, restoreClaudeSettings as d, toPromptSafeRelativePath as et, sanitizeAgentSubprocessEnv as f, GATEWAY_PROVIDER as g, createTriageLLMProvider as h, runAgent as i, WIZARD_TOOL_NAMES as j, WIZARD_ASK_SUBJECT_DESCRIPTION as k, classifySettingsConflicts as l, assembleCommandments as m, buildRunTags as n, createIsolatedAgentConfigDir as o, AgentOutputSignals as p, fetchWithRetry as q, initializeAgent as r, backupAndFixClaudeSettings as s, buildAgentEnv as t, markGrantRevoked as tt, recoverOrphanedSettingsBackups as u, withGatewayRemint as v, CHECK_ENV_KEYS_DESCRIPTION as w, PUBLISH_HANDOFF_DESCRIPTION as x, createSecretVault as y, legacyKeyNameRefusal as z };
|
|
4149
3955
|
|
|
4150
|
-
//# sourceMappingURL=agent-interface-
|
|
3956
|
+
//# sourceMappingURL=agent-interface-BKLTDSyN.js.map
|