@volter/twin-ai-gateway 0.1.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 (42) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +176 -0
  3. package/dist/src/ai-gateway-capabilities.d.ts +4 -0
  4. package/dist/src/ai-gateway-capabilities.js +772 -0
  5. package/dist/src/ai-gateway-conformance.d.ts +11 -0
  6. package/dist/src/ai-gateway-conformance.js +72 -0
  7. package/dist/src/ai-gateway-connector.d.ts +50 -0
  8. package/dist/src/ai-gateway-connector.js +97 -0
  9. package/dist/src/ai-gateway-models.d.ts +27 -0
  10. package/dist/src/ai-gateway-models.js +65 -0
  11. package/dist/src/ai-gateway-perform-harness.d.ts +5 -0
  12. package/dist/src/ai-gateway-perform-harness.js +17 -0
  13. package/dist/src/ai-gateway-scenario.d.ts +36 -0
  14. package/dist/src/ai-gateway-scenario.js +125 -0
  15. package/dist/src/ai-gateway-server.d.ts +16 -0
  16. package/dist/src/ai-gateway-server.js +107 -0
  17. package/dist/src/ai-gateway-stub.d.ts +20 -0
  18. package/dist/src/ai-gateway-stub.js +124 -0
  19. package/dist/src/ai-gateway-twin.d.ts +2 -0
  20. package/dist/src/ai-gateway-twin.js +994 -0
  21. package/dist/src/ai-gateway-types.d.ts +94 -0
  22. package/dist/src/ai-gateway-types.js +1 -0
  23. package/dist/src/ai-gateway-v3.d.ts +5 -0
  24. package/dist/src/ai-gateway-v3.js +367 -0
  25. package/dist/src/cli.d.ts +2 -0
  26. package/dist/src/cli.js +24 -0
  27. package/dist/src/index.d.ts +12 -0
  28. package/dist/src/index.js +54 -0
  29. package/package.json +66 -0
  30. package/src/ai-gateway-capabilities.ts +894 -0
  31. package/src/ai-gateway-conformance.ts +77 -0
  32. package/src/ai-gateway-connector.ts +100 -0
  33. package/src/ai-gateway-models.ts +105 -0
  34. package/src/ai-gateway-perform-harness.ts +17 -0
  35. package/src/ai-gateway-scenario.ts +137 -0
  36. package/src/ai-gateway-server.ts +122 -0
  37. package/src/ai-gateway-stub.ts +115 -0
  38. package/src/ai-gateway-twin.ts +1068 -0
  39. package/src/ai-gateway-types.ts +96 -0
  40. package/src/ai-gateway-v3.ts +372 -0
  41. package/src/cli.ts +23 -0
  42. package/src/index.ts +67 -0
@@ -0,0 +1,20 @@
1
+ import type { ChatMessage } from './ai-gateway-types.js';
2
+ export declare function contentToText(content: unknown): string;
3
+ export declare function lastUserText(messages: ChatMessage[]): string;
4
+ export declare function estimateTokens(input: string): number;
5
+ export declare function countPromptTokens(messages: ChatMessage[]): number;
6
+ export declare function stubAssistantText(messages: ChatMessage[], model: string): string;
7
+ export declare function stableHash(value: unknown): string;
8
+ /** Synthesize a deterministic value conforming to a JSON schema — used for json_schema
9
+ * structured outputs AND for tool-call arguments, so an unmodified SDK's own schema
10
+ * validation of the stubbed output passes. */
11
+ export declare function synthesizeJsonSchemaValue(schema: unknown, key?: string): unknown;
12
+ type NormalizedTool = {
13
+ name: string;
14
+ parameters: unknown;
15
+ };
16
+ export declare function normalizeTool(tool: unknown): NormalizedTool | null;
17
+ /** Build the deterministic tool_call the stub emits for a chosen tool: id from the tool name,
18
+ * arguments synthesized to CONFORM to the tool's own parameters schema. */
19
+ export declare function buildToolCall(tool: NormalizedTool): Record<string, unknown>;
20
+ export {};
@@ -0,0 +1,124 @@
1
+ export function contentToText(content) {
2
+ if (typeof content === 'string')
3
+ return content;
4
+ if (Array.isArray(content)) {
5
+ return content.map((part) => {
6
+ if (typeof part === 'string')
7
+ return part;
8
+ if (part && typeof part === 'object' && 'text' in part)
9
+ return String(part.text ?? '');
10
+ return '';
11
+ }).filter(Boolean).join(' ');
12
+ }
13
+ return '';
14
+ }
15
+ export function lastUserText(messages) {
16
+ for (let i = messages.length - 1; i >= 0; i--) {
17
+ if (messages[i]?.role === 'user')
18
+ return contentToText(messages[i]?.content);
19
+ }
20
+ return '';
21
+ }
22
+ export function estimateTokens(input) {
23
+ const trimmed = input.trim();
24
+ if (!trimmed)
25
+ return 0;
26
+ return Math.max(1, Math.ceil(trimmed.length / 4));
27
+ }
28
+ export function countPromptTokens(messages) {
29
+ return messages.reduce((sum, message) => sum + estimateTokens(`${message.role}: ${contentToText(message.content)}`), 0);
30
+ }
31
+ export function stubAssistantText(messages, model) {
32
+ const text = lastUserText(messages) || 'empty prompt';
33
+ return `[twin-stub:ai-gateway:${model}] Echoing the last user message for deterministic simulation: ${text}`;
34
+ }
35
+ export function stableHash(value) {
36
+ const s = JSON.stringify(value);
37
+ let h = 2166136261;
38
+ for (let i = 0; i < s.length; i++) {
39
+ h ^= s.charCodeAt(i);
40
+ h = Math.imul(h, 16777619);
41
+ }
42
+ return (h >>> 0).toString(16).padStart(8, '0');
43
+ }
44
+ function schemaType(schema) {
45
+ const type = schema.type;
46
+ if (typeof type === 'string')
47
+ return type;
48
+ if (Array.isArray(type))
49
+ return type.find((item) => item !== 'null' && typeof item === 'string');
50
+ return undefined;
51
+ }
52
+ function schemaString(key) {
53
+ const k = key.toLowerCase();
54
+ if (k.includes('timestamp') || k.includes('date'))
55
+ return '2026-06-16T00:00:00.000Z';
56
+ if (k.includes('url'))
57
+ return 'http://127.0.0.1/twin';
58
+ if (k.includes('summary'))
59
+ return 'Twin structured-output stub summary.';
60
+ if (k.includes('description'))
61
+ return 'Deterministic twin structured-output stub description.';
62
+ return 'twin stub';
63
+ }
64
+ /** Synthesize a deterministic value conforming to a JSON schema — used for json_schema
65
+ * structured outputs AND for tool-call arguments, so an unmodified SDK's own schema
66
+ * validation of the stubbed output passes. */
67
+ export function synthesizeJsonSchemaValue(schema, key = 'value') {
68
+ if (!schema || typeof schema !== 'object' || Array.isArray(schema))
69
+ return {};
70
+ const s = schema;
71
+ if (Array.isArray(s.enum) && s.enum.length > 0)
72
+ return s.enum[0];
73
+ if (Array.isArray(s.const))
74
+ return s.const[0];
75
+ if (s.const !== undefined)
76
+ return s.const;
77
+ if (Array.isArray(s.anyOf) && s.anyOf.length > 0)
78
+ return synthesizeJsonSchemaValue(s.anyOf[0], key);
79
+ if (Array.isArray(s.oneOf) && s.oneOf.length > 0)
80
+ return synthesizeJsonSchemaValue(s.oneOf[0], key);
81
+ const type = schemaType(s);
82
+ if (type === 'object' || (!type && s.properties && typeof s.properties === 'object')) {
83
+ const out = {};
84
+ const props = (s.properties && typeof s.properties === 'object' && !Array.isArray(s.properties))
85
+ ? s.properties
86
+ : {};
87
+ for (const [propKey, propSchema] of Object.entries(props)) {
88
+ out[propKey] = synthesizeJsonSchemaValue(propSchema, propKey);
89
+ }
90
+ return out;
91
+ }
92
+ if (type === 'array')
93
+ return [];
94
+ if (type === 'string')
95
+ return schemaString(key);
96
+ if (type === 'number' || type === 'integer')
97
+ return 0;
98
+ if (type === 'boolean')
99
+ return true;
100
+ if (type === 'null')
101
+ return null;
102
+ return {};
103
+ }
104
+ export function normalizeTool(tool) {
105
+ if (!tool || typeof tool !== 'object')
106
+ return null;
107
+ const t = tool;
108
+ const fn = t.function && typeof t.function === 'object' ? t.function : t;
109
+ if (typeof fn.name !== 'string' || !fn.name)
110
+ return null;
111
+ return { name: fn.name, parameters: fn.parameters };
112
+ }
113
+ /** Build the deterministic tool_call the stub emits for a chosen tool: id from the tool name,
114
+ * arguments synthesized to CONFORM to the tool's own parameters schema. */
115
+ export function buildToolCall(tool) {
116
+ return {
117
+ id: `call_twin_${stableHash(tool.name).slice(0, 8)}`,
118
+ type: 'function',
119
+ function: {
120
+ name: tool.name,
121
+ arguments: JSON.stringify(synthesizeJsonSchemaValue(tool.parameters)),
122
+ },
123
+ };
124
+ }
@@ -0,0 +1,2 @@
1
+ import type { AiGatewayRequest, AiGatewayResponse } from './ai-gateway-types.js';
2
+ export declare function handleAiGatewayTwinRequest(req: AiGatewayRequest): Promise<AiGatewayResponse>;