Skip to content

Commit a14738a

Browse files
authored
feat: add UI for prompt templates (#1671)
still using configmaps to store the prompts/fragments, but we'll need a follow up issue to implement a PromptLibrary CRD and replace configmaps with that. <img width="1181" height="837" alt="Screenshot 2026-04-13 at 4 09 34 PM" src="https://github.com/user-attachments/assets/16754f5d-acd6-494c-a36e-bace341fd7e9" /> <img width="961" height="727" alt="Screenshot 2026-04-13 at 4 10 17 PM" src="https://github.com/user-attachments/assets/902be34a-3dd4-41d4-b94e-92b7a4787b77" /> --------- Signed-off-by: Peter Jausovec <peter.jausovec@solo.io>
1 parent d45cd4d commit a14738a

31 files changed

Lines changed: 2563 additions & 17 deletions

go/api/httpapi/types.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,33 @@ type UpdateMemoryRequest struct {
227227
PineconeParams *v1alpha1.PineconeConfig `json:"pinecone,omitempty"`
228228
}
229229

230+
// PromptTemplateSummary is a lightweight entry for listing prompt ConfigMaps.
231+
type PromptTemplateSummary struct {
232+
Namespace string `json:"namespace"`
233+
Name string `json:"name"`
234+
KeyCount int `json:"keyCount"`
235+
Keys []string `json:"keys,omitempty"`
236+
}
237+
238+
// PromptTemplateDetail includes all string keys for editing.
239+
type PromptTemplateDetail struct {
240+
Namespace string `json:"namespace"`
241+
Name string `json:"name"`
242+
Data map[string]string `json:"data"`
243+
}
244+
245+
// CreatePromptTemplateRequest creates a labeled ConfigMap in the namespace.
246+
type CreatePromptTemplateRequest struct {
247+
Namespace string `json:"namespace"`
248+
Name string `json:"name"`
249+
Data map[string]string `json:"data"`
250+
}
251+
252+
// UpdatePromptTemplateRequest replaces the data map of an existing ConfigMap.
253+
type UpdatePromptTemplateRequest struct {
254+
Data map[string]string `json:"data"`
255+
}
256+
230257
// Namespace types
231258

232259
// NamespaceResponse represents a namespace response

go/core/internal/controller/reconciler/reconciler.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,13 @@ func (a *kagentReconciler) reconcileTranslatedAgent(
172172
}
173173
}
174174

175-
ownedObjects, err := reconcilerutils.FindOwnedObjects(ctx, a.kube, agent.GetUID(), agent.GetNamespace(), a.adkTranslator.GetOwnedResourceTypes())
175+
// TODO: create different translations with different owned objects
176+
allOwnedTypes := a.adkTranslator.GetOwnedResourceTypes()
177+
ownedTypes, err := sandboxbackend.FilterTranslatorOwnedTypesForList(a.kube, agent, allOwnedTypes, a.sandboxBackend)
178+
if err != nil {
179+
return fmt.Errorf("filter owned types for list: %w", err)
180+
}
181+
ownedObjects, err := reconcilerutils.FindOwnedObjects(ctx, a.kube, agent.GetUID(), agent.GetNamespace(), ownedTypes)
176182
if err != nil {
177183
return err
178184
}

go/core/internal/controller/translator/agent/template_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
package agent
22

33
import (
4+
"context"
45
"testing"
56

67
"github.com/stretchr/testify/assert"
78
"github.com/stretchr/testify/require"
9+
corev1 "k8s.io/api/core/v1"
810
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11+
"k8s.io/apimachinery/pkg/runtime"
12+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
913

1014
"github.com/kagent-dev/kagent/go/api/adk"
1115
"github.com/kagent-dev/kagent/go/api/v1alpha2"
@@ -313,3 +317,59 @@ func TestBuildTemplateContext(t *testing.T) {
313317
})
314318
}
315319
}
320+
321+
func TestResolvePromptSources_AliasUsesAliasOnlyInLookup(t *testing.T) {
322+
ctx := context.Background()
323+
scheme := runtime.NewScheme()
324+
require.NoError(t, corev1.AddToScheme(scheme))
325+
326+
cm := &corev1.ConfigMap{
327+
ObjectMeta: metav1.ObjectMeta{Name: "kagent-builtin-prompts", Namespace: "ns"},
328+
Data: map[string]string{
329+
"safety-guardrails": "be safe",
330+
},
331+
}
332+
cl := fake.NewClientBuilder().WithScheme(scheme).WithObjects(cm).Build()
333+
334+
sources := []v1alpha2.PromptSource{
335+
{
336+
TypedLocalReference: v1alpha2.TypedLocalReference{
337+
Kind: "ConfigMap",
338+
ApiGroup: "",
339+
Name: "kagent-builtin-prompts",
340+
},
341+
Alias: "builtin",
342+
},
343+
}
344+
345+
lookup, err := resolvePromptSources(ctx, cl, "ns", sources)
346+
require.NoError(t, err)
347+
348+
assert.Equal(t, "be safe", lookup["builtin/safety-guardrails"])
349+
_, byName := lookup["kagent-builtin-prompts/safety-guardrails"]
350+
assert.False(t, byName, "when alias is set, include paths must use alias/key, not ConfigMap name")
351+
352+
out, err := executeSystemMessageTemplate(`{{include "builtin/safety-guardrails"}}`, lookup, PromptTemplateContext{})
353+
require.NoError(t, err)
354+
assert.Equal(t, "be safe", out)
355+
}
356+
357+
func TestResolvePromptSources_NoAliasUsesConfigMapNameInLookup(t *testing.T) {
358+
ctx := context.Background()
359+
scheme := runtime.NewScheme()
360+
require.NoError(t, corev1.AddToScheme(scheme))
361+
362+
cm := &corev1.ConfigMap{
363+
ObjectMeta: metav1.ObjectMeta{Name: "my-lib", Namespace: "ns"},
364+
Data: map[string]string{"k": "v"},
365+
}
366+
cl := fake.NewClientBuilder().WithScheme(scheme).WithObjects(cm).Build()
367+
368+
lookup, err := resolvePromptSources(ctx, cl, "ns", []v1alpha2.PromptSource{
369+
{
370+
TypedLocalReference: v1alpha2.TypedLocalReference{Kind: "ConfigMap", ApiGroup: "", Name: "my-lib"},
371+
},
372+
})
373+
require.NoError(t, err)
374+
assert.Equal(t, "v", lookup["my-lib/k"])
375+
}

go/core/internal/httpserver/handlers/handlers.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type Handlers struct {
2424
Memory *MemoryHandler
2525
Feedback *FeedbackHandler
2626
Namespaces *NamespacesHandler
27+
PromptTemplates *PromptTemplatesHandler
2728
Tasks *TasksHandler
2829
Checkpoints *CheckpointsHandler
2930
CrewAI *CrewAIHandler
@@ -64,6 +65,7 @@ func NewHandlers(kubeClient client.Client, defaultModelConfig types.NamespacedNa
6465
Memory: NewMemoryHandler(base),
6566
Feedback: NewFeedbackHandler(base),
6667
Namespaces: NewNamespacesHandler(base, watchedNamespaces),
68+
PromptTemplates: NewPromptTemplatesHandler(base),
6769
Tasks: NewTasksHandler(base),
6870
Checkpoints: NewCheckpointsHandler(base),
6971
CrewAI: NewCrewAIHandler(base),

0 commit comments

Comments
 (0)