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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | 1x 5x 5x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 2x 2x 2x 2x 2x 4x 2x | import { mergeDisjointRecords } from '@metamask/kernel-utils';
import type { Logger } from '@metamask/logger';
import type { LanguageModel } from '@ocap/kernel-language-model-service';
import { doAttempt } from './attempt.ts';
import { TaskManager } from './task.ts';
import type { Message, MessageTypeBase } from './types/messages.ts';
import type {
Agent,
CapabilityRecord,
PrepareAttempt,
TaskArgs,
} from './types.ts';
import { ifDefined } from './utils.ts';
export type MakeAgentArgs = {
languageModel: LanguageModel<unknown, { response: string }>;
capabilities: CapabilityRecord;
logger?: Logger;
};
/**
* Make a capability-augmented agent
*
* @param args - The arguments to make the agent.
* @param args.languageModel - The language model to use for the agent
* @param args.capabilities - The agent's capabilities
* @param args.logger - The logger to use for the agent
* @param prepareAttempt - A strategy function to prepare the attempt.
* @returns A kernel agent
*/
export const makeAgent = <
State extends Message<MessageTypeBase>[],
Action extends Message<MessageTypeBase>,
Observation extends Message<MessageTypeBase>,
>(
{
languageModel,
capabilities: agentCapabilities,
logger: agentLogger,
}: MakeAgentArgs,
prepareAttempt: PrepareAttempt<State, Action, Observation>,
): Agent => {
const taskManager = new TaskManager();
return {
/**
* Task the agent to fulfill an objective.
*
* @param intent - A string specifying the objective of the task.
* @param judgment - A function that determines if the task is complete.
* @param options - The options for the task.
* @param options.invocationBudget - The maximum number of steps the agent is allowed to take.
* @param options.seed - The seed for the task.
* @param options.logger - The logger for the task.
* @param options.capabilities - The capabilities for the task.
* @param options.nAttempts - The number of attempts the agent is allowed to make.
* @returns The result of the task.
*/
task: async <Result>(
intent: string,
judgment?: (result: unknown) => result is Result,
{
invocationBudget = 10,
seed = Date.now().valueOf(), // XXX: Replace with something more real
logger: printLogger,
capabilities: taskCapabilities = {},
nAttempts = 1,
}: TaskArgs = {},
) => {
const capabilities = mergeDisjointRecords(
agentCapabilities,
taskCapabilities,
) as CapabilityRecord;
const thisTask = taskManager.makeTask<Result>({
intent,
capabilities,
...ifDefined({ judgment }),
});
const { id: taskId, objective, context } = thisTask;
const taskLogger = agentLogger?.subLogger({ tags: [taskId] });
taskLogger?.info('intent:', intent);
for (let attempt = 0; attempt < nAttempts; attempt++) {
taskLogger?.info(`Attempt ${attempt + 1} of ${nAttempts}`);
const [prep, state] = prepareAttempt({
objective,
context,
options: ifDefined({ seed, printLogger, taskLogger }),
});
const { history } = state;
try {
const result = await doAttempt(
prep,
state,
languageModel,
ifDefined({ maxSteps: invocationBudget, logger: taskLogger }),
);
thisTask.attempts.push({ history, result });
return result;
} catch (error) {
if (error instanceof Error) {
thisTask.attempts.push({ history, error });
} else E{
throw new Error(`Unknown error: ${error as string}`, {
cause: error,
});
}
}
}
const howManyAttempts = `${nAttempts} attempt${nAttempts === 1 ? '' : 's'}`;
throw new Error(
[
`Failed to complete task in ${howManyAttempts}`,
...thisTask.attempts.map(
(attempt, index) =>
`${index + 1}: ${attempt.error?.message ?? 'Unknown'}`,
),
].join('\n'),
);
},
/**
* Get the experiences of the agent. Used for learning.
*
* @returns An iterator over the experiences.
*/
get experiences() {
return (async function* () {
for (const task of taskManager.tasks) {
for (const attempt of task.attempts) {
yield {
objective: task.objective,
context: task.context,
...attempt,
};
}
}
})();
},
};
};
|