Production already ships an empty pin; remove the leftover mcp_metadata candidate path so parameter resolution only uses declare/Cobra sources. Co-authored-by: Cursor <cursoragent@cursor.com>
246 lines
9.6 KiB
Go
246 lines
9.6 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 cli
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
"sync/atomic"
|
|
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/corecmd/contract"
|
|
)
|
|
|
|
// schema_agent_metadata/*.json is retired as a shipped artifact. Production
|
|
// Agent selection / safety / interface authority is leaf ContractFinal and
|
|
// ProductDecl via RegisterSchemaSourceRoot → ResolveSchemaBuild.
|
|
// InstallBuildTimeAgentMetadataJSON is a CI/local dump helper for
|
|
// cmd_schema_catalog only; it is not a production source.
|
|
|
|
// Wire provenance / metadata_source labels (#602 Catalog contract).
|
|
// Const identifiers may be renamed; the string values must not change.
|
|
const (
|
|
ProvenanceEmbeddedSkillMetadata = "embedded-skill-metadata"
|
|
ProvenanceReviewedManual = "reviewed_manual"
|
|
)
|
|
|
|
type agentMetadata struct {
|
|
Version int `json:"version"`
|
|
SourceHash string `json:"source_hash"`
|
|
SurfaceHash string `json:"surface_hash,omitempty"`
|
|
Coverage agentMetadataCoverage `json:"coverage"`
|
|
Products map[string]agentProductMetadata `json:"products"`
|
|
Domains []string `json:"domains"`
|
|
Tools map[string]agentToolMetadata `json:"tools"`
|
|
}
|
|
|
|
type agentMetadataCoverage struct {
|
|
SurfaceProducts int `json:"surface_products,omitempty"`
|
|
ProductsWithMetadata int `json:"products_with_metadata"`
|
|
SurfaceTools int `json:"surface_tools,omitempty"`
|
|
ToolsWithMetadata int `json:"tools_with_metadata"`
|
|
ToolsWithSummary int `json:"tools_with_agent_summary,omitempty"`
|
|
ToolsWithUseWhen int `json:"tools_with_use_when,omitempty"`
|
|
ToolsWithAvoidWhen int `json:"tools_with_avoid_when,omitempty"`
|
|
ToolsWithExamples int `json:"tools_with_examples,omitempty"`
|
|
ToolsWithInterfaceMode int `json:"tools_with_interface_mode,omitempty"`
|
|
UnmatchedSkillTools int `json:"unmatched_skill_tools,omitempty"`
|
|
UnreviewedSkillTools int `json:"unreviewed_skill_tools,omitempty"`
|
|
}
|
|
|
|
type agentProductMetadata struct {
|
|
AgentSummary string `json:"agent_summary,omitempty"`
|
|
AgentSummarySource string `json:"agent_summary_source,omitempty"`
|
|
UseWhen []string `json:"use_when,omitempty"`
|
|
AvoidWhen []string `json:"avoid_when,omitempty"`
|
|
SourceRefs []string `json:"source_refs,omitempty"`
|
|
FieldProvenance map[string]contract.FieldProvenance `json:"field_provenance,omitempty"`
|
|
}
|
|
|
|
type agentToolMetadata struct {
|
|
AgentSummary string `json:"agent_summary,omitempty"`
|
|
AgentSummarySource string `json:"agent_summary_source,omitempty"`
|
|
UseWhen []string `json:"use_when,omitempty"`
|
|
AvoidWhen []string `json:"avoid_when,omitempty"`
|
|
Prerequisites []string `json:"prerequisites,omitempty"`
|
|
Tips []string `json:"tips,omitempty"`
|
|
Effect string `json:"effect,omitempty"`
|
|
EffectSource string `json:"effect_source,omitempty"`
|
|
Risk string `json:"risk,omitempty"`
|
|
Confirmation string `json:"confirmation,omitempty"`
|
|
Idempotency string `json:"idempotency,omitempty"`
|
|
WorkflowRefs []string `json:"workflow_refs,omitempty"`
|
|
Examples []string `json:"examples,omitempty"`
|
|
Reviewed *bool `json:"reviewed,omitempty"`
|
|
SourceRefs []string `json:"source_refs,omitempty"`
|
|
InterfaceRef *embeddedMCPInterfaceRef `json:"interface_ref,omitempty"`
|
|
InterfaceMode string `json:"interface_mode,omitempty"`
|
|
Availability string `json:"availability,omitempty"`
|
|
InterfaceReason string `json:"interface_reason,omitempty"`
|
|
FieldProvenance map[string]contract.FieldProvenance `json:"field_provenance,omitempty"`
|
|
}
|
|
|
|
var runtimeAgentMetadataLazy struct {
|
|
once sync.Once
|
|
metadata agentMetadata
|
|
}
|
|
|
|
var runtimeAgentMetadataLazyLoadCount atomic.Uint64
|
|
|
|
var (
|
|
buildTimeAgentMetadataMu sync.Mutex
|
|
buildTimeAgentMetadataOverride *agentMetadata
|
|
)
|
|
|
|
// InstallBuildTimeAgentMetadataJSON installs generator-produced Agent metadata
|
|
// for cmd_schema_catalog CI/local dump assembly only. Production binaries never
|
|
// call this; production authority remains leaf ContractFinal / ProductDecl.
|
|
// The dump helper injects an in-memory snapshot so schema_agent_metadata/ is
|
|
// neither committed nor embedded.
|
|
func InstallBuildTimeAgentMetadataJSON(data []byte) error {
|
|
var metadata agentMetadata
|
|
if err := json.Unmarshal(data, &metadata); err != nil {
|
|
return fmt.Errorf("decode build-time Agent metadata: %w", err)
|
|
}
|
|
if metadata.Products == nil {
|
|
metadata.Products = map[string]agentProductMetadata{}
|
|
}
|
|
if metadata.Tools == nil {
|
|
metadata.Tools = map[string]agentToolMetadata{}
|
|
}
|
|
buildTimeAgentMetadataMu.Lock()
|
|
defer buildTimeAgentMetadataMu.Unlock()
|
|
copied := metadata
|
|
buildTimeAgentMetadataOverride = &copied
|
|
return nil
|
|
}
|
|
|
|
// ClearBuildTimeAgentMetadata removes a cmd_schema_catalog dump-helper injection.
|
|
func ClearBuildTimeAgentMetadata() {
|
|
buildTimeAgentMetadataMu.Lock()
|
|
defer buildTimeAgentMetadataMu.Unlock()
|
|
buildTimeAgentMetadataOverride = nil
|
|
}
|
|
|
|
// runtimeAgentMetadata returns build-time injected Agent metadata when the
|
|
// CI dump helper installed one; otherwise an empty snapshot. Shipped
|
|
// binaries no longer embed schema_agent_metadata/*.json; production Agent
|
|
// facts come from ContractFinal / ProductDecl.
|
|
func runtimeAgentMetadata() agentMetadata {
|
|
buildTimeAgentMetadataMu.Lock()
|
|
override := buildTimeAgentMetadataOverride
|
|
buildTimeAgentMetadataMu.Unlock()
|
|
if override != nil {
|
|
return *override
|
|
}
|
|
runtimeAgentMetadataLazy.once.Do(func() {
|
|
runtimeAgentMetadataLazyLoadCount.Add(1)
|
|
runtimeAgentMetadataLazy.metadata = emptyAgentMetadata()
|
|
})
|
|
return runtimeAgentMetadataLazy.metadata
|
|
}
|
|
|
|
func emptyAgentMetadata() agentMetadata {
|
|
return agentMetadata{
|
|
Products: map[string]agentProductMetadata{},
|
|
Tools: map[string]agentToolMetadata{},
|
|
}
|
|
}
|
|
|
|
func cloneFieldProvenance(source map[string]contract.FieldProvenance) map[string]contract.FieldProvenance {
|
|
if len(source) == 0 {
|
|
return nil
|
|
}
|
|
out := make(map[string]contract.FieldProvenance, len(source))
|
|
for field, provenance := range source {
|
|
provenance.Value = append(json.RawMessage(nil), provenance.Value...)
|
|
provenance.Candidates = cloneFieldCandidates(provenance.Candidates)
|
|
provenance.OverriddenCandidates = cloneFieldCandidates(provenance.OverriddenCandidates)
|
|
out[field] = provenance
|
|
}
|
|
return out
|
|
}
|
|
|
|
func cloneFieldCandidates(source []contract.FieldCandidateProvenance) []contract.FieldCandidateProvenance {
|
|
if len(source) == 0 {
|
|
return nil
|
|
}
|
|
out := make([]contract.FieldCandidateProvenance, len(source))
|
|
for index, candidate := range source {
|
|
candidate.Value = append(json.RawMessage(nil), candidate.Value...)
|
|
if candidate.Selected != nil {
|
|
value := *candidate.Selected
|
|
candidate.Selected = &value
|
|
}
|
|
out[index] = candidate
|
|
}
|
|
return out
|
|
}
|
|
|
|
// agentMetadataSummaryFromProducts publishes Catalog-level Agent coverage from
|
|
// the assembled Schema surface (ContractFinal / ProductDecl). This keeps
|
|
// runtime delivery and CI dumps hash-aligned without requiring build-time
|
|
// Agent metadata inject as a published summary source.
|
|
func agentMetadataSummaryFromProducts(products []ProductSpec) map[string]any {
|
|
productsWith := 0
|
|
toolsWith := 0
|
|
toolsWithSummary := 0
|
|
surfaceTools := 0
|
|
for _, product := range products {
|
|
if productHasPublishedAgentMetadata(product) {
|
|
productsWith++
|
|
}
|
|
for _, tool := range product.Tools {
|
|
surfaceTools++
|
|
if toolHasPublishedAgentMetadata(tool) {
|
|
toolsWith++
|
|
}
|
|
if strings.TrimSpace(tool.Selection.AgentSummary) != "" {
|
|
toolsWithSummary++
|
|
}
|
|
}
|
|
}
|
|
summary := map[string]any{
|
|
"source": ProvenanceEmbeddedSkillMetadata,
|
|
"version": 1,
|
|
"source_hash": "",
|
|
"products_with_metadata": productsWith,
|
|
"tools_with_metadata": toolsWith,
|
|
}
|
|
if len(products) > 0 {
|
|
summary["surface_products"] = len(products)
|
|
}
|
|
if surfaceTools > 0 {
|
|
summary["surface_tools"] = surfaceTools
|
|
}
|
|
if toolsWithSummary > 0 {
|
|
summary["tools_with_agent_summary"] = toolsWithSummary
|
|
}
|
|
return summary
|
|
}
|
|
|
|
func productHasPublishedAgentMetadata(product ProductSpec) bool {
|
|
return strings.TrimSpace(product.Selection.AgentSummary) != "" ||
|
|
len(product.Selection.UseWhen) > 0 ||
|
|
len(product.Selection.AvoidWhen) > 0
|
|
}
|
|
|
|
func toolHasPublishedAgentMetadata(tool ToolSpec) bool {
|
|
return strings.TrimSpace(tool.Selection.AgentSummary) != "" ||
|
|
len(tool.Selection.UseWhen) > 0 ||
|
|
len(tool.Selection.AvoidWhen) > 0 ||
|
|
len(tool.Selection.Examples) > 0
|
|
}
|