File size: 4,536 Bytes
3d700dd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/**
 * AgentProfilesService wraps the SDK's AgentProfilesClient, creating a client
 * per-call so it always picks up the active backend's host/apiKey (same pattern
 * as ProfilesService / SettingsService).
 *
 * Backs the Settings → Agent profiles library + reused agent editor. The
 * `AgentProfilesClient` ships in ts-client (pinned 1.28.0 here); the
 * `/api/agent-profiles` endpoints it targets shipped in agent-server v1.29.0
 * (local) and in the enterprise cloud app-server (OpenHands #15060, epic
 * #3730). Cloud exposes the SAME contract but authenticates with a bearer
 * token + `X-Org-Id`, so cloud calls route through `callCloudProxy` (see
 * `cloud/agent-profiles-service.api.ts`) instead of the direct client.
 */
import {
  AgentProfilesClient,
  type GetAgentProfileOptions,
} from "@openhands/typescript-client/clients";
import type {
  AgentProfile,
  AgentProfileSummary,
  AgentProfileSaveInput,
  AgentProfileListResponse,
  AgentProfileDetailResponse,
  AgentProfileMutationResponse,
  ActivateAgentProfileResponse,
  ExposeSecretsMode,
} from "@openhands/typescript-client";
import { getAgentServerClientOptions } from "../agent-server-client-options";
import { getActiveBackend } from "../backend-registry/active-store";
import {
  listCloudAgentProfiles,
  getCloudAgentProfile,
  saveCloudAgentProfile,
  deleteCloudAgentProfile,
  renameCloudAgentProfile,
  activateCloudAgentProfile,
} from "../cloud/agent-profiles-service.api";

function isCloud(): boolean {
  return getActiveBackend().backend.kind === "cloud";
}

/**
 * The seeded, well-known baseline agent profile. The backend lazily seeds it to
 * mirror the user's global config (#3719), and onboarding configures it from the
 * user's choice. It stands in for global `agent_settings`, so the home-launch
 * path treats it as the enriched baseline rather than a deliberate profile
 * selection (see `useCreateConversation`).
 */
export const WELL_KNOWN_DEFAULT_AGENT_PROFILE_NAME = "default";

// Re-export SDK types for consumers.
export type {
  AgentProfile,
  AgentProfileSummary,
  AgentProfileSaveInput,
  AgentProfileListResponse,
  AgentProfileDetailResponse,
  AgentProfileMutationResponse,
  ActivateAgentProfileResponse,
};

class AgentProfilesService {
  static async listProfiles(): Promise<AgentProfileListResponse> {
    if (isCloud()) return listCloudAgentProfiles();
    return new AgentProfilesClient(
      getAgentServerClientOptions(),
    ).listAgentProfiles();
  }

  static async getProfile(
    name: string,
    exposeSecrets?: ExposeSecretsMode,
  ): Promise<AgentProfileDetailResponse> {
    // Agent profiles are secret-free at rest now (embedded skills and their
    // `mcp_tools` were removed in #4017 — a profile carries only refs + the
    // `disabled_skills` deny-list of names), so `exposeSecrets` is vestigial and
    // cloud ignores it; kept for local signature parity with ProfilesService.
    if (isCloud()) return getCloudAgentProfile(name);
    const options: GetAgentProfileOptions = exposeSecrets
      ? { exposeSecrets }
      : {};
    return new AgentProfilesClient(
      getAgentServerClientOptions(),
    ).getAgentProfile(name, options);
  }

  /** Create or overwrite a profile by name (upsert). */
  static async saveProfile(
    name: string,
    profile: AgentProfileSaveInput,
  ): Promise<AgentProfileMutationResponse> {
    if (isCloud()) return saveCloudAgentProfile(name, profile);
    return new AgentProfilesClient(
      getAgentServerClientOptions(),
    ).saveAgentProfile(name, profile);
  }

  static async deleteProfile(
    name: string,
  ): Promise<AgentProfileMutationResponse> {
    if (isCloud()) return deleteCloudAgentProfile(name);
    return new AgentProfilesClient(
      getAgentServerClientOptions(),
    ).deleteAgentProfile(name);
  }

  static async renameProfile(
    name: string,
    newName: string,
  ): Promise<AgentProfileMutationResponse> {
    if (isCloud()) return renameCloudAgentProfile(name, newName);
    return new AgentProfilesClient(
      getAgentServerClientOptions(),
    ).renameAgentProfile(name, newName);
  }

  /** Activate by the profile's stable UUID `id` (pointer-only; never writes
   * agent_settings). */
  static async activateProfile(
    profileId: string,
  ): Promise<ActivateAgentProfileResponse> {
    if (isCloud()) return activateCloudAgentProfile(profileId);
    return new AgentProfilesClient(
      getAgentServerClientOptions(),
    ).activateAgentProfile(profileId);
  }
}

export default AgentProfilesService;