diff --git a/.gitignore b/.gitignore
index ca54b99..83e00e5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,4 +23,4 @@ lcov.info
go.work
# Local .env files
-*.local
\ No newline at end of file
+*.local.idea/
diff --git a/go.mod b/go.mod
index 1f343f2..10caf84 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module github.com/lambda-feedback/shimmy
-go 1.24.5
+go 1.25
require (
github.com/aws/aws-lambda-go v1.46.0
@@ -23,12 +23,23 @@ require (
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/deckarep/golang-set/v2 v2.6.0 // indirect
+ github.com/getkin/kin-openapi v0.138.0 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
+ github.com/go-openapi/jsonpointer v0.21.0 // indirect
+ github.com/go-openapi/swag v0.23.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/holiman/uint256 v1.2.4 // indirect
+ github.com/josharian/intern v1.0.0 // indirect
+ github.com/mailru/easyjson v0.7.7 // indirect
+ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
+ github.com/oasdiff/yaml v0.0.9 // indirect
+ github.com/oasdiff/yaml3 v0.0.12 // indirect
+ github.com/perimeterx/marshmallow v1.1.5 // indirect
+ github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
+ github.com/woodsbury/decimal128 v1.3.0 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
golang.org/x/crypto v0.24.0 // indirect
diff --git a/go.sum b/go.sum
index b65c019..014f78c 100644
--- a/go.sum
+++ b/go.sum
@@ -31,6 +31,8 @@ github.com/ethereum/go-ethereum v1.14.5 h1:szuFzO1MhJmweXjoM5nSAeDvjNUH3vIQoMzzQ
github.com/ethereum/go-ethereum v1.14.5/go.mod h1:VEDGGhSxY7IEjn98hJRFXl/uFvpRgbIIf2PpXiyGGgc=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/getkin/kin-openapi v0.138.0 h1:ebfE0JAmF6AqHrNBy1KO3Fs68K9tPs48HalvLPo7Rv4=
+github.com/getkin/kin-openapi v0.138.0/go.mod h1:vUYWaKyMqj7PfTybelXtLuLN9tReS12vxnzMRK+z2GY=
github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps=
github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
@@ -38,6 +40,10 @@ github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3Bop
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
+github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
+github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
+github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
+github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 h1:TQcrn6Wq+sKGkpyPvppOz99zsMBaUOKXq6HSv655U1c=
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
@@ -48,6 +54,8 @@ github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU
github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs=
github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
github.com/knadh/koanf/parsers/json v0.1.0 h1:dzSZl5pf5bBcW0Acnu20Djleto19T0CfHcvZ14NJ6fU=
@@ -60,18 +68,28 @@ github.com/knadh/koanf/providers/file v0.1.0 h1:fs6U7nrV58d3CFAFh8VTde8TM262ObYf
github.com/knadh/koanf/providers/file v0.1.0/go.mod h1:rjJ/nHQl64iYCtAW2QQnF0eSmDEX/YZ/eNFj5yR6BvA=
github.com/knadh/koanf/v2 v2.1.0 h1:eh4QmHHBuU8BybfIJ8mB8K8gsGCD/AUQTdwGq/GzId8=
github.com/knadh/koanf/v2 v2.1.0/go.mod h1:4mnTRbZCK+ALuBXHZMjDfG9y714L7TykVnZkXbMU3Es=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
+github.com/oasdiff/yaml v0.0.9 h1:zQOvd2UKoozsSsAknnWoDJlSK4lC0mpmjfDsfqNwX48=
+github.com/oasdiff/yaml v0.0.9/go.mod h1:8lvhgJG4xiKPj3HN5lDow4jZHPlx1i7dIwzkdAo6oAM=
+github.com/oasdiff/yaml3 v0.0.12 h1:75urAtPeDg2/iDEWwzNrLOWxI9N/dCh81nTTJtokt2M=
+github.com/oasdiff/yaml3 v0.0.12/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU=
github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4=
+github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
+github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -80,6 +98,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
+github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -96,6 +116,8 @@ github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+F
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
+github.com/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0=
+github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
diff --git a/internal/server/module.go b/internal/server/module.go
index f41556b..7644bed 100644
--- a/internal/server/module.go
+++ b/internal/server/module.go
@@ -6,6 +6,8 @@ func Module(config HttpConfig) fx.Option {
return fx.Module("server",
// provide config
fx.Supply(config),
+ // provide openapi spec
+ fx.Provide(LoadOpenAPISpec),
// provide server
fx.Provide(NewLifecycleServer),
// invoke server
diff --git a/internal/server/openapi.go b/internal/server/openapi.go
new file mode 100644
index 0000000..f94f392
--- /dev/null
+++ b/internal/server/openapi.go
@@ -0,0 +1,72 @@
+package server
+
+import (
+ "io"
+ "net/http"
+ "net/http/httptest"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/getkin/kin-openapi/openapi3filter"
+ "github.com/getkin/kin-openapi/routers/legacy"
+ "go.uber.org/zap"
+
+ "github.com/lambda-feedback/shimmy/runtime/schema"
+)
+
+func LoadOpenAPISpec() (*openapi3.T, error) {
+ loader := openapi3.NewLoader()
+ return loader.LoadFromData(schema.OpenAPISpec)
+}
+
+func OpenAPIMiddleware(spec *openapi3.T, log *zap.Logger) func(http.Handler) http.Handler {
+ router, _ := legacy.NewRouter(spec)
+ opts := &openapi3filter.Options{AuthenticationFunc: openapi3filter.NoopAuthenticationFunc}
+
+ return func(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ route, pathParams, err := router.FindRoute(r)
+ if err != nil {
+ // Not a µEd route — pass through unvalidated
+ next.ServeHTTP(w, r)
+ return
+ }
+
+ // Validate request
+ reqInput := &openapi3filter.RequestValidationInput{
+ Request: r,
+ PathParams: pathParams,
+ Route: route,
+ Options: opts,
+ }
+ if err := openapi3filter.ValidateRequest(r.Context(), reqInput); err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ return
+ }
+
+ // Capture response for validation
+ rec := httptest.NewRecorder()
+ next.ServeHTTP(rec, r)
+
+ // Validate response (lenient — log only)
+ respInput := &openapi3filter.ResponseValidationInput{
+ RequestValidationInput: reqInput,
+ Status: rec.Code,
+ Header: rec.Header(),
+ Body: io.NopCloser(rec.Body),
+ Options: opts,
+ }
+ if err := openapi3filter.ValidateResponse(r.Context(), respInput); err != nil {
+ log.Error("response failed OpenAPI validation", zap.Error(err))
+ http.Error(w, "invalid response format", http.StatusInternalServerError)
+ return
+ }
+
+ // Forward captured response
+ for k, v := range rec.Header() {
+ w.Header()[k] = v
+ }
+ w.WriteHeader(rec.Code)
+ w.Write(rec.Body.Bytes()) //nolint:errcheck
+ })
+ }
+}
diff --git a/internal/server/server.go b/internal/server/server.go
index 883be2f..c9c7c84 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -6,6 +6,7 @@ import (
"net"
"net/http"
+ "github.com/getkin/kin-openapi/openapi3"
"go.uber.org/fx"
"go.uber.org/zap"
"golang.org/x/net/http2"
@@ -18,6 +19,7 @@ type HttpServerParams struct {
Context context.Context
Config HttpConfig
+ Spec *openapi3.T
Handlers []*HttpHandler `group:"handlers"`
Logger *zap.Logger
@@ -39,8 +41,9 @@ func NewHttpServer(params HttpServerParams) *HttpServer {
}
var handler http.Handler = NormalizePath(mux)
+ handler = OpenAPIMiddleware(params.Spec, params.Logger)(handler)
if params.Config.H2c {
- handler = h2c.NewHandler(NormalizePath(mux), &http2.Server{})
+ handler = h2c.NewHandler(handler, &http2.Server{})
}
server := &http.Server{
diff --git a/runtime/schema/mued_v0.1.0.yml b/runtime/schema/mued_v0.1.0.yml
new file mode 100644
index 0000000..c5ca3c8
--- /dev/null
+++ b/runtime/schema/mued_v0.1.0.yml
@@ -0,0 +1,2050 @@
+openapi: 3.1.0
+info:
+ title: µEd API - Educational Microservices
+ version: 0.1.0
+ contact:
+ name: µEd API Maintainers
+ description: |
+ The µEd API ("microservices for education") is a specification for interoperable educational services.
Currently defined endpoints:
- **Evaluate Task**: automatic feedback and grading for student submissions.
- **Chat**: conversational interactions around tasks, submissions, or general
+ learning questions.
+tags:
+ - name: evaluate
+ description: Endpoints for evaluating student submissions and generating feedback.
+ - name: chat
+ description: Conversational endpoints for educational dialogue.
+paths:
+ /evaluate:
+ post:
+ summary: Evaluate a submission and generate feedback
+ operationId: evaluateSubmission
+ description: |
+ Generates a list of feedback items for a given student submission. The request can optionally include the task context, user information, criteria to evaluate on, pre-submission feedback options, configuration, and a callback URL for asynchronous result delivery.
+ tags:
+ - evaluate
+ parameters:
+ - $ref: '#/components/parameters/Authorization'
+ - $ref: '#/components/parameters/X-Request-Id'
+ - $ref: '#/components/parameters/X-Api-Version'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/EvaluateRequest'
+ examples:
+ simpleTextSubmission:
+ summary: Simple text submission without user or criteria
+ value:
+ submission:
+ submissionId: sub-123
+ taskId: task-42
+ type: TEXT
+ format: plain
+ content:
+ text: Explain what polymorphism is in object-oriented programming.
+ submittedAt: '2025-12-16T09:30:00Z'
+ version: 1
+ configuration: null
+ preSubmissionFeedbackExample:
+ summary: Pre-submission feedback (non-final)
+ value:
+ submission:
+ submissionId: sub-777
+ taskId: task-42
+ type: TEXT
+ format: plain
+ content:
+ text: My short answer...
+ preSubmissionFeedback:
+ enabled: true
+ configuration:
+ llm:
+ model: gpt-5.2
+ temperature: 0.4
+ asyncCallbackExample:
+ summary: Asynchronous processing via callback URL
+ value:
+ submission:
+ submissionId: sub-async-001
+ taskId: task-42
+ type: TEXT
+ format: plain
+ content:
+ text: Detailed essay answer that may require longer processing.
+ submittedAt: '2025-12-16T09:45:00Z'
+ version: 1
+ callbackUrl: https://learning-platform.example.com/hooks/evaluate-result
+ withTaskAndExtras:
+ summary: With task context, user, criteria and configuration
+ value:
+ task:
+ taskId: task-12
+ title: Explain polymorphism
+ content:
+ text: Define polymorphism and give at least one example in Java.
+ learningObjectives:
+ - Explain the concept of polymorphism.
+ - Provide an example of subtype polymorphism in Java.
+ referenceSolution:
+ text: |
+ Polymorphism allows the same method call to result in different behavior depending on the object's runtime type. For example, a variable of type Shape can reference a Circle or Rectangle, and calling draw() will invoke the appropriate implementation.
+ context:
+ constraints: Answer in 3-6 sentences.
+ language: en
+ submission:
+ submissionId: sub-456
+ taskId: task-12
+ type: TEXT
+ format: plain
+ content:
+ text: |
+ Polymorphism means that an object can take many forms, for example subclasses implementing methods differently.
+ submittedAt: '2025-12-16T10:00:00Z'
+ version: 2
+ user:
+ userId: user-789
+ type: LEARNER
+ detailPreference: DETAILED
+ tonePreference: FRIENDLY
+ languagePreference: en
+ criteria:
+ - criterionId: crit-1
+ name: Correctness
+ context: The explanation of polymorphism is conceptually correct.
+ maxPoints: 10
+ - criterionId: crit-2
+ name: Clarity
+ context: The explanation is clear, well-structured, and easy to understand.
+ maxPoints: 5
+ preSubmissionFeedback:
+ enabled: false
+ configuration:
+ llm:
+ model: gpt-5.2
+ temperature: 0.2
+ maxTokens: 800
+ credentials:
+ type: JWT
+ key: Some-Key
+ enforceRubricStrictness: true
+ codeSubmissionExample:
+ summary: Code submission (Python)
+ value:
+ submission:
+ submissionId: sub-code-001
+ taskId: task-python-101
+ type: CODE
+ format: python
+ content:
+ code: |
+ def fibonacci(n):
+ if n <= 1:
+ return n
+ return fibonacci(n-1) + fibonacci(n-2)
+
+ # Test the function
+ for i in range(10):
+ print(fibonacci(i))
+ submittedAt: '2025-12-16T11:00:00Z'
+ version: 1
+ codeMultiFileExample:
+ summary: Code submission with multiple files
+ value:
+ submission:
+ submissionId: sub-code-002
+ taskId: task-java-201
+ type: CODE
+ format: java
+ content:
+ files:
+ - path: src/Main.java
+ content: |
+ public class Main {
+ public static void main(String[] args) {
+ Calculator calc = new Calculator();
+ System.out.println(calc.add(2, 3));
+ }
+ }
+ - path: src/Calculator.java
+ content: |
+ public class Calculator {
+ public int add(int a, int b) {
+ return a + b;
+ }
+ }
+ entryPoint: src/Main.java
+ submittedAt: '2025-12-16T11:30:00Z'
+ version: 1
+ codeSympyExample:
+ summary: Math submission (SymPy/Python)
+ value:
+ submission:
+ submissionId: sub-math-002
+ taskId: task-algebra-101
+ type: CODE
+ format: sympy
+ content:
+ expression: solve(x**2 - 4, x)
+ imports:
+ - from sympy import symbols, solve
+ - x = symbols('x')
+ submittedAt: '2025-12-16T12:30:00Z'
+ version: 1
+ mathInlineLatexExample:
+ summary: Inline math submission (Inline LaTeX)
+ value:
+ submission:
+ submissionId: sub-math-001
+ taskId: task-calculus-101
+ type: MATH
+ format: latex
+ content:
+ expression: \int_{0}^{\infty} e^{-x^2} dx = \frac{\sqrt{\pi}}{2}
+ submittedAt: '2025-12-16T12:00:00Z'
+ version: 1
+ mathMathMLExample:
+ summary: Math submission (MathML)
+ value:
+ submission:
+ submissionId: sub-math-003
+ taskId: task-geometry-101
+ type: MATH
+ format: mathml
+ content:
+ expression: |
+
+ submittedAt: '2025-12-16T13:00:00Z'
+ version: 1
+ modelUmlExample:
+ summary: Model submission (UML class diagram - PlantUML)
+ value:
+ submission:
+ submissionId: sub-model-001
+ taskId: task-oop-design-101
+ type: MODEL
+ format: uml
+ content:
+ model: |
+ @startuml
+ abstract class Animal {
+ +name: String
+ +speak(): String
+ }
+
+ class Dog extends Animal {
+ +speak(): String
+ }
+
+ class Cat extends Animal {
+ +speak(): String
+ }
+ @enduml
+ notation: plantuml
+ diagramType: class
+ submittedAt: '2025-12-16T14:00:00Z'
+ version: 1
+ modelErExample:
+ summary: Model submission (ER diagram - JSON structure)
+ value:
+ submission:
+ submissionId: sub-model-002
+ taskId: task-database-101
+ type: MODEL
+ format: er
+ content:
+ model:
+ entities:
+ - name: Student
+ attributes:
+ - name: student_id
+ type: INTEGER
+ primaryKey: true
+ - name: name
+ type: VARCHAR(100)
+ - name: email
+ type: VARCHAR(255)
+ - name: Course
+ attributes:
+ - name: course_id
+ type: INTEGER
+ primaryKey: true
+ - name: title
+ type: VARCHAR(200)
+ relationships:
+ - name: enrolls_in
+ from: Student
+ to: Course
+ cardinality: many-to-many
+ notation: json
+ submittedAt: '2025-12-16T14:30:00Z'
+ version: 1
+ modelBpmnExample:
+ summary: Model submission (BPMN process)
+ value:
+ submission:
+ submissionId: sub-model-003
+ taskId: task-process-101
+ type: MODEL
+ format: bpmn
+ content:
+ model: |
+
+
+
+
+
+
+
+
+
+
+ notation: bpmn-xml
+ submittedAt: '2025-12-16T15:00:00Z'
+ version: 1
+ textMarkdownExample:
+ summary: Text submission (Markdown with formatting)
+ value:
+ submission:
+ submissionId: sub-text-002
+ taskId: task-essay-101
+ type: TEXT
+ format: markdown
+ content:
+ markdown: |
+ # Introduction to Polymorphism
+
+ Polymorphism is a fundamental concept in **object-oriented programming** that allows objects to be treated as instances of their parent class.
+
+ ## Key Points
+
+ 1. **Subtype polymorphism**: Different classes can be used interchangeably
+ 2. **Method overriding**: Subclasses provide specific implementations
+ submittedAt: '2025-12-16T15:30:00Z'
+ version: 1
+ responses:
+ '200':
+ description: Successfully generated feedback.
+ headers:
+ X-Request-Id:
+ description: Request id for tracing this request across services.
+ schema:
+ type: string
+ X-Api-Version:
+ description: The API version that was used to serve this response.
+ schema:
+ type: string
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Feedback'
+ examples:
+ exampleResponse:
+ summary: Example feedback response
+ value:
+ - feedbackId: fb-1
+ title: Clarify your definition
+ message: Your explanation of polymorphism is generally correct, but it would help to distinguish between subtype polymorphism and parametric polymorphism.
+ suggestedAction: Add one or two concrete examples of polymorphism in Java, e.g., method overriding.
+ awardedPoints: 2.5
+ criterion:
+ criterionId: crit-1
+ name: Correctness
+ context: The solution produces correct results for the specified problem.
+ maxPoints: 10
+ target:
+ artefactType: TEXT
+ format: plain
+ locator:
+ type: span
+ startIndex: 0
+ endIndex: 120
+ - feedbackId: fb-2
+ title: Overall structure
+ message: The overall structure of your answer is clear and easy to follow.
+ '202':
+ $ref: '#/components/responses/202-Accepted'
+ '400':
+ $ref: '#/components/responses/400-BadRequest'
+ '403':
+ $ref: '#/components/responses/403-Forbidden'
+ '406':
+ $ref: '#/components/responses/406-VersionNotSupported'
+ '500':
+ $ref: '#/components/responses/500-InternalError'
+ '501':
+ $ref: '#/components/responses/501-NotImplemented'
+ /evaluate/health:
+ get:
+ summary: Health and capabilities of the evaluate service
+ operationId: getEvaluateHealth
+ description: |
+ Returns health information and capabilities of the evaluate service. Clients can use this endpoint to discover whether the service supports optional features such as pre-submission feedback, formative feedback, and summative feedback.
+ tags:
+ - evaluate
+ parameters:
+ - $ref: '#/components/parameters/X-Request-Id'
+ - $ref: '#/components/parameters/X-Api-Version'
+ responses:
+ '200':
+ description: Evaluate service is reachable and reporting capabilities.
+ headers:
+ X-Request-Id:
+ description: Request id for tracing this request across services.
+ schema:
+ type: string
+ X-Api-Version:
+ description: The API version that was used to serve this response.
+ schema:
+ type: string
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/EvaluateHealthResponse'
+ examples:
+ exampleHealth:
+ summary: Example healthy service with capabilities
+ value:
+ status: OK
+ message: Service healthy
+ version: 1.0.0
+ capabilities:
+ supportsEvaluate: true
+ supportsPreSubmissionFeedback: false
+ supportsFormativeFeedback: true
+ supportsSummativeFeedback: true
+ supportsDataPolicy: PARTIAL
+ supportedArtefactProfiles:
+ - type: TEXT
+ supportedFormats:
+ - plain
+ - markdown
+ - type: CODE
+ supportedFormats:
+ - python
+ - java
+ - javascript
+ - type: MATH
+ supportedFormats:
+ - latex
+ - mathml
+ supportedLanguages:
+ - en
+ - de
+ supportedVersions:
+ - 0.1.0
+ '406':
+ $ref: '#/components/responses/406-VersionNotSupported'
+ '501':
+ description: The server does not implement the health endpoint for evaluate.
+ $ref: '#/components/responses/501-NotImplemented'
+ '503':
+ $ref: '#/components/responses/503-ServiceUnavailable'
+ /chat:
+ post:
+ summary: Chat about tasks, submissions, or learning topics
+ operationId: chat
+ description: |
+ Conversational endpoint for educational chat use cases. A conversation can be grounded in a specific course, task or submission and may use user information to adapt tone and detail. Typical use cases include: asking follow-up questions on feedback, requesting hints, or clarifying concepts.
+ tags:
+ - chat
+ parameters:
+ - $ref: '#/components/parameters/Authorization'
+ - $ref: '#/components/parameters/X-Request-Id'
+ - $ref: '#/components/parameters/X-Api-Version'
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ChatRequest'
+ examples:
+ minimalChat:
+ summary: Minimal chat request
+ value:
+ messages:
+ - role: USER
+ content: Can you explain polymorphism?
+ configuration: null
+ chatWithLlmConfig:
+ summary: Chat request with optional LLM configuration
+ value:
+ conversationId: conv-1001
+ user:
+ userId: user-456
+ type: LEARNER
+ detailPreference: MEDIUM
+ tonePreference: FRIENDLY
+ languagePreference: en
+ messages:
+ - role: USER
+ content: Give me a hint for my answer about polymorphism.
+ context:
+ task:
+ taskId: task-12
+ title: Explain polymorphism
+ content:
+ text: Define polymorphism and give at least one example in Java.
+ configuration:
+ type: Java Assistant
+ llm:
+ model: gpt-5.2
+ temperature: 0.7
+ stream: false
+ credentials:
+ type: JWT
+ key: Some-Key
+ chatWithContext:
+ summary: Chat request with complex educational context
+ value:
+ messages:
+ - role: USER
+ content: What should I do for this part?
+ user:
+ userId: user-321
+ type: LEARNER
+ detailPreference: DETAILED
+ tonePreference: NEUTRAL
+ languagePreference: en
+ taskProgress:
+ currentQuestionId: question-321
+ timeSpentOnQuestion: 30 minutes
+ currentPart:
+ partId: part-1
+ timeSpentOnPart: 10 minutes
+ submission:
+ type: TEXT
+ content:
+ text: outputs= ["Woof!", "Meow!"]
+ feedback:
+ - feedbackId: fb-101
+ message: Incomplete answer, explain why these outputs occur.
+ context:
+ module:
+ moduleId: module-456
+ title: Introduction to Object-Oriented Programming (OOP)
+ set:
+ setId: set-789
+ title: Fundamentals
+ question:
+ questionId: question-321
+ title: Understanding Polymorphism
+ content: |
+ Answer the questions for the following example of polymorphism in Python.
+ ```python class Animal:
+ def speak(self):
+ pass
+
+ class Dog(Animal):
+ def speak(self):
+ return "Woof!"
+
+ class Cat(Animal):
+ def speak(self):
+ return "Meow!"
+
+ animals = [Dog(), Cat()] for animal in animals:
+ print(animal.speak())
+ ```
+ estimatedTime: 15-25 minutes
+ parts:
+ - partId: part-1
+ content: |
+ Looking at the code example, identify which method is being overridden and explain how this demonstrates polymorphism. What output would the code produce and why?
+ - partId: part-2
+ content: |
+ Write a new class called `Bird` that inherits from `Animal` and overrides the `speak()` method to return "Tweet!". Then add an instance of `Bird` to the animals list.
+ referenceSolution:
+ code: |
+ class Bird(Animal):
+ def speak(self):
+ return "Tweet!"
+
+ animals = [Dog(), Cat(), Bird()]
+ for animal in animals:
+ print(animal.speak())
+ configuration:
+ type: CS Assistant
+ llm:
+ model: gpt-5.2
+ temperature: 0.5
+ responses:
+ '200':
+ description: Successful chat response.
+ headers:
+ X-Request-Id:
+ description: Request id for tracing this request across services.
+ schema:
+ type: string
+ X-Api-Version:
+ description: The API version that was used to serve this response.
+ schema:
+ type: string
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ChatResponse'
+ examples:
+ minimalChatResponse:
+ summary: Minimal chat response
+ value:
+ output:
+ role: ASSISTANT
+ content: |
+ Polymorphism is a core concept in object-oriented programming that allows objects of different classes to be treated as objects of a common superclass. It enables a single interface to represent different underlying forms (data types). For example, in Java, you can have a superclass `Animal` with a method `speak()`, and subclasses like `Dog` and `Cat` that provide their own implementations of `speak()`. When you call `speak()` on an `Animal` reference, the appropriate subclass method is invoked based on the actual object type at runtime.
+ metadata: null
+ chatWithLlmConfigResponse:
+ summary: Chat response with LLM configuration
+ value:
+ output:
+ role: ASSISTANT
+ content: |
+ Here's a hint for your answer about polymorphism: Focus on how polymorphism allows methods to do different things based on the object that it is acting upon, even when accessed through a common interface. You might want to mention method overriding and how it enables this behavior in object-oriented programming.
+ metadata:
+ responseTimeMs: 1800
+ type: Java Assistant
+ createdAt: '2025-12-10T11:15:00Z'
+ llm:
+ model: gpt-5.2
+ temperature: 0.7
+ outputTokens: 78
+ chatWithContextResponse:
+ summary: Chat response with context
+ value:
+ output:
+ role: ASSISTANT
+ content: |
+ In the provided code example, the `speak()` method is being overridden in the `Dog` and `Cat` subclasses of the `Animal` superclass. This demonstrates polymorphism because when we call `speak()` on each animal in the `animals` list, the method that gets executed depends on the actual object type (either `Dog` or `Cat`), not the reference type (`Animal`). The output of the code would be:
+ ``` Woof! Meow! ```
+ This happens because each subclass provides its own implementation of the `speak()` method, and at runtime, the correct method is called based on the object's type.
+ metadata:
+ responseTimeMs: 2000
+ type: CS Assistant
+ createdAt: '2025-12-10T11:15:00Z'
+ llm:
+ model: gpt-5.2
+ temperature: 0.5
+ outputTokens: 143
+ '400':
+ $ref: '#/components/responses/400-BadRequest-2'
+ '403':
+ $ref: '#/components/responses/403-Forbidden'
+ '406':
+ $ref: '#/components/responses/406-VersionNotSupported'
+ '500':
+ $ref: '#/components/responses/500-InternalError-2'
+ '501':
+ $ref: '#/components/responses/501-NotImplemented-2'
+ /chat/health:
+ get:
+ summary: Health and capabilities of the chat service
+ operationId: getChatHealth
+ description: |
+ Returns health information and capabilities of the chat service. Clients can use this endpoint to discover whether the service supports optional features such as user preferences or streaming responses.
+ tags:
+ - chat
+ parameters:
+ - $ref: '#/components/parameters/X-Request-Id'
+ - $ref: '#/components/parameters/X-Api-Version'
+ responses:
+ '200':
+ description: Chat service is reachable and reporting capabilities.
+ headers:
+ X-Request-Id:
+ description: Request id for tracing this request across services.
+ schema:
+ type: string
+ X-Api-Version:
+ description: The API version that was used to serve this response.
+ schema:
+ type: string
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ChatHealthResponse'
+ examples:
+ exampleHealth:
+ summary: Example healthy service with capabilities
+ value:
+ status: OK
+ statusMessage: Service healthy
+ version: 1.0.0
+ capabilities:
+ supportsChat: true
+ supportsUserPreferences: true
+ supportsStreaming: true
+ supportsDataPolicy: NOT_SUPPORTED
+ supportedLanguages:
+ - en
+ - de
+ supportedModels:
+ - gpt-4o
+ - llama-3
+ supportedVersions:
+ - 0.1.0
+ '406':
+ $ref: '#/components/responses/406-VersionNotSupported'
+ '501':
+ description: The server does not implement the health endpoint for chat.
+ $ref: '#/components/responses/501-NotImplemented-2'
+ '503':
+ $ref: '#/components/responses/503-ServiceUnavailable-2'
+components:
+ parameters:
+ Authorization:
+ in: header
+ name: Authorization
+ schema:
+ type: string
+ required: false
+ description: Optional authorization header.
+ X-Request-Id:
+ in: header
+ name: X-Request-Id
+ description: Request id for tracing this request across services.
+ schema:
+ type: string
+ X-Api-Version:
+ in: header
+ name: X-Api-Version
+ description: |
+ The µEd API version the client is targeting (e.g. "0.1.0"). If omitted, the server will use the latest version it supports. If the requested version cannot be served, the server returns 406 Version Not Supported.
+ required: false
+ schema:
+ type: string
+ example: 0.1.0
+ schemas:
+ Task:
+ type: object
+ description: |
+ Task context including the content, learning objectives, optional reference solution, optional context information, and optional metadata.
+ required:
+ - title
+ properties:
+ taskId:
+ type: string
+ description: Optional unique identifier for the task.
+ title:
+ type: string
+ description: Short title or label for the task.
+ content:
+ type:
+ - object
+ - 'null'
+ description: Optional content shown to the learner (structure is task-specific).
+ additionalProperties: true
+ context:
+ type:
+ - object
+ - 'null'
+ description: Optional educational context (e.g., course material).
+ additionalProperties: true
+ learningObjectives:
+ type:
+ - array
+ - 'null'
+ description: Optional list of learning objectives addressed by this task.
+ items:
+ type: string
+ referenceSolution:
+ type:
+ - object
+ - 'null'
+ description: Optional reference or example solution (structure is task-specific).
+ additionalProperties: true
+ metadata:
+ type:
+ - object
+ - 'null'
+ description: Optional metadata such as difficulty, topic, tags, etc.
+ additionalProperties: true
+ ArtefactType:
+ type: string
+ description: |
+ High-level type of artefact. Use the 'format' field to specify the exact format (e.g., programming language for CODE, notation for MATH).
+ enum:
+ - TEXT
+ - CODE
+ - MODEL
+ - MATH
+ - OTHER
+ Submission:
+ type: object
+ description: |
+ A student's submission for a task. The structure of 'content' is intentionally generic and task-specific.
+ required:
+ - type
+ - content
+ properties:
+ submissionId:
+ type: string
+ description: Optional unique identifier of the submission.
+ taskId:
+ type:
+ - string
+ - 'null'
+ description: Optional identifier of the task this submission belongs to.
+ type:
+ $ref: '#/components/schemas/ArtefactType'
+ format:
+ type:
+ - string
+ - 'null'
+ description: |
+ Optional format specifier providing additional detail about the artefact. For TEXT: plain_text, markdown, html, rich_text, etc. For CODE: programming language (e.g., python, java, javascript, wolfram, matlab). For MATH: latex, mathml, sympy, wolfram, asciimath, etc. For MODEL: uml, er, bpmn, petri_net, state_machine, etc. Use lowercase values and snakecase. Services should document which formats they support.
+ content:
+ type: object
+ additionalProperties: true
+ description: |
+ Logical representation of the submission content. The expected structure depends on the artefact type: - TEXT: { text: string } or { markdown: string } - CODE: { code: string } or { files: [{ path: string, content: string }], entryPoint?: string } - MATH: { expression: string } - MODEL: { model: string | object, notation?: string }
+ submittedAt:
+ type:
+ - string
+ - 'null'
+ format: date-time
+ description: Optional timestamp when the submission was created.
+ version:
+ type:
+ - integer
+ - 'null'
+ format: int32
+ description: Optional version number (e.g., resubmissions).
+ UserType:
+ type: string
+ description: Type of user interacting with the API.
+ enum:
+ - LEARNER
+ - TEACHER
+ - EDU_ADMIN
+ - SYS_ADMIN
+ - OTHER
+ Detail:
+ type: string
+ description: Level of detail preferred in responses or feedback.
+ enum:
+ - BRIEF
+ - MEDIUM
+ - DETAILED
+ Tone:
+ type: string
+ description: Preferred tone for responses or feedback.
+ enum:
+ - FORMAL
+ - NEUTRAL
+ - FRIENDLY
+ User:
+ type: object
+ description: User information including type and optional preferences influencing response tone, detail, and language.
+ required:
+ - type
+ additionalProperties: true
+ properties:
+ userId:
+ type:
+ - string
+ - 'null'
+ description: Optional unique identifier for the user.
+ type:
+ $ref: '#/components/schemas/UserType'
+ preference:
+ type: object
+ properties:
+ detail:
+ description: Optional preferred level of detail in responses.
+ $ref: '#/components/schemas/Detail'
+ tone:
+ description: Optional preferred tone for responses.
+ $ref: '#/components/schemas/Tone'
+ language:
+ type:
+ - string
+ - 'null'
+ description: Optional preferred language code following ISO 639 language codes (e.g., 'en', 'de').
+ additionalProperties: true
+ taskProgress:
+ type:
+ - object
+ - 'null'
+ description: Optional information about the user's progress on this task/topic.
+ additionalProperties: true
+ NumericGrade:
+ title: Numeric Grade
+ type: object
+ required:
+ - min
+ - max
+ - value
+ properties:
+ min:
+ type: number
+ description: Minimum value for the numeric range
+ max:
+ type: number
+ description: Maximum value for the numeric range
+ value:
+ type: number
+ description: The actual rating value within the min-max range
+ LetterOnlyGrade:
+ title: Letter Only Grade
+ type: object
+ required:
+ - value
+ properties:
+ value:
+ type: string
+ enum:
+ - A
+ - B
+ - C
+ - D
+ - E
+ - F
+ - n/a
+ LetterPlusMinusGrade:
+ title: Letter +/- grades
+ type: object
+ required:
+ - value
+ properties:
+ value:
+ type: string
+ enum:
+ - A+
+ - A
+ - A-
+ - B+
+ - B
+ - B-
+ - C+
+ - C
+ - C-
+ - D+
+ - D
+ - D-
+ - E+
+ - E
+ - E-
+ - F
+ OtherGrade:
+ title: Other
+ type: object
+ required:
+ - value
+ properties:
+ value:
+ type: string
+ description: Free-form string rating
+ Criterion:
+ type: object
+ description: A criterion used to assess one dimension of a submission.
+ required:
+ - name
+ properties:
+ criterionId:
+ type: string
+ description: Optional unique identifier of the criterion.
+ name:
+ type: string
+ description: Human-readable name of the criterion.
+ context:
+ type:
+ - string
+ - object
+ - 'null'
+ description: Optional additional context about how to apply this criterion.
+ additionalProperties: true
+ gradeConfig:
+ oneOf:
+ - $ref: '#/components/schemas/NumericGrade'
+ - $ref: '#/components/schemas/LetterOnlyGrade'
+ - $ref: '#/components/schemas/LetterPlusMinusGrade'
+ - $ref: '#/components/schemas/OtherGrade'
+ description: Optional configuration for grades for this criterion.
+ PreSubmissionFeedback:
+ type: object
+ description: Optional configuration for pre-submission feedback runs.
+ required:
+ - enabled
+ additionalProperties: true
+ properties:
+ enabled:
+ type: boolean
+ description: Indicates whether pre-submission feedback is requested.
+ LLMConfiguration:
+ type: object
+ description: |
+ Optional configuration for an LLM provider. All fields are optional and provider-specific values may be included via additional properties.
+ additionalProperties: true
+ properties:
+ model:
+ type:
+ - string
+ - 'null'
+ description: Optional model identifier (e.g., 'gpt-4o', 'llama-3').
+ temperature:
+ type:
+ - number
+ - 'null'
+ description: Optional sampling temperature.
+ maxTokens:
+ type:
+ - integer
+ - 'null'
+ description: Optional maximum number of tokens to generate.
+ stream:
+ type:
+ - boolean
+ - 'null'
+ description: Optional flag indicating whether streaming responses are requested.
+ credentials:
+ type:
+ - object
+ - 'null'
+ description: Optional credentials object to be supplied with time-based key via a proxy.
+ additionalProperties: true
+ Region:
+ type: string
+ description: |
+ Geographic regions using ISO 3166-1 alpha-2 country codes (e.g., US, GB, DE) or regional groupings (e.g., EEA, EU, APAC).
+ AnonymizationLevel:
+ type: string
+ description: Level of required anonymization.
+ enum:
+ - NONE
+ - PSEUDONYMIZED
+ - ANONYMIZED
+ - AGGREGATED
+ DataPolicy:
+ type: object
+ description: |
+ Declares what downstream services are allowed to do with data associated with this request: which legal regimes apply, what uses are permitted, how long data may be retained, where it may be processed, and what constraints apply (especially for children / sensitive data).
+ additionalProperties: true
+ properties:
+ legal:
+ type:
+ - object
+ - 'null'
+ description: Legal framework and authority governing this data.
+ properties:
+ applicableLaws:
+ type: array
+ description: One or more applicable legal regimes.
+ items:
+ type: string
+ enum:
+ - GDPR
+ - UK_GDPR
+ - EPRIVACY
+ - CCPA_CPRA
+ - COPPA
+ - FERPA
+ - PPRA
+ - PIPEDA
+ - LGPD
+ - POPIA
+ - APPI
+ - PIPL
+ - OTHER
+ legalBasis:
+ type:
+ - array
+ - 'null'
+ description: Optional but recommended legal basis for processing.
+ items:
+ type: string
+ enum:
+ - CONSENT
+ - CONTRACT
+ - LEGAL_OBLIGATION
+ - PUBLIC_TASK
+ - LEGITIMATE_INTERESTS
+ - VITAL_INTERESTS
+ - OTHER
+ jurisdiction:
+ type:
+ - object
+ - 'null'
+ description: Geographic constraints for data subjects and processing.
+ properties:
+ dataSubjectRegions:
+ type:
+ - array
+ - 'null'
+ description: Where the data subjects are located.
+ items:
+ $ref: '#/components/schemas/Region'
+ allowedProcessingRegions:
+ type:
+ - array
+ - 'null'
+ description: Where processing/storage is allowed.
+ items:
+ $ref: '#/components/schemas/Region'
+ disallowedProcessingRegions:
+ type:
+ - array
+ - 'null'
+ description: Explicit exclusions for processing regions.
+ items:
+ $ref: '#/components/schemas/Region'
+ dataSubject:
+ type:
+ - object
+ - 'null'
+ description: Information about who this data is about.
+ properties:
+ population:
+ type:
+ - string
+ - 'null'
+ description: Type of population this data concerns.
+ enum:
+ - STUDENT
+ - STAFF
+ - GUARDIAN
+ - MIXED
+ - OTHER
+ isChildData:
+ type:
+ - boolean
+ - 'null'
+ description: Indicates whether this data concerns children. If true, then minAge required.
+ minAge:
+ type:
+ - integer
+ - 'null'
+ description: Minimum age of data subjects, if relevant/known.
+ dataCategory:
+ type:
+ - object
+ - 'null'
+ description: Classification of the type of data.
+ properties:
+ classification:
+ type:
+ - string
+ - 'null'
+ description: Primary classification of the data.
+ enum:
+ - ANONYMOUS
+ - PSEUDONYMOUS
+ - PERSONAL
+ - EDUCATION_RECORD
+ - SENSITIVE
+ - OTHER
+ additionalProperties: true
+ retentionPermission:
+ type:
+ - array
+ - 'null'
+ description: What retention and secondary uses are permitted.
+ items:
+ type: string
+ enum:
+ - NEVER
+ - SECURITY
+ - LOGGING
+ - PRODUCT-IMPROVEMENT-NO-SHARE
+ - PRODUCT-IMPROVEMENT-SHARE-LIMITED
+ - RESEARCH-CONFIDENTIAL
+ - PUBLIC
+ - OTHER
+ retention:
+ type:
+ - object
+ - 'null'
+ description: How long data may be retained.
+ properties:
+ retentionPeriod:
+ type:
+ - string
+ - 'null'
+ description: Concrete retention period, following ISO 8601 standard.
+ deleteOnRequest:
+ type:
+ - boolean
+ - 'null'
+ description: Whether data must be deleted on user request.
+ legalHoldAllowed:
+ type:
+ - boolean
+ - 'null'
+ description: Whether legal holds are permitted on this data.
+ sharing:
+ type:
+ - object
+ - 'null'
+ description: Constraints on who can receive this data.
+ properties:
+ thirdPartySharing:
+ type:
+ - string
+ - 'null'
+ description: Third-party sharing policy.
+ enum:
+ - PROHIBITED
+ - ALLOWED
+ - ALLOWED-LIMITED
+ subprocessorsAllowed:
+ type:
+ - boolean
+ - 'null'
+ description: Whether subprocessors are allowed.
+ allowedRecipients:
+ type:
+ - array
+ - 'null'
+ description: Categories of allowed recipients.
+ items:
+ type: string
+ enum:
+ - CONTROLLER-ONLY
+ - INTERNAL-SERVICES
+ - NAMED-PARTNERS
+ - PUBLIC
+ deidentification:
+ type:
+ - object
+ - 'null'
+ description: Required deidentification for specific uses.
+ properties:
+ requiredForServiceImprovement:
+ $ref: '#/components/schemas/AnonymizationLevel'
+ requiredForResearch:
+ $ref: '#/components/schemas/AnonymizationLevel'
+ ExecutionPolicy:
+ type: object
+ description: |
+ Declares execution constraints that the server or client consuming this API should apply when triggering calls to external providers (such as LLMs). Covers queue management and response timeouts.
+ additionalProperties: true
+ properties:
+ priority:
+ type:
+ - string
+ - 'null'
+ description: Request priority for queue management when capacity is constrained.
+ enum:
+ - low
+ - normal
+ - high
+ - null
+ timeout:
+ type:
+ - integer
+ - 'null'
+ description: Maximum time in milliseconds to wait for a complete response before failing.
+ minimum: 1
+ EvaluateRequest:
+ type: object
+ description: |
+ Input for task evaluate service. The submission is mandatory; task, user, criteria, pre-submission feedback options, and configuration, and callback URL are optional.
+ required:
+ - submission
+ properties:
+ task:
+ description: |
+ Optional task context that can include prompt content, learning objectives, a reference solution, and additional context metadata.
+ type:
+ - object
+ - 'null'
+ allOf:
+ - $ref: '#/components/schemas/Task'
+ submission:
+ $ref: '#/components/schemas/Submission'
+ user:
+ description: Optional user information including type and preferences that can influence response tone, detail, and language.
+ type:
+ - object
+ - 'null'
+ allOf:
+ - $ref: '#/components/schemas/User'
+ criteria:
+ type:
+ - array
+ - 'null'
+ description: Optional criteria used for evaluate.
+ items:
+ $ref: '#/components/schemas/Criterion'
+ preSubmissionFeedback:
+ description: |
+ Optional settings for pre-submission feedback (non-final). When enabled, the service should avoid committing or finalizing grades.
+ type:
+ - object
+ - 'null'
+ allOf:
+ - $ref: '#/components/schemas/PreSubmissionFeedback'
+ callbackUrl:
+ type:
+ - string
+ - 'null'
+ format: uri
+ description: |
+ Optional HTTPS callback URL for asynchronous processing. If provided, the service may return 202 Accepted immediately and deliver feedback results to this URL once processing is complete.
+ configuration:
+ description: |
+ Optional key-value configuration dictionary for provider-specific or experimental parameters. Not standardized.
+ type:
+ - object
+ - 'null'
+ additionalProperties: true
+ properties:
+ llm:
+ description: Optional LLM configuration used for this request.
+ type:
+ - object
+ - 'null'
+ allOf:
+ - $ref: '#/components/schemas/LLMConfiguration'
+ dataPolicy:
+ description: Optional data policy governing how this request's data may be processed and retained.
+ type:
+ - object
+ - 'null'
+ allOf:
+ - $ref: '#/components/schemas/DataPolicy'
+ executionPolicy:
+ description: Optional execution constraints for this request.
+ type:
+ - object
+ - 'null'
+ allOf:
+ - $ref: '#/components/schemas/ExecutionPolicy'
+ FeedbackTarget:
+ type: object
+ description: Optional reference to a specific part of the submission.
+ required:
+ - artefactType
+ properties:
+ artefactType:
+ $ref: '#/components/schemas/ArtefactType'
+ format:
+ type:
+ - string
+ - 'null'
+ description: |
+ Optional format specifier matching the submission format (e.g., python, latex).
+ locator:
+ type:
+ - object
+ - 'null'
+ description: |
+ Optional locator into the submission content. Standard locator types: - TEXT: { type: "span", startIndex: number, endIndex: number } - CODE: { type: "range", file?: string, startLine: number, endLine: number, startColumn?: number, endColumn?: number } - MATH: { type: "subexpression", path: string } (e.g., path to subexpression) - MODEL: { type: "element", elementId: string, elementType?: string }
+ additionalProperties: true
+ Feedback:
+ type: object
+ description: |
+ A single feedback item produced for the submission. It may include suggested actions, optional points, optional criterion linkage, and optional targeting into the submission.
+ properties:
+ feedbackId:
+ type: string
+ description: Unique identifier of the feedback item.
+ title:
+ type:
+ - string
+ - 'null'
+ description: Optional short label for this feedback item.
+ message:
+ type:
+ - string
+ - 'null'
+ description: Optional feedback text shown to the learner.
+ suggestedAction:
+ type:
+ - string
+ - 'null'
+ description: Optional suggestion for how to act on this feedback.
+ awardedPoints:
+ type:
+ - number
+ - 'null'
+ format: double
+ description: Optional points awarded for this feedback item.
+ criterion:
+ type:
+ - object
+ - 'null'
+ description: Optional criterion linked to this feedback item.
+ allOf:
+ - $ref: '#/components/schemas/Criterion'
+ target:
+ type:
+ - object
+ - 'null'
+ description: Optional target reference inside the submission.
+ allOf:
+ - $ref: '#/components/schemas/FeedbackTarget'
+ EvaluateAcceptedResponse:
+ type: object
+ description: Acknowledgement that evaluation was accepted for asynchronous processing.
+ required:
+ - status
+ - requestId
+ properties:
+ status:
+ type: string
+ enum:
+ - ACCEPTED
+ description: Indicates that the request has been accepted for asynchronous processing.
+ requestId:
+ type: string
+ description: Identifier to correlate this accepted request with callback delivery.
+ message:
+ type:
+ - string
+ - 'null'
+ description: Optional human-readable message about asynchronous processing.
+ ErrorResponse:
+ type: object
+ description: Standard error response returned by µEd API services.
+ required:
+ - title
+ properties:
+ title:
+ type: string
+ description: Short, human-readable error title.
+ message:
+ type:
+ - string
+ - 'null'
+ description: Optional human-readable error message.
+ code:
+ type:
+ - string
+ - 'null'
+ description: Optional application-specific error code.
+ trace:
+ type:
+ - string
+ - 'null'
+ description: Optional debug trace or stack trace (should be omitted in production by default).
+ details:
+ type:
+ - object
+ - 'null'
+ description: Optional provider-specific details for debugging or programmatic handling.
+ additionalProperties: true
+ HealthStatus:
+ type: string
+ description: Overall health status of the service.
+ enum:
+ - OK
+ - DEGRADED
+ - UNAVAILABLE
+ EvaluateRequirements:
+ type: object
+ description: |
+ Requirements for calling the evaluate endpoint, e.g. whether an Authorization header and/or LLM configuration or credentials (provided via a proxy, preferably time-based and/or signed tokens) are required.
+ additionalProperties: true
+ properties:
+ requiresAuthorizationHeader:
+ type:
+ - boolean
+ - 'null'
+ description: Optional flag indicating whether an Authorization header is required.
+ requiresLlmConfiguration:
+ type:
+ - boolean
+ - 'null'
+ description: Optional flag indicating whether configuration.llm must be provided.
+ requiresLlmCredentialProxy:
+ type:
+ - boolean
+ - 'null'
+ description: Optional flag indicating whether configuration.llm.credentials must be provided via a proxy.
+ DataPolicySupport:
+ type: string
+ enum:
+ - SUPPORTED
+ - NOT_SUPPORTED
+ - PARTIAL
+ description: Indicates whether the service supports data policy configuration.
+ ArtefactProfile:
+ type: object
+ description: |
+ Describes support for a specific artefact type and its formats. Used in health/capabilities responses to advertise what a service can handle.
+ required:
+ - type
+ properties:
+ type:
+ $ref: '#/components/schemas/ArtefactType'
+ supportedFormats:
+ type:
+ - array
+ - 'null'
+ description: |
+ List of supported formats for this artefact type. Use lowercase values. If null or empty, the service accepts any format for this type.
+ items:
+ type: string
+ examples:
+ - - plain
+ - markdown
+ - - python
+ - java
+ - javascript
+ - wolfram
+ - matlab
+ - - latex
+ - mathml
+ contentSchema:
+ type:
+ - object
+ - 'null'
+ description: |
+ Optional JSON Schema describing the expected content structure for this artefact type. Allows services to advertise their exact requirements.
+ additionalProperties: true
+ locatorSchema:
+ type:
+ - object
+ - 'null'
+ description: |
+ Optional JSON Schema describing the locator structure used for feedback targeting within this artefact type.
+ additionalProperties: true
+ EvaluateCapabilities:
+ type: object
+ description: Capabilities of the evaluate service.
+ required:
+ - supportsEvaluate
+ - supportsPreSubmissionFeedback
+ - supportsFormativeFeedback
+ - supportsSummativeFeedback
+ - supportsDataPolicy
+ additionalProperties: true
+ properties:
+ supportsEvaluate:
+ type: boolean
+ description: Indicates whether the /evaluate endpoint is implemented and usable.
+ supportsPreSubmissionFeedback:
+ type: boolean
+ description: Indicates whether the service supports pre-submission feedback runs.
+ supportsFormativeFeedback:
+ type: boolean
+ description: Indicates whether the service supports qualitative feedback without points.
+ supportsSummativeFeedback:
+ type: boolean
+ description: Indicates whether the service supports feedback with points / grading signals.
+ supportsDataPolicy:
+ $ref: '#/components/schemas/DataPolicySupport'
+ supportedArtefactProfiles:
+ type:
+ - array
+ - 'null'
+ description: |
+ Optional list of supported artefact profiles. Each profile specifies an artefact type and the formats supported for that type.
+ items:
+ $ref: '#/components/schemas/ArtefactProfile'
+ supportedLanguages:
+ type:
+ - array
+ - 'null'
+ description: Optional list of supported language codes (e.g., 'en', 'de').
+ items:
+ type: string
+ supportedAPIVersions:
+ type:
+ - array
+ - 'null'
+ description: |
+ Optional list of µEd API versions supported by this service implementation (e.g., ["0.1.0"]). Clients can use this to select a compatible X-Api-Version.
+ items:
+ type: string
+ EvaluateHealthResponse:
+ type: object
+ description: Health status and capabilities of the evaluate service.
+ required:
+ - status
+ - capabilities
+ properties:
+ status:
+ $ref: '#/components/schemas/HealthStatus'
+ message:
+ type:
+ - string
+ - 'null'
+ description: Optional human-readable status message.
+ version:
+ type:
+ - string
+ - 'null'
+ description: Optional version of the evaluate service implementation.
+ requirements:
+ type:
+ - object
+ - 'null'
+ description: Optional requirements clients must satisfy to use this service.
+ allOf:
+ - $ref: '#/components/schemas/EvaluateRequirements'
+ capabilities:
+ $ref: '#/components/schemas/EvaluateCapabilities'
+ Message:
+ type: object
+ required:
+ - role
+ - content
+ properties:
+ role:
+ type: string
+ enum:
+ - USER
+ - ASSISTANT
+ - SYSTEM
+ - TOOL
+ content:
+ type: string
+ ChatRequest:
+ type: object
+ description: Request body for the chat endpoint.
+ required:
+ - messages
+ properties:
+ messages:
+ type: array
+ description: List of messages in the conversation (including history).
+ items:
+ $ref: '#/components/schemas/Message'
+ conversationId:
+ type:
+ - string
+ - 'null'
+ description: Optional identifier for the conversation session.
+ user:
+ description: Optional user information to adapt the chat style and level.
+ type:
+ - object
+ - 'null'
+ allOf:
+ - $ref: '#/components/schemas/User'
+ context:
+ type:
+ - object
+ - 'null'
+ description: Optional educational context (e.g., course material, task context).
+ additionalProperties: true
+ configuration:
+ type:
+ - object
+ - 'null'
+ description: Optional configuration for the model(s).
+ additionalProperties: true
+ properties:
+ type:
+ type:
+ - string
+ - 'null'
+ description: Optional type for the chatbot or chat model.
+ llm:
+ description: Optional LLM configuration used for this request.
+ type:
+ - object
+ - 'null'
+ allOf:
+ - $ref: '#/components/schemas/LLMConfiguration'
+ dataPolicy:
+ description: Optional data policy governing how this request's data may be processed and retained.
+ type:
+ - object
+ - 'null'
+ allOf:
+ - $ref: '#/components/schemas/DataPolicy'
+ executionPolicy:
+ description: Optional execution constraints for this request.
+ type:
+ - object
+ - 'null'
+ allOf:
+ - $ref: '#/components/schemas/ExecutionPolicy'
+ ChatResponse:
+ type: object
+ description: Response body for the chat endpoint.
+ required:
+ - output
+ properties:
+ output:
+ $ref: '#/components/schemas/Message'
+ description: The generated assistant response.
+ metadata:
+ type:
+ - object
+ - 'null'
+ description: Optional metadata about response generation.
+ additionalProperties: true
+ ChatCapabilities:
+ type: object
+ description: Capabilities of the chat service.
+ required:
+ - supportsChat
+ - supportsDataPolicy
+ additionalProperties: true
+ properties:
+ supportsChat:
+ type: boolean
+ description: Indicates whether the /chat endpoint is implemented and usable.
+ supportsUserPreferences:
+ type: boolean
+ description: Indicates whether the service supports adapting to user preferences.
+ supportsStreaming:
+ type: boolean
+ description: Indicates whether the service supports streaming responses.
+ supportsDataPolicy:
+ $ref: '#/components/schemas/DataPolicySupport'
+ supportedLanguages:
+ type:
+ - array
+ - 'null'
+ description: Optional list of supported language codes.
+ items:
+ type: string
+ supportedModels:
+ type:
+ - array
+ - 'null'
+ description: Optional list of supported models.
+ items:
+ type: string
+ supportedAPIVersions:
+ type:
+ - array
+ - 'null'
+ description: |
+ Optional list of µEd API versions supported by this service implementation (e.g., ["0.1.0"]). Clients can use this to select a compatible X-Api-Version.
+ items:
+ type: string
+ ChatHealthResponse:
+ type: object
+ description: Health status and capabilities of the chat service.
+ required:
+ - status
+ - capabilities
+ properties:
+ status:
+ $ref: '#/components/schemas/HealthStatus'
+ statusMessage:
+ type:
+ - string
+ - 'null'
+ description: Optional human-readable status message.
+ version:
+ type:
+ - string
+ - 'null'
+ description: Optional version of the chat service implementation.
+ capabilities:
+ $ref: '#/components/schemas/ChatCapabilities'
+ responses:
+ 202-Accepted:
+ description: Request accepted for asynchronous evaluation processing.
+ headers:
+ X-Request-Id:
+ description: Request id for tracing this request across services.
+ schema:
+ type: string
+ X-Api-Version:
+ description: The API version that was used to serve this response.
+ schema:
+ type: string
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/EvaluateAcceptedResponse'
+ examples:
+ asyncAccepted:
+ summary: Example accepted async request
+ value:
+ status: ACCEPTED
+ requestId: req-7c193f38
+ message: Evaluation queued. Results will be sent to callbackUrl.
+ 400-BadRequest:
+ description: Invalid request (e.g. missing content or invalid schema).
+ headers:
+ X-Request-Id:
+ description: Request id for tracing this request across services.
+ schema:
+ type: string
+ X-Api-Version:
+ description: The API version that was used to serve this response.
+ schema:
+ type: string
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ examples:
+ validationError:
+ summary: Example validation error
+ value:
+ title: Invalid request
+ message: submission.content must not be empty.
+ code: VALIDATION_ERROR
+ trace: null
+ details:
+ field: submission.content
+ 403-Forbidden:
+ description: Forbidden (e.g. insufficient permissions or access denied).
+ headers:
+ X-Request-Id:
+ description: Request id for tracing this request across services.
+ schema:
+ type: string
+ X-Api-Version:
+ description: The API version that was used to serve this response.
+ schema:
+ type: string
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ examples:
+ permissionError:
+ summary: Example permission error
+ value:
+ title: Forbidden
+ message: You do not have permission to access this resource.
+ code: PERMISSION_DENIED
+ trace: null
+ details:
+ resource: submission
+ required_permission: write
+ 406-VersionNotSupported:
+ description: |
+ The requested API version (supplied via X-Api-Version) is not supported by this service.
+ headers:
+ X-Request-Id:
+ description: Request id for tracing this request across services.
+ schema:
+ type: string
+ X-Api-Version:
+ description: The API version that was used to serve this response.
+ schema:
+ type: string
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ examples:
+ versionNotSupported:
+ summary: Example version not supported error
+ value:
+ title: API version not supported
+ message: 'The requested API version ''0.0'' is not supported. Supported versions are: [''0.1.0''].'
+ code: VERSION_NOT_SUPPORTED
+ trace: null
+ details:
+ requestedVersion: '0.0'
+ supportedVersions:
+ - 0.1.0
+ 500-InternalError:
+ description: Internal server error.
+ headers:
+ X-Request-Id:
+ description: Request id for tracing this request across services.
+ schema:
+ type: string
+ X-Api-Version:
+ description: The API version that was used to serve this response.
+ schema:
+ type: string
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ examples:
+ internalError:
+ summary: Example internal error
+ value:
+ title: Internal server error
+ message: Unexpected failure while generating feedback.
+ code: INTERNAL_ERROR
+ trace: 'java.lang.RuntimeException: ... (stack trace omitted)'
+ details:
+ subsystem: llm-provider
+ 501-NotImplemented:
+ description: |
+ The server does not support the evaluate method. This allows service providers to implement only subsets of the µEd API.
+ headers:
+ X-Request-Id:
+ description: Request id for tracing this request across services.
+ schema:
+ type: string
+ X-Api-Version:
+ description: The API version that was used to serve this response.
+ schema:
+ type: string
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ examples:
+ notImplemented:
+ summary: Example not implemented error
+ value:
+ title: Not implemented
+ message: This service does not implement /evaluate.
+ code: NOT_IMPLEMENTED
+ trace: null
+ details: null
+ 503-ServiceUnavailable:
+ description: Service is currently unavailable or unhealthy.
+ headers:
+ X-Request-Id:
+ description: Request id for tracing this request across services.
+ schema:
+ type: string
+ X-Api-Version:
+ description: The API version that was used to serve this response.
+ schema:
+ type: string
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ examples:
+ serviceUnavailable:
+ summary: Example unavailable error
+ value:
+ title: Service unavailable
+ message: Evaluate service is currently unavailable.
+ code: SERVICE_UNAVAILABLE
+ trace: null
+ details:
+ reason: Database connection failed
+ unhealthy:
+ summary: Example degraded / unavailable service
+ value:
+ title: Service unhealthy
+ status: UNAVAILABLE
+ message: Database connection failed
+ version: 1.0.0
+ capabilities:
+ supportsEvaluate: false
+ supportsPreSubmissionFeedback: false
+ supportsFormativeFeedback: false
+ supportsSummativeFeedback: false
+ supportsDataPolicy: NOT_SUPPORTED
+ supportedArtefactProfiles: []
+ supportedLanguages: []
+ 400-BadRequest-2:
+ description: Invalid request (e.g. missing content or invalid schema).
+ headers:
+ X-Request-Id:
+ description: Request id for tracing this request across services.
+ schema:
+ type: string
+ X-Api-Version:
+ description: The API version that was used to serve this response.
+ schema:
+ type: string
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ examples:
+ invalidChatRequest:
+ summary: Example invalid chat request
+ value:
+ title: Invalid request
+ message: messages must contain at least one item.
+ code: VALIDATION_ERROR
+ trace: null
+ details:
+ field: messages
+ 500-InternalError-2:
+ description: Internal server error.
+ headers:
+ X-Request-Id:
+ description: Request id for tracing this request across services.
+ schema:
+ type: string
+ X-Api-Version:
+ description: The API version that was used to serve this response.
+ schema:
+ type: string
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ examples:
+ modelProviderError:
+ summary: Example model provider error
+ value:
+ title: Model provider error
+ message: LLM provider returned an error while generating a response.
+ code: LLM_PROVIDER_ERROR
+ trace: null
+ details:
+ provider: openai
+ 501-NotImplemented-2:
+ description: |
+ The server does not support the chat method. This allows service providers to implement only subsets of the µEd API.
+ headers:
+ X-Request-Id:
+ description: Request id for tracing this request across services.
+ schema:
+ type: string
+ X-Api-Version:
+ description: The API version that was used to serve this response.
+ schema:
+ type: string
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ examples:
+ notImplemented:
+ summary: Example not implemented error
+ value:
+ title: Not implemented
+ message: This service does not implement /chat.
+ code: NOT_IMPLEMENTED
+ trace: null
+ details: null
+ 503-ServiceUnavailable-2:
+ description: Service is currently unavailable or unhealthy.
+ headers:
+ X-Request-Id:
+ description: Request id for tracing this request across services.
+ schema:
+ type: string
+ X-Api-Version:
+ description: The API version that was used to serve this response.
+ schema:
+ type: string
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ErrorResponse'
+ examples:
+ serviceUnavailable:
+ summary: Example unavailable error
+ value:
+ title: Service unavailable
+ message: Chat service is currently unavailable.
+ code: SERVICE_UNAVAILABLE
+ trace: null
+ details:
+ reason: LLM provider connection failed
+ serviceUnhealthy:
+ summary: Example degraded / unavailable service
+ value:
+ title: Service unhealthy
+ message: LLM provider connection failed
+ code: SERVICE_UNHEALTHY
+ version: 1.0.0
+ capabilities:
+ supportsChat: false
+ supportsUserPreferences: false
+ supportsStreaming: false
+ supportsDataPolicy: NOT_SUPPORTED
+ supportedLanguages: []
+ supportedModels: []
diff --git a/runtime/schema/openapi.go b/runtime/schema/openapi.go
new file mode 100644
index 0000000..b771890
--- /dev/null
+++ b/runtime/schema/openapi.go
@@ -0,0 +1,6 @@
+package schema
+
+import _ "embed"
+
+//go:embed mued_v0.1.0.yml
+var OpenAPISpec []byte