feat(app): the operator's overview of screens, grants to several people at once with one budget each, assistants by provider

Halkyon Learn's ADR 0021, D57 to D63, on halkyon_base's budgets and
effort:

- The operator's screen is an overview (Waiting, Operators, Accounts,
  Assistants, each with its count) whose rows open screens of their own,
  read 50 at a time as they scroll (OperatorListCubit, OperatorPage), so
  hundreds of accounts push nothing else down (D62).
- A handle is picked among the accounts there are (AccountSuggestionField):
  appointing an operator and granting take no other (D61).
- AssistantGrantsScreen replaces AssistantGrantsCard: the assistants set
  up by provider, with their efforts and prices; the people granted, found
  by their handle's start; one sheet granting several assistants, a
  provider's at once, to several people, each with one budget in money and
  tokens a day and a month, or changing one person's (D58, D59).
- Assistants are grouped by provider wherever they are listed, each under
  its name with a dot in its colour (ProviderLabel, D60).
- AssistantsCard shows what is left of the person's budget for all their
  assistants together; the months of the figures run oldest first (D57).
- AssistantChoice says the efforts a question may ask at and the ceiling
  on output each asks for (D63); a person's own key gets none and keeps
  4,096 tokens.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-26 16:05:49 +01:00
commit cc87120bc8
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -764,6 +764,28 @@
"@operatorWaitingTitle": {
"description": "The card of accounts that wait for approval, new or suspended."
},
"operatorOperatorsCount": "{count, plural, =1{1 operator} other{{count} operators}}",
"@operatorOperatorsCount": {
"description": "How many operate the instance, in the overview's row.",
"placeholders": {
"count": {
"type": "int"
}
}
},
"operatorAccountsTitle": "Accounts",
"@operatorAccountsTitle": {
"description": "The overview's row leading to every account, and that screen's title."
},
"operatorAccountsCount": "{count, plural, =1{1 account} other{{count} accounts}}",
"@operatorAccountsCount": {
"description": "How many accounts the instance has.",
"placeholders": {
"count": {
"type": "int"
}
}
},
"operatorNobodyWaits": "Nobody waits.",
"@operatorNobodyWaits": {
"description": "The waiting card, empty."
@ -842,9 +864,9 @@
"@operatorHandle": {
"description": "The field for an account's handle."
},
"operatorFindTitle": "Find an account",
"@operatorFindTitle": {
"description": "The card searching accounts by the start of their handle."
"operatorHandleSuggested": "Only handles there are here are suggested.",
"@operatorHandleSuggested": {
"description": "Below a field suggesting handles as they are typed."
},
"operatorFoundNone": "No account's handle starts like this.",
"@operatorFoundNone": {
@ -923,7 +945,98 @@
"@assistantGrantsNone": {
"description": "No assistant is granted to anyone."
},
"assistantGrant": "Grant an assistant",
"assistantSetCount": "{count, plural, =0{None set up} =1{1 assistant} other{{count} assistants}}",
"@assistantSetCount": {
"description": "How many assistants are set up, in the overview's row.",
"placeholders": {
"count": {
"type": "int"
}
}
},
"assistantPeopleCount": "{count, plural, =0{nobody granted} =1{1 person} other{{count} people}}",
"@assistantPeopleCount": {
"description": "How many people have an assistant, after how many are set up.",
"placeholders": {
"count": {
"type": "int"
}
}
},
"assistantSetUpTitle": "Set up here",
"@assistantSetUpTitle": {
"description": "The card of the assistants set up in deploy/assistants.env."
},
"assistantPeopleTitle": "People",
"@assistantPeopleTitle": {
"description": "The card, and the sheet section, of the people granted assistants."
},
"assistantGranteesFoundNone": "Nobody with an assistant has a handle starting like this.",
"@assistantGranteesFoundNone": {
"description": "No person granted one matches the start of a handle typed."
},
"assistantUnpriced": "No prices: counts its tokens only",
"@assistantUnpriced": {
"description": "An assistant set up without prices, which a budget counts in tokens alone."
},
"assistantEffort": "{effort, select, low{low} medium{medium} high{high} xhigh{extra high} max{max} other{{effort}}}",
"@assistantEffort": {
"description": "How much a model thinks before it answers, as a word in a sentence.",
"placeholders": {
"effort": {
"type": "String"
}
}
},
"assistantEffortName": "{effort, select, low{Low} medium{Medium} high{High} xhigh{Extra high} max{Max} other{{effort}}}",
"@assistantEffortName": {
"description": "How much a model thinks before it answers, as a name standing alone, as in a menu.",
"placeholders": {
"effort": {
"type": "String"
}
}
},
"assistantEffortSetUp": "Effort {effort}, up to {max}",
"@assistantEffortSetUp": {
"description": "An assistant's effort unless asked otherwise, and the highest a question may ask.",
"placeholders": {
"effort": {
"type": "String"
},
"max": {
"type": "String"
}
}
},
"assistantEffortFixed": "Effort {effort}",
"@assistantEffortFixed": {
"description": "An assistant's effort, the only one it takes.",
"placeholders": {
"effort": {
"type": "String"
}
}
},
"assistantNameUnset": "{name} (no longer set up)",
"@assistantNameUnset": {
"description": "An assistant granted that is no longer set up.",
"placeholders": {
"name": {
"type": "String"
}
}
},
"assistantNotAgreedCount": "{count, plural, =1{1 not agreed to yet} other{{count} not agreed to yet}}",
"@assistantNotAgreedCount": {
"description": "How many of a person's assistants they haven't agreed to yet.",
"placeholders": {
"count": {
"type": "int"
}
}
},
"assistantGrant": "Grant assistants",
"@assistantGrant": {
"description": "Opens the sheet granting an assistant to an account."
},
@ -931,39 +1044,65 @@
"@assistantGrantSave": {
"description": "The grant sheet's button."
},
"assistantGrantChange": "Change limits",
"assistantGrantChange": "Change assistants",
"@assistantGrantChange": {
"description": "A grant's menu item, and the sheet's title, changing its limits."
},
"assistantGrantAssistant": "Assistant",
"@assistantGrantAssistant": {
"description": "Above the choice of assistant in the grant sheet."
},
"assistantGrantDaily": "Limit a day",
"@assistantGrantDaily": {
"description": "The daily limit field."
},
"assistantGrantMonthly": "Limit a month",
"@assistantGrantMonthly": {
"description": "The monthly limit field."
"description": "The sheet changing a person's assistants and budget, and a person's menu item."
},
"assistantGrantLimitHelper": "Empty for none. Days and months are UTC's.",
"@assistantGrantLimitHelper": {
"description": "Under the limit fields: the instance counts by UTC days and months (D42)."
},
"assistantGrantBudget": "Budget, for all of them together",
"@assistantGrantBudget": {
"description": "The sheet's section of a person's budget."
},
"assistantGrantMoneyDaily": "Money a day",
"@assistantGrantMoneyDaily": {
"description": "A budget field."
},
"assistantGrantMoneyMonthly": "Money a month",
"@assistantGrantMoneyMonthly": {
"description": "A budget field."
},
"assistantGrantTokensDaily": "Tokens a day",
"@assistantGrantTokensDaily": {
"description": "A budget field."
},
"assistantGrantTokensMonthly": "Tokens a month",
"@assistantGrantTokensMonthly": {
"description": "A budget field."
},
"assistantGrantMoneyNote": "Money counts the assistants with prices, tokens count every one. Whichever runs out first stops them.",
"@assistantGrantMoneyNote": {
"description": "Below the budget fields."
},
"assistantGrantReplaces": "{count, plural, =1{Granting replaces the budget this person has:} other{Granting replaces the budgets these people have:}}",
"@assistantGrantReplaces": {
"description": "Before the people whose budget a grant replaces, each with theirs.",
"placeholders": {
"count": {
"type": "int"
}
}
},
"assistantGrantUnsetDropped": "Saving takes back what is no longer set up: {names}.",
"@assistantGrantUnsetDropped": {
"description": "Changing a person's assistants drops those no longer set up.",
"placeholders": {
"names": {
"type": "String"
}
}
},
"assistantGrantLimitInvalid": "Not a number this takes",
"@assistantGrantLimitInvalid": {
"description": "A limit typed that is no amount or number of tokens."
},
"assistantGrantNoHandle": "No account has this handle.",
"@assistantGrantNoHandle": {
"description": "The grant sheet: the handle typed is nobody's."
},
"assistantGrantTokens": "tokens",
"@assistantGrantTokens": {
"description": "After a limit in tokens, for an assistant without prices."
},
"assistantGrantNote": "They agree once to what goes where before they ask it. You see how much they use, never what they ask.",
"assistantGrantNote": "They agree once to what goes where before they ask one. Assistants they have already stay. You see how much they use, never what they ask.",
"@assistantGrantNote": {
"description": "In the grant sheet: consent (D40) and what the operator sees (D3)."
},
@ -989,36 +1128,15 @@
"@assistantNoLimits": {
"description": "A grant without limits."
},
"assistantGrantAgreed": "Agreed",
"@assistantGrantAgreed": {
"description": "A grant whose person agreed to what goes where."
},
"assistantGrantNotAgreed": "Not agreed yet",
"@assistantGrantNotAgreed": {
"description": "A grant whose person hasn't agreed yet."
},
"assistantGrantOutdated": "Its prices changed: set its limits again",
"@assistantGrantOutdated": {
"description": "A grant whose limits are in another unit than the pricing now; it answers nothing until set again."
},
"assistantGrantUnset": "No longer set up",
"@assistantGrantUnset": {
"description": "A grant of an assistant taken out of deploy/assistants.env."
},
"assistantRevoke": "Take back",
"@assistantRevoke": {
"description": "A grant's menu item."
},
"assistantRevokeTitle": "Take back {assistant}?",
"@assistantRevokeTitle": {
"description": "Asks before taking a grant back.",
"placeholders": {
"assistant": {
"type": "String"
}
}
"assistantRevokeAllTitle": "Take back every assistant?",
"@assistantRevokeAllTitle": {
"description": "Asks before taking every assistant back from a person."
},
"assistantRevokeMessage": "They can no longer ask it. What they used stays counted.",
"assistantRevokeMessage": "They can no longer ask any of them, and their budget goes. What they used stays counted.",
"@assistantRevokeMessage": {
"description": "Under the question taking a grant back."
},
@ -1096,14 +1214,14 @@
}
}
},
"assistantYourBudget": "Your budget, for all of them",
"@assistantYourBudget": {
"description": "The person's budget for all their assistants."
},
"assistantAgree": "Read and agree",
"@assistantAgree": {
"description": "Opens the consent sheet of an assistant not agreed to yet."
},
"assistantWaitsForLimits": "Waits for its limits to be set again",
"@assistantWaitsForLimits": {
"description": "An assistant whose limits are outdated: it answers nothing until the operator sets them again."
},
"assistantYourUse": "Your use",
"@assistantYourUse": {
"description": "Opens the person's own figures."
@ -1276,6 +1394,10 @@
"@assistantProblemNotAgreed": {
"description": "notAgreed."
},
"assistantProblemInvalidEffort": "It doesn't think at this effort.",
"@assistantProblemInvalidEffort": {
"description": "A question asked an effort its assistant does not take."
},
"assistantProblemLimitReached": "Its limit is reached until {time}.",
"@assistantProblemLimitReached": {
"description": "limitReached, with when it resets.",
@ -1289,10 +1411,6 @@
"@assistantProblemLimitReachedNow": {
"description": "Refused: a limit is reached, the instance not saying until when."
},
"assistantProblemLimitOutdated": "It waits for its limits to be set again.",
"@assistantProblemLimitOutdated": {
"description": "limitOutdated."
},
"assistantProblemImagesNotRead": "It reads no images.",
"@assistantProblemImagesNotRead": {
"description": "imagesNotRead."