{"record":{"id":"dd16fc0ad34656df","repo":"linshenkx/prompt-optimizer","slug":"extraction-result-must-have-a-summary-string","errorCode":null,"errorMessage":"Extraction result must have a \"summary\" string.","messagePattern":"Extraction result must have a \"summary\" string\\.","errorType":"validation","errorClass":"VariableExtractionParseError","httpStatus":null,"severity":"error","filePath":"packages/core/src/services/variable-extraction/service.ts","lineNumber":204,"sourceCode":"    }\n  }\n\n  /**\n   * 标准化提取响应（统一结构）\n   */\n  private normalizeExtractionResponse(data: any): VariableExtractionResponse {\n    if (!data || typeof data !== 'object') {\n      throw new VariableExtractionParseError('Extraction result is not a valid object.');\n    }\n\n    // 验证 variables 字段\n    if (!Array.isArray(data.variables)) {\n      throw new VariableExtractionParseError('Extraction result must have a \"variables\" array.');\n    }\n\n    // 验证 summary 字段\n    if (typeof data.summary !== 'string') {\n      throw new VariableExtractionParseError('Extraction result must have a \"summary\" string.');\n    }\n\n    // 标准化每个变量\n    const variables: ExtractedVariable[] = data.variables.map((variable: any, index: number) => {\n      // 验证必需字段\n      if (!variable || typeof variable !== 'object') {\n        throw new VariableExtractionParseError(`variables[${index}] is not a valid object.`);\n      }\n\n      if (typeof variable.name !== 'string' || !variable.name.trim()) {\n        throw new VariableExtractionParseError(`variables[${index}] is missing a valid \"name\" field.`);\n      }\n\n      if (typeof variable.value !== 'string') {\n        throw new VariableExtractionParseError(`variables[${index}] is missing a valid \"value\" field.`);\n      }\n\n      if (!variable.position || typeof variable.position !== 'object') {","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/linshenkx/prompt-optimizer/blob/3e677b1d9f7e0493c142c175560531e7ae786dce/packages/core/src/services/variable-extraction/service.ts#L186-L222","documentation":"The parsed LLM response object has a 'summary' field that is missing or not a string. The unified extraction schema requires a top-level string summary, so normalization fails even if the variables array is fine.","triggerScenarios":"Model returns an object with a valid variables array but omits summary, returns summary as null/number/object, or nests it one level deeper. Reached via extract() during normalizeExtractionResponse.","commonSituations":"Model instructed only to extract variables so it drops the summary field; model returns \"summary\": null when nothing to summarize; template's output-format section no longer mentions summary after an edit.","solutions":["Update the prompt/template to require \"summary\" as a string (e.g. \"summary\": \"\" when nothing to say).","Add a defensive default before normalization: if (typeof parsed.summary !== 'string') parsed.summary = ''.","Log the parsed response to confirm which shape the model emits.","Provide a few-shot example in the template showing summary present."],"exampleFix":"// before\nreturn this.normalizeExtractionResponse(parsed);\n\n// after\nif (typeof parsed.summary !== 'string') parsed.summary = '';\nreturn this.normalizeExtractionResponse(parsed);","handlingStrategy":"validation","validationCode":null,"typeGuard":"const hasStringSummary = (d: unknown): boolean =>\n  isExtractionObject(d) && typeof (d as any).summary === 'string';","tryCatchPattern":"try {\n  await extractionService.extract({ modelKey, content });\n} catch (e) {\n  if (e instanceof VariableExtractionParseError && /\"summary\" string/.test(e.message)) {\n    // inject a default summary and retry, or fix the prompt\n  }\n  throw e;\n}","preventionTips":["Default missing summaries in your own layer: parsed.summary ??= '' before validation.","Mention the summary field (and its type) in the prompt's output-format instruction.","Add schema-constrained output when the provider offers it."],"tags":["llm","json","schema","validation"],"backgroundTag":"llm-response-schema-mismatch","analyzedSha":"3e677b1d9f7e0493c142c175560531e7ae786dce","analyzedAt":"2026-08-27T21:29:16.709Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}