@aigne/core 0.4.204 → 0.4.205-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/lib/cjs/agent.js +60 -0
  2. package/lib/cjs/definitions/data-type-schema.js +46 -0
  3. package/lib/cjs/definitions/memory.js +21 -0
  4. package/lib/cjs/function-agent.js +1 -1
  5. package/lib/cjs/function-runner.js +2 -2
  6. package/lib/cjs/index.js +2 -2
  7. package/lib/cjs/llm-agent.js +93 -87
  8. package/lib/cjs/llm-decision-agent.js +40 -33
  9. package/lib/cjs/llm-model.js +2 -2
  10. package/lib/cjs/local-function-agent.js +11 -9
  11. package/lib/cjs/memorable.js +32 -0
  12. package/lib/cjs/pipeline-agent.js +2 -4
  13. package/lib/cjs/runnable.js +3 -1
  14. package/lib/cjs/tsconfig.tsbuildinfo +1 -1
  15. package/lib/cjs/utils/message-utils.js +72 -0
  16. package/lib/cjs/utils/nullable.js +2 -0
  17. package/lib/cjs/utils/ordered-map.js +25 -0
  18. package/lib/cjs/utils/stream-utils.js +43 -5
  19. package/lib/cjs/utils/structured-output-schema.js +39 -0
  20. package/lib/esm/agent.js +53 -0
  21. package/lib/esm/definitions/data-type-schema.js +43 -0
  22. package/lib/esm/definitions/memory.js +18 -0
  23. package/lib/esm/function-agent.js +1 -1
  24. package/lib/esm/function-runner.js +2 -2
  25. package/lib/esm/index.js +2 -2
  26. package/lib/esm/llm-agent.js +94 -88
  27. package/lib/esm/llm-decision-agent.js +41 -34
  28. package/lib/esm/llm-model.js +2 -2
  29. package/lib/esm/local-function-agent.js +11 -9
  30. package/lib/esm/memorable.js +27 -0
  31. package/lib/esm/pipeline-agent.js +2 -4
  32. package/lib/esm/runnable.js +3 -1
  33. package/lib/esm/tsconfig.tsbuildinfo +1 -1
  34. package/lib/esm/utils/message-utils.js +64 -0
  35. package/lib/esm/utils/nullable.js +1 -0
  36. package/lib/esm/utils/ordered-map.js +25 -0
  37. package/lib/esm/utils/stream-utils.js +42 -5
  38. package/lib/esm/utils/structured-output-schema.js +33 -0
  39. package/lib/types/agent.d.ts +42 -0
  40. package/lib/types/context.d.ts +5 -1
  41. package/lib/types/definitions/data-type-schema.d.ts +40 -0
  42. package/lib/types/definitions/memory.d.ts +40 -0
  43. package/lib/types/function-agent.d.ts +1 -1
  44. package/lib/types/function-runner.d.ts +2 -1
  45. package/lib/types/index.d.ts +2 -2
  46. package/lib/types/llm-agent.d.ts +74 -19
  47. package/lib/types/llm-decision-agent.d.ts +54 -30
  48. package/lib/types/llm-model.d.ts +2 -1
  49. package/lib/types/local-function-agent.d.ts +51 -20
  50. package/lib/types/memorable.d.ts +183 -0
  51. package/lib/types/pipeline-agent.d.ts +2 -3
  52. package/lib/types/runnable.d.ts +23 -2
  53. package/lib/types/tsconfig.tsbuildinfo +1 -1
  54. package/lib/types/utils/message-utils.d.ts +20 -0
  55. package/lib/types/utils/nullable.d.ts +7 -0
  56. package/lib/types/utils/ordered-map.d.ts +6 -0
  57. package/lib/types/utils/stream-utils.d.ts +12 -1
  58. package/lib/types/utils/structured-output-schema.d.ts +3 -0
  59. package/lib/types/utils/union.d.ts +1 -1
  60. package/package.json +1 -1
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Agent = void 0;
7
+ const logger_1 = __importDefault(require("./logger"));
8
+ const runnable_1 = require("./runnable");
9
+ const utils_1 = require("./utils");
10
+ class Agent extends runnable_1.Runnable {
11
+ async getMemoryQuery(input, query) {
12
+ if (query?.from === 'variable') {
13
+ const i = utils_1.OrderedRecord.find(this.definition.inputs, (i) => i.id === query.fromVariableId);
14
+ if (!i)
15
+ throw new Error(`Input variable ${query.fromVariableId} not found`);
16
+ const value = input[i.name];
17
+ return (0, utils_1.renderMessage)('{{value}}', { value });
18
+ }
19
+ return Object.entries(input)
20
+ .map(([key, value]) => `${key} ${value}`)
21
+ .join('\n');
22
+ }
23
+ /**
24
+ * Load memories that are defined in the agent definition.
25
+ * @param input The agent input.
26
+ * @param context The AIGNE context.
27
+ * @returns A dictionary of memories, where the key is the memory name and the value is an array of memory items.
28
+ */
29
+ async loadMemories(input, context) {
30
+ const { memories } = this.definition;
31
+ const { userId, sessionId } = context?.state ?? {};
32
+ return Object.fromEntries((await Promise.all(utils_1.OrderedRecord.map(memories, async ({ name, memory, query, options }) => {
33
+ if (!name || !memory)
34
+ return null;
35
+ const q = await this.getMemoryQuery(input, query);
36
+ const { results: memories } = await memory.search(q, { ...options, userId, sessionId });
37
+ return [name, memories];
38
+ }))).filter(utils_1.isNonNullable));
39
+ }
40
+ /**
41
+ * Update memories by user messages and assistant responses.
42
+ * @param messages Messages to be added to memories.
43
+ */
44
+ async updateMemories(messages) {
45
+ const { memories } = this.definition;
46
+ const { userId, sessionId } = this.context?.state ?? {};
47
+ await Promise.all(utils_1.OrderedRecord.map(memories, async ({ memory }) => {
48
+ if (!memory) {
49
+ logger_1.default.warn(`Memory is not defined in agent ${this.name || this.id}`);
50
+ return;
51
+ }
52
+ return await memory.add(messages, { userId, sessionId });
53
+ }));
54
+ }
55
+ async run(input, options) {
56
+ const memories = await this.loadMemories(input, this.context);
57
+ return this.process(input, { ...options, memories });
58
+ }
59
+ }
60
+ exports.Agent = Agent;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.schemaToDataType = schemaToDataType;
4
+ const nanoid_1 = require("nanoid");
5
+ const utils_1 = require("../utils");
6
+ function schemaToDataType(dataType) {
7
+ return utils_1.OrderedRecord.fromArray(Object.entries(dataType).map(([name, schema]) => {
8
+ const base = {
9
+ ...schema,
10
+ id: (0, nanoid_1.nanoid)(),
11
+ name,
12
+ };
13
+ switch (schema.type) {
14
+ case 'string':
15
+ return {
16
+ ...base,
17
+ type: 'string',
18
+ };
19
+ case 'number':
20
+ return {
21
+ ...base,
22
+ type: 'number',
23
+ };
24
+ case 'boolean':
25
+ return {
26
+ ...base,
27
+ type: 'boolean',
28
+ };
29
+ case 'object':
30
+ return {
31
+ ...base,
32
+ type: 'object',
33
+ properties: schemaToDataType(schema.properties),
34
+ };
35
+ case 'array':
36
+ return {
37
+ ...base,
38
+ type: 'array',
39
+ items: utils_1.OrderedRecord.find(schemaToDataType({ items: schema.items }), (i) => i.name === 'items'),
40
+ };
41
+ default: {
42
+ throw new Error(`Unknown data type: ${schema.type}`);
43
+ }
44
+ }
45
+ }));
46
+ }
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toRunnableMemories = toRunnableMemories;
4
+ const nanoid_1 = require("nanoid");
5
+ const utils_1 = require("../utils");
6
+ function toRunnableMemories(agentName, inputs, memories) {
7
+ return utils_1.OrderedRecord.fromArray(Object.entries(memories).map(([name, { memory, query, options }]) => {
8
+ const queryFromVariable = query?.fromVariable
9
+ ? utils_1.OrderedRecord.find(inputs, (j) => j.name === query.fromVariable)
10
+ : null;
11
+ if (query?.fromVariable && !queryFromVariable)
12
+ throw new Error(`LLMAgent ${agentName} -> Memory ${name} -> Query variable ${query.fromVariable.toString()} not found`);
13
+ return {
14
+ id: name || (0, nanoid_1.nanoid)(),
15
+ name: name,
16
+ memory: memory,
17
+ query: queryFromVariable ? { from: 'variable', fromVariableId: queryFromVariable.id } : undefined,
18
+ options,
19
+ };
20
+ }));
21
+ }
@@ -18,7 +18,7 @@ exports.createFunctionAgentDefinition = createFunctionAgentDefinition;
18
18
  const nanoid_1 = require("nanoid");
