Skip to content

Commit

Permalink
Calculate task id base on user definition
Browse files Browse the repository at this point in the history
The calculation would before also consider library defaults, but either
the defaults would not contribute to differentiating the id or in some
cases, where the functions are overriden, it would erroneously generate
the same id for two tasks that are different.

Change-type: patch
  • Loading branch information
pipex committed Dec 6, 2024
1 parent 65c160e commit 3dd97f4
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 15 deletions.
22 changes: 20 additions & 2 deletions lib/task/tasks.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe('Tasks', () => {
description: '+1',
});
expect(inc.id).to.equal(
'79fae6f74c3f2816281e0a7e3f6f4a33376aee1428ffd036e9a91aece14da1ef',
'68635e74289a6533db2ac4389c4a0190c8ffc5ea2177f06001972fd778167504',
);

const inc2 = Task.from<number>({
Expand Down Expand Up @@ -41,7 +41,7 @@ describe('Tasks', () => {
description: '+2',
});
expect(byTwo.id).to.equal(
'7e3d92c6d21f4f0e63d3b3f2b571fdb5e7424a670d14718a23e2dd2d0588eddd',
'244a7aa41b5dfea349fb2736551f434f9c5e4158487f0e99d9e38b00eb56bb37',
);
expect(dec.id).to.not.equal(byTwo.id);

Expand All @@ -51,6 +51,24 @@ describe('Tasks', () => {
description: '+2',
});
expect(byTwo.id).to.equal(byTwo2.id);

type Numbers = { [k: string]: number };
const remove1 = Task.of<Numbers>().from({
op: 'delete',
effect: () => {
console.log('nothing to do');
},
description: 'remove',
});
const remove2 = Task.of<Numbers>().from({
op: 'delete',
effect: () => {
console.log('also nothing to do');
},
description: 'remove',
});

expect(remove1.id).to.not.equal(remove2.id);
});

it('create tasks should automatically check that the property does not exist beforehand', function () {
Expand Down
28 changes: 15 additions & 13 deletions lib/task/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,17 @@ function isActionProps<
);
}

function serialize<T extends object>(props: T): string {
// Serialize the task specification converting all elements to strings
// including the function bodys where it applies
const serialized = (Object.keys(props) as Array<keyof T>).reduce(
(o, k) => ({ ...o, [k]: String(props[k]) }),
{},
);

return createHash('sha256').update(JSON.stringify(serialized)).digest('hex');
}

/**
* A task is base unit of knowledge of an autonomous agent.
*/
Expand Down Expand Up @@ -402,6 +413,10 @@ function from<
// Check that the path is valid
const lens = Path.from(taskProps.lens ?? ('/' as TPath));

// Generate a deterministic id for
// the task. This is useful for diagramming
const id = serialize(taskProps);

const opLabel = op === '*' ? 'modify' : op;

// The default description is
Expand Down Expand Up @@ -474,19 +489,6 @@ function from<
}
})();

// Serialize the task specification converting all elements to strings
// including the function bodys where it applies
const serialized = (Object.keys(tProps) as Array<keyof typeof tProps>).reduce(
(o, k) => ({ ...o, [k]: String(tProps[k]) }),
{},
);

// Thid allows us to generate a deterministic id for
// the task. This is useful for diagramming
const id = createHash('sha256')
.update(JSON.stringify(serialized))
.digest('hex');

// The final task spec. Typescript doesn't seem to
// correctly infer the type here unfortunately
const tSpec = { id, ...tProps };
Expand Down

0 comments on commit 3dd97f4

Please sign in to comment.