Skip to content

Latest commit

 

History

19 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RFP-Agent-On-MSFoundry

A compact Microsoft Agent Framework and Microsoft Foundry demo for turning a customer opportunity into an enterprise-ready solution assessment. The samples show the progression from model-only reasoning to organizational grounding with Foundry IQ, enterprise tools, hosted execution, and observability.

The included healthcare records and opportunity details are synthetic. The project is intended for demonstrations and learning, not as production clinical software.

Foundry IQ integration uses the 2026-05-01-preview Azure AI Search API and a beta Azure Search SDK. Review preview compatibility before production use.

Harness Office

Demo 03 is a conversational Agent Framework sandbox rendered as an observable pixel-art office. Avery, the session-scoped lead agent, retains chat history, decides whether each turn needs a plan, and selects bounded tools. Retrieval visits, delegation to Riley (the style-review agent), retries, and publication all come from real Harness tools and middleware events; the composer stays locked while a turn is active.

Current public research is delegated to Mona, a separate Agent Framework agent whose only capability is Foundry's native web-search tool. Mona cannot run until the user approves the precise delegated task with the in-office checkmark; rejection returns control to Avery without web access.

The chat accepts one PDF, DOCX, TXT, Markdown, CSV, or JSON attachment per turn, up to 5 MB. Documents are parsed in memory, capped at 60,000 extracted characters, treated as untrusted source material, and sent to the configured model as part of the turn.

Harness Office showing a live adaptive work plan and Foundry IQ search

Idle office Style-review subagent
The main agent sleeping in the Harness Office between turns The main agent visiting the proposal style reviewer in the neighboring studio

Foundry IQ and Azure AI Search document inspector

Start the local experience after completing Setup:

.\start.ps1

Harness Office opens at http://127.0.0.1:8090.

What this repository demonstrates

  1. Single-agent assessment - Publishes a prompt agent that calls an Agent Framework tool to read the opportunity and create a concise brief.
  2. Foundry IQ proposal generation - Uses hybrid agentic retrieval to match prior opportunities, retrieves their linked proposals, and writes a cited draft.
  3. Enterprise tools and hosting - Grounds an agent in CRM, architecture, and cost-profile tools and can expose the agent through the Foundry Responses protocol.
  4. Evaluation and tracing - Exports Agent Framework traces and records a simple enterprise-coverage score.

How it works

flowchart LR
  H[Seven synthetic cross-industry solutions] --> I[Ingestion script]
  P[Seven linked proposals] --> I
    I --> OS[Opportunity Search index]
    I --> PS[Proposal Search index]
    OS --> OKB[Opportunity knowledge base]
    PS --> PKB[Proposal knowledge base]

    O[New customer opportunity] --> OT[Opportunity tool]
    OT --> D1[Demo 1: baseline assessment]
    O --> D2[Demo 2: grounded proposal]
    OKB --> D2
    PKB --> D2
    D2 --> B[Timestamped Markdown proposal]

    O --> D3[Demo 3: Harness orchestration]
    OKB --> D3
    PKB --> D3
    D3 --> SR[Style-review Agent]
    D3 --> WR[Mona web-research Agent]
    WR --> HA[Human approval]
    HA --> WS[Foundry web search]
    SR --> GP[Review-gated publish]
    GP --> B

    T[Approved enterprise tools] --> D4[Demo 4: tool-grounded agent]
    D4 --> R[Local run or Responses host]

    O --> D5[Demo 5: observable assessment]
    D5 --> M[Foundry Toolkit, OTLP, or Application Insights]
Loading

The Foundry IQ path is deliberately separate from model generation:

  • ingest_foundry_iq.py creates separate opportunity and proposal indexes with semantic ranking, vectors, Azure OpenAI query-time vectorizers, knowledge sources, and planner-backed knowledge bases.
  • 02_patterns.py builds an explicit Agent Framework workflow graph with four nodes and three edges: opportunity retrieval → linked-proposal retrieval → proposal drafting → Sources assembly.
  • The assessment agent receives both the new opportunity and retrieved evidence. Historical claims use citations such as [0], while unsupported choices are labeled as recommendations or assumptions. The script prints only the uploaded proposal URL.

