computeAutomaticInstructions.ts ×13

Frontier kind: Code frontier

unlabeled · c_cbbdd496db70

9 tests · 68103 LOC · 327 files · introduces 0 tests · 91 LOC · 1 file

Introduces — evidence that enters the hierarchy at this concept

Code
13 ranges91 lines · 1 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
6627 ranges68103 lines · 327 files · Browse complete extent
All tests (intent)
9 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

1 file ranked by introduced lines: 91 introduced LOC across 13 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/workbench/contrib/chat/common/promptSyntax/computeAutomaticInstructions.ts 91 introduced LOC · 13 ranges

Open complete file

133
134 private async _logSkillLoadedTelemetry(skills: readonly IAgentSkill[]): Promise<void> {
135 > type SkillLoadedIntoContextEvent = { computeAutomaticInstructions.ts
136 > skillNameHash: string;
137 > skillStorage: string;
138 > extensionIdHash: string;
139 > extensionVersion: string;
140 > pluginNameHash: string;
141 > pluginVersion: string;
142 > };
143 >
144 > type SkillLoadedIntoContextClassification = {
145 > skillNameHash: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Hash of the skill name loaded into the agent context.' };
146 > skillStorage: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The storage source of the skill (local, user, extension, plugin, internal).' };
147 > extensionIdHash: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Hash of the contributing extension identifier, empty if none.' };
148 > extensionVersion: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Semver version of the contributing extension, empty if none.' };
149 > pluginNameHash: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Hash of the plugin display name, empty if not from a plugin.' };
150 > pluginVersion: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Semver version of the plugin, empty if unavailable.' };
151 > owner: 'manishj, dbreshears';
152 > comment: 'Tracks individual skill loading into agent context with provenance metadata.';
153 > };
154 >
155 > try {
156 > // Build map of plugin URI to plugin metadata for provenance
157 > const pluginByUri = new ResourceMap<IAgentPlugin>();
158 > const allPlugins = this._agentPluginService.plugins.get();
159 > for (const plugin of allPlugins) {
160 pluginByUri.set(plugin.uri, plugin);
161 }
163 > const hashOrEmpty = (value: string | undefined) => {
164 > return value !== undefined ? String(hash(value)) : '';
165 > };
166 >
167 > for (const skill of skills) {
168 > const skillPlugin = skill.pluginUri ? pluginByUri.get(skill.pluginUri) : undefined;
169 > this._telemetryService.publicLog2<SkillLoadedIntoContextEvent, SkillLoadedIntoContextClassification>('skillLoadedIntoContext', {
170 > skillNameHash: hashOrEmpty(skill.name),
171 > skillStorage: skill.storage,
172 > extensionIdHash: hashOrEmpty(skill.extension?.identifier.value),
173 > extensionVersion: skill.extension?.version ?? '',
174 > pluginNameHash: hashOrEmpty(skillPlugin?.label),
175 > pluginVersion: skillPlugin?.fromMarketplace?.version ?? '',
176 > });
177 > }
178 > } catch (err) {
179 this._logService.error('[InstructionsContextComputer] Failed to log skill telemetry', err);
180 }
182
183 /** public for testing */
407 const isFileLoggingEnabled = this._configurationService.getValue<boolean>(AGENT_DEBUG_LOG_FILE_LOGGING_ENABLED_SETTING);
408 const modelInvocableSkills = agentSkills?.filter(skill => {
409 > if (!skill.description) { computeAutomaticInstructions.ts
410 debugInfo.debugDetails.push({ category: 'skipped', name: skill.name, uri: skill.uri, reason: localize('debugDetail.skillNoDescription', 'no description for model invocation') });
411 return false;
412 }
413 > if (skill.disableModelInvocation) { computeAutomaticInstructions.ts
414 debugInfo.debugDetails.push({ category: 'skipped', name: skill.name, uri: skill.uri, reason: localize('debugDetail.skillNotModelInvocable', 'model invocation disabled') });
415 return false;
416 }
417 > if (!matchesSessionType(skill.sessionTypes, currentSessionType)) { computeAutomaticInstructions.ts
418 debugInfo.debugDetails.push({ category: 'skipped', name: skill.name, uri: skill.uri, reason: localize('debugDetail.skillSessionType', 'session type not matched') });
419 return false;
420 }
421 > if (!isFileLoggingEnabled && skill.uri.path.includes(TROUBLESHOOT_SKILL_PATH)) { computeAutomaticInstructions.ts
422 debugInfo.debugDetails.push({ category: 'skipped', name: skill.name, uri: skill.uri, reason: localize('debugDetail.skillDebugDisabled', 'debug logging disabled') });
423 return false;
424 }
425 > return true; computeAutomaticInstructions.ts
426 });
427 if (modelInvocableSkills && modelInvocableSkills.length > 0) {
428 > // Log per-skill telemetry for each skill loaded into context computeAutomaticInstructions.ts
429 > this._logSkillLoadedTelemetry(modelInvocableSkills);
430 > for (const skill of modelInvocableSkills) {
431 > debugInfo.debugDetails.push({ category: 'skill', name: skill.name, uri: skill.uri, reason: skill.storage });
432 > }
433 >
434 > const useSkillAdherencePrompt = this._configurationService.getValue(PromptsConfig.USE_SKILL_ADHERENCE_PROMPT);
435 > // When the skill tool is available, direct the model to use it by name
436 > // instead of reading SKILL.md files directly. This keeps file paths out of
437 > // the listing and routes through the proper skill loading pipeline.
438 > const skillLoadTool = skillTool ?? fileReadTool;
439 > entries.push('<skills>');
440 > if (useSkillAdherencePrompt) {
441 // Stronger skill adherence prompt for experimental feature
442 entries.push('Skills provide specialized capabilities, domain knowledge, and refined workflows for producing high-quality outputs. Each skill folder contains tested instructions for specific domains like testing strategies, API design, or performance optimization. Multiple skills can be combined when a task spans different domains.');
456 entries.push(`- "Add a discount code field to checkout" -> Load both the checkout-flow and form-validation skills FIRST`);
457 entries.push('Available skills:');
459 > if (skillTool) {
460 entries.push('Here is a list of skills that contain domain specific knowledge on a variety of topics.');
461 entries.push(`When a user asks you to perform a task that falls within the domain of a skill, use the ${skillTool.variable} tool with the skill name to load it.`);
463 > entries.push('Here is a list of skills that contain domain specific knowledge on a variety of topics.');
464 > entries.push('Each skill comes with a description of the topic and a file path that contains the detailed instructions.');
465 > entries.push(`When a user asks you to perform a task that falls within the domain of a skill, use the ${fileReadTool.variable} tool to acquire the full instructions from the file URI.`);
466 > }
467 > }
468 > const SKILL_DESCRIPTION_CHAR_BUDGET = 15000;
469 > const TRUNCATED_NAMES_CHAR_BUDGET = 5000;
470 > let skillCharCount = 0;
471 > let truncatedAtIndex = modelInvocableSkills.length;
472 > for (let i = 0; i < modelInvocableSkills.length; i++) {
473 > const skill = modelInvocableSkills[i];
474 > const skillEntry = [`<skill>`, `<name>${skill.name}</name>`];
475 > if (skill.description) {
476 > skillEntry.push(`<description>${skill.description}</description>`);
477 > }
478 > skillEntry.push(`<file>${filePath(skill.uri)}</file>`);
479 > skillEntry.push(`</skill>`);
480 > const entryLength = skillEntry.join('\n').length + 1; // +1 for joining newline
481 > if (skillTool && skillCharCount + entryLength > SKILL_DESCRIPTION_CHAR_BUDGET) {
482 truncatedAtIndex = i;
483 break;
484 }
485 > skillCharCount += entryLength; computeAutomaticInstructions.ts
486 > entries.push(...skillEntry);
487 > }
488 > // When skills are truncated by the character budget, include remaining
489 > // skill names so the model can still discover and invoke them.
490 > if (truncatedAtIndex < modelInvocableSkills.length) {
491 const truncatedSkills = modelInvocableSkills.slice(truncatedAtIndex);
492 const names: string[] = [];
506 : `Additional skills available (invoke by name): ${nameList}`);
507 }
508 > entries.push('</skills>', '', ''); // add trailing newline computeAutomaticInstructions.ts
509 > }
510 }
511 if (runSubagentTool) {