@schlenkr/ragents 0.1.8 → 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 (174) 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/product-relay.ts +10 -2
  12. package/apps/server/src/plugin-support/workspace-sandbox-host.ts +18 -9
  13. package/apps/server/src/profile/bundle-manifest.ts +7 -3
  14. package/apps/server/src/profile/compose.ts +6 -0
  15. package/apps/server/src/profile/plugin-discovery.ts +6 -1
  16. package/apps/server/src/profile/provisioning.ts +6 -5
  17. package/apps/server/src/ragents/engine.ts +0 -1
  18. package/apps/server/src/ragents/host-services.ts +4 -0
  19. package/apps/server/src/ragents/session.ts +1 -1
  20. package/apps/server/src/server.ts +1 -0
  21. package/apps/server/tsconfig.json +2 -0
  22. package/apps/web/dist/help/guide-clients.html +14 -6
  23. package/apps/web/dist/help/guide-clients.md +14 -6
  24. package/apps/web/dist/help/guide-distributed.html +12 -4
  25. package/apps/web/dist/help/guide-distributed.md +12 -4
  26. package/apps/web/dist/help/guide-getting-started.html +12 -8
  27. package/apps/web/dist/help/guide-getting-started.md +12 -8
  28. package/apps/web/dist/help/guide-plugins.html +6 -2
  29. package/apps/web/dist/help/guide-plugins.md +6 -2
  30. package/apps/web/dist/help/guide-runtime.html +2 -1
  31. package/apps/web/dist/help/guide-runtime.md +2 -1
  32. package/apps/web/dist/help/index.html +3328 -1135
  33. package/apps/web/dist/host-web.json +3 -3
  34. package/bundles/ragents.activity/ragents-bundle.json +3 -3
  35. package/bundles/ragents.actor-programs/ragents-bundle.json +3 -3
  36. package/bundles/ragents.ask/ragents-bundle.json +4 -4
  37. package/bundles/ragents.ask/server/index.js +42 -11
  38. package/bundles/ragents.ask/server/index.js.map +3 -3
  39. package/bundles/ragents.ask/web/chunks/chunk-WFN4374U.js +2 -0
  40. package/bundles/ragents.ask/web/chunks/chunk-WFN4374U.js.map +7 -0
  41. package/bundles/ragents.ask/web/classes.json +1 -1
  42. package/bundles/ragents.ask/web/exports/ask-payload.js +1 -1
  43. package/bundles/ragents.ask/web/index.js +1 -1
  44. package/bundles/ragents.ask/web/index.js.map +3 -3
  45. package/bundles/ragents.browser/executor/index.mjs +357 -0
  46. package/bundles/ragents.browser/executor/index.mjs.map +7 -0
  47. package/bundles/ragents.browser/ragents-bundle.json +5 -8
  48. package/bundles/ragents.browser/server/chunks/{chunk-2GKLLCBE.js → chunk-CWLX4VA5.js} +1 -1
  49. package/bundles/ragents.browser/server/chunks/chunk-CWLX4VA5.js.map +7 -0
  50. package/bundles/ragents.browser/server/exports/server/contract.js +1 -1
  51. package/bundles/ragents.browser/server/index.js +20 -9
  52. package/bundles/ragents.browser/server/index.js.map +4 -4
  53. package/bundles/ragents.documents/ragents-bundle.json +3 -3
  54. package/bundles/ragents.lsp-fsharp/executor/index.mjs +68 -0
  55. package/bundles/ragents.lsp-fsharp/executor/index.mjs.map +7 -0
  56. package/bundles/ragents.lsp-fsharp/ragents-bundle.json +5 -9
  57. package/bundles/ragents.lsp-fsharp/server/index.js +21 -6
  58. package/bundles/ragents.lsp-fsharp/server/index.js.map +4 -4
  59. package/bundles/ragents.lsp-roslyn/executor/index.mjs +68 -0
  60. package/bundles/ragents.lsp-roslyn/executor/index.mjs.map +7 -0
  61. package/bundles/ragents.lsp-roslyn/ragents-bundle.json +6 -8
  62. package/bundles/ragents.lsp-roslyn/server/index.js +54 -15
  63. package/bundles/ragents.lsp-roslyn/server/index.js.map +4 -4
  64. package/bundles/ragents.lsp-typescript/executor/index.mjs +49 -0
  65. package/bundles/ragents.lsp-typescript/executor/index.mjs.map +7 -0
  66. package/bundles/ragents.lsp-typescript/ragents-bundle.json +5 -7
  67. package/bundles/ragents.lsp-typescript/server/index.js +22 -2
  68. package/bundles/ragents.lsp-typescript/server/index.js.map +3 -3
  69. package/bundles/ragents.model-relay/ragents-bundle.json +4 -4
  70. package/bundles/ragents.model-relay/server/index.js +3 -2
  71. package/bundles/ragents.model-relay/server/index.js.map +2 -2
  72. package/bundles/ragents.orchestration/ragents-bundle.json +3 -3
  73. package/bundles/ragents.overseer/ragents-bundle.json +3 -3
  74. package/bundles/ragents.processes/ragents-bundle.json +3 -3
  75. package/bundles/ragents.product/ragents-bundle.json +3 -3
  76. package/bundles/ragents.profile-distribution/ragents-bundle.json +4 -4
  77. package/bundles/ragents.profile-distribution/server/index.js +1 -1
  78. package/bundles/ragents.profile-distribution/server/index.js.map +2 -2
  79. package/bundles/ragents.reference/ragents-bundle.json +3 -3
  80. package/bundles/ragents.todo/ragents-bundle.json +3 -3
  81. package/bundles/ragents.transcript/ragents-bundle.json +3 -3
  82. package/bundles/ragents.watch/ragents-bundle.json +3 -3
  83. package/bundles/ragents.workspace/ragents-bundle.json +11 -5
  84. package/bundles/ragents.workspace/server/index.js +101 -28
  85. package/bundles/ragents.workspace/server/index.js.map +3 -3
  86. package/bundles/ragents.workspace/web/classes.json +1 -1
  87. package/bundles/ragents.workspace/web/index.js +1 -1
  88. package/bundles/ragents.workspace/web/index.js.map +3 -3
  89. package/package.json +2 -2
  90. package/packages/agent/dist/core/agent-settings.d.ts +1 -7
  91. package/packages/agent/dist/core/compaction/compaction.d.ts +17 -13
  92. package/packages/agent/dist/core/model-runtime.d.ts +5 -4
  93. package/packages/agent/dist/core/provider-composer.d.ts +2 -1
  94. package/packages/agent/dist/core/tools/bash.d.ts +9 -3
  95. package/packages/agent/dist/index.d.ts +1 -1
  96. package/packages/agent/src/core/agent-settings.ts +1 -4
  97. package/packages/agent/src/core/compaction/compaction.ts +68 -30
  98. package/packages/agent/src/core/model-runtime.ts +12 -5
  99. package/packages/agent/src/core/provider-composer.ts +5 -0
  100. package/packages/agent/src/core/tools/bash.ts +36 -30
  101. package/packages/agent/src/index.ts +3 -0
  102. package/packages/ai/dist/types.d.ts +11 -0
  103. package/packages/ai/src/types.ts +12 -0
  104. package/packages/ragents/src/domain/event-semantics.ts +3 -0
  105. package/packages/ragents/src/domain/event-validation.ts +15 -2
  106. package/packages/ragents/src/domain/events.ts +3 -0
  107. package/packages/ragents/src/domain/model.ts +2 -0
  108. package/packages/ragents/src/domain/projection.ts +1 -0
  109. package/packages/ragents/src/drivers/agent-runtime.ts +1 -1
  110. package/packages/ragents/src/drivers/agent-turn.ts +8 -6
  111. package/packages/ragents/src/runtime/decisions/inputs.ts +6 -2
  112. package/packages/ragents/src/runtime/journal-storage.ts +5 -4
  113. package/packages/workspace-executor/package.json +0 -1
  114. package/packages/workspace-executor/src/bash-launch.ts +56 -10
  115. package/packages/workspace-executor/src/context.ts +4 -0
  116. package/packages/workspace-executor/src/contributions.ts +150 -0
  117. package/packages/workspace-executor/src/executor.ts +1 -1
  118. package/packages/workspace-executor/src/index.ts +16 -19
  119. package/packages/workspace-executor/src/language-server/host.ts +3 -0
  120. package/packages/workspace-executor/src/language-server/module.ts +12 -2
  121. package/packages/workspace-executor/src/language-server/roots.ts +0 -5
  122. package/packages/workspace-executor/src/modules.ts +7 -6
  123. package/packages/workspace-executor/src/sandbox-tools.ts +3 -9
  124. package/packages/workspace-executor/src/shell-platform.ts +14 -3
  125. package/packages/workspace-executor/src/tools.ts +0 -3
  126. package/plugins/ragents.ask/ask-payload.ts +9 -0
  127. package/plugins/ragents.ask/server/ask-service.ts +53 -13
  128. package/plugins/ragents.ask/web/AskActionView.tsx +3 -2
  129. package/plugins/ragents.browser/executor/index.ts +5 -0
  130. package/{packages/workspace-executor/src/browser → plugins/ragents.browser/executor}/module.ts +25 -31
  131. package/{packages/workspace-executor/src/browser → plugins/ragents.browser/executor}/playwright.ts +9 -23
  132. package/plugins/ragents.browser/provision.ts +1 -1
  133. package/plugins/ragents.browser/server/browser.ts +3 -3
  134. package/plugins/ragents.browser/server/contract.ts +2 -2
  135. package/plugins/ragents.browser/server/index.ts +1 -1
  136. package/plugins/ragents.lsp-fsharp/executor.ts +80 -0
  137. package/plugins/ragents.lsp-fsharp/provision.ts +1 -1
  138. package/plugins/ragents.lsp-fsharp/server/index.ts +2 -2
  139. package/plugins/ragents.lsp-roslyn/executor.ts +64 -0
  140. package/plugins/ragents.lsp-roslyn/provision.ts +1 -1
  141. package/plugins/ragents.lsp-roslyn/server/index.ts +28 -5
  142. package/plugins/ragents.lsp-roslyn/server/solution-on-start.ts +18 -6
  143. package/plugins/ragents.lsp-typescript/executor.ts +50 -0
  144. package/plugins/ragents.lsp-typescript/server/index.ts +2 -2
  145. package/plugins/ragents.model-relay/server/config.ts +1 -1
  146. package/plugins/ragents.model-relay/server/relay.ts +4 -2
  147. package/plugins/ragents.profile-distribution/server/archive.ts +2 -1
  148. package/plugins/ragents.workspace/client/workspace-client.ts +111 -28
  149. package/plugins/ragents.workspace/contract.ts +33 -2
  150. package/plugins/ragents.workspace/server/binding.ts +10 -4
  151. package/plugins/ragents.workspace/server/clients.ts +56 -9
  152. package/plugins/ragents.workspace/server/config.ts +9 -0
  153. package/plugins/ragents.workspace/server/index.ts +13 -4
  154. package/plugins/ragents.workspace/server/runtime.ts +10 -0
  155. package/plugins/ragents.workspace/server/shell-platform.ts +6 -5
  156. package/plugins/ragents.workspace/web/WorkspaceBinding.tsx +1 -1
  157. package/ragents.config.core.ts +4 -1
  158. package/ragents.config.showcase.ts +4 -1
  159. package/scripts/agent/journal.ts +3 -1
  160. package/scripts/package/build-package.ts +3 -1
  161. package/scripts/provision/run-provision.ts +2 -2
  162. package/scripts/workspace-client/run-workspace-client.ts +7 -4
  163. package/apps/web/dist/help/screenshots/release-checklist-vscode.png +0 -0
  164. package/apps/web/dist/help/screenshots/release-checklist-web.png +0 -0
  165. package/bundles/ragents.ask/web/chunks/chunk-HGFDGTNC.js +0 -2
  166. package/bundles/ragents.ask/web/chunks/chunk-HGFDGTNC.js.map +0 -7
  167. package/bundles/ragents.browser/server/chunks/chunk-2GKLLCBE.js.map +0 -7
  168. package/packages/workspace-executor/src/language-server/adapters/fsharp.ts +0 -60
  169. package/packages/workspace-executor/src/language-server/adapters/index.ts +0 -7
  170. package/packages/workspace-executor/src/language-server/adapters/roslyn.ts +0 -56
  171. package/packages/workspace-executor/src/language-server/adapters/typescript.ts +0 -74
  172. package/packages/workspace-executor/src/language-server/solution.ts +0 -13
  173. /package/{packages/workspace-executor/src/browser → plugins/ragents.browser/executor}/contract.ts +0 -0
  174. /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);
