@contractspec/lib.knowledge 1.46.2 → 1.47.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.
@@ -1 +1 @@
1
- {"version":3,"file":"guard.js","names":["DEFAULT_DISALLOWED_WRITE: KnowledgeCategory[]"],"sources":["../../src/access/guard.ts"],"sourcesContent":["import type {\n ResolvedAppConfig,\n ResolvedKnowledge,\n KnowledgeCategory,\n} from '@contractspec/lib.contracts';\nimport type { KnowledgeAccessContext, KnowledgeAccessResult } from '../types';\n\nexport interface KnowledgeAccessGuardOptions {\n disallowWriteCategories?: KnowledgeCategory[];\n requireWorkflowBinding?: boolean;\n requireAgentBinding?: boolean;\n}\n\nconst DEFAULT_DISALLOWED_WRITE: KnowledgeCategory[] = ['external', 'ephemeral'];\n\nexport class KnowledgeAccessGuard {\n private readonly disallowedWrite: Set<KnowledgeCategory>;\n private readonly requireWorkflowBinding: boolean;\n private readonly requireAgentBinding: boolean;\n\n constructor(options: KnowledgeAccessGuardOptions = {}) {\n this.disallowedWrite = new Set(\n options.disallowWriteCategories ?? DEFAULT_DISALLOWED_WRITE\n );\n this.requireWorkflowBinding = options.requireWorkflowBinding ?? true;\n this.requireAgentBinding = options.requireAgentBinding ?? false;\n }\n\n checkAccess(\n spaceBinding: ResolvedKnowledge,\n context: KnowledgeAccessContext,\n appConfig: ResolvedAppConfig\n ): KnowledgeAccessResult {\n const { binding, space } = spaceBinding;\n\n if (\n binding.required !== false &&\n !this.isSpaceBound(spaceBinding, appConfig)\n ) {\n return {\n allowed: false,\n reason: `Knowledge space \"${space.meta.key}\" is not bound in the resolved app config.`,\n };\n }\n\n if (\n context.operation === 'write' &&\n this.disallowedWrite.has(space.meta.category)\n ) {\n return {\n allowed: false,\n reason: `Knowledge space \"${space.meta.key}\" is category \"${space.meta.category}\" and is read-only.`,\n };\n }\n\n if (this.requireWorkflowBinding && context.workflowName) {\n const allowedWorkflows = binding.scope?.workflows;\n if (\n allowedWorkflows &&\n !allowedWorkflows.includes(context.workflowName)\n ) {\n return {\n allowed: false,\n reason: `Workflow \"${context.workflowName}\" is not authorized to access knowledge space \"${space.meta.key}\".`,\n };\n }\n }\n\n if (this.requireAgentBinding && context.agentName) {\n const allowedAgents = binding.scope?.agents;\n if (allowedAgents && !allowedAgents.includes(context.agentName)) {\n return {\n allowed: false,\n reason: `Agent \"${context.agentName}\" is not authorized to access knowledge space \"${space.meta.key}\".`,\n };\n }\n }\n\n if (space.meta.category === 'ephemeral') {\n return {\n allowed: true,\n severity: 'warning',\n reason: `Knowledge space \"${space.meta.key}\" is ephemeral; results may be transient.`,\n };\n }\n\n return { allowed: true };\n }\n\n private isSpaceBound(\n resolved: ResolvedKnowledge,\n appConfig: ResolvedAppConfig\n ): boolean {\n return appConfig.knowledge.some(\n (entry) =>\n entry.space.meta.key === resolved.space.meta.key &&\n (resolved.space.meta.version == null ||\n entry.space.meta.version === resolved.space.meta.version)\n );\n }\n}\n"],"mappings":";AAaA,MAAMA,2BAAgD,CAAC,YAAY,YAAY;AAE/E,IAAa,uBAAb,MAAkC;CAChC,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YAAY,UAAuC,EAAE,EAAE;AACrD,OAAK,kBAAkB,IAAI,IACzB,QAAQ,2BAA2B,yBACpC;AACD,OAAK,yBAAyB,QAAQ,0BAA0B;AAChE,OAAK,sBAAsB,QAAQ,uBAAuB;;CAG5D,YACE,cACA,SACA,WACuB;EACvB,MAAM,EAAE,SAAS,UAAU;AAE3B,MACE,QAAQ,aAAa,SACrB,CAAC,KAAK,aAAa,cAAc,UAAU,CAE3C,QAAO;GACL,SAAS;GACT,QAAQ,oBAAoB,MAAM,KAAK,IAAI;GAC5C;AAGH,MACE,QAAQ,cAAc,WACtB,KAAK,gBAAgB,IAAI,MAAM,KAAK,SAAS,CAE7C,QAAO;GACL,SAAS;GACT,QAAQ,oBAAoB,MAAM,KAAK,IAAI,iBAAiB,MAAM,KAAK,SAAS;GACjF;AAGH,MAAI,KAAK,0BAA0B,QAAQ,cAAc;GACvD,MAAM,mBAAmB,QAAQ,OAAO;AACxC,OACE,oBACA,CAAC,iBAAiB,SAAS,QAAQ,aAAa,CAEhD,QAAO;IACL,SAAS;IACT,QAAQ,aAAa,QAAQ,aAAa,iDAAiD,MAAM,KAAK,IAAI;IAC3G;;AAIL,MAAI,KAAK,uBAAuB,QAAQ,WAAW;GACjD,MAAM,gBAAgB,QAAQ,OAAO;AACrC,OAAI,iBAAiB,CAAC,cAAc,SAAS,QAAQ,UAAU,CAC7D,QAAO;IACL,SAAS;IACT,QAAQ,UAAU,QAAQ,UAAU,iDAAiD,MAAM,KAAK,IAAI;IACrG;;AAIL,MAAI,MAAM,KAAK,aAAa,YAC1B,QAAO;GACL,SAAS;GACT,UAAU;GACV,QAAQ,oBAAoB,MAAM,KAAK,IAAI;GAC5C;AAGH,SAAO,EAAE,SAAS,MAAM;;CAG1B,AAAQ,aACN,UACA,WACS;AACT,SAAO,UAAU,UAAU,MACxB,UACC,MAAM,MAAM,KAAK,QAAQ,SAAS,MAAM,KAAK,QAC5C,SAAS,MAAM,KAAK,WAAW,QAC9B,MAAM,MAAM,KAAK,YAAY,SAAS,MAAM,KAAK,SACtD"}
1
+ {"version":3,"file":"guard.js","names":[],"sources":["../../src/access/guard.ts"],"sourcesContent":["import type {\n ResolvedAppConfig,\n ResolvedKnowledge,\n KnowledgeCategory,\n} from '@contractspec/lib.contracts';\nimport type { KnowledgeAccessContext, KnowledgeAccessResult } from '../types';\n\nexport interface KnowledgeAccessGuardOptions {\n disallowWriteCategories?: KnowledgeCategory[];\n requireWorkflowBinding?: boolean;\n requireAgentBinding?: boolean;\n}\n\nconst DEFAULT_DISALLOWED_WRITE: KnowledgeCategory[] = ['external', 'ephemeral'];\n\nexport class KnowledgeAccessGuard {\n private readonly disallowedWrite: Set<KnowledgeCategory>;\n private readonly requireWorkflowBinding: boolean;\n private readonly requireAgentBinding: boolean;\n\n constructor(options: KnowledgeAccessGuardOptions = {}) {\n this.disallowedWrite = new Set(\n options.disallowWriteCategories ?? DEFAULT_DISALLOWED_WRITE\n );\n this.requireWorkflowBinding = options.requireWorkflowBinding ?? true;\n this.requireAgentBinding = options.requireAgentBinding ?? false;\n }\n\n checkAccess(\n spaceBinding: ResolvedKnowledge,\n context: KnowledgeAccessContext,\n appConfig: ResolvedAppConfig\n ): KnowledgeAccessResult {\n const { binding, space } = spaceBinding;\n\n if (\n binding.required !== false &&\n !this.isSpaceBound(spaceBinding, appConfig)\n ) {\n return {\n allowed: false,\n reason: `Knowledge space \"${space.meta.key}\" is not bound in the resolved app config.`,\n };\n }\n\n if (\n context.operation === 'write' &&\n this.disallowedWrite.has(space.meta.category)\n ) {\n return {\n allowed: false,\n reason: `Knowledge space \"${space.meta.key}\" is category \"${space.meta.category}\" and is read-only.`,\n };\n }\n\n if (this.requireWorkflowBinding && context.workflowName) {\n const allowedWorkflows = binding.scope?.workflows;\n if (\n allowedWorkflows &&\n !allowedWorkflows.includes(context.workflowName)\n ) {\n return {\n allowed: false,\n reason: `Workflow \"${context.workflowName}\" is not authorized to access knowledge space \"${space.meta.key}\".`,\n };\n }\n }\n\n if (this.requireAgentBinding && context.agentName) {\n const allowedAgents = binding.scope?.agents;\n if (allowedAgents && !allowedAgents.includes(context.agentName)) {\n return {\n allowed: false,\n reason: `Agent \"${context.agentName}\" is not authorized to access knowledge space \"${space.meta.key}\".`,\n };\n }\n }\n\n if (space.meta.category === 'ephemeral') {\n return {\n allowed: true,\n severity: 'warning',\n reason: `Knowledge space \"${space.meta.key}\" is ephemeral; results may be transient.`,\n };\n }\n\n return { allowed: true };\n }\n\n private isSpaceBound(\n resolved: ResolvedKnowledge,\n appConfig: ResolvedAppConfig\n ): boolean {\n return appConfig.knowledge.some(\n (entry) =>\n entry.space.meta.key === resolved.space.meta.key &&\n (resolved.space.meta.version == null ||\n entry.space.meta.version === resolved.space.meta.version)\n );\n }\n}\n"],"mappings":";AAaA,MAAM,2BAAgD,CAAC,YAAY,YAAY;AAE/E,IAAa,uBAAb,MAAkC;CAChC,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,YAAY,UAAuC,EAAE,EAAE;AACrD,OAAK,kBAAkB,IAAI,IACzB,QAAQ,2BAA2B,yBACpC;AACD,OAAK,yBAAyB,QAAQ,0BAA0B;AAChE,OAAK,sBAAsB,QAAQ,uBAAuB;;CAG5D,YACE,cACA,SACA,WACuB;EACvB,MAAM,EAAE,SAAS,UAAU;AAE3B,MACE,QAAQ,aAAa,SACrB,CAAC,KAAK,aAAa,cAAc,UAAU,CAE3C,QAAO;GACL,SAAS;GACT,QAAQ,oBAAoB,MAAM,KAAK,IAAI;GAC5C;AAGH,MACE,QAAQ,cAAc,WACtB,KAAK,gBAAgB,IAAI,MAAM,KAAK,SAAS,CAE7C,QAAO;GACL,SAAS;GACT,QAAQ,oBAAoB,MAAM,KAAK,IAAI,iBAAiB,MAAM,KAAK,SAAS;GACjF;AAGH,MAAI,KAAK,0BAA0B,QAAQ,cAAc;GACvD,MAAM,mBAAmB,QAAQ,OAAO;AACxC,OACE,oBACA,CAAC,iBAAiB,SAAS,QAAQ,aAAa,CAEhD,QAAO;IACL,SAAS;IACT,QAAQ,aAAa,QAAQ,aAAa,iDAAiD,MAAM,KAAK,IAAI;IAC3G;;AAIL,MAAI,KAAK,uBAAuB,QAAQ,WAAW;GACjD,MAAM,gBAAgB,QAAQ,OAAO;AACrC,OAAI,iBAAiB,CAAC,cAAc,SAAS,QAAQ,UAAU,CAC7D,QAAO;IACL,SAAS;IACT,QAAQ,UAAU,QAAQ,UAAU,iDAAiD,MAAM,KAAK,IAAI;IACrG;;AAIL,MAAI,MAAM,KAAK,aAAa,YAC1B,QAAO;GACL,SAAS;GACT,UAAU;GACV,QAAQ,oBAAoB,MAAM,KAAK,IAAI;GAC5C;AAGH,SAAO,EAAE,SAAS,MAAM;;CAG1B,AAAQ,aACN,UACA,WACS;AACT,SAAO,UAAU,UAAU,MACxB,UACC,MAAM,MAAM,KAAK,QAAQ,SAAS,MAAM,KAAK,QAC5C,SAAS,MAAM,KAAK,WAAW,QAC9B,MAAM,MAAM,KAAK,YAAY,SAAS,MAAM,KAAK,SACtD"}
@@ -1 +1 @@
1
- {"version":3,"file":"embedding-service.js","names":["results: EmbeddingResult[]","documents: EmbeddingDocument[]"],"sources":["../../src/ingestion/embedding-service.ts"],"sourcesContent":["import type {\n EmbeddingDocument,\n EmbeddingProvider,\n EmbeddingResult,\n} from '@contractspec/lib.contracts';\nimport type { DocumentFragment } from './document-processor';\n\nexport class EmbeddingService {\n private readonly provider: EmbeddingProvider;\n private readonly batchSize: number;\n\n constructor(provider: EmbeddingProvider, batchSize = 16) {\n this.provider = provider;\n this.batchSize = batchSize;\n }\n\n async embedFragments(\n fragments: DocumentFragment[]\n ): Promise<EmbeddingResult[]> {\n const results: EmbeddingResult[] = [];\n for (let i = 0; i < fragments.length; i += this.batchSize) {\n const slice = fragments.slice(i, i + this.batchSize);\n const documents: EmbeddingDocument[] = slice.map((fragment) => ({\n id: fragment.id,\n text: fragment.text,\n metadata: fragment.metadata,\n }));\n const embeddings = await this.provider.embedDocuments(documents);\n results.push(...embeddings);\n }\n return results;\n }\n}\n"],"mappings":";AAOA,IAAa,mBAAb,MAA8B;CAC5B,AAAiB;CACjB,AAAiB;CAEjB,YAAY,UAA6B,YAAY,IAAI;AACvD,OAAK,WAAW;AAChB,OAAK,YAAY;;CAGnB,MAAM,eACJ,WAC4B;EAC5B,MAAMA,UAA6B,EAAE;AACrC,OAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK,KAAK,WAAW;GAEzD,MAAMC,YADQ,UAAU,MAAM,GAAG,IAAI,KAAK,UAAU,CACP,KAAK,cAAc;IAC9D,IAAI,SAAS;IACb,MAAM,SAAS;IACf,UAAU,SAAS;IACpB,EAAE;GACH,MAAM,aAAa,MAAM,KAAK,SAAS,eAAe,UAAU;AAChE,WAAQ,KAAK,GAAG,WAAW;;AAE7B,SAAO"}
1
+ {"version":3,"file":"embedding-service.js","names":[],"sources":["../../src/ingestion/embedding-service.ts"],"sourcesContent":["import type {\n EmbeddingDocument,\n EmbeddingProvider,\n EmbeddingResult,\n} from '@contractspec/lib.contracts';\nimport type { DocumentFragment } from './document-processor';\n\nexport class EmbeddingService {\n private readonly provider: EmbeddingProvider;\n private readonly batchSize: number;\n\n constructor(provider: EmbeddingProvider, batchSize = 16) {\n this.provider = provider;\n this.batchSize = batchSize;\n }\n\n async embedFragments(\n fragments: DocumentFragment[]\n ): Promise<EmbeddingResult[]> {\n const results: EmbeddingResult[] = [];\n for (let i = 0; i < fragments.length; i += this.batchSize) {\n const slice = fragments.slice(i, i + this.batchSize);\n const documents: EmbeddingDocument[] = slice.map((fragment) => ({\n id: fragment.id,\n text: fragment.text,\n metadata: fragment.metadata,\n }));\n const embeddings = await this.provider.embedDocuments(documents);\n results.push(...embeddings);\n }\n return results;\n }\n}\n"],"mappings":";AAOA,IAAa,mBAAb,MAA8B;CAC5B,AAAiB;CACjB,AAAiB;CAEjB,YAAY,UAA6B,YAAY,IAAI;AACvD,OAAK,WAAW;AAChB,OAAK,YAAY;;CAGnB,MAAM,eACJ,WAC4B;EAC5B,MAAM,UAA6B,EAAE;AACrC,OAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK,KAAK,WAAW;GAEzD,MAAM,YADQ,UAAU,MAAM,GAAG,IAAI,KAAK,UAAU,CACP,KAAK,cAAc;IAC9D,IAAI,SAAS;IACb,MAAM,SAAS;IACf,UAAU,SAAS;IACpB,EAAE;GACH,MAAM,aAAa,MAAM,KAAK,SAAS,eAAe,UAAU;AAChE,WAAQ,KAAK,GAAG,WAAW;;AAE7B,SAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"gmail-adapter.js","names":["gmail: EmailInboundProvider","processor: DocumentProcessor","embeddings: EmbeddingService","indexer: VectorIndexer"],"sources":["../../src/ingestion/gmail-adapter.ts"],"sourcesContent":["import type {\n EmailInboundProvider,\n EmailThread,\n} from '@contractspec/lib.contracts';\nimport type { DocumentProcessor, RawDocument } from './document-processor';\nimport type { EmbeddingService } from './embedding-service';\nimport type { VectorIndexer } from './vector-indexer';\n\nexport class GmailIngestionAdapter {\n constructor(\n private readonly gmail: EmailInboundProvider,\n private readonly processor: DocumentProcessor,\n private readonly embeddings: EmbeddingService,\n private readonly indexer: VectorIndexer\n ) {}\n\n async syncThreads(\n query?: Parameters<EmailInboundProvider['listThreads']>[0]\n ) {\n const threads = await this.gmail.listThreads(query);\n for (const thread of threads) {\n await this.ingestThread(thread);\n }\n }\n\n async ingestThread(thread: EmailThread) {\n const document = this.toRawDocument(thread);\n const fragments = await this.processor.process(document);\n const embeddings = await this.embeddings.embedFragments(fragments);\n await this.indexer.upsert(fragments, embeddings);\n }\n\n private toRawDocument(thread: EmailThread): RawDocument {\n const content = composeThreadText(thread);\n return {\n id: thread.id,\n mimeType: 'text/plain',\n data: Buffer.from(content, 'utf-8'),\n metadata: {\n subject: thread.subject ?? '',\n participants: thread.participants.map((p) => p.email).join(', '),\n updatedAt: thread.updatedAt.toISOString(),\n },\n };\n }\n}\n\nfunction composeThreadText(thread: EmailThread): string {\n const header = [\n `Subject: ${thread.subject ?? ''}`,\n `Snippet: ${thread.snippet ?? ''}`,\n ];\n const messageTexts = thread.messages.map((message) => {\n const parts = [\n `From: ${formatAddress(message.from)}`,\n `To: ${message.to.map(formatAddress).join(', ')}`,\n ];\n if (message.sentAt) {\n parts.push(`Date: ${message.sentAt.toISOString()}`);\n }\n const body = message.textBody ?? stripHtml(message.htmlBody ?? '');\n return `${parts.join('\\n')}\\n\\n${body ?? ''}`;\n });\n return [...header, ...messageTexts].join('\\n\\n---\\n\\n');\n}\n\nfunction formatAddress(address: { email: string; name?: string }): string {\n return address.name ? `${address.name} <${address.email}>` : address.email;\n}\n\nfunction stripHtml(html: string): string {\n return html.replace(/<[^>]+>/g, ' ');\n}\n"],"mappings":";AAQA,IAAa,wBAAb,MAAmC;CACjC,YACE,AAAiBA,OACjB,AAAiBC,WACjB,AAAiBC,YACjB,AAAiBC,SACjB;EAJiB;EACA;EACA;EACA;;CAGnB,MAAM,YACJ,OACA;EACA,MAAM,UAAU,MAAM,KAAK,MAAM,YAAY,MAAM;AACnD,OAAK,MAAM,UAAU,QACnB,OAAM,KAAK,aAAa,OAAO;;CAInC,MAAM,aAAa,QAAqB;EACtC,MAAM,WAAW,KAAK,cAAc,OAAO;EAC3C,MAAM,YAAY,MAAM,KAAK,UAAU,QAAQ,SAAS;EACxD,MAAM,aAAa,MAAM,KAAK,WAAW,eAAe,UAAU;AAClE,QAAM,KAAK,QAAQ,OAAO,WAAW,WAAW;;CAGlD,AAAQ,cAAc,QAAkC;EACtD,MAAM,UAAU,kBAAkB,OAAO;AACzC,SAAO;GACL,IAAI,OAAO;GACX,UAAU;GACV,MAAM,OAAO,KAAK,SAAS,QAAQ;GACnC,UAAU;IACR,SAAS,OAAO,WAAW;IAC3B,cAAc,OAAO,aAAa,KAAK,MAAM,EAAE,MAAM,CAAC,KAAK,KAAK;IAChE,WAAW,OAAO,UAAU,aAAa;IAC1C;GACF;;;AAIL,SAAS,kBAAkB,QAA6B;CACtD,MAAM,SAAS,CACb,YAAY,OAAO,WAAW,MAC9B,YAAY,OAAO,WAAW,KAC/B;CACD,MAAM,eAAe,OAAO,SAAS,KAAK,YAAY;EACpD,MAAM,QAAQ,CACZ,SAAS,cAAc,QAAQ,KAAK,IACpC,OAAO,QAAQ,GAAG,IAAI,cAAc,CAAC,KAAK,KAAK,GAChD;AACD,MAAI,QAAQ,OACV,OAAM,KAAK,SAAS,QAAQ,OAAO,aAAa,GAAG;EAErD,MAAM,OAAO,QAAQ,YAAY,UAAU,QAAQ,YAAY,GAAG;AAClE,SAAO,GAAG,MAAM,KAAK,KAAK,CAAC,MAAM,QAAQ;GACzC;AACF,QAAO,CAAC,GAAG,QAAQ,GAAG,aAAa,CAAC,KAAK,cAAc;;AAGzD,SAAS,cAAc,SAAmD;AACxE,QAAO,QAAQ,OAAO,GAAG,QAAQ,KAAK,IAAI,QAAQ,MAAM,KAAK,QAAQ;;AAGvE,SAAS,UAAU,MAAsB;AACvC,QAAO,KAAK,QAAQ,YAAY,IAAI"}
1
+ {"version":3,"file":"gmail-adapter.js","names":[],"sources":["../../src/ingestion/gmail-adapter.ts"],"sourcesContent":["import type {\n EmailInboundProvider,\n EmailThread,\n} from '@contractspec/lib.contracts';\nimport type { DocumentProcessor, RawDocument } from './document-processor';\nimport type { EmbeddingService } from './embedding-service';\nimport type { VectorIndexer } from './vector-indexer';\n\nexport class GmailIngestionAdapter {\n constructor(\n private readonly gmail: EmailInboundProvider,\n private readonly processor: DocumentProcessor,\n private readonly embeddings: EmbeddingService,\n private readonly indexer: VectorIndexer\n ) {}\n\n async syncThreads(\n query?: Parameters<EmailInboundProvider['listThreads']>[0]\n ) {\n const threads = await this.gmail.listThreads(query);\n for (const thread of threads) {\n await this.ingestThread(thread);\n }\n }\n\n async ingestThread(thread: EmailThread) {\n const document = this.toRawDocument(thread);\n const fragments = await this.processor.process(document);\n const embeddings = await this.embeddings.embedFragments(fragments);\n await this.indexer.upsert(fragments, embeddings);\n }\n\n private toRawDocument(thread: EmailThread): RawDocument {\n const content = composeThreadText(thread);\n return {\n id: thread.id,\n mimeType: 'text/plain',\n data: Buffer.from(content, 'utf-8'),\n metadata: {\n subject: thread.subject ?? '',\n participants: thread.participants.map((p) => p.email).join(', '),\n updatedAt: thread.updatedAt.toISOString(),\n },\n };\n }\n}\n\nfunction composeThreadText(thread: EmailThread): string {\n const header = [\n `Subject: ${thread.subject ?? ''}`,\n `Snippet: ${thread.snippet ?? ''}`,\n ];\n const messageTexts = thread.messages.map((message) => {\n const parts = [\n `From: ${formatAddress(message.from)}`,\n `To: ${message.to.map(formatAddress).join(', ')}`,\n ];\n if (message.sentAt) {\n parts.push(`Date: ${message.sentAt.toISOString()}`);\n }\n const body = message.textBody ?? stripHtml(message.htmlBody ?? '');\n return `${parts.join('\\n')}\\n\\n${body ?? ''}`;\n });\n return [...header, ...messageTexts].join('\\n\\n---\\n\\n');\n}\n\nfunction formatAddress(address: { email: string; name?: string }): string {\n return address.name ? `${address.name} <${address.email}>` : address.email;\n}\n\nfunction stripHtml(html: string): string {\n return html.replace(/<[^>]+>/g, ' ');\n}\n"],"mappings":";AAQA,IAAa,wBAAb,MAAmC;CACjC,YACE,AAAiB,OACjB,AAAiB,WACjB,AAAiB,YACjB,AAAiB,SACjB;EAJiB;EACA;EACA;EACA;;CAGnB,MAAM,YACJ,OACA;EACA,MAAM,UAAU,MAAM,KAAK,MAAM,YAAY,MAAM;AACnD,OAAK,MAAM,UAAU,QACnB,OAAM,KAAK,aAAa,OAAO;;CAInC,MAAM,aAAa,QAAqB;EACtC,MAAM,WAAW,KAAK,cAAc,OAAO;EAC3C,MAAM,YAAY,MAAM,KAAK,UAAU,QAAQ,SAAS;EACxD,MAAM,aAAa,MAAM,KAAK,WAAW,eAAe,UAAU;AAClE,QAAM,KAAK,QAAQ,OAAO,WAAW,WAAW;;CAGlD,AAAQ,cAAc,QAAkC;EACtD,MAAM,UAAU,kBAAkB,OAAO;AACzC,SAAO;GACL,IAAI,OAAO;GACX,UAAU;GACV,MAAM,OAAO,KAAK,SAAS,QAAQ;GACnC,UAAU;IACR,SAAS,OAAO,WAAW;IAC3B,cAAc,OAAO,aAAa,KAAK,MAAM,EAAE,MAAM,CAAC,KAAK,KAAK;IAChE,WAAW,OAAO,UAAU,aAAa;IAC1C;GACF;;;AAIL,SAAS,kBAAkB,QAA6B;CACtD,MAAM,SAAS,CACb,YAAY,OAAO,WAAW,MAC9B,YAAY,OAAO,WAAW,KAC/B;CACD,MAAM,eAAe,OAAO,SAAS,KAAK,YAAY;EACpD,MAAM,QAAQ,CACZ,SAAS,cAAc,QAAQ,KAAK,IACpC,OAAO,QAAQ,GAAG,IAAI,cAAc,CAAC,KAAK,KAAK,GAChD;AACD,MAAI,QAAQ,OACV,OAAM,KAAK,SAAS,QAAQ,OAAO,aAAa,GAAG;EAErD,MAAM,OAAO,QAAQ,YAAY,UAAU,QAAQ,YAAY,GAAG;AAClE,SAAO,GAAG,MAAM,KAAK,KAAK,CAAC,MAAM,QAAQ;GACzC;AACF,QAAO,CAAC,GAAG,QAAQ,GAAG,aAAa,CAAC,KAAK,cAAc;;AAGzD,SAAS,cAAc,SAAmD;AACxE,QAAO,QAAQ,OAAO,GAAG,QAAQ,KAAK,IAAI,QAAQ,MAAM,KAAK,QAAQ;;AAGvE,SAAS,UAAU,MAAsB;AACvC,QAAO,KAAK,QAAQ,YAAY,IAAI"}
@@ -1 +1 @@
1
- {"version":3,"file":"storage-adapter.js","names":["processor: DocumentProcessor","embeddings: EmbeddingService","indexer: VectorIndexer"],"sources":["../../src/ingestion/storage-adapter.ts"],"sourcesContent":["import type { GetObjectResult } from '@contractspec/lib.contracts';\nimport type { DocumentProcessor } from './document-processor';\nimport type { EmbeddingService } from './embedding-service';\nimport type { VectorIndexer } from './vector-indexer';\n\nexport class StorageIngestionAdapter {\n constructor(\n private readonly processor: DocumentProcessor,\n private readonly embeddings: EmbeddingService,\n private readonly indexer: VectorIndexer\n ) {}\n\n async ingestObject(object: GetObjectResult): Promise<void> {\n if (!('data' in object) || !object.data) {\n throw new Error('Storage ingestion requires object data');\n }\n\n const raw = {\n id: object.key,\n mimeType: object.contentType ?? 'application/octet-stream',\n data: object.data,\n metadata: {\n bucket: object.bucket,\n checksum: object.checksum ?? '',\n },\n };\n\n const fragments = await this.processor.process(raw);\n const embeddings = await this.embeddings.embedFragments(fragments);\n await this.indexer.upsert(fragments, embeddings);\n }\n}\n"],"mappings":";AAKA,IAAa,0BAAb,MAAqC;CACnC,YACE,AAAiBA,WACjB,AAAiBC,YACjB,AAAiBC,SACjB;EAHiB;EACA;EACA;;CAGnB,MAAM,aAAa,QAAwC;AACzD,MAAI,EAAE,UAAU,WAAW,CAAC,OAAO,KACjC,OAAM,IAAI,MAAM,yCAAyC;EAG3D,MAAM,MAAM;GACV,IAAI,OAAO;GACX,UAAU,OAAO,eAAe;GAChC,MAAM,OAAO;GACb,UAAU;IACR,QAAQ,OAAO;IACf,UAAU,OAAO,YAAY;IAC9B;GACF;EAED,MAAM,YAAY,MAAM,KAAK,UAAU,QAAQ,IAAI;EACnD,MAAM,aAAa,MAAM,KAAK,WAAW,eAAe,UAAU;AAClE,QAAM,KAAK,QAAQ,OAAO,WAAW,WAAW"}
1
+ {"version":3,"file":"storage-adapter.js","names":[],"sources":["../../src/ingestion/storage-adapter.ts"],"sourcesContent":["import type { GetObjectResult } from '@contractspec/lib.contracts';\nimport type { DocumentProcessor } from './document-processor';\nimport type { EmbeddingService } from './embedding-service';\nimport type { VectorIndexer } from './vector-indexer';\n\nexport class StorageIngestionAdapter {\n constructor(\n private readonly processor: DocumentProcessor,\n private readonly embeddings: EmbeddingService,\n private readonly indexer: VectorIndexer\n ) {}\n\n async ingestObject(object: GetObjectResult): Promise<void> {\n if (!('data' in object) || !object.data) {\n throw new Error('Storage ingestion requires object data');\n }\n\n const raw = {\n id: object.key,\n mimeType: object.contentType ?? 'application/octet-stream',\n data: object.data,\n metadata: {\n bucket: object.bucket,\n checksum: object.checksum ?? '',\n },\n };\n\n const fragments = await this.processor.process(raw);\n const embeddings = await this.embeddings.embedFragments(fragments);\n await this.indexer.upsert(fragments, embeddings);\n }\n}\n"],"mappings":";AAKA,IAAa,0BAAb,MAAqC;CACnC,YACE,AAAiB,WACjB,AAAiB,YACjB,AAAiB,SACjB;EAHiB;EACA;EACA;;CAGnB,MAAM,aAAa,QAAwC;AACzD,MAAI,EAAE,UAAU,WAAW,CAAC,OAAO,KACjC,OAAM,IAAI,MAAM,yCAAyC;EAG3D,MAAM,MAAM;GACV,IAAI,OAAO;GACX,UAAU,OAAO,eAAe;GAChC,MAAM,OAAO;GACb,UAAU;IACR,QAAQ,OAAO;IACf,UAAU,OAAO,YAAY;IAC9B;GACF;EAED,MAAM,YAAY,MAAM,KAAK,UAAU,QAAQ,IAAI;EACnD,MAAM,aAAa,MAAM,KAAK,WAAW,eAAe,UAAU;AAClE,QAAM,KAAK,QAAQ,OAAO,WAAW,WAAW"}
@@ -1 +1 @@
1
- {"version":3,"file":"vector-indexer.js","names":["request: VectorUpsertRequest"],"sources":["../../src/ingestion/vector-indexer.ts"],"sourcesContent":["import type {\n VectorStoreProvider,\n VectorUpsertRequest,\n EmbeddingResult,\n} from '@contractspec/lib.contracts';\nimport type { DocumentFragment } from './document-processor';\n\nexport interface VectorIndexConfig {\n collection: string;\n namespace?: string;\n metadata?: Record<string, string>;\n}\n\nexport class VectorIndexer {\n private readonly provider: VectorStoreProvider;\n private readonly config: VectorIndexConfig;\n\n constructor(provider: VectorStoreProvider, config: VectorIndexConfig) {\n this.provider = provider;\n this.config = config;\n }\n\n async upsert(\n fragments: DocumentFragment[],\n embeddings: EmbeddingResult[]\n ): Promise<void> {\n const documents = embeddings.map((embedding) => {\n const fragment = fragments.find((f) => f.id === embedding.id);\n return {\n id: embedding.id,\n vector: embedding.vector,\n payload: {\n ...this.config.metadata,\n ...(fragment?.metadata ?? {}),\n documentId: fragment?.documentId,\n },\n namespace: this.config.namespace,\n };\n });\n\n const request: VectorUpsertRequest = {\n collection: this.config.collection,\n documents,\n };\n\n await this.provider.upsert(request);\n }\n}\n"],"mappings":";AAaA,IAAa,gBAAb,MAA2B;CACzB,AAAiB;CACjB,AAAiB;CAEjB,YAAY,UAA+B,QAA2B;AACpE,OAAK,WAAW;AAChB,OAAK,SAAS;;CAGhB,MAAM,OACJ,WACA,YACe;EACf,MAAM,YAAY,WAAW,KAAK,cAAc;GAC9C,MAAM,WAAW,UAAU,MAAM,MAAM,EAAE,OAAO,UAAU,GAAG;AAC7D,UAAO;IACL,IAAI,UAAU;IACd,QAAQ,UAAU;IAClB,SAAS;KACP,GAAG,KAAK,OAAO;KACf,GAAI,UAAU,YAAY,EAAE;KAC5B,YAAY,UAAU;KACvB;IACD,WAAW,KAAK,OAAO;IACxB;IACD;EAEF,MAAMA,UAA+B;GACnC,YAAY,KAAK,OAAO;GACxB;GACD;AAED,QAAM,KAAK,SAAS,OAAO,QAAQ"}
1
+ {"version":3,"file":"vector-indexer.js","names":[],"sources":["../../src/ingestion/vector-indexer.ts"],"sourcesContent":["import type {\n VectorStoreProvider,\n VectorUpsertRequest,\n EmbeddingResult,\n} from '@contractspec/lib.contracts';\nimport type { DocumentFragment } from './document-processor';\n\nexport interface VectorIndexConfig {\n collection: string;\n namespace?: string;\n metadata?: Record<string, string>;\n}\n\nexport class VectorIndexer {\n private readonly provider: VectorStoreProvider;\n private readonly config: VectorIndexConfig;\n\n constructor(provider: VectorStoreProvider, config: VectorIndexConfig) {\n this.provider = provider;\n this.config = config;\n }\n\n async upsert(\n fragments: DocumentFragment[],\n embeddings: EmbeddingResult[]\n ): Promise<void> {\n const documents = embeddings.map((embedding) => {\n const fragment = fragments.find((f) => f.id === embedding.id);\n return {\n id: embedding.id,\n vector: embedding.vector,\n payload: {\n ...this.config.metadata,\n ...(fragment?.metadata ?? {}),\n documentId: fragment?.documentId,\n },\n namespace: this.config.namespace,\n };\n });\n\n const request: VectorUpsertRequest = {\n collection: this.config.collection,\n documents,\n };\n\n await this.provider.upsert(request);\n }\n}\n"],"mappings":";AAaA,IAAa,gBAAb,MAA2B;CACzB,AAAiB;CACjB,AAAiB;CAEjB,YAAY,UAA+B,QAA2B;AACpE,OAAK,WAAW;AAChB,OAAK,SAAS;;CAGhB,MAAM,OACJ,WACA,YACe;EACf,MAAM,YAAY,WAAW,KAAK,cAAc;GAC9C,MAAM,WAAW,UAAU,MAAM,MAAM,EAAE,OAAO,UAAU,GAAG;AAC7D,UAAO;IACL,IAAI,UAAU;IACd,QAAQ,UAAU;IAClB,SAAS;KACP,GAAG,KAAK,OAAO;KACf,GAAI,UAAU,YAAY,EAAE;KAC5B,YAAY,UAAU;KACvB;IACD,WAAW,KAAK,OAAO;IACxB;IACD;EAEF,MAAM,UAA+B;GACnC,YAAY,KAAK,OAAO;GACxB;GACD;AAED,QAAM,KAAK,SAAS,OAAO,QAAQ"}
@@ -1 +1 @@
1
- {"version":3,"file":"static-retriever.js","names":["results: RetrievalResult[]"],"sources":["../../src/retriever/static-retriever.ts"],"sourcesContent":["import type { RetrievalResult, RetrievalOptions } from '../types';\nimport type { KnowledgeRetriever, RetrieverConfig } from './interface';\n\n/**\n * Configuration for the static retriever.\n */\nexport interface StaticRetrieverConfig extends RetrieverConfig {\n /** Map of space key to static content */\n content: Map<string, string> | Record<string, string>;\n}\n\n/**\n * A simple in-memory retriever for static knowledge content.\n *\n * Useful for:\n * - Required knowledge that doesn't need semantic search\n * - Testing and development\n * - Small knowledge bases that fit in memory\n */\nexport class StaticRetriever implements KnowledgeRetriever {\n private readonly content: Map<string, string>;\n\n constructor(config: StaticRetrieverConfig) {\n this.content =\n config.content instanceof Map\n ? config.content\n : new Map(Object.entries(config.content));\n }\n\n async retrieve(\n query: string,\n options: RetrievalOptions\n ): Promise<RetrievalResult[]> {\n const content = this.content.get(options.spaceKey);\n if (!content) return [];\n\n // Simple keyword matching for static retriever\n const queryLower = query.toLowerCase();\n const lines = content.split('\\n').filter((line) => line.trim());\n\n const results: RetrievalResult[] = [];\n for (const line of lines) {\n if (line.toLowerCase().includes(queryLower)) {\n results.push({\n content: line,\n source: options.spaceKey,\n score: 1.0,\n metadata: { type: 'static' },\n });\n }\n }\n\n return results.slice(0, options.topK ?? 5);\n }\n\n async getStatic(spaceKey: string): Promise<string | null> {\n return this.content.get(spaceKey) ?? null;\n }\n\n supportsSpace(spaceKey: string): boolean {\n return this.content.has(spaceKey);\n }\n\n listSpaces(): string[] {\n return [...this.content.keys()];\n }\n}\n\n/**\n * Create a static retriever from a content map.\n */\nexport function createStaticRetriever(\n content: Record<string, string> | Map<string, string>\n): StaticRetriever {\n return new StaticRetriever({ content });\n}\n"],"mappings":";;;;;;;;;AAmBA,IAAa,kBAAb,MAA2D;CACzD,AAAiB;CAEjB,YAAY,QAA+B;AACzC,OAAK,UACH,OAAO,mBAAmB,MACtB,OAAO,UACP,IAAI,IAAI,OAAO,QAAQ,OAAO,QAAQ,CAAC;;CAG/C,MAAM,SACJ,OACA,SAC4B;EAC5B,MAAM,UAAU,KAAK,QAAQ,IAAI,QAAQ,SAAS;AAClD,MAAI,CAAC,QAAS,QAAO,EAAE;EAGvB,MAAM,aAAa,MAAM,aAAa;EACtC,MAAM,QAAQ,QAAQ,MAAM,KAAK,CAAC,QAAQ,SAAS,KAAK,MAAM,CAAC;EAE/D,MAAMA,UAA6B,EAAE;AACrC,OAAK,MAAM,QAAQ,MACjB,KAAI,KAAK,aAAa,CAAC,SAAS,WAAW,CACzC,SAAQ,KAAK;GACX,SAAS;GACT,QAAQ,QAAQ;GAChB,OAAO;GACP,UAAU,EAAE,MAAM,UAAU;GAC7B,CAAC;AAIN,SAAO,QAAQ,MAAM,GAAG,QAAQ,QAAQ,EAAE;;CAG5C,MAAM,UAAU,UAA0C;AACxD,SAAO,KAAK,QAAQ,IAAI,SAAS,IAAI;;CAGvC,cAAc,UAA2B;AACvC,SAAO,KAAK,QAAQ,IAAI,SAAS;;CAGnC,aAAuB;AACrB,SAAO,CAAC,GAAG,KAAK,QAAQ,MAAM,CAAC;;;;;;AAOnC,SAAgB,sBACd,SACiB;AACjB,QAAO,IAAI,gBAAgB,EAAE,SAAS,CAAC"}
1
+ {"version":3,"file":"static-retriever.js","names":[],"sources":["../../src/retriever/static-retriever.ts"],"sourcesContent":["import type { RetrievalResult, RetrievalOptions } from '../types';\nimport type { KnowledgeRetriever, RetrieverConfig } from './interface';\n\n/**\n * Configuration for the static retriever.\n */\nexport interface StaticRetrieverConfig extends RetrieverConfig {\n /** Map of space key to static content */\n content: Map<string, string> | Record<string, string>;\n}\n\n/**\n * A simple in-memory retriever for static knowledge content.\n *\n * Useful for:\n * - Required knowledge that doesn't need semantic search\n * - Testing and development\n * - Small knowledge bases that fit in memory\n */\nexport class StaticRetriever implements KnowledgeRetriever {\n private readonly content: Map<string, string>;\n\n constructor(config: StaticRetrieverConfig) {\n this.content =\n config.content instanceof Map\n ? config.content\n : new Map(Object.entries(config.content));\n }\n\n async retrieve(\n query: string,\n options: RetrievalOptions\n ): Promise<RetrievalResult[]> {\n const content = this.content.get(options.spaceKey);\n if (!content) return [];\n\n // Simple keyword matching for static retriever\n const queryLower = query.toLowerCase();\n const lines = content.split('\\n').filter((line) => line.trim());\n\n const results: RetrievalResult[] = [];\n for (const line of lines) {\n if (line.toLowerCase().includes(queryLower)) {\n results.push({\n content: line,\n source: options.spaceKey,\n score: 1.0,\n metadata: { type: 'static' },\n });\n }\n }\n\n return results.slice(0, options.topK ?? 5);\n }\n\n async getStatic(spaceKey: string): Promise<string | null> {\n return this.content.get(spaceKey) ?? null;\n }\n\n supportsSpace(spaceKey: string): boolean {\n return this.content.has(spaceKey);\n }\n\n listSpaces(): string[] {\n return [...this.content.keys()];\n }\n}\n\n/**\n * Create a static retriever from a content map.\n */\nexport function createStaticRetriever(\n content: Record<string, string> | Map<string, string>\n): StaticRetriever {\n return new StaticRetriever({ content });\n}\n"],"mappings":";;;;;;;;;AAmBA,IAAa,kBAAb,MAA2D;CACzD,AAAiB;CAEjB,YAAY,QAA+B;AACzC,OAAK,UACH,OAAO,mBAAmB,MACtB,OAAO,UACP,IAAI,IAAI,OAAO,QAAQ,OAAO,QAAQ,CAAC;;CAG/C,MAAM,SACJ,OACA,SAC4B;EAC5B,MAAM,UAAU,KAAK,QAAQ,IAAI,QAAQ,SAAS;AAClD,MAAI,CAAC,QAAS,QAAO,EAAE;EAGvB,MAAM,aAAa,MAAM,aAAa;EACtC,MAAM,QAAQ,QAAQ,MAAM,KAAK,CAAC,QAAQ,SAAS,KAAK,MAAM,CAAC;EAE/D,MAAM,UAA6B,EAAE;AACrC,OAAK,MAAM,QAAQ,MACjB,KAAI,KAAK,aAAa,CAAC,SAAS,WAAW,CACzC,SAAQ,KAAK;GACX,SAAS;GACT,QAAQ,QAAQ;GAChB,OAAO;GACP,UAAU,EAAE,MAAM,UAAU;GAC7B,CAAC;AAIN,SAAO,QAAQ,MAAM,GAAG,QAAQ,QAAQ,EAAE;;CAG5C,MAAM,UAAU,UAA0C;AACxD,SAAO,KAAK,QAAQ,IAAI,SAAS,IAAI;;CAGvC,cAAc,UAA2B;AACvC,SAAO,KAAK,QAAQ,IAAI,SAAS;;CAGnC,aAAuB;AACrB,SAAO,CAAC,GAAG,KAAK,QAAQ,MAAM,CAAC;;;;;;AAOnC,SAAgB,sBACd,SACiB;AACjB,QAAO,IAAI,gBAAgB,EAAE,SAAS,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contractspec/lib.knowledge",
3
- "version": "1.46.2",
3
+ "version": "1.47.0",
4
4
  "description": "RAG and knowledge base primitives",
5
5
  "keywords": [
6
6
  "contractspec",
@@ -10,8 +10,6 @@
10
10
  "typescript"
11
11
  ],
12
12
  "type": "module",
13
- "main": "./dist/index.js",
14
- "module": "./dist/index.js",
15
13
  "types": "./dist/index.d.ts",
16
14
  "files": [
17
15
  "dist",
@@ -31,12 +29,12 @@
31
29
  "test": "bun test"
32
30
  },
33
31
  "dependencies": {
34
- "@contractspec/lib.contracts": "1.46.2"
32
+ "@contractspec/lib.contracts": "1.47.0"
35
33
  },
36
34
  "devDependencies": {
37
- "@contractspec/tool.tsdown": "1.46.2",
38
- "@contractspec/tool.typescript": "1.46.2",
39
- "tsdown": "^0.18.3",
35
+ "@contractspec/tool.tsdown": "1.47.0",
36
+ "@contractspec/tool.typescript": "1.47.0",
37
+ "tsdown": "^0.19.0",
40
38
  "typescript": "^5.9.3"
41
39
  },
42
40
  "exports": {