@neutrome/open-ai-router 0.6.0 → 0.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neutrome/open-ai-router",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./src/index.ts"
@@ -11,8 +11,8 @@
11
11
  "hono": "^4.12.18",
12
12
  "posthog-node": "^5.41.0",
13
13
  "zod": "^4.2.1",
14
- "@neutrome/lil-engine": "0.4.0",
15
- "@neutrome/lilsdk": "0.4.0"
14
+ "@neutrome/lil-engine": "0.4.1",
15
+ "@neutrome/lilsdk": "0.4.1"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@types/node": "^25.9.3",
@@ -55,7 +55,11 @@ import type {
55
55
  import type { RequestContext } from "../upstream-auth/types.ts";
56
56
  import { isSse } from "../util/headers.ts";
57
57
  import { eventDataLines, splitSseEvents } from "../util/sse.ts";
58
- import { resolveInvocationTarget, type ResolvedTarget } from "./resolve.ts";
58
+ import {
59
+ resolveInvocationTarget,
60
+ resolveNestedInvocationTarget,
61
+ type ResolvedTarget,
62
+ } from "./resolve.ts";
59
63
  import type { RemoteMcpClientFactory } from "./mcp.ts";
60
64
  import type { ProviderRuntime, RouterRuntime } from "./runtime.ts";
61
65
  import { observeTimedExecution } from "./execution-events.ts";
@@ -113,7 +117,11 @@ export function createRouterExecutionRuntime(
113
117
  ): ExecutionRuntime {
114
118
  const runtimeOptions: ExecutionRuntimeOptions = {
115
119
  signal: ctx.request.signal,
116
- resolveTarget(request: Program) {
120
+ resolveTarget(request: Program, invokeOptions) {
121
+ if (invokeOptions?.parentExecutionId) {
122
+ const model = getModel(request);
123
+ if (model) return resolveNestedInvocationTarget(runtime, model).target;
124
+ }
117
125
  return resolveRequestTarget(runtime, request).target;
118
126
  },
119
127
  providerInvoker: createFetchProviderInvoker(
@@ -4,6 +4,7 @@ import {
4
4
  listConfiguredModels,
5
5
  resolveInvocationTarget,
6
6
  resolveInvocationTargets,
7
+ resolveNestedInvocationTarget,
7
8
  } from "./resolve.ts";
8
9
 
9
10
  describe("router resolution", () => {
@@ -72,6 +73,33 @@ describe("router resolution", () => {
72
73
  });
73
74
  });
74
75
 
76
+ it("allows nested executors to invoke unexported providers", () => {
77
+ const runtime = createRouterRuntime({
78
+ config: {
79
+ providers: {
80
+ emma: {
81
+ apiBaseUrl: "https://api.example.test/v1",
82
+ style: "chat-completions",
83
+ exports: [],
84
+ },
85
+ },
86
+ modelNamespaces: {},
87
+ },
88
+ });
89
+
90
+ expect(() =>
91
+ resolveInvocationTarget(runtime, "emma/openai/gpt-oss-120b"),
92
+ ).toThrow("does not exist");
93
+ expect(
94
+ resolveNestedInvocationTarget(runtime, "emma/openai/gpt-oss-120b").target,
95
+ ).toEqual({
96
+ kind: "provider",
97
+ provider: "emma",
98
+ model: "openai/gpt-oss-120b",
99
+ transforms: [],
100
+ });
101
+ });
102
+
75
103
  it("requires configured suffixes", () => {
76
104
  const runtime = createRouterRuntime({
77
105
  config: {
@@ -27,6 +27,41 @@ export function resolveInvocationTarget(
27
27
  return candidates[0]!;
28
28
  }
29
29
 
30
+ export function resolveNestedInvocationTarget(
31
+ runtime: RouterRuntime,
32
+ requestedModel: string,
33
+ ): ResolvedTarget {
34
+ const resolved = resolveInvocationTargets(runtime, requestedModel);
35
+ if (resolved.length > 0) return resolved[0]!;
36
+
37
+ const parsed = parseModelSyntax(requestedModel, runtime.modelSuffixes);
38
+ const qualified = splitQualified(parsed.baseModel);
39
+ if (!qualified) {
40
+ throw new Error(
41
+ `The model \`${requestedModel}\` does not exist or you do not have access to it.`,
42
+ );
43
+ }
44
+ const provider = runtime.providers.get(qualified.namespace);
45
+ if (!provider || runtime.modelNamespaces.has(qualified.namespace)) {
46
+ throw new Error(
47
+ `The model \`${requestedModel}\` does not exist or you do not have access to it.`,
48
+ );
49
+ }
50
+ return {
51
+ requestedModel,
52
+ namespace: qualified.namespace,
53
+ source: "provider",
54
+ suffixes: parsed.suffixes,
55
+ mcps: [],
56
+ target: {
57
+ kind: "provider",
58
+ provider: qualified.namespace,
59
+ model: qualified.model,
60
+ transforms: parsed.suffixes.map((suffix) => suffix.raw),
61
+ },
62
+ };
63
+ }
64
+
30
65
  export function resolveInvocationTargets(
31
66
  runtime: RouterRuntime,
32
67
  requestedModel: string,