theokit 0.48.13 → 0.48.14

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 (105) hide show
  1. package/dist/{actions-virtual-module-YQXRSSMW.js → actions-virtual-module-E4PISKMB.js} +3 -3
  2. package/dist/{actions-virtual-module-LB4NGONI.js → actions-virtual-module-YZRZMHAX.js} +3 -3
  3. package/dist/{agent-7JJW3TPB.js → agent-XAQCUQNB.js} +3 -3
  4. package/dist/{app-typed-client-GHO3EWZK.js → app-typed-client-HLP26EYM.js} +3 -3
  5. package/dist/{app-typed-client-G3J5G7E5.js → app-typed-client-I4X2UJWW.js} +3 -3
  6. package/dist/{aws-lambda-CYNDGU5O.js → aws-lambda-KES4MFJV.js} +3 -3
  7. package/dist/{build-WU6AKKIB.js → build-F2Q5QTSC.js} +6 -6
  8. package/dist/{bun-33RD6K7O.js → bun-A5B2MJMO.js} +3 -3
  9. package/dist/{chunk-S433N3CT.js → chunk-AATSV4UV.js} +2 -2
  10. package/dist/{chunk-6E5WKMDS.js → chunk-AXKUA57G.js} +31 -4
  11. package/dist/chunk-AXKUA57G.js.map +1 -0
  12. package/dist/{chunk-E576KYYT.js → chunk-BHOTGS7N.js} +2 -2
  13. package/dist/{chunk-GVW5EKEU.js → chunk-CMYSHZFT.js} +2 -2
  14. package/dist/{chunk-6GGWS7J3.js → chunk-DQIPV7L5.js} +29 -2
  15. package/dist/chunk-DQIPV7L5.js.map +1 -0
  16. package/dist/{chunk-PXFXSFJL.js → chunk-DS5MCU2X.js} +5 -5
  17. package/dist/{chunk-GXEX4CBH.js → chunk-FTFN4MYN.js} +98 -32
  18. package/dist/chunk-FTFN4MYN.js.map +1 -0
  19. package/dist/{chunk-OJLL4YD6.js → chunk-KTKTHIUF.js} +5 -3
  20. package/dist/chunk-KTKTHIUF.js.map +1 -0
  21. package/dist/{chunk-GRI4XHBJ.js → chunk-NTWNO24W.js} +6 -4
  22. package/dist/{chunk-GRI4XHBJ.js.map → chunk-NTWNO24W.js.map} +1 -1
  23. package/dist/{chunk-YRBR424R.js → chunk-OOBYPCZC.js} +99 -35
  24. package/dist/chunk-OOBYPCZC.js.map +1 -0
  25. package/dist/{chunk-7VPQHEAJ.js → chunk-WSXNGF7X.js} +1 -1
  26. package/dist/{chunk-7VPQHEAJ.js.map → chunk-WSXNGF7X.js.map} +1 -1
  27. package/dist/{chunk-BIVCP6X5.js → chunk-WYHYOYRH.js} +6 -4
  28. package/dist/{chunk-BIVCP6X5.js.map → chunk-WYHYOYRH.js.map} +1 -1
  29. package/dist/{chunk-J5MXCGKA.js → chunk-YXG2SGQ3.js} +1 -1
  30. package/dist/{chunk-J5MXCGKA.js.map → chunk-YXG2SGQ3.js.map} +1 -1
  31. package/dist/cli/index.js +8 -8
  32. package/dist/{cloudflare-KYUWCEPL.js → cloudflare-IN2WB7FZ.js} +3 -3
  33. package/dist/{deno-deploy-CCTB7HGS.js → deno-deploy-LYXQEJ6A.js} +3 -3
  34. package/dist/{dev-MUWJAZRD.js → dev-CDFPXISP.js} +8 -8
  35. package/dist/{index-BEtEv6ZH.d.ts → index-D_PxPXgQ.d.ts} +2 -2
  36. package/dist/index.js +3 -3
  37. package/dist/{info-XW7HGUPH.js → info-QXZW722N.js} +4 -4
  38. package/dist/{internal-api-V5L65YSJ.js → internal-api-FBK2YXSI.js} +3 -3
  39. package/dist/{internal-api-WEOSTMSN.js → internal-api-ZCJWJ5EC.js} +3 -3
  40. package/dist/{load-config-VKD6LKWU.js → load-config-FIWNKOJO.js} +4 -4
  41. package/dist/{mcp-ULUFJNSZ.js → mcp-KTYP4ZON.js} +4 -4
  42. package/dist/{netlify-AFMDNKT4.js → netlify-DLEOCFAD.js} +3 -3
  43. package/dist/node-QXYSUWQ4.js +10 -0
  44. package/dist/{openapi-HZXR335W.js → openapi-OUXNB2F2.js} +4 -4
  45. package/dist/{plugin-runner-BFEcgtmJ.d.ts → plugin-runner-DHVr1cC5.d.ts} +1 -1
  46. package/dist/{plugin-types-D69-lJZ9.d.ts → plugin-types-4VN1GMqV.d.ts} +12 -0
  47. package/dist/registry-S7OMF3OS.js +23 -0
  48. package/dist/{routes-OLNQX7CT.js → routes-NJR4ISCT.js} +4 -4
  49. package/dist/{schema-ZO3OSWVG.js → schema-DNIT7JQX.js} +3 -3
  50. package/dist/server/agent/index.d.ts +20 -5
  51. package/dist/server/agent/index.js +1 -1
  52. package/dist/server/define/index.d.ts +9 -1
  53. package/dist/server/define/index.js +1 -1
  54. package/dist/server/http/index.d.ts +3 -3
  55. package/dist/server/index.d.ts +4 -4
  56. package/dist/server/index.js +2 -2
  57. package/dist/server/plugins/index.d.ts +3 -3
  58. package/dist/{services-typed-client-PSAGRPFF.js → services-typed-client-P4JERLBL.js} +2 -2
  59. package/dist/{start-KR2JJR7K.js → start-25OV2CAK.js} +198 -29
  60. package/dist/start-25OV2CAK.js.map +1 -0
  61. package/dist/{static-M2W4HUWS.js → static-RTO637XW.js} +3 -3
  62. package/dist/{theo-cloud-XAHWOUFK.js → theo-cloud-UZ3GINRU.js} +2 -2
  63. package/dist/{vercel-SRS2DH6O.js → vercel-6D6EZUVD.js} +3 -3
  64. package/dist/vite-plugin/index.js +3 -3
  65. package/dist/{vite-plugin-VPJFD4HK.js → vite-plugin-RJFKLF2U.js} +8 -8
  66. package/package.json +3 -3
  67. package/dist/chunk-6E5WKMDS.js.map +0 -1
  68. package/dist/chunk-6GGWS7J3.js.map +0 -1
  69. package/dist/chunk-GXEX4CBH.js.map +0 -1
  70. package/dist/chunk-OJLL4YD6.js.map +0 -1
  71. package/dist/chunk-YRBR424R.js.map +0 -1
  72. package/dist/node-ZJQEJSP3.js +0 -10
  73. package/dist/registry-GKR3EWRW.js +0 -23
  74. package/dist/start-KR2JJR7K.js.map +0 -1
  75. /package/dist/{actions-virtual-module-YQXRSSMW.js.map → actions-virtual-module-E4PISKMB.js.map} +0 -0
  76. /package/dist/{actions-virtual-module-LB4NGONI.js.map → actions-virtual-module-YZRZMHAX.js.map} +0 -0
  77. /package/dist/{agent-7JJW3TPB.js.map → agent-XAQCUQNB.js.map} +0 -0
  78. /package/dist/{app-typed-client-GHO3EWZK.js.map → app-typed-client-HLP26EYM.js.map} +0 -0
  79. /package/dist/{app-typed-client-G3J5G7E5.js.map → app-typed-client-I4X2UJWW.js.map} +0 -0
  80. /package/dist/{aws-lambda-CYNDGU5O.js.map → aws-lambda-KES4MFJV.js.map} +0 -0
  81. /package/dist/{build-WU6AKKIB.js.map → build-F2Q5QTSC.js.map} +0 -0
  82. /package/dist/{bun-33RD6K7O.js.map → bun-A5B2MJMO.js.map} +0 -0
  83. /package/dist/{chunk-S433N3CT.js.map → chunk-AATSV4UV.js.map} +0 -0
  84. /package/dist/{chunk-E576KYYT.js.map → chunk-BHOTGS7N.js.map} +0 -0
  85. /package/dist/{chunk-GVW5EKEU.js.map → chunk-CMYSHZFT.js.map} +0 -0
  86. /package/dist/{chunk-PXFXSFJL.js.map → chunk-DS5MCU2X.js.map} +0 -0
  87. /package/dist/{cloudflare-KYUWCEPL.js.map → cloudflare-IN2WB7FZ.js.map} +0 -0
  88. /package/dist/{deno-deploy-CCTB7HGS.js.map → deno-deploy-LYXQEJ6A.js.map} +0 -0
  89. /package/dist/{dev-MUWJAZRD.js.map → dev-CDFPXISP.js.map} +0 -0
  90. /package/dist/{info-XW7HGUPH.js.map → info-QXZW722N.js.map} +0 -0
  91. /package/dist/{internal-api-V5L65YSJ.js.map → internal-api-FBK2YXSI.js.map} +0 -0
  92. /package/dist/{internal-api-WEOSTMSN.js.map → internal-api-ZCJWJ5EC.js.map} +0 -0
  93. /package/dist/{load-config-VKD6LKWU.js.map → load-config-FIWNKOJO.js.map} +0 -0
  94. /package/dist/{mcp-ULUFJNSZ.js.map → mcp-KTYP4ZON.js.map} +0 -0
  95. /package/dist/{netlify-AFMDNKT4.js.map → netlify-DLEOCFAD.js.map} +0 -0
  96. /package/dist/{node-ZJQEJSP3.js.map → node-QXYSUWQ4.js.map} +0 -0
  97. /package/dist/{openapi-HZXR335W.js.map → openapi-OUXNB2F2.js.map} +0 -0
  98. /package/dist/{registry-GKR3EWRW.js.map → registry-S7OMF3OS.js.map} +0 -0
  99. /package/dist/{routes-OLNQX7CT.js.map → routes-NJR4ISCT.js.map} +0 -0
  100. /package/dist/{schema-ZO3OSWVG.js.map → schema-DNIT7JQX.js.map} +0 -0
  101. /package/dist/{services-typed-client-PSAGRPFF.js.map → services-typed-client-P4JERLBL.js.map} +0 -0
  102. /package/dist/{static-M2W4HUWS.js.map → static-RTO637XW.js.map} +0 -0
  103. /package/dist/{theo-cloud-XAHWOUFK.js.map → theo-cloud-UZ3GINRU.js.map} +0 -0
  104. /package/dist/{vercel-SRS2DH6O.js.map → vercel-6D6EZUVD.js.map} +0 -0
  105. /package/dist/{vite-plugin-VPJFD4HK.js.map → vite-plugin-RJFKLF2U.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- import "./chunk-OJLL4YD6.js";
1
+ import "./chunk-KTKTHIUF.js";
2
2
  import "./chunk-XALU5LCU.js";
3
3
  import "./chunk-47FFT43U.js";
4
4
  import "./chunk-NTDN54XO.js";
@@ -16,7 +16,7 @@ import "./chunk-OLGPYOLO.js";
16
16
  import "./chunk-AVQU5CQF.js";
17
17
  import "./chunk-ACKBVBUI.js";
18
18
  import "./chunk-IZ3TIL6K.js";
19
- import "./chunk-6E5WKMDS.js";
19
+ import "./chunk-AXKUA57G.js";
20
20
  import "./chunk-JA2ZAT5Q.js";
21
21
  import "./chunk-U267AOWS.js";
22
22
  import "./chunk-XTHN6JBX.js";
@@ -222,4 +222,4 @@ export const actions = manifest
222
222
  export {
223
223
  actionsVirtualModule
224
224
  };
225
- //# sourceMappingURL=actions-virtual-module-YQXRSSMW.js.map
225
+ //# sourceMappingURL=actions-virtual-module-E4PISKMB.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import "tsx/esm";
3
- import "./chunk-BIVCP6X5.js";
4
- import "./chunk-6GGWS7J3.js";
3
+ import "./chunk-WYHYOYRH.js";
4
+ import "./chunk-DQIPV7L5.js";
5
5
  import "./chunk-T5C46IIU.js";
6
6
  import "./chunk-ZB7D62OA.js";
7
7
  import "./chunk-LNVMHQ2Z.js";
@@ -212,4 +212,4 @@ export const actions = manifest
212
212
  export {
213
213
  actionsVirtualModule
214
214
  };
215
- //# sourceMappingURL=actions-virtual-module-LB4NGONI.js.map
215
+ //# sourceMappingURL=actions-virtual-module-YZRZMHAX.js.map
@@ -3,13 +3,13 @@ import "tsx/esm";
3
3
  import {
4
4
  agentCommand,
5
5
  createAgentSsrLoader
6
- } from "./chunk-PXFXSFJL.js";
6
+ } from "./chunk-DS5MCU2X.js";
7
7
  import "./chunk-HBU2GIMZ.js";
