From eaaa1f2e0e4ab2d60faa987501347cd7ba5c368f Mon Sep 17 00:00:00 2001 From: a2a-platform Date: Mon, 29 Jun 2026 00:46:25 +0000 Subject: [PATCH] deploy --- .a2a/agent.dsl.json | 13 +++++++++++-- README.md | 2 ++ a2a.yaml | 2 +- agent.py | 30 +++++++++++++++++++++++++++++- skills/auth/SKILL.md | 6 ++++++ skills/courses/SKILL.md | 1 + 6 files changed, 50 insertions(+), 4 deletions(-) diff --git a/.a2a/agent.dsl.json b/.a2a/agent.dsl.json index 12f2ebe..6772b58 100644 --- a/.a2a/agent.dsl.json +++ b/.a2a/agent.dsl.json @@ -3,7 +3,7 @@ "language": "python", "name": "learnhouse-agent", "description": "LearnHouse is an open-source platform tailored for learning experiences.", - "version": "1.2.9", + "version": "1.2.10", "entrypoint": { "module": "agent", "class_name": "LearnhouseAgent", @@ -88,6 +88,15 @@ "required": false, "input_type": "url", "options": [] + }, + { + "name": "LEARNHOUSE_AUTH", + "kind": "secret", + "label": "LearnHouse auth", + "description": "Paste a LearnHouse user auth value: either 'Bearer ', a raw access token, or a Cookie header such as 'LH_access=...; LH_refresh=...'.", + "required": true, + "input_type": "password", + "options": [] } ] }, @@ -163,7 +172,7 @@ "source": "python-a2a-pack", "project_manifest": { "name": "learnhouse-agent", - "version": "1.2.9", + "version": "1.2.10", "entrypoint": "agent:LearnhouseAgent" } } diff --git a/README.md b/README.md index 1a5c504..6bdf866 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ Deployment context: LearnHouse Enterprise multi-organization mode. - Course creation uses multipart form fields: `name`, `description`, `public`, and `about`. +- Auth setup is required as `LEARNHOUSE_AUTH`. Use `Bearer `, a + raw access token, or a Cookie header containing `LH_access`/`LH_refresh`. The generated code is intentionally editable. Tune prompts, operation grouping, auth names, and safety policy before publishing serious agents. diff --git a/a2a.yaml b/a2a.yaml index 3e54712..2e910c1 100644 --- a/a2a.yaml +++ b/a2a.yaml @@ -1,5 +1,5 @@ name: learnhouse-agent -version: 1.2.9 +version: 1.2.10 entrypoint: agent:LearnhouseAgent description: LearnHouse is an open-source platform tailored for learning experiences. runtime: diff --git a/agent.py b/agent.py index 9d7e83c..1a579fd 100644 --- a/agent.py +++ b/agent.py @@ -63,9 +63,17 @@ class OperationInput(BaseModel): class LearnhouseAgent(A2AAgent): name = "learnhouse-agent" description = "LearnHouse is an open-source platform tailored for learning experiences." - version = "1.2.9" + version = "1.2.10" consumer_setup = ConsumerSetup.from_fields( ConsumerSetupField.config("OPENAPI_BASE_URL", label="API base URL", description="Override the default API server (https://learnhouse.a2acloud.io).", required=False, input_type="url"), + ConsumerSetupField.secret( + "LEARNHOUSE_AUTH", + label="LearnHouse auth", + description=( + "Paste a LearnHouse user auth value: either 'Bearer ', " + "a raw access token, or a Cookie header such as 'LH_access=...; LH_refresh=...'." + ), + ), ) llm_provisioning = LLMProvisioning.PLATFORM pricing = Pricing( @@ -383,6 +391,7 @@ class LearnhouseAgent(A2AAgent): raise ValueError("missing required path parameter(s): " + missing) if cookies: headers["cookie"] = "; ".join(f"{key}={value}" for key, value in cookies.items()) + headers.update(_learnhouse_auth_headers(ctx)) auth_headers, auth_query = self._auth_for_operation(ctx, operation) headers.update(auth_headers) query.update(auth_query) @@ -446,6 +455,25 @@ def _consumer_secret_optional(ctx: RunContext, name: str | None) -> str: return "" +def _learnhouse_auth_headers(ctx: RunContext) -> dict[str, str]: + raw = ctx.consumer_secret("LEARNHOUSE_AUTH").strip() + if not raw: + raise ConsumerSetupMissing("operation requires consumer setup secret(s): LEARNHOUSE_AUTH") + + lower = raw.lower() + if lower.startswith("authorization:"): + value = raw.split(":", 1)[1].strip() + return {"authorization": value} + if lower.startswith("cookie:"): + value = raw.split(":", 1)[1].strip() + return {"cookie": value} + if lower.startswith("bearer "): + return {"authorization": raw} + if "=" in raw and (";" in raw or lower.startswith("lh_") or "session" in lower): + return {"cookie": raw} + return {"authorization": f"Bearer {raw}"} + + def _request_body_content_types(operation: dict[str, Any]) -> set[str]: request_body = operation.get("request_body") if not isinstance(request_body, dict): diff --git a/skills/auth/SKILL.md b/skills/auth/SKILL.md index 3fa8dc4..8bcf6fd 100644 --- a/skills/auth/SKILL.md +++ b/skills/auth/SKILL.md @@ -11,6 +11,12 @@ Use the generated operation tools to make real API calls. Do not invent API resp If a tool reports missing setup, return the exact setup field name to the caller. For write, update, or delete operations, state the intended action before calling the tool. +Deployment auth note: + +- Agent calls use required consumer setup secret `LEARNHOUSE_AUTH`. +- `POST /api/v1/auth/login` accepts `application/x-www-form-urlencoded` credentials and returns `access_token`/`refresh_token` under `tokens`, while also setting `LH_access` and `LH_refresh` cookies. +- For subsequent API calls, set `LEARNHOUSE_AUTH` to `Bearer ` or a Cookie header containing `LH_access`/`LH_refresh`. + ## Operations ### login_api_v1_auth_login_post diff --git a/skills/courses/SKILL.md b/skills/courses/SKILL.md index a0e7056..8c5b9e3 100644 --- a/skills/courses/SKILL.md +++ b/skills/courses/SKILL.md @@ -20,6 +20,7 @@ Deployment context for this LearnHouse instance: - When listing courses and the user does not provide pagination, use `page=1` and `limit=50`. - When creating a course, use query parameter `org_id=1` unless the user explicitly provides another org ID. - Course creation must send multipart form fields `name`, `description`, `public`, and `about`. If the user only gives a title, use it as `name`, provide short `description` and `about` values, and set `public=false` unless the user asks for a public course. +- Course creation and course management require `LEARNHOUSE_AUTH` consumer setup. ## Operations