Skip to content

Commit 5685c7d

Browse files
committed
feat: finish most refactor and get it to build
1 parent de53b8e commit 5685c7d

33 files changed

+823
-438
lines changed

src/api-types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,13 +138,15 @@ export type {
138138
// Agent/Generator Types
139139
export type {
140140
Blueprint as BlueprintType,
141+
PhasicBlueprint,
141142
CodeReviewOutputType,
142143
FileConceptType,
143144
FileOutputType as GeneratedFile,
144145
} from 'worker/agents/schemas';
145146

146147
export type {
147-
CodeGenState
148+
AgentState,
149+
PhasicState
148150
} from 'worker/agents/core/state';
149151

150152
export type {

src/routes/chat/chat.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { ViewModeSwitch } from './components/view-mode-switch';
2121
import { DebugPanel, type DebugMessage } from './components/debug-panel';
2222
import { DeploymentControls } from './components/deployment-controls';
2323
import { useChat, type FileType } from './hooks/use-chat';
24-
import { type ModelConfigsData, type BlueprintType, SUPPORTED_IMAGE_MIME_TYPES } from '@/api-types';
24+
import { type ModelConfigsData, type BlueprintType, type PhasicBlueprint, SUPPORTED_IMAGE_MIME_TYPES } from '@/api-types';
2525
import { Copy } from './components/copy';
2626
import { useFileContentStream } from './hooks/use-file-content-stream';
2727
import { logger } from '@/utils/logger';
@@ -42,6 +42,9 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigge
4242
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog';
4343
import { sendWebSocketMessage } from './utils/websocket-helpers';
4444

45+
const isPhasicBlueprint = (blueprint?: BlueprintType | null): blueprint is PhasicBlueprint =>
46+
!!blueprint && 'implementationRoadmap' in blueprint;
47+
4548
export default function Chat() {
4649
const { chatId: urlChatId } = useParams();
4750

@@ -492,11 +495,13 @@ export default function Chat() {
492495
const completedPhases = phaseTimeline.filter(p => p.status === 'completed').length;
493496

494497
// Get predicted phase count from blueprint, fallback to current phase count
495-
const predictedPhaseCount = blueprint?.implementationRoadmap?.length || 0;
498+
const predictedPhaseCount = isPhasicBlueprint(blueprint)
499+
? blueprint.implementationRoadmap.length
500+
: 0;
496501
const totalPhases = Math.max(predictedPhaseCount, phaseTimeline.length, 1);
497502

498503
return [completedPhases, totalPhases];
499-
}, [phaseTimeline, blueprint?.implementationRoadmap]);
504+
}, [phaseTimeline, blueprint]);
500505

501506
if (import.meta.env.DEV) {
502507
logger.debug({
@@ -1262,4 +1267,4 @@ export default function Chat() {
12621267
)}
12631268
</div>
12641269
);
1265-
}
1270+
}

src/routes/chat/components/blueprint.tsx

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
import type { BlueprintType } from '@/api-types';
1+
import type { BlueprintType, PhasicBlueprint } from '@/api-types';
22
import clsx from 'clsx';
33
import { Markdown } from './messages';
44

5+
const isPhasicBlueprint = (blueprint: BlueprintType): blueprint is PhasicBlueprint =>
6+
'views' in blueprint;
7+
58
export function Blueprint({
69
blueprint,
710
className,
@@ -11,6 +14,8 @@ export function Blueprint({
1114
}) {
1215
if (!blueprint) return null;
1316

17+
const phasicBlueprint = isPhasicBlueprint(blueprint) ? blueprint : null;
18+
1419
return (
1520
<div className={clsx('w-full flex flex-col', className)} {...props}>
1621
<div className="bg-accent p-6 rounded-t-xl flex items-center bg-graph-paper">
@@ -84,13 +89,13 @@ export function Blueprint({
8489
</div>
8590

8691
{/* Views */}
87-
{Array.isArray(blueprint.views) && blueprint.views.length > 0 && (
92+
{phasicBlueprint && phasicBlueprint.views.length > 0 && (
8893
<div>
8994
<h3 className="text-sm font-medium mb-3 text-text-50/70 uppercase tracking-wider">
9095
Views
9196
</h3>
9297
<div className="space-y-3">
93-
{blueprint.views.map((view, index) => (
98+
{phasicBlueprint.views.map((view, index) => (
9499
<div key={`view-${index}`} className="space-y-1">
95100
<h4 className="text-xs font-medium text-text-50/70">
96101
{view.name}
@@ -105,41 +110,41 @@ export function Blueprint({
105110
)}
106111

107112
{/* User Flow */}
108-
{blueprint.userFlow && (
113+
{phasicBlueprint?.userFlow && (
109114
<div>
110115
<h3 className="text-sm font-medium mb-3 text-text-50/70 uppercase tracking-wider">
111116
User Flow
112117
</h3>
113118
<div className="space-y-4">
114-
{blueprint.userFlow?.uiLayout && (
119+
{phasicBlueprint.userFlow.uiLayout && (
115120
<div>
116121
<h4 className="text-xs font-medium mb-2 text-text-50/70">
117122
UI Layout
118123
</h4>
119124
<Markdown className="text-sm text-text-50">
120-
{blueprint.userFlow.uiLayout}
125+
{phasicBlueprint.userFlow.uiLayout}
121126
</Markdown>
122127
</div>
123128
)}
124129

125-
{blueprint.userFlow?.uiDesign && (
130+
{phasicBlueprint.userFlow.uiDesign && (
126131
<div>
127132
<h4 className="text-xs font-medium mb-2 text-text-50/70">
128133
UI Design
129134
</h4>
130135
<Markdown className="text-sm text-text-50">
131-
{blueprint.userFlow.uiDesign}
136+
{phasicBlueprint.userFlow.uiDesign}
132137
</Markdown>
133138
</div>
134139
)}
135140

136-
{blueprint.userFlow?.userJourney && (
141+
{phasicBlueprint.userFlow.userJourney && (
137142
<div>
138143
<h4 className="text-xs font-medium mb-2 text-text-50/70">
139144
User Journey
140145
</h4>
141146
<Markdown className="text-sm text-text-50">
142-
{blueprint.userFlow?.userJourney}
147+
{phasicBlueprint.userFlow.userJourney}
143148
</Markdown>
144149
</div>
145150
)}
@@ -148,25 +153,25 @@ export function Blueprint({
148153
)}
149154

150155
{/* Data Flow */}
151-
{(blueprint.dataFlow || blueprint.architecture?.dataFlow) && (
156+
{phasicBlueprint && (phasicBlueprint.dataFlow || phasicBlueprint.architecture?.dataFlow) && (
152157
<div>
153158
<h3 className="text-sm font-medium mb-2 text-text-50/70 uppercase tracking-wider">
154159
Data Flow
155160
</h3>
156161
<Markdown className="text-sm text-text-50">
157-
{blueprint.dataFlow || blueprint.architecture?.dataFlow}
162+
{phasicBlueprint.dataFlow || phasicBlueprint.architecture?.dataFlow}
158163
</Markdown>
159164
</div>
160165
)}
161166

162167
{/* Implementation Roadmap */}
163-
{Array.isArray(blueprint.implementationRoadmap) && blueprint.implementationRoadmap.length > 0 && (
168+
{phasicBlueprint && phasicBlueprint.implementationRoadmap.length > 0 && (
164169
<div>
165170
<h3 className="text-sm font-medium mb-2 text-text-50/70 uppercase tracking-wider">
166171
Implementation Roadmap
167172
</h3>
168173
<div className="space-y-3">
169-
{blueprint.implementationRoadmap.map((roadmapItem, index) => (
174+
{phasicBlueprint.implementationRoadmap.map((roadmapItem, index) => (
170175
<div key={`roadmap-${index}`} className="space-y-1">
171176
<h4 className="text-xs font-medium text-text-50/70">
172177
Phase {index + 1}: {roadmapItem.phase}
@@ -181,26 +186,26 @@ export function Blueprint({
181186
)}
182187

183188
{/* Initial Phase */}
184-
{blueprint.initialPhase && (
189+
{phasicBlueprint?.initialPhase && (
185190
<div>
186191
<h3 className="text-sm font-medium mb-2 text-text-50/70 uppercase tracking-wider">
187192
Initial Phase
188193
</h3>
189194
<div className="space-y-3">
190195
<div>
191196
<h4 className="text-xs font-medium mb-2 text-text-50/70">
192-
{blueprint.initialPhase.name}
197+
{phasicBlueprint.initialPhase.name}
193198
</h4>
194199
<Markdown className="text-sm text-text-50 mb-3">
195-
{blueprint.initialPhase.description}
200+
{phasicBlueprint.initialPhase.description}
196201
</Markdown>
197-
{Array.isArray(blueprint.initialPhase.files) && blueprint.initialPhase.files.length > 0 && (
202+
{Array.isArray(phasicBlueprint.initialPhase.files) && phasicBlueprint.initialPhase.files.length > 0 && (
198203
<div>
199204
<h5 className="text-xs font-medium mb-2 text-text-50/60">
200205
Files to be created:
201206
</h5>
202207
<div className="space-y-2">
203-
{blueprint.initialPhase.files.map((file, fileIndex) => (
208+
{phasicBlueprint.initialPhase.files.map((file, fileIndex) => (
204209
<div key={`initial-phase-file-${fileIndex}`} className="border-l-2 border-text/10 pl-3">
205210
<div className="font-mono text-xs text-text-50/80">{file.path}</div>
206211
<div className="text-xs text-text-50/60">{file.purpose}</div>
@@ -215,14 +220,14 @@ export function Blueprint({
215220
)}
216221

217222
{/* Pitfalls */}
218-
{Array.isArray(blueprint.pitfalls) && blueprint.pitfalls.length > 0 && (
223+
{phasicBlueprint && phasicBlueprint.pitfalls.length > 0 && (
219224
<div>
220225
<h3 className="text-sm font-medium mb-2 text-text-50/70 uppercase tracking-wider">
221226
Pitfalls
222227
</h3>
223228
<div className="prose prose-sm prose-invert">
224229
<ul className="">
225-
{blueprint.pitfalls?.map((pitfall, index) => (
230+
{phasicBlueprint.pitfalls.map((pitfall, index) => (
226231
<li key={`pitfall-${index}`} className="">
227232
{pitfall}
228233
</li>

src/routes/chat/utils/handle-websocket-message.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { WebSocket } from 'partysocket';
2-
import type { WebSocketMessage, BlueprintType, ConversationMessage } from '@/api-types';
2+
import type { WebSocketMessage, BlueprintType, ConversationMessage, AgentState, PhasicState } from '@/api-types';
33
import { deduplicateMessages, isAssistantMessageDuplicate } from './deduplicate-messages';
44
import { logger } from '@/utils/logger';
55
import { getFileType } from '@/utils/string';
@@ -23,6 +23,9 @@ import { sendWebSocketMessage } from './websocket-helpers';
2323
import type { FileType, PhaseTimelineItem } from '../hooks/use-chat';
2424
import { toast } from 'sonner';
2525

26+
const isPhasicState = (state: AgentState): state is PhasicState =>
27+
state.behaviorType === 'phasic';
28+
2629
export interface HandleMessageDeps {
2730
// State setters
2831
setFiles: React.Dispatch<React.SetStateAction<FileType[]>>;
@@ -191,12 +194,12 @@ export function createWebSocketMessageHandler(deps: HandleMessageDeps) {
191194
);
192195
}
193196

194-
if (state.generatedPhases && state.generatedPhases.length > 0 && phaseTimeline.length === 0) {
197+
if (isPhasicState(state) && state.generatedPhases.length > 0 && phaseTimeline.length === 0) {
195198
logger.debug('📋 Restoring phase timeline:', state.generatedPhases);
196199
// If not actively generating, mark incomplete phases as cancelled (they were interrupted)
197200
const isActivelyGenerating = state.shouldBeGenerating === true;
198201

199-
const timeline = state.generatedPhases.map((phase: any, index: number) => {
202+
const timeline = state.generatedPhases.map((phase, index: number) => {
200203
// Determine phase status:
201204
// - completed if explicitly marked complete
202205
// - cancelled if incomplete and not actively generating (interrupted)
@@ -212,7 +215,7 @@ export function createWebSocketMessageHandler(deps: HandleMessageDeps) {
212215
name: phase.name,
213216
description: phase.description,
214217
status: phaseStatus,
215-
files: phase.files.map((filesConcept: any) => {
218+
files: phase.files.map(filesConcept => {
216219
const file = state.generatedFilesMap?.[filesConcept.path];
217220
// File status:
218221
// - completed if it exists in generated files

worker/agents/core/AgentCore.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { BaseProjectState } from "./state";
66
import { WebSocketMessageType } from "../../api/websocketTypes";
77
import { WebSocketMessageData } from "../../api/websocketTypes";
88
import { ConversationMessage, ConversationState } from "../inferutils/common";
9+
import { TemplateDetails } from "worker/services/sandbox/sandboxTypes";
910

1011
/**
1112
* Infrastructure interface for agent implementations.
@@ -34,4 +35,12 @@ export interface AgentInfrastructure<TState extends BaseProjectState> {
3435
readonly fileManager: FileManager;
3536
readonly deploymentManager: DeploymentManager;
3637
readonly git: GitVersionControl;
38+
39+
// Git export infrastructure
40+
exportGitObjects(): Promise<{
41+
gitObjects: Array<{ path: string; data: Uint8Array }>;
42+
query: string;
43+
hasCommits: boolean;
44+
templateDetails: TemplateDetails | null;
45+
}>;
3746
}

worker/agents/core/behaviors/agentic.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export class AgenticCodingBehavior extends BaseCodingBehavior<AgenticState> impl
6161
query,
6262
language: language!,
6363
frameworks: frameworks!,
64+
projectType: this.state.projectType,
6465
templateDetails: templateInfo?.templateDetails,
6566
templateMetaInfo: templateInfo?.selection,
6667
images: initArgs.images,

0 commit comments

Comments
 (0)