Compare commits
1 Commits
chore/qwen
...
chore/bett
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0a57374c2 |
2
Makefile
2
Makefile
@@ -11,7 +11,7 @@ cleanup-tests:
|
|||||||
docker compose down
|
docker compose down
|
||||||
|
|
||||||
tests: prepare-tests
|
tests: prepare-tests
|
||||||
LOCALAGI_MCPBOX_URL="http://localhost:9090" LOCALAGI_MODEL="qwen3-8b" LOCALAI_API_URL="http://localhost:8081" LOCALAGI_API_URL="http://localhost:8080" $(GOCMD) run github.com/onsi/ginkgo/v2/ginkgo --fail-fast -v -r ./...
|
LOCALAGI_MCPBOX_URL="http://localhost:9090" LOCALAGI_MODEL="gemma-3-12b-it-qat" LOCALAI_API_URL="http://localhost:8081" LOCALAGI_API_URL="http://localhost:8080" $(GOCMD) run github.com/onsi/ginkgo/v2/ginkgo --fail-fast -v -r ./...
|
||||||
|
|
||||||
run-nokb:
|
run-nokb:
|
||||||
$(MAKE) run KBDISABLEINDEX=true
|
$(MAKE) run KBDISABLEINDEX=true
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ LocalAGI supports multiple hardware configurations through Docker Compose profil
|
|||||||
- Supports text, multimodal, and image generation models
|
- Supports text, multimodal, and image generation models
|
||||||
- Run with: `docker compose -f docker-compose.nvidia.yaml up`
|
- Run with: `docker compose -f docker-compose.nvidia.yaml up`
|
||||||
- Default models:
|
- Default models:
|
||||||
- Text: `qwen3-8b`
|
- Text: `gemma-3-12b-it-qat`
|
||||||
- Multimodal: `minicpm-v-2_6`
|
- Multimodal: `minicpm-v-2_6`
|
||||||
- Image: `sd-1.5-ggml`
|
- Image: `sd-1.5-ggml`
|
||||||
- Environment variables:
|
- Environment variables:
|
||||||
@@ -136,7 +136,7 @@ LocalAGI supports multiple hardware configurations through Docker Compose profil
|
|||||||
- Supports text, multimodal, and image generation models
|
- Supports text, multimodal, and image generation models
|
||||||
- Run with: `docker compose -f docker-compose.intel.yaml up`
|
- Run with: `docker compose -f docker-compose.intel.yaml up`
|
||||||
- Default models:
|
- Default models:
|
||||||
- Text: `qwen3-8b`
|
- Text: `gemma-3-12b-it-qat`
|
||||||
- Multimodal: `minicpm-v-2_6`
|
- Multimodal: `minicpm-v-2_6`
|
||||||
- Image: `sd-1.5-ggml`
|
- Image: `sd-1.5-ggml`
|
||||||
- Environment variables:
|
- Environment variables:
|
||||||
@@ -167,7 +167,7 @@ docker compose -f docker-compose.intel.yaml up
|
|||||||
```
|
```
|
||||||
|
|
||||||
If no models are specified, it will use the defaults:
|
If no models are specified, it will use the defaults:
|
||||||
- Text model: `qwen3-8b`
|
- Text model: `gemma-3-12b-it-qat`
|
||||||
- Multimodal model: `minicpm-v-2_6`
|
- Multimodal model: `minicpm-v-2_6`
|
||||||
- Image model: `sd-1.5-ggml`
|
- Image model: `sd-1.5-ggml`
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ services:
|
|||||||
# Image list (dockerhub): https://hub.docker.com/r/localai/localai
|
# Image list (dockerhub): https://hub.docker.com/r/localai/localai
|
||||||
image: localai/localai:master-ffmpeg-core
|
image: localai/localai:master-ffmpeg-core
|
||||||
command:
|
command:
|
||||||
- ${MODEL_NAME:-qwen3-8b}
|
- ${MODEL_NAME:-gemma-3-12b-it-qat}
|
||||||
- ${MULTIMODAL_MODEL:-minicpm-v-2_6}
|
- ${MULTIMODAL_MODEL:-minicpm-v-2_6}
|
||||||
- ${IMAGE_MODEL:-sd-1.5-ggml}
|
- ${IMAGE_MODEL:-sd-1.5-ggml}
|
||||||
- granite-embedding-107m-multilingual
|
- granite-embedding-107m-multilingual
|
||||||
@@ -91,7 +91,7 @@ services:
|
|||||||
- 8080:3000
|
- 8080:3000
|
||||||
#image: quay.io/mudler/localagi:master
|
#image: quay.io/mudler/localagi:master
|
||||||
environment:
|
environment:
|
||||||
- LOCALAGI_MODEL=${MODEL_NAME:-qwen3-8b}
|
- LOCALAGI_MODEL=${MODEL_NAME:-gemma-3-12b-it-qat}
|
||||||
- LOCALAGI_MULTIMODAL_MODEL=${MULTIMODAL_MODEL:-minicpm-v-2_6}
|
- LOCALAGI_MULTIMODAL_MODEL=${MULTIMODAL_MODEL:-minicpm-v-2_6}
|
||||||
- LOCALAGI_IMAGE_MODEL=${IMAGE_MODEL:-sd-1.5-ggml}
|
- LOCALAGI_IMAGE_MODEL=${IMAGE_MODEL:-sd-1.5-ggml}
|
||||||
- LOCALAGI_LLM_API_URL=http://localai:8080
|
- LOCALAGI_LLM_API_URL=http://localai:8080
|
||||||
|
|||||||
1
main.go
1
main.go
@@ -66,7 +66,6 @@ func main() {
|
|||||||
localRAG,
|
localRAG,
|
||||||
services.Actions(map[string]string{
|
services.Actions(map[string]string{
|
||||||
"browser-agent-runner-base-url": localOperatorBaseURL,
|
"browser-agent-runner-base-url": localOperatorBaseURL,
|
||||||
"deep-research-runner-base-url": localOperatorBaseURL,
|
|
||||||
}),
|
}),
|
||||||
services.Connectors,
|
services.Connectors,
|
||||||
services.DynamicPrompts,
|
services.DynamicPrompts,
|
||||||
|
|||||||
@@ -4,146 +4,69 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Client represents a client for interacting with the LocalOperator API
|
||||||
type Client struct {
|
type Client struct {
|
||||||
baseURL string
|
baseURL string
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(baseURL string, timeout ...time.Duration) *Client {
|
// NewClient creates a new API client
|
||||||
defaultTimeout := 30 * time.Second
|
func NewClient(baseURL string) *Client {
|
||||||
if len(timeout) > 0 {
|
|
||||||
defaultTimeout = timeout[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Client{
|
return &Client{
|
||||||
baseURL: baseURL,
|
baseURL: baseURL,
|
||||||
httpClient: &http.Client{
|
httpClient: &http.Client{},
|
||||||
Timeout: defaultTimeout,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AgentRequest represents the request body for running an agent
|
||||||
type AgentRequest struct {
|
type AgentRequest struct {
|
||||||
Goal string `json:"goal"`
|
Goal string `json:"goal"`
|
||||||
MaxAttempts int `json:"max_attempts,omitempty"`
|
MaxAttempts int `json:"max_attempts,omitempty"`
|
||||||
MaxNoActionAttempts int `json:"max_no_action_attempts,omitempty"`
|
MaxNoActionAttempts int `json:"max_no_action_attempts,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DesktopAgentRequest struct {
|
// StateDescription represents a single state in the agent's history
|
||||||
AgentRequest
|
|
||||||
DesktopURL string `json:"desktop_url"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DeepResearchRequest struct {
|
|
||||||
Topic string `json:"topic"`
|
|
||||||
MaxCycles int `json:"max_cycles,omitempty"`
|
|
||||||
MaxNoActionAttempts int `json:"max_no_action_attempts,omitempty"`
|
|
||||||
MaxResults int `json:"max_results,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Response types
|
|
||||||
type StateDescription struct {
|
type StateDescription struct {
|
||||||
CurrentURL string `json:"current_url"`
|
CurrentURL string `json:"current_url"`
|
||||||
PageTitle string `json:"page_title"`
|
PageTitle string `json:"page_title"`
|
||||||
PageContentDescription string `json:"page_content_description"`
|
PageContentDescription string `json:"page_content_description"`
|
||||||
Screenshot string `json:"screenshot"`
|
Screenshot string `json:"screenshot"`
|
||||||
ScreenshotMimeType string `json:"screenshot_mime_type"`
|
ScreenshotMimeType string `json:"screenshot_mime_type"` // MIME type of the screenshot (e.g., "image/png")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StateHistory represents the complete history of states during agent execution
|
||||||
type StateHistory struct {
|
type StateHistory struct {
|
||||||
States []StateDescription `json:"states"`
|
States []StateDescription `json:"states"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DesktopStateDescription struct {
|
// RunAgent sends a request to run an agent with the given goal
|
||||||
ScreenContent string `json:"screen_content"`
|
|
||||||
ScreenshotPath string `json:"screenshot_path"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DesktopStateHistory struct {
|
|
||||||
States []DesktopStateDescription `json:"states"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type SearchResult struct {
|
|
||||||
Title string `json:"title"`
|
|
||||||
URL string `json:"url"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResearchResult struct {
|
|
||||||
Topic string `json:"topic"`
|
|
||||||
Summary string `json:"summary"`
|
|
||||||
Sources []SearchResult `json:"sources"`
|
|
||||||
KnowledgeGaps []string `json:"knowledge_gaps"`
|
|
||||||
SearchQueries []string `json:"search_queries"`
|
|
||||||
ResearchCycles int `json:"research_cycles"`
|
|
||||||
CompletionTime time.Duration `json:"completion_time"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) RunBrowserAgent(req AgentRequest) (*StateHistory, error) {
|
func (c *Client) RunBrowserAgent(req AgentRequest) (*StateHistory, error) {
|
||||||
return post[*StateHistory](c.httpClient, c.baseURL+"/api/browser/run", req)
|
body, err := json.Marshal(req)
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) RunDesktopAgent(req DesktopAgentRequest) (*DesktopStateHistory, error) {
|
|
||||||
return post[*DesktopStateHistory](c.httpClient, c.baseURL+"/api/desktop/run", req)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) RunDeepResearch(req DeepResearchRequest) (*ResearchResult, error) {
|
|
||||||
return post[*ResearchResult](c.httpClient, c.baseURL+"/api/deep-research/run", req)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) Readyz() (string, error) {
|
|
||||||
return c.get("/readyz")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) Healthz() (string, error) {
|
|
||||||
return c.get("/healthz")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) get(path string) (string, error) {
|
|
||||||
resp, err := c.httpClient.Get(c.baseURL + path)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to make request: %w", err)
|
return nil, fmt.Errorf("failed to marshal request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.httpClient.Post(
|
||||||
|
fmt.Sprintf("%s/api/browser/run", c.baseURL),
|
||||||
|
"application/json",
|
||||||
|
bytes.NewBuffer(body),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to send request: %w", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
body, _ := io.ReadAll(resp.Body)
|
return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
|
||||||
return "", fmt.Errorf("unexpected status code: %d, body: %s", resp.StatusCode, string(body))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return resp.Status, nil
|
var state StateHistory
|
||||||
}
|
if err := json.NewDecoder(resp.Body).Decode(&state); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode response: %w", err)
|
||||||
func post[T any](client *http.Client, url string, body interface{}) (T, error) {
|
}
|
||||||
var result T
|
|
||||||
jsonBody, err := json.Marshal(body)
|
return &state, nil
|
||||||
if err != nil {
|
|
||||||
return result, fmt.Errorf("failed to marshal request body: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Sending request", "url", url, "body", string(jsonBody))
|
|
||||||
|
|
||||||
resp, err := client.Post(url, "application/json", bytes.NewBuffer(jsonBody))
|
|
||||||
if err != nil {
|
|
||||||
return result, fmt.Errorf("failed to make request: %w", err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
fmt.Println("Response", "status", resp.StatusCode)
|
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
body, _ := io.ReadAll(resp.Body)
|
|
||||||
return result, fmt.Errorf("unexpected status code: %d, body: %s", resp.StatusCode, string(body))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
|
||||||
return result, fmt.Errorf("failed to decode response: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ const (
|
|||||||
ActionSearch = "search"
|
ActionSearch = "search"
|
||||||
ActionCustom = "custom"
|
ActionCustom = "custom"
|
||||||
ActionBrowserAgentRunner = "browser-agent-runner"
|
ActionBrowserAgentRunner = "browser-agent-runner"
|
||||||
ActionDeepResearchRunner = "deep-research-runner"
|
|
||||||
ActionGithubIssueLabeler = "github-issue-labeler"
|
ActionGithubIssueLabeler = "github-issue-labeler"
|
||||||
ActionGithubIssueOpener = "github-issue-opener"
|
ActionGithubIssueOpener = "github-issue-opener"
|
||||||
ActionGithubIssueCloser = "github-issue-closer"
|
ActionGithubIssueCloser = "github-issue-closer"
|
||||||
@@ -55,7 +54,6 @@ var AvailableActions = []string{
|
|||||||
ActionGithubRepositoryGet,
|
ActionGithubRepositoryGet,
|
||||||
ActionGithubGetAllContent,
|
ActionGithubGetAllContent,
|
||||||
ActionBrowserAgentRunner,
|
ActionBrowserAgentRunner,
|
||||||
ActionDeepResearchRunner,
|
|
||||||
ActionGithubRepositoryCreateOrUpdate,
|
ActionGithubRepositoryCreateOrUpdate,
|
||||||
ActionGithubIssueReader,
|
ActionGithubIssueReader,
|
||||||
ActionGithubIssueCommenter,
|
ActionGithubIssueCommenter,
|
||||||
@@ -123,8 +121,6 @@ func Action(name, agentName string, config map[string]string, pool *state.AgentP
|
|||||||
a = actions.NewGithubIssueSearch(config)
|
a = actions.NewGithubIssueSearch(config)
|
||||||
case ActionBrowserAgentRunner:
|
case ActionBrowserAgentRunner:
|
||||||
a = actions.NewBrowserAgentRunner(config, actionsConfigs["browser-agent-runner-base-url"])
|
a = actions.NewBrowserAgentRunner(config, actionsConfigs["browser-agent-runner-base-url"])
|
||||||
case ActionDeepResearchRunner:
|
|
||||||
a = actions.NewDeepResearchRunner(config, actionsConfigs["deep-research-runner-base-url"])
|
|
||||||
case ActionGithubIssueReader:
|
case ActionGithubIssueReader:
|
||||||
a = actions.NewGithubIssueReader(config)
|
a = actions.NewGithubIssueReader(config)
|
||||||
case ActionGithubPRReader:
|
case ActionGithubPRReader:
|
||||||
@@ -185,11 +181,6 @@ func ActionsConfigMeta() []config.FieldGroup {
|
|||||||
Label: "Browser Agent Runner",
|
Label: "Browser Agent Runner",
|
||||||
Fields: actions.BrowserAgentRunnerConfigMeta(),
|
Fields: actions.BrowserAgentRunnerConfigMeta(),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Name: "deep-research-runner",
|
|
||||||
Label: "Deep Research Runner",
|
|
||||||
Fields: actions.DeepResearchRunnerConfigMeta(),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Name: "generate_image",
|
Name: "generate_image",
|
||||||
Label: "Generate Image",
|
Label: "Generate Image",
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package actions
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/mudler/LocalAGI/core/types"
|
"github.com/mudler/LocalAGI/core/types"
|
||||||
"github.com/mudler/LocalAGI/pkg/config"
|
"github.com/mudler/LocalAGI/pkg/config"
|
||||||
@@ -25,7 +24,7 @@ func NewBrowserAgentRunner(config map[string]string, defaultURL string) *Browser
|
|||||||
config["baseURL"] = defaultURL
|
config["baseURL"] = defaultURL
|
||||||
}
|
}
|
||||||
|
|
||||||
client := api.NewClient(config["baseURL"], 15*time.Minute)
|
client := api.NewClient(config["baseURL"])
|
||||||
|
|
||||||
return &BrowserAgentRunner{
|
return &BrowserAgentRunner{
|
||||||
client: client,
|
client: client,
|
||||||
|
|||||||
@@ -1,130 +0,0 @@
|
|||||||
package actions
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/mudler/LocalAGI/core/types"
|
|
||||||
"github.com/mudler/LocalAGI/pkg/config"
|
|
||||||
api "github.com/mudler/LocalAGI/pkg/localoperator"
|
|
||||||
"github.com/sashabaranov/go-openai/jsonschema"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
MetadataDeepResearchResult = "deep_research_result"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DeepResearchRunner struct {
|
|
||||||
baseURL, customActionName string
|
|
||||||
client *api.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDeepResearchRunner(config map[string]string, defaultURL string) *DeepResearchRunner {
|
|
||||||
if config["baseURL"] == "" {
|
|
||||||
config["baseURL"] = defaultURL
|
|
||||||
}
|
|
||||||
|
|
||||||
client := api.NewClient(config["baseURL"], 15*time.Minute)
|
|
||||||
|
|
||||||
return &DeepResearchRunner{
|
|
||||||
client: client,
|
|
||||||
baseURL: config["baseURL"],
|
|
||||||
customActionName: config["customActionName"],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeepResearchRunner) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
|
|
||||||
result := api.DeepResearchRequest{}
|
|
||||||
err := params.Unmarshal(&result)
|
|
||||||
if err != nil {
|
|
||||||
return types.ActionResult{}, fmt.Errorf("failed to unmarshal params: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req := api.DeepResearchRequest{
|
|
||||||
Topic: result.Topic,
|
|
||||||
MaxCycles: result.MaxCycles,
|
|
||||||
MaxNoActionAttempts: result.MaxNoActionAttempts,
|
|
||||||
MaxResults: result.MaxResults,
|
|
||||||
}
|
|
||||||
|
|
||||||
researchResult, err := d.client.RunDeepResearch(req)
|
|
||||||
if err != nil {
|
|
||||||
return types.ActionResult{}, fmt.Errorf("failed to run deep research: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format the research result into a readable string
|
|
||||||
var resultStr string
|
|
||||||
|
|
||||||
resultStr += "Deep research result\n"
|
|
||||||
resultStr += fmt.Sprintf("Topic: %s\n", researchResult.Topic)
|
|
||||||
resultStr += fmt.Sprintf("Summary: %s\n", researchResult.Summary)
|
|
||||||
resultStr += fmt.Sprintf("Research Cycles: %d\n", researchResult.ResearchCycles)
|
|
||||||
resultStr += fmt.Sprintf("Completion Time: %s\n\n", researchResult.CompletionTime)
|
|
||||||
|
|
||||||
if len(researchResult.Sources) > 0 {
|
|
||||||
resultStr += "Sources:\n"
|
|
||||||
for _, source := range researchResult.Sources {
|
|
||||||
resultStr += fmt.Sprintf("- %s (%s)\n %s\n", source.Title, source.URL, source.Description)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return types.ActionResult{
|
|
||||||
Result: fmt.Sprintf("Deep research completed successfully.\n%s", resultStr),
|
|
||||||
Metadata: map[string]interface{}{MetadataDeepResearchResult: researchResult},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeepResearchRunner) Definition() types.ActionDefinition {
|
|
||||||
actionName := "run_deep_research"
|
|
||||||
if d.customActionName != "" {
|
|
||||||
actionName = d.customActionName
|
|
||||||
}
|
|
||||||
description := "Run a deep research on a specific topic, gathering information from multiple sources and providing a comprehensive summary"
|
|
||||||
return types.ActionDefinition{
|
|
||||||
Name: types.ActionDefinitionName(actionName),
|
|
||||||
Description: description,
|
|
||||||
Properties: map[string]jsonschema.Definition{
|
|
||||||
"topic": {
|
|
||||||
Type: jsonschema.String,
|
|
||||||
Description: "The topic to research",
|
|
||||||
},
|
|
||||||
"max_cycles": {
|
|
||||||
Type: jsonschema.Number,
|
|
||||||
Description: "Maximum number of research cycles to perform (optional)",
|
|
||||||
},
|
|
||||||
"max_no_action_attempts": {
|
|
||||||
Type: jsonschema.Number,
|
|
||||||
Description: "Maximum number of attempts without taking an action (optional)",
|
|
||||||
},
|
|
||||||
"max_results": {
|
|
||||||
Type: jsonschema.Number,
|
|
||||||
Description: "Maximum number of results to collect (optional)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Required: []string{"topic"},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DeepResearchRunner) Plannable() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepResearchRunnerConfigMeta returns the metadata for Deep Research Runner action configuration fields
|
|
||||||
func DeepResearchRunnerConfigMeta() []config.Field {
|
|
||||||
return []config.Field{
|
|
||||||
{
|
|
||||||
Name: "baseURL",
|
|
||||||
Label: "Base URL",
|
|
||||||
Type: config.FieldTypeText,
|
|
||||||
Required: false,
|
|
||||||
HelpText: "Base URL of the LocalOperator API",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "customActionName",
|
|
||||||
Label: "Custom Action Name",
|
|
||||||
Type: config.FieldTypeText,
|
|
||||||
HelpText: "Custom name for this action",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user