{"record":{"id":"1686b2cdcde9f73a","repo":"JuliusBrussee/caveman","slug":"strategy-must-be-all-or-deferred","errorCode":null,"errorMessage":"strategy must be all or deferred","messagePattern":"strategy must be all or deferred","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/sdk/typescript/src/index.ts","lineNumber":471,"sourceCode":"   */\n  exporter(config: { serviceName?: string } = {}): OTelExporter {\n    return new OTelExporter(this, config.serviceName ?? this.options.agent);\n  }\n\n  /**\n   * Build a tool-catalog handle with server-side search via /sdk/v1/tool-search.\n   *\n   * strategy \"all\"      → initial = whole catalog; search() still calls the server.\n   * strategy \"deferred\" → initial = alwaysLoad tools (subset sent on first turn);\n   *                       search() calls the server to load relevant tools on demand.\n   *\n   * Breaking change from 1.0: search() is now async and returns ToolSearchResult\n   * (previously sync, returning CaveTool[]). Callers must await search().\n   */\n  tools(config: { catalog: CaveTool[]; strategy?: \"all\" | \"deferred\"; initialToolCount?: number; maxLoadedTools?: number }) {\n    const strategy = config.strategy ?? \"all\";\n    if (strategy !== \"all\" && strategy !== \"deferred\") {\n      throw new Error(\"strategy must be all or deferred\");\n    }\n    const initialToolCount = config.initialToolCount ?? 8;\n    if (!Number.isSafeInteger(initialToolCount) || initialToolCount < 0) {\n      throw new Error(\"initialToolCount must be a non-negative integer\");\n    }\n    if (config.maxLoadedTools !== undefined && (!Number.isSafeInteger(config.maxLoadedTools) || config.maxLoadedTools < 1)) {\n      throw new Error(\"maxLoadedTools must be a positive integer\");\n    }\n    let initial: CaveTool[];\n    if (strategy === \"all\") {\n      initial = config.catalog.slice();\n    } else {\n      const always = config.catalog.filter((tool) => tool.alwaysLoad);\n      if (config.maxLoadedTools !== undefined && always.length > config.maxLoadedTools) {\n        throw new Error(\"maxLoadedTools must be at least the alwaysLoad tool count\");\n      }\n      const lazy = config.catalog.filter((tool) => !tool.alwaysLoad);\n      const lazyLimit = config.maxLoadedTools === undefined","sourceCodeStart":453,"sourceCodeEnd":489,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/sdk/typescript/src/index.ts#L453-L489","documentation":"The tools() descriptor validates the optional strategy option, which must be exactly \"all\" (load all tools up front) or \"deferred\" (lazy tool loading). Any other string — including older strategy names from the 1.0 API — is rejected. The strategy controls the deferred-loading behavior introduced in the 2.0 breaking change, so unknown values cannot be safely interpreted.","triggerScenarios":"cave.tools({ catalog, strategy: \"lazy\" }) or strategy: \"none\" or a strategy value read from config/env as free text; upgrading from 1.0 and passing a strategy value that no longer exists.","commonSituations":"Typos like \"deffered\"; using pre-2.0 strategy names after the breaking change (the doc note says search() became async in the same release); strategies chosen conditionally with string building instead of the union type.","solutions":["Pass strategy: \"all\" or strategy: \"deferred\" exactly, or omit it to default to \"all\".","Type the value as `\"all\" | \"deferred\"` in your config so invalid values fail at compile time.","If migrating from 1.0, review the 2.0 changelog for renamed options and update call sites."],"exampleFix":"// before\ncave.tools({ catalog, strategy: \"lazy\" });\n\n// after\ncave.tools({ catalog, strategy: \"deferred\" });","handlingStrategy":"validation","validationCode":"const isToolStrategy = (v: unknown): v is \"all\" | \"deferred\" => v === \"all\" || v === \"deferred\";\nif (config.strategy !== undefined && !isToolStrategy(config.strategy)) throw new Error(`strategy must be 'all' or 'deferred', got ${JSON.stringify(config.strategy)}`);","typeGuard":"const isToolStrategy = (v: unknown): v is \"all\" | \"deferred\" =>\n  typeof v === \"string\" && (v === \"all\" || v === \"deferred\");","tryCatchPattern":"try {\n  const desc = cave.tools({ catalog, strategy });\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"strategy must be all or deferred\")) {\n    const desc = cave.tools({ catalog }); // default strategy \"all\"\n  } else throw e;\n}","preventionTips":["Use only \"all\" or \"deferred\"; omit the option for the default.","Type strategy as the union `\"all\" | \"deferred\"`, never plain string.","When migrating from the 1.0 API, re-check option names and allowed values against 2.0 docs."],"tags":["validation","enum","tools","configuration"],"backgroundTag":"invalid-enum-value","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}