Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Format Parsers #708

Open
5 of 9 tasks
mbleigh opened this issue Jul 29, 2024 · 0 comments
Open
5 of 9 tasks

Custom Format Parsers #708

mbleigh opened this issue Jul 29, 2024 · 0 comments
Labels
feature New feature or request js

Comments

@mbleigh
Copy link
Collaborator

mbleigh commented Jul 29, 2024

Currently the output() method on Genkit results attempts to leniently parse JSON based on whether format is supplied or an output schema is present. There are a variety of reasons, however, that someone might want to have greater control over output parsing than this.

Proposed is to extend the format option to instead be a registry of formatters with some defaults (text and json at a minimum), provided. To define a custom format parser, developers would specify it something like so:

defineFormat('csv', (req) => {
  return {
    parseResponse: (res) => {
      const toParse = extractCodeFence(res.text);
      return parseCSV(toParse);
    },
    // optional, if omitted streaming `.output()` is not supported for this format type
    parseChunk: (chunk) => {
      // here `chunk` contains only the most recent data, `partialResponse` contains
      // a Message with all chunks received so far
      const toParse = extractPartialCodeFence(chunk.accumulatedText);
      return parseCSV(toParse);
    },
    instructions: `Output should be in CSV format with the following columns:\n\n${schemaToCSVSpec(req.output.schema)}.`
  }
});

The parser definition semantics should be flexible enough to handle many different scenarios, including:

  1. Built-up response: where each chunk in a stream returns an incrementally more complete response
  2. Buffered chunking: where e.g. JSONL is streamed but only on complete objects (so parseChunk must have the ability to return null and not emit a chunk to the end user)
  3. Options/Schema: allow a format parser to access the full request including output schema and control how output validation occurs.

To use a custom format is simple: just use the format option already in output.

generate({
  prompt: "Generate a contact list with 10 people.",
  output: {
    format: 'csv',
    schema: z.array(z.object({firstName: z.string(), lastName: z.string()})
  },
});

Work Plan

  • Create an interface for formatters that can handle streaming as well as custom instructions.
  • Implement a base set of default formatters - text, json, array, jsonl, enum.
  • Refactor generate and generateStream to play nicely with new streaming semantics.
  • Figure out how to reconcile new streaming semantics with tool loop.
  • Figure out how media and multi-modal output should work.
  • Add instructions?: boolean | string | (req: GenerateRequest) => string for custom instructions control.
  • Add constrained?: boolean option to output for schema-constrained generation, and implement it for Gemini models.
  • Add enum mode to Gemini models.
  • Add support for ai.defineFormat to define custom formats.
@chrisraygill chrisraygill added the feature New feature or request label Jul 29, 2024
@chrisraygill chrisraygill added the js label Sep 5, 2024
galihlprakoso added a commit to galihlprakoso/genkit that referenced this issue Oct 23, 2024
mbleigh added a commit that referenced this issue Oct 28, 2024
Adds a new "Formatter" interface and re-implements existing JSON and text formatting with the new interface in addition to adding new "array" and "jsonl" format types.
mbleigh added a commit that referenced this issue Oct 30, 2024
…1131)

Also reorganizes `generate` into multiple files.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request js
Projects
Status: No status
Development

No branches or pull requests

2 participants