promptmetrics-sample 1.0.0

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 (55) hide show
  1. package/.env.example +12 -0
  2. package/README.md +235 -0
  3. package/dist/index.d.ts +7 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +29 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/tests/logs.test.d.ts +7 -0
  8. package/dist/tests/logs.test.d.ts.map +1 -0
  9. package/dist/tests/logs.test.js +163 -0
  10. package/dist/tests/logs.test.js.map +1 -0
  11. package/dist/tests/providers.test.d.ts +7 -0
  12. package/dist/tests/providers.test.d.ts.map +1 -0
  13. package/dist/tests/providers.test.js +99 -0
  14. package/dist/tests/providers.test.js.map +1 -0
  15. package/dist/tests/tags.test.d.ts +7 -0
  16. package/dist/tests/tags.test.d.ts.map +1 -0
  17. package/dist/tests/tags.test.js +220 -0
  18. package/dist/tests/tags.test.js.map +1 -0
  19. package/dist/tests/template-run-load.test.d.ts +11 -0
  20. package/dist/tests/template-run-load.test.d.ts.map +1 -0
  21. package/dist/tests/template-run-load.test.js +245 -0
  22. package/dist/tests/template-run-load.test.js.map +1 -0
  23. package/dist/tests/templates.test.d.ts +7 -0
  24. package/dist/tests/templates.test.d.ts.map +1 -0
  25. package/dist/tests/templates.test.js +152 -0
  26. package/dist/tests/templates.test.js.map +1 -0
  27. package/dist/tests/traceable.test.d.ts +7 -0
  28. package/dist/tests/traceable.test.d.ts.map +1 -0
  29. package/dist/tests/traceable.test.js +300 -0
  30. package/dist/tests/traceable.test.js.map +1 -0
  31. package/dist/tests/traces.test.d.ts +7 -0
  32. package/dist/tests/traces.test.d.ts.map +1 -0
  33. package/dist/tests/traces.test.js +264 -0
  34. package/dist/tests/traces.test.js.map +1 -0
  35. package/dist/tests/versions.test.d.ts +7 -0
  36. package/dist/tests/versions.test.d.ts.map +1 -0
  37. package/dist/tests/versions.test.js +145 -0
  38. package/dist/tests/versions.test.js.map +1 -0
  39. package/dist/utils/logger.d.ts +26 -0
  40. package/dist/utils/logger.d.ts.map +1 -0
  41. package/dist/utils/logger.js +79 -0
  42. package/dist/utils/logger.js.map +1 -0
  43. package/package.json +36 -0
  44. package/sample-project-plan.md +316 -0
  45. package/src/index.ts +36 -0
  46. package/src/tests/logs.test.ts +180 -0
  47. package/src/tests/providers.test.ts +99 -0
  48. package/src/tests/tags.test.ts +237 -0
  49. package/src/tests/template-run-load.test.ts +332 -0
  50. package/src/tests/templates.test.ts +154 -0
  51. package/src/tests/traceable.test.ts +290 -0
  52. package/src/tests/traces.test.ts +298 -0
  53. package/src/tests/versions.test.ts +155 -0
  54. package/src/utils/logger.ts +91 -0
  55. package/tsconfig.json +21 -0
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/env ts-node
2
+ /**
3
+ * Logs Test Suite
4
+ * Tests all log-related SDK operations
5
+ */
6
+
7
+ import "dotenv/config";
8
+ import { PromptMetrics } from "@promptmetrics/sdk";
9
+ import { runTestSuite, logger } from "../utils/logger";
10
+
11
+ const pm = new PromptMetrics({
12
+ apiKey: process.env.PROMPTMETRICS_API_KEY!,
13
+ });
14
+
15
+ const TEST_TEMPLATE_ID = process.env.TEST_TEMPLATE_ID;
16
+ const TEST_VERSION_ID = process.env.TEST_VERSION_ID;
17
+
18
+ // Store log ID from first test for subsequent tests
19
+ let fetchedLogId: string | null = null;
20
+
21
+ const tests = [
22
+ {
23
+ name: "List logs with pagination",
24
+ fn: async () => {
25
+ const result = await pm.logs.list({
26
+ page: 1,
27
+ limit: 10,
28
+ sort_by: "created_at",
29
+ sort_order: "desc",
30
+ });
31
+
32
+ if (!result) throw new Error("Failed to list logs");
33
+ logger.data("Logs Count", result.length);
34
+
35
+ if (result.length > 0) {
36
+ fetchedLogId = result[0]._id;
37
+ logger.data("First Log ID", result[0]._id);
38
+ logger.data("First Log Status", result[0].status);
39
+ }
40
+ },
41
+ },
42
+
43
+ {
44
+ name: "List logs filtered by template_id",
45
+ fn: async () => {
46
+ if (!TEST_TEMPLATE_ID) {
47
+ logger.info("Skipped - TEST_TEMPLATE_ID not set");
48
+ return;
49
+ }
50
+
51
+ const result = await pm.logs.list({
52
+ template_id: TEST_TEMPLATE_ID,
53
+ page: 1,
54
+ limit: 10,
55
+ });
56
+
57
+ if (!result) throw new Error("Failed to list logs");
58
+ logger.data("Logs for Template", result.length);
59
+ },
60
+ },
61
+
62
+ {
63
+ name: "List logs filtered by version_id",
64
+ fn: async () => {
65
+ if (!TEST_VERSION_ID) {
66
+ logger.info("Skipped - TEST_VERSION_ID not set");
67
+ return;
68
+ }
69
+
70
+ const result = await pm.logs.list({
71
+ template_version_id: TEST_VERSION_ID,
72
+ page: 1,
73
+ limit: 10,
74
+ });
75
+
76
+ if (!result) throw new Error("Failed to list logs");
77
+ logger.data("Logs for Version", result.length);
78
+ },
79
+ },
80
+
81
+ {
82
+ name: "List logs filtered by status (SUCCESS)",
83
+ fn: async () => {
84
+ const result = await pm.logs.list({
85
+ status: "SUCCESS",
86
+ page: 1,
87
+ limit: 10,
88
+ });
89
+
90
+ if (!result) throw new Error("Failed to list logs");
91
+ logger.data("Successful Logs", result.length);
92
+ },
93
+ },
94
+
95
+ {
96
+ name: "List logs filtered by status (ERROR)",
97
+ fn: async () => {
98
+ const result = await pm.logs.list({
99
+ status: "ERROR",
100
+ page: 1,
101
+ limit: 10,
102
+ });
103
+
104
+ if (!result) throw new Error("Failed to list logs");
105
+ logger.data("Error Logs", result.length);
106
+ },
107
+ },
108
+
109
+ {
110
+ name: "List logs filtered by source (SDK)",
111
+ fn: async () => {
112
+ const result = await pm.logs.list({
113
+ source: "sdk",
114
+ page: 1,
115
+ limit: 10,
116
+ });
117
+
118
+ if (!result) throw new Error("Failed to list logs");
119
+ logger.data("SDK Logs", result.length);
120
+ },
121
+ },
122
+
123
+ {
124
+ name: "Get log by ID",
125
+ fn: async () => {
126
+ if (!fetchedLogId) {
127
+ logger.info("Skipped - No log ID available from previous test");
128
+ return;
129
+ }
130
+
131
+ const log = await pm.logs.get(fetchedLogId);
132
+ if (!log) throw new Error("Log not found");
133
+
134
+ logger.data("Log ID", log._id);
135
+ logger.data("Request ID", log.request_id);
136
+ logger.data("Status", log.status);
137
+ logger.data("Latency", `${log.latency}s`);
138
+ logger.data("Total Cost", `$${log.total_cost}`);
139
+ logger.data("Tags", log.tags || "No tags");
140
+ },
141
+ },
142
+
143
+ {
144
+ name: "Verify log has tags (from pm_tags)",
145
+ fn: async () => {
146
+ // Run a version with tags first
147
+ const versionId = TEST_VERSION_ID;
148
+ if (!versionId) {
149
+ logger.info("Skipped - TEST_VERSION_ID not set");
150
+ return;
151
+ }
152
+
153
+ const runResult = await pm.versions.run(versionId, {
154
+ variables: { topic: "Tag Verification" },
155
+ pm_tags: ["verify-test", "log-check"],
156
+ });
157
+
158
+ // Get the log and verify tags
159
+ const logs = await pm.logs.list({
160
+ template_version_id: versionId,
161
+ limit: 1,
162
+ sort_by: "created_at",
163
+ sort_order: "desc",
164
+ });
165
+
166
+ if (logs.length > 0) {
167
+ const latestLog = logs[0];
168
+ logger.data("Log Tags", latestLog.tags);
169
+
170
+ if (latestLog.tags && latestLog.tags.includes("verify-test")) {
171
+ logger.success("Tags verified in log!");
172
+ } else {
173
+ logger.info("Tags may be stored but not returned in list");
174
+ }
175
+ }
176
+ },
177
+ },
178
+ ];
179
+
180
+ runTestSuite("Logs Test Suite", tests);
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env ts-node
2
+ /**
3
+ * Providers Test Suite
4
+ * Tests all provider-related SDK operations
5
+ */
6
+
7
+ import "dotenv/config";
8
+ import { PromptMetrics } from "@promptmetrics/sdk";
9
+ import { runTestSuite, logger } from "../utils/logger";
10
+
11
+ const pm = new PromptMetrics({
12
+ apiKey: process.env.PROMPTMETRICS_API_KEY!,
13
+ });
14
+
15
+ const tests = [
16
+ {
17
+ name: "List all LLM providers",
18
+ fn: async () => {
19
+ const providers = await pm.providers.list();
20
+ if (!providers) throw new Error("Failed to list providers");
21
+
22
+ logger.data("Providers Count", providers.length);
23
+
24
+ providers.forEach((provider) => {
25
+ logger.info(`Provider: ${provider.name} (${provider.slug})`);
26
+ logger.data(" Has Key", provider.has_key || false);
27
+ });
28
+ },
29
+ },
30
+
31
+ {
32
+ name: "Get models for OpenAI provider",
33
+ fn: async () => {
34
+ try {
35
+ const provider = await pm.providers.getModels("openai");
36
+ if (!provider) throw new Error("Provider not found");
37
+
38
+ logger.data("Provider Name", provider.name);
39
+ logger.data("Models Count", provider.models?.length || 0);
40
+
41
+ if (provider.models && provider.models.length > 0) {
42
+ logger.info("Sample models:");
43
+ provider.models.slice(0, 5).forEach((model) => {
44
+ logger.info(` - ${model.name}`);
45
+ });
46
+ }
47
+ } catch (error: unknown) {
48
+ const err = error as { message?: string };
49
+ if (err.message?.includes("not found")) {
50
+ logger.info("OpenAI provider not configured - this is OK");
51
+ } else {
52
+ throw error;
53
+ }
54
+ }
55
+ },
56
+ },
57
+
58
+ {
59
+ name: "Get models for Anthropic/Claude provider",
60
+ fn: async () => {
61
+ try {
62
+ const provider = await pm.providers.getModels("anthropic");
63
+ if (!provider) throw new Error("Provider not found");
64
+
65
+ logger.data("Provider Name", provider.name);
66
+ logger.data("Models Count", provider.models?.length || 0);
67
+ } catch (error: unknown) {
68
+ const err = error as { message?: string };
69
+ if (err.message?.includes("not found")) {
70
+ logger.info("Anthropic provider not configured - this is OK");
71
+ } else {
72
+ throw error;
73
+ }
74
+ }
75
+ },
76
+ },
77
+
78
+ {
79
+ name: "Get models for OpenRouter provider",
80
+ fn: async () => {
81
+ try {
82
+ const provider = await pm.providers.getModels("openrouter");
83
+ if (!provider) throw new Error("Provider not found");
84
+
85
+ logger.data("Provider Name", provider.name);
86
+ logger.data("Models Count", provider.models?.length || 0);
87
+ } catch (error: unknown) {
88
+ const err = error as { message?: string };
89
+ if (err.message?.includes("not found")) {
90
+ logger.info("OpenRouter provider not configured - this is OK");
91
+ } else {
92
+ throw error;
93
+ }
94
+ }
95
+ },
96
+ },
97
+ ];
98
+
99
+ runTestSuite("Providers Test Suite", tests);
@@ -0,0 +1,237 @@
1
+ #!/usr/bin/env ts-node
2
+ /**
3
+ * Tags Test Suite
4
+ * Tests the pm_tags feature for prompt logs
5
+ */
6
+
7
+ import "dotenv/config";
8
+ import { PromptMetrics } from "@promptmetrics/sdk";
9
+ import { runTestSuite, logger } from "../utils/logger";
10
+
11
+ const pm = new PromptMetrics({
12
+ apiKey: process.env.PROMPTMETRICS_API_KEY!,
13
+ });
14
+
15
+ const TEST_VERSION_ID = process.env.TEST_VERSION_ID;
16
+
17
+ const tests = [
18
+ {
19
+ name: "Run version with pm_tags array",
20
+ fn: async () => {
21
+ if (!TEST_VERSION_ID) {
22
+ logger.info("Skipped - TEST_VERSION_ID not set");
23
+ return;
24
+ }
25
+
26
+ const tags = ["sdk-test", "automated", "tag-feature-test"];
27
+
28
+ const result = await pm.versions.run(TEST_VERSION_ID, {
29
+ variables: {
30
+ topic: "Tags Feature Test",
31
+ },
32
+ pm_tags: tags,
33
+ });
34
+
35
+ if (!result) throw new Error("Run failed");
36
+
37
+ logger.data("Request ID", result.request_id);
38
+ logger.data("Status", result.status);
39
+ logger.data("Tags Sent", tags);
40
+ logger.data("Tags in Response", result.tags || "Not returned");
41
+ },
42
+ },
43
+
44
+ {
45
+ name: "Run version with empty pm_tags (should inherit from template)",
46
+ fn: async () => {
47
+ if (!TEST_VERSION_ID) {
48
+ logger.info("Skipped - TEST_VERSION_ID not set");
49
+ return;
50
+ }
51
+
52
+ const result = await pm.versions.run(TEST_VERSION_ID, {
53
+ variables: {
54
+ topic: "No Tags Test",
55
+ },
56
+ // No pm_tags - should inherit from template
57
+ });
58
+
59
+ if (!result) throw new Error("Run failed");
60
+
61
+ logger.data("Request ID", result.request_id);
62
+ logger.data("Status", result.status);
63
+ logger.data("Tags (inherited)", result.tags || "None");
64
+ },
65
+ },
66
+
67
+ {
68
+ name: "Run version with single tag",
69
+ fn: async () => {
70
+ if (!TEST_VERSION_ID) {
71
+ logger.info("Skipped - TEST_VERSION_ID not set");
72
+ return;
73
+ }
74
+
75
+ const result = await pm.versions.run(TEST_VERSION_ID, {
76
+ variables: {
77
+ topic: "Single Tag Test",
78
+ },
79
+ pm_tags: ["single-tag"],
80
+ });
81
+
82
+ if (!result) throw new Error("Run failed");
83
+
84
+ logger.data("Request ID", result.request_id);
85
+ logger.data("Tags", result.tags || "Not returned");
86
+ },
87
+ },
88
+
89
+ {
90
+ name: "Run version with many tags",
91
+ fn: async () => {
92
+ if (!TEST_VERSION_ID) {
93
+ logger.info("Skipped - TEST_VERSION_ID not set");
94
+ return;
95
+ }
96
+
97
+ const manyTags = [
98
+ "tag1",
99
+ "tag2",
100
+ "tag3",
101
+ "tag4",
102
+ "tag5",
103
+ "production",
104
+ "customer-support",
105
+ "high-priority",
106
+ "eu-region",
107
+ "compliance",
108
+ ];
109
+
110
+ const result = await pm.versions.run(TEST_VERSION_ID, {
111
+ variables: {
112
+ topic: "Many Tags Test",
113
+ },
114
+ pm_tags: manyTags,
115
+ });
116
+
117
+ if (!result) throw new Error("Run failed");
118
+
119
+ logger.data("Request ID", result.request_id);
120
+ logger.data("Tags Count", manyTags.length);
121
+ logger.data("Tags in Response", result.tags?.length || 0);
122
+ },
123
+ },
124
+
125
+ {
126
+ name: "Verify tags are stored in prompt log",
127
+ fn: async () => {
128
+ if (!TEST_VERSION_ID) {
129
+ logger.info("Skipped - TEST_VERSION_ID not set");
130
+ return;
131
+ }
132
+
133
+ const uniqueTag = `verify-${Date.now()}`;
134
+
135
+ // Run with unique tag
136
+ const runResult = await pm.versions.run(TEST_VERSION_ID, {
137
+ variables: {
138
+ topic: "Tag Verification",
139
+ },
140
+ pm_tags: [uniqueTag, "verification-test"],
141
+ });
142
+
143
+ logger.data("Run Request ID", runResult.request_id);
144
+
145
+ // Wait a moment for the log to be created
146
+ await new Promise((resolve) => setTimeout(resolve, 500));
147
+
148
+ // Fetch recent logs and check for our tag
149
+ const logs = await pm.logs.list({
150
+ template_version_id: TEST_VERSION_ID,
151
+ limit: 5,
152
+ sort_by: "created_at",
153
+ sort_order: "desc",
154
+ });
155
+
156
+ if (logs.length === 0) {
157
+ logger.info("No logs found to verify");
158
+ return;
159
+ }
160
+
161
+ const latestLog = logs[0];
162
+ logger.data("Latest Log ID", latestLog._id);
163
+ logger.data("Latest Log Tags", latestLog.tags || "None");
164
+
165
+ // Check if our unique tag is in the log
166
+ if (latestLog.tags && latestLog.tags.includes(uniqueTag)) {
167
+ logger.success(`Tag '${uniqueTag}' verified in log!`);
168
+ } else {
169
+ logger.info("Tag may be stored but not returned in list response");
170
+ }
171
+ },
172
+ },
173
+
174
+ {
175
+ name: "Tags with special characters",
176
+ fn: async () => {
177
+ if (!TEST_VERSION_ID) {
178
+ logger.info("Skipped - TEST_VERSION_ID not set");
179
+ return;
180
+ }
181
+
182
+ const specialTags = [
183
+ "tag-with-dash",
184
+ "tag_with_underscore",
185
+ "tag.with.dots",
186
+ "CamelCaseTag",
187
+ "UPPERCASE",
188
+ "lowercase",
189
+ "tag123",
190
+ ];
191
+
192
+ const result = await pm.versions.run(TEST_VERSION_ID, {
193
+ variables: {
194
+ topic: "Special Tags Test",
195
+ },
196
+ pm_tags: specialTags,
197
+ });
198
+
199
+ if (!result) throw new Error("Run failed");
200
+
201
+ logger.data("Request ID", result.request_id);
202
+ logger.data("Special Tags Sent", specialTags.length);
203
+ },
204
+ },
205
+
206
+ {
207
+ name: "Tags inside @traceable function",
208
+ fn: async () => {
209
+ if (!TEST_VERSION_ID) {
210
+ logger.info("Skipped - TEST_VERSION_ID not set");
211
+ return;
212
+ }
213
+
214
+ // Create a traceable function that runs a version with tags
215
+ class TaggedService {
216
+ @pm.traceable({ name: "tagged_llm_call" })
217
+ async runWithTags(topic: string, tags: string[]): Promise<object> {
218
+ return pm.versions.run(TEST_VERSION_ID!, {
219
+ variables: { topic },
220
+ pm_tags: tags,
221
+ });
222
+ }
223
+ }
224
+
225
+ const service = new TaggedService();
226
+ const result = await service.runWithTags("Traceable Tags Test", [
227
+ "traceable-test",
228
+ "nested-tags",
229
+ ]);
230
+
231
+ logger.data("Result Status", (result as { status?: string }).status);
232
+ logger.data("Trace ID", pm.getCurrentTraceId() || "N/A");
233
+ },
234
+ },
235
+ ];
236
+
237
+ runTestSuite("Tags (pm_tags) Test Suite", tests);