8
- import "./chunk-6GGWS7J3.js";
8
+ import "./chunk-DQIPV7L5.js";
9
9
  import "./chunk-LNVMHQ2Z.js";
10
10
  import "./chunk-A7JBF5FO.js";
11
11
  export {
12
12
  agentCommand,
13
13
  createAgentSsrLoader
14
14
  };
15
- //# sourceMappingURL=agent-7JJW3TPB.js.map
15
+ //# sourceMappingURL=agent-XAQCUQNB.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  scanControllerModules
3
- } from "./chunk-OJLL4YD6.js";
3
+ } from "./chunk-KTKTHIUF.js";
4
4
  import "./chunk-XALU5LCU.js";
5
5
  import "./chunk-47FFT43U.js";
6
6
  import "./chunk-NTDN54XO.js";
@@ -20,7 +20,7 @@ import "./chunk-OLGPYOLO.js";
20
20
  import "./chunk-AVQU5CQF.js";
21
21
  import "./chunk-ACKBVBUI.js";
22
22
  import "./chunk-IZ3TIL6K.js";
23
- import "./chunk-6E5WKMDS.js";
23
+ import "./chunk-AXKUA57G.js";
24
24
  import "./chunk-JA2ZAT5Q.js";
25
25
  import "./chunk-U267AOWS.js";
