An educational local C# project showing how a small agent workflow can stay trustworthy by combining trusted-vs-untrusted content labeling, deterministic tool authorization, approval-gated sensitive actions, and redacted audit storage.
This version uses a support operations scenario with customer messages, internal notes, a two-agent planning-review flow, deterministic least-privilege tool access, and file-backed redacted audit records.
This repository demonstrates a practical trusted-agent control flow:
- Load runtime configuration for local model mode, endpoint, timeout, data directory, approval TTL, and refund limits.
- Accept a support case made of trusted and untrusted content blocks.
- Classify each block for trust level, prompt-injection cues, and sensitive-data risk before planning.
- Redact emails, keys, long identifiers, and phone-like values before audit or memory-style persistence.
- Ask
PlanningAgentto return a structured JSON action proposal. - Ask
ReviewAgentto narrow or remove weak, unnecessary, or exfiltration-style actions. - Reinsert required bounded actions deterministically so critical workflow steps cannot disappear due to model drift.
- Evaluate every proposed tool call against internal scopes, operator role, refund threshold, and approval-token rules.
- Execute only allowed tools from a narrow internal registry and persist a redacted audit record of the full outcome.
The result is a real trusted-agent control plane without pretending that untrusted content or free-form model output should directly drive privileged actions.
- Trusted-vs-untrusted content labeling before model planning
- Prompt-injection cue detection for customer and external content
- PII and secret redaction before audit persistence
- Sequential
PlanningAgentandReviewAgentroles over a shared structured JSON contract - Deterministic required-action synthesis so live models cannot silently drop bounded workflow steps
- Least-privilege role scopes for tool access such as
ReadCustomerProfile,ResetMfa, andIssueRefund - Approval-token gating for MFA reset and high-value refund execution
- File-backed redacted audit history for replay and inspection
- .NET 10 SDK or later
- Optional for live model mode:
- Ollama or another OpenAI-compatible local endpoint
- a local chat model available at that endpoint
The checked-in runtime currently defaults to live local model mode against http://localhost:11434/v1. If you want deterministic offline behavior, set UseMockModel to true in TrustedAgentOperations/appsettings.json.
From the project root:
dotnet run --project TrustedAgentOperationsWhen RunInteractiveConsole is false, the app auto-runs the built-in demo scenarios and prints an audit snapshot. When RunInteractiveConsole is true, the console menu is:
1Run customer prompt-injection case as analyst2Run verified MFA reset case as supervisor3Run refund case as finance4Browse audit records0Exit
The app prints the content assessments, reviewed proposal, policy outcomes, tool outputs, final customer reply, and recent audit records.
Default settings are in TrustedAgentOperations/appsettings.json under App.
Example:
{
"App": {
"UseMockModel": false,
"BaseUrl": "http://localhost:11434/v1",
"ApiKey": "ollama",
"ModelId": "gpt-oss:20b",
"ModelTimeoutSeconds": 45,
"DataDirectory": "data/trusted-agent-operations",
"ApprovalTokenMinutes": 15,
"AutonomousRefundLimitUsd": 100.0,
"RunInteractiveConsole": false
}
}Environment variable overrides use prefix TRUSTOPS_:
TRUSTOPS_App__UseMockModelTRUSTOPS_App__BaseUrlTRUSTOPS_App__ApiKeyTRUSTOPS_App__ModelIdTRUSTOPS_App__ModelTimeoutSecondsTRUSTOPS_App__DataDirectoryTRUSTOPS_App__ApprovalTokenMinutesTRUSTOPS_App__AutonomousRefundLimitUsdTRUSTOPS_App__RunInteractiveConsole
Program.csloads config, chooses mock or live planning mode, constructs the policies, services, and stores, then runs the demo cases or opens the interactive console loop.ContentTrustPolicyclassifies each case block as trusted or untrusted, flags prompt-injection cues, and produces sanitized content for downstream planning.SensitiveDataSanitizerredacts emails, keys, long numbers, and phone-like values before anything is written to audit storage.MockPlanningModelClientorOpenAiCompatiblePlanningModelClientruns a two-stagePlanningAgentthenReviewAgentflow and returns a structuredAgentActionProposal.RequiredActionPolicydeterministically restores bounded workflow steps such as policy lookup, profile read, reply drafting, and case-specific candidate actions.ProposalNormalizationPolicycleans and stabilizes text and arguments so downstream policy logic works against a predictable proposal shape.ToolAuthorizationPolicymaps tool calls to deterministic internal scopes, enforces operator-role permissions, and applies approval-token requirements for MFA reset and refund execution.ToolRegistryexecutes only allowlisted internal tools such asKnowledgeBase.Search,CustomerProfile.Read,AccountAccess.ResetMfa, andBilling.IssueRefund.FinalReplyPolicyregenerates the customer-facing reply from actual execution outcomes instead of trusting model draft text, andJsonAuditStorepersists the redacted audit record for later inspection.
.
+-- TrustedAgentOperations.slnx
+-- TrustedAgentOperations/
| +-- TrustedAgentOperations.csproj
| +-- Program.cs
| +-- appsettings.json
| +-- App/
| | +-- AppConfig.cs
| +-- Domain/
| | +-- AgentActionProposal.cs
| | +-- ApprovalToken.cs
| | +-- AuditRecord.cs
| | +-- CaseContentBlock.cs
| | +-- CaseFile.cs
| | +-- ContentRiskAssessment.cs
| | +-- ExecutionEnums.cs
| | +-- ExecutionRecord.cs
| | +-- ProcessingResult.cs
| +-- Guardrails/
| | +-- ContentTrustPolicy.cs
| | +-- SensitiveDataSanitizer.cs
| +-- Llm/
| | +-- IPlanningModelClient.cs
| | +-- MockPlanningModelClient.cs
| | +-- OpenAiCompatiblePlanningModelClient.cs
| +-- Persistence/
| | +-- JsonAuditStore.cs
| +-- Services/
| +-- ApprovalTokenService.cs
| +-- CaseFactory.cs
| +-- CustomerProfileStore.cs
| +-- FinalReplyPolicy.cs
| +-- ProposalNormalizationPolicy.cs
| +-- RequiredActionPolicy.cs
| +-- ToolAuthorizationPolicy.cs
| +-- ToolRegistry.cs
| +-- TrustedAgentOperationsEngine.cs
+-- TrustedAgentOperations.Tests/
| +-- TrustedAgentOperations.Tests.csproj
| +-- ContentTrustPolicyTests.cs
| +-- FinalReplyPolicyTests.cs
| +-- ProposalNormalizationPolicyTests.cs
| +-- RequiredActionPolicyTests.cs
| +-- SensitiveDataSanitizerTests.cs
| +-- ToolAuthorizationPolicyTests.cs
| +-- ToolRegistryTests.cs
| +-- TrustedAgentOperationsEngineTests.cs
+-- LICENSE
+-- README.md
- Untrusted content is treated as data, not authority
- Tool permissions come from deterministic code, not model output
- The planning and review agents can propose actions, but execution semantics come from internal scope and approval policy
- Required bounded workflow steps are deterministically restored even if a live model omits them
- Unsupported or exfiltration-style tools are blocked even if proposed by the model
- Customer-facing replies are derived from actual execution outcomes, not trusted from draft model text
- Audit records are persisted only after redaction
Run the test project from the repo root:
dotnet test TrustedAgentOperations.slnxThe current test suite covers:
- prompt-injection cue detection and trust labeling
- PII and secret redaction
- deterministic restoration of required actions
- normalization of malformed or noisy proposal text
- approval requirements for privileged tools
- redacted audit persistence and blocked exfiltration attempts
See the LICENSE file for details.
Contributions are welcome for improvements within current project scope.
Suggested areas:
- Add richer approval workflows such as multi-step supervisor or finance sign-off
- Expand tool authorization with argument-level policy checks and stronger validation
- Persist richer audit metadata such as prompt versions, latency, and execution timing
- Add more scenario coverage for malformed model JSON, token expiry, and mixed-trust edge cases
- Extend the demo with additional support actions while keeping the least-privilege boundary explicit