Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 3 additions & 2 deletions .github/skills/add-feature/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,9 @@ bug fixes.
- Use the **`update-schema-docs` skill** to add examples to `docs/front-matter-spec.md`
and review `docs/architecture.md` for consistency
- Review the skill's PR checklist and address architectural concerns
3. Update `docs/front-matter-spec.md` and/or `docs/triggers.md` if the authoring
surface changed (for non-schema changes, or to refine schema-generated examples).
3. Update relevant docs under `docs/` (commonly `front-matter-spec.md`, `triggers.md`,
or other files as needed) if the authoring surface changed (for non-schema changes,
or to refine schema-generated examples).
4. Update `README.md` if user-facing behavior changed.
5. Update the FRD index in `docs/frds/README.md`.
6. Verify the `AGENTS.md` §8 Definition of Done, then open the PR.
Expand Down
2 changes: 1 addition & 1 deletion docs/AUTO_GENERATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ Trigger type documentation is defined in the `TRIGGER_TYPES` dictionary in `src/

### Field Descriptions

Enhanced descriptions are in `*_DESCRIPTIONS` dictionaries in the script. These complement the Pydantic model docstrings and add links to other docs sections.
Enhanced descriptions are in `*_DESCRIPTIONS` dictionaries in `src/azure_functions_agents/config/schema.py` alongside the Pydantic models. These complement the Pydantic model docstrings and add markdown formatting and links to other docs sections. To update field descriptions, edit the appropriate description dictionary in `schema.py`.
Comment thread
hallvictoria marked this conversation as resolved.

### Static Sections

Expand Down
97 changes: 89 additions & 8 deletions eng/ci/library-release.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
trigger:
batch: true
branches:
include:
- main
paths:
include:
- src/**
exclude:
- src/azure_functions_agents/__init__.py

pr: none

parameters:
- name: libraryVersion
type: string
default: ''
displayName: 'Library version to release (e.g., 0.1.0)'
- name: projectDisplayName
type: string
Expand All @@ -12,19 +26,19 @@ parameters:
displayName: 'Path to version file (e.g., __init__.py or version.py)'
- name: versionPattern
type: string
default: "__version__ = ['\"]([0-9])+\\.([0-9])+.*['\"]"
default: "__version__ = [\"]([0-9])+\\.([0-9])+.*[\"]"
Comment thread
hallvictoria marked this conversation as resolved.
displayName: 'Regex pattern to match version string in version file'
Comment thread
hallvictoria marked this conversation as resolved.
- name: versionReplacement
type: string
default: '__version__ = "{{VERSION}}"'
displayName: 'Replacement pattern for version (use {{VERSION}} as placeholder)'
- name: releaseBranchPrefix
type: string
default: 'release'
default: 'v'
displayName: 'Prefix for release branch (e.g., release or release-v2)'
- name: tagPrefix
type: string
default: ''
default: 'v'
displayName: 'Optional prefix for git tags (e.g., runtimes/v2-)'
- name: createPullRequest
type: boolean
Expand Down Expand Up @@ -71,12 +85,71 @@ extends:
os: windows

stages:
- stage: ResolveVersion
Comment thread
hallvictoria marked this conversation as resolved.
displayName: 'Resolve Library Version'
jobs:
- job: ResolveVersionJob
displayName: 'Compute next beta version'
pool:
name: 1es-pool-azfunc
image: 1es-windows-2022
os: windows
steps:
- powershell: |
$providedVersion = "${{ parameters.libraryVersion }}".Trim()
if (-not [string]::IsNullOrWhiteSpace($providedVersion)) {
Write-Host "Using provided libraryVersion: $providedVersion"
Write-Host "##vso[task.setvariable variable=resolvedLibraryVersion;isOutput=true]$providedVersion"
exit 0
}

$versionFilePath = "${{ parameters.versionFilePath }}"
if (-not (Test-Path -LiteralPath $versionFilePath)) {
Write-Host "Version file not found: $versionFilePath"
exit 1
}

$content = Get-Content -LiteralPath $versionFilePath -Raw
$match = [regex]::Match($content, '__version__\s*=\s*"(?<version>[^"]+)"')
if (-not $match.Success) {
$match = [regex]::Match($content, "__version__\s*=\s*'(?<version>[^']+)'")
}
if (-not $match.Success) {
Write-Host "Unable to read __version__ from $versionFilePath"
exit 1
}

$currentVersion = $match.Groups['version'].Value
$nextVersion = $null

$betaMatch = [regex]::Match($currentVersion, "^(?<base>\d+\.\d+\.\d+)b(?<beta>\d+)$")
if ($betaMatch.Success) {
$baseVersion = $betaMatch.Groups['base'].Value
$nextBeta = [int]$betaMatch.Groups['beta'].Value + 1
$nextVersion = "$baseVersion" + "b$nextBeta"
}
elseif ($currentVersion -match '^\d+\.\d+\.\d+$') {
$nextVersion = "$currentVersion" + "b1"
}
else {
Write-Host "Unsupported version format '$currentVersion'. Expected x.y.z or x.y.zbN"
exit 1
}

Write-Host "Resolved libraryVersion: $nextVersion (from $currentVersion)"
Write-Host "##vso[task.setvariable variable=resolvedLibraryVersion;isOutput=true]$nextVersion"
displayName: 'Resolve libraryVersion value'
name: setVersion

- stage: BumpVersion
displayName: 'Bump Version'
dependsOn: ResolveVersion
variables:
resolvedLibraryVersion: $[ stageDependencies.ResolveVersion.ResolveVersionJob.outputs['setVersion.resolvedLibraryVersion'] ]
jobs:
- template: /eng/templates/official/jobs/bump-version.yml@self
parameters:
libraryVersion: ${{ parameters.libraryVersion }}
libraryVersion: $(resolvedLibraryVersion)
projectDisplayName: ${{ parameters.projectDisplayName }}
versionFilePath: ${{ parameters.versionFilePath }}
versionPattern: ${{ parameters.versionPattern }}
Expand All @@ -89,24 +162,32 @@ extends:

- stage: Build
displayName: 'Build ${{ parameters.projectDisplayName }}'
dependsOn: BumpVersion
dependsOn:
- BumpVersion
- ResolveVersion
variables:
resolvedLibraryVersion: $[ stageDependencies.ResolveVersion.ResolveVersionJob.outputs['setVersion.resolvedLibraryVersion'] ]
jobs:
- template: /eng/templates/official/jobs/build-artifacts.yml@self
parameters:
artifactName: ${{ parameters.artifactName }}
projectDisplayName: ${{ parameters.projectDisplayName }}
libraryVersion: ${{ parameters.libraryVersion }}
libraryVersion: $(resolvedLibraryVersion)
releaseBranchPrefix: ${{ parameters.releaseBranchPrefix }}
githubOrg: ${{ parameters.githubOrg }}
githubRepo: ${{ parameters.githubRepo }}

- stage: Release
displayName: 'Release ${{ parameters.projectDisplayName }}'
dependsOn: Build
dependsOn:
- Build
- ResolveVersion
variables:
resolvedLibraryVersion: $[ stageDependencies.ResolveVersion.ResolveVersionJob.outputs['setVersion.resolvedLibraryVersion'] ]
jobs:
- template: /eng/templates/official/jobs/publish-release.yml@self
parameters:
libraryVersion: ${{ parameters.libraryVersion }}
libraryVersion: $(resolvedLibraryVersion)
projectDisplayName: ${{ parameters.projectDisplayName }}
releaseBranchPrefix: ${{ parameters.releaseBranchPrefix }}
tagPrefix: ${{ parameters.tagPrefix }}
Expand Down
16 changes: 16 additions & 0 deletions eng/scripts/generate_config_reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,22 @@
TRIGGER_TYPES = schema.TRIGGER_TYPES
WebRequestConfig = schema.WebRequestConfig

# Extract description and default value dictionaries
GLOBAL_CONFIG_DESCRIPTIONS = schema.GLOBAL_CONFIG_DESCRIPTIONS
Comment thread
hallvictoria marked this conversation as resolved.
GLOBAL_CONFIG_DEFAULTS = schema.GLOBAL_CONFIG_DEFAULTS
SYSTEM_TOOLS_CONFIG_DESCRIPTIONS = schema.SYSTEM_TOOLS_CONFIG_DESCRIPTIONS
DYNAMIC_SESSIONS_DESCRIPTIONS = schema.DYNAMIC_SESSIONS_DESCRIPTIONS
TOOLS_FILTER_DESCRIPTIONS = schema.TOOLS_FILTER_DESCRIPTIONS
AGENT_SPEC_REQUIRED_DESCRIPTIONS = schema.AGENT_SPEC_REQUIRED_DESCRIPTIONS
AGENT_SPEC_OPTIONAL_DESCRIPTIONS = schema.AGENT_SPEC_OPTIONAL_DESCRIPTIONS
TRIGGER_SPEC_DESCRIPTIONS = schema.TRIGGER_SPEC_DESCRIPTIONS
BUILTIN_ENDPOINTS_DESCRIPTIONS = schema.BUILTIN_ENDPOINTS_DESCRIPTIONS
SYSTEM_TOOLS_AGENT_DESCRIPTIONS = schema.SYSTEM_TOOLS_AGENT_DESCRIPTIONS
MCP_FILTER_DESCRIPTIONS = schema.MCP_FILTER_DESCRIPTIONS
SKILLS_FILTER_DESCRIPTIONS = schema.SKILLS_FILTER_DESCRIPTIONS
AGENT_TOOLS_FILTER_DESCRIPTIONS = schema.AGENT_TOOLS_FILTER_DESCRIPTIONS
WEB_REQUEST_DESCRIPTIONS = schema.WEB_REQUEST_DESCRIPTIONS


def format_type(field_info: FieldInfo, field_name: str) -> str:
"""Format field type annotation as a readable string."""
Expand Down
93 changes: 93 additions & 0 deletions src/azure_functions_agents/config/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,3 +329,96 @@ class ResolvedAgent(BaseModel):
"note": "No configuration properties. Receives Connector events.",
},
}


# Field description metadata for documentation generation
# Used by eng/scripts/generate_config_reference.py to enhance generated docs.
# These descriptions complement or override Pydantic field metadata and may include
# markdown formatting and internal document links.

GLOBAL_CONFIG_DESCRIPTIONS: dict[str, str] = {
"system_tools": "System-level tools configuration. [Details](#global-system_tools)",
"model": "Default LLM model identifier for all agents",
"timeout": "Default execution timeout in seconds",
"tools": "Global tool filtering configuration. [Details](#global-tools)",
}

GLOBAL_CONFIG_DEFAULTS: dict[str, str] = {
"system_tools": "`{}`",
"model": "Resolved from env/provider",
"timeout": "`900`",
"tools": "`{}`",
}

SYSTEM_TOOLS_CONFIG_DESCRIPTIONS: dict[str, str] = {
Comment thread
hallvictoria marked this conversation as resolved.
"dynamic_sessions_code_interpreter": "ACA Dynamic Sessions code interpreter configuration. [Details](#global-system_toolsdynamic_sessions_code_interpreter)",
"web_request": "Outbound HTTP request tool configuration. Enabled by default; set to `false` to disable app-wide. [Details](#global-system_toolsweb_request)",
}
Comment thread
Copilot marked this conversation as resolved.

DYNAMIC_SESSIONS_DESCRIPTIONS: dict[str, str] = {
"endpoint": "ACA session pool endpoint URL. Supports env var substitution.",
"client_id": "Optional managed identity client ID for multi-identity Function Apps",
}

TOOLS_FILTER_DESCRIPTIONS: dict[str, str] = {
"exclude": "Tool names to exclude globally from all agents",
}

AGENT_SPEC_REQUIRED_DESCRIPTIONS: dict[str, str] = {
"name": "Display name for the agent. Does not control function name or route.",
"description": "Brief description of the agent's purpose",
"trigger": "Required unless at least one `builtin_endpoints` value is enabled. [Details](#agent-trigger)",
}

AGENT_SPEC_OPTIONAL_DESCRIPTIONS: dict[str, str] = {
"builtin_endpoints": "Enable built-in chat UI, chat API, and/or MCP tool endpoints. [Details](#agent-builtin_endpoints)",
"model": "Override LLM model for this agent",
"timeout": "Override execution timeout (seconds) for this agent",
"logger": "Enable/disable response logging for triggered agents",
"substitute_variables": "Enable/disable environment variable substitution",
"system_tools": "Opt out of system tools. [Details](#agent-system_tools)",
"mcp": "MCP server filtering. [Details](#agent-mcp)",
"skills": "Skill filtering. [Details](#agent-skills)",
"tools": "Custom tool filtering. [Details](#agent-tools)",
"workflows": "Dynamic Workflow enablement and filtering. [Details](./front-matter-spec.md#workflows)",
"input_schema": "JSON Schema for HTTP request validation",
"response_schema": "JSON Schema for response validation",
"response_example": "Example response structure (multiline string)",
"metadata": "Additional metadata for organization. Free-form.",
}

TRIGGER_SPEC_DESCRIPTIONS: dict[str, str] = {
"type": "Trigger type identifier. See [Supported Trigger Types](#supported-trigger-types)",
"args": "Type-specific configuration. See [Supported Trigger Types](#supported-trigger-types)",
}

BUILTIN_ENDPOINTS_DESCRIPTIONS: dict[str, str] = {
"debug_chat_ui": "Enable browser-based chat UI at `/agents/{slug}/` plus backing chat APIs",
"chat_api": "Enable REST API endpoints (`/agents/{slug}/chat`, `/agents/{slug}/chatstream`)",
"mcp": "Expose agent as MCP tool on shared runtime MCP transport",
}

SYSTEM_TOOLS_AGENT_DESCRIPTIONS: dict[str, str] = {
"dynamic_sessions_code_interpreter": "Set to `false` to opt out of code execution capabilities",
"web_request": "Set to `false` to opt out of the default-on `web_request` tool for this agent",
}

MCP_FILTER_DESCRIPTIONS: dict[str, str] = {
"exclude": "MCP server names to exclude. Must match servers in `mcp.json`.",
}

SKILLS_FILTER_DESCRIPTIONS: dict[str, str] = {
"exclude": "Skill names to exclude. Matched against `SKILL.md` `name` field.",
}

AGENT_TOOLS_FILTER_DESCRIPTIONS: dict[str, str] = {
"exclude": "Tool names to exclude (in addition to global excludes)",
}

WEB_REQUEST_DESCRIPTIONS: dict[str, str] = {
"allowed_hosts": "Exact-match allowlist of hostnames the tool may call. Omit to allow any public host (still subject to the SSRF floor).",
"require_https": "Require `https://` URLs. Set to `false` to also allow `http://`.",
"timeout_seconds": "Per-request timeout in seconds, clamped to a runtime-defined ceiling (120 s).",
"max_response_bytes": "Maximum response body size read before truncating, clamped to a runtime-defined ceiling (10 MB).",
"max_request_bytes": "Maximum request body size accepted, clamped to a runtime-defined ceiling (10 MB).",
}