Add remote plugin skill read API (#20150)

## Summary

Adds an app-server `plugin/skill/read` method for remote plugin skill
markdown. The new method calls the plugin-service skill detail endpoint
and returns `skill_md_contents`, so clients can preview skills for
remote plugins before the bundle is installed locally.

## Why

Uninstalled remote plugin skills do not have local `SKILL.md` files.
Without an on-demand remote read, the desktop plugin details UI cannot
render the skill details modal for those skills.

## Validation

- `just write-app-server-schema`
- `just fmt`
- `cargo test -p codex-app-server-protocol`
- `cargo test -p codex-app-server --test all --
suite::v2::plugin_read::plugin_skill_read_reads_remote_skill_contents_when_remote_plugin_enabled
--exact`
- `just fix -p codex-app-server-protocol -p codex-core-plugins -p
codex-app-server`
This commit is contained in:
xli-oai
2026-05-01 00:16:25 -07:00
committed by GitHub
parent a62b52f826
commit 96d2ea9058
21 changed files with 1212 additions and 529 deletions

View File

@@ -10,7 +10,6 @@ from .generated.v2_all import (
ApprovalsReviewer,
AskForApproval,
ModelListResponse,
PermissionProfile,
Personality,
ReasoningEffort,
ReasoningSummary,
@@ -150,7 +149,6 @@ class Codex:
ephemeral: bool | None = None,
model: str | None = None,
model_provider: str | None = None,
permission_profile: PermissionProfile | None = None,
personality: Personality | None = None,
sandbox: SandboxMode | None = None,
service_name: str | None = None,
@@ -167,7 +165,6 @@ class Codex:
ephemeral=ephemeral,
model=model,
model_provider=model_provider,
permission_profile=permission_profile,
personality=personality,
sandbox=sandbox,
service_name=service_name,
@@ -215,10 +212,8 @@ class Codex:
config: JsonObject | None = None,
cwd: str | None = None,
developer_instructions: str | None = None,
exclude_turns: bool | None = None,
model: str | None = None,
model_provider: str | None = None,
permission_profile: PermissionProfile | None = None,
personality: Personality | None = None,
sandbox: SandboxMode | None = None,
service_tier: ServiceTier | None = None,
@@ -231,10 +226,8 @@ class Codex:
config=config,
cwd=cwd,
developer_instructions=developer_instructions,
exclude_turns=exclude_turns,
model=model,
model_provider=model_provider,
permission_profile=permission_profile,
personality=personality,
sandbox=sandbox,
service_tier=service_tier,
@@ -253,10 +246,8 @@ class Codex:
cwd: str | None = None,
developer_instructions: str | None = None,
ephemeral: bool | None = None,
exclude_turns: bool | None = None,
model: str | None = None,
model_provider: str | None = None,
permission_profile: PermissionProfile | None = None,
sandbox: SandboxMode | None = None,
service_tier: ServiceTier | None = None,
) -> Thread:
@@ -269,10 +260,8 @@ class Codex:
cwd=cwd,
developer_instructions=developer_instructions,
ephemeral=ephemeral,
exclude_turns=exclude_turns,
model=model,
model_provider=model_provider,
permission_profile=permission_profile,
sandbox=sandbox,
service_tier=service_tier,
)
@@ -356,7 +345,6 @@ class AsyncCodex:
ephemeral: bool | None = None,
model: str | None = None,
model_provider: str | None = None,
permission_profile: PermissionProfile | None = None,
personality: Personality | None = None,
sandbox: SandboxMode | None = None,
service_name: str | None = None,
@@ -374,7 +362,6 @@ class AsyncCodex:
ephemeral=ephemeral,
model=model,
model_provider=model_provider,
permission_profile=permission_profile,
personality=personality,
sandbox=sandbox,
service_name=service_name,
@@ -423,10 +410,8 @@ class AsyncCodex:
config: JsonObject | None = None,
cwd: str | None = None,
developer_instructions: str | None = None,
exclude_turns: bool | None = None,
model: str | None = None,
model_provider: str | None = None,
permission_profile: PermissionProfile | None = None,
personality: Personality | None = None,
sandbox: SandboxMode | None = None,
service_tier: ServiceTier | None = None,
@@ -440,10 +425,8 @@ class AsyncCodex:
config=config,
cwd=cwd,
developer_instructions=developer_instructions,
exclude_turns=exclude_turns,
model=model,
model_provider=model_provider,
permission_profile=permission_profile,
personality=personality,
sandbox=sandbox,
service_tier=service_tier,
@@ -462,10 +445,8 @@ class AsyncCodex:
cwd: str | None = None,
developer_instructions: str | None = None,
ephemeral: bool | None = None,
exclude_turns: bool | None = None,
model: str | None = None,
model_provider: str | None = None,
permission_profile: PermissionProfile | None = None,
sandbox: SandboxMode | None = None,
service_tier: ServiceTier | None = None,
) -> AsyncThread:
@@ -479,10 +460,8 @@ class AsyncCodex:
cwd=cwd,
developer_instructions=developer_instructions,
ephemeral=ephemeral,
exclude_turns=exclude_turns,
model=model,
model_provider=model_provider,
permission_profile=permission_profile,
sandbox=sandbox,
service_tier=service_tier,
)
@@ -519,7 +498,6 @@ class Thread:
effort: ReasoningEffort | None = None,
model: str | None = None,
output_schema: JsonObject | None = None,
permission_profile: PermissionProfile | None = None,
personality: Personality | None = None,
sandbox_policy: SandboxPolicy | None = None,
service_tier: ServiceTier | None = None,
@@ -533,7 +511,6 @@ class Thread:
effort=effort,
model=model,
output_schema=output_schema,
permission_profile=permission_profile,
personality=personality,
sandbox_policy=sandbox_policy,
service_tier=service_tier,
@@ -556,7 +533,6 @@ class Thread:
effort: ReasoningEffort | None = None,
model: str | None = None,
output_schema: JsonObject | None = None,
permission_profile: PermissionProfile | None = None,
personality: Personality | None = None,
sandbox_policy: SandboxPolicy | None = None,
service_tier: ServiceTier | None = None,
@@ -572,7 +548,6 @@ class Thread:
effort=effort,
model=model,
output_schema=output_schema,
permission_profile=permission_profile,
personality=personality,
sandbox_policy=sandbox_policy,
service_tier=service_tier,
@@ -607,7 +582,6 @@ class AsyncThread:
effort: ReasoningEffort | None = None,
model: str | None = None,
output_schema: JsonObject | None = None,
permission_profile: PermissionProfile | None = None,
personality: Personality | None = None,
sandbox_policy: SandboxPolicy | None = None,
service_tier: ServiceTier | None = None,
@@ -621,7 +595,6 @@ class AsyncThread:
effort=effort,
model=model,
output_schema=output_schema,
permission_profile=permission_profile,
personality=personality,
sandbox_policy=sandbox_policy,
service_tier=service_tier,
@@ -644,7 +617,6 @@ class AsyncThread:
effort: ReasoningEffort | None = None,
model: str | None = None,
output_schema: JsonObject | None = None,
permission_profile: PermissionProfile | None = None,
personality: Personality | None = None,
sandbox_policy: SandboxPolicy | None = None,
service_tier: ServiceTier | None = None,
@@ -661,7 +633,6 @@ class AsyncThread:
effort=effort,
model=model,
output_schema=output_schema,
permission_profile=permission_profile,
personality=personality,
sandbox_policy=sandbox_policy,
service_tier=service_tier,

View File

@@ -38,6 +38,7 @@ from .v2_all import PlanDeltaNotification
from .v2_all import ReasoningSummaryPartAddedNotification
from .v2_all import ReasoningSummaryTextDeltaNotification
from .v2_all import ReasoningTextDeltaNotification
from .v2_all import RemoteControlStatusChangedNotification
from .v2_all import ServerRequestResolvedNotification
from .v2_all import SkillsChangedNotification
from .v2_all import TerminalInteractionNotification
@@ -100,6 +101,7 @@ NOTIFICATION_MODELS: dict[str, type[BaseModel]] = {
"mcpServer/startupStatus/updated": McpServerStatusUpdatedNotification,
"model/rerouted": ModelReroutedNotification,
"model/verification": ModelVerificationNotification,
"remoteControl/status/changed": RemoteControlStatusChangedNotification,
"serverRequest/resolved": ServerRequestResolvedNotification,
"skills/changed": SkillsChangedNotification,
"thread/archived": ThreadArchivedNotification,

File diff suppressed because it is too large Load Diff