ai-model-verifier 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 (95) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +40 -0
  3. package/dist/detectors/response-metadata.d.ts +36 -0
  4. package/dist/detectors/response-metadata.d.ts.map +1 -0
  5. package/dist/detectors/response-metadata.js +91 -0
  6. package/dist/detectors/response-metadata.js.map +1 -0
  7. package/dist/detectors/thinking-signature.d.ts +70 -0
  8. package/dist/detectors/thinking-signature.d.ts.map +1 -0
  9. package/dist/detectors/thinking-signature.js +177 -0
  10. package/dist/detectors/thinking-signature.js.map +1 -0
  11. package/dist/detectors/throughput.d.ts +51 -0
  12. package/dist/detectors/throughput.d.ts.map +1 -0
  13. package/dist/detectors/throughput.js +83 -0
  14. package/dist/detectors/throughput.js.map +1 -0
  15. package/dist/detectors/token-truth.d.ts +40 -0
  16. package/dist/detectors/token-truth.d.ts.map +1 -0
  17. package/dist/detectors/token-truth.js +145 -0
  18. package/dist/detectors/token-truth.js.map +1 -0
  19. package/dist/handshake.d.ts +23 -0
  20. package/dist/handshake.d.ts.map +1 -0
  21. package/dist/handshake.js +90 -0
  22. package/dist/handshake.js.map +1 -0
  23. package/dist/highlight.d.ts +8 -0
  24. package/dist/highlight.d.ts.map +1 -0
  25. package/dist/highlight.js +63 -0
  26. package/dist/highlight.js.map +1 -0
  27. package/dist/index.d.ts +7 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +7 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/internal/utils.d.ts +6 -0
  32. package/dist/internal/utils.d.ts.map +1 -0
  33. package/dist/internal/utils.js +19 -0
  34. package/dist/internal/utils.js.map +1 -0
  35. package/dist/models.d.ts +5 -0
  36. package/dist/models.d.ts.map +1 -0
  37. package/dist/models.js +54 -0
  38. package/dist/models.js.map +1 -0
  39. package/dist/nonce.d.ts +4 -0
  40. package/dist/nonce.d.ts.map +1 -0
  41. package/dist/nonce.js +12 -0
  42. package/dist/nonce.js.map +1 -0
  43. package/dist/patterns.d.ts +16 -0
  44. package/dist/patterns.d.ts.map +1 -0
  45. package/dist/patterns.js +63 -0
  46. package/dist/patterns.js.map +1 -0
  47. package/dist/probes.d.ts +10 -0
  48. package/dist/probes.d.ts.map +1 -0
  49. package/dist/probes.js +54 -0
  50. package/dist/probes.js.map +1 -0
  51. package/dist/providers/anthropic.d.ts +3 -0
  52. package/dist/providers/anthropic.d.ts.map +1 -0
  53. package/dist/providers/anthropic.js +70 -0
  54. package/dist/providers/anthropic.js.map +1 -0
  55. package/dist/providers/config.d.ts +34 -0
  56. package/dist/providers/config.d.ts.map +1 -0
  57. package/dist/providers/config.js +14 -0
  58. package/dist/providers/config.js.map +1 -0
  59. package/dist/providers/gemini.d.ts +3 -0
  60. package/dist/providers/gemini.d.ts.map +1 -0
  61. package/dist/providers/gemini.js +58 -0
  62. package/dist/providers/gemini.js.map +1 -0
  63. package/dist/providers/openai.d.ts +3 -0
  64. package/dist/providers/openai.d.ts.map +1 -0
  65. package/dist/providers/openai.js +56 -0
  66. package/dist/providers/openai.js.map +1 -0
  67. package/dist/rules.d.ts +6 -0
  68. package/dist/rules.d.ts.map +1 -0
  69. package/dist/rules.js +28 -0
  70. package/dist/rules.js.map +1 -0
  71. package/dist/runner.d.ts +22 -0
  72. package/dist/runner.d.ts.map +1 -0
  73. package/dist/runner.js +298 -0
  74. package/dist/runner.js.map +1 -0
  75. package/dist/signals.d.ts +11 -0
  76. package/dist/signals.d.ts.map +1 -0
  77. package/dist/signals.js +64 -0
  78. package/dist/signals.js.map +1 -0
  79. package/dist/substitution.d.ts +24 -0
  80. package/dist/substitution.d.ts.map +1 -0
  81. package/dist/substitution.js +35 -0
  82. package/dist/substitution.js.map +1 -0
  83. package/dist/transport.d.ts +17 -0
  84. package/dist/transport.d.ts.map +1 -0
  85. package/dist/transport.js +79 -0
  86. package/dist/transport.js.map +1 -0
  87. package/dist/types.d.ts +55 -0
  88. package/dist/types.d.ts.map +1 -0
  89. package/dist/types.js +2 -0
  90. package/dist/types.js.map +1 -0
  91. package/dist/verdict.d.ts +26 -0
  92. package/dist/verdict.d.ts.map +1 -0
  93. package/dist/verdict.js +84 -0
  94. package/dist/verdict.js.map +1 -0
  95. package/package.json +56 -0
