feat: message-based build agent protocol implementation

- Add runner.proto with agent message protocol definitions
- Update edge registration client and server job client
- Add agent-message-protocol task documentation
- Update generated protobuf files for Dart and Go
This commit is contained in:
toki 2026-06-06 11:48:22 +09:00
parent 06b986af62
commit e6e383f116
14 changed files with 3102 additions and 35 deletions

View file

@ -0,0 +1,185 @@
<!-- task=m-agent-message-protocol/01_proto_contract plan=0 tag=API -->
# Code Review Reference - API
> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving.
> Fill implementation-owned sections, then stop with active files in place and report ready for review.
> If implementation is blocked by a user-only decision, user-owned external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. Evidence gaps that a follow-up agent can close by rerunning commands or collecting artifacts are normal follow-up issues, not user-review blockers by themselves.
> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation; record the needed decision in `사용자 리뷰 요청` and stop for code-review.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.
## 개요
date=2026-06-06
task=m-agent-message-protocol/01_proto_contract, plan=0, tag=API
## Roadmap Targets
- Milestone: `agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md`
- Task ids:
- `message-fields`: 각 메시지의 최소 필드와 실패 응답 형식이 정의되어 있다.
- Completion mode: check-on-pass
## 이 파일을 읽는 리뷰 에이전트에게
> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.
각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다.
1. 판정을 append한다.
2. `CODE_REVIEW-cloud-G05.md` -> `code_review_cloud_G05_N.log`, `PLAN-cloud-G05.md` -> `plan_cloud_G05_M.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-agent-message-protocol/01_proto_contract/`로 이동한다. WARN/FAIL이면 user-review gate를 확인한 뒤 다음 active plan/review 파일 또는 `USER_REVIEW.md`를 작성한다. `USER_REVIEW.md`가 사용자 결정으로 완료/PASS 해소되면 code-review가 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log` 작성 후 archive 이동한다.
4. PASS이고 task group이 `m-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.
---
## 구현 항목별 완료 여부
| 항목 | 완료 여부 |
|------|---------|
| [API-1] Proto message fields | [x] |
| [API-2] Dart request/response compatibility | [x] |
## 구현 체크리스트
- [x] `proto/oto/runner.proto`에 공통 실패 응답, run request, cancel, status, self-update 최소 메시지를 추가하고 기존 field number를 보존한다.
- [x] `make proto`로 Go/Dart generated protobuf 파일을 재생성한다.
- [x] Dart JSON helper와 `oto_agent_registration_test.dart`를 새 schema에 맞춰 갱신하되 기존 registration/job report payload를 보존한다.
- [x] `message-fields` 검증을 위해 YAML 파이프라인/Command catalog가 run request 위에서 어떻게 참조되는지 test assertion 또는 proto comment로 남긴다.
- [x] 최종 검증 명령을 실행하고 실제 stdout/stderr를 review stub에 기록한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## 코드리뷰 전용 체크리스트
> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.
- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [x] active `CODE_REVIEW-*-G??.md`를 `code_review_cloud_G05_N.log`로 아카이브한다.
- [x] active `PLAN-*-G??.md`를 `plan_cloud_G05_M.log`로 아카이브한다.
- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다.
- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [ ] PASS이면 active task 디렉터리 `agent-task/m-agent-message-protocol/01_proto_contract/`를 `agent-task/archive/YYYY/MM/m-agent-message-protocol/01_proto_contract/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [ ] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-agent-message-protocol/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [x] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-cloud-G05.md`와 `CODE_REVIEW-cloud-G05.md`를 작성하고 `complete.log`를 작성하지 않는다.
- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다.
- [ ] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다.
## 계획 대비 변경 사항
- 없음. 계획대로 정확히 수행되었다.
## 주요 설계 결정
- `ProtocolError`가 map object 형태로 JSON serialized 되어 응답될 때, Dart client(예: `OtoServerJobClient`, `RegistrationResult`)가 이를 `errorMessage`/`rejectReason`으로 안전하게 fallback 파싱할 수 있도록 `response['error']['message']` 파싱 로직을 추가했다.
- Dart 테스트에서 비동기 HTTP 호출의 예외 검증을 위해 동기 closure 대신 `await expectLater`를 적용하여 비동기 실행 및 예외를 대기하도록 올바르게 구현했다.
## 사용자 리뷰 요청
- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음
## 리뷰어를 위한 체크포인트
- 기존 proto field number가 바뀌지 않았는지 확인한다.
- `ProtocolError` 추가가 기존 `error_message`/`reject_reason` fallback을 깨지 않는지 확인한다.
- `RunRequest`가 YAML 파이프라인과 command catalog 경계를 표현하고 generic shell payload가 아닌지 확인한다.
- generated Go/Dart files가 `make proto` 결과와 일치하는지 확인한다.
## 검증 결과
### API-1 중간 검증
```bash
$ make proto
mkdir -p services/core/proto
mkdir -p services/core/oto
protoc -I proto --go_out=services/core --go_opt=paths=source_relative proto/oto/runner.proto
mkdir -p apps/runner/lib/oto/agent
protoc -I proto --dart_out=apps/runner/lib/oto/agent proto/oto/runner.proto
```
### API-2 중간 검증
```bash
$ cd apps/runner && dart test test/oto_agent_registration_test.dart
00:00 +0: loading test/oto_agent_registration_test.dart
00:00 +0: EdgeEndpoint EdgeEndpoint parses host and port from config edge url
00:00 +1: EdgeEndpoint EdgeEndpoint parses host and port from config edge url
00:00 +1: EdgeRegistrationClient.register ... result and closes the session
00:00 +2: EdgeRegistrationClient.register ... result and closes the session
00:00 +2: ... builds OTO Server registration request from config
...
00:01 +15: All tests passed!
```
### 최종 검증
```bash
$ make proto
mkdir -p services/core/oto
protoc -I proto --go_out=services/core --go_opt=paths=source_relative proto/oto/runner.proto
mkdir -p apps/runner/lib/oto/agent
protoc -I proto --dart_out=apps/runner/lib/oto/agent proto/oto/runner.proto
$ cd apps/runner && dart analyze
Analyzing runner...
No issues found!
$ cd apps/runner && dart test test/oto_agent_registration_test.dart
00:00 +0: loading test/oto_agent_registration_test.dart
00:00 +0: EdgeEndpoint EdgeEndpoint parses host and port from config edge url
...
00:01 +15: All tests passed!
$ cd services/core && go test ./...
? github.com/toki/oto/services/core/cmd/oto-core [no test files]
ok github.com/toki/oto/services/core/internal/cicdstate 0.003s
ok github.com/toki/oto/services/core/internal/httpserver 0.006s
ok github.com/toki/oto/services/core/internal/runnerregistry 0.003s
? github.com/toki/oto/services/core/oto [no test files]
```
---
> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?**
> If anything is blank, go back and fill it in before saving this file.
> Leave review-agent-only sections unchanged.
## 섹션 소유권
| Section | Owner | Note |
|---------|-------|------|
| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute archive/complete steps |
| Roadmap Targets | Fixed at stub creation | Code-review copies it into `complete.log` only on PASS |
| 구현 항목별 완료 여부 | Implementing agent | Check `[ ]` to `[x]` only |
| 구현 체크리스트 | Implementing agent | Preserve item text and order |
| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify |
| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | Replace placeholders with actual notes |
| 사용자 리뷰 요청 | Implementing agent | Keep `상태: 없음` unless a justified blocker exists |
| 리뷰어를 위한 체크포인트 | Fixed at stub creation | Review focus only |
| 검증 결과 | Implementing agent | Paste actual stdout/stderr |
## 코드리뷰 결과
- 종합 판정: FAIL
- 차원별 평가:
- correctness: Pass
- completeness: Fail
- test coverage: Pass
- API contract: Pass
- code quality: Pass
- plan deviation: Fail
- verification trust: Pass
- 발견된 문제:
- Required: `agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md:33`와 `agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md:36`에서 이번 task의 Roadmap Target이 아닌 `message-list`, `domain-boundary`를 직접 완료 처리했고, `agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md:64` 이후에 로드맵 컨텍스트를 추가했다. 이 구현 계획의 수정 파일/체크리스트에는 로드맵 문서 갱신이 포함되어 있지 않고, `m-agent-message-protocol` PASS 후 Roadmap Completion은 runtime/update-roadmap 경로가 처리해야 한다. 해당 로드맵 변경을 이번 구현 diff에서 제거하거나, 사용자 요청에 따른 별도 로드맵 갱신 작업으로 분리해야 한다.
- 다음 단계: FAIL follow-up plan/review를 생성해 계획 밖 로드맵 변경을 정리한 뒤 재리뷰한다.

View file

@ -0,0 +1,173 @@
<!-- task=m-agent-message-protocol/01_proto_contract plan=1 tag=REVIEW_API -->
# Code Review Reference - REVIEW_API
> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving.
> Fill implementation-owned sections, then stop with active files in place and report ready for review.
> If implementation is blocked by a user-only decision, user-owned external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. Evidence gaps that a follow-up agent can close by rerunning commands or collecting artifacts are normal follow-up issues, not user-review blockers by themselves.
> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation; record the needed decision in `사용자 리뷰 요청` and stop for code-review.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.
## 개요
date=2026-06-06
task=m-agent-message-protocol/01_proto_contract, plan=1, tag=REVIEW_API
## Roadmap Targets
- Milestone: `agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md`
- Task ids:
- `message-fields`: 각 메시지의 최소 필드와 실패 응답 형식이 정의되어 있다.
- Completion mode: check-on-pass
## 이 파일을 읽는 리뷰 에이전트에게
> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.
각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다.
1. 판정을 append한다.
2. `CODE_REVIEW-cloud-G05.md` -> `code_review_cloud_G05_N.log`, `PLAN-cloud-G05.md` -> `plan_cloud_G05_M.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-agent-message-protocol/01_proto_contract/`로 이동한다. WARN/FAIL이면 user-review gate를 확인한 뒤 다음 active plan/review 파일 또는 `USER_REVIEW.md`를 작성한다. `USER_REVIEW.md`가 사용자 결정으로 완료/PASS 해소되면 code-review가 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log` 작성 후 archive 이동한다.
4. PASS이고 task group이 `m-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.
---
## 구현 항목별 완료 여부
| 항목 | 완료 여부 |
|------|---------|
| [REVIEW_API-1] 계획 밖 로드맵 변경 정리 | [x] |
## 구현 체크리스트
- [x] `agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md`에서 구현 계획 밖으로 추가된 checklist 완료 표시와 컨텍스트 문단을 제거하고, proto/code/test 변경은 그대로 둔다.
- [x] 최종 검증 명령을 실행하고 실제 stdout/stderr를 review stub에 기록한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## 코드리뷰 전용 체크리스트
> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.
- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [x] active `CODE_REVIEW-*-G??.md`를 `code_review_cloud_G05_N.log`로 아카이브한다.
- [x] active `PLAN-*-G??.md`를 `plan_cloud_G05_M.log`로 아카이브한다.
- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다.
- [x] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [x] PASS이면 active task 디렉터리 `agent-task/m-agent-message-protocol/01_proto_contract/`를 `agent-task/archive/YYYY/MM/m-agent-message-protocol/01_proto_contract/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [x] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [x] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-agent-message-protocol/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-cloud-G05.md`와 `CODE_REVIEW-cloud-G05.md`를 작성하고 `complete.log`를 작성하지 않는다.
- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다.
- [ ] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다.
## 계획 대비 변경 사항
- 없음. 계획대로 정확히 수행되었다.
## 주요 설계 결정
- 구현 계획에 없던 로드맵 파일(`agent-message-protocol.md`)에 대한 수동 변경 내역(체크박스 마킹 및 컨텍스트 문단 추가)을 제거하여, 로드맵 갱신 책임을 런타임/완료 처리 프로세스로 온전히 넘기도록 조치했습니다.
## 사용자 리뷰 요청
- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음
## 리뷰어를 위한 체크포인트
- 로드맵 파일의 계획 밖 diff가 제거되었는지 확인한다.
- proto/code/test 변경이 follow-up에서 불필요하게 수정되지 않았는지 확인한다.
- `message-fields` Roadmap Target을 code-review가 직접 체크하거나 roadmap을 직접 갱신하지 않았는지 확인한다.
## 검증 결과
### REVIEW_API-1 중간 검증
```bash
$ git diff -- agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md
(empty)
```
### 최종 검증
```bash
$ git diff --check
(empty)
$ make proto
mkdir -p services/core/oto
protoc -I proto --go_out=services/core --go_opt=paths=source_relative proto/oto/runner.proto
mkdir -p apps/runner/lib/oto/agent
protoc -I proto --dart_out=apps/runner/lib/oto/agent proto/oto/runner.proto
$ cd apps/runner && dart analyze
Analyzing runner...
No issues found!
$ cd apps/runner && dart test test/oto_agent_migration_plan_test.dart test/oto_agent_bootstrap_script_test.dart test/oto_agent_cli_test.dart test/oto_agent_config_test.dart test/oto_agent_registration_test.dart test/oto_server_connection_smoke_test.dart
00:00 +0: loading test/oto_agent_migration_plan_test.dart
...
00:10 +47: All tests passed!
$ cd services/core && go test ./...
? github.com/toki/oto/services/core/cmd/oto-core [no test files]
ok github.com/toki/oto/services/core/internal/cicdstate (cached)
ok github.com/toki/oto/services/core/internal/httpserver (cached)
ok github.com/toki/oto/services/core/internal/runnerregistry (cached)
? github.com/toki/oto/services/core/oto [no test files]
$ git diff --name-only
apps/runner/lib/oto/agent/edge_registration_client.dart
apps/runner/lib/oto/agent/oto/runner.pb.dart
apps/runner/lib/oto/agent/oto/runner.pbjson.dart
apps/runner/lib/oto/agent/oto_server_job_client.dart
apps/runner/test/oto_agent_registration_test.dart
proto/oto/runner.proto
services/core/oto/runner.pb.go
```
---
> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?**
> If anything is blank, go back and fill it in before saving this file.
> Leave review-agent-only sections unchanged.
## 섹션 소유권
| Section | Owner | Note |
|---------|-------|------|
| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute archive/complete steps |
| Roadmap Targets | Fixed at stub creation | Code-review copies it into `complete.log` only on PASS |
| 구현 항목별 완료 여부 | Implementing agent | Check `[ ]` to `[x]` only |
| 구현 체크리스트 | Implementing agent | Preserve item text and order |
| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify |
| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | Replace placeholders with actual notes |
| 사용자 리뷰 요청 | Implementing agent | Keep `상태: 없음` unless a justified blocker exists |
| 리뷰어를 위한 체크포인트 | Fixed at stub creation | 계획에서 추출한 리뷰 포인트 |
| 검증 결과 | Implementing agent | Paste actual stdout/stderr |
| 코드리뷰 결과 | Review agent | Append only during code review |
## 코드리뷰 결과
- 종합 판정: PASS
- 차원별 평가:
- correctness: Pass
- completeness: Pass
- test coverage: Pass
- API contract: Pass
- code quality: Pass
- plan deviation: Pass
- verification trust: Pass
- 발견된 문제: 없음
- 다음 단계: PASS 완료 처리. `complete.log`를 작성하고 active task 디렉터리를 archive로 이동한다.

View file

@ -0,0 +1,49 @@
# Complete - m-agent-message-protocol/01_proto_contract
## 완료 일시
2026-06-06
## 요약
Proto contract foundation task completed after 2 review loops; final verdict PASS.
## 루프 이력
| Plan | Review | Verdict | 메모 |
|------|--------|---------|------|
| `plan_cloud_G05_0.log` | `code_review_cloud_G05_0.log` | FAIL | Proto/code/test implementation was sound, but planned scope was contaminated by direct roadmap edits. |
| `plan_cloud_G05_1.log` | `code_review_cloud_G05_1.log` | PASS | Out-of-scope roadmap diff was removed; tracked diff now contains only planned proto/code/test files. |
## 구현/정리 내용
- Added OTO runner protocol fields for `ProtocolError`, `RunRequest`, cancel/status/self-update messages, and response-level error objects while preserving existing field numbers.
- Regenerated Go and Dart protobuf outputs from `proto/oto/runner.proto`.
- Updated Dart registration/job clients to keep legacy string error fallback while accepting `error.message` map responses.
- Added Dart tests for the new protocol message fields and JSON fallback parsing.
- Removed implementation-time roadmap edits so milestone completion remains owned by the PASS completion runtime path.
## 최종 검증
- `git diff -- agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md` - PASS; no output.
- `git diff --check` - PASS; no output.
- `make proto` - PASS; Go and Dart protobuf generation completed without additional failures.
- `cd apps/runner && dart analyze` - PASS; `No issues found!`.
- `cd apps/runner && dart test test/oto_agent_migration_plan_test.dart test/oto_agent_bootstrap_script_test.dart test/oto_agent_cli_test.dart test/oto_agent_config_test.dart test/oto_agent_registration_test.dart test/oto_server_connection_smoke_test.dart` - PASS; `All tests passed!`.
- `cd services/core && go test ./...` - PASS; core package tests passed or reported no test files.
- `git diff --name-only` - PASS; tracked diff is limited to the planned proto/code/test files.
## Roadmap Completion
- Milestone: `agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md`
- Completed task ids:
- `message-fields`: PASS; evidence=`agent-task/archive/2026/06/m-agent-message-protocol/01_proto_contract/plan_cloud_G05_1.log`, `agent-task/archive/2026/06/m-agent-message-protocol/01_proto_contract/code_review_cloud_G05_1.log`; verification=`make proto`, `cd apps/runner && dart analyze`, `cd apps/runner && dart test test/oto_agent_migration_plan_test.dart test/oto_agent_bootstrap_script_test.dart test/oto_agent_cli_test.dart test/oto_agent_config_test.dart test/oto_agent_registration_test.dart test/oto_server_connection_smoke_test.dart`, `cd services/core && go test ./...`
- Not completed task ids: 없음
## 잔여 Nit
- 없음
## 후속 작업
- 없음

View file

@ -0,0 +1,245 @@
<!-- task=m-agent-message-protocol/01_proto_contract plan=0 tag=API -->
# Plan - API
## 이 파일을 읽는 구현 에이전트에게
`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채우는 것이 구현의 마지막 필수 단계다. 구현 후 검증을 실행하고 실제 내용과 출력을 리뷰 파일에 남긴 뒤 active 파일을 그대로 둔 채 리뷰 준비를 보고한다. 사용자만 결정할 수 있는 범위 변경, 사용자 소유 외부 환경/secret, 또는 scope conflict가 있으면 리뷰 파일의 `사용자 리뷰 요청`에 근거를 채우고 멈춘다. 구현 중 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 증거 공백은 사용자 리뷰 요청이 아니다.
## 배경
현재 `proto/oto/runner.proto`는 register, heartbeat, job claim, execution report, log append, artifact report를 담고 있지만 run request의 YAML 연결, cancel/status/self-update, 공통 실패 응답 계약이 없다. 마일스톤의 `message-fields` Task는 OTO Server와 runner가 같은 proto 계약으로 병렬 구현을 시작할 수 있어야 하므로 먼저 schema와 생성 코드를 닫는다. 이 작업은 후속 Core 호환성 검증 계획의 선행 작업이다.
## 사용자 리뷰 요청 흐름
구현 중 사용자 결정이 필요한 차단은 active review stub의 `사용자 리뷰 요청` 섹션에 `agent-ops/skills/common/_templates/implementation-user-review-request-section.md` 형식으로 기록한다. 직접 사용자 프롬프트는 금지이며, code-review가 요청의 타당성을 검증하고 실제 `USER_REVIEW.md` 작성을 소유한다.
## Roadmap Targets
- Milestone: `agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md`
- Task ids:
- `message-fields`: 각 메시지의 최소 필드와 실패 응답 형식이 정의되어 있다.
- Completion mode: check-on-pass
## 분석 결과
### 읽은 파일
- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/common/rules-roadmap.md`
- `agent-ops/skills/common/router.md`
- `agent-ops/skills/common/plan/SKILL.md`
- `agent-ops/skills/common/update-roadmap/SKILL.md`
- `agent-ops/skills/common/_templates/implementation-user-review-request-section.md`
- `agent-roadmap/current.md`
- `agent-roadmap/phase/message-based-build-agent/PHASE.md`
- `agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md`
- `agent-test/local/rules.md`
- `agent-test/local/agent-smoke.md`
- `agent-test/local/core-smoke.md`
- `agent-ops/rules/project/domain/agent/rules.md`
- `Makefile`
- `proto/oto/runner.proto`
- `apps/runner/lib/oto/agent/edge_registration_client.dart`
- `apps/runner/lib/oto/agent/oto_server_job_client.dart`
- `apps/runner/lib/oto/agent/agent_config.dart`
- `apps/runner/lib/oto/agent/agent_runner.dart`
- `apps/runner/test/oto_agent_registration_test.dart`
- `apps/runner/test/oto_agent_migration_plan_test.dart`
- `apps/runner/test/oto_server_connection_smoke_test.dart`
- `apps/runner/pubspec.yaml`
- `services/core/go.mod`
- `services/core/internal/runnerregistry/registry.go`
- `services/core/internal/runnerregistry/registry_test.go`
- `services/core/internal/httpserver/server.go`
- `services/core/internal/httpserver/server_test.go`
- `services/core/internal/cicdstate/store.go`
- `services/core/internal/cicdstate/store_test.go`
### 테스트 환경 규칙
- 선택한 test_env: `local`.
- `agent-test/local/rules.md`는 존재하고 읽었다.
- matching profile: agent 경로와 runner protocol 변경이므로 `agent-test/local/agent-smoke.md`를 읽었다. Core smoke는 Go Core fallback 판단을 위해 읽었지만 현재 local rules에는 `services/core/**` 라우팅이 없다.
- 적용 명령: agent profile의 `cd apps/runner && dart analyze`, `cd apps/runner && dart test test/oto_agent_migration_plan_test.dart test/oto_agent_bootstrap_script_test.dart test/oto_agent_cli_test.dart test/oto_agent_config_test.dart test/oto_agent_registration_test.dart test/oto_server_connection_smoke_test.dart`.
- fallback 검증: `Makefile`의 `make proto`, `services/core/go.mod` 기준 `cd services/core && go test ./...`.
- 공백: `proto/oto/**`와 `services/core/**`에 대한 별도 agent-test profile이 없다. 이 plan은 fallback 명령을 명시하고, 후속 `create-test/update-test`가 core/proto smoke profile을 보강할 수 있다.
### 테스트 커버리지 공백
- 새 proto 메시지와 generated code: 기존 테스트는 현재 등록/job report proto만 간접 검증한다. `oto_agent_registration_test.dart`에 새 메시지 생성, JSON helper, 기존 request payload 보존 assertion을 추가한다.
- run request YAML 연결 필드: 기존 테스트 없음. 새 assertion으로 `pipeline_yaml_path` 또는 inline YAML 중 하나가 표현되고 command catalog 경계가 남는지 확인한다.
- cancel/status/self-update 메시지: 기존 테스트 없음. proto class 생성과 기본 필드 round-trip assertion을 추가한다.
- 공통 실패 응답: 기존 response들은 `error_message` 문자열만 본다. 새 `ProtocolError` 필드를 추가하되 기존 문자열 필드를 유지하는 회귀 assertion이 필요하다.
### 심볼 참조
- renamed/removed symbols: none. 기존 proto field number와 Dart/Go generated getter 이름은 보존한다.
- 관련 참조: `RegisterRunnerRequest`는 `proto/oto/runner.proto:16`, `apps/runner/lib/oto/agent/edge_registration_client.dart:242`, `services/core/internal/runnerregistry/registry.go:56`, `services/core/internal/httpserver/server.go:91`에서 사용된다. `JobClaimRequest/Response`는 `proto/oto/runner.proto:57`, `apps/runner/lib/oto/agent/oto_server_job_client.dart:80`, `services/core/internal/httpserver/server.go:720` 이후 runner claim handler에서 사용된다.
### 분할 판단
- split decision policy를 plan 파일 선택 전에 평가했다.
- shared task group: `agent-task/m-agent-message-protocol/`.
- `01_proto_contract`: proto schema, generated Go/Dart code, Dart JSON helper/test에서 최소 메시지 필드를 정의한다. 의존성 없음.
- `02+01_core_compatibility`: registry/Core 호환성 검증과 version/capability 협상 기준을 적용한다. `01_proto_contract`의 `complete.log`가 필요하다.
- API/foundation과 broad call-site rollout이 분리되어 있어 split gate가 적용된다. 이 plan은 foundation only다.
### 범위 결정 근거
- 포함: `proto/oto/runner.proto`, generated `services/core/oto/runner.pb.go`, generated `apps/runner/lib/oto/agent/oto/runner.pb.dart|pbenum.dart|pbjson.dart`, Dart request/response JSON helper와 agent registration test.
- 제외: HTTP endpoint behavior, registry validation policy, job cancellation state transition 구현은 `02+01_core_compatibility`에서 다룬다.
- 제외: 웹 UI, artifact storage 운영 정책, scheduler policy, generic remote shell 기능.
### 빌드 등급
- build lane/grade: `cloud-G05`. 공용 protocol/schema 변경이며 생성 코드와 양쪽 언어 compile을 동시에 확인해야 하지만, 구현 범위는 proto foundation과 bounded tests로 제한된다.
## 구현 체크리스트
- [ ] `proto/oto/runner.proto`에 공통 실패 응답, run request, cancel, status, self-update 최소 메시지를 추가하고 기존 field number를 보존한다.
- [ ] `make proto`로 Go/Dart generated protobuf 파일을 재생성한다.
- [ ] Dart JSON helper와 `oto_agent_registration_test.dart`를 새 schema에 맞춰 갱신하되 기존 registration/job report payload를 보존한다.
- [ ] `message-fields` 검증을 위해 YAML 파이프라인/Command catalog가 run request 위에서 어떻게 참조되는지 test assertion 또는 proto comment로 남긴다.
- [ ] 최종 검증 명령을 실행하고 실제 stdout/stderr를 review stub에 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
### [API-1] Proto message fields
#### 문제
`proto/oto/runner.proto:25` 이후 response들은 `error_message` 또는 `reject_reason` 문자열만 갖고 있어 실패 코드와 세부 정보를 일관되게 표현하지 못한다. `proto/oto/runner.proto:57`의 `JobClaimRequest`는 `job_id`/`execution_id`만 claim하고, Server-owned run request가 YAML 파이프라인과 command catalog를 어떻게 연결하는지 표현하지 못한다. cancel/status/self-update 메시지도 없다.
#### 해결 방법
기존 field number를 바꾸지 않고 새 field를 append한다. 문자열 오류 필드는 backward compatibility로 유지하고, 새 `ProtocolError`를 추가한다.
```proto
// proto/oto/runner.proto:25 before
message JobClaimResponse {
bool accepted = 1;
string error_message = 2;
string job_id = 3;
string execution_id = 4;
string state = 5;
string runner_id = 6;
}
```
```proto
// proto/oto/runner.proto after
message ProtocolError {
string code = 1;
string message = 2;
map<string, string> details = 3;
}
message RunRequest {
string runner_id = 1;
string job_id = 2;
string execution_id = 3;
string pipeline_yaml_path = 4;
string pipeline_yaml = 5;
map<string, string> variables = 6;
repeated string command_types = 7;
}
message JobClaimResponse {
bool accepted = 1;
string error_message = 2;
string job_id = 3;
string execution_id = 4;
string state = 5;
string runner_id = 6;
RunRequest run_request = 7;
ProtocolError error = 8;
}
```
같은 방식으로 `ExecutionReportResponse`, `LogAppendResponse`, `ArtifactReportResponse`, `HeartbeatResponse`, `RegisterRunnerResponse`에 새 `ProtocolError error`를 append한다. `CancelRunRequest/Response`, `RunnerStatusRequest/Response`, `SelfUpdateRequest/Response`는 최소 identity, state/action, error 필드만 정의하고 동작 구현은 후속 plan에 둔다.
#### 수정 파일 및 체크리스트
- [ ] `proto/oto/runner.proto`: 새 message와 response error field 추가.
- [ ] `services/core/oto/runner.pb.go`: `make proto`로 재생성.
- [ ] `apps/runner/lib/oto/agent/oto/runner.pb.dart`: `make proto`로 재생성.
- [ ] `apps/runner/lib/oto/agent/oto/runner.pbenum.dart`: `make proto`로 재생성.
- [ ] `apps/runner/lib/oto/agent/oto/runner.pbjson.dart`: `make proto`로 재생성.
#### 테스트 작성
`apps/runner/test/oto_agent_registration_test.dart`에 proto class 생성/JSON round-trip assertion을 추가한다. 새 test name: `OTO runner protocol exposes run, cancel, status, self-update message fields`. 기존 generated code import를 사용하고, `RunRequest`가 `jobId`, `executionId`, `pipelineYamlPath` 또는 `pipelineYaml`, `commandTypes`를 표현하는지 확인한다.
#### 중간 검증
```bash
make proto
```
### [API-2] Dart request/response compatibility
#### 문제
`apps/runner/lib/oto/agent/edge_registration_client.dart:303`의 registration JSON helper는 기존 protocol/capability/catalog payload만 보낸다. `apps/runner/lib/oto/agent/oto_server_job_client.dart:219` 이후 helper들은 job/report/log/artifact request를 기존 필드만으로 만들며 새 run request/error field와의 backward compatibility를 검증하지 않는다.
#### 해결 방법
기존 payload key를 유지한다. 새 proto 필드가 response에 들어와도 기존 result parser가 깨지지 않게 `error_message` fallback을 유지하고, 필요하면 `ProtocolError` helper를 추가한다.
```dart
// apps/runner/lib/oto/agent/oto_server_job_client.dart:24 before
errorMessage: _emptyToNull(
(json['error_message'] ?? json['errorMessage'] ?? '').toString(),
),
```
```dart
// after
errorMessage: _emptyToNull(
(json['error_message'] ??
json['errorMessage'] ??
(json['error'] is Map ? json['error']['message'] : '') ??
'')
.toString(),
),
```
#### 수정 파일 및 체크리스트
- [ ] `apps/runner/lib/oto/agent/oto_server_job_client.dart`: 새 error object가 와도 기존 `errorMessage`가 채워지게 한다.
- [ ] `apps/runner/lib/oto/agent/edge_registration_client.dart`: registration payload 기존 key와 capability/catalog 출력이 변하지 않는지 유지한다.
- [ ] `apps/runner/test/oto_agent_registration_test.dart`: 기존 registration/job report payload assertion과 새 response error object fallback assertion을 함께 둔다.
#### 테스트 작성
`apps/runner/test/oto_agent_registration_test.dart`의 `job client claims jobs and reports build results` group에 error object fallback 케이스를 추가한다. 정상 payload assertion은 유지한다.
#### 중간 검증
```bash
cd apps/runner && dart test test/oto_agent_registration_test.dart
```
## 수정 파일 요약
| 파일 | 항목 |
|------|------|
| `proto/oto/runner.proto` | API-1 |
| `services/core/oto/runner.pb.go` | API-1 |
| `apps/runner/lib/oto/agent/oto/runner.pb.dart` | API-1 |
| `apps/runner/lib/oto/agent/oto/runner.pbenum.dart` | API-1 |
| `apps/runner/lib/oto/agent/oto/runner.pbjson.dart` | API-1 |
| `apps/runner/lib/oto/agent/oto_server_job_client.dart` | API-2 |
| `apps/runner/lib/oto/agent/edge_registration_client.dart` | API-2 |
| `apps/runner/test/oto_agent_registration_test.dart` | API-1, API-2 |
## 최종 검증
```bash
make proto
cd apps/runner && dart analyze
cd apps/runner && dart test test/oto_agent_registration_test.dart
cd services/core && go test ./...
```
기대 결과: proto generation이 완료되고 Dart analyzer issue가 없으며 지정 Dart test와 Go test가 통과한다. 모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.

View file