26
26
  import "./chunk-XTHN6JBX.js";
@@ -424,4 +424,4 @@ export {
424
424
  generateClientDts,
425
425
  shouldReemitForFile
426
426
  };
427
- //# sourceMappingURL=app-typed-client-GHO3EWZK.js.map
427
+ //# sourceMappingURL=app-typed-client-HLP26EYM.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import "tsx/esm";
3
- import "./chunk-BIVCP6X5.js";
4
- import "./chunk-6GGWS7J3.js";
3
+ import "./chunk-WYHYOYRH.js";
4
+ import "./chunk-DQIPV7L5.js";
5
5
  import {
6
6
  scanControllerModules
7
7
  } from "./chunk-T5C46IIU.js";
@@ -414,4 +414,4 @@ export {
414
414
  generateClientDts,
415
415
  shouldReemitForFile
416
416
  };
417
- //# sourceMappingURL=app-typed-client-G3J5G7E5.js.map
417
+ //# sourceMappingURL=app-typed-client-I4X2UJWW.js.map
@@ -2,11 +2,11 @@
2
2
  import "tsx/esm";
3
3
  import {
4
4
  nodeAdapter
5
- } from "./chunk-E576KYYT.js";
5
+ } from "./chunk-BHOTGS7N.js";
6
6
  import {
7
7
  assertServicesUnsupported,
8
8
  readManifest
9
- } from "./chunk-7VPQHEAJ.js";
9
+ } from "./chunk-WSXNGF7X.js";
10
10
 
11
11
  // src/adapters/aws-lambda.ts
12
12
  import { mkdirSync, writeFileSync } from "fs";
@@ -169,4 +169,4 @@ export {
169
169
  renderAwsLambdaEntry,
170
170
  responseToLambdaResultV2
171
171
  };
172
- //# sourceMappingURL=aws-lambda-CYNDGU5O.js.map
172
+ //# sourceMappingURL=aws-lambda-KES4MFJV.js.map
@@ -17,15 +17,15 @@ import {
17
17
  import {
18
18
  importUserModule,
19
19
  loadConfig
20
- } from "./chunk-S433N3CT.js";
20
+ } from "./chunk-AATSV4UV.js";
21
21
  import {
22
22
  loadEnv
23
23
  } from "./chunk-HBU2GIMZ.js";
24
- import "./chunk-GVW5EKEU.js";
24
+ import "./chunk-CMYSHZFT.js";
25
25
  import {
26
26
  buildManifest,
27
27
  writeManifest
28
- } from "./chunk-7VPQHEAJ.js";
28
+ } from "./chunk-WSXNGF7X.js";
29
29
  import "./chunk-T5C46IIU.js";
