Skip to content

Commit

Permalink
merge and fix lint
Browse files Browse the repository at this point in the history
  • Loading branch information
agola11 committed Jul 19, 2024
2 parents 1bf6427 + 5cd607b commit 96cfdfb
Show file tree
Hide file tree
Showing 35 changed files with 2,187 additions and 121 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/python_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
- name: Install dependencies
run: |
poetry install --with dev,lint
poetry run pip install -U langchain langchain-core langchain-openai
poetry run pip install -U langchain langchain-core langchain_anthropic langchain_openai
- name: Build ${{ matrix.python-version }}
run: poetry build
- name: Lint ${{ matrix.python-version }}
Expand Down
18 changes: 12 additions & 6 deletions _scripts/_fetch_schema.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Fetch and prune the Langsmith spec."""

import argparse
from pathlib import Path

Expand All @@ -19,7 +20,9 @@ def process_schema(sub_schema):
get_dependencies(schema, sub_schema["$ref"].split("/")[-1], new_components)
else:
if "items" in sub_schema and "$ref" in sub_schema["items"]:
get_dependencies(schema, sub_schema["items"]["$ref"].split("/")[-1], new_components)
get_dependencies(
schema, sub_schema["items"]["$ref"].split("/")[-1], new_components
)
for keyword in ["anyOf", "oneOf", "allOf"]:
if keyword in sub_schema:
for item in sub_schema[keyword]:
Expand All @@ -38,8 +41,6 @@ def process_schema(sub_schema):
process_schema(item)




def _extract_langsmith_routes_and_properties(schema, operation_ids):
new_paths = {}
new_components = {"schemas": {}}
Expand Down Expand Up @@ -98,20 +99,25 @@ def test_openapi_specification(spec: dict):
assert errors is None, f"OpenAPI validation failed: {errors}"


def main(out_file: str = "openapi.yaml", url: str = "https://web.smith.langchain.com/openapi.json"):
def main(
out_file: str = "openapi.yaml",
url: str = "https://web.smith.langchain.com/openapi.json",
):
langsmith_schema = get_langsmith_runs_schema(url=url)
parent_dir = Path(__file__).parent.parent
test_openapi_specification(langsmith_schema)
with (parent_dir / "openapi" / out_file).open("w") as f:
# Sort the schema keys so the openapi version and info come at the top
for key in ['openapi', 'info', 'paths', 'components']:
for key in ["openapi", "info", "paths", "components"]:
langsmith_schema[key] = langsmith_schema.pop(key)
f.write(yaml.dump(langsmith_schema, sort_keys=False))


if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--url", type=str, default="https://web.smith.langchain.com/openapi.json")
parser.add_argument(
"--url", type=str, default="https://web.smith.langchain.com/openapi.json"
)
parser.add_argument("--output", type=str, default="openapi.yaml")
args = parser.parse_args()
main(args.output, url=args.url)
1 change: 1 addition & 0 deletions js/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ Tracing can be activated by setting the following environment variables or by ma
```typescript
process.env["LANGSMITH_TRACING"] = "true";
process.env["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com";
// process.env["LANGCHAIN_ENDPOINT"] = "https://eu.api.smith.langchain.com"; // If signed up in the EU region
process.env["LANGCHAIN_API_KEY"] = "<YOUR-LANGSMITH-API-KEY>";
// process.env["LANGCHAIN_PROJECT"] = "My Project Name"; // Optional: "default" is used if not set
```
Expand Down
2 changes: 1 addition & 1 deletion js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "langsmith",
"version": "0.1.36",
"version": "0.1.38",
"description": "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform.",
"packageManager": "yarn@1.22.19",
"files": [
Expand Down
116 changes: 116 additions & 0 deletions js/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
Example,
ExampleCreate,
ExampleUpdate,
ExampleUpdateWithId,
Feedback,
FeedbackConfig,
FeedbackIngestToken,
Expand Down Expand Up @@ -481,6 +482,9 @@ export class Client {
} else if (this.apiUrl.split(".", 1)[0].includes("dev")) {
this.webUrl = "https://dev.smith.langchain.com";
return this.webUrl;
} else if (this.apiUrl.split(".", 1)[0].includes("eu")) {
this.webUrl = "https://eu.smith.langchain.com";
return this.webUrl;
} else {
this.webUrl = "https://smith.langchain.com";
return this.webUrl;
Expand Down Expand Up @@ -2300,6 +2304,118 @@ export class Client {
return result;
}

public async updateExamples(update: ExampleUpdateWithId[]): Promise<object> {
const response = await this.caller.call(
fetch,
`${this.apiUrl}/examples/bulk`,
{
method: "PATCH",
headers: { ...this.headers, "Content-Type": "application/json" },
body: JSON.stringify(update),
signal: AbortSignal.timeout(this.timeout_ms),
...this.fetchOptions,
}
);
if (!response.ok) {
throw new Error(
`Failed to update examples: ${response.status} ${response.statusText}`
);
}
const result = await response.json();
return result;
}

public async listDatasetSplits({
datasetId,
datasetName,
asOf,
}: {
datasetId?: string;
datasetName?: string;
asOf?: string | Date;
}): Promise<string[]> {
let datasetId_: string;
if (datasetId === undefined && datasetName === undefined) {
throw new Error("Must provide dataset name or ID");
} else if (datasetId !== undefined && datasetName !== undefined) {
throw new Error("Must provide either datasetName or datasetId, not both");
} else if (datasetId === undefined) {
const dataset = await this.readDataset({ datasetName });
datasetId_ = dataset.id;
} else {
datasetId_ = datasetId;
}

assertUuid(datasetId_);

const params = new URLSearchParams();
const dataset_version = asOf
? typeof asOf === "string"
? asOf
: asOf?.toISOString()
: undefined;
if (dataset_version) {
params.append("as_of", dataset_version);
}

const response = await this._get<string[]>(
`/datasets/${datasetId_}/splits`,
params
);
return response;
}

public async updateDatasetSplits({
datasetId,
datasetName,
splitName,
exampleIds,
remove = false,
}: {
datasetId?: string;
datasetName?: string;
splitName: string;
exampleIds: string[];
remove?: boolean;
}): Promise<void> {
let datasetId_: string;
if (datasetId === undefined && datasetName === undefined) {
throw new Error("Must provide dataset name or ID");
} else if (datasetId !== undefined && datasetName !== undefined) {
throw new Error("Must provide either datasetName or datasetId, not both");
} else if (datasetId === undefined) {
const dataset = await this.readDataset({ datasetName });
datasetId_ = dataset.id;
} else {
datasetId_ = datasetId;
}

assertUuid(datasetId_);

const data = {
split_name: splitName,
examples: exampleIds.map((id) => {
assertUuid(id);
return id;
}),
remove,
};

const response = await this.caller.call(
fetch,
`${this.apiUrl}/datasets/${datasetId_}/splits`,
{
method: "PUT",
headers: { ...this.headers, "Content-Type": "application/json" },
body: JSON.stringify(data),
signal: AbortSignal.timeout(this.timeout_ms),
...this.fetchOptions,
}
);

await raiseForStatus(response, "update dataset splits");
}

/**
* @deprecated This method is deprecated and will be removed in future LangSmith versions, use `evaluate` from `langsmith/evaluation` instead.
*/
Expand Down
2 changes: 1 addition & 1 deletion js/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ export type {
export { RunTree, type RunTreeConfig } from "./run_trees.js";

// Update using yarn bump-version
export const __version__ = "0.1.36";
export const __version__ = "0.1.38";
21 changes: 15 additions & 6 deletions js/src/langchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,21 @@ export async function getLangchainCallbacks(
}

if (langChainTracer != null) {
Object.assign(langChainTracer, {
runMap,
client: runTree.client,
projectName: runTree.project_name || langChainTracer.projectName,
exampleId: runTree.reference_example_id || langChainTracer.exampleId,
});
if (
"updateFromRunTree" in langChainTracer &&
typeof langChainTracer === "function"
) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore @langchain/core can use a different version of LangSmith
langChainTracer.updateFromRunTree(runTree);
} else {
Object.assign(langChainTracer, {
runMap,
client: runTree.client,
projectName: runTree.project_name || langChainTracer.projectName,
exampleId: runTree.reference_example_id || langChainTracer.exampleId,
});
}
}

return callbacks;
Expand Down
60 changes: 52 additions & 8 deletions js/src/run_trees.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,19 @@ export interface RunnableConfigLike {
interface CallbackManagerLike {
handlers: TracerLike[];
getParentRunId?: () => string | undefined;
copy?: () => CallbackManagerLike;
}

interface TracerLike {
name: string;
}

interface LangChainTracerLike extends TracerLike {
name: "langchain_tracer";
projectName: string;
getRun?: (id: string) => RunTree | undefined;
client: Client;
updateFromRunTree?: (runTree: RunTree) => void;
}

interface HeadersLike {
Expand Down Expand Up @@ -236,6 +239,36 @@ export class RunTree implements BaseRun {
child_execution_order: child_execution_order,
});

type ExtraWithSymbol = Record<string | symbol, unknown>;
const LC_CHILD = Symbol.for("lc:child_config");

const presentConfig =
(config.extra as ExtraWithSymbol | undefined)?.[LC_CHILD] ??
(this.extra as ExtraWithSymbol)[LC_CHILD];

// tracing for LangChain is defined by the _parentRunId and runMap of the tracer
if (isRunnableConfigLike(presentConfig)) {
const newConfig: RunnableConfigLike = { ...presentConfig };
const callbacks: CallbackManagerLike | unknown[] | undefined =
isCallbackManagerLike(newConfig.callbacks)
? newConfig.callbacks.copy?.()
: undefined;

if (callbacks) {
// update the parent run id
Object.assign(callbacks, { _parentRunId: child.id });

// only populate if we're in a newer LC.JS version
callbacks.handlers
?.find(isLangChainTracerLike)
?.updateFromRunTree?.(child);

newConfig.callbacks = callbacks;
}

(child.extra as ExtraWithSymbol)[LC_CHILD] = newConfig;
}

// propagate child_execution_order upwards
const visited = new Set<string>();
let current: RunTree | undefined = this as RunTree;
Expand Down Expand Up @@ -475,15 +508,26 @@ export function isRunTree(x?: unknown): x is RunTree {
);
}

function containsLangChainTracerLike(x?: unknown): x is LangChainTracerLike[] {
function isLangChainTracerLike(x: unknown): x is LangChainTracerLike {
return (
Array.isArray(x) &&
x.some((callback: unknown) => {
return (
typeof (callback as LangChainTracerLike).name === "string" &&
(callback as LangChainTracerLike).name === "langchain_tracer"
);
})
typeof x === "object" &&
x != null &&
typeof (x as LangChainTracerLike).name === "string" &&
(x as LangChainTracerLike).name === "langchain_tracer"
);
}

function containsLangChainTracerLike(x: unknown): x is LangChainTracerLike[] {
return (
Array.isArray(x) && x.some((callback) => isLangChainTracerLike(callback))
);
}

function isCallbackManagerLike(x: unknown): x is CallbackManagerLike {
return (
typeof x === "object" &&
x != null &&
Array.isArray((x as CallbackManagerLike).handlers)
);
}

Expand Down
4 changes: 4 additions & 0 deletions js/src/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,10 @@ export interface ExampleUpdate {
metadata?: KVMap;
split?: string | string[];
}

export interface ExampleUpdateWithId extends ExampleUpdate {
id: string;
}
export interface BaseDataset {
name: string;
description: string;
Expand Down
17 changes: 9 additions & 8 deletions js/src/singletons/traceable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,21 @@ class MockAsyncLocalStorage implements AsyncLocalStorageInterface {
}
}

class AsyncLocalStorageProvider {
private asyncLocalStorage: AsyncLocalStorageInterface =
new MockAsyncLocalStorage();
const TRACING_ALS_KEY = Symbol.for("ls:tracing_async_local_storage");

private hasBeenInitialized = false;
const mockAsyncLocalStorage = new MockAsyncLocalStorage();

class AsyncLocalStorageProvider {
getInstance(): AsyncLocalStorageInterface {
return this.asyncLocalStorage;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (globalThis as any)[TRACING_ALS_KEY] ?? mockAsyncLocalStorage;
}

initializeGlobalInstance(instance: AsyncLocalStorageInterface) {
if (!this.hasBeenInitialized) {
this.hasBeenInitialized = true;
this.asyncLocalStorage = instance;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if ((globalThis as any)[TRACING_ALS_KEY] === undefined) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(globalThis as any)[TRACING_ALS_KEY] = instance;
}
}
}
Expand Down
Loading

0 comments on commit 96cfdfb

Please sign in to comment.