All files / kernel-agents/src attempt.ts

100% Statements 18/18
100% Branches 4/4
100% Functions 3/3
100% Lines 17/17

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62                2x                                     9x   9x 12x   12x     12x     12x 12x     12x 11x     1x       11x 6x 6x 6x       5x   5x    
import { SampleGenerationError } from '@metamask/kernel-errors';
import type { Logger } from '@metamask/logger';
import type { LanguageModel } from '@ocap/kernel-language-model-service';
 
import type { Message, MessageTypeBase } from './types/messages.ts';
import type { PREP, Progress } from './types.ts';
import { withRetries } from './utils.ts';
 
export const doAttempt = async <
  Result,
  State extends Message<MessageTypeBase>[],
  Action extends Message<MessageTypeBase>,
  Observation extends Message<MessageTypeBase>,
>(
  [prompter, reader, evaluator, printer]: PREP<State, Action, Observation>,
  progress: Progress<Result, State>,
  languageModel: LanguageModel<unknown, { response: string }>,
  {
    maxSteps = 10,
    maxRetries = 3,
    logger,
  }: {
    maxSteps?: number;
    maxRetries?: number;
    logger?: Logger;
  },
): Promise<Result> => {
  const { history } = progress;
 
  for (let step = 1; step <= maxSteps; step++) {
    logger?.info(`Step ${step} of ${maxSteps}`);
 
    const actionAndOutcome = await withRetries(
      async () => {
        // Observe
        const { prompt, readerArgs } = prompter(history);
 
        // Act
        const { stream, abort } = await languageModel.sample(prompt);
        const action = await reader({ stream, abort, ...readerArgs });
 
        // Step
        const outcome = await evaluator(history, action);
        return [action, outcome];
      },
      maxRetries,
      (error) => error instanceof SampleGenerationError,
    );
 
    // If done, exit
    if (progress.isDone()) {
      const { result } = progress;
      logger?.info('done:', result);
      return result as Result;
    }
 
    // Render
    printer(...actionAndOutcome);
  }
  throw new Error('Invocation budget exceeded');
};