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

Method compact

src/core/agent.ts:487–570  ·  view source on GitHub ↗

Summarize the conversation so far and replace history with the summary.

()

Source from the content-addressed store, hash-verified

485
486 /** Summarize the conversation so far and replace history with the summary. */
487 async compact(): Promise<void> {
488 const { onEvent } = this.options.callbacks
489 if (this.messages.length === 0) {
490 onEvent({ type: "error", message: "Nothing to compact yet." })
491 onEvent({ type: "turn-end" })
492 return
493 }
494 // Covers the resume-then-immediately-/compact path, so SessionStart
495 // always fires before any SessionEnd.
496 await this.maybeFireSessionStart()
497 // If SessionStart produced context, fold it into the compaction request
498 // rather than letting it linger for the next turn.
499 let startContext = ""
500 if (this.pendingStartContext) {
501 startContext = wrapHookContext("SessionStart", this.pendingStartContext) + "\n\n"
502 this.pendingStartContext = ""
503 }
504 // PreCompact runs before summarizing (it cannot cancel compaction).
505 if (this.hooks.hasHooks("PreCompact")) {
506 await this.hooks.run("PreCompact", { trigger: "manual", custom_instructions: "" })
507 }
508 this.abortController = new AbortController()
509 const signal = this.abortController.signal
510 try {
511 const request: OpenAI.Chat.ChatCompletionMessageParam[] = [
512 ...this.outgoingMessages(),
513 {
514 role: "user",
515 content:
516 startContext +
517 "Summarize this conversation so it can replace the full history. Capture the user's goals, decisions made, files created or modified (with paths), important code details, and any remaining next steps. Be thorough but concise. Respond with only the summary.",
518 },
519 ]
520 let summary = ""
521 for await (const chunk of this.streamWithRetry(
522 () => this.client.createMessage(this.systemPrompt, request, [], signal),
523 signal,
524 () => {
525 // Compaction only streams text (committed once at the end), so a
526 // mid-stream retry just discards the partial summary.
527 summary = ""
528 onEvent({ type: "stream-reset" })
529 return true
530 },
531 )) {
532 if (signal.aborted) throw new DOMException("aborted", "AbortError")
533 if (chunk.type === "text") {
534 summary += chunk.text
535 onEvent({ type: "text-delta", text: chunk.text })
536 } else if (chunk.type === "usage") {
537 this.totalCost += chunk.totalCost ?? 0
538 this.contextTokens = (chunk.inputTokens ?? 0) + (chunk.outputTokens ?? 0)
539 onEvent({
540 type: "usage",
541 inputTokens: chunk.inputTokens,
542 outputTokens: chunk.outputTokens,
543 cost: chunk.totalCost ?? 0,
544 totalCost: this.totalCost,

Callers 2

AppFunction · 0.80

Calls 8

maybeFireSessionStartMethod · 0.95
outgoingMessagesMethod · 0.95
streamWithRetryMethod · 0.95
persistMethod · 0.95
wrapHookContextFunction · 0.85
hasHooksMethod · 0.80
runMethod · 0.80
createMessageMethod · 0.65

Tested by

no test coverage detected