Repository layout

Path Purpose
kickoffdemos/01_intro.py Tool-sourced baseline opportunity assessment
kickoffdemos/ingest_foundry_iq.py Cross-industry Azure AI Search and Foundry IQ ingestion
kickoffdemos/02_patterns.py Two-stage hybrid agentic retrieval and grounded proposal generation
kickoffdemos/03_harness_simple.py Standalone Harness hello world with one synthetic tool
kickoffdemos/harness_simple_agent.py Reusable minimal Harness factory for local and hosted execution
kickoffdemos/03_harness.py Adaptive Harness orchestration with todos, bounded tools, and a style-review subagent
kickoffdemos/hosted_proposal_agent.py Foundry Hosted Agent adapter for the complete Demo 02 workflow
hosted_harness_simple.py Foundry Responses host for the minimal Harness demo
kickoffdemos/04_hosted_tools.py Enterprise tool calling and optional Responses host
kickoffdemos/05_observability.py Tracing and a custom coverage score
tests/test_demo_contracts.py Offline regression tests for ingestion, authentication, cleanup, and story contracts
RUN_DEMOS.md Detailed setup, execution, validation, and troubleshooting runbook
DEMO_GUIDE.md Presenter runbook for the consistent five-demo story
docs/images/ Release screenshots used by this README
.github/workflows/ci.yml Offline tests, Python compilation, and frontend syntax validation
.env.example Safe configuration template
requirements.txt Base dependencies for local demos
requirements-hosted.txt Optional prerelease dependency for Demo 4 hosted mode
LICENSE MIT license

Prerequisites

The local demos and hosted deployment have different requirements. You do not need Python 3.13, the Azure Developer CLI, or Foundry Toolkit to run the numbered demos or Harness Office locally.

Local demos and Harness Office

  • Python 3.12 for the numbered demos and Harness Office
  • Azure CLI
  • A Microsoft Foundry project with at least one deployed chat model
  • Permission for your Azure identity to use the project and invoke its model deployment
  • For Demos 2 and 3: an Azure AI Search service, an embedding deployment, and either:
    • a Search connection in the Foundry project, or
    • Azure RBAC access to the Search service for the signed-in Azure CLI identity
  • Optional Azure Storage for Demo 2; without it, proposals are written under outputs/
  • Optional Application Insights, an OTLP endpoint, or the Foundry Toolkit trace viewer for Demo 5

Check the required local tools from PowerShell:

py -3.12 --version
az --version

If the Python launcher is unavailable but python --version reports Python 3.12, use python in place of py -3.12 below.

Optional hosted-agent path

The hosted sections additionally require:

  • Python 3.13 or later
  • Azure Developer CLI (azd) with the Microsoft Foundry agent commands
  • Foundry Toolkit for VS Code only when using the F5 and Agent Inspector workflow

Verify that the hosted toolchain is available before following a hosted section:

py -3.13 --version
azd version
azd ai agent --help

Live model, Search, Storage, and telemetry calls may incur Azure charges.

Setup

Run all commands from the repository root.

1. Create the local Python environment

In PowerShell:

py -3.12 -m venv .venv
.\.venv\Scripts\python.exe -m pip install --upgrade pip
.\.venv\Scripts\python.exe -m pip install -r requirements.txt

Using the environment's Python executable directly avoids PowerShell execution-policy issues, so activation is optional. On macOS or Linux, use:

python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r requirements.txt

2. Sign in to Azure

az login
az account show --output table

Confirm that the selected tenant and subscription can access the Foundry project and Search service. The scripts use AzureCliCredential; do not put Azure access keys or client secrets in .env.

Typical access for the full demo is:

  • Foundry project access that permits model invocation and agent-version creation
  • Search Service Contributor and Search Index Data Contributor on the Search service when using direct or keyless Search access
  • Storage Blob Data Contributor on the optional Storage account
  • Cognitive Services OpenAI User for the Search service managed identity on the embedding resource, and Cognitive Services User on the Foundry planner resource

