@schlenkr/ragents 0.1.7 → 0.1.9

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 (187) hide show
  1. package/apps/server/src/config-definition.ts +24 -2
  2. package/apps/server/src/config.ts +0 -6
  3. package/apps/server/src/host-api.json +3 -10
  4. package/apps/server/src/host-api.ts +6 -7
  5. package/apps/server/src/plugin-build/build.ts +28 -5
  6. package/apps/server/src/plugin-build/plugin-description.ts +1 -1
  7. package/apps/server/src/plugin-build/typecheck.ts +2 -2
  8. package/apps/server/src/plugin-support/language-server/plugin.ts +8 -7
  9. package/apps/server/src/plugin-support/language-server/tools.ts +7 -6
  10. package/apps/server/src/plugin-support/model-aliases.ts +55 -25
  11. package/apps/server/src/plugin-support/plugin-folder.ts +2 -1
  12. package/apps/server/src/plugin-support/product-relay.ts +10 -2
  13. package/apps/server/src/plugin-support/workspace-sandbox-host.ts +18 -9
  14. package/apps/server/src/profile/bundle-manifest.ts +7 -3
  15. package/apps/server/src/profile/compose.ts +6 -0
  16. package/apps/server/src/profile/plugin-discovery.ts +6 -1
  17. package/apps/server/src/profile/provisioning.ts +6 -5
  18. package/apps/server/src/ragents/engine.ts +18 -12
  19. package/apps/server/src/ragents/host-services.ts +4 -0
  20. package/apps/server/src/ragents/session.ts +1 -1
  21. package/apps/server/src/server.ts +1 -0
  22. package/apps/server/tsconfig.json +2 -0
  23. package/apps/web/dist/assets/{highlighted-body-KPVGNVTW-CFhTJEmH.js → highlighted-body-KPVGNVTW-xXXhTDbh.js} +1 -1
  24. package/apps/web/dist/assets/{main-DlzW4t4c.js → main-C7JeZFjs.js} +1 -1
  25. package/apps/web/dist/assets/{mermaid-HWGCJPDP-kxkB991i.js → mermaid-HWGCJPDP-DfsU5ofC.js} +2 -2
  26. package/apps/web/dist/assets/{runPanel-BJEFQ__w.js → runPanel-ZT6TPDLM.js} +1 -1
  27. package/apps/web/dist/help/guide-clients.html +14 -6
  28. package/apps/web/dist/help/guide-clients.md +14 -6
  29. package/apps/web/dist/help/guide-distributed.html +12 -4
  30. package/apps/web/dist/help/guide-distributed.md +12 -4
  31. package/apps/web/dist/help/guide-getting-started.html +12 -8
  32. package/apps/web/dist/help/guide-getting-started.md +12 -8
  33. package/apps/web/dist/help/guide-plugins.html +6 -2
  34. package/apps/web/dist/help/guide-plugins.md +6 -2
  35. package/apps/web/dist/help/guide-runtime.html +2 -1
  36. package/apps/web/dist/help/guide-runtime.md +2 -1
  37. package/apps/web/dist/help/index.html +3328 -1135
  38. package/apps/web/dist/host-web.json +4 -4
  39. package/apps/web/dist/index.html +2 -2
  40. package/apps/web/dist/run-panel.html +2 -2
  41. package/apps/web/src/StartTiles.tsx +1 -1
  42. package/bundles/ragents.activity/ragents-bundle.json +3 -3
  43. package/bundles/ragents.actor-programs/ragents-bundle.json +3 -3
  44. package/bundles/ragents.ask/ragents-bundle.json +4 -4
  45. package/bundles/ragents.ask/server/index.js +42 -11
  46. package/bundles/ragents.ask/server/index.js.map +3 -3
  47. package/bundles/ragents.ask/web/chunks/chunk-WFN4374U.js +2 -0
  48. package/bundles/ragents.ask/web/chunks/chunk-WFN4374U.js.map +7 -0
  49. package/bundles/ragents.ask/web/classes.json +1 -1
  50. package/bundles/ragents.ask/web/exports/ask-payload.js +1 -1
  51. package/bundles/ragents.ask/web/index.js +1 -1
  52. package/bundles/ragents.ask/web/index.js.map +3 -3
  53. package/bundles/ragents.browser/executor/index.mjs +357 -0
  54. package/bundles/ragents.browser/executor/index.mjs.map +7 -0
  55. package/bundles/ragents.browser/ragents-bundle.json +5 -8
  56. package/bundles/ragents.browser/server/chunks/{chunk-2GKLLCBE.js → chunk-CWLX4VA5.js} +1 -1
  57. package/bundles/ragents.browser/server/chunks/chunk-CWLX4VA5.js.map +7 -0
  58. package/bundles/ragents.browser/server/exports/server/contract.js +1 -1
  59. package/bundles/ragents.browser/server/index.js +20 -9
  60. package/bundles/ragents.browser/server/index.js.map +4 -4
  61. package/bundles/ragents.documents/ragents-bundle.json +3 -3
  62. package/bundles/ragents.lsp-fsharp/executor/index.mjs +68 -0
  63. package/bundles/ragents.lsp-fsharp/executor/index.mjs.map +7 -0
  64. package/bundles/ragents.lsp-fsharp/ragents-bundle.json +5 -9
  65. package/bundles/ragents.lsp-fsharp/server/index.js +21 -6
  66. package/bundles/ragents.lsp-fsharp/server/index.js.map +4 -4
  67. package/bundles/ragents.lsp-roslyn/executor/index.mjs +68 -0
  68. package/bundles/ragents.lsp-roslyn/executor/index.mjs.map +7 -0
  69. package/bundles/ragents.lsp-roslyn/ragents-bundle.json +6 -8
  70. package/bundles/ragents.lsp-roslyn/server/index.js +54 -15
  71. package/bundles/ragents.lsp-roslyn/server/index.js.map +4 -4
  72. package/bundles/ragents.lsp-typescript/executor/index.mjs +49 -0
  73. package/bundles/ragents.lsp-typescript/executor/index.mjs.map +7 -0
  74. package/bundles/ragents.lsp-typescript/ragents-bundle.json +5 -7
  75. package/bundles/ragents.lsp-typescript/server/index.js +22 -2
  76. package/bundles/ragents.lsp-typescript/server/index.js.map +3 -3
  77. package/bundles/ragents.model-relay/ragents-bundle.json +4 -4
  78. package/bundles/ragents.model-relay/server/index.js +3 -2
  79. package/bundles/ragents.model-relay/server/index.js.map +2 -2
  80. package/bundles/ragents.orchestration/ragents-bundle.json +3 -3
  81. package/bundles/ragents.overseer/ragents-bundle.json +3 -3
  82. package/bundles/ragents.processes/ragents-bundle.json +3 -3
  83. package/bundles/ragents.product/ragents-bundle.json +3 -3
  84. package/bundles/ragents.profile-distribution/ragents-bundle.json +4 -4
  85. package/bundles/ragents.profile-distribution/server/index.js +1 -1
  86. package/bundles/ragents.profile-distribution/server/index.js.map +2 -2
  87. package/bundles/ragents.reference/ragents-bundle.json +3 -3
  88. package/bundles/ragents.todo/ragents-bundle.json +3 -3
  89. package/bundles/ragents.transcript/ragents-bundle.json +3 -3
  90. package/bundles/ragents.watch/ragents-bundle.json +3 -3
  91. package/bundles/ragents.workspace/ragents-bundle.json +11 -5
  92. package/bundles/ragents.workspace/server/index.js +101 -28
  93. package/bundles/ragents.workspace/server/index.js.map +3 -3
  94. package/bundles/ragents.workspace/web/classes.json +1 -1
  95. package/bundles/ragents.workspace/web/index.js +1 -1
  96. package/bundles/ragents.workspace/web/index.js.map +3 -3
  97. package/package.json +2 -2
  98. package/packages/agent/dist/core/agent-settings.d.ts +1 -7
  99. package/packages/agent/dist/core/compaction/compaction.d.ts +17 -13
  100. package/packages/agent/dist/core/model-runtime.d.ts +5 -4
  101. package/packages/agent/dist/core/provider-composer.d.ts +2 -1
  102. package/packages/agent/dist/core/tools/bash.d.ts +9 -3
  103. package/packages/agent/dist/index.d.ts +1 -1
  104. package/packages/agent/src/core/agent-settings.ts +1 -4
  105. package/packages/agent/src/core/compaction/compaction.ts +68 -30
  106. package/packages/agent/src/core/model-runtime.ts +12 -5
  107. package/packages/agent/src/core/provider-composer.ts +5 -0
  108. package/packages/agent/src/core/tools/bash.ts +36 -30
  109. package/packages/agent/src/index.ts +3 -0
  110. package/packages/ai/dist/types.d.ts +11 -0
  111. package/packages/ai/src/types.ts +12 -0
  112. package/packages/ragents/src/agents/plugins.ts +5 -0
  113. package/packages/ragents/src/domain/event-semantics.ts +3 -0
  114. package/packages/ragents/src/domain/event-validation.ts +15 -2
  115. package/packages/ragents/src/domain/events.ts +3 -0
  116. package/packages/ragents/src/domain/model.ts +2 -0
  117. package/packages/ragents/src/domain/projection.ts +1 -0
  118. package/packages/ragents/src/drivers/agent-runtime.ts +1 -1
  119. package/packages/ragents/src/drivers/agent-turn.ts +8 -6
  120. package/packages/ragents/src/index.ts +1 -0
  121. package/packages/ragents/src/plugin-host.ts +58 -10
  122. package/packages/ragents/src/plugin-types.ts +7 -2
  123. package/packages/ragents/src/runtime/decisions/inputs.ts +6 -2
  124. package/packages/ragents/src/runtime/journal-storage.ts +5 -4
  125. package/packages/workspace-executor/package.json +0 -1
  126. package/packages/workspace-executor/src/bash-launch.ts +56 -10
  127. package/packages/workspace-executor/src/context.ts +4 -0
  128. package/packages/workspace-executor/src/contributions.ts +150 -0
  129. package/packages/workspace-executor/src/executor.ts +1 -1
  130. package/packages/workspace-executor/src/index.ts +16 -19
  131. package/packages/workspace-executor/src/language-server/host.ts +3 -0
  132. package/packages/workspace-executor/src/language-server/module.ts +12 -2
  133. package/packages/workspace-executor/src/language-server/roots.ts +0 -5
  134. package/packages/workspace-executor/src/modules.ts +7 -6
  135. package/packages/workspace-executor/src/sandbox-tools.ts +3 -9
  136. package/packages/workspace-executor/src/shell-platform.ts +14 -3
  137. package/packages/workspace-executor/src/tools.ts +0 -3
  138. package/plugins/ragents.ask/ask-payload.ts +9 -0
  139. package/plugins/ragents.ask/server/ask-service.ts +53 -13
  140. package/plugins/ragents.ask/web/AskActionView.tsx +3 -2
  141. package/plugins/ragents.browser/executor/index.ts +5 -0
  142. package/{packages/workspace-executor/src/browser → plugins/ragents.browser/executor}/module.ts +25 -31
  143. package/{packages/workspace-executor/src/browser → plugins/ragents.browser/executor}/playwright.ts +9 -23
  144. package/plugins/ragents.browser/provision.ts +1 -1
  145. package/plugins/ragents.browser/server/browser.ts +3 -3
  146. package/plugins/ragents.browser/server/contract.ts +2 -2
  147. package/plugins/ragents.browser/server/index.ts +1 -1
  148. package/plugins/ragents.lsp-fsharp/executor.ts +80 -0
  149. package/plugins/ragents.lsp-fsharp/provision.ts +1 -1
  150. package/plugins/ragents.lsp-fsharp/server/index.ts +2 -2
  151. package/plugins/ragents.lsp-roslyn/executor.ts +64 -0
  152. package/plugins/ragents.lsp-roslyn/provision.ts +1 -1
  153. package/plugins/ragents.lsp-roslyn/server/index.ts +28 -5
  154. package/plugins/ragents.lsp-roslyn/server/solution-on-start.ts +18 -6
  155. package/plugins/ragents.lsp-typescript/executor.ts +50 -0
  156. package/plugins/ragents.lsp-typescript/server/index.ts +2 -2
  157. package/plugins/ragents.model-relay/server/config.ts +1 -1
  158. package/plugins/ragents.model-relay/server/relay.ts +4 -2
  159. package/plugins/ragents.profile-distribution/server/archive.ts +2 -1
  160. package/plugins/ragents.workspace/client/workspace-client.ts +111 -28
  161. package/plugins/ragents.workspace/contract.ts +33 -2
  162. package/plugins/ragents.workspace/server/binding.ts +10 -4
  163. package/plugins/ragents.workspace/server/clients.ts +56 -9
  164. package/plugins/ragents.workspace/server/config.ts +9 -0
  165. package/plugins/ragents.workspace/server/index.ts +13 -4
  166. package/plugins/ragents.workspace/server/runtime.ts +10 -0
  167. package/plugins/ragents.workspace/server/shell-platform.ts +6 -5
  168. package/plugins/ragents.workspace/web/WorkspaceBinding.tsx +1 -1
  169. package/ragents.config.core.ts +4 -1
  170. package/ragents.config.showcase.ts +4 -1
  171. package/scripts/agent/journal.ts +3 -1
  172. package/scripts/package/build-package.ts +3 -1
  173. package/scripts/package/publish-package.ts +4 -3
  174. package/scripts/provision/run-provision.ts +2 -2
  175. package/scripts/workspace-client/run-workspace-client.ts +7 -4
  176. package/apps/web/dist/help/screenshots/release-checklist-vscode.png +0 -0
  177. package/apps/web/dist/help/screenshots/release-checklist-web.png +0 -0
  178. package/bundles/ragents.ask/web/chunks/chunk-HGFDGTNC.js +0 -2
  179. package/bundles/ragents.ask/web/chunks/chunk-HGFDGTNC.js.map +0 -7
  180. package/bundles/ragents.browser/server/chunks/chunk-2GKLLCBE.js.map +0 -7
  181. package/packages/workspace-executor/src/language-server/adapters/fsharp.ts +0 -60
  182. package/packages/workspace-executor/src/language-server/adapters/index.ts +0 -7
  183. package/packages/workspace-executor/src/language-server/adapters/roslyn.ts +0 -56
  184. package/packages/workspace-executor/src/language-server/adapters/typescript.ts +0 -74
  185. package/packages/workspace-executor/src/language-server/solution.ts +0 -13
  186. /package/{packages/workspace-executor/src/browser → plugins/ragents.browser/executor}/contract.ts +0 -0
  187. /package/{packages/workspace-executor/src/browser → plugins/ragents.browser/executor}/pages.ts +0 -0
