diff --git a/packages/backend/src/apps/anthropic/actions/index.js b/packages/backend/src/apps/anthropic/actions/index.js
new file mode 100644
index 00000000..92d67c2c
--- /dev/null
+++ b/packages/backend/src/apps/anthropic/actions/index.js
@@ -0,0 +1,3 @@
+import sendMessage from './send-message/index.js';
+
+export default [sendMessage];
diff --git a/packages/backend/src/apps/anthropic/actions/send-message/index.js b/packages/backend/src/apps/anthropic/actions/send-message/index.js
new file mode 100644
index 00000000..3215bafb
--- /dev/null
+++ b/packages/backend/src/apps/anthropic/actions/send-message/index.js
@@ -0,0 +1,124 @@
+import defineAction from '../../../../helpers/define-action.js';
+
+const castFloatOrUndefined = (value) => {
+ return value === '' ? undefined : parseFloat(value);
+};
+
+export default defineAction({
+ name: 'Send message',
+ key: 'send Message',
+ description:
+ 'Sends a structured list of input messages with text content, and the model will generate the next message in the conversation.',
+ arguments: [
+ {
+ label: 'Model',
+ key: 'model',
+ type: 'dropdown',
+ required: true,
+ variables: true,
+ description: 'The model that will complete your prompt.',
+ source: {
+ type: 'query',
+ name: 'getDynamicData',
+ arguments: [
+ {
+ name: 'key',
+ value: 'listModels',
+ },
+ ],
+ },
+ },
+ {
+ label: 'Messages',
+ key: 'messages',
+ type: 'dynamic',
+ required: true,
+ description: 'Add or remove messages as needed',
+ value: [{ role: 'assistant', body: '' }],
+ fields: [
+ {
+ label: 'Role',
+ key: 'role',
+ type: 'dropdown',
+ required: true,
+ options: [
+ {
+ label: 'Assistant',
+ value: 'assistant',
+ },
+ {
+ label: 'User',
+ value: 'user',
+ },
+ ],
+ },
+ {
+ label: 'Content',
+ key: 'content',
+ type: 'string',
+ required: true,
+ variables: true,
+ },
+ ],
+ },
+ {
+ label: 'Maximum tokens',
+ key: 'maxTokens',
+ type: 'string',
+ required: true,
+ variables: true,
+ description: 'The maximum number of tokens to generate before stopping.',
+ },
+ {
+ label: 'Temperature',
+ key: 'temperature',
+ type: 'string',
+ required: false,
+ variables: true,
+ value: '1.0',
+ description:
+ 'Amount of randomness injected into the response. Defaults to 1.0. Ranges from 0.0 to 1.0. Use temperature closer to 0.0 for analytical / multiple choice, and closer to 1.0 for creative and generative tasks.',
+ },
+ {
+ label: 'Stop sequences',
+ key: 'stopSequences',
+ type: 'dynamic',
+ required: false,
+ variables: true,
+ description:
+ 'Custom text sequences that will cause the model to stop generating.',
+ fields: [
+ {
+ label: 'Stop sequence',
+ key: 'stopSequence',
+ type: 'string',
+ required: false,
+ variables: true,
+ },
+ ],
+ },
+ ],
+
+ async run($) {
+ const nonEmptyStopSequences = $.step.parameters.stopSequences
+ .filter(({ stopSequence }) => stopSequence)
+ .map(({ stopSequence }) => stopSequence);
+
+ const payload = {
+ model: $.step.parameters.model,
+ temperature: castFloatOrUndefined($.step.parameters.temperature),
+ max_tokens: castFloatOrUndefined($.step.parameters.maxTokens),
+ stop_sequences: nonEmptyStopSequences,
+ messages: $.step.parameters.messages.map((message) => ({
+ role: message.role,
+ content: message.content,
+ })),
+ };
+
+ const { data } = await $.http.post('/v1/messages', payload);
+
+ $.setActionItem({
+ raw: data,
+ });
+ },
+});
diff --git a/packages/backend/src/apps/anthropic/assets/favicon.svg b/packages/backend/src/apps/anthropic/assets/favicon.svg
new file mode 100644
index 00000000..affdadef
--- /dev/null
+++ b/packages/backend/src/apps/anthropic/assets/favicon.svg
@@ -0,0 +1,8 @@
+
+
\ No newline at end of file
diff --git a/packages/backend/src/apps/anthropic/auth/index.js b/packages/backend/src/apps/anthropic/auth/index.js
new file mode 100644
index 00000000..947c8f8a
--- /dev/null
+++ b/packages/backend/src/apps/anthropic/auth/index.js
@@ -0,0 +1,34 @@
+import verifyCredentials from './verify-credentials.js';
+import isStillVerified from './is-still-verified.js';
+
+export default {
+ fields: [
+ {
+ key: 'screenName',
+ label: 'Screen Name',
+ type: 'string',
+ required: true,
+ readOnly: false,
+ value: null,
+ placeholder: null,
+ description:
+ 'Screen name of your connection to be used on Automatisch UI.',
+ clickToCopy: false,
+ },
+ {
+ key: 'apiKey',
+ label: 'API Key',
+ type: 'string',
+ required: true,
+ readOnly: false,
+ value: null,
+ placeholder: null,
+ description: 'Anthropic AI API key of your account.',
+ docUrl: 'https://automatisch.io/docs/anthropic#api-key',
+ clickToCopy: false,
+ },
+ ],
+
+ verifyCredentials,
+ isStillVerified,
+};
diff --git a/packages/backend/src/apps/anthropic/auth/is-still-verified.js b/packages/backend/src/apps/anthropic/auth/is-still-verified.js
new file mode 100644
index 00000000..531fc23a
--- /dev/null
+++ b/packages/backend/src/apps/anthropic/auth/is-still-verified.js
@@ -0,0 +1,7 @@
+const isStillVerified = async ($) => {
+ await $.http.get('/v1/models');
+
+ return true;
+};
+
+export default isStillVerified;
diff --git a/packages/backend/src/apps/anthropic/auth/verify-credentials.js b/packages/backend/src/apps/anthropic/auth/verify-credentials.js
new file mode 100644
index 00000000..7f43f884
--- /dev/null
+++ b/packages/backend/src/apps/anthropic/auth/verify-credentials.js
@@ -0,0 +1,5 @@
+const verifyCredentials = async ($) => {
+ await $.http.get('/v1/models');
+};
+
+export default verifyCredentials;
diff --git a/packages/backend/src/apps/anthropic/common/add-anthropic-version-header.js b/packages/backend/src/apps/anthropic/common/add-anthropic-version-header.js
new file mode 100644
index 00000000..9ff91ce2
--- /dev/null
+++ b/packages/backend/src/apps/anthropic/common/add-anthropic-version-header.js
@@ -0,0 +1,7 @@
+const addAuthHeader = ($, requestConfig) => {
+ requestConfig.headers['anthropic-version'] = '2023-06-01';
+
+ return requestConfig;
+};
+
+export default addAuthHeader;
diff --git a/packages/backend/src/apps/anthropic/common/add-auth-header.js b/packages/backend/src/apps/anthropic/common/add-auth-header.js
new file mode 100644
index 00000000..01bcae10
--- /dev/null
+++ b/packages/backend/src/apps/anthropic/common/add-auth-header.js
@@ -0,0 +1,9 @@
+const addAuthHeader = ($, requestConfig) => {
+ if ($.auth.data?.apiKey) {
+ requestConfig.headers['x-api-key'] = $.auth.data.apiKey;
+ }
+
+ return requestConfig;
+};
+
+export default addAuthHeader;
diff --git a/packages/backend/src/apps/anthropic/dynamic-data/index.js b/packages/backend/src/apps/anthropic/dynamic-data/index.js
new file mode 100644
index 00000000..6db48046
--- /dev/null
+++ b/packages/backend/src/apps/anthropic/dynamic-data/index.js
@@ -0,0 +1,3 @@
+import listModels from './list-models/index.js';
+
+export default [listModels];
diff --git a/packages/backend/src/apps/anthropic/dynamic-data/list-models/index.js b/packages/backend/src/apps/anthropic/dynamic-data/list-models/index.js
new file mode 100644
index 00000000..f47f5fb9
--- /dev/null
+++ b/packages/backend/src/apps/anthropic/dynamic-data/list-models/index.js
@@ -0,0 +1,31 @@
+export default {
+ name: 'List models',
+ key: 'listModels',
+
+ async run($) {
+ const models = {
+ data: [],
+ };
+
+ const params = {
+ limit: 999,
+ };
+
+ let hasMore = false;
+
+ do {
+ const { data } = await $.http.get('/v1/models', { params });
+ params.after_id = data.last_id;
+ hasMore = data.has_more;
+
+ for (const base of data.data) {
+ models.data.push({
+ value: base.id,
+ name: base.display_name,
+ });
+ }
+ } while (hasMore);
+
+ return models;
+ },
+};
diff --git a/packages/backend/src/apps/anthropic/index.js b/packages/backend/src/apps/anthropic/index.js
new file mode 100644
index 00000000..65f29ba2
--- /dev/null
+++ b/packages/backend/src/apps/anthropic/index.js
@@ -0,0 +1,21 @@
+import defineApp from '../../helpers/define-app.js';
+import addAuthHeader from './common/add-auth-header.js';
+import addAnthropicVersionHeader from './common/add-anthropic-version-header.js';
+import auth from './auth/index.js';
+import actions from './actions/index.js';
+import dynamicData from './dynamic-data/index.js';
+
+export default defineApp({
+ name: 'Anthropic',
+ key: 'anthropic',
+ baseUrl: 'https://anthropic.com',
+ apiBaseUrl: 'https://api.anthropic.com',
+ iconUrl: '{BASE_URL}/apps/anthropic/assets/favicon.svg',
+ authDocUrl: '{DOCS_URL}/apps/anthropic/connection',
+ primaryColor: '#181818',
+ supportsConnections: true,
+ beforeRequest: [addAuthHeader, addAnthropicVersionHeader],
+ auth,
+ actions,
+ dynamicData,
+});
diff --git a/packages/backend/src/models/__snapshots__/app.test.js.snap b/packages/backend/src/models/__snapshots__/app.test.js.snap
index 38324be3..7fb9a297 100644
--- a/packages/backend/src/models/__snapshots__/app.test.js.snap
+++ b/packages/backend/src/models/__snapshots__/app.test.js.snap
@@ -3,6 +3,7 @@
exports[`App model > list should have list of applications keys 1`] = `
[
"airtable",
+ "anthropic",
"appwrite",
"azure-openai",
"carbone",
diff --git a/packages/docs/pages/.vitepress/config.js b/packages/docs/pages/.vitepress/config.js
index 0fd2511b..1508b069 100644
--- a/packages/docs/pages/.vitepress/config.js
+++ b/packages/docs/pages/.vitepress/config.js
@@ -41,6 +41,15 @@ export default defineConfig({
{ text: 'Connection', link: '/apps/airtable/connection' },
],
},
+ {
+ text: 'Anthropic',
+ collapsible: true,
+ collapsed: true,
+ items: [
+ { text: 'Actions', link: '/apps/anthropic/actions' },
+ { text: 'Connection', link: '/apps/anthropic/connection' },
+ ],
+ },
{
text: 'Appwrite',
collapsible: true,
diff --git a/packages/docs/pages/apps/anthropic/actions.md b/packages/docs/pages/apps/anthropic/actions.md
new file mode 100644
index 00000000..6e8d4cf7
--- /dev/null
+++ b/packages/docs/pages/apps/anthropic/actions.md
@@ -0,0 +1,12 @@
+---
+favicon: /favicons/anthropic.svg
+items:
+ - name: Send message
+ desc: Sends a structured list of input messages with text content, and the model will generate the next message in the conversation.
+---
+
+
+
+
diff --git a/packages/docs/pages/apps/anthropic/connection.md b/packages/docs/pages/apps/anthropic/connection.md
new file mode 100644
index 00000000..92330b8b
--- /dev/null
+++ b/packages/docs/pages/apps/anthropic/connection.md
@@ -0,0 +1,8 @@
+# Anthropic
+
+1. Go to [API Keys page](https://console.anthropic.com/settings/keys) on Anthropic.
+2. Create a new key.
+3. Paste the key into the `API Key` field in Automatisch.
+4. Write any screen name to be displayed in Automatisch.
+5. Click `Save`.
+6. Start using Anthropic integration with Automatisch!
diff --git a/packages/docs/pages/guide/available-apps.md b/packages/docs/pages/guide/available-apps.md
index 4be6447b..6f010074 100644
--- a/packages/docs/pages/guide/available-apps.md
+++ b/packages/docs/pages/guide/available-apps.md
@@ -3,6 +3,7 @@
The following integrations are currently supported by Automatisch.
- [Airtable](/apps/airtable/actions)
+- [Anthropic](/apps/anthropic/actions)
- [Appwrite](/apps/appwrite/triggers)
- [Carbone](/apps/carbone/actions)
- [ClickUp](/apps/clickup/triggers)
diff --git a/packages/docs/pages/public/favicons/anthropic.svg b/packages/docs/pages/public/favicons/anthropic.svg
new file mode 100644
index 00000000..affdadef
--- /dev/null
+++ b/packages/docs/pages/public/favicons/anthropic.svg
@@ -0,0 +1,8 @@
+
+
\ No newline at end of file