An administrator may need to assign these roles, and new assignments can take several minutes to propagate. A key-based Foundry Search connection supplies its Search key in memory and does not require Search data-plane roles for the local user.

3. Configure the demo

Create the ignored local configuration file:

Copy-Item .env.example .env

Edit .env and replace the applicable your-... placeholders. Every model demo needs the Foundry project endpoint and a chat-model deployment name:

FOUNDRY_PROJECT_ENDPOINT=https://your-resource.services.ai.azure.com/api/projects/your-project
AZURE_AI_MODEL_DEPLOYMENT_NAME=your-chat-deployment-name

# Harness Office starts on its Medium profile. Point it to a deployment in the same project.
HARNESS_MODEL_MEDIUM_DEPLOYMENT=your-chat-deployment-name

Copy the project endpoint from the Foundry project, not the browser address or account-level endpoint. Use the deployment name shown under the project's deployed models, which may differ from the model family name.

The full Foundry IQ path in Demos 2 and 3 also needs an embedding deployment and one Search access mode. The recommended project-connection mode is:

FOUNDRY_IQ_SEARCH_CONNECTION_NAME=your-search-connection-name
AZURE_OPENAI_EMBEDDING_ENDPOINT=https://your-embedding-resource.openai.azure.com
AZURE_OPENAI_EMBEDDING_DEPLOYMENT=your-embedding-deployment-name
AZURE_OPENAI_EMBEDDING_MODEL=text-embedding-3-large

For direct, keyless Search access, comment out the connection-name setting and use this instead:

FOUNDRY_IQ_SEARCH_ENDPOINT=https://your-search-service.search.windows.net

If you select the Strong or Small profile in Harness Office, also set HARNESS_MODEL_STRONG_DEPLOYMENT or HARNESS_MODEL_SMALL_DEPLOYMENT to deployments that exist in the same project. The Configuration table documents aliases and optional overrides.

Never commit .env or credentials. The repository ignores .env and tracks only .env.example.

4. Run offline preflight checks

.\.venv\Scripts\python.exe -B -m unittest discover -s tests -v
.\.venv\Scripts\python.exe -B kickoffdemos\ingest_foundry_iq.py --dry-run

The tests should finish with OK. The dry run should validate seven synthetic projects without contacting Azure.

5. Complete the first local run

For a model-only smoke test that does not use Search, run:

.\.venv\Scripts\python.exe -B kickoffdemos\03_harness_simple.py

For the full Foundry IQ and Harness Office experience, ingest the synthetic project memory once, then start the local server:

.\.venv\Scripts\python.exe -B kickoffdemos\ingest_foundry_iq.py
.\start.ps1

Open http://127.0.0.1:8090. Ingestion creates or updates persistent Search indexes, knowledge sources, and knowledge bases; it is safe to rerun. See RUN_DEMOS.md for expected output, the complete five-demo sequence, troubleshooting, and presenter checks.

Configuration

The setup above lists the minimum values for the primary local experience. The remaining settings are aliases or optional overrides unless their description says otherwise.

