diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 2537c1f..f1c1e58 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.4.0" + ".": "0.5.0" } diff --git a/.stats.yml b/.stats.yml index 3bf9ffe..50cd37d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 46 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/contextual-ai%2Fsunrise-f43814080090927ee22816c5c7f517d8a7eb7f346329ada67915608e32124321.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/contextual-ai%2Fsunrise-194878b194cd507d7c5418ff38cc0fc53441ef618f991990d334b4b75775cd8f.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e09b2b..f50f6cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## 0.5.0 (2025-03-11) + +Full Changelog: [v0.4.0...v0.5.0](https://github.com/ContextualAI/contextual-client-node/compare/v0.4.0...v0.5.0) + +### Features + +* add SKIP_BREW env var to ./scripts/bootstrap ([#35](https://github.com/ContextualAI/contextual-client-node/issues/35)) ([bb0faca](https://github.com/ContextualAI/contextual-client-node/commit/bb0faca1da1cc716197e02d3a5e9b6614f2204b0)) +* **api:** update via SDK Studio ([#37](https://github.com/ContextualAI/contextual-client-node/issues/37)) ([1cc7907](https://github.com/ContextualAI/contextual-client-node/commit/1cc7907b119cb40734c3da6040feb6b999e70191)) +* **api:** update via SDK Studio ([#38](https://github.com/ContextualAI/contextual-client-node/issues/38)) ([b23a2e2](https://github.com/ContextualAI/contextual-client-node/commit/b23a2e2fa6bfcf37b61754eeb134d165c61e8d9d)) +* **client:** accept RFC6838 JSON content types ([#36](https://github.com/ContextualAI/contextual-client-node/issues/36)) ([5178d1d](https://github.com/ContextualAI/contextual-client-node/commit/5178d1ddbc4c67f035113faafcc292c0dc05f014)) + + +### Chores + +* **internal:** codegen related update ([#33](https://github.com/ContextualAI/contextual-client-node/issues/33)) ([7608b02](https://github.com/ContextualAI/contextual-client-node/commit/7608b02fa3f51ef345da11be72b90fba5018ed68)) + ## 0.4.0 (2025-03-03) Full Changelog: [v0.3.0...v0.4.0](https://github.com/ContextualAI/contextual-client-node/compare/v0.3.0...v0.4.0) diff --git a/api.md b/api.md index 6616f1d..c7a7a59 100644 --- a/api.md +++ b/api.md @@ -19,6 +19,7 @@ Methods: Types: +- CompositeMetadataFilter - DocumentMetadata - IngestionResponse - ListDocumentsResponse diff --git a/package.json b/package.json index 9f46c21..5d81b27 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "contextual-client", - "version": "0.4.0", + "version": "0.5.0", "description": "The official TypeScript library for the Contextual AI API", "author": "Contextual AI ", "types": "dist/index.d.ts", diff --git a/scripts/bootstrap b/scripts/bootstrap index 05dd47a..0af58e2 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -4,7 +4,7 @@ set -e cd "$(dirname "$0")/.." -if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ]; then +if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ]; then brew bundle check >/dev/null 2>&1 || { echo "==> Installing Homebrew dependencies…" brew bundle diff --git a/src/core.ts b/src/core.ts index 156ed7f..058bd17 100644 --- a/src/core.ts +++ b/src/core.ts @@ -48,8 +48,8 @@ async function defaultParseResponse(props: APIResponseProps): Promise { } const contentType = response.headers.get('content-type'); - const isJSON = - contentType?.includes('application/json') || contentType?.includes('application/vnd.api+json'); + const mediaType = contentType?.split(';')[0]?.trim(); + const isJSON = mediaType?.includes('application/json') || mediaType?.endsWith('+json'); if (isJSON) { const json = await response.json(); diff --git a/src/pagination.ts b/src/pagination.ts index 9c62a10..76ce5b7 100644 --- a/src/pagination.ts +++ b/src/pagination.ts @@ -53,7 +53,7 @@ export class DatastoresPage extends AbstractPage implements Datastor return { params: { - cursor: cursor, + cursor, }, }; } @@ -110,7 +110,7 @@ export class DocumentsPage extends AbstractPage implements Documents return { params: { - cursor: cursor, + cursor, }, }; } @@ -167,7 +167,7 @@ export class UsersPage extends AbstractPage implements UsersPageResp return { params: { - cursor: cursor, + cursor, }, }; } @@ -219,7 +219,7 @@ export class Page extends AbstractPage implements PageResponse return { params: { - cursor: cursor, + cursor, }, }; } diff --git a/src/resources/agents/agents.ts b/src/resources/agents/agents.ts index 671e5de..ed66df4 100644 --- a/src/resources/agents/agents.ts +++ b/src/resources/agents/agents.ts @@ -41,6 +41,11 @@ export class Agents extends APIResource { * If no `datastore_id` is provided in the configuration, this API automatically * creates an empty `Datastore` and configures the `Agent` to use the newly created * `Datastore`. + * + * > Note that self-serve users are currently required to create agents through our + * > UI. Otherwise, they will receive the following message: "This endpoint is + * > disabled as you need to go through checkout. Please use the UI to make this + * > request." */ create(body: AgentCreateParams, options?: Core.RequestOptions): Core.APIPromise { return this._client.post('/agents', { body, ...options }); @@ -132,6 +137,12 @@ export interface AgentMetadata { */ description?: string; + /** + * The prompt to an LLM which determines whether retrieved chunks are relevant to a + * given query and filters out irrelevant chunks. This prompt is applied per chunk. + */ + filter_prompt?: string; + /** * The model ID to use for generation. Tuned models can only be used for the agents * on which they were tuned. If no model is specified, the default model is used. @@ -195,6 +206,11 @@ export namespace AgentMetadata { * Parameters that affect response generation */ export interface GenerateResponseConfig { + /** + * This parameter controls generation of groundedness scores. + */ + calculate_groundedness?: boolean; + /** * This parameter adjusts how the model treats repeated tokens during text * generation. @@ -327,6 +343,12 @@ export interface AgentCreateParams { */ description?: string; + /** + * The prompt to an LLM which determines whether retrieved chunks are relevant to a + * given query and filters out irrelevant chunks. + */ + filter_prompt?: string; + /** * These queries will show up as suggestions in the Contextual UI when users load * the agent. We recommend including common queries that users will ask, as well as @@ -383,6 +405,11 @@ export namespace AgentCreateParams { * Parameters that affect response generation */ export interface GenerateResponseConfig { + /** + * This parameter controls generation of groundedness scores. + */ + calculate_groundedness?: boolean; + /** * This parameter adjusts how the model treats repeated tokens during text * generation. @@ -466,6 +493,12 @@ export interface AgentUpdateParams { */ datastore_ids?: Array; + /** + * The prompt to an LLM which determines whether retrieved chunks are relevant to a + * given query and filters out irrelevant chunks. + */ + filter_prompt?: string; + /** * The model ID to use for generation. Tuned models can only be used for the agents * on which they were tuned. If no model is specified, the default model is used. @@ -529,6 +562,11 @@ export namespace AgentUpdateParams { * Parameters that affect response generation */ export interface GenerateResponseConfig { + /** + * This parameter controls generation of groundedness scores. + */ + calculate_groundedness?: boolean; + /** * This parameter adjusts how the model treats repeated tokens during text * generation. diff --git a/src/resources/agents/query.ts b/src/resources/agents/query.ts index 827eafc..1abad48 100644 --- a/src/resources/agents/query.ts +++ b/src/resources/agents/query.ts @@ -3,6 +3,7 @@ import { APIResource } from '../../resource'; import { isRequestOptions } from '../../core'; import * as Core from '../../core'; +import * as DocumentsAPI from '../datastores/documents'; export class Query extends APIResource { /** @@ -96,6 +97,11 @@ export interface QueryResponse { */ attributions?: Array; + /** + * Groundedness scores for the response + */ + groundedness_scores?: Array; + /** * Response to the query request */ @@ -130,7 +136,7 @@ export namespace QueryResponse { /** * Format of the content, such as `pdf` or `html` */ - format: 'pdf' | 'html' | 'htm'; + format: 'pdf' | 'html' | 'htm' | 'mhtml' | 'doc' | 'docx' | 'ppt' | 'pptx'; /** * Source type of the content. Will be `file` for any docs ingested through @@ -180,6 +186,26 @@ export namespace QueryResponse { start_idx: number; } + /** + * Groundedness scores in a generated message`. + */ + export interface GroundednessScore { + /** + * End index of the span in the generated message + */ + end_idx: number; + + /** + * Groundedness score for the span + */ + score: number; + + /** + * Start index of the span in the generated message + */ + start_idx: number; + } + /** * Response to the query request */ @@ -308,6 +334,44 @@ export interface QueryCreateParams { */ conversation_id?: string; + /** + * Body param: Defines an Optional custom metadata filter, which can be a list of + * filters or nested filters. The expected input is a nested JSON object that can + * represent a single filter or a composite (logical) combination of filters. + * + * Unnested Example: + * + * ```json + * { + * "operator": "AND", + * "filters": [{ "field": "status", "operator": "equals", "value": "active" }] + * } + * ``` + * + * Nested example: + * + * ```json + * { + * "operator": "AND", + * "filters": [ + * { "field": "status", "operator": "equals", "value": "active" }, + * { + * "operator": "OR", + * "filters": [ + * { + * "field": "category", + * "operator": "containsany", + * "value": ["policy", "HR"] + * }, + * { "field": "tags", "operator": "exists" } + * ] + * } + * ] + * } + * ``` + */ + documents_filters?: QueryCreateParams.BaseMetadataFilter | DocumentsAPI.CompositeMetadataFilter; + /** * Body param: Model ID of the specific fine-tuned or aligned LLM model to use. * Defaults to base model if not specified. @@ -335,6 +399,43 @@ export namespace QueryCreateParams { */ role: 'user' | 'system' | 'assistant' | 'knowledge'; } + + /** + * Defines a custom metadata filter. The expected input is a dict which can have + * different operators, fields and values. For example: + * + * {"field": "title", "operator": "startswith", "value": "hr-"} + * + * For document_id and date_created the query is built using direct query without + * nesting. + */ + export interface BaseMetadataFilter { + /** + * Field name to search for in the metadata + */ + field: string; + + /** + * Operator to be used for the filter. + */ + operator: + | 'equals' + | 'containsany' + | 'exists' + | 'startswith' + | 'gt' + | 'gte' + | 'lt' + | 'lte' + | 'notequals' + | 'between'; + + /** + * The value to be searched for in the field. In case of exists operator, it is not + * needed. + */ + value?: string | number | boolean | Array | null; + } } export interface QueryFeedbackParams { @@ -362,6 +463,11 @@ export interface QueryFeedbackParams { } export interface QueryMetricsParams { + /** + * Filter messages by conversation ids. + */ + conversation_ids?: Array; + /** * Filters messages that are created after the specified timestamp. */ @@ -381,6 +487,11 @@ export interface QueryMetricsParams { * Offset for pagination. */ offset?: number; + + /** + * Filter messages by users. + */ + user_emails?: Array; } export interface QueryRetrievalInfoParams { diff --git a/src/resources/agents/tune/jobs.ts b/src/resources/agents/tune/jobs.ts index 894cd99..955955e 100644 --- a/src/resources/agents/tune/jobs.ts +++ b/src/resources/agents/tune/jobs.ts @@ -66,7 +66,7 @@ export interface TuneJobMetadata { /** * Metadata about the model evaluation, including status and results if completed. */ - evaluation_metadata?: unknown | null; + evaluation_metadata?: Array; /** * ID of the tuned model. Omitted if the tuning job failed or is still in progress. diff --git a/src/resources/datastores/datastores.ts b/src/resources/datastores/datastores.ts index a39c57a..acd0c9f 100644 --- a/src/resources/datastores/datastores.ts +++ b/src/resources/datastores/datastores.ts @@ -5,6 +5,7 @@ import { isRequestOptions } from '../../core'; import * as Core from '../../core'; import * as DocumentsAPI from './documents'; import { + CompositeMetadataFilter, DocumentDeleteResponse, DocumentIngestParams, DocumentListParams, @@ -31,6 +32,11 @@ export class Datastores extends APIResource { * relevant data. This flexible many-to-many relationship allows `Agents` to draw * from multiple sources of information. This linkage of `Datastore` to `Agent` is * done through the `Create Agent` or `Edit Agent` APIs. + * + * > Note that self-serve users are currently required to create datastores through + * > our UI. Otherwise, they will receive the following message: "This endpoint is + * > disabled as you need to go through checkout. Please use the UI to make this + * > request." */ create( body: DatastoreCreateParams, @@ -180,6 +186,7 @@ export declare namespace Datastores { export { Documents as Documents, + type CompositeMetadataFilter as CompositeMetadataFilter, type DocumentMetadata as DocumentMetadata, type IngestionResponse as IngestionResponse, type ListDocumentsResponse as ListDocumentsResponse, diff --git a/src/resources/datastores/documents.ts b/src/resources/datastores/documents.ts index 18bc7e7..9ade45c 100644 --- a/src/resources/datastores/documents.ts +++ b/src/resources/datastores/documents.ts @@ -55,7 +55,9 @@ export class Documents extends APIResource { * This `id` can also be used to delete the document through the * `DELETE /datastores/{datastore_id}/documents/{document_id}` API. * - * `file` must be a PDF or HTML file. + * `file` must be a PDF, HTML, DOC(X) or PPT(X) file. The filename must end with + * one of the following extensions: `.pdf`, `.html`, `.htm`, `.mhtml`, `.doc`, + * `.docx`, `.ppt`, `.pptx`. */ ingest( datastoreId: string, @@ -82,7 +84,7 @@ export class Documents extends APIResource { /** * Post details of a given document that will enrich the chunk and be added to the - * context or just for filtering. If JUst for filtering, start with "\_" in the + * context or just for filtering. If Just for filtering, start with "\_" in the * key. */ setMetadata( @@ -100,6 +102,61 @@ export class Documents extends APIResource { export class DocumentMetadataDocumentsPage extends DocumentsPage {} +/** + * "Defines a custom metadata filter as a Composite MetadataFilter. Which can be be + * a list of filters or nested filters. + */ +export interface CompositeMetadataFilter { + /** + * Filters added to the query for filtering docs + */ + filters: Array; + + /** + * Composite operator to be used to combine filters + */ + operator?: 'AND' | 'OR' | 'AND_NOT' | null; +} + +export namespace CompositeMetadataFilter { + /** + * Defines a custom metadata filter. The expected input is a dict which can have + * different operators, fields and values. For example: + * + * {"field": "title", "operator": "startswith", "value": "hr-"} + * + * For document_id and date_created the query is built using direct query without + * nesting. + */ + export interface BaseMetadataFilter { + /** + * Field name to search for in the metadata + */ + field: string; + + /** + * Operator to be used for the filter. + */ + operator: + | 'equals' + | 'containsany' + | 'exists' + | 'startswith' + | 'gt' + | 'gte' + | 'lt' + | 'lte' + | 'notequals' + | 'between'; + + /** + * The value to be searched for in the field. In case of exists operator, it is not + * needed. + */ + value?: string | number | boolean | Array | null; + } +} + /** * Document description */ @@ -186,16 +243,30 @@ export interface DocumentListParams extends DocumentsPageParams { export interface DocumentIngestParams { /** - * File to ingest + * File to ingest. */ file: Core.Uploadable; /** - * Metadata in `JSON` format. Metadata should be passed in a nested dictionary - * structure of `str` metadata type to `Dict` mapping `str` metadata keys to `str`, - * `bool`, `float` or `int` values. Currently, `custom_metadata` is the only - * supported metadata type.Example `metadata` dictionary: {"metadata": - * {"custom_metadata": {"customKey1": "value3", "\_filterKey": "filterValue3"}} + * Metadata in `JSON` format. Metadata should be passed as a nested dictionary + * structure where: + * + * - The **metadata type** `custom_metadata` is mapped to a dictionary. - The + * **dictionary keys** represent metadata attributes. - The **values** can be of + * type `str`, `bool`, `float`, or `int`. + * + * **Example Metadata JSON:** + * + * ```json + * { + * "metadata": { + * "custom_metadata": { + * "customKey1": "value3", + * "_filterKey": "filterValue3" + * } + * } + * } + * ``` */ metadata?: string; } @@ -208,6 +279,7 @@ Documents.DocumentMetadataDocumentsPage = DocumentMetadataDocumentsPage; export declare namespace Documents { export { + type CompositeMetadataFilter as CompositeMetadataFilter, type DocumentMetadata as DocumentMetadata, type IngestionResponse as IngestionResponse, type ListDocumentsResponse as ListDocumentsResponse, diff --git a/src/resources/datastores/index.ts b/src/resources/datastores/index.ts index 8ac77ea..4f96cde 100644 --- a/src/resources/datastores/index.ts +++ b/src/resources/datastores/index.ts @@ -14,6 +14,7 @@ export { export { DocumentMetadataDocumentsPage, Documents, + type CompositeMetadataFilter, type DocumentMetadata, type IngestionResponse, type ListDocumentsResponse, diff --git a/src/resources/generate.ts b/src/resources/generate.ts index 76cd1c6..7d97052 100644 --- a/src/resources/generate.ts +++ b/src/resources/generate.ts @@ -7,10 +7,14 @@ export class Generate extends APIResource { /** * Generate a response using Contextual's Grounded Language Model (GLM), an LLM * engineered specifically to prioritize faithfulness to in-context retrievals over - * parametric knowledge to reduce hallucinations in Retrieval-Augmented Generation. + * parametric knowledge to reduce hallucinations in Retrieval-Augmented Generation + * and agentic use cases. * - * The total request cannot exceed 32,000 tokens. Email glm-feedback@contextual.ai - * with any feedback or questions. + * The total request cannot exceed 32,000 tokens. See more details and code + * examples in our + * [our blog post](https://contextual.ai/blog/introducing-grounded-language-model/). + * Email [glm-feedback@contextual.ai](mailto:glm-feedback@contextual.ai) with any + * feedback or questions. */ create(body: GenerateCreateParams, options?: Core.RequestOptions): Core.APIPromise { return this._client.post('/generate', { body, ...options }); @@ -66,14 +70,14 @@ export interface GenerateCreateParams { /** * The sampling temperature, which affects the randomness in the response. Note - * that higher temperature values can reduce groundedness + * that higher temperature values can reduce groundedness. */ temperature?: number; /** * A parameter for nucleus sampling, an alternative to temperature which also * affects the randomness of the response. Note that higher top_p values can reduce - * groundedness + * groundedness. */ top_p?: number; } diff --git a/src/resources/rerank.ts b/src/resources/rerank.ts index 702d0b5..98f9ed8 100644 --- a/src/resources/rerank.ts +++ b/src/resources/rerank.ts @@ -5,10 +5,16 @@ import * as Core from '../core'; export class Rerank extends APIResource { /** - * Rank a list of documents according to their relevance to a query. + * Rank a list of documents according to their relevance to a query and your custom + * instructions about how to prioritize retrievals. We evaluated the model on + * instructions for recency, document type, source, and metadata, and it can + * generalize to other instructions as well. * - * The total request cannot exceed 400,000 tokens. The combined length of any - * document, instruction and the query must not exceed 4,000 tokens. + * The total request cannot exceed 400,000 tokens. The combined length of the + * query, instruction and any document with its metadata must not exceed 8,000 + * tokens. Email + * [rerank-feedback@contextual.ai](mailto:rerank-feedback@contextual.ai) with any + * feedback or questions. */ create(body: RerankCreateParams, options?: Core.RequestOptions): Core.APIPromise { return this._client.post('/rerank', { body, ...options }); @@ -50,12 +56,14 @@ export namespace RerankCreateResponse { export interface RerankCreateParams { /** - * The texts to be reranked according to their relevance to the query + * The texts to be reranked according to their relevance to the query and the + * optional instruction */ documents: Array; /** - * The version of the reranker to use. Currently, we just have "v1". + * The version of the reranker to use. Currently, we just have + * "ctxl-rerank-en-v1-instruct". */ model: string; @@ -65,13 +73,21 @@ export interface RerankCreateParams { query: string; /** - * The instruction to be used for the reranker + * Instructions that the reranker references when ranking retrievals. We evaluated + * the model on instructions for recency, document type, source, and metadata, and + * it can generalize to other instructions as well. Note that we do not guarantee + * that the reranker will follow these instructions exactly. Examples: "Prioritize + * internal sales documents over market analysis reports. More recent documents + * should be weighted higher. Enterprise portal content supersedes distributor + * communications." and "Emphasize forecasts from top-tier investment banks. Recent + * analysis should take precedence. Disregard aggregator sites and favor detailed + * research notes over news summaries." */ instruction?: string; /** * Metadata for documents being passed to the reranker. Must be the same length as - * the documents list. + * the documents list. If a document does not have metadata, add an empty string. */ metadata?: Array; diff --git a/src/version.ts b/src/version.ts index 4e7f788..1f5d158 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.4.0'; // x-release-please-version +export const VERSION = '0.5.0'; // x-release-please-version diff --git a/tests/api-resources/agents/agents.test.ts b/tests/api-resources/agents/agents.test.ts index 2660dbf..2d47dbc 100644 --- a/tests/api-resources/agents/agents.test.ts +++ b/tests/api-resources/agents/agents.test.ts @@ -26,6 +26,7 @@ describe('resource agents', () => { agent_configs: { filter_and_rerank_config: { top_k_reranked_chunks: 0 }, generate_response_config: { + calculate_groundedness: true, frequency_penalty: 0, max_new_tokens: 0, seed: 0, @@ -37,6 +38,7 @@ describe('resource agents', () => { }, datastore_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'], description: 'xxx', + filter_prompt: 'filter_prompt', suggested_queries: ['string'], system_prompt: 'system_prompt', }); diff --git a/tests/api-resources/agents/query.test.ts b/tests/api-resources/agents/query.test.ts index da47fd4..b815104 100644 --- a/tests/api-resources/agents/query.test.ts +++ b/tests/api-resources/agents/query.test.ts @@ -28,6 +28,7 @@ describe('resource query', () => { include_retrieval_content_text: true, retrievals_only: true, conversation_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + documents_filters: { field: 'field', operator: 'equals', value: 'string' }, llm_model_id: 'llm_model_id', stream: true, }); @@ -82,10 +83,12 @@ describe('resource query', () => { client.agents.query.metrics( '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { + conversation_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'], created_after: '2019-12-27T18:11:19.117Z', created_before: '2019-12-27T18:11:19.117Z', limit: 1000, offset: 0, + user_emails: ['string'], }, { path: '/_stainless_unknown_path' }, ),