From df83e1b39a8b3109ffff0795a82432883b1950a4 Mon Sep 17 00:00:00 2001 From: suguanYang Date: Mon, 13 Jul 2026 15:53:01 +0800 Subject: [PATCH] Attach notebook client metadata on Knowhere job creates. Share official-client defaults for created_by_client so OSS telemetry can attribute notebook uploads without leaking document content. Co-authored-by: Cursor --- src/domains/sources/document-metadata.test.ts | 49 +++++++++++++++++++ src/domains/sources/document-metadata.ts | 26 ++++++++++ src/domains/sources/knowhere-upload.ts | 15 +----- src/domains/sources/retry.test.ts | 1 + src/domains/sources/retry.ts | 15 +----- src/domains/sources/upload.test.ts | 2 + 6 files changed, 80 insertions(+), 28 deletions(-) create mode 100644 src/domains/sources/document-metadata.test.ts create mode 100644 src/domains/sources/document-metadata.ts diff --git a/src/domains/sources/document-metadata.test.ts b/src/domains/sources/document-metadata.test.ts new file mode 100644 index 0000000..ba64346 --- /dev/null +++ b/src/domains/sources/document-metadata.test.ts @@ -0,0 +1,49 @@ +import { describe, expect, it } from "vitest" + +import { + createNotebookDocumentMetadata, + NOTEBOOK_DOCUMENT_METADATA_DEFAULTS, +} from "./document-metadata" + +describe("createNotebookDocumentMetadata", () => { + it("attaches notebook client identity and display fields", () => { + expect( + createNotebookDocumentMetadata({ + title: "notes.pdf", + mimeType: "application/pdf", + sizeBytes: 12, + }), + ).toEqual({ + createdByClient: "notebook", + clientVersion: "0.1.0", + sourceFileName: "notes.pdf", + title: "notes.pdf", + mimeType: "application/pdf", + sizeBytes: 12, + }) + }) + + it("lets caller overrides win for identity fields", () => { + expect( + createNotebookDocumentMetadata({ + title: "notes.pdf", + mimeType: "application/pdf", + sizeBytes: 12, + overrides: { + createdByClient: "api", + clientVersion: "9.9.9", + }, + }), + ).toMatchObject({ + createdByClient: "api", + clientVersion: "9.9.9", + }) + }) + + it("exports notebook defaults", () => { + expect(NOTEBOOK_DOCUMENT_METADATA_DEFAULTS).toEqual({ + createdByClient: "notebook", + clientVersion: "0.1.0", + }) + }) +}) diff --git a/src/domains/sources/document-metadata.ts b/src/domains/sources/document-metadata.ts new file mode 100644 index 0000000..d6b608f --- /dev/null +++ b/src/domains/sources/document-metadata.ts @@ -0,0 +1,26 @@ +import packageJson from "../../../package.json"; + +/** + * Official notebook client identity for job `document_metadata`. + * Caller overrides win; defaults fill missing keys only when merged. + */ +export const NOTEBOOK_DOCUMENT_METADATA_DEFAULTS = { + createdByClient: "notebook", + clientVersion: packageJson.version, +} as const; + +export function createNotebookDocumentMetadata(input: { + readonly title: string; + readonly mimeType: string; + readonly sizeBytes: number; + readonly overrides?: Readonly>; +}): Readonly> { + return { + ...NOTEBOOK_DOCUMENT_METADATA_DEFAULTS, + sourceFileName: input.title, + title: input.title, + mimeType: input.mimeType, + sizeBytes: input.sizeBytes, + ...input.overrides, + }; +} diff --git a/src/domains/sources/knowhere-upload.ts b/src/domains/sources/knowhere-upload.ts index cdfdca5..1ea8396 100644 --- a/src/domains/sources/knowhere-upload.ts +++ b/src/domains/sources/knowhere-upload.ts @@ -15,6 +15,7 @@ import { validateUploadFile } from "./validation" import { TempFile, tempFileLayer } from "@/lib/temp-files" import { getUploadNamespace } from "./namespace" import { sourceFailureMessage } from "./failure-message" +import { createNotebookDocumentMetadata } from "./document-metadata" /** * Upload a browser file to Knowhere for parsing. @@ -213,20 +214,6 @@ const markSourceParsingEffect = (input: { ), ) -function createNotebookDocumentMetadata(input: { - readonly title: string - readonly mimeType: string - readonly sizeBytes: number -}): Readonly> { - return { - createdByClient: "notebook", - sourceFileName: input.title, - title: input.title, - mimeType: input.mimeType, - sizeBytes: input.sizeBytes, - } -} - function getDocumentId(job: UploadJobResult): string | null { return typeof job.documentId === "string" && job.documentId.length > 0 ? job.documentId diff --git a/src/domains/sources/retry.test.ts b/src/domains/sources/retry.test.ts index 19eb565..36c0eec 100644 --- a/src/domains/sources/retry.test.ts +++ b/src/domains/sources/retry.test.ts @@ -55,6 +55,7 @@ describe("retrySourceToKnowhereEffect", () => { namespace: "default", documentMetadata: { createdByClient: "notebook", + clientVersion: "0.1.0", sourceFileName: "notes.pdf", title: "notes.pdf", mimeType: "application/pdf", diff --git a/src/domains/sources/retry.ts b/src/domains/sources/retry.ts index 15ada9a..4ba37b4 100644 --- a/src/domains/sources/retry.ts +++ b/src/domains/sources/retry.ts @@ -9,6 +9,7 @@ import type { UploadKnowhereClient, } from "./source-upload-contracts" import { sourceFailureMessage } from "./failure-message" +import { createNotebookDocumentMetadata } from "./document-metadata" type RetrySourceRepository = { readonly markSourceParsing: ( @@ -123,20 +124,6 @@ const tryGetPlannedDocumentIdEffect = ( }).pipe(Effect.catchAll(() => Effect.succeed(null))) } -function createNotebookDocumentMetadata(input: { - readonly title: string - readonly mimeType: string - readonly sizeBytes: number -}): Readonly> { - return { - createdByClient: "notebook", - sourceFileName: input.title, - title: input.title, - mimeType: input.mimeType, - sizeBytes: input.sizeBytes, - } -} - function getDocumentId(job: UploadJobResult): string | null { return typeof job.documentId === "string" && job.documentId.length > 0 ? job.documentId diff --git a/src/domains/sources/upload.test.ts b/src/domains/sources/upload.test.ts index 77c9022..a9ad74c 100644 --- a/src/domains/sources/upload.test.ts +++ b/src/domains/sources/upload.test.ts @@ -113,6 +113,7 @@ describe("uploadSourceToKnowhere", () => { namespace: "default", documentMetadata: { createdByClient: "notebook", + clientVersion: "0.1.0", sourceFileName: "notes.pdf", title: "notes.pdf", mimeType: "application/pdf", @@ -324,6 +325,7 @@ describe("uploadSourceToKnowhere", () => { namespace: "default", documentMetadata: { createdByClient: "notebook", + clientVersion: "0.1.0", sourceFileName: "large.pdf", title: "large.pdf", mimeType: "application/pdf",