@ -0,0 +1,96 @@
<!-- task=m-agent-message-protocol/01_proto_contract plan=1 tag=REVIEW_API -->
# Plan - REVIEW_API
## 이 파일을 읽는 구현 에이전트에게
`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채우는 것이 구현의 마지막 필수 단계다. 구현 후 검증을 실행하고 실제 내용과 출력을 리뷰 파일에 남긴 뒤 active 파일을 그대로 둔 채 리뷰 준비를 보고한다. 사용자만 결정할 수 있는 범위 변경, 사용자 소유 외부 환경/secret, 또는 scope conflict가 있으면 리뷰 파일의 `사용자 리뷰 요청`에 근거를 채우고 멈춘다. 구현 중 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 증거 공백은 사용자 리뷰 요청이 아니다.
## 배경
이 follow-up은 `code_review_cloud_G05_0.log`의 FAIL 판정을 해결한다. Proto schema, generated Go/Dart code, Dart JSON fallback, 테스트 구현은 검증 명령에서 통과했다. 남은 Required 이슈는 구현 계획에 없던 로드맵 문서 변경이 같은 diff에 섞인 점이다.
## 사용자 리뷰 요청 흐름
구현 중 사용자 결정이 필요한 차단은 active review stub의 `사용자 리뷰 요청` 섹션에 `agent-ops/skills/common/_templates/implementation-user-review-request-section.md` 형식으로 기록한다. 직접 사용자 프롬프트는 금지이며, code-review가 요청의 타당성을 검증하고 실제 `USER_REVIEW.md` 작성을 소유한다.
## Roadmap Targets
- Milestone: `agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md`
- Task ids:
- `message-fields`: 각 메시지의 최소 필드와 실패 응답 형식이 정의되어 있다.
- Completion mode: check-on-pass
## 분석 결과
### 선행 리뷰
- Archived plan: `agent-task/m-agent-message-protocol/01_proto_contract/plan_cloud_G05_0.log`
- Archived review: `agent-task/m-agent-message-protocol/01_proto_contract/code_review_cloud_G05_0.log`
- Verdict: FAIL
- Required issue: 계획에 없던 `agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md` 변경이 포함되어 있고, `m-*` task의 roadmap completion은 PASS 이후 runtime/update-roadmap 경로가 처리해야 한다.
### 범위 결정 근거
- 포함: `agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md`에서 이번 구현 diff가 추가한 계획 밖 변경 제거.
- 제외: `proto/oto/runner.proto`, generated protobuf, Dart client, Dart tests, Go generated code의 기능 변경. 선행 리뷰에서 해당 변경은 통과했고 이번 follow-up은 그것들을 수정하지 않는다.
- 제외: 로드맵 Task 완료 처리 또는 새 로드맵 컨텍스트 작성. 필요하면 PASS 완료 이벤트 이후 runtime/update-roadmap 경로가 처리한다.
### 빌드 등급
- build lane/grade: `cloud-G05`. 기존 protocol/schema task의 후속 루프이며, 변경 범위는 좁지만 같은 active task에서 완료 판정을 이어간다.
## 구현 체크리스트
- [ ] `agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md`에서 구현 계획 밖으로 추가된 checklist 완료 표시와 컨텍스트 문단을 제거하고, proto/code/test 변경은 그대로 둔다.
- [ ] 최종 검증 명령을 실행하고 실제 stdout/stderr를 review stub에 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
### [REVIEW_API-1] 계획 밖 로드맵 변경 정리
#### 문제
`code_review_cloud_G05_0.log`는 이번 구현이 `agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md`의 `message-list`, `domain-boundary`를 직접 완료 처리하고, 새 로드맵 컨텍스트 문단을 추가한 점을 Required 이슈로 기록했다. 이 task의 목표는 `message-fields` proto 계약 구현이며, 로드맵 완료 갱신은 PASS 이후 runtime/update-roadmap 경로가 처리해야 한다.
#### 해결 방법
`agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md`에서 아래 구현 산출물만 제거한다.
- `message-list`, `domain-boundary` checklist를 구현 전 상태인 unchecked로 되돌린다.
- `작업 컨텍스트`에 추가된 `기본 메시지 방향성(2026-06-06)`, `제품 경계(2026-06-06)`, `기존 CLI 경계(2026-06-06)` 문단을 제거한다.
- `message-fields` Roadmap Target 자체는 이번 code-review PASS 이후 completion event가 처리할 대상이므로 수동으로 체크하지 않는다.
#### 수정 파일 및 체크리스트
- [ ] `agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md`: 계획 밖 로드맵 변경 제거.
#### 테스트 작성
테스트 추가 없음. production code 변경이 아니라 review artifact 정리다.
#### 중간 검증
```bash
git diff -- agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md
```
기대 결과: 이 follow-up 이후 해당 로드맵 파일 diff가 비어 있거나, 사용자 소유 변경이 있다면 이번 구현 산출물과 분리되어 review stub에 사유가 기록되어 있다.
## 수정 파일 요약
| 파일 | 항목 |
|------|------|
| `agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md` | REVIEW_API-1 |
## 최종 검증
```bash
git diff --check
make proto
cd apps/runner && dart analyze
cd apps/runner && dart test test/oto_agent_migration_plan_test.dart test/oto_agent_bootstrap_script_test.dart test/oto_agent_cli_test.dart test/oto_agent_config_test.dart test/oto_agent_registration_test.dart test/oto_server_connection_smoke_test.dart
cd services/core && go test ./...
git diff --name-only
```
기대 결과: whitespace error가 없고, proto generation이 추가 diff를 만들지 않으며, Dart analyzer/test와 Go test가 통과한다. `git diff --name-only`의 tracked diff에는 원래 계획된 proto/code/test 파일만 남고, 로드맵 파일은 남지 않는다. 모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다.

View file

@ -0,0 +1,161 @@
<!-- task=m-agent-message-protocol/02+01_core_compatibility plan=0 tag=API -->
# Code Review Reference - API
> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.**
> The task is NOT complete until every implementation-owned section below is filled in.
> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving.
> Fill implementation-owned sections, then stop with active files in place and report ready for review.
> If implementation is blocked by a user-only decision, user-owned external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. Evidence gaps that a follow-up agent can close by rerunning commands or collecting artifacts are normal follow-up issues, not user-review blockers by themselves.
> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation; record the needed decision in `사용자 리뷰 요청` and stop for code-review.
> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume.
> Follow the ownership table at the bottom of this file for which sections you own.
## 개요
date=2026-06-06
task=m-agent-message-protocol/02+01_core_compatibility, plan=0, tag=API
## Roadmap Targets
- Milestone: `agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md`
- Task ids:
- `version-capability`: 프로토콜 버전과 capability 협상 기준이 정의되어 있다.
- Completion mode: check-on-pass
## 이 파일을 읽는 리뷰 에이전트에게
> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다.
각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요.
리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다.
1. 판정을 append한다.
2. `CODE_REVIEW-cloud-G06.md` -> `code_review_cloud_G06_N.log`, `PLAN-cloud-G06.md` -> `plan_cloud_G06_M.log`로 아카이브한다.
3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-agent-message-protocol/02+01_core_compatibility/`로 이동한다. WARN/FAIL이면 user-review gate를 확인한 뒤 다음 active plan/review 파일 또는 `USER_REVIEW.md`를 작성한다. `USER_REVIEW.md`가 사용자 결정으로 완료/PASS 해소되면 code-review가 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log` 작성 후 archive 이동한다.
4. PASS이고 task group이 `m-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다.
5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다.
---
## 구현 항목별 완료 여부
| 항목 | 완료 여부 |
|------|---------|
| [API-1] Core registry compatibility policy | [ ] |
| [API-2] HTTP and Dart registration contract | [ ] |
## 구현 체크리스트
- [ ] `agent-task/m-agent-message-protocol/01_proto_contract/complete.log` 또는 matching archive complete.log가 있는지 확인하고, 없으면 구현하지 않고 review stub의 사용자 리뷰 요청이 아니라 dependency 대기 상태로 기록한다.
- [ ] Core registry에 supported protocol/capability 정책을 추가하고 reject reason과 structured error를 함께 채운다.
- [ ] HTTP registration handler와 tests가 새 reject response를 JSON으로 보존하는지 확인한다.
- [ ] Dart runner registration constants와 JSON payload tests를 Core policy와 맞춘다.
- [ ] 최종 검증 명령을 실행하고 실제 stdout/stderr를 review stub에 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## 코드리뷰 전용 체크리스트
> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다.
- [ ] `코드리뷰 결과``PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
- [ ] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다.
- [ ] active `CODE_REVIEW-*-G??.md``code_review_cloud_G06_N.log`로 아카이브한다.
- [ ] active `PLAN-*-G??.md``plan_cloud_G06_M.log`로 아카이브한다.
- [ ] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md``agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다.
- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다.
- [ ] PASS이면 active task 디렉터리 `agent-task/m-agent-message-protocol/02+01_core_compatibility/``agent-task/archive/YYYY/MM/m-agent-message-protocol/02+01_core_compatibility/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다.
- [ ] PASS이고 task group이 `m-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다.
- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-agent-message-protocol/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다.
- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-cloud-G06.md``CODE_REVIEW-cloud-G06.md`를 작성하고 `complete.log`를 작성하지 않는다.
- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다.
- [ ] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다.
## 계획 대비 변경 사항
_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._
## 주요 설계 결정
_구현 에이전트가 주요 설계 결정 사항을 기록한다._
## 사용자 리뷰 요청
_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._
- 상태: 없음
- 사유 유형: 없음
- 결정 필요: 없음
- 차단 근거: 없음
- 실행한 검증/명령: 없음
- 자동 후속 불가 이유: 없음
- 재개 조건: 없음
## 리뷰어를 위한 체크포인트
- `01_proto_contract``complete.log`가 실제로 존재하고 predecessor로 인용되었는지 확인한다.
- unsupported protocol/capability가 accepted=false로 거절되고 기존 accepted path가 유지되는지 확인한다.
- Dart runner constants와 Core policy가 drift 없이 같은 값을 쓰는지 확인한다.
- `remote-run-lifecycle` 범위인 cancel/status/self-update 동작 구현이 이 plan에 섞이지 않았는지 확인한다.
## 검증 결과
_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._
필수 규칙:
- 검증 명령은 고정된 계약이다. 임의로 대체하지 않는다.
- 대체가 필요하면 `계획 대비 변경 사항`에 이유와 대체 명령을 기록한다.
- `검증 결과`에는 실제 stdout/stderr를 붙여 넣는다.
- 사용자 리뷰 요청으로 명령을 끝까지 실행하지 못했다면 `사용자 리뷰 요청`에 실행한 명령, 실제 출력, 미실행 명령의 사유를 기록한다.
- mobile/UI hang, timeout, 또는 2분 무진행은 blind retry를 중단하고 focused rerun 명령과 screenshot/window/UI-tree evidence path를 남기며, 불가능하면 정확한 사유를 남긴다.
### API-1 중간 검증
```bash
$ cd services/core && go test ./internal/runnerregistry
(output)
```
### API-2 중간 검증
```bash
$ cd services/core && go test ./internal/httpserver ./internal/runnerregistry
(output)
$ cd apps/runner && dart test test/oto_agent_registration_test.dart
(output)
```
### 최종 검증
```bash
$ test -f agent-task/m-agent-message-protocol/01_proto_contract/complete.log || find agent-task/archive -path '*/m-agent-message-protocol/01_proto_contract/complete.log' -print -quit | grep -q .
(output)
$ cd services/core && go test ./...
(output)
$ cd apps/runner && dart analyze
(output)
$ cd apps/runner && dart test test/oto_agent_migration_plan_test.dart test/oto_agent_bootstrap_script_test.dart test/oto_agent_cli_test.dart test/oto_agent_config_test.dart test/oto_agent_registration_test.dart test/oto_server_connection_smoke_test.dart
(output)
```
---
> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?**
> If anything is blank, go back and fill it in before saving this file.
> Leave review-agent-only sections unchanged.
## 섹션 소유권
| Section | Owner | Note |
|---------|-------|------|
| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute archive/complete steps |
| Roadmap Targets | Fixed at stub creation | Code-review copies it into `complete.log` only on PASS |
| 구현 항목별 완료 여부 | Implementing agent | Check `[ ]` to `[x]` only |
| 구현 체크리스트 | Implementing agent | Preserve item text and order |
| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify |
| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | Replace placeholders with actual notes |
| 사용자 리뷰 요청 | Implementing agent | Keep `상태: 없음` unless a justified blocker exists |
| 리뷰어를 위한 체크포인트 | Fixed at stub creation | Review focus only |
| 검증 결과 | Implementing agent | Paste actual stdout/stderr |

View file

@ -0,0 +1,229 @@
<!-- task=m-agent-message-protocol/02+01_core_compatibility plan=0 tag=API -->
# Plan - API
## 이 파일을 읽는 구현 에이전트에게
`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채우는 것이 구현의 마지막 필수 단계다. 구현 후 검증을 실행하고 실제 내용과 출력을 리뷰 파일에 남긴 뒤 active 파일을 그대로 둔 채 리뷰 준비를 보고한다. 사용자만 결정할 수 있는 범위 변경, 사용자 소유 외부 환경/secret, 또는 scope conflict가 있으면 리뷰 파일의 `사용자 리뷰 요청`에 근거를 채우고 멈춘다. 구현 중 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 증거 공백은 사용자 리뷰 요청이 아니다.
## 배경
`01_proto_contract`가 runner protocol schema와 공통 실패 응답을 정의한 뒤, Core registry와 Dart runner client가 같은 version/capability 협상 기준을 적용해야 한다. 현재 Core는 protocol version이 비어 있지 않은지만 확인하고 capability는 optional로 저장한다. 이 작업은 registration acceptance boundary를 명확히 하면서 기존 runner registration, heartbeat, job report smoke를 유지한다.
## 사용자 리뷰 요청 흐름
구현 중 사용자 결정이 필요한 차단은 active review stub의 `사용자 리뷰 요청` 섹션에 `agent-ops/skills/common/_templates/implementation-user-review-request-section.md` 형식으로 기록한다. 직접 사용자 프롬프트는 금지이며, code-review가 요청의 타당성을 검증하고 실제 `USER_REVIEW.md` 작성을 소유한다.
## Roadmap Targets
- Milestone: `agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md`
- Task ids:
- `version-capability`: 프로토콜 버전과 capability 협상 기준이 정의되어 있다.
- Completion mode: check-on-pass
## 분석 결과
### 읽은 파일
- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/common/rules-roadmap.md`
- `agent-ops/skills/common/router.md`
- `agent-ops/skills/common/plan/SKILL.md`
- `agent-ops/skills/common/update-roadmap/SKILL.md`
- `agent-ops/skills/common/_templates/implementation-user-review-request-section.md`
- `agent-roadmap/current.md`
- `agent-roadmap/phase/message-based-build-agent/PHASE.md`
- `agent-roadmap/phase/message-based-build-agent/milestones/agent-message-protocol.md`
- `agent-test/local/rules.md`
- `agent-test/local/agent-smoke.md`
- `agent-test/local/core-smoke.md`
- `agent-ops/rules/project/domain/agent/rules.md`
- `Makefile`
- `proto/oto/runner.proto`
- `apps/runner/lib/oto/agent/edge_registration_client.dart`
- `apps/runner/lib/oto/agent/oto_server_job_client.dart`
- `apps/runner/lib/oto/agent/agent_config.dart`
- `apps/runner/lib/oto/agent/agent_runner.dart`
- `apps/runner/test/oto_agent_registration_test.dart`
- `apps/runner/test/oto_agent_migration_plan_test.dart`
- `apps/runner/test/oto_server_connection_smoke_test.dart`
- `apps/runner/pubspec.yaml`
- `services/core/go.mod`
- `services/core/internal/runnerregistry/registry.go`
- `services/core/internal/runnerregistry/registry_test.go`
- `services/core/internal/httpserver/server.go`
- `services/core/internal/httpserver/server_test.go`
- `services/core/internal/cicdstate/store.go`
- `services/core/internal/cicdstate/store_test.go`
### 테스트 환경 규칙
- 선택한 test_env: `local`.
- `agent-test/local/rules.md`는 존재하고 읽었다.
- matching profile: agent 도메인 변경이므로 `agent-test/local/agent-smoke.md`를 적용한다.
- 적용 명령: `cd apps/runner && dart analyze`, `cd apps/runner && dart test test/oto_agent_migration_plan_test.dart test/oto_agent_bootstrap_script_test.dart test/oto_agent_cli_test.dart test/oto_agent_config_test.dart test/oto_agent_registration_test.dart test/oto_server_connection_smoke_test.dart`.
- fallback 검증: `services/core/**` 라우팅이 없으므로 `Makefile``services/core/go.mod` 기준 `cd services/core && go test ./...`를 사용한다.
- 공백: local test rules에는 Core service profile이 아직 없다. 이 plan은 fallback을 명시하고 core/proto test profile 보강은 별도 test-rule maintenance 후보로 남긴다.
### 테스트 커버리지 공백
- unsupported protocol rejection: 기존 `registry_test.go`는 missing protocol만 검증한다. unsupported version과 reject code/message test를 추가한다.
- missing/wrong capability rejection: 기존 registry는 capability optional이라 테스트가 없다. name/version/command catalog boundary test를 추가한다.
- HTTP registration response: `server_test.go:99`는 accept path와 missing token만 본다. unsupported protocol/capability JSON response와 기존 200 response shape를 검증한다.
- Dart runner constants: `oto_agent_registration_test.dart:97`은 request 구성만 검증한다. Core가 요구하는 exact constants와 response error fallback test를 추가한다.
### 심볼 참조
- renamed/removed symbols: none.
- `otoRunnerProtocolVersion`, `otoRunnerCapabilityName`, `otoRunnerCapabilityVersion``apps/runner/lib/oto/agent/edge_registration_client.dart:14`에서 정의되고 `apps/runner/test/oto_agent_registration_test.dart:108`에서 검증된다.
- Core registry registration path는 `services/core/internal/runnerregistry/registry.go:56`에서 시작한다. HTTP handler는 `services/core/internal/httpserver/server.go:91`에서 registry response를 그대로 JSON으로 쓴다.
### 분할 판단
- split decision policy를 plan 파일 선택 전에 평가했다.
- shared task group: `agent-task/m-agent-message-protocol/`.
- predecessor `01`: `agent-task/m-agent-message-protocol/01_proto_contract/complete.log` 필요. 작성 시점에는 아직 active predecessor plan만 있고 `complete.log`는 없다.
- current subtask: `02+01_core_compatibility`, `01_proto_contract` 완료 후 구현해야 한다.
- 이 plan은 schema가 확정된 뒤 Core registry, HTTP response, Dart runner request constants를 맞추는 rollout 단계다.
### 범위 결정 근거
- 포함: Core registry acceptance policy, HTTP register response, Dart runner registration constants/tests, Go/Dart smoke tests.
- 제외: run execution lifecycle, cancel/status/self-update endpoint behavior, artifact storage policy는 후속 `remote-run-lifecycle` 마일스톤 범위다.
- 제외: protocol field number 변경이나 generated protobuf 직접 수동 수정은 `01_proto_contract` 범위다.
### 빌드 등급
- build lane/grade: `cloud-G06`. protocol/capability 협상은 cross-language contract와 server acceptance behavior를 바꾸므로 schema predecessor 완료 확인과 Go/Dart smoke evidence가 필요하다.
## 구현 체크리스트
- [ ] `agent-task/m-agent-message-protocol/01_proto_contract/complete.log` 또는 matching archive complete.log가 있는지 확인하고, 없으면 구현하지 않고 review stub의 사용자 리뷰 요청이 아니라 dependency 대기 상태로 기록한다.
- [ ] Core registry에 supported protocol/capability 정책을 추가하고 reject reason과 structured error를 함께 채운다.
- [ ] HTTP registration handler와 tests가 새 reject response를 JSON으로 보존하는지 확인한다.
- [ ] Dart runner registration constants와 JSON payload tests를 Core policy와 맞춘다.
- [ ] 최종 검증 명령을 실행하고 실제 stdout/stderr를 review stub에 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
## 의존 관계 및 구현 순서
이 task directory 이름은 `02+01_core_compatibility`다. runtime dependency source of truth는 predecessor index `01`이며, `agent-task/m-agent-message-protocol/01_proto_contract/complete.log` 또는 `agent-task/archive/*/*/m-agent-message-protocol/01_proto_contract/complete.log`가 있어야 구현을 시작한다. 작성 시점에는 predecessor complete evidence가 없다.
### [API-1] Core registry compatibility policy
#### 문제
`services/core/internal/runnerregistry/registry.go:61`은 enrollment token, runner id, protocol version 공백만 검증한다. `services/core/internal/runnerregistry/registry.go:82`는 capability가 있으면 저장하지만 없거나 다른 capability여도 registration을 accept한다. 이 상태에서는 runner와 server가 같은 protocol/capability 기준으로 병렬 구현을 시작했다는 증거가 부족하다.
#### 해결 방법
새 helper를 registry 내부에 둔다. 새 dependency를 추가하지 않고 stdlib 문자열 처리로 exact protocol과 capability name, compatible capability major version을 판정한다.
```go
// services/core/internal/runnerregistry/registry.go:61 before
protocolVersion := strings.TrimSpace(req.GetProtocolVersion())
if token == "" {
return rejected("missing enrollment token")
}
```
```go
// after
protocolVersion := strings.TrimSpace(req.GetProtocolVersion())
if token == "" {
return rejected("missing enrollment token")
}
if err := validateProtocolCompatibility(protocolVersion, req.GetCapability()); err != nil {
return rejectedWithCode("incompatible_runner", err.Error())
}
```
Policy:
- supported protocol: `oto.runner.v1`.
- required capability name: `oto-runner`.
- capability version: same major version as Core supported runner capability; reject empty or incompatible major.
- command catalog may be empty for bootstrap smoke but, when present, it remains the command extension boundary.
#### 수정 파일 및 체크리스트
- [ ] `services/core/internal/runnerregistry/registry.go`: constants and validation helper 추가.
- [ ] `services/core/internal/runnerregistry/registry_test.go`: unsupported protocol, missing capability, wrong capability, compatible capability tests 추가.
- [ ] `services/core/oto/runner.pb.go`: predecessor generated code와 compile 호환 확인만 한다.
#### 테스트 작성
`services/core/internal/runnerregistry/registry_test.go`에 table-driven rejection tests를 추가한다. 기존 `TestRegistryRejectsIncompleteRegistration`과 합치거나 새 `TestRegistryRejectsIncompatibleRunnerContract`로 분리한다.
#### 중간 검증
```bash
cd services/core && go test ./internal/runnerregistry
```
### [API-2] HTTP and Dart registration contract
#### 문제
`services/core/internal/httpserver/server.go:91`의 register handler는 registry response를 그대로 `200`으로 반환한다. `apps/runner/lib/oto/agent/edge_registration_client.dart:14`의 Dart constants가 Core policy와 같은 값이라는 검증은 request construction 수준에 머문다. `apps/runner/test/oto_agent_registration_test.dart:158`은 protocol/capability payload 일부만 확인한다.
#### 해결 방법
Core reject response는 기존 `accepted=false` shape를 유지하고, `reject_reason`과 predecessor schema의 `error` object를 함께 채운다. Dart request test는 protocol/capability version까지 exact match를 검증하고, rejected response parser는 `reject_reason` fallback을 유지한다.
```dart
// apps/runner/lib/oto/agent/edge_registration_client.dart:14 before
const otoRunnerProtocolVersion = 'oto.runner.v1';
const otoRunnerCapabilityName = 'oto-runner';
const otoRunnerCapabilityVersion = '1.0.0';
```
```dart
// after
const otoRunnerProtocolVersion = 'oto.runner.v1';
const otoRunnerCapabilityName = 'oto-runner';
const otoRunnerCapabilityVersion = '1.0.0';
```
상수 값은 바꾸지 않는다. 테스트에서 Core policy와 같은 exact values를 검증한다.
#### 수정 파일 및 체크리스트
- [ ] `services/core/internal/httpserver/server.go`: register reject response가 structured error를 보존하는지 확인하고 필요한 mapping을 추가한다.
- [ ] `services/core/internal/httpserver/server_test.go`: unsupported protocol/capability JSON response test 추가.
- [ ] `apps/runner/lib/oto/agent/edge_registration_client.dart`: constants 유지 또는 helper 추가.
- [ ] `apps/runner/test/oto_agent_registration_test.dart`: protocol/capability version payload와 rejected response parsing assertion 추가.
- [ ] `apps/runner/test/oto_server_connection_smoke_test.dart`: 기존 accepted smoke가 계속 통과하는지 확인한다.
#### 테스트 작성
Go: `TestHandleRunnerRegisterRejectsIncompatibleProtocol``TestHandleRunnerRegisterRejectsIncompatibleCapability` 추가. Dart: existing `builds OTO Server registration request from config``posts registration request` assertion에 capability version을 포함하고 rejected response parser test를 추가한다.
#### 중간 검증
```bash
cd services/core && go test ./internal/httpserver ./internal/runnerregistry
cd apps/runner && dart test test/oto_agent_registration_test.dart
```
## 수정 파일 요약
| 파일 | 항목 |
|------|------|
| `services/core/internal/runnerregistry/registry.go` | API-1 |
| `services/core/internal/runnerregistry/registry_test.go` | API-1 |
| `services/core/internal/httpserver/server.go` | API-2 |
| `services/core/internal/httpserver/server_test.go` | API-2 |
| `apps/runner/lib/oto/agent/edge_registration_client.dart` | API-2 |
| `apps/runner/test/oto_agent_registration_test.dart` | API-2 |
| `apps/runner/test/oto_server_connection_smoke_test.dart` | API-2 검증 |
## 최종 검증
```bash
test -f agent-task/m-agent-message-protocol/01_proto_contract/complete.log || find agent-task/archive -path '*/m-agent-message-protocol/01_proto_contract/complete.log' -print -quit | grep -q .
cd services/core && go test ./...
cd apps/runner && dart analyze
cd apps/runner && dart test test/oto_agent_migration_plan_test.dart test/oto_agent_bootstrap_script_test.dart test/oto_agent_cli_test.dart test/oto_agent_config_test.dart test/oto_agent_registration_test.dart test/oto_server_connection_smoke_test.dart
```
기대 결과: predecessor complete evidence가 존재하고, Go Core 전체 테스트와 agent local smoke baseline이 통과한다. 모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.