19
19
  const tsyringe_1 = require("tsyringe");
20
20
  const constants_1 = require("./constants");
21
- const data_type_schema_1 = require("./data-type-schema");
21
+ const data_type_schema_1 = require("./definitions/data-type-schema");
22
22
  const function_runner_1 = require("./function-runner");
23
23
  const runnable_1 = require("./runnable");
24
24
  const utils_1 = require("./utils");
@@ -4,7 +4,7 @@ exports.FunctionRunner = void 0;
4
4
  const runnable_1 = require("./runnable");
5
5
  const utils_1 = require("./utils");
6
6
  class FunctionRunner extends runnable_1.Runnable {
7
- constructor() {
7
+ constructor(context) {
8
8
  super({
9
9
  id: 'function_runner',
10
10
  type: 'function_runner',
@@ -23,7 +23,7 @@ class FunctionRunner extends runnable_1.Runnable {
23
23
  type: 'object',
24
24
  },
25
25
  ]),
26
- });
26
+ }, context);
27
27
  }
28
28
  }
29
29
  exports.FunctionRunner = FunctionRunner;
package/lib/cjs/index.js CHANGED
@@ -17,7 +17,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./utils"), exports);
18
18
  __exportStar(require("./constants"), exports);
19
19
  __exportStar(require("./data-type"), exports);
