fix(coding-agent): unify source provenance, closes #1734

This commit is contained in:
Mario Zechner
2026-03-23 02:02:42 +01:00
parent 883862a354
commit 4e5af01d73
26 changed files with 340 additions and 157 deletions

View File

@@ -75,7 +75,8 @@ import type { ResourceExtensionPaths, ResourceLoader } from "./resource-loader.j
import type { BranchSummaryEntry, CompactionEntry, SessionManager } from "./session-manager.js";
import { CURRENT_SESSION_VERSION, getLatestCompactionEntry, type SessionHeader } from "./session-manager.js";
import type { SettingsManager } from "./settings-manager.js";
import type { SlashCommandInfo, SlashCommandLocation } from "./slash-commands.js";
import type { SlashCommandInfo } from "./slash-commands.js";
import { createSyntheticSourceInfo, type SourceInfo } from "./source-info.js";
import { buildSystemPrompt } from "./system-prompt.js";
import type { BashOperations } from "./tools/bash.js";
import { createAllToolDefinitions } from "./tools/index.js";
@@ -201,6 +202,11 @@ export interface SessionStats {
cost: number;
}
interface ToolDefinitionEntry {
definition: ToolDefinition;
sourceInfo: SourceInfo;
}
// ============================================================================
// Constants
// ============================================================================
@@ -274,7 +280,7 @@ export class AgentSession {
// Tool registry for extension getTools/setTools
private _toolRegistry: Map<string, AgentTool> = new Map();
private _toolDefinitions: Map<string, ToolDefinition> = new Map();
private _toolDefinitions: Map<string, ToolDefinitionEntry> = new Map();
private _toolPromptSnippets: Map<string, string> = new Map();
private _toolPromptGuidelines: Map<string, string[]> = new Map();
@@ -710,18 +716,19 @@ export class AgentSession {
}
/**
* Get all configured tools with name, description, and parameter schema.
* Get all configured tools with name, description, parameter schema, and source metadata.
*/
getAllTools(): ToolInfo[] {
return Array.from(this._toolDefinitions.values()).map((t) => ({
name: t.name,
description: t.description,
parameters: t.parameters,
return Array.from(this._toolDefinitions.values()).map(({ definition, sourceInfo }) => ({
name: definition.name,
description: definition.description,
parameters: definition.parameters,
sourceInfo,
}));
}
getToolDefinition(name: string): ToolDefinition | undefined {
return this._toolDefinitions.get(name);
return this._toolDefinitions.get(name)?.definition;
}
/**
@@ -2084,20 +2091,12 @@ export class AgentSession {
}
private _bindExtensionCore(runner: ExtensionRunner): void {
const normalizeLocation = (source: string): SlashCommandLocation | undefined => {
if (source === "user" || source === "project" || source === "path") {
return source;
}
return undefined;
};
const getCommands = (): SlashCommandInfo[] => {
const extensionCommands: SlashCommandInfo[] = runner.getRegisteredCommands().map((command) => ({
name: command.name,
description: command.description,
source: "extension",
sourceInfo: command.sourceInfo,
path: command.extensionPath,
}));
const templates: SlashCommandInfo[] = this.promptTemplates.map((template) => ({
@@ -2105,8 +2104,6 @@ export class AgentSession {
description: template.description,
source: "prompt",
sourceInfo: template.sourceInfo,
location: normalizeLocation(template.source),
path: template.filePath,
}));
const skills: SlashCommandInfo[] = this._resourceLoader.getSkills().skills.map((skill) => ({
@@ -2114,8 +2111,6 @@ export class AgentSession {
description: skill.description,
source: "skill",
sourceInfo: skill.sourceInfo,
location: normalizeLocation(skill.source),
path: skill.filePath,
}));
return [...extensionCommands, ...templates, ...skills];
@@ -2209,16 +2204,30 @@ export class AgentSession {
const registeredTools = this._extensionRunner?.getAllRegisteredTools() ?? [];
const allCustomTools = [
...registeredTools,
...this._customTools.map((def) => ({ definition: def, extensionPath: "<sdk>" })),
...this._customTools.map((definition) => ({
definition,
sourceInfo: createSyntheticSourceInfo(`<sdk:${definition.name}>`, { source: "sdk" }),
})),
];
const definitionRegistry = new Map(this._baseToolDefinitions);
for (const { definition } of allCustomTools) {
definitionRegistry.set(definition.name, definition);
const definitionRegistry = new Map<string, ToolDefinitionEntry>(
Array.from(this._baseToolDefinitions.entries()).map(([name, definition]) => [
name,
{
definition,
sourceInfo: createSyntheticSourceInfo(`<builtin:${name}>`, { source: "builtin" }),
},
]),
);
for (const tool of allCustomTools) {
definitionRegistry.set(tool.definition.name, {
definition: tool.definition,
sourceInfo: tool.sourceInfo,
});
}
this._toolDefinitions = definitionRegistry;
this._toolPromptSnippets = new Map(
Array.from(definitionRegistry.values())
.map((definition) => {
.map(({ definition }) => {
const snippet = this._normalizePromptSnippet(definition.promptSnippet);
return snippet ? ([definition.name, snippet] as const) : undefined;
})
@@ -2226,7 +2235,7 @@ export class AgentSession {
);
this._toolPromptGuidelines = new Map(
Array.from(definitionRegistry.values())
.map((definition) => {
.map(({ definition }) => {
const guidelines = this._normalizePromptGuidelines(definition.promptGuidelines);
return guidelines.length > 0 ? ([definition.name, guidelines] as const) : undefined;
})