Summary
Expose two groups of StudyOS_Agent capabilities as assistant tools:
- Public campus tools: Mensa menus and Tübingen campus/location search.
- Private study tools: combined ILIAS/Moodle tasks and deadlines, the ALMA study planner, and richer term-aware academic status.
This issue is the first concrete implementation consumer of the shared data/action capability contract in #54. Public tools may be used by local and cloud providers. Authenticated university data must be fetched on-device and remain local-only by default.
Motivation
Latest main has one shared StudyOsToolSpec catalog and executor for cloud and local providers, but several live app capabilities are UI-only and core study workflows from tue-api-wrapper are still missing:
CampusClient already loads Tübingen Mensa menus.
MapSearchClient already searches bounded Tübingen locations.
tue-api-wrapper has tested contracts for ILIAS tasks/assignment deadlines, Moodle calendar events, the ALMA study planner, and enrollment/exam status.
Adding these through one capability architecture gives the assistant useful, grounded data without routing student credentials through hosted infrastructure.
Dependencies and overlap
Slice 1: public campus tools
get_mensa_options
Inputs:
date (optional ISO date)
canteen (optional ID or name filter)
preference (optional: any, vegetarian, vegan)
limit (optional, bounded)
Output:
- stable canteen/menu IDs where available
- canteen name, date, line, meal items, dietary markers, and student price
- source URL and freshness metadata
- explicit empty/unavailable/upstream-error states
Behavior:
- reuse
CampusClient and shared model-level filtering/sorting
- bound results before returning data to the model
- use an explicit short TTL cache with manual refresh/invalidation
- never return raw upstream JSON
search_campus_locations
Inputs:
query (required)
limit (optional, capped at 8)
Output:
- stable result ID for follow-up actions
- display name/address and coordinates
- source and freshness metadata
- explicit empty/unavailable/upstream-error states
Behavior:
- reuse
MapSearchClient and its Tübingen-bounded Nominatim request
- do not transmit device GPS position
- do not auto-open navigation; keep that as a separate future user-approved action using a returned result ID
Slice 2: private study tools
get_tasks
Inputs:
sources (optional subset of ilias, moodle; defaults to both)
limit (optional, capped at 50)
Output item contract:
- stable source-qualified ID
source, courseTitle, title, itemType
startAt, dueAt, status, and actionable when known
- local source URL/target for user navigation
- result-level freshness and partial-failure metadata
Data sources:
- ILIAS derived-task overview (
IliasTaskItem: title, URL, type, start, end)
- Moodle actionable dashboard/calendar events (
MoodleDashboardEvent)
Behavior:
- normalize dates to ISO-8601 with an explicit timezone when parsing is reliable
- preserve raw date hints separately when an exact timestamp cannot be established
- sort known due dates first, then undated tasks
- return successful sources when one portal fails and include a bounded per-source failure instead of failing the whole tool
get_deadlines
Inputs:
days (optional, default 30, range 1–180)
sources (optional subset of ilias, moodle; defaults to both)
limit (optional, capped at 100)
Output item contract:
- source-qualified ID and
source
- course, exercise/assignment title, requirement/status
dueAt plus the original due hint
- source URL/target
- result-level window, freshness, and partial-failure metadata
Data sources:
- ILIAS course assignment traversal (
IliasAssignmentDeadline / IliasExerciseAssignment)
- Moodle calendar action events within the requested time window (
MoodleCalendarPage)
Behavior:
- filter only confirmed dated entries into the requested window
- do not turn heuristic mail deadline matches into confirmed portal deadlines
- deduplicate by source + canonical URL/ID + title + due time
- cap course traversal and assignment scans before tool output
- preserve portal attribution so the assistant never claims an ILIAS deadline came from Moodle or vice versa
get_study_planner
Inputs: none for the first version.
Output:
- planner title and source URL
- visible semesters (
index, label, termLabel)
- bounded modules with number, title, semester column/span, earned/required credits, progress, detail URL, and expandability
- planner view-state flags and freshness metadata
Behavior:
- port/reuse the wrapper's
AlmaStudyPlannerPage contract and parser fixtures
- return structured planner data, not raw HTML
- keep module detail expansion out of the first version
Extend get_academic_status
Keep the existing tool name. Expand its response so it distinguishes:
- selected/available term
- course enrollment vs exam registration
- status, attempt/category, schedule text, and detail URL when present
- current report/parser notice and refresh timestamp
Do not infer “passed”, “registered”, or “cancelled” from missing/ambiguous fields. Preserve the portal's original status alongside any normalized status.
Local authenticated integration
The Flutter app must perform ALMA/ILIAS/Moodle requests locally using credentials from existing secure profile storage.
- Never send the username/password to a hosted wrapper, cloud model, tool argument, prompt, result, trace, log, or URL.
- Port the proven Shibboleth/SAML handoff, parser contracts, and fixtures from
tue-api-wrapper into focused Dart clients, or consume them from a shared pure-Dart wrapper package if one is available.
- Reuse a local authenticated session within one logical refresh where practical; inject/close HTTP clients deterministically.
- Detect login redirects/session expiry explicitly and return
authenticationRequired rather than empty data.
- Keep portal clients/repositories separate from assistant serialization so UI, feed, and assistant can share the same capability.
Capability and tool architecture
- Add/reuse typed capability results containing:
- data
- state (
fresh, stale, empty, unavailable, permissionDenied, authenticationRequired, failed)
- source(s)
fetchedAt and optional expiresAt
- reliability and bounded per-source failures
- Add policy metadata:
- public tools:
publicExternal, read-only, cloud/local allowed
- study tools:
privateLocal, read-only, local-only by default
- Register tools in the shared catalog so schemas, descriptions, traces, and provider filtering have one source of truth.
- Route execution through focused typed capability handlers rather than growing unrelated branches in
StudyOsToolExecutor.
- Serialize compact bounded JSON only at the tool boundary.
- Inject clients/clocks so tests can use deterministic fakes; production must not silently fall back to mock data.
If #54 has not landed, implement only the smallest compatible contract subset and keep it easy for #54 to adopt without a second migration.
Cloud privacy enforcement
Cloud tool calls execute on-device, but their results are sent back to the configured cloud model. Labels alone are insufficient.
cloudToolDefinitions must omit privateLocal tools by default.
- Local models may receive bounded private results on-device.
- A future explicit user opt-in may allow selected redacted private results to a configured cloud provider; that consent flow is out of scope here.
- Never place document bytes, attachments, cookies, auth headers, passwords, or full portal HTML in model context.
Caching and freshness
Use explicit per-capability caches, not hidden view futures:
- Mensa: short TTL keyed by date/filter inputs
- location search: short TTL keyed by normalized query
- tasks/deadlines: short authenticated TTL with manual refresh and logout invalidation
- study planner/academic status: longer TTL with manual refresh and logout invalidation
Never persist passwords, cookies, raw HTML, or attachment/document bytes in these caches. Consumers must be able to distinguish fresh, stale, empty, unavailable, and failed states.
Out of scope
- official-document listing/download
- automatic navigation/map opening
- campus seats, buildings, events, sports, TIMMS, Praxisportal, or Anny
- Moodle grades/messages/notifications beyond data needed for tasks/deadlines
- ALMA/ILIAS/Moodle write actions
- hosted credential storage/routing
- silent mock production data
Acceptance criteria
Shared/public
Private study
Tests/docs
Validation
Run from flutter_app/:
dart format --output=none --set-exit-if-changed lib test
flutter analyze
flutter test
flutter build web --release
Suggested delivery order
This issue may be implemented as focused PRs sharing the same capability contracts:
- capability result/policy/provider filtering + public tools
- local ILIAS/Moodle session and parsers +
get_tasks/get_deadlines
- ALMA planner + richer academic status
Follow-up issues can cover public course discovery/seats/events/TIMMS and explicit-confirmation university actions.
Summary
Expose two groups of
StudyOS_Agentcapabilities as assistant tools:This issue is the first concrete implementation consumer of the shared data/action capability contract in #54. Public tools may be used by local and cloud providers. Authenticated university data must be fetched on-device and remain local-only by default.
Motivation
Latest
mainhas one sharedStudyOsToolSpeccatalog and executor for cloud and local providers, but several live app capabilities are UI-only and core study workflows fromtue-api-wrapperare still missing:CampusClientalready loads Tübingen Mensa menus.MapSearchClientalready searches bounded Tübingen locations.tue-api-wrapperhas tested contracts for ILIAS tasks/assignment deadlines, Moodle calendar events, the ALMA study planner, and enrollment/exam status.Adding these through one capability architecture gives the assistant useful, grounded data without routing student credentials through hosted infrastructure.
Dependencies and overlap
tue-api-wrapperas the request/parsing/contract reference. Reuse its fixtures and typed shapes where practical instead of inventing incompatible models.Slice 1: public campus tools
get_mensa_optionsInputs:
date(optional ISO date)canteen(optional ID or name filter)preference(optional:any,vegetarian,vegan)limit(optional, bounded)Output:
Behavior:
CampusClientand shared model-level filtering/sortingsearch_campus_locationsInputs:
query(required)limit(optional, capped at 8)Output:
Behavior:
MapSearchClientand its Tübingen-bounded Nominatim requestSlice 2: private study tools
get_tasksInputs:
sources(optional subset ofilias,moodle; defaults to both)limit(optional, capped at 50)Output item contract:
source,courseTitle,title,itemTypestartAt,dueAt,status, andactionablewhen knownData sources:
IliasTaskItem: title, URL, type, start, end)MoodleDashboardEvent)Behavior:
get_deadlinesInputs:
days(optional, default 30, range 1–180)sources(optional subset ofilias,moodle; defaults to both)limit(optional, capped at 100)Output item contract:
sourcedueAtplus the original due hintData sources:
IliasAssignmentDeadline/IliasExerciseAssignment)MoodleCalendarPage)Behavior:
get_study_plannerInputs: none for the first version.
Output:
index,label,termLabel)Behavior:
AlmaStudyPlannerPagecontract and parser fixturesExtend
get_academic_statusKeep the existing tool name. Expand its response so it distinguishes:
Do not infer “passed”, “registered”, or “cancelled” from missing/ambiguous fields. Preserve the portal's original status alongside any normalized status.
Local authenticated integration
The Flutter app must perform ALMA/ILIAS/Moodle requests locally using credentials from existing secure profile storage.
tue-api-wrapperinto focused Dart clients, or consume them from a shared pure-Dart wrapper package if one is available.authenticationRequiredrather than empty data.Capability and tool architecture
fresh,stale,empty,unavailable,permissionDenied,authenticationRequired,failed)fetchedAtand optionalexpiresAtpublicExternal, read-only, cloud/local allowedprivateLocal, read-only, local-only by defaultStudyOsToolExecutor.If #54 has not landed, implement only the smallest compatible contract subset and keep it easy for #54 to adopt without a second migration.
Cloud privacy enforcement
Cloud tool calls execute on-device, but their results are sent back to the configured cloud model. Labels alone are insufficient.
cloudToolDefinitionsmust omitprivateLocaltools by default.Caching and freshness
Use explicit per-capability caches, not hidden view futures:
Never persist passwords, cookies, raw HTML, or attachment/document bytes in these caches. Consumers must be able to distinguish fresh, stale, empty, unavailable, and failed states.
Out of scope
Acceptance criteria
Shared/public
get_mensa_optionsandsearch_campus_locationsare advertised/executable in cloud and local assistant paths.Private study
get_tasks,get_deadlines, andget_study_plannerare available to the local assistant.get_academic_statusreturns the richer term-aware contract without breaking existing callers.Tests/docs
Validation
Run from
flutter_app/:Suggested delivery order
This issue may be implemented as focused PRs sharing the same capability contracts:
get_tasks/get_deadlinesFollow-up issues can cover public course discovery/seats/events/TIMMS and explicit-confirmation university actions.