Skip to main content

QRG Workflow

Overview

The QRG workflow supports both generation (creating new QRGs from EOP annexes) and editing (modifying existing QRG sections). Both expose async toolchains: kickoff → status → result.

Generation vs Editing

QRG Generation:

  • Processes entire Emergency Operation Plan (EOP) to generate Quick Reference Guides
  • Fetches annex forms from MOEOP API
  • Uses 4-step AI pipeline per annex: classify → extract → map → generate
  • Tracks processing status per annex with FormStatus for traceability
  • Logs all errors to qrg_execution_errors table
  • Saves QRGs to K12 only for FACILITY organizations (DISTRICT requires skipK12OrgValidation=true or no-save mode)
  • dryRun: true still persists internal request and tracking rows; it only skips K12 platform writes
  • QRG role mapping uses the EOP-selected role set and skips organization-wide role-universe fetches

QRG Editing:

  • Modifies individual QRG sections (BEFORE/DURING/AFTER)
  • Requires quickReferenceGuide metadata object
  • Single AI call to transform content based on prompt
  • Stores result in qrg_edits table

Form Processing & Validation

The QRG generation workflow processes annex forms with these principles:

  1. Permissive Selection: Forms are fetched from MOEOP regardless of content state
  2. Validation at Processing: Empty forms (data: {}) are caught during workflow execution
  3. FormStatus Tracking: Distinguishes between:
    • IN_PROGRESS + empty data → Error (user hasn't started)
    • COMPLETED + empty data → Valid (user accepted defaults)
    • Any status + has content → Process normally

Why this approach?

  • Database traceability: All processed forms appear in qrg_generation_annexes
  • Error debugging: qrg_execution_errors captures exactly which forms failed and why
  • User transparency: Can query "which forms were skipped vs errored"

Error Logging Architecture

Two complementary error tables:

  1. qrg_ai_calls - Individual AI call failures

    • Tracks each LLM invocation
    • Records prompt, response, tokens, duration
    • Status: success/error/timeout
  2. qrg_execution_errors - Workflow-level failures

    • Empty form validation failures
    • MOEOP API errors
    • Workflow step failures
    • Links to specific annex via (RequestId, AnnexId)

Use vw_qrg_error_summary for joined error analysis with request/annex context.

Public tool endpoints (APIM)

  • Base URL (K12 Azure Dev APIM): https://dev-k12-aitools-t27p-apim.azure-api.net
  • Endpoint template: POST /ai/api/tools/{toolId}/execute
  • Payload shape: { "data": { ... } }
  • Required headers (APIM):
    • Authorization: Bearer {access_token}
    • Ocp-Apim-Subscription-Key: {subscription_key}

Note: Examples on this page use APIM subscription keys for quick curl snippets; for tenant-hosted automation and production workflows, prefer OAuth bearer tokens (client credentials) issued by the Azure Entra tenant. - Content-Type: application/json

When calling a local dev server without APIM/auth, auth headers may be omitted.

Payload contract & required fields

  • userId (UUID) — requestor identifier
  • roleId (UUID) — persona performing the edit
  • sectionBEFORE|DURING|AFTER
  • content — current HTML content for the specified section
  • prompt — requested transformation (short, imperative)
  • quickReferenceGuide — metadata object (name, type, instructionFor, organization, tags)

Flow

The QRG editing surface is exposed as three tools to be called in sequence (kickoff → status → result). An optional cancel tool is also available.

1) Kickoff

  • Tool ID: k12-qrg-editing-kickoff
  • Endpoint: POST /ai/api/tools/k12-qrg-editing-kickoff/execute
  • Purpose: Enqueues a QRG editing job, persists the payload, and launches the workflow.

Notes:

  • requestId is server-generated; do not provide it.
  • sessionId is required and can be null to start a new session.

Example (cURL — kickoff):

