()
| 391 | } |
| 392 | |
| 393 | func (r *RootCmd) mcpServer() *serpent.Command { |
| 394 | var ( |
| 395 | instructions string |
| 396 | allowedTools []string |
| 397 | appStatusSlug string |
| 398 | aiAgentAPIURL url.URL |
| 399 | socketPath string |
| 400 | ) |
| 401 | cmd := &serpent.Command{ |
| 402 | Use: "server", |
| 403 | Handler: func(inv *serpent.Invocation) error { |
| 404 | client, err := r.TryInitClient(inv) |
| 405 | if err != nil { |
| 406 | return err |
| 407 | } |
| 408 | |
| 409 | var lastReport taskReport |
| 410 | // Create a queue that skips duplicates and preserves summaries. |
| 411 | queue := cliutil.NewQueue[taskReport](512).WithPredicate(func(report taskReport) (taskReport, bool) { |
| 412 | // Avoid queuing empty statuses (this would probably indicate a |
| 413 | // developer error) |
| 414 | if report.state == "" { |
| 415 | return report, false |
| 416 | } |
| 417 | // If this is a user message, discard if it is not new. |
| 418 | if report.messageID != nil && lastReport.messageID != nil && |
| 419 | *lastReport.messageID >= *report.messageID { |
| 420 | return report, false |
| 421 | } |
| 422 | // If this is not a user message, and the status is "working" and not |
| 423 | // self-reported (meaning it came from the screen watcher), then it |
| 424 | // means one of two things: |
| 425 | // |
| 426 | // 1. The AI agent is not working; the user is interacting with the |
| 427 | // terminal directly. |
| 428 | // 2. The AI agent is working. |
| 429 | // |
| 430 | // At the moment, we have no way to tell the difference between these |
| 431 | // two states. In the future, if we can reliably distinguish between |
| 432 | // user and AI agent activity, we can change this. |
| 433 | // |
| 434 | // If this is our first update, we assume it is the AI agent working and |
| 435 | // accept the update. |
| 436 | // |
| 437 | // Otherwise we discard the update. This risks missing cases where the |
| 438 | // user manually submits a new prompt and the AI agent becomes active |
| 439 | // (and does not update itself), but it avoids spamming useless status |
| 440 | // updates as the user is typing, so the tradeoff is worth it. |
| 441 | if report.messageID == nil && |
| 442 | report.state == codersdk.WorkspaceAppStatusStateWorking && |
| 443 | !report.selfReported && lastReport.state != "" { |
| 444 | return report, false |
| 445 | } |
| 446 | // Keep track of the last message ID so we can tell when a message is |
| 447 | // new or if it has been re-emitted. |
| 448 | if report.messageID == nil { |
| 449 | report.messageID = lastReport.messageID |
| 450 | } |
no test coverage detected