Skip to content
Open
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ The current `golemcore/*` modules in this repository are:

| Plugin | Purpose |
| --- | --- |
| `golemcore/airtable` | Airtable records tool plugin with configurable read/write operations for bases and tables. |
| `golemcore/brave-search` | Brave Search web search tool plugin with API-key backed queries. |
| `golemcore/browser` | Playwright-backed browser automation tool with screenshot support. |
| `golemcore/browserless` | Browserless smart scrape plugin for rendered HTML, markdown, and link extraction. |
Expand Down
12 changes: 12 additions & 0 deletions golemcore/airtable/plugin.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
id: golemcore/airtable
provider: golemcore
name: airtable
version: 1.0.0
pluginApiVersion: 1
engineVersion: ">=0.0.0 <1.0.0"
entrypoint: me.golemcore.plugins.golemcore.airtable.AirtablePluginBootstrap
description: Airtable records tool plugin backed by the Airtable REST API.
sourceUrl: https://github.com/alexk-dev/golemcore-plugins/tree/main/golemcore/airtable
license: Apache-2.0
maintainers:
- alexk-dev
104 changes: 104 additions & 0 deletions golemcore/airtable/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>me.golemcore.plugins</groupId>
<artifactId>golemcore-plugins</artifactId>
<version>1.0.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<version>1.0.0</version>
<artifactId>golemcore-airtable-plugin</artifactId>
<name>golemcore/airtable</name>
<description>Airtable records tool plugin for GolemCore</description>

<properties>
<plugin.owner>golemcore</plugin.owner>
<plugin.name>airtable</plugin.name>
<formatter.config.file>../../misc/formatter_eclipse.xml</formatter.config.file>
</properties>

<dependencies>
<dependency>
<groupId>me.golemcore.plugins</groupId>
<artifactId>golemcore-plugin-extension-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>me.golemcore.plugins</groupId>
<artifactId>golemcore-plugin-runtime-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp-jvm</artifactId>
<version>${okhttp.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>${project.basedir}</directory>
<includes>
<include>plugin.yaml</include>
</includes>
<targetPath>META-INF/golemcore</targetPath>
</resource>
</resources>
<plugins>
<plugin>
<groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>copy-plugin-artifact</id>
<phase>package</phase>
<configuration>
<target>
<mkdir dir="${project.basedir}/../../dist/${plugin.owner}/${plugin.name}/${project.version}" />
<copy file="${project.build.directory}/${project.build.finalName}.jar"
tofile="${project.basedir}/../../dist/${plugin.owner}/${plugin.name}/${project.version}/${project.artifactId}-${project.version}.jar"
overwrite="true" />
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package me.golemcore.plugins.golemcore.airtable;

import me.golemcore.plugin.api.extension.spi.PluginBootstrap;
import me.golemcore.plugin.api.extension.spi.PluginDescriptor;

public class AirtablePluginBootstrap implements PluginBootstrap {

@Override
public PluginDescriptor descriptor() {
return PluginDescriptor.builder()
.id("golemcore/airtable")
.provider("golemcore")
.name("airtable")
.entrypoint(getClass().getName())
.build();
}

@Override
public Class<?> configurationClass() {
return AirtablePluginConfiguration.class;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package me.golemcore.plugins.golemcore.airtable;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AirtablePluginConfig {

static final String DEFAULT_API_BASE_URL = "https://api.airtable.com";
static final int DEFAULT_MAX_RECORDS = 20;
static final int MAX_RECORDS_LIMIT = 100;

@Builder.Default
private Boolean enabled = false;

@Builder.Default
private String apiBaseUrl = DEFAULT_API_BASE_URL;

private String apiToken;
private String baseId;

@Builder.Default
private String defaultTable = "";

@Builder.Default
private String defaultView = "";

@Builder.Default
private Integer defaultMaxRecords = DEFAULT_MAX_RECORDS;

@Builder.Default
private Boolean allowWrite = false;

@Builder.Default
private Boolean allowDelete = false;

@Builder.Default
private Boolean typecast = false;

public void normalize() {
if (enabled == null) {
enabled = false;
}
apiBaseUrl = normalizeUrl(apiBaseUrl, DEFAULT_API_BASE_URL);
apiToken = normalizeText(apiToken, null);
baseId = normalizeText(baseId, null);
defaultTable = normalizeText(defaultTable, "");
defaultView = normalizeText(defaultView, "");
if (defaultMaxRecords == null || defaultMaxRecords <= 0) {
defaultMaxRecords = DEFAULT_MAX_RECORDS;
}
if (defaultMaxRecords > MAX_RECORDS_LIMIT) {
defaultMaxRecords = MAX_RECORDS_LIMIT;
}
if (allowWrite == null) {
allowWrite = false;
}
if (allowDelete == null) {
allowDelete = false;
}
if (typecast == null) {
typecast = false;
}
}

private String normalizeUrl(String value, String defaultValue) {
String trimmed = normalizeText(value, defaultValue);
while (trimmed.endsWith("/")) {
trimmed = trimmed.substring(0, trimmed.length() - 1);
}
return trimmed.isBlank() ? defaultValue : trimmed;
}

private String normalizeText(String value, String defaultValue) {
if (value == null) {
return defaultValue;
}
String trimmed = value.trim();
return trimmed.isEmpty() ? defaultValue : trimmed;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package me.golemcore.plugins.golemcore.airtable;

import com.fasterxml.jackson.databind.ObjectMapper;
import me.golemcore.plugin.api.runtime.PluginConfigurationService;
import org.springframework.stereotype.Service;

import java.util.Map;

@Service
public class AirtablePluginConfigService {

static final String PLUGIN_ID = "golemcore/airtable";

private final PluginConfigurationService pluginConfigurationService;
private final ObjectMapper objectMapper;

public AirtablePluginConfigService(PluginConfigurationService pluginConfigurationService) {
this.pluginConfigurationService = pluginConfigurationService;
this.objectMapper = new ObjectMapper();
}

public AirtablePluginConfig getConfig() {
Map<String, Object> raw = pluginConfigurationService.getPluginConfig(PLUGIN_ID);
AirtablePluginConfig config = raw.isEmpty()
? AirtablePluginConfig.builder().build()
: objectMapper.convertValue(raw, AirtablePluginConfig.class);
config.normalize();
return config;
}

@SuppressWarnings("unchecked")
public void save(AirtablePluginConfig config) {
config.normalize();
pluginConfigurationService.savePluginConfig(PLUGIN_ID, objectMapper.convertValue(config, Map.class));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package me.golemcore.plugins.golemcore.airtable;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
@ComponentScan(basePackageClasses = {
AirtableRecordsToolProvider.class,
AirtablePluginSettingsContributor.class
})
public class AirtablePluginConfiguration {
}
Loading
Loading