diff --git a/apps/docs/config/posthog.mjs b/apps/docs/config/posthog.mjs new file mode 100644 index 000000000..c4866d6a6 --- /dev/null +++ b/apps/docs/config/posthog.mjs @@ -0,0 +1,11 @@ +// Single source of truth for non-sensitive PostHog config. +// The project key stays in env (NEXT_PUBLIC_POSTHOG_KEY) — it is per-deploy. +// Exported as `posthogConfig` (not `posthog`) to avoid colliding with the +// `posthog` default import from "posthog-js" in instrumentation-client.ts. +export const posthogConfig = { + apiHost: "/ingest", // first-party reverse-proxy base path; also builds the rewrite sources + uiHost: "https://us.posthog.com", + ingestHost: "https://us.i.posthog.com", + assetsHost: "https://us-assets.i.posthog.com", + defaults: /** @type {import("posthog-js").ConfigDefaults} */ ("2025-05-24"), // maps 1:1 to posthog-js init() `defaults` option +}; diff --git a/apps/docs/instrumentation-client.ts b/apps/docs/instrumentation-client.ts index c828c589b..6f544a35b 100644 --- a/apps/docs/instrumentation-client.ts +++ b/apps/docs/instrumentation-client.ts @@ -1,9 +1,10 @@ import posthog from "posthog-js"; +import { posthogConfig } from "@/config/posthog.mjs"; posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, { - api_host: "/ingest", - ui_host: "https://us.posthog.com", - defaults: "2025-05-24", + api_host: posthogConfig.apiHost, + ui_host: posthogConfig.uiHost, + defaults: posthogConfig.defaults, capture_exceptions: true, // This enables capturing exceptions using Error Tracking debug: process.env.NODE_ENV === "development", }); diff --git a/apps/docs/next.config.mjs b/apps/docs/next.config.mjs index 0863cfeb5..3b4130885 100644 --- a/apps/docs/next.config.mjs +++ b/apps/docs/next.config.mjs @@ -1,4 +1,5 @@ import { createMDX } from "fumadocs-mdx/next"; +import { posthogConfig } from "./config/posthog.mjs"; const withMDX = createMDX(); @@ -30,16 +31,16 @@ const config = { destination: "/llms.mdx/:path*", }, { - source: "/ingest/static/:path*", - destination: "https://us-assets.i.posthog.com/static/:path*", + source: `${posthogConfig.apiHost}/static/:path*`, + destination: `${posthogConfig.assetsHost}/static/:path*`, }, { - source: "/ingest/:path*", - destination: "https://us.i.posthog.com/:path*", + source: `${posthogConfig.apiHost}/:path*`, + destination: `${posthogConfig.ingestHost}/:path*`, }, { - source: "/ingest/decide", - destination: "https://us.i.posthog.com/decide", + source: `${posthogConfig.apiHost}/decide`, + destination: `${posthogConfig.ingestHost}/decide`, }, ]; }, diff --git a/apps/examples/src/01-getting-started/agents/agent.ts b/apps/examples/src/01-getting-started/agents/agent.ts index e7b179748..a5aaa977d 100644 --- a/apps/examples/src/01-getting-started/agents/agent.ts +++ b/apps/examples/src/01-getting-started/agents/agent.ts @@ -1,5 +1,6 @@ import { AgentBuilder } from "@iqai/adk"; import z from "zod/v4"; // Ensure its v4! +import { DEFAULT_MODEL } from "../../config"; export function getRootAgent() { const outputSchema = z.object({ @@ -12,9 +13,7 @@ export function getRootAgent() { funFact: z.string().describe("An interesting fact about the city"), }); - return AgentBuilder.withModel( - process.env.LLM_MODEL || "gemini-3-flash-preview", - ) + return AgentBuilder.withModel(process.env.LLM_MODEL || DEFAULT_MODEL) .withOutputSchema(outputSchema) .build(); } diff --git a/apps/examples/src/02-tools-and-state/agents/agent.ts b/apps/examples/src/02-tools-and-state/agents/agent.ts index 74eba29c5..1d47b1361 100644 --- a/apps/examples/src/02-tools-and-state/agents/agent.ts +++ b/apps/examples/src/02-tools-and-state/agents/agent.ts @@ -1,5 +1,6 @@ import { AgentBuilder } from "@iqai/adk"; import dedent from "dedent"; +import { DEFAULT_MODEL } from "../../config"; import { addItemTool, viewCartTool } from "./tools"; export function getRootAgent() { @@ -9,7 +10,7 @@ export function getRootAgent() { }; return AgentBuilder.create("shopping_cart_agent") - .withModel(process.env.LLM_MODEL || "gemini-3-flash-preview") + .withModel(process.env.LLM_MODEL || DEFAULT_MODEL) .withInstruction( dedent` You are a shopping cart assistant. Help users manage their cart. diff --git a/apps/examples/src/03-multi-agent-systems/agents/agent.ts b/apps/examples/src/03-multi-agent-systems/agents/agent.ts index 53beaa2e7..5d26caefa 100644 --- a/apps/examples/src/03-multi-agent-systems/agents/agent.ts +++ b/apps/examples/src/03-multi-agent-systems/agents/agent.ts @@ -1,4 +1,5 @@ import { AgentBuilder } from "@iqai/adk"; +import { DEFAULT_MODEL } from "../../config"; import { getCustomerAnalyzerAgent } from "./customer-analyzer/agent"; import { getMenuValidatorAgent } from "./menu-validator/agent"; import { getOrderFinalizerAgent } from "./order-finalizer/agent"; @@ -14,7 +15,7 @@ export function getRootAgent() { }; return AgentBuilder.create("restaurant_order_system") - .withModel(process.env.LLM_MODEL || "gemini-3-flash-preview") + .withModel(process.env.LLM_MODEL || DEFAULT_MODEL) .withSubAgents([customerAnalyzer, menuValidator, orderFinalizer]) .withQuickSession({ state: initialState }) .build(); diff --git a/apps/examples/src/03-multi-agent-systems/agents/customer-analyzer/agent.ts b/apps/examples/src/03-multi-agent-systems/agents/customer-analyzer/agent.ts index 38338c194..839e31f59 100644 --- a/apps/examples/src/03-multi-agent-systems/agents/customer-analyzer/agent.ts +++ b/apps/examples/src/03-multi-agent-systems/agents/customer-analyzer/agent.ts @@ -1,5 +1,6 @@ import { LlmAgent } from "@iqai/adk"; import dedent from "dedent"; +import { DEFAULT_MODEL } from "../../../config"; export function getCustomerAnalyzerAgent() { return new LlmAgent({ @@ -10,6 +11,6 @@ export function getCustomerAnalyzerAgent() { Return the extracted information in a clear, structured format. `, outputKey: "customer_preferences", - model: process.env.LLM_MODEL || "gemini-3-flash-preview", + model: process.env.LLM_MODEL || DEFAULT_MODEL, }); } diff --git a/apps/examples/src/03-multi-agent-systems/agents/menu-validator/agent.ts b/apps/examples/src/03-multi-agent-systems/agents/menu-validator/agent.ts index 90c9a3d61..e9d2c0c49 100644 --- a/apps/examples/src/03-multi-agent-systems/agents/menu-validator/agent.ts +++ b/apps/examples/src/03-multi-agent-systems/agents/menu-validator/agent.ts @@ -1,5 +1,6 @@ import { LlmAgent } from "@iqai/adk"; import dedent from "dedent"; +import { DEFAULT_MODEL } from "../../../config"; export function getMenuValidatorAgent() { return new LlmAgent({ @@ -13,6 +14,6 @@ export function getMenuValidatorAgent() { Check availability and suggest alternatives if needed. `, outputKey: "menu_validation", - model: process.env.LLM_MODEL || "gemini-3-flash-preview", + model: process.env.LLM_MODEL || DEFAULT_MODEL, }); } diff --git a/apps/examples/src/03-multi-agent-systems/agents/order-finalizer/agent.ts b/apps/examples/src/03-multi-agent-systems/agents/order-finalizer/agent.ts index d86d16e80..1f2687ae2 100644 --- a/apps/examples/src/03-multi-agent-systems/agents/order-finalizer/agent.ts +++ b/apps/examples/src/03-multi-agent-systems/agents/order-finalizer/agent.ts @@ -1,5 +1,6 @@ import { LlmAgent } from "@iqai/adk"; import dedent from "dedent"; +import { DEFAULT_MODEL } from "../../../config"; export function getOrderFinalizerAgent() { return new LlmAgent({ @@ -12,6 +13,6 @@ export function getOrderFinalizerAgent() { Create final order summary with items, prices ($8-25 per item), total, and prep time (15-45 min). `, - model: process.env.LLM_MODEL || "gemini-3-flash-preview", + model: process.env.LLM_MODEL || DEFAULT_MODEL, }); } diff --git a/apps/examples/src/04-persistence-and-sessions/agents/agent.ts b/apps/examples/src/04-persistence-and-sessions/agents/agent.ts index c79dfefde..04b724fea 100644 --- a/apps/examples/src/04-persistence-and-sessions/agents/agent.ts +++ b/apps/examples/src/04-persistence-and-sessions/agents/agent.ts @@ -6,6 +6,7 @@ import { createDatabaseSessionService, InMemoryArtifactService, } from "@iqai/adk"; +import { DEFAULT_MODEL } from "../../config"; import { counterTool, saveCounterReportTool } from "./tools"; export async function getRootAgent() { @@ -19,9 +20,7 @@ export async function getRootAgent() { ); const artifactService = new InMemoryArtifactService(); - return await AgentBuilder.withModel( - process.env.LLM_MODEL || "gemini-3-flash-preview", - ) + return await AgentBuilder.withModel(process.env.LLM_MODEL || DEFAULT_MODEL) .withTools(counterTool, saveCounterReportTool) .withSessionService(sessionService) .withArtifactService(artifactService) diff --git a/apps/examples/src/05-planning-and-code-execution/agents/agent.ts b/apps/examples/src/05-planning-and-code-execution/agents/agent.ts index 3d67ffd1b..9e3622232 100644 --- a/apps/examples/src/05-planning-and-code-execution/agents/agent.ts +++ b/apps/examples/src/05-planning-and-code-execution/agents/agent.ts @@ -1,5 +1,6 @@ import { AgentBuilder, BuiltInCodeExecutor, PlanReActPlanner } from "@iqai/adk"; import dedent from "dedent"; +import { DEFAULT_MODEL_STABLE } from "../../config"; /** * Creates an agent with planning and code execution capabilities. @@ -14,7 +15,7 @@ import dedent from "dedent"; */ export async function getRootAgent() { return await AgentBuilder.create("code_planner_agent") - .withModel(process.env.LLM_MODEL || "gemini-2.5-flash") + .withModel(process.env.LLM_MODEL || DEFAULT_MODEL_STABLE) .withDescription("Agent with planning and code execution capabilities") .withInstruction( dedent` diff --git a/apps/examples/src/06-mcp-and-integrations/index.ts b/apps/examples/src/06-mcp-and-integrations/index.ts index 93f781ab0..2f145dc6a 100644 --- a/apps/examples/src/06-mcp-and-integrations/index.ts +++ b/apps/examples/src/06-mcp-and-integrations/index.ts @@ -1,4 +1,5 @@ import { AgentBuilder, createSamplingHandler, LlmRequest } from "@iqai/adk"; +import { DEFAULT_MODEL_STABLE } from "../config"; import { ask } from "../utils"; import { getCoingeckoTools, getGreetingTools } from "./tools"; @@ -21,7 +22,7 @@ import { getCoingeckoTools, getGreetingTools } from "./tools"; * This bidirectional flow is powerful for complex integrations. */ async function main() { - const modelName = process.env.LLM_MODEL || "gemini-2.5-flash"; + const modelName = process.env.LLM_MODEL || DEFAULT_MODEL_STABLE; // Two specialized agents for the sampling handler to route between const { runner: creativeRunner } = await AgentBuilder.withModel(modelName) diff --git a/apps/examples/src/07-guardrails-and-evaluation/agents/agent.ts b/apps/examples/src/07-guardrails-and-evaluation/agents/agent.ts index f1ea04ac9..1bce4c4d3 100644 --- a/apps/examples/src/07-guardrails-and-evaluation/agents/agent.ts +++ b/apps/examples/src/07-guardrails-and-evaluation/agents/agent.ts @@ -1,5 +1,6 @@ import { AgentBuilder } from "@iqai/adk"; import dedent from "dedent"; +import { DEFAULT_MODEL } from "../../config"; import { GuardrailsPlugin } from "./plugins"; import { getWeatherTool } from "./tools"; @@ -7,7 +8,7 @@ export function getRootAgent() { const guardrailsPlugin = new GuardrailsPlugin(); return AgentBuilder.create("weather_guardrails_agent") - .withModel(process.env.LLM_MODEL || "gemini-3-flash-preview") + .withModel(process.env.LLM_MODEL || DEFAULT_MODEL) .withDescription("A weather assistant with guardrails") .withInstruction( dedent` diff --git a/apps/examples/src/08-observability-and-plugins/agents/agent.ts b/apps/examples/src/08-observability-and-plugins/agents/agent.ts index 6faade2e9..bbbfc32dd 100644 --- a/apps/examples/src/08-observability-and-plugins/agents/agent.ts +++ b/apps/examples/src/08-observability-and-plugins/agents/agent.ts @@ -1,9 +1,10 @@ import { AgentBuilder } from "@iqai/adk"; +import { DEFAULT_MODEL } from "../../config"; import { getWeatherTool } from "./tools"; export function getRootAgent() { return AgentBuilder.create("weather_agent") - .withModel(process.env.LLM_MODEL || "gemini-3-flash-preview") + .withModel(process.env.LLM_MODEL || DEFAULT_MODEL) .withTools(getWeatherTool) .withInstruction("You help users check the weather.") .build(); diff --git a/apps/examples/src/09-memory-system/agents/agent.ts b/apps/examples/src/09-memory-system/agents/agent.ts index 83daabcaf..53c8ea0b5 100644 --- a/apps/examples/src/09-memory-system/agents/agent.ts +++ b/apps/examples/src/09-memory-system/agents/agent.ts @@ -9,6 +9,7 @@ import { RecallMemoryTool, VectorStorageProvider, } from "@iqai/adk"; +import { DEFAULT_MODEL_STABLE } from "../../config"; export async function getRootAgent() { const sessionService = new InMemorySessionService(); @@ -32,7 +33,7 @@ export async function getRootAgent() { }), }); - return AgentBuilder.withModel(process.env.LLM_MODEL || "gemini-2.5-flash") + return AgentBuilder.withModel(process.env.LLM_MODEL || DEFAULT_MODEL_STABLE) .withInstruction( "You are a helpful assistant. When asked about previous conversations or user preferences, use the recall_memory tool to search your memory. Only use tools that are provided to you.", ) diff --git a/apps/examples/src/09-scheduling/agents/agent.ts b/apps/examples/src/09-scheduling/agents/agent.ts index 149733cbe..bd8ef22c9 100644 --- a/apps/examples/src/09-scheduling/agents/agent.ts +++ b/apps/examples/src/09-scheduling/agents/agent.ts @@ -1,8 +1,9 @@ import { AgentBuilder } from "@iqai/adk"; +import { DEFAULT_MODEL_STABLE } from "../../config"; export function getReporterAgent() { return AgentBuilder.create("scheduled_reporter") - .withModel(process.env.LLM_MODEL || "gemini-2.5-flash") + .withModel(process.env.LLM_MODEL || DEFAULT_MODEL_STABLE) .withInstruction( "You are a concise status reporter. When asked, generate a short status update with a random fun fact. Keep it to 2-3 sentences.", ) diff --git a/apps/examples/src/config.ts b/apps/examples/src/config.ts new file mode 100644 index 000000000..516870854 --- /dev/null +++ b/apps/examples/src/config.ts @@ -0,0 +1,3 @@ +/** Default models for examples. Override per-run with the LLM_MODEL env var. */ +export const DEFAULT_MODEL = "gemini-3-flash-preview"; +export const DEFAULT_MODEL_STABLE = "gemini-2.5-flash"; diff --git a/apps/starter-templates/shade-agent/src/env.ts b/apps/starter-templates/shade-agent/src/env.ts index 5af2c31af..5ba31f536 100644 --- a/apps/starter-templates/shade-agent/src/env.ts +++ b/apps/starter-templates/shade-agent/src/env.ts @@ -14,6 +14,9 @@ export const envSchema = z.object({ ADK_DEBUG: z.coerce.boolean().default(false), GOOGLE_API_KEY: z.string(), LLM_MODEL: z.string().default("gemini-2.5-flash"), + // Optional, not required: a missing value must stay a graceful runtime + // error (handled in the routes), not a fail-at-boot Zod throw. + NEXT_PUBLIC_contractId: z.string().optional(), }); /** diff --git a/apps/starter-templates/shade-agent/src/routes/ethAccount.ts b/apps/starter-templates/shade-agent/src/routes/ethAccount.ts index a06cda676..3f54e7b57 100644 --- a/apps/starter-templates/shade-agent/src/routes/ethAccount.ts +++ b/apps/starter-templates/shade-agent/src/routes/ethAccount.ts @@ -1,11 +1,15 @@ import { Hono } from "hono"; +import { env } from "../env"; import { Evm } from "../utils/ethereum"; const app = new Hono(); app.get("/", async (c) => { // Fetch the environment variable inside the route - const contractId = process.env.NEXT_PUBLIC_contractId; + const contractId = env.NEXT_PUBLIC_contractId; + if (!contractId) { + return c.json({ error: "Contract ID not configured" }, 500); + } try { // Derive the price pusher Ethereum address const { address: senderAddress } = await Evm.deriveAddressAndPublicKey( diff --git a/apps/starter-templates/shade-agent/src/routes/transaction.ts b/apps/starter-templates/shade-agent/src/routes/transaction.ts index 166a926c5..0d0134bb7 100644 --- a/apps/starter-templates/shade-agent/src/routes/transaction.ts +++ b/apps/starter-templates/shade-agent/src/routes/transaction.ts @@ -3,6 +3,7 @@ import { utils } from "chainsig.js"; import { Contract, JsonRpcProvider } from "ethers"; import { Hono } from "hono"; import { getRootAgent } from "../agents/agent"; +import { env } from "../env"; import { Evm, ethContractAbi, @@ -17,7 +18,7 @@ const app = new Hono(); app.get("/", async (c) => { try { // Fetch the environment variable inside the route - const contractId = process.env.NEXT_PUBLIC_contractId; + const contractId = env.NEXT_PUBLIC_contractId; if (!contractId) { return c.json({ error: "Contract ID not configured" }, 500); }