MCPcopy Create free account
hub / github.com/MatterAIOrg/OrbCode / runStep

Method runStep

src/core/agent.ts:615–751  ·  view source on GitHub ↗

Run one model request + tool execution round. Returns true when the turn is over.

()

Source from the content-addressed store, hash-verified

613
614 /** Run one model request + tool execution round. Returns true when the turn is over. */
615 private async runStep(): Promise<boolean> {
616 const { onEvent } = this.options.callbacks
617 const signal = this.abortController!.signal
618
619 let assistantText = ""
620 // A reasoning segment is "open" from its first delta until visible content
621 // (text or a tool call) begins. We emit reasoning-done at that transition so
622 // "Thought for Ns" reflects only the thinking time — not the answer that
623 // follows — and the live "Thinking" block stops before the answer streams.
624 // A fresh segment can re-open if the model interleaves reasoning with content.
625 let reasoningOpen = false
626 let reasoningStart = 0
627 let reasoningDetails: unknown
628 // Once a reasoning-done row is committed to the transcript we can't roll it
629 // back, so a mid-stream retry after that point isn't clean.
630 let reasoningRowCommitted = false
631 const finalizeReasoning = () => {
632 if (reasoningOpen) {
633 reasoningOpen = false
634 reasoningRowCommitted = true
635 onEvent({ type: "reasoning-done", durationMs: Date.now() - reasoningStart })
636 }
637 }
638 const toolCallsByIndex = new Map<number, PendingToolCall>()
639 let nextSyntheticIndex = 10000
640
641 // Roll back this step's partial output so streamWithRetry can restart a
642 // dropped stream mid-flight. Tools only run after the stream completes, so
643 // nothing irreversible has happened yet; the one thing we can't undo is an
644 // already-committed reasoning row, so we decline the restart in that case.
645 const rollbackForRetry = (): boolean => {
646 if (reasoningRowCommitted) return false
647 assistantText = ""
648 reasoningOpen = false
649 reasoningStart = 0
650 reasoningDetails = undefined
651 toolCallsByIndex.clear()
652 nextSyntheticIndex = 10000
653 onEvent({ type: "stream-reset" })
654 return true
655 }
656
657 const stream = this.streamWithRetry(
658 () => this.client.createMessage(this.systemPrompt, this.outgoingMessages(), getActiveTools(this.mcp), signal),
659 signal,
660 rollbackForRetry,
661 )
662
663 for await (const chunk of stream) {
664 if (signal.aborted) throw new DOMException("aborted", "AbortError")
665 switch (chunk.type) {
666 case "text":
667 // Visible content begins — the reasoning phase (if any) is over.
668 finalizeReasoning()
669 assistantText += chunk.text
670 onEvent({ type: "text-delta", text: chunk.text })
671 break
672 case "reasoning":

Callers 1

runTurnMethod · 0.95

Calls 5

streamWithRetryMethod · 0.95
outgoingMessagesMethod · 0.95
handleToolCallMethod · 0.95
getActiveToolsFunction · 0.85
createMessageMethod · 0.65

Tested by

no test coverage detected