Skip to content

Commit 752fa29

Browse files
enowdevenowdev
authored andcommitted
fix: AskUserCard auto-attach text on Next/Submit; fix social tools wiring
- AskUserCard: removed Send button; Next auto-commits typed text before advancing; Submit auto-commits typed text before submitting; Enter key also commits and advances/submits - tools/registry.go: add email_read and social_browser to default toolset - tools/deps.go: SocialBrowserManager interface (Status returns string,string) - agent/agent.go + harness.go: add SocialBrowser field + SetSocialBrowser setter - socialbrowser/manager.go: Status returns (string, string) to match interface - cmd/antares/main.go: wire ag.SetSocialBrowser(rt.social)
1 parent f898e39 commit 752fa29

9 files changed

Lines changed: 65 additions & 45 deletions

File tree

.air.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ tmp_dir = ".air"
66
[build]
77
cmd = "go build -o ./.air/antares ./cmd/antares"
88
bin = "./.air/antares"
9-
full_bin = "./.air/antares serve"
9+
full_bin = "./.air/antares serve --foreground"
1010
include_ext = ["go", "yaml", "yml", "md"]
1111
exclude_dir = [".air", "web", "dist", ".git", "node_modules", "internal/server/dist"]
1212
exclude_regex = ["_test\\.go"]

cmd/antares/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ func bootstrap(ctx context.Context) (*runtimeServices, error) {
295295

296296
rt := &runtimeServices{cfg: cfg, db: db, shell: shell, agent: ag, skills: skillMgr}
297297
rt.social = socialbrowser.New()
298+
ag.SetSocialBrowser(rt.social)
298299

299300
// MCP servers are optional; a failing one is recorded, never fatal.
300301
rt.mcp = mcp.NewManager()

internal/agent/agent.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ type Agent struct {
171171
intel *engagement.Store
172172
roleperf *roleperf.Tracker
173173
board *board.Board
174+
socialBrowser tools.SocialBrowserManager
174175

175176
bg *bgManager
176177
// bgAct tracks background-tool usage per session (RAG index/retrieve, etc.).
@@ -764,6 +765,7 @@ func (a *Agent) executeTools(
764765
Deps: &tools.Deps{
765766
Config: a.cfg, Store: a.db, RAG: a.rag, Shell: a.shell,
766767
Sub: a.subAgentFor(req), Tasks: a.backgroundFor(req), Skills: a.skillLibrary(),
768+
SocialBrowser: a.socialBrowser,
767769
Checkpoint: func(sessionID, path, tool string) {
768770
a.saveCheckpoint(sessionID, path, tool, req.turnMarker)
769771
},

internal/agent/harness.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,9 @@ func (a *Agent) PruneCheckpoints(olderThan time.Duration) (int, error) {
604604
// SetPlugins attaches the plugin manager. Passing nil disables hooks.
605605
func (a *Agent) SetPlugins(m *plugin.Manager) { a.plugins = m }
606606

607+
// SetSocialBrowser attaches the persistent social media browser manager.
608+
func (a *Agent) SetSocialBrowser(m tools.SocialBrowserManager) { a.socialBrowser = m }
609+
607610
// Plugins exposes the manager, or nil when none is attached.
608611
func (a *Agent) Plugins() *plugin.Manager { return a.plugins }
609612

internal/server/dist/.gitkeep

Lines changed: 0 additions & 1 deletion
This file was deleted.

internal/socialbrowser/manager.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ func New() *Manager {
5353
}
5454

5555
// Status returns the current browser state and any error detail.
56-
func (m *Manager) Status() (State, string) {
56+
func (m *Manager) Status() (string, string) {
5757
m.mu.Lock()
5858
defer m.mu.Unlock()
59-
return m.state, m.errMsg
59+
return string(m.state), m.errMsg
6060
}
6161

6262
// Start launches the persistent browser if it is not already running.
@@ -189,10 +189,10 @@ func (m *Manager) WaitForRunning(timeout time.Duration) bool {
189189
deadline := time.Now().Add(timeout)
190190
for time.Now().Before(deadline) {
191191
state, _ := m.Status()
192-
if state == StateRunning {
192+
if state == string(StateRunning) {
193193
return true
194194
}
195-
if state == StateError {
195+
if state == string(StateError) {
196196
return false
197197
}
198198
time.Sleep(200 * time.Millisecond)

internal/tools/deps.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,10 @@ type Deps struct {
150150
}
151151

152152
// SocialBrowserManager is the minimal interface the social_browser tool needs
153-
// from the socialbrowser.Manager.
153+
// from the socialbrowser.Manager. The Status method returns (state, errMsg)
154+
// where state is a string enum.
154155
type SocialBrowserManager interface {
155-
Status() (state string, errMsg string)
156+
Status() (string, string)
156157
}
157158

158159
// RoleInfo is the subset of a role the tools need.

internal/tools/registry.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ var Toolsets = map[string][]string{
248248
"terminal", "process", "web_search", "web_fetch", "http_request", "browser", "todo", "board", "project_info", "set_soul", "memory", "list_proxies", "vps_run",
249249
"session_search", "rag_search", "rag_index", "skill", "delegate_task", "task", "list_roles", "image_generate", "view_image", "speak", "transcribe", "computer", "diagnostics", "ask_user", "schedule",
250250
"osint_dns", "osint_dorks", "osint_whois", "osint_ip", "osint_username", "osint_github", "osint_email", "osint_email_full", "osint_breach", "osint_shodan", "osint_reputation", "osint_crypto", "osint_domain", "osint_phone", "osint_scrape", "osint_paste", "osint_footprint", "osint_pivot", "osint_google", "osint_dorks_live", "check_dependencies", "re_info", "re_strings", "re_analyze", "re_decompile", "solve_captcha", "intercept",
251+
"email_read", "social_browser",
251252
},
252253
"all": nil, // resolved dynamically to every registered tool
253254
}

web/src/components/chat/AskUserCard.tsx

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useMemo, useState } from 'react'
2-
import { Question, PaperPlaneTilt, ArrowLeft, ArrowRight, Check } from '@phosphor-icons/react'
2+
import { Question, ArrowLeft, ArrowRight, Check } from '@phosphor-icons/react'
33
import { useI18n } from '@/lib/i18n'
44
import { cn } from '@/lib/utils'
55
import { Button } from '@/components/ui/button'
@@ -66,18 +66,37 @@ export function AskUserCard({
6666
if (multi) {
6767
setSelected(selected.includes(o) ? selected.filter((x) => x !== o) : [...selected, o])
6868
} else {
69-
// Single-select: pick, and for a one-question card that's the whole answer.
7069
setSelected([o])
7170
if (questions.length === 1) submit({ 0: [o] })
7271
}
7372
}
7473

75-
const addCustom = () => {
74+
// Commit the free-text input into the current question's answers.
75+
// Returns the updated answers record.
76+
const commitCustom = (base: typeof answers): typeof answers => {
7677
const v = custom.trim()
77-
if (!v) return
78-
setSelected(multi ? [...selected.filter((x) => x !== v), v] : [v])
78+
if (!v) return base
79+
const cur = base[idx] ?? []
80+
if (multi) {
81+
return { ...base, [idx]: [...cur.filter((x) => x !== v), v] }
82+
}
83+
return { ...base, [idx]: [v] }
84+
}
85+
86+
// Next button: attach text first, then advance to the next question.
87+
const handleNext = () => {
88+
const updated = commitCustom(answers)
89+
setAnswers(updated)
90+
setCustom('')
91+
setIdx((i) => Math.min(questions.length - 1, i + 1))
92+
}
93+
94+
// Submit button: attach text first, then submit all answers.
95+
const handleSubmit = () => {
96+
const updated = commitCustom(answers)
97+
setAnswers(updated)
7998
setCustom('')
80-
if (!multi && questions.length === 1) submit({ 0: [v] })
99+
submit(updated)
81100
}
82101

83102
const answeredCount = questions.filter((_, i) => (answers[i]?.length ?? 0) > 0).length
@@ -111,6 +130,8 @@ export function AskUserCard({
111130
)
112131
}
113132

133+
const hasOptions = (q.options ?? []).length > 0
134+
114135
return (
115136
<div className="fade-up rounded-[var(--radius-md)] border border-primary/40 bg-primary/[0.06] p-3.5">
116137
<div className="flex items-start gap-2.5">
@@ -134,7 +155,7 @@ export function AskUserCard({
134155
<p className="mt-1.5 whitespace-pre-wrap break-words text-sm font-medium">{q.question}</p>
135156

136157
<div className="mt-3 space-y-2">
137-
{(q.options ?? []).length > 0 ? (
158+
{hasOptions ? (
138159
<div className="flex flex-wrap gap-2">
139160
{q.options!.map((o) => {
140161
const on = selected.includes(o)
@@ -155,32 +176,25 @@ export function AskUserCard({
155176
</div>
156177
) : null}
157178

158-
{/* Free-text answer — always available (this is the "Other"). */}
159-
<div className="flex items-center gap-2">
160-
<Input
161-
value={custom}
162-
onChange={(e) => setCustom(e.target.value)}
163-
onKeyDown={(e) => {
164-
if (e.key === 'Enter' && !e.shiftKey) {
165-
e.preventDefault()
166-
addCustom()
179+
{/* Free-text input — no send button; Next/Submit commits it. */}
180+
<Input
181+
value={custom}
182+
onChange={(e) => setCustom(e.target.value)}
183+
onKeyDown={(e) => {
184+
if (e.key === 'Enter' && !e.shiftKey) {
185+
e.preventDefault()
186+
if (isLast) {
187+
handleSubmit()
188+
} else {
189+
handleNext()
167190
}
168-
}}
169-
placeholder={
170-
(q.options ?? []).length > 0 ? t('ask.otherPlaceholder') : t('ask.customPlaceholder')
171191
}
172-
disabled={disabled}
173-
/>
174-
<Button
175-
size="icon-sm"
176-
variant="outline"
177-
disabled={disabled || !custom.trim()}
178-
onClick={addCustom}
179-
aria-label={t('ask.add')}
180-
>
181-
<PaperPlaneTilt className="size-4" />
182-
</Button>
183-
</div>
192+
}}
193+
placeholder={
194+
hasOptions ? t('ask.otherPlaceholder') : t('ask.customPlaceholder')
195+
}
196+
disabled={disabled}
197+
/>
184198

185199
{multi && selected.length > 0 ? (
186200
<p className="text-[11px] text-muted-foreground">
@@ -189,9 +203,8 @@ export function AskUserCard({
189203
) : null}
190204
</div>
191205

192-
{/* Navigation. A single question with options submits on click, so the
193-
nav row only matters for multi-question or free-text cases. */}
194-
{questions.length > 1 || multi || (q.options ?? []).length === 0 ? (
206+
{/* Navigation. Next auto-attaches the typed text. */}
207+
{questions.length > 1 || multi || !hasOptions ? (
195208
<div className="mt-3 flex items-center justify-between gap-2">
196209
<Button
197210
size="sm"
@@ -206,8 +219,8 @@ export function AskUserCard({
206219
{isLast ? (
207220
<Button
208221
size="sm"
209-
disabled={disabled || answeredCount === 0}
210-
onClick={() => submit()}
222+
disabled={disabled || (answeredCount === 0 && !custom.trim())}
223+
onClick={handleSubmit}
211224
className="gap-1.5"
212225
>
213226
<Check className="size-4" />
@@ -218,7 +231,7 @@ export function AskUserCard({
218231
size="sm"
219232
variant="secondary"
220233
disabled={disabled}
221-
onClick={() => setIdx((i) => Math.min(questions.length - 1, i + 1))}
234+
onClick={handleNext}
222235
className="gap-1.5"
223236
>
224237
{t('ask.next')}

0 commit comments

Comments
 (0)