@@ -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
  },
@@ -1,5 +1,6 @@
1
1
  import { mkdir, realpath } from "node:fs/promises";
2
2
  import path from "node:path";
3
+ import { Value } from "typebox/value";
3
4
  import {
4
5
  DomainError,
5
6
  serviceToken,
@@ -28,6 +29,7 @@ import {
28
29
  type SessionIdent,
29
30
  type WorkspaceExecuteOptions,
30
31
  type WorkspaceExecutor,
32
+ type WorkspaceExecutorParts,
31
33
  type WorkspaceProcessContext,
32
34
  } from "@ragents/workspace-executor";
33
35
  import { hostRoot } from "../host-version.js";
@@ -70,6 +72,8 @@ export const sandboxServicesToken = serviceToken<SandboxServices>("ragents.works
70
72
 
71
73
  export interface WorkspaceSandboxHostOptions {
72
74
  contributorName: string;
75
+ /** Was die Plugins des Profils zum Executor dieses Servers beitragen; jeder Arbeitsplatz der Runs trägt dieselben Beiträge. */
76
+ contributions: readonly WorkspaceExecutorParts[];
73
77
  workspaceFor: (runId: string) => Promise<SessionWorkspace>;
74
78
  identFor: (runId: string) => Promise<SessionIdent | undefined>;
75
79
  skillPaths: () => Promise<readonly string[]>;
@@ -83,6 +87,10 @@ export interface WorkspaceSandboxHostOptions {
83
87
  processSandbox?: RunProcessSandboxes;
84
88
  /** Die Bash des Executors dieses Servers; unter Windows Pflicht, sonst ohne Angabe die des Systems. */
85
89
  bash?: string;
90
+ /** Das rg des Executors dieses Servers; ohne Angabe gilt eines im PATH. */
91
+ rg?: string;
92
+ /** Die Zeitgrenze von bash in Sekunden für Aufrufe ohne eigene, auf jeder Maschine der Runs; ohne Angabe die des Werkzeugs. */
93
+ bashTimeoutSeconds?: number;
86
94
  }
87
95
 
88
96
  const sandboxDescriptions: Readonly<Record<string, string>> = {
@@ -98,16 +106,13 @@ const describeSandboxTool = (definition: AgentToolDefinition): AgentToolDefiniti
98
106
  return { ...definition, description, longDescription: definition.description, nativeTool: true };
99
107
  };
100
108
 
101
- const sandboxDescriptorDefinitions = [
109
+ const sandboxDefinitions = (bashTimeoutSeconds: number | undefined): readonly AgentToolDefinition[] => [
102
110
  createReadToolDefinition("."),
103
111
  createEditToolDefinition("."),
104
112
  createWriteToolDefinition("."),
105
- createBashToolDefinition("."),
113
+ createBashToolDefinition(".", bashTimeoutSeconds === undefined ? {} : { defaultTimeoutSeconds: bashTimeoutSeconds }),
106
114
  ] as readonly AgentToolDefinition[];
107
115
 
108
- const sandboxDescriptors = sandboxDescriptorDefinitions.map((definition) =>
109
- toolDescriptorFrom(describeSandboxTool(definition), alwaysAvailable));
110
-
111
116
  const fileToolNames = new Set(["read", "edit", "write"]);
112
117
 
113
118
  interface StableRunParts {
@@ -142,6 +147,7 @@ const existingRoots = async (roots: readonly ResolvedWorkspaceRoot[]): Promise<R
142
147
  /** Der Executor des Servers mit den Wurzeln des Servers; eine Operation mit Alias läuft dort, jede andere beim Executor der Bindung des Runs. */
143
148
  export class WorkspaceSandboxHost implements SandboxServices {
144
149
  readonly #options: WorkspaceSandboxHostOptions;
150
+ readonly #definitions: readonly AgentToolDefinition[];
145
151
  readonly #workspaceRoots: RegisteredWorkspaceRoot[] = [];
146
152
  readonly #local: WorkspaceOperationExecutor;
147
153
  readonly #stable = new Map<string, Promise<StableRunParts>>();
@@ -150,9 +156,10 @@ export class WorkspaceSandboxHost implements SandboxServices {
150
156
 
151
157
  constructor(options: WorkspaceSandboxHostOptions) {
152
158
  this.#options = options;
159
+ this.#definitions = sandboxDefinitions(options.bashTimeoutSeconds);
153
160
  this.#local = new WorkspaceOperationExecutor({
154
161
  contextFor: (runId) => this.serverProcessContextFor(runId),
155
- modules: workspaceExecutorModules(),
162
+ modules: workspaceExecutorModules({ contributions: options.contributions }),
156
163
  });
157
164
  }
158
165
 
@@ -234,6 +241,7 @@ export class WorkspaceSandboxHost implements SandboxServices {
234
241
  runOperation: workspace.runOperation,
235
242
  ...(sandbox ? { sandbox } : {}),
236
243
  ...(this.#options.bash === undefined ? {} : { bash: this.#options.bash }),
244
+ ...(this.#options.rg === undefined ? {} : { rg: this.#options.rg }),
237
245
  });
238
246
  }
239
247
 
@@ -288,7 +296,7 @@ export class WorkspaceSandboxHost implements SandboxServices {
288
296
  workspaceTools(): ToolContributor {
289
297
  return {
290
298
  name: this.#options.contributorName,
291
- descriptors: sandboxDescriptors,
299
+ descriptors: this.#definitions.map((definition) => toolDescriptorFrom(describeSandboxTool(definition), alwaysAvailable)),
292
300
  tools: (context) => this.#workspaceToolsFor(context),
293
301
  };
294
302
  }
@@ -330,12 +338,13 @@ export class WorkspaceSandboxHost implements SandboxServices {
330
338
  }
331
339
 
332
340
  #workspaceToolsFor(context: PluginContext): Promise<RunFunction[]> {
333
- return Promise.resolve(sandboxDescriptorDefinitions.map((definition) => {
341
+ return Promise.resolve(this.#definitions.map((definition) => {
334
342
  const described = describeSandboxTool(definition);
335
343
  const proxy = {
336
344
  ...described,
345
+ // Die Vorgaben des Schemas, etwa die Zeitgrenze von bash, setzt der Server ein; so gilt auf jeder Maschine, was das Modell im Schema sieht.
337
346
  execute: (toolCallId: string, params: unknown, signal: AbortSignal | undefined) =>
338
- this.execute(context.runId, described.name, params, {
347
+ this.execute(context.runId, described.name, Value.Default(described.parameters, structuredClone(params)), {
339
348
  toolCallId,
340
349
  ...(signal ? { signal } : {}),
341
350
  }),