@turingpulse/sdk 1.0.1
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.
- package/.github/dependabot.yml +38 -0
- package/.github/workflows/ci.yml +246 -0
- package/.github/workflows/framework-compat.yml +169 -0
- package/.github/workflows/security.yml +336 -0
- package/CHANGELOG.md +29 -0
- package/LICENSE +13 -0
- package/MIGRATION.md +30 -0
- package/README.md +221 -0
- package/dist/attachments.d.ts +28 -0
- package/dist/attachments.d.ts.map +1 -0
- package/dist/attachments.js +59 -0
- package/dist/attachments.js.map +1 -0
- package/dist/config.d.ts +72 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +78 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +126 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +163 -0
- package/dist/context.js.map +1 -0
- package/dist/decorators.d.ts +6 -0
- package/dist/decorators.d.ts.map +1 -0
- package/dist/decorators.js +52 -0
- package/dist/decorators.js.map +1 -0
- package/dist/deploy.d.ts +89 -0
- package/dist/deploy.d.ts.map +1 -0
- package/dist/deploy.js +203 -0
- package/dist/deploy.js.map +1 -0
- package/dist/errors.d.ts +18 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +34 -0
- package/dist/errors.js.map +1 -0
- package/dist/eventBuilder.d.ts +21 -0
- package/dist/eventBuilder.d.ts.map +1 -0
- package/dist/eventBuilder.js +127 -0
- package/dist/eventBuilder.js.map +1 -0
- package/dist/fingerprint.d.ts +158 -0
- package/dist/fingerprint.d.ts.map +1 -0
- package/dist/fingerprint.js +339 -0
- package/dist/fingerprint.js.map +1 -0
- package/dist/governance.d.ts +47 -0
- package/dist/governance.d.ts.map +1 -0
- package/dist/governance.js +104 -0
- package/dist/governance.js.map +1 -0
- package/dist/http.d.ts +62 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +181 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/instrumentation.d.ts +40 -0
- package/dist/instrumentation.d.ts.map +1 -0
- package/dist/instrumentation.js +31 -0
- package/dist/instrumentation.js.map +1 -0
- package/dist/integrations/mastra.d.ts +64 -0
- package/dist/integrations/mastra.d.ts.map +1 -0
- package/dist/integrations/mastra.js +256 -0
- package/dist/integrations/mastra.js.map +1 -0
- package/dist/kpi.d.ts +21 -0
- package/dist/kpi.d.ts.map +1 -0
- package/dist/kpi.js +83 -0
- package/dist/kpi.js.map +1 -0
- package/dist/llmDetector.d.ts +22 -0
- package/dist/llmDetector.d.ts.map +1 -0
- package/dist/llmDetector.js +269 -0
- package/dist/llmDetector.js.map +1 -0
- package/dist/plugin.d.ts +33 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +312 -0
- package/dist/plugin.js.map +1 -0
- package/dist/registry.d.ts +13 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +18 -0
- package/dist/registry.js.map +1 -0
- package/dist/tracing.d.ts +10 -0
- package/dist/tracing.d.ts.map +1 -0
- package/dist/tracing.js +30 -0
- package/dist/tracing.js.map +1 -0
- package/dist/triggerState.d.ts +5 -0
- package/dist/triggerState.d.ts.map +1 -0
- package/dist/triggerState.js +19 -0
- package/dist/triggerState.js.map +1 -0
- package/dist/utils.d.ts +27 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +72 -0
- package/dist/utils.js.map +1 -0
- package/package.json +37 -0
- package/packages/anthropic/package.json +16 -0
- package/packages/anthropic/src/index.ts +5 -0
- package/packages/anthropic/src/wrapper.ts +102 -0
- package/packages/anthropic/tsconfig.build.json +20 -0
- package/packages/langchain/package.json +16 -0
- package/packages/langchain/src/index.ts +7 -0
- package/packages/langchain/src/wrapper.ts +51 -0
- package/packages/mastra/package.json +17 -0
- package/packages/mastra/src/index.ts +8 -0
- package/packages/mastra/src/wrapper.ts +301 -0
- package/packages/openai/package.json +16 -0
- package/packages/openai/src/index.ts +8 -0
- package/packages/openai/src/wrapper.ts +103 -0
- package/packages/openai/tsconfig.build.json +20 -0
- package/packages/openclaw/openclaw.plugin.json +100 -0
- package/packages/openclaw/package.json +41 -0
- package/packages/openclaw/src/buffer.ts +99 -0
- package/packages/openclaw/src/config.ts +139 -0
- package/packages/openclaw/src/hooks/governance.ts +267 -0
- package/packages/openclaw/src/hooks/lifecycle.ts +75 -0
- package/packages/openclaw/src/hooks/telemetry.ts +207 -0
- package/packages/openclaw/src/index.ts +91 -0
- package/packages/openclaw/src/mapper.ts +233 -0
- package/packages/openclaw/src/session-tracker.ts +181 -0
- package/packages/openclaw/src/types.ts +220 -0
- package/packages/openclaw/tests/buffer.test.ts +148 -0
- package/packages/openclaw/tests/config.test.ts +122 -0
- package/packages/openclaw/tests/governance.test.ts +232 -0
- package/packages/openclaw/tests/mapper.test.ts +242 -0
- package/packages/openclaw/tests/session-tracker.test.ts +124 -0
- package/packages/openclaw/tsconfig.json +18 -0
- package/packages/openclaw/vitest.config.ts +8 -0
- package/packages/vercel-ai/package.json +16 -0
- package/packages/vercel-ai/src/index.ts +5 -0
- package/packages/vercel-ai/src/wrapper.ts +49 -0
- package/scripts/bump-version.sh +58 -0
- package/scripts/update-readme-compat.mjs +151 -0
- package/src/__tests__/fingerprint.test.ts +328 -0
- package/src/attachments.ts +88 -0
- package/src/config.ts +164 -0
- package/src/context.ts +258 -0
- package/src/decorators.ts +61 -0
- package/src/deploy.ts +260 -0
- package/src/errors.ts +44 -0
- package/src/eventBuilder.ts +153 -0
- package/src/fingerprint.ts +421 -0
- package/src/governance.ts +156 -0
- package/src/http.ts +241 -0
- package/src/index.ts +57 -0
- package/src/instrumentation.ts +68 -0
- package/src/integrations/mastra.ts +335 -0
- package/src/kpi.ts +112 -0
- package/src/llmDetector.ts +330 -0
- package/src/plugin.ts +384 -0
- package/src/registry.ts +27 -0
- package/src/tracing.ts +39 -0
- package/src/triggerState.ts +27 -0
- package/src/utils.ts +78 -0
- package/tests/compat/anthropic.test.ts +61 -0
- package/tests/compat/cohere.test.ts +57 -0
- package/tests/compat/google-genai.test.ts +61 -0
- package/tests/compat/langchain-openai.test.ts +41 -0
- package/tests/compat/langchain.test.ts +64 -0
- package/tests/compat/mistral.test.ts +58 -0
- package/tests/compat/openai.test.ts +71 -0
- package/tests/compat/vercel-ai.test.ts +56 -0
- package/tests/plugins/anthropic-wrapper.test.ts +120 -0
- package/tests/plugins/langchain-wrapper.test.ts +128 -0
- package/tests/plugins/openai-wrapper.test.ts +165 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +9 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests for @turingpulse/sdk-openai plugin.
|
|
3
|
+
*
|
|
4
|
+
* These tests verify that patchOpenAI actually monkey-patches the caller's
|
|
5
|
+
* OpenAI module, instruments LLM calls, and emits events with all required
|
|
6
|
+
* metadata fields (node_type, model, provider, tokens, I/O).
|
|
7
|
+
*/
|
|
8
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
9
|
+
import { init } from '@turingpulse/sdk';
|
|
10
|
+
import { patchOpenAI, unpatchOpenAI } from '../../packages/openai/src/wrapper.js';
|
|
11
|
+
|
|
12
|
+
const MOCK_RESPONSE = {
|
|
13
|
+
id: 'chatcmpl-test',
|
|
14
|
+
object: 'chat.completion',
|
|
15
|
+
model: 'gpt-4o',
|
|
16
|
+
choices: [
|
|
17
|
+
{ index: 0, message: { role: 'assistant', content: 'instrumented reply' }, finish_reason: 'stop' },
|
|
18
|
+
],
|
|
19
|
+
usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 },
|
|
20
|
+
created: Math.floor(Date.now() / 1000),
|
|
21
|
+
system_fingerprint: 'fp_test',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
let capturedEvents: Record<string, unknown>[] = [];
|
|
25
|
+
let originalFetch: typeof globalThis.fetch;
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
capturedEvents = [];
|
|
29
|
+
originalFetch = globalThis.fetch;
|
|
30
|
+
|
|
31
|
+
globalThis.fetch = async (input: RequestInfo | URL, initOpts?: RequestInit): Promise<Response> => {
|
|
32
|
+
const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : (input as Request).url;
|
|
33
|
+
|
|
34
|
+
if (url.includes('api.openai.com')) {
|
|
35
|
+
return new Response(JSON.stringify(MOCK_RESPONSE), {
|
|
36
|
+
status: 200,
|
|
37
|
+
headers: { 'Content-Type': 'application/json' },
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (url.includes('/api/v1/sdk/events') && initOpts?.body) {
|
|
42
|
+
try {
|
|
43
|
+
const parsed = JSON.parse(initOpts.body as string);
|
|
44
|
+
const events = parsed.events ?? [parsed];
|
|
45
|
+
capturedEvents.push(...events);
|
|
46
|
+
} catch { /* ignore */ }
|
|
47
|
+
return new Response(JSON.stringify({ success: true }), {
|
|
48
|
+
status: 200,
|
|
49
|
+
headers: { 'Content-Type': 'application/json' },
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return new Response('{}', { status: 200 });
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
init({
|
|
57
|
+
apiKey: 'test-key',
|
|
58
|
+
workflowName: 'test-openai-plugin',
|
|
59
|
+
endpoint: 'https://test-endpoint.turingpulse.ai',
|
|
60
|
+
fetchImpl: globalThis.fetch,
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
afterEach(async () => {
|
|
65
|
+
await unpatchOpenAI();
|
|
66
|
+
globalThis.fetch = originalFetch;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
describe('patchOpenAI plugin wrapper', () => {
|
|
70
|
+
it('patches the caller-supplied OpenAI module prototype', async () => {
|
|
71
|
+
const openaiMod = await import('openai');
|
|
72
|
+
const proto = openaiMod.default.Chat.Completions.prototype;
|
|
73
|
+
const originalName = proto.create.name;
|
|
74
|
+
|
|
75
|
+
await patchOpenAI({ name: 'test-workflow', openaiModule: openaiMod });
|
|
76
|
+
|
|
77
|
+
expect(proto.create.name).toBe('instrumented');
|
|
78
|
+
expect(proto.create.name).not.toBe(originalName);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('restores prototype on unpatch', async () => {
|
|
82
|
+
const openaiMod = await import('openai');
|
|
83
|
+
const proto = openaiMod.default.Chat.Completions.prototype;
|
|
84
|
+
const originalCreate = proto.create;
|
|
85
|
+
|
|
86
|
+
await patchOpenAI({ name: 'test-workflow', openaiModule: openaiMod });
|
|
87
|
+
expect(proto.create).not.toBe(originalCreate);
|
|
88
|
+
|
|
89
|
+
await unpatchOpenAI();
|
|
90
|
+
expect(proto.create).toBe(originalCreate);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('emits event with correct node_type, model, provider, tokens, and I/O', async () => {
|
|
94
|
+
const openaiMod = await import('openai');
|
|
95
|
+
await patchOpenAI({ name: 'test-workflow', openaiModule: openaiMod });
|
|
96
|
+
|
|
97
|
+
const client = new openaiMod.default({ apiKey: 'mock-key' });
|
|
98
|
+
await client.chat.completions.create({
|
|
99
|
+
model: 'gpt-4o',
|
|
100
|
+
messages: [{ role: 'user', content: 'hello from test' }],
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
104
|
+
|
|
105
|
+
expect(capturedEvents.length).toBeGreaterThanOrEqual(1);
|
|
106
|
+
|
|
107
|
+
const event = capturedEvents[0] as Record<string, unknown>;
|
|
108
|
+
const payload = event.payload as Record<string, unknown>;
|
|
109
|
+
const metadata = payload.metadata as Record<string, string>;
|
|
110
|
+
|
|
111
|
+
expect(metadata.node_type).toBe('llm');
|
|
112
|
+
expect(metadata.model).toBe('gpt-4o');
|
|
113
|
+
expect(metadata.provider).toBe('openai');
|
|
114
|
+
expect(metadata.framework).toBe('openai');
|
|
115
|
+
expect(metadata.input).toBeDefined();
|
|
116
|
+
expect(metadata.output).toBeDefined();
|
|
117
|
+
|
|
118
|
+
const tokens = payload.tokens as { prompt: number; completion: number };
|
|
119
|
+
expect(tokens.prompt).toBe(10);
|
|
120
|
+
expect(tokens.completion).toBe(5);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('sets workflow_name in metadata', async () => {
|
|
124
|
+
const openaiMod = await import('openai');
|
|
125
|
+
await patchOpenAI({ name: 'my-agent-workflow', openaiModule: openaiMod });
|
|
126
|
+
|
|
127
|
+
const client = new openaiMod.default({ apiKey: 'mock-key' });
|
|
128
|
+
await client.chat.completions.create({
|
|
129
|
+
model: 'gpt-4o',
|
|
130
|
+
messages: [{ role: 'user', content: 'workflow test' }],
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
134
|
+
|
|
135
|
+
const event = capturedEvents[0] as Record<string, unknown>;
|
|
136
|
+
const payload = event.payload as Record<string, unknown>;
|
|
137
|
+
const metadata = payload.metadata as Record<string, string>;
|
|
138
|
+
|
|
139
|
+
expect(metadata.workflow_name).toBe('my-agent-workflow');
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('without openaiModule falls back to dynamic import (same-module scenario)', async () => {
|
|
143
|
+
await patchOpenAI({ name: 'fallback-test' });
|
|
144
|
+
|
|
145
|
+
const openaiMod = await import('openai');
|
|
146
|
+
const client = new openaiMod.default({ apiKey: 'mock-key' });
|
|
147
|
+
await client.chat.completions.create({
|
|
148
|
+
model: 'gpt-4o',
|
|
149
|
+
messages: [{ role: 'user', content: 'fallback' }],
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
153
|
+
await unpatchOpenAI();
|
|
154
|
+
|
|
155
|
+
if (capturedEvents.length > 0) {
|
|
156
|
+
const metadata = ((capturedEvents[0] as Record<string, unknown>).payload as Record<string, unknown>)
|
|
157
|
+
.metadata as Record<string, string>;
|
|
158
|
+
expect(metadata.framework).toBe('openai');
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('throws when name is missing', async () => {
|
|
163
|
+
await expect(patchOpenAI({})).rejects.toThrow(/name or TP_WORKFLOW_NAME/);
|
|
164
|
+
});
|
|
165
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "Bundler",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"declarationMap": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"outDir": "dist",
|
|
13
|
+
"rootDir": "src",
|
|
14
|
+
"sourceMap": true,
|
|
15
|
+
"resolveJsonModule": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src"],
|
|
18
|
+
"exclude": ["src/__tests__"]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|