From d0ef53ab325e6607fe6d360747c7e4397a662657 Mon Sep 17 00:00:00 2001 From: lforst <8118419+lforst@users.noreply.github.com> Date: Thu, 23 Jul 2026 15:03:48 +0000 Subject: [PATCH 1/3] feat: Add instrumentation for `@huggingface/transformers` --- e2e/config/pr-comment-scenarios.json | 23 + ...ce-transformers-v3-auto-esm.span-tree.json | 175 +++ ...ace-transformers-v3-auto-esm.span-tree.txt | 127 ++ ...sformers-v3-latest-auto-esm.span-tree.json | 175 +++ ...nsformers-v3-latest-auto-esm.span-tree.txt | 127 ++ ...nsformers-v3-latest-wrapped.span-tree.json | 175 +++ ...ansformers-v3-latest-wrapped.span-tree.txt | 127 ++ ...ace-transformers-v3-wrapped.span-tree.json | 175 +++ ...face-transformers-v3-wrapped.span-tree.txt | 127 ++ ...ce-transformers-v4-auto-esm.span-tree.json | 175 +++ ...ace-transformers-v4-auto-esm.span-tree.txt | 127 ++ ...sformers-v4-latest-auto-cjs.span-tree.json | 175 +++ ...nsformers-v4-latest-auto-cjs.span-tree.txt | 127 ++ ...sformers-v4-latest-auto-esm.span-tree.json | 175 +++ ...nsformers-v4-latest-auto-esm.span-tree.txt | 127 ++ ...nsformers-v4-latest-wrapped.span-tree.json | 175 +++ ...ansformers-v4-latest-wrapped.span-tree.txt | 127 ++ ...ace-transformers-v4-wrapped.span-tree.json | 175 +++ ...face-transformers-v4-wrapped.span-tree.txt | 127 ++ .../assertions.ts | 109 ++ .../package.json | 25 + .../pnpm-lock.yaml | 1066 +++++++++++++++++ .../scenario.auto.cjs | 7 + .../scenario.auto.mjs | 9 + .../scenario.impl.mjs | 211 ++++ .../scenario.test.ts | 101 ++ .../scenario.wrapper.ts | 13 + js/src/auto-instrumentations/configs/all.ts | 6 +- .../configs/huggingface-transformers.ts | 64 + js/src/exports.ts | 1 + .../instrumentation/braintrust-plugin.test.ts | 18 + js/src/instrumentation/braintrust-plugin.ts | 10 + js/src/instrumentation/config.ts | 2 + .../huggingface-transformers-channels.ts | 61 + .../huggingface-transformers-plugin.test.ts | 127 ++ .../huggingface-transformers-plugin.ts | 317 +++++ .../huggingface-transformers.ts | 45 + .../wrappers/huggingface-transformers.test.ts | 170 +++ js/src/wrappers/huggingface-transformers.ts | 165 +++ 39 files changed, 5267 insertions(+), 1 deletion(-) create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-auto-esm.span-tree.json create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-auto-esm.span-tree.txt create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-latest-auto-esm.span-tree.json create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-latest-auto-esm.span-tree.txt create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-latest-wrapped.span-tree.json create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-latest-wrapped.span-tree.txt create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-wrapped.span-tree.json create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-wrapped.span-tree.txt create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-auto-esm.span-tree.json create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-auto-esm.span-tree.txt create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-auto-cjs.span-tree.json create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-auto-cjs.span-tree.txt create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-auto-esm.span-tree.json create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-auto-esm.span-tree.txt create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-wrapped.span-tree.json create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-wrapped.span-tree.txt create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-wrapped.span-tree.json create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-wrapped.span-tree.txt create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/assertions.ts create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/package.json create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/pnpm-lock.yaml create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/scenario.auto.cjs create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/scenario.auto.mjs create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/scenario.impl.mjs create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/scenario.test.ts create mode 100644 e2e/scenarios/huggingface-transformers-instrumentation/scenario.wrapper.ts create mode 100644 js/src/auto-instrumentations/configs/huggingface-transformers.ts create mode 100644 js/src/instrumentation/plugins/huggingface-transformers-channels.ts create mode 100644 js/src/instrumentation/plugins/huggingface-transformers-plugin.test.ts create mode 100644 js/src/instrumentation/plugins/huggingface-transformers-plugin.ts create mode 100644 js/src/vendor-sdk-types/huggingface-transformers.ts create mode 100644 js/src/wrappers/huggingface-transformers.test.ts create mode 100644 js/src/wrappers/huggingface-transformers.ts diff --git a/e2e/config/pr-comment-scenarios.json b/e2e/config/pr-comment-scenarios.json index a644fd45d..7ab65ad1d 100644 --- a/e2e/config/pr-comment-scenarios.json +++ b/e2e/config/pr-comment-scenarios.json @@ -297,6 +297,29 @@ } ] }, + { + "scenarioDirName": "huggingface-transformers-instrumentation", + "label": "Hugging Face Transformers.js Instrumentation", + "metadataScenario": "huggingface-transformers-instrumentation", + "variants": [ + { + "variantKey": "huggingface-transformers-v3", + "label": "v3 pinned" + }, + { + "variantKey": "huggingface-transformers-v3-latest", + "label": "v3 latest" + }, + { + "variantKey": "huggingface-transformers-v4", + "label": "v4 pinned" + }, + { + "variantKey": "huggingface-transformers-v4-latest", + "label": "v4 latest" + } + ] + }, { "scenarioDirName": "langgraph-auto-instrumentation", "label": "LangGraph Auto-Instrumentation", diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-auto-esm.span-tree.json b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-auto-esm.span-tree.json new file mode 100644 index 000000000..e390ae0a4 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-auto-esm.span-tree.json @@ -0,0 +1,175 @@ +{ + "span_tree": [ + { + "name": "huggingface-transformers-instrumentation-root", + "type": "task", + "children": [ + { + "name": "transformers-text-generation-operation", + "children": [ + { + "name": "huggingface.transformers.text_generation", + "type": "llm", + "children": [], + "input": [ + { + "content": "Hello", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/text-generation", + "provider": "huggingface", + "temperature": 0 + } + } + ], + "metadata": { + "operation": "text-generation", + "testRunId": "" + } + }, + { + "name": "transformers-text2text-generation-operation", + "children": [ + { + "name": "huggingface.transformers.text2text_generation", + "type": "llm", + "children": [], + "input": [ + { + "content": "Translate this", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/text2text-generation", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "text2text-generation", + "testRunId": "" + } + }, + { + "name": "transformers-summarization-operation", + "children": [ + { + "name": "huggingface.transformers.summarization", + "type": "llm", + "children": [], + "input": [ + { + "content": "A deliberately long passage.", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/summarization", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "summarization", + "testRunId": "" + } + }, + { + "name": "transformers-feature-extraction-operation", + "children": [ + { + "name": "huggingface.transformers.feature_extraction", + "type": "llm", + "children": [], + "input": "Embed this", + "output": { + "embedding_batch_count": 1, + "embedding_count": 1, + "embedding_length": 3 + }, + "metadata": { + "model": "fixture/feature-extraction", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "feature-extraction", + "testRunId": "" + } + }, + { + "name": "transformers-question-answering-operation", + "children": [ + { + "name": "huggingface.transformers.question_answering", + "type": "llm", + "children": [], + "input": [ + { + "content": "Context:\nAda built it.\n\nQuestion:\nWho built it?", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Ada", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/question-answering", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "question-answering", + "testRunId": "" + } + } + ], + "metadata": { + "scenario": "huggingface-transformers-instrumentation", + "testRunId": "" + } + } + ] +} diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-auto-esm.span-tree.txt b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-auto-esm.span-tree.txt new file mode 100644 index 000000000..75ee4dfa8 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-auto-esm.span-tree.txt @@ -0,0 +1,127 @@ +span_tree: +└── huggingface-transformers-instrumentation-root [task] + metadata: { + "scenario": "huggingface-transformers-instrumentation", + "testRunId": "" + } + ├── transformers-text-generation-operation + │ metadata: { + │ "operation": "text-generation", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.text_generation [llm] + │ input: [ + │ { + │ "content": "Hello", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/text-generation", + │ "provider": "huggingface", + │ "temperature": 0 + │ } + ├── transformers-text2text-generation-operation + │ metadata: { + │ "operation": "text2text-generation", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.text2text_generation [llm] + │ input: [ + │ { + │ "content": "Translate this", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/text2text-generation", + │ "provider": "huggingface" + │ } + ├── transformers-summarization-operation + │ metadata: { + │ "operation": "summarization", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.summarization [llm] + │ input: [ + │ { + │ "content": "A deliberately long passage.", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/summarization", + │ "provider": "huggingface" + │ } + ├── transformers-feature-extraction-operation + │ metadata: { + │ "operation": "feature-extraction", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.feature_extraction [llm] + │ input: "Embed this" + │ output: { + │ "embedding_batch_count": 1, + │ "embedding_count": 1, + │ "embedding_length": 3 + │ } + │ metadata: { + │ "model": "fixture/feature-extraction", + │ "provider": "huggingface" + │ } + └── transformers-question-answering-operation + metadata: { + "operation": "question-answering", + "testRunId": "" + } + └── huggingface.transformers.question_answering [llm] + input: [ + { + "content": "Context:\nAda built it.\n\nQuestion:\nWho built it?", + "role": "user" + } + ] + output: [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Ada", + "role": "assistant" + } + } + ] + metadata: { + "model": "fixture/question-answering", + "provider": "huggingface" + } diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-latest-auto-esm.span-tree.json b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-latest-auto-esm.span-tree.json new file mode 100644 index 000000000..e390ae0a4 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-latest-auto-esm.span-tree.json @@ -0,0 +1,175 @@ +{ + "span_tree": [ + { + "name": "huggingface-transformers-instrumentation-root", + "type": "task", + "children": [ + { + "name": "transformers-text-generation-operation", + "children": [ + { + "name": "huggingface.transformers.text_generation", + "type": "llm", + "children": [], + "input": [ + { + "content": "Hello", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/text-generation", + "provider": "huggingface", + "temperature": 0 + } + } + ], + "metadata": { + "operation": "text-generation", + "testRunId": "" + } + }, + { + "name": "transformers-text2text-generation-operation", + "children": [ + { + "name": "huggingface.transformers.text2text_generation", + "type": "llm", + "children": [], + "input": [ + { + "content": "Translate this", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/text2text-generation", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "text2text-generation", + "testRunId": "" + } + }, + { + "name": "transformers-summarization-operation", + "children": [ + { + "name": "huggingface.transformers.summarization", + "type": "llm", + "children": [], + "input": [ + { + "content": "A deliberately long passage.", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/summarization", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "summarization", + "testRunId": "" + } + }, + { + "name": "transformers-feature-extraction-operation", + "children": [ + { + "name": "huggingface.transformers.feature_extraction", + "type": "llm", + "children": [], + "input": "Embed this", + "output": { + "embedding_batch_count": 1, + "embedding_count": 1, + "embedding_length": 3 + }, + "metadata": { + "model": "fixture/feature-extraction", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "feature-extraction", + "testRunId": "" + } + }, + { + "name": "transformers-question-answering-operation", + "children": [ + { + "name": "huggingface.transformers.question_answering", + "type": "llm", + "children": [], + "input": [ + { + "content": "Context:\nAda built it.\n\nQuestion:\nWho built it?", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Ada", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/question-answering", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "question-answering", + "testRunId": "" + } + } + ], + "metadata": { + "scenario": "huggingface-transformers-instrumentation", + "testRunId": "" + } + } + ] +} diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-latest-auto-esm.span-tree.txt b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-latest-auto-esm.span-tree.txt new file mode 100644 index 000000000..75ee4dfa8 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-latest-auto-esm.span-tree.txt @@ -0,0 +1,127 @@ +span_tree: +└── huggingface-transformers-instrumentation-root [task] + metadata: { + "scenario": "huggingface-transformers-instrumentation", + "testRunId": "" + } + ├── transformers-text-generation-operation + │ metadata: { + │ "operation": "text-generation", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.text_generation [llm] + │ input: [ + │ { + │ "content": "Hello", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/text-generation", + │ "provider": "huggingface", + │ "temperature": 0 + │ } + ├── transformers-text2text-generation-operation + │ metadata: { + │ "operation": "text2text-generation", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.text2text_generation [llm] + │ input: [ + │ { + │ "content": "Translate this", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/text2text-generation", + │ "provider": "huggingface" + │ } + ├── transformers-summarization-operation + │ metadata: { + │ "operation": "summarization", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.summarization [llm] + │ input: [ + │ { + │ "content": "A deliberately long passage.", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/summarization", + │ "provider": "huggingface" + │ } + ├── transformers-feature-extraction-operation + │ metadata: { + │ "operation": "feature-extraction", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.feature_extraction [llm] + │ input: "Embed this" + │ output: { + │ "embedding_batch_count": 1, + │ "embedding_count": 1, + │ "embedding_length": 3 + │ } + │ metadata: { + │ "model": "fixture/feature-extraction", + │ "provider": "huggingface" + │ } + └── transformers-question-answering-operation + metadata: { + "operation": "question-answering", + "testRunId": "" + } + └── huggingface.transformers.question_answering [llm] + input: [ + { + "content": "Context:\nAda built it.\n\nQuestion:\nWho built it?", + "role": "user" + } + ] + output: [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Ada", + "role": "assistant" + } + } + ] + metadata: { + "model": "fixture/question-answering", + "provider": "huggingface" + } diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-latest-wrapped.span-tree.json b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-latest-wrapped.span-tree.json new file mode 100644 index 000000000..e390ae0a4 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-latest-wrapped.span-tree.json @@ -0,0 +1,175 @@ +{ + "span_tree": [ + { + "name": "huggingface-transformers-instrumentation-root", + "type": "task", + "children": [ + { + "name": "transformers-text-generation-operation", + "children": [ + { + "name": "huggingface.transformers.text_generation", + "type": "llm", + "children": [], + "input": [ + { + "content": "Hello", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/text-generation", + "provider": "huggingface", + "temperature": 0 + } + } + ], + "metadata": { + "operation": "text-generation", + "testRunId": "" + } + }, + { + "name": "transformers-text2text-generation-operation", + "children": [ + { + "name": "huggingface.transformers.text2text_generation", + "type": "llm", + "children": [], + "input": [ + { + "content": "Translate this", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/text2text-generation", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "text2text-generation", + "testRunId": "" + } + }, + { + "name": "transformers-summarization-operation", + "children": [ + { + "name": "huggingface.transformers.summarization", + "type": "llm", + "children": [], + "input": [ + { + "content": "A deliberately long passage.", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/summarization", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "summarization", + "testRunId": "" + } + }, + { + "name": "transformers-feature-extraction-operation", + "children": [ + { + "name": "huggingface.transformers.feature_extraction", + "type": "llm", + "children": [], + "input": "Embed this", + "output": { + "embedding_batch_count": 1, + "embedding_count": 1, + "embedding_length": 3 + }, + "metadata": { + "model": "fixture/feature-extraction", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "feature-extraction", + "testRunId": "" + } + }, + { + "name": "transformers-question-answering-operation", + "children": [ + { + "name": "huggingface.transformers.question_answering", + "type": "llm", + "children": [], + "input": [ + { + "content": "Context:\nAda built it.\n\nQuestion:\nWho built it?", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Ada", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/question-answering", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "question-answering", + "testRunId": "" + } + } + ], + "metadata": { + "scenario": "huggingface-transformers-instrumentation", + "testRunId": "" + } + } + ] +} diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-latest-wrapped.span-tree.txt b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-latest-wrapped.span-tree.txt new file mode 100644 index 000000000..75ee4dfa8 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-latest-wrapped.span-tree.txt @@ -0,0 +1,127 @@ +span_tree: +└── huggingface-transformers-instrumentation-root [task] + metadata: { + "scenario": "huggingface-transformers-instrumentation", + "testRunId": "" + } + ├── transformers-text-generation-operation + │ metadata: { + │ "operation": "text-generation", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.text_generation [llm] + │ input: [ + │ { + │ "content": "Hello", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/text-generation", + │ "provider": "huggingface", + │ "temperature": 0 + │ } + ├── transformers-text2text-generation-operation + │ metadata: { + │ "operation": "text2text-generation", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.text2text_generation [llm] + │ input: [ + │ { + │ "content": "Translate this", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/text2text-generation", + │ "provider": "huggingface" + │ } + ├── transformers-summarization-operation + │ metadata: { + │ "operation": "summarization", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.summarization [llm] + │ input: [ + │ { + │ "content": "A deliberately long passage.", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/summarization", + │ "provider": "huggingface" + │ } + ├── transformers-feature-extraction-operation + │ metadata: { + │ "operation": "feature-extraction", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.feature_extraction [llm] + │ input: "Embed this" + │ output: { + │ "embedding_batch_count": 1, + │ "embedding_count": 1, + │ "embedding_length": 3 + │ } + │ metadata: { + │ "model": "fixture/feature-extraction", + │ "provider": "huggingface" + │ } + └── transformers-question-answering-operation + metadata: { + "operation": "question-answering", + "testRunId": "" + } + └── huggingface.transformers.question_answering [llm] + input: [ + { + "content": "Context:\nAda built it.\n\nQuestion:\nWho built it?", + "role": "user" + } + ] + output: [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Ada", + "role": "assistant" + } + } + ] + metadata: { + "model": "fixture/question-answering", + "provider": "huggingface" + } diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-wrapped.span-tree.json b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-wrapped.span-tree.json new file mode 100644 index 000000000..e390ae0a4 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-wrapped.span-tree.json @@ -0,0 +1,175 @@ +{ + "span_tree": [ + { + "name": "huggingface-transformers-instrumentation-root", + "type": "task", + "children": [ + { + "name": "transformers-text-generation-operation", + "children": [ + { + "name": "huggingface.transformers.text_generation", + "type": "llm", + "children": [], + "input": [ + { + "content": "Hello", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/text-generation", + "provider": "huggingface", + "temperature": 0 + } + } + ], + "metadata": { + "operation": "text-generation", + "testRunId": "" + } + }, + { + "name": "transformers-text2text-generation-operation", + "children": [ + { + "name": "huggingface.transformers.text2text_generation", + "type": "llm", + "children": [], + "input": [ + { + "content": "Translate this", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/text2text-generation", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "text2text-generation", + "testRunId": "" + } + }, + { + "name": "transformers-summarization-operation", + "children": [ + { + "name": "huggingface.transformers.summarization", + "type": "llm", + "children": [], + "input": [ + { + "content": "A deliberately long passage.", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/summarization", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "summarization", + "testRunId": "" + } + }, + { + "name": "transformers-feature-extraction-operation", + "children": [ + { + "name": "huggingface.transformers.feature_extraction", + "type": "llm", + "children": [], + "input": "Embed this", + "output": { + "embedding_batch_count": 1, + "embedding_count": 1, + "embedding_length": 3 + }, + "metadata": { + "model": "fixture/feature-extraction", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "feature-extraction", + "testRunId": "" + } + }, + { + "name": "transformers-question-answering-operation", + "children": [ + { + "name": "huggingface.transformers.question_answering", + "type": "llm", + "children": [], + "input": [ + { + "content": "Context:\nAda built it.\n\nQuestion:\nWho built it?", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Ada", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/question-answering", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "question-answering", + "testRunId": "" + } + } + ], + "metadata": { + "scenario": "huggingface-transformers-instrumentation", + "testRunId": "" + } + } + ] +} diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-wrapped.span-tree.txt b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-wrapped.span-tree.txt new file mode 100644 index 000000000..75ee4dfa8 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v3-wrapped.span-tree.txt @@ -0,0 +1,127 @@ +span_tree: +└── huggingface-transformers-instrumentation-root [task] + metadata: { + "scenario": "huggingface-transformers-instrumentation", + "testRunId": "" + } + ├── transformers-text-generation-operation + │ metadata: { + │ "operation": "text-generation", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.text_generation [llm] + │ input: [ + │ { + │ "content": "Hello", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/text-generation", + │ "provider": "huggingface", + │ "temperature": 0 + │ } + ├── transformers-text2text-generation-operation + │ metadata: { + │ "operation": "text2text-generation", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.text2text_generation [llm] + │ input: [ + │ { + │ "content": "Translate this", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/text2text-generation", + │ "provider": "huggingface" + │ } + ├── transformers-summarization-operation + │ metadata: { + │ "operation": "summarization", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.summarization [llm] + │ input: [ + │ { + │ "content": "A deliberately long passage.", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/summarization", + │ "provider": "huggingface" + │ } + ├── transformers-feature-extraction-operation + │ metadata: { + │ "operation": "feature-extraction", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.feature_extraction [llm] + │ input: "Embed this" + │ output: { + │ "embedding_batch_count": 1, + │ "embedding_count": 1, + │ "embedding_length": 3 + │ } + │ metadata: { + │ "model": "fixture/feature-extraction", + │ "provider": "huggingface" + │ } + └── transformers-question-answering-operation + metadata: { + "operation": "question-answering", + "testRunId": "" + } + └── huggingface.transformers.question_answering [llm] + input: [ + { + "content": "Context:\nAda built it.\n\nQuestion:\nWho built it?", + "role": "user" + } + ] + output: [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Ada", + "role": "assistant" + } + } + ] + metadata: { + "model": "fixture/question-answering", + "provider": "huggingface" + } diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-auto-esm.span-tree.json b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-auto-esm.span-tree.json new file mode 100644 index 000000000..e390ae0a4 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-auto-esm.span-tree.json @@ -0,0 +1,175 @@ +{ + "span_tree": [ + { + "name": "huggingface-transformers-instrumentation-root", + "type": "task", + "children": [ + { + "name": "transformers-text-generation-operation", + "children": [ + { + "name": "huggingface.transformers.text_generation", + "type": "llm", + "children": [], + "input": [ + { + "content": "Hello", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/text-generation", + "provider": "huggingface", + "temperature": 0 + } + } + ], + "metadata": { + "operation": "text-generation", + "testRunId": "" + } + }, + { + "name": "transformers-text2text-generation-operation", + "children": [ + { + "name": "huggingface.transformers.text2text_generation", + "type": "llm", + "children": [], + "input": [ + { + "content": "Translate this", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/text2text-generation", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "text2text-generation", + "testRunId": "" + } + }, + { + "name": "transformers-summarization-operation", + "children": [ + { + "name": "huggingface.transformers.summarization", + "type": "llm", + "children": [], + "input": [ + { + "content": "A deliberately long passage.", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/summarization", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "summarization", + "testRunId": "" + } + }, + { + "name": "transformers-feature-extraction-operation", + "children": [ + { + "name": "huggingface.transformers.feature_extraction", + "type": "llm", + "children": [], + "input": "Embed this", + "output": { + "embedding_batch_count": 1, + "embedding_count": 1, + "embedding_length": 3 + }, + "metadata": { + "model": "fixture/feature-extraction", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "feature-extraction", + "testRunId": "" + } + }, + { + "name": "transformers-question-answering-operation", + "children": [ + { + "name": "huggingface.transformers.question_answering", + "type": "llm", + "children": [], + "input": [ + { + "content": "Context:\nAda built it.\n\nQuestion:\nWho built it?", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Ada", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/question-answering", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "question-answering", + "testRunId": "" + } + } + ], + "metadata": { + "scenario": "huggingface-transformers-instrumentation", + "testRunId": "" + } + } + ] +} diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-auto-esm.span-tree.txt b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-auto-esm.span-tree.txt new file mode 100644 index 000000000..75ee4dfa8 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-auto-esm.span-tree.txt @@ -0,0 +1,127 @@ +span_tree: +└── huggingface-transformers-instrumentation-root [task] + metadata: { + "scenario": "huggingface-transformers-instrumentation", + "testRunId": "" + } + ├── transformers-text-generation-operation + │ metadata: { + │ "operation": "text-generation", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.text_generation [llm] + │ input: [ + │ { + │ "content": "Hello", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/text-generation", + │ "provider": "huggingface", + │ "temperature": 0 + │ } + ├── transformers-text2text-generation-operation + │ metadata: { + │ "operation": "text2text-generation", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.text2text_generation [llm] + │ input: [ + │ { + │ "content": "Translate this", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/text2text-generation", + │ "provider": "huggingface" + │ } + ├── transformers-summarization-operation + │ metadata: { + │ "operation": "summarization", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.summarization [llm] + │ input: [ + │ { + │ "content": "A deliberately long passage.", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/summarization", + │ "provider": "huggingface" + │ } + ├── transformers-feature-extraction-operation + │ metadata: { + │ "operation": "feature-extraction", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.feature_extraction [llm] + │ input: "Embed this" + │ output: { + │ "embedding_batch_count": 1, + │ "embedding_count": 1, + │ "embedding_length": 3 + │ } + │ metadata: { + │ "model": "fixture/feature-extraction", + │ "provider": "huggingface" + │ } + └── transformers-question-answering-operation + metadata: { + "operation": "question-answering", + "testRunId": "" + } + └── huggingface.transformers.question_answering [llm] + input: [ + { + "content": "Context:\nAda built it.\n\nQuestion:\nWho built it?", + "role": "user" + } + ] + output: [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Ada", + "role": "assistant" + } + } + ] + metadata: { + "model": "fixture/question-answering", + "provider": "huggingface" + } diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-auto-cjs.span-tree.json b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-auto-cjs.span-tree.json new file mode 100644 index 000000000..e390ae0a4 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-auto-cjs.span-tree.json @@ -0,0 +1,175 @@ +{ + "span_tree": [ + { + "name": "huggingface-transformers-instrumentation-root", + "type": "task", + "children": [ + { + "name": "transformers-text-generation-operation", + "children": [ + { + "name": "huggingface.transformers.text_generation", + "type": "llm", + "children": [], + "input": [ + { + "content": "Hello", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/text-generation", + "provider": "huggingface", + "temperature": 0 + } + } + ], + "metadata": { + "operation": "text-generation", + "testRunId": "" + } + }, + { + "name": "transformers-text2text-generation-operation", + "children": [ + { + "name": "huggingface.transformers.text2text_generation", + "type": "llm", + "children": [], + "input": [ + { + "content": "Translate this", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/text2text-generation", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "text2text-generation", + "testRunId": "" + } + }, + { + "name": "transformers-summarization-operation", + "children": [ + { + "name": "huggingface.transformers.summarization", + "type": "llm", + "children": [], + "input": [ + { + "content": "A deliberately long passage.", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/summarization", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "summarization", + "testRunId": "" + } + }, + { + "name": "transformers-feature-extraction-operation", + "children": [ + { + "name": "huggingface.transformers.feature_extraction", + "type": "llm", + "children": [], + "input": "Embed this", + "output": { + "embedding_batch_count": 1, + "embedding_count": 1, + "embedding_length": 3 + }, + "metadata": { + "model": "fixture/feature-extraction", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "feature-extraction", + "testRunId": "" + } + }, + { + "name": "transformers-question-answering-operation", + "children": [ + { + "name": "huggingface.transformers.question_answering", + "type": "llm", + "children": [], + "input": [ + { + "content": "Context:\nAda built it.\n\nQuestion:\nWho built it?", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Ada", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/question-answering", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "question-answering", + "testRunId": "" + } + } + ], + "metadata": { + "scenario": "huggingface-transformers-instrumentation", + "testRunId": "" + } + } + ] +} diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-auto-cjs.span-tree.txt b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-auto-cjs.span-tree.txt new file mode 100644 index 000000000..75ee4dfa8 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-auto-cjs.span-tree.txt @@ -0,0 +1,127 @@ +span_tree: +└── huggingface-transformers-instrumentation-root [task] + metadata: { + "scenario": "huggingface-transformers-instrumentation", + "testRunId": "" + } + ├── transformers-text-generation-operation + │ metadata: { + │ "operation": "text-generation", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.text_generation [llm] + │ input: [ + │ { + │ "content": "Hello", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/text-generation", + │ "provider": "huggingface", + │ "temperature": 0 + │ } + ├── transformers-text2text-generation-operation + │ metadata: { + │ "operation": "text2text-generation", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.text2text_generation [llm] + │ input: [ + │ { + │ "content": "Translate this", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/text2text-generation", + │ "provider": "huggingface" + │ } + ├── transformers-summarization-operation + │ metadata: { + │ "operation": "summarization", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.summarization [llm] + │ input: [ + │ { + │ "content": "A deliberately long passage.", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/summarization", + │ "provider": "huggingface" + │ } + ├── transformers-feature-extraction-operation + │ metadata: { + │ "operation": "feature-extraction", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.feature_extraction [llm] + │ input: "Embed this" + │ output: { + │ "embedding_batch_count": 1, + │ "embedding_count": 1, + │ "embedding_length": 3 + │ } + │ metadata: { + │ "model": "fixture/feature-extraction", + │ "provider": "huggingface" + │ } + └── transformers-question-answering-operation + metadata: { + "operation": "question-answering", + "testRunId": "" + } + └── huggingface.transformers.question_answering [llm] + input: [ + { + "content": "Context:\nAda built it.\n\nQuestion:\nWho built it?", + "role": "user" + } + ] + output: [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Ada", + "role": "assistant" + } + } + ] + metadata: { + "model": "fixture/question-answering", + "provider": "huggingface" + } diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-auto-esm.span-tree.json b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-auto-esm.span-tree.json new file mode 100644 index 000000000..e390ae0a4 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-auto-esm.span-tree.json @@ -0,0 +1,175 @@ +{ + "span_tree": [ + { + "name": "huggingface-transformers-instrumentation-root", + "type": "task", + "children": [ + { + "name": "transformers-text-generation-operation", + "children": [ + { + "name": "huggingface.transformers.text_generation", + "type": "llm", + "children": [], + "input": [ + { + "content": "Hello", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/text-generation", + "provider": "huggingface", + "temperature": 0 + } + } + ], + "metadata": { + "operation": "text-generation", + "testRunId": "" + } + }, + { + "name": "transformers-text2text-generation-operation", + "children": [ + { + "name": "huggingface.transformers.text2text_generation", + "type": "llm", + "children": [], + "input": [ + { + "content": "Translate this", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/text2text-generation", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "text2text-generation", + "testRunId": "" + } + }, + { + "name": "transformers-summarization-operation", + "children": [ + { + "name": "huggingface.transformers.summarization", + "type": "llm", + "children": [], + "input": [ + { + "content": "A deliberately long passage.", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/summarization", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "summarization", + "testRunId": "" + } + }, + { + "name": "transformers-feature-extraction-operation", + "children": [ + { + "name": "huggingface.transformers.feature_extraction", + "type": "llm", + "children": [], + "input": "Embed this", + "output": { + "embedding_batch_count": 1, + "embedding_count": 1, + "embedding_length": 3 + }, + "metadata": { + "model": "fixture/feature-extraction", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "feature-extraction", + "testRunId": "" + } + }, + { + "name": "transformers-question-answering-operation", + "children": [ + { + "name": "huggingface.transformers.question_answering", + "type": "llm", + "children": [], + "input": [ + { + "content": "Context:\nAda built it.\n\nQuestion:\nWho built it?", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Ada", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/question-answering", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "question-answering", + "testRunId": "" + } + } + ], + "metadata": { + "scenario": "huggingface-transformers-instrumentation", + "testRunId": "" + } + } + ] +} diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-auto-esm.span-tree.txt b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-auto-esm.span-tree.txt new file mode 100644 index 000000000..75ee4dfa8 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-auto-esm.span-tree.txt @@ -0,0 +1,127 @@ +span_tree: +└── huggingface-transformers-instrumentation-root [task] + metadata: { + "scenario": "huggingface-transformers-instrumentation", + "testRunId": "" + } + ├── transformers-text-generation-operation + │ metadata: { + │ "operation": "text-generation", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.text_generation [llm] + │ input: [ + │ { + │ "content": "Hello", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/text-generation", + │ "provider": "huggingface", + │ "temperature": 0 + │ } + ├── transformers-text2text-generation-operation + │ metadata: { + │ "operation": "text2text-generation", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.text2text_generation [llm] + │ input: [ + │ { + │ "content": "Translate this", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/text2text-generation", + │ "provider": "huggingface" + │ } + ├── transformers-summarization-operation + │ metadata: { + │ "operation": "summarization", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.summarization [llm] + │ input: [ + │ { + │ "content": "A deliberately long passage.", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/summarization", + │ "provider": "huggingface" + │ } + ├── transformers-feature-extraction-operation + │ metadata: { + │ "operation": "feature-extraction", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.feature_extraction [llm] + │ input: "Embed this" + │ output: { + │ "embedding_batch_count": 1, + │ "embedding_count": 1, + │ "embedding_length": 3 + │ } + │ metadata: { + │ "model": "fixture/feature-extraction", + │ "provider": "huggingface" + │ } + └── transformers-question-answering-operation + metadata: { + "operation": "question-answering", + "testRunId": "" + } + └── huggingface.transformers.question_answering [llm] + input: [ + { + "content": "Context:\nAda built it.\n\nQuestion:\nWho built it?", + "role": "user" + } + ] + output: [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Ada", + "role": "assistant" + } + } + ] + metadata: { + "model": "fixture/question-answering", + "provider": "huggingface" + } diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-wrapped.span-tree.json b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-wrapped.span-tree.json new file mode 100644 index 000000000..e390ae0a4 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-wrapped.span-tree.json @@ -0,0 +1,175 @@ +{ + "span_tree": [ + { + "name": "huggingface-transformers-instrumentation-root", + "type": "task", + "children": [ + { + "name": "transformers-text-generation-operation", + "children": [ + { + "name": "huggingface.transformers.text_generation", + "type": "llm", + "children": [], + "input": [ + { + "content": "Hello", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/text-generation", + "provider": "huggingface", + "temperature": 0 + } + } + ], + "metadata": { + "operation": "text-generation", + "testRunId": "" + } + }, + { + "name": "transformers-text2text-generation-operation", + "children": [ + { + "name": "huggingface.transformers.text2text_generation", + "type": "llm", + "children": [], + "input": [ + { + "content": "Translate this", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/text2text-generation", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "text2text-generation", + "testRunId": "" + } + }, + { + "name": "transformers-summarization-operation", + "children": [ + { + "name": "huggingface.transformers.summarization", + "type": "llm", + "children": [], + "input": [ + { + "content": "A deliberately long passage.", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/summarization", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "summarization", + "testRunId": "" + } + }, + { + "name": "transformers-feature-extraction-operation", + "children": [ + { + "name": "huggingface.transformers.feature_extraction", + "type": "llm", + "children": [], + "input": "Embed this", + "output": { + "embedding_batch_count": 1, + "embedding_count": 1, + "embedding_length": 3 + }, + "metadata": { + "model": "fixture/feature-extraction", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "feature-extraction", + "testRunId": "" + } + }, + { + "name": "transformers-question-answering-operation", + "children": [ + { + "name": "huggingface.transformers.question_answering", + "type": "llm", + "children": [], + "input": [ + { + "content": "Context:\nAda built it.\n\nQuestion:\nWho built it?", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Ada", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/question-answering", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "question-answering", + "testRunId": "" + } + } + ], + "metadata": { + "scenario": "huggingface-transformers-instrumentation", + "testRunId": "" + } + } + ] +} diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-wrapped.span-tree.txt b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-wrapped.span-tree.txt new file mode 100644 index 000000000..75ee4dfa8 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-latest-wrapped.span-tree.txt @@ -0,0 +1,127 @@ +span_tree: +└── huggingface-transformers-instrumentation-root [task] + metadata: { + "scenario": "huggingface-transformers-instrumentation", + "testRunId": "" + } + ├── transformers-text-generation-operation + │ metadata: { + │ "operation": "text-generation", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.text_generation [llm] + │ input: [ + │ { + │ "content": "Hello", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/text-generation", + │ "provider": "huggingface", + │ "temperature": 0 + │ } + ├── transformers-text2text-generation-operation + │ metadata: { + │ "operation": "text2text-generation", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.text2text_generation [llm] + │ input: [ + │ { + │ "content": "Translate this", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/text2text-generation", + │ "provider": "huggingface" + │ } + ├── transformers-summarization-operation + │ metadata: { + │ "operation": "summarization", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.summarization [llm] + │ input: [ + │ { + │ "content": "A deliberately long passage.", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/summarization", + │ "provider": "huggingface" + │ } + ├── transformers-feature-extraction-operation + │ metadata: { + │ "operation": "feature-extraction", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.feature_extraction [llm] + │ input: "Embed this" + │ output: { + │ "embedding_batch_count": 1, + │ "embedding_count": 1, + │ "embedding_length": 3 + │ } + │ metadata: { + │ "model": "fixture/feature-extraction", + │ "provider": "huggingface" + │ } + └── transformers-question-answering-operation + metadata: { + "operation": "question-answering", + "testRunId": "" + } + └── huggingface.transformers.question_answering [llm] + input: [ + { + "content": "Context:\nAda built it.\n\nQuestion:\nWho built it?", + "role": "user" + } + ] + output: [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Ada", + "role": "assistant" + } + } + ] + metadata: { + "model": "fixture/question-answering", + "provider": "huggingface" + } diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-wrapped.span-tree.json b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-wrapped.span-tree.json new file mode 100644 index 000000000..e390ae0a4 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-wrapped.span-tree.json @@ -0,0 +1,175 @@ +{ + "span_tree": [ + { + "name": "huggingface-transformers-instrumentation-root", + "type": "task", + "children": [ + { + "name": "transformers-text-generation-operation", + "children": [ + { + "name": "huggingface.transformers.text_generation", + "type": "llm", + "children": [], + "input": [ + { + "content": "Hello", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/text-generation", + "provider": "huggingface", + "temperature": 0 + } + } + ], + "metadata": { + "operation": "text-generation", + "testRunId": "" + } + }, + { + "name": "transformers-text2text-generation-operation", + "children": [ + { + "name": "huggingface.transformers.text2text_generation", + "type": "llm", + "children": [], + "input": [ + { + "content": "Translate this", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/text2text-generation", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "text2text-generation", + "testRunId": "" + } + }, + { + "name": "transformers-summarization-operation", + "children": [ + { + "name": "huggingface.transformers.summarization", + "type": "llm", + "children": [], + "input": [ + { + "content": "A deliberately long passage.", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Deterministic output", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/summarization", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "summarization", + "testRunId": "" + } + }, + { + "name": "transformers-feature-extraction-operation", + "children": [ + { + "name": "huggingface.transformers.feature_extraction", + "type": "llm", + "children": [], + "input": "Embed this", + "output": { + "embedding_batch_count": 1, + "embedding_count": 1, + "embedding_length": 3 + }, + "metadata": { + "model": "fixture/feature-extraction", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "feature-extraction", + "testRunId": "" + } + }, + { + "name": "transformers-question-answering-operation", + "children": [ + { + "name": "huggingface.transformers.question_answering", + "type": "llm", + "children": [], + "input": [ + { + "content": "Context:\nAda built it.\n\nQuestion:\nWho built it?", + "role": "user" + } + ], + "output": [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Ada", + "role": "assistant" + } + } + ], + "metadata": { + "model": "fixture/question-answering", + "provider": "huggingface" + } + } + ], + "metadata": { + "operation": "question-answering", + "testRunId": "" + } + } + ], + "metadata": { + "scenario": "huggingface-transformers-instrumentation", + "testRunId": "" + } + } + ] +} diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-wrapped.span-tree.txt b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-wrapped.span-tree.txt new file mode 100644 index 000000000..75ee4dfa8 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/__snapshots__/huggingface-transformers-v4-wrapped.span-tree.txt @@ -0,0 +1,127 @@ +span_tree: +└── huggingface-transformers-instrumentation-root [task] + metadata: { + "scenario": "huggingface-transformers-instrumentation", + "testRunId": "" + } + ├── transformers-text-generation-operation + │ metadata: { + │ "operation": "text-generation", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.text_generation [llm] + │ input: [ + │ { + │ "content": "Hello", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/text-generation", + │ "provider": "huggingface", + │ "temperature": 0 + │ } + ├── transformers-text2text-generation-operation + │ metadata: { + │ "operation": "text2text-generation", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.text2text_generation [llm] + │ input: [ + │ { + │ "content": "Translate this", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/text2text-generation", + │ "provider": "huggingface" + │ } + ├── transformers-summarization-operation + │ metadata: { + │ "operation": "summarization", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.summarization [llm] + │ input: [ + │ { + │ "content": "A deliberately long passage.", + │ "role": "user" + │ } + │ ] + │ output: [ + │ { + │ "finish_reason": "stop", + │ "index": 0, + │ "message": { + │ "content": "Deterministic output", + │ "role": "assistant" + │ } + │ } + │ ] + │ metadata: { + │ "model": "fixture/summarization", + │ "provider": "huggingface" + │ } + ├── transformers-feature-extraction-operation + │ metadata: { + │ "operation": "feature-extraction", + │ "testRunId": "" + │ } + │ └── huggingface.transformers.feature_extraction [llm] + │ input: "Embed this" + │ output: { + │ "embedding_batch_count": 1, + │ "embedding_count": 1, + │ "embedding_length": 3 + │ } + │ metadata: { + │ "model": "fixture/feature-extraction", + │ "provider": "huggingface" + │ } + └── transformers-question-answering-operation + metadata: { + "operation": "question-answering", + "testRunId": "" + } + └── huggingface.transformers.question_answering [llm] + input: [ + { + "content": "Context:\nAda built it.\n\nQuestion:\nWho built it?", + "role": "user" + } + ] + output: [ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Ada", + "role": "assistant" + } + } + ] + metadata: { + "model": "fixture/question-answering", + "provider": "huggingface" + } diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/assertions.ts b/e2e/scenarios/huggingface-transformers-instrumentation/assertions.ts new file mode 100644 index 000000000..ad76a9728 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/assertions.ts @@ -0,0 +1,109 @@ +import { beforeAll, describe, expect, test } from "vitest"; +import type { CapturedLogEvent } from "../../helpers/mock-braintrust-server"; +import { resolveFileSnapshotPath } from "../../helpers/file-snapshot"; +import { + withScenarioHarness, + type ScenarioRunContext, +} from "../../helpers/scenario-harness"; +import { matchSpanTreeSnapshot } from "../../helpers/span-tree"; +import { findLatestSpan } from "../../helpers/trace-selectors"; + +import { ROOT_NAME } from "./scenario.impl.mjs"; + +type RunScenario = (harness: { + runNodeScenarioDir: (options: { + entry: string; + env?: Record; + nodeArgs: string[]; + runContext?: ScenarioRunContext; + scenarioDir: string; + timeoutMs: number; + }) => Promise; + runScenarioDir: (options: { + entry: string; + env?: Record; + runContext?: ScenarioRunContext; + scenarioDir: string; + timeoutMs: number; + }) => Promise; +}) => Promise; + +const EXPECTED_SPANS = [ + "huggingface.transformers.text_generation", + "huggingface.transformers.text2text_generation", + "huggingface.transformers.summarization", + "huggingface.transformers.feature_extraction", + "huggingface.transformers.question_answering", +]; + +export function defineAssertions(options: { + name: string; + runScenario: RunScenario; + snapshotName: string; + testFileUrl: string; + timeoutMs: number; +}): void { + const snapshotPath = resolveFileSnapshotPath( + options.testFileUrl, + `${options.snapshotName}.span-tree.json`, + ); + const testConfig = { timeout: options.timeoutMs }; + + describe(options.name, () => { + let traceEvents: CapturedLogEvent[] = []; + + beforeAll(async () => { + await withScenarioHarness(async (harness) => { + await options.runScenario(harness); + const events = harness.events(); + const root = findLatestSpan(events, ROOT_NAME); + expect(root, "missing scenario root").toBeDefined(); + traceEvents = events.filter( + (event) => event.span.rootId === root?.span.rootId, + ); + }); + }, options.timeoutMs); + + test("captures all supported local pipeline executions", testConfig, () => { + for (const name of EXPECTED_SPANS) { + const matches = traceEvents.filter((event) => event.span.name === name); + expect(matches, `expected one ${name} span`).toHaveLength(1); + expect(matches[0]?.span.type).toBe("llm"); + expect(matches[0]?.metadata).toMatchObject({ + model: `fixture/${name.slice("huggingface.transformers.".length).replaceAll("_", "-")}`, + provider: "huggingface", + }); + } + + expect( + findLatestSpan( + traceEvents, + "huggingface.transformers.feature_extraction", + )?.output, + ).toEqual({ + embedding_batch_count: 1, + embedding_count: 1, + embedding_length: 3, + }); + expect( + findLatestSpan( + traceEvents, + "huggingface.transformers.question_answering", + )?.output, + ).toEqual([ + { + finish_reason: "stop", + index: 0, + message: { + content: "Ada", + role: "assistant", + }, + }, + ]); + }); + + test("matches span tree snapshot", testConfig, async () => { + await matchSpanTreeSnapshot(traceEvents, snapshotPath); + }); + }); +} diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/package.json b/e2e/scenarios/huggingface-transformers-instrumentation/package.json new file mode 100644 index 000000000..bff8aa172 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/package.json @@ -0,0 +1,25 @@ +{ + "name": "@braintrust/e2e-huggingface-transformers-instrumentation", + "private": true, + "type": "module", + "braintrustScenario": { + "bump": { + "dependencies": { + "huggingface-transformers-v3-latest": { + "package": "@huggingface/transformers", + "range": "3" + }, + "huggingface-transformers-v4-latest": { + "package": "@huggingface/transformers", + "range": "4" + } + } + } + }, + "dependencies": { + "huggingface-transformers-v3": "npm:@huggingface/transformers@3.0.0", + "huggingface-transformers-v3-latest": "npm:@huggingface/transformers@3.8.1", + "huggingface-transformers-v4": "npm:@huggingface/transformers@4.0.0", + "huggingface-transformers-v4-latest": "npm:@huggingface/transformers@4.2.0" + } +} diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/pnpm-lock.yaml b/e2e/scenarios/huggingface-transformers-instrumentation/pnpm-lock.yaml new file mode 100644 index 000000000..4c73499d6 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/pnpm-lock.yaml @@ -0,0 +1,1066 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + huggingface-transformers-v3: + specifier: npm:@huggingface/transformers@3.0.0 + version: '@huggingface/transformers@3.0.0' + huggingface-transformers-v3-latest: + specifier: npm:@huggingface/transformers@3.8.1 + version: '@huggingface/transformers@3.8.1' + huggingface-transformers-v4: + specifier: npm:@huggingface/transformers@4.0.0 + version: '@huggingface/transformers@4.0.0' + huggingface-transformers-v4-latest: + specifier: npm:@huggingface/transformers@4.2.0 + version: '@huggingface/transformers@4.2.0' + +packages: + + '@emnapi/runtime@1.11.2': + resolution: {integrity: sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==} + + '@huggingface/jinja@0.3.4': + resolution: {integrity: sha512-kFFQWJiWwvxezKQnvH1X7GjsECcMljFx+UZK9hx6P26aVHwwidJVTB0ptLfRVZQvVkOGHoMmTGvo4nT0X9hHOA==} + engines: {node: '>=18'} + + '@huggingface/jinja@0.5.9': + resolution: {integrity: sha512-uWTG+l3VJRsl7EXxYizuL3P+cCPoc3cRqbWWRcQN0FhejRfbdq0RNhCmbY/YDtnTcz9icdLYuLDjsnz4d8JMuw==} + engines: {node: '>=18'} + + '@huggingface/tokenizers@0.1.3': + resolution: {integrity: sha512-8rF/RRT10u+kn7YuUbUg0OF30K8rjTc78aHpxT+qJ1uWSqxT1MHi8+9ltwYfkFYJzT/oS+qw3JVfHtNMGAdqyA==} + + '@huggingface/transformers@3.0.0': + resolution: {integrity: sha512-OWIPnTijAw4DQ+IFHBOrej2SDdYyykYlTtpTLCEt5MZq/e9Cb65RS2YVhdGcgbaW/6JAL3i8ZA5UhDeWGm4iRQ==} + + '@huggingface/transformers@3.8.1': + resolution: {integrity: sha512-tsTk4zVjImqdqjS8/AOZg2yNLd1z9S5v+7oUPpXaasDRwEDhB+xnglK1k5cad26lL5/ZIaeREgWWy0bs9y9pPA==} + + '@huggingface/transformers@4.0.0': + resolution: {integrity: sha512-7shdBRvtjIDP7UUhdi0b4CMRCD+QXvQIsEsxECWS9VEDEsxSQF9Ci+51mwy2OWI8vbsoic8e4dbR4eI8aZWxaw==} + + '@huggingface/transformers@4.2.0': + resolution: {integrity: sha512-8BRCoBMH0XsWaEIamuR0LrJGAfftgHAfb2Vrffy0VKlSAE/MnUJ5/h/zTfEP3fDIft+nk7TqB8xXEyABGitBjQ==} + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.33.5': + resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.33.5': + resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.0.4': + resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.0.4': + resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.0.4': + resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.0.5': + resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.0.4': + resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.0.4': + resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.0.4': + resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.33.5': + resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.33.5': + resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.33.5': + resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.33.5': + resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.33.5': + resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.33.5': + resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.33.5': + resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.33.5': + resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.33.5': + resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.5': + resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==} + + '@protobufjs/eventemitter@1.1.1': + resolution: {integrity: sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==} + + '@protobufjs/fetch@1.1.1': + resolution: {integrity: sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.2': + resolution: {integrity: sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==} + + '@types/node@26.1.1': + resolution: {integrity: sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==} + + adm-zip@0.5.18: + resolution: {integrity: sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng==} + engines: {node: '>=12.0'} + + boolean@3.2.0: + resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + + color@4.2.3: + resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} + engines: {node: '>=12.5.0'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + detect-node@2.1.0: + resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es6-error@4.1.1: + resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + flatbuffers@1.12.0: + resolution: {integrity: sha512-c7CZADjRcl6j0PlvFy0ZqXQ67qSEZfrVPynmnL+2zPc+NtMvrF8Y0QceMo7QqnSPc7+uWjUIAbvCQ5WIKlMVdQ==} + + flatbuffers@25.9.23: + resolution: {integrity: sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ==} + + global-agent@3.0.0: + resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} + engines: {node: '>=10.0'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + guid-typescript@1.0.9: + resolution: {integrity: sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + is-arrayish@0.3.4: + resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==} + + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + + matcher@3.0.0: + resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==} + engines: {node: '>=10'} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + onnxruntime-common@1.19.2: + resolution: {integrity: sha512-a4R7wYEVFbZBlp0BfhpbFWqe4opCor3KM+5Wm22Az3NGDcQMiU2hfG/0MfnBs+1ZrlSGmlgWeMcXQkDk1UFb8Q==} + + onnxruntime-common@1.20.0-dev.20241016-2b8fc5529b: + resolution: {integrity: sha512-KZK8b6zCYGZFjd4ANze0pqBnqnFTS3GIVeclQpa2qseDpXrCQJfkWBixRcrZShNhm3LpFOZ8qJYFC5/qsJK9WQ==} + + onnxruntime-common@1.21.0: + resolution: {integrity: sha512-Q632iLLrtCAVOTO65dh2+mNbQir/QNTVBG3h/QdZBpns7mZ0RYbLRBgGABPbpU9351AgYy7SJf1WaeVwMrBFPQ==} + + onnxruntime-common@1.22.0-dev.20250409-89f8206ba4: + resolution: {integrity: sha512-vDJMkfCfb0b1A836rgHj+ORuZf4B4+cc2bASQtpeoJLueuFc5DuYwjIZUBrSvx/fO5IrLjLz+oTrB3pcGlhovQ==} + + onnxruntime-common@1.24.0-dev.20251116-b39e144322: + resolution: {integrity: sha512-BOoomdHYmNRL5r4iQ4bMvsl2t0/hzVQ3OM3PHD0gxeXu1PmggqBv3puZicEUVOA3AtHHYmqZtjMj9FOfGrATTw==} + + onnxruntime-common@1.24.3: + resolution: {integrity: sha512-GeuPZO6U/LBJXvwdaqHbuUmoXiEdeCjWi/EG7Y1HNnDwJYuk6WUbNXpF6luSUY8yASul3cmUlLGrCCL1ZgVXqA==} + + onnxruntime-node@1.19.2: + resolution: {integrity: sha512-9eHMP/HKbbeUcqte1JYzaaRC8JPn7ojWeCeoyShO86TOR97OCyIyAIOGX3V95ErjslVhJRXY8Em/caIUc0hm1Q==} + os: [win32, darwin, linux] + + onnxruntime-node@1.21.0: + resolution: {integrity: sha512-NeaCX6WW2L8cRCSqy3bInlo5ojjQqu2fD3D+9W5qb5irwxhEyWKXeH2vZ8W9r6VxaMPUan+4/7NDwZMtouZxEw==} + os: [win32, darwin, linux] + + onnxruntime-node@1.24.3: + resolution: {integrity: sha512-JH7+czbc8ALA819vlTgcV+Q214/+VjGeBHDjX81+ZCD0PCVCIFGFNtT0V4sXG/1JXypKPgScQcB3ij/hk3YnTg==} + os: [win32, darwin, linux] + + onnxruntime-web@1.20.0-dev.20241016-2b8fc5529b: + resolution: {integrity: sha512-1XovqtgqeEFtupuyzdDQo7Tqj4GRyNHzOoXjapCEo4rfH3JrXok5VtqucWfRXHPsOI5qoNxMQ9VE+drDIp6woQ==} + + onnxruntime-web@1.22.0-dev.20250409-89f8206ba4: + resolution: {integrity: sha512-0uS76OPgH0hWCPrFKlL8kYVV7ckM7t/36HfbgoFw6Nd0CZVVbQC4PkrR8mBX8LtNUFZO25IQBqV2Hx2ho3FlbQ==} + + onnxruntime-web@1.25.0-dev.20260327-722743c0e2: + resolution: {integrity: sha512-8PXdZy4Ekhg10CLg+cFFt39b4tFDGMRJB6lGjnQL6eA+2boUQYDymZ0gtxiS+H6oIWoCjQp/ziyirvFbaFKfiw==} + + onnxruntime-web@1.26.0-dev.20260416-b7804b056c: + resolution: {integrity: sha512-MD6Ss4GSpQBo6zqoJzyT9LRbKYs7x/JVN23FT24EcEvlqF4VuzPOeH6X38orZPKHQDbprn7K+SBpu0/mj2CQiw==} + + platform@1.3.6: + resolution: {integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==} + + protobufjs@7.6.5: + resolution: {integrity: sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==} + engines: {node: '>=12.0.0'} + + roarr@2.15.4: + resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==} + engines: {node: '>=8.0'} + + semver-compare@1.0.0: + resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + serialize-error@7.0.1: + resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} + engines: {node: '>=10'} + + sharp@0.33.5: + resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + simple-swizzle@0.2.4: + resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==} + + sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + + tar@7.5.21: + resolution: {integrity: sha512-XdhtCvlMywwxpCW8YEq3lOXBJpUPTR2OHHcwLPO3HwsJqOHa2Ok/oJ7ruGzp+JrKoRPVCzJwAdEjqLW/vNRPHA==} + engines: {node: '>=18'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-fest@0.13.1: + resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} + engines: {node: '>=10'} + + undici-types@8.3.0: + resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} + + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + +snapshots: + + '@emnapi/runtime@1.11.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@huggingface/jinja@0.3.4': {} + + '@huggingface/jinja@0.5.9': {} + + '@huggingface/tokenizers@0.1.3': {} + + '@huggingface/transformers@3.0.0': + dependencies: + '@huggingface/jinja': 0.3.4 + onnxruntime-node: 1.19.2 + onnxruntime-web: 1.20.0-dev.20241016-2b8fc5529b + sharp: 0.33.5 + + '@huggingface/transformers@3.8.1': + dependencies: + '@huggingface/jinja': 0.5.9 + onnxruntime-node: 1.21.0 + onnxruntime-web: 1.22.0-dev.20250409-89f8206ba4 + sharp: 0.34.5 + + '@huggingface/transformers@4.0.0': + dependencies: + '@huggingface/jinja': 0.5.9 + '@huggingface/tokenizers': 0.1.3 + onnxruntime-node: 1.24.3 + onnxruntime-web: 1.25.0-dev.20260327-722743c0e2 + sharp: 0.34.5 + + '@huggingface/transformers@4.2.0': + dependencies: + '@huggingface/jinja': 0.5.9 + '@huggingface/tokenizers': 0.1.3 + onnxruntime-node: 1.24.3 + onnxruntime-web: 1.26.0-dev.20260416-b7804b056c + sharp: 0.34.5 + + '@img/colour@1.1.0': {} + + '@img/sharp-darwin-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.0.4 + optional: true + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.0.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.0.4': + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.0.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.0.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.0.5': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.0.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.0.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.0.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.0.4 + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.0.5 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.0.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.0.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.33.5': + dependencies: + '@emnapi/runtime': 1.11.2 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.11.2 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.33.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.33.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.3 + + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.5': {} + + '@protobufjs/eventemitter@1.1.1': {} + + '@protobufjs/fetch@1.1.1': + dependencies: + '@protobufjs/aspromise': 1.1.2 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.2': {} + + '@types/node@26.1.1': + dependencies: + undici-types: 8.3.0 + + adm-zip@0.5.18: {} + + boolean@3.2.0: {} + + chownr@3.0.0: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + color-string@1.9.1: + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.4 + + color@4.2.3: + dependencies: + color-convert: 2.0.1 + color-string: 1.9.1 + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + detect-libc@2.1.2: {} + + detect-node@2.1.0: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es6-error@4.1.1: {} + + escape-string-regexp@4.0.0: {} + + flatbuffers@1.12.0: {} + + flatbuffers@25.9.23: {} + + global-agent@3.0.0: + dependencies: + boolean: 3.2.0 + es6-error: 4.1.1 + matcher: 3.0.0 + roarr: 2.15.4 + semver: 7.8.5 + serialize-error: 7.0.1 + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + gopd@1.2.0: {} + + guid-typescript@1.0.9: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + is-arrayish@0.3.4: {} + + json-stringify-safe@5.0.1: {} + + long@5.3.2: {} + + matcher@3.0.0: + dependencies: + escape-string-regexp: 4.0.0 + + minipass@7.1.3: {} + + minizlib@3.1.0: + dependencies: + minipass: 7.1.3 + + object-keys@1.1.1: {} + + onnxruntime-common@1.19.2: {} + + onnxruntime-common@1.20.0-dev.20241016-2b8fc5529b: {} + + onnxruntime-common@1.21.0: {} + + onnxruntime-common@1.22.0-dev.20250409-89f8206ba4: {} + + onnxruntime-common@1.24.0-dev.20251116-b39e144322: {} + + onnxruntime-common@1.24.3: {} + + onnxruntime-node@1.19.2: + dependencies: + onnxruntime-common: 1.19.2 + tar: 7.5.21 + + onnxruntime-node@1.21.0: + dependencies: + global-agent: 3.0.0 + onnxruntime-common: 1.21.0 + tar: 7.5.21 + + onnxruntime-node@1.24.3: + dependencies: + adm-zip: 0.5.18 + global-agent: 3.0.0 + onnxruntime-common: 1.24.3 + + onnxruntime-web@1.20.0-dev.20241016-2b8fc5529b: + dependencies: + flatbuffers: 1.12.0 + guid-typescript: 1.0.9 + long: 5.3.2 + onnxruntime-common: 1.20.0-dev.20241016-2b8fc5529b + platform: 1.3.6 + protobufjs: 7.6.5 + + onnxruntime-web@1.22.0-dev.20250409-89f8206ba4: + dependencies: + flatbuffers: 25.9.23 + guid-typescript: 1.0.9 + long: 5.3.2 + onnxruntime-common: 1.22.0-dev.20250409-89f8206ba4 + platform: 1.3.6 + protobufjs: 7.6.5 + + onnxruntime-web@1.25.0-dev.20260327-722743c0e2: + dependencies: + flatbuffers: 25.9.23 + guid-typescript: 1.0.9 + long: 5.3.2 + onnxruntime-common: 1.24.0-dev.20251116-b39e144322 + platform: 1.3.6 + protobufjs: 7.6.5 + + onnxruntime-web@1.26.0-dev.20260416-b7804b056c: + dependencies: + flatbuffers: 25.9.23 + guid-typescript: 1.0.9 + long: 5.3.2 + onnxruntime-common: 1.24.0-dev.20251116-b39e144322 + platform: 1.3.6 + protobufjs: 7.6.5 + + platform@1.3.6: {} + + protobufjs@7.6.5: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.5 + '@protobufjs/eventemitter': 1.1.1 + '@protobufjs/fetch': 1.1.1 + '@protobufjs/float': 1.0.2 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.2 + '@types/node': 26.1.1 + long: 5.3.2 + + roarr@2.15.4: + dependencies: + boolean: 3.2.0 + detect-node: 2.1.0 + globalthis: 1.0.4 + json-stringify-safe: 5.0.1 + semver-compare: 1.0.0 + sprintf-js: 1.1.3 + + semver-compare@1.0.0: {} + + semver@7.8.5: {} + + serialize-error@7.0.1: + dependencies: + type-fest: 0.13.1 + + sharp@0.33.5: + dependencies: + color: 4.2.3 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.33.5 + '@img/sharp-darwin-x64': 0.33.5 + '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-linux-arm': 0.33.5 + '@img/sharp-linux-arm64': 0.33.5 + '@img/sharp-linux-s390x': 0.33.5 + '@img/sharp-linux-x64': 0.33.5 + '@img/sharp-linuxmusl-arm64': 0.33.5 + '@img/sharp-linuxmusl-x64': 0.33.5 + '@img/sharp-wasm32': 0.33.5 + '@img/sharp-win32-ia32': 0.33.5 + '@img/sharp-win32-x64': 0.33.5 + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + + simple-swizzle@0.2.4: + dependencies: + is-arrayish: 0.3.4 + + sprintf-js@1.1.3: {} + + tar@7.5.21: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.3 + minizlib: 3.1.0 + yallist: 5.0.0 + + tslib@2.8.1: + optional: true + + type-fest@0.13.1: {} + + undici-types@8.3.0: {} + + yallist@5.0.0: {} diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/scenario.auto.cjs b/e2e/scenarios/huggingface-transformers-instrumentation/scenario.auto.cjs new file mode 100644 index 000000000..88b06b337 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/scenario.auto.cjs @@ -0,0 +1,7 @@ +const packageName = process.env.HUGGINGFACE_TRANSFORMERS_PACKAGE_NAME; +if (!packageName) { + throw new Error("HUGGINGFACE_TRANSFORMERS_PACKAGE_NAME must be set"); +} + +const sdk = require(packageName); +void import("./scenario.impl.mjs").then(({ runScenario }) => runScenario(sdk)); diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/scenario.auto.mjs b/e2e/scenarios/huggingface-transformers-instrumentation/scenario.auto.mjs new file mode 100644 index 000000000..2749d625d --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/scenario.auto.mjs @@ -0,0 +1,9 @@ +import { runScenario } from "./scenario.impl.mjs"; + +const packageName = process.env.HUGGINGFACE_TRANSFORMERS_PACKAGE_NAME; +if (!packageName) { + throw new Error("HUGGINGFACE_TRANSFORMERS_PACKAGE_NAME must be set"); +} + +const sdk = await import(packageName); +await runScenario(sdk); diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/scenario.impl.mjs b/e2e/scenarios/huggingface-transformers-instrumentation/scenario.impl.mjs new file mode 100644 index 000000000..c1f63003c --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/scenario.impl.mjs @@ -0,0 +1,211 @@ +import { + runOperation, + runTracedScenario, +} from "../../helpers/provider-runtime.mjs"; + +export const ROOT_NAME = "huggingface-transformers-instrumentation-root"; +export const SCENARIO_NAME = "huggingface-transformers-instrumentation"; +export const SCENARIO_TIMEOUT_MS = 90_000; +export const SCENARIO_SPECS = [ + { + dependencyName: "huggingface-transformers-v3", + snapshotName: "huggingface-transformers-v3", + }, + { + dependencyName: "huggingface-transformers-v3-latest", + snapshotName: "huggingface-transformers-v3-latest", + }, + { + dependencyName: "huggingface-transformers-v4", + snapshotName: "huggingface-transformers-v4", + }, + { + dependencyName: "huggingface-transformers-v4-latest", + snapshotName: "huggingface-transformers-v4-latest", + }, +]; + +function tensor(sdk, type, values, dims) { + const data = + type === "float32" + ? new Float32Array(values) + : new BigInt64Array(values.map((value) => BigInt(value))); + return new sdk.Tensor(type, data, dims); +} + +function makeTokenizer(sdk) { + const tokenizer = (texts, options = {}) => { + if (options.text_pair !== undefined) { + return { + input_ids: tensor(sdk, "int64", [101, 200, 102, 300, 301, 102], [1, 6]), + attention_mask: tensor(sdk, "int64", [1, 1, 1, 1, 1, 1], [1, 6]), + }; + } + + const batchSize = Array.isArray(texts) ? texts.length : 1; + return { + input_ids: tensor( + sdk, + "int64", + Array.from({ length: batchSize * 2 }, (_, index) => index + 1), + [batchSize, 2], + ), + attention_mask: tensor( + sdk, + "int64", + Array.from({ length: batchSize * 2 }, () => 1), + [batchSize, 2], + ), + }; + }; + tokenizer.add_bos_token = false; + tokenizer.add_eos_token = false; + tokenizer.all_special_ids = [101, 102]; + tokenizer.sep_token_id = 102; + tokenizer.batch_decode = (tokenIds) => + Array.from({ length: tokenIds.dims[0] }, () => "Deterministic output"); + tokenizer.decode = (tokenIds) => + tokenIds.some((value) => Number(value) === 300) ? "Ada" : "decoded"; + return tokenizer; +} + +function makeGenerationModel(sdk, modelName) { + return { + config: { + _name_or_path: modelName, + model_type: "fixture", + }, + generate: async () => tensor(sdk, "int64", [1, 2, 3], [1, 3]), + dispose: async () => {}, + }; +} + +function makeFeatureModel(sdk, modelName) { + return Object.assign( + async () => ({ + last_hidden_state: tensor(sdk, "float32", [0.1, 0.2, 0.3], [1, 1, 3]), + }), + { + config: { + _name_or_path: modelName, + model_type: "fixture", + }, + dispose: async () => {}, + }, + ); +} + +function makeQuestionAnsweringModel(sdk, modelName) { + return Object.assign( + async () => ({ + start_logits: tensor(sdk, "float32", [0, 0, 0, 10, 0, 0], [1, 6]), + end_logits: tensor(sdk, "float32", [0, 0, 0, 10, 0, 0], [1, 6]), + }), + { + config: { + _name_or_path: modelName, + model_type: "fixture", + }, + dispose: async () => {}, + }, + ); +} + +function createPipeline(sdk, task, modelName) { + const tokenizer = makeTokenizer(sdk); + switch (task) { + case "text-generation": + return new sdk.TextGenerationPipeline({ + task, + model: makeGenerationModel(sdk, modelName), + tokenizer, + }); + case "text2text-generation": + return new sdk.Text2TextGenerationPipeline({ + task, + model: makeGenerationModel(sdk, modelName), + tokenizer, + }); + case "summarization": + return new sdk.SummarizationPipeline({ + task, + model: makeGenerationModel(sdk, modelName), + tokenizer, + }); + case "feature-extraction": + return new sdk.FeatureExtractionPipeline({ + task, + model: makeFeatureModel(sdk, modelName), + tokenizer, + }); + case "question-answering": + return new sdk.QuestionAnsweringPipeline({ + task, + model: makeQuestionAnsweringModel(sdk, modelName), + tokenizer, + }); + default: + throw new Error(`Unsupported fixture task: ${task}`); + } +} + +export function withFixturePipelineFactory(sdk) { + return { + ...sdk, + pipeline: async (task, model) => + createPipeline(sdk, task, model ?? `fixture/${task}`), + }; +} + +export async function runScenario(sdk, options = {}) { + const create = + options.usePipelineFactory === true + ? (task, model) => sdk.pipeline(task, model) + : async (task, model) => createPipeline(sdk, task, model); + + await runTracedScenario({ + callback: async () => { + const operations = [ + { + task: "text-generation", + args: ["Hello", { temperature: 0 }], + }, + { + task: "text2text-generation", + args: ["Translate this"], + }, + { + task: "summarization", + args: ["A deliberately long passage."], + }, + { + task: "feature-extraction", + args: ["Embed this"], + }, + { + task: "question-answering", + args: ["Who built it?", "Ada built it."], + }, + ]; + + for (const operation of operations) { + await runOperation( + `transformers-${operation.task}-operation`, + operation.task, + async () => { + const pipeline = await create( + operation.task, + `fixture/${operation.task}`, + ); + await pipeline(...operation.args); + }, + ); + } + }, + metadata: { + scenario: SCENARIO_NAME, + }, + projectNameBase: SCENARIO_NAME, + rootName: ROOT_NAME, + }); +} diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/scenario.test.ts b/e2e/scenarios/huggingface-transformers-instrumentation/scenario.test.ts new file mode 100644 index 000000000..b419ed6fb --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/scenario.test.ts @@ -0,0 +1,101 @@ +import { describe } from "vitest"; +import { + prepareScenarioDir, + readInstalledPackageVersion, + resolveScenarioDir, +} from "../../helpers/scenario-harness"; +import { defineAssertions } from "./assertions"; +import { SCENARIO_SPECS, SCENARIO_TIMEOUT_MS } from "./scenario.impl.mjs"; + +const originalScenarioDir = resolveScenarioDir(import.meta.url); +const scenarioDir = await prepareScenarioDir({ + scenarioDir: originalScenarioDir, +}); +const scenarios = await Promise.all( + SCENARIO_SPECS.map(async (scenario) => ({ + ...scenario, + version: await readInstalledPackageVersion( + scenarioDir, + scenario.dependencyName, + ), + })), +); + +describe.concurrent("variants", () => { + for (const scenario of scenarios) { + describe.sequential(`Transformers.js ${scenario.version}`, () => { + defineAssertions({ + name: "wrapped instrumentation", + runScenario: async ({ runScenarioDir }) => { + await runScenarioDir({ + entry: "scenario.wrapper.ts", + env: { + HUGGINGFACE_TRANSFORMERS_PACKAGE_NAME: scenario.dependencyName, + }, + runContext: { + cassette: false, + originalScenarioDir, + variantKey: scenario.snapshotName, + }, + scenarioDir, + timeoutMs: SCENARIO_TIMEOUT_MS, + }); + }, + snapshotName: `${scenario.snapshotName}-wrapped`, + testFileUrl: import.meta.url, + timeoutMs: SCENARIO_TIMEOUT_MS, + }); + + defineAssertions({ + name: "auto-hook instrumentation ESM", + runScenario: async ({ runNodeScenarioDir }) => { + await runNodeScenarioDir({ + entry: "scenario.auto.mjs", + env: { + HUGGINGFACE_TRANSFORMERS_PACKAGE_NAME: scenario.dependencyName, + }, + nodeArgs: ["--import", "braintrust/hook.mjs"], + runContext: { + cassette: false, + originalScenarioDir, + variantKey: scenario.snapshotName, + }, + scenarioDir, + timeoutMs: SCENARIO_TIMEOUT_MS, + }); + }, + snapshotName: `${scenario.snapshotName}-auto-esm`, + testFileUrl: import.meta.url, + timeoutMs: SCENARIO_TIMEOUT_MS, + }); + }); + } +}); + +const latestV4 = scenarios.at(-1); +if (!latestV4) { + throw new Error("Expected a latest Transformers.js v4 scenario"); +} + +defineAssertions({ + name: `Transformers.js ${latestV4.version} auto-hook instrumentation CJS`, + runScenario: async ({ runNodeScenarioDir }) => { + await runNodeScenarioDir({ + entry: "scenario.auto.cjs", + env: { + HUGGINGFACE_TRANSFORMERS_PACKAGE_NAME: latestV4.dependencyName, + }, + nodeArgs: ["--import", "braintrust/hook.mjs"], + runContext: { + cassette: false, + originalScenarioDir, + variantKey: latestV4.snapshotName, + }, + scenarioDir, + timeoutMs: SCENARIO_TIMEOUT_MS, + }); + }, + snapshotName: `${latestV4.snapshotName}-auto-cjs`, + testFileUrl: import.meta.url, + timeoutMs: SCENARIO_TIMEOUT_MS, +}); diff --git a/e2e/scenarios/huggingface-transformers-instrumentation/scenario.wrapper.ts b/e2e/scenarios/huggingface-transformers-instrumentation/scenario.wrapper.ts new file mode 100644 index 000000000..7f7d37502 --- /dev/null +++ b/e2e/scenarios/huggingface-transformers-instrumentation/scenario.wrapper.ts @@ -0,0 +1,13 @@ +import { wrapHuggingFaceTransformers } from "braintrust"; +import { runScenario, withFixturePipelineFactory } from "./scenario.impl.mjs"; + +const packageName = process.env.HUGGINGFACE_TRANSFORMERS_PACKAGE_NAME; +if (!packageName) { + throw new Error("HUGGINGFACE_TRANSFORMERS_PACKAGE_NAME must be set"); +} + +const sdk = await import(packageName); +await runScenario( + wrapHuggingFaceTransformers(withFixturePipelineFactory(sdk)), + { usePipelineFactory: true }, +); diff --git a/js/src/auto-instrumentations/configs/all.ts b/js/src/auto-instrumentations/configs/all.ts index b2d778960..c4d4b4cb5 100644 --- a/js/src/auto-instrumentations/configs/all.ts +++ b/js/src/auto-instrumentations/configs/all.ts @@ -17,6 +17,7 @@ import { googleADKConfigs } from "./google-adk"; import { googleGenAIConfigs } from "./google-genai"; import { groqConfigs } from "./groq"; import { huggingFaceConfigs } from "./huggingface"; +import { huggingFaceTransformersConfigs } from "./huggingface-transformers"; import { langchainConfigs } from "./langchain"; import { langSmithConfigs } from "./langsmith"; import { mistralConfigs } from "./mistral"; @@ -62,7 +63,10 @@ const defaultInstrumentationConfigGroups: readonly InstrumentationConfigGroup[] integrations: ["google", "googleGenAI"], configs: googleGenAIConfigs, }, - { integrations: ["huggingface"], configs: huggingFaceConfigs }, + { + integrations: ["huggingface"], + configs: [...huggingFaceConfigs, ...huggingFaceTransformersConfigs], + }, { integrations: ["langchain", "langgraph"], configs: langchainConfigs, diff --git a/js/src/auto-instrumentations/configs/huggingface-transformers.ts b/js/src/auto-instrumentations/configs/huggingface-transformers.ts new file mode 100644 index 000000000..dd951ac25 --- /dev/null +++ b/js/src/auto-instrumentations/configs/huggingface-transformers.ts @@ -0,0 +1,64 @@ +import type { InstrumentationConfig } from "../orchestrion-js"; +import { huggingFaceTransformersChannels } from "../../instrumentation/plugins/huggingface-transformers-channels"; + +const moduleFiles = [ + { + filePath: "dist/transformers.mjs", + versionRange: ">=3.0.0 <3.4.0", + }, + { + filePath: "dist/transformers.cjs", + versionRange: ">=3.0.0 <3.4.0", + }, + { + filePath: "dist/transformers.js", + versionRange: ">=3.0.0 <3.4.0", + }, + { + filePath: "dist/transformers.node.mjs", + versionRange: ">=3.4.0 <5.0.0", + }, + { + filePath: "dist/transformers.node.cjs", + versionRange: ">=3.4.0 <5.0.0", + }, + { + filePath: "dist/transformers.web.js", + versionRange: ">=3.4.0 <5.0.0", + }, +] as const; +const pipelineClasses = [ + "TextGenerationPipeline", + "Text2TextGenerationPipeline", + "FeatureExtractionPipeline", + "QuestionAnsweringPipeline", +] as const; + +export const huggingFaceTransformersConfigs: InstrumentationConfig[] = + moduleFiles.flatMap(({ filePath, versionRange }) => [ + { + channelName: huggingFaceTransformersChannels.pipeline.channelName, + module: { + name: "@huggingface/transformers", + versionRange, + filePath, + }, + functionQuery: { + functionName: "pipeline", + kind: "Async", + }, + }, + ...pipelineClasses.map((className) => ({ + channelName: huggingFaceTransformersChannels.pipelineCall.channelName, + module: { + name: "@huggingface/transformers", + versionRange, + filePath, + }, + functionQuery: { + className, + methodName: "_call", + kind: "Async" as const, + }, + })), + ]); diff --git a/js/src/exports.ts b/js/src/exports.ts index 36a38946a..880f464c0 100644 --- a/js/src/exports.ts +++ b/js/src/exports.ts @@ -215,6 +215,7 @@ export { wrapGoogleGenAI } from "./wrappers/google-genai"; export { wrapGoogleADK } from "./wrappers/google-adk"; export { wrapGenkit } from "./wrappers/genkit"; export { wrapHuggingFace } from "./wrappers/huggingface"; +export { wrapHuggingFaceTransformers } from "./wrappers/huggingface-transformers"; export { wrapOpenRouterAgent } from "./wrappers/openrouter-agent"; export { wrapOpenRouter } from "./wrappers/openrouter"; export { wrapMistral } from "./wrappers/mistral"; diff --git a/js/src/instrumentation/braintrust-plugin.test.ts b/js/src/instrumentation/braintrust-plugin.test.ts index fdce9dc99..97d83be48 100644 --- a/js/src/instrumentation/braintrust-plugin.test.ts +++ b/js/src/instrumentation/braintrust-plugin.test.ts @@ -8,6 +8,7 @@ import { ClaudeAgentSDKPlugin } from "./plugins/claude-agent-sdk-plugin"; import { OpenAIAgentsPlugin } from "./plugins/openai-agents-plugin"; import { GoogleGenAIPlugin } from "./plugins/google-genai-plugin"; import { HuggingFacePlugin } from "./plugins/huggingface-plugin"; +import { HuggingFaceTransformersPlugin } from "./plugins/huggingface-transformers-plugin"; import { OpenRouterAgentPlugin } from "./plugins/openrouter-agent-plugin"; import { OpenRouterPlugin } from "./plugins/openrouter-plugin"; import { MistralPlugin } from "./plugins/mistral-plugin"; @@ -71,6 +72,10 @@ vi.mock("./plugins/huggingface-plugin", () => ({ HuggingFacePlugin: createPluginClassMock(), })); +vi.mock("./plugins/huggingface-transformers-plugin", () => ({ + HuggingFaceTransformersPlugin: createPluginClassMock(), +})); + vi.mock("./plugins/openrouter-plugin", () => ({ OpenRouterPlugin: createPluginClassMock(), })); @@ -188,6 +193,10 @@ describe("BraintrustPlugin", () => { expect(HuggingFacePlugin).toHaveBeenCalledTimes(1); const mockInstance = vi.mocked(HuggingFacePlugin).mock.results[0].value; expect(mockInstance.enable).toHaveBeenCalledTimes(1); + expect(HuggingFaceTransformersPlugin).toHaveBeenCalledTimes(1); + const transformersMockInstance = vi.mocked(HuggingFaceTransformersPlugin) + .mock.results[0].value; + expect(transformersMockInstance.enable).toHaveBeenCalledTimes(1); }); it("should create and enable OpenRouter plugin by default", () => { @@ -443,6 +452,7 @@ describe("BraintrustPlugin", () => { plugin.enable(); expect(HuggingFacePlugin).not.toHaveBeenCalled(); + expect(HuggingFaceTransformersPlugin).not.toHaveBeenCalled(); expect(OpenAIPlugin).toHaveBeenCalledTimes(1); expect(AnthropicPlugin).toHaveBeenCalledTimes(1); expect(AISDKPlugin).toHaveBeenCalledTimes(1); @@ -810,6 +820,9 @@ describe("BraintrustPlugin", () => { vi.mocked(GoogleGenAIPlugin).mock.results[0].value; const huggingFaceMock = vi.mocked(HuggingFacePlugin).mock.results[0].value; + const huggingFaceTransformersMock = vi.mocked( + HuggingFaceTransformersPlugin, + ).mock.results[0].value; const openRouterMock = vi.mocked(OpenRouterPlugin).mock.results[0].value; const openRouterAgentMock = vi.mocked(OpenRouterAgentPlugin).mock .results[0].value; @@ -830,6 +843,7 @@ describe("BraintrustPlugin", () => { expect(openAIAgentsMock.enable).toHaveBeenCalledTimes(1); expect(googleGenAIMock.enable).toHaveBeenCalledTimes(1); expect(huggingFaceMock.enable).toHaveBeenCalledTimes(1); + expect(huggingFaceTransformersMock.enable).toHaveBeenCalledTimes(1); expect(openRouterMock.enable).toHaveBeenCalledTimes(1); expect(openRouterAgentMock.enable).toHaveBeenCalledTimes(1); expect(mistralMock.enable).toHaveBeenCalledTimes(1); @@ -857,6 +871,9 @@ describe("BraintrustPlugin", () => { vi.mocked(GoogleGenAIPlugin).mock.results[0].value; const huggingFaceMock = vi.mocked(HuggingFacePlugin).mock.results[0].value; + const huggingFaceTransformersMock = vi.mocked( + HuggingFaceTransformersPlugin, + ).mock.results[0].value; const openRouterMock = vi.mocked(OpenRouterPlugin).mock.results[0].value; const openRouterAgentMock = vi.mocked(OpenRouterAgentPlugin).mock .results[0].value; @@ -879,6 +896,7 @@ describe("BraintrustPlugin", () => { expect(openAIAgentsMock.disable).toHaveBeenCalledTimes(1); expect(googleGenAIMock.disable).toHaveBeenCalledTimes(1); expect(huggingFaceMock.disable).toHaveBeenCalledTimes(1); + expect(huggingFaceTransformersMock.disable).toHaveBeenCalledTimes(1); expect(openRouterMock.disable).toHaveBeenCalledTimes(1); expect(openRouterAgentMock.disable).toHaveBeenCalledTimes(1); expect(mistralMock.disable).toHaveBeenCalledTimes(1); diff --git a/js/src/instrumentation/braintrust-plugin.ts b/js/src/instrumentation/braintrust-plugin.ts index d5435f2b0..a150538e8 100644 --- a/js/src/instrumentation/braintrust-plugin.ts +++ b/js/src/instrumentation/braintrust-plugin.ts @@ -8,6 +8,7 @@ import { CursorSDKPlugin } from "./plugins/cursor-sdk-plugin"; import { OpenAIAgentsPlugin } from "./plugins/openai-agents-plugin"; import { GoogleGenAIPlugin } from "./plugins/google-genai-plugin"; import { HuggingFacePlugin } from "./plugins/huggingface-plugin"; +import { HuggingFaceTransformersPlugin } from "./plugins/huggingface-transformers-plugin"; import { OpenRouterAgentPlugin } from "./plugins/openrouter-agent-plugin"; import { OpenRouterPlugin } from "./plugins/openrouter-plugin"; import { MistralPlugin } from "./plugins/mistral-plugin"; @@ -56,6 +57,8 @@ export class BraintrustPlugin extends BasePlugin { private openAIAgentsPlugin: OpenAIAgentsPlugin | null = null; private googleGenAIPlugin: GoogleGenAIPlugin | null = null; private huggingFacePlugin: HuggingFacePlugin | null = null; + private huggingFaceTransformersPlugin: HuggingFaceTransformersPlugin | null = + null; private openRouterPlugin: OpenRouterPlugin | null = null; private openRouterAgentPlugin: OpenRouterAgentPlugin | null = null; private mistralPlugin: MistralPlugin | null = null; @@ -130,6 +133,8 @@ export class BraintrustPlugin extends BasePlugin { if (integrations.huggingface !== false) { this.huggingFacePlugin = new HuggingFacePlugin(); this.huggingFacePlugin.enable(); + this.huggingFaceTransformersPlugin = new HuggingFaceTransformersPlugin(); + this.huggingFaceTransformersPlugin.enable(); } if (integrations.openrouter !== false) { @@ -262,6 +267,11 @@ export class BraintrustPlugin extends BasePlugin { this.huggingFacePlugin = null; } + if (this.huggingFaceTransformersPlugin) { + this.huggingFaceTransformersPlugin.disable(); + this.huggingFaceTransformersPlugin = null; + } + if (this.openRouterPlugin) { this.openRouterPlugin.disable(); this.openRouterPlugin = null; diff --git a/js/src/instrumentation/config.ts b/js/src/instrumentation/config.ts index 8a2d43373..fe6f62126 100644 --- a/js/src/instrumentation/config.ts +++ b/js/src/instrumentation/config.ts @@ -79,6 +79,8 @@ const envIntegrationAliases: Record< "google-genai": "googleGenAI", googlegenai: "googleGenAI", huggingface: "huggingface", + "@huggingface/transformers": "huggingface", + transformers: "huggingface", openrouter: "openrouter", openrouteragent: "openrouterAgent", "openrouter-agent": "openrouterAgent", diff --git a/js/src/instrumentation/plugins/huggingface-transformers-channels.ts b/js/src/instrumentation/plugins/huggingface-transformers-channels.ts new file mode 100644 index 000000000..74956406a --- /dev/null +++ b/js/src/instrumentation/plugins/huggingface-transformers-channels.ts @@ -0,0 +1,61 @@ +import { channel, defineChannels } from "../core/channel-definitions"; +import type { + HuggingFaceTransformersPipeline, + HuggingFaceTransformersTensor, +} from "../../vendor-sdk-types/huggingface-transformers"; + +export type HuggingFaceTransformersEventContext = { + moduleVersion?: string; + self?: HuggingFaceTransformersPipeline; +}; + +export type HuggingFaceTransformersPipelineInfo = { + model?: string; + task: string; +}; + +const pipelineInfo = new WeakMap(); + +export function registerHuggingFaceTransformersPipeline( + pipeline: HuggingFaceTransformersPipeline, + task: unknown, + model: unknown, +): void { + if (typeof task !== "string") { + return; + } + + pipelineInfo.set(pipeline, { + task, + ...(typeof model === "string" ? { model } : {}), + }); +} + +export function getHuggingFaceTransformersPipelineInfo( + pipeline: HuggingFaceTransformersPipeline | undefined, +): HuggingFaceTransformersPipelineInfo | undefined { + return pipeline ? pipelineInfo.get(pipeline) : undefined; +} + +export const huggingFaceTransformersChannels = defineChannels( + "@huggingface/transformers", + { + pipeline: channel< + [string, (string | null)?, Record?], + HuggingFaceTransformersPipeline, + HuggingFaceTransformersEventContext + >({ + channelName: "pipeline", + kind: "async", + }), + + pipelineCall: channel< + [unknown, ...unknown[]], + unknown | HuggingFaceTransformersTensor, + HuggingFaceTransformersEventContext + >({ + channelName: "pipeline.call", + kind: "async", + }), + }, +); diff --git a/js/src/instrumentation/plugins/huggingface-transformers-plugin.test.ts b/js/src/instrumentation/plugins/huggingface-transformers-plugin.test.ts new file mode 100644 index 000000000..643dce42b --- /dev/null +++ b/js/src/instrumentation/plugins/huggingface-transformers-plugin.test.ts @@ -0,0 +1,127 @@ +import { describe, expect, it } from "vitest"; +import { + registerHuggingFaceTransformersPipeline, + type HuggingFaceTransformersEventContext, +} from "./huggingface-transformers-channels"; +import { _exportsForTestingOnly } from "./huggingface-transformers-plugin"; +import type { HuggingFaceTransformersPipeline } from "../../vendor-sdk-types/huggingface-transformers"; + +const { extractInput, extractMetadata, extractOutput, isSupportedTask } = + _exportsForTestingOnly; + +describe("HuggingFaceTransformersPlugin extraction", () => { + it("normalizes generation and chat payloads", () => { + expect(extractInput("text-generation", ["Hello"])).toEqual([ + { role: "user", content: "Hello" }, + ]); + expect( + extractInput("text-generation", [[{ role: "user", content: "Hello" }]]), + ).toEqual([{ role: "user", content: "Hello" }]); + expect( + extractOutput("text-generation", [ + { + generated_text: [ + { role: "user", content: "Hello" }, + { role: "assistant", content: "Hi!" }, + ], + }, + ]), + ).toEqual([ + { + index: 0, + finish_reason: "stop", + message: { role: "assistant", content: "Hi!" }, + }, + ]); + }); + + it("normalizes text-to-text, summarization, and question answering", () => { + expect( + extractOutput("text2text-generation", [{ generated_text: "translated" }]), + ).toEqual([ + { + index: 0, + finish_reason: "stop", + message: { role: "assistant", content: "translated" }, + }, + ]); + expect( + extractOutput("summarization", [{ summary_text: "summary" }]), + ).toEqual([ + { + index: 0, + finish_reason: "stop", + message: { role: "assistant", content: "summary" }, + }, + ]); + expect( + extractInput("question-answering", ["Who built it?", "Ada built it."]), + ).toEqual([ + { + role: "user", + content: "Context:\nAda built it.\n\nQuestion:\nWho built it?", + }, + ]); + expect( + extractOutput("question-answering", { + answer: "Ada", + score: 0.99, + }), + ).toEqual([ + { + index: 0, + finish_reason: "stop", + message: { role: "assistant", content: "Ada" }, + }, + ]); + }); + + it("summarizes feature extraction tensors without logging vectors", () => { + expect( + extractOutput("feature-extraction", { + dims: [2, 5, 384], + data: new Float32Array(2 * 5 * 384), + }), + ).toEqual({ + embedding_batch_count: 2, + embedding_count: 5, + embedding_length: 384, + }); + }); + + it("uses factory metadata and only keeps allowed request settings", () => { + const pipeline = Object.assign(async () => [], { + task: "text-generation", + model: { config: { model_type: "gpt2" } }, + }) as HuggingFaceTransformersPipeline; + registerHuggingFaceTransformersPipeline( + pipeline, + "text-generation", + "onnx-community/tiny-model", + ); + + expect( + extractMetadata( + { self: pipeline } satisfies HuggingFaceTransformersEventContext, + [ + "Hello", + { + temperature: 0, + top_p: 0.9, + max_new_tokens: 5, + }, + ], + ), + ).toEqual({ + model: "onnx-community/tiny-model", + provider: "huggingface", + temperature: 0, + top_p: 0.9, + }); + }); + + it("limits tracing to the approved pipeline tasks", () => { + expect(isSupportedTask("feature-extraction")).toBe(true); + expect(isSupportedTask("text-classification")).toBe(false); + }); +}); diff --git a/js/src/instrumentation/plugins/huggingface-transformers-plugin.ts b/js/src/instrumentation/plugins/huggingface-transformers-plugin.ts new file mode 100644 index 000000000..27986dd58 --- /dev/null +++ b/js/src/instrumentation/plugins/huggingface-transformers-plugin.ts @@ -0,0 +1,317 @@ +import { BasePlugin } from "../core"; +import { traceAsyncChannel, unsubscribeAll } from "../core/channel-tracing"; +import type { ChannelMessage } from "../core/channel-definitions"; +import type { IsoChannelHandlers, IsoTracingChannel } from "../../isomorph"; +import { SpanTypeAttribute, isObject } from "../../../util"; +import type { + HuggingFaceTransformersPipeline, + HuggingFaceTransformersTask, + HuggingFaceTransformersTensor, +} from "../../vendor-sdk-types/huggingface-transformers"; +import { + getHuggingFaceTransformersPipelineInfo, + huggingFaceTransformersChannels, + registerHuggingFaceTransformersPipeline, + type HuggingFaceTransformersEventContext, +} from "./huggingface-transformers-channels"; + +const SUPPORTED_TASKS: ReadonlySet = new Set([ + "text-generation", + "text2text-generation", + "summarization", + "feature-extraction", + "question-answering", +]); + +export class HuggingFaceTransformersPlugin extends BasePlugin { + protected onEnable(): void { + this.subscribeToPipelineFactory(); + this.unsubscribers.push( + traceAsyncChannel(huggingFaceTransformersChannels.pipelineCall, { + name: (_args, event) => + `huggingface.transformers.${getTask(event as HuggingFaceTransformersEventContext)?.replaceAll("-", "_") ?? "unknown"}`, + type: SpanTypeAttribute.LLM, + shouldTrace: (_args, event) => + isSupportedTask( + getTask(event as HuggingFaceTransformersEventContext), + ), + extractInput: (args, event) => ({ + input: extractInput( + getTask(event as HuggingFaceTransformersEventContext), + args, + ), + metadata: extractMetadata( + event as HuggingFaceTransformersEventContext, + args, + ), + }), + extractOutput: (result, event) => + extractOutput( + getTask(event as HuggingFaceTransformersEventContext), + result, + ), + extractMetrics: () => ({}), + }), + ); + } + + protected onDisable(): void { + this.unsubscribers = unsubscribeAll(this.unsubscribers); + } + + private subscribeToPipelineFactory(): void { + const channel = + huggingFaceTransformersChannels.pipeline.tracingChannel() as IsoTracingChannel< + ChannelMessage + >; + const handlers: IsoChannelHandlers< + ChannelMessage + > = { + asyncEnd: (event) => { + if (typeof event.result !== "function") { + return; + } + registerHuggingFaceTransformersPipeline( + event.result, + event.arguments?.[0], + event.arguments?.[1], + ); + }, + }; + + channel.subscribe(handlers); + this.unsubscribers.push(() => channel.unsubscribe(handlers)); + } +} + +function isSupportedTask( + task: string | undefined, +): task is HuggingFaceTransformersTask { + return task !== undefined && SUPPORTED_TASKS.has(task); +} + +function getTask( + event: HuggingFaceTransformersEventContext, +): string | undefined { + const self = event.self; + return ( + getHuggingFaceTransformersPipelineInfo(self)?.task ?? + (typeof self?.task === "string" ? self.task : undefined) + ); +} + +function extractMetadata( + event: HuggingFaceTransformersEventContext, + args: unknown[], +): Record { + const metadata: Record = { + provider: "huggingface", + }; + const registeredModel = getHuggingFaceTransformersPipelineInfo( + event.self, + )?.model; + const model = registeredModel ?? modelIdentifier(event.self); + if (model) { + metadata.model = model; + } + + const task = getTask(event); + const options = + task === "question-answering" ? args[2] : isObject(args[1]) ? args[1] : {}; + if (isObject(options)) { + for (const key of ["temperature", "top_p", "max_tokens", "stop"]) { + if (options[key] !== undefined) { + metadata[key] = options[key]; + } + } + } + return metadata; +} + +function modelIdentifier( + pipeline: HuggingFaceTransformersPipeline | undefined, +): string | undefined { + const model = pipeline?.model; + if (!isObject(model)) { + return undefined; + } + + const config = isObject(model.config) ? model.config : undefined; + for (const value of [ + config?._name_or_path, + config?.name_or_path, + config?.model_id, + config?.modelId, + model.name, + ]) { + if (typeof value === "string" && value.length > 0) { + return value; + } + } + return undefined; +} + +function extractInput(task: string | undefined, args: unknown[]): unknown { + if (task === "feature-extraction") { + return args[0]; + } + + if (task === "question-answering") { + const question = args[0]; + const context = args[1]; + if ( + Array.isArray(question) && + Array.isArray(context) && + question.every((value) => typeof value === "string") && + context.every((value) => typeof value === "string") + ) { + return question.map((value, index) => [ + { + role: "user", + content: `Context:\n${context[index] ?? ""}\n\nQuestion:\n${value}`, + }, + ]); + } + if (typeof question === "string" && typeof context === "string") { + return [ + { + role: "user", + content: `Context:\n${context}\n\nQuestion:\n${question}`, + }, + ]; + } + return { context, question }; + } + + const input = args[0]; + if (task === "text-generation" && isChat(input)) { + return input; + } + if ( + task === "text-generation" && + Array.isArray(input) && + input.every(isChat) + ) { + return input; + } + if (typeof input === "string") { + return [{ role: "user", content: input }]; + } + if ( + Array.isArray(input) && + input.every((value) => typeof value === "string") + ) { + return input.map((value) => [{ role: "user", content: value }]); + } + return input; +} + +function isChat(value: unknown): value is Array> { + return ( + Array.isArray(value) && + value.length > 0 && + value.every( + (message) => + isObject(message) && + typeof message.role === "string" && + "content" in message, + ) + ); +} + +function extractOutput(task: string | undefined, result: unknown): unknown { + if (task === "feature-extraction") { + return summarizeEmbedding(result); + } + if (task === "question-answering") { + return choicesFromAnswers(result); + } + return choicesFromGenerations(result); +} + +function summarizeEmbedding( + result: unknown, +): Record | undefined { + if (!isObject(result) || !Array.isArray(result.dims)) { + return undefined; + } + + const dims = (result as HuggingFaceTransformersTensor).dims; + if ( + !dims || + dims.length === 0 || + !dims.every((dimension) => typeof dimension === "number") + ) { + return undefined; + } + if (dims.length === 1) { + return { embedding_length: dims[0] }; + } + if (dims.length === 2) { + return { + embedding_count: dims[0], + embedding_length: dims[1], + }; + } + return { + embedding_batch_count: dims[0], + embedding_count: dims[1], + embedding_length: dims.at(-1) ?? 0, + }; +} + +function choicesFromAnswers(result: unknown): unknown { + const answers = Array.isArray(result) ? result.flat() : [result]; + const choices = answers.flatMap((answer, index) => + isObject(answer) && typeof answer.answer === "string" + ? [ + { + index, + finish_reason: "stop", + message: { + role: "assistant", + content: answer.answer, + }, + }, + ] + : [], + ); + return choices.length > 0 ? choices : undefined; +} + +function choicesFromGenerations(result: unknown): unknown { + const generations = Array.isArray(result) ? result.flat() : [result]; + const choices = generations.flatMap((generation, index) => { + if (!isObject(generation)) { + return []; + } + const generated = + generation.generated_text ?? generation.summary_text ?? undefined; + const content = + typeof generated === "string" + ? generated + : isChat(generated) + ? generated.at(-1)?.content + : undefined; + return typeof content === "string" + ? [ + { + index, + finish_reason: "stop", + message: { + role: "assistant", + content, + }, + }, + ] + : []; + }); + return choices.length > 0 ? choices : undefined; +} + +export const _exportsForTestingOnly = { + extractInput, + extractMetadata, + extractOutput, + isSupportedTask, +}; diff --git a/js/src/vendor-sdk-types/huggingface-transformers.ts b/js/src/vendor-sdk-types/huggingface-transformers.ts new file mode 100644 index 000000000..ab9d47266 --- /dev/null +++ b/js/src/vendor-sdk-types/huggingface-transformers.ts @@ -0,0 +1,45 @@ +export type HuggingFaceTransformersTask = + | "text-generation" + | "text2text-generation" + | "summarization" + | "feature-extraction" + | "question-answering"; + +export interface HuggingFaceTransformersTensor { + dims?: readonly number[]; + data?: ArrayLike; + tolist?: () => unknown; + [key: string]: unknown; +} + +export interface HuggingFaceTransformersModel { + config?: Record; + name?: string; + [key: string]: unknown; +} + +export interface HuggingFaceTransformersPipeline { + (...args: unknown[]): Promise; + task?: string; + model?: HuggingFaceTransformersModel; + tokenizer?: unknown; + [key: string]: unknown; +} + +export interface HuggingFaceTransformersPipelineConstructor { + new (...args: unknown[]): HuggingFaceTransformersPipeline; +} + +export interface HuggingFaceTransformersModule { + pipeline?: ( + task: string, + model?: string | null, + options?: Record, + ) => Promise; + TextGenerationPipeline?: HuggingFaceTransformersPipelineConstructor; + Text2TextGenerationPipeline?: HuggingFaceTransformersPipelineConstructor; + SummarizationPipeline?: HuggingFaceTransformersPipelineConstructor; + FeatureExtractionPipeline?: HuggingFaceTransformersPipelineConstructor; + QuestionAnsweringPipeline?: HuggingFaceTransformersPipelineConstructor; + [key: string]: unknown; +} diff --git a/js/src/wrappers/huggingface-transformers.test.ts b/js/src/wrappers/huggingface-transformers.test.ts new file mode 100644 index 000000000..31bdb6724 --- /dev/null +++ b/js/src/wrappers/huggingface-transformers.test.ts @@ -0,0 +1,170 @@ +import { + afterEach, + beforeAll, + beforeEach, + describe, + expect, + test, +} from "vitest"; +import { + _exportsForTestingOnly, + initLogger, + type TestBackgroundLogger, +} from "../logger"; +import { configureNode } from "../node/config"; +import { wrapHuggingFaceTransformers } from "./huggingface-transformers"; + +try { + configureNode(); +} catch { + // Shared process setup in tests can run this more than once. +} + +function makePipeline(task: string) { + const outputs: Record = { + "text-generation": [{ generated_text: "Hello world" }], + "text2text-generation": [{ generated_text: "Bonjour" }], + summarization: [{ summary_text: "Short summary" }], + "feature-extraction": { + dims: [1, 3], + data: new Float32Array([0.1, 0.2, 0.3]), + }, + "question-answering": { answer: "Ada", score: 0.99 }, + }; + return Object.assign(async (..._args: unknown[]) => outputs[task], { + task, + model: { + config: { _name_or_path: "instance-model" }, + }, + }); +} + +function makeModule() { + return { + pipeline: async (task: string) => makePipeline(task), + TextGenerationPipeline: function (options: { task: string }) { + return makePipeline(options.task); + }, + }; +} + +describe("wrapHuggingFaceTransformers", () => { + let backgroundLogger: TestBackgroundLogger; + + beforeAll(async () => { + await _exportsForTestingOnly.simulateLoginForTests(); + }); + + beforeEach(() => { + backgroundLogger = _exportsForTestingOnly.useTestBackgroundLogger(); + initLogger({ + projectName: "huggingface-transformers.test.ts", + projectId: "test-project-id", + }); + }); + + afterEach(() => { + _exportsForTestingOnly.clearTestBackgroundLogger(); + }); + + test("traces the five supported pipeline tasks through the factory", async () => { + const transformers = wrapHuggingFaceTransformers(makeModule()); + const calls = [ + ["text-generation", ["Hello", { temperature: 0 }]], + ["text2text-generation", ["Hello"]], + ["summarization", ["Long text"]], + ["feature-extraction", ["Embedding input"]], + ["question-answering", ["Who?", "Ada did."]], + ] as const; + + for (const [task, args] of calls) { + const pipeline = await transformers.pipeline?.(task, `model/${task}`); + await pipeline?.(...args); + } + + const spans = await backgroundLogger.drain(); + expect(spans).toHaveLength(5); + expect(spans.map((span) => span.span_attributes?.name)).toEqual([ + "huggingface.transformers.text_generation", + "huggingface.transformers.text2text_generation", + "huggingface.transformers.summarization", + "huggingface.transformers.feature_extraction", + "huggingface.transformers.question_answering", + ]); + expect(spans[0]).toMatchObject({ + input: [{ role: "user", content: "Hello" }], + metadata: { + model: "model/text-generation", + provider: "huggingface", + temperature: 0, + }, + output: [ + { + index: 0, + message: { role: "assistant", content: "Hello world" }, + }, + ], + span_attributes: { type: "llm" }, + }); + expect(spans[3]).toMatchObject({ + output: { + embedding_count: 1, + embedding_length: 3, + }, + }); + }); + + test("wraps exported pipeline constructors and is idempotent", async () => { + const module = makeModule(); + const wrapped = wrapHuggingFaceTransformers(module); + expect(wrapHuggingFaceTransformers(wrapped)).toBe(wrapped); + + const Pipeline = wrapped.TextGenerationPipeline; + const pipeline = Pipeline + ? new Pipeline({ task: "text-generation" }) + : undefined; + expect(pipeline && wrapHuggingFaceTransformers(pipeline)).toBe(pipeline); + await pipeline?.("Hello"); + + const spans = await backgroundLogger.drain(); + expect(spans).toHaveLength(1); + expect(spans[0]).toMatchObject({ + metadata: { + model: "instance-model", + provider: "huggingface", + }, + span_attributes: { + name: "huggingface.transformers.text_generation", + }, + }); + }); + + test("does not trace unsupported tasks", async () => { + const transformers = wrapHuggingFaceTransformers(makeModule()); + const pipeline = await transformers.pipeline?.( + "text-classification", + "model/classifier", + ); + await pipeline?.("Hello"); + + expect(await backgroundLogger.drain()).toHaveLength(0); + }); + + test("propagates pipeline errors and logs the original failure", async () => { + const failure = new Error("local inference failed"); + const pipeline = Object.assign( + async () => { + throw failure; + }, + { task: "text-generation" }, + ); + const wrapped = wrapHuggingFaceTransformers(pipeline); + + await expect(wrapped("Hello")).rejects.toBe(failure); + const spans = await backgroundLogger.drain(); + expect(spans).toHaveLength(1); + expect(spans[0]).toMatchObject({ + error: "local inference failed", + }); + }); +}); diff --git a/js/src/wrappers/huggingface-transformers.ts b/js/src/wrappers/huggingface-transformers.ts new file mode 100644 index 000000000..10c2703fe --- /dev/null +++ b/js/src/wrappers/huggingface-transformers.ts @@ -0,0 +1,165 @@ +import { isObject } from "../../util"; +import { huggingFaceTransformersChannels } from "../instrumentation/plugins/huggingface-transformers-channels"; +import type { + HuggingFaceTransformersModule, + HuggingFaceTransformersPipeline, + HuggingFaceTransformersPipelineConstructor, +} from "../vendor-sdk-types/huggingface-transformers"; + +const PIPELINE_CONSTRUCTOR_KEYS = new Set([ + "TextGenerationPipeline", + "Text2TextGenerationPipeline", + "SummarizationPipeline", + "FeatureExtractionPipeline", + "QuestionAnsweringPipeline", +]); +const SUPPORTED_TASKS = new Set([ + "text-generation", + "text2text-generation", + "summarization", + "feature-extraction", + "question-answering", +]); +const wrappedValues = new WeakMap(); + +export function wrapHuggingFaceTransformers( + transformers: HuggingFaceTransformersModule, +): HuggingFaceTransformersModule; +export function wrapHuggingFaceTransformers( + transformers: HuggingFaceTransformersPipeline, +): HuggingFaceTransformersPipeline; +export function wrapHuggingFaceTransformers(transformers: T): T; +export function wrapHuggingFaceTransformers(transformers: unknown): unknown { + const pipelineTask = (transformers as { task?: unknown } | null)?.task; + if ( + typeof transformers === "function" && + typeof pipelineTask === "string" && + SUPPORTED_TASKS.has(pipelineTask) + ) { + return wrapPipeline(transformers as HuggingFaceTransformersPipeline); + } + if (!isSupportedModule(transformers)) { + return transformers; + } + const existing = wrappedValues.get(transformers); + if (existing) { + return existing; + } + + const proxy = new Proxy(Object.create(transformers), { + get(_target, property, receiver) { + const value = Reflect.get(transformers, property, receiver); + if (property === "pipeline" && typeof value === "function") { + return wrapPipelineFactory(value); + } + if ( + typeof property === "string" && + PIPELINE_CONSTRUCTOR_KEYS.has(property) && + typeof value === "function" + ) { + return wrapPipelineConstructor( + value as HuggingFaceTransformersPipelineConstructor, + ); + } + return value; + }, + }); + wrappedValues.set(transformers, proxy); + wrappedValues.set(proxy, proxy); + return proxy; +} + +function isSupportedModule( + value: unknown, +): value is HuggingFaceTransformersModule { + if (!isObject(value)) { + return false; + } + return ( + typeof value.pipeline === "function" || + [...PIPELINE_CONSTRUCTOR_KEYS].some( + (key) => typeof value[key] === "function", + ) + ); +} + +function wrapPipelineFactory( + factory: NonNullable, +): HuggingFaceTransformersModule["pipeline"] { + const existing = wrappedValues.get(factory); + if (existing) { + return existing as HuggingFaceTransformersModule["pipeline"]; + } + const wrapped = function ( + this: unknown, + ...args: [ + task: string, + model?: string | null, + options?: Record, + ] + ) { + const [task] = args; + const context: Parameters< + typeof huggingFaceTransformersChannels.pipeline.tracePromise + >[1] = { + arguments: args, + }; + return huggingFaceTransformersChannels.pipeline + .tracePromise(() => Reflect.apply(factory, this, args), context) + .then((pipeline) => + SUPPORTED_TASKS.has(pipeline.task ?? task) + ? wrapPipeline(pipeline) + : pipeline, + ); + }; + wrappedValues.set(factory, wrapped); + wrappedValues.set(wrapped, wrapped); + return wrapped; +} + +function wrapPipelineConstructor( + constructor: HuggingFaceTransformersPipelineConstructor, +): HuggingFaceTransformersPipelineConstructor { + const existing = wrappedValues.get(constructor); + if (existing) { + return existing as HuggingFaceTransformersPipelineConstructor; + } + const proxy = new Proxy(constructor, { + construct(target, args, newTarget) { + const pipeline = Reflect.construct(target, args, newTarget); + return typeof pipeline.task === "string" && + SUPPORTED_TASKS.has(pipeline.task) + ? wrapPipeline(pipeline) + : pipeline; + }, + }); + wrappedValues.set(constructor, proxy); + wrappedValues.set(proxy, proxy); + return proxy; +} + +function wrapPipeline( + pipeline: HuggingFaceTransformersPipeline, +): HuggingFaceTransformersPipeline { + const existing = wrappedValues.get(pipeline); + if (existing) { + return existing as HuggingFaceTransformersPipeline; + } + const proxy = new Proxy(pipeline, { + apply(target, thisArg, args) { + const context: Parameters< + typeof huggingFaceTransformersChannels.pipelineCall.tracePromise + >[1] = { + arguments: args as [unknown, ...unknown[]], + self: target, + }; + return huggingFaceTransformersChannels.pipelineCall.tracePromise( + () => Reflect.apply(target, thisArg, args), + context, + ); + }, + }); + wrappedValues.set(pipeline, proxy); + wrappedValues.set(proxy, proxy); + return proxy; +} From 6468a3e05aa001b177bc6e0b0d3268e1723fef78 Mon Sep 17 00:00:00 2001 From: lforst <8118419+lforst@users.noreply.github.com> Date: Thu, 23 Jul 2026 15:05:56 +0000 Subject: [PATCH 2/3] Update PR #2271 --- .changeset/trace-huggingface-transformers.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/trace-huggingface-transformers.md diff --git a/.changeset/trace-huggingface-transformers.md b/.changeset/trace-huggingface-transformers.md new file mode 100644 index 000000000..f34186b64 --- /dev/null +++ b/.changeset/trace-huggingface-transformers.md @@ -0,0 +1,5 @@ +--- +"braintrust": patch +--- + +feat: Add instrumentation for `@huggingface/transformers` From e061e08d3a01fe09abf7dd2fdfc1dc66587d4e07 Mon Sep 17 00:00:00 2001 From: lforst <8118419+lforst@users.noreply.github.com> Date: Thu, 23 Jul 2026 15:16:02 +0000 Subject: [PATCH 3/3] Update PR #2271 --- .../huggingface-transformers-channels.ts | 4 +- .../huggingface-transformers-plugin.test.ts | 11 ++-- .../huggingface-transformers.ts | 4 -- .../wrappers/huggingface-transformers.test.ts | 54 ++++++++++++++----- 4 files changed, 50 insertions(+), 23 deletions(-) diff --git a/js/src/instrumentation/plugins/huggingface-transformers-channels.ts b/js/src/instrumentation/plugins/huggingface-transformers-channels.ts index 74956406a..2afee96ed 100644 --- a/js/src/instrumentation/plugins/huggingface-transformers-channels.ts +++ b/js/src/instrumentation/plugins/huggingface-transformers-channels.ts @@ -1,4 +1,5 @@ import { channel, defineChannels } from "../core/channel-definitions"; +import { INSTRUMENTATION_NAMES } from "../../span-origin"; import type { HuggingFaceTransformersPipeline, HuggingFaceTransformersTensor, @@ -9,7 +10,7 @@ export type HuggingFaceTransformersEventContext = { self?: HuggingFaceTransformersPipeline; }; -export type HuggingFaceTransformersPipelineInfo = { +type HuggingFaceTransformersPipelineInfo = { model?: string; task: string; }; @@ -58,4 +59,5 @@ export const huggingFaceTransformersChannels = defineChannels( kind: "async", }), }, + { instrumentationName: INSTRUMENTATION_NAMES.HUGGINGFACE }, ); diff --git a/js/src/instrumentation/plugins/huggingface-transformers-plugin.test.ts b/js/src/instrumentation/plugins/huggingface-transformers-plugin.test.ts index 643dce42b..667fc19c7 100644 --- a/js/src/instrumentation/plugins/huggingface-transformers-plugin.test.ts +++ b/js/src/instrumentation/plugins/huggingface-transformers-plugin.test.ts @@ -90,10 +90,13 @@ describe("HuggingFaceTransformersPlugin extraction", () => { }); it("uses factory metadata and only keeps allowed request settings", () => { - const pipeline = Object.assign(async () => [], { - task: "text-generation", - model: { config: { model_type: "gpt2" } }, - }) as HuggingFaceTransformersPipeline; + const pipeline: HuggingFaceTransformersPipeline = Object.assign( + async () => [], + { + task: "text-generation", + model: { config: { model_type: "gpt2" } }, + }, + ); registerHuggingFaceTransformersPipeline( pipeline, "text-generation", diff --git a/js/src/vendor-sdk-types/huggingface-transformers.ts b/js/src/vendor-sdk-types/huggingface-transformers.ts index ab9d47266..bfc817b1b 100644 --- a/js/src/vendor-sdk-types/huggingface-transformers.ts +++ b/js/src/vendor-sdk-types/huggingface-transformers.ts @@ -9,13 +9,11 @@ export interface HuggingFaceTransformersTensor { dims?: readonly number[]; data?: ArrayLike; tolist?: () => unknown; - [key: string]: unknown; } export interface HuggingFaceTransformersModel { config?: Record; name?: string; - [key: string]: unknown; } export interface HuggingFaceTransformersPipeline { @@ -23,7 +21,6 @@ export interface HuggingFaceTransformersPipeline { task?: string; model?: HuggingFaceTransformersModel; tokenizer?: unknown; - [key: string]: unknown; } export interface HuggingFaceTransformersPipelineConstructor { @@ -41,5 +38,4 @@ export interface HuggingFaceTransformersModule { SummarizationPipeline?: HuggingFaceTransformersPipelineConstructor; FeatureExtractionPipeline?: HuggingFaceTransformersPipelineConstructor; QuestionAnsweringPipeline?: HuggingFaceTransformersPipelineConstructor; - [key: string]: unknown; } diff --git a/js/src/wrappers/huggingface-transformers.test.ts b/js/src/wrappers/huggingface-transformers.test.ts index 31bdb6724..4b6770f38 100644 --- a/js/src/wrappers/huggingface-transformers.test.ts +++ b/js/src/wrappers/huggingface-transformers.test.ts @@ -13,6 +13,11 @@ import { } from "../logger"; import { configureNode } from "../node/config"; import { wrapHuggingFaceTransformers } from "./huggingface-transformers"; +import type { + HuggingFaceTransformersModule, + HuggingFaceTransformersPipeline, + HuggingFaceTransformersPipelineConstructor, +} from "../vendor-sdk-types/huggingface-transformers"; try { configureNode(); @@ -20,7 +25,7 @@ try { // Shared process setup in tests can run this more than once. } -function makePipeline(task: string) { +function makePipeline(task: string): HuggingFaceTransformersPipeline { const outputs: Record = { "text-generation": [{ generated_text: "Hello world" }], "text2text-generation": [{ generated_text: "Bonjour" }], @@ -39,12 +44,9 @@ function makePipeline(task: string) { }); } -function makeModule() { +function makeModule(): HuggingFaceTransformersModule { return { pipeline: async (task: string) => makePipeline(task), - TextGenerationPipeline: function (options: { task: string }) { - return makePipeline(options.task); - }, }; } @@ -84,12 +86,32 @@ describe("wrapHuggingFaceTransformers", () => { const spans = await backgroundLogger.drain(); expect(spans).toHaveLength(5); - expect(spans.map((span) => span.span_attributes?.name)).toEqual([ - "huggingface.transformers.text_generation", - "huggingface.transformers.text2text_generation", - "huggingface.transformers.summarization", - "huggingface.transformers.feature_extraction", - "huggingface.transformers.question_answering", + expect(spans).toMatchObject([ + { + span_attributes: { + name: "huggingface.transformers.text_generation", + }, + }, + { + span_attributes: { + name: "huggingface.transformers.text2text_generation", + }, + }, + { + span_attributes: { + name: "huggingface.transformers.summarization", + }, + }, + { + span_attributes: { + name: "huggingface.transformers.feature_extraction", + }, + }, + { + span_attributes: { + name: "huggingface.transformers.question_answering", + }, + }, ]); expect(spans[0]).toMatchObject({ input: [{ role: "user", content: "Hello" }], @@ -115,7 +137,11 @@ describe("wrapHuggingFaceTransformers", () => { }); test("wraps exported pipeline constructors and is idempotent", async () => { - const module = makeModule(); + const module: HuggingFaceTransformersModule = { + TextGenerationPipeline: function (options: { task: string }) { + return makePipeline(options.task); + } as unknown as HuggingFaceTransformersPipelineConstructor, + }; const wrapped = wrapHuggingFaceTransformers(module); expect(wrapHuggingFaceTransformers(wrapped)).toBe(wrapped); @@ -152,8 +178,8 @@ describe("wrapHuggingFaceTransformers", () => { test("propagates pipeline errors and logs the original failure", async () => { const failure = new Error("local inference failed"); - const pipeline = Object.assign( - async () => { + const pipeline: HuggingFaceTransformersPipeline = Object.assign( + async (..._args: unknown[]) => { throw failure; }, { task: "text-generation" },