Variable Used by Description
FOUNDRY_PROJECT_ENDPOINT All model demos; Search connection mode Foundry project endpoint
AZURE_AI_PROJECT_ENDPOINT azure.yaml, azd, and all model demos Foundry project endpoint alias; use the same value as FOUNDRY_PROJECT_ENDPOINT
AZURE_AI_MODEL_DEPLOYMENT_NAME Demos 1-5 Model deployment name
HARNESS_MODEL_STRONG_DEPLOYMENT Demo 3 playground Optional strong-tier deployment override; defaults to gpt-5.2
HARNESS_MODEL_MEDIUM_DEPLOYMENT Demo 3 playground Optional medium-tier deployment override; defaults to gpt-4.1
HARNESS_MODEL_SMALL_DEPLOYMENT Demo 3 playground Optional small-tier deployment override; defaults to gpt-5-nano
FOUNDRY_IQ_SEARCH_CONNECTION_NAME Ingestion and Demo 2 Foundry project Search connection; required unless a direct Search endpoint is set
AZURE_AI_SEARCH_CONNECTION_NAME Hosted Demo 2 Alias for the Foundry project Search connection used by azure.yaml
FOUNDRY_IQ_SEARCH_ENDPOINT Ingestion and Demo 2 Optional direct Search endpoint using AzureCliCredential
AZURE_SEARCH_ENDPOINT Ingestion and Demo 2 Alias for the direct Search endpoint
FOUNDRY_IQ_OPPORTUNITY_INDEX_NAME Ingestion Optional index-name override
FOUNDRY_IQ_OPPORTUNITY_KNOWLEDGE_SOURCE_NAME Ingestion and Demo 2 Optional knowledge-source override
FOUNDRY_IQ_OPPORTUNITY_KNOWLEDGE_BASE_NAME Ingestion and Demo 2 Optional knowledge-base override
FOUNDRY_IQ_PROPOSAL_INDEX_NAME Ingestion Optional proposal index-name override
FOUNDRY_IQ_PROPOSAL_KNOWLEDGE_SOURCE_NAME Ingestion and Demo 2 Optional proposal knowledge-source override
FOUNDRY_IQ_PROPOSAL_KNOWLEDGE_BASE_NAME Ingestion and Demo 2 Optional proposal knowledge-base override
AZURE_OPENAI_EMBEDDING_ENDPOINT Ingestion Azure OpenAI resource root used for document and query vectorization
AZURE_OPENAI_EMBEDDING_DEPLOYMENT Ingestion Embedding deployment name
AZURE_OPENAI_EMBEDDING_MODEL Ingestion Embedding model name; defaults to the deployment name
AZURE_OPENAI_EMBEDDING_DIMENSIONS Ingestion Optional vector dimensions; inferred for known embedding models
FOUNDRY_IQ_PLANNER_MODEL_NAME Ingestion Optional model-name override for agentic query planning
AZURE_STORAGE_ACCOUNT_URL Demo 2 Optional Blob service URL; absent or blocked storage falls back to outputs/
AZURE_STORAGE_PROPOSAL_CONTAINER_NAME Demo 2 Optional container override; defaults to opportunity-proposals
APPLICATIONINSIGHTS_CONNECTION_STRING Demo 5 Optional Application Insights export
OTEL_EXPORTER_OTLP_ENDPOINT Demo 5 Optional generic OpenTelemetry export

AZURE_AI_PROJECT_ENDPOINT, project_endpoint, FOUNDRY_MODEL, and deployment_name remain supported aliases in the sample code.

Search authentication

The ingestion and retrieval scripts support two modes:

  • Foundry connection: Set FOUNDRY_PROJECT_ENDPOINT and FOUNDRY_IQ_SEARCH_CONNECTION_NAME. The scripts resolve the Search endpoint from that project connection. Key-based connections use their in-memory key; keyless connections use AzureCliCredential and require the signed-in identity to have the appropriate Azure AI Search roles.
  • Direct endpoint: Set FOUNDRY_IQ_SEARCH_ENDPOINT or AZURE_SEARCH_ENDPOINT. The scripts use AzureCliCredential; assign the signed-in identity the appropriate Azure AI Search roles for index management, document upload, and retrieval.

The default persistent resource names are:

  • Opportunity index/base: si-healthcare-opportunity-history / si-healthcare-opportunity-assessment-kb
  • Proposal index/base: si-healthcare-opportunity-proposals / si-healthcare-opportunity-proposals-kb

Running ingestion again updates both vectorized indexes and uploads the same three IDs per index, making the operation idempotent. The Search service managed identity needs Cognitive Services OpenAI User on the embedding resource and Cognitive Services User on the Foundry planner resource.

Proposal storage

Demo 2 uses AzureCliCredential to create the proposal container when needed and upload a Markdown blob. Assign the signed-in identity Azure Storage Blob Data Contributor at the storage-account scope so it can upload and create a user-delegation read SAS.

New containers remain private. For a private container, the printed URL contains a one-hour read-only SAS. If the account and existing container already permit anonymous blob access, the script detects that setting and prints the direct blob URL instead. It never enables public access itself.

Run the Foundry IQ scenario

Validate the sample records without contacting Azure:

