Skip to content

Commit ad65660

Browse files
committed
fix (tasks): removed manual task creation
fix (self-host): added proper vars for self hosting
1 parent 9f9de1a commit ad65660

11 files changed

Lines changed: 45 additions & 278 deletions

File tree

src/.env.selfhost.template

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
# Root environment variables for docker-compose.yml (self-hosting)
1+
# Root environment variables for docker-compose.selfhost.yaml
22
# Copy this file to .env in the same directory (src/.env) and fill in the values.
33

4+
# --- Client Build-Time Variables ---
45
# The public-facing URL of your client application.
56
# This is crucial for OAuth redirects to work correctly.
67
APP_BASE_URL=http://localhost:3000
78

8-
# --- Client Build-Time Variables ---
99
# The URL where the backend server will be accessible from the user's browser
1010
NEXT_PUBLIC_APP_SERVER_URL=http://localhost:5000
1111

@@ -21,9 +21,17 @@ NEXT_PUBLIC_ENVIRONMENT=selfhost
2121
# This should be a long, random, secret string. It must match SELF_HOST_AUTH_SECRET in server/.env.selfhost
2222
SELF_HOST_AUTH_TOKEN=<generate_a_strong_secret_here>
2323

24+
# --- Server Build-Time Variables (for conditional Ollama install) ---
25+
# Set OPENAI_API_KEY to "ollama" to install Ollama in the container.
26+
# Otherwise, provide your key for a remote service.
27+
OPENAI_API_KEY=ollama
28+
# The model to pull if using Ollama, or the model to use from a remote service.
29+
OPENAI_MODEL_NAME=qwen3:4b
30+
31+
2432
# --- Database Credentials ---
2533
MONGO_USER=sentient
2634
MONGO_PASS=<generate_a_strong_password_for_mongo>
2735

2836
# --- Redis Password ---
29-
REDIS_PASSWORD=<generate_a_strong_password_for_redis>
37+
REDIS_PASSWORD=<generate_a_strong_password_for_redis>

src/client/app/tasks/page.js

Lines changed: 5 additions & 232 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,13 @@ import {
1717
IconAlertCircle,
1818
IconFilter,
1919
IconChevronUp,
20-
IconPlus,
2120
IconGripVertical,
2221
IconBrain,
2322
IconBook,
2423
IconMail,
2524
IconCalendarEvent,
2625
IconMessage,
27-
IconArrowRight,
2826
IconPlugConnected,
29-
IconChevronDown,
3027
IconChecklist,
3128
IconHelpCircle as HelpIcon
3229
} from "@tabler/icons-react"
@@ -112,32 +109,14 @@ const Tasks = () => {
112109
const [error, setError] = useState(null)
113110
const [editingTask, setEditingTask] = useState(null)
114111
const [filterStatus, setFilterStatus] = useState("all")
115-
const [isGeneratingPlan, setIsGeneratingPlan] = useState(false)
116112
const [searchTerm, setSearchTerm] = useState("")
117113
const [viewingTask, setViewingTask] = useState(null)
118-
const [isCreatePlanOpen, setCreatePlanOpen] = useState(false)
119-
const [createStep, setCreateStep] = useState("generate") // 'generate' or 'review'
120114
const [openSections, setOpenSections] = useState({
121-
// By default, only show sections that are likely to need action
122-
// The user can expand the others if needed.
123-
// This improves the initial view by reducing clutter.
124115
active: false, // Recurring tasks are less frequently managed
125116
approval_pending: true,
126117
processing: true,
127118
completed: true
128119
})
129-
const [isAdding, setIsAdding] = useState(false)
130-
const [generationPrompt, setGenerationPrompt] = useState("")
131-
const [newTaskDescription, setNewTaskDescription] = useState("")
132-
const [newTaskPriority, setNewTaskPriority] = useState(1)
133-
const [newTaskPlan, setNewTaskPlan] = useState([])
134-
const [newSchedule, setNewSchedule] = useState({
135-
type: "once",
136-
run_at: null,
137-
frequency: "daily",
138-
time: "09:00",
139-
days: []
140-
})
141120
const [allTools, setAllTools] = useState([])
142121
const [integrations, setIntegrations] = useState([])
143122
const [loadingIntegrations, setLoadingIntegrations] = useState(true)
@@ -218,50 +197,9 @@ const Tasks = () => {
218197
fetchAllToolsAndIntegrations()
219198
const intervalId = setInterval(fetchTasksData, 60000)
220199
return () => clearInterval(intervalId)
221-
}, [fetchTasksData])
222-
223-
const handleShortcuts = useCallback((e) => {
224-
if (e.ctrlKey && e.key === "Enter") {
225-
e.preventDefault()
226-
setCreatePlanOpen((prev) => !prev)
227-
}
228200
}, [])
229-
useEffect(() => {
230-
window.addEventListener("keydown", handleShortcuts)
231-
return () => window.removeEventListener("keydown", handleShortcuts)
232-
}, [fetchTasksData])
233-
234-
const handleGeneratePlan = async () => {
235-
if (!generationPrompt.trim()) {
236-
toast.error("Please enter a goal for your plan.")
237-
return
238-
}
239-
setIsGeneratingPlan(true)
240-
try {
241-
const response = await fetch("/api/tasks/generate-plan", {
242-
method: "POST",
243-
headers: { "Content-Type": "application/json" },
244-
body: JSON.stringify({ prompt: generationPrompt })
245-
})
246-
const data = await response.json()
247-
if (!response.ok) throw new Error(data.detail)
248-
if (!data.plan || data.plan.length === 0) {
249-
toast.error(
250-
"The agent could not generate a plan for this goal. Please try rephrasing."
251-
)
252-
} else {
253-
setNewTaskDescription(data.description || generationPrompt)
254-
setNewTaskPlan(data.plan)
255-
setCreateStep("review")
256-
toast.success("Plan generated! Review and save it below.")
257-
}
258-
} catch (error) {
259-
toast.error(`Plan Generation Failed: ${error.message}`)
260-
} finally {
261-
setIsGeneratingPlan(false)
262-
}
263-
}
264201

202+
const handleEditTask = (task) => setEditingTask({ ...task })
265203
const handleUpdateTaskSchedule = async (taskId, schedule) => {
266204
if (!taskId) return false
267205
try {
@@ -279,66 +217,6 @@ const Tasks = () => {
279217
return false
280218
}
281219
}
282-
283-
const handleAddTask = async () => {
284-
if (!newTaskDescription.trim())
285-
return toast.error("Please enter a task description.")
286-
if (newTaskPlan.some((step) => !step.tool || !step.description.trim()))
287-
return toast.error(
288-
"All plan steps must have a tool and description."
289-
)
290-
setIsAdding(true)
291-
try {
292-
// Clean up schedule object before sending
293-
const schedulePayload =
294-
newSchedule.type === "once"
295-
? { type: "once", run_at: newSchedule.run_at || null }
296-
: newSchedule
297-
298-
const taskData = {
299-
description: newTaskDescription,
300-
priority: newTaskPriority,
301-
plan: newTaskPlan,
302-
schedule: schedulePayload
303-
}
304-
305-
const response = await fetch("/api/tasks/add", {
306-
method: "POST",
307-
headers: { "Content-Type": "application/json" },
308-
body: JSON.stringify(taskData)
309-
})
310-
if (!response.ok) {
311-
const data = await response.json()
312-
throw new Error(data.error || "Failed to add task")
313-
}
314-
toast.success("New plan created successfully!")
315-
posthog?.capture("workflow_created", {
316-
plan_steps: taskData.plan.length,
317-
is_recurring: taskData.schedule.type === "recurring",
318-
priority: taskData.priority
319-
})
320-
setGenerationPrompt("")
321-
setNewTaskDescription("")
322-
setNewTaskPriority(1)
323-
setNewTaskPlan([])
324-
setNewSchedule({
325-
type: "once",
326-
run_at: null,
327-
frequency: "daily",
328-
time: "09:00",
329-
days: []
330-
})
331-
setCreateStep("generate")
332-
setCreatePlanOpen(false)
333-
await fetchTasksData()
334-
} catch (error) {
335-
toast.error(`Failed to add task: ${error.message}`)
336-
} finally {
337-
setIsAdding(false)
338-
}
339-
}
340-
341-
const handleEditTask = (task) => setEditingTask({ ...task })
342220
const handleUpdateTask = async () => {
343221
if (
344222
!editingTask ||
@@ -476,7 +354,7 @@ const Tasks = () => {
476354
<Tooltip id="tasks-tooltip" />
477355
<Tooltip id="page-help-tooltip" />
478356
<div className="flex-1 flex flex-col overflow-hidden relative">
479-
<HelpTooltip content="This is the Tasks page. Here you can view all your tasks, approve new ones, and create custom multi-step plans (workflows). Press Ctrl + Enter to toggle the plan creator." />
357+
<HelpTooltip content="This is the Tasks page. Here you can view all your tasks and approve new ones." />
480358
<motion.header
481359
initial={{ y: -20, opacity: 0 }}
482360
animate={{ y: 0, opacity: 1 }}
@@ -533,7 +411,7 @@ const Tasks = () => {
533411
</motion.header>
534412

535413
<main className="flex-1 w-full max-w-3xl mx-auto flex flex-col overflow-y-auto custom-scrollbar px-4">
536-
<div className="space-y-2 pt-6 pb-36">
414+
<div className="space-y-2 pt-6 pb-6">
537415
{loading || loadingIntegrations ? (
538416
<div className="flex justify-center items-center h-full">
539417
<IconLoader className="w-12 h-12 animate-spin text-[var(--color-accent-blue)]" />
@@ -544,7 +422,7 @@ const Tasks = () => {
544422
</div>
545423
) : filteredTasks.length === 0 ? (
546424
<p className="text-gray-500 text-center py-20 mt-5">
547-
No tasks found. Create a new plan below!
425+
No tasks found.
548426
</p>
549427
) : (
550428
<>
@@ -596,111 +474,6 @@ const Tasks = () => {
596474
)}
597475
</div>
598476
</main>
599-
600-
<div className="absolute bottom-0 left-0 right-0 p-4 bg-gradient-to-t from-black/50 via-neutral-900/80 to-transparent backdrop-blur-sm border-t border-neutral-700/50 z-20">
601-
<div className="max-w-3xl mx-auto">
602-
<div
603-
onClick={() => setCreatePlanOpen(!isCreatePlanOpen)}
604-
className="flex justify-between items-center cursor-pointer"
605-
>
606-
<h3 className="text-lg font-semibold text-white">
607-
Create a New Plan
608-
</h3>
609-
<IconChevronDown
610-
className={cn(
611-
"transform transition-transform duration-200",
612-
!isCreatePlanOpen && "rotate-180"
613-
)}
614-
/>
615-
</div>
616-
<AnimatePresence>
617-
{isCreatePlanOpen && (
618-
<motion.div
619-
key="create-plan-panel"
620-
initial={{ height: 0, opacity: 0 }}
621-
animate={{ height: "auto", opacity: 1 }}
622-
exit={{ height: 0, opacity: 0 }}
623-
className="overflow-hidden"
624-
>
625-
{createStep === "generate" ? (
626-
<div className="space-y-4 pt-4">
627-
<label className="text-sm font-medium text-gray-300 mb-1 block">
628-
What is your goal?
629-
</label>
630-
<textarea
631-
placeholder="e.g., Send a daily summary of my calendar to my boss"
632-
value={generationPrompt}
633-
onChange={(e) =>
634-
setGenerationPrompt(
635-
e.target.value
636-
)
637-
}
638-
rows={3}
639-
className="w-full p-3 bg-neutral-800/50 border border-neutral-700 rounded-lg text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500 backdrop-blur-sm transition-colors"
640-
/>
641-
<div className="flex justify-end">
642-
<button
643-
onClick={handleGeneratePlan}
644-
disabled={isGeneratingPlan}
645-
className="p-3 px-6 bg-[var(--color-accent-blue)] hover:bg-[var(--color-accent-blue-hover)] rounded-lg text-white font-semibold transition-colors disabled:opacity-50 flex items-center gap-2"
646-
>
647-
{isGeneratingPlan ? (
648-
<IconLoader className="w-5 h-5 animate-spin" />
649-
) : (
650-
<>
651-
Next: Review Plan{" "}
652-
<IconArrowRight className="w-4 h-4" />
653-
</>
654-
)}
655-
</button>
656-
</div>
657-
</div>
658-
) : (
659-
// REVIEW STEP
660-
<div className="space-y-6 pt-4">
661-
<PlanEditor
662-
description={newTaskDescription}
663-
setDescription={
664-
setNewTaskDescription
665-
}
666-
priority={newTaskPriority}
667-
setPriority={setNewTaskPriority}
668-
plan={newTaskPlan}
669-
setPlan={setNewTaskPlan}
670-
schedule={newSchedule}
671-
setSchedule={setNewSchedule}
672-
allTools={allTools}
673-
integrations={integrations}
674-
/>
675-
<div className="flex justify-between items-center">
676-
<button
677-
onClick={() =>
678-
setCreateStep(
679-
"generate"
680-
)
681-
}
682-
className="py-2.5 px-6 rounded-lg bg-[var(--color-primary-surface-elevated)] hover:bg-[var(--color-primary-surface)] text-white text-sm font-semibold"
683-
>
684-
Back
685-
</button>
686-
<button
687-
onClick={handleAddTask}
688-
disabled={isAdding}
689-
className="py-2.5 px-6 rounded-lg bg-[var(--color-accent-blue)] hover:bg-[var(--color-accent-blue-hover)] text-white text-sm font-semibold transition-colors disabled:opacity-50 flex items-center gap-2"
690-
>
691-
{isAdding && (
692-
<IconLoader className="h-5 h-5 animate-spin" />
693-
)}
694-
Save New Plan
695-
</button>
696-
</div>
697-
</div>
698-
)}
699-
</motion.div>
700-
)}
701-
</AnimatePresence>
702-
</div>
703-
</div>
704477
</div>
705478
{viewingTask && (
706479
<TaskDetailsModal
@@ -861,7 +634,7 @@ const PlanEditor = ({
861634
onClick={handleAddStep}
862635
className="flex items-center gap-1.5 py-1.5 px-3 rounded-full bg-[var(--color-primary-surface-elevated)] hover:bg-[var(--color-primary-surface)] text-xs"
863636
>
864-
<IconPlus className="h-4 w-4" /> Add Step
637+
<IconGripVertical className="h-4 w-4" /> Add Step
865638
</button>
866639
</div>
867640
<div>

src/docker-compose.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
# docker-compose.yml for self-hosting Sentient
22
# This file should be placed in the `src` directory.
33

4-
version: "3.8"
5-
64
services:
75
# Client (Next.js Frontend)
86
client:

src/server/.env.selfhost.template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ CELERY_RESULT_BACKEND=redis://:${REDIS_PASSWORD}@redis:6379/0
2828
# Standard OpenAI API compatible endpoint configuration.
2929
# For local Ollama, use the following. The Docker container will run Ollama internally.
3030
OPENAI_API_BASE_URL=http://localhost:11434
31-
OPENAI_MODEL_NAME=qwen2:1.5b
31+
OPENAI_MODEL_NAME=qwen3:4b
3232
OPENAI_API_KEY=ollama
3333

3434
# --- 3rd Party API Keys (Optional but recommended for full functionality) ---

src/server/main/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@
319319
# --- OpenAI API Standard Configuration ---
320320
# This can point to OpenAI, Ollama, Groq, or any other compatible service.
321321
OPENAI_API_BASE_URL = os.getenv("OPENAI_API_BASE_URL", "http://localhost:11434")
322-
OPENAI_MODEL_NAME = os.getenv("OPENAI_MODEL_NAME", "qwen2:1.5b")
322+
OPENAI_MODEL_NAME = os.getenv("OPENAI_MODEL_NAME", "qwen3:4b")
323323
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "ollama") # Default key for Ollama
324324

325325
# MCP Server URLs

0 commit comments

Comments
 (0)