20
- __exportStar(require("./data-type-schema"), exports);
20
+ __exportStar(require("./definitions/data-type-schema"), exports);
21
21
  __exportStar(require("./context"), exports);
22
22
  __exportStar(require("./runnable"), exports);
23
23
  __exportStar(require("./pipeline-agent"), exports);
@@ -27,4 +27,4 @@ __exportStar(require("./function-agent"), exports);
27
27
  __exportStar(require("./function-runner"), exports);
28
28
  __exportStar(require("./llm-decision-agent"), exports);
29
29
  __exportStar(require("./local-function-agent"), exports);
30
- __exportStar(require("./memory"), exports);
30
+ __exportStar(require("./memorable"), exports);
@@ -15,79 +15,63 @@ var LLMAgent_1;
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
16
  exports.LLMAgent = void 0;
17
17
  exports.createLLMAgentDefinition = createLLMAgentDefinition;
18
- const lodash_1 = require("lodash");
19
18
  const nanoid_1 = require("nanoid");
20
19
  const tsyringe_1 = require("tsyringe");
20
+ const agent_1 = require("./agent");
21
21
  const constants_1 = require("./constants");
22
- const data_type_schema_1 = require("./data-type-schema");
22
+ const data_type_schema_1 = require("./definitions/data-type-schema");
23
+ const memory_1 = require("./definitions/memory");
23
24
  const llm_model_1 = require("./llm-model");
24
- const runnable_1 = require("./runnable");
25
25
  const utils_1 = require("./utils");
26
+ const message_utils_1 = require("./utils/message-utils");
26
27
  const mustache_utils_1 = require("./utils/mustache-utils");
27
28
  const ordered_map_1 = require("./utils/ordered-map");
