diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 76d5538..7d9b009 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.9.0" + ".": "0.10.0" } diff --git a/.stats.yml b/.stats.yml index ed70296..64eaa82 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 34 +configured_endpoints: 36 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/contextual-ai%2Fsunrise-c8152db455001be3f09a3bc60d63711699d2c2a4ea5f7bbc1d71726efda0fd9b.yml openapi_spec_hash: 97719df292ca220de5d35d36f9756b95 -config_hash: ae81af9b7eb88a788a80bcf3480e0b6b +config_hash: fdaf751580ba8a60e222e560847af1ac diff --git a/CHANGELOG.md b/CHANGELOG.md index 6820cf5..d979c31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.10.0 (2025-11-11) + +Full Changelog: [v0.9.0...v0.10.0](https://github.com/ContextualAI/contextual-client-node/compare/v0.9.0...v0.10.0) + +### Features + +* **api:** update via SDK Studio ([314253f](https://github.com/ContextualAI/contextual-client-node/commit/314253f03cbf07ecc2f6a0f4e856d4d0000f544e)) + ## 0.9.0 (2025-10-28) Full Changelog: [v0.8.0...v0.9.0](https://github.com/ContextualAI/contextual-client-node/compare/v0.8.0...v0.9.0) diff --git a/api.md b/api.md index 709af94..9962ca7 100644 --- a/api.md +++ b/api.md @@ -40,6 +40,18 @@ Methods: - client.datastores.documents.metadata(datastoreId, documentId) -> DocumentMetadata - client.datastores.documents.setMetadata(datastoreId, documentId, { ...params }) -> DocumentMetadata +## Contents + +Types: + +- ContentListResponse +- ContentMetadataResponse + +Methods: + +- client.datastores.contents.list(datastoreId, { ...params }) -> ContentListResponsesContentsPage +- client.datastores.contents.metadata(datastoreId, contentId, { ...params }) -> ContentMetadataResponse + # Agents Types: diff --git a/package.json b/package.json index 4b72526..28494c8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "contextual-client", - "version": "0.9.0", + "version": "0.10.0", "description": "The official TypeScript library for the Contextual AI API", "author": "Contextual AI ", "types": "dist/index.d.ts", diff --git a/src/index.ts b/src/index.ts index 327ce39..a8b7138 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,6 +6,8 @@ import * as Core from './core'; import * as Errors from './error'; import * as Pagination from './pagination'; import { + type ContentsPageParams, + ContentsPageResponse, type DatastoresPageParams, DatastoresPageResponse, type DocumentsPageParams, @@ -281,6 +283,9 @@ export declare namespace ContextualAI { export import Page = Pagination.Page; export { type PageParams as PageParams, type PageResponse as PageResponse }; + export import ContentsPage = Pagination.ContentsPage; + export { type ContentsPageParams as ContentsPageParams, type ContentsPageResponse as ContentsPageResponse }; + export { Datastores as Datastores, type CreateDatastoreResponse as CreateDatastoreResponse, diff --git a/src/pagination.ts b/src/pagination.ts index 76ce5b7..c6d868d 100644 --- a/src/pagination.ts +++ b/src/pagination.ts @@ -224,3 +224,50 @@ export class Page extends AbstractPage implements PageResponse }; } } + +export interface ContentsPageResponse { + data: Array; +} + +export interface ContentsPageParams { + limit?: number; + + offset?: number; +} + +export class ContentsPage extends AbstractPage implements ContentsPageResponse { + data: Array; + + constructor( + client: APIClient, + response: Response, + body: ContentsPageResponse, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.data = body.data || []; + } + + getPaginatedItems(): Item[] { + return this.data ?? []; + } + + // @deprecated Please use `nextPageInfo()` instead + nextPageParams(): Partial | null { + const info = this.nextPageInfo(); + if (!info) return null; + if ('params' in info) return info.params; + const params = Object.fromEntries(info.url.searchParams); + if (!Object.keys(params).length) return null; + return params; + } + + nextPageInfo(): PageInfo | null { + const offset = (this.options.query as ContentsPageParams).offset ?? 0; + const length = this.getPaginatedItems().length; + const currentCount = offset + length; + + return { params: { offset: currentCount } }; + } +} diff --git a/src/resources/datastores/contents.ts b/src/resources/datastores/contents.ts new file mode 100644 index 0000000..046805d --- /dev/null +++ b/src/resources/datastores/contents.ts @@ -0,0 +1,240 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../resource'; +import { isRequestOptions } from '../../core'; +import * as Core from '../../core'; +import { ContentsPage, type ContentsPageParams } from '../../pagination'; + +export class Contents extends APIResource { + /** + * Get Document Contents + */ + list( + datastoreId: string, + query?: ContentListParams, + options?: Core.RequestOptions, + ): Core.PagePromise; + list( + datastoreId: string, + options?: Core.RequestOptions, + ): Core.PagePromise; + list( + datastoreId: string, + query: ContentListParams | Core.RequestOptions = {}, + options?: Core.RequestOptions, + ): Core.PagePromise { + if (isRequestOptions(query)) { + return this.list(datastoreId, {}, query); + } + return this._client.getAPIList(`/datastores/${datastoreId}/contents`, ContentListResponsesContentsPage, { + query, + ...options, + }); + } + + /** + * Get Content Metadata + */ + metadata( + datastoreId: string, + contentId: string, + query?: ContentMetadataParams, + options?: Core.RequestOptions, + ): Core.APIPromise; + metadata( + datastoreId: string, + contentId: string, + options?: Core.RequestOptions, + ): Core.APIPromise; + metadata( + datastoreId: string, + contentId: string, + query: ContentMetadataParams | Core.RequestOptions = {}, + options?: Core.RequestOptions, + ): Core.APIPromise { + if (isRequestOptions(query)) { + return this.metadata(datastoreId, contentId, {}, query); + } + return this._client.get(`/datastores/${datastoreId}/contents/${contentId}/metadata`, { + query, + ...options, + }); + } +} + +export class ContentListResponsesContentsPage extends ContentsPage {} + +/** + * Content entry type + */ +export type ContentListResponse = + | ContentListResponse.DocumentContentEntry + | ContentListResponse.StructuredContentEntry; + +export namespace ContentListResponse { + export interface DocumentContentEntry { + /** + * ID of the content + */ + content_id: string; + + /** + * Page number of the content + */ + page_number: number; + + content_type?: 'unstructured'; + } + + /** + * Tabular content entry used in query retrieval. + */ + export interface StructuredContentEntry { + /** + * ID of the content + */ + content_id: string; + + /** + * Name of the table + */ + table_name: string; + + content_type?: 'structured'; + + /** + * Name of the schema of the table + */ + schema?: string | null; + } +} + +/** + * Content type + */ +export type ContentMetadataResponse = + | ContentMetadataResponse.UnstructuredContentMetadata + | ContentMetadataResponse.StructuredContentMetadata + | ContentMetadataResponse.FileAnalysisContentMetadata; + +export namespace ContentMetadataResponse { + export interface UnstructuredContentMetadata { + /** + * Id of the content. + */ + content_id: string; + + /** + * Text of the content. + */ + content_text: string; + + /** + * Id of the document which the content belongs to. + */ + document_id: string; + + /** + * Height of the image. + */ + height: number; + + /** + * Page number of the content. + */ + page: number; + + /** + * Image of the page on which the content occurs. + */ + page_img: string; + + /** + * Width of the image. + */ + width: number; + + /** + * X coordinate of the top left corner on the bounding box. + */ + x0: number; + + /** + * X coordinate of the bottom right corner on the bounding box. + */ + x1: number; + + /** + * Y coordinate of the top left corner on the bounding box. + */ + y0: number; + + /** + * Y coordinate of the bottom right corner on the bounding box. + */ + y1: number; + + content_type?: 'unstructured'; + } + + export interface StructuredContentMetadata { + /** + * Id of the content. + */ + content_id: string; + + /** + * Text of the content. + */ + content_text: unknown; + + content_type?: 'structured'; + } + + export interface FileAnalysisContentMetadata { + /** + * Id of the content. + */ + content_id: string; + + /** + * Format of the file. + */ + file_format: string; + + /** + * GCP location of the file. + */ + gcp_location: string; + + content_type?: 'file_analysis'; + } +} + +export interface ContentListParams extends ContentsPageParams { + /** + * Document ID of the document to retrieve details for + */ + document_id?: string; + + /** + * The query to search keywords for + */ + search?: string; +} + +export interface ContentMetadataParams { + cursor?: string; +} + +Contents.ContentListResponsesContentsPage = ContentListResponsesContentsPage; + +export declare namespace Contents { + export { + type ContentListResponse as ContentListResponse, + type ContentMetadataResponse as ContentMetadataResponse, + ContentListResponsesContentsPage as ContentListResponsesContentsPage, + type ContentListParams as ContentListParams, + type ContentMetadataParams as ContentMetadataParams, + }; +} diff --git a/src/resources/datastores/datastores.ts b/src/resources/datastores/datastores.ts index f78c6c3..34bfe90 100644 --- a/src/resources/datastores/datastores.ts +++ b/src/resources/datastores/datastores.ts @@ -3,6 +3,15 @@ import { APIResource } from '../../resource'; import { isRequestOptions } from '../../core'; import * as Core from '../../core'; +import * as ContentsAPI from './contents'; +import { + ContentListParams, + ContentListResponse, + ContentListResponsesContentsPage, + ContentMetadataParams, + ContentMetadataResponse, + Contents, +} from './contents'; import * as DocumentsAPI from './documents'; import { BaseMetadataFilter, @@ -23,6 +32,7 @@ import { DatastoresPage, type DatastoresPageParams } from '../../pagination'; export class Datastores extends APIResource { documents: DocumentsAPI.Documents = new DocumentsAPI.Documents(this._client); + contents: ContentsAPI.Contents = new ContentsAPI.Contents(this._client); /** * Create a new `Datastore`. @@ -664,6 +674,8 @@ export interface DatastoreListParams extends DatastoresPageParams { Datastores.DatastoresDatastoresPage = DatastoresDatastoresPage; Datastores.Documents = Documents; Datastores.DocumentMetadataDocumentsPage = DocumentMetadataDocumentsPage; +Datastores.Contents = Contents; +Datastores.ContentListResponsesContentsPage = ContentListResponsesContentsPage; export declare namespace Datastores { export { @@ -695,4 +707,13 @@ export declare namespace Datastores { type DocumentIngestParams as DocumentIngestParams, type DocumentSetMetadataParams as DocumentSetMetadataParams, }; + + export { + Contents as Contents, + type ContentListResponse as ContentListResponse, + type ContentMetadataResponse as ContentMetadataResponse, + ContentListResponsesContentsPage as ContentListResponsesContentsPage, + type ContentListParams as ContentListParams, + type ContentMetadataParams as ContentMetadataParams, + }; } diff --git a/src/resources/datastores/index.ts b/src/resources/datastores/index.ts index b8e3e30..2b28448 100644 --- a/src/resources/datastores/index.ts +++ b/src/resources/datastores/index.ts @@ -1,5 +1,13 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +export { + ContentListResponsesContentsPage, + Contents, + type ContentListResponse, + type ContentMetadataResponse, + type ContentListParams, + type ContentMetadataParams, +} from './contents'; export { DatastoresDatastoresPage, Datastores, diff --git a/src/version.ts b/src/version.ts index 5c16194..c2e5b96 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.9.0'; // x-release-please-version +export const VERSION = '0.10.0'; // x-release-please-version diff --git a/tests/api-resources/datastores/contents.test.ts b/tests/api-resources/datastores/contents.test.ts new file mode 100644 index 0000000..618f096 --- /dev/null +++ b/tests/api-resources/datastores/contents.test.ts @@ -0,0 +1,79 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import ContextualAI from 'contextual-client'; +import { Response } from 'node-fetch'; + +const client = new ContextualAI({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource contents', () => { + test('list', async () => { + const responsePromise = client.datastores.contents.list('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('list: request options instead of params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.datastores.contents.list('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { + path: '/_stainless_unknown_path', + }), + ).rejects.toThrow(ContextualAI.NotFoundError); + }); + + test('list: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.datastores.contents.list( + '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + { document_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', limit: 0, offset: 0, search: 'search' }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(ContextualAI.NotFoundError); + }); + + test('metadata', async () => { + const responsePromise = client.datastores.contents.metadata( + '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + ); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('metadata: request options instead of params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.datastores.contents.metadata( + '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(ContextualAI.NotFoundError); + }); + + test('metadata: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.datastores.contents.metadata( + '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + { cursor: 'cursor' }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(ContextualAI.NotFoundError); + }); +});