@posthog/ai 8.10.4 → 8.11.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.
@@ -3,7 +3,7 @@ let _google_adk = require("@google/adk");
3
3
  let uuid = require("uuid");
4
4
  let _posthog_core = require("@posthog/core");
5
5
  //#region package.json
6
- var version = "8.10.4";
6
+ var version = "8.11.0";
7
7
  //#endregion
8
8
  //#region src/captureAiEvent.ts
9
9
  /** @internal */
@@ -2,7 +2,7 @@ import { BasePlugin } from "@google/adk";
2
2
  import { v4 } from "uuid";
3
3
  import { toJsonSafeValue, uuidv7 } from "@posthog/core";
4
4
  //#region package.json
5
- var version = "8.10.4";
5
+ var version = "8.11.0";
6
6
  //#endregion
7
7
  //#region src/captureAiEvent.ts
8
8
  /** @internal */
@@ -367,7 +367,7 @@ function addDefaults(params) {
367
367
  }
368
368
  //#endregion
369
369
  //#region package.json
370
- var version = "8.10.4";
370
+ var version = "8.11.0";
371
371
  //#endregion
372
372
  //#region src/serializeError.ts
373
373
  const DEFAULT_MAX_DEPTH = 3;
@@ -340,7 +340,7 @@ function addDefaults(params) {
340
340
  }
341
341
  //#endregion
342
342
  //#region package.json
343
- var version = "8.10.4";
343
+ var version = "8.11.0";
344
344
  //#endregion
345
345
  //#region src/serializeError.ts
346
346
  const DEFAULT_MAX_DEPTH = 3;
@@ -411,7 +411,7 @@ function addDefaults(params) {
411
411
  }
412
412
  //#endregion
413
413
  //#region package.json
414
- var version = "8.10.4";
414
+ var version = "8.11.0";
415
415
  //#endregion
416
416
  //#region src/serializeError.ts
417
417
  const DEFAULT_MAX_DEPTH = 3;
@@ -407,7 +407,7 @@ function addDefaults(params) {
407
407
  }
408
408
  //#endregion
409
409
  //#region package.json
410
- var version = "8.10.4";
410
+ var version = "8.11.0";
411
411
  //#endregion
412
412
  //#region src/serializeError.ts
413
413
  const DEFAULT_MAX_DEPTH = 3;
package/dist/index.cjs CHANGED
@@ -392,7 +392,7 @@ function sanitizeValues(obj) {
392
392
  }
393
393
  //#endregion
394
394
  //#region package.json
395
- var version = "8.10.4";
395
+ var version = "8.11.0";
396
396
  //#endregion
397
397
  //#region src/serializeError.ts
398
398
  const DEFAULT_MAX_DEPTH = 3;
