langwatch 0.3.0-prerelease.1 → 0.3.0-prerelease.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/dist/chunk-4BZATFKJ.mjs +181 -0
  2. package/dist/chunk-4BZATFKJ.mjs.map +1 -0
  3. package/dist/chunk-CSC3CMIT.mjs +118 -0
  4. package/dist/chunk-CSC3CMIT.mjs.map +1 -0
  5. package/dist/chunk-F63YKTXA.mjs +47 -0
  6. package/dist/chunk-F63YKTXA.mjs.map +1 -0
  7. package/dist/chunk-G3AUABT7.js +4 -0
  8. package/dist/chunk-G3AUABT7.js.map +1 -0
  9. package/dist/chunk-HPC6Z7J4.js +118 -0
  10. package/dist/chunk-HPC6Z7J4.js.map +1 -0
  11. package/dist/chunk-KGDAENGD.js +50 -0
  12. package/dist/chunk-KGDAENGD.js.map +1 -0
  13. package/dist/chunk-LD74LVRU.js +47 -0
  14. package/dist/chunk-LD74LVRU.js.map +1 -0
  15. package/dist/chunk-OM7VY3XT.mjs +4 -0
  16. package/dist/chunk-OM7VY3XT.mjs.map +1 -0
  17. package/dist/chunk-PCQVQ7SB.js +45 -0
  18. package/dist/chunk-PCQVQ7SB.js.map +1 -0
  19. package/dist/chunk-PMBEK6YE.mjs +424 -0
  20. package/dist/chunk-PMBEK6YE.mjs.map +1 -0
  21. package/dist/chunk-PR3JDWC3.mjs +50 -0
  22. package/dist/chunk-PR3JDWC3.mjs.map +1 -0
  23. package/dist/chunk-PTJ6AAI7.js +360 -0
  24. package/dist/chunk-PTJ6AAI7.js.map +1 -0
  25. package/dist/chunk-QEWDG5QE.mjs +45 -0
  26. package/dist/chunk-QEWDG5QE.mjs.map +1 -0
  27. package/dist/chunk-REUCVT7A.mjs +39 -0
  28. package/dist/chunk-REUCVT7A.mjs.map +1 -0
  29. package/dist/chunk-SVJ7SCGB.js +424 -0
  30. package/dist/chunk-SVJ7SCGB.js.map +1 -0
  31. package/dist/chunk-VJSOCNPA.js +181 -0
  32. package/dist/chunk-VJSOCNPA.js.map +1 -0
  33. package/dist/chunk-WM2GRSRW.js +39 -0
  34. package/dist/chunk-WM2GRSRW.js.map +1 -0
  35. package/dist/chunk-Z5J5UI5E.mjs +360 -0
  36. package/dist/chunk-Z5J5UI5E.mjs.map +1 -0
  37. package/dist/client-B2HqIKg6.d.ts +51 -0
  38. package/dist/client-XyCqclCi.d.mts +51 -0
  39. package/dist/client-browser.d.mts +8 -0
  40. package/dist/client-browser.d.ts +8 -0
  41. package/dist/client-browser.js +83 -0
  42. package/dist/client-browser.js.map +1 -0
  43. package/dist/client-browser.mjs +83 -0
  44. package/dist/client-browser.mjs.map +1 -0
  45. package/dist/client-node.d.mts +8 -0
  46. package/dist/client-node.d.ts +8 -0
  47. package/dist/client-node.js +90 -0
  48. package/dist/client-node.js.map +1 -0
  49. package/dist/client-node.mjs +90 -0
  50. package/dist/client-node.mjs.map +1 -0
  51. package/dist/evaluation/index.d.mts +897 -0
  52. package/dist/evaluation/index.d.ts +897 -0
  53. package/dist/evaluation/index.js +13 -0
  54. package/dist/evaluation/index.js.map +1 -0
  55. package/dist/evaluation/index.mjs +13 -0
  56. package/dist/evaluation/index.mjs.map +1 -0
  57. package/dist/filterable-batch-span-processor-zO5kcjBY.d.mts +64 -0
  58. package/dist/filterable-batch-span-processor-zO5kcjBY.d.ts +64 -0
  59. package/dist/index.d.mts +48 -0
  60. package/{src/observability/exporters/langwatch-exporter.ts → dist/index.d.ts} +13 -18
  61. package/dist/index.js +30 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/index.mjs +30 -0
  64. package/dist/index.mjs.map +1 -0
  65. package/dist/observability/index.d.mts +260 -0
  66. package/dist/observability/index.d.ts +260 -0
  67. package/dist/observability/index.js +20 -0
  68. package/dist/observability/index.js.map +1 -0
  69. package/dist/observability/index.mjs +20 -0
  70. package/dist/observability/index.mjs.map +1 -0
  71. package/dist/observability/instrumentation/langchain/index.d.mts +40 -0
  72. package/dist/observability/instrumentation/langchain/index.d.ts +40 -0
  73. package/dist/observability/instrumentation/langchain/index.js +666 -0
  74. package/dist/observability/instrumentation/langchain/index.js.map +1 -0
  75. package/dist/observability/instrumentation/langchain/index.mjs +666 -0
  76. package/dist/observability/instrumentation/langchain/index.mjs.map +1 -0
  77. package/dist/prompt/index.d.mts +10 -0
  78. package/dist/prompt/index.d.ts +10 -0
  79. package/dist/prompt/index.js +18 -0
  80. package/dist/prompt/index.js.map +1 -0
  81. package/dist/prompt/index.mjs +18 -0
  82. package/dist/prompt/index.mjs.map +1 -0
  83. package/dist/prompt-BXJWdbQp.d.mts +1967 -0
  84. package/dist/prompt-BXJWdbQp.d.ts +1967 -0
  85. package/dist/record-evaluation-CmxMXa-3.d.mts +25 -0
  86. package/dist/record-evaluation-CmxMXa-3.d.ts +25 -0
  87. package/dist/trace-D-bZOuqb.d.mts +622 -0
  88. package/dist/trace-G2312klE.d.ts +622 -0
  89. package/package.json +9 -4
  90. package/.editorconfig +0 -16
  91. package/.eslintrc.cjs +0 -37
  92. package/copy-types.sh +0 -28
  93. package/examples/langchain/.env.example +0 -2
  94. package/examples/langchain/README.md +0 -42
  95. package/examples/langchain/package-lock.json +0 -2930
  96. package/examples/langchain/package.json +0 -27
  97. package/examples/langchain/src/cli-markdown.d.ts +0 -137
  98. package/examples/langchain/src/index.ts +0 -109
  99. package/examples/langchain/tsconfig.json +0 -25
  100. package/examples/langgraph/.env.example +0 -2
  101. package/examples/langgraph/README.md +0 -42
  102. package/examples/langgraph/package-lock.json +0 -3031
  103. package/examples/langgraph/package.json +0 -28
  104. package/examples/langgraph/src/cli-markdown.d.ts +0 -137
  105. package/examples/langgraph/src/index.ts +0 -196
  106. package/examples/langgraph/tsconfig.json +0 -25
  107. package/examples/mastra/.env.example +0 -2
  108. package/examples/mastra/README.md +0 -57
  109. package/examples/mastra/package-lock.json +0 -5296
  110. package/examples/mastra/package.json +0 -32
  111. package/examples/mastra/src/cli-markdown.d.ts +0 -137
  112. package/examples/mastra/src/index.ts +0 -120
  113. package/examples/mastra/src/mastra/agents/weather-agent.ts +0 -30
  114. package/examples/mastra/src/mastra/index.ts +0 -21
  115. package/examples/mastra/src/mastra/tools/weather-tool.ts +0 -102
  116. package/examples/mastra/tsconfig.json +0 -25
  117. package/examples/vercel-ai/.env.example +0 -2
  118. package/examples/vercel-ai/README.md +0 -38
  119. package/examples/vercel-ai/package-lock.json +0 -2571
  120. package/examples/vercel-ai/package.json +0 -27
  121. package/examples/vercel-ai/src/cli-markdown.d.ts +0 -137
  122. package/examples/vercel-ai/src/index.ts +0 -110
  123. package/examples/vercel-ai/src/instrumentation.ts +0 -9
  124. package/examples/vercel-ai/tsconfig.json +0 -25
  125. package/src/__tests__/client-browser.test.ts +0 -92
  126. package/src/__tests__/client-node.test.ts +0 -76
  127. package/src/__tests__/client.test.ts +0 -71
  128. package/src/__tests__/integration/client-browser.test.ts +0 -46
  129. package/src/__tests__/integration/client-node.test.ts +0 -46
  130. package/src/client-browser.ts +0 -70
  131. package/src/client-node.ts +0 -82
  132. package/src/client-shared.ts +0 -72
  133. package/src/client.ts +0 -119
  134. package/src/evaluation/__tests__/record-evaluation.test.ts +0 -112
  135. package/src/evaluation/__tests__/run-evaluation.test.ts +0 -171
  136. package/src/evaluation/index.ts +0 -2
  137. package/src/evaluation/record-evaluation.ts +0 -101
  138. package/src/evaluation/run-evaluation.ts +0 -133
  139. package/src/evaluation/tracer.ts +0 -3
  140. package/src/evaluation/types.ts +0 -23
  141. package/src/index.ts +0 -13
  142. package/src/internal/api/__tests__/errors.test.ts +0 -98
  143. package/src/internal/api/client.ts +0 -30
  144. package/src/internal/api/errors.ts +0 -32
  145. package/src/internal/generated/openapi/.gitkeep +0 -0
  146. package/src/internal/generated/types/.gitkeep +0 -0
  147. package/src/observability/__tests__/integration/base.test.ts +0 -74
  148. package/src/observability/__tests__/integration/browser-setup-ordering.test.ts +0 -60
  149. package/src/observability/__tests__/integration/complex-nested-spans.test.ts +0 -29
  150. package/src/observability/__tests__/integration/error-handling.test.ts +0 -24
  151. package/src/observability/__tests__/integration/langwatch-disabled-otel.test.ts +0 -24
  152. package/src/observability/__tests__/integration/langwatch-first-then-vercel.test.ts +0 -24
  153. package/src/observability/__tests__/integration/multiple-setup-attempts.test.ts +0 -27
  154. package/src/observability/__tests__/integration/otel-ordering.test.ts +0 -27
  155. package/src/observability/__tests__/integration/vercel-configurations.test.ts +0 -20
  156. package/src/observability/__tests__/integration/vercel-first-then-langwatch.test.ts +0 -27
  157. package/src/observability/__tests__/span.test.ts +0 -214
  158. package/src/observability/__tests__/trace.test.ts +0 -180
  159. package/src/observability/exporters/index.ts +0 -1
  160. package/src/observability/index.ts +0 -4
  161. package/src/observability/instrumentation/langchain/__tests__/integration/langchain-chatbot.test.ts +0 -112
  162. package/src/observability/instrumentation/langchain/__tests__/langchain.test.ts +0 -284
  163. package/src/observability/instrumentation/langchain/index.ts +0 -624
  164. package/src/observability/processors/__tests__/filterable-batch-span-exporter.test.ts +0 -98
  165. package/src/observability/processors/filterable-batch-span-processor.ts +0 -99
  166. package/src/observability/processors/index.ts +0 -1
  167. package/src/observability/semconv/attributes.ts +0 -185
  168. package/src/observability/semconv/events.ts +0 -42
  169. package/src/observability/semconv/index.ts +0 -16
  170. package/src/observability/semconv/values.ts +0 -159
  171. package/src/observability/span.ts +0 -728
  172. package/src/observability/trace.ts +0 -301
  173. package/src/prompt/__tests__/prompt.test.ts +0 -139
  174. package/src/prompt/get-prompt-version.ts +0 -49
  175. package/src/prompt/get-prompt.ts +0 -44
  176. package/src/prompt/index.ts +0 -3
  177. package/src/prompt/prompt.ts +0 -133
  178. package/src/prompt/service.ts +0 -221
  179. package/src/prompt/tracer.ts +0 -3
  180. package/src/prompt/types.ts +0 -0
  181. package/ts-to-zod.config.js +0 -35
  182. package/tsconfig.json +0 -26
  183. package/tsup.config.ts +0 -20
  184. package/vitest.config.ts +0 -9
@@ -1,101 +0,0 @@
1
- import { EvaluationRESTResult } from "../internal/generated/types/evaluations";
2
- import * as intSemconv from "../observability/semconv";
3
- import { Attributes, SpanStatusCode } from "@opentelemetry/api";
4
- import { generate } from "xksuid";
5
- import { tracer } from "./tracer";
6
-
7
- export interface RecordedEvaluationDetails {
8
- evaluationId?: string;
9
- name: string;
10
- type?: string;
11
- isGuardrail?: boolean;
12
- status?: "processed" | "skipped" | "error";
13
- passed?: boolean;
14
- score?: number;
15
- label?: string;
16
- details?: string;
17
- cost?: number | { currency: string; amount: number };
18
- error?: Error;
19
- timestamps?: {
20
- startedAtUnixMs: number;
21
- finishedAtUnixMs: number;
22
- };
23
- }
24
-
25
- export function recordEvaluation(
26
- details: RecordedEvaluationDetails,
27
- attributes?: Attributes,
28
- ) {
29
- let result: EvaluationRESTResult;
30
- const status = details.status || "processed";
31
-
32
- if (status === "skipped") {
33
- result = {
34
- status: "skipped",
35
- details: details.details,
36
- };
37
- } else if (status === "error") {
38
- result = {
39
- status: "error",
40
- error_type: details.error?.name || "Unknown",
41
- details: details.details || details.error?.message || "Unknown error",
42
- };
43
- } else {
44
- result = {
45
- status: "processed",
46
- passed: details.passed,
47
- score: details.score,
48
- label: details.label,
49
- details: details.details,
50
- };
51
- if (details.cost) {
52
- (result as any).cost =
53
- typeof details.cost === "number"
54
- ? { currency: "USD", amount: details.cost }
55
- : details.cost;
56
- }
57
- }
58
-
59
- tracer.startActiveSpan("record evaluation", (span) => {
60
- try {
61
- span.setType(details.isGuardrail ? "guardrail" : "evaluation");
62
- span.addEvent(intSemconv.ATTR_LANGWATCH_EVALUATION_CUSTOM, {
63
- json_encoded_event: JSON.stringify({
64
- evaluation_id: details.evaluationId ?? `eval_${generate()}`,
65
- name: details.name,
66
- type: details.type,
67
- is_guardrail: details.isGuardrail,
68
- status: result.status,
69
- passed: details.passed,
70
- score: details.score,
71
- label: details.label,
72
- details: details.details,
73
- cost: details.cost,
74
- error: details.error,
75
- timestamps: details.timestamps,
76
- }),
77
- });
78
-
79
- span.setOutput(result);
80
-
81
- if (attributes) {
82
- span.setAttributes(attributes);
83
- }
84
- if (details.cost) {
85
- span.setMetrics({
86
- cost:
87
- typeof details.cost === "number"
88
- ? details.cost
89
- : details.cost.amount,
90
- });
91
- }
92
- } catch (error) {
93
- span.recordException(error as Error);
94
- span.setStatus({ code: SpanStatusCode.ERROR, message: (error as Error)?.message });
95
- } finally {
96
- span.end();
97
- }
98
-
99
- return;
100
- });
101
- }
@@ -1,133 +0,0 @@
1
- import { LangWatchApiError } from "../internal/api/errors";
2
- import { canAutomaticallyCaptureInput, getApiKey, getEndpoint } from "../client";
3
- import { Conversation } from "../internal/generated/types/evaluations";
4
- import {
5
- Evaluators,
6
- EvaluatorTypes,
7
- SingleEvaluationResult,
8
- } from "../internal/generated/types/evaluators.generated";
9
- import { RAGChunk } from "../internal/generated/types/tracer";
10
- import { tracer } from "./tracer";
11
- import { EvaluationResultModel } from "./types";
12
- import { SpanStatusCode } from "@opentelemetry/api";
13
-
14
- export interface BasicEvaluationData {
15
- input?: string;
16
- output?: string;
17
- expected_output?: unknown;
18
- contexts?: RAGChunk[] | string[];
19
- expected_contexts?: RAGChunk[] | string[];
20
- conversation?: Conversation;
21
- }
22
-
23
- export interface EvaluationDetailsBase {
24
- name?: string;
25
- data: BasicEvaluationData | Record<string, unknown>;
26
- contexts?: RAGChunk[] | string[];
27
- conversation?: Conversation;
28
- asGuardrail?: boolean;
29
- }
30
-
31
- export interface SavedEvaluationDetails extends EvaluationDetailsBase {
32
- slug: string;
33
- settings?: Record<string, unknown>;
34
- }
35
-
36
- export interface LangEvalsEvaluationDetails<T extends EvaluatorTypes>
37
- extends EvaluationDetailsBase {
38
- evaluator: T;
39
- settings?: Evaluators[T]["settings"];
40
- }
41
-
42
- export type EvaluationDetails =
43
- | SavedEvaluationDetails
44
- | LangEvalsEvaluationDetails<EvaluatorTypes>;
45
-
46
- export async function runEvaluation(
47
- details: EvaluationDetails,
48
- ): Promise<SingleEvaluationResult> {
49
- return await tracer.startActiveSpan("run evaluation", async (span) => {
50
- span.setType(details.asGuardrail ? "guardrail" : "evaluation");
51
-
52
- try {
53
- const evaluatorId =
54
- "slug" in details ? details.slug : details.evaluator;
55
- const request = {
56
- trace_id: span.spanContext().traceId,
57
- span_id: span.spanContext().spanId,
58
- data: details.data,
59
- name: details.name,
60
- settings: details.settings,
61
- as_guardrail: details.asGuardrail,
62
- };
63
-
64
- if (canAutomaticallyCaptureInput()) {
65
- span.setInput(request);
66
- }
67
-
68
- const url = new URL(
69
- `/api/evaluations/${evaluatorId}/evaluate`,
70
- getEndpoint(),
71
- );
72
-
73
- const response = await fetch(url.toString(), {
74
- method: "POST",
75
- headers: {
76
- "X-Auth-Token": getApiKey(),
77
- "Content-Type": "application/json",
78
- },
79
- body: JSON.stringify(request),
80
- });
81
- if (!response.ok) {
82
- const err = new LangWatchApiError("Unable to run evaluation", response);
83
- await err.safeParseBody(response);
84
-
85
- throw err;
86
- }
87
-
88
- const result: EvaluationResultModel = await response.json();
89
-
90
- span.setMetrics({
91
- cost: result.cost?.amount,
92
- });
93
-
94
- span.setOutputEvaluation(details.asGuardrail ?? false, result);
95
-
96
- if (result.status === "processed") {
97
- return {
98
- status: "processed",
99
- passed: result.passed,
100
- score: result.score,
101
- details: result.details,
102
- label: result.label,
103
- cost: result.cost,
104
- } as SingleEvaluationResult;
105
- } else if (result.status === "skipped") {
106
- return {
107
- status: "skipped",
108
- details: result.details,
109
- } as SingleEvaluationResult;
110
- } else if (result.status === "error") {
111
- return {
112
- status: "error",
113
- error_type: (result as any).error_type || "Unknown",
114
- details: result.details || "Unknown error",
115
- traceback: (result as any).traceback || [],
116
- } as SingleEvaluationResult;
117
- } else {
118
- return {
119
- status: "error",
120
- error_type: "UnknownStatus",
121
- details: `Unknown evaluation status: ${result.status}`,
122
- traceback: [],
123
- } as SingleEvaluationResult;
124
- }
125
- } catch (error) {
126
- span.recordException(error as Error);
127
- span.setStatus({ code: SpanStatusCode.ERROR, message: (error as Error)?.message });
128
- throw error;
129
- } finally {
130
- span.end();
131
- }
132
- });
133
- }
@@ -1,3 +0,0 @@
1
- import { getLangWatchTracer } from "../observability/trace";
2
-
3
- export const tracer = getLangWatchTracer("langwatch.evaluation");
@@ -1,23 +0,0 @@
1
- export class EvaluationError extends Error {
2
- readonly httpStatus: number;
3
- readonly body: unknown;
4
-
5
- constructor(message: string, httpStatus: number, body: unknown) {
6
- super(message);
7
- this.name = "EvaluationError";
8
- this.httpStatus = httpStatus;
9
- this.body = body;
10
- }
11
- }
12
-
13
- export interface EvaluationResultModel {
14
- status: "processed" | "skipped" | "error";
15
- passed?: boolean;
16
- score?: number;
17
- details?: string;
18
- label?: string;
19
- cost?: {
20
- currency: string;
21
- amount: number;
22
- };
23
- }
package/src/index.ts DELETED
@@ -1,13 +0,0 @@
1
- export { getLangWatchTracer, type LangWatchSpan } from "./observability";
2
- export {
3
- FilterableBatchSpanProcessor,
4
- type SpanProcessingExcludeRule,
5
- } from "./observability/processors";
6
- export { LangWatchExporter } from "./observability/exporters";
7
-
8
- export { recordEvaluation, runEvaluation } from "./evaluation";
9
-
10
- export {
11
- getPrompt,
12
- getPromptVersion,
13
- } from "./prompt";
@@ -1,98 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { LangWatchApiError } from '../errors';
3
-
4
- describe('LangWatchApiError', () => {
5
- it('creates error with message and response', () => {
6
- const mockResponse = {
7
- status: 400,
8
- statusText: 'Bad Request'
9
- } as Response;
10
-
11
- const error = new LangWatchApiError('Test error message', mockResponse);
12
- expect(error.message).toBe('Test error message');
13
- expect(error.name).toBe('Error');
14
- expect(error.httpStatus).toBe(400);
15
- expect(error.httpStatusText).toBe('Bad Request');
16
- });
17
-
18
- it('inherits from Error', () => {
19
- const mockResponse = { status: 500, statusText: 'Internal Server Error' } as Response;
20
- const error = new LangWatchApiError('Test error', mockResponse);
21
- expect(error).toBeInstanceOf(Error);
22
- expect(error).toBeInstanceOf(LangWatchApiError);
23
- });
24
-
25
- it('has stack trace', () => {
26
- const mockResponse = { status: 404, statusText: 'Not Found' } as Response;
27
- const error = new LangWatchApiError('Test error', mockResponse);
28
- expect(error.stack).toBeDefined();
29
- expect(typeof error.stack).toBe('string');
30
- });
31
-
32
- it('parses JSON response body', async () => {
33
- const mockResponse = {
34
- status: 400,
35
- statusText: 'Bad Request',
36
- headers: {
37
- get: vi.fn().mockReturnValue('application/json')
38
- },
39
- json: vi.fn().mockResolvedValue({ error: 'Invalid API key' })
40
- } as unknown as Response;
41
-
42
- const error = new LangWatchApiError('Bad request', mockResponse);
43
- await error.safeParseBody(mockResponse);
44
-
45
- expect(error.body).toEqual({ error: 'Invalid API key' });
46
- expect(error.apiError).toBe('Invalid API key');
47
- });
48
-
49
- it('parses text response body for non-JSON content', async () => {
50
- const mockResponse = {
51
- status: 500,
52
- statusText: 'Internal Server Error',
53
- headers: {
54
- get: vi.fn().mockReturnValue('text/plain')
55
- },
56
- text: vi.fn().mockResolvedValue('Server error occurred')
57
- } as unknown as Response;
58
-
59
- const error = new LangWatchApiError('Server error', mockResponse);
60
- await error.safeParseBody(mockResponse);
61
-
62
- expect(error.body).toBe('Server error occurred');
63
- expect(error.apiError).toBeUndefined();
64
- });
65
-
66
- it('handles parsing errors gracefully', async () => {
67
- const mockResponse = {
68
- status: 500,
69
- statusText: 'Internal Server Error',
70
- headers: {
71
- get: vi.fn().mockReturnValue('application/json')
72
- },
73
- json: vi.fn().mockRejectedValue(new Error('Parse error'))
74
- } as unknown as Response;
75
-
76
- const error = new LangWatchApiError('Server error', mockResponse);
77
- await error.safeParseBody(mockResponse);
78
-
79
- expect(error.body).toBe(null);
80
- });
81
-
82
- it('handles JSON without error field', async () => {
83
- const mockResponse = {
84
- status: 400,
85
- statusText: 'Bad Request',
86
- headers: {
87
- get: vi.fn().mockReturnValue('application/json')
88
- },
89
- json: vi.fn().mockResolvedValue({ message: 'Something went wrong' })
90
- } as unknown as Response;
91
-
92
- const error = new LangWatchApiError('Bad request', mockResponse);
93
- await error.safeParseBody(mockResponse);
94
-
95
- expect(error.body).toEqual({ message: 'Something went wrong' });
96
- expect(error.apiError).toBeUndefined();
97
- });
98
- });
@@ -1,30 +0,0 @@
1
- import openApiCreateClient from "openapi-fetch";
2
- import type { paths } from "../generated/openapi/api-client";
3
- import { z } from "zod";
4
- import { getApiKey, getEndpoint } from "../../client";
5
-
6
- // Define the client type explicitly to avoid naming issues
7
- export type LangwatchApiClient = ReturnType<typeof openApiCreateClient<paths>>;
8
-
9
- const configSchema = z.object({
10
- apiKey: z.string().min(1, "API key is required"),
11
- endpoint: z.string().url("Endpoint must be a valid URL"),
12
- });
13
-
14
- export function createLangWatchApiClient(apiKey?: string | undefined, endpoint?: string | undefined ): LangwatchApiClient {
15
- // This will error if the config is invalid
16
- const config = configSchema.parse({
17
- apiKey: apiKey ?? getApiKey(),
18
- endpoint: endpoint ?? getEndpoint(),
19
- });
20
-
21
- return openApiCreateClient<paths>({
22
- baseUrl: config.endpoint,
23
- headers: {
24
- "X-Auth-Token": config.apiKey,
25
- "Content-Type": "application/json",
26
- },
27
- });
28
- }
29
-
30
-
@@ -1,32 +0,0 @@
1
- export class LangWatchApiError extends Error {
2
- public readonly httpStatus: number;
3
- public readonly httpStatusText: string;
4
- public apiError: string | undefined;
5
- public body: unknown;
6
-
7
- constructor(message: string, response: Response) {
8
- super(message);
9
- this.httpStatus = response.status;
10
- this.httpStatusText = response.statusText;
11
- }
12
-
13
- async safeParseBody(response: Response): Promise<void> {
14
- try {
15
- if (response.headers.get("Content-Type")?.includes("application/json")) {
16
- const json = await response.json();
17
-
18
- this.body = json;
19
-
20
- if (json.error && typeof json.error === "string") {
21
- this.apiError = json.error;
22
- }
23
-
24
- return;
25
- }
26
-
27
- this.body = await response.text();
28
- } catch {
29
- this.body = null;
30
- }
31
- }
32
- }
File without changes
File without changes
@@ -1,74 +0,0 @@
1
- import { beforeAll, describe, expect, it } from "vitest";
2
- import { setupLangWatch } from "../../../client-node";
3
- import { getLangWatchTracer } from "../../trace";
4
-
5
- const tracerName = "basic-observability.test";
6
-
7
- describe("basic observability tests around tracing", () => {
8
- beforeAll(async () => {
9
- await setupLangWatch();
10
- });
11
-
12
- it("traces should be sent", async () => {
13
- const tracer = getLangWatchTracer(tracerName);
14
- await tracer.withActiveSpan(
15
- "basic trace",
16
- async () => { },
17
- );
18
- });
19
-
20
- it("traces should be sent with complex arguments", async () => {
21
- const tracer = getLangWatchTracer(tracerName);
22
- await tracer.withActiveSpan(
23
- "complex argument trace",
24
- { attributes: { foo: "bar" }, root: true },
25
- async (span) => {
26
- span.setAttributes({
27
- bar: "bas",
28
- });
29
- span.addEvent("test event", {
30
- foo: "bar",
31
- });
32
- },
33
- );
34
- });
35
-
36
- it("traces exceptions", async () => {
37
- const tracer = getLangWatchTracer(tracerName);
38
-
39
- await expect(
40
- tracer.withActiveSpan(
41
- "trace exception",
42
- async () => {
43
- throw new Error("this is meant to error");
44
- },
45
- )
46
- ).rejects.toThrow("this is meant to error");
47
- });
48
-
49
- it("traces handle complex nesting", async () => {
50
- const tracer = getLangWatchTracer(tracerName);
51
- await tracer.withActiveSpan(
52
- "complex nesting trace",
53
- async () => {
54
- await tracer.withActiveSpan(
55
- "nested trace alpha",
56
- async () => { },
57
- );
58
- await tracer.withActiveSpan(
59
- "nested trace beta",
60
- async () => { },
61
- );
62
- await tracer.withActiveSpan(
63
- "nested trace gamma",
64
- async () => {
65
- await tracer.withActiveSpan(
66
- "nested trace gamma child",
67
- async () => { },
68
- );
69
- },
70
- );
71
- },
72
- );
73
- });
74
- });
@@ -1,60 +0,0 @@
1
- import { describe, it, expect, vi } from "vitest";
2
- import { setupLangWatch as setupBrowser } from "../../../client-browser";
3
- import { getLangWatchTracer } from "../../trace";
4
-
5
- // Mock window object for Node.js test environment
6
- const mockWindow = {
7
- addEventListener: vi.fn(),
8
- removeEventListener: vi.fn(),
9
- };
10
- global.window = mockWindow as any;
11
-
12
- describe("Browser SDK setup ordering", () => {
13
- it("should work when LangWatch browser setup is called multiple times", async () => {
14
- // First setup
15
- await setupBrowser({
16
- apiKey: "test-key-1",
17
- endpoint: "http://localhost:9999",
18
- skipOpenTelemetrySetup: false,
19
- });
20
-
21
- // Second setup should work (browser doesn't have the same restriction as node)
22
- await setupBrowser({
23
- apiKey: "test-key-2",
24
- endpoint: "http://localhost:9999",
25
- skipOpenTelemetrySetup: false,
26
- });
27
-
28
- // Test that LangWatch still works
29
- const tracer = getLangWatchTracer("browser-multiple-test");
30
- await tracer.withActiveSpan("test span", async () => {
31
- expect(true).toBe(true);
32
- });
33
- });
34
-
35
- it("should work when LangWatch is set up with skipOpenTelemetrySetup=true", async () => {
36
- // Setup LangWatch with automatic setup disabled
37
- await setupBrowser({
38
- apiKey: "test-key",
39
- endpoint: "http://localhost:9999",
40
- skipOpenTelemetrySetup: true,
41
- });
42
-
43
- // Test that LangWatch still works
44
- const tracer = getLangWatchTracer("browser-disabled-test");
45
- await tracer.withActiveSpan("test span", async () => {
46
- expect(true).toBe(true);
47
- });
48
- });
49
-
50
- it("should handle window event listeners correctly", async () => {
51
- await setupBrowser({
52
- apiKey: "test-key",
53
- endpoint: "http://localhost:9999",
54
- skipOpenTelemetrySetup: false,
55
- });
56
-
57
- // Check that window event listeners were added
58
- expect(mockWindow.addEventListener).toHaveBeenCalled();
59
- });
60
- });
@@ -1,29 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { registerOTel } from '@vercel/otel';
3
- import { setupLangWatch } from "../../../client-node";
4
- import { getLangWatchTracer } from "../../trace";
5
-
6
- describe("Complex nested spans with Vercel AI", () => {
7
- it("should work with complex nested spans when Vercel AI is set up first", async () => {
8
- registerOTel({ serviceName: 'complex-test' });
9
- await setupLangWatch({
10
- apiKey: "test-key",
11
- endpoint: "http://localhost:9999",
12
- skipOpenTelemetrySetup: false,
13
- });
14
-
15
- const tracer = getLangWatchTracer("complex-otel-test");
16
-
17
- await tracer.withActiveSpan("root span", async () => {
18
- await tracer.withActiveSpan("child span 1", async () => {
19
- await tracer.withActiveSpan("grandchild span", async () => {
20
- expect(true).toBe(true);
21
- });
22
- });
23
-
24
- await tracer.withActiveSpan("child span 2", async () => {
25
- expect(true).toBe(true);
26
- });
27
- });
28
- });
29
- });
@@ -1,24 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { registerOTel } from '@vercel/otel';
3
- import { setupLangWatch } from "../../../client-node";
4
- import { getLangWatchTracer } from "../../trace";
5
-
6
- describe("Error handling with Vercel AI", () => {
7
- it("should handle errors gracefully when both are set up", async () => {
8
- registerOTel({ serviceName: 'error-test' });
9
- await setupLangWatch({
10
- apiKey: "test-key",
11
- endpoint: "http://localhost:9999",
12
- skipOpenTelemetrySetup: false,
13
- });
14
-
15
- const tracer = getLangWatchTracer("error-otel-test");
16
-
17
- // Test that exceptions in spans are properly handled
18
- await expect(
19
- tracer.withActiveSpan("error span", async () => {
20
- throw new Error("Test error");
21
- })
22
- ).rejects.toThrow("Test error");
23
- });
24
- });
@@ -1,24 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { registerOTel } from '@vercel/otel';
3
- import { setupLangWatch } from "../../../client-node";
4
- import { getLangWatchTracer } from "../../trace";
5
-
6
- describe("LangWatch with skipOpenTelemetrySetup=true", () => {
7
- it("should work when LangWatch is set up with skipOpenTelemetrySetup=true", async () => {
8
- // Setup Vercel AI first
9
- registerOTel({ serviceName: 'vercel-first' });
10
-
11
- // Then setup LangWatch with automatic setup disabled
12
- await setupLangWatch({
13
- apiKey: "test-key",
14
- endpoint: "http://localhost:9999",
15
- skipOpenTelemetrySetup: true,
16
- });
17
-
18
- // Test that LangWatch still works
19
- const tracer = getLangWatchTracer("disabled-otel-test");
20
- await tracer.withActiveSpan("test span", async () => {
21
- expect(true).toBe(true);
22
- });
23
- });
24
- });
@@ -1,24 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { registerOTel } from '@vercel/otel';
3
- import { setupLangWatch } from "../../../client-node";
4
- import { getLangWatchTracer } from "../../trace";
5
-
6
- describe("LangWatch setup first, then Vercel AI", () => {
7
- it("should work when LangWatch is set up first, then Vercel AI", async () => {
8
- // Setup LangWatch first
9
- await setupLangWatch({
10
- apiKey: "test-key",
11
- endpoint: "http://localhost:9999",
12
- skipOpenTelemetrySetup: false,
13
- });
14
-
15
- // Then setup Vercel AI
16
- registerOTel({ serviceName: 'langwatch-first' });
17
-
18
- // Test that LangWatch still works
19
- const tracer = getLangWatchTracer("langwatch-first-test");
20
- await tracer.withActiveSpan("test span", async () => {
21
- expect(true).toBe(true);
22
- });
23
- });
24
- });