From e0a9f2f97b003cae4318e2d253b01f05f9cae233 Mon Sep 17 00:00:00 2001 From: William FH <13333726+hinthornw@users.noreply.github.com> Date: Tue, 16 Jan 2024 12:40:32 -0800 Subject: [PATCH] Add version info to user-agent header (#357) --- .github/workflows/js_test.yml | 2 ++ .github/workflows/release_js.yml | 2 ++ js/package.json | 6 ++++-- js/scripts/bump-version.js | 21 +++++++++++++++++++++ js/scripts/check-version.js | 17 +++++++++++++++++ js/src/client.ts | 5 ++++- js/src/index.ts | 3 +++ js/src/utils/env.ts | 26 +++++++++++++++++--------- python/langsmith/client.py | 3 ++- python/langsmith/env/_runtime_env.py | 1 + python/pyproject.toml | 2 +- python/tests/unit_tests/test_client.py | 5 +++-- 12 files changed, 77 insertions(+), 16 deletions(-) create mode 100644 js/scripts/bump-version.js create mode 100644 js/scripts/check-version.js diff --git a/.github/workflows/js_test.yml b/.github/workflows/js_test.yml index 48df0def4..c8309c334 100644 --- a/.github/workflows/js_test.yml +++ b/.github/workflows/js_test.yml @@ -104,5 +104,7 @@ jobs: run: yarn install --immutable - name: Build run: yarn run build + - name: Check version + run: yarn run check-version - name: Test run: yarn run test \ No newline at end of file diff --git a/.github/workflows/release_js.yml b/.github/workflows/release_js.yml index fa7a466a3..81199c183 100644 --- a/.github/workflows/release_js.yml +++ b/.github/workflows/release_js.yml @@ -29,6 +29,8 @@ jobs: run: cd js && yarn install --immutable - name: Build run: cd js && yarn run build + - name: Check version + run: yarn run check-version - name: Publish package to NPM run: | cd js diff --git a/js/package.json b/js/package.json index 459ea066a..95a8e1b4b 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "langsmith", - "version": "0.0.59", + "version": "0.0.60", "description": "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform.", "files": [ "dist/", @@ -28,6 +28,8 @@ "types": "./dist/index.d.ts", "scripts": { "build": "yarn clean && yarn build:esm && yarn build:cjs && node scripts/create-entrypoints.js && node scripts/create-cli.js", + "bump-version": "node scripts/bump-version.js", + "check-version": "node scripts/check-version.js", "clean": "rm -rf dist/ && node scripts/create-entrypoints.js clean", "build:esm": "tsc --outDir dist/ && rm -rf dist/tests dist/**/tests", "build:cjs": "tsc --outDir dist-cjs/ -p tsconfig.cjs.json && node scripts/move-cjs-to-dist.js && rm -r dist-cjs", @@ -119,4 +121,4 @@ }, "./package.json": "./package.json" } -} +} \ No newline at end of file diff --git a/js/scripts/bump-version.js b/js/scripts/bump-version.js new file mode 100644 index 000000000..f8abbfc1e --- /dev/null +++ b/js/scripts/bump-version.js @@ -0,0 +1,21 @@ +import { readFileSync, writeFileSync } from 'fs'; +import process from 'process'; +const packageJson = JSON.parse(readFileSync('package.json')); + +let newVersion; +if (process.argv.length > 2) { + newVersion = process.argv[2]; +} else { + const versionParts = packageJson.version.split('.'); + versionParts[2] = parseInt(versionParts[2]) + 1; + newVersion = versionParts.join('.'); +} +console.log(`Bumping version to ${newVersion}`); + +packageJson.version = newVersion; +writeFileSync('package.json', JSON.stringify(packageJson, null, 2)); + +const indexFilePath = 'src/index.ts'; +let indexFileContent = readFileSync(indexFilePath, 'utf-8'); +indexFileContent = indexFileContent.replace(/export const __version__ = "[0-9]+\.[0-9]+\.[0-9]+";/g, `export const __version__ = "${newVersion}";`); +writeFileSync(indexFilePath, indexFileContent); diff --git a/js/scripts/check-version.js b/js/scripts/check-version.js new file mode 100644 index 000000000..70642b576 --- /dev/null +++ b/js/scripts/check-version.js @@ -0,0 +1,17 @@ +import { readFileSync } from "fs"; +import { join } from "path"; +const indexFilePath = "src/index.ts"; +const packageJson = JSON.parse(readFileSync("package.json")); +let indexFileContent = readFileSync(indexFilePath, "utf-8"); + +const packageVersion = packageJson.version; +const indexVersion = indexFileContent.match( + /__version__\s*=\s*['"]([^'"]+)['"]/ +)[1]; + +if (packageVersion !== indexVersion) { + throw new Error( + `Version mismatch! package.json version: ${packageVersion}, index.ts version: ${indexVersion}` + ); +} +console.log(`Version check passed: ${packageVersion} === ${indexVersion}`); \ No newline at end of file diff --git a/js/src/client.ts b/js/src/client.ts index edae1b327..609bc6c53 100644 --- a/js/src/client.ts +++ b/js/src/client.ts @@ -26,6 +26,7 @@ import { import { getEnvironmentVariable, getRuntimeEnvironment } from "./utils/env.js"; import { RunEvaluator } from "./evaluation/evaluator.js"; +import { __version__ } from "./index.js"; interface ClientConfig { apiUrl?: string; @@ -243,7 +244,9 @@ export class Client { } private get headers(): { [header: string]: string } { - const headers: { [header: string]: string } = {}; + const headers: { [header: string]: string } = { + "User-Agent": `langsmith-js/${__version__}`, + }; if (this.apiKey) { headers["x-api-key"] = `${this.apiKey}`; } diff --git a/js/src/index.ts b/js/src/index.ts index 6bbee102e..02336604e 100644 --- a/js/src/index.ts +++ b/js/src/index.ts @@ -3,3 +3,6 @@ export { Client } from "./client.js"; export { Dataset, Example, TracerSession, Run, Feedback } from "./schemas.js"; export { RunTree, RunTreeConfig } from "./run_trees.js"; + +// Update using yarn bump-version +export const __version__ = "0.0.60"; diff --git a/js/src/utils/env.ts b/js/src/utils/env.ts index 91d4f7999..d5a15f203 100644 --- a/js/src/utils/env.ts +++ b/js/src/utils/env.ts @@ -1,4 +1,5 @@ // Inlined from https://github.com/flexdinesh/browser-or-node +import { __version__ } from "../index.js"; declare global { const Deno: | { @@ -9,6 +10,8 @@ declare global { | undefined; } +let globalEnv: string; + export const isBrowser = () => typeof window !== "undefined" && typeof window.document !== "undefined"; @@ -35,27 +38,31 @@ export const isNode = () => !isDeno(); export const getEnv = () => { - let env: string; + if (globalEnv) { + return globalEnv; + } if (isBrowser()) { - env = "browser"; + globalEnv = "browser"; } else if (isNode()) { - env = "node"; + globalEnv = "node"; } else if (isWebWorker()) { - env = "webworker"; + globalEnv = "webworker"; } else if (isJsDom()) { - env = "jsdom"; + globalEnv = "jsdom"; } else if (isDeno()) { - env = "deno"; + globalEnv = "deno"; } else { - env = "other"; + globalEnv = "other"; } - return env; + return globalEnv; }; export type RuntimeEnvironment = { library: string; libraryVersion?: string; + sdk: string; + sdk_version: string; runtime: string; runtimeVersion?: string; }; @@ -66,10 +73,11 @@ export async function getRuntimeEnvironment(): Promise { if (runtimeEnvironment === undefined) { const env = getEnv(); const releaseEnv = getShas(); - runtimeEnvironment = { library: "langsmith", runtime: env, + sdk: "langsmith-js", + sdk_version: __version__, ...releaseEnv, }; } diff --git a/python/langsmith/client.py b/python/langsmith/client.py index 203c78bd9..b8a706116 100644 --- a/python/langsmith/client.py +++ b/python/langsmith/client.py @@ -37,6 +37,7 @@ from requests import adapters as requests_adapters from urllib3.util import Retry +import langsmith from langsmith import env as ls_env from langsmith import schemas as ls_schemas from langsmith import utils as ls_utils @@ -362,7 +363,7 @@ def _headers(self) -> Dict[str, str]: Dict[str, str] The headers for the API request. """ - headers = {} + headers = {"User-Agent": f"langsmith-py/{langsmith.__version__}"} if self.api_key: headers["x-api-key"] = self.api_key return headers diff --git a/python/langsmith/env/_runtime_env.py b/python/langsmith/env/_runtime_env.py index d43123203..635da5341 100644 --- a/python/langsmith/env/_runtime_env.py +++ b/python/langsmith/env/_runtime_env.py @@ -68,6 +68,7 @@ def get_runtime_environment() -> dict: shas = get_release_shas() return { + "sdk": "langsmith-py", "sdk_version": __version__, "library": "langsmith", "platform": platform.platform(), diff --git a/python/pyproject.toml b/python/pyproject.toml index dec91b451..64a753cab 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langsmith" -version = "0.0.80" +version = "0.0.81" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." authors = ["LangChain "] license = "MIT" diff --git a/python/tests/unit_tests/test_client.py b/python/tests/unit_tests/test_client.py index 09780345c..c3d24a351 100644 --- a/python/tests/unit_tests/test_client.py +++ b/python/tests/unit_tests/test_client.py @@ -51,10 +51,11 @@ def test_validate_api_key_if_hosted(monkeypatch: pytest.MonkeyPatch) -> None: def test_headers(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.delenv("LANGCHAIN_API_KEY", raising=False) client = Client(api_url="http://localhost:1984", api_key="123") - assert client._headers == {"x-api-key": "123"} + assert "x-api-key" in client._headers + assert client._headers["x-api-key"] == "123" client_no_key = Client(api_url="http://localhost:1984") - assert client_no_key._headers == {} + assert "x-api-key" not in client_no_key._headers @mock.patch("langsmith.client.requests.Session")