mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-05 08:10:14 +00:00
fix: ensure lossless artifact storage and strict mode compatibility
- OutputInterceptor: Buffer ALL chunks before spilling to disk to preserve full content losslessly. Previously, the rolling tail buffer could drop middle content before the spill decision was made. - read_command_output schema: Include all properties in 'required' array for OpenAI strict mode compliance. With strict: true, all properties must be listed in required (optional ones use null union types).
This commit is contained in:
parent
cf7472945d
commit
2dcd3a187f
2 changed files with 22 additions and 17 deletions
|
|
@ -70,7 +70,9 @@ export default {
|
|||
description: LIMIT_DESCRIPTION,
|
||||
},
|
||||
},
|
||||
required: ["artifact_id"],
|
||||
// With strict: true, ALL properties must be listed in required.
|
||||
// Optional params use union type with null (e.g., ["string", "null"]).
|
||||
required: ["artifact_id", "search", "offset", "limit"],
|
||||
additionalProperties: false,
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -67,6 +67,13 @@ export class OutputInterceptor {
|
|||
/** Number of bytes omitted from the middle */
|
||||
private omittedBytes: number = 0
|
||||
|
||||
/**
|
||||
* Pending chunks accumulated before spilling to disk.
|
||||
* These contain ALL content (lossless) until we decide to spill.
|
||||
* Once spilled, this array is cleared and subsequent writes go directly to disk.
|
||||
*/
|
||||
private pendingChunks: string[] = []
|
||||
|
||||
private writeStream: fs.WriteStream | null = null
|
||||
private artifactPath: string
|
||||
private totalBytes: number = 0
|
||||
|
|
@ -115,8 +122,11 @@ export class OutputInterceptor {
|
|||
|
||||
// Handle disk spilling for full output preservation
|
||||
if (!this.spilledToDisk) {
|
||||
// Accumulate ALL chunks for lossless disk storage
|
||||
this.pendingChunks.push(chunk)
|
||||
|
||||
if (this.totalBytes > this.previewBytes) {
|
||||
this.spillToDisk(chunk)
|
||||
this.spillToDisk()
|
||||
}
|
||||
} else {
|
||||
// Already spilling - write directly to disk
|
||||
|
|
@ -254,7 +264,7 @@ export class OutputInterceptor {
|
|||
*
|
||||
* @private
|
||||
*/
|
||||
private spillToDisk(currentChunk: string): void {
|
||||
private spillToDisk(): void {
|
||||
// Ensure directory exists
|
||||
const dir = path.dirname(this.artifactPath)
|
||||
if (!fs.existsSync(dir)) {
|
||||
|
|
@ -262,22 +272,15 @@ export class OutputInterceptor {
|
|||
}
|
||||
|
||||
this.writeStream = fs.createWriteStream(this.artifactPath)
|
||||
// Write the full head buffer + any tail content accumulated so far
|
||||
// Note: We need to reconstruct full output seen so far
|
||||
// The full content before this chunk is: totalBytes - currentChunkBytes
|
||||
// But we've already been tracking head/tail, so we write head + omitted + tail + current
|
||||
// Actually, we need to write the complete original content
|
||||
// Since we're spilling on the chunk that pushes us over, we need to write everything
|
||||
// that came before plus this chunk
|
||||
|
||||
// Reconstruct: we have headBuffer (complete head) + whatever was in tail before trimming
|
||||
// For simplicity, write head + tail + current chunk (the tail already has some data)
|
||||
this.writeStream.write(this.headBuffer)
|
||||
if (this.tailBuffer.length > 0) {
|
||||
this.writeStream.write(this.tailBuffer)
|
||||
// Write ALL pending chunks to disk for lossless storage.
|
||||
// This ensures no content is lost, even if the preview buffers have dropped middle content.
|
||||
for (const chunk of this.pendingChunks) {
|
||||
this.writeStream.write(chunk)
|
||||
}
|
||||
// Don't write currentChunk here - it was already processed into head/tail buffers
|
||||
// and will be written via the streaming path
|
||||
|
||||
// Clear pending chunks to free memory - subsequent writes go directly to disk
|
||||
this.pendingChunks = []
|
||||
|
||||
this.spilledToDisk = true
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue