Skip to content

[AgentProfile][ts-client] AgentProfile types + client + resolve/materialize types + deriveSwitchPlan #3722

@simonrosenberg

Description

@simonrosenberg

Phase 3 — typescript-client · typescript-client · size M · Parent epic #3713

Depends on: [agent-server] /api/agent-profiles router + provenance (#3719, #3720)

ts-client is a small, hand-written repo (no codegen). Work is purely additive. Split into 2 PRs only if the diff gets unwieldy.

Context

The client is a thin, hand-written wrapper (no codegen). Hard ordering: author only after the SDK schema + routers are frozen. No MCPProfilesClient is needed — mcp_server_refs is a plain string[] | null field. The ACP provider credential metadata (api_key_env_var, base_url_env_var, file_secrets) is static and goes directly into src/utils/acp.ts — no API call needed.

Scope

1. AgentProfile union + client

  • AgentProfile discriminated union (on agent_kind) in src/models/agent-profile.ts:
    • OpenHands variant: { id, name, revision, llm_profile_ref: string, mcp_server_refs: string[] | null, agent, skills, system_message_suffix, condenser, verification, enable_sub_agents, tool_concurrency_limit }
    • ACP variant: { id, name, revision, acp_server, acp_model, acp_session_mode, acp_prompt_timeout, acp_command, acp_args, mcp_server_refs: string[] | null }no llm_profile_ref, no credential field
    • AgentProfileSummary for lists.
  • src/client/agent-profiles-client.ts over /api/agent-profiles (list/get/save/delete/rename/activate/materialize), surfacing 409-on-referenced + 422-dangling-mcp-server-ref errors via HttpError status.
  • Typed agent_profile_id on the conversation-create path (CreateConversationPayload is Record<string, unknown> today — additive, no break).

2. ACP provider descriptor extension

3. Resolve/materialize types + deriveSwitchPlan

  • Type the materialize response (resolved AgentSettingsConfig union + ref resolved/dangling status + valid verdict) and the LaunchedProfile { id, revision, snapshot } provenance.
  • Pure deriveSwitchPlan(snapshot, targetProfile, providerInfo) → current | switch-live(mutableFields) | start-new(reason) | disabled(reason), consuming ACPProviderInfo.supports_runtime_model_switch + the existing switchProfile/switchLLM/switchAcpModel methods (conversation-client.ts:262–283). OpenHands→OpenHands live only if just the LLM differs; ACP→ACP live only if same provider + identity and only acp_model differs and the provider supports it; kind change never live.

Wiring/publish: dedicated clients only. Wire into ConversationManager, export from src/clients.ts + src/index.ts, add api-clients.test.ts coverage. Publishing is tag-driven; canvas re-pins via the usual temp-SHA dance.

Acceptance criteria

  • Exported types match the SDK schemas field-for-field; union narrows on agent_kind (both variants have mcp_server_refs: string[] | null).
  • ACPProviderInfo has credential metadata fields for all three providers; no hardcoded provider lists in canvas.
  • FK error statuses surfaced; deriveSwitchPlan is pure + unit-tested across all ACP providers + OpenHands.
  • tsc clean; new clients tested.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions