Skip to content

Commit

Permalink
Entity details (#707)
Browse files Browse the repository at this point in the history
* feat: entity details template

* fix: backwards compatibility for old agent nexus

* feat: agent indexer supports entities
  • Loading branch information
gabehamilton authored Mar 15, 2024
1 parent 0039dfd commit 6995a20
Show file tree
Hide file tree
Showing 11 changed files with 787 additions and 56 deletions.
100 changes: 71 additions & 29 deletions indexers/agents/agents.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,39 +82,81 @@ async function getBlock(block: Block) {
});
};

// Agi Guild
const agiWrites = getSocialOperations(block, "agiguild");

agiWrites.map(async ({ accountId, data }) => {
try {
const entityTypes = Object.keys(data);
entityTypes.map(async (entityType)=> {
const entities = Object.keys(data[entityType]);
entities.map(async (name) => {
const entityProps = data[entityType][name];
const {displayName, logoUrl, ...entityAttributes} = entityProps;
const entity = {
entity_type: entityType,
account_id: accountId,
name: name,
display_name: displayName,
logo_url: logoUrl,
attributes: entityAttributes,
};
await context.db.Entities.upsert(
entity,
["entity_type", "account_id", "name"],
[
"display_name",
"logo_url",
"attributes",
]
);

console.log(`${entityType} from ${accountId} has been added to the database`);
});
});
} catch (e) {
console.log(`Failed to store agent from ${accountId} to the database`, e);
}
});

// Legacy
const agentWrites = getSocialOperations(block, "agent");
agentWrites.map(async ({ accountId, data }) => {
try {
const agent = {
name: data.name,
account_id: accountId,
display_name: data.displayName,
preferred_provider: data.preferredProvider,
preferred_model: data.preferredModel,
prompt: data.prompt,
variables: data.variables,
component: data.component,
logo_url: data.logoUrl,
tools: data.tools,
properties: data.properties,
};
await context.db.Agents.upsert(
agent,
["account_id", "name"],
[
"display_name",
"preferred_provider",
"preferred_model",
"prompt",
"variables",
"component",
"logo_url",
"tools",
"properties",
]
);
const names = Object.keys(data);
names.map( async (name) => {
const agentProps = data[name];
const agent = {
name: name,
account_id: accountId,
display_name: agentProps.displayName,
preferred_provider: agentProps.preferredProvider,
preferred_model: agentProps.preferredModel,
prompt: agentProps.prompt,
variables: agentProps.variables,
component: agentProps.component,
logo_url: agentProps.logoUrl,
tools: agentProps.tools,
properties: agentProps.properties,
};
await context.db.Agents.upsert(
agent,
["account_id", "name"],
[
"display_name",
"preferred_provider",
"preferred_model",
"prompt",
"variables",
"component",
"logo_url",
"tools",
"properties",
]
);

console.log(`Agent from ${accountId} has been added to the database`);
console.log(`Agent from ${accountId} has been added to the database`);
});
} catch (e) {
console.log(`Failed to store agent from ${accountId} to the database`, e);
}
Expand Down
25 changes: 24 additions & 1 deletion indexers/agents/agents.sql
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,27 @@ CREATE TABLE
PRIMARY KEY ("id")
);

ALTER TABLE "agents" ADD CONSTRAINT "unique_name" UNIQUE ("account_id", "name");
ALTER TABLE "agents" ADD CONSTRAINT "unique_name" UNIQUE ("account_id", "name");

-- commented lines are features that are not supported by context.db but are in the table
-- that was created in the db
CREATE TABLE "entities"
(
"id" SERIAL NOT NULL,
"entity_type" TEXT NOT NULL,
"account_id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"display_name" TEXT,
"logo_url" TEXT,
"attributes" JSONB,
"stars" integer, -- default 0
-- "created_at" timestamp with time zone default now(),
-- "updated_at" timestamp with time zone default now(),
PRIMARY KEY ("entity_type", "account_id", "name")
);

-- CREATE TRIGGER set_dataplatform_near_agents_entities_updated_at
-- BEFORE UPDATE
-- ON dataplatform_near_agents.entities
-- FOR EACH ROW
-- EXECUTE FUNCTION dataplatform_near_agents.set_current_timestamp_updated_at();
18 changes: 17 additions & 1 deletion src/AI/Agent/AgentCreate.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const onSubmitFunction = onSubmit ?? onSubmitDefault;

const AgentInputsPartialSchema = {
name: {
type: "string",
inputProps: {
min: 2,
max: 80,
Expand All @@ -19,6 +20,7 @@ const AgentInputsPartialSchema = {
order: 1,
},
displayName: {
type: "string",
inputProps: {
min: 2,
max: 255,
Expand All @@ -29,6 +31,7 @@ const AgentInputsPartialSchema = {
order: 2,
},
prompt: {
type: "string",
inputProps: {
min: 2,
max: 8192,
Expand Down Expand Up @@ -70,6 +73,7 @@ const AgentInputsPartialSchema = {
// order: 6,
// },
component: {
type: "string",
inputProps: {
min: 0,
max: 255,
Expand All @@ -80,6 +84,7 @@ const AgentInputsPartialSchema = {
order: 7,
},
logoUrl: {
type: "string",
inputProps: {
min: 4,
max: 255,
Expand Down Expand Up @@ -124,6 +129,17 @@ const agentInputsValidator = (formValues) =>
return !required || typeof formValues[key] === "string";
});

const initialValues = (schema, data) => {
const initial = data ?? {};
Object.keys(schema).forEach((key) => {
const fieldProps = schema[key];
if (!data[key] && fieldProps.displayType !== "hidden" && fieldProps.type === "string") {
initial[key] = "";
}
});
return initial;
};

return (
<Widget
src="devhub.near/widget/devhub.components.organism.Configurator"
Expand All @@ -141,7 +157,7 @@ return (
},
submitLabel: data ? "Save" : "Launch",
onCancel: onCancel,
externalState: data,
externalState: initialValues(AgentInputsPartialSchema, data),
}}
/>
);
10 changes: 9 additions & 1 deletion src/AI/Nexus.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,15 @@ return (
<Widget src="${REPL_ACCOUNT}/widget/AI.Agent.AgentHeader" props={{ text: description, color: "#11181c" }} />
<Widget
src="${REPL_ACCOUNT}/widget/Entities.Template.EntityList"
props={{ entityType, buildQueries, queryName, collection, renderItem, createWidget }}
props={{
entityType,
buildQueries,
queryName,
collection,
renderItem,
createWidget,
schema: { entityTitle: "Agent" },
}}
/>
</div>
);
19 changes: 19 additions & 0 deletions src/Entities/QueryApi/Client.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,28 @@ function loadItems(queries, queryName, offset, collection, onLoad) {
});
}

function convertObjectKeysSnakeToPascal(item) {
const newItem = {};
Object.keys(item).forEach((key) => {
const pascalKey = key.replace(/(_\w)/g, (m) => m[1].toUpperCase());
newItem[pascalKey] = item[key];
});
return newItem;
}
function convertObjectKeysPascalToSnake(item) {
const newItem = {};
Object.keys(item).forEach((key) => {
const snakeKey = key.replace(/([A-Z])/g, (m) => "_" + m.toLowerCase());
newItem[snakeKey] = item[key];
});
return newItem;
}

return {
fetchGraphQL,
loadItems,
convertObjectKeysSnakeToPascal,
convertObjectKeysPascalToSnake,
LIMIT,
GRAPHQL_ENDPOINT,
HASURA_ROLE,
Expand Down
11 changes: 7 additions & 4 deletions src/Entities/Template/EntityCreate.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
const { data, onSubmit, onCancel, cancelLabel, entityType, schema } = props;
const { data, onSubmit, onCancel, cancelLabel, schema } = props;
const entityType = schema.entityType;
const capitalize = (s) => (s ? s.charAt(0).toUpperCase() + s.slice(1) : s);
const capitalizedEntityType = capitalize(entityType);
if (!schema || !entityType) {
if (!schema) {
return <>Missing properties schema or entityType</>;
}
const displayedSchema = Object.keys(schema)
.filter((key) => schema[key]?.displayType !== "hidden")
.filter((key) => typeof schema[key] === "object" && schema[key]?.displayType !== "hidden")
.reduce((acc, key) => {
if (key) acc[key] = schema[key];
return acc;
}, {});
const namespace = schema.namespace;
const onSubmitDefault = (formValues) => {
const { name, ...rest } = formValues;
const entity = { [name]: rest };
Social.set({ [entityType]: entity }, { force: true });
const data = namespace ? { [namespace]: { [entityType]: entity } } : { [entityType]: entity };
Social.set(data, { force: true });
};
const onSubmitFunction = onSubmit ?? onSubmitDefault;

Expand Down
Loading

0 comments on commit 6995a20

Please sign in to comment.