feat(gateway,cli): agent enrollment command family (M4-4b) (#1483)
ci/woodpecker/push/publish Pipeline was successful
ci/woodpecker/push/publish Pipeline was successful
Co-authored-by: fred <[email protected]>
This commit was merged in pull request #1483.
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
import { Type } from 'class-transformer';
|
||||
import {
|
||||
IsIn,
|
||||
IsOptional,
|
||||
IsString,
|
||||
IsUUID,
|
||||
MaxLength,
|
||||
MinLength,
|
||||
ValidateIf,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
|
||||
/**
|
||||
* Agent enrollment command DTOs (design
|
||||
* docs/plans/2026-08-29-agent-enrollment-command-design.md §3.1/§3.2,
|
||||
* contract 5 §4.1 typed boundary).
|
||||
*
|
||||
* The global ValidationPipe runs with whitelist + forbidNonWhitelisted, so
|
||||
* closure is contract surface here exactly as in the hierarchy DTOs:
|
||||
* - EnrollAgentDto declares NO isSystem field — `is_system` is never
|
||||
* settable through this command (design §3.1 rule 4); the pipe refuses it.
|
||||
* - replayMode admits ONLY 'actor-bound': `shared` is seed-only (contract 3
|
||||
* §4.3), so a shared declaration is refused `validation_failed` at the
|
||||
* boundary, executes nothing, and records no fence row (design §3.1).
|
||||
* Every class here must be registered in PIPE_GUARDED_DTOS so the boot-time
|
||||
* assertion proves the pipe sees the decorators.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Credential input, discriminated on `mode` (design §3.1):
|
||||
* - `{ mode: 'reference' }` — a stored credential for (actor, provider)
|
||||
* must already exist; `type`/`value` must be ABSENT (the repository
|
||||
* refuses a reference that smuggles a value).
|
||||
* - `{ mode: 'intake', type: 'api_key', value }` — the value is sealed
|
||||
* into the credential store inside the enrollment transaction and is
|
||||
* never echoed anywhere (§3.1 rule 1).
|
||||
*/
|
||||
export class EnrollCredentialDto {
|
||||
@IsIn(['reference', 'intake'])
|
||||
mode!: 'reference' | 'intake';
|
||||
|
||||
@ValidateIf((o: EnrollCredentialDto) => o.mode === 'intake')
|
||||
@IsIn(['api_key'])
|
||||
type?: 'api_key';
|
||||
|
||||
@ValidateIf((o: EnrollCredentialDto) => o.mode === 'intake')
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(4096)
|
||||
value?: string;
|
||||
}
|
||||
|
||||
export class EnrollAgentDto {
|
||||
/** Registered harness name; a well-formed name missing from the registry is `precondition_failed`. */
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(200)
|
||||
harness!: string;
|
||||
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(200)
|
||||
name!: string;
|
||||
|
||||
/** Stored as the agent's system prompt; null/absent leaves it unset. */
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(20000)
|
||||
persona?: string | null;
|
||||
|
||||
/** Provider-qualified model id. */
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(200)
|
||||
model!: string;
|
||||
|
||||
/** Names the credential's provider. */
|
||||
@IsString()
|
||||
@MinLength(1)
|
||||
@MaxLength(200)
|
||||
provider!: string;
|
||||
|
||||
@ValidateNested()
|
||||
@Type(() => EnrollCredentialDto)
|
||||
credential!: EnrollCredentialDto;
|
||||
|
||||
/** REQUIRED — contract 3 §4.3, ratified into contract 5 §4 via §7 item 4. */
|
||||
@IsUUID()
|
||||
idempotencyKey!: string;
|
||||
|
||||
/** Optional; generated when absent (contract 5 §4.3). */
|
||||
@IsOptional()
|
||||
@IsUUID()
|
||||
correlationId?: string;
|
||||
|
||||
/** Only 'actor-bound' is admissible on this family — see module doc. */
|
||||
@IsOptional()
|
||||
@IsIn(['actor-bound'])
|
||||
replayMode?: 'actor-bound';
|
||||
}
|
||||
|
||||
/** Query envelope for agent.enrollment.get (design §3.2): correlation only, no idempotency key. */
|
||||
export class GetEnrollmentQueryDto {
|
||||
@IsOptional()
|
||||
@IsUUID()
|
||||
correlationId?: string;
|
||||
}
|
||||
Reference in New Issue
Block a user