1pub use kcode_k1_codex_conversations::{
2 Config, DynamicTool, Error, ErrorKind, Event, ToolCall, ToolResult,
3};
4use kcode_k1_codex_conversations::{
5 Diagnostics, Pending, State, ToolToken, parse_rpc_id, thread_start_params, turn_start_params,
6};
7use kcode_k1_codex_events::{
8 DynamicToolCall as DecodedToolCall, Inbound, ResponseOutcome, RpcId, ScopedEvent, ScopedKind,
9 ServerError, TurnCompleted, TurnStatus, decode, rejection_payload,
10};
11use kcode_k1_codex_transport::{
12 ClientInfo, Config as WireConfig, Error as WireError, ErrorKind as WireKind, Transport,
13};
14use serde_json::{Value, json};
15use std::{
16 fmt,
17 sync::{Arc, Weak},
18 time::Duration,
19};
20use tokio::sync::{mpsc, oneshot};
21const EARLY_LIMIT: usize = 1024;
22type Events = mpsc::UnboundedSender<Event>;
23type Reply = oneshot::Sender<Result<(), Error>>;
24type CloseReply = Option<Reply>;
25type StartReply = oneshot::Sender<Result<u64, Error>>;
26enum Command {
27 Start {
28 key: String,
29 input: String,
30 events: Events,
31 reply: StartReply,
32 },
33 Respond {
34 key: String,
35 turn: u64,
36 call: String,
37 result: ToolResult,
38 reply: Reply,
39 },
40 Abandon {
41 key: String,
42 turn: u64,
43 },
44 Close {
45 key: String,
46 reply: Reply,
47 },
48}
49struct Client {
50 commands: mpsc::UnboundedSender<Command>,
51 diagnostics: Diagnostics,
52}
53#[derive(Clone)]
54pub struct Adapter {
55 client: Arc<Client>,
56}
57impl Adapter {
58 pub async fn open(config: Config) -> Result<Self, Error> {
59 open(config).await
60 }
61 pub async fn start_turn(
62 &self,
63 conversation_key: impl Into<String>,
64 input: impl Into<String>,
65 ) -> Result<Turn, Error> {
66 let key = conversation_key.into();
67 let (events, receiver) = mpsc::unbounded_channel();
68 let (reply, answer) = oneshot::channel();
69 self.client
70 .commands
71 .send(Command::Start {
72 key: key.clone(),
73 input: input.into(),
74 events,
75 reply,
76 })
77 .map_err(|_| self.unavailable())?;
78 let serial = answer.await.map_err(|_| self.unavailable())??;
79 Ok(Turn {
80 key,
81 serial,
82 client: Arc::downgrade(&self.client),
83 events: receiver,
84 diagnostics: self.client.diagnostics.clone(),
85 terminal: false,
86 })
87 }
88 pub async fn close_conversation(&self, key: impl Into<String>) -> Result<(), Error> {
89 let (reply, answer) = oneshot::channel();
90 self.client
91 .commands
92 .send(Command::Close {
93 key: key.into(),
94 reply,
95 })
96 .map_err(|_| self.unavailable())?;
97 answer.await.map_err(|_| self.unavailable())?
98 }
99 pub fn diagnostics(&self) -> Vec<u8> {
100 self.client.diagnostics.snapshot()
101 }
102 fn unavailable(&self) -> Error {
103 self.client
104 .diagnostics
105 .error(ErrorKind::Unavailable, "Codex app-server is unavailable")
106 }
107}
108pub struct Turn {
109 key: String,
110 serial: u64,
111 client: Weak<Client>,
112 events: mpsc::UnboundedReceiver<Event>,
113 diagnostics: Diagnostics,
114 terminal: bool,
115}
116impl fmt::Debug for Turn {
117 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
118 formatter
119 .debug_struct("Turn")
120 .field("key", &self.key)
121 .field("serial", &self.serial)
122 .finish_non_exhaustive()
123 }
124}
125impl Turn {
126 pub async fn next_event(&mut self) -> Option<Event> {
127 let event = self.events.recv().await;
128 if event
129 .as_ref()
130 .is_none_or(|event| matches!(event, Event::Done | Event::Error(_)))
131 {
132 self.terminal = true;
133 }
134 event
135 }
136 pub async fn respond(
137 &self,
138 call_id: impl Into<String>,
139 result: ToolResult,
140 ) -> Result<(), Error> {
141 let client = self.client.upgrade().ok_or_else(|| self.unavailable())?;
142 let (reply, answer) = oneshot::channel();
143 client
144 .commands
145 .send(Command::Respond {
146 key: self.key.clone(),
147 turn: self.serial,
148 call: call_id.into(),
149 result,
150 reply,
151 })
152 .map_err(|_| self.unavailable())?;
153 answer.await.map_err(|_| self.unavailable())?
154 }
155 fn unavailable(&self) -> Error {
156 self.diagnostics
157 .error(ErrorKind::Unavailable, "Codex app-server is unavailable")
158 }
159}
160impl Drop for Turn {
161 fn drop(&mut self) {
162 if !self.terminal
163 && let Some(client) = self.client.upgrade()
164 {
165 let _ = client.commands.send(Command::Abandon {
166 key: self.key.clone(),
167 turn: self.serial,
168 });
169 }
170 }
171}
172struct Actor {
173 transport: Transport,
174 commands: mpsc::UnboundedReceiver<Command>,
175 config: Config,
176 diagnostics: Diagnostics,
177 state: State<Events, CloseReply>,
178}
179async fn open(config: Config) -> Result<Adapter, Error> {
180 config.validate()?;
181 let mut wire = WireConfig::new(config.executable.clone(), config.working_directory.clone());
182 wire.reasoning_effort = config.reasoning_effort.clone();
183 wire.client = ClientInfo {
184 name: "kcode-k1-codex-adapter".into(),
185 title: "K1 Codex Adapter".into(),
186 version: "0.2.1".into(),
187 };
188 let transport = Transport::open(wire).await.map_err(map_wire)?;
189 let diagnostics = Diagnostics::new(transport.diagnostics());
190 let (commands, receiver) = mpsc::unbounded_channel();
191 let client = Arc::new(Client {
192 commands,
193 diagnostics: diagnostics.clone(),
194 });
195 let mut actor = Actor {
196 transport,
197 commands: receiver,
198 config,
199 diagnostics,
200 state: State::default(),
201 };
202 tokio::spawn(async move {
203 let outcome = actor.run().await;
204 actor.refresh();
205 let mut error = outcome
206 .err()
207 .unwrap_or_else(|| actor.error(ErrorKind::Unavailable, "Codex app-server was closed"));
208 let _ = actor.reject_all("adapter stopped").await;
209 let sinks = actor.state.take_sinks();
210 actor.refresh();
211 error.diagnostics = actor.diagnostics.snapshot();
212 for sink in sinks {
213 let _ = sink.send(Event::Error(error.clone()));
214 }
215 let _ = actor.transport.close().await;
216 actor.refresh();
217 });
218 Ok(Adapter { client })
219}
220impl Actor {
221 async fn run(&mut self) -> Result<(), Error> {
222 let mut tick = tokio::time::interval(Duration::from_millis(20));
223 loop {
224 tokio::select! {
225 command = self.commands.recv() => match command {
226 Some(command) => self.command(command).await?,
227 None => return Ok(()),
228 },
229 message = self.transport.receive() => self.message(message.map_err(map_wire)?).await?,
230 _ = tick.tick() => self.refresh(),
231 }
232 }
233 }
234 async fn command(&mut self, command: Command) -> Result<(), Error> {
235 self.refresh();
236 match command {
237 Command::Start {
238 key,
239 input,
240 events,
241 reply,
242 } => {
243 if self.start_pending(&key) {
244 let _ = reply.send(Err(
245 self.error(ErrorKind::Busy, "conversation already has an active turn")
246 ));
247 return Ok(());
248 }
249 let serial = match self.state.begin_turn(key.clone(), events) {
250 Ok(serial) => serial,
251 Err(error) => {
252 let _ = reply.send(Err(self.stamp(error)));
253 return Ok(());
254 }
255 };
256 let request = if let Some(thread) = self.state.thread(&key).map(str::to_owned) {
257 self.request(
258 "turn/start",
259 turn_start_params(&thread, input),
260 Pending::Turn {
261 key: key.clone(),
262 serial,
263 },
264 )
265 .await
266 } else {
267 self.request(
268 "thread/start",
269 thread_start_params(&self.config),
270 Pending::Thread {
271 key: key.clone(),
272 serial,
273 input,
274 },
275 )
276 .await
277 };
278 if let Err(error) = request {
279 self.state.take_active(&key, serial);
280 let _ = reply.send(Err(error.clone()));
281 return Err(error);
282 }
283 if reply.send(Ok(serial)).is_err()
284 && let Some(active) = self.state.take_active(&key, serial)
285 {
286 self.reject_early(active.early, "turn start receiver was dropped")
287 .await?;
288 }
289 }
290 Command::Respond {
291 key,
292 turn,
293 call,
294 result,
295 reply,
296 } => {
297 let token: ToolToken = (key, turn, call);
298 let Some(pending) = self.state.take_tool(&token) else {
299 let _ = reply.send(Err(self.error(
300 ErrorKind::InvalidToolResult,
301 "tool call is not pending on this turn",
302 )));
303 return Ok(());
304 };
305 let message = json!({"id": pending.id, "result": {"contentItems": [{"type": "inputText", "text": result.output}], "success": result.success}});
306 if let Err(error) = self.transport.send(&message).await.map_err(map_wire) {
307 let _ = reply.send(Err(error.clone()));
308 return Err(error);
309 }
310 let _ = reply.send(Ok(()));
311 }
312 Command::Abandon { key, turn } => self.abandon(&key, turn).await?,
313 Command::Close { key, reply } => {
314 if self.start_pending(&key) {
315 let _ = reply.send(Err(
316 self.error(ErrorKind::Busy, "conversation is active or already closing")
317 ));
318 return Ok(());
319 }
320 let thread = match self.state.begin_close(&key) {
321 Ok(Some(thread)) => thread,
322 Ok(None) => {
323 let _ = reply.send(Ok(()));
324 return Ok(());
325 }
326 Err(error) => {
327 let _ = reply.send(Err(self.stamp(error)));
328 return Ok(());
329 }
330 };
331 if let Err(error) = self
332 .request(
333 "thread/unsubscribe",
334 json!({"threadId": thread}),
335 Pending::Close {
336 key: key.clone(),
337 thread,
338 reply: Some(reply),
339 },
340 )
341 .await
342 {
343 self.state.cancel_close(&key);
344 return Err(error);
345 }
346 }
347 }
348 Ok(())
349 }
350 async fn message(&mut self, message: Value) -> Result<(), Error> {
351 self.refresh();
352 match decode(message.clone()) {
353 Inbound::ClientResponse(response) => self.response(response.id, response.outcome).await,
354 Inbound::Scoped(event) => self.scoped(event, message).await,
355 Inbound::ResolvedRequest(id) => {
356 self.state
357 .resolve_tool(&id.as_value())
358 .map_err(|error| self.stamp(error))?;
359 Ok(())
360 }
361 Inbound::GlobalServerError(error) => Err(error.to_error(self.transport.diagnostics())),
362 Inbound::ModelReroute(reroute) => {
363 if let Some(id) = reroute.id {
364 self.reject(&id, -32602, "model rerouting is unsupported")
365 .await?;
366 }
367 Err(self.error(ErrorKind::Protocol, "model rerouting is unsupported"))
368 }
369 Inbound::UnsupportedServerRequest(request) => {
370 self.reject(&request.id, -32601, "unsupported server request")
371 .await
372 }
373 Inbound::IgnoredNotification { .. } => Ok(()),
374 Inbound::Malformed(error) => self.malformed(&message, error).await,
375 }
376 }
377 async fn malformed(&mut self, message: &Value, error: Error) -> Result<(), Error> {
378 if message.get("method").and_then(Value::as_str) == Some("item/tool/call")
379 && let Some(id) = message.get("id")
380 && let Ok(id) = RpcId::try_from(id)
381 {
382 self.reject(&id, -32602, "malformed dynamic tool request")
383 .await?;
384 }
385 Err(self.stamp(error))
386 }
387 async fn response(&mut self, id: u64, outcome: ResponseOutcome) -> Result<(), Error> {
388 let pending = self
389 .state
390 .take_pending(id)
391 .map_err(|error| self.stamp(error))?;
392 let result = match outcome {
393 ResponseOutcome::Result(result) => result,
394 ResponseOutcome::Error(error) => {
395 return self
396 .pending_failed(pending, error.to_error(self.transport.diagnostics()))
397 .await;
398 }
399 };
400 match pending {
401 Pending::Thread { key, serial, input } => {
402 let Some(thread) = result
403 .pointer("/thread/id")
404 .and_then(Value::as_str)
405 .map(str::to_owned)
406 else {
407 let error = self.error(
408 ErrorKind::Protocol,
409 "thread/start response omitted thread.id",
410 );
411 return self.prestart_fail(&key, serial, error).await;
412 };
413 let live = match self
414 .state
415 .conversations
416 .get(&key)
417 .and_then(|conversation| conversation.active.as_ref())
418 {
419 Some(active) if active.serial == serial => !active.cancelled,
420 Some(_) => {
421 return Err(self.error(
422 ErrorKind::Protocol,
423 "thread/start response crossed conversation turns",
424 ));
425 }
426 None => false,
427 };
428 if let Err(error) = self.state.set_thread(&key, thread.clone()) {
429 let error = self.stamp(error);
430 return self.prestart_fail(&key, serial, error).await;
431 }
432 if !live {
433 if let Some(active) = self.state.take_active(&key, serial) {
434 self.reject_early(active.early, "turn was abandoned")
435 .await?;
436 }
437 return self.retire_thread(&key).await;
438 }
439 self.request(
440 "turn/start",
441 turn_start_params(&thread, input),
442 Pending::Turn { key, serial },
443 )
444 .await?;
445 }
446 Pending::Turn { key, serial } => {
447 let Some(turn) = result
448 .pointer("/turn/id")
449 .and_then(Value::as_str)
450 .map(str::to_owned)
451 else {
452 let error =
453 self.error(ErrorKind::Protocol, "turn/start response omitted turn.id");
454 return self.prestart_fail(&key, serial, error).await;
455 };
456 let Some(early) = self.state.set_native_turn(&key, serial, turn.clone()) else {
457 return self.retire_turn(&key, &turn).await;
458 };
459 for message in early {
460 match decode(message.clone()) {
461 Inbound::Scoped(event) => self.scoped(event, message).await?,
462 Inbound::Malformed(error) => return Err(self.stamp(error)),
463 _ => {
464 return Err(self.error(
465 ErrorKind::Protocol,
466 "buffered event changed classification",
467 ));
468 }
469 }
470 }
471 self.interrupt(&key, serial).await?;
472 }
473 Pending::Close { key, thread, reply } => {
474 if let Err(error) = self.state.finish_close(&key, &thread) {
475 let error = self.stamp(error);
476 if let Some(reply) = reply {
477 let _ = reply.send(Err(error.clone()));
478 }
479 return Err(error);
480 }
481 if let Some(reply) = reply {
482 let _ = reply.send(Ok(()));
483 }
484 }
485 Pending::Interrupt => {}
486 }
487 Ok(())
488 }
489 async fn pending_failed(
490 &mut self,
491 pending: Pending<CloseReply>,
492 error: Error,
493 ) -> Result<(), Error> {
494 match pending {
495 Pending::Thread { key, serial, .. } | Pending::Turn { key, serial } => {
496 self.prestart_fail(&key, serial, error).await
497 }
498 Pending::Close { key, reply, .. } => {
499 self.state.cancel_close(&key);
500 if let Some(reply) = reply {
501 let _ = reply.send(Err(error));
502 }
503 Ok(())
504 }
505 Pending::Interrupt => Err(error),
506 }
507 }
508 async fn scoped(&mut self, event: ScopedEvent, message: Value) -> Result<(), Error> {
509 let ScopedEvent { scope, kind } = event;
510 let Some(key) = self.state.owner(&scope.thread_id).map(str::to_owned) else {
511 self.reject_if_tool(&kind, "unknown thread").await?;
512 return Ok(());
513 };
514 let Some((serial, current, cancelled)) = self
515 .state
516 .conversations
517 .get(&key)
518 .and_then(|conversation| conversation.active.as_ref())
519 .map(|active| (active.serial, active.turn.clone(), active.cancelled))
520 else {
521 self.reject_if_tool(&kind, "no active turn").await?;
522 return Ok(());
523 };
524 let Some(current) = current else {
525 if cancelled && !matches!(&kind, ScopedKind::TurnCompleted(_) | ScopedKind::Error(_)) {
526 self.reject_if_tool(&kind, "turn was abandoned").await?;
527 return Ok(());
528 }
529 let active = self
530 .state
531 .conversations
532 .get_mut(&key)
533 .and_then(|conversation| conversation.active.as_mut())
534 .expect("active turn exists");
535 if active.early.len() >= EARLY_LIMIT {
536 self.reject_if_tool(&kind, "early event limit exceeded")
537 .await?;
538 return Err(self.error(ErrorKind::Protocol, "early event limit exceeded"));
539 }
540 active.early.push(message);
541 return Ok(());
542 };
543 if current != scope.turn_id {
544 self.reject_if_tool(&kind, "request is outside the active turn")
545 .await?;
546 return Ok(());
547 }
548 if cancelled && !matches!(&kind, ScopedKind::TurnCompleted(_)) {
549 self.reject_if_tool(&kind, "turn was abandoned").await?;
550 return Ok(());
551 }
552 self.dispatch(key, serial, kind).await
553 }
554 async fn dispatch(&mut self, key: String, serial: u64, kind: ScopedKind) -> Result<(), Error> {
555 match kind {
556 ScopedKind::AgentTextDelta(delta) => {
557 if !self.emit(&key, serial, Event::TextDelta(delta)) {
558 self.abandon(&key, serial).await?;
559 }
560 }
561 ScopedKind::DynamicToolCall(call) => self.tool_call(&key, serial, call).await?,
562 ScopedKind::TurnCompleted(completed) => self.complete(&key, serial, completed).await?,
563 ScopedKind::Error(error) => {
564 if let Some(active) = self
565 .state
566 .conversations
567 .get_mut(&key)
568 .and_then(|conversation| conversation.active.as_mut())
569 .filter(|active| active.serial == serial)
570 {
571 active.failure = Some(error.details);
572 }
573 }
574 ScopedKind::TurnStarted => {}
575 }
576 Ok(())
577 }
578 async fn tool_call(
579 &mut self,
580 key: &str,
581 serial: u64,
582 call: DecodedToolCall,
583 ) -> Result<(), Error> {
584 if !self.config.tools.iter().any(|tool| tool.name == call.name) {
585 self.reject(&call.rpc_id, -32602, "unconfigured dynamic tool")
586 .await?;
587 return self
588 .fail_turn(
589 key,
590 serial,
591 self.error(ErrorKind::Protocol, "unconfigured dynamic tool requested"),
592 )
593 .await;
594 }
595 let id = call.rpc_id.as_value();
596 if let Err(error) = self
597 .state
598 .track_tool(key, serial, call.call_id.clone(), &id)
599 {
600 let error = self.stamp(error);
601 if error.message != "duplicate dynamic tool call id" {
602 return Err(error);
603 }
604 self.reject(&call.rpc_id, -32602, &error.message).await?;
605 return self.fail_turn(key, serial, error).await;
606 }
607 if !self.emit(
608 key,
609 serial,
610 Event::ToolCall(ToolCall {
611 call_id: call.call_id,
612 name: call.name,
613 arguments: call.arguments,
614 }),
615 ) {
616 self.abandon(key, serial).await?;
617 }
618 Ok(())
619 }
620 async fn complete(
621 &mut self,
622 key: &str,
623 serial: u64,
624 completed: TurnCompleted,
625 ) -> Result<(), Error> {
626 let pending = self
627 .state
628 .tools
629 .keys()
630 .filter(|(owner, turn, _)| owner == key && *turn == serial)
631 .count();
632 if pending != 0 {
633 self.reject_tools(key, serial, "turn completed before tool results")
634 .await?;
635 }
636 let Some(mut active) = self.state.take_active(key, serial) else {
637 return Ok(());
638 };
639 if active.cancelled {
640 return Ok(());
641 }
642 let failure = completed
643 .failure
644 .or_else(|| active.failure.take().map(ServerError::new));
645 let event = match completed.status {
646 TurnStatus::Completed if pending == 0 => Event::Done,
647 TurnStatus::Completed => Event::Error(self.error(
648 ErrorKind::Protocol,
649 "turn completed with pending tool calls",
650 )),
651 TurnStatus::Interrupted => {
652 Event::Error(self.error(ErrorKind::Interrupted, "Codex turn was interrupted"))
653 }
654 TurnStatus::Failed => Event::Error(
655 failure
656 .unwrap_or_else(|| ServerError::new(Value::Null))
657 .to_error(self.transport.diagnostics()),
658 ),
659 };
660 if let Some(events) = active.sink {
661 let _ = events.send(event);
662 }
663 Ok(())
664 }
665 async fn prestart_fail(&mut self, key: &str, serial: u64, error: Error) -> Result<(), Error> {
666 if let Some(active) = self.state.take_active(key, serial) {
667 if let Some(events) = active.sink {
668 let _ = events.send(Event::Error(error));
669 }
670 self.reject_early(active.early, "turn failed to start")
671 .await?;
672 }
673 Ok(())
674 }
675 async fn fail_turn(&mut self, key: &str, serial: u64, error: Error) -> Result<(), Error> {
676 if let Some(active) = self
677 .state
678 .conversations
679 .get_mut(key)
680 .and_then(|conversation| conversation.active.as_mut())
681 .filter(|active| active.serial == serial)
682 {
683 if let Some(events) = active.sink.take() {
684 let _ = events.send(Event::Error(error));
685 }
686 active.cancelled = true;
687 }
688 self.reject_tools(key, serial, "turn failed").await?;
689 self.interrupt(key, serial).await
690 }
691 async fn abandon(&mut self, key: &str, serial: u64) -> Result<(), Error> {
692 if let Some(active) = self
693 .state
694 .conversations
695 .get_mut(key)
696 .and_then(|conversation| conversation.active.as_mut())
697 .filter(|active| active.serial == serial)
698 {
699 active.sink.take();
700 active.cancelled = true;
701 }
702 self.reject_tools(key, serial, "turn was abandoned").await?;
703 self.interrupt(key, serial).await
704 }
705 async fn interrupt(&mut self, key: &str, serial: u64) -> Result<(), Error> {
706 let cancelled = self
707 .state
708 .conversations
709 .get(key)
710 .and_then(|conversation| conversation.active.as_ref())
711 .is_some_and(|active| active.serial == serial && active.cancelled);
712 if cancelled && let Some((thread, turn)) = self.state.interrupt_target(key, serial) {
713 self.request(
714 "turn/interrupt",
715 json!({"threadId": thread, "turnId": turn}),
716 Pending::Interrupt,
717 )
718 .await?;
719 }
720 Ok(())
721 }
722 async fn retire_turn(&mut self, key: &str, turn: &str) -> Result<(), Error> {
723 let thread = self
724 .state
725 .thread(key)
726 .ok_or_else(|| {
727 self.error(
728 ErrorKind::Protocol,
729 "orphan turn had no conversation thread",
730 )
731 })?
732 .to_owned();
733 self.request(
734 "turn/interrupt",
735 json!({"threadId": thread, "turnId": turn}),
736 Pending::Interrupt,
737 )
738 .await?;
739 self.retire_thread(key).await
740 }
741 async fn retire_thread(&mut self, key: &str) -> Result<(), Error> {
742 let thread = match self.state.begin_close(key) {
743 Ok(Some(thread)) => thread,
744 Ok(None) => return Ok(()),
745 Err(error) => return Err(self.stamp(error)),
746 };
747 self.request(
748 "thread/unsubscribe",
749 json!({"threadId": thread}),
750 Pending::Close {
751 key: key.to_owned(),
752 thread,
753 reply: None,
754 },
755 )
756 .await
757 }
758 async fn reject_early(&mut self, early: Vec<Value>, reason: &str) -> Result<(), Error> {
759 for message in early {
760 match decode(message) {
761 Inbound::Scoped(event) => self.reject_if_tool(&event.kind, reason).await?,
762 Inbound::Malformed(error) => return Err(self.stamp(error)),
763 _ => {
764 return Err(
765 self.error(ErrorKind::Protocol, "buffered event changed classification")
766 );
767 }
768 }
769 }
770 Ok(())
771 }
772 async fn reject_tools(&mut self, key: &str, serial: u64, reason: &str) -> Result<(), Error> {
773 for (_, pending) in self.state.take_turn_tools(key, serial) {
774 let id = RpcId::try_from(&pending.id).map_err(|error| self.stamp(error))?;
775 self.reject(&id, -32800, reason).await?;
776 }
777 Ok(())
778 }
779 async fn reject_all(&mut self, reason: &str) -> Result<(), Error> {
780 let tokens: Vec<_> = self.state.tools.keys().cloned().collect();
781 for token in tokens {
782 if let Some(pending) = self.state.take_tool(&token) {
783 let id = RpcId::try_from(&pending.id).map_err(|error| self.stamp(error))?;
784 self.reject(&id, -32800, reason).await?;
785 }
786 }
787 Ok(())
788 }
789 async fn reject_if_tool(&mut self, kind: &ScopedKind, reason: &str) -> Result<(), Error> {
790 if let ScopedKind::DynamicToolCall(call) = kind {
791 self.reject(&call.rpc_id, -32602, reason).await?;
792 }
793 Ok(())
794 }
795 async fn reject(&mut self, id: &RpcId, code: i64, reason: &str) -> Result<(), Error> {
796 let (_, key) = parse_rpc_id(&id.as_value()).map_err(|error| self.stamp(error))?;
797 if self.state.rpc_ids.contains(&key) {
798 return Err(self.error(ErrorKind::Protocol, "duplicate app-server request id"));
799 }
800 self.transport
801 .send(&rejection_payload(id, code, reason))
802 .await
803 .map_err(map_wire)
804 }
805 async fn request(
806 &mut self,
807 method: &str,
808 params: Value,
809 pending: Pending<CloseReply>,
810 ) -> Result<(), Error> {
811 let id = self
812 .state
813 .allocate_request_id()
814 .map_err(|error| self.stamp(error))?;
815 self.transport
816 .send(&json!({"method": method, "id": id, "params": params}))
817 .await
818 .map_err(map_wire)?;
819 self.state
820 .insert_pending(id, pending)
821 .map_err(|error| self.stamp(error))
822 }
823 fn start_pending(&self, key: &str) -> bool {
824 self.state.pending.values().any(|pending| matches!(pending, Pending::Thread { key: owner, .. } | Pending::Turn { key: owner, .. } if owner == key))
825 }
826 fn emit(&mut self, key: &str, serial: u64, event: Event) -> bool {
827 self.state
828 .conversations
829 .get_mut(key)
830 .and_then(|conversation| conversation.active.as_mut())
831 .filter(|active| active.serial == serial)
832 .and_then(|active| active.sink.as_ref())
833 .is_some_and(|events| events.send(event).is_ok())
834 }
835 fn error(&self, kind: ErrorKind, message: impl Into<String>) -> Error {
836 Error {
837 kind,
838 message: message.into(),
839 diagnostics: self.transport.diagnostics(),
840 }
841 }
842 fn stamp(&self, mut error: Error) -> Error {
843 error.diagnostics = self.transport.diagnostics();
844 error
845 }
846 fn refresh(&self) {
847 self.diagnostics.replace(self.transport.diagnostics());
848 }
849}
850fn map_wire(error: WireError) -> Error {
851 let kind = match error.kind {
852 WireKind::Protocol => ErrorKind::Protocol,
853 WireKind::Server => ErrorKind::Server,
854 WireKind::Spawn | WireKind::Timeout | WireKind::Io | WireKind::Closed => {
855 ErrorKind::Unavailable
856 }
857 };
858 Error {
859 kind,
860 message: error.message,
861 diagnostics: error.diagnostics,
862 }
863}