diff --git a/README.md b/README.md index 1c0159c..cd6b26d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# BlogWriter, an open source project is [documented here](https://jesseliberty.com) +# BlogWriter: an open source project -This program, **Blog Writer**, is designed to research and write blog posts. It was written with *Microsoft Agent Framework* and the principal actors are the **BloggerAgent** which works as the orchestrator, the **ResearcherAgent** which goes out to the Web to research the requested topic, the **AuthorAgent** which then writes the blog post, and the **ReviewerAgent** which reviews the proposed blog post, sending it back to the AuthorAgent if it is not approved. +This program, **Blog Writer**, is designed to research and write blog posts. It was written with *Microsoft Agent Framework* and the principal actors are the **BloggerAgent** which works as the orchestrator, the **ResearcherAgent** which goes out to the Web (and to *Microsoft Learn*) to research the requested topic, the **AuthorAgent** which then writes the blog post, and the **ReviewerAgent** which reviews the proposed blog post, sending it back to the AuthorAgent if it is not approved. *Note: BlogWriter was written as a demonstration program and is not ready for production.* @@ -11,15 +11,15 @@ the same workflow and Cosmos session store. It includes separate draft and revie panes, prompt and revision inputs, numbered saved-session recall, bounded cancellation, and responsive WCAG 2.2 AA-oriented controls. The compact `Min` and `Max` fields between the prompts and content panes set the target word range for new drafts and revisions; -they default to 1000 and 2000 words. Workflow progress, validation, cancellation, and -failure messages appear as an ordered log beneath the New/List/Revise/Quit buttons. -Reviewer feedback is kept in Reviewer notes as it arrives and accumulates across -revisions for the active session; it is cleared when starting New or loading another -session. In List mode, enter the one-based session number beside List to restore the -saved MainTask and optional CurrentSubTask and launch it immediately. The `?` command -shows and copies the HTTPS launch command. The Revision request field is editable after -New, while Revise becomes available once a draft/session exists. Workflow status is -shown as one latest-message line; Reviewer notes remain separate. +they default to 1000 and 2000 words. Workflow progresss below the buttons. +Reviewer feedback is displayed in the window when the draft is rejected. +It is cleared when starting New or loading another +session or modifying the current query. + +In List mode, enter the one-based session number beside List to restore the +saved MainTask and optional CurrentSubTask and launch it immediately. For now, the `?` command +shows and copies the HTTPS launch command. The query field is editable after +New, while Revise becomes available once a draft/session exists. After configuring Microsoft Entra, Foundry, and Cosmos values from [docs/configuration.md](docs/configuration.md), start it with: @@ -35,7 +35,7 @@ The original console remains available with `dotnet run --project BlogWriter.csp The 4 agents are deployed as independent **Azure AI Foundry Hosted Agents** (Foundry Agent Service), each with its own managed compute, dedicated Microsoft Entra ID identity, and OpenAI-compatible `/responses` endpoint. The -console app (this project) no longer builds the agents in-process — it only +console app does not build the agents in-process — it only **orchestrates** them locally via the MAF Workflow in `BlogWorkflow.cs`, calling each hosted agent as a remote `IChatClient` using the Microsoft Agent Framework Foundry integration. @@ -69,11 +69,13 @@ auth, no API keys: | `AUTHOR_AGENT_NAME` | no | `Author` | | | `REVIEWER_AGENT_NAME` | no | `Reviewer` | | | `MAX_TOTAL_TOKENS` | no | `40000` | Cumulative process-wide cap (`TokenCapChatClient`) | +| `COSMOS_ENDPOINT` | yes | `cosmos endpoint` | | +| `COSMOS_DATABASE_NAME` | yes | `blogWriter` | | +| `COSMOS_CONTAINER_NAME` | yes | container name | | ## Documentation * [docs/architecture.md](docs/architecture.md) — full architecture, workflow graph, auth, and token-budget details. -* [docs/changelog-v1-to-v2.md](docs/changelog-v1-to-v2.md) — what changed from the original in-process design to the current hosted-agent one. * [docs/deployment.md](docs/deployment.md) — the `azd` flow for deploying/redeploying each hosted agent and running the console app locally. * [docs/configuration.md](docs/configuration.md) — every environment variable/secret used by the console app and the four hosted agents. @@ -88,4 +90,3 @@ auth, no API keys: * Middleware is used to manage the tools. * OpenTelemetry is used to manage logging and emits a GenAI span per model round-trip. * ChatOptions sets the temperature to 0 for maximum consistency. - diff --git a/docs/~configuration.md.saved.bak b/docs/~configuration.md.saved.bak deleted file mode 100644 index 4481cf7..0000000 --- a/docs/~configuration.md.saved.bak +++ /dev/null @@ -1,117 +0,0 @@ -# Configuration reference - -All values below are read from environment variables, with `dotnet user-secrets` -recommended for local development of the console app (secrets win over environment -variables on key collisions). None of the four hosted agents or the console app use API -keys — every credential is Microsoft Entra ID (`AzureCliCredential` locally, -`DefaultAzureCredential` in hosted agents). - -## Console app (`BlogWriter.csproj`, root `Program.cs`) - -| Key | Required | Default | Notes | -| --- | --- | --- | --- | -| `FOUNDRY_PROJECT_ENDPOINT` | yes | — | e.g. `https://.services.ai.azure.com/api/projects/` | -| `AZURE_TENANT_ID` | yes | — | Microsoft Entra tenant hosting the Foundry project | -| `BLOGGER_AGENT_NAME` | no | `Blogger` | Name of the deployed hosted agent to call | -| `RESEARCHER_AGENT_NAME` | no | `Researcher` | | -| `AUTHOR_AGENT_NAME` | no | `Author` | | -| `REVIEWER_AGENT_NAME` | no | `Reviewer` | | -| `MAX_TOTAL_TOKENS` | no | `40000` | Cumulative cross-agent token cap (`TokenCapChatClient`); parse failures fall back to the default | -| `COSMOS_ENDPOINT` | yes | — | URI of the Azure Cosmos DB for NoSQL account; authenticates with Microsoft Entra ID | -| `COSMOS_DATABASE_NAME` | yes | — | Database containing BlogWriter session documents | -| `COSMOS_CONTAINER_NAME` | yes | — | Owner-partitioned container containing BlogWriter session documents | - -Set with, e.g.: - -```powershell -dotnet user-secrets set "FOUNDRY_PROJECT_ENDPOINT" "https://.services.ai.azure.com/api/projects/" -dotnet user-secrets set "AZURE_TENANT_ID" "" -``` - -## Each hosted agent (`HostedAgents/Blogger`, `Researcher`, `Author`, `Reviewer`) - -| Key | Required | Default | Notes | -| --- | --- | --- | --- | -| `FOUNDRY_PROJECT_ENDPOINT` | yes | — | Same Foundry project the console app points at | -| `AZURE_AI_MODEL_DEPLOYMENT_NAME` | no | `gpt-5-mini` | Model deployment used by that specific agent; set per-project in its own `azure.yaml` | - -These are set as `environmentVariables` in each project's `azure.yaml` and provisioned by -`azd` — see [deployment.md](deployment.md). They're not read from `dotnet user-secrets` -since hosted agents run in Azure, not locally, once deployed. - -## Blazor web app (`BlogWriter.Web/BlogWriter.Web.csproj`) - -The web host uses Microsoft Entra OpenID Connect for user sign-in. The signed-in -user's `oid` claim owns session data; a separate Azure credential authorizes the -server to call Foundry and Cosmos. - -The web host uses the authorization-code flow with PKCE. In the Entra app -registration, configure `https://localhost:7056/signin-oidc` as a **Web** redirect -URI. Do not enable the implicit-grant access-token or ID-token checkboxes. - -| Key | Required | Default | Notes | -| --- | --- | --- | --- | -| `AzureAd:TenantId` | yes | — | Entra tenant for user sign-in | -| `AzureAd:ClientId` | yes | — | Web app registration client ID | -| `AzureAd:ClientSecret` | local only | — | Store in user secrets; never commit | -| `AzureAd:CallbackPath` | no | `/signin-oidc` | Must match the app registration redirect URI | -| `AzureAd:ClientCredentials:0:SourceType` | production | `KeyVault` | Certificate credential source | -| `AzureAd:ClientCredentials:0:KeyVaultUrl` | production | — | Key Vault containing the OIDC certificate | -| `AzureAd:ClientCredentials:0:KeyVaultCertificateName` | production | — | Certificate name registered with the Entra app | -| `AzureResources:CredentialMode` | yes | `AzureCli` | `AzureCli` locally; `ManagedIdentity` in production | -| `Foundry:ProjectEndpoint` | yes | — | Existing Foundry project endpoint | -| `Foundry:*AgentName` | no | role name | Existing hosted-agent names | -| `Foundry:MaxTotalTokens` | no | `40000` | Shared process token cap | -| `Cosmos:Endpoint` | yes | — | Cosmos account endpoint | -| `Cosmos:DatabaseName` | yes | — | Session database | -| `Cosmos:ContainerName` | yes | — | Owner-partitioned session container | - -Local setup: - -```powershell -dotnet user-secrets --project BlogWriter.Web/BlogWriter.Web.csproj set "AzureAd:TenantId" "" -dotnet user-secrets --project BlogWriter.Web/BlogWriter.Web.csproj set "AzureAd:ClientId" "" -dotnet user-secrets --project BlogWriter.Web/BlogWriter.Web.csproj set "AzureAd:ClientSecret" "" -dotnet user-secrets --project BlogWriter.Web/BlogWriter.Web.csproj set "Foundry:ProjectEndpoint" "https://.services.ai.azure.com/api/projects/" -dotnet user-secrets --project BlogWriter.Web/BlogWriter.Web.csproj set "Cosmos:Endpoint" "https://.documents.azure.com:443/" -dotnet user-secrets --project BlogWriter.Web/BlogWriter.Web.csproj set "Cosmos:DatabaseName" "blogwriter" -dotnet user-secrets --project BlogWriter.Web/BlogWriter.Web.csproj set "Cosmos:ContainerName" "sessions" -``` - -`Authentication:UseTestingIdentity` is accepted only when the host environment is -`Testing`. It exists for automated browser checks and must never be enabled in a -development, staging, or production deployment. - -### Word-count and submission controls - -The web workspace displays `Min`, `Max`, and `Go` between the prompt inputs and the -Draft/Reviewer panes. Min and Max default to 1000 and 2000, accept positive whole -numbers, and require Max to be at least Min. Go is the only control that starts draft -or revision processing; Enter adds text to a prompt without submitting it. When both -inputs have text, Go processes the revision request first. The values are session -state, not configuration keys: loading a saved session restores its range, and a -successful revision persists the updated range. Unsaved range changes participate in -the existing New/List/Quit discard confirmation. - -### Workflow log and Reviewer notes - -The web workspace places an ordered workflow log directly beneath the command buttons. -It contains progress, success, validation, cancellation, conflict, and failure output; -the separate status/validation stack is not used. Reviewer feedback is routed to the -Reviewer notes pane as it becomes available and is retained across revisions for the -active session. New and loading a different saved session clear transient log history -and reviewer history; incremental output is not persisted as a separate record. - -In List mode, the inline three-digit selector uses the displayed one-based position. -Valid selection restores `MainTask`, restores non-empty `CurrentSubTask` as the Revision -request, and starts one initial writing operation. The `?` command displays and copies -the HTTPS launch command. Revision request and Revise are disabled until a -non-whitespace draft is displayed, and remain disabled while processing. Workflow -status is presented as one latest-message line while Reviewer notes remain independently -visible. - -## Keeping prompts in sync - -Each hosted agent's `AgentPrompt.cs` must be kept in sync with the corresponding section -of the console app's `Prompts.cs`. There's no automated check for this today — when -changing one, update the other.