curl -X POST "$BASE_URL/ai/api/tools/k12-qrg-editing-kickoff/execute" \
-H "Authorization: Bearer $TOKEN" \
-H "Ocp-Apim-Subscription-Key: $SUBSCRIPTION_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": {
"userId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"roleId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"sessionId": null,
"section": "BEFORE",
"content": "<ul><li>Know evacuation routes</li></ul>",
"prompt": "Add a bullet about checking fire extinguisher locations",
"quickReferenceGuide": {
"name": "Fire Safety Procedures",
"type": "FUNCTIONAL",
"instructionFor": "FIRE",
"generalUserTagManagementType": "ASSIGN_SELECTED",
"generalUserTags": []
}
}
}'

Example response (accepted):

{ "status": "accepted", "requestId": "qrg-req-001", "message": "QRG generation started" }

2) Status polling

  • Tool ID: k12-qrg-editing-status
  • Endpoint: POST /ai/api/tools/k12-qrg-editing-status/execute
  • Request shape: { "data": { "requestIds": ["..."] } }

Example (cURL — status poll):

curl -X POST "$BASE_URL/ai/api/tools/k12-qrg-editing-status/execute" \
-H "Authorization: Bearer $TOKEN" \
-H "Ocp-Apim-Subscription-Key: $SUBSCRIPTION_KEY" \
-H "Content-Type: application/json" \
-d '{"data": {"requestIds": ["$REQUEST_ID"]}}'

Example response:

[
{
"requestId": "9fd2055d-42ab-4c29-bf0d-51bd8f7db3ec",
"sessionId": "0e1a5e3f-3a3c-4d1f-bbc6-0e76b1c4a8c7",
"status": "processing"
}
]

3) Result retrieval

  • Tool ID: k12-qrg-editing-result
  • Endpoint: POST /ai/api/tools/k12-qrg-editing-result/execute

Example (cURL — result fetch):

curl -X POST "$BASE_URL/ai/api/tools/k12-qrg-editing-result/execute" \
-H "Authorization: Bearer $TOKEN" \
-H "Ocp-Apim-Subscription-Key: $SUBSCRIPTION_KEY" \
-H "Content-Type: application/json" \
-d '{"data": {"requestId": "$REQUEST_ID"}}'

Example response (success):

{
"requestId": "9fd2055d-42ab-4c29-bf0d-51bd8f7db3ec",
"sessionId": "0e1a5e3f-3a3c-4d1f-bbc6-0e76b1c4a8c7",
"status": "success",
"message": "<p>Edited QRG section content...</p>",
"isEdit": true
}

4) Cancel job (optional)

  • Tool ID: k12-qrg-cancel
  • Endpoint: POST /ai/api/tools/k12-qrg-cancel/execute

Example (cURL — cancel):

curl -X POST "$BASE_URL/ai/api/tools/k12-qrg-cancel/execute" \
-H "Authorization: Bearer $TOKEN" \
-H "Ocp-Apim-Subscription-Key: $SUBSCRIPTION_KEY" \
-H "Content-Type: application/json" \
-d '{"data": {"requestId": "$REQUEST_ID"}}'

Note: For EOP cancellation, use the separate k12-cancel-task-request tool which operates on the EOP task tables.

Kickoff payload example (QRG)

{
"userId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"roleId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"sessionId": null,
"section": "BEFORE",
"content": "<ul><li>Know evacuation routes</li></ul>",
"prompt": "Add a bullet about fire extinguisher locations",
"quickReferenceGuide": {
"name": "Fire Safety Procedures",
"type": "FUNCTIONAL",
"instructionFor": "FIRE"
}
}

Tests

  • QRG tool unit tests: packages/domain-k12/tests/tools/qrg-tools.test.ts
  • E2E tests: tests/e2e/k12/annex-editing.e2e.test.ts
  • Bruno tests: npm run bruno:test:k12

Reference & samples

  • Endpoint docs and sample cURL in docs/reference/workflows/k12/k12-qrg-editing-tool-endpoints.md