Skip to content
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
2326bc2
feat: add agent skills support for declarative agents
sebastienlevert Mar 26, 2026
793bdd0
fix(vsc): fix VSIX packaging - mismatched nls key and files/vscodeign…
sebastienlevert Mar 26, 2026
62e1d4b
feat(vscode): add 'Add Skill' tree view item in Development section
sebastienlevert Mar 26, 2026
99d30d4
feat: change expose-to-copilot from confirm to Yes/No quickpick
sebastienlevert Mar 26, 2026
76f3553
feat(vscode): use lightbulb icon for Add Skill tree item
sebastienlevert Mar 26, 2026
7320f92
fix: remove pre-action confirm dialog from addSkill flow
sebastienlevert Mar 26, 2026
608cd61
feat: restore confirm dialog before modifying DA manifest in addSkill
sebastienlevert Mar 27, 2026
b3ec1e6
feat: improve skill name validation and simplify CLI flags
sebastienlevert Mar 27, 2026
83e088e
feat: make --name and --description optional when using --from
sebastienlevert Mar 27, 2026
147ae76
feat: validate folder name and SKILL.md name match for --from
sebastienlevert Mar 27, 2026
98f961f
feat: gate agent skills behind TEAMSFX_AGENT_SKILLS feature flag
sebastienlevert Mar 27, 2026
938127e
chore: apply prettier formatting
sebastienlevert Mar 27, 2026
0edc81e
fix: export AgentSkillElement from DeclarativeAgentManifestWrapper
sebastienlevert Mar 27, 2026
1931a95
style: apply prettier formatting across all packages
sebastienlevert Mar 27, 2026
e66cabd
fix: resolve PR review comments
sebastienlevert Mar 27, 2026
8c885ed
fix: CI formatting and tree view test count
sebastienlevert Mar 27, 2026
d85c3e2
Merge remote-tracking branch 'upstream/dev' into feature/agent-skills…
sebastienlevert Mar 27, 2026
d7ac8b2
fix: merge dev, fix formatting, add coverage tests
sebastienlevert Mar 27, 2026
bd70dc5
Add coverage tests for skill questions, validation, and log errors
sebastienlevert Mar 27, 2026
a569e13
Add coverage for VSCode .then() callback and undefined skill partials
sebastienlevert Mar 27, 2026
29c713f
Fix skill folders not included in app package
sebastienlevert Apr 2, 2026
ed5499e
fix: support x-agent_skills fallback in app package creation
sebastienlevert Apr 2, 2026
1262dae
feat: add zip import support for agent skills
sebastienlevert Apr 7, 2026
0bce04b
Merge branch 'dev' into feature/agent-skills-support
qfai Apr 15, 2026
7810d35
feat: add configurable max package size limit to zipAppPackage action
sebastienlevert May 1, 2026
7d4dac0
feat: enforce 10 MB package size limit on MOS/Titles API uploads
sebastienlevert Apr 20, 2026
4f3d379
fix: validate package size before parsing zip and fix test stubs
sebastienlevert Apr 20, 2026
0b016a1
fix: remove MOS API reference from package size error message
sebastienlevert Apr 20, 2026
1abd49d
feat: enforce hard 10 MB package size limit on zipAppPackage action
sebastienlevert Apr 20, 2026
b4db6aa
chore: remove expose_to_copilot property and all related options
sebastienlevert May 1, 2026
e32c039
fix: zip path traversal test now uses binary-patched zip
sebastienlevert May 1, 2026
bc24cd4
Merge branch 'dev' into feature/agent-skills-support
sebastienlevert May 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/api/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export enum Stage {
kiotaRegenerate = "kiotaRegenerate",
addAuthAction = "addAuthAction",
addKnowledge = "addKnowledge",
addSkill = "addSkill",
setSensitivityLabel = "setSensitivityLabel",
installApp = "installApp",
updateActionWithMCP = "updateActionWithMCP",
Expand Down
12 changes: 11 additions & 1 deletion packages/cli/src/commands/models/add.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { CLICommand } from "@microsoft/teamsfx-api";
import { featureFlagManager, FeatureFlags } from "@microsoft/teamsfx-core";
import { commands } from "../../resource";
import { addSPFxWebpartCommand } from "./addSPFxWebpart";
import { addPluginCommand } from "./addPlugin";
import { addAuthConfigCommand } from "./addAuthConfig";
import { addCapabilityCommand } from "./addCapability";
import { addSkillCommand } from "./addSkill";

const adjustCommands = (): CLICommand[] => {
return [addSPFxWebpartCommand, addPluginCommand, addAuthConfigCommand, addCapabilityCommand];
return [
addSPFxWebpartCommand,
addPluginCommand,
addAuthConfigCommand,
addCapabilityCommand,
...(featureFlagManager.getBooleanValue(FeatureFlags.AgentSkillsEnabled)
? [addSkillCommand]
: []),
];
};
export function addCommand(): CLICommand {
return {
Expand Down
23 changes: 23 additions & 0 deletions packages/cli/src/commands/models/addSkill.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { CLICommand } from "@microsoft/teamsfx-api";
import { AddSkillInputs, AddSkillOptions } from "@microsoft/teamsfx-core";
import { getFxCore } from "../../activate";
import { commands } from "../../resource";
import { TelemetryEvent } from "../../telemetry/cliTelemetryEvents";
import { ProjectFolderOption } from "../common";

export const addSkillCommand: CLICommand = {
name: "skill",
description: commands["add.skill"].description,
options: [...AddSkillOptions, ProjectFolderOption],
telemetry: {
event: TelemetryEvent.AddSkill,
},
handler: async (ctx) => {
const inputs = ctx.optionValues as AddSkillInputs;
const core = getFxCore();
const res = await core.addSkill(inputs);
return res;
},
};
3 changes: 3 additions & 0 deletions packages/cli/src/resource/commands.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@
"add.capability": {
"description": "A capability to extend Copilot using your APIs."
},
"add.skill": {
"description": "An agent skill to bundle with your Declarative Agent."
},
"regenerate": {
"description": "Regenerate existing resources for your app."
},
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/telemetry/cliTelemetryEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export enum TelemetryEvent {
AddCopilotPlugin = "add-copilot-plugin",
RegneratePlugin = "regenerate-copilot-plugin",
AddAuthAction = "add-auth-action",
AddSkill = "add-skill",

SetSensitivityLabel = "set-sensitivity-label",
}
Expand Down
25 changes: 25 additions & 0 deletions packages/fx-core/resource/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
"core.regenerateApi.continue": "Regenerate",
"core.addKnowledge.confirm": "Microsoft 365 Agents Toolkit will modify files in your \"%s\" folder based on the capability source you provided. To avoid losing unexpected changes, back up your files or use git for change tracking before proceeding.",
"core.addKnowledge.continue": "Add",
"core.addSkill.confirm": "Microsoft 365 Agents Toolkit will modify files in your \"%s\" folder to add the agent skill. To avoid losing unexpected changes, back up your files or use git for change tracking before proceeding.",
"core.addSkill.continue": "Add",
"core.setSensitivityLabel.confirm": "Teams Toolkit will modify the file \"%s\" based on the sensitivity label you provided. To avoid losing unexpected changes, back up your files or use git for change tracking before proceeding.",
"core.setSensitivityLabel.continue": "Set",
"core.provision.provision": "Provision",
Expand Down Expand Up @@ -479,6 +481,9 @@
"core.addKnowledge.success.vsc": "Capability source added to the project successfully.",
"core.addKnowledge.success": "Capability source added to the project successfully. View agent manifest in \"%s\".",
"core.addKnowledge.success.viewAgentManifest": "View agent manifest",
"core.addSkill.success.vsc": "Agent skill added to the project successfully.",
"core.addSkill.success": "Agent skill added to the project successfully. View agent manifest in \"%s\".",
"core.addSkill.success.viewAgentManifest": "View agent manifest",
"core.scaffold.warning.summary": "We have detected following issues:\n%s",
"core.addPlugin.warning.manifestVariables": "Environment variables \"%s\" found in manifest of the added plugin. Ensure the values are set in .env file or system environment variables.",
"core.addPlugin.warning.apiSpecVariables": "Environment variables \"%s\" found in API specification of the added plugin. Ensure the values are set in .env file or system environment variables.",
Expand Down Expand Up @@ -1059,6 +1064,26 @@
"driver.typespec.error.multipleActionError": "More than one action found in declarativeAgent.json. Please make sure your TypeSpec files are valid and try again.",
"driver.typeSpec.progressBar": "Compiling and generating files...",
"core.addKnowledge.doubleConfirm": "Performing this action will overwrite your existing manifest file and can't be undone. To keep your existing data, please back it up before proceeding. Would you like to add new content?",
"core.addSkillQuestion.name.title": "Skill Name",
"core.addSkillQuestion.name.placeholder": "Enter a name for your skill (letters, numbers, and hyphens only)",
"core.addSkillQuestion.name.validation": "Skill name must start with a letter and contain only letters, numbers, and hyphens.",
"core.addSkillQuestion.name.duplicate": "A skill named \"%s\" already exists. Please choose a different name.",
"core.addSkillQuestion.description.title": "Skill Description",
"core.addSkillQuestion.description.placeholder": "Describe what this skill does",
"core.addSkillQuestion.expose.title": "Expose skill to M365 Copilot",
"core.addSkillQuestion.expose.yes": "Yes",
"core.addSkillQuestion.expose.no": "No",
"core.addSkillQuestion.sourceType.title": "How would you like to add a skill?",
"core.addSkillQuestion.sourceType.new": "Create a new skill",
"core.addSkillQuestion.sourceType.newDetail": "Start from scratch with a blank skill template",
"core.addSkillQuestion.sourceType.existing": "Start from an existing skill",
"core.addSkillQuestion.sourceType.existingDetail": "Import a skill from a .zip file",
"core.addSkillQuestion.zipFile.title": "Select a skill zip file",
"core.addSkillQuestion.zipFile.placeholder": "Select a .zip file containing a skill",
"core.addSkill.zipInvalidEntries": "The zip file contains invalid entries (path traversal or absolute paths). Please provide a valid skill zip file.",
"core.addSkill.zipNoSkillMd": "The zip file does not contain a SKILL.md file. Each skill must include a SKILL.md file.",
"core.addSkill.zipInvalidLayout": "The zip file has an invalid layout. It must contain either a single skill folder or skill files at the root level.",
"core.addSkill.zipSkillFolderExists": "A skill folder named \"%s\" already exists in the app package. Please remove it first or choose a different skill.",
"error.dep.InstallNodeJSError": "Unable to install Node.js for reason: %s. Please install it manually from https://nodejs.org and restart Visual Studio Code.",
"action.devTool.nodeInstaller.Progress.title": "Install NodeJS",
"action.devTool.nodeInstaller.Progress1": "Checking NodeJS in system environment",
Expand Down
5 changes: 5 additions & 0 deletions packages/fx-core/src/common/featureFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export class FeatureFlagName {
static readonly CFShortcutMetaOS = "TEAMSFX_CF_SHORTCUT_METAOS";
static readonly MCPForDA = "TEAMSFX_MCP_FOR_DA";
static readonly BrokerAuth = "TEAMSFX_BROKER_AUTH";
static readonly AgentSkillsEnabled = "TEAMSFX_AGENT_SKILLS";
// Add config files to existing project to make it toolkit compatible
static readonly GenerateConfigFiles = "TEAMSFX_GENERATE_CONFIG_FILES";

Expand Down Expand Up @@ -102,6 +103,10 @@ export class FeatureFlags {
name: FeatureFlagName.BrokerAuth,
defaultValue: "false",
};
static readonly AgentSkillsEnabled = {
name: FeatureFlagName.AgentSkillsEnabled,
defaultValue: "false",
};
static readonly GenerateConfigFiles = {
name: FeatureFlagName.GenerateConfigFiles,
defaultValue: "false",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,39 @@ export class CreateAppPackageDriver implements StepDriver {
}
}
}
// Add agent skill directories (support both agent_skills and x-agent_skills)
const agentSkills =
getCopilotGptRes.value.agent_skills || (getCopilotGptRes.value as any)["x-agent_skills"];
if (agentSkills && Array.isArray(agentSkills)) {
for (const skill of agentSkills) {
if (skill.folder) {
// Resolve skill folder relative to appDirectory (not .generated/)
// since skill folders don't support env var substitution
const skillFolderAbsolutePath = path.resolve(appDirectory, skill.folder);
const checkExistenceRes = await this.validateReferencedFile(
skillFolderAbsolutePath,
appDirectory
);
if (checkExistenceRes.isErr()) {
return err(checkExistenceRes.error);
}

const skillMdPath = path.join(skillFolderAbsolutePath, "SKILL.md");
if (!(await fs.pathExists(skillMdPath))) {
return err(
new FileNotFoundError(
actionName,
skillMdPath,
"https://aka.ms/teamsfx-actions/teamsapp-zipAppPackage"
)
);
}

const skillRelativePath = path.relative(appDirectory, skillFolderAbsolutePath);
zip.addLocalFolder(skillFolderAbsolutePath, skillRelativePath);
}
}
}
} else {
return err(getCopilotGptRes.error);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,17 @@ export interface DeclarativeCopilotManifestValidationResult {
filePath: string;
validationResult: string[];
actionValidationResult: PluginManifestValidationResult[];
skillValidationResult: SkillValidationResult[];
}

export interface PluginManifestValidationResult {
id: string;
filePath: string;
validationResult: string[];
}

export interface SkillValidationResult {
folder: string;
filePath: string;
validationResult: string[];
}
Loading
Loading