Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/langchain agent #784

Draft
wants to merge 14 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion frontend/components/AgentSelection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ const EachAgent = memo(
if (
agentType === AgentType.Memeooorr ||
agentType === AgentType.Modius ||
agentType === AgentType.AgentsFunCelo
agentType === AgentType.AgentsFunCelo ||
agentType == AgentType.Langchain
) {
// if the selected type requires setting up an agent - should redirect to SetupYourAgent first
// TODO: can have this as a boolean flag in agentConfig?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const FUNDS_REQUIRED_FOR_BY_AGENT_TYPE = {
[AgentType.Memeooorr]: 'for agent operations',
[AgentType.Modius]: 'minimum for investment',
[AgentType.AgentsFunCelo]: 'for agent operations',
[AgentType.Langchain]: 'for testing'
};

export const FundsToActivate = ({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { Button, Divider, Form, Input, message, Typography } from 'antd';
import React, { useCallback, useState } from 'react';
import { useUnmount } from 'usehooks-ts';

import { ServiceTemplate } from '@/client';
import { SetupScreen } from '@/enums/SetupScreen';
import { useSetup } from '@/hooks/useSetup';
import { useStakingProgram } from '@/hooks/useStakingProgram';

import { commonFieldProps, validateMessages } from '../formUtils';
import { onDummyServiceCreation } from '../utils';
import {
TavilyApiKeyLabel,
OpenAIApiKeyLabel,
} from './labels';

const { Text } = Typography;

type FieldValues = {
tavilyApiKey: string;
openAIApiKey: string;
};

type LangchainAgentFormProps = { serviceTemplate: ServiceTemplate };

export const LangchainAgentForm = ({ serviceTemplate }: LangchainAgentFormProps) => {
const { goto } = useSetup();
const { defaultStakingProgramId } = useStakingProgram();

const [form] = Form.useForm<FieldValues>();
const [isSubmitting, setIsSubmitting] = useState(false);
const [submitButtonText, setSubmitButtonText] = useState('Continue');

const onFinish = useCallback(
async (values: Record<keyof FieldValues, string>) => {
if (!defaultStakingProgramId) return;

try {
setIsSubmitting(true);

// wait for agent setup to complete
setSubmitButtonText('Setting up agent...');

const overriddenServiceConfig: ServiceTemplate = {
...serviceTemplate,
env_variables: {
...serviceTemplate.env_variables,
TAVILY_API_KEY: {
...serviceTemplate.env_variables.TAVILY_API_KEY,
value: values.tavilyApiKey,
},
OPENAI_API_KEY: {
...serviceTemplate.env_variables.OPENAI_API_KEY,
value: values.openAIApiKey,
},
},
};

await onDummyServiceCreation(
defaultStakingProgramId,
overriddenServiceConfig,
);

message.success('Agent setup complete');

// move to next page
goto(SetupScreen.SetupEoaFunding);
} catch (error) {
message.error('Something went wrong. Please try again.');
console.error(error);
} finally {
setIsSubmitting(false);
setSubmitButtonText('Continue');
}
},
[defaultStakingProgramId, serviceTemplate, goto],
);

// Clean up
useUnmount(async () => {
setIsSubmitting(false);
setSubmitButtonText('Continue');
});

const canSubmitForm = isSubmitting || !defaultStakingProgramId;

return (
<>
<Text>
Set up your agent providing a Tavily and OpenAI API key as a search engine tool required for the
agent.
</Text>
<Divider style={{ margin: '8px 0' }} />

<Form<FieldValues>
form={form}
name="setup-your-agent"
layout="vertical"
onFinish={onFinish}
validateMessages={validateMessages}
disabled={canSubmitForm}
>
<Form.Item
name="tavilyApiKey"
label={<TavilyApiKeyLabel />}
{...commonFieldProps}
>
<Input />
</Form.Item>

<Form.Item
name="openAIApiKey"
label={<OpenAIApiKeyLabel />}
{...commonFieldProps}
>
<Input />
</Form.Item>

<Form.Item>
<Button
type="primary"
htmlType="submit"
size="large"
block
loading={isSubmitting}
disabled={canSubmitForm}
>
{submitButtonText}
</Button>
</Form.Item>
</Form>
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Flex, Typography } from 'antd';

import { InfoTooltip } from '@/components/InfoTooltip';
import { UNICODE_SYMBOLS } from '@/constants/symbols';

const { Paragraph, Text } = Typography;

const TOOLTIP_STYLE = { width: '400px' };

export const TavilyApiKeyLabel = () => (
<Flex align="center" gap={8}>
<Text>Tavily API key</Text>
<InfoTooltip placement="bottom" overlayInnerStyle={TOOLTIP_STYLE}>
<Paragraph className="text-sm mt-0">
The Tavily API Key enables your agent to to use Tavily as one of its AI tools in this example.
</Paragraph>
<Paragraph className="text-sm m-0">To locate your API key:</Paragraph>
<ol className="pl-16 text-sm">
<li>
<Text className="text-sm">
Log in to your{' '}
<a target="_blank" href="https://tavily.com/">
Tavily account&nbsp;
{UNICODE_SYMBOLS.EXTERNAL_LINK}
</a>
.
</Text>
</li>
<li>
<Text className="text-sm">
Go to <span className="font-weight-600">Overview.</span>
</Text>
</li>
<li>
<Text className="text-sm">
Find your key under the{' '}
<span className="font-weight-600">API Keys</span> section.
</Text>
</li>
</ol>
</InfoTooltip>
</Flex>
);

export const OpenAIApiKeyLabel = () => (
<Flex align="center" gap={8}>
<Text>OpenAI API key</Text>
<InfoTooltip placement="bottom" overlayInnerStyle={TOOLTIP_STYLE}>
<Paragraph className="text-sm mt-0">
The OpenAI API Key enables your agent to to use OpenAI as one of its tools.
</Paragraph>
<Paragraph className="text-sm m-0">To locate your API key:</Paragraph>
<ol className="pl-16 text-sm">
<li>
<Text className="text-sm">
Log in to your{' '}
<a target="_blank" href="https://platform.openai.com/">
OpenAI account&nbsp;
{UNICODE_SYMBOLS.EXTERNAL_LINK}
</a>
.
</Text>
</li>
<li>
<Text className="text-sm">
Go to <span className="font-weight-600">Dashboard.</span>
</Text>
</li>
<li>
<Text className="text-sm">
Click on <span className="font-weight-600">API Keys</span> on the left menu.
</Text>
</li>
<li>
<Text className="text-sm">
Click on <span className="font-weight-600">Create new secret key</span> at the top right.
</Text>
</li>
<li>
<Text className="text-sm">
Copy you key.
</Text>
</li>
</ol>
</InfoTooltip>
</Flex>
);
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { LOCAL_FORM_THEME } from '@/theme';
import { SetupCreateHeader } from '../Create/SetupCreateHeader';
import { MemeooorrAgentForm } from './MemeooorrAgentForm/MemeooorrAgentForm';
import { ModiusAgentForm } from './ModiusAgentForm/ModiusAgentForm';
import { LangchainAgentForm } from './LangchainAgentForm/LangchainAgentForm';

const { Title, Text } = Typography;

Expand Down Expand Up @@ -46,6 +47,10 @@ export const SetupYourAgent = () => {
<ModiusAgentForm serviceTemplate={serviceTemplate} />
)}

{selectedAgentType === AgentType.Langchain && (
<LangchainAgentForm serviceTemplate={serviceTemplate} />
)}

<Text
type="secondary"
className="text-sm"
Expand Down
12 changes: 12 additions & 0 deletions frontend/config/agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { TokenSymbol } from '@/enums/Token';
import { AgentsFunBaseService } from '@/service/agents/AgentsFunBase';
import { ModiusService } from '@/service/agents/Modius';
import { PredictTraderService } from '@/service/agents/PredictTrader';
import { LangchainService } from '@/service/agents/Langchain';
import { AgentConfig } from '@/types/Agent';

import { MODE_TOKEN_CONFIG } from './tokens';
Expand Down Expand Up @@ -46,6 +47,17 @@ export const AGENT_CONFIG: {
'Autonomously posts to Twitter, creates and trades memecoins, and interacts with other agents. Agent is operating on Base chain.',
isAgentEnabled: true,
},
[AgentType.Langchain]: {
name: 'Basic Langchain agent',
evmHomeChainId: EvmChainId.Gnosis,
middlewareHomeChainId: MiddlewareChain.GNOSIS,
requiresAgentSafesOn: [EvmChainId.Gnosis],
requiresMasterSafesOn: [EvmChainId.Gnosis],
serviceApi: LangchainService,
displayName: 'Basic Langchain agent',
description: 'Basic Langchain agent',
isAgentEnabled: true,
},
[AgentType.Modius]: {
name: 'Modius agent',
evmHomeChainId: EvmChainId.Mode,
Expand Down
52 changes: 52 additions & 0 deletions frontend/constants/serviceTemplates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,57 @@ export const AGENTS_FUN_CELO_TEMPLATE: ServiceTemplate = {
...AGENTS_FUN_COMMON_TEMPLATE,
} as const;

export const LANGCHAIN_TEMPLATE: ServiceTemplate = {
agentType: AgentType.Langchain,
hash: 'bafybeif6t6kxdkklesvsxohqrdfbypzjtoy5wlmzovfxp3wklr4k3nusiu',
name: 'Langchain',// Should be unique across all services and not be updated
description: 'Basic Langchain Agent',
image:
'https://gateway.autonolas.tech/ipfs/QmWGuWJ5oVgvdJrjxjfssDyoFxGXwKfB8pFL7Et54qT9H7',
service_version: 'v0.18.1',
home_chain: MiddlewareChain.GNOSIS,
configurations: {
[MiddlewareChain.GNOSIS]: {
//staking_program_id: StakingProgramId., // default, may be overwritten
nft: 'bafybeif6t6kxdkklesvsxohqrdfbypzjtoy5wlmzovfxp3wklr4k3nusiu',
rpc: 'http://localhost:8545', // overwritten
agent_id: 1, //TODO REPLACE
threshold: 1,
use_staking: false,
//values below copied from Trader template
cost_of_bond: +parseEther(0.001),
monthly_gas_estimate: +parseEther(10),
fund_requirements: {
[ethers.constants.AddressZero]: {
agent: +parseEther(2),
safe: +parseEther(5),
},
//values above copied from Trader template
},
},
},
env_variables: {
GNOSIS_LEDGER_RPC: {
name: 'Gnosis ledger RPC',
description: '',
value: '',
provision_type: EnvProvisionType.COMPUTED,
},
TAVILY_API_KEY: {
name: 'Tavily API Key',
description: '',
value: '',
provision_type: EnvProvisionType.USER,
},
OPENAI_API_KEY: {
name: 'OpenAI API Key',
description: '',
value: '',
provision_type: EnvProvisionType.USER,
},
},
} as const;

export const MODIUS_SERVICE_TEMPLATE: ServiceTemplate = {
agentType: AgentType.Modius,
name: 'Optimus', // Should be unique across all services and not be updated
Expand Down Expand Up @@ -374,6 +425,7 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [
AGENTS_FUN_BASE_TEMPLATE,
MODIUS_SERVICE_TEMPLATE,
AGENTS_FUN_CELO_TEMPLATE,
LANGCHAIN_TEMPLATE,
] as const;

export const getServiceTemplates = (): ServiceTemplate[] => SERVICE_TEMPLATES;
Expand Down
1 change: 1 addition & 0 deletions frontend/enums/Agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const AgentType = {
Memeooorr: 'memeooorr',
AgentsFunCelo: 'agents-fun-celo',
Modius: 'modius',
Langchain: 'langchain'
} as const;

export type AgentType = (typeof AgentType)[keyof typeof AgentType];
11 changes: 11 additions & 0 deletions frontend/hooks/useFeatureFlag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@ const FEATURES_CONFIG = FeaturesConfigSchema.parse({
'backup-via-safe': true,
'agent-settings': false,
},
[AgentType.Langchain]: {
'manage-wallet': true,
'withdraw-funds': true,
'last-transactions': true,
'rewards-streak': true,
'staking-contract-section': false,
'low-funds': true,
'agent-activity': false,
'backup-via-safe': true,
'agent-settings': true,
},
[AgentType.Memeooorr]: {
'manage-wallet': true,
'withdraw-funds': false,
Expand Down
Loading