@intelli-1113/stratos-sdk 1.2.3 → 1.3.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.
- package/README.md +552 -64
- package/package.json +49 -22
- package/src/cli-inspect.js +95 -0
- package/src/enforcement.js +163 -0
- package/src/index.js +139 -43
- package/src/inspect-langchain.js +428 -0
- package/src/mcp-proxy.js +42 -2
- package/src/postinstall.js +29 -0
- package/src/register.js +57 -5
- package/src/vercel-ai-inject.js +78 -0
- package/src/vercel-ai-loader.js +111 -0
- package/src/vercel-ai.js +62 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// Node custom module loader: rewrite bare specifier `ai` → Stratos shim
|
|
2
|
+
// that re-exports the real package with telemetry injected on generate*/stream*/embed*.
|
|
3
|
+
//
|
|
4
|
+
// Registered from register.js BEFORE start(), so client code needs no changes:
|
|
5
|
+
// import "@intelli-1113/stratos-sdk/register";
|
|
6
|
+
// import { generateText } from "ai"; // ← gets wrapped exports
|
|
7
|
+
|
|
8
|
+
import { createRequire } from "node:module";
|
|
9
|
+
import { pathToFileURL } from "node:url";
|
|
10
|
+
import { dirname, join } from "node:path";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
12
|
+
import { TELEMETRY_CALL_NAMES } from "./vercel-ai-inject.js";
|
|
13
|
+
|
|
14
|
+
const SHIM_URL = "stratos-sdk:ai";
|
|
15
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
const INJECT_URL = pathToFileURL(join(__dirname, "vercel-ai-inject.js")).href;
|
|
17
|
+
// The network guard (enforcement.js, installed from register.js) already
|
|
18
|
+
// refuses these calls at the fetch layer once blocked — Vercel AI's own client
|
|
19
|
+
// uses fetch internally, same as everyone else. This second check is
|
|
20
|
+
// redundant with that but deliberately kept: it fails before Vercel AI builds
|
|
21
|
+
// its request/retry/streaming machinery, and the error reads as ours rather
|
|
22
|
+
// than as a generic fetch failure surfaced through their error wrapper.
|
|
23
|
+
const ENFORCEMENT_URL = pathToFileURL(join(__dirname, "enforcement.js")).href;
|
|
24
|
+
|
|
25
|
+
function flagEnabled(name, defaultOn = true) {
|
|
26
|
+
const v = process.env[name];
|
|
27
|
+
if (v == null || v === "") return defaultOn;
|
|
28
|
+
return !["0", "false", "off", "no"].includes(String(v).toLowerCase());
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function resolve(specifier, context, nextResolve) {
|
|
32
|
+
if (!flagEnabled("STRATOS_VERCEL_AI", true)) {
|
|
33
|
+
return nextResolve(specifier, context);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Only rewrite the bare package name. Absolute/file imports of real `ai` pass through
|
|
37
|
+
// (used by this shim to load the original module without recursion).
|
|
38
|
+
if (specifier === "ai") {
|
|
39
|
+
return {
|
|
40
|
+
shortCircuit: true,
|
|
41
|
+
url: SHIM_URL,
|
|
42
|
+
format: "module",
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return nextResolve(specifier, context);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function load(url, context, nextLoad) {
|
|
49
|
+
if (url !== SHIM_URL) {
|
|
50
|
+
return nextLoad(url, context);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const req = createRequire(join(process.cwd(), "package.json"));
|
|
54
|
+
let realPath;
|
|
55
|
+
try {
|
|
56
|
+
realPath = req.resolve("ai");
|
|
57
|
+
} catch (err) {
|
|
58
|
+
// Consumer doesn't have `ai` — fall through to a clear error on use
|
|
59
|
+
return {
|
|
60
|
+
format: "module",
|
|
61
|
+
shortCircuit: true,
|
|
62
|
+
source: `throw new Error("[stratos] package \\"ai\\" (Vercel AI SDK) is not installed in this project");\n`,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const realUrl = pathToFileURL(realPath).href;
|
|
67
|
+
// Load real module via absolute URL (does not match specifier === "ai")
|
|
68
|
+
const real = await import(realUrl);
|
|
69
|
+
const wrapSet = new Set(TELEMETRY_CALL_NAMES);
|
|
70
|
+
const keys = Object.keys(real).filter(
|
|
71
|
+
(k) => k !== "default" && k !== "__esModule" && /^[A-Za-z_$][\w$]*$/.test(k)
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
let source = "";
|
|
75
|
+
source += `import * as __real from ${JSON.stringify(realUrl)};\n`;
|
|
76
|
+
source += `import { injectTelemetryOptions } from ${JSON.stringify(INJECT_URL)};\n`;
|
|
77
|
+
source += `import { isBlocked } from ${JSON.stringify(ENFORCEMENT_URL)};\n`;
|
|
78
|
+
source += `
|
|
79
|
+
function __stratosWrap(fn) {
|
|
80
|
+
if (typeof fn !== "function" || fn.__stratosWrapped) return fn;
|
|
81
|
+
const wrapped = function stratosVercelAiWrap(opts, ...rest) {
|
|
82
|
+
const __b = isBlocked();
|
|
83
|
+
if (__b.blocked) {
|
|
84
|
+
throw new Error("[stratos] request blocked: " + (__b.reason || "budget or lifecycle limit reached"));
|
|
85
|
+
}
|
|
86
|
+
return fn.call(this, injectTelemetryOptions(opts), ...rest);
|
|
87
|
+
};
|
|
88
|
+
wrapped.__stratosWrapped = true;
|
|
89
|
+
try { Object.defineProperty(wrapped, "name", { value: fn.name || "stratosVercelAiWrap" }); } catch {}
|
|
90
|
+
return wrapped;
|
|
91
|
+
}
|
|
92
|
+
`;
|
|
93
|
+
|
|
94
|
+
for (const k of keys) {
|
|
95
|
+
if (wrapSet.has(k)) {
|
|
96
|
+
source += `export const ${k} = __stratosWrap(__real[${JSON.stringify(k)}]);\n`;
|
|
97
|
+
} else {
|
|
98
|
+
source += `export const ${k} = __real[${JSON.stringify(k)}];\n`;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (Object.prototype.hasOwnProperty.call(real, "default")) {
|
|
103
|
+
source += `export default __real.default;\n`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
format: "module",
|
|
108
|
+
shortCircuit: true,
|
|
109
|
+
source,
|
|
110
|
+
};
|
|
111
|
+
}
|
package/src/vercel-ai.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Vercel AI auto-telemetry orchestration for Stratos.
|
|
2
|
+
// Hooks are registered from register.js (custom ESM loader) before app code runs.
|
|
3
|
+
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { injectTelemetryOptions, TELEMETRY_CALL_NAMES } from "./vercel-ai-inject.js";
|
|
8
|
+
|
|
9
|
+
export { injectTelemetryOptions, TELEMETRY_CALL_NAMES };
|
|
10
|
+
|
|
11
|
+
function resolveFromCwd(pkg) {
|
|
12
|
+
try {
|
|
13
|
+
return createRequire(join(process.cwd(), "package.json")).resolve(pkg);
|
|
14
|
+
} catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function flagEnabled(name, defaultOn = true) {
|
|
20
|
+
const v = process.env[name];
|
|
21
|
+
if (v == null || v === "") return defaultOn;
|
|
22
|
+
return !["0", "false", "off", "no"].includes(String(v).toLowerCase());
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Optional AI SDK v7 global registerTelemetry when @ai-sdk/otel is present.
|
|
27
|
+
* Safe no-op on v5/v6.
|
|
28
|
+
*/
|
|
29
|
+
export async function enableVercelAiTelemetry() {
|
|
30
|
+
if (!flagEnabled("STRATOS_VERCEL_AI", true)) {
|
|
31
|
+
return { enabled: false, mode: "disabled" };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const aiPath = resolveFromCwd("ai");
|
|
35
|
+
if (!aiPath) return { enabled: false, mode: null };
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
// Via our shim if loader is active, or direct file URL
|
|
39
|
+
const ai = await import(pathToFileURL(aiPath).href);
|
|
40
|
+
|
|
41
|
+
if (typeof ai.registerTelemetry === "function") {
|
|
42
|
+
const otelPath = resolveFromCwd("@ai-sdk/otel");
|
|
43
|
+
if (otelPath) {
|
|
44
|
+
try {
|
|
45
|
+
const otel = await import(pathToFileURL(otelPath).href);
|
|
46
|
+
const OpenTelemetry = otel.OpenTelemetry || otel.LegacyOpenTelemetry;
|
|
47
|
+
if (typeof OpenTelemetry === "function") {
|
|
48
|
+
ai.registerTelemetry(new OpenTelemetry());
|
|
49
|
+
return { enabled: true, mode: "registerTelemetry" };
|
|
50
|
+
}
|
|
51
|
+
} catch {
|
|
52
|
+
/* fall through */
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ESM loader path is the primary mechanism (stratos-sdk:ai shim)
|
|
58
|
+
return { enabled: true, mode: "esm-loader-shim" };
|
|
59
|
+
} catch {
|
|
60
|
+
return { enabled: true, mode: "esm-loader-shim" };
|
|
61
|
+
}
|
|
62
|
+
}
|