@@ -1,3 +1,5 @@
1
+ import type { ModelCompaction } from "@ragents/ai";
2
+ import type { ThinkingLevel } from "@ragents/engine";
1
3
  import type { hostConfigDescriptors } from "./config.js";
2
4
 
3
5
  export interface EnvironmentReference {
@@ -52,7 +54,23 @@ export interface ProfileUser extends ProfileAnonymousUser {
52
54
  readonly token?: EnvironmentReference;
53
55
  }
54
56
 
55
- export type ConfigValue = string | number | boolean | readonly string[] | EnvironmentReference | ProvisionedReference;
57
+ /** Ein Eintrag von MODEL_ALIASES: ein Modell unter eigenem Namen mit den Kompaktierungswerten, die für dieses Modell gelten. */
58
+ export interface ProfileModelAlias {
59
+ readonly alias: string;
60
+ /** Das Ziel als anbieter/modell aus dem eingebauten Katalog des Anbieters. */
61
+ readonly model: string;
62
+ readonly thinking?: ThinkingLevel;
63
+ readonly compaction: Readonly<ModelCompaction>;
64
+ }
65
+
66
+ export type ConfigValue =
67
+ | string
68
+ | number
69
+ | boolean
70
+ | readonly string[]
71
+ | readonly ProfileModelAlias[]
72
+ | EnvironmentReference
73
+ | ProvisionedReference;
56
74
 
57
75
  type Descriptors = readonly { readonly key: string }[];
58
76
 
@@ -64,6 +82,10 @@ type Section<T extends Descriptors> = {
64
82
  readonly [Key in T[number]["key"]]?: Key extends SecretKeyOf<T> ? EnvironmentReference : ConfigValue;
65
83
  };
66
84
 
85
+ type HostSection = Omit<Section<typeof hostConfigDescriptors>, "MODEL_ALIASES"> & {
86
+ readonly MODEL_ALIASES?: readonly ProfileModelAlias[];
87
+ };
88
+
67
89
  // Der Kern kennt keine Plugin-IDs: welche Sektion und welcher Schlüssel gültig ist, entscheidet die
68
90
  // Laufzeitprüfung gegen die Deklarationen der geladenen Plugins.
69
91
  export type PluginSection = {
@@ -76,5 +98,5 @@ export type PluginSection = {
76
98
  };
77
99
 
78
100
  export type RAgentsConfig =
79
- & { readonly host?: Section<typeof hostConfigDescriptors> }
101
+ & { readonly host?: HostSection }
80
102
  & { readonly [pluginId: string]: PluginSection | undefined };
@@ -11,8 +11,6 @@ export const hostConfigDescriptors = [
11
11
  { key: "PORT", source: "environment" },
12
12
  { key: "DATA_DIR", source: "environment" },
13
13
  { key: "AGENT_THINKING", source: "environment" },
14
- { key: "AGENT_COMPACTION_RESERVE_TOKENS", source: "environment" },
15
- { key: "AGENT_COMPACTION_KEEP_RECENT_TOKENS", source: "environment" },
16
14
  { key: "COMPACTION_PROVIDER", source: "environment" },
17
15
  { key: "COMPACTION_MODEL", source: "environment" },
18
16
  ...modelAliasEnvDescriptors,
@@ -37,10 +35,6 @@ export const config = Object.freeze({
37
35
  dataDir: path.resolve(env.value("DATA_DIR", defaultDataDirectory(env.required("PRODUCT_PROFILE")))),
38
36
  webDistDir: hostWebDirectory(rootDir),
39
37
  agentThinking: env.value("AGENT_THINKING", "high"),
40
- agentCompaction: {
41
- ...(env.optional("AGENT_COMPACTION_RESERVE_TOKENS") ? { reserveTokens: env.positiveNumber("AGENT_COMPACTION_RESERVE_TOKENS", "") } : {}),
42
- ...(env.optional("AGENT_COMPACTION_KEEP_RECENT_TOKENS") ? { keepRecentTokens: env.positiveNumber("AGENT_COMPACTION_KEEP_RECENT_TOKENS", "") } : {}),
43
- },
44
38
  compactionProvider: env.value("COMPACTION_PROVIDER", "openrouter"),
45
39
  compactionModel: env.value("COMPACTION_MODEL", ""),
46
40
  productProfile: env.required("PRODUCT_PROFILE"),
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": 6,
2
+ "version": 7,
3
3
  "server": {
4
4
  "@ragents/engine": [
5
5
  "DomainError",
@@ -239,6 +239,7 @@
239
239
  "runManagementToken"
240
240
  ],
241
241
  "@ragents/host/ragents/host-services": [
242
+ "executorContributionsToken",
242
243
  "hostAddressToken",
243
244
  "runGuardToken",
244
245
  "runWorkspaceProviderToken",
@@ -266,31 +267,23 @@
266
267
  "workflowInstructions"
267
268
  ],
268
269
  "@ragents/workspace-executor": [
269
- "BROWSER_EXECUTABLE_VARIABLE",
270
- "BROWSER_OPERATIONS",
271
270
  "COMMAND_OPERATIONS",
272
271
  "FILE_OPERATIONS",
273
- "FSHARP_SERVER_FILE",
274
- "FSHARP_SERVER_VARIABLE",
275
272
  "PROCESS_OPERATIONS",
276
- "ROSLYN_SERVER_FILE",
277
- "ROSLYN_SERVER_VARIABLE",
278
273
  "RUN_FOLDER_OPERATIONS",
279
274
  "RUN_MARKER_ENV",
280
275
  "WORKSPACE_EXECUTOR_VERSION",
281
- "fsharpAdapter",
282
276
  "languageServerOpenOperation",
283
277
  "languageServerSolutionsOperation",
284
278
  "listDirectory",
285
279
  "readTextFile",
286
- "roslynAdapter",
280
+ "ripgrepAvailable",
287
281
  "runManagedProcess",
288
282
  "safeProcessEnvironment",
289
283
  "sandboxRunEnvironment",
290
284
  "sandboxedLaunch",
291
285
  "shellPlatformText",
292
286
  "startManagedService",
293
- "typescriptAdapter",
294
287
  "watchDirectory"
295
288
  ],
296
289
  "@ragents/workspace-executor/src/git-config-environment": [
@@ -1,5 +1,5 @@
1
1
  /** The number of the host API a plugin is built against; it changes with every incompatible change of a list, a listed name or a library. */
2
- export const HOST_API_VERSION = 6;
2
+ export const HOST_API_VERSION = 7;
3
3
 
4
4
  /** A library the host shares whole, as its installed version exports it; host code instead names each value it offers. */
5
5
  export const LIBRARY = "library";
@@ -90,7 +90,8 @@ export const hostApi: { readonly server: HostApiModules; readonly web: HostApiMo
90
90
  "@ragents/host/ragents/document-store": ["documentStoreToken"],
91
91
  "@ragents/host/ragents/global-chat": ["globalChatToken", "runManagementToken"],
92
92
  "@ragents/host/ragents/host-services": [
93
- "hostAddressToken", "runtimeProviderToken", "secretEnvNamesToken", "runGuardToken", "runWorkspaceProviderToken", "workspaceGuardToken",
93
+ "executorContributionsToken", "hostAddressToken", "runtimeProviderToken", "secretEnvNamesToken", "runGuardToken", "runWorkspaceProviderToken",
94
+ "workspaceGuardToken",
94
95
  ],
95
96
  "@ragents/host/ragents/product-runtime": ["productRuntimeToken"],
96
97
  "@ragents/host/ragents/runtime-bridge": ["runtimeBridgeToken"],
@@ -100,11 +101,9 @@ export const hostApi: { readonly server: HostApiModules; readonly web: HostApiMo
100
101
  ],
101
102
  "@ragents/workflow": ["defineWorkflow", "workflowInstructions"],
102
103
  "@ragents/workspace-executor": [
103
- "BROWSER_EXECUTABLE_VARIABLE", "BROWSER_OPERATIONS", "COMMAND_OPERATIONS", "FILE_OPERATIONS",
104
- "FSHARP_SERVER_FILE", "FSHARP_SERVER_VARIABLE", "PROCESS_OPERATIONS", "ROSLYN_SERVER_FILE",
105
- "ROSLYN_SERVER_VARIABLE", "RUN_FOLDER_OPERATIONS", "RUN_MARKER_ENV", "WORKSPACE_EXECUTOR_VERSION", "fsharpAdapter",
106
- "languageServerOpenOperation", "languageServerSolutionsOperation", "listDirectory", "readTextFile", "roslynAdapter", "runManagedProcess", "safeProcessEnvironment", "sandboxRunEnvironment", "sandboxedLaunch",
107
- "shellPlatformText", "startManagedService", "typescriptAdapter", "watchDirectory",
104
+ "COMMAND_OPERATIONS", "FILE_OPERATIONS", "PROCESS_OPERATIONS", "RUN_FOLDER_OPERATIONS", "RUN_MARKER_ENV", "WORKSPACE_EXECUTOR_VERSION",
105
+ "languageServerOpenOperation", "languageServerSolutionsOperation", "listDirectory", "readTextFile", "ripgrepAvailable", "runManagedProcess", "safeProcessEnvironment", "sandboxRunEnvironment", "sandboxedLaunch",
106
+ "shellPlatformText", "startManagedService", "watchDirectory",
108
107
  ],
109
108
  "@ragents/workspace-executor/src/git-config-environment": ["withGitConfigPairs"],
110
109
  "@ragents/workspace-executor/src/managed-process": ["ProcessGroupJoinError"],
@@ -5,6 +5,7 @@ import path from "node:path";
5
5
  import { Scanner } from "@tailwindcss/oxide";
6
6
  import { build as esbuild, type Message, type Metafile, type OutputFile, type PartialMessage, type Plugin } from "esbuild";
7
7
  import ts from "typescript";
8
+ import { EXECUTOR_CONTRIBUTION_FILE } from "@ragents/workspace-executor";
8
9
  import { installFolder, withLock } from "../folder-install.js";
9
10
  import { HOST_API_VERSION, HOST_MODULES_GLOBAL, LIBRARY, hostApi, hostOnly, providedByHost, type HostApiHalf } from "../host-api.js";
10
11
  import { checkedHostApiRecord, hostRoot, type HostApiRecord } from "../host-version.js";
@@ -172,13 +173,27 @@ interface HalfState {
172
173
  }
173
174
 
174
175
  /** Keeps a half to the host API, its own folder and declared exports of other plugins; everything else is a build error with its cause. */
175
- const boundaryPlugin = (source: PluginSource, half: HostApiHalf, environment: BuildEnvironment, state: HalfState, assets: readonly string[]): Plugin => ({
176
+ const boundaryPlugin = (
177
+ source: PluginSource,
178
+ half: HostApiHalf,
179
+ environment: BuildEnvironment,
180
+ state: HalfState,
181
+ assets: readonly string[],
182
+ selfContained: boolean,
183
+ ): Plugin => ({
176
184
  name: "ragents-plugin-boundary",
177
185
  setup(build) {
178
186
  const id = source.description.id;
179
187
  const packageProblems = new Map<string, string | undefined>();
180
188
 
189
+ /** The executor contribution loads in every process without the host's loader, the VS Code extension included. */
190
+ const outsideContribution = (specifier: string) => ({ errors: [{
191
+ text: `${specifier}: der Executor-Beitrag lädt in jedem Node-Prozess ohne die Auflösung des Hosts; er importiert nur node:*, eigene Dateien, `
192
+ + "gebündelte Bibliotheken und vom Host Typen (import type), alles andere bekommt er über die Maschine",
193
+ }] });
194
+
181
195
  const crossImport = (owner: string, name: string) => {
196
+ if (selfContained) return outsideContribution(`@ragents/plugins/${owner}/${name}`);
182
197
  state.uses.add(owner);
183
198
  return half === "server"
184
199
  ? { path: `@ragents/plugins/${owner}/${name}`, external: true }
@@ -221,6 +236,7 @@ const boundaryPlugin = (source: PluginSource, half: HostApiHalf, environment: Bu
221
236
  }
222
237
  return crossImport(owner, name);
223
238
  }
239
+ if (selfContained && (providedByHost(half, specifier) || hostOnly(specifier))) return outsideContribution(specifier);
224
240
  if (providedByHost(half, specifier)) {
225
241
  if (args.kind === "dynamic-import" && (half === "web" || !isLibrary(half, specifier))) {
226
242
  return { errors: [{ text: `import() von ${specifier}: ein Modul des Hosts wird statisch importiert, damit der Bau jeden Namen gegen die Host-API prüft` }] };
@@ -381,23 +397,27 @@ const nodePathsOf = (root: string, half: HostApiHalf): string[] =>
381
397
  [path.join(root, "node_modules"), path.join(root, half === "server" ? "apps/server/node_modules" : "apps/web/node_modules")]
382
398
  .filter((folder) => existsSync(folder));
383
399
 
400
+ /** Builds a half; `selfContained` builds the executor contribution as one file under executor/ that imports nothing but node:*. */
384
401
  const buildHalf = async (
385
402
  source: PluginSource,
386
403
  half: HostApiHalf,
387
404
  entries: readonly { readonly in: string; readonly out: string }[],
388
405
  environment: BuildEnvironment,
389
406
  assets: readonly string[],
407
+ selfContained = false,
390
408
  ): Promise<HalfResult | { readonly problems: readonly string[] }> => {
391
409
  const state: HalfState = { uses: new Set() };
392
410
  const id = source.description.id;
393
- const problemsOf = (messages: readonly Message[]): readonly string[] => messages.map((message) => `${half}: ${messageText(message, source.folder)}`);
411
+ const part = selfContained ? path.posix.dirname(EXECUTOR_CONTRIBUTION_FILE) : half;
412
+ const problemsOf = (messages: readonly Message[]): readonly string[] => messages.map((message) => `${part}: ${messageText(message, source.folder)}`);
394
413
  try {
395
414
  const result = await esbuild({
396
415
  absWorkingDir: source.folder,
397
416
  entryPoints: [...entries],
398
- outdir: path.join(environment.out, id, half),
417
+ outdir: path.join(environment.out, id, part),
399
418
  bundle: true,
400
- splitting: true,
419
+ splitting: !selfContained,
420
+ ...(selfContained ? { outExtension: { ".js": path.posix.extname(EXECUTOR_CONTRIBUTION_FILE) } } : {}),
401
421
  format: "esm",
402
422
  write: false,
403
423
  metafile: true,
@@ -416,7 +436,7 @@ const buildHalf = async (
416
436
  define: { "process.env.NODE_ENV": JSON.stringify("production") },
417
437
  } : { banner: { js: SERVER_BANNER } }),
418
438
  logLevel: "silent",
419
- plugins: [boundaryPlugin(source, half, environment, state, assets)],
439
+ plugins: [boundaryPlugin(source, half, environment, state, assets, selfContained)],
420
440
  });
421
441
  const fatal = result.warnings.filter((warning) => FATAL_WARNINGS.has(warning.id));
422
442
  if (fatal.length > 0) return { problems: problemsOf(fatal) };
@@ -472,6 +492,7 @@ const buildPlugin = async (folder: string, environment: BuildEnvironment, typeEr
472
492
  const serverEntry = sourceFileOf(path.join(source.folder, "server/index"));
473
493
  const webEntry = sourceFileOf(path.join(source.folder, "web/index"));
474
494
  const provision = sourceFileOf(path.join(source.folder, "provision"));
495
+ const executorEntry = sourceFileOf(path.join(source.folder, "executor"));
475
496
  const exportEntries = (half: HostApiHalf) => source.description.exports[half].map((name) => ({
476
497
  in: sourceFileOf(path.join(source.folder, name))!,
477
498
  out: `exports/${name}`,
@@ -481,6 +502,7 @@ const buildPlugin = async (folder: string, environment: BuildEnvironment, typeEr
481
502
  const results = await Promise.all([
482
503
  buildHalf(source, "server", [{ in: provision ? "ragents-entry:server" : serverEntry, out: "index" }, ...exportEntries("server")], environment, assets),
483
504
  ...(hasWeb ? [buildHalf(source, "web", [...(webEntry ? [{ in: webEntry, out: "index" }] : []), ...exportEntries("web")], environment, assets)] : []),
505
+ ...(executorEntry ? [buildHalf(source, "server", [{ in: executorEntry, out: path.posix.parse(EXECUTOR_CONTRIBUTION_FILE).name }], environment, assets, true)] : []),
484
506
  ]);
485
507
  const problems = results.flatMap((result) => "problems" in result ? result.problems : []);
486
508
  if (problems.length > 0) return failed(problems);
@@ -525,6 +547,7 @@ const buildPlugin = async (folder: string, environment: BuildEnvironment, typeEr
525
547
  classes: "web/classes.json",
526
548
  },
527
549
  } : {}),
550
+ ...(executorEntry ? { executor: EXECUTOR_CONTRIBUTION_FILE } : {}),
528
551
  exports: {
529
552
  server: Object.fromEntries(source.description.exports.server.map((name) => [name, exportOutput("server", name)])),
530
553
  web: Object.fromEntries(source.description.exports.web.map((name) => [name, exportOutput("web", name)])),
@@ -19,7 +19,7 @@ export interface PluginSource {
19
19
 
20
20
  const ID_PATTERN = /^[a-z0-9]+(?:[.-][a-z0-9]+)*$/;
21
21
  /** Places of the bundle the build tool writes itself; an asset there would overwrite its output or publish sources under /plugins/<id>/web/. */
22
- const RESERVED_ASSET_ROOTS = new Set(["server", "web", "ragents-bundle.json"]);
22
+ const RESERVED_ASSET_ROOTS = new Set(["server", "web", "executor", "ragents-bundle.json"]);
23
23
  const DESCRIPTION_KEYS = new Set(["id", "exports", "assets"]);
24
24
  const HALVES = new Set(["server", "web"]);
25
25
 
@@ -11,9 +11,9 @@ export const PLUGIN_TSCONFIG: Readonly<Record<HostApiHalf, string>> = {
11
11
  web: "apps/web/tsconfig.plugin.json",
12
12
  };
13
13
 
14
- /** The files a half starts from: its entry, the provisioning for the server, and the declared exports. */
14
+ /** The files a half starts from: its entry, the provisioning and the executor contribution for the server, and the declared exports. */
15
15
  export const halfEntries = (source: PluginSource, half: HostApiHalf): readonly string[] => {
16
- const own = half === "server" ? ["server/index", "provision"] : ["web/index"];
16
+ const own = half === "server" ? ["server/index", "provision", "executor"] : ["web/index"];
17
17
  return [...own, ...source.description.exports[half]]
18
18
  .map((name) => sourceFileOf(path.join(source.folder, name)))
19
19
  .filter((file): file is string => file !== undefined);
@@ -1,5 +1,5 @@
1
1
  import type { PluginConfigDescriptor, RAgentsPlugin } from "@ragents/engine";
2
- import type { LanguageServerAdapter } from "@ragents/workspace-executor";
2
+ import type { LanguageServerDescription } from "@ragents/workspace-executor";
3
3
  import { workspaceGuardToken } from "../../ragents/host-services.js";
4
4
  import { sandboxServicesToken } from "../workspace-sandbox-host.js";
5
5
  import { createLanguageServerSnapshotMethod, createLanguageServerSolutionMethods } from "./snapshot-method.js";
@@ -7,7 +7,8 @@ import { createLanguageServerToolContributor } from "./tools.js";
7
7
 
8
8
  export interface LanguageServerPluginOptions {
9
9
  id: string;
10
- adapter: LanguageServerAdapter;
10
+ /** Beschreibt den Sprachserver für Werkzeuge und Reiter; gestartet wird er im Executor aus dem Beitrag des Plugins. */
11
+ languageServer: LanguageServerDescription;
11
12
  tabLabel?: string;
12
13
  configDescriptors?: readonly PluginConfigDescriptor[];
13
14
  /** Nach jedem erfolgreichen Öffnen über Werkzeug oder Umschalten, mit dem Run. */
@@ -20,16 +21,16 @@ export const createLanguageServerPlugin = (options: LanguageServerPluginOptions)
20
21
  const sandbox = host.service(sandboxServicesToken);
21
22
  if (options.configDescriptors) host.config(...options.configDescriptors);
22
23
  const opened = options.onOpened ?? (() => undefined);
23
- host.functions(createLanguageServerToolContributor(options.adapter, sandbox, opened));
24
- const solutions = options.adapter.solutionExtensions !== undefined;
24
+ host.functions(createLanguageServerToolContributor(options.id, options.languageServer, sandbox, opened));
25
+ const solutions = options.languageServer.solutionExtensions !== undefined;
25
26
  host.clientConfig({
26
- label: options.tabLabel ?? options.adapter.label,
27
- openTool: `${options.adapter.id}_open`,
27
+ label: options.tabLabel ?? options.languageServer.label,
28
+ openTool: `${options.languageServer.id}_open`,
28
29
  solutions,
29
30
  });
30
31
  const methodOptions = {
31
32
  pluginId: options.id,
32
- adapterId: options.adapter.id,
33
+ adapterId: options.languageServer.id,
33
34
  sandbox,
34
35
  ensureWorkspaceAccess: host.service(workspaceGuardToken),
35
36
  opened,
@@ -5,7 +5,7 @@ import {
5
5
  languageServerDiagnosticsOperation,
6
6
  languageServerOpenOperation,
7
7
  languageServerSolutionsOperation,
8
- type LanguageServerAdapter,
8
+ type LanguageServerDescription,
9
9
  type LanguageServerSolutions,
10
10
  type LanguageServerState,
11
11
  } from "@ragents/workspace-executor";
@@ -30,11 +30,12 @@ export const formatSolutions = (label: string, listing: LanguageServerSolutions)
30
30
 
31
31
  /** Beschreibung und Weiterreichung: der Sprachserver läuft im Executor des Runs, nicht in diesem Plugin. */
32
32
  export const createLanguageServerToolContributor = (
33
- adapter: LanguageServerAdapter,
33
+ pluginId: string,
34
+ languageServer: LanguageServerDescription,
34
35
  sandbox: SandboxServices,
35
36
  opened: (runId: string) => void,
36
37
  ): ToolContributor => {
37
- const { id, label, rootDescription, languages } = adapter;
38
+ const { id, label, rootDescription, languages } = languageServer;
38
39
  const extensions = Object.keys(languages).join(", ");
39
40
  const openMetadata = {
40
41
  name: languageServerOpenOperation(id),
@@ -96,7 +97,7 @@ export const createLanguageServerToolContributor = (
96
97
  const solutionsMetadata = {
97
98
  name: languageServerSolutionsOperation(id),
98
99
  nativeTool: true,
99
- description: `List the solution files (${(adapter.solutionExtensions ?? []).join(", ")}) of this run's workspace and mark `
100
+ description: `List the solution files (${(languageServer.solutionExtensions ?? []).join(", ")}) of this run's workspace and mark `
100
101
  + `which ones the ${label} language server has open. ${openMetadata.name} loads another one in addition; `
101
102
  + "the open ones stay open.",
102
103
  } as const;
@@ -128,9 +129,9 @@ export const createLanguageServerToolContributor = (
128
129
  ...(scope.signal ? { signal: scope.signal } : {}),
129
130
  }) as string,
130
131
  });
131
- const withSolutions = adapter.solutionExtensions !== undefined;
132
+ const withSolutions = languageServer.solutionExtensions !== undefined;
132
133
  return {
133
- name: `ragents.lsp-${id}`,
134
+ name: pluginId,
134
135
  descriptors: [
135
136
  toolDescriptorFrom(openMetadata, alwaysAvailable),
136
137
  toolDescriptorFrom(diagnosticsMetadata, alwaysAvailable),
@@ -1,10 +1,10 @@
1
- import { aliasedModel, type ModelAlias as RuntimeModelAlias } from "@ragents/agent";
1
+ import { aliasedModel, compactionProblem, type ModelAlias as RuntimeModelAlias } from "@ragents/agent";
2
2
  import { getSupportedThinkingLevels, type Api, type Model } from "@ragents/ai";
3
3
  import { getBuiltinModels, type BuiltinProvider } from "@ragents/ai/providers/all";
4
4
  import { isThinkingLevel, type ThinkingLevel } from "@ragents/engine";
5
5
  import { declaredEnvironment } from "./plugin-config.js";
6
6
 
7
- /** Ein Alias des Profils mit seinem Ziel und optional der Denktiefe, die gilt, solange niemand eine andere wählt. */
7
+ /** Ein Alias des Profils mit Ziel und Kompaktierungswerten und optional der Denktiefe, die gilt, solange niemand eine andere wählt. */
8
8
  export interface ModelAlias extends RuntimeModelAlias {
9
9
  readonly thinking?: ThinkingLevel;
10
10
  }
@@ -17,47 +17,77 @@ export const modelAliasEnvDescriptors = [
17
17
  ] as const;
18
18
 
19
19
  const ALIAS = /^[a-z0-9][a-z0-9._-]{0,63}$/;
20
+ const ENTRY_KEYS: readonly string[] = ["alias", "model", "thinking", "compaction"];
20
21
 
21
- /** MODEL_ALIASES: eine Liste "alias=anbieter/modell" oder "alias=anbieter/modell@denktiefe"; der Alias ist der einzige Name, den Oberfläche, Journal und Relay-Clients sehen. */
22
- export const parseModelAliases = (entries: readonly string[]): readonly ModelAlias[] => {
23
- const aliases = entries.map((entry): ModelAlias => {
24
- const separator = entry.indexOf("=");
25
- const alias = separator > 0 ? entry.slice(0, separator).trim() : "";
26
- const rest = separator > 0 ? entry.slice(separator + 1).trim() : "";
27
- const at = rest.lastIndexOf("@");
28
- const target = at < 0 ? rest : rest.slice(0, at);
29
- const thinking = at < 0 ? undefined : rest.slice(at + 1);
30
- const slash = target.indexOf("/");
31
- if (!ALIAS.test(alias) || slash <= 0 || slash === target.length - 1) {
32
- throw new Error(`MODEL_ALIASES: "${entry}" hat nicht das Format "alias=anbieter/modell" oder "alias=anbieter/modell@denktiefe"`);
33
- }
34
- if (thinking !== undefined && !isThinkingLevel(thinking)) throw new Error(`MODEL_ALIASES: "${entry}" nennt die unbekannte Denktiefe "${thinking}"`);
35
- return { alias, upstream: target.slice(0, slash), model: target.slice(slash + 1), ...(thinking === undefined ? {} : { thinking }) };
36
- });
22
+ const aliasOf = (value: unknown, index: number): ModelAlias => {
23
+ const location = `MODEL_ALIASES[${index}]`;
24
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
25
+ throw new Error(`${location} must be an object with alias, model, compaction and optionally thinking`);
26
+ }
27
+ const entry = value as Record<string, unknown>;
28
+ const unknown = Object.keys(entry).find((key) => !ENTRY_KEYS.includes(key));
29
+ if (unknown) throw new Error(`${location}.${unknown} is not supported; allowed are ${ENTRY_KEYS.join(", ")}`);
30
+ if (typeof entry.alias !== "string" || !ALIAS.test(entry.alias)) {
31
+ throw new Error(`${location}.alias needs 1 to 64 lowercase letters, digits, dots, underscores or hyphens`);
32
+ }
33
+ const target = typeof entry.model === "string" ? entry.model : "";
34
+ const slash = target.indexOf("/");
35
+ if (slash <= 0 || slash === target.length - 1) throw new Error(`${location}.model of ${entry.alias} needs the form "provider/model"`);
36
+ if (entry.thinking !== undefined && !isThinkingLevel(entry.thinking)) {
37
+ throw new Error(`${location}.thinking of ${entry.alias} names the unknown thinking level "${String(entry.thinking)}"`);
38
+ }
39
+ const problem = compactionProblem(entry.compaction);
40
+ if (problem) throw new Error(`${location}, ${entry.alias}: ${problem}`);
41
+ return {
42
+ alias: entry.alias,
43
+ upstream: target.slice(0, slash),
44
+ model: target.slice(slash + 1),
45
+ ...(entry.thinking === undefined ? {} : { thinking: entry.thinking }),
46
+ compaction: entry.compaction as ModelAlias["compaction"],
47
+ };
48
+ };
49
+
50
+ /** MODEL_ALIASES: eine Liste von { alias, model: "anbieter/modell", thinking?, compaction }; der Alias ist der einzige Name, den Oberfläche, Journal und Relay-Clients sehen. */
51
+ export const parseModelAliases = (entries: unknown): readonly ModelAlias[] => {
52
+ if (!Array.isArray(entries)) throw new Error("MODEL_ALIASES must be a list of aliases");
53
+ const aliases = entries.map(aliasOf);
37
54
  const duplicate = aliases.find((entry, index) => aliases.findIndex((other) => other.alias === entry.alias) !== index);
38
- if (duplicate) throw new Error(`MODEL_ALIASES nennt den Alias ${duplicate.alias} mehrfach`);
55
+ if (duplicate) throw new Error(`MODEL_ALIASES names the alias ${duplicate.alias} more than once`);
39
56
  return aliases;
40
57
  };
41
58
 
42
59
  const env = declaredEnvironment(modelAliasEnvDescriptors);
43
60
 
44
- export const configuredModelAliases = (): readonly ModelAlias[] => parseModelAliases(env.list("MODEL_ALIASES"));
61
+ /** Die Aliasse des Profils; in der Umgebung steht MODEL_ALIASES als JSON der Liste aus der Profildatei. */
62
+ export const configuredModelAliases = (): readonly ModelAlias[] => {
63
+ const value = env.optional("MODEL_ALIASES");
64
+ if (value === undefined || value === "") return [];
65
+ let parsed: unknown;
66
+ try {
67
+ parsed = JSON.parse(value);
68
+ } catch {
69
+ throw new Error("MODEL_ALIASES is no JSON list of aliases");
70
+ }
71
+ return parseModelAliases(parsed);
72
+ };
45
73
 
46
74
  /** Der Katalog der Aliasse aus den eingebauten Katalogen ihrer Anbieter, so wie die Modelllaufzeit sie anbietet. */
47
75
  export const aliasCatalog = (aliases: readonly ModelAlias[] = configuredModelAliases()): readonly Model<Api>[] => {
48
- if (aliases.length === 0) throw new Error(`Der Anbieter ${ALIAS_PROVIDER} braucht MODEL_ALIASES im Abschnitt host`);
76
+ if (aliases.length === 0) throw new Error(`The provider ${ALIAS_PROVIDER} needs MODEL_ALIASES in the host section`);
49
77
  return aliases.map((entry) => {
50
78
  const target = getBuiltinModels(entry.upstream as BuiltinProvider).find((model) => model.id === entry.model);
51
- if (!target) throw new Error(`MODEL_ALIASES: das Modell ${entry.model} hinter ${entry.alias} fehlt im Katalog von ${entry.upstream}`);
79
+ if (!target) throw new Error(`MODEL_ALIASES: the model ${entry.model} behind ${entry.alias} is missing from the catalog of ${entry.upstream}`);
52
80
  const supported = getSupportedThinkingLevels(target);
53
81
  if (entry.thinking !== undefined && !supported.includes(entry.thinking)) {
54
- throw new Error(`MODEL_ALIASES: die Denktiefe ${entry.thinking} gibt es für ${entry.alias} nicht (gültig: ${supported.join(", ")})`);
82
+ throw new Error(`MODEL_ALIASES: the thinking level ${entry.thinking} does not exist for ${entry.alias} (valid: ${supported.join(", ")})`);
55
83
  }
56
- return aliasedModel(ALIAS_PROVIDER, entry.alias, target);
84
+ const problem = compactionProblem(entry.compaction, target);
85
+ if (problem) throw new Error(`MODEL_ALIASES: ${entry.alias} on ${entry.upstream}/${entry.model}: ${problem}`);
86
+ return aliasedModel(ALIAS_PROVIDER, entry, target);
57
87
  });
58
88
  };
59
89
 
60
- /** Die Aliasse des Profils, geprüft gegen die Kataloge ihrer Ziele samt Denktiefe. */
90
+ /** Die Aliasse des Profils, geprüft gegen die Kataloge ihrer Ziele samt Denktiefe und Kompaktierungswerten. */
61
91
  export const validatedModelAliases = (): readonly ModelAlias[] => {
62
92
  const aliases = configuredModelAliases();
63
93
  if (aliases.length > 0) aliasCatalog(aliases);
@@ -74,8 +74,9 @@ export const withFolderAssets = (plugin: RAgentsPlugin): RAgentsPlugin => ({
74
74
  if (skillPaths.length === 0) return;
75
75
  host.skills({
76
76
  id: `${plugin.manifest.id}.folder-skills`,
77
+ // Ein ausdrücklich angemeldeter Pfad gehört in jedem Run dem ausdrücklichen Beitrag, auch wo der ihn für diesen Run weglässt.
77
78
  paths: async (context) => {
78
- const explicit = await Promise.all(explicitSkills.map((skill) => skill.paths(context)));
79
+ const explicit = await Promise.all(explicitSkills.flatMap((skill) => [skill.paths(undefined), skill.paths(context)]));
79
80
  const taken = new Set(explicit.flat());
80
81
  return skillPaths.filter((skillPath) => !taken.has(skillPath));
81
82
  },
@@ -1,4 +1,5 @@
1
- import type { Api, Model } from "@ragents/ai";
1
+ import { compactionProblem } from "@ragents/agent";
2
+ import type { Api, Model, ModelCompaction } from "@ragents/ai";
2
3
  import type { ModelProviderRegistration } from "@ragents/engine";
3
4
 
4
5
  export const RELAY_PROVIDER = "relay";
@@ -9,7 +10,7 @@ export interface RelayConnection {
9
10
  readonly token: string;
10
11
  }
11
12
 
12
- /** Was das Relay je Alias über das dahinterliegende Modell verrät; der echte Name bleibt beim Server. */
13
+ /** Was das Relay je Alias über das dahinterliegende Modell verrät, samt den Kompaktierungswerten des Alias; der echte Name bleibt beim Server. */
13
14
  export interface RelayCatalogEntry {
14
15
  readonly id: string;
15
16
  readonly object: "model";
@@ -19,6 +20,7 @@ export interface RelayCatalogEntry {
19
20
  readonly input: Model<Api>["input"];
20
21
  readonly contextWindow: number;
21
22
  readonly maxTokens: number;
23
+ readonly compaction: ModelCompaction;
22
24
  readonly compat?: Model<Api>["compat"];
23
25
  };
24
26
  }
@@ -61,6 +63,7 @@ const modelOf = (entry: RelayCatalogEntry, baseUrl: string): Model<"openai-compl
61
63
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
62
64
  contextWindow: entry.catalog.contextWindow,
63
65
  maxTokens: entry.catalog.maxTokens,
66
+ compaction: entry.catalog.compaction,
64
67
  ...(entry.catalog.compat ? { compat: entry.catalog.compat as Model<"openai-completions">["compat"] } : {}),
65
68
  });
66
69
 
@@ -83,6 +86,10 @@ export const createRelayCatalog = (connection: RelayConnection, fetchImpl: typeo
83
86
  const body = await response.json() as { data?: unknown };
84
87
  if (!Array.isArray(body.data) || !body.data.every(isEntry)) throw new Error(`Das Modell-Relay ${address} liefert keinen gültigen Aliaskatalog`);
85
88
  if (body.data.length === 0) throw new Error(`Das Modell-Relay ${address} bietet keine Modelle an`);
89
+ for (const entry of body.data) {
90
+ const problem = compactionProblem(entry.catalog.compaction, entry.catalog);
91
+ if (problem) throw new Error(`The model relay ${address} offers ${entry.id} without valid compaction values: ${problem}`);
92
+ }
86
93
  loaded = body.data.map((entry) => modelOf(entry, baseUrl));
87
94
  return loaded;
88
95
  };
@@ -110,6 +117,7 @@ export const createRelayCatalog = (connection: RelayConnection, fetchImpl: typeo
110
117
  cost: model.cost,
111
118
  contextWindow: model.contextWindow,
112
119
  maxTokens: model.maxTokens,
120
+ ...(model.compaction ? { compaction: model.compaction } : {}),
113
121
  ...(model.compat ? { compat: model.compat } : {}),
114
122
  })),
115
123
  },