Skip to content

Commit 7bd109d

Browse files
sallyomclaude
andcommitted
Generate feature branch of context repos only when user does not provide one
Co-Authored-By: Claude Sonnet 4.5 <[email protected]> Signed-off-by: sallyom <[email protected]>
1 parent a842983 commit 7bd109d

File tree

7 files changed

+130
-57
lines changed

7 files changed

+130
-57
lines changed

components/backend/handlers/helpers.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ func RetryWithBackoff(maxRetries int, initialDelay, maxDelay time.Duration, oper
4848
return fmt.Errorf("operation failed after %d retries: %w", maxRetries, lastErr)
4949
}
5050

51+
// ComputeAutoBranch generates the auto-branch name from a session name
52+
// This is the single source of truth for auto-branch naming in the backend
53+
// IMPORTANT: Keep pattern in sync with runner (main.py)
54+
// Pattern: ambient/{session-name}
55+
func ComputeAutoBranch(sessionName string) string {
56+
return fmt.Sprintf("ambient/%s", sessionName)
57+
}
58+
5159
// ValidateSecretAccess checks if the user has permission to perform the given verb on secrets
5260
// Returns an error if the user lacks the required permission
5361
// Accepts kubernetes.Interface for compatibility with dependency injection in tests

components/backend/handlers/sessions.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,8 @@ func ListSessions(c *gin.Context) {
409409
session.Status = parseStatus(status)
410410
}
411411

412+
session.AutoBranch = ComputeAutoBranch(item.GetName())
413+
412414
sessions = append(sessions, session)
413415
}
414416

@@ -553,9 +555,10 @@ func CreateSession(c *gin.Context) {
553555
timeout = *req.Timeout
554556
}
555557

556-
// Generate unique name
558+
// Generate unique name (timestamp-based)
559+
// Note: Runner will create branch as "ambient/{session-name}"
557560
timestamp := time.Now().Unix()
558-
name := fmt.Sprintf("ambient-%d", timestamp)
561+
name := fmt.Sprintf("%d", timestamp)
559562

560563
// Create the custom resource
561564
// Metadata
@@ -722,9 +725,10 @@ func CreateSession(c *gin.Context) {
722725
// This ensures consistent behavior whether sessions are created via API or kubectl.
723726

724727
c.JSON(http.StatusCreated, gin.H{
725-
"message": "Agentic session created successfully",
726-
"name": name,
727-
"uid": created.GetUID(),
728+
"message": "Agentic session created successfully",
729+
"name": name,
730+
"uid": created.GetUID(),
731+
"autoBranch": ComputeAutoBranch(name),
728732
})
729733
}
730734

@@ -773,6 +777,8 @@ func GetSession(c *gin.Context) {
773777
session.Status = parseStatus(status)
774778
}
775779

780+
session.AutoBranch = ComputeAutoBranch(sessionName)
781+
776782
c.JSON(http.StatusOK, session)
777783
}
778784

components/backend/types/session.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ type AgenticSession struct {
77
Metadata map[string]interface{} `json:"metadata"`
88
Spec AgenticSessionSpec `json:"spec"`
99
Status *AgenticSessionStatus `json:"status,omitempty"`
10+
// Computed field: auto-generated branch name if user doesn't provide one
11+
// IMPORTANT: Keep in sync with runner (main.py) and frontend (add-context-modal.tsx)
12+
AutoBranch string `json:"autoBranch,omitempty"`
1013
}
1114

1215
type AgenticSessionSpec struct {

components/frontend/src/app/projects/[name]/sessions/[sessionName]/components/modals/add-context-modal.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ type AddContextModalProps = {
1616
onAddRepository: (url: string, branch: string, autoPush?: boolean) => Promise<void>;
1717
onUploadFile?: () => void;
1818
isLoading?: boolean;
19-
sessionName?: string;
19+
autoBranch?: string; // Auto-generated branch from backend (single source of truth)
2020
};
2121

2222
export function AddContextModal({
@@ -25,27 +25,28 @@ export function AddContextModal({
2525
onAddRepository,
2626
onUploadFile,
2727
isLoading = false,
28-
sessionName,
28+
autoBranch,
2929
}: AddContextModalProps) {
3030
const [contextUrl, setContextUrl] = useState("");
31-
const [contextBranch, setContextBranch] = useState("main");
31+
const [contextBranch, setContextBranch] = useState(""); // Empty = use auto-generated branch
3232
const [autoPush, setAutoPush] = useState(false);
3333

3434
const handleSubmit = async () => {
3535
if (!contextUrl.trim()) return;
3636

37-
const defaultBranch = sessionName ? `sessions/${sessionName}` : 'main';
37+
// Use autoBranch from backend (single source of truth), or empty to let runner auto-generate
38+
const defaultBranch = autoBranch || '';
3839
await onAddRepository(contextUrl.trim(), contextBranch.trim() || defaultBranch, autoPush);
3940

4041
// Reset form
4142
setContextUrl("");
42-
setContextBranch("main");
43+
setContextBranch("");
4344
setAutoPush(false);
4445
};
4546

4647
const handleCancel = () => {
4748
setContextUrl("");
48-
setContextBranch("main");
49+
setContextBranch("");
4950
setAutoPush(false);
5051
onOpenChange(false);
5152
};
@@ -85,7 +86,8 @@ export function AddContextModal({
8586
<Label htmlFor="context-branch">Branch (optional)</Label>
8687
<Input
8788
id="context-branch"
88-
placeholder={sessionName ? `sessions/${sessionName}` : "main"}
89+
// Use autoBranch from backend (single source of truth)
90+
placeholder={autoBranch}
8991
value={contextBranch}
9092
onChange={(e) => setContextBranch(e.target.value)}
9193
/>

components/frontend/src/app/projects/[name]/sessions/[sessionName]/page.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1666,7 +1666,7 @@ export default function ProjectSessionDetailPage({
16661666
if (option) setSelectedDirectory(option);
16671667
}}
16681668
>
1669-
<SelectTrigger className="w-[250px] h-8">
1669+
<SelectTrigger className="w-[300px] min-h-[2.5rem]">
16701670
<SelectValue />
16711671
</SelectTrigger>
16721672
<SelectContent>
@@ -1699,6 +1699,7 @@ export default function ProjectSessionDetailPage({
16991699
<SelectItem
17001700
key={`${opt.type}:${opt.path}`}
17011701
value={`${opt.type}:${opt.path}`}
1702+
className="py-2"
17021703
>
17031704
<div className="flex items-center gap-2 flex-wrap w-full">
17041705
{opt.type === "artifacts" && (
@@ -2013,7 +2014,7 @@ export default function ProjectSessionDetailPage({
20132014
}}
20142015
onUploadFile={() => setUploadModalOpen(true)}
20152016
isLoading={addRepoMutation.isPending}
2016-
sessionName={sessionName}
2017+
autoBranch={session?.autoBranch}
20172018
/>
20182019

20192020
<UploadFileModal

components/frontend/src/types/api/sessions.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ export type AgenticSession = {
109109
};
110110
spec: AgenticSessionSpec;
111111
status?: AgenticSessionStatus;
112+
// Computed field from backend - auto-generated branch name
113+
// IMPORTANT: Keep in sync with backend (sessions.go) and runner (main.py)
114+
autoBranch?: string;
112115
};
113116

114117
export type CreateAgenticSessionRequest = {
@@ -130,6 +133,7 @@ export type CreateAgenticSessionResponse = {
130133
message: string;
131134
name: string;
132135
uid: string;
136+
autoBranch: string; // Auto-generated branch name (e.g., "ambient/1234567890")
133137
};
134138

135139
export type GetAgenticSessionResponse = {

0 commit comments

Comments
 (0)