Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

YamlReporter: structuredOutput is stored as a JSON-encoded string inside a block scalar, not as native YAML data

オープン 初心者向け
#76 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
78/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
静か
技術スタック
typescript, yaml
領域
tooling

調査の方向性

src/reporters/yaml.ts から始めて、現在はシリアライズされた部分文字列だけを検証している既存の YAML reporter のテストを確認してください。structuredOutput のパスを変更する前に、そのテストを実行してください。YAML パーサーが入力と同じネストされたデータを持つオブジェクトとして structuredOutput を返し、既存のレポート動作が維持されれば完了です。

索引モデルが issue の本文から書いたものです。

説明

bug S3

Observed behavior

When a successful result includes structuredOutput, YamlReporter.append serialises it by JSON.stringify'ing the value and writing the resulting text into a YAML block scalar:

// src/reporters/yaml.ts
if (result.structuredOutput !== undefined) {
  lines.push('structuredOutput: |');
  const json = JSON.stringify(result.structuredOutput, null, 2);
  for (const line of formatBlockScalar(json).split('\n')) {
    lines.push(line === '' ? /* istanbul ignore next */ '' : `  ${line}`);
  }
}

A consumer parsing the report file with any YAML loader gets back structuredOutput as a string containing JSON, not as the structured object the agent produced. To use the data they have to do a second JSON.parse step that they would not have to do for any other field in the report.

This is inconsistent with JsonlReporter, which spreads the result into the output line:

// src/reporters/jsonl.ts
const output = `${JSON.stringify({ ...prompt, ...result })}\n`;

For the JSONL reporter, structuredOutput round-trips as a nested object, so a consumer can read entry.structuredOutput.found directly. Switching the configured reporter from JSONL to YAML (or to the default, which is YAML) silently changes the shape of structuredOutput from "structured object" to "JSON-encoded string".

The existing test only asserts that the YAML contains the substrings "found": true and "a.ts": "bug", so the bug is not caught.

Expected behavior

structuredOutput is documented in src/types.ts as "the parsed object that conforms to the schema". A reporter that persists a result entry should preserve that shape: parsing the YAML report should yield an object, not a string. This is also what users will expect from a structured-data report format.

Minimal reproduction

import { mkdtemp, readFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { parseAllDocuments } from 'yaml';

import { YamlReporter } from 'loop-the-loop/reporters/yaml';

const dir = await mkdtemp(join(tmpdir(), 'yaml-structured-bug-'));
const reporter = await YamlReporter.create({ outputDir: dir, jobName: 'demo' });

await reporter.append(
  { id: 'a', prompt: 'p' },
  {
    status: 'success',
    output: 'ok',
    structuredOutput: { found: true, items: ['a', 'b'] },
  },
);

const text = await readFile(join(dir, 'demo-report.yaml'), 'utf-8');
const obj = parseAllDocuments(text)[0].toJS();

console.log(typeof obj.structuredOutput);    // 'string'
console.log(obj.structuredOutput.found);     // undefined
console.log(JSON.parse(obj.structuredOutput).found); // true

Suggested fix

Emit structuredOutput as native YAML so it round-trips as an object. The minimal change is to use a YAML serializer for this single field (the rest of the entry could stay hand-written for now):

import { stringify } from 'yaml';

if (result.structuredOutput !== undefined) {
  // `stringify` returns a trailing newline; indent under the parent key
  const yaml = stringify(result.structuredOutput, { indent: 2 });
  lines.push('structuredOutput:');
  for (const line of yaml.trimEnd().split('\n')) {
    lines.push(`  ${line}`);
  }
}

The longer-term fix is to delegate serialization of the whole entry to a YAML library, which also resolves the related issues #69 (id field not escaped) and #75 (block scalar indent bug). A test that round-trips structuredOutput through a real YAML parser and asserts deep-equality with the input would prevent regression.

主要言語
TypeScript
スター
2
フォーク
1
PR マージ指標
30日以内にマージされた PR はありません

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

joewalker/loop-the-loop のほかの issue

joewalker/loop-the-loop の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。