Skip to content

Commit

Permalink
Add a new seed_type, let-multi.
Browse files Browse the repository at this point in the history
Like let, but it allows setting multiple values at once.

Part of #18. Part of #36.
  • Loading branch information
jkomoros committed Jul 4, 2023
1 parent 3d29ce9 commit 7203a03
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 2 deletions.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ Array is useful when you want to execute multiple statements in sequence, for ex

Required parameters:
- `items` - An array of values. The values may be LeafValue or a SeedReference / SubSeed.
- `return` (optional, default: 'all') - One of {'all', 'first', 'last'}. If all, will return the full array of values. If 'first', will return the single first result, or null if there are no items. If 'last' will return the first result, or null if there are no items.

#### var

Expand All @@ -421,7 +422,7 @@ Required parameters:

#### let

Sets a named variable in environment to value for sub-expressions in block. It returns the return value of block. See also `var`.
Sets a named variable in environment to value for sub-expressions in block. It returns the return value of block. See also `var` and `let-multi`.

A value that persists is available with seed_type `store`.

Expand All @@ -432,6 +433,18 @@ Required parameters:
- `value` - The value to set the variable to.
- `block` - The sub-seed that will be evaluated where the environment will have `name=value`.

#### let-multi

Sets multiple names to variables in environment to value for sub-expressions in block. It returns the return value of block. See also `var` and `let`.

A value that persists is available with seed_type `store`.

Note that this doesn't change the environment globally, but only for the context of calculating the seeds nested beneath `block`.

Required parameters:
- `values` - The object of name -> value pairs to set.
- `block` - The sub-seed that will be evaluated where the environment will have `name=value`.

#### store

Stores a value in the long-term key/val store.
Expand Down
76 changes: 76 additions & 0 deletions seed-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1432,6 +1432,82 @@
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"id": {
"$ref": "#/definitions/seedData/anyOf/0/properties/id"
},
"description": {
"$ref": "#/definitions/seedData/anyOf/0/properties/description"
},
"type": {
"type": "string",
"const": "let-multi"
},
"values": {
"anyOf": [
{
"$ref": "#/definitions/seedData"
},
{
"$ref": "#/definitions/seedData/anyOf/0/properties/prompt/anyOf/1"
},
{
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "null"
},
{
"type": "number"
},
{
"type": "string"
},
{
"type": "boolean"
},
{}
]
},
"propertyNames": {
"pattern": "^(?!type$)[a-zA-Z0-9_-]+$"
},
"description": "The map of name -> variables to set"
}
]
},
"block": {
"anyOf": [
{
"$ref": "#/definitions/seedData"
},
{
"$ref": "#/definitions/seedData/anyOf/0/properties/prompt/anyOf/1"
},
{
"anyOf": [
{
"$ref": "#/definitions/seedData/anyOf/5/properties/value/anyOf/2/anyOf/0"
},
{
"$ref": "#/definitions/seedData/anyOf/5/properties/value/anyOf/2/anyOf/1"
}
],
"description": "The sub-expression where name=value will be set in environment"
}
]
}
},
"required": [
"type",
"values",
"block"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
Expand Down
23 changes: 22 additions & 1 deletion src/grow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ import {
inputValue,
SeedDataRetrieve,
SeedDataDelete,
arrayReturnType
arrayReturnType,
SeedDataLetMulti,
EnvironmentData
} from './types.js';

import {
Expand Down Expand Up @@ -493,6 +495,22 @@ const growLet = async (seed : Seed<SeedDataLet>, env : Environment) : Promise<Va
return await getProperty(seed, newEnv, data.block);
};

const growLetMulti = async (seed : Seed<SeedDataLetMulti>, env : Environment) : Promise<Value> => {
const data = seed.data;

const values = await getProperty(seed, env, data.values);
if (typeof values != 'object') throw new Error('Values must be an object');
if (Array.isArray(values)) throw new Error('Values must be an object');
if (!values) throw new Error('Values must be an object');
const vars : EnvironmentData = {};
for (const [key, val] of Object.entries(values)) {
if (knownEnvironmentSecretKey.safeParse(key).success) throw new Error(`let may not set secret keys: ${key}`);
vars[key] = val;
}
const newEnv = env.clone(vars);
return await getProperty(seed, newEnv, data.block);
};

const growStore = async (seed : Seed<SeedDataStore>, env : Environment) : Promise<Value> => {
const data = seed.data;
const storeID = extractString(await getProperty(seed, env, data.store, env.getKnownStringKey('store')));
Expand Down Expand Up @@ -598,6 +616,9 @@ export const grow = async (seed : Seed, env : Environment) : Promise<Value> => {
case 'let':
result = await growLet(seed as Seed<SeedDataLet>, env);
break;
case 'let-multi':
result = await growLetMulti(seed as Seed<SeedDataLetMulti>, env);
break;
case 'store':
result = await growStore(seed as Seed<SeedDataStore>, env);
break;
Expand Down
15 changes: 15 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,19 @@ const seedDataLet = makeSeedData(seedDataConfigLet);

export type SeedDataLet = z.infer<typeof seedDataLet>;

const seedDataConfigLetMulti = {
type: z.literal('let-multi'),
properties: {
values: valueObject.describe('The map of name -> variables to set'),
block: inputNonObjectValue.describe('The sub-expression where name=value will be set in environment')
}
};

const nestedSeedDataLetMulti = makeNestedSeedData(seedDataConfigLetMulti);
const seedDataLetMulti = makeSeedData(seedDataConfigLetMulti);

export type SeedDataLetMulti = z.infer<typeof seedDataLetMulti>;

const seedDataConfigStore = {
type: z.literal('store'),
properties: {
Expand Down Expand Up @@ -700,6 +713,7 @@ export const expandedSeedData = z.discriminatedUnion('type', [
seedDataArray,
seedDataVar,
seedDataLet,
seedDataLetMulti,
seedDataStore,
seedDataRetrieve,
seedDataDelete
Expand Down Expand Up @@ -731,6 +745,7 @@ export const seedData = z.discriminatedUnion('type', [
nestedSeedDataArray,
nestedSeedDataVar,
nestedSeedDataLet,
nestedSeedDataLetMulti,
nestedSeedDataStore,
nestedSeedDataRetrieve,
nestedSeedDataDelete
Expand Down
24 changes: 24 additions & 0 deletions test/base/a_test.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,30 @@
}
}
},
"let-multi-test": {
"type": "let-multi",
"values": {
"name": "Alex",
"foo": 3
},
"block": {
"type": "render",
"template": "{{age}} is {{name}}",
"vars": {
"type": "object",
"properties": {
"age": {
"type": "var",
"name": "foo"
},
"name": {
"type": "var",
"name": "name"
}
}
}
}
},
"let-test-secret-key": {
"type": "let",
"name": "openai_secret_key",
Expand Down
8 changes: 8 additions & 0 deletions test/base/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,14 @@ describe('Garden smoke test', () => {
assert.deepStrictEqual(result, golden);
});

it ('testing let-multi seed', async () => {
const garden = loadTestGarden();
const seed = await garden.seed('let-multi-test');
const result = await seed.grow();
const golden = '3 is Alex';
assert.deepStrictEqual(result, golden);
});

it ('testing let seed with secret key fails', async () => {
const garden = loadTestGarden();
const seed = await garden.seed('let-test-secret-key');
Expand Down

0 comments on commit 7203a03

Please sign in to comment.