30
30
  import {
31
31
  generateManifest,
@@ -543,7 +543,7 @@ async function buildCommand(options) {
543
543
  `);
544
544
  }
545
545
  async function runAdapterBuild(target, config, cwd) {
546
- const { theoPluginAsync } = await import("./vite-plugin-VPJFD4HK.js");
546
+ const { theoPluginAsync } = await import("./vite-plugin-RJFKLF2U.js");
547
547
  const { default: react } = await import("@vitejs/plugin-react");
548
548
  const ctx = {
549
549
  // `react()` may return Plugin or Plugin[] depending on version; spread the
@@ -561,7 +561,7 @@ async function runAdapterBuild(target, config, cwd) {
561
561
  })
562
562
  ].flat()
563
563
  };
564
- const { resolveAdapter } = await import("./registry-GKR3EWRW.js");
564
+ const { resolveAdapter } = await import("./registry-S7OMF3OS.js");
565
565
  const adapter = await resolveAdapter(target);
566
566
  await adapter.build(config, cwd, ctx);
567
567
  }
@@ -629,4 +629,4 @@ function relativize3(absPath, root) {
629
629
  export {
630
630
  buildCommand
631
631
  };
632
- //# sourceMappingURL=build-WU6AKKIB.js.map
632
+ //# sourceMappingURL=build-F2Q5QTSC.js.map
@@ -2,11 +2,11 @@
2
2
  import "tsx/esm";
3
3
  import {
4
4
  nodeAdapter
5
- } from "./chunk-E576KYYT.js";
5
+ } from "./chunk-BHOTGS7N.js";
6
6
  import {
7
7
  assertServicesUnsupported,
8
8
  readManifest
9
- } from "./chunk-7VPQHEAJ.js";
9
+ } from "./chunk-WSXNGF7X.js";
10
10
 
11
11
  // src/adapters/bun.ts
12
12
  import { mkdirSync, writeFileSync } from "fs";
@@ -136,4 +136,4 @@ export {
136
136
  bunAdapter,
137
137
  renderBunEntry
138
138
  };
139
- //# sourceMappingURL=bun-33RD6K7O.js.map
139
+ //# sourceMappingURL=bun-A5B2MJMO.js.map
@@ -5,7 +5,7 @@ import {
5
5
  } from "./chunk-HBU2GIMZ.js";
6
6
  import {
7
7
  theoConfigSchema
8
- } from "./chunk-GVW5EKEU.js";
8
+ } from "./chunk-CMYSHZFT.js";
9
9
 
10
10
  // src/config/load-config.ts
11
11
  import { existsSync } from "fs";
@@ -140,4 +140,4 @@ export {
140
140
  deepMerge,
141
141
  loadConfig
142
142
  };
143
- //# sourceMappingURL=chunk-S433N3CT.js.map
143
+ //# sourceMappingURL=chunk-AATSV4UV.js.map
@@ -20,6 +20,7 @@ var DEFAULT_REGISTRY = [
20
20
  }
21
21
  ];
22
22
  var registry = [...DEFAULT_REGISTRY];
23
+ var announced = /* @__PURE__ */ new Set();
23
24
  function registerProvider(descriptor) {
24
25
  const idx = registry.findIndex((p) => p.name === descriptor.name);
25
26
  if (idx >= 0) registry[idx] = descriptor;
@@ -32,11 +33,37 @@ function resetProviderRegistry() {
32
33
  function listProviders() {
33
34
  return [...registry].sort((a, b) => a.priority - b.priority);
34
35
  }
35
- function resolveProvider() {
36
+ function announce(desc, how, options) {
37
+ if (announced.has(desc.name)) return;
38
+ announced.add(desc.name);
39
+ const line = `[theokit] provider=${desc.name} (${how}) source=${desc.envKey} baseUrl=${desc.baseUrl}`;
40
+ if (options?.announce) options.announce(line);
41
+ else console.warn(line);
42
+ }
43
+ function providerOf(modelId, registered) {
44
+ if (modelId === void 0) return void 0;
45
+ const slash = modelId.indexOf("/");
46
+ if (slash <= 0) return void 0;
47
+ const prefix = modelId.slice(0, slash);
48
+ return registered.find((p) => p.name === prefix);
49
+ }
50
+ function resolveProvider(modelId, options) {
36
51
  const sorted = [...registry].sort((a, b) => a.priority - b.priority);
52
+ const declared = modelId === void 0 ? void 0 : providerOf(modelId, sorted);
53
+ if (declared !== void 0 && modelId !== void 0) {
54
+ const apiKey = process.env[declared.envKey];
55
+ if (apiKey && apiKey.length > 0) {
56
+ announce(declared, "declared by the model", options);
57
+ return { name: declared.name, apiKey, baseUrl: declared.baseUrl };
58
+ }
59
+ throw new Error(
60
+ `Model "${modelId}" declares provider "${declared.name}", but ${declared.envKey} is not set. Set ${declared.envKey}, or change the model's provider prefix.`
61
+ );
62
+ }
37
63
  for (const desc of sorted) {
38
64
  const apiKey = process.env[desc.envKey];
39
65
  if (apiKey && apiKey.length > 0) {
66
+ announce(desc, "by env priority", options);
40
67
  return {
41
68
  name: desc.name,
42
69
  apiKey,
@@ -49,9 +76,9 @@ function resolveProvider() {
49
76
  `No LLM provider API key found in environment. Set one of: ${envKeys}. Get a free OpenRouter key at https://openrouter.ai/keys (recommended \u2014 one key, many models).`
50
77
  );
51
78
  }
52
- function tryResolveProvider() {
79
+ function tryResolveProvider(modelId) {
53
80
  try {
54
- return resolveProvider();
81
+ return resolveProvider(modelId);
55
82
  } catch {
56
83
  return null;
57
84
  }
@@ -64,4 +91,4 @@ export {
64
91
  resolveProvider,
65
92
  tryResolveProvider
66
93
  };
67
- //# sourceMappingURL=chunk-6E5WKMDS.js.map
94
+ //# sourceMappingURL=chunk-AXKUA57G.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server/agent/provider-resolver.ts"],"mappings":";AAgEA,IAAM,mBAAyC;AAAA,EAC7C;AAAA,IACE,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,EACZ;AACF;AAMA,IAAM,WAAiC,CAAC,GAAG,gBAAgB;AAU3D,IAAM,YAAY,oBAAI,IAAY;AA2B3B,SAAS,iBAAiB,YAAsC;AAErE,QAAM,MAAM,SAAS,UAAU,CAAC,MAAM,EAAE,SAAS,WAAW,IAAI;AAChE,MAAI,OAAO,EAAG,UAAS,GAAG,IAAI;AAAA,MACzB,UAAS,KAAK,UAAU;AAC/B;AAOO,SAAS,wBAA8B;AAC5C,WAAS,SAAS;AAClB,WAAS,KAAK,GAAG,gBAAgB;AACnC;AAOO,SAAS,gBAA+C;AAC7D,SAAO,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AAC7D;AASA,SAAS,SACP,MACA,KACA,SACM;AACN,MAAI,UAAU,IAAI,KAAK,IAAI,EAAG;AAC9B,YAAU,IAAI,KAAK,IAAI;AACvB,QAAM,OAAO,sBAAsB,KAAK,IAAI,KAAK,GAAG,YAAY,KAAK,MAAM,YAAY,KAAK,OAAO;AACnG,MAAI,SAAS,SAAU,SAAQ,SAAS,IAAI;AAAA,MAIvC,SAAQ,KAAK,IAAI;AACxB;AAaA,SAAS,WACP,SACA,YACgC;AAChC,MAAI,YAAY,OAAW,QAAO;AAClC,QAAM,QAAQ,QAAQ,QAAQ,GAAG;AACjC,MAAI,SAAS,EAAG,QAAO;AACvB,QAAM,SAAS,QAAQ,MAAM,GAAG,KAAK;AACrC,SAAO,WAAW,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AACjD;AAaO,SAAS,gBAAgB,SAAkB,SAA4C;AAC5F,QAAM,SAAS,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AAEnE,QAAM,WAAW,YAAY,SAAY,SAAY,WAAW,SAAS,MAAM;AAC/E,MAAI,aAAa,UAAa,YAAY,QAAW;AACnD,UAAM,SAAS,QAAQ,IAAI,SAAS,MAAM;AAC1C,QAAI,UAAU,OAAO,SAAS,GAAG;AAC/B,eAAS,UAAU,yBAAyB,OAAO;AACnD,aAAO,EAAE,MAAM,SAAS,MAAM,QAAQ,SAAS,SAAS,QAAQ;AAAA,IAClE;AAIA,UAAM,IAAI;AAAA,MACR,UAAU,OAAO,wBAAwB,SAAS,IAAI,UAAU,SAAS,MAAM,oBACtE,SAAS,MAAM;AAAA,IAC1B;AAAA,EACF;AAEA,aAAW,QAAQ,QAAQ;AACzB,UAAM,SAAS,QAAQ,IAAI,KAAK,MAAM;AACtC,QAAI,UAAU,OAAO,SAAS,GAAG;AAC/B,eAAS,MAAM,mBAAmB,OAAO;AACzC,aAAO;AAAA,QACL,MAAM,KAAK;AAAA,QACX;AAAA,QACA,SAAS,KAAK;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,MAAM;AACvD,QAAM,IAAI;AAAA,IACR,6DAA6D,OAAO;AAAA,EAEtE;AACF;AAQO,SAAS,mBAAmB,SAA2C;AAC5E,MAAI;AACF,WAAO,gBAAgB,OAAO;AAAA,EAChC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
@@ -4,7 +4,7 @@ import {
4
4
  generateCaddyfile,
5
5
  generateComposeYaml,
6
6
  readManifest
7
- } from "./chunk-7VPQHEAJ.js";
7
+ } from "./chunk-WSXNGF7X.js";
8
8
 
9
9
  // src/adapters/node.ts
10
10
  import { writeFileSync } from "fs";
@@ -62,4 +62,4 @@ var nodeAdapter = {
62
62
  export {
63
63
  nodeAdapter
64
64
  };
65
- //# sourceMappingURL=chunk-E576KYYT.js.map
65
+ //# sourceMappingURL=chunk-BHOTGS7N.js.map
@@ -2,7 +2,7 @@
2
2
  import "tsx/esm";
3
3
  import {
4
4
  servicesConfigSchema
5
- } from "./chunk-7VPQHEAJ.js";
5
+ } from "./chunk-WSXNGF7X.js";
6
6
 
7
7
  // src/config/schema.ts
8
8
  import { z as z8 } from "zod";
@@ -419,4 +419,4 @@ export {
419
419
  storageSchema,
420
420
  theoConfigSchema
421
421
  };
422
- //# sourceMappingURL=chunk-GVW5EKEU.js.map
422
+ //# sourceMappingURL=chunk-CMYSHZFT.js.map
@@ -23,11 +23,38 @@ var DEFAULT_REGISTRY = [
23
23
  }
24
24
  ];
25
25
  var registry = [...DEFAULT_REGISTRY];
26
- function resolveProvider() {
26
+ var announced = /* @__PURE__ */ new Set();
27
+ function announce(desc, how, options) {
28
+ if (announced.has(desc.name)) return;
29
+ announced.add(desc.name);
30
+ const line = `[theokit] provider=${desc.name} (${how}) source=${desc.envKey} baseUrl=${desc.baseUrl}`;
31
+ if (options?.announce) options.announce(line);
32
+ else console.warn(line);
33
+ }
34
+ function providerOf(modelId, registered) {
35
+ if (modelId === void 0) return void 0;
36
+ const slash = modelId.indexOf("/");
37
+ if (slash <= 0) return void 0;
38
+ const prefix = modelId.slice(0, slash);
39
+ return registered.find((p) => p.name === prefix);
40
+ }
41
+ function resolveProvider(modelId, options) {
27
42
  const sorted = [...registry].sort((a, b) => a.priority - b.priority);
43
+ const declared = modelId === void 0 ? void 0 : providerOf(modelId, sorted);
44
+ if (declared !== void 0 && modelId !== void 0) {
45
+ const apiKey = process.env[declared.envKey];
46
+ if (apiKey && apiKey.length > 0) {
47
+ announce(declared, "declared by the model", options);
48
+ return { name: declared.name, apiKey, baseUrl: declared.baseUrl };
49
+ }
50
+ throw new Error(
51
+ `Model "${modelId}" declares provider "${declared.name}", but ${declared.envKey} is not set. Set ${declared.envKey}, or change the model's provider prefix.`
52
+ );
53
+ }
28
54
  for (const desc of sorted) {
29
55
  const apiKey = process.env[desc.envKey];
30
56
  if (apiKey && apiKey.length > 0) {
57
+ announce(desc, "by env priority", options);
31
58
  return {
32
59
  name: desc.name,
33
60
  apiKey,
@@ -88,4 +115,4 @@ export {
88
115
  getApprovalRegistry,
89
116
  resolveProvider
90
117
  };
91
- //# sourceMappingURL=chunk-6GGWS7J3.js.map
118
+ //# sourceMappingURL=chunk-DQIPV7L5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server/agent/provider-resolver.ts","../src/server/agent/approval-registry.ts"],"sourcesContent":["/**\n * Provider Resolver — Strategy + Registry pattern (FAANG-grade).\n *\n * Inspiration: Dapr Conversation Registry (`dapr/pkg/components/conversation/registry.go`)\n * + Encore Manager provider array (`encore/runtimes/go/pubsub/manager_internal.go`).\n *\n * Principle: provider routing is the FRAMEWORK's responsibility, not the consumer's — but the\n * consumer still gets to SAY which provider it wants, and it says so in the model id.\n *\n * `provider/model` is the convention every agent in this ecosystem already writes\n * (`anthropic/claude-sonnet-4-6`, `openrouter/anthropic/claude-haiku-4.5`), and it is the one the\n * SDK routes on. Until theokit#326 this resolver ignored it entirely and picked by env-var\n * priority, so an agent that declared `anthropic/...` was handed an OpenRouter key whenever one\n * happened to be present — and every turn failed with `auth_failed (HTTP 401)` against a provider\n * nobody asked for. The declared provider now wins; priority is the fallback for a bare model id.\n *\n * Wire protocol: OpenAI Chat Completions (universal — implemented by every\n * os providers: OpenRouter, Groq, Mistral, Together, Anthropic via proxy, etc).\n *\n * Resolution by priority (FIRST match wins):\n * 1. OPENROUTER_API_KEY → baseUrl=openrouter.ai (multi-model gateway)\n * 2. OPENAI_API_KEY → baseUrl=api.openai.com\n * 3. ANTHROPIC_API_KEY → direct Anthropic (Messages API, not OpenAI-compat)\n *\n * Escape hatch: an explicit `options.apiKey` OVERRIDES auto-resolution\n * (the consumer can force a specific provider if it wants to).\n */\n\n/**\n * Provider configuration descriptor — Registry entry shape.\n *\n * @public\n */\nexport interface ProviderDescriptor {\n /** Stable name used internally — not exposed on the wire. */\n name: string\n /** Environment variable that holds the API key for this provider. */\n envKey: string\n /** Base URL for the provider's OpenAI-compatible (or native) API. */\n baseUrl: string\n /** Resolution priority (lower = higher priority). FIRST match wins. */\n priority: number\n}\n\n/**\n * Resolved provider configuration — output of `resolveProvider()`.\n *\n * @public\n */\nexport interface ResolvedProvider {\n name: string\n apiKey: string\n baseUrl: string\n}\n\n/**\n * Default provider registry. Order = priority (first = highest).\n *\n * Adding a new provider:\n * 1. Append entry below (or register via `registerProvider()`).\n * 2. Set `envKey` matching the user's env var convention.\n * 3. Set `baseUrl` to the OpenAI-compat endpoint (or native if not compat).\n * 4. Provider name used in telemetry/logs only — never wire-exposed.\n */\nconst DEFAULT_REGISTRY: ProviderDescriptor[] = [\n {\n name: 'openrouter',\n envKey: 'OPENROUTER_API_KEY',\n baseUrl: 'https://openrouter.ai/api/v1',\n priority: 1,\n },\n {\n name: 'openai',\n envKey: 'OPENAI_API_KEY',\n baseUrl: 'https://api.openai.com/v1',\n priority: 2,\n },\n {\n name: 'anthropic',\n envKey: 'ANTHROPIC_API_KEY',\n baseUrl: 'https://api.anthropic.com',\n priority: 3,\n },\n]\n\n/**\n * Runtime registry — copy of DEFAULT_REGISTRY mutable via registerProvider().\n * Sorted by priority on every resolve (stable, O(n log n) — n <= ~10 providers).\n */\nconst registry: ProviderDescriptor[] = [...DEFAULT_REGISTRY]\n\n/**\n * Providers already announced, so a boot line does not become a per-request line.\n *\n * theokit#326 — resolution was silent on success. `resolveProvider` returns `{ name, apiKey,\n * baseUrl }` and every call site consumes only the key, so an operator could only learn which\n * provider was selected from an error message: exactly when it has already failed, and never in\n * the case that hurts most — a stale key that resolves cleanly and 401s at the provider.\n */\nconst announced = new Set<string>()\n\n/** Test-only reset, so announcement state does not leak between cases. @public */\nexport function resetProviderAnnouncements(): void {\n announced.clear()\n}\n\n/** Where the announcement goes, and what it may contain. @public */\nexport interface ResolveOptions {\n /** Receives one line per provider, at most once. NEVER receives the key. */\n announce?: (line: string) => void\n}\n\n/**\n * Register a new provider (Registry pattern — runtime extension point).\n * Useful for self-hosted endpoints or custom providers without touching theokit src.\n *\n * @example\n * registerProvider({\n * name: 'self-hosted',\n * envKey: 'SELF_HOSTED_API_KEY',\n * baseUrl: 'https://llm.internal.acme.com/v1',\n * priority: 0, // highest priority\n * })\n *\n * @public\n */\nexport function registerProvider(descriptor: ProviderDescriptor): void {\n // Idempotent — replace existing by name.\n const idx = registry.findIndex((p) => p.name === descriptor.name)\n if (idx >= 0) registry[idx] = descriptor\n else registry.push(descriptor)\n}\n\n/**\n * Reset registry to DEFAULT_REGISTRY (test-only / dev escape hatch).\n *\n * @public\n */\nexport function resetProviderRegistry(): void {\n registry.length = 0\n registry.push(...DEFAULT_REGISTRY)\n}\n\n/**\n * Get current registry snapshot (read-only — inspection).\n *\n * @public\n */\nexport function listProviders(): readonly ProviderDescriptor[] {\n return [...registry].sort((a, b) => a.priority - b.priority)\n}\n\n/**\n * Says which provider was selected, once.\n *\n * Carries the provider, HOW it was chosen, and the variable the credential came from — never the\n * credential. Which env var holds it is what an operator needs to fix a mis-selection; the value\n * is what a log must never hold.\n */\nfunction announce(\n desc: ProviderDescriptor,\n how: 'declared by the model' | 'by env priority',\n options: ResolveOptions | undefined,\n): void {\n if (announced.has(desc.name)) return\n announced.add(desc.name)\n const line = `[theokit] provider=${desc.name} (${how}) source=${desc.envKey} baseUrl=${desc.baseUrl}`\n if (options?.announce) options.announce(line)\n // `warn` rather than `info` because the repo's lint rule allows only `warn`/`error` — and this\n // line is closer to a warning in spirit anyway: it is the one chance an operator gets to notice\n // that the provider serving their agents is not the one they expected.\n else console.warn(line)\n}\n\n/**\n * The provider a model id declares, or `undefined` when it declares none.\n *\n * `provider/model` and `gateway/provider/model` both resolve on the FIRST segment: a gateway is a\n * provider from the framework's point of view (it holds the credential), and everything after it\n * is the upstream namespace the gateway itself routes on.\n *\n * A bare id (`gpt-4o-mini`, `qwen2.5:3b`) declares nothing, and an unregistered prefix is treated\n * the same way rather than as an error — a project may legitimately point a custom id at a\n * registered provider's endpoint, and refusing it here would break that before it reached the SDK.\n */\nfunction providerOf(\n modelId: string | undefined,\n registered: readonly ProviderDescriptor[],\n): ProviderDescriptor | undefined {\n if (modelId === undefined) return undefined\n const slash = modelId.indexOf('/')\n if (slash <= 0) return undefined\n const prefix = modelId.slice(0, slash)\n return registered.find((p) => p.name === prefix)\n}\n\n/**\n * Resolve the provider for a model.\n *\n * When `modelId` declares a registered provider (`anthropic/…`), THAT provider's key is\n * required — no substitution. Otherwise the registry is walked by priority, first match wins.\n *\n * @returns ResolvedProvider with apiKey + baseUrl + name\n * @throws Error if NO provider env var is set (actionable message)\n *\n * @public\n */\nexport function resolveProvider(modelId?: string, options?: ResolveOptions): ResolvedProvider {\n const sorted = [...registry].sort((a, b) => a.priority - b.priority)\n\n const declared = modelId === undefined ? undefined : providerOf(modelId, sorted)\n if (declared !== undefined && modelId !== undefined) {\n const apiKey = process.env[declared.envKey]\n if (apiKey && apiKey.length > 0) {\n announce(declared, 'declared by the model', options)\n return { name: declared.name, apiKey, baseUrl: declared.baseUrl }\n }\n // Deliberately NOT falling back to another provider's key. Silently substituting one is how\n // theokit#326 produced a 401 nobody could attribute: the request went somewhere the agent\n // never named. Say which variable is missing and stop.\n throw new Error(\n `Model \"${modelId}\" declares provider \"${declared.name}\", but ${declared.envKey} is not set. ` +\n `Set ${declared.envKey}, or change the model's provider prefix.`,\n )\n }\n\n for (const desc of sorted) {\n const apiKey = process.env[desc.envKey]\n if (apiKey && apiKey.length > 0) {\n announce(desc, 'by env priority', options)\n return {\n name: desc.name,\n apiKey,\n baseUrl: desc.baseUrl,\n }\n }\n }\n // No env var found — emit actionable error.\n const envKeys = sorted.map((p) => p.envKey).join(' OR ')\n throw new Error(\n `No LLM provider API key found in environment. Set one of: ${envKeys}. ` +\n `Get a free OpenRouter key at https://openrouter.ai/keys (recommended — one key, many models).`,\n )\n}\n\n/**\n * Try to resolve — does NOT throw. Returns null if no provider available.\n * Useful for graceful degradation (e.g., mock mode).\n *\n * @public\n */\nexport function tryResolveProvider(modelId?: string): ResolvedProvider | null {\n try {\n return resolveProvider(modelId)\n } catch {\n return null\n }\n}\n","/**\n * M4 (theokit-ai-first) — the in-process HITL approval registry.\n *\n * The HITL plugin's `awaitApproval` calls `register(approvalId)` and awaits the returned Promise\n * (this is what genuinely PAUSES the SDK run — the SDK `pre_tool_call` hook is awaited). The\n * approve route calls `resolve(approvalId, approved)` to settle it. A per-approval timeout settles\n * the Promise deterministically per the `@HumanInTheLoop` `onTimeout` policy so a hung approval\n * never leaks the paused stream.\n *\n * Single-process contract (ADR 0038 / plan Drawback 2): a multi-instance deploy needs a shared\n * registry — the interface is injectable so a durable impl (Redis, etc.) slots in without touching\n * the harness. We do NOT build a durable store now (YAGNI).\n */\n// The timeout policy vocabulary is owned by the `@HumanInTheLoop` decorator (DRY / G12) — reuse it\n// rather than re-declaring the union, so the two can never drift.\nimport type { TimeoutAction } from '@theokit/agents'\n\nexport interface RegisterOptions {\n /** Milliseconds before the approval auto-settles per `onTimeout`. */\n timeoutMs: number\n /**\n * What a timeout means. Only `'proceed'` auto-approves; `'abort'` and `'retry'` both deny — the\n * registry does NOT implement retry semantics (a timed-out `'retry'` is a deny, not a re-prompt).\n */\n onTimeout: TimeoutAction\n /** M14 — the gated tool name, surfaced by `list()` (optional; absent for legacy callers). */\n toolName?: string\n /** M14 — the approval question, surfaced by `list()` (optional). */\n question?: string\n /**\n * M20 — an optional JSON-schema descriptor of the custom payload the approver may attach. Carried\n * verbatim into `list()` + the `approval_required` event so the UI knows what to collect. Kept as\n * a plain JSON object (not a live Zod schema) so the registry stays serializable and SDK-free.\n */\n payloadSchema?: Record<string, unknown>\n}\n\n/**\n * M20 — a settled HITL decision. `approved` is the allow/deny bit (backward-compatible with the\n * legacy boolean); `reason` + `payload` are the optional approver-attached extras that surface to\n * the model (on denial, via the veto message) and to the app/UI.\n */\nexport interface ApprovalDecision {\n approved: boolean\n reason?: string\n payload?: unknown\n}\n\n/** M14 — a pending approval as surfaced by {@link ApprovalRegistry.list}. */\nexport interface PendingApproval {\n approvalId: string\n toolName?: string\n question?: string\n /** Epoch millis when the pending approval auto-settles (registeredAt + timeoutMs). */\n expiresAt: number\n /** M20 — the declared custom-payload schema, if the gated tool declares one. */\n payloadSchema?: Record<string, unknown>\n}\n\nexport interface ApprovalRegistry {\n /**\n * Register a pending approval; the returned Promise settles with the full {@link ApprovalDecision}\n * on `resolve` or timeout (M20 — was a bare boolean pre-M20).\n */\n register(approvalId: string, opts: RegisterOptions): Promise<ApprovalDecision>\n /**\n * Settle a pending approval. Accepts a full {@link ApprovalDecision} OR a bare boolean (coerced to\n * `{ approved }` — backward-compatible). Returns false if the id is unknown or already settled.\n */\n resolve(approvalId: string, decision: boolean | ApprovalDecision): boolean\n /** M14 — list the currently-pending approvals (process-wide; single-process contract). */\n list(): PendingApproval[]\n}\n\ninterface Pending {\n settle: (decision: ApprovalDecision) => void\n timer: ReturnType<typeof setTimeout>\n info: PendingApproval\n}\n\n/**\n * The one process-wide registry the stream mount (`mountAgent`) and the approve route share.\n *\n * The in-process impl holds LIVE Promise resolvers in memory — the approval a request awaits and\n * the approval the route resolves MUST be the same object, so a single instance per process is not\n * a convenience but a correctness requirement. Lazily created; a durable/multi-instance deploy\n * swaps this accessor for a shared-store impl (ADR 0038 / plan Drawback 2) without touching callers.\n * Tests use {@link createInProcessApprovalRegistry} directly — never this singleton.\n */\nlet serverRegistry: ApprovalRegistry | undefined\nexport function getApprovalRegistry(): ApprovalRegistry {\n serverRegistry ??= createInProcessApprovalRegistry()\n return serverRegistry\n}\n\nexport function createInProcessApprovalRegistry(): ApprovalRegistry {\n const pending = new Map<string, Pending>()\n\n return {\n register(approvalId, opts) {\n return new Promise<ApprovalDecision>((resolve) => {\n const settle = (decision: ApprovalDecision): void => {\n const entry = pending.get(approvalId)\n if (!entry) return\n clearTimeout(entry.timer)\n pending.delete(approvalId)\n resolve(decision)\n }\n // 'proceed' → allow on timeout; 'abort'/'retry' → deny on timeout.\n const timer = setTimeout(() => {\n settle({ approved: opts.onTimeout === 'proceed' })\n }, opts.timeoutMs)\n const info: PendingApproval = {\n approvalId,\n toolName: opts.toolName,\n question: opts.question,\n expiresAt: Date.now() + opts.timeoutMs,\n ...(opts.payloadSchema !== undefined ? { payloadSchema: opts.payloadSchema } : {}),\n }\n pending.set(approvalId, { settle, timer, info })\n })\n },\n resolve(approvalId, decision) {\n const entry = pending.get(approvalId)\n if (!entry) return false\n // M20 — coerce the legacy bare-boolean form to a decision object.\n entry.settle(typeof decision === 'boolean' ? { approved: decision } : decision)\n return true\n },\n list() {\n return [...pending.values()].map((p) => p.info)\n },\n }\n}\n"],"mappings":"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","names":[]}
@@ -6,7 +6,7 @@ import {
6
6
  import {
7
7
  getApprovalRegistry,
8
8
  resolveProvider
9
- } from "./chunk-6GGWS7J3.js";
9
+ } from "./chunk-DQIPV7L5.js";
10
10
  import {
11
11
  scanAgents
12
12
  } from "./chunk-LNVMHQ2Z.js";
@@ -145,7 +145,7 @@ async function agentCommand(name, message, deps = {}) {
145
145
  );
146
146
  }
147
147
  const projectRoot = deps.projectRoot ?? process.cwd();
148
- const agentsDir = deps.agentsDir ?? (await (await import("./load-config-VKD6LKWU.js")).loadConfig(projectRoot)).agentsDir;
148
+ const agentsDir = deps.agentsDir ?? (await (await import("./load-config-FIWNKOJO.js")).loadConfig(projectRoot)).agentsDir;
149
149
  const agents = scanAgents(projectRoot, agentsDir);
150
150
  const agent = agents.find((a) => a.name === name);
151
151
  if (!agent) {
@@ -178,8 +178,8 @@ async function agentCommand(name, message, deps = {}) {
178
178
  async function createAgentSsrLoader(projectRoot) {
179
179
  const { createServer } = await import("vite");
180
180
  const react = (await import("@vitejs/plugin-react")).default;
181
- const { theoPluginAsync } = await import("./vite-plugin-VPJFD4HK.js");
182
- const { loadConfig } = await import("./load-config-VKD6LKWU.js");
181
+ const { theoPluginAsync } = await import("./vite-plugin-RJFKLF2U.js");
182
+ const { loadConfig } = await import("./load-config-FIWNKOJO.js");
183
183
  const config = await loadConfig(projectRoot);
184
184
  const theoPlugins = await theoPluginAsync({
185
185
  root: projectRoot,
@@ -212,4 +212,4 @@ export {
212
212
  agentCommand,
213
213
  createAgentSsrLoader
214
214
  };
215
- //# sourceMappingURL=chunk-PXFXSFJL.js.map
215
+ //# sourceMappingURL=chunk-DS5MCU2X.js.map
@@ -18,7 +18,7 @@ import {
18
18
  mintRunId,
19
19
  mountAgent,
20
20
  parseAgentRequestBody
21
- } from "./chunk-OJLL4YD6.js";
21
+ } from "./chunk-KTKTHIUF.js";
22
22
  import {
23
23
  loadEnv,
24
24
  resolveTransformer
@@ -74,7 +74,7 @@ import {
74
74
  } from "./chunk-YOIVCCZT.js";
75
75
  import {
76
76
  resolveProvider
77
- } from "./chunk-6E5WKMDS.js";
77
+ } from "./chunk-AXKUA57G.js";
78
78
  import {
79
79
  generateNonce
80
80
  } from "./chunk-JA2ZAT5Q.js";
@@ -1481,7 +1481,9 @@ async function serveThreadRoute(request, method, urlPath, deps) {
1481
1481
  const mod = await deps.loadModule(agent.filePath);
1482
1482
  return handleThreadMessage({
1483
1483
  mod,
1484
- apiKey: deps.resolveApiKey(),
1484
+ // Passed unresolved: `makeThreadStartRun` calls it once the module is compiled and the
1485
+ // model is known (theokit#328).
1486
+ apiKey: deps.resolveApiKey,
1485
1487
  sessionId: msg.sessionId,
1486
1488
  request,
1487
1489
  source: `agent "${msg.name}"`,
@@ -1600,7 +1602,8 @@ async function serveAux(req, res, next, urlPath, deps) {
1600
1602
  baseUrl: `http://${req.headers.host ?? "localhost"}`,
1601
1603
  csrfMode: deps.csrfMode,
1602
1604
  // M39 — the thread follow-up route drives the agent; resolve the key on demand.
1603
- resolveApiKey: () => resolveProvider().apiKey
1605
+ // theokit#328 the thread route drives an agent, so its key follows the model too.
1606
+ resolveApiKey: (model) => resolveProvider(model).apiKey
1604
1607
  });
1605
1608
  if (response === null) {
1606
1609
  next();
@@ -1627,7 +1630,7 @@ async function serveAux(req, res, next, urlPath, deps) {
1627
1630
  requestId
1628
1631
  });
1629
1632
  }
1630
- function createAgentMiddleware(vite, projectRoot, csrfMode = "strict", agentsDir = "agents") {
1633
+ function createAgentMiddleware(vite, projectRoot, csrfMode = "strict", agentsDir = "agents", pluginRunner) {
1631
1634
  const loadModule = createViteLoader(vite);
1632
1635
  return (req, res, next) => {
1633
1636
  void (async () => {
@@ -1675,30 +1678,90 @@ function createAgentMiddleware(vite, projectRoot, csrfMode = "strict", agentsDir
1675
1678
  logRequest({ method, url, status: 405, duration: Date.now() - start, requestId });
1676
1679
  return;
1677
1680
  }
1678
- try {
1679
- const mod = await loadModule(agent.filePath);
1680
- const apiKey = resolveProvider().apiKey;
1681
- const request = incomingMessageToWebRequest(req);
1682
- const response = await mountAgent(mod, request, apiKey, {
1683
- source: agent.filePath,
1684
- csrfMode,
1685
- projectRoot
1686
- });
1687
- await writeWebResponseToServerResponse(response, res);
1688
- } catch (err) {
1689
- sendError(
1690
- res,
1691
- "INTERNAL",
1692
- err instanceof Error ? err.message : "Agent handler failed",
1693
- 500,
1694
- void 0,
1695
- requestId
1696
- );
1697
- }
1698
- logRequest({ method, url, status: res.statusCode, duration: Date.now() - start, requestId });
1681
+ await serveAgentTurn({
1682
+ req,
1683
+ res,
1684
+ agent,
1685
+ method,
1686
+ url,
1687
+ requestId,
1688
+ start,
1689
+ loadModule,
1690
+ csrfMode,
1691
+ projectRoot,
1692
+ pluginRunner
1693
+ });
1699
1694
  })();
1700
1695
  };
1701
1696
  }
1697
+ async function serveAgentTurn(t) {
1698
+ const {
1699
+ req,
1700
+ res,
1701
+ agent,
1702
+ method,
1703
+ url,
1704
+ requestId,
1705
+ start,
1706
+ loadModule,
1707
+ csrfMode,
1708
+ projectRoot,
1709
+ pluginRunner
1710
+ } = t;
1711
+ let pluginCtx;
1712
+ let request;
1713
+ try {
1714
+ request = incomingMessageToWebRequest(req);
1715
+ pluginCtx = { request, response: res, ctx: {}, requestId };
1716
+ } catch (err) {
1717
+ sendError(
1718
+ res,
1719
+ "INTERNAL",
1720
+ err instanceof Error ? err.message : "Agent handler failed",
1721
+ 500,
1722
+ void 0,
1723
+ requestId
1724
+ );
1725
+ logRequest({ method, url, status: res.statusCode, duration: Date.now() - start, requestId });
1726
+ return;
1727
+ }
1728
+ if (pluginRunner) {
1729
+ pluginRunner.applyDecorations(pluginCtx.ctx);
1730
+ const onRequest = await pluginRunner.runOnRequest(pluginCtx);
1731
+ if (onRequest.shortCircuited) {
1732
+ logRequest({
1733
+ method,
1734
+ url,
1735
+ status: res.statusCode,
1736
+ duration: Date.now() - start,
1737
+ requestId
1738
+ });
1739
+ return;
1740
+ }
1741
+ }
1742
+ try {
1743
+ const mod = await loadModule(agent.filePath);
1744
+ const apiKey = (model) => resolveProvider(model).apiKey;
1745
+ const response = await mountAgent(mod, request, apiKey, {
1746
+ source: agent.filePath,
1747
+ csrfMode,
1748
+ projectRoot
1749
+ });
1750
+ await writeWebResponseToServerResponse(response, res);
1751
+ } catch (err) {
1752
+ if (pluginRunner) await pluginRunner.runOnError(pluginCtx, err);
1753
+ sendError(
1754
+ res,
1755
+ "INTERNAL",
1756
+ err instanceof Error ? err.message : "Agent handler failed",
1757
+ 500,
1758
+ void 0,
1759
+ requestId
1760
+ );
1761
+ }
1762
+ if (pluginRunner) await pluginRunner.runOnResponse(pluginCtx);
1763
+ logRequest({ method, url, status: res.statusCode, duration: Date.now() - start, requestId });
1764
+ }
1702
1765
 
1703
1766
  // src/vite-plugin/api-middleware.ts
1704
1767
  import { resolve as resolve4 } from "path";
@@ -1817,7 +1880,10 @@ async function tryControllerFallthrough(ctx) {
1817
1880
  requestId: ctx.requestId,
1818
1881
  // M47 — serve @Expose-bound agent routes via the ONE runtime (mountAgent). CSRF is already enforced
1819
1882
  // once at the controller-dispatch boundary (G5), so mountAgent runs with csrfMode 'off' (no double gate).
1820
- serveAgent: (agent, request) => mountAgent(agent, request, resolveProvider().apiKey, { source: "expose", csrfMode: "off" })
1883
+ serveAgent: (agent, request) => mountAgent(agent, request, (model) => resolveProvider(model).apiKey, {
1884
+ source: "expose",
1885
+ csrfMode: "off"
1886
+ })
1821
1887
  });
1822
1888
  if (!handled) return false;
1823
1889
  logRequest(
@@ -2151,7 +2217,7 @@ async function runConfigureServer(server, ctx) {
2151
2217
  })
2152
2218
  );
2153
2219
  server.middlewares.use(
2154
- createAgentMiddleware(server, ctx.projectRoot, ctx.csrfMode, ctx.agentsDir)
2220
+ createAgentMiddleware(server, ctx.projectRoot, ctx.csrfMode, ctx.agentsDir, ctx.pluginRunner)
2155
2221
  );
2156
2222
  const servicesProxyPrefixes = ctx.services && Object.keys(ctx.services).length > 0 ? Object.values(ctx.services).map((s) => s.proxy) : [];
2157
2223
  const csrfReadinessStore = ctx.csrfReadinessStoreOverride ?? new CsrfReadinessStore();
@@ -3293,19 +3359,19 @@ async function theoPluginAsync(rootOrOptions) {
3293
3359
  })
3294
3360
  );
3295
3361
  }
3296
- const { appTypedClientPlugin } = await import("./app-typed-client-GHO3EWZK.js");
3362
+ const { appTypedClientPlugin } = await import("./app-typed-client-HLP26EYM.js");
3297
3363
  const appClientPlugin = appTypedClientPlugin({
3298
3364
  cwd: projectRoot,
3299
3365
  serverDir: serverDirAbs,
3300
3366
  distDir: resolve9(projectRoot, ".theokit")
3301
3367
  });
3302
- const { actionsVirtualModule } = await import("./actions-virtual-module-YQXRSSMW.js");
3368
+ const { actionsVirtualModule } = await import("./actions-virtual-module-E4PISKMB.js");
3303
3369
  const actionsPlugin = actionsVirtualModule({
3304
3370
  serverDir: serverDirAbs,
3305
3371
  distDir: resolve9(projectRoot, ".theokit")
3306
3372
  });
3307
3373
  const { agentsTypedClientPlugin } = await import("./agents-typed-client-INR2E7B3.js");
3308
- const { generateManifest } = await import("./internal-api-WEOSTMSN.js");
3374
+ const { generateManifest } = await import("./internal-api-ZCJWJ5EC.js");
3309
3375
  const agentsClientPlugin = agentsTypedClientPlugin({
3310
3376
  projectRoot,
3311
3377
  agentsDir: agentsDirName,
@@ -3499,4 +3565,4 @@ export {
3499
3565
  theoPluginAsync,
3500
3566
  theoPlugin
3501
3567
  };
3502
- //# sourceMappingURL=chunk-GXEX4CBH.js.map
3568
+ //# sourceMappingURL=chunk-FTFN4MYN.js.map