@theia/ai-core 1.77.0-next.7 → 1.77.0-next.77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/agents-md-frontend-application-contribution.d.ts +65 -0
- package/lib/browser/agents-md-frontend-application-contribution.d.ts.map +1 -0
- package/lib/browser/agents-md-frontend-application-contribution.js +269 -0
- package/lib/browser/agents-md-frontend-application-contribution.js.map +1 -0
- package/lib/browser/agents-md-frontend-application-contribution.spec.d.ts +2 -0
- package/lib/browser/agents-md-frontend-application-contribution.spec.d.ts.map +1 -0
- package/lib/browser/agents-md-frontend-application-contribution.spec.js +225 -0
- package/lib/browser/agents-md-frontend-application-contribution.spec.js.map +1 -0
- package/lib/browser/agents-md-migration-service.d.ts +78 -0
- package/lib/browser/agents-md-migration-service.d.ts.map +1 -0
- package/lib/browser/agents-md-migration-service.js +195 -0
- package/lib/browser/agents-md-migration-service.js.map +1 -0
- package/lib/browser/agents-md-migration-service.spec.d.ts +2 -0
- package/lib/browser/agents-md-migration-service.spec.d.ts.map +1 -0
- package/lib/browser/agents-md-migration-service.spec.js +278 -0
- package/lib/browser/agents-md-migration-service.spec.js.map +1 -0
- package/lib/browser/agents-md-prompt-fragment-contribution.d.ts +13 -0
- package/lib/browser/agents-md-prompt-fragment-contribution.d.ts.map +1 -0
- package/lib/browser/agents-md-prompt-fragment-contribution.js +76 -0
- package/lib/browser/agents-md-prompt-fragment-contribution.js.map +1 -0
- package/lib/browser/agents-md-service.d.ts +58 -0
- package/lib/browser/agents-md-service.d.ts.map +1 -0
- package/lib/browser/agents-md-service.js +191 -0
- package/lib/browser/agents-md-service.js.map +1 -0
- package/lib/browser/agents-md-service.spec.d.ts +2 -0
- package/lib/browser/agents-md-service.spec.d.ts.map +1 -0
- package/lib/browser/agents-md-service.spec.js +220 -0
- package/lib/browser/agents-md-service.spec.js.map +1 -0
- package/lib/browser/agents-md-variable-contribution.d.ts +66 -0
- package/lib/browser/agents-md-variable-contribution.d.ts.map +1 -0
- package/lib/browser/agents-md-variable-contribution.js +169 -0
- package/lib/browser/agents-md-variable-contribution.js.map +1 -0
- package/lib/browser/agents-md-variable-contribution.spec.d.ts +2 -0
- package/lib/browser/agents-md-variable-contribution.spec.d.ts.map +1 -0
- package/lib/browser/agents-md-variable-contribution.spec.js +148 -0
- package/lib/browser/agents-md-variable-contribution.spec.js.map +1 -0
- package/lib/browser/ai-core-frontend-module.d.ts.map +1 -1
- package/lib/browser/ai-core-frontend-module.js +17 -0
- package/lib/browser/ai-core-frontend-module.js.map +1 -1
- package/lib/browser/file-variable-contribution.d.ts +2 -0
- package/lib/browser/file-variable-contribution.d.ts.map +1 -1
- package/lib/browser/file-variable-contribution.js +8 -23
- package/lib/browser/file-variable-contribution.js.map +1 -1
- package/lib/browser/file-variable-contribution.spec.d.ts +2 -0
- package/lib/browser/file-variable-contribution.spec.d.ts.map +1 -0
- package/lib/browser/file-variable-contribution.spec.js +98 -0
- package/lib/browser/file-variable-contribution.spec.js.map +1 -0
- package/lib/browser/frontend-language-model-service.d.ts.map +1 -1
- package/lib/browser/frontend-language-model-service.js +0 -8
- package/lib/browser/frontend-language-model-service.js.map +1 -1
- package/lib/browser/frontend-prompt-customization-service.d.ts +2 -1
- package/lib/browser/frontend-prompt-customization-service.d.ts.map +1 -1
- package/lib/browser/frontend-prompt-customization-service.js +10 -0
- package/lib/browser/frontend-prompt-customization-service.js.map +1 -1
- package/lib/browser/frontend-prompt-customization-service.spec.js +19 -1
- package/lib/browser/frontend-prompt-customization-service.spec.js.map +1 -1
- package/lib/browser/frontend-variable-service.js +1 -1
- package/lib/browser/frontend-variable-service.js.map +1 -1
- package/lib/browser/index.d.ts +6 -0
- package/lib/browser/index.d.ts.map +1 -1
- package/lib/browser/index.js +6 -0
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/prompt-variable-contribution.js +1 -1
- package/lib/browser/prompt-variable-contribution.js.map +1 -1
- package/lib/browser/prompt-variable-contribution.spec.js +2 -1
- package/lib/browser/prompt-variable-contribution.spec.js.map +1 -1
- package/lib/browser/prompttemplate-contribution.js +1 -1
- package/lib/browser/prompttemplate-contribution.js.map +1 -1
- package/lib/browser/reasoning-labels.d.ts +4 -0
- package/lib/browser/reasoning-labels.d.ts.map +1 -0
- package/lib/browser/reasoning-labels.js +41 -0
- package/lib/browser/reasoning-labels.js.map +1 -0
- package/lib/browser/reasoning-labels.spec.d.ts +2 -0
- package/lib/browser/reasoning-labels.spec.d.ts.map +1 -0
- package/lib/browser/reasoning-labels.spec.js +28 -0
- package/lib/browser/reasoning-labels.spec.js.map +1 -0
- package/lib/browser/skill-service.spec.js +2 -1
- package/lib/browser/skill-service.spec.js.map +1 -1
- package/lib/browser/skills-variable-contribution.spec.js +2 -1
- package/lib/browser/skills-variable-contribution.spec.js.map +1 -1
- package/lib/browser/theia-variable-contribution.js +3 -3
- package/lib/browser/theia-variable-contribution.js.map +1 -1
- package/lib/browser/workspace-relative-path-resolver.d.ts +20 -0
- package/lib/browser/workspace-relative-path-resolver.d.ts.map +1 -0
- package/lib/browser/workspace-relative-path-resolver.js +78 -0
- package/lib/browser/workspace-relative-path-resolver.js.map +1 -0
- package/lib/common/agents-md.d.ts +20 -0
- package/lib/common/agents-md.d.ts.map +1 -0
- package/lib/common/agents-md.js +38 -0
- package/lib/common/agents-md.js.map +1 -0
- package/lib/common/ai-core-preferences.d.ts.map +1 -1
- package/lib/common/ai-core-preferences.js +6 -3
- package/lib/common/ai-core-preferences.js.map +1 -1
- package/lib/common/ai-variable-resource.js +3 -3
- package/lib/common/ai-variable-resource.js.map +1 -1
- package/lib/common/capability-variable-contribution.js +1 -1
- package/lib/common/capability-variable-contribution.js.map +1 -1
- package/lib/common/index.d.ts +2 -0
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js +2 -0
- package/lib/common/index.js.map +1 -1
- package/lib/common/language-model-service.d.ts.map +1 -1
- package/lib/common/language-model-service.js +7 -0
- package/lib/common/language-model-service.js.map +1 -1
- package/lib/common/language-model-service.spec.js +21 -0
- package/lib/common/language-model-service.spec.js.map +1 -1
- package/lib/common/language-model.d.ts +10 -3
- package/lib/common/language-model.d.ts.map +1 -1
- package/lib/common/language-model.js +17 -4
- package/lib/common/language-model.js.map +1 -1
- package/lib/common/language-model.spec.js +18 -0
- package/lib/common/language-model.spec.js.map +1 -1
- package/lib/common/prompt-service.d.ts +12 -0
- package/lib/common/prompt-service.d.ts.map +1 -1
- package/lib/common/prompt-service.js.map +1 -1
- package/lib/common/prompt-service.spec.js +2 -1
- package/lib/common/prompt-service.spec.js.map +1 -1
- package/lib/common/tool-call-execution.d.ts +89 -0
- package/lib/common/tool-call-execution.d.ts.map +1 -0
- package/lib/common/tool-call-execution.js +67 -0
- package/lib/common/tool-call-execution.js.map +1 -0
- package/lib/common/tool-call-execution.spec.d.ts +2 -0
- package/lib/common/tool-call-execution.spec.d.ts.map +1 -0
- package/lib/common/tool-call-execution.spec.js +114 -0
- package/lib/common/tool-call-execution.spec.js.map +1 -0
- package/lib/common/tool-request-parameters.spec.d.ts +2 -0
- package/lib/common/tool-request-parameters.spec.d.ts.map +1 -0
- package/lib/common/tool-request-parameters.spec.js +62 -0
- package/lib/common/tool-request-parameters.spec.js.map +1 -0
- package/lib/common/variable-service.spec.js +2 -1
- package/lib/common/variable-service.spec.js.map +1 -1
- package/lib/node/ai-core-backend-module.d.ts.map +1 -1
- package/lib/node/ai-core-backend-module.js +2 -0
- package/lib/node/ai-core-backend-module.js.map +1 -1
- package/lib/node/model-snapshot-store.js +2 -2
- package/lib/node/model-snapshot-store.js.map +1 -1
- package/lib/node/proxy-util.js +2 -1
- package/lib/node/proxy-util.js.map +1 -1
- package/package.json +9 -9
- package/src/browser/agents-md-frontend-application-contribution.spec.ts +244 -0
- package/src/browser/agents-md-frontend-application-contribution.ts +291 -0
- package/src/browser/agents-md-migration-service.spec.ts +338 -0
- package/src/browser/agents-md-migration-service.ts +226 -0
- package/src/browser/agents-md-prompt-fragment-contribution.ts +73 -0
- package/src/browser/agents-md-service.spec.ts +258 -0
- package/src/browser/agents-md-service.ts +212 -0
- package/src/browser/agents-md-variable-contribution.spec.ts +180 -0
- package/src/browser/agents-md-variable-contribution.ts +182 -0
- package/src/browser/ai-core-frontend-module.ts +19 -0
- package/src/browser/file-variable-contribution.spec.ts +107 -0
- package/src/browser/file-variable-contribution.ts +8 -27
- package/src/browser/frontend-language-model-service.ts +1 -10
- package/src/browser/frontend-prompt-customization-service.spec.ts +24 -0
- package/src/browser/frontend-prompt-customization-service.ts +13 -1
- package/src/browser/index.ts +6 -0
- package/src/browser/reasoning-labels.spec.ts +28 -0
- package/src/browser/reasoning-labels.ts +41 -0
- package/src/browser/theia-variable-contribution.ts +3 -3
- package/src/browser/workspace-relative-path-resolver.ts +71 -0
- package/src/common/agents-md.ts +37 -0
- package/src/common/ai-core-preferences.ts +6 -3
- package/src/common/ai-variable-resource.ts +1 -1
- package/src/common/index.ts +2 -0
- package/src/common/language-model-service.spec.ts +23 -1
- package/src/common/language-model-service.ts +11 -1
- package/src/common/language-model.spec.ts +21 -0
- package/src/common/language-model.ts +26 -6
- package/src/common/prompt-service.ts +14 -0
- package/src/common/tool-call-execution.spec.ts +162 -0
- package/src/common/tool-call-execution.ts +161 -0
- package/src/common/tool-request-parameters.spec.ts +81 -0
- package/src/node/ai-core-backend-module.ts +5 -1
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 EclipseSource GmbH.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { inject, injectable, named, postConstruct } from '@theia/core/shared/inversify';
|
|
18
|
+
import { Deferred } from '@theia/core/lib/common/promise-util';
|
|
19
|
+
import { Disposable, DisposableCollection, Emitter, Event, ILogger, URI } from '@theia/core';
|
|
20
|
+
import { FileService } from '@theia/filesystem/lib/browser/file-service';
|
|
21
|
+
import { FileChangesEvent, FileOperationEvent } from '@theia/filesystem/lib/common/files';
|
|
22
|
+
import { WorkspaceService } from '@theia/workspace/lib/browser';
|
|
23
|
+
import { AGENTS_MD_FILE_NAME } from '../common/agents-md';
|
|
24
|
+
|
|
25
|
+
/** Debounce delay for coalescing rapid file system events. */
|
|
26
|
+
const UPDATE_DEBOUNCE_MS = 50;
|
|
27
|
+
|
|
28
|
+
export interface AgentsMdFile {
|
|
29
|
+
/** URI of the discovered `AGENTS.md`. */
|
|
30
|
+
uri: URI;
|
|
31
|
+
/** Content as of the last scan. */
|
|
32
|
+
content: string;
|
|
33
|
+
/** Name of the workspace root holding the file, used as provenance label when merging several roots. */
|
|
34
|
+
rootName: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const AgentsMdService = Symbol('AgentsMdService');
|
|
38
|
+
export interface AgentsMdService {
|
|
39
|
+
/** The `AGENTS.md` files discovered in the workspace roots, in workspace root order. */
|
|
40
|
+
getAgentsMdFiles(): AgentsMdFile[];
|
|
41
|
+
|
|
42
|
+
/** Fired after every scan, whether or not the result changed. */
|
|
43
|
+
readonly onDidChange: Event<void>;
|
|
44
|
+
|
|
45
|
+
/** Resolves once the initial scan is complete. Always resolves, even if the scan failed. */
|
|
46
|
+
readonly ready: Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Discovers `<root>/AGENTS.md` for every workspace root and keeps the content up to date.
|
|
51
|
+
*
|
|
52
|
+
* Only the workspace roots themselves are scanned. A nested `AGENTS.md` cascade with proximity
|
|
53
|
+
* precedence, `@path` imports and a global `~/.agents/AGENTS.md` are deliberately out of scope.
|
|
54
|
+
*/
|
|
55
|
+
@injectable()
|
|
56
|
+
export class DefaultAgentsMdService implements AgentsMdService, Disposable {
|
|
57
|
+
|
|
58
|
+
@inject(FileService)
|
|
59
|
+
protected readonly fileService: FileService;
|
|
60
|
+
|
|
61
|
+
@inject(WorkspaceService)
|
|
62
|
+
protected readonly workspaceService: WorkspaceService;
|
|
63
|
+
|
|
64
|
+
@inject(ILogger) @named('ai-core:DefaultAgentsMdService')
|
|
65
|
+
protected readonly logger: ILogger;
|
|
66
|
+
|
|
67
|
+
protected files: AgentsMdFile[] = [];
|
|
68
|
+
|
|
69
|
+
/** Watchers of the current scan; disposed and rebuilt on every rescan. */
|
|
70
|
+
protected toDispose = new DisposableCollection();
|
|
71
|
+
/** Kept apart from {@link toDispose}, which does not survive a rescan. */
|
|
72
|
+
protected readonly toDisposeOnServiceDispose = new DisposableCollection();
|
|
73
|
+
|
|
74
|
+
/** URIs of the `AGENTS.md` files we react to: one per workspace root, whether or not it exists. */
|
|
75
|
+
protected watchedFiles = new Set<string>();
|
|
76
|
+
|
|
77
|
+
protected updateDebounceTimeout: ReturnType<typeof setTimeout> | undefined;
|
|
78
|
+
|
|
79
|
+
/** True while {@link update} is running, so concurrent callers do not duplicate the scan. */
|
|
80
|
+
protected updateInProgress = false;
|
|
81
|
+
/** Set when {@link update} is called while another run is in progress; triggers a follow-up scan. */
|
|
82
|
+
protected updateRescheduled = false;
|
|
83
|
+
|
|
84
|
+
protected readonly onDidChangeEmitter = new Emitter<void>();
|
|
85
|
+
readonly onDidChange: Event<void> = this.onDidChangeEmitter.event;
|
|
86
|
+
|
|
87
|
+
protected _ready = new Deferred<void>();
|
|
88
|
+
get ready(): Promise<void> {
|
|
89
|
+
return this._ready.promise;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@postConstruct()
|
|
93
|
+
protected init(): void {
|
|
94
|
+
this.toDisposeOnServiceDispose.push(this.onDidChangeEmitter);
|
|
95
|
+
this.toDisposeOnServiceDispose.push(this.fileService.onDidFilesChange((event: FileChangesEvent) => {
|
|
96
|
+
if (event.changes.some(change => this.isWatched(change.resource))) {
|
|
97
|
+
this.scheduleUpdate();
|
|
98
|
+
}
|
|
99
|
+
}));
|
|
100
|
+
// The watcher above only reports what the backend sees, and `FileService.watch` registers
|
|
101
|
+
// that watcher asynchronously. An `AGENTS.md` written through the application right after
|
|
102
|
+
// startup - most notably by the migration - therefore lands in the gap before the watcher is
|
|
103
|
+
// live and would be missed for the rest of the session. Operations performed through the
|
|
104
|
+
// FileService are reported here synchronously, independent of any watcher.
|
|
105
|
+
this.toDisposeOnServiceDispose.push(this.fileService.onDidRunOperation((event: FileOperationEvent) => {
|
|
106
|
+
if (this.isWatched(event.resource) || (event.target && this.isWatched(event.target.resource))) {
|
|
107
|
+
this.scheduleUpdate();
|
|
108
|
+
}
|
|
109
|
+
}));
|
|
110
|
+
this.initialize();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
protected async initialize(): Promise<void> {
|
|
114
|
+
try {
|
|
115
|
+
await this.workspaceService.ready;
|
|
116
|
+
} catch (error) {
|
|
117
|
+
this.logger.error('Failed to resolve the workspace, scanning the already known roots for AGENTS.md', error);
|
|
118
|
+
}
|
|
119
|
+
// Listen before the initial scan, otherwise a change landing while it runs is recorded as
|
|
120
|
+
// already applied and dropped. update()'s in-progress guard coalesces the overlap.
|
|
121
|
+
this.toDisposeOnServiceDispose.push(this.workspaceService.onWorkspaceChanged(() => this.scheduleUpdate()));
|
|
122
|
+
try {
|
|
123
|
+
await this.update();
|
|
124
|
+
} catch (error) {
|
|
125
|
+
this.logger.error('Initial AGENTS.md scan failed', error);
|
|
126
|
+
}
|
|
127
|
+
this._ready.resolve();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
getAgentsMdFiles(): AgentsMdFile[] {
|
|
131
|
+
return [...this.files];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Whether `resource` is one of the `AGENTS.md` locations this service tracks. */
|
|
135
|
+
protected isWatched(resource: URI): boolean {
|
|
136
|
+
return this.watchedFiles.has(resource.toString());
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
dispose(): void {
|
|
140
|
+
if (this.updateDebounceTimeout) {
|
|
141
|
+
clearTimeout(this.updateDebounceTimeout);
|
|
142
|
+
this.updateDebounceTimeout = undefined;
|
|
143
|
+
}
|
|
144
|
+
this.toDisposeOnServiceDispose.dispose();
|
|
145
|
+
this.toDispose.dispose();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
protected scheduleUpdate(): void {
|
|
149
|
+
if (this.updateDebounceTimeout) {
|
|
150
|
+
clearTimeout(this.updateDebounceTimeout);
|
|
151
|
+
}
|
|
152
|
+
this.updateDebounceTimeout = setTimeout(() => {
|
|
153
|
+
this.updateDebounceTimeout = undefined;
|
|
154
|
+
this.update();
|
|
155
|
+
}, UPDATE_DEBOUNCE_MS);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
protected async update(): Promise<void> {
|
|
159
|
+
if (this.updateDebounceTimeout) {
|
|
160
|
+
clearTimeout(this.updateDebounceTimeout);
|
|
161
|
+
this.updateDebounceTimeout = undefined;
|
|
162
|
+
}
|
|
163
|
+
// Serialise concurrent calls: a workspace-ready trigger and a file-change-driven
|
|
164
|
+
// scheduleUpdate() can fire within the same async tick. The second caller records a pending
|
|
165
|
+
// request and lets the first finish; the follow-up is re-scheduled through the debouncer.
|
|
166
|
+
if (this.updateInProgress) {
|
|
167
|
+
this.updateRescheduled = true;
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
this.updateInProgress = true;
|
|
171
|
+
try {
|
|
172
|
+
await this.doUpdate();
|
|
173
|
+
} finally {
|
|
174
|
+
this.updateInProgress = false;
|
|
175
|
+
if (this.updateRescheduled) {
|
|
176
|
+
this.updateRescheduled = false;
|
|
177
|
+
this.scheduleUpdate();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
protected async doUpdate(): Promise<void> {
|
|
183
|
+
const newDisposables = new DisposableCollection();
|
|
184
|
+
const newFiles: AgentsMdFile[] = [];
|
|
185
|
+
const roots = this.workspaceService.tryGetRoots();
|
|
186
|
+
|
|
187
|
+
// Publish the tracked locations before doing any I/O. A file operation landing while this
|
|
188
|
+
// scan is still running has to be recognized so that the in-progress guard can reschedule;
|
|
189
|
+
// assigning only at the end would drop it and leave this scan's stale result in place.
|
|
190
|
+
this.watchedFiles = new Set(roots.map(root => root.resource.resolve(AGENTS_MD_FILE_NAME).toString()));
|
|
191
|
+
|
|
192
|
+
for (const root of roots) {
|
|
193
|
+
const fileUri = root.resource.resolve(AGENTS_MD_FILE_NAME);
|
|
194
|
+
// Watch the root, not the file: a watcher on a missing file cannot report its creation.
|
|
195
|
+
newDisposables.push(this.fileService.watch(root.resource, { recursive: false, excludes: [] }));
|
|
196
|
+
try {
|
|
197
|
+
if (await this.fileService.exists(fileUri)) {
|
|
198
|
+
const content = await this.fileService.read(fileUri);
|
|
199
|
+
newFiles.push({ uri: fileUri, content: content.value, rootName: root.name });
|
|
200
|
+
}
|
|
201
|
+
} catch (error) {
|
|
202
|
+
this.logger.error(`Failed to read '${fileUri.toString()}': ${error}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
this.toDispose.dispose();
|
|
207
|
+
this.toDispose = newDisposables;
|
|
208
|
+
this.files = newFiles;
|
|
209
|
+
|
|
210
|
+
this.onDidChangeEmitter.fire();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 EclipseSource GmbH.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { enableJSDOM } from '@theia/core/lib/browser/test/jsdom';
|
|
18
|
+
const disableJSDOM = enableJSDOM();
|
|
19
|
+
|
|
20
|
+
import { FrontendApplicationConfigProvider } from '@theia/core/lib/browser/frontend-application-config-provider';
|
|
21
|
+
// Guarded: another spec in the same mocha process may already have set it, and `set` throws on a
|
|
22
|
+
// second call.
|
|
23
|
+
try {
|
|
24
|
+
FrontendApplicationConfigProvider.get();
|
|
25
|
+
} catch {
|
|
26
|
+
FrontendApplicationConfigProvider.set({});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
import { expect } from 'chai';
|
|
30
|
+
import { URI } from '@theia/core';
|
|
31
|
+
import { AgentsMdFile, AgentsMdService } from './agents-md-service';
|
|
32
|
+
import { AGENTS_MD_AUTO_LOADED_VARIABLE, AGENTS_MD_CONTENT_VARIABLE, AGENTS_MD_VARIABLE, AgentsMdVariableContribution } from './agents-md-variable-contribution';
|
|
33
|
+
import { AIVariableContext } from '../common/variable-service';
|
|
34
|
+
import { matchFunctionsRegEx } from '../common/prompt-service-util';
|
|
35
|
+
|
|
36
|
+
disableJSDOM();
|
|
37
|
+
|
|
38
|
+
describe('AgentsMdVariableContribution', () => {
|
|
39
|
+
|
|
40
|
+
function file(rootName: string, content: string): AgentsMdFile {
|
|
41
|
+
return { uri: new URI(`file:///${rootName}/AGENTS.md`), content, rootName };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param rootCount how many workspace roots are open. Defaults to one per discovered file, which
|
|
46
|
+
* is the ordinary case; pass it explicitly to build a workspace whose root count and file count
|
|
47
|
+
* differ, since auto-loading keys on roots rather than files.
|
|
48
|
+
*/
|
|
49
|
+
function createContribution(files: AgentsMdFile[], rootCount = files.length): AgentsMdVariableContribution {
|
|
50
|
+
const contribution = new AgentsMdVariableContribution();
|
|
51
|
+
const service: AgentsMdService = {
|
|
52
|
+
getAgentsMdFiles: () => files,
|
|
53
|
+
onDidChange: () => ({ dispose: () => { } }),
|
|
54
|
+
ready: Promise.resolve()
|
|
55
|
+
};
|
|
56
|
+
(contribution as unknown as { agentsMdService: AgentsMdService }).agentsMdService = service;
|
|
57
|
+
(contribution as unknown as { workspaceService: unknown }).workspaceService = {
|
|
58
|
+
tryGetRoots: () => new Array(rootCount).fill({})
|
|
59
|
+
};
|
|
60
|
+
return contribution;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function resolve(files: AgentsMdFile[], variable: typeof AGENTS_MD_VARIABLE, rootCount?: number): Promise<string> {
|
|
64
|
+
const resolved = await createContribution(files, rootCount).resolve({ variable }, {} as AIVariableContext);
|
|
65
|
+
return resolved!.value;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
describe('agentsMdAutoLoaded', () => {
|
|
69
|
+
it('resolves to nothing when the workspace has no AGENTS.md', async () => {
|
|
70
|
+
expect(await resolve([], AGENTS_MD_AUTO_LOADED_VARIABLE, 1)).to.equal('');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('inlines the root file when the workspace has a single root', async () => {
|
|
74
|
+
expect(await resolve([file('theia', '# Project\n\nUse npm.')], AGENTS_MD_AUTO_LOADED_VARIABLE)).to.equal(
|
|
75
|
+
'<project_instructions path="theia/AGENTS.md">\n# Project\n\nUse npm.\n</project_instructions>'
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('loads nothing once the workspace has more than one root', async () => {
|
|
80
|
+
expect(await resolve([file('a', 'x'), file('b', 'y')], AGENTS_MD_AUTO_LOADED_VARIABLE)).to.equal('');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('loads nothing in a multi-root workspace where only one root has a file', async () => {
|
|
84
|
+
// Keyed on root count, not file count: a workspace with several roots has no single
|
|
85
|
+
// project root, even when only one of them carries an AGENTS.md.
|
|
86
|
+
expect(await resolve([file('a', 'x')], AGENTS_MD_AUTO_LOADED_VARIABLE, 2)).to.equal('');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('escapes the path but leaves the Markdown content untouched', async () => {
|
|
90
|
+
const resolved = await resolve([file('a&b', '# Heading <not xml> & "quoted"')], AGENTS_MD_AUTO_LOADED_VARIABLE, 1);
|
|
91
|
+
expect(resolved).to.contain('path="a&b/AGENTS.md"');
|
|
92
|
+
expect(resolved).to.contain('# Heading <not xml> & "quoted"');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('keeps function references in the content from attaching tools', async () => {
|
|
96
|
+
const resolved = await resolve([file('a', 'Use ~{getFileContent} and {{selectedText}}.')], AGENTS_MD_AUTO_LOADED_VARIABLE, 1);
|
|
97
|
+
expect(matchFunctionsRegEx(resolved)).to.be.empty;
|
|
98
|
+
expect(resolved).to.contain('{{selectedText}}');
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('agentsMd', () => {
|
|
103
|
+
it('resolves to nothing when the workspace has no AGENTS.md', async () => {
|
|
104
|
+
expect(await resolve([], AGENTS_MD_VARIABLE)).to.equal('');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('advertises nothing when the single root file is already loaded', async () => {
|
|
108
|
+
// Otherwise the model is told to read a file it has just been handed.
|
|
109
|
+
expect(await resolve([file('theia', 'x')], AGENTS_MD_VARIABLE)).to.equal('');
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('advertises one entry per root once there is more than one root', async () => {
|
|
113
|
+
expect(await resolve([file('a', 'x'), file('b', 'y')], AGENTS_MD_VARIABLE)).to.equal(
|
|
114
|
+
'<agents_md_files>\n<file>a/AGENTS.md</file>\n<file>b/AGENTS.md</file>\n</agents_md_files>'
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('advertises the single file of a multi-root workspace rather than loading it', async () => {
|
|
119
|
+
expect(await resolve([file('a', 'x')], AGENTS_MD_VARIABLE, 2)).to.equal(
|
|
120
|
+
'<agents_md_files>\n<file>a/AGENTS.md</file>\n</agents_md_files>'
|
|
121
|
+
);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('escapes XML in the root name', async () => {
|
|
125
|
+
expect(await resolve([file('a&b', 'x')], AGENTS_MD_VARIABLE, 2)).to.contain('<file>a&b/AGENTS.md</file>');
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('never inlines the content', async () => {
|
|
129
|
+
expect(await resolve([file('a', 'secret project conventions'), file('b', 'y')], AGENTS_MD_VARIABLE))
|
|
130
|
+
.to.not.contain('secret project conventions');
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
describe('the two are mutually exclusive', () => {
|
|
135
|
+
it('never emits both for the same workspace', async () => {
|
|
136
|
+
for (const [files, roots] of [
|
|
137
|
+
[[file('theia', 'x')], 1],
|
|
138
|
+
[[file('a', 'x'), file('b', 'y')], 2],
|
|
139
|
+
[[file('a', 'x')], 2],
|
|
140
|
+
[[], 1]
|
|
141
|
+
] as [AgentsMdFile[], number][]) {
|
|
142
|
+
const loaded = await resolve(files, AGENTS_MD_AUTO_LOADED_VARIABLE, roots);
|
|
143
|
+
const listed = await resolve(files, AGENTS_MD_VARIABLE, roots);
|
|
144
|
+
expect(loaded === '' || listed === '', `both were non-empty for ${roots} root(s)`).to.be.true;
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe('agentsMdContent', () => {
|
|
150
|
+
it('resolves to nothing when the workspace has no AGENTS.md', async () => {
|
|
151
|
+
expect(await resolve([], AGENTS_MD_CONTENT_VARIABLE)).to.equal('');
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('inlines a single root verbatim, without provenance framing', async () => {
|
|
155
|
+
expect(await resolve([file('theia', '# Project\n\nUse npm.')], AGENTS_MD_CONTENT_VARIABLE)).to.equal('# Project\n\nUse npm.');
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('labels the sources when several roots contribute', async () => {
|
|
159
|
+
expect(await resolve([file('a', 'first'), file('b', 'second')], AGENTS_MD_CONTENT_VARIABLE)).to.equal(
|
|
160
|
+
'### a\n\nfirst\n\n### b\n\nsecond'
|
|
161
|
+
);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('keeps function references in the content from attaching tools', async () => {
|
|
165
|
+
expect(matchFunctionsRegEx(await resolve([file('a', '~{getFileContent}')], AGENTS_MD_CONTENT_VARIABLE))).to.be.empty;
|
|
166
|
+
expect(matchFunctionsRegEx(await resolve([file('a', '~{x}'), file('b', '~{y}')], AGENTS_MD_CONTENT_VARIABLE))).to.be.empty;
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe('canResolve', () => {
|
|
171
|
+
it('claims all three variables and nothing else', () => {
|
|
172
|
+
const contribution = createContribution([]);
|
|
173
|
+
const context = {} as AIVariableContext;
|
|
174
|
+
expect(contribution.canResolve({ variable: AGENTS_MD_AUTO_LOADED_VARIABLE }, context)).to.equal(1);
|
|
175
|
+
expect(contribution.canResolve({ variable: AGENTS_MD_VARIABLE }, context)).to.equal(1);
|
|
176
|
+
expect(contribution.canResolve({ variable: AGENTS_MD_CONTENT_VARIABLE }, context)).to.equal(1);
|
|
177
|
+
expect(contribution.canResolve({ variable: { id: 'other', name: 'other', description: '' } }, context)).to.equal(-1);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
});
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// *****************************************************************************
|
|
2
|
+
// Copyright (C) 2026 EclipseSource GmbH.
|
|
3
|
+
//
|
|
4
|
+
// This program and the accompanying materials are made available under the
|
|
5
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
//
|
|
8
|
+
// This Source Code may also be made available under the following Secondary
|
|
9
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
// with the GNU Classpath Exception which is available at
|
|
12
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
//
|
|
14
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
15
|
+
// *****************************************************************************
|
|
16
|
+
|
|
17
|
+
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
18
|
+
import { MaybePromise, nls } from '@theia/core';
|
|
19
|
+
import {
|
|
20
|
+
AIVariable, AIVariableContext, AIVariableContribution, AIVariableResolutionRequest,
|
|
21
|
+
AIVariableResolver, AIVariableService, ResolvedAIVariable
|
|
22
|
+
} from '../common/variable-service';
|
|
23
|
+
import { WorkspaceService } from '@theia/workspace/lib/browser';
|
|
24
|
+
import { AGENTS_MD_FILE_NAME } from '../common/agents-md';
|
|
25
|
+
import { AgentsMdFile, AgentsMdService } from './agents-md-service';
|
|
26
|
+
|
|
27
|
+
export const AGENTS_MD_AUTO_LOADED_VARIABLE: AIVariable = {
|
|
28
|
+
id: 'agentsMdAutoLoaded',
|
|
29
|
+
name: 'agentsMdAutoLoaded',
|
|
30
|
+
description: nls.localize('theia/ai/core/agentsMdAutoLoadedVariable/description',
|
|
31
|
+
'Returns the content of the workspace root AGENTS.md when the workspace has a single root, so that it is always in context')
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const AGENTS_MD_VARIABLE: AIVariable = {
|
|
35
|
+
id: 'agentsMd',
|
|
36
|
+
name: 'agentsMd',
|
|
37
|
+
description: nls.localize('theia/ai/core/agentsMdVariable/description',
|
|
38
|
+
'Lists the AGENTS.md files an agent has to read on demand, i.e. the ones that are not already loaded')
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const AGENTS_MD_CONTENT_VARIABLE: AIVariable = {
|
|
42
|
+
id: 'agentsMdContent',
|
|
43
|
+
name: 'agentsMdContent',
|
|
44
|
+
description: nls.localize('theia/ai/core/agentsMdContentVariable/description',
|
|
45
|
+
'Returns the full content of the AGENTS.md files of the workspace')
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Resolves the three ways of consuming `AGENTS.md`.
|
|
50
|
+
*
|
|
51
|
+
* A **single-root** workspace has an unambiguous project root, so its `AGENTS.md` is always in
|
|
52
|
+
* context, mirroring how other tools implementing the standard treat the root file. A workspace with
|
|
53
|
+
* several roots has no such file, so nothing is loaded and every discovered file is advertised
|
|
54
|
+
* instead, to be read on demand. {@link AGENTS_MD_AUTO_LOADED_VARIABLE} and
|
|
55
|
+
* {@link AGENTS_MD_VARIABLE} are therefore mutually exclusive by construction: at most one of them is
|
|
56
|
+
* ever non-empty.
|
|
57
|
+
*
|
|
58
|
+
* - {@link AGENTS_MD_AUTO_LOADED_VARIABLE} inlines the single root's file, or nothing.
|
|
59
|
+
* - {@link AGENTS_MD_VARIABLE} advertises files by path so a tool-calling agent can fetch them with
|
|
60
|
+
* `getFileContent`, or nothing.
|
|
61
|
+
* - {@link AGENTS_MD_CONTENT_VARIABLE} always inlines everything discovered, regardless of root
|
|
62
|
+
* count, for consumers such as code completion that have no tool-calling loop and therefore cannot
|
|
63
|
+
* fetch anything on demand.
|
|
64
|
+
*
|
|
65
|
+
* All three resolve to the empty string when the workspace has no `AGENTS.md`.
|
|
66
|
+
*/
|
|
67
|
+
@injectable()
|
|
68
|
+
export class AgentsMdVariableContribution implements AIVariableContribution, AIVariableResolver {
|
|
69
|
+
|
|
70
|
+
@inject(AgentsMdService)
|
|
71
|
+
protected readonly agentsMdService: AgentsMdService;
|
|
72
|
+
|
|
73
|
+
@inject(WorkspaceService)
|
|
74
|
+
protected readonly workspaceService: WorkspaceService;
|
|
75
|
+
|
|
76
|
+
registerVariables(service: AIVariableService): void {
|
|
77
|
+
service.registerResolver(AGENTS_MD_AUTO_LOADED_VARIABLE, this);
|
|
78
|
+
service.registerResolver(AGENTS_MD_VARIABLE, this);
|
|
79
|
+
service.registerResolver(AGENTS_MD_CONTENT_VARIABLE, this);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
canResolve(request: AIVariableResolutionRequest, _context: AIVariableContext): MaybePromise<number> {
|
|
83
|
+
if (request.variable.name === AGENTS_MD_AUTO_LOADED_VARIABLE.name
|
|
84
|
+
|| request.variable.name === AGENTS_MD_VARIABLE.name
|
|
85
|
+
|| request.variable.name === AGENTS_MD_CONTENT_VARIABLE.name) {
|
|
86
|
+
return 1;
|
|
87
|
+
}
|
|
88
|
+
return -1;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async resolve(request: AIVariableResolutionRequest, _context: AIVariableContext): Promise<ResolvedAIVariable | undefined> {
|
|
92
|
+
// Without this a request issued before the initial scan completes would silently report that
|
|
93
|
+
// the workspace has no project context.
|
|
94
|
+
await this.agentsMdService.ready;
|
|
95
|
+
const files = this.agentsMdService.getAgentsMdFiles();
|
|
96
|
+
|
|
97
|
+
if (request.variable.name === AGENTS_MD_AUTO_LOADED_VARIABLE.name) {
|
|
98
|
+
return { variable: request.variable, value: this.generateAutoLoaded(files) };
|
|
99
|
+
}
|
|
100
|
+
if (request.variable.name === AGENTS_MD_VARIABLE.name) {
|
|
101
|
+
// Suppressed when the root file is already in context, so the model is never told to read
|
|
102
|
+
// a file it has just been handed.
|
|
103
|
+
return { variable: request.variable, value: this.isAutoLoading() ? '' : this.generateAgentsMdXML(files) };
|
|
104
|
+
}
|
|
105
|
+
if (request.variable.name === AGENTS_MD_CONTENT_VARIABLE.name) {
|
|
106
|
+
return { variable: request.variable, value: this.mergeContent(files) };
|
|
107
|
+
}
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Whether the workspace root's `AGENTS.md` is put into context rather than advertised. Keyed on
|
|
113
|
+
* the number of workspace **roots**, not the number of discovered files: a workspace with several
|
|
114
|
+
* roots has no single project root whose file could stand for the whole session, even when only
|
|
115
|
+
* one of those roots happens to carry an `AGENTS.md`.
|
|
116
|
+
*/
|
|
117
|
+
protected isAutoLoading(): boolean {
|
|
118
|
+
return this.workspaceService.tryGetRoots().length === 1;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Inlines the single root's file. The content is raw Markdown and not XML-escaped; only the path,
|
|
123
|
+
* which is an attribute, is.
|
|
124
|
+
*/
|
|
125
|
+
protected generateAutoLoaded(files: AgentsMdFile[]): string {
|
|
126
|
+
if (!this.isAutoLoading() || files.length === 0) {
|
|
127
|
+
return '';
|
|
128
|
+
}
|
|
129
|
+
const file = files[0];
|
|
130
|
+
return `<project_instructions path="${this.escapeXml(this.toWorkspaceRelativePath(file))}">\n${this.escapeFunctionReferences(file.content)}\n</project_instructions>`;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Advertises the files by their `<rootName>/AGENTS.md` path, the path format the workspace tools
|
|
135
|
+
* accept and return, so the model can pass it to `getFileContent` verbatim.
|
|
136
|
+
*/
|
|
137
|
+
protected generateAgentsMdXML(files: AgentsMdFile[]): string {
|
|
138
|
+
if (files.length === 0) {
|
|
139
|
+
return '';
|
|
140
|
+
}
|
|
141
|
+
const entries = files.map(file => `<file>${this.escapeXml(this.toWorkspaceRelativePath(file))}</file>`).join('\n');
|
|
142
|
+
return `<agents_md_files>\n${entries}\n</agents_md_files>`;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Inlines the content. A single root contributes its file verbatim; only a multi-root workspace
|
|
147
|
+
* gets provenance headings, mirroring how equal-priority prompt fragment sources are merged.
|
|
148
|
+
*/
|
|
149
|
+
protected mergeContent(files: AgentsMdFile[]): string {
|
|
150
|
+
if (files.length === 0) {
|
|
151
|
+
return '';
|
|
152
|
+
}
|
|
153
|
+
if (files.length === 1) {
|
|
154
|
+
return this.escapeFunctionReferences(files[0].content);
|
|
155
|
+
}
|
|
156
|
+
return files.map(file => `### ${file.rootName}\n\n${this.escapeFunctionReferences(file.content)}`).join('\n\n');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Keeps `~{...}` in inlined content literal. Function references are matched on the resolved
|
|
161
|
+
* prompt text, so a `~{someTool}` in a file anyone in the repository can edit would otherwise
|
|
162
|
+
* attach that tool to every agent using the fragment. A zero-width space between `~` and `{`
|
|
163
|
+
* breaks the match without changing what the model reads. `{{...}}` needs no such treatment, as
|
|
164
|
+
* variables are not resolved recursively.
|
|
165
|
+
*/
|
|
166
|
+
protected escapeFunctionReferences(content: string): string {
|
|
167
|
+
return content.replace(/~\{/g, '~\u200B{');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
protected toWorkspaceRelativePath(file: AgentsMdFile): string {
|
|
171
|
+
return `${file.rootName}/${AGENTS_MD_FILE_NAME}`;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
protected escapeXml(text: string): string {
|
|
175
|
+
return text
|
|
176
|
+
.replace(/&/g, '&')
|
|
177
|
+
.replace(/</g, '<')
|
|
178
|
+
.replace(/>/g, '>')
|
|
179
|
+
.replace(/"/g, '"')
|
|
180
|
+
.replace(/'/g, ''');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -67,6 +67,7 @@ import { DefaultPromptFragmentCustomizationService } from './frontend-prompt-cus
|
|
|
67
67
|
import { DefaultFrontendVariableService, FrontendVariableService } from './frontend-variable-service';
|
|
68
68
|
import { PromptTemplateContribution } from './prompttemplate-contribution';
|
|
69
69
|
import { FileVariableContribution } from './file-variable-contribution';
|
|
70
|
+
import { WorkspaceRelativePathResolver } from './workspace-relative-path-resolver';
|
|
70
71
|
import { TheiaVariableContribution } from './theia-variable-contribution';
|
|
71
72
|
import { TodayVariableContribution } from '../common/today-variable-contribution';
|
|
72
73
|
import { AgentsVariableContribution } from '../common/agents-variable-contribution';
|
|
@@ -84,6 +85,11 @@ import { ProductNameVariableContribution } from './product-name-variable-contrib
|
|
|
84
85
|
import { CapabilityVariableContribution } from '../common/capability-variable-contribution';
|
|
85
86
|
import { GenericCapabilitiesVariableContribution } from './generic-capabilities-variable-contribution';
|
|
86
87
|
import { GenericCapabilitiesPromptFragmentContribution } from './generic-capabilities-prompt-fragment-contribution';
|
|
88
|
+
import { AgentsMdService, DefaultAgentsMdService } from './agents-md-service';
|
|
89
|
+
import { AgentsMdVariableContribution } from './agents-md-variable-contribution';
|
|
90
|
+
import { AgentsMdPromptFragmentContribution } from './agents-md-prompt-fragment-contribution';
|
|
91
|
+
import { AgentsMdMigrationService } from './agents-md-migration-service';
|
|
92
|
+
import { AgentsMdFrontendApplicationContribution } from './agents-md-frontend-application-contribution';
|
|
87
93
|
import { LanguageModelService } from '../common/language-model-service';
|
|
88
94
|
import { FrontendLanguageModelServiceImpl } from './frontend-language-model-service';
|
|
89
95
|
import { TokenUsageFrontendService } from './token-usage-frontend-service';
|
|
@@ -142,6 +148,13 @@ export default new ContainerModule(bind => {
|
|
|
142
148
|
bind(SkillPromptCoordinator).toSelf().inSingletonScope();
|
|
143
149
|
bind(FrontendApplicationContribution).toService(SkillPromptCoordinator);
|
|
144
150
|
|
|
151
|
+
bind(DefaultAgentsMdService).toSelf().inSingletonScope();
|
|
152
|
+
bind(AgentsMdService).toService(DefaultAgentsMdService);
|
|
153
|
+
bind(AgentsMdMigrationService).toSelf().inSingletonScope();
|
|
154
|
+
bind(AgentsMdFrontendApplicationContribution).toSelf().inSingletonScope();
|
|
155
|
+
bind(FrontendApplicationContribution).toService(AgentsMdFrontendApplicationContribution);
|
|
156
|
+
bind(CommandContribution).toService(AgentsMdFrontendApplicationContribution);
|
|
157
|
+
|
|
145
158
|
bindRootContributionProvider(bind, SkillDirectoryContribution);
|
|
146
159
|
|
|
147
160
|
bindRootContributionProvider(bind, AIVariableContribution);
|
|
@@ -156,12 +169,15 @@ export default new ContainerModule(bind => {
|
|
|
156
169
|
bind(PromptVariableContribution).toSelf().inSingletonScope();
|
|
157
170
|
bind(AIVariableContribution).toService(PromptVariableContribution);
|
|
158
171
|
bind(AIVariableContribution).to(TodayVariableContribution).inSingletonScope();
|
|
172
|
+
bind(WorkspaceRelativePathResolver).toSelf().inSingletonScope();
|
|
159
173
|
bind(AIVariableContribution).to(FileVariableContribution).inSingletonScope();
|
|
160
174
|
bind(AgentsVariableContribution).toSelf().inSingletonScope();
|
|
161
175
|
bind(AIVariableContribution).toService(AgentsVariableContribution);
|
|
162
176
|
bind(AIVariableContribution).to(OpenEditorsVariableContribution).inSingletonScope();
|
|
163
177
|
bind(SkillsVariableContribution).toSelf().inSingletonScope();
|
|
164
178
|
bind(AIVariableContribution).toService(SkillsVariableContribution);
|
|
179
|
+
bind(AgentsMdVariableContribution).toSelf().inSingletonScope();
|
|
180
|
+
bind(AIVariableContribution).toService(AgentsMdVariableContribution);
|
|
165
181
|
bind(AIVariableContribution).to(CapabilityVariableContribution).inSingletonScope();
|
|
166
182
|
bind(AIVariableContribution).to(ProductNameVariableContribution).inSingletonScope();
|
|
167
183
|
|
|
@@ -171,6 +187,9 @@ export default new ContainerModule(bind => {
|
|
|
171
187
|
bind(GenericCapabilitiesPromptFragmentContribution).toSelf().inSingletonScope();
|
|
172
188
|
bind(FrontendApplicationContribution).toService(GenericCapabilitiesPromptFragmentContribution);
|
|
173
189
|
|
|
190
|
+
bind(AgentsMdPromptFragmentContribution).toSelf().inSingletonScope();
|
|
191
|
+
bind(FrontendApplicationContribution).toService(AgentsMdPromptFragmentContribution);
|
|
192
|
+
|
|
174
193
|
bind(FrontendApplicationContribution).to(AICoreFrontendApplicationContribution).inSingletonScope();
|
|
175
194
|
|
|
176
195
|
bind(ToolInvocationRegistry).to(ToolInvocationRegistryImpl).inSingletonScope();
|