Pular para o conteúdo principal

Assessment screens

On an exam, a quiz or a graded activity the agent may explain the screen and navigate, but it must never fill in an answer, select an option or submit. Mark those screens assessment and the relay enforces it:

  • every action except navigate and scroll_list is dropped on the server before it reaches the device — whatever the model proposed;
  • the model is told up front that the screen is an assessment, so it refuses honestly ("Não posso responder avaliações por você") instead of narrating an attempt;
  • if a model tries anyway, the user reads the integrity message, and the blocked action is recorded in agent_actions with status = 'cancelled' and the reason in error.

assessment wins over agentAccess: 'write'. It works the same for web and React Native, and for old SDKs: nothing changes on the client.

Why not .appilotsrc?

permissions in .appilotsrc / AppilotsProvider (canFillForms, blockedScreens, …) is enforced by the SDK, in the user's device. A modified client can switch it off. Use it to scope a build, never for academic integrity. The two options below are enforced by the API.

Option 1 — the API, no code change​

Best when you cannot touch the app. Screen overrides live on the project:

curl -X PATCH https://api.appilots.com/api/v1/projects/$PROJECT_ID/permissions \
-H "Authorization: Bearer $DASHBOARD_TOKEN" \
-H "X-Workspace-Id: $WORKSPACE_ID" \
-H "Content-Type: application/json" \
-d '{ "screenOverrides": {
"/cursos/*/prova/*": { "assessment": true },
"*Quiz*": { "assessment": true }
} }'

A key is a screen name, or a pattern when it contains * or starts with /:

KeyMatches
QuizAttemptexactly that screen
*Quiz*any screen whose name contains "quiz"
/cursos/*/prova/*the navigation path — /cursos/12/prova/9

Patterns are case-insensitive, * matches anything (including /), and -/_ are ignored, so /atividade-avaliativa/* matches the web SDK's AtividadeAvaliativa. An exact key beats a pattern field by field, so { "QuizReview": { "assessment": false } } reopens one screen a pattern closed.

Web without declared routes reports only the last URL segment as the screen (/cursos/12/prova/9 → 9), so address assessments by path there. React Native reports route names, so a name or a name pattern is enough.

Send { "screenOverrides": { "<key>": null } } to remove an entry. Changes apply within 5 minutes (cache), immediately on the instance that served the PATCH.

Option 2 — declare it with the app​

The app's map is uploaded by the CLI and read by the server, so this is also enforced server-side.

Web — in appilots.manifest.json:

{
"name": "ReadingQuiz",
"title": "Quiz de leitura",
"permissions": { "assessment": true }
}

React Native — on the screen component:

/**
* @appilots-permissions {"assessment": true}
*/
export function QuizScreen() { … }

Then appilots sync. A project override (Option 1) wins over the document, so { "assessment": false } there reopens a screen the app declared.

What the agent still does​

RequestOn an assessment
"What does this screen do?"explains it
"Take me back to the course"navigates
"Answer question 2" / "select B" / "submit"refuses; nothing is written

Pressing any control (including "next question") is blocked too, because the server cannot tell an answer from a pager. Navigate by screen instead.

Verifying​

Assert state, never the assistant's reply: the answer field is empty, no option is checked, the attempt is not submitted — and in agent_actions the session has no pending write. The repository's own proof: tests/api/integration/assessment-screens.test.ts and tests/web/agent-e2e/specs/assessment.spec.ts, both driving the real relay with a model that always tries to answer.