python -B kickoffdemos/ingest_foundry_iq.py --dry-run

Create or update the index, documents, knowledge source, and knowledge base:

python -B kickoffdemos/ingest_foundry_iq.py

Run the baseline assessment:

python -B kickoffdemos/01_intro.py

Create, upload, and get the URL for the grounded proposal:

python -B kickoffdemos/02_patterns.py

Show each retrieval and generation stage in the terminal while preserving the final output path on stdout:

python -B kickoffdemos/02_patterns.py --verbose

Run the standalone minimal Harness example. It has one synthetic weather tool and no opportunity, retrieval, workflow, or publication logic:

python -B kickoffdemos/03_harness_simple.py

Then compare the fixed graph with the fuller Harness agent that plans the same job through built-in todos and plan/execute modes. It receives separate opportunity retrieval, linked-proposal retrieval, and publication tools; those tools still enforce ordering, citations, and the final Sources section:

python -B kickoffdemos/03_harness.py --verbose

Launch the observable pixel-art Harness Office at http://127.0.0.1:8090:

.\start.ps1

Send sequential messages through the chat composer. The same local Agent Framework session handles every turn and retains conversation history; the composer is disabled until both execution and office animation finish. Simple questions can be answered without a plan. For multi-step work, the agent can use TodoProvider and choose a request-specific plan with no predetermined step count. Structured middleware and bounded-tool events drive the work plan, speech bubbles, timeline, and route, which records every workstation return and retry without exposing private chain-of-thought. Use .\start.ps1 -Port <port> when port 8090 is occupied. The first turn opens with a visitor handing over an attached document; plain chat wakes Avery in place and creates no route stops unless planning or a tool is actually used. Before publication, the main agent walks to the neighboring style studio and invokes Riley, a separate riley-style-reviewer Agent Framework agent. The publishing tool accepts only the exact revised Markdown returned by Riley. When Avery needs current public information, Mona appears at the web-search desk and requests approval inside the same illustration. The chat remains locked while the checkmark/reject decision is pending. Attach a supported document with the paperclip button before sending. The app never writes attachment bytes to disk. Extracted text remains in the in-memory Agent Framework session context for follow-up turns; the visible transcript retains only the safe filename. Model responses keep store: False. After retrieval, select either library shelf in Harness Office to browse the synthetic Foundry IQ references backed by Azure AI Search. The inspector shows source metadata, reranker scores, index and knowledge-base names, and the full retrieved document content; credentials and connection details are never sent to the browser.

Launch the browser-based Agent Framework DevUI:

python -B kickoffdemos/02_patterns.py --devui

If port 8080 is occupied, choose another loopback port:

python -B kickoffdemos/02_patterns.py --devui --devui-port 8081

In DevUI, select opportunity-proposal-workflow. Its structured input is titled Customer Opportunity / Call for Offer. Paste the complete customer request, RFP excerpt, or opportunity brief into Customer Opportunity / Call-for-Offer Text, including the business goal, current process, constraints, required controls, target outcomes, and mandatory human approvals. The graph displays retrieve_opportunities, retrieve_linked_proposals, draft_proposal, and assemble_sources as separate nodes connected by directed edges. The first three nodes emit intermediate progress events; the final node emits the cited proposal. DevUI binds only to 127.0.0.1 and disables authentication for this local development experience.

Open DevUI's Traces tab, expand an executor.process ... span, and select its workflow.output ... child span. The child span includes a readable summary and a demo.workflow.output.data attribute containing that stage's full synthetic output: Foundry IQ grounding and references for retrieval stages, or Markdown for drafting stages. This content capture is enabled only by --devui; normal CLI workflow traces retain counts and titles without raw bodies. After the final stage persists the draft, DevUI also shows a separate workflow.output draft_file span. Its demo.workflow.output.file_name and demo.workflow.output.storage_type attributes identify the actual timestamped Markdown file and whether it was saved to Azure Blob Storage or outputs/.

Run the minimal Harness in Foundry Toolkit

