mirror of
https://github.com/DingTalk-Real-AI/dingtalk-workspace-cli.git
synced 2026-09-28 13:14:08 +08:00
- Collapse SetDynamicServers/registerDynamicServer/AppendDynamicServer into one registration core; the ServerOverride-skip now applies to all paths and AppendDynamicServer keeps its cmd-key no-overwrite guard. - Delete executor.NewWorkflowInvocation (never constructed, no gate accepts the kind) and newLegacyHiddenCommands (always returned nil). - Route the single-profile branch through the runnerResolveProfile seam, matching the multi-profile branch. - Refresh stale discovery-era comments (no wire strings changed).
150 lines
4.0 KiB
Go
150 lines
4.0 KiB
Go
// Copyright 2026 Alibaba Group
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package executor
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
|
|
apperrors "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/errors"
|
|
)
|
|
|
|
type Invocation struct {
|
|
Kind string `json:"kind"`
|
|
Stage string `json:"stage"`
|
|
Implemented bool `json:"implemented"`
|
|
DryRun bool `json:"dry_run,omitempty"`
|
|
CanonicalProduct string `json:"canonical_product"`
|
|
Tool string `json:"tool"`
|
|
CanonicalPath string `json:"canonical_path"`
|
|
LegacyPath string `json:"legacy_path,omitempty"`
|
|
Params map[string]any `json:"params"`
|
|
}
|
|
|
|
type Result struct {
|
|
Invocation Invocation `json:"invocation"`
|
|
Response map[string]any `json:"response,omitempty"`
|
|
}
|
|
|
|
type Runner interface {
|
|
Run(context.Context, Invocation) (Result, error)
|
|
}
|
|
|
|
type EchoRunner struct{}
|
|
|
|
func (EchoRunner) Run(_ context.Context, invocation Invocation) (Result, error) {
|
|
if invocation.DryRun {
|
|
return Result{
|
|
Invocation: invocation,
|
|
Response: map[string]any{
|
|
"dry_run": true,
|
|
"request": ToolCallRequest(invocation.Tool, invocation.Params),
|
|
"note": "execution skipped by --dry-run",
|
|
},
|
|
}, nil
|
|
}
|
|
return Result{Invocation: invocation}, nil
|
|
}
|
|
|
|
func NewCompatibilityInvocation(legacyPath, canonicalProduct, tool string, params map[string]any) Invocation {
|
|
if params == nil {
|
|
params = map[string]any{}
|
|
}
|
|
return Invocation{
|
|
Kind: "compat_invocation",
|
|
Stage: "compat_cli",
|
|
Implemented: false,
|
|
CanonicalProduct: canonicalProduct,
|
|
Tool: tool,
|
|
CanonicalPath: canonicalProduct + "." + tool,
|
|
LegacyPath: legacyPath,
|
|
Params: params,
|
|
}
|
|
}
|
|
|
|
func NewHelperInvocation(legacyPath, canonicalProduct, tool string, params map[string]any) Invocation {
|
|
if params == nil {
|
|
params = map[string]any{}
|
|
}
|
|
return Invocation{
|
|
Kind: "helper_invocation",
|
|
Stage: "helper_override",
|
|
Implemented: false,
|
|
CanonicalProduct: canonicalProduct,
|
|
Tool: tool,
|
|
CanonicalPath: canonicalProduct + "." + tool,
|
|
LegacyPath: legacyPath,
|
|
Params: params,
|
|
}
|
|
}
|
|
|
|
func MergePayloads(jsonPayload, paramsPayload string, overrides map[string]any) (map[string]any, error) {
|
|
merged := make(map[string]any)
|
|
|
|
for _, payload := range []struct {
|
|
label string
|
|
raw string
|
|
}{
|
|
{label: "--json", raw: jsonPayload},
|
|
{label: "--params", raw: paramsPayload},
|
|
} {
|
|
value, err := parseJSONObject(payload.label, payload.raw)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for key, raw := range value {
|
|
merged[key] = raw
|
|
}
|
|
}
|
|
|
|
for key, value := range overrides {
|
|
merged[key] = value
|
|
}
|
|
return merged, nil
|
|
}
|
|
|
|
func parseJSONObject(label, raw string) (map[string]any, error) {
|
|
if strings.TrimSpace(raw) == "" {
|
|
return map[string]any{}, nil
|
|
}
|
|
|
|
var value any
|
|
if err := json.Unmarshal([]byte(raw), &value); err != nil {
|
|
return nil, apperrors.NewValidation(fmt.Sprintf("%s must be valid JSON: %v", label, err))
|
|
}
|
|
|
|
object, ok := value.(map[string]any)
|
|
if !ok {
|
|
return nil, apperrors.NewValidation(fmt.Sprintf("%s must decode to a JSON object", label))
|
|
}
|
|
return object, nil
|
|
}
|
|
|
|
func ToolCallRequest(tool string, params map[string]any) map[string]any {
|
|
if params == nil {
|
|
params = map[string]any{}
|
|
}
|
|
return map[string]any{
|
|
"jsonrpc": "2.0",
|
|
"id": 3,
|
|
"method": "tools/call",
|
|
"params": map[string]any{
|
|
"name": tool,
|
|
"arguments": params,
|
|
},
|
|
}
|
|
}
|