@usewhisper/sdk 3.0.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,7 +14,7 @@ npm install @usewhisper/sdk
14
14
  import { WhisperContext } from '@usewhisper/sdk';
15
15
 
16
16
  const whisper = new WhisperContext({
17
- apiKey: 'wsk_your_api_key_here'
17
+ apiKey: 'wsk_your_api_key_here'
18
18
  });
19
19
 
20
20
  // Create a project
@@ -48,7 +48,7 @@ Get your API key from the [Whisper dashboard](https://usewhisper.dev/dashboard):
48
48
 
49
49
  ```typescript
50
50
  const whisper = new WhisperContext({
51
- apiKey: 'wsk_...', // Your API key
51
+ apiKey: 'wsk_...', // Your API key
52
52
  baseUrl: 'https://context.usewhisper.dev' // Optional, defaults to production
53
53
  });
54
54
  ```
package/index.d.mts CHANGED
@@ -215,6 +215,7 @@ interface RuntimeClientOptions {
215
215
  compatMode?: CompatMode;
216
216
  timeouts?: Partial<TimeoutBudgets>;
217
217
  retryPolicy?: RetryPolicy;
218
+ fetchImpl?: typeof fetch;
218
219
  }
219
220
  interface RuntimeResponse<T> {
220
221
  data: T;
@@ -324,6 +325,8 @@ declare class RuntimeClient {
324
325
  private readonly timeouts;
325
326
  private readonly diagnostics;
326
327
  private readonly inFlight;
328
+ private readonly sendApiKeyHeader;
329
+ private readonly fetchImpl;
327
330
  constructor(options: RuntimeClientOptions, diagnostics?: DiagnosticsStore);
328
331
  getDiagnosticsStore(): DiagnosticsStore;
329
332
  getCompatMode(): CompatMode;
@@ -332,6 +335,8 @@ declare class RuntimeClient {
332
335
  private shouldRetryStatus;
333
336
  private backoff;
334
337
  private runtimeName;
338
+ private apiKeyOnlyPrefixes;
339
+ private shouldAttachApiKeyHeader;
335
340
  private createRequestFingerprint;
336
341
  request<T>(options: RuntimeRequestOptions): Promise<RuntimeResponse<T>>;
337
342
  private performRequest;
@@ -411,11 +416,13 @@ interface MemoryWriteAck$1 {
411
416
  success: boolean;
412
417
  mode?: "async" | "sync";
413
418
  trace_id?: string;
419
+ memory_id?: string;
414
420
  job_id?: string;
415
421
  status_url?: string;
416
422
  accepted_at?: string;
417
423
  visibility_sla_ms?: number;
418
424
  pending_visibility?: boolean;
425
+ semantic_status?: "pending" | "ready";
419
426
  queued?: boolean;
420
427
  event_id?: string;
421
428
  created?: number;
@@ -496,6 +503,9 @@ declare class MemoryModule {
496
503
  memories: Array<Record<string, unknown>>;
497
504
  count: number;
498
505
  }>;
506
+ get(memoryId: string): Promise<{
507
+ memory: Record<string, unknown>;
508
+ }>;
499
509
  update(memoryId: string, params: {
500
510
  content: string;
501
511
  reasoning?: string;
@@ -613,6 +623,7 @@ interface WhisperClientConfig {
613
623
  baseUrl?: string;
614
624
  project?: string;
615
625
  compatMode?: CompatMode;
626
+ fetch?: typeof fetch;
616
627
  timeouts?: Partial<TimeoutBudgets>;
617
628
  retryPolicy?: RetryPolicy;
618
629
  cache?: {
@@ -654,6 +665,9 @@ declare class WhisperClient {
654
665
  add: (params: Parameters<MemoryModule["add"]>[0]) => Promise<MemoryWriteAck$1>;
655
666
  addBulk: (params: Parameters<MemoryModule["addBulk"]>[0]) => Promise<MemoryWriteAck$1>;
656
667
  search: (params: Parameters<MemoryModule["search"]>[0]) => Promise<MemorySearchResponse$1>;
668
+ get: (memoryId: string) => Promise<{
669
+ memory: Record<string, unknown>;
670
+ }>;
657
671
  getUserProfile: (params: Parameters<MemoryModule["getUserProfile"]>[0]) => ReturnType<MemoryModule["getUserProfile"]>;
658
672
  getSessionMemories: (params: Parameters<MemoryModule["getSessionMemories"]>[0]) => ReturnType<MemoryModule["getSessionMemories"]>;
659
673
  update: (memoryId: string, params: {
@@ -996,6 +1010,65 @@ interface Source {
996
1010
  createdAt: string;
997
1011
  updatedAt: string;
998
1012
  }
1013
+ interface VideoSourceMetadata {
1014
+ source_kind: "video";
1015
+ video_url: string;
1016
+ platform: "youtube" | "loom" | "generic";
1017
+ duration_seconds?: number;
1018
+ published_at?: string;
1019
+ channel_or_author?: string;
1020
+ }
1021
+ interface VideoIngestionStatus {
1022
+ source_id: string;
1023
+ status: string;
1024
+ stage: "extracting" | "transcribing" | "segmenting" | "enriching" | "indexing" | "completed" | "failed";
1025
+ sync_job_id?: string | null;
1026
+ progress?: {
1027
+ current: number;
1028
+ total: number;
1029
+ message: string;
1030
+ } | null;
1031
+ duration_seconds?: number | null;
1032
+ chunks_indexed?: number | null;
1033
+ decisions_detected?: number | null;
1034
+ entities_extracted?: string[];
1035
+ last_error?: string | null;
1036
+ updated_at?: string;
1037
+ }
1038
+ type CanonicalSourceType = "github" | "web" | "pdf" | "local" | "slack";
1039
+ interface CanonicalSourceCreateParams {
1040
+ type: CanonicalSourceType;
1041
+ name?: string;
1042
+ auto_index?: boolean;
1043
+ metadata?: Record<string, string>;
1044
+ ingestion_profile?: "auto" | "repo" | "web_docs" | "pdf_layout" | "video_transcript" | "plain_text";
1045
+ strategy_override?: "fixed" | "recursive" | "semantic" | "hierarchical" | "adaptive";
1046
+ profile_config?: Record<string, any>;
1047
+ owner?: string;
1048
+ repo?: string;
1049
+ branch?: string;
1050
+ paths?: string[];
1051
+ url?: string;
1052
+ crawl_depth?: number;
1053
+ include_paths?: string[];
1054
+ exclude_paths?: string[];
1055
+ file_path?: string;
1056
+ path?: string;
1057
+ glob?: string;
1058
+ max_files?: number;
1059
+ workspace_id?: string;
1060
+ channel_ids?: string[];
1061
+ since?: string;
1062
+ token?: string;
1063
+ auth_ref?: string;
1064
+ }
1065
+ interface CanonicalSourceCreateResult {
1066
+ source_id: string;
1067
+ status: "queued" | "indexing" | "ready" | "failed";
1068
+ job_id: string | null;
1069
+ index_started: boolean;
1070
+ warnings: string[];
1071
+ }
999
1072
  interface Memory {
1000
1073
  id: string;
1001
1074
  projectId: string;
@@ -1082,6 +1155,20 @@ interface MemoryWriteAck {
1082
1155
  pending_visibility?: boolean;
1083
1156
  [key: string]: any;
1084
1157
  }
1158
+ interface MemoryWriteResult {
1159
+ id: string;
1160
+ success: boolean;
1161
+ path: "sota" | "legacy";
1162
+ fallback_used: boolean;
1163
+ mode?: "async" | "sync";
1164
+ memory_id?: string;
1165
+ job_id?: string;
1166
+ status_url?: string;
1167
+ accepted_at?: string;
1168
+ visibility_sla_ms?: number;
1169
+ pending_visibility?: boolean;
1170
+ semantic_status?: "pending" | "ready";
1171
+ }
1085
1172
  type WhisperErrorCode = "INVALID_API_KEY" | "PROJECT_NOT_FOUND" | "PROJECT_AMBIGUOUS" | "RATE_LIMITED" | "TEMPORARY_UNAVAILABLE" | "NETWORK_ERROR" | "TIMEOUT" | "REQUEST_FAILED" | "MISSING_PROJECT";
1086
1173
  declare class WhisperError extends Error {
1087
1174
  code: WhisperErrorCode;
@@ -1139,12 +1226,35 @@ declare class WhisperContext {
1139
1226
  sync_schedule?: string;
1140
1227
  }): Promise<Source>;
1141
1228
  syncSource(sourceId: string): Promise<any>;
1229
+ addSourceByType(projectId: string, params: {
1230
+ type: "video";
1231
+ url: string;
1232
+ auto_sync?: boolean;
1233
+ tags?: string[];
1234
+ platform?: "youtube" | "loom" | "generic";
1235
+ language?: string;
1236
+ allow_stt_fallback?: boolean;
1237
+ max_duration_minutes?: number;
1238
+ name?: string;
1239
+ ingestion_profile?: "auto" | "repo" | "web_docs" | "pdf_layout" | "video_transcript" | "plain_text";
1240
+ strategy_override?: "fixed" | "recursive" | "semantic" | "hierarchical" | "adaptive";
1241
+ profile_config?: Record<string, any>;
1242
+ }): Promise<{
1243
+ source_id: string;
1244
+ sync_job_id?: string | null;
1245
+ status: "processing" | "queued" | "created";
1246
+ }>;
1247
+ getSourceStatus(sourceId: string): Promise<VideoIngestionStatus>;
1248
+ createCanonicalSource(project: string, params: CanonicalSourceCreateParams): Promise<CanonicalSourceCreateResult>;
1142
1249
  ingest(projectId: string, documents: Array<{
1143
1250
  id?: string;
1144
1251
  title: string;
1145
1252
  content: string;
1146
1253
  metadata?: Record<string, any>;
1147
1254
  file_path?: string;
1255
+ ingestion_profile?: "auto" | "repo" | "web_docs" | "pdf_layout" | "video_transcript" | "plain_text";
1256
+ strategy_override?: "fixed" | "recursive" | "semantic" | "hierarchical" | "adaptive";
1257
+ profile_config?: Record<string, any>;
1148
1258
  }>): Promise<{
1149
1259
  ingested: number;
1150
1260
  }>;
@@ -1169,12 +1279,7 @@ declare class WhisperContext {
1169
1279
  async?: boolean;
1170
1280
  write_mode?: "async" | "sync";
1171
1281
  allow_legacy_fallback?: boolean;
1172
- }): Promise<{
1173
- id: string;
1174
- success: boolean;
1175
- path: "sota" | "legacy";
1176
- fallback_used: boolean;
1177
- }>;
1282
+ }): Promise<MemoryWriteResult>;
1178
1283
  addMemoriesBulk(params: {
1179
1284
  project?: string;
1180
1285
  memories: Array<{
@@ -1299,6 +1404,9 @@ declare class WhisperContext {
1299
1404
  memories: any[];
1300
1405
  count: number;
1301
1406
  }>;
1407
+ getMemory(memoryId: string): Promise<{
1408
+ memory: any;
1409
+ }>;
1302
1410
  getMemoryVersions(memoryId: string): Promise<{
1303
1411
  memory_id: string;
1304
1412
  versions: any[];
@@ -1539,16 +1647,28 @@ declare class WhisperContext {
1539
1647
  config: Record<string, any>;
1540
1648
  sync_schedule?: string;
1541
1649
  }) => Promise<Source>;
1650
+ addSource: (projectId: string, params: {
1651
+ type: "video";
1652
+ url: string;
1653
+ auto_sync?: boolean;
1654
+ tags?: string[];
1655
+ platform?: "youtube" | "loom" | "generic";
1656
+ language?: string;
1657
+ allow_stt_fallback?: boolean;
1658
+ max_duration_minutes?: number;
1659
+ name?: string;
1660
+ }) => Promise<{
1661
+ source_id: string;
1662
+ sync_job_id?: string | null;
1663
+ status: "processing" | "queued" | "created";
1664
+ }>;
1542
1665
  sync: (sourceId: string) => Promise<any>;
1543
1666
  syncSource: (sourceId: string) => Promise<any>;
1667
+ status: (sourceId: string) => Promise<VideoIngestionStatus>;
1668
+ getStatus: (sourceId: string) => Promise<VideoIngestionStatus>;
1544
1669
  };
1545
1670
  readonly memory: {
1546
- add: (params: Parameters<WhisperContext["addMemory"]>[0]) => Promise<{
1547
- id: string;
1548
- success: boolean;
1549
- path: "sota" | "legacy";
1550
- fallback_used: boolean;
1551
- }>;
1671
+ add: (params: Parameters<WhisperContext["addMemory"]>[0]) => Promise<MemoryWriteResult>;
1552
1672
  addBulk: (params: Parameters<WhisperContext["addMemoriesBulk"]>[0]) => Promise<any>;
1553
1673
  extract: (params: Parameters<WhisperContext["extractMemories"]>[0]) => Promise<MemoryExtractionResult>;
1554
1674
  extractSession: (params: Parameters<WhisperContext["extractSessionMemories"]>[0]) => Promise<{
@@ -1574,6 +1694,9 @@ declare class WhisperContext {
1574
1694
  memories: any[];
1575
1695
  count: number;
1576
1696
  }>;
1697
+ get: (memoryId: string) => Promise<{
1698
+ memory: any;
1699
+ }>;
1577
1700
  getVersions: (memoryId: string) => Promise<{
1578
1701
  memory_id: string;
1579
1702
  versions: any[];
@@ -1679,4 +1802,4 @@ declare class WhisperContext {
1679
1802
  };
1680
1803
  }
1681
1804
 
1682
- export { type ExtractedMemory, LangChainMemoryAdapter, LangGraphCheckpointAdapter, type Memory, type MemoryExtractionResult, type MemoryKind, type MemoryLatencyBreakdown, type MemorySearchResponse, type MemoryWriteAck, type Project, type QueryParams, type QueryResult, type Source, Whisper, WhisperAgentMiddleware, WhisperClient, type WhisperConfig, WhisperContext, Whisper as WhisperDefault, WhisperError, type WhisperErrorCode, WhisperClient as WhisperRuntimeClient, createAgentMiddleware, createLangChainMemoryAdapter, createLangGraphCheckpointAdapter, WhisperContext as default, memoryGraphToMermaid };
1805
+ export { type CanonicalSourceCreateParams, type CanonicalSourceCreateResult, type CanonicalSourceType, type ExtractedMemory, LangChainMemoryAdapter, LangGraphCheckpointAdapter, type Memory, type MemoryExtractionResult, type MemoryKind, type MemoryLatencyBreakdown, type MemorySearchResponse, type MemoryWriteAck, type MemoryWriteResult, type Project, type QueryParams, type QueryResult, type Source, type VideoIngestionStatus, type VideoSourceMetadata, Whisper, WhisperAgentMiddleware, WhisperClient, type WhisperConfig, WhisperContext, Whisper as WhisperDefault, WhisperError, type WhisperErrorCode, WhisperClient as WhisperRuntimeClient, createAgentMiddleware, createLangChainMemoryAdapter, createLangGraphCheckpointAdapter, WhisperContext as default, memoryGraphToMermaid };
package/index.d.ts CHANGED
@@ -215,6 +215,7 @@ interface RuntimeClientOptions {
215
215
  compatMode?: CompatMode;
216
216
  timeouts?: Partial<TimeoutBudgets>;
217
217
  retryPolicy?: RetryPolicy;
218
+ fetchImpl?: typeof fetch;
218
219
  }
219
220
  interface RuntimeResponse<T> {
220
221
  data: T;
@@ -324,6 +325,8 @@ declare class RuntimeClient {
324
325
  private readonly timeouts;
325
326
  private readonly diagnostics;
326
327
  private readonly inFlight;
328
+ private readonly sendApiKeyHeader;
329
+ private readonly fetchImpl;
327
330
  constructor(options: RuntimeClientOptions, diagnostics?: DiagnosticsStore);
328
331
  getDiagnosticsStore(): DiagnosticsStore;
329
332
  getCompatMode(): CompatMode;
@@ -332,6 +335,8 @@ declare class RuntimeClient {
332
335
  private shouldRetryStatus;
333
336
  private backoff;
334
337
  private runtimeName;
338
+ private apiKeyOnlyPrefixes;
339
+ private shouldAttachApiKeyHeader;
335
340
  private createRequestFingerprint;
336
341
  request<T>(options: RuntimeRequestOptions): Promise<RuntimeResponse<T>>;
337
342
  private performRequest;
@@ -411,11 +416,13 @@ interface MemoryWriteAck$1 {
411
416
  success: boolean;
412
417
  mode?: "async" | "sync";
413
418
  trace_id?: string;
419
+ memory_id?: string;
414
420
  job_id?: string;
415
421
  status_url?: string;
416
422
  accepted_at?: string;
417
423
  visibility_sla_ms?: number;
418
424
  pending_visibility?: boolean;
425
+ semantic_status?: "pending" | "ready";
419
426
  queued?: boolean;
420
427
  event_id?: string;
421
428
  created?: number;
@@ -496,6 +503,9 @@ declare class MemoryModule {
496
503
  memories: Array<Record<string, unknown>>;
497
504
  count: number;
498
505
  }>;
506
+ get(memoryId: string): Promise<{
507
+ memory: Record<string, unknown>;
508
+ }>;
499
509
  update(memoryId: string, params: {
500
510
  content: string;
501
511
  reasoning?: string;
@@ -613,6 +623,7 @@ interface WhisperClientConfig {
613
623
  baseUrl?: string;
614
624
  project?: string;
615
625
  compatMode?: CompatMode;
626
+ fetch?: typeof fetch;
616
627
  timeouts?: Partial<TimeoutBudgets>;
617
628
  retryPolicy?: RetryPolicy;
618
629
  cache?: {
@@ -654,6 +665,9 @@ declare class WhisperClient {
654
665
  add: (params: Parameters<MemoryModule["add"]>[0]) => Promise<MemoryWriteAck$1>;
655
666
  addBulk: (params: Parameters<MemoryModule["addBulk"]>[0]) => Promise<MemoryWriteAck$1>;
656
667
  search: (params: Parameters<MemoryModule["search"]>[0]) => Promise<MemorySearchResponse$1>;
668
+ get: (memoryId: string) => Promise<{
669
+ memory: Record<string, unknown>;
670
+ }>;
657
671
  getUserProfile: (params: Parameters<MemoryModule["getUserProfile"]>[0]) => ReturnType<MemoryModule["getUserProfile"]>;
658
672
  getSessionMemories: (params: Parameters<MemoryModule["getSessionMemories"]>[0]) => ReturnType<MemoryModule["getSessionMemories"]>;
659
673
  update: (memoryId: string, params: {
@@ -996,6 +1010,65 @@ interface Source {
996
1010
  createdAt: string;
997
1011
  updatedAt: string;
998
1012
  }
1013
+ interface VideoSourceMetadata {
1014
+ source_kind: "video";
1015
+ video_url: string;
1016
+ platform: "youtube" | "loom" | "generic";
1017
+ duration_seconds?: number;
1018
+ published_at?: string;
1019
+ channel_or_author?: string;
1020
+ }
1021
+ interface VideoIngestionStatus {
1022
+ source_id: string;
1023
+ status: string;
1024
+ stage: "extracting" | "transcribing" | "segmenting" | "enriching" | "indexing" | "completed" | "failed";
1025
+ sync_job_id?: string | null;
1026
+ progress?: {
1027
+ current: number;
1028
+ total: number;
1029
+ message: string;
1030
+ } | null;
1031
+ duration_seconds?: number | null;
1032
+ chunks_indexed?: number | null;
1033
+ decisions_detected?: number | null;
1034
+ entities_extracted?: string[];
1035
+ last_error?: string | null;
1036
+ updated_at?: string;
1037
+ }
1038
+ type CanonicalSourceType = "github" | "web" | "pdf" | "local" | "slack";
1039
+ interface CanonicalSourceCreateParams {
1040
+ type: CanonicalSourceType;
1041
+ name?: string;
1042
+ auto_index?: boolean;
1043
+ metadata?: Record<string, string>;
1044
+ ingestion_profile?: "auto" | "repo" | "web_docs" | "pdf_layout" | "video_transcript" | "plain_text";
1045
+ strategy_override?: "fixed" | "recursive" | "semantic" | "hierarchical" | "adaptive";
1046
+ profile_config?: Record<string, any>;
1047
+ owner?: string;
1048
+ repo?: string;
1049
+ branch?: string;
1050
+ paths?: string[];
1051
+ url?: string;
1052
+ crawl_depth?: number;
1053
+ include_paths?: string[];
1054
+ exclude_paths?: string[];
1055
+ file_path?: string;
1056
+ path?: string;
1057
+ glob?: string;
1058
+ max_files?: number;
1059
+ workspace_id?: string;
1060
+ channel_ids?: string[];
1061
+ since?: string;
1062
+ token?: string;
1063
+ auth_ref?: string;
1064
+ }
1065
+ interface CanonicalSourceCreateResult {
1066
+ source_id: string;
1067
+ status: "queued" | "indexing" | "ready" | "failed";
1068
+ job_id: string | null;
1069
+ index_started: boolean;
1070
+ warnings: string[];
1071
+ }
999
1072
  interface Memory {
1000
1073
  id: string;
1001
1074
  projectId: string;
@@ -1082,6 +1155,20 @@ interface MemoryWriteAck {
1082
1155
  pending_visibility?: boolean;
1083
1156
  [key: string]: any;
1084
1157
  }
1158
+ interface MemoryWriteResult {
1159
+ id: string;
1160
+ success: boolean;
1161
+ path: "sota" | "legacy";
1162
+ fallback_used: boolean;
1163
+ mode?: "async" | "sync";
1164
+ memory_id?: string;
1165
+ job_id?: string;
1166
+ status_url?: string;
1167
+ accepted_at?: string;
1168
+ visibility_sla_ms?: number;
1169
+ pending_visibility?: boolean;
1170
+ semantic_status?: "pending" | "ready";
1171
+ }
1085
1172
  type WhisperErrorCode = "INVALID_API_KEY" | "PROJECT_NOT_FOUND" | "PROJECT_AMBIGUOUS" | "RATE_LIMITED" | "TEMPORARY_UNAVAILABLE" | "NETWORK_ERROR" | "TIMEOUT" | "REQUEST_FAILED" | "MISSING_PROJECT";
1086
1173
  declare class WhisperError extends Error {
1087
1174
  code: WhisperErrorCode;
@@ -1139,12 +1226,35 @@ declare class WhisperContext {
1139
1226
  sync_schedule?: string;
1140
1227
  }): Promise<Source>;
1141
1228
  syncSource(sourceId: string): Promise<any>;
1229
+ addSourceByType(projectId: string, params: {
1230
+ type: "video";
1231
+ url: string;
1232
+ auto_sync?: boolean;
1233
+ tags?: string[];
1234
+ platform?: "youtube" | "loom" | "generic";
1235
+ language?: string;
1236
+ allow_stt_fallback?: boolean;
1237
+ max_duration_minutes?: number;
1238
+ name?: string;
1239
+ ingestion_profile?: "auto" | "repo" | "web_docs" | "pdf_layout" | "video_transcript" | "plain_text";
1240
+ strategy_override?: "fixed" | "recursive" | "semantic" | "hierarchical" | "adaptive";
1241
+ profile_config?: Record<string, any>;
1242
+ }): Promise<{
1243
+ source_id: string;
1244
+ sync_job_id?: string | null;
1245
+ status: "processing" | "queued" | "created";
1246
+ }>;
1247
+ getSourceStatus(sourceId: string): Promise<VideoIngestionStatus>;
1248
+ createCanonicalSource(project: string, params: CanonicalSourceCreateParams): Promise<CanonicalSourceCreateResult>;
1142
1249
  ingest(projectId: string, documents: Array<{
1143
1250
  id?: string;
1144
1251
  title: string;
1145
1252
  content: string;
1146
1253
  metadata?: Record<string, any>;
1147
1254
  file_path?: string;
1255
+ ingestion_profile?: "auto" | "repo" | "web_docs" | "pdf_layout" | "video_transcript" | "plain_text";
1256
+ strategy_override?: "fixed" | "recursive" | "semantic" | "hierarchical" | "adaptive";
1257
+ profile_config?: Record<string, any>;
1148
1258
  }>): Promise<{
1149
1259
  ingested: number;
1150
1260
  }>;
@@ -1169,12 +1279,7 @@ declare class WhisperContext {
1169
1279
  async?: boolean;
1170
1280
  write_mode?: "async" | "sync";
1171
1281
  allow_legacy_fallback?: boolean;
1172
- }): Promise<{
1173
- id: string;
1174
- success: boolean;
1175
- path: "sota" | "legacy";
1176
- fallback_used: boolean;
1177
- }>;
1282
+ }): Promise<MemoryWriteResult>;
1178
1283
  addMemoriesBulk(params: {
1179
1284
  project?: string;
1180
1285
  memories: Array<{
@@ -1299,6 +1404,9 @@ declare class WhisperContext {
1299
1404
  memories: any[];
1300
1405
  count: number;
1301
1406
  }>;
1407
+ getMemory(memoryId: string): Promise<{
1408
+ memory: any;
1409
+ }>;
1302
1410
  getMemoryVersions(memoryId: string): Promise<{
1303
1411
  memory_id: string;
1304
1412
  versions: any[];
@@ -1539,16 +1647,28 @@ declare class WhisperContext {
1539
1647
  config: Record<string, any>;
1540
1648
  sync_schedule?: string;
1541
1649
  }) => Promise<Source>;
1650
+ addSource: (projectId: string, params: {
1651
+ type: "video";
1652
+ url: string;
1653
+ auto_sync?: boolean;
1654
+ tags?: string[];
1655
+ platform?: "youtube" | "loom" | "generic";
1656
+ language?: string;
1657
+ allow_stt_fallback?: boolean;
1658
+ max_duration_minutes?: number;
1659
+ name?: string;
1660
+ }) => Promise<{
1661
+ source_id: string;
1662
+ sync_job_id?: string | null;
1663
+ status: "processing" | "queued" | "created";
1664
+ }>;
1542
1665
  sync: (sourceId: string) => Promise<any>;
1543
1666
  syncSource: (sourceId: string) => Promise<any>;
1667
+ status: (sourceId: string) => Promise<VideoIngestionStatus>;
1668
+ getStatus: (sourceId: string) => Promise<VideoIngestionStatus>;
1544
1669
  };
1545
1670
  readonly memory: {
1546
- add: (params: Parameters<WhisperContext["addMemory"]>[0]) => Promise<{
1547
- id: string;
1548
- success: boolean;
1549
- path: "sota" | "legacy";
1550
- fallback_used: boolean;
1551
- }>;
1671
+ add: (params: Parameters<WhisperContext["addMemory"]>[0]) => Promise<MemoryWriteResult>;
1552
1672
  addBulk: (params: Parameters<WhisperContext["addMemoriesBulk"]>[0]) => Promise<any>;
1553
1673
  extract: (params: Parameters<WhisperContext["extractMemories"]>[0]) => Promise<MemoryExtractionResult>;
1554
1674
  extractSession: (params: Parameters<WhisperContext["extractSessionMemories"]>[0]) => Promise<{
@@ -1574,6 +1694,9 @@ declare class WhisperContext {
1574
1694
  memories: any[];
1575
1695
  count: number;
1576
1696
  }>;
1697
+ get: (memoryId: string) => Promise<{
1698
+ memory: any;
1699
+ }>;
1577
1700
  getVersions: (memoryId: string) => Promise<{
1578
1701
  memory_id: string;
1579
1702
  versions: any[];
@@ -1679,4 +1802,4 @@ declare class WhisperContext {
1679
1802
  };
1680
1803
  }
1681
1804
 
1682
- export { type ExtractedMemory, LangChainMemoryAdapter, LangGraphCheckpointAdapter, type Memory, type MemoryExtractionResult, type MemoryKind, type MemoryLatencyBreakdown, type MemorySearchResponse, type MemoryWriteAck, type Project, type QueryParams, type QueryResult, type Source, Whisper, WhisperAgentMiddleware, WhisperClient, type WhisperConfig, WhisperContext, Whisper as WhisperDefault, WhisperError, type WhisperErrorCode, WhisperClient as WhisperRuntimeClient, createAgentMiddleware, createLangChainMemoryAdapter, createLangGraphCheckpointAdapter, WhisperContext as default, memoryGraphToMermaid };
1805
+ export { type CanonicalSourceCreateParams, type CanonicalSourceCreateResult, type CanonicalSourceType, type ExtractedMemory, LangChainMemoryAdapter, LangGraphCheckpointAdapter, type Memory, type MemoryExtractionResult, type MemoryKind, type MemoryLatencyBreakdown, type MemorySearchResponse, type MemoryWriteAck, type MemoryWriteResult, type Project, type QueryParams, type QueryResult, type Source, type VideoIngestionStatus, type VideoSourceMetadata, Whisper, WhisperAgentMiddleware, WhisperClient, type WhisperConfig, WhisperContext, Whisper as WhisperDefault, WhisperError, type WhisperErrorCode, WhisperClient as WhisperRuntimeClient, createAgentMiddleware, createLangChainMemoryAdapter, createLangGraphCheckpointAdapter, WhisperContext as default, memoryGraphToMermaid };
package/index.js CHANGED
@@ -134,6 +134,7 @@ var DEFAULT_TIMEOUTS = {
134
134
  sessionMs: 2500
135
135
  };
136
136
  var DEFAULT_RETRYABLE_STATUS = [408, 429, 500, 502, 503, 504];
137
+ var DEFAULT_API_KEY_ONLY_PREFIXES = ["/v1/memory", "/v1/context/query"];
137
138
  var DEFAULT_RETRY_ATTEMPTS = {
138
139
  search: 3,
139
140
  writeAck: 2,
@@ -182,6 +183,8 @@ var RuntimeClient = class {
182
183
  timeouts;
183
184
  diagnostics;
184
185
  inFlight = /* @__PURE__ */ new Map();
186
+ sendApiKeyHeader;
187
+ fetchImpl;
185
188
  constructor(options, diagnostics) {
186
189
  if (!options.apiKey) {
187
190
  throw new RuntimeClientError({
@@ -205,6 +208,8 @@ var RuntimeClient = class {
205
208
  ...DEFAULT_TIMEOUTS,
206
209
  ...options.timeouts || {}
207
210
  };
211
+ this.sendApiKeyHeader = process.env.WHISPER_SEND_X_API_KEY === "1";
212
+ this.fetchImpl = options.fetchImpl || fetch;
208
213
  this.diagnostics = diagnostics || new DiagnosticsStore(1e3);
209
214
  }
210
215
  getDiagnosticsStore() {
@@ -248,6 +253,16 @@ var RuntimeClient = class {
248
253
  const maybeWindow = globalThis.window;
249
254
  return maybeWindow && typeof maybeWindow === "object" ? "browser" : "node";
250
255
  }
256
+ apiKeyOnlyPrefixes() {
257
+ const raw = process.env.WHISPER_API_KEY_ONLY_PREFIXES;
258
+ if (!raw || !raw.trim()) return DEFAULT_API_KEY_ONLY_PREFIXES;
259
+ return raw.split(",").map((p) => p.trim()).filter((p) => p.length > 0);
260
+ }
261
+ shouldAttachApiKeyHeader(endpoint) {
262
+ if (this.sendApiKeyHeader) return true;
263
+ const prefixes = this.apiKeyOnlyPrefixes();
264
+ return prefixes.some((prefix) => endpoint === prefix || endpoint.startsWith(`${prefix}/`));
265
+ }
251
266
  createRequestFingerprint(options) {
252
267
  const normalizedEndpoint = normalizeEndpoint(options.endpoint);
253
268
  const authFingerprint = stableHash(this.apiKey.replace(/^Bearer\s+/i, ""));
@@ -314,14 +329,15 @@ var RuntimeClient = class {
314
329
  const controller = new AbortController();
315
330
  const timeout = setTimeout(() => controller.abort(), timeoutMs);
316
331
  try {
317
- const response = await fetch(`${this.baseUrl}${normalizedEndpoint}`, {
332
+ const attachApiKeyHeader = this.shouldAttachApiKeyHeader(normalizedEndpoint);
333
+ const response = await this.fetchImpl(`${this.baseUrl}${normalizedEndpoint}`, {
318
334
  method,
319
335
  signal: controller.signal,
320
336
  keepalive: method !== "GET",
321
337
  headers: {
322
338
  "Content-Type": "application/json",
323
339
  Authorization: this.apiKey.startsWith("Bearer ") ? this.apiKey : `Bearer ${this.apiKey}`,
324
- "X-API-Key": this.apiKey.replace(/^Bearer\s+/i, ""),
340
+ ...attachApiKeyHeader ? { "X-API-Key": this.apiKey.replace(/^Bearer\s+/i, "") } : {},
325
341
  "x-trace-id": traceId,
326
342
  "x-span-id": spanId,
327
343
  "x-sdk-version": this.sdkVersion,
@@ -1023,7 +1039,7 @@ var MemoryModule = class {
1023
1039
  async add(params) {
1024
1040
  const project = this.resolveProject(params.project);
1025
1041
  const queueEnabled = this.options.queueEnabled !== false;
1026
- const useQueue = queueEnabled && params.write_mode !== "sync" && params.async !== false;
1042
+ const useQueue = queueEnabled && (params.write_mode === "async" || params.async === true);
1027
1043
  if (useQueue) {
1028
1044
  const queued = await this.queue.enqueue({
1029
1045
  project,
@@ -1068,14 +1084,18 @@ var MemoryModule = class {
1068
1084
  metadata: params.metadata,
1069
1085
  document_date: params.document_date,
1070
1086
  event_date: params.event_date,
1071
- write_mode: "sync"
1087
+ write_mode: params.write_mode === "async" || params.async === true ? "async" : "sync"
1072
1088
  }
1073
1089
  });
1074
1090
  this.invalidate(project, params.user_id, params.session_id);
1075
1091
  return {
1076
1092
  success: true,
1077
1093
  mode: "sync",
1078
- trace_id: response.traceId
1094
+ trace_id: response.trace_id || response.traceId,
1095
+ memory_id: response.memory_id || response.memory?.id,
1096
+ semantic_status: response.semantic_status || response.memory?.semantic_status,
1097
+ pending_visibility: Boolean(response.pending_visibility),
1098
+ visibility_sla_ms: response.visibility_sla_ms
1079
1099
  };
1080
1100
  } catch (error) {
1081
1101
  if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
@@ -1113,7 +1133,7 @@ var MemoryModule = class {
1113
1133
  });
1114
1134
  }
1115
1135
  const queueEnabled = this.options.queueEnabled !== false;
1116
- const useQueue = queueEnabled && params.write_mode !== "sync" && params.async !== false;
1136
+ const useQueue = queueEnabled && (params.write_mode === "async" || params.async === true);
1117
1137
  if (useQueue) {
1118
1138
  const queued = await Promise.all(
1119
1139
  params.memories.map(
@@ -1157,7 +1177,7 @@ var MemoryModule = class {
1157
1177
  ...memory,
1158
1178
  memory_type: toSotaType(memory.memory_type)
1159
1179
  })),
1160
- write_mode: "sync"
1180
+ write_mode: params.write_mode === "async" || params.async === true ? "async" : "sync"
1161
1181
  }
1162
1182
  });
1163
1183
  for (const memory of params.memories) {
@@ -1318,6 +1338,28 @@ var MemoryModule = class {
1318
1338
  });
1319
1339
  return response.data;
1320
1340
  }
1341
+ async get(memoryId) {
1342
+ try {
1343
+ const response = await this.client.request({
1344
+ endpoint: `/v1/memory/${memoryId}`,
1345
+ method: "GET",
1346
+ operation: "get",
1347
+ idempotent: true
1348
+ });
1349
+ return response.data;
1350
+ } catch (error) {
1351
+ if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
1352
+ throw error;
1353
+ }
1354
+ const legacy = await this.client.request({
1355
+ endpoint: `/v1/memories/${memoryId}`,
1356
+ method: "GET",
1357
+ operation: "get",
1358
+ idempotent: true
1359
+ });
1360
+ return legacy.data;
1361
+ }
1362
+ }
1321
1363
  async update(memoryId, params) {
1322
1364
  try {
1323
1365
  await this.client.request({
@@ -1568,7 +1610,8 @@ var WhisperClient = class _WhisperClient {
1568
1610
  baseUrl: config.baseUrl,
1569
1611
  compatMode: config.compatMode || "fallback",
1570
1612
  timeouts: config.timeouts,
1571
- retryPolicy: config.retryPolicy
1613
+ retryPolicy: config.retryPolicy,
1614
+ fetchImpl: config.fetch
1572
1615
  },
1573
1616
  this.diagnosticsStore
1574
1617
  );
@@ -1672,6 +1715,7 @@ var WhisperClient = class _WhisperClient {
1672
1715
  add: (params) => this.memoryModule.add(params),
1673
1716
  addBulk: (params) => this.memoryModule.addBulk(params),
1674
1717
  search: (params) => this.memoryModule.search(params),
1718
+ get: (memoryId) => this.memoryModule.get(memoryId),
1675
1719
  getUserProfile: (params) => this.memoryModule.getUserProfile(params),
1676
1720
  getSessionMemories: (params) => this.memoryModule.getSessionMemories(params),
1677
1721
  update: (memoryId, params) => this.memoryModule.update(memoryId, params),
@@ -2345,7 +2389,7 @@ var WhisperContext = class _WhisperContext {
2345
2389
  });
2346
2390
  warnDeprecatedOnce2(
2347
2391
  "whisper_context_class",
2348
- "[Whisper SDK] WhisperContext remains supported in v2 but is legacy. Prefer WhisperClient for runtime features (queue/cache/session/diagnostics)."
2392
+ "[Whisper SDK] WhisperContext is deprecated in v3 and scheduled for removal in v4. Prefer WhisperClient for runtime features and future contract compatibility."
2349
2393
  );
2350
2394
  }
2351
2395
  withProject(project) {
@@ -2589,6 +2633,72 @@ var WhisperContext = class _WhisperContext {
2589
2633
  async syncSource(sourceId) {
2590
2634
  return this.request(`/v1/sources/${sourceId}/sync`, { method: "POST" });
2591
2635
  }
2636
+ async addSourceByType(projectId, params) {
2637
+ const resolvedProjectId = await this.resolveProjectId(projectId);
2638
+ return this.request(`/v1/projects/${resolvedProjectId}/add_source`, {
2639
+ method: "POST",
2640
+ body: JSON.stringify(params)
2641
+ });
2642
+ }
2643
+ async getSourceStatus(sourceId) {
2644
+ return this.request(`/v1/sources/${sourceId}/status`, { method: "GET" });
2645
+ }
2646
+ async createCanonicalSource(project, params) {
2647
+ const connector_type = params.type === "github" ? "github" : params.type === "web" ? "website" : params.type === "pdf" ? "pdf" : params.type === "local" ? "local-folder" : "slack";
2648
+ const config = {};
2649
+ if (params.type === "github") {
2650
+ if (!params.owner || !params.repo) throw new WhisperError({ code: "REQUEST_FAILED", message: "github source requires owner and repo" });
2651
+ config.owner = params.owner;
2652
+ config.repo = params.repo;
2653
+ if (params.branch) config.branch = params.branch;
2654
+ if (params.paths) config.paths = params.paths;
2655
+ } else if (params.type === "web") {
2656
+ if (!params.url) throw new WhisperError({ code: "REQUEST_FAILED", message: "web source requires url" });
2657
+ config.url = params.url;
2658
+ if (params.crawl_depth !== void 0) config.crawl_depth = params.crawl_depth;
2659
+ if (params.include_paths) config.include_paths = params.include_paths;
2660
+ if (params.exclude_paths) config.exclude_paths = params.exclude_paths;
2661
+ } else if (params.type === "pdf") {
2662
+ if (!params.url && !params.file_path) throw new WhisperError({ code: "REQUEST_FAILED", message: "pdf source requires url or file_path" });
2663
+ if (params.url) config.url = params.url;
2664
+ if (params.file_path) config.file_path = params.file_path;
2665
+ } else if (params.type === "local") {
2666
+ if (!params.path) throw new WhisperError({ code: "REQUEST_FAILED", message: "local source requires path" });
2667
+ config.path = params.path;
2668
+ if (params.glob) config.glob = params.glob;
2669
+ if (params.max_files !== void 0) config.max_files = params.max_files;
2670
+ } else {
2671
+ config.channel_ids = params.channel_ids || [];
2672
+ if (params.since) config.since = params.since;
2673
+ if (params.workspace_id) config.workspace_id = params.workspace_id;
2674
+ if (params.token) config.token = params.token;
2675
+ if (params.auth_ref) config.auth_ref = params.auth_ref;
2676
+ }
2677
+ if (params.metadata) config.metadata = params.metadata;
2678
+ if (params.ingestion_profile) config.ingestion_profile = params.ingestion_profile;
2679
+ if (params.strategy_override) config.strategy_override = params.strategy_override;
2680
+ if (params.profile_config) config.profile_config = params.profile_config;
2681
+ config.auto_index = params.auto_index ?? true;
2682
+ const created = await this.addSource(project, {
2683
+ name: params.name || `${params.type}-source-${Date.now()}`,
2684
+ connector_type,
2685
+ config
2686
+ });
2687
+ let status = "queued";
2688
+ let jobId = null;
2689
+ if (params.auto_index ?? true) {
2690
+ const syncRes = await this.syncSource(created.id);
2691
+ status = "indexing";
2692
+ jobId = String(syncRes?.id || syncRes?.job_id || "");
2693
+ }
2694
+ return {
2695
+ source_id: created.id,
2696
+ status,
2697
+ job_id: jobId,
2698
+ index_started: params.auto_index ?? true,
2699
+ warnings: []
2700
+ };
2701
+ }
2592
2702
  async ingest(projectId, documents) {
2593
2703
  const resolvedProjectId = await this.resolveProjectId(projectId);
2594
2704
  return this.request(`/v1/projects/${resolvedProjectId}/ingest`, {
@@ -2649,15 +2759,42 @@ var WhisperContext = class _WhisperContext {
2649
2759
  importance: params.importance,
2650
2760
  metadata: params.metadata,
2651
2761
  async: params.async,
2652
- write_mode: params.write_mode
2762
+ write_mode: params.write_mode || (params.async === true ? "async" : "sync")
2653
2763
  })
2654
2764
  });
2655
- const id2 = direct?.memory?.id || direct?.id || direct?.memory_id || direct?.job_id;
2765
+ const mode = direct?.mode === "async" ? "async" : direct?.mode === "sync" ? "sync" : void 0;
2766
+ const memoryId = direct?.memory?.id || direct?.memory_id || (mode !== "async" ? direct?.id : void 0);
2767
+ const jobId = direct?.job_id || (mode === "async" ? direct?.id : void 0);
2768
+ const id2 = memoryId || jobId || "";
2656
2769
  if (id2) {
2657
- return { id: id2, success: true, path: "sota", fallback_used: false };
2770
+ return {
2771
+ id: id2,
2772
+ success: true,
2773
+ path: "sota",
2774
+ fallback_used: false,
2775
+ mode,
2776
+ ...memoryId ? { memory_id: memoryId } : {},
2777
+ ...jobId ? { job_id: jobId } : {},
2778
+ ...direct?.status_url ? { status_url: direct.status_url } : {},
2779
+ ...direct?.accepted_at ? { accepted_at: direct.accepted_at } : {},
2780
+ ...direct?.visibility_sla_ms ? { visibility_sla_ms: direct.visibility_sla_ms } : {},
2781
+ ...direct?.pending_visibility !== void 0 ? { pending_visibility: Boolean(direct.pending_visibility) } : {},
2782
+ ...direct?.semantic_status ? { semantic_status: direct.semantic_status } : {}
2783
+ };
2658
2784
  }
2659
2785
  if (direct?.success === true) {
2660
- return { id: "", success: true, path: "sota", fallback_used: false };
2786
+ return {
2787
+ id: "",
2788
+ success: true,
2789
+ path: "sota",
2790
+ fallback_used: false,
2791
+ mode,
2792
+ ...direct?.status_url ? { status_url: direct.status_url } : {},
2793
+ ...direct?.accepted_at ? { accepted_at: direct.accepted_at } : {},
2794
+ ...direct?.visibility_sla_ms ? { visibility_sla_ms: direct.visibility_sla_ms } : {},
2795
+ ...direct?.pending_visibility !== void 0 ? { pending_visibility: Boolean(direct.pending_visibility) } : {},
2796
+ ...direct?.semantic_status ? { semantic_status: direct.semantic_status } : {}
2797
+ };
2661
2798
  }
2662
2799
  } catch (error) {
2663
2800
  if (params.allow_legacy_fallback === false) {
@@ -2685,7 +2822,15 @@ var WhisperContext = class _WhisperContext {
2685
2822
  message: "Memory create succeeded but no memory id was returned by the API"
2686
2823
  });
2687
2824
  }
2688
- return { id, success: true, path: "legacy", fallback_used: true };
2825
+ return {
2826
+ id,
2827
+ success: true,
2828
+ path: "legacy",
2829
+ fallback_used: true,
2830
+ mode: "sync",
2831
+ memory_id: id,
2832
+ semantic_status: "ready"
2833
+ };
2689
2834
  });
2690
2835
  }
2691
2836
  async addMemoriesBulk(params) {
@@ -2884,6 +3029,16 @@ var WhisperContext = class _WhisperContext {
2884
3029
  }
2885
3030
  });
2886
3031
  }
3032
+ async getMemory(memoryId) {
3033
+ try {
3034
+ return await this.request(`/v1/memory/${memoryId}`);
3035
+ } catch (error) {
3036
+ if (!this.isEndpointNotFoundError(error)) {
3037
+ throw error;
3038
+ }
3039
+ return this.request(`/v1/memories/${memoryId}`);
3040
+ }
3041
+ }
2887
3042
  async getMemoryVersions(memoryId) {
2888
3043
  return this.request(`/v1/memory/${memoryId}/versions`);
2889
3044
  }
@@ -3066,8 +3221,11 @@ var WhisperContext = class _WhisperContext {
3066
3221
  };
3067
3222
  sources = {
3068
3223
  add: (projectId, params) => this.addSource(projectId, params),
3224
+ addSource: (projectId, params) => this.addSourceByType(projectId, params),
3069
3225
  sync: (sourceId) => this.syncSource(sourceId),
3070
- syncSource: (sourceId) => this.syncSource(sourceId)
3226
+ syncSource: (sourceId) => this.syncSource(sourceId),
3227
+ status: (sourceId) => this.getSourceStatus(sourceId),
3228
+ getStatus: (sourceId) => this.getSourceStatus(sourceId)
3071
3229
  };
3072
3230
  memory = {
3073
3231
  add: (params) => this.addMemory(params),
@@ -3079,6 +3237,7 @@ var WhisperContext = class _WhisperContext {
3079
3237
  ingestSession: (params) => this.ingestSession(params),
3080
3238
  getSessionMemories: (params) => this.getSessionMemories(params),
3081
3239
  getUserProfile: (params) => this.getUserProfile(params),
3240
+ get: (memoryId) => this.getMemory(memoryId),
3082
3241
  getVersions: (memoryId) => this.getMemoryVersions(memoryId),
3083
3242
  update: (memoryId, params) => this.updateMemory(memoryId, params),
3084
3243
  delete: (memoryId) => this.deleteMemory(memoryId),
package/index.mjs CHANGED
@@ -85,6 +85,7 @@ var DEFAULT_TIMEOUTS = {
85
85
  sessionMs: 2500
86
86
  };
87
87
  var DEFAULT_RETRYABLE_STATUS = [408, 429, 500, 502, 503, 504];
88
+ var DEFAULT_API_KEY_ONLY_PREFIXES = ["/v1/memory", "/v1/context/query"];
88
89
  var DEFAULT_RETRY_ATTEMPTS = {
89
90
  search: 3,
90
91
  writeAck: 2,
@@ -133,6 +134,8 @@ var RuntimeClient = class {
133
134
  timeouts;
134
135
  diagnostics;
135
136
  inFlight = /* @__PURE__ */ new Map();
137
+ sendApiKeyHeader;
138
+ fetchImpl;
136
139
  constructor(options, diagnostics) {
137
140
  if (!options.apiKey) {
138
141
  throw new RuntimeClientError({
@@ -156,6 +159,8 @@ var RuntimeClient = class {
156
159
  ...DEFAULT_TIMEOUTS,
157
160
  ...options.timeouts || {}
158
161
  };
162
+ this.sendApiKeyHeader = process.env.WHISPER_SEND_X_API_KEY === "1";
163
+ this.fetchImpl = options.fetchImpl || fetch;
159
164
  this.diagnostics = diagnostics || new DiagnosticsStore(1e3);
160
165
  }
161
166
  getDiagnosticsStore() {
@@ -199,6 +204,16 @@ var RuntimeClient = class {
199
204
  const maybeWindow = globalThis.window;
200
205
  return maybeWindow && typeof maybeWindow === "object" ? "browser" : "node";
201
206
  }
207
+ apiKeyOnlyPrefixes() {
208
+ const raw = process.env.WHISPER_API_KEY_ONLY_PREFIXES;
209
+ if (!raw || !raw.trim()) return DEFAULT_API_KEY_ONLY_PREFIXES;
210
+ return raw.split(",").map((p) => p.trim()).filter((p) => p.length > 0);
211
+ }
212
+ shouldAttachApiKeyHeader(endpoint) {
213
+ if (this.sendApiKeyHeader) return true;
214
+ const prefixes = this.apiKeyOnlyPrefixes();
215
+ return prefixes.some((prefix) => endpoint === prefix || endpoint.startsWith(`${prefix}/`));
216
+ }
202
217
  createRequestFingerprint(options) {
203
218
  const normalizedEndpoint = normalizeEndpoint(options.endpoint);
204
219
  const authFingerprint = stableHash(this.apiKey.replace(/^Bearer\s+/i, ""));
@@ -265,14 +280,15 @@ var RuntimeClient = class {
265
280
  const controller = new AbortController();
266
281
  const timeout = setTimeout(() => controller.abort(), timeoutMs);
267
282
  try {
268
- const response = await fetch(`${this.baseUrl}${normalizedEndpoint}`, {
283
+ const attachApiKeyHeader = this.shouldAttachApiKeyHeader(normalizedEndpoint);
284
+ const response = await this.fetchImpl(`${this.baseUrl}${normalizedEndpoint}`, {
269
285
  method,
270
286
  signal: controller.signal,
271
287
  keepalive: method !== "GET",
272
288
  headers: {
273
289
  "Content-Type": "application/json",
274
290
  Authorization: this.apiKey.startsWith("Bearer ") ? this.apiKey : `Bearer ${this.apiKey}`,
275
- "X-API-Key": this.apiKey.replace(/^Bearer\s+/i, ""),
291
+ ...attachApiKeyHeader ? { "X-API-Key": this.apiKey.replace(/^Bearer\s+/i, "") } : {},
276
292
  "x-trace-id": traceId,
277
293
  "x-span-id": spanId,
278
294
  "x-sdk-version": this.sdkVersion,
@@ -974,7 +990,7 @@ var MemoryModule = class {
974
990
  async add(params) {
975
991
  const project = this.resolveProject(params.project);
976
992
  const queueEnabled = this.options.queueEnabled !== false;
977
- const useQueue = queueEnabled && params.write_mode !== "sync" && params.async !== false;
993
+ const useQueue = queueEnabled && (params.write_mode === "async" || params.async === true);
978
994
  if (useQueue) {
979
995
  const queued = await this.queue.enqueue({
980
996
  project,
@@ -1019,14 +1035,18 @@ var MemoryModule = class {
1019
1035
  metadata: params.metadata,
1020
1036
  document_date: params.document_date,
1021
1037
  event_date: params.event_date,
1022
- write_mode: "sync"
1038
+ write_mode: params.write_mode === "async" || params.async === true ? "async" : "sync"
1023
1039
  }
1024
1040
  });
1025
1041
  this.invalidate(project, params.user_id, params.session_id);
1026
1042
  return {
1027
1043
  success: true,
1028
1044
  mode: "sync",
1029
- trace_id: response.traceId
1045
+ trace_id: response.trace_id || response.traceId,
1046
+ memory_id: response.memory_id || response.memory?.id,
1047
+ semantic_status: response.semantic_status || response.memory?.semantic_status,
1048
+ pending_visibility: Boolean(response.pending_visibility),
1049
+ visibility_sla_ms: response.visibility_sla_ms
1030
1050
  };
1031
1051
  } catch (error) {
1032
1052
  if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
@@ -1064,7 +1084,7 @@ var MemoryModule = class {
1064
1084
  });
1065
1085
  }
1066
1086
  const queueEnabled = this.options.queueEnabled !== false;
1067
- const useQueue = queueEnabled && params.write_mode !== "sync" && params.async !== false;
1087
+ const useQueue = queueEnabled && (params.write_mode === "async" || params.async === true);
1068
1088
  if (useQueue) {
1069
1089
  const queued = await Promise.all(
1070
1090
  params.memories.map(
@@ -1108,7 +1128,7 @@ var MemoryModule = class {
1108
1128
  ...memory,
1109
1129
  memory_type: toSotaType(memory.memory_type)
1110
1130
  })),
1111
- write_mode: "sync"
1131
+ write_mode: params.write_mode === "async" || params.async === true ? "async" : "sync"
1112
1132
  }
1113
1133
  });
1114
1134
  for (const memory of params.memories) {
@@ -1269,6 +1289,28 @@ var MemoryModule = class {
1269
1289
  });
1270
1290
  return response.data;
1271
1291
  }
1292
+ async get(memoryId) {
1293
+ try {
1294
+ const response = await this.client.request({
1295
+ endpoint: `/v1/memory/${memoryId}`,
1296
+ method: "GET",
1297
+ operation: "get",
1298
+ idempotent: true
1299
+ });
1300
+ return response.data;
1301
+ } catch (error) {
1302
+ if (this.client.getCompatMode() !== "fallback" || !isEndpointNotFound(error)) {
1303
+ throw error;
1304
+ }
1305
+ const legacy = await this.client.request({
1306
+ endpoint: `/v1/memories/${memoryId}`,
1307
+ method: "GET",
1308
+ operation: "get",
1309
+ idempotent: true
1310
+ });
1311
+ return legacy.data;
1312
+ }
1313
+ }
1272
1314
  async update(memoryId, params) {
1273
1315
  try {
1274
1316
  await this.client.request({
@@ -1519,7 +1561,8 @@ var WhisperClient = class _WhisperClient {
1519
1561
  baseUrl: config.baseUrl,
1520
1562
  compatMode: config.compatMode || "fallback",
1521
1563
  timeouts: config.timeouts,
1522
- retryPolicy: config.retryPolicy
1564
+ retryPolicy: config.retryPolicy,
1565
+ fetchImpl: config.fetch
1523
1566
  },
1524
1567
  this.diagnosticsStore
1525
1568
  );
@@ -1623,6 +1666,7 @@ var WhisperClient = class _WhisperClient {
1623
1666
  add: (params) => this.memoryModule.add(params),
1624
1667
  addBulk: (params) => this.memoryModule.addBulk(params),
1625
1668
  search: (params) => this.memoryModule.search(params),
1669
+ get: (memoryId) => this.memoryModule.get(memoryId),
1626
1670
  getUserProfile: (params) => this.memoryModule.getUserProfile(params),
1627
1671
  getSessionMemories: (params) => this.memoryModule.getSessionMemories(params),
1628
1672
  update: (memoryId, params) => this.memoryModule.update(memoryId, params),
@@ -2296,7 +2340,7 @@ var WhisperContext = class _WhisperContext {
2296
2340
  });
2297
2341
  warnDeprecatedOnce2(
2298
2342
  "whisper_context_class",
2299
- "[Whisper SDK] WhisperContext remains supported in v2 but is legacy. Prefer WhisperClient for runtime features (queue/cache/session/diagnostics)."
2343
+ "[Whisper SDK] WhisperContext is deprecated in v3 and scheduled for removal in v4. Prefer WhisperClient for runtime features and future contract compatibility."
2300
2344
  );
2301
2345
  }
2302
2346
  withProject(project) {
@@ -2540,6 +2584,72 @@ var WhisperContext = class _WhisperContext {
2540
2584
  async syncSource(sourceId) {
2541
2585
  return this.request(`/v1/sources/${sourceId}/sync`, { method: "POST" });
2542
2586
  }
2587
+ async addSourceByType(projectId, params) {
2588
+ const resolvedProjectId = await this.resolveProjectId(projectId);
2589
+ return this.request(`/v1/projects/${resolvedProjectId}/add_source`, {
2590
+ method: "POST",
2591
+ body: JSON.stringify(params)
2592
+ });
2593
+ }
2594
+ async getSourceStatus(sourceId) {
2595
+ return this.request(`/v1/sources/${sourceId}/status`, { method: "GET" });
2596
+ }
2597
+ async createCanonicalSource(project, params) {
2598
+ const connector_type = params.type === "github" ? "github" : params.type === "web" ? "website" : params.type === "pdf" ? "pdf" : params.type === "local" ? "local-folder" : "slack";
2599
+ const config = {};
2600
+ if (params.type === "github") {
2601
+ if (!params.owner || !params.repo) throw new WhisperError({ code: "REQUEST_FAILED", message: "github source requires owner and repo" });
2602
+ config.owner = params.owner;
2603
+ config.repo = params.repo;
2604
+ if (params.branch) config.branch = params.branch;
2605
+ if (params.paths) config.paths = params.paths;
2606
+ } else if (params.type === "web") {
2607
+ if (!params.url) throw new WhisperError({ code: "REQUEST_FAILED", message: "web source requires url" });
2608
+ config.url = params.url;
2609
+ if (params.crawl_depth !== void 0) config.crawl_depth = params.crawl_depth;
2610
+ if (params.include_paths) config.include_paths = params.include_paths;
2611
+ if (params.exclude_paths) config.exclude_paths = params.exclude_paths;
2612
+ } else if (params.type === "pdf") {
2613
+ if (!params.url && !params.file_path) throw new WhisperError({ code: "REQUEST_FAILED", message: "pdf source requires url or file_path" });
2614
+ if (params.url) config.url = params.url;
2615
+ if (params.file_path) config.file_path = params.file_path;
2616
+ } else if (params.type === "local") {
2617
+ if (!params.path) throw new WhisperError({ code: "REQUEST_FAILED", message: "local source requires path" });
2618
+ config.path = params.path;
2619
+ if (params.glob) config.glob = params.glob;
2620
+ if (params.max_files !== void 0) config.max_files = params.max_files;
2621
+ } else {
2622
+ config.channel_ids = params.channel_ids || [];
2623
+ if (params.since) config.since = params.since;
2624
+ if (params.workspace_id) config.workspace_id = params.workspace_id;
2625
+ if (params.token) config.token = params.token;
2626
+ if (params.auth_ref) config.auth_ref = params.auth_ref;
2627
+ }
2628
+ if (params.metadata) config.metadata = params.metadata;
2629
+ if (params.ingestion_profile) config.ingestion_profile = params.ingestion_profile;
2630
+ if (params.strategy_override) config.strategy_override = params.strategy_override;
2631
+ if (params.profile_config) config.profile_config = params.profile_config;
2632
+ config.auto_index = params.auto_index ?? true;
2633
+ const created = await this.addSource(project, {
2634
+ name: params.name || `${params.type}-source-${Date.now()}`,
2635
+ connector_type,
2636
+ config
2637
+ });
2638
+ let status = "queued";
2639
+ let jobId = null;
2640
+ if (params.auto_index ?? true) {
2641
+ const syncRes = await this.syncSource(created.id);
2642
+ status = "indexing";
2643
+ jobId = String(syncRes?.id || syncRes?.job_id || "");
2644
+ }
2645
+ return {
2646
+ source_id: created.id,
2647
+ status,
2648
+ job_id: jobId,
2649
+ index_started: params.auto_index ?? true,
2650
+ warnings: []
2651
+ };
2652
+ }
2543
2653
  async ingest(projectId, documents) {
2544
2654
  const resolvedProjectId = await this.resolveProjectId(projectId);
2545
2655
  return this.request(`/v1/projects/${resolvedProjectId}/ingest`, {
@@ -2600,15 +2710,42 @@ var WhisperContext = class _WhisperContext {
2600
2710
  importance: params.importance,
2601
2711
  metadata: params.metadata,
2602
2712
  async: params.async,
2603
- write_mode: params.write_mode
2713
+ write_mode: params.write_mode || (params.async === true ? "async" : "sync")
2604
2714
  })
2605
2715
  });
2606
- const id2 = direct?.memory?.id || direct?.id || direct?.memory_id || direct?.job_id;
2716
+ const mode = direct?.mode === "async" ? "async" : direct?.mode === "sync" ? "sync" : void 0;
2717
+ const memoryId = direct?.memory?.id || direct?.memory_id || (mode !== "async" ? direct?.id : void 0);
2718
+ const jobId = direct?.job_id || (mode === "async" ? direct?.id : void 0);
2719
+ const id2 = memoryId || jobId || "";
2607
2720
  if (id2) {
2608
- return { id: id2, success: true, path: "sota", fallback_used: false };
2721
+ return {
2722
+ id: id2,
2723
+ success: true,
2724
+ path: "sota",
2725
+ fallback_used: false,
2726
+ mode,
2727
+ ...memoryId ? { memory_id: memoryId } : {},
2728
+ ...jobId ? { job_id: jobId } : {},
2729
+ ...direct?.status_url ? { status_url: direct.status_url } : {},
2730
+ ...direct?.accepted_at ? { accepted_at: direct.accepted_at } : {},
2731
+ ...direct?.visibility_sla_ms ? { visibility_sla_ms: direct.visibility_sla_ms } : {},
2732
+ ...direct?.pending_visibility !== void 0 ? { pending_visibility: Boolean(direct.pending_visibility) } : {},
2733
+ ...direct?.semantic_status ? { semantic_status: direct.semantic_status } : {}
2734
+ };
2609
2735
  }
2610
2736
  if (direct?.success === true) {
2611
- return { id: "", success: true, path: "sota", fallback_used: false };
2737
+ return {
2738
+ id: "",
2739
+ success: true,
2740
+ path: "sota",
2741
+ fallback_used: false,
2742
+ mode,
2743
+ ...direct?.status_url ? { status_url: direct.status_url } : {},
2744
+ ...direct?.accepted_at ? { accepted_at: direct.accepted_at } : {},
2745
+ ...direct?.visibility_sla_ms ? { visibility_sla_ms: direct.visibility_sla_ms } : {},
2746
+ ...direct?.pending_visibility !== void 0 ? { pending_visibility: Boolean(direct.pending_visibility) } : {},
2747
+ ...direct?.semantic_status ? { semantic_status: direct.semantic_status } : {}
2748
+ };
2612
2749
  }
2613
2750
  } catch (error) {
2614
2751
  if (params.allow_legacy_fallback === false) {
@@ -2636,7 +2773,15 @@ var WhisperContext = class _WhisperContext {
2636
2773
  message: "Memory create succeeded but no memory id was returned by the API"
2637
2774
  });
2638
2775
  }
2639
- return { id, success: true, path: "legacy", fallback_used: true };
2776
+ return {
2777
+ id,
2778
+ success: true,
2779
+ path: "legacy",
2780
+ fallback_used: true,
2781
+ mode: "sync",
2782
+ memory_id: id,
2783
+ semantic_status: "ready"
2784
+ };
2640
2785
  });
2641
2786
  }
2642
2787
  async addMemoriesBulk(params) {
@@ -2835,6 +2980,16 @@ var WhisperContext = class _WhisperContext {
2835
2980
  }
2836
2981
  });
2837
2982
  }
2983
+ async getMemory(memoryId) {
2984
+ try {
2985
+ return await this.request(`/v1/memory/${memoryId}`);
2986
+ } catch (error) {
2987
+ if (!this.isEndpointNotFoundError(error)) {
2988
+ throw error;
2989
+ }
2990
+ return this.request(`/v1/memories/${memoryId}`);
2991
+ }
2992
+ }
2838
2993
  async getMemoryVersions(memoryId) {
2839
2994
  return this.request(`/v1/memory/${memoryId}/versions`);
2840
2995
  }
@@ -3017,8 +3172,11 @@ var WhisperContext = class _WhisperContext {
3017
3172
  };
3018
3173
  sources = {
3019
3174
  add: (projectId, params) => this.addSource(projectId, params),
3175
+ addSource: (projectId, params) => this.addSourceByType(projectId, params),
3020
3176
  sync: (sourceId) => this.syncSource(sourceId),
3021
- syncSource: (sourceId) => this.syncSource(sourceId)
3177
+ syncSource: (sourceId) => this.syncSource(sourceId),
3178
+ status: (sourceId) => this.getSourceStatus(sourceId),
3179
+ getStatus: (sourceId) => this.getSourceStatus(sourceId)
3022
3180
  };
3023
3181
  memory = {
3024
3182
  add: (params) => this.addMemory(params),
@@ -3030,6 +3188,7 @@ var WhisperContext = class _WhisperContext {
3030
3188
  ingestSession: (params) => this.ingestSession(params),
3031
3189
  getSessionMemories: (params) => this.getSessionMemories(params),
3032
3190
  getUserProfile: (params) => this.getUserProfile(params),
3191
+ get: (memoryId) => this.getMemory(memoryId),
3033
3192
  getVersions: (memoryId) => this.getMemoryVersions(memoryId),
3034
3193
  update: (memoryId, params) => this.updateMemory(memoryId, params),
3035
3194
  delete: (memoryId) => this.deleteMemory(memoryId),
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@usewhisper/sdk",
3
- "version": "3.0.0",
3
+ "version": "3.2.0",
4
+ "whisperContractVersion": "2026.03.09",
4
5
  "scripts": {
5
6
  "build": "tsup ../src/sdk/index.ts --format esm,cjs --dts --out-dir .",
6
7
  "prepublishOnly": "npm run build"