The source headers, LICENSE files, and license metadata had drifted apart. Align the entire project to MIT: - Convert every source-file header to the MIT text across all comment styles (Go, TS, TSX, JS, MJS, SQL, CSS, GraphQL, shell), including SPDX-License-Identifier tags - Set the root and cookie-banner LICENSE files to the MIT text with a "MIT License" title line - Switch the package.json license fields, Docker image label, and cookie-banner README to MIT - Update docs and the genmodels header generator accordingly - Normalize copyright lines to a single format (Copyright (c) <year(s)> Probo Inc <hello@probo.com>.): unify the hello@getprobo.com and hello@probo.inc emails to hello@probo.com and the comma-separated years to a hyphenated range Genuine third-party references are intentionally left untouched: the Lucide icon attributions (Lucide is ISC) and the trivy dependency license allowlist. Signed-off-by: Sacha Al Himdani <sacha@probo.com>
131 lines
5.2 KiB
Go
131 lines
5.2 KiB
Go
// Copyright (c) 2026 Probo Inc <hello@probo.com>.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
// SOFTWARE.
|
|
|
|
package probod
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"go.gearno.de/kit/log"
|
|
"go.opentelemetry.io/otel/trace"
|
|
"go.probo.inc/probo/pkg/cookiebanner"
|
|
"go.probo.inc/probo/pkg/thirdparty"
|
|
)
|
|
|
|
// buildTrackerAgents wires the three tracker agents from the probod
|
|
// config, each with its own LLM client and tuning: the tracker-mapping
|
|
// agent (catalog identification), the common-pattern enrichment agent
|
|
// (description research), and the third-party disambiguation agent. All
|
|
// are opt-in: when `llm.tracker-mapping.provider` is empty it returns
|
|
// zero configs (nil LLM clients) so callers run without agent fallback.
|
|
//
|
|
// The enrichment and disambiguation agents fall back to the
|
|
// tracker-mapping config when their own provider slot is empty, so a
|
|
// deployment that configures only `tracker-mapping` keeps wiring all
|
|
// three agents.
|
|
func (impl *Implm) buildTrackerAgents(
|
|
l *log.Logger,
|
|
tp trace.TracerProvider,
|
|
r prometheus.Registerer,
|
|
) (cookiebanner.TrackerMappingAgentConfig, cookiebanner.TrackerEnrichmentAgentConfig, thirdparty.DisambiguationAgentConfig, error) {
|
|
if impl.cfg.Agents.TrackerMapping.Provider == "" {
|
|
return cookiebanner.TrackerMappingAgentConfig{}, cookiebanner.TrackerEnrichmentAgentConfig{}, thirdparty.DisambiguationAgentConfig{}, nil
|
|
}
|
|
|
|
firecrawlAPIKey := impl.cfg.Agents.Tools.FirecrawlAPIKey
|
|
|
|
mappingAgentCfg, mappingClient, err := impl.resolveAgentClient(
|
|
"tracker-mapping",
|
|
impl.cfg.Agents.TrackerMapping,
|
|
l,
|
|
tp,
|
|
r,
|
|
)
|
|
if err != nil {
|
|
return cookiebanner.TrackerMappingAgentConfig{}, cookiebanner.TrackerEnrichmentAgentConfig{}, thirdparty.DisambiguationAgentConfig{}, fmt.Errorf("cannot resolve tracker mapping agent client: %w", err)
|
|
}
|
|
|
|
mappingCfg := cookiebanner.TrackerMappingAgentConfig{
|
|
LLMClient: mappingClient,
|
|
Model: mappingAgentCfg.ModelName,
|
|
FirecrawlAPIKey: firecrawlAPIKey,
|
|
ChromeAddr: impl.cfg.ChromeDPAddr,
|
|
MaxTokens: mappingAgentCfg.MaxTokens,
|
|
Temperature: mappingAgentCfg.Temperature,
|
|
Timeout: time.Duration(impl.cfg.TrackerMappingWorker.AgentTimeout) * time.Second,
|
|
MaxTurns: impl.cfg.TrackerMappingWorker.AgentMaxTurns,
|
|
}
|
|
|
|
enrichmentSlot := impl.cfg.Agents.TrackerEnrichment
|
|
if enrichmentSlot.Provider == "" {
|
|
enrichmentSlot = impl.cfg.Agents.TrackerMapping
|
|
}
|
|
|
|
enrichmentAgentCfg, enrichmentClient, err := impl.resolveAgentClient(
|
|
"tracker-enrichment",
|
|
enrichmentSlot,
|
|
l,
|
|
tp,
|
|
r,
|
|
)
|
|
if err != nil {
|
|
return cookiebanner.TrackerMappingAgentConfig{}, cookiebanner.TrackerEnrichmentAgentConfig{}, thirdparty.DisambiguationAgentConfig{}, fmt.Errorf("cannot resolve tracker enrichment agent client: %w", err)
|
|
}
|
|
|
|
enrichmentCfg := cookiebanner.TrackerEnrichmentAgentConfig{
|
|
LLMClient: enrichmentClient,
|
|
Model: enrichmentAgentCfg.ModelName,
|
|
FirecrawlAPIKey: firecrawlAPIKey,
|
|
ChromeAddr: impl.cfg.ChromeDPAddr,
|
|
MaxTokens: enrichmentAgentCfg.MaxTokens,
|
|
Temperature: enrichmentAgentCfg.Temperature,
|
|
Timeout: time.Duration(impl.cfg.CommonPatternEnrichmentWorker.AgentTimeout) * time.Second,
|
|
MaxTurns: impl.cfg.CommonPatternEnrichmentWorker.AgentMaxTurns,
|
|
}
|
|
|
|
disambiguationSlot := impl.cfg.Agents.ThirdPartyDisambiguation
|
|
if disambiguationSlot.Provider == "" {
|
|
disambiguationSlot = impl.cfg.Agents.TrackerMapping
|
|
}
|
|
|
|
disambiguationAgentCfg, disambiguationClient, err := impl.resolveAgentClient(
|
|
"third-party-disambiguation",
|
|
disambiguationSlot,
|
|
l,
|
|
tp,
|
|
r,
|
|
)
|
|
if err != nil {
|
|
return cookiebanner.TrackerMappingAgentConfig{}, cookiebanner.TrackerEnrichmentAgentConfig{}, thirdparty.DisambiguationAgentConfig{}, fmt.Errorf("cannot resolve third party disambiguation agent client: %w", err)
|
|
}
|
|
|
|
disambiguationCfg := thirdparty.DisambiguationAgentConfig{
|
|
LLMClient: disambiguationClient,
|
|
Model: disambiguationAgentCfg.ModelName,
|
|
MaxTokens: disambiguationAgentCfg.MaxTokens,
|
|
Temperature: disambiguationAgentCfg.Temperature,
|
|
Timeout: time.Duration(impl.cfg.TrackerMappingWorker.DisambiguationAgentTimeout) * time.Second,
|
|
}
|
|
|
|
return mappingCfg, enrichmentCfg, disambiguationCfg, nil
|
|
}
|