@@ -1084,6 +1084,7 @@ const wrapVercelLanguageModel = (model, phClient, options) => {
1084
1084
  //#region src/prompts.ts
1085
1085
  const DEFAULT_CACHE_TTL_SECONDS = 300;
1086
1086
  const DEFAULT_PROMPTS_HOST = "https://us.posthog.com";
1087
+ const MAX_PROMPT_LIST_PAGES = 100;
1087
1088
  const DEFAULT_REFETCH_COOLDOWN_SECONDS = 60;
1088
1089
  const MAX_REFETCH_COOLDOWN_SECONDS = 3600;
1089
1090
  function normalizeApiKey(value) {
@@ -1121,6 +1122,31 @@ function isPromptApiResponse(data) {
1121
1122
  const record = data;
1122
1123
  return typeof record.prompt === "string" && typeof record.name === "string" && typeof record.version === "number" && (record.label === void 0 || typeof record.label === "string");
1123
1124
  }
1125
+ function isSameOrigin(url, host) {
1126
+ try {
1127
+ return new URL(url).origin === new URL(host).origin;
1128
+ } catch {
1129
+ return false;
1130
+ }
1131
+ }
1132
+ /**
1133
+ * Classify how a list row relates to the requested label, via its all_labels
1134
+ * field.
1135
+ *
1136
+ * 'resolved': the row is the version the label points to.
1137
+ * 'moved': the prompt carries the label, but on another version. Happens when
1138
+ * the label moves between the query and the response.
1139
+ * 'absent': the prompt does not carry the label at any version. A server that
1140
+ * filters by label never returns such a row, so this means the server ignored
1141
+ * the label param (an older PostHog release) and served latest versions.
1142
+ */
1143
+ function rowLabelState(row, label) {
1144
+ const allLabels = row.all_labels;
1145
+ if (!Array.isArray(allLabels)) return "absent";
1146
+ const entry = allLabels.find((candidate) => typeof candidate === "object" && candidate !== null && candidate.name === label);
1147
+ if (entry === void 0) return "absent";
1148
+ return entry.version === row.version ? "resolved" : "moved";
1149
+ }
1124
1150
  function isPromptsWithPostHog(options) {
1125
1151
  return "posthog" in options;
1126
1152
  }
@@ -1155,6 +1181,9 @@ function isPromptsWithPostHog(options) {
1155
1181
  * label: 'production',
1156
1182
  * })
1157
1183
  *
1184
+ * // Or fetch all prompts at a label in one request and warm the cache
1185
+ * const prodPrompts = await prompts.getAll({ label: 'production' })
1186
+ *
1158
1187
  * // Compile with variables
1159
1188
  * const systemPrompt = prompts.compile(result.prompt, {
1160
1189
  * company: 'Acme Corp',
@@ -1221,6 +1250,61 @@ var Prompts = class {
1221
1250
  }
1222
1251
  }
1223
1252
  /**
1253
+ * Fetch every prompt that carries a label, in one batch.
1254
+ *
1255
+ * Returns an object mapping prompt name to `PromptRemoteResult`, with each
1256
+ * prompt at the version the label points to. Prompts without the label are
1257
+ * not included.
1258
+ *
1259
+ * Each fetched prompt is stored in the cache, so later
1260
+ * `get(name, { label })` calls are served from cache within the TTL. An app
1261
+ * with many prompts can call this once per cache cycle instead of making one
1262
+ * `get()` request per prompt.
1263
+ *
1264
+ * Throws if the request fails, or if the server does not support fetching
1265
+ * prompts by label on the list endpoint (PostHog releases from before
1266
+ * September 2026).
1267
+ */
1268
+ async getAll(options) {
1269
+ const label = options.label;
1270
+ const rows = await this.fetchPromptListFromApi(label);
1271
+ const resolvedRows = [];
1272
+ const skipped = [];
1273
+ for (const row of rows) {
1274
+ if (!isPromptApiResponse(row)) throw new Error(`[PostHog Prompts] Invalid response format for prompts with label "${label}"`);
1275
+ const labelState = rowLabelState(row, label);
1276
+ if (labelState === "absent") throw new Error(`[PostHog Prompts] The server returned a prompt that does not carry label "${label}". It may not support fetching prompts by label on the list endpoint yet. Upgrade PostHog, or fetch prompts one by one with get().`);
1277
+ if (labelState === "moved") {
1278
+ skipped.push(row.name);
1279
+ continue;
1280
+ }
1281
+ resolvedRows.push(row);
1282
+ }
1283
+ const now = Date.now();
1284
+ const results = /* @__PURE__ */ new Map();
1285
+ for (const row of resolvedRows) {
1286
+ const config = extractConfig(row.config);
1287
+ this.getOrCreatePromptCache(row.name).set(label, {
1288
+ prompt: row.prompt,
1289
+ name: row.name,
1290
+ version: row.version,
1291
+ label,
1292
+ config,
1293
+ fetchedAt: now
1294
+ });
1295
+ results.set(row.name, {
1296
+ source: "api",
1297
+ prompt: row.prompt,
1298
+ name: row.name,
1299
+ version: row.version,
1300
+ label,
1301
+ config: cloneConfig(config)
1302
+ });
1303
+ }
1304
+ if (skipped.length > 0) console.warn(`[PostHog Prompts] Skipped ${skipped.length} prompt(s) that did not resolve label "${label}": ${skipped.join(", ")}`);
1305
+ return Object.fromEntries(results);
1306
+ }
1307
+ /**
1224
1308
  * Internal method that handles cache + fetch logic, returning full metadata.
1225
1309
  * Does NOT handle the string `fallback` option — callers handle that.
1226
1310
  */
@@ -1310,9 +1394,43 @@ var Prompts = class {
1310
1394
  promptVersions?.delete(version);
1311
1395
  if (promptVersions?.size === 0) this.cache.delete(name);
1312
1396
  }
1313
- async fetchPromptFromApi(name, version, label) {
1397
+ requireCredentials() {
1314
1398
  if (!this.personalApiKey) throw new Error("[PostHog Prompts] personalApiKey is required to fetch prompts. Please provide it when initializing the Prompts instance.");
1315
1399
  if (!this.projectApiKey) throw new Error("[PostHog Prompts] projectApiKey is required to fetch prompts. Please provide it when initializing the Prompts instance.");
1400
+ }
1401
+ /**
1402
+ * Fetch all prompts at a label from the paginated list endpoint.
1403
+ * Follows pagination links until the last page and returns the raw rows.
1404
+ */
1405
+ async fetchPromptListFromApi(label) {
1406
+ this.requireCredentials();
1407
+ const query = `token=${encodeURIComponent(this.projectApiKey)}&label=${encodeURIComponent(label)}&content=full`;
1408
+ let url = `${this.host}/api/environments/@current/llm_prompts/?${query}`;
1409
+ const reference = `prompts with label "${label}"`;
1410
+ const rows = [];
1411
+ let pages = 0;
1412
+ while (url !== void 0) {
1413
+ if (pages >= MAX_PROMPT_LIST_PAGES) throw new Error(`[PostHog Prompts] ${reference} spans more than ${MAX_PROMPT_LIST_PAGES} pages. Refusing to return an incomplete result.`);
1414
+ const response = await fetch(url, {
1415
+ method: "GET",
1416
+ headers: { Authorization: `Bearer ${this.personalApiKey}` }
1417
+ });
1418
+ if (!response.ok) {
1419
+ if (response.status === 403) throw new Error(`[PostHog Prompts] Access denied for ${reference}. Check that your personalApiKey has the correct permissions and the LLM prompts feature is enabled.`);
1420
+ throw new PromptFetchError(`[PostHog Prompts] Failed to fetch ${reference}: HTTP ${response.status}`, response.status === 429 ? parseRetryAfterSeconds(response.headers?.get("Retry-After")) : void 0);
1421
+ }
1422
+ const data = await response.json();
1423
+ if (typeof data !== "object" || data === null || !Array.isArray(data.results)) throw new Error(`[PostHog Prompts] Invalid response format for ${reference}`);
1424
+ rows.push(...data.results);
1425
+ const nextUrl = data.next;
1426
+ if (nextUrl !== null && nextUrl !== void 0 && (typeof nextUrl !== "string" || !isSameOrigin(nextUrl, this.host))) throw new Error(`[PostHog Prompts] Refusing to follow a pagination link off the configured host while fetching ${reference}.`);
1427
+ url = nextUrl === null || nextUrl === void 0 ? void 0 : nextUrl;
1428
+ pages += 1;
1429
+ }
1430
+ return rows;
1431
+ }
1432
+ async fetchPromptFromApi(name, version, label) {
1433
+ this.requireCredentials();
1316
1434
  const encodedPromptName = encodeURIComponent(name);
1317
1435
  const encodedProjectApiKey = encodeURIComponent(this.projectApiKey);
1318
1436
  const versionQuery = version === void 0 ? "" : `&version=${encodeURIComponent(String(version))}`;