View file

@ -99,7 +99,10 @@ class RegistrationResult {
oto.RegisterRunnerResponse response,
) {
if (!response.accepted) {
return RegistrationResult.rejected(response.rejectReason);
final reason = response.rejectReason.isNotEmpty
? response.rejectReason
: (response.hasError() ? response.error.message : 'rejected');
return RegistrationResult.rejected(reason);
}
return RegistrationResult.accepted(
@ -112,8 +115,13 @@ class RegistrationResult {
factory RegistrationResult.fromOtoJson(Map<String, dynamic> json) {
final accepted = json['accepted'] == true;
if (!accepted) {
final err = json['error'];
final errMessageFromObj = (err is Map) ? err['message'] : null;
return RegistrationResult.rejected(
(json['reject_reason'] ?? json['rejectReason'] ?? 'rejected')
(json['reject_reason'] ??
json['rejectReason'] ??
errMessageFromObj ??
'rejected')
.toString(),
);
}

View file

@ -262,12 +262,14 @@ class RegisterRunnerResponse extends $pb.GeneratedMessage {
$core.String? rejectReason,
$core.String? runnerId,
$core.String? alias,
ProtocolError? error,
}) {
final result = create();
if (accepted != null) result.accepted = accepted;
if (rejectReason != null) result.rejectReason = rejectReason;
if (runnerId != null) result.runnerId = runnerId;
if (alias != null) result.alias = alias;
if (error != null) result.error = error;
return result;
}
@ -288,6 +290,8 @@ class RegisterRunnerResponse extends $pb.GeneratedMessage {
..aOS(2, _omitFieldNames ? '' : 'rejectReason')
..aOS(3, _omitFieldNames ? '' : 'runnerId')
..aOS(4, _omitFieldNames ? '' : 'alias')
..aOM<ProtocolError>(5, _omitFieldNames ? '' : 'error',
subBuilder: ProtocolError.create)
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
@ -345,6 +349,17 @@ class RegisterRunnerResponse extends $pb.GeneratedMessage {
$core.bool hasAlias() => $_has(3);
@$pb.TagNumber(4)
void clearAlias() => $_clearField(4);
@$pb.TagNumber(5)
ProtocolError get error => $_getN(4);
@$pb.TagNumber(5)
set error(ProtocolError value) => $_setField(5, value);
@$pb.TagNumber(5)
$core.bool hasError() => $_has(4);
@$pb.TagNumber(5)
void clearError() => $_clearField(5);
@$pb.TagNumber(5)
ProtocolError ensureError() => $_ensure(4);
}
class HeartbeatRequest extends $pb.GeneratedMessage {
@ -418,10 +433,12 @@ class HeartbeatResponse extends $pb.GeneratedMessage {
factory HeartbeatResponse({
$core.bool? success,
$core.String? errorMessage,
ProtocolError? error,
}) {
final result = create();
if (success != null) result.success = success;
if (errorMessage != null) result.errorMessage = errorMessage;
if (error != null) result.error = error;
return result;
}
@ -440,6 +457,8 @@ class HeartbeatResponse extends $pb.GeneratedMessage {
createEmptyInstance: create)
..aOB(1, _omitFieldNames ? '' : 'success')
..aOS(2, _omitFieldNames ? '' : 'errorMessage')
..aOM<ProtocolError>(3, _omitFieldNames ? '' : 'error',
subBuilder: ProtocolError.create)
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
@ -478,6 +497,17 @@ class HeartbeatResponse extends $pb.GeneratedMessage {
$core.bool hasErrorMessage() => $_has(1);
@$pb.TagNumber(2)
void clearErrorMessage() => $_clearField(2);
@$pb.TagNumber(3)
ProtocolError get error => $_getN(2);
@$pb.TagNumber(3)
set error(ProtocolError value) => $_setField(3, value);
@$pb.TagNumber(3)
$core.bool hasError() => $_has(2);
@$pb.TagNumber(3)
void clearError() => $_clearField(3);
@$pb.TagNumber(3)
ProtocolError ensureError() => $_ensure(2);
}
class BootstrapCommandRequest extends $pb.GeneratedMessage {
@ -688,6 +718,8 @@ class JobClaimResponse extends $pb.GeneratedMessage {
$core.String? executionId,
$core.String? state,
$core.String? runnerId,
RunRequest? runRequest,
ProtocolError? error,
}) {
final result = create();
if (accepted != null) result.accepted = accepted;
@ -696,6 +728,8 @@ class JobClaimResponse extends $pb.GeneratedMessage {
if (executionId != null) result.executionId = executionId;
if (state != null) result.state = state;
if (runnerId != null) result.runnerId = runnerId;
if (runRequest != null) result.runRequest = runRequest;
if (error != null) result.error = error;
return result;
}
@ -718,6 +752,10 @@ class JobClaimResponse extends $pb.GeneratedMessage {
..aOS(4, _omitFieldNames ? '' : 'executionId')
..aOS(5, _omitFieldNames ? '' : 'state')
..aOS(6, _omitFieldNames ? '' : 'runnerId')
..aOM<RunRequest>(7, _omitFieldNames ? '' : 'runRequest',
subBuilder: RunRequest.create)
..aOM<ProtocolError>(8, _omitFieldNames ? '' : 'error',
subBuilder: ProtocolError.create)
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
@ -792,6 +830,28 @@ class JobClaimResponse extends $pb.GeneratedMessage {
$core.bool hasRunnerId() => $_has(5);
@$pb.TagNumber(6)
void clearRunnerId() => $_clearField(6);
@$pb.TagNumber(7)
RunRequest get runRequest => $_getN(6);
@$pb.TagNumber(7)
set runRequest(RunRequest value) => $_setField(7, value);
@$pb.TagNumber(7)
$core.bool hasRunRequest() => $_has(6);
@$pb.TagNumber(7)
void clearRunRequest() => $_clearField(7);
@$pb.TagNumber(7)
RunRequest ensureRunRequest() => $_ensure(6);
@$pb.TagNumber(8)
ProtocolError get error => $_getN(7);
@$pb.TagNumber(8)
set error(ProtocolError value) => $_setField(8, value);
@$pb.TagNumber(8)
$core.bool hasError() => $_has(7);
@$pb.TagNumber(8)
void clearError() => $_clearField(8);
@$pb.TagNumber(8)
ProtocolError ensureError() => $_ensure(7);
}
class StepEventReport extends $pb.GeneratedMessage {
@ -1060,6 +1120,7 @@ class ExecutionReportResponse extends $pb.GeneratedMessage {
$core.String? executionId,
$core.String? state,
$core.String? runnerId,
ProtocolError? error,
}) {
final result = create();
if (accepted != null) result.accepted = accepted;
@ -1068,6 +1129,7 @@ class ExecutionReportResponse extends $pb.GeneratedMessage {
if (executionId != null) result.executionId = executionId;
if (state != null) result.state = state;
if (runnerId != null) result.runnerId = runnerId;
if (error != null) result.error = error;
return result;
}
@ -1090,6 +1152,8 @@ class ExecutionReportResponse extends $pb.GeneratedMessage {
..aOS(4, _omitFieldNames ? '' : 'executionId')
..aOS(5, _omitFieldNames ? '' : 'state')
..aOS(6, _omitFieldNames ? '' : 'runnerId')
..aOM<ProtocolError>(7, _omitFieldNames ? '' : 'error',
subBuilder: ProtocolError.create)
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
@ -1165,6 +1229,17 @@ class ExecutionReportResponse extends $pb.GeneratedMessage {
$core.bool hasRunnerId() => $_has(5);
@$pb.TagNumber(6)
void clearRunnerId() => $_clearField(6);
@$pb.TagNumber(7)
ProtocolError get error => $_getN(6);
@$pb.TagNumber(7)
set error(ProtocolError value) => $_setField(7, value);
@$pb.TagNumber(7)
$core.bool hasError() => $_has(6);
@$pb.TagNumber(7)
void clearError() => $_clearField(7);
@$pb.TagNumber(7)
ProtocolError ensureError() => $_ensure(6);
}
class LogAppendRequest extends $pb.GeneratedMessage {
@ -1249,10 +1324,12 @@ class LogAppendResponse extends $pb.GeneratedMessage {
factory LogAppendResponse({
$core.bool? accepted,
$core.String? errorMessage,
ProtocolError? error,
}) {
final result = create();
if (accepted != null) result.accepted = accepted;
if (errorMessage != null) result.errorMessage = errorMessage;
if (error != null) result.error = error;
return result;
}
@ -1271,6 +1348,8 @@ class LogAppendResponse extends $pb.GeneratedMessage {
createEmptyInstance: create)
..aOB(1, _omitFieldNames ? '' : 'accepted')
..aOS(2, _omitFieldNames ? '' : 'errorMessage')
..aOM<ProtocolError>(3, _omitFieldNames ? '' : 'error',
subBuilder: ProtocolError.create)
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
@ -1309,6 +1388,17 @@ class LogAppendResponse extends $pb.GeneratedMessage {
$core.bool hasErrorMessage() => $_has(1);
@$pb.TagNumber(2)
void clearErrorMessage() => $_clearField(2);
@$pb.TagNumber(3)
ProtocolError get error => $_getN(2);
@$pb.TagNumber(3)
set error(ProtocolError value) => $_setField(3, value);
@$pb.TagNumber(3)
$core.bool hasError() => $_has(2);
@$pb.TagNumber(3)
void clearError() => $_clearField(3);
@$pb.TagNumber(3)
ProtocolError ensureError() => $_ensure(2);
}
class ArtifactReportRequest extends $pb.GeneratedMessage {
@ -1406,10 +1496,12 @@ class ArtifactReportResponse extends $pb.GeneratedMessage {
factory ArtifactReportResponse({
$core.bool? accepted,
$core.String? errorMessage,
ProtocolError? error,
}) {
final result = create();
if (accepted != null) result.accepted = accepted;
if (errorMessage != null) result.errorMessage = errorMessage;
if (error != null) result.error = error;
return result;
}
@ -1428,6 +1520,8 @@ class ArtifactReportResponse extends $pb.GeneratedMessage {
createEmptyInstance: create)
..aOB(1, _omitFieldNames ? '' : 'accepted')
..aOS(2, _omitFieldNames ? '' : 'errorMessage')
..aOM<ProtocolError>(3, _omitFieldNames ? '' : 'error',
subBuilder: ProtocolError.create)
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
@ -1467,6 +1561,676 @@ class ArtifactReportResponse extends $pb.GeneratedMessage {
$core.bool hasErrorMessage() => $_has(1);
@$pb.TagNumber(2)
void clearErrorMessage() => $_clearField(2);
@$pb.TagNumber(3)
ProtocolError get error => $_getN(2);
@$pb.TagNumber(3)
set error(ProtocolError value) => $_setField(3, value);
@$pb.TagNumber(3)
$core.bool hasError() => $_has(2);
@$pb.TagNumber(3)
void clearError() => $_clearField(3);
@$pb.TagNumber(3)
ProtocolError ensureError() => $_ensure(2);
}
class ProtocolError extends $pb.GeneratedMessage {
factory ProtocolError({
$core.String? code,
$core.String? message,
$core.Iterable<$core.MapEntry<$core.String, $core.String>>? details,
}) {
final result = create();
if (code != null) result.code = code;
if (message != null) result.message = message;
if (details != null) result.details.addEntries(details);
return result;
}
ProtocolError._();
factory ProtocolError.fromBuffer($core.List<$core.int> data,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(data, registry);
factory ProtocolError.fromJson($core.String json,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(json, registry);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'ProtocolError',
package: const $pb.PackageName(_omitMessageNames ? '' : 'oto.runner.v1'),
createEmptyInstance: create)
..aOS(1, _omitFieldNames ? '' : 'code')
..aOS(2, _omitFieldNames ? '' : 'message')
..m<$core.String, $core.String>(3, _omitFieldNames ? '' : 'details',
entryClassName: 'ProtocolError.DetailsEntry',
keyFieldType: $pb.PbFieldType.OS,
valueFieldType: $pb.PbFieldType.OS,
packageName: const $pb.PackageName('oto.runner.v1'))
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
ProtocolError clone() => deepCopy();
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
ProtocolError copyWith(void Function(ProtocolError) updates) =>
super.copyWith((message) => updates(message as ProtocolError))
as ProtocolError;
@$core.override
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static ProtocolError create() => ProtocolError._();
@$core.override
ProtocolError createEmptyInstance() => create();
@$core.pragma('dart2js:noInline')
static ProtocolError getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<ProtocolError>(create);
static ProtocolError? _defaultInstance;
@$pb.TagNumber(1)
$core.String get code => $_getSZ(0);
@$pb.TagNumber(1)
set code($core.String value) => $_setString(0, value);
@$pb.TagNumber(1)
$core.bool hasCode() => $_has(0);
@$pb.TagNumber(1)
void clearCode() => $_clearField(1);
@$pb.TagNumber(2)
$core.String get message => $_getSZ(1);
@$pb.TagNumber(2)
set message($core.String value) => $_setString(1, value);
@$pb.TagNumber(2)
$core.bool hasMessage() => $_has(1);
@$pb.TagNumber(2)
void clearMessage() => $_clearField(2);
@$pb.TagNumber(3)
$pb.PbMap<$core.String, $core.String> get details => $_getMap(2);
}
class RunRequest extends $pb.GeneratedMessage {
factory RunRequest({
$core.String? runnerId,
$core.String? jobId,
$core.String? executionId,
$core.String? pipelineYamlPath,
$core.String? pipelineYaml,
$core.Iterable<$core.MapEntry<$core.String, $core.String>>? variables,
$core.Iterable<$core.String>? commandTypes,
}) {
final result = create();
if (runnerId != null) result.runnerId = runnerId;
if (jobId != null) result.jobId = jobId;
if (executionId != null) result.executionId = executionId;
if (pipelineYamlPath != null) result.pipelineYamlPath = pipelineYamlPath;
if (pipelineYaml != null) result.pipelineYaml = pipelineYaml;
if (variables != null) result.variables.addEntries(variables);
if (commandTypes != null) result.commandTypes.addAll(commandTypes);
return result;
}
RunRequest._();
factory RunRequest.fromBuffer($core.List<$core.int> data,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(data, registry);
factory RunRequest.fromJson($core.String json,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(json, registry);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'RunRequest',
package: const $pb.PackageName(_omitMessageNames ? '' : 'oto.runner.v1'),
createEmptyInstance: create)
..aOS(1, _omitFieldNames ? '' : 'runnerId')
..aOS(2, _omitFieldNames ? '' : 'jobId')
..aOS(3, _omitFieldNames ? '' : 'executionId')
..aOS(4, _omitFieldNames ? '' : 'pipelineYamlPath')
..aOS(5, _omitFieldNames ? '' : 'pipelineYaml')
..m<$core.String, $core.String>(6, _omitFieldNames ? '' : 'variables',
entryClassName: 'RunRequest.VariablesEntry',
keyFieldType: $pb.PbFieldType.OS,
valueFieldType: $pb.PbFieldType.OS,
packageName: const $pb.PackageName('oto.runner.v1'))
..pPS(7, _omitFieldNames ? '' : 'commandTypes')
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
RunRequest clone() => deepCopy();
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
RunRequest copyWith(void Function(RunRequest) updates) =>
super.copyWith((message) => updates(message as RunRequest)) as RunRequest;
@$core.override
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static RunRequest create() => RunRequest._();
@$core.override
RunRequest createEmptyInstance() => create();
@$core.pragma('dart2js:noInline')
static RunRequest getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<RunRequest>(create);
static RunRequest? _defaultInstance;
@$pb.TagNumber(1)
$core.String get runnerId => $_getSZ(0);
@$pb.TagNumber(1)
set runnerId($core.String value) => $_setString(0, value);
@$pb.TagNumber(1)
$core.bool hasRunnerId() => $_has(0);
@$pb.TagNumber(1)
void clearRunnerId() => $_clearField(1);
@$pb.TagNumber(2)
$core.String get jobId => $_getSZ(1);
@$pb.TagNumber(2)
set jobId($core.String value) => $_setString(1, value);
@$pb.TagNumber(2)
$core.bool hasJobId() => $_has(1);
@$pb.TagNumber(2)
void clearJobId() => $_clearField(2);
@$pb.TagNumber(3)
$core.String get executionId => $_getSZ(2);
@$pb.TagNumber(3)
set executionId($core.String value) => $_setString(2, value);
@$pb.TagNumber(3)
$core.bool hasExecutionId() => $_has(2);
@$pb.TagNumber(3)
void clearExecutionId() => $_clearField(3);
@$pb.TagNumber(4)
$core.String get pipelineYamlPath => $_getSZ(3);
@$pb.TagNumber(4)
set pipelineYamlPath($core.String value) => $_setString(3, value);
@$pb.TagNumber(4)
$core.bool hasPipelineYamlPath() => $_has(3);
@$pb.TagNumber(4)
void clearPipelineYamlPath() => $_clearField(4);
@$pb.TagNumber(5)
$core.String get pipelineYaml => $_getSZ(4);
@$pb.TagNumber(5)
set pipelineYaml($core.String value) => $_setString(4, value);
@$pb.TagNumber(5)
$core.bool hasPipelineYaml() => $_has(4);
@$pb.TagNumber(5)
void clearPipelineYaml() => $_clearField(5);
@$pb.TagNumber(6)
$pb.PbMap<$core.String, $core.String> get variables => $_getMap(5);
@$pb.TagNumber(7)
$pb.PbList<$core.String> get commandTypes => $_getList(6);
}
class CancelRunRequest extends $pb.GeneratedMessage {
factory CancelRunRequest({
$core.String? runnerId,
$core.String? executionId,
$core.String? reason,
}) {
final result = create();
if (runnerId != null) result.runnerId = runnerId;
if (executionId != null) result.executionId = executionId;
if (reason != null) result.reason = reason;
return result;
}
CancelRunRequest._();
factory CancelRunRequest.fromBuffer($core.List<$core.int> data,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(data, registry);
factory CancelRunRequest.fromJson($core.String json,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(json, registry);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'CancelRunRequest',
package: const $pb.PackageName(_omitMessageNames ? '' : 'oto.runner.v1'),
createEmptyInstance: create)
..aOS(1, _omitFieldNames ? '' : 'runnerId')
..aOS(2, _omitFieldNames ? '' : 'executionId')
..aOS(3, _omitFieldNames ? '' : 'reason')
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
CancelRunRequest clone() => deepCopy();
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
CancelRunRequest copyWith(void Function(CancelRunRequest) updates) =>
super.copyWith((message) => updates(message as CancelRunRequest))
as CancelRunRequest;
@$core.override
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static CancelRunRequest create() => CancelRunRequest._();
@$core.override
CancelRunRequest createEmptyInstance() => create();
@$core.pragma('dart2js:noInline')
static CancelRunRequest getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<CancelRunRequest>(create);
static CancelRunRequest? _defaultInstance;
@$pb.TagNumber(1)
$core.String get runnerId => $_getSZ(0);
@$pb.TagNumber(1)
set runnerId($core.String value) => $_setString(0, value);
@$pb.TagNumber(1)
$core.bool hasRunnerId() => $_has(0);
@$pb.TagNumber(1)
void clearRunnerId() => $_clearField(1);
@$pb.TagNumber(2)
$core.String get executionId => $_getSZ(1);
@$pb.TagNumber(2)
set executionId($core.String value) => $_setString(1, value);
@$pb.TagNumber(2)
$core.bool hasExecutionId() => $_has(1);
@$pb.TagNumber(2)
void clearExecutionId() => $_clearField(2);
@$pb.TagNumber(3)
$core.String get reason => $_getSZ(2);
@$pb.TagNumber(3)
set reason($core.String value) => $_setString(2, value);
@$pb.TagNumber(3)
$core.bool hasReason() => $_has(2);
@$pb.TagNumber(3)
void clearReason() => $_clearField(3);
}
class CancelRunResponse extends $pb.GeneratedMessage {
factory CancelRunResponse({
$core.bool? success,
$core.String? errorMessage,
ProtocolError? error,
}) {
final result = create();
if (success != null) result.success = success;
if (errorMessage != null) result.errorMessage = errorMessage;
if (error != null) result.error = error;
return result;
}
CancelRunResponse._();
factory CancelRunResponse.fromBuffer($core.List<$core.int> data,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(data, registry);
factory CancelRunResponse.fromJson($core.String json,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(json, registry);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'CancelRunResponse',
package: const $pb.PackageName(_omitMessageNames ? '' : 'oto.runner.v1'),
createEmptyInstance: create)
..aOB(1, _omitFieldNames ? '' : 'success')
..aOS(2, _omitFieldNames ? '' : 'errorMessage')
..aOM<ProtocolError>(3, _omitFieldNames ? '' : 'error',
subBuilder: ProtocolError.create)
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
CancelRunResponse clone() => deepCopy();
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
CancelRunResponse copyWith(void Function(CancelRunResponse) updates) =>
super.copyWith((message) => updates(message as CancelRunResponse))
as CancelRunResponse;
@$core.override
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static CancelRunResponse create() => CancelRunResponse._();
@$core.override
CancelRunResponse createEmptyInstance() => create();
@$core.pragma('dart2js:noInline')
static CancelRunResponse getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<CancelRunResponse>(create);
static CancelRunResponse? _defaultInstance;
@$pb.TagNumber(1)
$core.bool get success => $_getBF(0);
@$pb.TagNumber(1)
set success($core.bool value) => $_setBool(0, value);
@$pb.TagNumber(1)
$core.bool hasSuccess() => $_has(0);
@$pb.TagNumber(1)
void clearSuccess() => $_clearField(1);
@$pb.TagNumber(2)
$core.String get errorMessage => $_getSZ(1);
@$pb.TagNumber(2)
set errorMessage($core.String value) => $_setString(1, value);
@$pb.TagNumber(2)
$core.bool hasErrorMessage() => $_has(1);
@$pb.TagNumber(2)
void clearErrorMessage() => $_clearField(2);
@$pb.TagNumber(3)
ProtocolError get error => $_getN(2);
@$pb.TagNumber(3)
set error(ProtocolError value) => $_setField(3, value);
@$pb.TagNumber(3)
$core.bool hasError() => $_has(2);
@$pb.TagNumber(3)
void clearError() => $_clearField(3);
@$pb.TagNumber(3)
ProtocolError ensureError() => $_ensure(2);
}
class RunnerStatusRequest extends $pb.GeneratedMessage {
factory RunnerStatusRequest({
$core.String? runnerId,
}) {
final result = create();
if (runnerId != null) result.runnerId = runnerId;
return result;
}
RunnerStatusRequest._();
factory RunnerStatusRequest.fromBuffer($core.List<$core.int> data,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(data, registry);
factory RunnerStatusRequest.fromJson($core.String json,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(json, registry);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'RunnerStatusRequest',
package: const $pb.PackageName(_omitMessageNames ? '' : 'oto.runner.v1'),
createEmptyInstance: create)
..aOS(1, _omitFieldNames ? '' : 'runnerId')
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
RunnerStatusRequest clone() => deepCopy();
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
RunnerStatusRequest copyWith(void Function(RunnerStatusRequest) updates) =>
super.copyWith((message) => updates(message as RunnerStatusRequest))
as RunnerStatusRequest;
@$core.override
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static RunnerStatusRequest create() => RunnerStatusRequest._();
@$core.override
RunnerStatusRequest createEmptyInstance() => create();
@$core.pragma('dart2js:noInline')
static RunnerStatusRequest getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<RunnerStatusRequest>(create);
static RunnerStatusRequest? _defaultInstance;
@$pb.TagNumber(1)
$core.String get runnerId => $_getSZ(0);
@$pb.TagNumber(1)
set runnerId($core.String value) => $_setString(0, value);
@$pb.TagNumber(1)
$core.bool hasRunnerId() => $_has(0);
@$pb.TagNumber(1)
void clearRunnerId() => $_clearField(1);
}
class RunnerStatusResponse extends $pb.GeneratedMessage {
factory RunnerStatusResponse({
$core.String? runnerId,
$core.String? status,
$core.String? currentExecutionId,
ProtocolError? error,
}) {
final result = create();
if (runnerId != null) result.runnerId = runnerId;
if (status != null) result.status = status;
if (currentExecutionId != null)
result.currentExecutionId = currentExecutionId;
if (error != null) result.error = error;
return result;
}
RunnerStatusResponse._();
factory RunnerStatusResponse.fromBuffer($core.List<$core.int> data,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(data, registry);
factory RunnerStatusResponse.fromJson($core.String json,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(json, registry);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'RunnerStatusResponse',
package: const $pb.PackageName(_omitMessageNames ? '' : 'oto.runner.v1'),
createEmptyInstance: create)
..aOS(1, _omitFieldNames ? '' : 'runnerId')
..aOS(2, _omitFieldNames ? '' : 'status')
..aOS(3, _omitFieldNames ? '' : 'currentExecutionId')
..aOM<ProtocolError>(4, _omitFieldNames ? '' : 'error',
subBuilder: ProtocolError.create)
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
RunnerStatusResponse clone() => deepCopy();
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
RunnerStatusResponse copyWith(void Function(RunnerStatusResponse) updates) =>
super.copyWith((message) => updates(message as RunnerStatusResponse))
as RunnerStatusResponse;
@$core.override
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static RunnerStatusResponse create() => RunnerStatusResponse._();
@$core.override
RunnerStatusResponse createEmptyInstance() => create();
@$core.pragma('dart2js:noInline')
static RunnerStatusResponse getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<RunnerStatusResponse>(create);
static RunnerStatusResponse? _defaultInstance;
@$pb.TagNumber(1)
$core.String get runnerId => $_getSZ(0);
@$pb.TagNumber(1)
set runnerId($core.String value) => $_setString(0, value);
@$pb.TagNumber(1)
$core.bool hasRunnerId() => $_has(0);
@$pb.TagNumber(1)
void clearRunnerId() => $_clearField(1);
@$pb.TagNumber(2)
$core.String get status => $_getSZ(1);
@$pb.TagNumber(2)
set status($core.String value) => $_setString(1, value);
@$pb.TagNumber(2)
$core.bool hasStatus() => $_has(1);
@$pb.TagNumber(2)
void clearStatus() => $_clearField(2);
@$pb.TagNumber(3)
$core.String get currentExecutionId => $_getSZ(2);
@$pb.TagNumber(3)
set currentExecutionId($core.String value) => $_setString(2, value);
@$pb.TagNumber(3)
$core.bool hasCurrentExecutionId() => $_has(2);
@$pb.TagNumber(3)
void clearCurrentExecutionId() => $_clearField(3);
@$pb.TagNumber(4)
ProtocolError get error => $_getN(3);
@$pb.TagNumber(4)
set error(ProtocolError value) => $_setField(4, value);
@$pb.TagNumber(4)
$core.bool hasError() => $_has(3);
@$pb.TagNumber(4)
void clearError() => $_clearField(4);
@$pb.TagNumber(4)
ProtocolError ensureError() => $_ensure(3);
}
class SelfUpdateRequest extends $pb.GeneratedMessage {
factory SelfUpdateRequest({
$core.String? runnerId,
$core.String? version,
$core.String? downloadUrl,
}) {
final result = create();
if (runnerId != null) result.runnerId = runnerId;
if (version != null) result.version = version;
if (downloadUrl != null) result.downloadUrl = downloadUrl;
return result;
}
SelfUpdateRequest._();
factory SelfUpdateRequest.fromBuffer($core.List<$core.int> data,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(data, registry);
factory SelfUpdateRequest.fromJson($core.String json,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(json, registry);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'SelfUpdateRequest',
package: const $pb.PackageName(_omitMessageNames ? '' : 'oto.runner.v1'),
createEmptyInstance: create)
..aOS(1, _omitFieldNames ? '' : 'runnerId')
..aOS(2, _omitFieldNames ? '' : 'version')
..aOS(3, _omitFieldNames ? '' : 'downloadUrl')
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
SelfUpdateRequest clone() => deepCopy();
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
SelfUpdateRequest copyWith(void Function(SelfUpdateRequest) updates) =>
super.copyWith((message) => updates(message as SelfUpdateRequest))
as SelfUpdateRequest;
@$core.override
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static SelfUpdateRequest create() => SelfUpdateRequest._();
@$core.override
SelfUpdateRequest createEmptyInstance() => create();
@$core.pragma('dart2js:noInline')
static SelfUpdateRequest getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<SelfUpdateRequest>(create);
static SelfUpdateRequest? _defaultInstance;
@$pb.TagNumber(1)
$core.String get runnerId => $_getSZ(0);
@$pb.TagNumber(1)
set runnerId($core.String value) => $_setString(0, value);
@$pb.TagNumber(1)
$core.bool hasRunnerId() => $_has(0);
@$pb.TagNumber(1)
void clearRunnerId() => $_clearField(1);
@$pb.TagNumber(2)
$core.String get version => $_getSZ(1);
@$pb.TagNumber(2)
set version($core.String value) => $_setString(1, value);
@$pb.TagNumber(2)
$core.bool hasVersion() => $_has(1);
@$pb.TagNumber(2)
void clearVersion() => $_clearField(2);
@$pb.TagNumber(3)
$core.String get downloadUrl => $_getSZ(2);
@$pb.TagNumber(3)
set downloadUrl($core.String value) => $_setString(2, value);
@$pb.TagNumber(3)
$core.bool hasDownloadUrl() => $_has(2);
@$pb.TagNumber(3)
void clearDownloadUrl() => $_clearField(3);
}
class SelfUpdateResponse extends $pb.GeneratedMessage {
factory SelfUpdateResponse({
$core.bool? success,
$core.String? errorMessage,
ProtocolError? error,
}) {
final result = create();
if (success != null) result.success = success;
if (errorMessage != null) result.errorMessage = errorMessage;
if (error != null) result.error = error;
return result;
}
SelfUpdateResponse._();
factory SelfUpdateResponse.fromBuffer($core.List<$core.int> data,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(data, registry);
factory SelfUpdateResponse.fromJson($core.String json,
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(json, registry);
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
_omitMessageNames ? '' : 'SelfUpdateResponse',
package: const $pb.PackageName(_omitMessageNames ? '' : 'oto.runner.v1'),
createEmptyInstance: create)
..aOB(1, _omitFieldNames ? '' : 'success')
..aOS(2, _omitFieldNames ? '' : 'errorMessage')
..aOM<ProtocolError>(3, _omitFieldNames ? '' : 'error',
subBuilder: ProtocolError.create)
..hasRequiredFields = false;
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
SelfUpdateResponse clone() => deepCopy();
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
SelfUpdateResponse copyWith(void Function(SelfUpdateResponse) updates) =>
super.copyWith((message) => updates(message as SelfUpdateResponse))
as SelfUpdateResponse;
@$core.override
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static SelfUpdateResponse create() => SelfUpdateResponse._();
@$core.override
SelfUpdateResponse createEmptyInstance() => create();
@$core.pragma('dart2js:noInline')
static SelfUpdateResponse getDefault() => _defaultInstance ??=
$pb.GeneratedMessage.$_defaultFor<SelfUpdateResponse>(create);
static SelfUpdateResponse? _defaultInstance;
@$pb.TagNumber(1)
$core.bool get success => $_getBF(0);
@$pb.TagNumber(1)
set success($core.bool value) => $_setBool(0, value);
@$pb.TagNumber(1)
$core.bool hasSuccess() => $_has(0);
@$pb.TagNumber(1)
void clearSuccess() => $_clearField(1);
@$pb.TagNumber(2)
$core.String get errorMessage => $_getSZ(1);
@$pb.TagNumber(2)
set errorMessage($core.String value) => $_setString(1, value);
@$pb.TagNumber(2)
$core.bool hasErrorMessage() => $_has(1);
@$pb.TagNumber(2)
void clearErrorMessage() => $_clearField(2);
@$pb.TagNumber(3)
ProtocolError get error => $_getN(2);
@$pb.TagNumber(3)
set error(ProtocolError value) => $_setField(3, value);
@$pb.TagNumber(3)
$core.bool hasError() => $_has(2);
@$pb.TagNumber(3)
void clearError() => $_clearField(3);
@$pb.TagNumber(3)
ProtocolError ensureError() => $_ensure(2);
}
const $core.bool _omitFieldNames =

View file

@ -102,6 +102,14 @@ const RegisterRunnerResponse$json = {
{'1': 'reject_reason', '3': 2, '4': 1, '5': 9, '10': 'rejectReason'},
{'1': 'runner_id', '3': 3, '4': 1, '5': 9, '10': 'runnerId'},
{'1': 'alias', '3': 4, '4': 1, '5': 9, '10': 'alias'},
{
'1': 'error',
'3': 5,
'4': 1,
'5': 11,
'6': '.oto.runner.v1.ProtocolError',
'10': 'error'
},
],
};
@ -109,7 +117,8 @@ const RegisterRunnerResponse$json = {
final $typed_data.Uint8List registerRunnerResponseDescriptor = $convert.base64Decode(
'ChZSZWdpc3RlclJ1bm5lclJlc3BvbnNlEhoKCGFjY2VwdGVkGAEgASgIUghhY2NlcHRlZBIjCg'
'1yZWplY3RfcmVhc29uGAIgASgJUgxyZWplY3RSZWFzb24SGwoJcnVubmVyX2lkGAMgASgJUghy'
'dW5uZXJJZBIUCgVhbGlhcxgEIAEoCVIFYWxpYXM=');
'dW5uZXJJZBIUCgVhbGlhcxgEIAEoCVIFYWxpYXMSMgoFZXJyb3IYBSABKAsyHC5vdG8ucnVubm'
'VyLnYxLlByb3RvY29sRXJyb3JSBWVycm9y');
@$core.Deprecated('Use heartbeatRequestDescriptor instead')
const HeartbeatRequest$json = {
@ -138,13 +147,22 @@ const HeartbeatResponse$json = {
'2': [
{'1': 'success', '3': 1, '4': 1, '5': 8, '10': 'success'},
{'1': 'error_message', '3': 2, '4': 1, '5': 9, '10': 'errorMessage'},
{
'1': 'error',
'3': 3,
'4': 1,
'5': 11,
'6': '.oto.runner.v1.ProtocolError',
'10': 'error'
},
],
};
/// Descriptor for `HeartbeatResponse`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List heartbeatResponseDescriptor = $convert.base64Decode(
'ChFIZWFydGJlYXRSZXNwb25zZRIYCgdzdWNjZXNzGAEgASgIUgdzdWNjZXNzEiMKDWVycm9yX2'
'1lc3NhZ2UYAiABKAlSDGVycm9yTWVzc2FnZQ==');
'1lc3NhZ2UYAiABKAlSDGVycm9yTWVzc2FnZRIyCgVlcnJvchgDIAEoCzIcLm90by5ydW5uZXIu'
'djEuUHJvdG9jb2xFcnJvclIFZXJyb3I=');
@$core.Deprecated('Use bootstrapCommandRequestDescriptor instead')
const BootstrapCommandRequest$json = {
@ -206,6 +224,22 @@ const JobClaimResponse$json = {
{'1': 'execution_id', '3': 4, '4': 1, '5': 9, '10': 'executionId'},
{'1': 'state', '3': 5, '4': 1, '5': 9, '10': 'state'},
{'1': 'runner_id', '3': 6, '4': 1, '5': 9, '10': 'runnerId'},
{
'1': 'run_request',
'3': 7,
'4': 1,
'5': 11,
'6': '.oto.runner.v1.RunRequest',
'10': 'runRequest'
},
{
'1': 'error',
'3': 8,
'4': 1,
'5': 11,
'6': '.oto.runner.v1.ProtocolError',
'10': 'error'
},
],
};
@ -214,7 +248,9 @@ final $typed_data.Uint8List jobClaimResponseDescriptor = $convert.base64Decode(
'ChBKb2JDbGFpbVJlc3BvbnNlEhoKCGFjY2VwdGVkGAEgASgIUghhY2NlcHRlZBIjCg1lcnJvcl'
'9tZXNzYWdlGAIgASgJUgxlcnJvck1lc3NhZ2USFQoGam9iX2lkGAMgASgJUgVqb2JJZBIhCgxl'
'eGVjdXRpb25faWQYBCABKAlSC2V4ZWN1dGlvbklkEhQKBXN0YXRlGAUgASgJUgVzdGF0ZRIbCg'
'lydW5uZXJfaWQYBiABKAlSCHJ1bm5lcklk');
'lydW5uZXJfaWQYBiABKAlSCHJ1bm5lcklkEjoKC3J1bl9yZXF1ZXN0GAcgASgLMhkub3RvLnJ1'
'bm5lci52MS5SdW5SZXF1ZXN0UgpydW5SZXF1ZXN0EjIKBWVycm9yGAggASgLMhwub3RvLnJ1bm'
'5lci52MS5Qcm90b2NvbEVycm9yUgVlcnJvcg==');
@$core.Deprecated('Use stepEventReportDescriptor instead')
const StepEventReport$json = {
@ -298,6 +334,14 @@ const ExecutionReportResponse$json = {
{'1': 'execution_id', '3': 4, '4': 1, '5': 9, '10': 'executionId'},
{'1': 'state', '3': 5, '4': 1, '5': 9, '10': 'state'},
{'1': 'runner_id', '3': 6, '4': 1, '5': 9, '10': 'runnerId'},
{
'1': 'error',
'3': 7,
'4': 1,
'5': 11,
'6': '.oto.runner.v1.ProtocolError',
'10': 'error'
},
],
};
@ -306,7 +350,8 @@ final $typed_data.Uint8List executionReportResponseDescriptor = $convert.base64D
'ChdFeGVjdXRpb25SZXBvcnRSZXNwb25zZRIaCghhY2NlcHRlZBgBIAEoCFIIYWNjZXB0ZWQSIw'
'oNZXJyb3JfbWVzc2FnZRgCIAEoCVIMZXJyb3JNZXNzYWdlEhUKBmpvYl9pZBgDIAEoCVIFam9i'
'SWQSIQoMZXhlY3V0aW9uX2lkGAQgASgJUgtleGVjdXRpb25JZBIUCgVzdGF0ZRgFIAEoCVIFc3'
'RhdGUSGwoJcnVubmVyX2lkGAYgASgJUghydW5uZXJJZA==');
'RhdGUSGwoJcnVubmVyX2lkGAYgASgJUghydW5uZXJJZBIyCgVlcnJvchgHIAEoCzIcLm90by5y'
'dW5uZXIudjEuUHJvdG9jb2xFcnJvclIFZXJyb3I=');
@$core.Deprecated('Use logAppendRequestDescriptor instead')
const LogAppendRequest$json = {
@ -329,13 +374,22 @@ const LogAppendResponse$json = {
'2': [
{'1': 'accepted', '3': 1, '4': 1, '5': 8, '10': 'accepted'},
{'1': 'error_message', '3': 2, '4': 1, '5': 9, '10': 'errorMessage'},
{
'1': 'error',
'3': 3,
'4': 1,
'5': 11,
'6': '.oto.runner.v1.ProtocolError',
'10': 'error'
},
],
};
/// Descriptor for `LogAppendResponse`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List logAppendResponseDescriptor = $convert.base64Decode(
'ChFMb2dBcHBlbmRSZXNwb25zZRIaCghhY2NlcHRlZBgBIAEoCFIIYWNjZXB0ZWQSIwoNZXJyb3'
'JfbWVzc2FnZRgCIAEoCVIMZXJyb3JNZXNzYWdl');
'JfbWVzc2FnZRgCIAEoCVIMZXJyb3JNZXNzYWdlEjIKBWVycm9yGAMgASgLMhwub3RvLnJ1bm5l'
'ci52MS5Qcm90b2NvbEVycm9yUgVlcnJvcg==');
@$core.Deprecated('Use artifactReportRequestDescriptor instead')
const ArtifactReportRequest$json = {
@ -360,11 +414,222 @@ const ArtifactReportResponse$json = {
'2': [
{'1': 'accepted', '3': 1, '4': 1, '5': 8, '10': 'accepted'},
{'1': 'error_message', '3': 2, '4': 1, '5': 9, '10': 'errorMessage'},
{
'1': 'error',
'3': 3,
'4': 1,
'5': 11,
'6': '.oto.runner.v1.ProtocolError',
'10': 'error'
},
],
};
/// Descriptor for `ArtifactReportResponse`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List artifactReportResponseDescriptor =
final $typed_data.Uint8List artifactReportResponseDescriptor = $convert.base64Decode(
'ChZBcnRpZmFjdFJlcG9ydFJlc3BvbnNlEhoKCGFjY2VwdGVkGAEgASgIUghhY2NlcHRlZBIjCg'
'1lcnJvcl9tZXNzYWdlGAIgASgJUgxlcnJvck1lc3NhZ2USMgoFZXJyb3IYAyABKAsyHC5vdG8u'
'cnVubmVyLnYxLlByb3RvY29sRXJyb3JSBWVycm9y');
@$core.Deprecated('Use protocolErrorDescriptor instead')
const ProtocolError$json = {
'1': 'ProtocolError',
'2': [
{'1': 'code', '3': 1, '4': 1, '5': 9, '10': 'code'},
{'1': 'message', '3': 2, '4': 1, '5': 9, '10': 'message'},
{
'1': 'details',
'3': 3,
'4': 3,
'5': 11,
'6': '.oto.runner.v1.ProtocolError.DetailsEntry',
'10': 'details'
},
],
'3': [ProtocolError_DetailsEntry$json],
};
@$core.Deprecated('Use protocolErrorDescriptor instead')
const ProtocolError_DetailsEntry$json = {
'1': 'DetailsEntry',
'2': [
{'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'},
{'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'},
],
'7': {'7': true},
};
/// Descriptor for `ProtocolError`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List protocolErrorDescriptor = $convert.base64Decode(
'Cg1Qcm90b2NvbEVycm9yEhIKBGNvZGUYASABKAlSBGNvZGUSGAoHbWVzc2FnZRgCIAEoCVIHbW'
'Vzc2FnZRJDCgdkZXRhaWxzGAMgAygLMikub3RvLnJ1bm5lci52MS5Qcm90b2NvbEVycm9yLkRl'
'dGFpbHNFbnRyeVIHZGV0YWlscxo6CgxEZXRhaWxzRW50cnkSEAoDa2V5GAEgASgJUgNrZXkSFA'
'oFdmFsdWUYAiABKAlSBXZhbHVlOgI4AQ==');
@$core.Deprecated('Use runRequestDescriptor instead')
const RunRequest$json = {
'1': 'RunRequest',
'2': [
{'1': 'runner_id', '3': 1, '4': 1, '5': 9, '10': 'runnerId'},
{'1': 'job_id', '3': 2, '4': 1, '5': 9, '10': 'jobId'},
{'1': 'execution_id', '3': 3, '4': 1, '5': 9, '10': 'executionId'},
{
'1': 'pipeline_yaml_path',
'3': 4,
'4': 1,
'5': 9,
'10': 'pipelineYamlPath'
},
{'1': 'pipeline_yaml', '3': 5, '4': 1, '5': 9, '10': 'pipelineYaml'},
{
'1': 'variables',
'3': 6,
'4': 3,
'5': 11,
'6': '.oto.runner.v1.RunRequest.VariablesEntry',
'10': 'variables'
},
{'1': 'command_types', '3': 7, '4': 3, '5': 9, '10': 'commandTypes'},
],
'3': [RunRequest_VariablesEntry$json],
};
@$core.Deprecated('Use runRequestDescriptor instead')
const RunRequest_VariablesEntry$json = {
'1': 'VariablesEntry',
'2': [
{'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'},
{'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'},
],
'7': {'7': true},
};
/// Descriptor for `RunRequest`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List runRequestDescriptor = $convert.base64Decode(
'CgpSdW5SZXF1ZXN0EhsKCXJ1bm5lcl9pZBgBIAEoCVIIcnVubmVySWQSFQoGam9iX2lkGAIgAS'
'gJUgVqb2JJZBIhCgxleGVjdXRpb25faWQYAyABKAlSC2V4ZWN1dGlvbklkEiwKEnBpcGVsaW5l'
'X3lhbWxfcGF0aBgEIAEoCVIQcGlwZWxpbmVZYW1sUGF0aBIjCg1waXBlbGluZV95YW1sGAUgAS'
'gJUgxwaXBlbGluZVlhbWwSRgoJdmFyaWFibGVzGAYgAygLMigub3RvLnJ1bm5lci52MS5SdW5S'
'ZXF1ZXN0LlZhcmlhYmxlc0VudHJ5Ugl2YXJpYWJsZXMSIwoNY29tbWFuZF90eXBlcxgHIAMoCV'
'IMY29tbWFuZFR5cGVzGjwKDlZhcmlhYmxlc0VudHJ5EhAKA2tleRgBIAEoCVIDa2V5EhQKBXZh'
'bHVlGAIgASgJUgV2YWx1ZToCOAE=');
@$core.Deprecated('Use cancelRunRequestDescriptor instead')
const CancelRunRequest$json = {
'1': 'CancelRunRequest',
'2': [
{'1': 'runner_id', '3': 1, '4': 1, '5': 9, '10': 'runnerId'},
{'1': 'execution_id', '3': 2, '4': 1, '5': 9, '10': 'executionId'},
{'1': 'reason', '3': 3, '4': 1, '5': 9, '10': 'reason'},
],
};
/// Descriptor for `CancelRunRequest`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List cancelRunRequestDescriptor = $convert.base64Decode(
'ChBDYW5jZWxSdW5SZXF1ZXN0EhsKCXJ1bm5lcl9pZBgBIAEoCVIIcnVubmVySWQSIQoMZXhlY3'
'V0aW9uX2lkGAIgASgJUgtleGVjdXRpb25JZBIWCgZyZWFzb24YAyABKAlSBnJlYXNvbg==');
@$core.Deprecated('Use cancelRunResponseDescriptor instead')
const CancelRunResponse$json = {
'1': 'CancelRunResponse',
'2': [
{'1': 'success', '3': 1, '4': 1, '5': 8, '10': 'success'},
{'1': 'error_message', '3': 2, '4': 1, '5': 9, '10': 'errorMessage'},
{
'1': 'error',
'3': 3,
'4': 1,
'5': 11,
'6': '.oto.runner.v1.ProtocolError',
'10': 'error'
},
],
};
/// Descriptor for `CancelRunResponse`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List cancelRunResponseDescriptor = $convert.base64Decode(
'ChFDYW5jZWxSdW5SZXNwb25zZRIYCgdzdWNjZXNzGAEgASgIUgdzdWNjZXNzEiMKDWVycm9yX2'
'1lc3NhZ2UYAiABKAlSDGVycm9yTWVzc2FnZRIyCgVlcnJvchgDIAEoCzIcLm90by5ydW5uZXIu'
'djEuUHJvdG9jb2xFcnJvclIFZXJyb3I=');
@$core.Deprecated('Use runnerStatusRequestDescriptor instead')
const RunnerStatusRequest$json = {
'1': 'RunnerStatusRequest',
'2': [
{'1': 'runner_id', '3': 1, '4': 1, '5': 9, '10': 'runnerId'},
],
};
/// Descriptor for `RunnerStatusRequest`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List runnerStatusRequestDescriptor =
$convert.base64Decode(
'ChZBcnRpZmFjdFJlcG9ydFJlc3BvbnNlEhoKCGFjY2VwdGVkGAEgASgIUghhY2NlcHRlZBIjCg'
'1lcnJvcl9tZXNzYWdlGAIgASgJUgxlcnJvck1lc3NhZ2U=');
'ChNSdW5uZXJTdGF0dXNSZXF1ZXN0EhsKCXJ1bm5lcl9pZBgBIAEoCVIIcnVubmVySWQ=');
@$core.Deprecated('Use runnerStatusResponseDescriptor instead')
const RunnerStatusResponse$json = {
'1': 'RunnerStatusResponse',
'2': [
{'1': 'runner_id', '3': 1, '4': 1, '5': 9, '10': 'runnerId'},
{'1': 'status', '3': 2, '4': 1, '5': 9, '10': 'status'},
{
'1': 'current_execution_id',
'3': 3,
'4': 1,
'5': 9,
'10': 'currentExecutionId'
},
{
'1': 'error',
'3': 4,
'4': 1,
'5': 11,
'6': '.oto.runner.v1.ProtocolError',
'10': 'error'
},
],
};
/// Descriptor for `RunnerStatusResponse`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List runnerStatusResponseDescriptor = $convert.base64Decode(
'ChRSdW5uZXJTdGF0dXNSZXNwb25zZRIbCglydW5uZXJfaWQYASABKAlSCHJ1bm5lcklkEhYKBn'
'N0YXR1cxgCIAEoCVIGc3RhdHVzEjAKFGN1cnJlbnRfZXhlY3V0aW9uX2lkGAMgASgJUhJjdXJy'
'ZW50RXhlY3V0aW9uSWQSMgoFZXJyb3IYBCABKAsyHC5vdG8ucnVubmVyLnYxLlByb3RvY29sRX'
'Jyb3JSBWVycm9y');
@$core.Deprecated('Use selfUpdateRequestDescriptor instead')
const SelfUpdateRequest$json = {
'1': 'SelfUpdateRequest',
'2': [
{'1': 'runner_id', '3': 1, '4': 1, '5': 9, '10': 'runnerId'},
{'1': 'version', '3': 2, '4': 1, '5': 9, '10': 'version'},
{'1': 'download_url', '3': 3, '4': 1, '5': 9, '10': 'downloadUrl'},
],
};
/// Descriptor for `SelfUpdateRequest`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List selfUpdateRequestDescriptor = $convert.base64Decode(
'ChFTZWxmVXBkYXRlUmVxdWVzdBIbCglydW5uZXJfaWQYASABKAlSCHJ1bm5lcklkEhgKB3Zlcn'
'Npb24YAiABKAlSB3ZlcnNpb24SIQoMZG93bmxvYWRfdXJsGAMgASgJUgtkb3dubG9hZFVybA==');
@$core.Deprecated('Use selfUpdateResponseDescriptor instead')
const SelfUpdateResponse$json = {
'1': 'SelfUpdateResponse',
'2': [
{'1': 'success', '3': 1, '4': 1, '5': 8, '10': 'success'},
{'1': 'error_message', '3': 2, '4': 1, '5': 9, '10': 'errorMessage'},
{
'1': 'error',
'3': 3,
'4': 1,
'5': 11,
'6': '.oto.runner.v1.ProtocolError',
'10': 'error'
},
],
};
/// Descriptor for `SelfUpdateResponse`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List selfUpdateResponseDescriptor = $convert.base64Decode(
'ChJTZWxmVXBkYXRlUmVzcG9uc2USGAoHc3VjY2VzcxgBIAEoCFIHc3VjY2VzcxIjCg1lcnJvcl'
'9tZXNzYWdlGAIgASgJUgxlcnJvck1lc3NhZ2USMgoFZXJyb3IYAyABKAsyHC5vdG8ucnVubmVy'
'LnYxLlByb3RvY29sRXJyb3JSBWVycm9y');

View file

@ -22,10 +22,16 @@ class JobClaimResult {
});
factory JobClaimResult.fromJson(Map<String, dynamic> json) {
final err = json['error'];
final errMessageFromObj = (err is Map) ? err['message'] : null;
return JobClaimResult(
accepted: json['accepted'] == true,
errorMessage: _emptyToNull(
(json['error_message'] ?? json['errorMessage'] ?? '').toString(),
(json['error_message'] ??
json['errorMessage'] ??
errMessageFromObj ??
'')
.toString(),
),
jobId: (json['job_id'] ?? json['jobId'] ?? '').toString(),
executionId: (json['execution_id'] ?? json['executionId'] ?? '')
@ -51,10 +57,16 @@ class ExecutionReportResult {
});
factory ExecutionReportResult.fromJson(Map<String, dynamic> json) {
final err = json['error'];
final errMessageFromObj = (err is Map) ? err['message'] : null;
return ExecutionReportResult(
accepted: json['accepted'] == true,
errorMessage: _emptyToNull(
(json['error_message'] ?? json['errorMessage'] ?? '').toString(),
(json['error_message'] ??
json['errorMessage'] ??
errMessageFromObj ??
'')
.toString(),
),
jobId: (json['job_id'] ?? json['jobId'] ?? '').toString(),
executionId: (json['execution_id'] ?? json['executionId'] ?? '')
@ -126,9 +138,12 @@ class OtoServerJobClient {
expectedStatus: HttpStatus.created,
);
if (response['accepted'] != true) {
final err = response['error'];
final errMessageFromObj = (err is Map) ? err['message'] : null;
throw HttpException(
(response['error_message'] ??
response['errorMessage'] ??
errMessageFromObj ??
'log rejected')
.toString(),
);
@ -151,9 +166,12 @@ class OtoServerJobClient {
expectedStatus: HttpStatus.created,
);
if (response['accepted'] != true) {
final err = response['error'];
final errMessageFromObj = (err is Map) ? err['message'] : null;
throw HttpException(
(response['error_message'] ??
response['errorMessage'] ??
errMessageFromObj ??
'artifact rejected')
.toString(),
);

View file

@ -9,6 +9,7 @@ import 'package:oto/oto/agent/edge_registration_client.dart';
import 'package:oto/oto/agent/oto_server_job_client.dart';
import 'package:oto/oto/core/build_result.dart';
import 'package:oto/oto/core/execution_context.dart';
import 'package:oto/oto/agent/oto/runner.pb.dart' as oto;
class FakeEdgeAgentSession implements EdgeAgentSession {
@override
@ -477,6 +478,189 @@ runtime:
await server.close(force: true);
}
});
test('OTO runner protocol exposes run, cancel, status, self-update message fields', () {
final runRequest = oto.RunRequest()
..runnerId = 'agent-123'
..jobId = 'job-123'
..executionId = 'exec-123'
..pipelineYamlPath = '/path/to/pipeline.yaml'
..pipelineYaml = 'commands:\n - type: Shell'
..variables.addAll({'foo': 'bar'})
..commandTypes.addAll(['Shell', 'Git']);
expect(runRequest.runnerId, 'agent-123');
expect(runRequest.jobId, 'job-123');
expect(runRequest.executionId, 'exec-123');
expect(runRequest.pipelineYamlPath, '/path/to/pipeline.yaml');
expect(runRequest.pipelineYaml, 'commands:\n - type: Shell');
expect(runRequest.variables['foo'], 'bar');
expect(runRequest.commandTypes, ['Shell', 'Git']);
final claimResponse = oto.JobClaimResponse()
..accepted = true
..runRequest = runRequest;
expect(claimResponse.runRequest.jobId, 'job-123');
final cancelRequest = oto.CancelRunRequest()
..runnerId = 'agent-123'
..executionId = 'exec-123'
..reason = 'user cancelled';
expect(cancelRequest.reason, 'user cancelled');
final cancelResponse = oto.CancelRunResponse()
..success = false
..error = (oto.ProtocolError()
..code = 'CANCEL_FAILED'
..message = 'execution not found');
expect(cancelResponse.error.code, 'CANCEL_FAILED');
expect(cancelResponse.error.message, 'execution not found');
final statusRequest = oto.RunnerStatusRequest()
..runnerId = 'agent-123';
expect(statusRequest.runnerId, 'agent-123');
final statusResponse = oto.RunnerStatusResponse()
..runnerId = 'agent-123'
..status = 'RUNNING'
..currentExecutionId = 'exec-123';
expect(statusResponse.status, 'RUNNING');
final selfUpdateRequest = oto.SelfUpdateRequest()
..runnerId = 'agent-123'
..version = 'v2.0.0'
..downloadUrl = 'http://example.com/download';
expect(selfUpdateRequest.version, 'v2.0.0');
final selfUpdateResponse = oto.SelfUpdateResponse()
..success = true;
expect(selfUpdateResponse.success, isTrue);
});
test('registration client fallback error parsing from ProtocolError map object', () async {
final server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
final serverSub = server.listen((request) async {
request.response
..headers.contentType = ContentType.json
..write(
jsonEncode({
'accepted': false,
'error': {
'code': 'REGISTRATION_FAILED',
'message': 'Failed to register via protocol error',
}
}),
);
await request.response.close();
});
try {
final config = AgentConfig(
agent: validConfig.agent,
server: ServerConnectionConfig(
url: 'http://${server.address.host}:${server.port}',
),
runtime: validConfig.runtime,
);
final client = OtoServerRegistrationClient(
commandTypes: ['Shell', 'Git'],
);
final result = await client.register(config);
expect(result.accepted, isFalse);
expect(result.rejectReason, 'Failed to register via protocol error');
} finally {
await serverSub.cancel();
await server.close(force: true);
}
});
test('job client fallback error parsing from ProtocolError map object', () async {
final server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
final serverSub = server.listen((request) async {
request.response.headers.contentType = ContentType.json;
if (request.uri.path.contains('/jobs/claim')) {
request.response.write(
jsonEncode({
'accepted': false,
'error': {
'code': 'CLAIM_FAILED',
'message': 'Failed to claim job via protocol error',
}
}),
);
} else if (request.uri.path.contains('/report')) {
request.response.write(
jsonEncode({
'accepted': false,
'error': {
'code': 'REPORT_FAILED',
'message': 'Failed to report execution via protocol error',
}
}),
);
} else if (request.uri.path.contains('/logs')) {
request.response.statusCode = HttpStatus.created;
request.response.write(
jsonEncode({
'accepted': false,
'error': {
'code': 'LOG_FAILED',
'message': 'Failed to append log via protocol error',
}
}),
);
} else if (request.uri.path.contains('/artifacts')) {
request.response.statusCode = HttpStatus.created;
request.response.write(
jsonEncode({
'accepted': false,
'error': {
'code': 'ARTIFACT_FAILED',
'message': 'Failed to report artifact via protocol error',
}
}),
);
}
await request.response.close();
});
final client = OtoServerJobClient(
serverUrl: 'http://${server.address.host}:${server.port}',
runnerId: 'agent-123',
);
try {
final claim = await client.claimJob(
jobId: 'job-123',
executionId: 'exec-123',
);
expect(claim.accepted, isFalse);
expect(claim.errorMessage, 'Failed to claim job via protocol error');
final report = await client.reportExecution(
jobId: 'job-123',
executionId: 'exec-123',
result: BuildResult.failure('fail', StackTrace.empty),
);
expect(report.accepted, isFalse);
expect(report.errorMessage, 'Failed to report execution via protocol error');
await expectLater(
client.appendLog(executionId: 'exec-123', line: 'test log'),
throwsA(isA<HttpException>().having((e) => e.message, 'message', 'Failed to append log via protocol error')),
);
await expectLater(
client.reportArtifact(executionId: 'exec-123', name: 'art', path: 'path'),
throwsA(isA<HttpException>().having((e) => e.message, 'message', 'Failed to report artifact via protocol error')),
);
} finally {
client.close();
await serverSub.cancel();
await server.close(force: true);
}
});
});
group('AgentRunner', () {

View file

@ -27,6 +27,7 @@ message RegisterRunnerResponse {
string reject_reason = 2;
string runner_id = 3;
string alias = 4;
ProtocolError error = 5;
}
enum HeartbeatStatus {
@ -43,6 +44,7 @@ message HeartbeatRequest {
message HeartbeatResponse {
bool success = 1;
string error_message = 2;
ProtocolError error = 3;
}
message BootstrapCommandRequest {
@ -67,6 +69,8 @@ message JobClaimResponse {
string execution_id = 4;
string state = 5;
string runner_id = 6;
RunRequest run_request = 7;
ProtocolError error = 8;
}
message StepEventReport {
@ -97,6 +101,7 @@ message ExecutionReportResponse {
string execution_id = 4;
string state = 5;
string runner_id = 6;
ProtocolError error = 7;
}
message LogAppendRequest {
@ -108,6 +113,7 @@ message LogAppendRequest {
message LogAppendResponse {
bool accepted = 1;
string error_message = 2;
ProtocolError error = 3;
}
message ArtifactReportRequest {
@ -120,4 +126,56 @@ message ArtifactReportRequest {
message ArtifactReportResponse {
bool accepted = 1;
string error_message = 2;
ProtocolError error = 3;
}
message ProtocolError {
string code = 1;
string message = 2;
map<string, string> details = 3;
}
message RunRequest {
string runner_id = 1;
string job_id = 2;
string execution_id = 3;
string pipeline_yaml_path = 4; // Path to the pipeline YAML file to be executed
string pipeline_yaml = 5; // Inline content of the pipeline YAML if passed directly
map<string, string> variables = 6; // Execution variables/parameters
repeated string command_types = 7; // List of command types that are allowed or required, representing the capability/catalog limits
}
message CancelRunRequest {
string runner_id = 1;
string execution_id = 2;
string reason = 3;
}
message CancelRunResponse {
bool success = 1;
string error_message = 2;
ProtocolError error = 3;
}
message RunnerStatusRequest {
string runner_id = 1;
}
message RunnerStatusResponse {
string runner_id = 1;
string status = 2;
string current_execution_id = 3;
ProtocolError error = 4;
}
message SelfUpdateRequest {
string runner_id = 1;
string version = 2;
string download_url = 3;
}
message SelfUpdateResponse {
bool success = 1;
string error_message = 2;
ProtocolError error = 3;
}

View file

@ -256,6 +256,7 @@ type RegisterRunnerResponse struct {
RejectReason string `protobuf:"bytes,2,opt,name=reject_reason,json=rejectReason,proto3" json:"reject_reason,omitempty"`
RunnerId string `protobuf:"bytes,3,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"`
Alias string `protobuf:"bytes,4,opt,name=alias,proto3" json:"alias,omitempty"`
Error *ProtocolError `protobuf:"bytes,5,opt,name=error,proto3" json:"error,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@ -318,6 +319,13 @@ func (x *RegisterRunnerResponse) GetAlias() string {
return ""
}
func (x *RegisterRunnerResponse) GetError() *ProtocolError {
if x != nil {
return x.Error
}
return nil
}
type HeartbeatRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
RunnerId string `protobuf:"bytes,1,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"`
@ -374,6 +382,7 @@ type HeartbeatResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
ErrorMessage string `protobuf:"bytes,2,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"`
Error *ProtocolError `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@ -422,6 +431,13 @@ func (x *HeartbeatResponse) GetErrorMessage() string {
return ""
}
func (x *HeartbeatResponse) GetError() *ProtocolError {
if x != nil {
return x.Error
}
return nil
}
type BootstrapCommandRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
RunnerId string `protobuf:"bytes,1,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"`
@ -586,6 +602,8 @@ type JobClaimResponse struct {
ExecutionId string `protobuf:"bytes,4,opt,name=execution_id,json=executionId,proto3" json:"execution_id,omitempty"`
State string `protobuf:"bytes,5,opt,name=state,proto3" json:"state,omitempty"`
RunnerId string `protobuf:"bytes,6,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"`
RunRequest *RunRequest `protobuf:"bytes,7,opt,name=run_request,json=runRequest,proto3" json:"run_request,omitempty"`
Error *ProtocolError `protobuf:"bytes,8,opt,name=error,proto3" json:"error,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@ -662,6 +680,20 @@ func (x *JobClaimResponse) GetRunnerId() string {
return ""
}
func (x *JobClaimResponse) GetRunRequest() *RunRequest {
if x != nil {
return x.RunRequest
}
return nil
}
func (x *JobClaimResponse) GetError() *ProtocolError {
if x != nil {
return x.Error
}
return nil
}
type StepEventReport struct {
state protoimpl.MessageState `protogen:"open.v1"`
StepId int32 `protobuf:"varint,1,opt,name=step_id,json=stepId,proto3" json:"step_id,omitempty"`
@ -862,6 +894,7 @@ type ExecutionReportResponse struct {
ExecutionId string `protobuf:"bytes,4,opt,name=execution_id,json=executionId,proto3" json:"execution_id,omitempty"`
State string `protobuf:"bytes,5,opt,name=state,proto3" json:"state,omitempty"`
RunnerId string `protobuf:"bytes,6,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"`
Error *ProtocolError `protobuf:"bytes,7,opt,name=error,proto3" json:"error,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@ -938,6 +971,13 @@ func (x *ExecutionReportResponse) GetRunnerId() string {
return ""
}
func (x *ExecutionReportResponse) GetError() *ProtocolError {
if x != nil {
return x.Error
}
return nil
}
type LogAppendRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
RunnerId string `protobuf:"bytes,1,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"`
@ -1002,6 +1042,7 @@ type LogAppendResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Accepted bool `protobuf:"varint,1,opt,name=accepted,proto3" json:"accepted,omitempty"`
ErrorMessage string `protobuf:"bytes,2,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"`
Error *ProtocolError `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@ -1050,6 +1091,13 @@ func (x *LogAppendResponse) GetErrorMessage() string {
return ""
}
func (x *LogAppendResponse) GetError() *ProtocolError {
if x != nil {
return x.Error
}
return nil
}
type ArtifactReportRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
RunnerId string `protobuf:"bytes,1,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"`
@ -1122,6 +1170,7 @@ type ArtifactReportResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Accepted bool `protobuf:"varint,1,opt,name=accepted,proto3" json:"accepted,omitempty"`
ErrorMessage string `protobuf:"bytes,2,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"`
Error *ProtocolError `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@ -1170,6 +1219,517 @@ func (x *ArtifactReportResponse) GetErrorMessage() string {
return ""
}
func (x *ArtifactReportResponse) GetError() *ProtocolError {
if x != nil {
return x.Error
}
return nil
}
type ProtocolError struct {
state protoimpl.MessageState `protogen:"open.v1"`
Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"`
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
Details map[string]string `protobuf:"bytes,3,rep,name=details,proto3" json:"details,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ProtocolError) Reset() {
*x = ProtocolError{}
mi := &file_oto_runner_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ProtocolError) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ProtocolError) ProtoMessage() {}
func (x *ProtocolError) ProtoReflect() protoreflect.Message {
mi := &file_oto_runner_proto_msgTypes[17]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ProtocolError.ProtoReflect.Descriptor instead.
func (*ProtocolError) Descriptor() ([]byte, []int) {
return file_oto_runner_proto_rawDescGZIP(), []int{17}
}
func (x *ProtocolError) GetCode() string {
if x != nil {
return x.Code
}
return ""
}
func (x *ProtocolError) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
func (x *ProtocolError) GetDetails() map[string]string {
if x != nil {
return x.Details
}
return nil
}
type RunRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
RunnerId string `protobuf:"bytes,1,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"`
JobId string `protobuf:"bytes,2,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
ExecutionId string `protobuf:"bytes,3,opt,name=execution_id,json=executionId,proto3" json:"execution_id,omitempty"`
PipelineYamlPath string `protobuf:"bytes,4,opt,name=pipeline_yaml_path,json=pipelineYamlPath,proto3" json:"pipeline_yaml_path,omitempty"` // Path to the pipeline YAML file to be executed
PipelineYaml string `protobuf:"bytes,5,opt,name=pipeline_yaml,json=pipelineYaml,proto3" json:"pipeline_yaml,omitempty"` // Inline content of the pipeline YAML if passed directly
Variables map[string]string `protobuf:"bytes,6,rep,name=variables,proto3" json:"variables,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // Execution variables/parameters
CommandTypes []string `protobuf:"bytes,7,rep,name=command_types,json=commandTypes,proto3" json:"command_types,omitempty"` // List of command types that are allowed or required, representing the capability/catalog limits
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RunRequest) Reset() {
*x = RunRequest{}
mi := &file_oto_runner_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RunRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RunRequest) ProtoMessage() {}
func (x *RunRequest) ProtoReflect() protoreflect.Message {
mi := &file_oto_runner_proto_msgTypes[18]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RunRequest.ProtoReflect.Descriptor instead.
func (*RunRequest) Descriptor() ([]byte, []int) {
return file_oto_runner_proto_rawDescGZIP(), []int{18}
}
func (x *RunRequest) GetRunnerId() string {
if x != nil {
return x.RunnerId
}
return ""
}
func (x *RunRequest) GetJobId() string {
if x != nil {
return x.JobId
}
return ""
}
func (x *RunRequest) GetExecutionId() string {
if x != nil {
return x.ExecutionId
}
return ""
}
func (x *RunRequest) GetPipelineYamlPath() string {
if x != nil {
return x.PipelineYamlPath
}
return ""
}
func (x *RunRequest) GetPipelineYaml() string {
if x != nil {
return x.PipelineYaml
}
return ""
}
func (x *RunRequest) GetVariables() map[string]string {
if x != nil {
return x.Variables
}
return nil
}
func (x *RunRequest) GetCommandTypes() []string {
if x != nil {
return x.CommandTypes
}
return nil
}
type CancelRunRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
RunnerId string `protobuf:"bytes,1,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"`
ExecutionId string `protobuf:"bytes,2,opt,name=execution_id,json=executionId,proto3" json:"execution_id,omitempty"`
Reason string `protobuf:"bytes,3,opt,name=reason,proto3" json:"reason,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CancelRunRequest) Reset() {
*x = CancelRunRequest{}
mi := &file_oto_runner_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CancelRunRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CancelRunRequest) ProtoMessage() {}
func (x *CancelRunRequest) ProtoReflect() protoreflect.Message {
mi := &file_oto_runner_proto_msgTypes[19]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CancelRunRequest.ProtoReflect.Descriptor instead.
func (*CancelRunRequest) Descriptor() ([]byte, []int) {
return file_oto_runner_proto_rawDescGZIP(), []int{19}
}
func (x *CancelRunRequest) GetRunnerId() string {
if x != nil {
return x.RunnerId
}
return ""
}
func (x *CancelRunRequest) GetExecutionId() string {
if x != nil {
return x.ExecutionId
}
return ""
}
func (x *CancelRunRequest) GetReason() string {
if x != nil {
return x.Reason
}
return ""
}
type CancelRunResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
ErrorMessage string `protobuf:"bytes,2,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"`
Error *ProtocolError `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CancelRunResponse) Reset() {
*x = CancelRunResponse{}
mi := &file_oto_runner_proto_msgTypes[20]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CancelRunResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CancelRunResponse) ProtoMessage() {}
func (x *CancelRunResponse) ProtoReflect() protoreflect.Message {
mi := &file_oto_runner_proto_msgTypes[20]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CancelRunResponse.ProtoReflect.Descriptor instead.
func (*CancelRunResponse) Descriptor() ([]byte, []int) {
return file_oto_runner_proto_rawDescGZIP(), []int{20}
}
func (x *CancelRunResponse) GetSuccess() bool {
if x != nil {
return x.Success
}
return false
}
func (x *CancelRunResponse) GetErrorMessage() string {
if x != nil {
return x.ErrorMessage
}
return ""
}
func (x *CancelRunResponse) GetError() *ProtocolError {
if x != nil {
return x.Error
}
return nil
}
type RunnerStatusRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
RunnerId string `protobuf:"bytes,1,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RunnerStatusRequest) Reset() {
*x = RunnerStatusRequest{}
mi := &file_oto_runner_proto_msgTypes[21]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RunnerStatusRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RunnerStatusRequest) ProtoMessage() {}
func (x *RunnerStatusRequest) ProtoReflect() protoreflect.Message {
mi := &file_oto_runner_proto_msgTypes[21]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RunnerStatusRequest.ProtoReflect.Descriptor instead.
func (*RunnerStatusRequest) Descriptor() ([]byte, []int) {
return file_oto_runner_proto_rawDescGZIP(), []int{21}
}
func (x *RunnerStatusRequest) GetRunnerId() string {
if x != nil {
return x.RunnerId
}
return ""
}
type RunnerStatusResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
RunnerId string `protobuf:"bytes,1,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"`
Status string `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"`
CurrentExecutionId string `protobuf:"bytes,3,opt,name=current_execution_id,json=currentExecutionId,proto3" json:"current_execution_id,omitempty"`
Error *ProtocolError `protobuf:"bytes,4,opt,name=error,proto3" json:"error,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RunnerStatusResponse) Reset() {
*x = RunnerStatusResponse{}
mi := &file_oto_runner_proto_msgTypes[22]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RunnerStatusResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RunnerStatusResponse) ProtoMessage() {}
func (x *RunnerStatusResponse) ProtoReflect() protoreflect.Message {
mi := &file_oto_runner_proto_msgTypes[22]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RunnerStatusResponse.ProtoReflect.Descriptor instead.
func (*RunnerStatusResponse) Descriptor() ([]byte, []int) {
return file_oto_runner_proto_rawDescGZIP(), []int{22}
}
func (x *RunnerStatusResponse) GetRunnerId() string {
if x != nil {
return x.RunnerId
}
return ""
}
func (x *RunnerStatusResponse) GetStatus() string {
if x != nil {
return x.Status
}
return ""
}
func (x *RunnerStatusResponse) GetCurrentExecutionId() string {
if x != nil {
return x.CurrentExecutionId
}
return ""
}
func (x *RunnerStatusResponse) GetError() *ProtocolError {
if x != nil {
return x.Error
}
return nil
}
type SelfUpdateRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
RunnerId string `protobuf:"bytes,1,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"`
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
DownloadUrl string `protobuf:"bytes,3,opt,name=download_url,json=downloadUrl,proto3" json:"download_url,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SelfUpdateRequest) Reset() {
*x = SelfUpdateRequest{}
mi := &file_oto_runner_proto_msgTypes[23]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SelfUpdateRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SelfUpdateRequest) ProtoMessage() {}
func (x *SelfUpdateRequest) ProtoReflect() protoreflect.Message {
mi := &file_oto_runner_proto_msgTypes[23]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SelfUpdateRequest.ProtoReflect.Descriptor instead.
func (*SelfUpdateRequest) Descriptor() ([]byte, []int) {
return file_oto_runner_proto_rawDescGZIP(), []int{23}
}
func (x *SelfUpdateRequest) GetRunnerId() string {
if x != nil {
return x.RunnerId
}
return ""
}
func (x *SelfUpdateRequest) GetVersion() string {
if x != nil {
return x.Version
}
return ""
}
func (x *SelfUpdateRequest) GetDownloadUrl() string {
if x != nil {
return x.DownloadUrl
}
return ""
}
type SelfUpdateResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
ErrorMessage string `protobuf:"bytes,2,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"`
Error *ProtocolError `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *SelfUpdateResponse) Reset() {
*x = SelfUpdateResponse{}
mi := &file_oto_runner_proto_msgTypes[24]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *SelfUpdateResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*SelfUpdateResponse) ProtoMessage() {}
func (x *SelfUpdateResponse) ProtoReflect() protoreflect.Message {
mi := &file_oto_runner_proto_msgTypes[24]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use SelfUpdateResponse.ProtoReflect.Descriptor instead.
func (*SelfUpdateResponse) Descriptor() ([]byte, []int) {
return file_oto_runner_proto_rawDescGZIP(), []int{24}
}
func (x *SelfUpdateResponse) GetSuccess() bool {
if x != nil {
return x.Success
}
return false
}
func (x *SelfUpdateResponse) GetErrorMessage() string {
if x != nil {
return x.ErrorMessage
}
return ""
}
func (x *SelfUpdateResponse) GetError() *ProtocolError {
if x != nil {
return x.Error
}
return nil
}
var File_oto_runner_proto protoreflect.FileDescriptor
const file_oto_runner_proto_rawDesc = "" +
@ -1188,18 +1748,20 @@ const file_oto_runner_proto_rawDesc = "" +
"\n" +
"capability\x18\x05 \x01(\v2\x1f.oto.runner.v1.RunnerCapabilityR\n" +
"capability\x12M\n" +
"\x0fcommand_catalog\x18\x06 \x01(\v2$.oto.runner.v1.CommandCatalogSummaryR\x0ecommandCatalog\"\x8c\x01\n" +
"\x0fcommand_catalog\x18\x06 \x01(\v2$.oto.runner.v1.CommandCatalogSummaryR\x0ecommandCatalog\"\xc0\x01\n" +
"\x16RegisterRunnerResponse\x12\x1a\n" +
"\baccepted\x18\x01 \x01(\bR\baccepted\x12#\n" +
"\rreject_reason\x18\x02 \x01(\tR\frejectReason\x12\x1b\n" +
"\trunner_id\x18\x03 \x01(\tR\brunnerId\x12\x14\n" +
"\x05alias\x18\x04 \x01(\tR\x05alias\"g\n" +
"\x05alias\x18\x04 \x01(\tR\x05alias\x122\n" +
"\x05error\x18\x05 \x01(\v2\x1c.oto.runner.v1.ProtocolErrorR\x05error\"g\n" +
"\x10HeartbeatRequest\x12\x1b\n" +
"\trunner_id\x18\x01 \x01(\tR\brunnerId\x126\n" +
"\x06status\x18\x02 \x01(\x0e2\x1e.oto.runner.v1.HeartbeatStatusR\x06status\"R\n" +
"\x06status\x18\x02 \x01(\x0e2\x1e.oto.runner.v1.HeartbeatStatusR\x06status\"\x86\x01\n" +
"\x11HeartbeatResponse\x12\x18\n" +
"\asuccess\x18\x01 \x01(\bR\asuccess\x12#\n" +
"\rerror_message\x18\x02 \x01(\tR\ferrorMessage\"a\n" +
"\rerror_message\x18\x02 \x01(\tR\ferrorMessage\x122\n" +
"\x05error\x18\x03 \x01(\v2\x1c.oto.runner.v1.ProtocolErrorR\x05error\"a\n" +
"\x17BootstrapCommandRequest\x12\x1b\n" +
"\trunner_id\x18\x01 \x01(\tR\brunnerId\x12)\n" +
"\x10enrollment_token\x18\x02 \x01(\tR\x0fenrollmentToken\"G\n" +
@ -1208,14 +1770,17 @@ const file_oto_runner_proto_rawDesc = "" +
"\x0fJobClaimRequest\x12\x1b\n" +
"\trunner_id\x18\x01 \x01(\tR\brunnerId\x12\x15\n" +
"\x06job_id\x18\x02 \x01(\tR\x05jobId\x12!\n" +
"\fexecution_id\x18\x03 \x01(\tR\vexecutionId\"\xc0\x01\n" +
"\fexecution_id\x18\x03 \x01(\tR\vexecutionId\"\xb0\x02\n" +
"\x10JobClaimResponse\x12\x1a\n" +
"\baccepted\x18\x01 \x01(\bR\baccepted\x12#\n" +
"\rerror_message\x18\x02 \x01(\tR\ferrorMessage\x12\x15\n" +
"\x06job_id\x18\x03 \x01(\tR\x05jobId\x12!\n" +
"\fexecution_id\x18\x04 \x01(\tR\vexecutionId\x12\x14\n" +
"\x05state\x18\x05 \x01(\tR\x05state\x12\x1b\n" +
"\trunner_id\x18\x06 \x01(\tR\brunnerId\"\xdf\x02\n" +
"\trunner_id\x18\x06 \x01(\tR\brunnerId\x12:\n" +
"\vrun_request\x18\a \x01(\v2\x19.oto.runner.v1.RunRequestR\n" +
"runRequest\x122\n" +
"\x05error\x18\b \x01(\v2\x1c.oto.runner.v1.ProtocolErrorR\x05error\"\xdf\x02\n" +
"\x0fStepEventReport\x12\x17\n" +
"\astep_id\x18\x01 \x01(\x05R\x06stepId\x12%\n" +
"\x0eworkflow_index\x18\x02 \x01(\x05R\rworkflowIndex\x12\x1b\n" +
@ -1238,29 +1803,74 @@ const file_oto_runner_proto_rawDesc = "" +
"\texit_code\x18\x05 \x01(\x05R\bexitCode\x12\x18\n" +
"\amessage\x18\x06 \x01(\tR\amessage\x12?\n" +
"\vstep_events\x18\a \x03(\v2\x1e.oto.runner.v1.StepEventReportR\n" +
"stepEvents\"\xc7\x01\n" +
"stepEvents\"\xfb\x01\n" +
"\x17ExecutionReportResponse\x12\x1a\n" +
"\baccepted\x18\x01 \x01(\bR\baccepted\x12#\n" +
"\rerror_message\x18\x02 \x01(\tR\ferrorMessage\x12\x15\n" +
"\x06job_id\x18\x03 \x01(\tR\x05jobId\x12!\n" +
"\fexecution_id\x18\x04 \x01(\tR\vexecutionId\x12\x14\n" +
"\x05state\x18\x05 \x01(\tR\x05state\x12\x1b\n" +
"\trunner_id\x18\x06 \x01(\tR\brunnerId\"f\n" +
"\trunner_id\x18\x06 \x01(\tR\brunnerId\x122\n" +
"\x05error\x18\a \x01(\v2\x1c.oto.runner.v1.ProtocolErrorR\x05error\"f\n" +
"\x10LogAppendRequest\x12\x1b\n" +
"\trunner_id\x18\x01 \x01(\tR\brunnerId\x12!\n" +
"\fexecution_id\x18\x02 \x01(\tR\vexecutionId\x12\x12\n" +
"\x04line\x18\x03 \x01(\tR\x04line\"T\n" +
"\x04line\x18\x03 \x01(\tR\x04line\"\x88\x01\n" +
"\x11LogAppendResponse\x12\x1a\n" +
"\baccepted\x18\x01 \x01(\bR\baccepted\x12#\n" +
"\rerror_message\x18\x02 \x01(\tR\ferrorMessage\"\x7f\n" +
"\rerror_message\x18\x02 \x01(\tR\ferrorMessage\x122\n" +
"\x05error\x18\x03 \x01(\v2\x1c.oto.runner.v1.ProtocolErrorR\x05error\"\x7f\n" +
"\x15ArtifactReportRequest\x12\x1b\n" +
"\trunner_id\x18\x01 \x01(\tR\brunnerId\x12!\n" +
"\fexecution_id\x18\x02 \x01(\tR\vexecutionId\x12\x12\n" +
"\x04name\x18\x03 \x01(\tR\x04name\x12\x12\n" +
"\x04path\x18\x04 \x01(\tR\x04path\"Y\n" +
"\x04path\x18\x04 \x01(\tR\x04path\"\x8d\x01\n" +
"\x16ArtifactReportResponse\x12\x1a\n" +
"\baccepted\x18\x01 \x01(\bR\baccepted\x12#\n" +
"\rerror_message\x18\x02 \x01(\tR\ferrorMessage*q\n" +
"\rerror_message\x18\x02 \x01(\tR\ferrorMessage\x122\n" +
"\x05error\x18\x03 \x01(\v2\x1c.oto.runner.v1.ProtocolErrorR\x05error\"\xbe\x01\n" +
"\rProtocolError\x12\x12\n" +
"\x04code\x18\x01 \x01(\tR\x04code\x12\x18\n" +
"\amessage\x18\x02 \x01(\tR\amessage\x12C\n" +
"\adetails\x18\x03 \x03(\v2).oto.runner.v1.ProtocolError.DetailsEntryR\adetails\x1a:\n" +
"\fDetailsEntry\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xe1\x02\n" +
"\n" +
"RunRequest\x12\x1b\n" +
"\trunner_id\x18\x01 \x01(\tR\brunnerId\x12\x15\n" +
"\x06job_id\x18\x02 \x01(\tR\x05jobId\x12!\n" +
"\fexecution_id\x18\x03 \x01(\tR\vexecutionId\x12,\n" +
"\x12pipeline_yaml_path\x18\x04 \x01(\tR\x10pipelineYamlPath\x12#\n" +
"\rpipeline_yaml\x18\x05 \x01(\tR\fpipelineYaml\x12F\n" +
"\tvariables\x18\x06 \x03(\v2(.oto.runner.v1.RunRequest.VariablesEntryR\tvariables\x12#\n" +
"\rcommand_types\x18\a \x03(\tR\fcommandTypes\x1a<\n" +
"\x0eVariablesEntry\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"j\n" +
"\x10CancelRunRequest\x12\x1b\n" +
"\trunner_id\x18\x01 \x01(\tR\brunnerId\x12!\n" +
"\fexecution_id\x18\x02 \x01(\tR\vexecutionId\x12\x16\n" +
"\x06reason\x18\x03 \x01(\tR\x06reason\"\x86\x01\n" +
"\x11CancelRunResponse\x12\x18\n" +
"\asuccess\x18\x01 \x01(\bR\asuccess\x12#\n" +
"\rerror_message\x18\x02 \x01(\tR\ferrorMessage\x122\n" +
"\x05error\x18\x03 \x01(\v2\x1c.oto.runner.v1.ProtocolErrorR\x05error\"2\n" +
"\x13RunnerStatusRequest\x12\x1b\n" +
"\trunner_id\x18\x01 \x01(\tR\brunnerId\"\xb1\x01\n" +
"\x14RunnerStatusResponse\x12\x1b\n" +
"\trunner_id\x18\x01 \x01(\tR\brunnerId\x12\x16\n" +
"\x06status\x18\x02 \x01(\tR\x06status\x120\n" +
"\x14current_execution_id\x18\x03 \x01(\tR\x12currentExecutionId\x122\n" +
"\x05error\x18\x04 \x01(\v2\x1c.oto.runner.v1.ProtocolErrorR\x05error\"m\n" +
"\x11SelfUpdateRequest\x12\x1b\n" +
"\trunner_id\x18\x01 \x01(\tR\brunnerId\x12\x18\n" +
"\aversion\x18\x02 \x01(\tR\aversion\x12!\n" +
"\fdownload_url\x18\x03 \x01(\tR\vdownloadUrl\"\x87\x01\n" +
"\x12SelfUpdateResponse\x12\x18\n" +
"\asuccess\x18\x01 \x01(\bR\asuccess\x12#\n" +
"\rerror_message\x18\x02 \x01(\tR\ferrorMessage\x122\n" +
"\x05error\x18\x03 \x01(\v2\x1c.oto.runner.v1.ProtocolErrorR\x05error*q\n" +
"\x0fHeartbeatStatus\x12 \n" +
"\x1cHEARTBEAT_STATUS_UNSPECIFIED\x10\x00\x12\x1c\n" +
"\x18HEARTBEAT_STATUS_HEALTHY\x10\x01\x12\x1e\n" +
@ -1279,7 +1889,7 @@ func file_oto_runner_proto_rawDescGZIP() []byte {
}
var file_oto_runner_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_oto_runner_proto_msgTypes = make([]protoimpl.MessageInfo, 18)
var file_oto_runner_proto_msgTypes = make([]protoimpl.MessageInfo, 28)
var file_oto_runner_proto_goTypes = []any{
(HeartbeatStatus)(0), // 0: oto.runner.v1.HeartbeatStatus
(*RunnerCapability)(nil), // 1: oto.runner.v1.RunnerCapability
@ -1299,19 +1909,41 @@ var file_oto_runner_proto_goTypes = []any{
(*LogAppendResponse)(nil), // 15: oto.runner.v1.LogAppendResponse
(*ArtifactReportRequest)(nil), // 16: oto.runner.v1.ArtifactReportRequest
(*ArtifactReportResponse)(nil), // 17: oto.runner.v1.ArtifactReportResponse
nil, // 18: oto.runner.v1.StepEventReport.ErrorEntry
(*ProtocolError)(nil), // 18: oto.runner.v1.ProtocolError
(*RunRequest)(nil), // 19: oto.runner.v1.RunRequest
(*CancelRunRequest)(nil), // 20: oto.runner.v1.CancelRunRequest
(*CancelRunResponse)(nil), // 21: oto.runner.v1.CancelRunResponse
(*RunnerStatusRequest)(nil), // 22: oto.runner.v1.RunnerStatusRequest
(*RunnerStatusResponse)(nil), // 23: oto.runner.v1.RunnerStatusResponse
(*SelfUpdateRequest)(nil), // 24: oto.runner.v1.SelfUpdateRequest
(*SelfUpdateResponse)(nil), // 25: oto.runner.v1.SelfUpdateResponse
nil, // 26: oto.runner.v1.StepEventReport.ErrorEntry
nil, // 27: oto.runner.v1.ProtocolError.DetailsEntry
nil, // 28: oto.runner.v1.RunRequest.VariablesEntry
}
var file_oto_runner_proto_depIdxs = []int32{
1, // 0: oto.runner.v1.RegisterRunnerRequest.capability:type_name -> oto.runner.v1.RunnerCapability
2, // 1: oto.runner.v1.RegisterRunnerRequest.command_catalog:type_name -> oto.runner.v1.CommandCatalogSummary
0, // 2: oto.runner.v1.HeartbeatRequest.status:type_name -> oto.runner.v1.HeartbeatStatus
18, // 3: oto.runner.v1.StepEventReport.error:type_name -> oto.runner.v1.StepEventReport.ErrorEntry
11, // 4: oto.runner.v1.ExecutionReportRequest.step_events:type_name -> oto.runner.v1.StepEventReport
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
18, // 2: oto.runner.v1.RegisterRunnerResponse.error:type_name -> oto.runner.v1.ProtocolError
0, // 3: oto.runner.v1.HeartbeatRequest.status:type_name -> oto.runner.v1.HeartbeatStatus
18, // 4: oto.runner.v1.HeartbeatResponse.error:type_name -> oto.runner.v1.ProtocolError
19, // 5: oto.runner.v1.JobClaimResponse.run_request:type_name -> oto.runner.v1.RunRequest
18, // 6: oto.runner.v1.JobClaimResponse.error:type_name -> oto.runner.v1.ProtocolError
26, // 7: oto.runner.v1.StepEventReport.error:type_name -> oto.runner.v1.StepEventReport.ErrorEntry
11, // 8: oto.runner.v1.ExecutionReportRequest.step_events:type_name -> oto.runner.v1.StepEventReport
18, // 9: oto.runner.v1.ExecutionReportResponse.error:type_name -> oto.runner.v1.ProtocolError
18, // 10: oto.runner.v1.LogAppendResponse.error:type_name -> oto.runner.v1.ProtocolError
18, // 11: oto.runner.v1.ArtifactReportResponse.error:type_name -> oto.runner.v1.ProtocolError
27, // 12: oto.runner.v1.ProtocolError.details:type_name -> oto.runner.v1.ProtocolError.DetailsEntry
28, // 13: oto.runner.v1.RunRequest.variables:type_name -> oto.runner.v1.RunRequest.VariablesEntry
18, // 14: oto.runner.v1.CancelRunResponse.error:type_name -> oto.runner.v1.ProtocolError
18, // 15: oto.runner.v1.RunnerStatusResponse.error:type_name -> oto.runner.v1.ProtocolError
18, // 16: oto.runner.v1.SelfUpdateResponse.error:type_name -> oto.runner.v1.ProtocolError
17, // [17:17] is the sub-list for method output_type
17, // [17:17] is the sub-list for method input_type
17, // [17:17] is the sub-list for extension type_name
17, // [17:17] is the sub-list for extension extendee
0, // [0:17] is the sub-list for field type_name
}
func init() { file_oto_runner_proto_init() }
@ -1325,7 +1957,7 @@ func file_oto_runner_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_oto_runner_proto_rawDesc), len(file_oto_runner_proto_rawDesc)),
NumEnums: 1,
NumMessages: 18,
NumMessages: 28,
NumExtensions: 0,
NumServices: 0,
},