28
- let LLMAgent = LLMAgent_1 = class LLMAgent extends runnable_1.Runnable {
29
+ const structured_output_schema_1 = require("./utils/structured-output-schema");
30
+ let LLMAgent = LLMAgent_1 = class LLMAgent extends agent_1.Agent {
29
31
  definition;
30
32
  model;
31
33
  static create(options) {
32
34
  const definition = createLLMAgentDefinition(options);
33
35
  return new LLMAgent_1(definition);
34
36
  }
35
- constructor(definition, model) {
36
- super(definition);
37
+ constructor(definition, context, model) {
38
+ super(definition, context);
37
39
  this.definition = definition;
38
40
  this.model = model;
39
41
  }
40
- async run(input, options) {
42
+ async process(input, options) {
41
43
  const { definition, model } = this;
42
44
  if (!model)
43
45
  throw new Error('LLM model is required');
44
- const messages = ordered_map_1.OrderedRecord.toArray(definition.messages);
45
- if (!messages.length)
46
- throw new Error('Messages are required');
47
- // TODO: support comment/image for messages
46
+ const { originalMessages, messagesWithMemory } = (0, message_utils_1.prepareMessages)(definition, input, options.memories);
48
47
  const llmInputs = {
49
- messages: messages.map(({ role, content }) => ({
50
- role,
51
- content: (0, mustache_utils_1.renderMessage)(content, input),
52
- })),
48
+ messages: messagesWithMemory,
53
49
  modelOptions: definition.modelOptions,
54
50
  };
55
- const outputs = ordered_map_1.OrderedRecord.toArray(definition.outputs).filter((0, utils_1.isPropsNonNullable)('name'));
56
- const textOutput = outputs.find((i) => i.name === constants_1.StreamTextOutputName);
57
- const jsonOutputs = outputs.filter((i) => i.name !== constants_1.StreamTextOutputName);
58
- const outputJsonSchema = jsonOutputs.length ? outputsToJsonSchema(ordered_map_1.OrderedRecord.fromArray(jsonOutputs)) : undefined;
59
- const jsonOutput = outputJsonSchema
60
- ? model
61
- .run({
62
- ...llmInputs,
63
- responseFormat: outputJsonSchema && {
64
- type: 'json_schema',
65
- jsonSchema: {
66
- name: 'output',
67
- schema: outputJsonSchema,
68
- strict: true,
69
- },
70
- },
71
- })
72
- .then(async (response) => {
73
- if (!response.$text)
74
- throw new Error('No text in JSON mode response');
75
- const json = JSON.parse(response.$text);
76
- // TODO: validate json with outputJsonSchema
77
- return json;
78
- })
51
+ const jsonOutput = this.runWithStructuredOutput(llmInputs);
52
+ const textOutput = ordered_map_1.OrderedRecord.find(definition.outputs, (i) => i.name === constants_1.StreamTextOutputName)
53
+ ? await this.runWithTextOutput(llmInputs)
79
54
  : undefined;
55
+ const updateMemories = (text, json) => {
56
+ return this.updateMemories([
57
+ ...originalMessages,
58
+ { role: 'assistant', content: (0, mustache_utils_1.renderMessage)('{{text}}\n{{json}}', { text, json }).trim() },
59
+ ]);
60
+ };
80
61
  if (options?.stream) {
62
+ let $text = '';
81
63
  return new ReadableStream({
82
64
  start: async (controller) => {
83
65
  try {
84
66
  if (textOutput) {
85
- const textStreamOutput = await model.run(llmInputs, { stream: true });
86
- for await (const chunk of textStreamOutput) {
67
+ for await (const chunk of textOutput) {
68
+ $text += chunk.$text || '';
87
69
  controller.enqueue({ $text: chunk.$text });
88
70
  }
89
71
  }
90
- controller.enqueue({ delta: await jsonOutput });
72
+ const json = await jsonOutput;
73
+ controller.enqueue({ delta: json });
74
+ await updateMemories($text || undefined, json);
91
75
  }
92
76
  catch (error) {
93
77
  controller.error(error);
@@ -98,62 +82,84 @@ let LLMAgent = LLMAgent_1 = class LLMAgent extends runnable_1.Runnable {
98
82
  },
99
83
  });
100
84
  }
101
- const text = textOutput ? await model.run(llmInputs) : undefined;
102
- return {
103
- $text: text?.$text,
104
- ...(await jsonOutput),
105
- };
85
+ const [$text, json] = await Promise.all([
86
+ textOutput ? (0, utils_1.runnableResponseStreamToObject)(textOutput).then((res) => res.$text || undefined) : undefined,
87
+ jsonOutput,
88
+ ]);
89
+ await updateMemories($text, json);
90
+ return { $text, ...json };
91
+ }
92
+ async runWithStructuredOutput(llmInputs) {
93
+ const jsonOutputs = ordered_map_1.OrderedRecord.filter(this.definition.outputs, (i) => i.name !== constants_1.StreamTextOutputName // ignore `$text` output
94
+ );
95
+ if (!jsonOutputs.length)
96
+ return null;
97
+ const schema = (0, structured_output_schema_1.outputsToJsonSchema)(ordered_map_1.OrderedRecord.fromArray(jsonOutputs));
98
+ const { model } = this;
99
+ if (!model)
100
+ throw new Error('LLM model is required');
101
+ const response = await model.run({
102
+ ...llmInputs,
103
+ responseFormat: {
104
+ type: 'json_schema',
105
+ jsonSchema: {
106
+ name: 'output',
107
+ schema: schema,
108
+ strict: true,
109
+ },
110
+ },
111
+ });
112
+ if (!response.$text)
113
+ throw new Error('No text in JSON mode response');
114
+ const json = JSON.parse(response.$text);
115
+ // TODO: validate json with outputJsonSchema
116
+ return json;
117
+ }
118
+ async runWithTextOutput(llmInputs) {
119
+ const { model } = this;
120
+ if (!model)
121
+ throw new Error('LLM model is required');
122
+ return model.run(llmInputs, { stream: true });
106
123
  }
107
124
  };
108
125
  exports.LLMAgent = LLMAgent;
109
126
  exports.LLMAgent = LLMAgent = LLMAgent_1 = __decorate([
110
127
  (0, tsyringe_1.injectable)(),
111
128
  __param(0, (0, tsyringe_1.inject)(constants_1.TYPES.definition)),
112
- __param(1, (0, tsyringe_1.inject)(constants_1.TYPES.llmModel)),
113
- __metadata("design:paramtypes", [Object, llm_model_1.LLMModel])
129
+ __param(1, (0, tsyringe_1.inject)(constants_1.TYPES.context)),
130
+ __param(2, (0, tsyringe_1.inject)(constants_1.TYPES.llmModel)),
131
+ __metadata("design:paramtypes", [Object, Object, llm_model_1.LLMModel])
114
132
  ], LLMAgent);
133
+ /**
134
+ * Create LLMAgent definition.
135
+ * @param options Options to create LLMAgent.
136
+ * @returns LLMAgent definition.
137
+ */
115
138
  function createLLMAgentDefinition(options) {
139
+ const agentId = options.name || (0, nanoid_1.nanoid)();
140
+ const inputs = (0, data_type_schema_1.schemaToDataType)(options.inputs);
141
+ const outputs = (0, data_type_schema_1.schemaToDataType)(options.outputs);
142
+ const memories = (0, memory_1.toRunnableMemories)(agentId, inputs, options.memories ?? {});
143
+ const primaryMemoryNames = Object.entries(options.memories ?? {})
144
+ .filter(([, i]) => i.primary)
145
+ .map(([name]) => name);
146
+ if (primaryMemoryNames && primaryMemoryNames.length > 1) {
147
+ throw new Error('Only one primary memory is allowed');
148
+ }
149
+ const messages = ordered_map_1.OrderedRecord.fromArray(options.messages?.map((i) => ({
150
+ id: (0, nanoid_1.nanoid)(),
151
+ role: i.role,
152
+ content: i.content,
153
+ })));
116
154
  return {
117
- id: options.id || options.name || (0, nanoid_1.nanoid)(),
155
+ id: agentId,
118
156
  name: options.name,
119
157
  type: 'llm_agent',
120
- inputs: (0, data_type_schema_1.schemaToDataType)(options.inputs),
121
- outputs: (0, data_type_schema_1.schemaToDataType)(options.outputs),
158
+ inputs,
159
+ outputs,
160
+ primaryMemoryId: primaryMemoryNames?.at(0),
161
+ memories,
122
162
  modelOptions: options.modelOptions,
123
- messages: ordered_map_1.OrderedRecord.fromArray(options.messages?.map((i) => ({
124
- id: (0, nanoid_1.nanoid)(),
125
- role: i.role,
126
- content: i.content,
127
- }))),
128
- };
129
- }
130
- function outputsToJsonSchema(outputs) {
131
- const outputToSchema = (output) => {
132
- const properties = output.type === 'object' && output.properties?.$indexes.length
133
- ? ordered_map_1.OrderedRecord.map(output.properties, (property) => {
134
- if (!property.name)
135
- return null;
136
- const schema = outputToSchema(property);
137
- if (!schema)
138
- return null;
139
- return { schema, property };
140
- }).filter(utils_1.isNonNullable)
141
- : undefined;
142
- return (0, lodash_1.omitBy)({
143
- type: output.type,
144
- description: output.description,
145
- properties: properties?.length
146
- ? Object.fromEntries(properties.map((p) => [p.property.name, p.schema]))
147
- : undefined,
148
- items: output.type === 'array' && output.items ? outputToSchema(output.items) : undefined,
149
- additionalProperties: output.type === 'object' ? false : undefined,
150
- required: properties?.length
151
- ? properties.filter((i) => i.property.required).map((i) => i.property.name)
152
- : undefined,
153
- }, (v) => v === undefined);
163
+ messages,
154
164
  };
155
- return outputToSchema({
156
- type: 'object',
157
- properties: outputs,
158
- });
159
165
  }
@@ -17,33 +17,31 @@ exports.LLMDecisionAgent = void 0;
17
17
  exports.createLLMDecisionAgentDefinition = createLLMDecisionAgentDefinition;
18
18
  const nanoid_1 = require("nanoid");
19
19
  const tsyringe_1 = require("tsyringe");
20
+ const agent_1 = require("./agent");
20
21
  const constants_1 = require("./constants");
22
+ const memory_1 = require("./definitions/memory");
21
23
  const llm_model_1 = require("./llm-model");
22
- const runnable_1 = require("./runnable");
23
24
  const utils_1 = require("./utils");
24
- let LLMDecisionAgent = LLMDecisionAgent_1 = class LLMDecisionAgent extends runnable_1.Runnable {
25
+ const message_utils_1 = require("./utils/message-utils");
26
+ let LLMDecisionAgent = LLMDecisionAgent_1 = class LLMDecisionAgent extends agent_1.Agent {
25
27
  definition;
26
28
  model;
27
- context;
28
29
  static create(options) {
29
30
  const definition = createLLMDecisionAgentDefinition(options);
30
31
  return new LLMDecisionAgent_1(definition);
31
32
  }
32
- constructor(definition, model, context) {
33
- super(definition);
33
+ constructor(definition, context, model) {
34
+ super(definition, context);
34
35
  this.definition = definition;
35
36
  this.model = model;
36
- this.context = context;
37
37
  }
38
- async run(input, options) {
38
+ async process(input, options) {
39
39
  const { definition, context, model } = this;
40
40
  if (!model)
41
41
  throw new Error('LLM model is required');
42
42
  if (!context)
43
43
  throw new Error('Context is required');
44
- const messages = utils_1.OrderedRecord.toArray(definition.messages);
45
- if (!messages.length)
46
- throw new Error('Messages are required');
44
+ const { originalMessages, messagesWithMemory } = (0, message_utils_1.prepareMessages)(definition, input, options.memories);
47
45
  const cases = await Promise.all(utils_1.OrderedRecord.map(definition.cases, async (t) => {
48
46
  if (!t.runnable?.id)
49
47
  throw new Error('Runnable is required');
@@ -52,13 +50,10 @@ let LLMDecisionAgent = LLMDecisionAgent_1 = class LLMDecisionAgent extends runna
52
50
  const name = t.name || runnable.name;
53
51
  if (!name)
54
52
  throw new Error('Case name is required');
55
- return { name, description: t.description, runnable, input: t.input };
53
+ return { name, description: t.description, runnable };
56
54
  }));
57
55
  const llmInputs = {
58
- messages: messages.map(({ role, content }) => ({
59
- role,
60
- content: typeof content === 'string' ? (0, utils_1.renderMessage)(content, input) : content,
61
- })),
56
+ messages: messagesWithMemory,
62
57
  modelOptions: definition.modelOptions,
63
58
  tools: cases.map((t) => {
64
59
  // TODO: auto generate parameters by llm model if needed
@@ -82,40 +77,52 @@ let LLMDecisionAgent = LLMDecisionAgent_1 = class LLMDecisionAgent extends runna
82
77
  if (!caseToCall)
83
78
  throw new Error('Case not found');
84
79
  // TODO: check result structure and omit undefined values
85
- return (await caseToCall.runnable.run(input, options));
80
+ const output = (await caseToCall.runnable.run(input, options));
81
+ return (0, utils_1.extractOutputsFromRunnableOutput)(output, ({ $text, ...json }) => this.updateMemories([
82
+ ...originalMessages,
83
+ { role: 'assistant', content: (0, utils_1.renderMessage)('{{$text}}\n{{json}}', { $text, json }).trim() },
84
+ ]));
86
85
  }
87
86
  };
88
87
  exports.LLMDecisionAgent = LLMDecisionAgent;
89
88
  exports.LLMDecisionAgent = LLMDecisionAgent = LLMDecisionAgent_1 = __decorate([
90
89
  (0, tsyringe_1.injectable)(),
91
90
  __param(0, (0, tsyringe_1.inject)(constants_1.TYPES.definition)),
92
- __param(1, (0, tsyringe_1.inject)(constants_1.TYPES.llmModel)),
93
- __param(2, (0, tsyringe_1.inject)(constants_1.TYPES.context)),
94
- __metadata("design:paramtypes", [Object, llm_model_1.LLMModel, Object])
91
+ __param(1, (0, tsyringe_1.inject)(constants_1.TYPES.context)),
92
+ __param(2, (0, tsyringe_1.inject)(constants_1.TYPES.llmModel)),
93
+ __metadata("design:paramtypes", [Object, Object, llm_model_1.LLMModel])
95
94
  ], LLMDecisionAgent);
96
95
  function createLLMDecisionAgentDefinition(options) {
97
- const messages = utils_1.OrderedRecord.fromArray([
98
- {
99
- id: (0, nanoid_1.nanoid)(),
100
- role: 'system',
101
- content: options.messages,
102
- },
103
- ]);
104
- const cases = utils_1.OrderedRecord.fromArray(options.cases.map((c) => ({
96
+ const agentId = options.name || (0, nanoid_1.nanoid)();
97
+ const cases = utils_1.OrderedRecord.fromArray(Object.entries(options.cases).map(([name, c]) => ({
105
98
  id: (0, nanoid_1.nanoid)(),
106
- name: c.name || c.runnable.name,
99
+ name: name || c.runnable.name,
107
100
  description: c.description,
108
101
  runnable: { id: c.runnable.id },
109
102
  })));
103
+ const inputs = utils_1.OrderedRecord.merge(...Object.values(options.cases).map((i) => i.runnable.definition.inputs));
104
+ const outputs = utils_1.OrderedRecord.fromArray(utils_1.OrderedRecord.map(utils_1.OrderedRecord.merge(...Object.values(options.cases).map((i) => i.runnable.definition.outputs)), (o) => ({ ...o, required: false })));
105
+ const memories = (0, memory_1.toRunnableMemories)(agentId, inputs, options.memories ?? {});
106
+ const primaryMemoryNames = Object.entries(options.memories ?? {})
107
+ .filter(([, i]) => i.primary)
108
+ .map(([name]) => name);
109
+ if (primaryMemoryNames && primaryMemoryNames.length > 1) {
110
+ throw new Error('Only one primary memory is allowed');
111
+ }
112
+ const messages = utils_1.OrderedRecord.fromArray(options.messages?.map((i) => ({
113
+ id: (0, nanoid_1.nanoid)(),
114
+ role: i.role,
115
+ content: i.content,
116
+ })));
110
117
  return {
111
- id: options.id || options.name || (0, nanoid_1.nanoid)(),
118
+ id: agentId,
112
119
  name: options.name,
113
120
  type: 'llm_decision_agent',
114
- // TODO: decision agent inputs should be the intersection of all case inputs
115
- inputs: utils_1.OrderedRecord.fromArray([]),
116
- // TODO: decision agent outputs should be the union of all case outputs
117
- outputs: utils_1.OrderedRecord.fromArray([]),
121
+ inputs,
122
+ outputs,
118
123
  messages,
124
+ primaryMemoryId: primaryMemoryNames?.at(0),
125
+ memories,
119
126
  modelOptions: options.modelOptions,
120
127
  cases,
121
128
  };
@@ -4,7 +4,7 @@ exports.LLMModel = void 0;
4
4
  const runnable_1 = require("./runnable");
5
5
  const utils_1 = require("./utils");
6
6
  class LLMModel extends runnable_1.Runnable {
7
- constructor() {
7
+ constructor(context) {
8
8
  super({
9
9
  id: 'llm_model',
10
10
  type: 'llm_model',
@@ -21,7 +21,7 @@ class LLMModel extends runnable_1.Runnable {
21
21
  { id: '$text', name: '$text', type: 'string' },
22
22
  { id: 'toolCalls', name: 'toolCalls', type: 'object' },
23
23
  ]),
24
- });
24
+ }, context);
25
25
  }
26
26
  }
27
27
  exports.LLMModel = LLMModel;
@@ -17,29 +17,28 @@ exports.LocalFunctionAgent = void 0;
17
17
  exports.createLocalFunctionAgentDefinition = createLocalFunctionAgentDefinition;
18
18
  const nanoid_1 = require("nanoid");
19
19
  const tsyringe_1 = require("tsyringe");
20
+ const agent_1 = require("./agent");
20
21
  const constants_1 = require("./constants");
21
- const data_type_schema_1 = require("./data-type-schema");
22
- const runnable_1 = require("./runnable");
22
+ const data_type_schema_1 = require("./definitions/data-type-schema");
23
+ const memory_1 = require("./definitions/memory");
23
24
  const utils_1 = require("./utils");
24
- let LocalFunctionAgent = LocalFunctionAgent_1 = class LocalFunctionAgent extends runnable_1.Runnable {
25
+ let LocalFunctionAgent = LocalFunctionAgent_1 = class LocalFunctionAgent extends agent_1.Agent {
25
26
  definition;
26
- context;
27
27
  static create(options) {
28
28
  const definition = createLocalFunctionAgentDefinition(options);
29
29
  return new LocalFunctionAgent_1(definition);
30
30
  }
31
31
  constructor(definition, context) {
32
- super(definition);
32
+ super(definition, context);
33
33
  this.definition = definition;
34
- this.context = context;
35
34
  }
36
- async run(input, options) {
35
+ async process(input, options) {
37
36
  const { definition: { function: func }, context, } = this;
38
37
  if (!func)
39
38
  throw new Error('Function is required');
40
39
  if (!context)
41
40
  throw new Error('Context is required');
42
- const result = (await func(input, { context }));
41
+ const result = await func(input, { context, memories: options.memories });
43
42
  // TODO: validate the result against the definition.outputs
44
43
  return options?.stream
45
44
  ? result instanceof ReadableStream
@@ -58,14 +57,17 @@ exports.LocalFunctionAgent = LocalFunctionAgent = LocalFunctionAgent_1 = __decor
58
57
  __metadata("design:paramtypes", [Object, Object])
59
58
  ], LocalFunctionAgent);
60
59
  function createLocalFunctionAgentDefinition(options) {
60
+ const agentId = options.name || (0, nanoid_1.nanoid)();
61
61
  const inputs = (0, data_type_schema_1.schemaToDataType)(options.inputs);
62
62
  const outputs = (0, data_type_schema_1.schemaToDataType)(options.outputs);
63
+ const memories = (0, memory_1.toRunnableMemories)(agentId, inputs, options.memories || {});
63
64
  return {
64
- id: options.id || options.name || (0, nanoid_1.nanoid)(),
65
+ id: agentId,
65
66
  name: options.name,
66
67
  type: 'local_function_agent',
67
68
  inputs,
68
69
  outputs,
70
+ memories,
69
71
  function: options.function,
70
72
  };
71
73
  }
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MemoryRunner = exports.Memorable = void 0;
4
+ const lodash_1 = require("lodash");
5
+ const runnable_1 = require("./runnable");
6
+ const utils_1 = require("./utils");
7
+ class Memorable extends runnable_1.Runnable {
8
+ constructor() {
9
+ super({
10
+ id: 'memory',
11
+ type: 'memory',
12
+ name: 'Memory',
13
+ inputs: utils_1.OrderedRecord.fromArray([]),
14
+ outputs: utils_1.OrderedRecord.fromArray([]),
15
+ });
16
+ }
17
+ }
18
+ exports.Memorable = Memorable;
19
+ class MemoryRunner extends runnable_1.Runnable {
20
+ constructor(name) {
21
+ const id = `${(0, lodash_1.camelCase)(name)}_runner`;
22
+ super({
23
+ id,
24
+ type: id,
25
+ name: `${(0, lodash_1.startCase)(name)} Runner`,
26
+ description: `${(0, lodash_1.startCase)(name)} Runner`,
27
+ inputs: utils_1.OrderedRecord.fromArray([]),
28
+ outputs: utils_1.OrderedRecord.fromArray([]),
29
+ });
30
+ }
31
+ }
32
+ exports.MemoryRunner = MemoryRunner;