feat: SmartHopper 2.0.0 - Google Gemini Provider, Batch API, Vision Input, and Breaking Changes#420
Open
marc-romu wants to merge 181 commits into
Open
feat: SmartHopper 2.0.0 - Google Gemini Provider, Batch API, Vision Input, and Breaking Changes#420marc-romu wants to merge 181 commits into
marc-romu wants to merge 181 commits into
Conversation
…xt2json tool - Add `text2json` AI tool for generating structured JSON from prompts conforming to JSON Schema - Add `AIText2JsonComponent` in `SmartHopper > JSON` category with Prompt, Instructions, and Schema inputs - Add JSON utility components requiring no AI: - `JsonSchemaComponent`: builds JSON Schema from property definitions with dot-notation nesting support - `JsonObjectComponent`: creates JSON objects from key-value pairs
…ts-toolkit/SmartHopper into feature/2.0.0-text2json
…mposition - Add `JsonSchemaPropComponent` (`JsonSchemaProp`): builds scalar property definitions from Name, Type, and Description inputs - Add `JsonSchemaPropObjectComponent` (`JsonSchemaPropObj`): builds object properties by prefixing sub-properties with dot-notation - Add `JsonSchemaPropArrayComponent` (`JsonSchemaPropArr`): builds array properties with configurable Items Type using `array[itemsType]` encoding - Update `JsonSchemaComponent`
…t reconstruction - Add `OnBatchCompleted` override to decode batch results and reconstruct output trees - Add batch submission calls in worker `DoWorkAsync` after processing all items - Add reconstructed tree handling in worker `SetOutput` to use batch results when available - Implement provider-based result decoding using `AIInteractionText` extraction - Add batch support to `AIImg2TextComponent`, `AIText2JsonComponent`, `AIFile
… prevent stale parameter usage
…nent When a batch job completes but individual items fail (e.g. OpenAI `BadRequest` due to `max_tokens` too large), the error was silently discarded and the component showed "Done".
…ns via img2text
- **AIFile2MdComponent**: File conversion and image extraction now run locally via `file2md` with `describeImages=false`. Each extracted image is then described via `CallAiToolAsync("img2text", ...)` which is batch-interceptable. `OnBatchCompleted` reassembles final markdown from locally-stored per-file context and batch image description results using `ImageSentinelContext` dictionary.
…re queuing - Add `IsValid()` validation call on batch requests before adding to queue - Surface validation warnings to component using `SurfaceMessagesFromReturn` - Surface validation errors but allow queuing to proceed (non-blocking) - Add debug logging for validation message counts
…ding images section - Add `InsertImagePlaceholders` to inject `[image N]` placeholders into markdown during file2md conversion - Add `ImageIndex` property to `ImageSentinelContext` for 1-based placeholder tracking - Replace image section assembly with placeholder substitution in both batch and non-batch modes - Add `_sentinelContextsInitialized` flag to prevent clearing sentinel contexts during batch polling re-runs
… days - Update milestone management guide to reflect 15-day waiting period between beta and rc releases - Update GitHub Actions default `days-lookback` parameter from 30 to 15 days - Update promotion PR body template to reference 15-day period - Update release workflow documentation to reflect 15-day requirements for release age and last closed issue - Update release-promotion workflow comments and validation table to show 15-day minimum
…ng brace in AIFile2MdComponent - Add missing closing brace in `AIFile2MdComponent.OnBatchCompleted` after markdown assembly - Consolidate warning and error validation message handling into single loop in `AIStatefulAsyncComponentBase` - Use `AddRuntimeMessage(severity, origin, message)` instead of passing message object directly - Update debug logging to reflect combined warning/error count
…nd skip output during active batch - Move AIReturnSnapshot and batch state clearing from BeforeSolveInstance to new OnEnteringProcessingState hook - Remove metricsInitializedForRun flag in favor of state transition-based clearing - Add OnEnteringProcessingState virtual method to StatefulComponentBase called during Processing state entry - Skip SetMetricsOutput in OnSolveInstancePostSolve when batch submission is still active
… convention - Rename `WebToMdComponent` to `Web2MdComponent` and update nickname from "WebToMd" to "Web2Md" - Rename icon resource from `webtomd` to `Web2Md` - Rename `WebToMdAsync` method to `Web2MdAsync` in web2md AI tool - Update CHANGELOG.md and DEV.md references from WebToMdComponent to Web2MdComponent - Update debug logging prefix from "WebToMd" to "Web2Md"
…alongside McNeel and Ladybug forum support - Add generic `DiscourseSearch`, `DiscoursePostGet`, `DiscoursePostOpen`, `DiscoursePostDeconstruct` components - Add generic `AIDiscoursePostSummarize` and `AIDiscourseTopicSummarize` components
…ings instead of SurfaceMessagesFromReturn
…e-line format in DiscourseToolsBase - Replace verbatim multi-line JSON schema strings with single-line interpolated strings - Rename `baseUrlSchemaProperty` to `baseUrlProperty` for consistency - Simplify schema formatting while maintaining identical structure and functionality
…ng with improved logging - Add try-catch block around CallAiToolAsync to handle exceptions during batch item processing - Add null check for toolResult with warning message when tool returns null - Add error messages with batch item index when exceptions occur - Update debug logging to use "batch item" terminology instead of "index" for consistency - Add empty string outputs for failed batch items to maintain output alignment
…centralizing timeout configuration - Add `CreateBatchHttpClient()` protected helper method to `AIProvider` base class with 5-minute default timeout (300 seconds) - Refactor `OpenAIProvider`, `AnthropicProvider`, and `MistralAIProvider` to use centralized helper instead of default HttpClient - Add timeout clamping (1-600 seconds) and debug logging for batch HTTP client creation - Update CHANGELOG.md to document batch processing
…with configurable UI controls - Add `HttpTimeoutSeconds` (default 120s) and `BatchHttpTimeoutSeconds` (default 300s) global settings in ProvidersSettingsPage under "Network Settings" section - Add NumericStepper controls (1-600 seconds range) with descriptive labels and help text for both timeout types - Update `AIProvider.CreateBatchHttpClient()` to read `BatchHttpTimeoutSeconds` from provider settings instead of hardcoded 300s default
…per-file storage with ordered image slots - Replace `ImageSentinelContext` with `FileBatchContext` containing base markdown and ordered `ImageSlot` list - Rename `_sentinelContexts` to `_fileContexts` and key by representative sentinel ID (first image) instead of per-image - Add `ImageSlot` class to store per-image metadata (index, sentinel ID, mode, context, MIME type, base64)
…stead of per-provider settings
- Update `CreateBatchHttpClient()` to read `BatchHttpTimeoutSeconds` from global settings instead of provider-specific settings
- Update `CreateHttpClient()` to read `HttpTimeoutSeconds` from global settings instead of provider-specific settings
- Use `SmartHopperSettings.Instance.GetSetting("Global", ...)` for both timeout configurations
- Maintain same default values (120s for HTTP, 300s for batch
…nel tree output during active batch operations - Add debug logging throughout File2Md and file2md batch processing to track tool execution flow - Override `RestorePersistentOutputs()` in AIStatefulAsyncComponentBase to skip sentinel tree output during active batch submission - Update AIFile2MdComponent to extract image descriptions from AIInteractionToolResult instead of AIInteractionText
…ription extraction across execute and batch paths - Add `Write`/`Read` methods to serialize `_fileContexts` (base markdown + image slot metadata) so batch results survive Grasshopper file save/reload - Add `_batchContextLost` flag to prevent `GatherInput` from resetting `_fileContextsInitialized` during active batch, fixing same-session context overwrite bug - Update `OnBatchCompleted` to extract image descriptions from `AIInteractionText.Content` instead of
…s persistence after batch completion - Add `HasActiveBatchSubmission` protected property to distinguish poll cycles from new runs in derived classes - Call `SetMetricsOutput(null)` in `OnBatchCompleted` to persist aggregated metrics for `RestorePersistentOutputs` (since `OnSolveInstancePostSolve` is skipped during batch) - Update `AIMetrics.CombineWith()` to skip overwriting Provider/Model with "Unknown" or empty values during
- Add "provider: Gemini" label configuration to issue-labeler, labeler, and labels files - Remove '**/*.md' glob from documentation labeler to prevent over-labeling markdown files
…ts-toolkit/SmartHopper into feature/2.0.0-text2json
…instead of string matching
…that do not support it
…easoning support - Switch OpenAI default endpoint from /chat/completions to /responses - Add ForceChatCompletions provider setting for legacy endpoint override - Refactor OpenAI batch, encode, decode, standard, tools, and vision tests to validate both Responses and Chat Completions endpoints - Add Anthropic thinking/redacted_thinking block decoding - Add OpenRouter reasoning and reasoning_details field extraction - Standardize test message agents from Context to User across providers - Adjust batch polling timeouts to use call-specific defaults
…version - Add `ConvertToolsToResponsesFormat` method to flatten Chat Completions tool definitions into Responses API format (strict functions at root level) - Extend `OpenAIStreamingAdapter` to handle both `/v1/responses` and `/v1/chat/completions` streaming endpoints - Implement Responses API SSE event handlers: `response.output_text.delta`, `response.content.delta`, `response.refusal.delta`, `response.output_item.added`, `response.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat: SmartHopper 2.0.0 - Google Gemini Provider, Batch API, Vision Input, and Breaking Changes
Description
This PR introduces SmartHopper 2.0.0, a major release with significant new features, architectural improvements, and breaking changes. This is a large-scale refactor spanning 490 files with >45,000 insertions and 7,500 deletions.
Key Features Added
🚀 Google Gemini Provider (Full Integration)
x-goog-api-keyauthentication in centralizedCallApimethod⚡ Mixed-Type Data Tree Support
GH_Boolean,GH_String, etc.)GHStructureConverterutility for converting typed structures toIGH_GooDataTreeProcessorwithIGH_Gootype gate for branch groupingProcessingResult<T>classes for returning output trees and messagesAIText2BooleanComponentandAIList2BooleanComponentto mixed-type pipelines📊 Batch API Support (OpenAI, Anthropic, MistralAI, Gemini)
IAIBatchProviderinterface implementation across three providersBatchTierparameter inAIRequestParameters(replacesservice_tierextra)🖼️ Vision Input Support
img2textAI toolAIInteractionImagewith vision input methods andMimeTypepropertyGH_ExtractedImageGoo type for Grasshopper integrationAIImgToTextComponentfor standalone image descriptionAIFile2MdComponentwith image modes:embed,describe,caption📄 File-to-Markdown Conversion
file2mdAI tool supporting 12 formats: PDF, DOCX, XLSX, PPTX, HTML, CSV, JSON, XML, TXT, EML, EPUB, RTFFile2MdComponent(non-AI) andAIFile2MdComponent(AI-powered)🌐 Web-to-Markdown Conversion
web2mdAI tool (replacesweb_generic_page_read)⚙️ AI Settings Components
AISettingsComponent: Universal settings component for cross-provider parametersAIExtraSettingsComponent: Dynamic inputs based on provider-specific extrasAIRequestParametersimmutable record with fluent builderGH_AIRequestParametersGrasshopper wrapper with backward-compatible string casting🛠️ JSON Tools & Components
text2jsonAI tool for structured JSON generation from promptsAIText2JsonComponentfor AI-powered JSON creationJsonSchemaComponent,JsonObjectComponent,JsonArrayComponent,JsonArray2TextListComponent,JsonObject2TextComponent,JsonGetValueComponent,JsonMergeComponentJsonSchemaPropComponent,JsonSchemaPropObjectComponent,JsonSchemaPropArrayComponentBreaking Changes
There is a new "Timeout" input in the "AI Settings" component. This means that files saved in previous versions may need to reconnect inputs.
text_generatetext2texttext_evaluatetext2booleanlist_generatetext2textlistlist_evaluatetextlist2booleanimg_generatetext2imgimg_to_textimg2textweb_to_mdweb2mdweb_generic_page_readweb2md)The components listed in this table that were saved in previous files will not work with SmartHopper 2.0 or above. You will need to manually replace them with their equivalent new component.
AITextGenerateAIText2TextComponentAITextEvaluateAIText2BooleanComponentAITextListGenerateAIText2TextListComponentAIListEvaluateAIList2BooleanComponentAIImgGenerateComponentAIText2ImgComponentAIImgToTextComponentAIImg2TextComponentWebPageReadComponentWeb2MdComponent)Testing Done
Comprehensive testing plan created in docs/Reviews/260402-PR-Testing-Plan.md covering 202 test cases across 11 feature areas.
🔴 P0 - Breaking Changes (15 tests)
.ghfiles with old components -> Renamed components need to replaceWebPageReadComponentremoval doesn't crash file loadservice_tier=batchin existing files is silently ignoredAISettingsComponentworks correctly🔴 P0 - Google Gemini Provider (19 tests)
AIText2TextComponentAIText2BooleanComponentAIText2JsonComponent🔴 P0 - Mixed-Type Data Trees (17 tests)
GH_Structure<GH_String>toGH_Structure<IGH_Goo>GH_Structure<GH_Boolean>toGH_Structure<IGH_Goo>GH_Structure<GH_Integer>toGH_Structure<IGH_Goo>GH_Structure<GH_Number>toGH_Structure<IGH_Goo>groupIdenticalBrancheswithIGH_Gootype gateRunAsync<T>overload for heterogeneous outputExtractTypedTree<U>helper methodAIText2BooleanComponent- mixed-type input tree withGH_BooleanfallbackAIList2BooleanComponent- mixed-type input tree withGH_BooleanfallbackProcessingResult<IGH_Goo>.OutputsaccessExtractTypedTree<GH_String>()from heterogeneous resultsRunProcessingAsync<GH_String>with tree broadcastingItemGraftpath management consistencyComponentProcessingOptionsproperty behavior🔴 P0 - Batch API (26 tests)
/v1/files/v1/batches/v1/files/{output_file_id}/content/v1/batches/{id}/cancelrequest_counts.completedupdates progressPOST /v1/messages/batchesprocessing_statusonGET /v1/messages/batches/{id}results_urlPOST /v1/messages/batches/{id}/cancelrequest_counts.succeededupdates progressPOST /v1/batch/jobsGET /v1/batch/jobs/{id}/v1/files/{output_file}/contentPOST /v1/batch/jobs/{id}/cancelsucceeded_requestsupdates progressAITextGeneratebatch completion withOnBatchCompletedoverrideReconstructOutputTree<T>replaces sentinels correctlyCustomIdsserialization inWrite()/Read()AIInteractionErrordetection in providerDecode()methodsPreparing X/X...during data collection🟡 P1 - Vision Input (25 tests)
MimeTypeproperty is correctly setCreateVisionInput()methodCreateVisionInputFromBase64()methodAddImageInput()fluent methodAddImageInputFromBase64()fluent methoddata:{mime};base64,{data})imagecontent blocks with base64image_urlcontent blocksimageUrlparameterimageBase64+mimeTypepromptparameterAICapability.Image2Textrequirement enforcementAIImgToTextComponent- file path inputAIImgToTextComponent- URL inputAIImgToTextComponent- base64 inputAIImgToTextComponent-GH_ExtractedImageinput (regression test for MistralAI fix)AIFile2MdComponent- image modeembedAIFile2MdComponent- image modedescribeAIFile2MdComponent- image modecaptionScriptVariable()returnsBitmapGH_StringBitmap🟡 P1 - File-to-Markdown (32 tests)
RecursiveXYCutImagePartsSlidePart.ImagePartsTryGetPngFile2MdComponent- basic conversionFile2MdComponent-Imagesoutput withGH_ExtractedImageAIFile2MdComponent- AI-powered conversionAIFile2MdComponent- image modes (embed,describe,caption)AIFile2MdComponent- batch context persistence across save/reloaddescribeImagesparameterimagesarray always returned in resultimageModeparameter (embed,describe,caption)🟡 P1 - Web-to-Markdown (12 tests)
Web2MdComponent- basic URL conversionweb_generic_page_readremoval - useweb2mdinstead🟡 P1 - AI Settings Components (23 tests)
AIRequestParametersfrom inputsSettings (S)wire connects to AI componentsAIRequestParametersBuilderfluent methodsWithBatchTier()/ClearBatchTier()GH_AIRequestParametersEncode()🟡 P1 - JSON Tools (24 tests)
promptparameter (required)instructionsparameter (optional)jsonSchemaparameter (required)AICapability.TextInput | JsonOutputenforcementSmartHopper > JSONcategoryItemGraft + GroupIdenticalBranchesprocessing topologyJsonSchemaComponent- build schema from propertiesJsonSchemaComponent- nested properties via dot-notationJsonObjectComponent- create JSON from Key+Value listsJsonArrayComponent- create JSON array from itemsJsonArray2TextListComponent- parse JSON array to GH text listJsonObject2TextComponent- serialize JSON to stringJsonGetValueComponent- extract nested value by dot-notationJsonMergeComponent- merge multiple JSON objectsJsonSchemaPropComponent- scalar property definitionJsonSchemaPropObjectComponent- object property with sub-propertiesJsonSchemaPropArrayComponent- array property with items type🟢 P2 - Provider Model Updates (11 tests)
🟢 P2 - UI/UX (8 tests)
Processing batch (0/XX)...(YY/XX)...Preparing X/X...shown during data collectionMigration Guide
SmartHopper 2.0.0-alpha will automatically install from Rhino Package Manager once released.
For Breaking Changes
.ghfiles - Components might have some issues loading. Remove and replace some components the changed components with the new ones.WebPageReadComponentmust be replaced withWeb2MdComponentFor New Features
AISettingsComponentwithBatch=trueon compatible components and providersAIImgToTextComponentor use inAIFile2MdComponentAIText2JsonComponentwith schema inputsChecklist
[Unreleased]Related Issues