@@ -0,0 +1,26 @@
1
+ import type { ResponseMetadata } from "./detectors/response-metadata";
2
+ import type { ProviderConfig } from "./providers/config";
3
+ import type { ProbeOutcome, ProbeSignal, VerifyVerdict } from "./types";
4
+ /**
5
+ * A probe's outcome plus the working values the runner needs but never stores:
6
+ * the reply text, and the envelope facts read while the raw payload was still
7
+ * in scope.
8
+ */
9
+ export type ProbeEval = ProbeOutcome & {
10
+ text: string | undefined;
11
+ envelope?: ResponseMetadata;
12
+ };
13
+ export type VerdictResult = {
14
+ verdict: VerifyVerdict;
15
+ reasons: string[];
16
+ versionUnverifiable: boolean;
17
+ };
18
+ export declare function aggregateVerdict(args: {
19
+ model: string;
20
+ cfg: ProviderConfig;
21
+ results: ProbeEval[];
22
+ /** Model id echoed by the endpoint, when it reported one. */
23
+ detectedModel?: string | null;
24
+ }): VerdictResult;
25
+ export declare function probeReason(pass: boolean, signal: ProbeSignal, muxFailure: boolean, transient: boolean): string;
26
+ //# sourceMappingURL=verdict.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verdict.d.ts","sourceRoot":"","sources":["../src/verdict.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAEV,YAAY,EACZ,WAAW,EACX,aAAa,EACd,MAAM,SAAS,CAAC;AAEjB;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG;IACrC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO,CAAC;CAC9B,CAAC;AAWF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,cAAc,CAAC;IACpB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,6DAA6D;IAC7D,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,GAAG,aAAa,CAwEhB;AAUD,wBAAgB,WAAW,CACzB,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,WAAW,EACnB,UAAU,EAAE,OAAO,EACnB,SAAS,EAAE,OAAO,GACjB,MAAM,CAUR"}
@@ -0,0 +1,84 @@
1
+ import { detectTierMismatch } from "./signals";
2
+ import { detectSubstitution } from "./substitution";
3
+ const labelsWith = (results, sig) => results
4
+ .filter((r) => r.signal === sig)
5
+ .map((r) => r.label)
6
+ .join(", ");
7
+ const firstSignal = (results, sig) => results.some((r) => r.signal === sig) ? labelsWith(results, sig) : null;
8
+ export function aggregateVerdict(args) {
9
+ const results = args.results;
10
+ const reasons = [];
11
+ const codingTool = firstSignal(results, "coding-tool");
12
+ if (codingTool)
13
+ return suspicious(`coding-tool-refusal: ${codingTool}`);
14
+ const scam = firstSignal(results, "scam");
15
+ if (scam)
16
+ return suspicious(`scam-page: ${scam}`);
17
+ const cjk = firstSignal(results, "cjk-leak");
18
+ if (cjk)
19
+ return suspicious(`cjk-language-leak: ${cjk}`);
20
+ const muxLabels = results.filter((r) => r.muxFailure).map((r) => r.label);
21
+ if (muxLabels.length >= 2)
22
+ return suspicious(`unsafe-proxy: response-mixing on ${muxLabels.join(", ")}`);
23
+ const foreignOnIdentity = results.some((r) => r.signal === "foreign" &&
24
+ (r.label === "model-name" || r.label === "identity"));
25
+ if (foreignOnIdentity)
26
+ return suspicious(`foreign-identity: ${labelsWith(results, "foreign")}`);
27
+ if (args.cfg.tiers) {
28
+ const modelNameText = results.find((r) => r.label === "model-name")?.text;
29
+ const served = detectTierMismatch(args.model, modelNameText, args.cfg.tiers);
30
+ if (served)
31
+ return suspicious(`tier-mismatch: requested ${args.model}, served ${served}`);
32
+ }
33
+ // Envelope check, free: the endpoint told us which model answered, and it is
34
+ // not the one asked for. Runs after tier-mismatch because that names the
35
+ // cheaper tier specifically, which reads better than a raw id diff.
36
+ const substituted = detectSubstitution(args.model, args.detectedModel);
37
+ if (substituted)
38
+ return suspicious(`substituted: requested ${args.model}, served ${substituted}`);
39
+ const passed = results.filter((r) => r.pass).length;
40
+ const failed = results.filter((r) => !r.pass);
41
+ const passing = passed >= 3;
42
+ if (passing)
43
+ return {
44
+ verdict: "genuine",
45
+ reasons,
46
+ versionUnverifiable: true,
47
+ };
48
+ const transientFails = failed.filter((r) => r.transient).length;
49
+ const nonTransientFails = failed.filter((r) => !r.transient && r.signal !== null).length;
50
+ if (transientFails > 0 && nonTransientFails === 0)
51
+ return {
52
+ verdict: "unverified",
53
+ reasons: [`transient: ${failed.map((r) => r.label).join(", ")}`],
54
+ versionUnverifiable: false,
55
+ };
56
+ return suspicious(`failed: ${failed.map((r) => r.label).join(", ")}`);
57
+ }
58
+ function suspicious(reason) {
59
+ return {
60
+ verdict: "suspicious",
61
+ reasons: [reason],
62
+ versionUnverifiable: false,
63
+ };
64
+ }
65
+ export function probeReason(pass, signal, muxFailure, transient) {
66
+ if (signal === "coding-tool")
67
+ return "coding-tool wrapper detected";
68
+ if (signal === "scam")
69
+ return "scam page detected";
70
+ if (signal === "cjk-leak")
71
+ return "CJK leaked into an English reply";
72
+ if (signal === "foreign")
73
+ return "foreign vendor named";
74
+ if (signal === "cloud-host")
75
+ return "cloud host named (accepted)";
76
+ if (signal === "blank")
77
+ return "blank response";
78
+ if (muxFailure)
79
+ return "response mixing (nonce mismatch)";
80
+ if (transient)
81
+ return "transient upstream error";
82
+ return pass ? "passed" : "failed quality check";
83
+ }
84
+ //# sourceMappingURL=verdict.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verdict.js","sourceRoot":"","sources":["../src/verdict.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "ai-model-verifier",
3
+ "version": "1.0.0",
4
+ "description": "Verify an AI API endpoint really serves the model it claims: model substitution, Claude thinking signatures, token-billing accuracy, response-envelope and throughput evidence.",
5
+ "license": "AGPL-3.0-only",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/unorouter/ai-model-verifier.git"
10
+ },
11
+ "keywords": [
12
+ "ai",
13
+ "llm",
14
+ "relay",
15
+ "proxy",
16
+ "verify",
17
+ "authenticity",
18
+ "model-verification",
19
+ "fake-model",
20
+ "anthropic",
21
+ "claude",
22
+ "openai",
23
+ "gemini",
24
+ "token-billing"
25
+ ],
26
+ "sideEffects": false,
27
+ "files": [
28
+ "dist"
29
+ ],
30
+ "exports": {
31
+ ".": {
32
+ "types": "./dist/index.d.ts",
33
+ "default": "./dist/index.js"
34
+ },
35
+ "./providers/*": {
36
+ "types": "./dist/providers/*.d.ts",
37
+ "default": "./dist/providers/*.js"
38
+ },
39
+ "./*": {
40
+ "types": "./dist/*.d.ts",
41
+ "default": "./dist/*.js"
42
+ }
43
+ },
44
+ "scripts": {
45
+ "build": "tsc -p tsconfig.build.json",
46
+ "typecheck": "tsc --noEmit",
47
+ "prepublishOnly": "bun run build"
48
+ },
49
+ "devDependencies": {
50
+ "typescript": "^7.0.2"
51
+ },
52
+ "homepage": "https://github.com/unorouter/ai-model-verifier",
53
+ "bugs": {
54
+ "url": "https://github.com/unorouter/ai-model-verifier/issues"
55
+ }
56
+ }