@usewhisper/mcp-server 2.15.0 → 2.16.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.
Files changed (2) hide show
  1. package/dist/server.js +797 -448
  2. package/package.json +1 -1
package/dist/server.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // ../src/mcp/server.ts
4
4
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
- import { z } from "zod";
6
+ import { z as z2 } from "zod";
7
7
  import { execSync, spawnSync } from "child_process";
8
8
  import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync, appendFileSync } from "fs";
9
9
  import { join, relative, extname, normalize as normalizePath, resolve as resolvePath } from "path";
@@ -127,6 +127,8 @@ var RuntimeClientError = class extends Error {
127
127
  code;
128
128
  details;
129
129
  traceId;
130
+ hint;
131
+ requestId;
130
132
  constructor(args) {
131
133
  super(args.message);
132
134
  this.name = "RuntimeClientError";
@@ -135,6 +137,8 @@ var RuntimeClientError = class extends Error {
135
137
  this.code = args.code;
136
138
  this.details = args.details;
137
139
  this.traceId = args.traceId;
140
+ this.hint = args.hint;
141
+ this.requestId = args.requestId;
138
142
  }
139
143
  };
140
144
  var RuntimeClient = class {
@@ -339,14 +343,22 @@ var RuntimeClient = class {
339
343
  };
340
344
  }
341
345
  const message = toMessage(payload, response.status, response.statusText);
342
- const retryable = this.shouldRetryStatus(response.status);
346
+ const payloadObject = isObject(payload) ? payload : {};
347
+ const payloadCode = typeof payloadObject.code === "string" ? payloadObject.code : void 0;
348
+ const payloadHint = typeof payloadObject.hint === "string" ? payloadObject.hint : void 0;
349
+ const payloadRequestId = typeof payloadObject.requestId === "string" ? payloadObject.requestId : typeof payloadObject.request_id === "string" ? payloadObject.request_id : void 0;
350
+ const payloadRetryable = typeof payloadObject.retryable === "boolean" ? payloadObject.retryable : void 0;
351
+ const statusRetryable = this.shouldRetryStatus(response.status);
352
+ const retryable = payloadRetryable ?? statusRetryable;
343
353
  const error = new RuntimeClientError({
344
354
  message,
345
355
  status: response.status,
346
356
  retryable,
347
- code: response.status === 404 ? "NOT_FOUND" : "REQUEST_FAILED",
357
+ code: payloadCode || (response.status === 404 ? "NOT_FOUND" : "REQUEST_FAILED"),
348
358
  details: payload,
349
- traceId
359
+ traceId: payloadRequestId || traceId,
360
+ requestId: payloadRequestId || traceId,
361
+ hint: payloadHint
350
362
  });
351
363
  lastError = error;
352
364
  if (!retryable || attempt === maxAttempts - 1) {
@@ -360,7 +372,8 @@ var RuntimeClient = class {
360
372
  message: isAbort ? "Request timed out" : error instanceof Error ? error.message : "Network error",
361
373
  retryable: this.retryPolicy.retryOnNetworkError ?? true,
362
374
  code: isAbort ? "TIMEOUT" : "NETWORK_ERROR",
363
- traceId
375
+ traceId,
376
+ requestId: traceId
364
377
  });
365
378
  lastError = mapped;
366
379
  this.diagnostics.add({
@@ -391,6 +404,26 @@ var RuntimeClient = class {
391
404
  }
392
405
  };
393
406
 
407
+ // ../src/sdk/errors.ts
408
+ var WhisperError = class extends Error {
409
+ code;
410
+ status;
411
+ retryable;
412
+ hint;
413
+ requestId;
414
+ details;
415
+ constructor(args) {
416
+ super(args.message, args.cause ? { cause: args.cause } : void 0);
417
+ this.name = "WhisperError";
418
+ this.code = args.code;
419
+ this.status = args.status;
420
+ this.retryable = args.retryable ?? false;
421
+ this.hint = args.hint;
422
+ this.requestId = args.requestId;
423
+ this.details = args.details;
424
+ }
425
+ };
426
+
394
427
  // ../src/sdk/core/cache.ts
395
428
  var SearchResponseCache = class {
396
429
  ttlMs;
@@ -2186,12 +2219,44 @@ ${lines.join("\n")}`;
2186
2219
 
2187
2220
  // ../src/sdk/whisper.ts
2188
2221
  var PROJECT_CACHE_TTL_MS = 3e4;
2222
+ var IDENTITY_WARNINGS = /* @__PURE__ */ new Set();
2189
2223
  function isLikelyProjectId(projectRef) {
2190
2224
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(projectRef);
2191
2225
  }
2226
+ function randomRequestId() {
2227
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
2228
+ return crypto.randomUUID();
2229
+ }
2230
+ return `req_${Math.random().toString(36).slice(2, 11)}`;
2231
+ }
2232
+ function parseIdentityMode(value) {
2233
+ return value === "app-identity" ? "app-identity" : "demo-local";
2234
+ }
2235
+ function parseEnvironment(value) {
2236
+ if (value === "staging" || value === "production") return value;
2237
+ return "local";
2238
+ }
2239
+ function classifyRuntimeErrorCode(error) {
2240
+ if (error.code === "MISSING_PROJECT") return "MISSING_PROJECT";
2241
+ if (error.code === "TIMEOUT") return "TIMEOUT";
2242
+ if (error.code === "NETWORK_ERROR") return "NETWORK_ERROR";
2243
+ if (error.code === "VALIDATION_ERROR") return "VALIDATION_ERROR";
2244
+ if (error.status === 401 || error.status === 403) return "INVALID_API_KEY";
2245
+ if (error.status === 408) return "TIMEOUT";
2246
+ if (error.status === 429) return "RATE_LIMITED";
2247
+ if (error.status && error.status >= 500) return "TEMPORARY_UNAVAILABLE";
2248
+ if (error.code === "PROJECT_NOT_FOUND" || error.code === "NOT_FOUND") return "PROJECT_NOT_FOUND";
2249
+ return "REQUEST_FAILED";
2250
+ }
2192
2251
  var WhisperClient = class _WhisperClient {
2193
2252
  constructor(config) {
2194
2253
  this.config = config;
2254
+ const env = typeof process !== "undefined" ? process.env : {};
2255
+ this.identityMode = parseIdentityMode(config.identityMode || env.WHISPER_IDENTITY_MODE);
2256
+ this.environment = parseEnvironment(config.environment || env.WHISPER_ENV || (env.NODE_ENV === "production" ? "production" : "local"));
2257
+ this.strictIdentityMode = config.strictIdentityMode ?? env.WHISPER_DEMO_LOCAL_STRICT === "true";
2258
+ this.getIdentity = config.getIdentity;
2259
+ this.enforceIdentityModeGuardrail();
2195
2260
  this.diagnosticsStore = new DiagnosticsStore(config.telemetry?.maxEntries || 1e3);
2196
2261
  this.runtimeClient = new RuntimeClient(
2197
2262
  {
@@ -2301,26 +2366,29 @@ var WhisperClient = class _WhisperClient {
2301
2366
  status: () => this.writeQueue.status()
2302
2367
  };
2303
2368
  this.memory = {
2304
- add: (params) => this.memoryModule.add(params),
2305
- addBulk: (params) => this.memoryModule.addBulk(params),
2306
- search: (params) => this.memoryModule.search(params),
2307
- get: (memoryId) => this.memoryModule.get(memoryId),
2308
- getUserProfile: (params) => this.memoryModule.getUserProfile(params),
2309
- getSessionMemories: (params) => this.memoryModule.getSessionMemories(params),
2310
- update: (memoryId, params) => this.memoryModule.update(memoryId, params),
2311
- delete: (memoryId) => this.memoryModule.delete(memoryId),
2312
- flag: (params) => this.memoryModule.flag(params)
2369
+ add: (params) => this.runOrThrow(async () => this.memoryModule.add(await this.withIdentity(params))),
2370
+ addBulk: (params) => this.runOrThrow(async () => this.memoryModule.addBulk({
2371
+ ...params,
2372
+ memories: await Promise.all(params.memories.map((memory) => this.withIdentity(memory)))
2373
+ })),
2374
+ search: (params) => this.runOrThrow(async () => this.memoryModule.search(await this.withIdentity(params))),
2375
+ get: (memoryId) => this.runOrThrow(async () => this.memoryModule.get(memoryId)),
2376
+ getUserProfile: (params) => this.runOrThrow(async () => this.profileModule.getUserProfile(await this.withIdentity(params, true))),
2377
+ getSessionMemories: (params) => this.runOrThrow(async () => this.profileModule.getSessionMemories(await this.withIdentity(params))),
2378
+ update: (memoryId, params) => this.runOrThrow(async () => this.memoryModule.update(memoryId, params)),
2379
+ delete: (memoryId) => this.runOrThrow(async () => this.memoryModule.delete(memoryId)),
2380
+ flag: (params) => this.runOrThrow(async () => this.memoryModule.flag(params))
2313
2381
  };
2314
2382
  this.session = {
2315
- start: (params) => this.sessionModule.start(params),
2316
- event: (params) => this.sessionModule.event(params),
2317
- suspend: (params) => this.sessionModule.suspend(params),
2318
- resume: (params) => this.sessionModule.resume(params),
2319
- end: (params) => this.sessionModule.end(params)
2383
+ start: (params) => this.runOrThrow(async () => this.sessionModule.start(await this.withSessionIdentity(params))),
2384
+ event: (params) => this.runOrThrow(async () => this.sessionModule.event(params)),
2385
+ suspend: (params) => this.runOrThrow(async () => this.sessionModule.suspend(params)),
2386
+ resume: (params) => this.runOrThrow(async () => this.sessionModule.resume(params)),
2387
+ end: (params) => this.runOrThrow(async () => this.sessionModule.end(params))
2320
2388
  };
2321
2389
  this.profile = {
2322
- getUserProfile: (params) => this.profileModule.getUserProfile(params),
2323
- getSessionMemories: (params) => this.profileModule.getSessionMemories(params)
2390
+ getUserProfile: (params) => this.runOrThrow(async () => this.profileModule.getUserProfile(await this.withIdentity(params, true))),
2391
+ getSessionMemories: (params) => this.runOrThrow(async () => this.profileModule.getSessionMemories(await this.withIdentity(params)))
2324
2392
  };
2325
2393
  this.analytics = {
2326
2394
  diagnosticsSnapshot: () => this.analyticsModule.diagnosticsSnapshot(),
@@ -2342,18 +2410,158 @@ var WhisperClient = class _WhisperClient {
2342
2410
  profileModule;
2343
2411
  analyticsModule;
2344
2412
  projectRefToId = /* @__PURE__ */ new Map();
2413
+ identityMode;
2414
+ environment;
2415
+ strictIdentityMode;
2416
+ getIdentity;
2345
2417
  projectCache = [];
2346
2418
  projectCacheExpiresAt = 0;
2419
+ enforceIdentityModeGuardrail(requestId = randomRequestId()) {
2420
+ if (this.identityMode !== "demo-local") return;
2421
+ if (this.environment === "local") return;
2422
+ const message = "[Whisper SDK] WHISPER_IDENTITY_MODE=demo-local is intended only for local development. Switch to app-identity and provide getIdentity() or per-call user_id/session_id.";
2423
+ if (this.strictIdentityMode || this.environment === "production") {
2424
+ throw new WhisperError({
2425
+ code: "MISCONFIGURED_IDENTITY_MODE",
2426
+ message,
2427
+ retryable: false,
2428
+ hint: "Set identityMode: 'app-identity' and provide a getIdentity() function that returns { userId, sessionId? }. To override for testing, set environment: 'local' explicitly."
2429
+ });
2430
+ }
2431
+ const warningKey = `${this.environment}:${this.identityMode}`;
2432
+ if (!IDENTITY_WARNINGS.has(warningKey)) {
2433
+ IDENTITY_WARNINGS.add(warningKey);
2434
+ if (typeof console !== "undefined" && typeof console.warn === "function") {
2435
+ console.warn(`${message} requestId=${requestId}`);
2436
+ }
2437
+ }
2438
+ }
2439
+ toWhisperError(error, hint) {
2440
+ if (error instanceof WhisperError) return error;
2441
+ if (error instanceof RuntimeClientError) {
2442
+ return new WhisperError({
2443
+ code: classifyRuntimeErrorCode(error),
2444
+ message: error.message,
2445
+ status: error.status,
2446
+ retryable: error.retryable,
2447
+ hint: error.hint || hint,
2448
+ requestId: error.requestId || error.traceId,
2449
+ details: error.details,
2450
+ cause: error
2451
+ });
2452
+ }
2453
+ if (error instanceof Error) {
2454
+ return new WhisperError({
2455
+ code: "REQUEST_FAILED",
2456
+ message: error.message,
2457
+ retryable: false,
2458
+ hint,
2459
+ cause: error
2460
+ });
2461
+ }
2462
+ return new WhisperError({
2463
+ code: "REQUEST_FAILED",
2464
+ message: "Unknown SDK error",
2465
+ retryable: false,
2466
+ hint,
2467
+ details: error
2468
+ });
2469
+ }
2470
+ async runOrThrow(work, hint) {
2471
+ try {
2472
+ return await work();
2473
+ } catch (error) {
2474
+ throw this.toWhisperError(error, hint);
2475
+ }
2476
+ }
2477
+ async resolveIdentityOverride() {
2478
+ if (!this.getIdentity) return null;
2479
+ const resolved = await this.getIdentity();
2480
+ const userId = String(resolved?.userId || "").trim();
2481
+ const sessionId = resolved?.sessionId ? String(resolved.sessionId).trim() : void 0;
2482
+ if (!userId) {
2483
+ throw new WhisperError({
2484
+ code: "AUTH_IDENTITY_INVALID",
2485
+ message: "getIdentity() returned an invalid identity payload.",
2486
+ retryable: false,
2487
+ hint: "Return { userId, sessionId? } from getIdentity()."
2488
+ });
2489
+ }
2490
+ return {
2491
+ userId,
2492
+ sessionId: sessionId || void 0
2493
+ };
2494
+ }
2495
+ async withIdentity(params, requireUser = false) {
2496
+ const currentUser = params.user_id ? String(params.user_id).trim() : "";
2497
+ const currentSession = params.session_id ? String(params.session_id).trim() : "";
2498
+ if (currentUser) {
2499
+ return {
2500
+ ...params,
2501
+ user_id: currentUser,
2502
+ session_id: currentSession || params.session_id
2503
+ };
2504
+ }
2505
+ const resolved = await this.resolveIdentityOverride();
2506
+ if (resolved) {
2507
+ return {
2508
+ ...params,
2509
+ user_id: resolved.userId,
2510
+ session_id: currentSession || resolved.sessionId
2511
+ };
2512
+ }
2513
+ if (requireUser || this.identityMode === "app-identity") {
2514
+ throw new WhisperError({
2515
+ code: "AUTH_IDENTITY_REQUIRED",
2516
+ message: "A user identity is required in app-identity mode.",
2517
+ retryable: false,
2518
+ hint: "Provide user_id/session_id per call or configure getIdentity() in WhisperClient."
2519
+ });
2520
+ }
2521
+ return params;
2522
+ }
2523
+ async withSessionIdentity(params) {
2524
+ const userId = params.userId ? String(params.userId).trim() : "";
2525
+ const sessionId = params.sessionId ? String(params.sessionId).trim() : "";
2526
+ if (userId) {
2527
+ return {
2528
+ ...params,
2529
+ userId,
2530
+ sessionId: sessionId || params.sessionId
2531
+ };
2532
+ }
2533
+ const resolved = await this.resolveIdentityOverride();
2534
+ if (resolved?.userId) {
2535
+ return {
2536
+ ...params,
2537
+ userId: resolved.userId,
2538
+ sessionId: sessionId || resolved.sessionId
2539
+ };
2540
+ }
2541
+ throw new WhisperError({
2542
+ code: "AUTH_IDENTITY_REQUIRED",
2543
+ message: "Session operations require a user identity.",
2544
+ retryable: false,
2545
+ hint: "Pass userId explicitly or configure getIdentity() in WhisperClient."
2546
+ });
2547
+ }
2347
2548
  static fromEnv(overrides = {}) {
2348
2549
  const env = typeof process !== "undefined" ? process.env : {};
2349
2550
  const apiKey = overrides.apiKey || env.WHISPER_API_KEY || env.USEWHISPER_API_KEY || env.API_KEY;
2350
2551
  if (!apiKey) {
2351
- throw new Error("Missing API key. Set WHISPER_API_KEY / USEWHISPER_API_KEY / API_KEY.");
2552
+ throw new WhisperError({
2553
+ code: "INVALID_API_KEY",
2554
+ message: "Missing API key. Set WHISPER_API_KEY / USEWHISPER_API_KEY / API_KEY.",
2555
+ retryable: false
2556
+ });
2352
2557
  }
2353
2558
  return new _WhisperClient({
2354
2559
  apiKey,
2355
2560
  baseUrl: overrides.baseUrl || env.WHISPER_BASE_URL || env.API_BASE_URL || "https://context.usewhisper.dev",
2356
2561
  project: overrides.project || env.WHISPER_PROJECT || env.PROJECT,
2562
+ identityMode: overrides.identityMode || parseIdentityMode(env.WHISPER_IDENTITY_MODE),
2563
+ environment: overrides.environment || parseEnvironment(env.WHISPER_ENV || (env.NODE_ENV === "production" ? "production" : "local")),
2564
+ strictIdentityMode: overrides.strictIdentityMode ?? env.WHISPER_DEMO_LOCAL_STRICT === "true",
2357
2565
  ...overrides
2358
2566
  });
2359
2567
  }
@@ -2390,10 +2598,11 @@ var WhisperClient = class _WhisperClient {
2390
2598
  getRequiredProject(project) {
2391
2599
  const resolved = project || this.config.project;
2392
2600
  if (!resolved) {
2393
- throw new RuntimeClientError({
2601
+ throw new WhisperError({
2394
2602
  code: "MISSING_PROJECT",
2395
2603
  message: "Project is required",
2396
- retryable: false
2604
+ retryable: false,
2605
+ hint: "Pass project in the call or configure a default project in WhisperClient."
2397
2606
  });
2398
2607
  }
2399
2608
  return resolved;
@@ -2435,81 +2644,182 @@ var WhisperClient = class _WhisperClient {
2435
2644
  }
2436
2645
  }
2437
2646
  async resolveProject(projectRef) {
2438
- const resolvedRef = this.getRequiredProject(projectRef);
2439
- const cachedProjects = await this.refreshProjectCache(false);
2440
- const cachedProject = cachedProjects.find(
2441
- (project) => project.id === resolvedRef || project.slug === resolvedRef || project.name === resolvedRef
2442
- );
2443
- if (cachedProject) {
2444
- return cachedProject;
2647
+ return this.runOrThrow(async () => {
2648
+ const resolvedRef = this.getRequiredProject(projectRef);
2649
+ const cachedProjects = await this.refreshProjectCache(false);
2650
+ const cachedProject = cachedProjects.find(
2651
+ (project) => project.id === resolvedRef || project.slug === resolvedRef || project.name === resolvedRef
2652
+ );
2653
+ if (cachedProject) {
2654
+ return cachedProject;
2655
+ }
2656
+ const resolvedProject = await this.fetchResolvedProject(resolvedRef);
2657
+ if (resolvedProject) {
2658
+ this.projectRefToId.set(resolvedProject.id, resolvedProject.id);
2659
+ this.projectRefToId.set(resolvedProject.slug, resolvedProject.id);
2660
+ this.projectRefToId.set(resolvedProject.name, resolvedProject.id);
2661
+ this.projectCache = [
2662
+ ...this.projectCache.filter((project) => project.id !== resolvedProject.id),
2663
+ resolvedProject
2664
+ ];
2665
+ this.projectCacheExpiresAt = Date.now() + PROJECT_CACHE_TTL_MS;
2666
+ return resolvedProject;
2667
+ }
2668
+ if (isLikelyProjectId(resolvedRef)) {
2669
+ return {
2670
+ id: resolvedRef,
2671
+ orgId: "",
2672
+ name: resolvedRef,
2673
+ slug: resolvedRef,
2674
+ createdAt: (/* @__PURE__ */ new Date(0)).toISOString(),
2675
+ updatedAt: (/* @__PURE__ */ new Date(0)).toISOString()
2676
+ };
2677
+ }
2678
+ throw new WhisperError({
2679
+ code: "PROJECT_NOT_FOUND",
2680
+ message: `Project '${resolvedRef}' not found`,
2681
+ retryable: false
2682
+ });
2683
+ });
2684
+ }
2685
+ async preflight(options) {
2686
+ const requestId = randomRequestId();
2687
+ const checks = [];
2688
+ try {
2689
+ this.enforceIdentityModeGuardrail(requestId);
2690
+ } catch (error) {
2691
+ throw this.toWhisperError(error, "Update identity mode before running preflight.");
2692
+ }
2693
+ const apiKeyOk = typeof this.config.apiKey === "string" && this.config.apiKey.trim().length > 0;
2694
+ checks.push({
2695
+ check: "api_key",
2696
+ ok: apiKeyOk,
2697
+ message: apiKeyOk ? "API key is configured." : "Missing API key.",
2698
+ hint: apiKeyOk ? void 0 : "Set WHISPER_API_KEY or pass apiKey to WhisperClient."
2699
+ });
2700
+ try {
2701
+ await this.runtimeClient.request({
2702
+ endpoint: "/v1/projects",
2703
+ method: "GET",
2704
+ operation: "get",
2705
+ idempotent: true,
2706
+ traceId: requestId
2707
+ });
2708
+ checks.push({
2709
+ check: "api_connectivity",
2710
+ ok: true,
2711
+ message: "Connected to Whisper API."
2712
+ });
2713
+ } catch (error) {
2714
+ const mapped = this.toWhisperError(error, "Confirm WHISPER_BASE_URL and API key permissions.");
2715
+ checks.push({
2716
+ check: "api_connectivity",
2717
+ ok: false,
2718
+ message: mapped.message,
2719
+ hint: mapped.hint
2720
+ });
2445
2721
  }
2446
- const resolvedProject = await this.fetchResolvedProject(resolvedRef);
2447
- if (resolvedProject) {
2448
- this.projectRefToId.set(resolvedProject.id, resolvedProject.id);
2449
- this.projectRefToId.set(resolvedProject.slug, resolvedProject.id);
2450
- this.projectRefToId.set(resolvedProject.name, resolvedProject.id);
2451
- this.projectCache = [
2452
- ...this.projectCache.filter((project) => project.id !== resolvedProject.id),
2453
- resolvedProject
2454
- ];
2455
- this.projectCacheExpiresAt = Date.now() + PROJECT_CACHE_TTL_MS;
2456
- return resolvedProject;
2722
+ const projectRef = options?.project || this.config.project;
2723
+ if (projectRef) {
2724
+ try {
2725
+ await this.resolveProject(projectRef);
2726
+ checks.push({
2727
+ check: "project_access",
2728
+ ok: true,
2729
+ message: `Project '${projectRef}' is reachable.`
2730
+ });
2731
+ } catch (error) {
2732
+ const mapped = this.toWhisperError(error, "Create or grant access to the configured project.");
2733
+ checks.push({
2734
+ check: "project_access",
2735
+ ok: false,
2736
+ message: mapped.message,
2737
+ hint: mapped.hint
2738
+ });
2739
+ }
2740
+ } else {
2741
+ checks.push({
2742
+ check: "project_access",
2743
+ ok: true,
2744
+ message: "No default project configured (project will be required per call)."
2745
+ });
2457
2746
  }
2458
- if (isLikelyProjectId(resolvedRef)) {
2459
- return {
2460
- id: resolvedRef,
2461
- orgId: "",
2462
- name: resolvedRef,
2463
- slug: resolvedRef,
2464
- createdAt: (/* @__PURE__ */ new Date(0)).toISOString(),
2465
- updatedAt: (/* @__PURE__ */ new Date(0)).toISOString()
2466
- };
2747
+ if (options?.requireIdentity || this.identityMode === "app-identity") {
2748
+ try {
2749
+ const identity = await this.resolveIdentityOverride();
2750
+ const ok = Boolean(identity?.userId);
2751
+ checks.push({
2752
+ check: "identity_resolution",
2753
+ ok,
2754
+ message: ok ? "Identity resolver is configured." : "Identity resolver is missing.",
2755
+ hint: ok ? void 0 : "Provide getIdentity() or pass user_id/session_id per call."
2756
+ });
2757
+ } catch (error) {
2758
+ const mapped = this.toWhisperError(error, "Fix identity resolver output before production usage.");
2759
+ checks.push({
2760
+ check: "identity_resolution",
2761
+ ok: false,
2762
+ message: mapped.message,
2763
+ hint: mapped.hint
2764
+ });
2765
+ }
2467
2766
  }
2468
- throw new RuntimeClientError({
2469
- code: "PROJECT_NOT_FOUND",
2470
- message: `Project '${resolvedRef}' not found`,
2471
- retryable: false
2472
- });
2767
+ return {
2768
+ ok: checks.every((check) => check.ok),
2769
+ checks,
2770
+ requestId,
2771
+ identityMode: this.identityMode,
2772
+ environment: this.environment
2773
+ };
2473
2774
  }
2474
2775
  async query(params) {
2475
- const project = (await this.resolveProject(params.project)).id;
2476
- const response = await this.runtimeClient.request({
2477
- endpoint: "/v1/context/query",
2478
- method: "POST",
2479
- operation: "search",
2480
- body: {
2481
- ...params,
2482
- project
2483
- },
2484
- idempotent: true
2776
+ return this.runOrThrow(async () => {
2777
+ const identityParams = await this.withIdentity(params);
2778
+ const project = (await this.resolveProject(identityParams.project)).id;
2779
+ const response = await this.runtimeClient.request({
2780
+ endpoint: "/v1/context/query",
2781
+ method: "POST",
2782
+ operation: "search",
2783
+ body: {
2784
+ ...identityParams,
2785
+ project
2786
+ },
2787
+ idempotent: true
2788
+ });
2789
+ return response.data;
2485
2790
  });
2486
- return response.data;
2487
2791
  }
2488
2792
  async ingestSession(params) {
2489
- const project = (await this.resolveProject(params.project)).id;
2490
- const response = await this.runtimeClient.request({
2491
- endpoint: "/v1/memory/ingest/session",
2492
- method: "POST",
2493
- operation: "session",
2494
- body: {
2495
- ...params,
2496
- project
2497
- }
2793
+ return this.runOrThrow(async () => {
2794
+ const identityParams = await this.withIdentity(params);
2795
+ const project = (await this.resolveProject(identityParams.project)).id;
2796
+ const response = await this.runtimeClient.request({
2797
+ endpoint: "/v1/memory/ingest/session",
2798
+ method: "POST",
2799
+ operation: "session",
2800
+ body: {
2801
+ ...identityParams,
2802
+ project
2803
+ }
2804
+ });
2805
+ return response.data;
2498
2806
  });
2499
- return response.data;
2500
2807
  }
2501
2808
  async learn(params) {
2502
- const project = (await this.resolveProject(params.project)).id;
2503
- const response = await this.runtimeClient.request({
2504
- endpoint: "/v1/learn",
2505
- method: "POST",
2506
- operation: params.mode === "conversation" ? "session" : "bulk",
2507
- body: {
2508
- ...params,
2509
- project
2510
- }
2809
+ return this.runOrThrow(async () => {
2810
+ const identityParams = params.mode === "conversation" ? await this.withIdentity(params) : params;
2811
+ const project = (await this.resolveProject(identityParams.project)).id;
2812
+ const response = await this.runtimeClient.request({
2813
+ endpoint: "/v1/learn",
2814
+ method: "POST",
2815
+ operation: params.mode === "conversation" ? "session" : "bulk",
2816
+ body: {
2817
+ ...identityParams,
2818
+ project
2819
+ }
2820
+ });
2821
+ return response.data;
2511
2822
  });
2512
- return response.data;
2513
2823
  }
2514
2824
  createAgentRuntime(options = {}) {
2515
2825
  const baseContext = {
@@ -2571,26 +2881,60 @@ var WhisperClient = class _WhisperClient {
2571
2881
  diagnostics: base.diagnostics
2572
2882
  };
2573
2883
  }
2884
+ async deleteSource(sourceId) {
2885
+ return this.runOrThrow(async () => {
2886
+ const response = await this.runtimeClient.request({
2887
+ endpoint: `/v1/sources/${sourceId}`,
2888
+ method: "DELETE",
2889
+ operation: "writeAck"
2890
+ });
2891
+ return response.data;
2892
+ });
2893
+ }
2894
+ async extractMemories(params) {
2895
+ return this.runOrThrow(async () => {
2896
+ const project = (await this.resolveProject(params.project)).id;
2897
+ const response = await this.runtimeClient.request({
2898
+ endpoint: "/v1/memory/extract",
2899
+ method: "POST",
2900
+ operation: "writeAck",
2901
+ body: { project, message: params.message }
2902
+ });
2903
+ return response.data;
2904
+ });
2905
+ }
2574
2906
  async shutdown() {
2575
2907
  await this.writeQueue.stop();
2576
2908
  }
2577
2909
  };
2578
2910
 
2911
+ // ../src/sdk/adapters/tools.ts
2912
+ import { z } from "zod";
2913
+ var searchInputSchema = z.object({
2914
+ q: z.string().min(1),
2915
+ project: z.string().optional(),
2916
+ topK: z.number().int().positive().max(50).optional(),
2917
+ userId: z.string().optional(),
2918
+ sessionId: z.string().optional()
2919
+ });
2920
+ var rememberInputSchema = z.object({
2921
+ content: z.string().min(1),
2922
+ project: z.string().optional(),
2923
+ memoryType: z.enum([
2924
+ "factual",
2925
+ "preference",
2926
+ "event",
2927
+ "relationship",
2928
+ "opinion",
2929
+ "goal",
2930
+ "instruction"
2931
+ ]).optional(),
2932
+ userId: z.string().optional(),
2933
+ sessionId: z.string().optional(),
2934
+ metadata: z.record(z.unknown()).optional()
2935
+ });
2936
+
2579
2937
  // ../src/sdk/index.ts
2580
- var WhisperError = class extends Error {
2581
- code;
2582
- status;
2583
- retryable;
2584
- details;
2585
- constructor(args) {
2586
- super(args.message);
2587
- this.name = "WhisperError";
2588
- this.code = args.code;
2589
- this.status = args.status;
2590
- this.retryable = args.retryable ?? false;
2591
- this.details = args.details;
2592
- }
2593
- };
2594
2938
  var DEFAULT_MAX_ATTEMPTS = 3;
2595
2939
  var DEFAULT_BASE_DELAY_MS = 250;
2596
2940
  var DEFAULT_MAX_DELAY_MS = 2e3;
@@ -2961,7 +3305,10 @@ var WhisperContext = class _WhisperContext {
2961
3305
  message,
2962
3306
  status: error.status,
2963
3307
  retryable,
2964
- details: error.details
3308
+ hint: error.hint,
3309
+ requestId: error.requestId || error.traceId,
3310
+ details: error.details,
3311
+ cause: error
2965
3312
  });
2966
3313
  }
2967
3314
  }
@@ -6128,9 +6475,9 @@ server.tool(
6128
6475
  "index.workspace_resolve",
6129
6476
  "Resolve workspace identity from path + API key and map to a project without mandatory dashboard setup.",
6130
6477
  {
6131
- path: z.string().optional().describe("Workspace path. Defaults to current working directory."),
6132
- workspace_id: z.string().optional(),
6133
- project: z.string().optional()
6478
+ path: z2.string().optional().describe("Workspace path. Defaults to current working directory."),
6479
+ workspace_id: z2.string().optional(),
6480
+ project: z2.string().optional()
6134
6481
  },
6135
6482
  async ({ path, workspace_id, project }) => {
6136
6483
  try {
@@ -6167,8 +6514,8 @@ server.tool(
6167
6514
  "index.workspace_status",
6168
6515
  "Check index freshness, coverage, commit, and pending changes before retrieval/edits.",
6169
6516
  {
6170
- workspace_id: z.string().optional(),
6171
- path: z.string().optional()
6517
+ workspace_id: z2.string().optional(),
6518
+ path: z2.string().optional()
6172
6519
  },
6173
6520
  async ({ workspace_id, path }) => {
6174
6521
  try {
@@ -6205,10 +6552,10 @@ server.tool(
6205
6552
  "index.workspace_run",
6206
6553
  "Refresh local workspace index metadata (coverage, commit, freshness) for trust checks. This does not upload files or create backend embeddings.",
6207
6554
  {
6208
- workspace_id: z.string().optional(),
6209
- path: z.string().optional(),
6210
- mode: z.enum(["full", "incremental"]).optional().default("incremental"),
6211
- max_files: z.number().optional().default(1500)
6555
+ workspace_id: z2.string().optional(),
6556
+ path: z2.string().optional(),
6557
+ mode: z2.enum(["full", "incremental"]).optional().default("incremental"),
6558
+ max_files: z2.number().optional().default(1500)
6212
6559
  },
6213
6560
  async ({ workspace_id, path, mode, max_files }) => {
6214
6561
  try {
@@ -6254,11 +6601,11 @@ server.tool(
6254
6601
  "index.local_scan_ingest",
6255
6602
  "Ingest local files into Whisper backend (chunk/embed/index) and persist incremental manifest. Requires WHISPER_MCP_MODE=auto or local.",
6256
6603
  {
6257
- project: z.string().optional().describe("Project name or slug"),
6258
- path: z.string().optional().describe("Local path to ingest. Defaults to current working directory."),
6259
- glob: z.string().optional().describe("Optional include glob"),
6260
- max_files: z.number().optional().default(200),
6261
- chunk_chars: z.number().optional().default(2e4)
6604
+ project: z2.string().optional().describe("Project name or slug"),
6605
+ path: z2.string().optional().describe("Local path to ingest. Defaults to current working directory."),
6606
+ glob: z2.string().optional().describe("Optional include glob"),
6607
+ max_files: z2.number().optional().default(200),
6608
+ chunk_chars: z2.number().optional().default(2e4)
6262
6609
  },
6263
6610
  async ({ project, path, glob, max_files, chunk_chars }) => {
6264
6611
  try {
@@ -6290,12 +6637,12 @@ server.tool(
6290
6637
  "index.auto_repair",
6291
6638
  "Diagnose and apply deterministic retrieval/setup repairs. This is the canonical zero-stress repair path.",
6292
6639
  {
6293
- path: z.string().optional(),
6294
- workspace_id: z.string().optional(),
6295
- project: z.string().optional(),
6296
- apply: z.boolean().optional().default(true),
6297
- repair_scope: z.enum(["safe", "full"]).optional().default("safe"),
6298
- allow_restart_hint: z.boolean().optional().default(true)
6640
+ path: z2.string().optional(),
6641
+ workspace_id: z2.string().optional(),
6642
+ project: z2.string().optional(),
6643
+ apply: z2.boolean().optional().default(true),
6644
+ repair_scope: z2.enum(["safe", "full"]).optional().default("safe"),
6645
+ allow_restart_hint: z2.boolean().optional().default(true)
6299
6646
  },
6300
6647
  async ({ path, workspace_id, project, apply, repair_scope, allow_restart_hint }) => {
6301
6648
  try {
@@ -6317,12 +6664,12 @@ server.tool(
6317
6664
  "fix",
6318
6665
  "Primary alias for zero-stress setup/retrieval repair. Delegates to index.auto_repair.",
6319
6666
  {
6320
- path: z.string().optional(),
6321
- workspace_id: z.string().optional(),
6322
- project: z.string().optional(),
6323
- apply: z.boolean().optional().default(true),
6324
- repair_scope: z.enum(["safe", "full"]).optional().default("safe"),
6325
- allow_restart_hint: z.boolean().optional().default(true)
6667
+ path: z2.string().optional(),
6668
+ workspace_id: z2.string().optional(),
6669
+ project: z2.string().optional(),
6670
+ apply: z2.boolean().optional().default(true),
6671
+ repair_scope: z2.enum(["safe", "full"]).optional().default("safe"),
6672
+ allow_restart_hint: z2.boolean().optional().default(true)
6326
6673
  },
6327
6674
  async ({ path, workspace_id, project, apply, repair_scope, allow_restart_hint }) => {
6328
6675
  try {
@@ -6591,17 +6938,17 @@ server.tool(
6591
6938
  "context.get_relevant",
6592
6939
  "Default grounded retrieval step for workspace/project questions. Returns ranked evidence with file:line citations and may abstain when workspace/repo trust is not ready.",
6593
6940
  {
6594
- question: z.string().describe("Task/question to retrieve context for"),
6595
- path: z.string().optional().describe("Workspace path. Defaults to current working directory."),
6596
- workspace_id: z.string().optional(),
6597
- project: z.string().optional(),
6598
- top_k: z.number().optional().default(12),
6599
- include_memories: z.boolean().optional().default(true),
6600
- include_graph: z.boolean().optional().default(true),
6601
- session_id: z.string().optional(),
6602
- user_id: z.string().optional(),
6603
- include_parent_content: z.boolean().optional().default(false),
6604
- retrieval_profile: z.enum(MCP_RETRIEVAL_PROFILE_VALUES).optional()
6941
+ question: z2.string().describe("Task/question to retrieve context for"),
6942
+ path: z2.string().optional().describe("Workspace path. Defaults to current working directory."),
6943
+ workspace_id: z2.string().optional(),
6944
+ project: z2.string().optional(),
6945
+ top_k: z2.number().optional().default(12),
6946
+ include_memories: z2.boolean().optional().default(true),
6947
+ include_graph: z2.boolean().optional().default(true),
6948
+ session_id: z2.string().optional(),
6949
+ user_id: z2.string().optional(),
6950
+ include_parent_content: z2.boolean().optional().default(false),
6951
+ retrieval_profile: z2.enum(MCP_RETRIEVAL_PROFILE_VALUES).optional()
6605
6952
  },
6606
6953
  async ({ question, path, workspace_id, project, top_k, include_memories, include_graph, session_id, user_id, include_parent_content, retrieval_profile }) => {
6607
6954
  try {
@@ -6629,12 +6976,12 @@ server.tool(
6629
6976
  "context.claim_verify",
6630
6977
  "Verify whether a claim is supported by retrieved context. Returns supported/partial/unsupported with evidence.",
6631
6978
  {
6632
- claim: z.string().describe("Claim to verify"),
6633
- path: z.string().optional().describe("Workspace path. Defaults to current working directory."),
6634
- workspace_id: z.string().optional(),
6635
- project: z.string().optional(),
6636
- context_ids: z.array(z.string()).optional(),
6637
- strict: z.boolean().optional().default(true)
6979
+ claim: z2.string().describe("Claim to verify"),
6980
+ path: z2.string().optional().describe("Workspace path. Defaults to current working directory."),
6981
+ workspace_id: z2.string().optional(),
6982
+ project: z2.string().optional(),
6983
+ context_ids: z2.array(z2.string()).optional(),
6984
+ strict: z2.boolean().optional().default(true)
6638
6985
  },
6639
6986
  async ({ claim, path, workspace_id, project, context_ids, strict }) => {
6640
6987
  try {
@@ -6704,20 +7051,20 @@ server.tool(
6704
7051
  "context.evidence_answer",
6705
7052
  "Answer a question only when evidence requirements are met. Fails closed with an abstain payload when not verifiable.",
6706
7053
  {
6707
- question: z.string(),
6708
- path: z.string().optional().describe("Workspace path. Defaults to current working directory."),
6709
- workspace_id: z.string().optional(),
6710
- project: z.string().optional(),
6711
- constraints: z.object({
6712
- require_citations: z.boolean().optional().default(true),
6713
- min_evidence_items: z.number().optional().default(2),
6714
- min_confidence: z.number().optional().default(0.65),
6715
- max_staleness_hours: z.number().optional().default(168)
7054
+ question: z2.string(),
7055
+ path: z2.string().optional().describe("Workspace path. Defaults to current working directory."),
7056
+ workspace_id: z2.string().optional(),
7057
+ project: z2.string().optional(),
7058
+ constraints: z2.object({
7059
+ require_citations: z2.boolean().optional().default(true),
7060
+ min_evidence_items: z2.number().optional().default(2),
7061
+ min_confidence: z2.number().optional().default(0.65),
7062
+ max_staleness_hours: z2.number().optional().default(168)
6716
7063
  }).optional(),
6717
- retrieval: z.object({
6718
- top_k: z.number().optional().default(12),
6719
- include_symbols: z.boolean().optional().default(true),
6720
- include_recent_decisions: z.boolean().optional().default(true)
7064
+ retrieval: z2.object({
7065
+ top_k: z2.number().optional().default(12),
7066
+ include_symbols: z2.boolean().optional().default(true),
7067
+ include_recent_decisions: z2.boolean().optional().default(true)
6721
7068
  }).optional()
6722
7069
  },
6723
7070
  async ({ question, path, workspace_id, project, constraints, retrieval }) => {
@@ -6830,18 +7177,18 @@ server.tool(
6830
7177
  "context.query",
6831
7178
  "Use this when answering from project knowledge rather than general model memory. Retrieves packed context and auto-falls back between repo, local, and memory routes based on trust/readiness.",
6832
7179
  {
6833
- project: z.string().optional().describe("Project name or slug (optional if WHISPER_PROJECT is set)"),
6834
- query: z.string().describe("What are you looking for?"),
6835
- path: z.string().optional().describe("Workspace path. Defaults to current working directory."),
6836
- top_k: z.number().optional().default(10).describe("Number of results"),
6837
- chunk_types: z.array(z.string()).optional().describe("Filter: code, function, class, documentation, api_spec, schema, config, text"),
6838
- include_memories: z.boolean().optional().describe("Include relevant memories. Omit to use automatic runtime defaults."),
6839
- include_graph: z.boolean().optional().default(false).describe("Include knowledge graph traversal"),
6840
- user_id: z.string().optional().describe("User ID for memory scoping"),
6841
- session_id: z.string().optional().describe("Session ID for memory scoping"),
6842
- max_tokens: z.number().optional().describe("Max tokens for packed context"),
6843
- include_parent_content: z.boolean().optional().default(false),
6844
- retrieval_profile: z.enum(MCP_RETRIEVAL_PROFILE_VALUES).optional()
7180
+ project: z2.string().optional().describe("Project name or slug (optional if WHISPER_PROJECT is set)"),
7181
+ query: z2.string().describe("What are you looking for?"),
7182
+ path: z2.string().optional().describe("Workspace path. Defaults to current working directory."),
7183
+ top_k: z2.number().optional().default(10).describe("Number of results"),
7184
+ chunk_types: z2.array(z2.string()).optional().describe("Filter: code, function, class, documentation, api_spec, schema, config, text"),
7185
+ include_memories: z2.boolean().optional().describe("Include relevant memories. Omit to use automatic runtime defaults."),
7186
+ include_graph: z2.boolean().optional().default(false).describe("Include knowledge graph traversal"),
7187
+ user_id: z2.string().optional().describe("User ID for memory scoping"),
7188
+ session_id: z2.string().optional().describe("Session ID for memory scoping"),
7189
+ max_tokens: z2.number().optional().describe("Max tokens for packed context"),
7190
+ include_parent_content: z2.boolean().optional().default(false),
7191
+ retrieval_profile: z2.enum(MCP_RETRIEVAL_PROFILE_VALUES).optional()
6845
7192
  },
6846
7193
  async ({ project, query, path, top_k, chunk_types, include_memories, include_graph, user_id, session_id, max_tokens, include_parent_content, retrieval_profile }) => {
6847
7194
  try {
@@ -6868,14 +7215,14 @@ server.tool(
6868
7215
  "memory.add",
6869
7216
  "Store a memory (fact, preference, decision) that persists across conversations. Memories can be scoped to a user, session, or agent.",
6870
7217
  {
6871
- project: z.string().optional().describe("Project name or slug"),
6872
- content: z.string().describe("The memory content to store"),
6873
- memory_type: z.enum(["factual", "preference", "event", "relationship", "opinion", "goal", "instruction"]).optional().default("factual"),
6874
- scope: z.enum(["personal", "shared_project"]).optional().default("personal"),
6875
- user_id: z.string().optional().describe("User this memory belongs to"),
6876
- session_id: z.string().optional().describe("Session scope"),
6877
- agent_id: z.string().optional().describe("Agent scope"),
6878
- importance: z.number().optional().default(0.5).describe("Importance 0-1")
7218
+ project: z2.string().optional().describe("Project name or slug"),
7219
+ content: z2.string().describe("The memory content to store"),
7220
+ memory_type: z2.enum(["factual", "preference", "event", "relationship", "opinion", "goal", "instruction"]).optional().default("factual"),
7221
+ scope: z2.enum(["personal", "shared_project"]).optional().default("personal"),
7222
+ user_id: z2.string().optional().describe("User this memory belongs to"),
7223
+ session_id: z2.string().optional().describe("Session scope"),
7224
+ agent_id: z2.string().optional().describe("Agent scope"),
7225
+ importance: z2.number().optional().default(0.5).describe("Importance 0-1")
6879
7226
  },
6880
7227
  async ({ project, content, memory_type, scope, user_id, session_id, agent_id, importance }) => {
6881
7228
  try {
@@ -6926,13 +7273,13 @@ server.tool(
6926
7273
  "memory.search",
6927
7274
  "Call this before answering questions about user history (preferences, prior decisions, past tasks, or 'what did we discuss/search'). Returns memory context you would not otherwise know.",
6928
7275
  {
6929
- project: z.string().optional().describe("Project name or slug"),
6930
- query: z.string().describe("What to search for"),
6931
- scope: z.enum(["personal", "shared_project"]).optional().default("personal"),
6932
- user_id: z.string().optional().describe("Filter by user"),
6933
- session_id: z.string().optional().describe("Filter by session"),
6934
- top_k: z.number().optional().default(10).describe("Number of results"),
6935
- memory_types: z.array(z.enum(["factual", "preference", "event", "relationship", "opinion", "goal", "instruction"])).optional()
7276
+ project: z2.string().optional().describe("Project name or slug"),
7277
+ query: z2.string().describe("What to search for"),
7278
+ scope: z2.enum(["personal", "shared_project"]).optional().default("personal"),
7279
+ user_id: z2.string().optional().describe("Filter by user"),
7280
+ session_id: z2.string().optional().describe("Filter by session"),
7281
+ top_k: z2.number().optional().default(10).describe("Number of results"),
7282
+ memory_types: z2.array(z2.enum(["factual", "preference", "event", "relationship", "opinion", "goal", "instruction"])).optional()
6936
7283
  },
6937
7284
  async ({ project, query, scope, user_id, session_id, top_k, memory_types }) => {
6938
7285
  try {
@@ -7006,7 +7353,7 @@ server.tool(
7006
7353
  server.tool(
7007
7354
  "context.list_sources",
7008
7355
  "List all data sources connected to a project.",
7009
- { project: z.string().optional().describe("Project name or slug") },
7356
+ { project: z2.string().optional().describe("Project name or slug") },
7010
7357
  async ({ project }) => {
7011
7358
  try {
7012
7359
  const sourceData = await whisper.listSources(project || DEFAULT_PROJECT);
@@ -7022,38 +7369,38 @@ server.tool(
7022
7369
  "context.add_source",
7023
7370
  "Compatibility learning tool. Add a source to a project with normalized source contract and auto-index by default. Prefer `learn` for new integrations.",
7024
7371
  {
7025
- project: z.string().optional().describe("Project name or slug"),
7026
- type: z.enum(["github", "web", "playwright", "pdf", "local", "slack", "video"]).default("github"),
7027
- name: z.string().optional(),
7028
- auto_index: z.boolean().optional().default(true),
7029
- metadata: z.record(z.string()).optional(),
7030
- ingestion_profile: z.enum(["auto", "repo", "web_docs", "pdf_layout", "video_transcript", "plain_text"]).optional(),
7031
- strategy_override: z.enum(["fixed", "recursive", "semantic", "hierarchical", "adaptive"]).optional(),
7032
- profile_config: z.record(z.any()).optional(),
7033
- owner: z.string().optional(),
7034
- repo: z.string().optional(),
7035
- branch: z.string().optional(),
7036
- paths: z.array(z.string()).optional(),
7037
- url: z.string().url().optional(),
7038
- crawl_depth: z.number().optional(),
7039
- include_paths: z.array(z.string()).optional(),
7040
- exclude_paths: z.array(z.string()).optional(),
7041
- file_path: z.string().optional(),
7042
- path: z.string().optional(),
7043
- glob: z.string().optional(),
7044
- max_files: z.number().optional(),
7045
- max_pages: z.number().optional(),
7046
- extract_mode: z.enum(["text", "structured", "markdown"]).optional(),
7047
- workspace_id: z.string().optional(),
7048
- channel_ids: z.array(z.string()).optional(),
7049
- since: z.string().optional(),
7050
- token: z.string().optional(),
7051
- auth_ref: z.string().optional(),
7052
- platform: z.enum(["youtube", "loom", "generic"]).optional(),
7053
- language: z.string().optional(),
7054
- allow_stt_fallback: z.boolean().optional(),
7055
- max_duration_minutes: z.number().optional(),
7056
- max_chunks: z.number().optional()
7372
+ project: z2.string().optional().describe("Project name or slug"),
7373
+ type: z2.enum(["github", "web", "playwright", "pdf", "local", "slack", "video"]).default("github"),
7374
+ name: z2.string().optional(),
7375
+ auto_index: z2.boolean().optional().default(true),
7376
+ metadata: z2.record(z2.string()).optional(),
7377
+ ingestion_profile: z2.enum(["auto", "repo", "web_docs", "pdf_layout", "video_transcript", "plain_text"]).optional(),
7378
+ strategy_override: z2.enum(["fixed", "recursive", "semantic", "hierarchical", "adaptive"]).optional(),
7379
+ profile_config: z2.record(z2.any()).optional(),
7380
+ owner: z2.string().optional(),
7381
+ repo: z2.string().optional(),
7382
+ branch: z2.string().optional(),
7383
+ paths: z2.array(z2.string()).optional(),
7384
+ url: z2.string().url().optional(),
7385
+ crawl_depth: z2.number().optional(),
7386
+ include_paths: z2.array(z2.string()).optional(),
7387
+ exclude_paths: z2.array(z2.string()).optional(),
7388
+ file_path: z2.string().optional(),
7389
+ path: z2.string().optional(),
7390
+ glob: z2.string().optional(),
7391
+ max_files: z2.number().optional(),
7392
+ max_pages: z2.number().optional(),
7393
+ extract_mode: z2.enum(["text", "structured", "markdown"]).optional(),
7394
+ workspace_id: z2.string().optional(),
7395
+ channel_ids: z2.array(z2.string()).optional(),
7396
+ since: z2.string().optional(),
7397
+ token: z2.string().optional(),
7398
+ auth_ref: z2.string().optional(),
7399
+ platform: z2.enum(["youtube", "loom", "generic"]).optional(),
7400
+ language: z2.string().optional(),
7401
+ allow_stt_fallback: z2.boolean().optional(),
7402
+ max_duration_minutes: z2.number().optional(),
7403
+ max_chunks: z2.number().optional()
7057
7404
  },
7058
7405
  async (input) => {
7059
7406
  try {
@@ -7109,7 +7456,7 @@ server.tool(
7109
7456
  "context.source_status",
7110
7457
  "Get status and stage/progress details for a source sync job.",
7111
7458
  {
7112
- source_id: z.string().describe("Source id")
7459
+ source_id: z2.string().describe("Source id")
7113
7460
  },
7114
7461
  async ({ source_id }) => {
7115
7462
  try {
@@ -7124,12 +7471,12 @@ server.tool(
7124
7471
  "context.add_text",
7125
7472
  "Compatibility learning tool. Add text content to a project's knowledge base. Prefer `learn` for new integrations.",
7126
7473
  {
7127
- project: z.string().optional().describe("Project name or slug"),
7128
- title: z.string().describe("Title for this content"),
7129
- content: z.string().describe("The text content to index"),
7130
- ingestion_profile: z.enum(["auto", "repo", "web_docs", "pdf_layout", "video_transcript", "plain_text"]).optional(),
7131
- strategy_override: z.enum(["fixed", "recursive", "semantic", "hierarchical", "adaptive"]).optional(),
7132
- profile_config: z.record(z.any()).optional()
7474
+ project: z2.string().optional().describe("Project name or slug"),
7475
+ title: z2.string().describe("Title for this content"),
7476
+ content: z2.string().describe("The text content to index"),
7477
+ ingestion_profile: z2.enum(["auto", "repo", "web_docs", "pdf_layout", "video_transcript", "plain_text"]).optional(),
7478
+ strategy_override: z2.enum(["fixed", "recursive", "semantic", "hierarchical", "adaptive"]).optional(),
7479
+ profile_config: z2.record(z2.any()).optional()
7133
7480
  },
7134
7481
  async ({ project, title, content, ingestion_profile, strategy_override, profile_config }) => {
7135
7482
  try {
@@ -7157,18 +7504,18 @@ server.tool(
7157
7504
  "context.add_document",
7158
7505
  "Compatibility learning tool. Ingest a document into project knowledge. Supports plain text and video URLs. Prefer `learn` for new integrations.",
7159
7506
  {
7160
- project: z.string().optional().describe("Project name or slug"),
7161
- source_type: z.enum(["text", "video"]).default("text"),
7162
- title: z.string().optional().describe("Title for text documents"),
7163
- content: z.string().optional().describe("Text document content"),
7164
- url: z.string().url().optional().describe("Video URL when source_type=video"),
7165
- auto_sync: z.boolean().optional().default(true),
7166
- tags: z.array(z.string()).optional(),
7167
- platform: z.enum(["youtube", "loom", "generic"]).optional(),
7168
- language: z.string().optional(),
7169
- ingestion_profile: z.enum(["auto", "repo", "web_docs", "pdf_layout", "video_transcript", "plain_text"]).optional(),
7170
- strategy_override: z.enum(["fixed", "recursive", "semantic", "hierarchical", "adaptive"]).optional(),
7171
- profile_config: z.record(z.any()).optional()
7507
+ project: z2.string().optional().describe("Project name or slug"),
7508
+ source_type: z2.enum(["text", "video"]).default("text"),
7509
+ title: z2.string().optional().describe("Title for text documents"),
7510
+ content: z2.string().optional().describe("Text document content"),
7511
+ url: z2.string().url().optional().describe("Video URL when source_type=video"),
7512
+ auto_sync: z2.boolean().optional().default(true),
7513
+ tags: z2.array(z2.string()).optional(),
7514
+ platform: z2.enum(["youtube", "loom", "generic"]).optional(),
7515
+ language: z2.string().optional(),
7516
+ ingestion_profile: z2.enum(["auto", "repo", "web_docs", "pdf_layout", "video_transcript", "plain_text"]).optional(),
7517
+ strategy_override: z2.enum(["fixed", "recursive", "semantic", "hierarchical", "adaptive"]).optional(),
7518
+ profile_config: z2.record(z2.any()).optional()
7172
7519
  },
7173
7520
  async ({ project, source_type, title, content, url, auto_sync, tags, platform, language, ingestion_profile, strategy_override, profile_config }) => {
7174
7521
  try {
@@ -7223,15 +7570,15 @@ server.tool(
7223
7570
  "memory.search_sota",
7224
7571
  "SOTA memory search with temporal reasoning and relation graphs. Searches memories with support for temporal queries ('what did I say yesterday?'), type filtering, and knowledge graph traversal.",
7225
7572
  {
7226
- project: z.string().optional().describe("Project name or slug"),
7227
- query: z.string().describe("Search query (supports temporal: 'yesterday', 'last week')"),
7228
- scope: z.enum(["personal", "shared_project"]).optional().default("personal"),
7229
- user_id: z.string().optional().describe("Filter by user"),
7230
- session_id: z.string().optional().describe("Filter by session"),
7231
- question_date: z.string().optional().describe("ISO datetime for temporal grounding"),
7232
- memory_types: z.array(z.enum(["factual", "preference", "event", "relationship", "opinion", "goal", "instruction"])).optional(),
7233
- top_k: z.number().optional().default(10),
7234
- include_relations: z.boolean().optional().default(true).describe("Include related memories via knowledge graph")
7573
+ project: z2.string().optional().describe("Project name or slug"),
7574
+ query: z2.string().describe("Search query (supports temporal: 'yesterday', 'last week')"),
7575
+ scope: z2.enum(["personal", "shared_project"]).optional().default("personal"),
7576
+ user_id: z2.string().optional().describe("Filter by user"),
7577
+ session_id: z2.string().optional().describe("Filter by session"),
7578
+ question_date: z2.string().optional().describe("ISO datetime for temporal grounding"),
7579
+ memory_types: z2.array(z2.enum(["factual", "preference", "event", "relationship", "opinion", "goal", "instruction"])).optional(),
7580
+ top_k: z2.number().optional().default(10),
7581
+ include_relations: z2.boolean().optional().default(true).describe("Include related memories via knowledge graph")
7235
7582
  },
7236
7583
  async ({ project, query, scope, user_id, session_id, question_date, memory_types, top_k, include_relations }) => {
7237
7584
  try {
@@ -7275,13 +7622,13 @@ server.tool(
7275
7622
  "memory.ingest_conversation",
7276
7623
  "Compatibility learning tool. Extract memories from a conversation session. Prefer `learn` for new integrations.",
7277
7624
  {
7278
- project: z.string().optional().describe("Project name or slug"),
7279
- session_id: z.string().describe("Session identifier"),
7280
- user_id: z.string().optional().describe("User identifier"),
7281
- messages: z.array(z.object({
7282
- role: z.string(),
7283
- content: z.string(),
7284
- timestamp: z.string()
7625
+ project: z2.string().optional().describe("Project name or slug"),
7626
+ session_id: z2.string().describe("Session identifier"),
7627
+ user_id: z2.string().optional().describe("User identifier"),
7628
+ messages: z2.array(z2.object({
7629
+ role: z2.string(),
7630
+ content: z2.string(),
7631
+ timestamp: z2.string()
7285
7632
  })).describe("Array of conversation messages with timestamps")
7286
7633
  },
7287
7634
  async ({ project, session_id, user_id, messages }) => {
@@ -7329,11 +7676,11 @@ server.tool(
7329
7676
  "research.oracle",
7330
7677
  "Oracle Research Mode - Tree-guided document navigation with multi-step reasoning. More precise than standard search, especially for bleeding-edge features.",
7331
7678
  {
7332
- project: z.string().optional().describe("Project name or slug"),
7333
- query: z.string().describe("Research question"),
7334
- mode: z.enum(["search", "research"]).optional().default("search").describe("'search' for tree-guided, 'research' for multi-step reasoning"),
7335
- max_results: z.number().optional().default(5),
7336
- max_steps: z.number().optional().default(5).describe("For research mode: max reasoning steps")
7679
+ project: z2.string().optional().describe("Project name or slug"),
7680
+ query: z2.string().describe("Research question"),
7681
+ mode: z2.enum(["search", "research"]).optional().default("search").describe("'search' for tree-guided, 'research' for multi-step reasoning"),
7682
+ max_results: z2.number().optional().default(5),
7683
+ max_steps: z2.number().optional().default(5).describe("For research mode: max reasoning steps")
7337
7684
  },
7338
7685
  async ({ project, query, mode, max_results, max_steps }) => {
7339
7686
  try {
@@ -7377,13 +7724,13 @@ server.tool(
7377
7724
  "index.autosubscribe_deps",
7378
7725
  "Automatically index a project's dependencies (package.json, requirements.txt, etc.). Resolves docs URLs and indexes documentation.",
7379
7726
  {
7380
- project: z.string().optional().describe("Project name or slug"),
7381
- source_type: z.enum(["github", "local"]).describe("Source location"),
7382
- github_owner: z.string().optional().describe("For GitHub: owner/org name"),
7383
- github_repo: z.string().optional().describe("For GitHub: repository name"),
7384
- local_path: z.string().optional().describe("For local: path to dependency file"),
7385
- dependency_file: z.enum(["package.json", "requirements.txt", "Cargo.toml", "go.mod", "Gemfile"]).optional(),
7386
- index_limit: z.number().optional().default(20).describe("Max dependencies to index")
7727
+ project: z2.string().optional().describe("Project name or slug"),
7728
+ source_type: z2.enum(["github", "local"]).describe("Source location"),
7729
+ github_owner: z2.string().optional().describe("For GitHub: owner/org name"),
7730
+ github_repo: z2.string().optional().describe("For GitHub: repository name"),
7731
+ local_path: z2.string().optional().describe("For local: path to dependency file"),
7732
+ dependency_file: z2.enum(["package.json", "requirements.txt", "Cargo.toml", "go.mod", "Gemfile"]).optional(),
7733
+ index_limit: z2.number().optional().default(20).describe("Max dependencies to index")
7387
7734
  },
7388
7735
  async ({ project, source_type, github_owner, github_repo, local_path, dependency_file, index_limit }) => {
7389
7736
  try {
@@ -7410,10 +7757,10 @@ server.tool(
7410
7757
  "context.share",
7411
7758
  "Create a shareable snapshot of a conversation with memories. Returns a URL that can be shared or resumed later.",
7412
7759
  {
7413
- project: z.string().optional().describe("Project name or slug"),
7414
- session_id: z.string().describe("Session to share"),
7415
- title: z.string().optional().describe("Title for the shared context"),
7416
- expiry_days: z.number().optional().default(30).describe("Days until expiry")
7760
+ project: z2.string().optional().describe("Project name or slug"),
7761
+ session_id: z2.string().describe("Session to share"),
7762
+ title: z2.string().optional().describe("Title for the shared context"),
7763
+ expiry_days: z2.number().optional().default(30).describe("Days until expiry")
7417
7764
  },
7418
7765
  async ({ project, session_id, title, expiry_days }) => {
7419
7766
  try {
@@ -7448,9 +7795,9 @@ server.tool(
7448
7795
  "memory.consolidate",
7449
7796
  "Find and merge duplicate memories to reduce bloat. Uses vector similarity + LLM merging.",
7450
7797
  {
7451
- project: z.string().optional().describe("Project name or slug"),
7452
- similarity_threshold: z.number().optional().default(0.95).describe("Similarity threshold (0-1)"),
7453
- dry_run: z.boolean().optional().default(false).describe("Preview without merging")
7798
+ project: z2.string().optional().describe("Project name or slug"),
7799
+ similarity_threshold: z2.number().optional().default(0.95).describe("Similarity threshold (0-1)"),
7800
+ dry_run: z2.boolean().optional().default(false).describe("Preview without merging")
7454
7801
  },
7455
7802
  async ({ project, similarity_threshold, dry_run }) => {
7456
7803
  try {
@@ -7491,8 +7838,8 @@ server.tool(
7491
7838
  "context.cost_summary",
7492
7839
  "Get cost tracking summary showing spending by model and task. Includes savings vs always-Opus.",
7493
7840
  {
7494
- project: z.string().optional().describe("Project name or slug (optional for org-wide)"),
7495
- days: z.number().optional().default(30).describe("Time period in days")
7841
+ project: z2.string().optional().describe("Project name or slug (optional for org-wide)"),
7842
+ days: z2.number().optional().default(30).describe("Time period in days")
7496
7843
  },
7497
7844
  async ({ project, days }) => {
7498
7845
  try {
@@ -7534,17 +7881,17 @@ server.tool(
7534
7881
  "memory.forget",
7535
7882
  "Delete or invalidate memories with immutable audit logging.",
7536
7883
  {
7537
- workspace_id: z.string().optional(),
7538
- project: z.string().optional(),
7539
- scope: z.enum(["personal", "shared_project"]).optional().default("personal"),
7540
- user_id: z.string().optional(),
7541
- session_id: z.string().optional(),
7542
- target: z.object({
7543
- memory_id: z.string().optional(),
7544
- query: z.string().optional()
7884
+ workspace_id: z2.string().optional(),
7885
+ project: z2.string().optional(),
7886
+ scope: z2.enum(["personal", "shared_project"]).optional().default("personal"),
7887
+ user_id: z2.string().optional(),
7888
+ session_id: z2.string().optional(),
7889
+ target: z2.object({
7890
+ memory_id: z2.string().optional(),
7891
+ query: z2.string().optional()
7545
7892
  }),
7546
- mode: z.enum(["delete", "invalidate"]).optional().default("invalidate"),
7547
- reason: z.string().optional()
7893
+ mode: z2.enum(["delete", "invalidate"]).optional().default("invalidate"),
7894
+ reason: z2.string().optional()
7548
7895
  },
7549
7896
  async ({ workspace_id, project, scope, user_id, session_id, target, mode, reason }) => {
7550
7897
  try {
@@ -7712,8 +8059,8 @@ server.tool(
7712
8059
  "context.export_bundle",
7713
8060
  "Export project/workspace memory and context to a portable bundle with checksum.",
7714
8061
  {
7715
- workspace_id: z.string().optional(),
7716
- project: z.string().optional()
8062
+ workspace_id: z2.string().optional(),
8063
+ project: z2.string().optional()
7717
8064
  },
7718
8065
  async ({ workspace_id, project }) => {
7719
8066
  try {
@@ -7763,26 +8110,26 @@ server.tool(
7763
8110
  "context.import_bundle",
7764
8111
  "Import a portable context bundle with merge/replace modes and checksum verification.",
7765
8112
  {
7766
- workspace_id: z.string().optional(),
7767
- bundle: z.object({
7768
- bundle_version: z.string(),
7769
- workspace_id: z.string(),
7770
- project: z.string().optional(),
7771
- exported_at: z.string(),
7772
- contents: z.object({
7773
- memories: z.array(z.any()).default([]),
7774
- entities: z.array(z.any()).default([]),
7775
- decisions: z.array(z.any()).default([]),
7776
- failures: z.array(z.any()).default([]),
7777
- annotations: z.array(z.any()).default([]),
7778
- session_summaries: z.array(z.any()).default([]),
7779
- documents: z.array(z.any()).default([]),
7780
- index_metadata: z.record(z.any()).default({})
8113
+ workspace_id: z2.string().optional(),
8114
+ bundle: z2.object({
8115
+ bundle_version: z2.string(),
8116
+ workspace_id: z2.string(),
8117
+ project: z2.string().optional(),
8118
+ exported_at: z2.string(),
8119
+ contents: z2.object({
8120
+ memories: z2.array(z2.any()).default([]),
8121
+ entities: z2.array(z2.any()).default([]),
8122
+ decisions: z2.array(z2.any()).default([]),
8123
+ failures: z2.array(z2.any()).default([]),
8124
+ annotations: z2.array(z2.any()).default([]),
8125
+ session_summaries: z2.array(z2.any()).default([]),
8126
+ documents: z2.array(z2.any()).default([]),
8127
+ index_metadata: z2.record(z2.any()).default({})
7781
8128
  }),
7782
- checksum: z.string()
8129
+ checksum: z2.string()
7783
8130
  }),
7784
- mode: z.enum(["merge", "replace"]).optional().default("merge"),
7785
- dedupe_strategy: z.enum(["semantic", "id", "none"]).optional().default("semantic")
8131
+ mode: z2.enum(["merge", "replace"]).optional().default("merge"),
8132
+ dedupe_strategy: z2.enum(["semantic", "id", "none"]).optional().default("semantic")
7786
8133
  },
7787
8134
  async ({ workspace_id, bundle, mode, dedupe_strategy }) => {
7788
8135
  try {
@@ -7926,13 +8273,13 @@ server.tool(
7926
8273
  "context.diff",
7927
8274
  "Return deterministic context changes from an explicit anchor (session_id, timestamp, or commit).",
7928
8275
  {
7929
- workspace_id: z.string().optional(),
7930
- anchor: z.object({
7931
- type: z.enum(["session_id", "timestamp", "commit"]),
7932
- value: z.string()
8276
+ workspace_id: z2.string().optional(),
8277
+ anchor: z2.object({
8278
+ type: z2.enum(["session_id", "timestamp", "commit"]),
8279
+ value: z2.string()
7933
8280
  }).optional(),
7934
- scope: z.object({
7935
- include: z.array(z.enum(["decisions", "failures", "entities", "documents", "summaries"])).optional().default(["decisions", "failures", "entities", "documents", "summaries"])
8281
+ scope: z2.object({
8282
+ include: z2.array(z2.enum(["decisions", "failures", "entities", "documents", "summaries"])).optional().default(["decisions", "failures", "entities", "documents", "summaries"])
7936
8283
  }).optional()
7937
8284
  },
7938
8285
  async ({ workspace_id, anchor, scope }) => {
@@ -8043,12 +8390,12 @@ server.tool(
8043
8390
  "code.search_semantic",
8044
8391
  "Semantically search a local codebase without pre-indexing. Unlike grep/ripgrep, this understands meaning \u2014 so 'find authentication logic' finds auth code even if it doesn't literally say 'auth'. Uses vector embeddings via the Whisper API. Perfect for exploring unfamiliar codebases.",
8045
8392
  {
8046
- query: z.string().describe("Natural language description of what you're looking for. E.g. 'authentication and session management', 'database connection pooling', 'error handling middleware'"),
8047
- path: z.string().optional().describe("Absolute path to the codebase root. Defaults to current working directory."),
8048
- file_types: z.array(z.string()).optional().describe("Limit to specific extensions e.g. ['ts', 'py']. Defaults to all common code files."),
8049
- top_k: z.number().optional().default(10).describe("Number of most relevant files to return"),
8050
- threshold: z.number().optional().default(0.2).describe("Minimum similarity score 0-1. Lower = more results but less precise."),
8051
- max_files: z.number().optional().default(150).describe("Max files to scan. For large codebases, narrow with file_types instead of raising this.")
8393
+ query: z2.string().describe("Natural language description of what you're looking for. E.g. 'authentication and session management', 'database connection pooling', 'error handling middleware'"),
8394
+ path: z2.string().optional().describe("Absolute path to the codebase root. Defaults to current working directory."),
8395
+ file_types: z2.array(z2.string()).optional().describe("Limit to specific extensions e.g. ['ts', 'py']. Defaults to all common code files."),
8396
+ top_k: z2.number().optional().default(10).describe("Number of most relevant files to return"),
8397
+ threshold: z2.number().optional().default(0.2).describe("Minimum similarity score 0-1. Lower = more results but less precise."),
8398
+ max_files: z2.number().optional().default(150).describe("Max files to scan. For large codebases, narrow with file_types instead of raising this.")
8052
8399
  },
8053
8400
  async ({ query, path: searchPath, file_types, top_k, threshold, max_files }) => {
8054
8401
  try {
@@ -8123,13 +8470,13 @@ server.tool(
8123
8470
  "code.search_text",
8124
8471
  "Search files and content in a local directory without requiring pre-indexing. Uses ripgrep when available, falls back to Node.js. Great for finding files, functions, patterns, or any text across a codebase instantly.",
8125
8472
  {
8126
- query: z.string().describe("What to search for \u2014 natural language keyword, function name, pattern, etc."),
8127
- path: z.string().optional().describe("Absolute path to search in. Defaults to current working directory."),
8128
- mode: z.enum(["content", "filename", "both"]).optional().default("both").describe("Search file contents, filenames, or both"),
8129
- file_types: z.array(z.string()).optional().describe("Limit to these file extensions e.g. ['ts', 'js', 'py', 'go']"),
8130
- max_results: z.number().optional().default(20).describe("Max number of matching files to return"),
8131
- context_lines: z.number().optional().default(2).describe("Lines of context around each match"),
8132
- case_sensitive: z.boolean().optional().default(false)
8473
+ query: z2.string().describe("What to search for \u2014 natural language keyword, function name, pattern, etc."),
8474
+ path: z2.string().optional().describe("Absolute path to search in. Defaults to current working directory."),
8475
+ mode: z2.enum(["content", "filename", "both"]).optional().default("both").describe("Search file contents, filenames, or both"),
8476
+ file_types: z2.array(z2.string()).optional().describe("Limit to these file extensions e.g. ['ts', 'js', 'py', 'go']"),
8477
+ max_results: z2.number().optional().default(20).describe("Max number of matching files to return"),
8478
+ context_lines: z2.number().optional().default(2).describe("Lines of context around each match"),
8479
+ case_sensitive: z2.boolean().optional().default(false)
8133
8480
  },
8134
8481
  async ({ query, path: searchPath, mode, file_types, max_results, context_lines, case_sensitive }) => {
8135
8482
  const rootPath = searchPath || process.cwd();
@@ -8262,13 +8609,13 @@ server.tool(
8262
8609
  "code.semantic_documents",
8263
8610
  "Semantic vector search over provided documents. Uses embeddings to find semantically similar content. Perfect for AI code search, finding similar functions, or searching by meaning rather than keywords.",
8264
8611
  {
8265
- query: z.string().describe("What to search for semantically (e.g. 'authentication logic', 'database connection')"),
8266
- documents: z.array(z.object({
8267
- id: z.string().describe("Unique identifier (file path, URL, or any ID)"),
8268
- content: z.string().describe("The text content to search in")
8612
+ query: z2.string().describe("What to search for semantically (e.g. 'authentication logic', 'database connection')"),
8613
+ documents: z2.array(z2.object({
8614
+ id: z2.string().describe("Unique identifier (file path, URL, or any ID)"),
8615
+ content: z2.string().describe("The text content to search in")
8269
8616
  })).describe("Documents to search over"),
8270
- top_k: z.number().optional().default(5).describe("Number of results to return"),
8271
- threshold: z.number().optional().default(0.3).describe("Minimum similarity score 0-1")
8617
+ top_k: z2.number().optional().default(5).describe("Number of results to return"),
8618
+ threshold: z2.number().optional().default(0.3).describe("Minimum similarity score 0-1")
8272
8619
  },
8273
8620
  async ({ query, documents, top_k, threshold }) => {
8274
8621
  try {
@@ -8306,14 +8653,14 @@ server.tool(
8306
8653
  "search",
8307
8654
  "Primary retrieval alias. Call this whenever the user asks to find or recall context: use `query` for semantic retrieval, `id` for exact memory fetch, or both for hybrid recall.",
8308
8655
  {
8309
- project: z.string().optional().describe("Project name or slug"),
8310
- query: z.string().optional().describe("Semantic retrieval query"),
8311
- id: z.string().optional().describe("Exact memory id to fetch"),
8312
- top_k: z.number().optional().default(10),
8313
- include_memories: z.boolean().optional().default(false),
8314
- include_graph: z.boolean().optional().default(false),
8315
- user_id: z.string().optional(),
8316
- session_id: z.string().optional()
8656
+ project: z2.string().optional().describe("Project name or slug"),
8657
+ query: z2.string().optional().describe("Semantic retrieval query"),
8658
+ id: z2.string().optional().describe("Exact memory id to fetch"),
8659
+ top_k: z2.number().optional().default(10),
8660
+ include_memories: z2.boolean().optional().default(false),
8661
+ include_graph: z2.boolean().optional().default(false),
8662
+ user_id: z2.string().optional(),
8663
+ session_id: z2.string().optional()
8317
8664
  },
8318
8665
  async ({ project, query, id, top_k, include_memories, include_graph, user_id, session_id }) => {
8319
8666
  try {
@@ -8377,12 +8724,12 @@ server.tool(
8377
8724
  "search_code",
8378
8725
  "Semantically search a local codebase by meaning. Use this for questions like 'where is auth handled?' or 'find retry logic'.",
8379
8726
  {
8380
- query: z.string().describe("Natural-language code search query"),
8381
- path: z.string().optional().describe("Codebase root. Defaults to current working directory."),
8382
- file_types: z.array(z.string()).optional(),
8383
- top_k: z.number().optional().default(10),
8384
- threshold: z.number().optional().default(0.2),
8385
- max_files: z.number().optional().default(150)
8727
+ query: z2.string().describe("Natural-language code search query"),
8728
+ path: z2.string().optional().describe("Codebase root. Defaults to current working directory."),
8729
+ file_types: z2.array(z2.string()).optional(),
8730
+ top_k: z2.number().optional().default(10),
8731
+ threshold: z2.number().optional().default(0.2),
8732
+ max_files: z2.number().optional().default(150)
8386
8733
  },
8387
8734
  async ({ query, path, file_types, top_k, threshold, max_files }) => {
8388
8735
  try {
@@ -8403,11 +8750,11 @@ server.tool(
8403
8750
  "grep",
8404
8751
  "Regex or text search across a local codebase. Use this when you know the symbol, string, or pattern you want.",
8405
8752
  {
8406
- query: z.string().describe("Text or regex-like pattern to search for"),
8407
- path: z.string().optional().describe("Search root. Defaults to current working directory."),
8408
- file_types: z.array(z.string()).optional(),
8409
- max_results: z.number().optional().default(20),
8410
- case_sensitive: z.boolean().optional().default(false)
8753
+ query: z2.string().describe("Text or regex-like pattern to search for"),
8754
+ path: z2.string().optional().describe("Search root. Defaults to current working directory."),
8755
+ file_types: z2.array(z2.string()).optional(),
8756
+ max_results: z2.number().optional().default(20),
8757
+ case_sensitive: z2.boolean().optional().default(false)
8411
8758
  },
8412
8759
  async ({ query, path, file_types, max_results, case_sensitive }) => {
8413
8760
  const rootPath = path || process.cwd();
@@ -8455,9 +8802,9 @@ server.tool(
8455
8802
  "read",
8456
8803
  "Read a local file with optional line ranges. Use this after search or grep when you want the actual source.",
8457
8804
  {
8458
- path: z.string().describe("Absolute or relative path to the file to read."),
8459
- start_line: z.number().optional().default(1),
8460
- end_line: z.number().optional().default(200)
8805
+ path: z2.string().describe("Absolute or relative path to the file to read."),
8806
+ start_line: z2.number().optional().default(1),
8807
+ end_line: z2.number().optional().default(200)
8461
8808
  },
8462
8809
  async ({ path, start_line, end_line }) => {
8463
8810
  try {
@@ -8482,9 +8829,9 @@ server.tool(
8482
8829
  "explore",
8483
8830
  "Browse a repository tree or directory structure. Use this to orient yourself before reading files.",
8484
8831
  {
8485
- path: z.string().optional().describe("Root directory to inspect. Defaults to current working directory."),
8486
- max_depth: z.number().optional().default(3),
8487
- max_entries: z.number().optional().default(200)
8832
+ path: z2.string().optional().describe("Root directory to inspect. Defaults to current working directory."),
8833
+ max_depth: z2.number().optional().default(3),
8834
+ max_entries: z2.number().optional().default(200)
8488
8835
  },
8489
8836
  async ({ path, max_depth, max_entries }) => {
8490
8837
  try {
@@ -8513,11 +8860,11 @@ server.tool(
8513
8860
  "research",
8514
8861
  "Run deeper research over indexed sources. Use this when search is not enough and you want synthesis or multi-step investigation.",
8515
8862
  {
8516
- project: z.string().optional(),
8517
- query: z.string().describe("Research question"),
8518
- mode: z.enum(["search", "research"]).optional().default("research"),
8519
- max_results: z.number().optional().default(5),
8520
- max_steps: z.number().optional().default(5)
8863
+ project: z2.string().optional(),
8864
+ query: z2.string().describe("Research question"),
8865
+ mode: z2.enum(["search", "research"]).optional().default("research"),
8866
+ max_results: z2.number().optional().default(5),
8867
+ max_steps: z2.number().optional().default(5)
8521
8868
  },
8522
8869
  async ({ project, query, mode, max_results, max_steps }) => {
8523
8870
  try {
@@ -8539,27 +8886,27 @@ server.tool(
8539
8886
  "index",
8540
8887
  "Administrative indexing tool. Call this when retrieval is stale/missing or the user asks to connect new data. Use action='source' to add GitHub/web/pdf/local/slack/video, action='workspace' to refresh local workspace metadata.",
8541
8888
  {
8542
- action: z.enum(["source", "workspace"]).default("source"),
8543
- project: z.string().optional(),
8544
- type: z.enum(["github", "web", "playwright", "pdf", "local", "slack", "video"]).optional(),
8545
- name: z.string().optional(),
8546
- owner: z.string().optional(),
8547
- repo: z.string().optional(),
8548
- branch: z.string().optional(),
8549
- url: z.string().optional(),
8550
- file_path: z.string().optional(),
8551
- path: z.string().optional(),
8552
- glob: z.string().optional(),
8553
- max_files: z.number().optional(),
8554
- channel_ids: z.array(z.string()).optional(),
8555
- token: z.string().optional(),
8556
- workspace_id: z.string().optional(),
8557
- mode: z.enum(["full", "incremental"]).optional().default("incremental"),
8558
- platform: z.enum(["youtube", "loom", "generic"]).optional(),
8559
- language: z.string().optional(),
8560
- allow_stt_fallback: z.boolean().optional(),
8561
- max_duration_minutes: z.number().optional(),
8562
- max_chunks: z.number().optional()
8889
+ action: z2.enum(["source", "workspace"]).default("source"),
8890
+ project: z2.string().optional(),
8891
+ type: z2.enum(["github", "web", "playwright", "pdf", "local", "slack", "video"]).optional(),
8892
+ name: z2.string().optional(),
8893
+ owner: z2.string().optional(),
8894
+ repo: z2.string().optional(),
8895
+ branch: z2.string().optional(),
8896
+ url: z2.string().optional(),
8897
+ file_path: z2.string().optional(),
8898
+ path: z2.string().optional(),
8899
+ glob: z2.string().optional(),
8900
+ max_files: z2.number().optional(),
8901
+ channel_ids: z2.array(z2.string()).optional(),
8902
+ token: z2.string().optional(),
8903
+ workspace_id: z2.string().optional(),
8904
+ mode: z2.enum(["full", "incremental"]).optional().default("incremental"),
8905
+ platform: z2.enum(["youtube", "loom", "generic"]).optional(),
8906
+ language: z2.string().optional(),
8907
+ allow_stt_fallback: z2.boolean().optional(),
8908
+ max_duration_minutes: z2.number().optional(),
8909
+ max_chunks: z2.number().optional()
8563
8910
  },
8564
8911
  async (input) => {
8565
8912
  try {
@@ -8620,14 +8967,14 @@ server.tool(
8620
8967
  "remember",
8621
8968
  "Call this whenever the user states a durable preference, decision, instruction, or personal/project fact that should persist across sessions. Save proactively without waiting for an explicit 'remember this'.",
8622
8969
  {
8623
- project: z.string().optional(),
8624
- content: z.string().describe("Memory content"),
8625
- memory_type: z.enum(["factual", "preference", "event", "relationship", "opinion", "goal", "instruction"]).optional().default("factual"),
8626
- scope: z.enum(["personal", "shared_project"]).optional().default("personal"),
8627
- user_id: z.string().optional(),
8628
- session_id: z.string().optional(),
8629
- agent_id: z.string().optional(),
8630
- importance: z.number().optional().default(0.5)
8970
+ project: z2.string().optional(),
8971
+ content: z2.string().describe("Memory content"),
8972
+ memory_type: z2.enum(["factual", "preference", "event", "relationship", "opinion", "goal", "instruction"]).optional().default("factual"),
8973
+ scope: z2.enum(["personal", "shared_project"]).optional().default("personal"),
8974
+ user_id: z2.string().optional(),
8975
+ session_id: z2.string().optional(),
8976
+ agent_id: z2.string().optional(),
8977
+ importance: z2.number().optional().default(0.5)
8631
8978
  },
8632
8979
  async ({ project, content, memory_type, scope, user_id, session_id, agent_id, importance }) => {
8633
8980
  try {
@@ -8677,17 +9024,17 @@ server.tool(
8677
9024
  "record",
8678
9025
  "Record what just happened in a session or conversation. Use this for temporal capture, not durable preference storage.",
8679
9026
  {
8680
- project: z.string().optional(),
8681
- session_id: z.string().describe("Session to record into"),
8682
- user_id: z.string().optional(),
8683
- messages: z.array(z.object({
8684
- role: z.string().optional(),
8685
- content: z.string(),
8686
- timestamp: z.string().optional()
9027
+ project: z2.string().optional(),
9028
+ session_id: z2.string().describe("Session to record into"),
9029
+ user_id: z2.string().optional(),
9030
+ messages: z2.array(z2.object({
9031
+ role: z2.string().optional(),
9032
+ content: z2.string(),
9033
+ timestamp: z2.string().optional()
8687
9034
  })).optional(),
8688
- role: z.string().optional(),
8689
- content: z.string().optional(),
8690
- timestamp: z.string().optional()
9035
+ role: z2.string().optional(),
9036
+ content: z2.string().optional(),
9037
+ timestamp: z2.string().optional()
8691
9038
  },
8692
9039
  async ({ project, session_id, user_id, messages, role, content, timestamp }) => {
8693
9040
  try {
@@ -8739,60 +9086,62 @@ server.tool(
8739
9086
  "learn",
8740
9087
  "Unified ingestion entrypoint. Call this when the user asks to import knowledge: mode='conversation' for chat logs, mode='text' for raw text, mode='source' for external sources to index. Prefer this over legacy compatibility tools.",
8741
9088
  {
8742
- mode: z.enum(["conversation", "text", "source"]).describe("What kind of learning to perform"),
8743
- project: z.string().optional(),
8744
- user_id: z.string().optional().describe("Optional end-user identity for conversation learning"),
8745
- session_id: z.string().optional().describe("Session identifier for conversation learning"),
8746
- messages: z.array(z.object({
8747
- role: z.string(),
8748
- content: z.string(),
8749
- timestamp: z.string().optional()
9089
+ mode: z2.enum(["conversation", "text", "source"]).describe("What kind of learning to perform"),
9090
+ project: z2.string().optional(),
9091
+ user_id: z2.string().optional().describe("Optional end-user identity for conversation learning"),
9092
+ session_id: z2.string().optional().describe("Session identifier for conversation learning"),
9093
+ messages: z2.array(z2.object({
9094
+ role: z2.string(),
9095
+ content: z2.string(),
9096
+ timestamp: z2.string().optional()
8750
9097
  })).optional().describe("Conversation messages to learn from"),
8751
- title: z.string().optional().describe("Title for text learning"),
8752
- content: z.string().optional().describe("Inline text content to ingest"),
8753
- metadata: z.record(z.any()).optional(),
8754
- tags: z.array(z.string()).optional(),
8755
- namespace: z.string().optional(),
8756
- type: z.enum(["github", "web", "playwright", "pdf", "local", "slack", "video"]).optional().describe("Source type when mode=source"),
8757
- url: z.string().optional().describe("URL to learn from"),
8758
- owner: z.string().optional().describe("GitHub owner"),
8759
- repo: z.string().optional().describe("GitHub repository"),
8760
- branch: z.string().optional(),
8761
- paths: z.array(z.string()).optional(),
8762
- path: z.string().optional().describe("Local path to learn from"),
8763
- file_path: z.string().optional().describe("Single file path to learn from"),
8764
- name: z.string().optional().describe("Optional source name"),
8765
- channel_ids: z.array(z.string()).optional(),
8766
- since: z.string().optional(),
8767
- token: z.string().optional(),
8768
- auth_ref: z.string().optional(),
8769
- platform: z.enum(["youtube", "loom", "generic"]).optional(),
8770
- language: z.string().optional(),
8771
- options: z.object({
8772
- async: z.boolean().optional(),
8773
- auto_index: z.boolean().optional(),
8774
- ingestion_profile: z.enum(["auto", "repo", "web_docs", "pdf_layout", "video_transcript", "plain_text"]).optional(),
8775
- strategy_override: z.enum(["fixed", "recursive", "semantic", "hierarchical", "adaptive"]).optional(),
8776
- profile_config: z.record(z.any()).optional(),
8777
- crawl_depth: z.number().optional(),
8778
- include_paths: z.array(z.string()).optional(),
8779
- exclude_paths: z.array(z.string()).optional(),
8780
- glob: z.string().optional(),
8781
- max_files: z.number().optional(),
8782
- max_pages: z.number().optional(),
8783
- extract_mode: z.enum(["text", "structured", "markdown"]).optional(),
8784
- workspace_id: z.string().optional(),
8785
- allow_stt_fallback: z.boolean().optional(),
8786
- max_duration_minutes: z.number().optional(),
8787
- max_chunks: z.number().optional()
9098
+ title: z2.string().optional().describe("Title for text learning"),
9099
+ content: z2.string().optional().describe("Inline text content to ingest"),
9100
+ metadata: z2.record(z2.any()).optional(),
9101
+ tags: z2.array(z2.string()).optional(),
9102
+ namespace: z2.string().optional(),
9103
+ type: z2.enum(["github", "web", "playwright", "pdf", "local", "slack", "video"]).optional().describe("Source type when mode=source"),
9104
+ url: z2.string().optional().describe("URL to learn from"),
9105
+ owner: z2.string().optional().describe("GitHub owner"),
9106
+ repo: z2.string().optional().describe("GitHub repository"),
9107
+ branch: z2.string().optional(),
9108
+ paths: z2.array(z2.string()).optional(),
9109
+ path: z2.string().optional().describe("Local path to learn from"),
9110
+ file_path: z2.string().optional().describe("Single file path to learn from"),
9111
+ name: z2.string().optional().describe("Optional source name"),
9112
+ channel_ids: z2.array(z2.string()).optional(),
9113
+ since: z2.string().optional(),
9114
+ token: z2.string().optional(),
9115
+ auth_ref: z2.string().optional(),
9116
+ platform: z2.enum(["youtube", "loom", "generic"]).optional(),
9117
+ language: z2.string().optional(),
9118
+ options: z2.object({
9119
+ async: z2.boolean().optional(),
9120
+ auto_index: z2.boolean().optional(),
9121
+ ingestion_profile: z2.enum(["auto", "repo", "web_docs", "pdf_layout", "video_transcript", "plain_text"]).optional(),
9122
+ strategy_override: z2.enum(["fixed", "recursive", "semantic", "hierarchical", "adaptive"]).optional(),
9123
+ profile_config: z2.record(z2.any()).optional(),
9124
+ crawl_depth: z2.number().optional(),
9125
+ include_paths: z2.array(z2.string()).optional(),
9126
+ exclude_paths: z2.array(z2.string()).optional(),
9127
+ glob: z2.string().optional(),
9128
+ max_files: z2.number().optional(),
9129
+ max_pages: z2.number().optional(),
9130
+ extract_mode: z2.enum(["text", "structured", "markdown"]).optional(),
9131
+ workspace_id: z2.string().optional(),
9132
+ allow_stt_fallback: z2.boolean().optional(),
9133
+ max_duration_minutes: z2.number().optional(),
9134
+ max_chunks: z2.number().optional()
8788
9135
  }).optional()
8789
9136
  },
8790
9137
  async (input) => {
8791
9138
  try {
8792
9139
  const result = await learnFromInput(input);
9140
+ const indexingNote = result.mode === "source" && result.index_started ? "Indexing has started in the background and usually completes in 1\u20132 minutes. Queries may return limited results until then. Run `index.workspace_status` or `context.source_status` to check progress." : void 0;
8793
9141
  return primaryToolSuccess({
8794
9142
  tool: "learn",
8795
- ...result
9143
+ ...result,
9144
+ ...indexingNote ? { _note: indexingNote } : {}
8796
9145
  });
8797
9146
  } catch (error) {
8798
9147
  return primaryToolError(error.message);
@@ -8803,10 +9152,10 @@ server.tool(
8803
9152
  "share_context",
8804
9153
  "Create a shareable snapshot of a session so another agent or teammate can continue with the same context.",
8805
9154
  {
8806
- project: z.string().optional(),
8807
- session_id: z.string().describe("Session to share"),
8808
- title: z.string().optional(),
8809
- expiry_days: z.number().optional().default(30)
9155
+ project: z2.string().optional(),
9156
+ session_id: z2.string().describe("Session to share"),
9157
+ title: z2.string().optional(),
9158
+ expiry_days: z2.number().optional().default(30)
8810
9159
  },
8811
9160
  async ({ project, session_id, title, expiry_days }) => {
8812
9161
  try {