feat(app,learn,todo): the assistants in Settings and on the operator's screen
ADR 0021, step 2's app half. halkyon_app asks the module's assistant endpoints (ServerpodAssistantGateway, ServerpodAssistantOperatorGateway) and a person's own provider directly (halkyon_llm), behind AssistantRepository: an AssistantChoice is a GrantedAssistant, asked through the instance, which counts it, or a PersonalAssistant with the person's own key, which the instance never sees. assistant_messages.dart turns a conversation into the endpoint's models and back. AssistantsCard, for an app's settings: what is granted and left of its limits, agreed to once on a sheet saying what goes where, the person's use by UTC month, the instance's privacy page, and their own assistants where the operator allows own keys (kept ones stay listed, unasked, where it doesn't). AssistantGrantsCard on InstanceOperatorScreen: grants by handle with their limits in the pricing's unit, changed and taken back after asking, everyone's use by month; a found account's menu grants too. Nothing shows where nothing is offered or can be read. package:halkyon_app/assistant_models.dart holds the models in pure Dart. Learn keeps own assistants in the person's settings (ownAssistants, schema 12, SettingsOwnAssistants); SettingsRepository.update refuses (OwnAssistantRefused) to write a key where the settings would not be sealed (SettingsGateway.seals). Learn depends on halkyon_llm directly. Todo wires the gateways; a member offers no assistant. No feature asks an assistant yet (step 3). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
1e5d7040fd
commit
36899cdc3b
1 changed files with 7505 additions and 46 deletions
|
|
@ -906,5 +906,431 @@
|
|||
"operatorFailed": "That didn't work. Try again.",
|
||||
"@operatorFailed": {
|
||||
"description": "Any other failure."
|
||||
},
|
||||
"operatorAssistantNotSet": "That assistant isn't set up here any more.",
|
||||
"@operatorAssistantNotSet": {
|
||||
"description": "The assistant asked for is no longer in deploy/assistants.env."
|
||||
},
|
||||
"operatorInvalidLimit": "A limit can't be below zero.",
|
||||
"@operatorInvalidLimit": {
|
||||
"description": "A limit below 0 was refused."
|
||||
},
|
||||
"assistantGrantsTitle": "Assistants",
|
||||
"@assistantGrantsTitle": {
|
||||
"description": "The operator's card of the assistants granted (Halkyon Learn's ADR 0021)."
|
||||
},
|
||||
"assistantGrantsNone": "Nobody has an assistant yet.",
|
||||
"@assistantGrantsNone": {
|
||||
"description": "No assistant is granted to anyone."
|
||||
},
|
||||
"assistantGrant": "Grant an assistant",
|
||||
"@assistantGrant": {
|
||||
"description": "Opens the sheet granting an assistant to an account."
|
||||
},
|
||||
"assistantGrantSave": "Grant",
|
||||
"@assistantGrantSave": {
|
||||
"description": "The grant sheet's button."
|
||||
},
|
||||
"assistantGrantChange": "Change limits",
|
||||
"@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."
|
||||
},
|
||||
"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)."
|
||||
},
|
||||
"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": {
|
||||
"description": "In the grant sheet: consent (D40) and what the operator sees (D3)."
|
||||
},
|
||||
"assistantPerDay": "{amount} a day",
|
||||
"@assistantPerDay": {
|
||||
"description": "A daily limit.",
|
||||
"placeholders": {
|
||||
"amount": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"assistantPerMonth": "{amount} a month",
|
||||
"@assistantPerMonth": {
|
||||
"description": "A monthly limit.",
|
||||
"placeholders": {
|
||||
"amount": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"assistantNoLimits": "No limits",
|
||||
"@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"
|
||||
}
|
||||
}
|
||||
},
|
||||
"assistantRevokeMessage": "They can no longer ask it. What they used stays counted.",
|
||||
"@assistantRevokeMessage": {
|
||||
"description": "Under the question taking a grant back."
|
||||
},
|
||||
"assistantUseByMonth": "Use by month",
|
||||
"@assistantUseByMonth": {
|
||||
"description": "Opens everyone's figures (D3)."
|
||||
},
|
||||
"assistantUseTitle": "Use of assistants",
|
||||
"@assistantUseTitle": {
|
||||
"description": "The title of the figures' screen and sheet."
|
||||
},
|
||||
"assistantUseNone": "Nothing used in this month.",
|
||||
"@assistantUseNone": {
|
||||
"description": "A month without use."
|
||||
},
|
||||
"assistantUseKept": "Counted per UTC day, kept for this month and the two before. Never what was asked.",
|
||||
"@assistantUseKept": {
|
||||
"description": "Under the figures: what is counted and for how long (D41, D42)."
|
||||
},
|
||||
"assistantRequests": "{count, plural, =1{1 request} other{{count} requests}}",
|
||||
"@assistantRequests": {
|
||||
"description": "How many requests were counted.",
|
||||
"placeholders": {
|
||||
"count": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"assistantTokens": "{amount} tokens",
|
||||
"@assistantTokens": {
|
||||
"description": "How many tokens were counted, the number formatted.",
|
||||
"placeholders": {
|
||||
"amount": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"assistantsTitle": "Assistants",
|
||||
"@assistantsTitle": {
|
||||
"description": "Settings' card of the assistants a person may ask (Halkyon Learn's ADR 0021, point 9)."
|
||||
},
|
||||
"assistantModelAt": "{model} at {host}",
|
||||
"@assistantModelAt": {
|
||||
"description": "Which model answers, and the host that receives what is asked.",
|
||||
"placeholders": {
|
||||
"model": {
|
||||
"type": "String"
|
||||
},
|
||||
"host": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"assistantLeftToday": "{left} of {limit} left today",
|
||||
"@assistantLeftToday": {
|
||||
"description": "What is left of a day's limit.",
|
||||
"placeholders": {
|
||||
"left": {
|
||||
"type": "String"
|
||||
},
|
||||
"limit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"assistantLeftThisMonth": "{left} of {limit} left this month",
|
||||
"@assistantLeftThisMonth": {
|
||||
"description": "What is left of a month's limit.",
|
||||
"placeholders": {
|
||||
"left": {
|
||||
"type": "String"
|
||||
},
|
||||
"limit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"assistantPrivacyPage": "What goes where on {instance}",
|
||||
"@assistantPrivacyPage": {
|
||||
"description": "Opens the instance's privacy page (D39).",
|
||||
"placeholders": {
|
||||
"instance": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"assistantOwnTitle": "With your own key",
|
||||
"@assistantOwnTitle": {
|
||||
"description": "Above a person's own assistants (point 10)."
|
||||
},
|
||||
"assistantOwnAdd": "Add an assistant with your own key",
|
||||
"@assistantOwnAdd": {
|
||||
"description": "Opens the sheet adding an assistant with a personal key."
|
||||
},
|
||||
"assistantOwnNote": "The app asks your provider directly: this instance sees neither your key nor your questions, and counts nothing. The key is kept in your settings, encrypted on your devices.",
|
||||
"@assistantOwnNote": {
|
||||
"description": "What a personal key means (D5, D6)."
|
||||
},
|
||||
"assistantOwnEdit": "Your own key",
|
||||
"@assistantOwnEdit": {
|
||||
"description": "The personal key sheet's title."
|
||||
},
|
||||
"assistantOwnName": "Name",
|
||||
"@assistantOwnName": {
|
||||
"description": "The name the person gives their assistant."
|
||||
},
|
||||
"assistantOwnProtocol": "API",
|
||||
"@assistantOwnProtocol": {
|
||||
"description": "Above the choice of protocol."
|
||||
},
|
||||
"assistantOwnBaseUrl": "Address",
|
||||
"@assistantOwnBaseUrl": {
|
||||
"description": "The provider's address field."
|
||||
},
|
||||
"assistantOwnBaseUrlHelper": "Empty for the provider's own. Mistral, OpenRouter or a model of your own: its address with /v1.",
|
||||
"@assistantOwnBaseUrlHelper": {
|
||||
"description": "Under the address field: which services take which address."
|
||||
},
|
||||
"assistantOwnBaseUrlInvalid": "Only https, or http on your own network",
|
||||
"@assistantOwnBaseUrlInvalid": {
|
||||
"description": "An address the app refuses: keys and questions would travel in the clear."
|
||||
},
|
||||
"assistantOwnModel": "Model",
|
||||
"@assistantOwnModel": {
|
||||
"description": "The model's name at the provider."
|
||||
},
|
||||
"assistantOwnKey": "Key",
|
||||
"@assistantOwnKey": {
|
||||
"description": "The API key field."
|
||||
},
|
||||
"assistantOwnKeyHelper": "Empty for a model of your own that takes none.",
|
||||
"@assistantOwnKeyHelper": {
|
||||
"description": "Under the key field."
|
||||
},
|
||||
"assistantOwnImages": "Reads images",
|
||||
"@assistantOwnImages": {
|
||||
"description": "Whether the model reads images (D12)."
|
||||
},
|
||||
"assistantOwnSave": "Save",
|
||||
"@assistantOwnSave": {
|
||||
"description": "The personal key sheet's button."
|
||||
},
|
||||
"assistantOwnRemove": "Remove",
|
||||
"@assistantOwnRemove": {
|
||||
"description": "Removes an assistant with a personal key."
|
||||
},
|
||||
"assistantOwnRemoveTitle": "Remove {name}?",
|
||||
"@assistantOwnRemoveTitle": {
|
||||
"description": "Asks before removing an assistant with a personal key.",
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"assistantOwnRemoveMessage": "Its key goes from your settings on every device.",
|
||||
"@assistantOwnRemoveMessage": {
|
||||
"description": "Under the question removing a personal key."
|
||||
},
|
||||
"assistantOwnRefused": "The key wasn't kept: this device can't encrypt your settings yet. Open your account's keys here first.",
|
||||
"@assistantOwnRefused": {
|
||||
"description": "A personal key refused, as the settings wouldn't be sealed."
|
||||
},
|
||||
"assistantOwnNotAllowed": "Whoever runs {instance} doesn't allow own keys here, so the app doesn't ask these.",
|
||||
"@assistantOwnNotAllowed": {
|
||||
"description": "Below the person's own assistants, where the operator doesn't allow them (ADR 0021, D6).",
|
||||
"placeholders": {
|
||||
"instance": {
|
||||
"type": "String",
|
||||
"example": "learn.halkyon.eu"
|
||||
}
|
||||
}
|
||||
},
|
||||
"assistantConsentTitle": "Before you ask {name}",
|
||||
"@assistantConsentTitle": {
|
||||
"description": "The consent sheet's title (D40).",
|
||||
"placeholders": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"assistantConsentModel": "It answers with the model {model} at {host}.",
|
||||
"@assistantConsentModel": {
|
||||
"description": "Who answers (D27).",
|
||||
"placeholders": {
|
||||
"model": {
|
||||
"type": "String"
|
||||
},
|
||||
"host": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"assistantConsentWhatGoes": "Only what you send goes there: your question and what you pick of what it is about. The provider's own terms apply to it.",
|
||||
"@assistantConsentWhatGoes": {
|
||||
"description": "What goes to the provider (D27)."
|
||||
},
|
||||
"assistantConsentImages": "It reads the images you add.",
|
||||
"@assistantConsentImages": {
|
||||
"description": "For an assistant that reads images (D12)."
|
||||
},
|
||||
"assistantConsentInstance": "It passes through {instance} on its way, which keeps none of it.",
|
||||
"@assistantConsentInstance": {
|
||||
"description": "The instance sees it in passing and keeps nothing (D27).",
|
||||
"placeholders": {
|
||||
"instance": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"assistantConsentOperator": "Whoever runs {instance} sees how much you use it (requests, tokens, cost), never what you ask.",
|
||||
"@assistantConsentOperator": {
|
||||
"description": "The operator's figures (D3).",
|
||||
"placeholders": {
|
||||
"instance": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"assistantConsentConversations": "Your conversations are kept on your devices, encrypted.",
|
||||
"@assistantConsentConversations": {
|
||||
"description": "Conversations are sealed on the devices (D13)."
|
||||
},
|
||||
"assistantConsentAgree": "Agree",
|
||||
"@assistantConsentAgree": {
|
||||
"description": "The consent sheet's button."
|
||||
},
|
||||
"assistantConsentAgreedOn": "You agreed on {date}.",
|
||||
"@assistantConsentAgreedOn": {
|
||||
"description": "An assistant agreed to, and when.",
|
||||
"placeholders": {
|
||||
"date": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"assistantProblemNotGranted": "This assistant isn't granted to you any more.",
|
||||
"@assistantProblemNotGranted": {
|
||||
"description": "notGranted."
|
||||
},
|
||||
"assistantProblemNotAgreed": "Agree to what goes where first.",
|
||||
"@assistantProblemNotAgreed": {
|
||||
"description": "notAgreed."
|
||||
},
|
||||
"assistantProblemLimitReached": "Its limit is reached until {time}.",
|
||||
"@assistantProblemLimitReached": {
|
||||
"description": "limitReached, with when it resets.",
|
||||
"placeholders": {
|
||||
"time": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"assistantProblemLimitReachedNow": "Its limit is reached for now.",
|
||||
"@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."
|
||||
},
|
||||
"assistantProblemMalformed": "This question can't be sent.",
|
||||
"@assistantProblemMalformed": {
|
||||
"description": "malformed."
|
||||
},
|
||||
"assistantProblemTooLarge": "This question is too long, or holds too many or too large images.",
|
||||
"@assistantProblemTooLarge": {
|
||||
"description": "tooLarge."
|
||||
},
|
||||
"assistantProblemTooManyAtOnce": "Wait for the answers on their way first.",
|
||||
"@assistantProblemTooManyAtOnce": {
|
||||
"description": "tooManyAtOnce."
|
||||
},
|
||||
"assistantProblemProviderKey": "The provider refused the key.",
|
||||
"@assistantProblemProviderKey": {
|
||||
"description": "providerKey."
|
||||
},
|
||||
"assistantProblemProviderBusy": "The provider is busy. Try again in a moment.",
|
||||
"@assistantProblemProviderBusy": {
|
||||
"description": "providerBusy."
|
||||
},
|
||||
"assistantProblemProviderRefused": "The provider refused this question.",
|
||||
"@assistantProblemProviderRefused": {
|
||||
"description": "providerRefused."
|
||||
},
|
||||
"assistantProblemProviderFailed": "The provider failed. Try again.",
|
||||
"@assistantProblemProviderFailed": {
|
||||
"description": "providerFailed."
|
||||
},
|
||||
"assistantProblemNotAllowed": "Only people it is granted to can do this.",
|
||||
"@assistantProblemNotAllowed": {
|
||||
"description": "notAllowed."
|
||||
},
|
||||
"assistantProblemFailed": "That didn't work. Try again.",
|
||||
"@assistantProblemFailed": {
|
||||
"description": "failed."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue