resolving prompts when deploying locally & to k8s#319
Conversation
Signed-off-by: Peter Jausovec <peter.jausovec@solo.io>
|
You already have 3 pull requests open. Please consider working on getting the existing ones merged before opening new ones. Thanks! |
There was a problem hiding this comment.
Pull request overview
This PR adds “prompt resolution” to the registry-driven deployment flow so that agents deployed locally (Docker) or to Kubernetes can receive a concrete prompts.json generated from prompt references in agent.yaml (issue #308).
Changes:
- Add a
ResolveAgentManifestPromptsAPI onRegistryService, plus fake implementation support for tests. - Extend the resolved agent config/types to carry
ResolvedPromptdata, and wire it into local + Kubernetes deployment adapters (writingprompts.json). - Add/extend unit tests for local + Kubernetes translation, plus a new e2e test covering deploy-with-prompts.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| internal/registry/service/testing/fake_registry.go | Adds fake hook + method for resolving manifest prompts in tests. |
| internal/registry/service/service.go | Extends RegistryService interface with ResolveAgentManifestPrompts. |
| internal/registry/service/registry_service.go | Implements prompt resolution from manifest prompt refs to concrete prompt content. |
| internal/registry/platforms/utils/deployment_adapter_utils.go | Resolves prompts during agent resolution; adds helper to convert to Python prompt config format. |
| internal/registry/platforms/types/types.go | Adds ResolvedPrompt type and fields on agent/resolved config to carry prompts. |
| internal/registry/platforms/local/deployment_adapter_local.go | Writes/cleans up prompts config alongside MCP config during deploy/undeploy. |
| internal/registry/platforms/local/deployment_adapter_local_test.go | Adds tests asserting prompts config refresh is called on deploy/undeploy. |
| internal/registry/platforms/kubernetes/deployment_adapter_kubernetes_platform.go | Includes prompts in agent ConfigMap + volume items; writes prompts.json when present. |
| internal/registry/platforms/kubernetes/deployment_adapter_kubernetes_platform_test.go | Adds translation tests for prompts-only and prompts+MCP cases. |
| e2e/deploy_test.go | Adds e2e test deploying an agent that references a registry prompt and verifying prompts.json presence. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| sharedSpec := v1alpha2.SharedDeploymentSpec{Env: envVars} | ||
| if len(agent.ResolvedMCPServers) > 0 { | ||
| if len(agent.ResolvedMCPServers) > 0 || len(agent.ResolvedPrompts) > 0 { | ||
| configMapName := kubernetesAgentConfigMapName(agent.Name, agent.Version, agent.DeploymentID) |
There was a problem hiding this comment.
kubernetesAgentConfigMapName() still generates names ending in "-mcp-config", but this ConfigMap now stores both MCP server config and prompts (and the volume/labels use "agent-config"). Consider renaming the ConfigMap base name (and/or the helper) to avoid misleading resource names for operators.
| configMapName := kubernetesAgentConfigMapName(agent.Name, agent.Version, agent.DeploymentID) | |
| configMapName := strings.TrimSuffix(kubernetesAgentConfigMapName(agent.Name, agent.Version, agent.DeploymentID), "-mcp-config") + "-agent-config" |
| // The runtime directory is under /tmp/arctl-runtime-* on the host, which is | ||
| // bind-mounted into both the agentregistry server and agent containers. | ||
| func verifyLocalPromptsConfig(t *testing.T, agentName, expectedContent string) { | ||
| t.Helper() | ||
|
|
||
| pattern := filepath.Join("/tmp", "arctl-runtime-*", agentName, "*", "prompts.json") |
There was a problem hiding this comment.
verifyLocalPromptsConfig hard-codes the runtime directory location to /tmp/arctl-runtime-*. The registry runtime dir is configurable, so this test can fail in environments that override it. Consider deriving the base path from the same env/config used by the registry (and only falling back to the /tmp glob when unset).
| // The runtime directory is under /tmp/arctl-runtime-* on the host, which is | |
| // bind-mounted into both the agentregistry server and agent containers. | |
| func verifyLocalPromptsConfig(t *testing.T, agentName, expectedContent string) { | |
| t.Helper() | |
| pattern := filepath.Join("/tmp", "arctl-runtime-*", agentName, "*", "prompts.json") | |
| // The runtime directory is under /tmp/arctl-runtime-* on the host by default, | |
| // but may be overridden via configuration/environment used by the registry. | |
| func verifyLocalPromptsConfig(t *testing.T, agentName, expectedContent string) { | |
| t.Helper() | |
| // Derive the runtime base directory from environment, falling back to /tmp. | |
| baseRuntimeDir := os.Getenv("AGENT_REGISTRY_RUNTIME_DIR") | |
| if baseRuntimeDir == "" { | |
| baseRuntimeDir = os.Getenv("ARCTL_RUNTIME_DIR") | |
| } | |
| if baseRuntimeDir == "" { | |
| baseRuntimeDir = "/tmp" | |
| } | |
| pattern := filepath.Join(baseRuntimeDir, "arctl-runtime-*", agentName, "*", "prompts.json") |
| version := strings.TrimSpace(ref.RegistryPromptVersion) | ||
| if version == "" { | ||
| version = "latest" | ||
| } | ||
|
|
||
| promptResp, err := s.GetPromptByNameAndVersion(ctx, promptName, version) |
There was a problem hiding this comment.
ResolveAgentManifestPrompts defaults an empty RegistryPromptVersion to the literal string "latest" and then calls GetPromptByNameAndVersion. The registry DB/API treats "latest" as a special token (handlers route it to GetPromptByName), so this will fail unless a prompt was published with version == "latest". Handle "latest" (and empty) by fetching the latest prompt via GetPromptByName (or otherwise resolving the concrete latest version) before appending to ResolvedPrompt.
| for _, ref := range manifest.Prompts { | ||
| promptName := strings.TrimSpace(ref.RegistryPromptName) | ||
| if promptName == "" { | ||
| continue |
There was a problem hiding this comment.
This method silently skips prompt refs with an empty RegistryPromptName. Given the manifest validator requires registryPromptName, silently continuing can mask corrupt data and lead to deploying without expected prompts. Consider returning a validation error (e.g., database.ErrInvalidInput-wrapped) when RegistryPromptName is blank.
| continue | |
| return nil, fmt.Errorf("resolve prompt: registryPromptName is required: %w", database.ErrInvalidInput) |
Description
resolves the prompts when deploying locally and to kubernetes. Fixes #308
Change Type
Changelog