@juspay/neurolink 12.34.2 → 12.35.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.
- package/CHANGELOG.md +3 -3
- package/dist/browser/neurolink.min.js +388 -388
- package/dist/proxy/proxyIR.d.ts +44 -0
- package/dist/proxy/proxyIR.js +127 -0
- package/dist/services/server/ai/observability/instrumentation.d.ts +5 -0
- package/dist/services/server/ai/observability/instrumentation.js +31 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/proxyIR.d.ts +283 -0
- package/dist/types/proxyIR.js +21 -0
- package/package.json +1 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exhaustiveness enforcement for the translation IR.
|
|
3
|
+
*
|
|
4
|
+
* A translation layer fails quietly: an unhandled content part or event variant
|
|
5
|
+
* becomes a missing tool call, and the only symptom is the next hop rejecting a
|
|
6
|
+
* request nobody can explain. `assertProxyIRExhaustive` makes that a compile
|
|
7
|
+
* error instead. Passing a value whose type is not `never` does not type-check,
|
|
8
|
+
* so a new IR variant breaks every `switch` that has not handled it.
|
|
9
|
+
*
|
|
10
|
+
* It throws at runtime as well, because the compile-time guarantee only holds for
|
|
11
|
+
* values that really are typed. A wire payload narrowed from `unknown` can reach a
|
|
12
|
+
* default branch at runtime, and failing loudly there beats translating a request
|
|
13
|
+
* with a silently dropped element.
|
|
14
|
+
*/
|
|
15
|
+
import type { ProxyIRContentPart, ProxyIRResponseEvent, ProxyIRTerminalOutcome, ProxyIRUnmappableValue } from "../types/index.js";
|
|
16
|
+
/**
|
|
17
|
+
* Refuse an unhandled IR variant.
|
|
18
|
+
*
|
|
19
|
+
* `context` names the switch that failed, since the value alone rarely says which
|
|
20
|
+
* of several exhaustive switches over the same union let it through.
|
|
21
|
+
*/
|
|
22
|
+
export declare function assertProxyIRExhaustive(value: never, context: string): never;
|
|
23
|
+
/** Mark a wire value no codec could represent, preserving it for the caller. */
|
|
24
|
+
export declare function proxyIRUnmappable(sourceKind: string, reason: string, raw: unknown): ProxyIRUnmappableValue;
|
|
25
|
+
/** Narrow a collected codec result to the unmappable marker. */
|
|
26
|
+
export declare function isProxyIRUnmappable(value: unknown): value is ProxyIRUnmappableValue;
|
|
27
|
+
/**
|
|
28
|
+
* Name a content part for a diagnostic.
|
|
29
|
+
*
|
|
30
|
+
* This lives in `src` rather than in the suite that asserts on it because
|
|
31
|
+
* `tsconfig.json` excludes `test`: an exhaustive switch written only in a test
|
|
32
|
+
* gives no compile-time guarantee at all. These describers are the shipped
|
|
33
|
+
* consumers that pin every union, so adding an IR variant fails `tsc --noEmit`
|
|
34
|
+
* here before it can reach a codec that silently drops it.
|
|
35
|
+
*
|
|
36
|
+
* Deliberately excludes the payload of text, thinking and tool arguments: a
|
|
37
|
+
* describer's output reaches logs and span attributes, and prompt content does
|
|
38
|
+
* not belong there.
|
|
39
|
+
*/
|
|
40
|
+
export declare function describeProxyIRPart(part: ProxyIRContentPart): string;
|
|
41
|
+
/** Name a stream event for a diagnostic, without its payload. */
|
|
42
|
+
export declare function describeProxyIRResponseEvent(event: ProxyIRResponseEvent): string;
|
|
43
|
+
/** Name a terminal outcome, keeping an unmodelled upstream stop reason visible. */
|
|
44
|
+
export declare function describeProxyIRTerminalOutcome(outcome: ProxyIRTerminalOutcome): string;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exhaustiveness enforcement for the translation IR.
|
|
3
|
+
*
|
|
4
|
+
* A translation layer fails quietly: an unhandled content part or event variant
|
|
5
|
+
* becomes a missing tool call, and the only symptom is the next hop rejecting a
|
|
6
|
+
* request nobody can explain. `assertProxyIRExhaustive` makes that a compile
|
|
7
|
+
* error instead. Passing a value whose type is not `never` does not type-check,
|
|
8
|
+
* so a new IR variant breaks every `switch` that has not handled it.
|
|
9
|
+
*
|
|
10
|
+
* It throws at runtime as well, because the compile-time guarantee only holds for
|
|
11
|
+
* values that really are typed. A wire payload narrowed from `unknown` can reach a
|
|
12
|
+
* default branch at runtime, and failing loudly there beats translating a request
|
|
13
|
+
* with a silently dropped element.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Refuse an unhandled IR variant.
|
|
17
|
+
*
|
|
18
|
+
* `context` names the switch that failed, since the value alone rarely says which
|
|
19
|
+
* of several exhaustive switches over the same union let it through.
|
|
20
|
+
*/
|
|
21
|
+
export function assertProxyIRExhaustive(value, context) {
|
|
22
|
+
throw new Error(`[proxy-ir] ${context} did not handle variant: ${describeProxyIRVariant(value)}`);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Describe a value for the exhaustiveness error without assuming its shape.
|
|
26
|
+
*
|
|
27
|
+
* The parameter is `never` at the call site, so nothing about it can be trusted
|
|
28
|
+
* here: it may be a primitive, or an object with no discriminant at all — and an
|
|
29
|
+
* untagged object is exactly the shape a malformed wire payload takes. Reviewed
|
|
30
|
+
* finding (PR #1826): serializing that object's fields defeated the point of a
|
|
31
|
+
* log/span-safe diagnostic, since the object can carry the same text or tool
|
|
32
|
+
* arguments the typed describers deliberately withhold. The fallback is now a
|
|
33
|
+
* fixed, shape-only marker — never the object's own content — for every
|
|
34
|
+
* untagged case, not only the ones this file happens to call today.
|
|
35
|
+
*/
|
|
36
|
+
function describeProxyIRVariant(value) {
|
|
37
|
+
if (value === null || typeof value !== "object") {
|
|
38
|
+
return String(value);
|
|
39
|
+
}
|
|
40
|
+
const record = value;
|
|
41
|
+
for (const discriminant of ["kind", "status", "source", "format"]) {
|
|
42
|
+
const tag = record[discriminant];
|
|
43
|
+
if (typeof tag === "string") {
|
|
44
|
+
return `${discriminant}=${tag}`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return "[object without recognized discriminant]";
|
|
48
|
+
}
|
|
49
|
+
/** Mark a wire value no codec could represent, preserving it for the caller. */
|
|
50
|
+
export function proxyIRUnmappable(sourceKind, reason, raw) {
|
|
51
|
+
return { proxyIRUnmappable: true, sourceKind, reason, raw };
|
|
52
|
+
}
|
|
53
|
+
/** Narrow a collected codec result to the unmappable marker. */
|
|
54
|
+
export function isProxyIRUnmappable(value) {
|
|
55
|
+
return (value !== null &&
|
|
56
|
+
typeof value === "object" &&
|
|
57
|
+
value.proxyIRUnmappable === true);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Name a content part for a diagnostic.
|
|
61
|
+
*
|
|
62
|
+
* This lives in `src` rather than in the suite that asserts on it because
|
|
63
|
+
* `tsconfig.json` excludes `test`: an exhaustive switch written only in a test
|
|
64
|
+
* gives no compile-time guarantee at all. These describers are the shipped
|
|
65
|
+
* consumers that pin every union, so adding an IR variant fails `tsc --noEmit`
|
|
66
|
+
* here before it can reach a codec that silently drops it.
|
|
67
|
+
*
|
|
68
|
+
* Deliberately excludes the payload of text, thinking and tool arguments: a
|
|
69
|
+
* describer's output reaches logs and span attributes, and prompt content does
|
|
70
|
+
* not belong there.
|
|
71
|
+
*/
|
|
72
|
+
export function describeProxyIRPart(part) {
|
|
73
|
+
switch (part.kind) {
|
|
74
|
+
case "text":
|
|
75
|
+
return `text(${part.text.length}b)`;
|
|
76
|
+
case "thinking":
|
|
77
|
+
return `thinking(${part.text.length}b)`;
|
|
78
|
+
case "image":
|
|
79
|
+
return `image(${part.encoding})`;
|
|
80
|
+
case "tool_call":
|
|
81
|
+
return `tool_call(${part.toolName})`;
|
|
82
|
+
case "tool_result":
|
|
83
|
+
return `tool_result(${part.content.length} parts${part.isError ? ", error" : ""})`;
|
|
84
|
+
case "unmapped":
|
|
85
|
+
return `unmapped(${part.sourceKind}: ${part.reason})`;
|
|
86
|
+
default:
|
|
87
|
+
return assertProxyIRExhaustive(part, "describeProxyIRPart");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** Name a stream event for a diagnostic, without its payload. */
|
|
91
|
+
export function describeProxyIRResponseEvent(event) {
|
|
92
|
+
switch (event.kind) {
|
|
93
|
+
case "text_delta":
|
|
94
|
+
return `text_delta(${event.text.length}b)`;
|
|
95
|
+
case "thinking_delta":
|
|
96
|
+
return `thinking_delta(${event.text.length}b)`;
|
|
97
|
+
case "tool_call_start":
|
|
98
|
+
return `tool_call_start(${event.toolName})`;
|
|
99
|
+
case "tool_call_arguments_delta":
|
|
100
|
+
return `tool_call_arguments_delta(${event.partialArguments.length}b)`;
|
|
101
|
+
case "tool_call_done":
|
|
102
|
+
return "tool_call_done";
|
|
103
|
+
case "item_done":
|
|
104
|
+
return "item_done";
|
|
105
|
+
case "usage":
|
|
106
|
+
return "usage";
|
|
107
|
+
case "terminal":
|
|
108
|
+
return `terminal(${describeProxyIRTerminalOutcome(event.outcome)})`;
|
|
109
|
+
default:
|
|
110
|
+
return assertProxyIRExhaustive(event, "describeProxyIRResponseEvent");
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** Name a terminal outcome, keeping an unmodelled upstream stop reason visible. */
|
|
114
|
+
export function describeProxyIRTerminalOutcome(outcome) {
|
|
115
|
+
switch (outcome.status) {
|
|
116
|
+
case "completed":
|
|
117
|
+
return outcome.finishReason === "other"
|
|
118
|
+
? `completed:${outcome.rawFinishReason}`
|
|
119
|
+
: `completed:${outcome.finishReason}`;
|
|
120
|
+
case "failed":
|
|
121
|
+
return `failed:${outcome.error.code}`;
|
|
122
|
+
case "incomplete":
|
|
123
|
+
return `incomplete:${outcome.reason}`;
|
|
124
|
+
default:
|
|
125
|
+
return assertProxyIRExhaustive(outcome, "describeProxyIRTerminalOutcome");
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -51,6 +51,11 @@ export declare function initializeOpenTelemetry(config: LangfuseConfig): Promise
|
|
|
51
51
|
export declare function flushOpenTelemetry(): Promise<void>;
|
|
52
52
|
/**
|
|
53
53
|
* Shutdown OpenTelemetry and Langfuse span processor
|
|
54
|
+
*
|
|
55
|
+
* Concurrent callers share one in-flight teardown, the same way concurrent
|
|
56
|
+
* initializers share one in-flight `initializeOpenTelemetry`: a second
|
|
57
|
+
* shutdown call joins the first instead of tearing down the same provider
|
|
58
|
+
* instances a second time.
|
|
54
59
|
*/
|
|
55
60
|
export declare function shutdownOpenTelemetry(): Promise<void>;
|
|
56
61
|
/**
|
|
@@ -106,6 +106,7 @@ let loggerProvider = null;
|
|
|
106
106
|
let langfuseProcessor = null;
|
|
107
107
|
let isInitialized = false;
|
|
108
108
|
let initializationPromise = null;
|
|
109
|
+
let shutdownPromise = null;
|
|
109
110
|
let isCredentialsValid = false;
|
|
110
111
|
let currentConfig = null;
|
|
111
112
|
let usingExternalProvider = false;
|
|
@@ -841,6 +842,15 @@ async function initializeStandaloneOpenTelemetryMode(config, resource, otlpEndpo
|
|
|
841
842
|
* flush or shutdown wait for the same initialization before touching providers.
|
|
842
843
|
*/
|
|
843
844
|
export async function initializeOpenTelemetry(config) {
|
|
845
|
+
if (shutdownPromise) {
|
|
846
|
+
// A shutdown already in flight is what made isInitialized/
|
|
847
|
+
// initializationPromise true or null in the first place; either reading
|
|
848
|
+
// is stale until it actually finishes. Waiting here means this call sees
|
|
849
|
+
// the settled post-teardown state — nothing initialized, nothing
|
|
850
|
+
// pending — and falls through to build fresh providers, rather than
|
|
851
|
+
// returning early on a flag that is about to flip out from under it.
|
|
852
|
+
await shutdownPromise;
|
|
853
|
+
}
|
|
844
854
|
if (isInitialized) {
|
|
845
855
|
currentConfig = config;
|
|
846
856
|
logger.debug(`${LOG_PREFIX} Already initialized, config updated`, {
|
|
@@ -991,8 +1001,29 @@ export async function flushOpenTelemetry() {
|
|
|
991
1001
|
}
|
|
992
1002
|
/**
|
|
993
1003
|
* Shutdown OpenTelemetry and Langfuse span processor
|
|
1004
|
+
*
|
|
1005
|
+
* Concurrent callers share one in-flight teardown, the same way concurrent
|
|
1006
|
+
* initializers share one in-flight `initializeOpenTelemetry`: a second
|
|
1007
|
+
* shutdown call joins the first instead of tearing down the same provider
|
|
1008
|
+
* instances a second time.
|
|
994
1009
|
*/
|
|
995
1010
|
export async function shutdownOpenTelemetry() {
|
|
1011
|
+
if (shutdownPromise) {
|
|
1012
|
+
await shutdownPromise;
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
const pending = shutdownOpenTelemetryOnce();
|
|
1016
|
+
shutdownPromise = pending;
|
|
1017
|
+
try {
|
|
1018
|
+
await pending;
|
|
1019
|
+
}
|
|
1020
|
+
finally {
|
|
1021
|
+
if (shutdownPromise === pending) {
|
|
1022
|
+
shutdownPromise = null;
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
async function shutdownOpenTelemetryOnce() {
|
|
996
1027
|
if (initializationPromise) {
|
|
997
1028
|
try {
|
|
998
1029
|
await initializationPromise;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -55,6 +55,7 @@ export * from "./providerCatalog.js";
|
|
|
55
55
|
export * from "./providerCatalog.generated.js";
|
|
56
56
|
export * from "./providers.js";
|
|
57
57
|
export * from "./proxy.js";
|
|
58
|
+
export * from "./proxyIR.js";
|
|
58
59
|
export * from "./proxyClient.js";
|
|
59
60
|
export * from "./proxyContext.js";
|
|
60
61
|
export * from "./rag.js";
|
package/dist/types/index.js
CHANGED
|
@@ -59,6 +59,7 @@ export * from "./providerCatalog.js";
|
|
|
59
59
|
export * from "./providerCatalog.generated.js";
|
|
60
60
|
export * from "./providers.js";
|
|
61
61
|
export * from "./proxy.js";
|
|
62
|
+
export * from "./proxyIR.js";
|
|
62
63
|
export * from "./proxyClient.js";
|
|
63
64
|
export * from "./proxyContext.js";
|
|
64
65
|
export * from "./rag.js";
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire-neutral intermediate representation for proxy protocol translation.
|
|
3
|
+
*
|
|
4
|
+
* Translation between provider wire formats was previously pairwise and ad hoc:
|
|
5
|
+
* `codexFallback.ts` converts an Anthropic request into a Codex one and casts a
|
|
6
|
+
* role to reach Claude Code's inline-system convention inside a converter that is
|
|
7
|
+
* meant to be neutral. Adding the reverse direction pairwise would double that,
|
|
8
|
+
* and a third provider would square it.
|
|
9
|
+
*
|
|
10
|
+
* So each format gets a codec to and from this IR, and adding a provider is a new
|
|
11
|
+
* codec rather than new branching. The IR is deliberately not `ClaudeRequest`:
|
|
12
|
+
* that type is simultaneously the literal Anthropic wire shape, so using it as
|
|
13
|
+
* the hub makes every other provider's quirks leak into the Anthropic hot path.
|
|
14
|
+
* `ClaudeRequest` and `ClaudeResponse` stay untouched.
|
|
15
|
+
*
|
|
16
|
+
* Every union here is discriminated on a literal `kind`, `status` or `source`, so
|
|
17
|
+
* `assertProxyIRExhaustive` turns an unhandled variant into a compile error. That
|
|
18
|
+
* is the point of the IR: a field that cannot be represented must be stated, via
|
|
19
|
+
* `ProxyIRUnmappedPart`, rather than dropped silently.
|
|
20
|
+
*/
|
|
21
|
+
import type { CodexReasoningEffort } from "./codex.js";
|
|
22
|
+
import type { UsageContext } from "./proxy.js";
|
|
23
|
+
/**
|
|
24
|
+
* A wire dialect a codec can speak.
|
|
25
|
+
*
|
|
26
|
+
* Distinct from `ProxyFormat` ("claude" | "openai" | "gemini"), which selects a
|
|
27
|
+
* request-translation surface for a different subsystem. These must not be
|
|
28
|
+
* conflated: this one names the two dialects the fallback codecs translate.
|
|
29
|
+
*/
|
|
30
|
+
export type ProxyIRWireFormat = "anthropic-messages" | "codex-responses";
|
|
31
|
+
/**
|
|
32
|
+
* Message roles across both dialects.
|
|
33
|
+
*
|
|
34
|
+
* `developer` has no Anthropic equivalent and is native Codex's own role for
|
|
35
|
+
* instruction blocks that sit inside the ordered input array rather than in a
|
|
36
|
+
* leading system field. It is kept distinct from `system` so a codec targeting
|
|
37
|
+
* Anthropic can decide where it belongs instead of inheriting a lossy merge.
|
|
38
|
+
*/
|
|
39
|
+
export type ProxyIRRole = "system" | "developer" | "user" | "assistant";
|
|
40
|
+
/**
|
|
41
|
+
* A request to cache the prefix up to and including the annotated element.
|
|
42
|
+
*
|
|
43
|
+
* Only meaningful for Anthropic, whose caching is explicit and breakpoint-driven.
|
|
44
|
+
* A codec targeting a dialect with automatic caching ignores it, which is correct
|
|
45
|
+
* rather than lossy: nothing on that wire can carry it.
|
|
46
|
+
*/
|
|
47
|
+
export type ProxyIRCacheHint = {
|
|
48
|
+
ttl?: "5m" | "1h";
|
|
49
|
+
};
|
|
50
|
+
export type ProxyIRTextPart = {
|
|
51
|
+
kind: "text";
|
|
52
|
+
text: string;
|
|
53
|
+
cacheHint?: ProxyIRCacheHint;
|
|
54
|
+
};
|
|
55
|
+
/** `signature` is reserved for Anthropic's signed thinking blocks and unused today. */
|
|
56
|
+
export type ProxyIRThinkingPart = {
|
|
57
|
+
kind: "thinking";
|
|
58
|
+
text: string;
|
|
59
|
+
signature?: string;
|
|
60
|
+
};
|
|
61
|
+
export type ProxyIRImagePart = {
|
|
62
|
+
kind: "image";
|
|
63
|
+
encoding: "base64" | "url";
|
|
64
|
+
mediaType?: string;
|
|
65
|
+
data: string;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* A model-emitted call to a tool.
|
|
69
|
+
*
|
|
70
|
+
* `argumentsRaw` is authoritative and always present; `argumentsJson` is a
|
|
71
|
+
* convenience for the common case where the raw text parses. Keeping the raw text
|
|
72
|
+
* means a call whose arguments are streamed in fragments, or are not valid JSON,
|
|
73
|
+
* survives translation instead of being normalised into something the next hop
|
|
74
|
+
* never sent.
|
|
75
|
+
*/
|
|
76
|
+
export type ProxyIRToolCallPart = {
|
|
77
|
+
kind: "tool_call";
|
|
78
|
+
callId: string;
|
|
79
|
+
toolName: string;
|
|
80
|
+
argumentsRaw: string;
|
|
81
|
+
argumentsJson?: Record<string, unknown>;
|
|
82
|
+
};
|
|
83
|
+
export type ProxyIRToolResultPart = {
|
|
84
|
+
kind: "tool_result";
|
|
85
|
+
callId: string;
|
|
86
|
+
content: (ProxyIRTextPart | ProxyIRImagePart)[];
|
|
87
|
+
isError?: boolean;
|
|
88
|
+
cacheHint?: ProxyIRCacheHint;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* A wire element no codec could represent, carried forward verbatim.
|
|
92
|
+
*
|
|
93
|
+
* The alternative is dropping it, which is how a translation layer loses tool
|
|
94
|
+
* calls: silently, and only visibly as a downstream rejection. `raw` keeps the
|
|
95
|
+
* original so a renderer can pass it through or a test can assert on it, and
|
|
96
|
+
* `reason` records why it could not be mapped.
|
|
97
|
+
*/
|
|
98
|
+
export type ProxyIRUnmappedPart = {
|
|
99
|
+
kind: "unmapped";
|
|
100
|
+
sourceKind: string;
|
|
101
|
+
reason: string;
|
|
102
|
+
raw: unknown;
|
|
103
|
+
};
|
|
104
|
+
export type ProxyIRContentPart = ProxyIRTextPart | ProxyIRThinkingPart | ProxyIRImagePart | ProxyIRToolCallPart | ProxyIRToolResultPart | ProxyIRUnmappedPart;
|
|
105
|
+
/**
|
|
106
|
+
* One message, with system and developer messages kept in sequence.
|
|
107
|
+
*
|
|
108
|
+
* There is no separate bucket for leading instructions: native Codex sends
|
|
109
|
+
* instruction blocks as ordered `developer` items inside the input array, and
|
|
110
|
+
* lifting them out would lose their position relative to the conversation. A
|
|
111
|
+
* codec that needs a leading system field extracts it; the IR does not presume
|
|
112
|
+
* one exists.
|
|
113
|
+
*/
|
|
114
|
+
export type ProxyIRMessage = {
|
|
115
|
+
role: ProxyIRRole;
|
|
116
|
+
content: ProxyIRContentPart[];
|
|
117
|
+
};
|
|
118
|
+
export type ProxyIRFunctionToolDeclaration = {
|
|
119
|
+
kind: "function";
|
|
120
|
+
name: string;
|
|
121
|
+
description?: string;
|
|
122
|
+
parametersSchema: Record<string, unknown>;
|
|
123
|
+
cacheHint?: ProxyIRCacheHint;
|
|
124
|
+
};
|
|
125
|
+
/** A tool constrained by a grammar rather than a JSON schema; Codex-only today. */
|
|
126
|
+
export type ProxyIRCustomGrammarToolDeclaration = {
|
|
127
|
+
kind: "custom_grammar";
|
|
128
|
+
name: string;
|
|
129
|
+
description?: string;
|
|
130
|
+
grammar: string;
|
|
131
|
+
};
|
|
132
|
+
export type ProxyIRToolDeclaration = ProxyIRFunctionToolDeclaration | ProxyIRCustomGrammarToolDeclaration;
|
|
133
|
+
export type ProxyIRToolChoice = {
|
|
134
|
+
kind: "auto";
|
|
135
|
+
} | {
|
|
136
|
+
kind: "none";
|
|
137
|
+
} | {
|
|
138
|
+
kind: "any";
|
|
139
|
+
} | {
|
|
140
|
+
kind: "named";
|
|
141
|
+
toolName: string;
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* Reasoning configuration, tagged by the dialect that expressed it.
|
|
145
|
+
*
|
|
146
|
+
* Anthropic budgets thinking in tokens; Codex selects a named effort level. There
|
|
147
|
+
* is no faithful numeric mapping between them, so the source is recorded and each
|
|
148
|
+
* codec decides how to honour the other's form rather than a lossy conversion
|
|
149
|
+
* happening once, invisibly, in the middle.
|
|
150
|
+
*/
|
|
151
|
+
export type ProxyIRReasoning = {
|
|
152
|
+
source: "none";
|
|
153
|
+
} | {
|
|
154
|
+
source: "anthropic_thinking";
|
|
155
|
+
type: string;
|
|
156
|
+
budgetTokens?: number;
|
|
157
|
+
} | {
|
|
158
|
+
source: "codex_effort";
|
|
159
|
+
effort: CodexReasoningEffort;
|
|
160
|
+
};
|
|
161
|
+
export type ProxyIRRequest = {
|
|
162
|
+
sourceFormat: ProxyIRWireFormat;
|
|
163
|
+
sourceModel: string;
|
|
164
|
+
originSessionId?: string;
|
|
165
|
+
originThreadId?: string;
|
|
166
|
+
messages: ProxyIRMessage[];
|
|
167
|
+
tools: ProxyIRToolDeclaration[];
|
|
168
|
+
toolChoice?: ProxyIRToolChoice;
|
|
169
|
+
reasoning: ProxyIRReasoning;
|
|
170
|
+
stream: boolean;
|
|
171
|
+
/** Prefix-derived routing hint. Never serialized onto any wire. */
|
|
172
|
+
promptCachePrefixKey?: string;
|
|
173
|
+
};
|
|
174
|
+
export type ProxyIRRequestTargetOptions = {
|
|
175
|
+
model: string;
|
|
176
|
+
reasoningEffort?: CodexReasoningEffort;
|
|
177
|
+
};
|
|
178
|
+
export type ProxyIRProviderError = {
|
|
179
|
+
code: string;
|
|
180
|
+
httpStatus?: number;
|
|
181
|
+
retryable?: boolean;
|
|
182
|
+
message?: string;
|
|
183
|
+
};
|
|
184
|
+
/**
|
|
185
|
+
* How a response ended.
|
|
186
|
+
*
|
|
187
|
+
* `finishReason: "other"` carries `rawFinishReason` because Anthropic's
|
|
188
|
+
* `stop_reason` is typed `string | null` on the wire, deliberately open. A closed
|
|
189
|
+
* union here would make any legitimate but unmodelled stop reason an
|
|
190
|
+
* exhaustiveness throw at runtime, turning a successful upstream response into a
|
|
191
|
+
* proxy failure.
|
|
192
|
+
*/
|
|
193
|
+
export type ProxyIRTerminalOutcome = {
|
|
194
|
+
status: "completed";
|
|
195
|
+
finishReason: "end_turn" | "tool_use" | "max_tokens" | "stop_sequence";
|
|
196
|
+
} | {
|
|
197
|
+
status: "completed";
|
|
198
|
+
finishReason: "other";
|
|
199
|
+
rawFinishReason: string;
|
|
200
|
+
} | {
|
|
201
|
+
status: "failed";
|
|
202
|
+
error: ProxyIRProviderError;
|
|
203
|
+
} | {
|
|
204
|
+
status: "incomplete";
|
|
205
|
+
reason: string;
|
|
206
|
+
};
|
|
207
|
+
export type ProxyIRResponseEvent = {
|
|
208
|
+
kind: "text_delta";
|
|
209
|
+
text: string;
|
|
210
|
+
} | {
|
|
211
|
+
kind: "thinking_delta";
|
|
212
|
+
text: string;
|
|
213
|
+
} | {
|
|
214
|
+
kind: "tool_call_start";
|
|
215
|
+
callId: string;
|
|
216
|
+
toolName: string;
|
|
217
|
+
} | {
|
|
218
|
+
kind: "tool_call_arguments_delta";
|
|
219
|
+
callId: string;
|
|
220
|
+
partialArguments: string;
|
|
221
|
+
} | {
|
|
222
|
+
kind: "tool_call_done";
|
|
223
|
+
callId: string;
|
|
224
|
+
} | {
|
|
225
|
+
kind: "item_done";
|
|
226
|
+
} | {
|
|
227
|
+
kind: "usage";
|
|
228
|
+
usage: UsageContext;
|
|
229
|
+
} | {
|
|
230
|
+
kind: "terminal";
|
|
231
|
+
outcome: ProxyIRTerminalOutcome;
|
|
232
|
+
};
|
|
233
|
+
export type ProxyIROutputItem = {
|
|
234
|
+
kind: "text";
|
|
235
|
+
text: string;
|
|
236
|
+
} | {
|
|
237
|
+
kind: "thinking";
|
|
238
|
+
text: string;
|
|
239
|
+
} | {
|
|
240
|
+
kind: "tool_call";
|
|
241
|
+
callId: string;
|
|
242
|
+
toolName: string;
|
|
243
|
+
argumentsRaw: string;
|
|
244
|
+
argumentsJson?: Record<string, unknown>;
|
|
245
|
+
};
|
|
246
|
+
export type ProxyIRResponse = {
|
|
247
|
+
items: ProxyIROutputItem[];
|
|
248
|
+
usage?: UsageContext;
|
|
249
|
+
outcome: ProxyIRTerminalOutcome;
|
|
250
|
+
};
|
|
251
|
+
/**
|
|
252
|
+
* Codec capabilities, kept separate rather than bundled into one interface.
|
|
253
|
+
*
|
|
254
|
+
* No dialect needs all four in every direction: for outbound Codex fallback, the
|
|
255
|
+
* Codex side is only ever parsed from and rendered to, never dispatched to, so a
|
|
256
|
+
* single monolithic codec type would force stub implementations whose only
|
|
257
|
+
* possible body is a throw.
|
|
258
|
+
*/
|
|
259
|
+
export type ProxyIRRequestParser<TWireRequest> = {
|
|
260
|
+
format: ProxyIRWireFormat;
|
|
261
|
+
parseRequest(wire: TWireRequest): ProxyIRRequest;
|
|
262
|
+
};
|
|
263
|
+
export type ProxyIRRequestBuilder<TWireRequest> = {
|
|
264
|
+
format: ProxyIRWireFormat;
|
|
265
|
+
buildRequest(ir: ProxyIRRequest, target: ProxyIRRequestTargetOptions): TWireRequest;
|
|
266
|
+
};
|
|
267
|
+
export type ProxyIRResponseParser = {
|
|
268
|
+
format: ProxyIRWireFormat;
|
|
269
|
+
parseBufferedResponse(wireText: string): ProxyIRResponse;
|
|
270
|
+
parseResponseStream(upstream: Response): AsyncGenerator<ProxyIRResponseEvent, ProxyIRResponse>;
|
|
271
|
+
};
|
|
272
|
+
export type ProxyIRResponseRenderer = {
|
|
273
|
+
format: ProxyIRWireFormat;
|
|
274
|
+
renderResponseEvent(event: ProxyIRResponseEvent): string[];
|
|
275
|
+
renderTerminalOutcome(outcome: ProxyIRTerminalOutcome, usage?: UsageContext): string[];
|
|
276
|
+
};
|
|
277
|
+
/** Marks a value a codec refused to map, for callers that collect rather than throw. */
|
|
278
|
+
export type ProxyIRUnmappableValue = {
|
|
279
|
+
proxyIRUnmappable: true;
|
|
280
|
+
sourceKind: string;
|
|
281
|
+
reason: string;
|
|
282
|
+
raw: unknown;
|
|
283
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire-neutral intermediate representation for proxy protocol translation.
|
|
3
|
+
*
|
|
4
|
+
* Translation between provider wire formats was previously pairwise and ad hoc:
|
|
5
|
+
* `codexFallback.ts` converts an Anthropic request into a Codex one and casts a
|
|
6
|
+
* role to reach Claude Code's inline-system convention inside a converter that is
|
|
7
|
+
* meant to be neutral. Adding the reverse direction pairwise would double that,
|
|
8
|
+
* and a third provider would square it.
|
|
9
|
+
*
|
|
10
|
+
* So each format gets a codec to and from this IR, and adding a provider is a new
|
|
11
|
+
* codec rather than new branching. The IR is deliberately not `ClaudeRequest`:
|
|
12
|
+
* that type is simultaneously the literal Anthropic wire shape, so using it as
|
|
13
|
+
* the hub makes every other provider's quirks leak into the Anthropic hot path.
|
|
14
|
+
* `ClaudeRequest` and `ClaudeResponse` stay untouched.
|
|
15
|
+
*
|
|
16
|
+
* Every union here is discriminated on a literal `kind`, `status` or `source`, so
|
|
17
|
+
* `assertProxyIRExhaustive` turns an unhandled variant into a compile error. That
|
|
18
|
+
* is the point of the IR: a field that cannot be represented must be stated, via
|
|
19
|
+
* `ProxyIRUnmappedPart`, rather than dropped silently.
|
|
20
|
+
*/
|
|
21
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.35.0",
|
|
4
4
|
"packageManager": "pnpm@10.15.1",
|
|
5
5
|
"description": "The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002/call) for routing, tool selection and context budgeting. MCP-native (4 transports), voice TTS/STT/realtime, RAG, agents, memory, compaction, 9 observability exporters. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · TypeSafe Jev and more.",
|
|
6
6
|
"author": {
|