The harness-simple-agent service is the shortest Hosted Agent demonstration: one reusable Agent Framework Harness factory, one synthetic tool, and a Responses host. It uses DefaultAzureCredential and keeps default_options={"store": False}. Foundry injects FOUNDRY_PROJECT_ENDPOINT; the service configuration supplies only the model deployment name.

Create the dedicated Python 3.13 environment once:

py -3.13 -m venv .venv-hosted
.\.venv-hosted\Scripts\python.exe -m pip install -r requirements-hosted.txt

The F5 task invokes .venv-hosted directly. Optionally select that interpreter in VS Code so editor analysis uses the same packages. Open Run and Debug, select Debug Harness Simple Hosted Agent, and press F5. Foundry Toolkit opens Agent Inspector after the Responses server reaches port 8088. Send:

What is the weather in Seattle?

The same smoke test is available from two terminals:

$env:AZURE_DEV_USER_AGENT = "microsoft_foundry_skill"
azd ai agent run harness-simple-agent --no-client --start-command ".\.venv-hosted\Scripts\python.exe hosted_harness_simple.py"
# In a second terminal:
azd ai agent invoke harness-simple-agent --local "What is the weather in Seattle?"

Prepare and deploy the hosted workflow

The second hosted service is configured in azure.yaml as opportunity-proposal-agent using direct code deployment and the Responses protocol. It returns proposal Markdown directly instead of a container-local output path.

Run locally and invoke once:

$env:AZURE_DEV_USER_AGENT = "microsoft_foundry_skill"
azd ai agent run opportunity-proposal-agent --no-client
# In a second terminal:
azd ai agent invoke opportunity-proposal-agent --local "<customer opportunity>"

Deploy when the local smoke test succeeds:

$env:AZURE_DEV_USER_AGENT = "microsoft_foundry_skill"
azd deploy opportunity-proposal-agent --no-prompt
azd ai agent show --output json
azd ai agent invoke opportunity-proposal-agent "<customer opportunity>"

Each deployment creates an immutable hosted-agent version. The deployed agent identity must be able to read the Foundry project connection and the two Azure AI Search knowledge bases.

You can pass a different opportunity as the positional argument. Retrieval quality depends on its similarity to the seven cross-industry projects.

Run the remaining demos

Run the tool-grounded agent locally:

python -B kickoffdemos/04_hosted_tools.py

Hosted mode uses a prerelease package and requires a configured Foundry Hosted Agent environment:

python -m pip install -r requirements-hosted.txt
python -B kickoffdemos/04_hosted_tools.py --serve

Run the observable assessment:

python -B kickoffdemos/05_observability.py

Prompt and completion content capture is disabled by default. Use --include-content only with non-sensitive data and an approved telemetry destination.

Test offline contracts

After installing the base requirements, run the standard-library unittest suite without contacting Azure:

python -B -m unittest discover -s tests -v

The suite checks ingestion, Search authentication, retrieval cleanup, timestamped non-overwriting proposal uploads, public and private URL behavior, untrusted-evidence instructions, disabled response storage, the shared opportunity, and Demo 5 coverage.

Operational notes

  • The ingestion records are synthetic and contain no patient data.
  • Retrieved documents are treated as evidence, not executable instructions.
  • The opportunity assessment keeps clinician approval as a mandatory boundary.
  • Stateless agent calls set store=False so model responses are not stored by the Responses API.
  • Demo 1 prompt-agent versions and the Demo 2 Search, knowledge, container, and proposal blobs persist after the scripts exit; this repository does not delete Azure resources.
  • The custom Demo 5 coverage score checks for expected phrases. It is illustrative, not a production quality or safety evaluation.
  • Review identity, networking, content safety, evaluations, error handling, and lifecycle management before adapting these samples for production.

Public release checklist

  • Confirm .env, caches, traces, and credentials are not staged.
  • Review all resource names and sample content for your organization.
  • Run the dry run and all --help commands in a clean environment.
  • Run live ingestion and Demo 2 against a non-production Azure environment.
  • Review the preview SDK/API pins before upgrading.
  • Confirm the MIT license is compatible with your organization's release policy.

License

This project is licensed under the MIT License.

References

About

Demo repository for an RFP agent with game-like agent real-time visualization

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages