(ctx context.Context)
| 1349 | } |
| 1350 | |
| 1351 | func (cli *ChatCLI) runAgentLogic(ctx context.Context) { |
| 1352 | cli.setExecutionProfile(ProfileAgent) |
| 1353 | defer cli.setExecutionProfile(ProfileNormal) |
| 1354 | |
| 1355 | if len(cli.commandHistory) == 0 { |
| 1356 | return |
| 1357 | } |
| 1358 | lastCommand := cli.commandHistory[len(cli.commandHistory)-1] |
| 1359 | |
| 1360 | query := "" |
| 1361 | if strings.HasPrefix(lastCommand, "/agent") { |
| 1362 | query = strings.TrimSpace(strings.TrimPrefix(lastCommand, "/agent")) |
| 1363 | } else if strings.HasPrefix(lastCommand, "/run") { |
| 1364 | query = strings.TrimSpace(strings.TrimPrefix(lastCommand, "/run")) |
| 1365 | } else if strings.HasPrefix(lastCommand, "/plan") { |
| 1366 | query = strings.TrimSpace(strings.TrimPrefix(lastCommand, "/plan")) |
| 1367 | // Optional subcommands after /plan |
| 1368 | for _, sub := range []string{"preview", "dry", "agent"} { |
| 1369 | if strings.HasPrefix(query, sub+" ") || query == sub { |
| 1370 | query = strings.TrimSpace(strings.TrimPrefix(query, sub)) |
| 1371 | break |
| 1372 | } |
| 1373 | } |
| 1374 | } else { |
| 1375 | fmt.Println(i18n.T("error.agent_query_extraction")) |
| 1376 | return |
| 1377 | } |
| 1378 | if query == "" { |
| 1379 | // Defense-in-depth: the /agent and /run entry points already |
| 1380 | // refuse empty inputs, but if some upstream change bypasses |
| 1381 | // them we still don't want to ship an empty user message to |
| 1382 | // the LLM. |
| 1383 | fmt.Println(colorize(" "+i18n.T("agent.usage.hint"), ColorYellow)) |
| 1384 | return |
| 1385 | } |
| 1386 | |
| 1387 | rendererAgent := agent.NewUIRenderer(cli.logger) |
| 1388 | rendererAgent.RenderModeBanner("🤖", i18n.T("agent.banner.title"), agent.ColorLime, [][2]string{ |
| 1389 | {i18n.T("agent.banner.task"), query}, |
| 1390 | {i18n.T("agent.banner.mode"), i18n.T("agent.banner.mode_value")}, |
| 1391 | }) |
| 1392 | |
| 1393 | query, additionalContext, images := cli.processSpecialCommands(ctx, query) |
| 1394 | images, visionDesc := cli.gateImagesForModel(ctx, images) |
| 1395 | additionalContext += visionDesc |
| 1396 | |
| 1397 | if cli.agentMode == nil { |
| 1398 | cli.agentMode = NewAgentMode(cli, cli.logger) |
| 1399 | } |
| 1400 | |
| 1401 | cli.agentMode.pendingUserImages = images |
| 1402 | cli.agentMode.isOneShot = false // interactive /agent: keep the loop conversational |
| 1403 | cli.runWithCancellation(ctx, "Agent Mode", func(ctx context.Context) error { |
| 1404 | return cli.agentMode.Run(ctx, query, additionalContext, "") |
| 1405 | }) |
| 1406 | |
| 1407 | // Nudge memory worker after agent run |
| 1408 | if cli.memWorker != nil { |
no test coverage detected