Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
780e649
refactor: clean unecessary LoadSettings function in OpenAI and Templa…
marc-romu Jun 20, 2025
7f3f829
feat(deepseek): add deepseek provider
marc-romu Jun 20, 2025
d930b5e
fix(deepseek): remove endpoint verification and usage, directly call …
marc-romu Jun 20, 2025
9ab35bd
Update src/SmartHopper.Providers.DeepSeek/DeepSeekProviderSettings.cs
marc-romu Jun 20, 2025
220deed
ci: added file and line info for trailing space check
marc-romu Jun 20, 2025
b918399
Merge branch 'feat/deep-seek' of https://github.com/architects-toolki…
marc-romu Jun 20, 2025
5834eef
refactor: sort using directives
marc-romu Jun 20, 2025
7a26b2e
refactor: removed trailing spaces
marc-romu Jun 20, 2025
232fe50
refactor: removed trailing spaces
marc-romu Jun 20, 2025
05d0760
feat: deepseek logo
marc-romu Jun 20, 2025
837b348
refactor: using references
marc-romu Jun 20, 2025
442b252
feat: deepseek (#224)
marc-romu Jun 20, 2025
c084074
docs: update version badge for dev
actions-user Jun 20, 2025
c830166
docs: update version badge for dev to 0.3.3-dev.250620 (#225)
marc-romu Jun 20, 2025
db88f7c
docs: update readme
marc-romu Jun 20, 2025
3585f12
docs: update readme
marc-romu Jun 20, 2025
a546981
docs: update readme
marc-romu Jun 20, 2025
43e3937
docs: update readme
marc-romu Jun 20, 2025
928f635
docs: update readme (#226)
marc-romu Jun 20, 2025
87cea8c
fix(ailist): incorrect json array preventing component from returning…
marc-romu Jun 20, 2025
b160296
Merge branch 'dev' into fix/220-ai-list-filter
marc-romu Jun 20, 2025
af84a93
fix(ailist): incorrect json array preventing component from returning…
marc-romu Jun 20, 2025
f1c1470
feat: add more auto-deletion branched prefixes
marc-romu Jun 20, 2025
7380104
Merge branch 'dev' of https://github.com/architects-toolkit/SmartHopp…
marc-romu Jun 20, 2025
4e3d3a0
ci(workflows): add close label to issue only if not marked as completed
marc-romu Jun 20, 2025
1d67e84
refactor(deepseek): increase token limit in settings to 100000
marc-romu Jun 20, 2025
9151c89
docs: update readme installation
marc-romu Jun 20, 2025
0cf0e12
Merge branch 'feat/magistral-thinking' into dev
marc-romu Jun 21, 2025
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
10 changes: 4 additions & 6 deletions .github/actions/code-style/trailing-whitespace/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,14 @@ runs:
sed -i 's/\r$//' "$file"
else
# Report trailing whitespace
while IFS= read -r entry; do
path="${entry%%:*}"
num="${entry#*:}"
while IFS=: read -r file_num; do
if [[ "${{ inputs.mode }}" == "soft-check" ]]; then
echo "::warning file=$path,line=$num::Trailing whitespace found"
echo "::warning file=$file,line=$file_num::Trailing whitespace found in $file (line $file_num)"
else
echo "::error file=$path,line=$num::Trailing whitespace found"
echo "::error file=$file,line=$file_num::Trailing whitespace found in $file (line $file_num)"
ERR=1
fi
done < <(grep -nE '[[:blank:]]$' "$file" || true)
done < <(grep -nE '[^[:space:]]+[[:space:]]+$' "$file" | cut -d: -f1,3- || true)
# # Report CRLF
# while IFS= read -r entry; do
# path="${entry%%:*}"
Expand Down
3 changes: 3 additions & 0 deletions .github/labels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@
- name: "provider: OpenAI"
color: "000"
description: "Issues related to the OpenAI provider"
- name: "provider: DeepSeek"
color: "000"
description: "Issues related to the DeepSeek provider"

# Feature Labels
- name: "feature: Settings"
Expand Down
36 changes: 21 additions & 15 deletions .github/workflows/github-issue-labels-on-close.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,27 @@ jobs:
script: |
const issue = context.payload.issue;
const currentLabels = issue.labels.map(label => label.name);

// Remove all status labels
const statusLabels = currentLabels.filter(label => label.toLowerCase().startsWith('status:'));

if (statusLabels.length > 0) {
for (const label of statusLabels) {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
name: label
});
}
console.log(`Removed status labels: ${statusLabels.join(', ')}`);
}

// Skip close label mapping if issue is completed
if (issue.state_reason === 'completed') {
console.log('Skipping close-label mapping for completed issue');
return;
}

// Define label mappings (status label -> close label)
const labelMappings = {
Expand Down Expand Up @@ -55,18 +76,3 @@ jobs:
});
console.log(`Added labels: ${labelsToAdd.join(', ')}`);
}

// Remove all status labels
const statusLabels = currentLabels.filter(label => label.toLowerCase().startsWith('status:'));

if (statusLabels.length > 0) {
for (const label of statusLabels) {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
name: label
});
}
console.log(`Removed status labels: ${statusLabels.join(', ')}`);
}
4 changes: 3 additions & 1 deletion .github/workflows/pr-delete-auto-branches.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ jobs:
startsWith(github.event.pull_request.head.ref, 'ci/') ||
startsWith(github.event.pull_request.head.ref, 'release/') ||
startsWith(github.event.pull_request.head.ref, 'feature/') ||
startsWith(github.event.pull_request.head.ref, 'feat/') ||
startsWith(github.event.pull_request.head.ref, 'hotfix/') ||
startsWith(github.event.pull_request.head.ref, 'bugfix/')
startsWith(github.event.pull_request.head.ref, 'bugfix/') ||
startsWith(github.event.pull_request.head.ref, 'fix/')
runs-on: ubuntu-latest
steps:
- name: Delete branch
Expand Down
3 changes: 2 additions & 1 deletion .windsurf/rules/general-guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ trigger: always_on
- Use native Grasshopper types & methods when possible
- Refer to https://developer.rhino3d.com/ as the official documentation
- Use English only
- Only change code lines directly needed to implement the request; avoid unrelated refactors
- Only change code lines directly needed to implement the request; avoid unrelated refactors
- Prefer copy/pasting, renaming, and removing files via PowerShell commands, rather than direct edits
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Added DeepSeek provider ([#222](https://github.com/architects-toolkit/SmartHopper/issues/222)).
- Render reasoning panels for `<think>` tags in chat UI as collapsible `<details>` blocks.
- Exclude reasoning from copy-paste (`mdContent`) and include in HTML display (`htmlContent`).
- Added configurable reasoning_effort setting (low, medium, high) for OpenAI provider.

### Changed

- Increased max tokens for OpenAI and MistralAI providers to 100000.
- Increased max tokens for OpenAI, MistralAI and DeepSeek providers to 100000.
- Updated deprecated OpenAI max_tokens parameter to max_completion_tokens.
- Refactored OpenAI, MistralAI and TemplateProvider settings validation to use centralized validation methods.

### Removed

- Removed `private LoadSettings` method from `OpenAISettings`.
- Removed `private LoadSettings` method from `TemplateProviderSettings`.
- Removed `ConcatenateItemsToJsonList` method from `ParsingTools` since it was not used.

### Fixed

- Fixed `AI List Filter might not be working as expected` ([#220](https://github.com/architects-toolkit/SmartHopper/issues/220)).

## [0.3.2-alpha] - 2025-06-15

### Added
Expand Down
66 changes: 32 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# SmartHopper - AI-Powered Grasshopper3D Plugin

[![Version](https://img.shields.io/badge/version-0%2E3%2E2--alpha-orange)](https://github.com/architects-toolkit/SmartHopper/releases)
[![Status](https://img.shields.io/badge/status-Alpha-orange)](https://github.com/architects-toolkit/SmartHopper/releases)
[![Version](https://img.shields.io/badge/version-0%2E3%2E3--dev%2E250620-brown)](https://github.com/architects-toolkit/SmartHopper/releases)
[![Status](https://img.shields.io/badge/status-Unstable%20Development-brown)](https://github.com/architects-toolkit/SmartHopper/releases)
[![Test results](https://img.shields.io/github/actions/workflow/status/architects-toolkit/SmartHopper/.github/workflows/ci-dotnet-tests.yml?label=.NET%20CI&logo=dotnet)](https://github.com/architects-toolkit/SmartHopper/actions/workflows/ci-dotnet-tests.yml)
[![Grasshopper](https://img.shields.io/badge/plugin_for-Grasshopper3D-darkgreen?logo=rhinoceros)](https://www.rhino3d.com/)
[![MistralAI](https://img.shields.io/badge/AI--powered-MistralAI-orange?logo=mistralai)](https://mistral.ai/)
[![OpenAI](https://img.shields.io/badge/AI--powered-OpenAI-blue?logo=openai)](https://openai.com/)
[![OpenAI](https://img.shields.io/badge/AI--powered-OpenAI-lightgrey?logo=openai)](https://openai.com/)
[![DeepSeek](https://img.shields.io/badge/AI--powered-DeepSeek-blue?logo=deepseek)](https://deepseek.com/)
[![License](https://img.shields.io/badge/license-LGPLv3-white)](LICENSE)

SmartHopper is a groundbreaking plugin that enables AI to directly interact with your Grasshopper canvas! Ask for help, search on the McNeel forum, reorganize components, toggle preview on or off, and much more, just by chatting with your customizable AI assistant. Additionally, this plugins includes multiple components that correspond to individual AI tools, so that you can integrate text- or list-based operations directly into your definition.
Expand All @@ -14,7 +15,7 @@ SmartHopper is a groundbreaking plugin that enables AI to directly interact with

- 🔍 **Direct AI Access to Grasshopper Files**: SmartHopper allows AI to read and understand your Grasshopper definitions through GhJSON conversion, enabling intelligent analysis and manipulation of parametric models.
- 🧠 **AI-Powered Workflow Enhancement**: Leverage AI to generate text, evaluate designs, filter data, and more - all within your familiar Grasshopper environment.
- 🤖 **Multiple AI Provider Support**: Choose between [**MistralAI**](https://mistral.ai/) and [**OpenAI**](https://openai.com/) APIs. You need to [provide your own API keys](#️-Available-Providers).
- 🤖 **Multiple AI Provider Support**: Choose between [**MistralAI**](https://mistral.ai/), [**OpenAI**](https://openai.com/) and [**DeepSeek**](https://deepseek.com/) APIs. You need to [provide your own API keys](#️-Available-Providers).
- 🔄 **Bidirectional Integration**: Not only can AI read your Grasshopper, but it can also generate and place definitions directly on your canvas *[coming soon]*.

## 👥 Who Is This For?
Expand All @@ -32,7 +33,26 @@ SmartHopper is a groundbreaking plugin that enables AI to directly interact with

## 💻 Installation

SmartHopper is not yet available through Food4Rhino. We will be releasing it soon! In the meanwhile, you can download it directly from the [Releases](https://github.com/architects-toolkit/SmartHopper/releases) section in this repository.
You can install SmartHopper through multiple methods:

1. **Rhino Package Manager** (Recommended):
- Open Rhino 8
- Type `PackageManager` in the command line
- In the Package Manager, select "include pre-releases"
- Search for "SmartHopper"
- Click "Install"

2. **Food4Rhino**:
- Go to [Food4Rhino](https://www.food4rhino.com/en/app/smarthopper)
- Click "Install"

3. **GitHub Releases**:
- Download the latest release from our [GitHub Releases](https://github.com/architects-toolkit/SmartHopper/releases) page
- Extract the downloaded ZIP file
- Copy the contents to your Grasshopper plugins folder
- Restart Rhino

After installation, all SmartHopper components will be available in the Grasshopper palette.

## 📊 Development Status

Expand All @@ -45,7 +65,7 @@ SmartHopper is not yet available through Food4Rhino. We will be releasing it soo
| Grasshopper Retrieve Components (GhRetrieveComponents)<br><sub>Retrieve all available Grasshopper components in your environment as JSON with optional category filter.</sub> | ⚪ | 🟡 | 🟠 | 🟢 |
| Grasshopper Tidy Up (GhTidyUp)<br><sub>Reorganize selected components into a clear, dependency-based grid.</sub> | ⚪ | 🟡 | 🟠 | 🟢 |
| AI Grasshopper Generate (AIGhGenerate)<br><sub>Automatically generate Grasshopper definitions using AI</sub> | ⚪ | - | - | - |
| AI Chat (AiChat)<br><sub>Interactive AI-powered conversational interface</sub> | ⚪ | 🟡 | 🟠 | - |
| AI Chat (AiChat)<br><sub>Interactive AI-powered conversational interface</sub> | ⚪ | 🟡 | 🟠 | 🟢 |
| AI Chat Input (AiChatInput)<br><sub>Send some data from your Grasshopper to the AI Chat</sub> | ⚪ | - | - | - |
| AI Chat Output (AiChatOutput)<br><sub>Receive some data from the AI Chat to your Grasshopper</sub> | ⚪ | - | - | - |
| AI Text Evaluate (AiTextEvaluate)<br><sub>Return a boolean from a text content using AI-powered checks</sub> | ⚪ | 🟡 | 🟠 | 🟢 |
Expand All @@ -69,15 +89,17 @@ SmartHopper is not yet available through Food4Rhino. We will be releasing it soo

### AI Tools

AI Tools are the interface between AI and Grasshopper, allowing to, for example, read your selected components, get the available Grasshopper components, or write a new script. All these tools are available to the provider to use while chatting in the AI Chat component.

| Tool Name | Description | Planned | In Progress | Testing | Released 🎉 |
|-----------|-------------|:-------:|:-----------:|:-------:|:-----------:|
| text_evaluate | Evaluates text against a true/false question | ⚪ | 🟡 | 🟠 | 🟢 |
| text_generate | Generates text based on a prompt and optional instructions | ⚪ | 🟡 | 🟠 | 🟢 |
| list_evaluate | Evaluates a list based on a natural language question | ⚪ | 🟡 | 🟠 | 🟢 |
| list_filter | Filters a list based on natural language criteria | ⚪ | 🟡 | 🟠 | 🟢 |
| script_review | Review a script for potential issues using AI-powered checks | ⚪ | 🟡 | 🟠 | - |
| script_review | Review a script for potential issues using AI-powered checks | ⚪ | 🟡 | 🟠 | 🟢 |
| script_edit | Modify the script from an existing component | ⚪ | 🟡 | - | - |
| script_new | Place a new script component from a natural language prompt | ⚪ | 🟡 | 🟠 | - |
| script_new | Place a new script component from a natural language prompt | ⚪ | 🟡 | 🟠 | 🟢 |
| json_generate | Generate an AI response in strict JSON output | ⚪ | - | - | - |
| web_fetch_page_text | Retrieve plain text content of a webpage, excluding HTML, scripts, and images, with robots.txt compliance | ⚪ | 🟡 | 🟠 | 🟢 |
| web_search_rhino_forum | Search Rhino Discourse forum posts by query and return matching results | ⚪ | 🟡 | 🟠 | 🟢 |
Expand All @@ -103,8 +125,8 @@ SmartHopper is currently supporting the following AI providers:
|----------|:------:|-------------------|
| [MistralAI](https://mistral.ai/) | ✅ Supported | [Le Plateforme](https://console.mistral.ai/) |
| [OpenAI](https://openai.com/) | ✅ Supported | [OpenAI Platform](https://platform.openai.com/) |
| [DeepSeek](https://deepseek.com/) | ✅ Supported | [DeepSeek Platform](https://platform.deepseek.com/) |
| [Anthropic](https://anthropic.com/) | 🔜 Planned | [Anthropic Console](https://console.anthropic.com/) |
| [DeepSeek](https://deepseek.com/) | 🔜 Planned | [DeepSeek Platform](https://platform.deepseek.com/) |

## 🔢 Supported Data Types

Expand All @@ -123,31 +145,7 @@ SmartHopper is designed to work with various Grasshopper-native data types. Addi

## 📚 Usage Examples

**Disclaimer:** All videos correspond to previous versions. Since version 0.2.0, the plugin made a huge step forward and the interface has been completely redesigned. It looks much better now, and its functionality has been enhanced.

### 1 Generate a Title for the Current Document

[![SmartHopper_Generate Title](https://i.vimeocdn.com/filter/overlay?src0=https%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F1966651352-6cfca3b39c99d01e9bbdb1590ac7f1325d35b8dfa16e0b5ced2aad704eef2bbe-d_295x166&src1=http%3A%2F%2Ff.vimeocdn.com%2Fp%2Fimages%2Fcrawler_play.png)](https://vimeo.com/1043447175)

### 2 Working with a CSV file

[![SmartHopper_Working With CSV](https://i.vimeocdn.com/filter/overlay?src0=https%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F1966651410-3ca705fd2e8fe276e9ee965339714c2de11f579ecf73d39fa92299b7b9015707-d_295x166&src1=http%3A%2F%2Ff.vimeocdn.com%2Fp%2Fimages%2Fcrawler_play.png)](https://vimeo.com/1043447217)

## ⚙️ Configuration

### Set Up the API Key and Other Settings

[![SmartHopper_Settings](https://i.vimeocdn.com/filter/overlay?src0=https%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F1966651378-ee922c5452393594d6ec931f112e24c82cceadb6c5dab80ced5e362a13ef0d45-d_200x150&src1=http%3A%2F%2Ff.vimeocdn.com%2Fp%2Fimages%2Fcrawler_play.png)](https://vimeo.com/1043447205)

### Choose the Provider for each Component

[![SmartHopper_Select Provider](https://i.vimeocdn.com/filter/overlay?src0=https%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F1966651347-eb497ba95d6fc8008fdb3db9b6288dbdaa4b7b4ab7a3f5f99ccd55495545a00f-d_200x150&src1=http%3A%2F%2Ff.vimeocdn.com%2Fp%2Fimages%2Fcrawler_play.png)](https://vimeo.com/1043447190)

## ⏩ Developing the Chat Interface

**Disclaimer:** The following video was a previous conceptual preview of the chat interface. From version 0.2.0, the chat interface is now available with a different design. Features will be added in future releases.

[![SmartHopper_Chat Concept](https://i.vimeocdn.com/filter/overlay?src0=https%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F1966657705-a1e9c281ab11e341df94bd14ee797d816afe34413b5af057841d6eb6191595fd-d_295x166&src1=http%3A%2F%2Ff.vimeocdn.com%2Fp%2Fimages%2Fcrawler_play.png)](https://vimeo.com/1043452514)
No usage examples available at the moment.

## 🤝 Contributing

Expand Down
19 changes: 19 additions & 0 deletions SmartHopper.sln
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartHopper.Providers.OpenA
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartHopper.Config.Tests", "src\SmartHopper.Config.Tests\SmartHopper.Config.Tests.csproj", "{469B4BA9-C2CB-4270-8896-0F04DAF67887}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartHopper.Providers.DeepSeek", "src\SmartHopper.Providers.DeepSeek\SmartHopper.Providers.DeepSeek.csproj", "{D31727FC-90E8-4F17-AD1F-F7FE9F79616A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -138,10 +142,25 @@ Global
{469B4BA9-C2CB-4270-8896-0F04DAF67887}.Release|x64.Build.0 = Release|Any CPU
{469B4BA9-C2CB-4270-8896-0F04DAF67887}.Release|x86.ActiveCfg = Release|Any CPU
{469B4BA9-C2CB-4270-8896-0F04DAF67887}.Release|x86.Build.0 = Release|Any CPU
{D31727FC-90E8-4F17-AD1F-F7FE9F79616A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D31727FC-90E8-4F17-AD1F-F7FE9F79616A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D31727FC-90E8-4F17-AD1F-F7FE9F79616A}.Debug|x64.ActiveCfg = Debug|Any CPU
{D31727FC-90E8-4F17-AD1F-F7FE9F79616A}.Debug|x64.Build.0 = Debug|Any CPU
{D31727FC-90E8-4F17-AD1F-F7FE9F79616A}.Debug|x86.ActiveCfg = Debug|Any CPU
{D31727FC-90E8-4F17-AD1F-F7FE9F79616A}.Debug|x86.Build.0 = Debug|Any CPU
{D31727FC-90E8-4F17-AD1F-F7FE9F79616A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D31727FC-90E8-4F17-AD1F-F7FE9F79616A}.Release|Any CPU.Build.0 = Release|Any CPU
{D31727FC-90E8-4F17-AD1F-F7FE9F79616A}.Release|x64.ActiveCfg = Release|Any CPU
{D31727FC-90E8-4F17-AD1F-F7FE9F79616A}.Release|x64.Build.0 = Release|Any CPU
{D31727FC-90E8-4F17-AD1F-F7FE9F79616A}.Release|x86.ActiveCfg = Release|Any CPU
{D31727FC-90E8-4F17-AD1F-F7FE9F79616A}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{D31727FC-90E8-4F17-AD1F-F7FE9F79616A} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0D5011CB-B808-41E4-A6FC-C01F3190649C}
EndGlobalSection
Expand Down
2 changes: 1 addition & 1 deletion src/SmartHopper.Components/List/AIListEvaluate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ private static async Task<Dictionary<string, List<GH_Boolean>>> ProcessData(Dict
Debug.WriteLine($"[Worker] Items per tree: {branches.Values.Max(branch => branch.Count)}");

// Get the trees
var listAsJson = ParsingTools.ConcatenateItemsToJson(branches["List"]);
var listAsJson = ParsingTools.ConcatenateItemsToJson(branches["List"], "array");
var questionTree = branches["Question"];

// Normalize tree lengths
Expand Down
Loading
Loading