feat(agentic): add fleet platform actions and commands
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
f7cbf58470
commit
85f3a02361
8 changed files with 1624 additions and 183 deletions
183
go.sum
183
go.sum
|
|
@ -1,5 +1,3 @@
|
|||
cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
|
||||
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
|
||||
dappco.re/go/core v0.8.0-alpha.1 h1:gj7+Scv+L63Z7wMxbJYHhaRFkHJo2u4MMPuUSv/Dhtk=
|
||||
dappco.re/go/core v0.8.0-alpha.1/go.mod h1:f2/tBZ3+3IqDrg2F5F598llv0nmb/4gJVCFzM5geE4A=
|
||||
dappco.re/go/core/api v0.2.0 h1:5OcN9nawpp18Jp6dB1OwI2CBfs0Tacb0y0zqxFB6TJ0=
|
||||
|
|
@ -12,30 +10,20 @@ dappco.re/go/core/log v0.1.0 h1:pa71Vq2TD2aoEUQWFKwNcaJ3GBY8HbaNGqtE688Unyc=
|
|||
dappco.re/go/core/log v0.1.0/go.mod h1:Nkqb8gsXhZAO8VLpx7B8i1iAmohhzqA20b9Zr8VUcJs=
|
||||
dappco.re/go/core/process v0.3.0 h1:BPF9R79+8ZWe34qCIy/sZy+P4HwbaO95js2oPJL7IqM=
|
||||
dappco.re/go/core/process v0.3.0/go.mod h1:qwx8kt6x+J9gn7fu8lavuess72Ye9jPBODqDZQ9K0as=
|
||||
dappco.re/go/core/ws v0.2.4/go.mod h1:C3riJyLLcV6QhLvYlq3P/XkGTsN598qQeGBoLdoHBU4=
|
||||
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
|
||||
forge.lthn.ai/Snider/Borg v0.3.1/go.mod h1:Z7DJD0yHXsxSyM7Mjl6/g4gH1NBsIz44Bf5AFlV76Wg=
|
||||
forge.lthn.ai/core/api v0.1.5 h1:NwZrcOyBjaiz5/cn0n0tnlMUodi8Or6FHMx59C7Kv2o=
|
||||
forge.lthn.ai/core/api v0.1.5/go.mod h1:PBnaWyOVXSOGy+0x2XAPUFMYJxQ2CNhppia/D06ZPII=
|
||||
forge.lthn.ai/core/cli v0.3.7/go.mod h1:DBUppJkA9P45ZFGgI2B8VXw1rAZxamHoI/KG7fRvTNs=
|
||||
forge.lthn.ai/core/go v0.3.3 h1:kYYZ2nRYy0/Be3cyuLJspRjLqTMxpckVyhb/7Sw2gd0=
|
||||
forge.lthn.ai/core/go v0.3.3/go.mod h1:Cp4ac25pghvO2iqOu59t1GyngTKVOzKB5/VPdhRi9CQ=
|
||||
forge.lthn.ai/core/go-ai v0.1.12 h1:OHt0bUABlyhvgxZxyMwueRoh8rS3YKWGFY6++zCAwC8=
|
||||
forge.lthn.ai/core/go-ai v0.1.12/go.mod h1:5Pc9lszxgkO7Aj2Z3dtq4L9Xk9l/VNN+Baj1t///OCM=
|
||||
forge.lthn.ai/core/go-crypt v0.1.6/go.mod h1:4VZAGqxlbadhSB66sJkdj54/HSJ+bSxVgwWK5kMMYDo=
|
||||
forge.lthn.ai/core/go-i18n v0.1.7/go.mod h1:0VDjwtY99NSj2iqwrI09h5GUsJeM9s48MLkr+/Dn4G8=
|
||||
forge.lthn.ai/core/go-inference v0.1.7/go.mod h1:jfWz+IJX55wAH98+ic6FEqqGB6/P31CHlg7VY7pxREw=
|
||||
forge.lthn.ai/core/go-io v0.1.7 h1:Tdb6sqh+zz1lsGJaNX9RFWM6MJ/RhSAyxfulLXrJsbk=
|
||||
forge.lthn.ai/core/go-io v0.1.7/go.mod h1:8lRLFk4Dnp5cR/Cyzh9WclD5566TbpdRgwcH7UZLWn4=
|
||||
forge.lthn.ai/core/go-log v0.0.4 h1:KTuCEPgFmuM8KJfnyQ8vPOU1Jg654W74h8IJvfQMfv0=
|
||||
forge.lthn.ai/core/go-log v0.0.4/go.mod h1:r14MXKOD3LF/sI8XUJQhRk/SZHBE7jAFVuCfgkXoZPw=
|
||||
forge.lthn.ai/core/go-ml v0.1.0/go.mod h1:FPV9JhIUOZdLeJpX1ggC15BpmM740NPg6rycnOc5vss=
|
||||
forge.lthn.ai/core/go-mlx v0.1.0/go.mod h1:b4BJX67nx9QZiyREl2lmYIPJ+Yp5amZug3y7vXaRy/Y=
|
||||
forge.lthn.ai/core/go-process v0.2.9 h1:Wql+5TUF+lfU2oJ9I+S764MkTqJhBsuyMM0v1zsfZC4=
|
||||
forge.lthn.ai/core/go-process v0.2.9/go.mod h1:NIzZOF5IVYYCjHkcNIGcg1mZH+bzGoie4SlZUDYOKIM=
|
||||
forge.lthn.ai/core/go-rag v0.1.11 h1:KXTOtnOdrx8YKmvnj0EOi2EI/+cKjE8w2PpJCQIrSd8=
|
||||
forge.lthn.ai/core/go-rag v0.1.11/go.mod h1:vIlOKVD1SdqqjkJ2XQyXPuKPtiajz/STPLCaDpqOzk8=
|
||||
forge.lthn.ai/core/go-scm v0.2.0/go.mod h1:Q/PV2FbqDlWnAOsXAd1pgSiHOlRCPW4HcPmOt8Z9H+E=
|
||||
forge.lthn.ai/core/go-webview v0.1.6 h1:szXQxRJf2bOZJKh3v1P01B1Vf9mgXaBCXzh0EZu9aoc=
|
||||
forge.lthn.ai/core/go-webview v0.1.6/go.mod h1:5n1tECD1wBV/uFZRY9ZjfPFO5TYZrlaR3mQFwvO2nek=
|
||||
forge.lthn.ai/core/go-ws v0.2.5 h1:ZIV7Yrv01R/xpJUogA5vrfP9yB9li1w7EV3eZFMt8h0=
|
||||
|
|
@ -44,17 +32,10 @@ forge.lthn.ai/core/mcp v0.4.8 h1:nd1x3AL8AkUfl0kziltoJUX96Nx1BeFWEbgHmfrkKz8=
|
|||
forge.lthn.ai/core/mcp v0.4.8/go.mod h1:eU35WT/8Mc0oJDVWdKaXEtNp27+Hc8KvnTKPf4DAqXE=
|
||||
github.com/99designs/gqlgen v0.17.88 h1:neMQDgehMwT1vYIOx/w5ZYPUU/iMNAJzRO44I5Intoc=
|
||||
github.com/99designs/gqlgen v0.17.88/go.mod h1:qeqYFEgOeSKqWedOjogPizimp2iu4E23bdPvl4jTYic=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0=
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/ProtonMail/go-crypto v1.4.0/go.mod h1:e1OaTyu5SYVrO9gKOEhTc+5UcXtTUa+P3uLudwcgPqo=
|
||||
github.com/PuerkitoBio/goquery v1.11.0 h1:jZ7pwMQXIITcUXNH83LLk+txlaEy6NVOfTuP43xxfqw=
|
||||
github.com/PuerkitoBio/goquery v1.11.0/go.mod h1:wQHgxUOU3JGuj3oD/QFfxUdlzW6xPHfqyHre6VMY4DQ=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/TheTitanrain/w32 v0.0.0-20180517000239-4f5cfb03fabf/go.mod h1:peYoMncQljjNS6tZwI9WVyQB3qZS6u79/N3mBOcnd3I=
|
||||
github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM=
|
||||
github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
|
||||
|
|
@ -63,31 +44,13 @@ github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwTo
|
|||
github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
|
||||
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
|
||||
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
|
||||
github.com/antonlindstrom/pgstore v0.0.0-20220421113606-e3a6e3fed12a/go.mod h1:Sdr/tmSOLEnncCuXS5TwZRxuk7deH1WXVY8cve3eVBM=
|
||||
github.com/apache/arrow-go/v18 v18.5.2/go.mod h1:yNoizNTT4peTciJ7V01d2EgOkE1d0fQ1vZcFOsVtFsw=
|
||||
github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40/go.mod h1:Q7yQnSMnLvcXlZ8RV+jwz/6y1rQTqbX6C82SndT52Zs=
|
||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
|
||||
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.4/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.7/go.mod h1:lyw7GFp3qENLh7kwzf7iMzAxDn+NzjXEAGjKS2UOKqI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20/go.mod h1:oydPDJKcfMhgfcgBUZaG+toBbwy8yPWubJXBVERtI4o=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20/go.mod h1:YJ898MhD067hSHA6xYCx5ts/jEd8BSOLtQDL3iZsvbc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.21/go.mod h1:UUxgWxofmOdAMuqEsSppbDtGKLfR04HGsD0HXzvhI1k=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.12/go.mod h1:v2pNpJbRNl4vEUWEh5ytQok0zACAKfdmKS51Hotc3pQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.20/go.mod h1:V4X406Y666khGa8ghKmphma/7C0DAtEQYhkq9z4vpbk=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.20/go.mod h1:4TLZCmVJDM3FOu5P5TJP0zOlu9zWgDWU7aUxWbr+rcw=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.97.1/go.mod h1:qXVal5H0ChqXP63t6jze5LmFalc7+ZE7wOdLtZ0LCP0=
|
||||
github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
||||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs=
|
||||
github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
|
||||
github.com/boj/redistore v1.4.1/go.mod h1:c0Tvw6aMjslog4jHIAcNv6EtJM849YoOAhMY7JBbWpI=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c=
|
||||
github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20240916143655-c0e34fd2f304/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
|
|
@ -105,36 +68,12 @@ github.com/casbin/casbin/v2 v2.135.0/go.mod h1:FmcfntdXLTcYXv/hxgNntcRPqAbwOG9xs
|
|||
github.com/casbin/govaluate v1.3.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
|
||||
github.com/casbin/govaluate v1.10.0 h1:ffGw51/hYH3w3rZcxO/KcaUIDOLP84w7nsidMVgaDG0=
|
||||
github.com/casbin/govaluate v1.10.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
|
||||
github.com/charmbracelet/colorprofile v0.4.3/go.mod h1:/zT4BhpD5aGFpqQQqw7a+VtHCzu+zrQtt1zhMt9mR4Q=
|
||||
github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834/go.mod h1:aKC/t2arECF6rNOnaKaVU6y4t4ZeHQzqfxedE/VkVhA=
|
||||
github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.15/go.mod h1:J1YVbR7MUuEGIFPCaaZ96KDl5NoS0DAWkskup+mOY+Q=
|
||||
github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/chewxy/hm v1.0.0/go.mod h1:qg9YI4q6Fkj/whwHR1D+bOGeF7SniIP40VweVepLjg0=
|
||||
github.com/chewxy/math32 v1.11.0/go.mod h1:dOB2rcuFrCn6UHrze36WSLVPKtzPMRAQvBvUwkSsLqs=
|
||||
github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0=
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
|
||||
github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
|
||||
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
||||
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI=
|
||||
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
||||
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
|
||||
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
|
||||
github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc=
|
||||
github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8=
|
||||
github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
|
||||
github.com/d4l3k/go-bfloat16 v0.0.0-20211005043715-690c3bdd05f1/go.mod h1:uw2gLcxEuYUlAd/EXyjc/v55nd3+47YAgWbSXVxPrNI=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
|
|
@ -143,20 +82,6 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r
|
|||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54 h1:SG7nF6SRlWhcT7cNTs5R6Hk4V2lcmLz2NsG2VnInyNo=
|
||||
github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=
|
||||
github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98=
|
||||
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/gin-contrib/authz v1.0.6 h1:qAO4sSSzOPCwYRZI6YtubC+h2tZVwhwSJeyEZn2W+5k=
|
||||
|
|
@ -187,7 +112,6 @@ github.com/gin-contrib/timeout v1.1.0 h1:WAmWseo5gfBUbMrMJu5hJxDclehfSJUmK2wGwCC
|
|||
github.com/gin-contrib/timeout v1.1.0/go.mod h1:NpRo4gd1Ad8ZQ4T6bQLVFDqiplCmPRs2nvfckxS2Fw4=
|
||||
github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8=
|
||||
github.com/gin-gonic/gin v1.12.0/go.mod h1:VxccKfsSllpKshkBWgVgRniFFAzFb9csfngsqANjnLc=
|
||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
|
||||
github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
|
|
@ -195,7 +119,6 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
|||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||
github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA=
|
||||
github.com/go-openapi/jsonpointer v0.22.5/go.mod h1:gyUR3sCvGSWchA2sUBJGluYMbe1zazrYWIkWPjjMUY0=
|
||||
github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe+pJyVWRdiE=
|
||||
|
|
@ -203,7 +126,6 @@ github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZL
|
|||
github.com/go-openapi/spec v0.22.4 h1:4pxGjipMKu0FzFiu/DPwN3CTBRlVM2yLf/YTWorYfDQ=
|
||||
github.com/go-openapi/spec v0.22.4/go.mod h1:WQ6Ai0VPWMZgMT4XySjlRIE6GP1bGQOtEThn3gcWLtQ=
|
||||
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
|
||||
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+tGu97g=
|
||||
github.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k=
|
||||
github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo=
|
||||
|
|
@ -238,17 +160,12 @@ github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU=
|
|||
github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
|
||||
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/gomodule/redigo v1.9.2/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw=
|
||||
github.com/google/flatbuffers v25.12.19+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
|
|
@ -268,50 +185,20 @@ github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aN
|
|||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jordanlewis/gcassert v0.0.0-20250430164644-389ef753e22e/go.mod h1:ZybsQk6DWyN5t7An1MuPm1gtSZ1xDaTXS9ZjIOxvQrk=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b/go.mod h1:g2nVr8KZVXJSS97Jo8pJ0jgq29P6H7dG0oplUA86MQw=
|
||||
github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/laziness-coders/mongostore v0.0.14/go.mod h1:Rh+yJax2Vxc2QY62clIM/kRnLk+TxivgSLHOXENXPtk=
|
||||
github.com/ledongthuc/pdf v0.0.0-20250511090121-5959a4027728/go.mod h1:1fEHWurg7pvf5SG6XNE5Q8UZmOwex51Mkx3SLhrW5B4=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/logrusorgru/aurora/v4 v4.0.0/go.mod h1:lP0iIa2nrnT/qoFXcOZSrZQpJ1o6n2CUf/hyHi2Q4ZQ=
|
||||
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
|
||||
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mailru/easyjson v0.9.2 h1:dX8U45hQsZpxd80nLvDGihsQ/OxlvTkVUXH2r/8cb2M=
|
||||
github.com/mailru/easyjson v0.9.2/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||
github.com/marcboeker/go-duckdb v1.8.5/go.mod h1:6mK7+WQE4P4u5AFLvVBmhFxY5fvhymFptghgJX6B+/8=
|
||||
github.com/matryer/moq v0.6.0/go.mod h1:iEVhY/XBwFG/nbRyEf0oV+SqnTHZJ5wectzx7yT+y98=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||
github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc=
|
||||
github.com/mattn/go-runewidth v0.0.21/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
|
||||
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/memcachier/mc v2.0.1+incompatible/go.mod h1:7bkvFE61leUBvXz+yxsOnGBQSZpBSPIMUQSmmSHvuXc=
|
||||
github.com/memcachier/mc/v3 v3.0.3/go.mod h1:GzjocBahcXPxt2cmqzknrgqCOmMxiSzhVKPOe90Tpug=
|
||||
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||
github.com/moby/go-archive v0.2.0/go.mod h1:mNeivT14o8xU+5q1YnNrkQVpK+dnNe/K6fHqnTg4qPU=
|
||||
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
|
||||
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
|
||||
github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
|
||||
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
|
||||
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
|
||||
github.com/modelcontextprotocol/go-sdk v1.4.1 h1:M4x9GyIPj+HoIlHNGpK2hq5o3BFhC+78PkEaldQRphc=
|
||||
github.com/modelcontextprotocol/go-sdk v1.4.1/go.mod h1:Bo/mS87hPQqHSRkMv4dQq1XCu6zv4INdXnFZabkNU6s=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
|
|
@ -319,60 +206,31 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
|
|||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||
github.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw=
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
||||
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
||||
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/nlpodyssey/gopickle v0.3.0/go.mod h1:f070HJ/yR+eLi5WmM1OXJEGaTpuJEUiib19olXgYha0=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/ollama/ollama v0.18.2 h1:RsOY8oZ6TufRiPgsSlKJp4/V/X+oBREscUlEHZfd554=
|
||||
github.com/ollama/ollama v0.18.2/go.mod h1:tCX4IMV8DHjl3zY0THxuEkpWDZSOchJpzTuLACpMwFw=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
|
||||
github.com/parquet-go/bitpack v1.0.0/go.mod h1:XnVk9TH+O40eOOmvpAVZ7K2ocQFrQwysLMnc6M/8lgs=
|
||||
github.com/parquet-go/jsonlite v1.4.0/go.mod h1:nDjpkpL4EOtqs6NQugUsi0Rleq9sW/OtC1NnZEnxzF0=
|
||||
github.com/parquet-go/parquet-go v0.29.0/go.mod h1:navtkAYr2LGoJVp141oXPlO/sxLvaOe3la2JEoD8+rg=
|
||||
github.com/pdevine/tensor v0.0.0-20240510204454-f88f4562727c/go.mod h1:PSojXDXF7TbgQiD6kkd98IHOS0QqTyUEaWRiS8+BLu8=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/pierrec/lz4/v4 v4.1.26/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/qdrant/go-client v1.17.1 h1:7QmPwDddrHL3hC4NfycwtQlraVKRLcRi++BX6TTm+3g=
|
||||
github.com/qdrant/go-client v1.17.1/go.mod h1:n1h6GhkdAzcohoXt/5Z19I2yxbCkMA6Jejob3S6NZT8=
|
||||
github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg=
|
||||
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
|
||||
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
|
||||
github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=
|
||||
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
|
||||
github.com/redis/go-redis/v9 v9.18.0 h1:pMkxYPkEbMPwRdenAzUNyFNrDgHx9U+DrBabWNfSRQs=
|
||||
github.com/redis/go-redis/v9 v9.18.0/go.mod h1:k3ufPphLU5YXwNTUcCRXGxUoF1fqxnhFQmscfkCoDA0=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
|
||||
github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
||||
github.com/segmentio/encoding v0.5.4 h1:OW1VRern8Nw6ITAtwSZ7Idrl3MXCFwXHPgqESYfvNt0=
|
||||
github.com/segmentio/encoding v0.5.4/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0=
|
||||
github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw=
|
||||
github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/shirou/gopsutil/v4 v4.26.1/go.mod h1:medLI9/UNAb0dOI9Q3/7yWSqKkj00u+1tgY8nvv41pc=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
|
||||
github.com/sosodev/duration v1.4.0 h1:35ed0KiVFriGHHzZZJaZLgmTEEICIyt8Sx0RQfj9IjE=
|
||||
github.com/sosodev/duration v1.4.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
|
||||
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
|
||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
|
|
@ -390,54 +248,31 @@ github.com/swaggo/gin-swagger v1.6.1 h1:Ri06G4gc9N4t4k8hekMigJ9zKTFSlqj/9paAQCQs
|
|||
github.com/swaggo/gin-swagger v1.6.1/go.mod h1:LQ+hJStHakCWRiK/YNYtJOu4mR2FP+pxLnILT/qNiTw=
|
||||
github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI=
|
||||
github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg=
|
||||
github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY=
|
||||
github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=
|
||||
github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=
|
||||
github.com/tkrajina/go-reflector v0.5.5/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
|
||||
github.com/tkrajina/typescriptify-golang-structs v0.2.0/go.mod h1:sjU00nti/PMEOZb07KljFlR+lJ+RotsC0GBQMv9EKls=
|
||||
github.com/tree-sitter/go-tree-sitter v0.25.0/go.mod h1:r77ig7BikoZhHrrsjAnv8RqGti5rtSyvDHPzgTPsUuU=
|
||||
github.com/tree-sitter/tree-sitter-cpp v0.23.4/go.mod h1:doqNW64BriC7WBCQ1klf0KmJpdEvfxyXtoEybnBo6v8=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/twpayne/go-geom v1.6.1/go.mod h1:Kr+Nly6BswFsKM5sd31YaoWS5PeDDH2NftJTK7Gd028=
|
||||
github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
|
||||
github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/urfave/cli/v3 v3.7.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso=
|
||||
github.com/vektah/gqlparser/v2 v2.5.32 h1:k9QPJd4sEDTL+qB4ncPLflqTJ3MmjB9SrVzJrawpFSc=
|
||||
github.com/vektah/gqlparser/v2 v2.5.32/go.mod h1:c1I28gSOVNzlfc4WuDlqU7voQnsqI6OG2amkBAFmgts=
|
||||
github.com/wader/gormstore/v2 v2.0.3/go.mod h1:sr3N3a8F1+PBc3fHoKaphFqDXLRJ9Oe6Yow0HxKFbbg=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8=
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||
github.com/xtgo/set v1.0.0/go.mod h1:d3NHzGzSa0NmB2NhFyECA+QdRp29oEn2xbT+TpeFoM8=
|
||||
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs=
|
||||
github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s=
|
||||
go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE=
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.39.0/go.mod h1:t/OGqzHBa5v6RHZwrDBJ2OirWc+4q/w2fTbLZwAKjTk=
|
||||
go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.67.0 h1:E7DmskpIO7ZR6QI6zKSEKIDNUYoKw9oHXP23gzbCdU0=
|
||||
go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.67.0/go.mod h1:WB2cS9y+AwqqKhoo9gw6/ZxlSjFBUQGZ8BQOaD3FVXM=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0=
|
||||
go.opentelemetry.io/contrib/propagators/b3 v1.42.0 h1:B2Pew5ufEtgkjLF+tSkXjgYZXQr9m7aCm1wLKB0URbU=
|
||||
go.opentelemetry.io/contrib/propagators/b3 v1.42.0/go.mod h1:iPgUcSEF5DORW6+yNbdw/YevUy+QqJ508ncjhrRSCjc=
|
||||
go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho=
|
||||
go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0/go.mod h1:khvBS2IggMFNwZK/6lEeHg/W57h/IX6J4URh57fuI40=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0 h1:s/1iRkCKDfhlh1JF26knRneorus8aOwVIDhvYx9WoDw=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0/go.mod h1:UI3wi0FXg1Pofb8ZBiBLhtMzgoTm1TYkMvn71fAqDzs=
|
||||
go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4=
|
||||
|
|
@ -456,15 +291,12 @@ go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
|||
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
go4.org/unsafe/assume-no-moving-gc v0.0.0-20231121144256-b99613f794b6/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
|
||||
golang.org/x/arch v0.25.0 h1:qnk6Ksugpi5Bz32947rkUgDt9/s5qvqDPl/gBKdMJLE=
|
||||
golang.org/x/arch v0.25.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
||||
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
||||
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ=
|
||||
golang.org/x/image v0.22.0/go.mod h1:9hPFhljd4zZ1GNSIZJ49sqbp45GKK9t6w+iXvGqZUz4=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
|
||||
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
|
||||
|
|
@ -490,7 +322,6 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/telemetry v0.0.0-20260312161427-1546bf4b83fe/go.mod h1:TpUTTEp9frx7rTdLpC9gFG9kdI7zVLFTFFlqaH2Cncw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
|
|
@ -502,7 +333,6 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
||||
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
|
|
@ -510,10 +340,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
|
||||
golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
|
||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260319201613-d00831a3d3e7 h1:ndE4FoJqsIceKP2oYSnUZqhTdYufCYYkqwtFzfrhI7w=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
|
||||
|
|
@ -523,17 +351,6 @@ google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j
|
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorgonia.org/vecf32 v0.9.0/go.mod h1:NCc+5D2oxddRL11hd+pCB1PEyXWOyiQxfZ/1wwhOXCA=
|
||||
gorgonia.org/vecf64 v0.9.0/go.mod h1:hp7IOWCnRiVQKON73kkC/AUMtEXyf9kGlVrtPQ9ccVA=
|
||||
gorm.io/driver/sqlite v1.5.7/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=
|
||||
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||
modernc.org/libc v1.70.0/go.mod h1:OVmxFGP1CI/Z4L3E0Q3Mf1PDE0BucwMkcXjjLntvHJo=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
|
||||
modernc.org/sqlite v1.47.0/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||
|
|
|
|||
500
pkg/agentic/commands_platform.go
Normal file
500
pkg/agentic/commands_platform.go
Normal file
|
|
@ -0,0 +1,500 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
package agentic
|
||||
|
||||
import (
|
||||
core "dappco.re/go/core"
|
||||
)
|
||||
|
||||
func (s *PrepSubsystem) registerPlatformCommands() {
|
||||
c := s.Core()
|
||||
c.Command("sync/push", core.Command{Description: "Push completed dispatch state to the platform API", Action: s.cmdSyncPush})
|
||||
c.Command("sync/pull", core.Command{Description: "Pull shared fleet context from the platform API", Action: s.cmdSyncPull})
|
||||
c.Command("sync/status", core.Command{Description: "Show platform sync status for the current or named agent", Action: s.cmdSyncStatus})
|
||||
|
||||
c.Command("fleet/register", core.Command{Description: "Register a fleet node with the platform API", Action: s.cmdFleetRegister})
|
||||
c.Command("fleet/heartbeat", core.Command{Description: "Send a heartbeat for a registered fleet node", Action: s.cmdFleetHeartbeat})
|
||||
c.Command("fleet/deregister", core.Command{Description: "Deregister a fleet node from the platform API", Action: s.cmdFleetDeregister})
|
||||
c.Command("fleet/nodes", core.Command{Description: "List registered fleet nodes", Action: s.cmdFleetNodes})
|
||||
c.Command("fleet/task/assign", core.Command{Description: "Assign a task to a fleet node", Action: s.cmdFleetTaskAssign})
|
||||
c.Command("fleet/task/complete", core.Command{Description: "Complete a fleet task and report findings", Action: s.cmdFleetTaskComplete})
|
||||
c.Command("fleet/task/next", core.Command{Description: "Ask the platform for the next fleet task", Action: s.cmdFleetTaskNext})
|
||||
c.Command("fleet/stats", core.Command{Description: "Show fleet activity statistics", Action: s.cmdFleetStats})
|
||||
|
||||
c.Command("credits/award", core.Command{Description: "Award credits to a fleet node", Action: s.cmdCreditsAward})
|
||||
c.Command("credits/balance", core.Command{Description: "Show credit balance for a fleet node", Action: s.cmdCreditsBalance})
|
||||
c.Command("credits/history", core.Command{Description: "Show credit history for a fleet node", Action: s.cmdCreditsHistory})
|
||||
|
||||
c.Command("subscription/detect", core.Command{Description: "Detect available provider capabilities", Action: s.cmdSubscriptionDetect})
|
||||
c.Command("subscription/budget", core.Command{Description: "Show compute budget for a fleet node", Action: s.cmdSubscriptionBudget})
|
||||
c.Command("subscription/update-budget", core.Command{Description: "Update compute budget for a fleet node", Action: s.cmdSubscriptionUpdateBudget})
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdSyncPush(options core.Options) core.Result {
|
||||
result := s.handleSyncPush(s.commandContext(), options)
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdSyncPush", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
output, ok := result.Value.(SyncPushOutput)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdSyncPush", "invalid sync push output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
core.Print(nil, "synced: %d", output.Count)
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdSyncPull(options core.Options) core.Result {
|
||||
result := s.handleSyncPull(s.commandContext(), options)
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdSyncPull", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
output, ok := result.Value.(SyncPullOutput)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdSyncPull", "invalid sync pull output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
core.Print(nil, "context items: %d", output.Count)
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdSyncStatus(options core.Options) core.Result {
|
||||
result := s.handleSyncStatus(s.commandContext(), options)
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdSyncStatus", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
output, ok := result.Value.(SyncStatusOutput)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdSyncStatus", "invalid sync status output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
core.Print(nil, "agent: %s", output.AgentID)
|
||||
core.Print(nil, "status: %s", output.Status)
|
||||
core.Print(nil, "queued: %d", output.Queued)
|
||||
core.Print(nil, "context items: %d", output.ContextCount)
|
||||
if output.LastPushAt != "" {
|
||||
core.Print(nil, "last push: %s", output.LastPushAt)
|
||||
}
|
||||
if output.LastPullAt != "" {
|
||||
core.Print(nil, "last pull: %s", output.LastPullAt)
|
||||
}
|
||||
if output.RemoteError != "" {
|
||||
core.Print(nil, "remote error: %s", output.RemoteError)
|
||||
}
|
||||
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdFleetRegister(options core.Options) core.Result {
|
||||
if optionStringValue(options, "agent_id", "agent-id", "_arg") == "" {
|
||||
core.Print(nil, "usage: core-agent fleet register <agent-id> --platform=linux [--models=codex,gpt-5.4] [--capabilities=go,review]")
|
||||
return core.Result{Value: core.E("agentic.cmdFleetRegister", "agent_id is required", nil), OK: false}
|
||||
}
|
||||
|
||||
result := s.handleFleetRegister(s.commandContext(), normalisePlatformCommandOptions(options))
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdFleetRegister", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
node, ok := result.Value.(FleetNode)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdFleetRegister", "invalid fleet register output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
core.Print(nil, "registered: %s", node.AgentID)
|
||||
core.Print(nil, "status: %s", node.Status)
|
||||
core.Print(nil, "platform: %s", node.Platform)
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdFleetHeartbeat(options core.Options) core.Result {
|
||||
if optionStringValue(options, "agent_id", "agent-id", "_arg") == "" || optionStringValue(options, "status") == "" {
|
||||
core.Print(nil, "usage: core-agent fleet heartbeat <agent-id> --status=online [--compute-budget='{\"max_daily_hours\":2}']")
|
||||
return core.Result{Value: core.E("agentic.cmdFleetHeartbeat", "agent_id and status are required", nil), OK: false}
|
||||
}
|
||||
|
||||
result := s.handleFleetHeartbeat(s.commandContext(), normalisePlatformCommandOptions(options))
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdFleetHeartbeat", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
node, ok := result.Value.(FleetNode)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdFleetHeartbeat", "invalid fleet heartbeat output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
core.Print(nil, "heartbeat: %s", node.AgentID)
|
||||
core.Print(nil, "status: %s", node.Status)
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdFleetDeregister(options core.Options) core.Result {
|
||||
if optionStringValue(options, "agent_id", "agent-id", "_arg") == "" {
|
||||
core.Print(nil, "usage: core-agent fleet deregister <agent-id>")
|
||||
return core.Result{Value: core.E("agentic.cmdFleetDeregister", "agent_id is required", nil), OK: false}
|
||||
}
|
||||
|
||||
result := s.handleFleetDeregister(s.commandContext(), normalisePlatformCommandOptions(options))
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdFleetDeregister", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
data, ok := result.Value.(map[string]any)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdFleetDeregister", "invalid fleet deregister output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
core.Print(nil, "deregistered: %s", stringValue(data["agent_id"]))
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdFleetNodes(options core.Options) core.Result {
|
||||
result := s.handleFleetNodes(s.commandContext(), options)
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdFleetNodes", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
output, ok := result.Value.(FleetNodesOutput)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdFleetNodes", "invalid fleet nodes output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
if len(output.Nodes) == 0 {
|
||||
core.Print(nil, "no fleet nodes")
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
for _, node := range output.Nodes {
|
||||
core.Print(nil, " %-10s %-8s %-10s %s", node.Status, node.Platform, node.AgentID, core.Join(",", node.Models...))
|
||||
}
|
||||
core.Print(nil, "")
|
||||
core.Print(nil, "total: %d", output.Total)
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdFleetTaskAssign(options core.Options) core.Result {
|
||||
agentID := optionStringValue(options, "agent_id", "agent-id", "_arg")
|
||||
if agentID == "" || optionStringValue(options, "repo") == "" || optionStringValue(options, "task") == "" {
|
||||
core.Print(nil, "usage: core-agent fleet task assign <agent-id> --repo=core/go-io --task=\"...\" [--branch=dev] [--template=coding] [--agent-model=codex:gpt-5.4]")
|
||||
return core.Result{Value: core.E("agentic.cmdFleetTaskAssign", "agent_id, repo, and task are required", nil), OK: false}
|
||||
}
|
||||
|
||||
result := s.handleFleetAssignTask(s.commandContext(), normalisePlatformCommandOptions(options))
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdFleetTaskAssign", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
task, ok := result.Value.(FleetTask)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdFleetTaskAssign", "invalid fleet task output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
printFleetTask(task)
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdFleetTaskComplete(options core.Options) core.Result {
|
||||
agentID := optionStringValue(options, "agent_id", "agent-id", "_arg")
|
||||
taskID := optionIntValue(options, "task_id", "task-id")
|
||||
if agentID == "" || taskID == 0 {
|
||||
core.Print(nil, "usage: core-agent fleet task complete <agent-id> --task-id=N [--result='{\"status\":\"completed\"}'] [--findings='[{\"file\":\"x.go\"}]']")
|
||||
return core.Result{Value: core.E("agentic.cmdFleetTaskComplete", "agent_id and task_id are required", nil), OK: false}
|
||||
}
|
||||
|
||||
result := s.handleFleetCompleteTask(s.commandContext(), normalisePlatformCommandOptions(options))
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdFleetTaskComplete", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
task, ok := result.Value.(FleetTask)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdFleetTaskComplete", "invalid fleet task output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
printFleetTask(task)
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdFleetTaskNext(options core.Options) core.Result {
|
||||
if optionStringValue(options, "agent_id", "agent-id", "_arg") == "" {
|
||||
core.Print(nil, "usage: core-agent fleet task next <agent-id> [--capabilities=go,review]")
|
||||
return core.Result{Value: core.E("agentic.cmdFleetTaskNext", "agent_id is required", nil), OK: false}
|
||||
}
|
||||
|
||||
result := s.handleFleetNextTask(s.commandContext(), normalisePlatformCommandOptions(options))
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdFleetTaskNext", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
task, ok := result.Value.(*FleetTask)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdFleetTaskNext", "invalid fleet next-task output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
if task == nil {
|
||||
core.Print(nil, "no task available")
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
printFleetTask(*task)
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdFleetStats(options core.Options) core.Result {
|
||||
result := s.handleFleetStats(s.commandContext(), options)
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdFleetStats", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
stats, ok := result.Value.(FleetStats)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdFleetStats", "invalid fleet stats output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
core.Print(nil, "nodes online: %d", stats.NodesOnline)
|
||||
core.Print(nil, "tasks today: %d", stats.TasksToday)
|
||||
core.Print(nil, "tasks week: %d", stats.TasksWeek)
|
||||
core.Print(nil, "repos touched: %d", stats.ReposTouched)
|
||||
core.Print(nil, "findings total: %d", stats.FindingsTotal)
|
||||
core.Print(nil, "compute hours: %d", stats.ComputeHours)
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdCreditsAward(options core.Options) core.Result {
|
||||
agentID := optionStringValue(options, "agent_id", "agent-id", "_arg")
|
||||
taskType := optionStringValue(options, "task_type", "task-type")
|
||||
amount := optionIntValue(options, "amount")
|
||||
if agentID == "" || taskType == "" || amount == 0 {
|
||||
core.Print(nil, "usage: core-agent credits award <agent-id> --task-type=fleet-task --amount=2 [--description=\"...\"]")
|
||||
return core.Result{Value: core.E("agentic.cmdCreditsAward", "agent_id, task_type, and amount are required", nil), OK: false}
|
||||
}
|
||||
|
||||
result := s.handleCreditsAward(s.commandContext(), normalisePlatformCommandOptions(options))
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdCreditsAward", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
entry, ok := result.Value.(CreditEntry)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdCreditsAward", "invalid credit award output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
core.Print(nil, "entry: %d", entry.ID)
|
||||
core.Print(nil, "task type: %s", entry.TaskType)
|
||||
core.Print(nil, "amount: %d", entry.Amount)
|
||||
core.Print(nil, "balance after: %d", entry.BalanceAfter)
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdCreditsBalance(options core.Options) core.Result {
|
||||
if optionStringValue(options, "agent_id", "agent-id", "_arg") == "" {
|
||||
core.Print(nil, "usage: core-agent credits balance <agent-id>")
|
||||
return core.Result{Value: core.E("agentic.cmdCreditsBalance", "agent_id is required", nil), OK: false}
|
||||
}
|
||||
|
||||
result := s.handleCreditsBalance(s.commandContext(), normalisePlatformCommandOptions(options))
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdCreditsBalance", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
balance, ok := result.Value.(CreditBalance)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdCreditsBalance", "invalid credit balance output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
core.Print(nil, "agent: %s", balance.AgentID)
|
||||
core.Print(nil, "balance: %d", balance.Balance)
|
||||
core.Print(nil, "entries: %d", balance.Entries)
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdCreditsHistory(options core.Options) core.Result {
|
||||
if optionStringValue(options, "agent_id", "agent-id", "_arg") == "" {
|
||||
core.Print(nil, "usage: core-agent credits history <agent-id> [--limit=50]")
|
||||
return core.Result{Value: core.E("agentic.cmdCreditsHistory", "agent_id is required", nil), OK: false}
|
||||
}
|
||||
|
||||
result := s.handleCreditsHistory(s.commandContext(), normalisePlatformCommandOptions(options))
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdCreditsHistory", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
output, ok := result.Value.(CreditsHistoryOutput)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdCreditsHistory", "invalid credit history output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
if len(output.Entries) == 0 {
|
||||
core.Print(nil, "no credit entries")
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
for _, entry := range output.Entries {
|
||||
core.Print(nil, " #%-4d %-12s %+d balance=%d", entry.ID, entry.TaskType, entry.Amount, entry.BalanceAfter)
|
||||
}
|
||||
core.Print(nil, "")
|
||||
core.Print(nil, "total: %d", output.Total)
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdSubscriptionDetect(options core.Options) core.Result {
|
||||
result := s.handleSubscriptionDetect(s.commandContext(), options)
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdSubscriptionDetect", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
capabilities, ok := result.Value.(SubscriptionCapabilities)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdSubscriptionDetect", "invalid capability output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
core.Print(nil, "available: %s", core.Join(",", capabilities.Available...))
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdSubscriptionBudget(options core.Options) core.Result {
|
||||
if optionStringValue(options, "agent_id", "agent-id", "_arg") == "" {
|
||||
core.Print(nil, "usage: core-agent subscription budget <agent-id>")
|
||||
return core.Result{Value: core.E("agentic.cmdSubscriptionBudget", "agent_id is required", nil), OK: false}
|
||||
}
|
||||
|
||||
result := s.handleSubscriptionBudget(s.commandContext(), normalisePlatformCommandOptions(options))
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdSubscriptionBudget", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
budget, ok := result.Value.(map[string]any)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdSubscriptionBudget", "invalid budget output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
core.Print(nil, "%s", core.JSONMarshalString(budget))
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdSubscriptionUpdateBudget(options core.Options) core.Result {
|
||||
if optionStringValue(options, "agent_id", "agent-id", "_arg") == "" || len(optionAnyMapValue(options, "limits")) == 0 {
|
||||
core.Print(nil, "usage: core-agent subscription update-budget <agent-id> --limits='{\"max_daily_hours\":2}'")
|
||||
return core.Result{Value: core.E("agentic.cmdSubscriptionUpdateBudget", "agent_id and limits are required", nil), OK: false}
|
||||
}
|
||||
|
||||
result := s.handleSubscriptionBudgetUpdate(s.commandContext(), normalisePlatformCommandOptions(options))
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdSubscriptionUpdateBudget", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
budget, ok := result.Value.(map[string]any)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdSubscriptionUpdateBudget", "invalid updated budget output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
core.Print(nil, "%s", core.JSONMarshalString(budget))
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
func normalisePlatformCommandOptions(options core.Options) core.Options {
|
||||
normalised := core.NewOptions(options.Items()...)
|
||||
if normalised.String("agent_id") == "" {
|
||||
if agentID := optionStringValue(options, "_arg", "agent-id"); agentID != "" {
|
||||
normalised.Set("agent_id", agentID)
|
||||
}
|
||||
}
|
||||
return normalised
|
||||
}
|
||||
|
||||
func commandResultError(action string, result core.Result) error {
|
||||
if err, ok := result.Value.(error); ok && err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
message := stringValue(result.Value)
|
||||
if message != "" {
|
||||
return core.E(action, message, nil)
|
||||
}
|
||||
|
||||
return core.E(action, "command failed", nil)
|
||||
}
|
||||
|
||||
func printFleetTask(task FleetTask) {
|
||||
core.Print(nil, "task: %d", task.ID)
|
||||
core.Print(nil, "repo: %s", task.Repo)
|
||||
core.Print(nil, "status: %s", task.Status)
|
||||
if task.Branch != "" {
|
||||
core.Print(nil, "branch: %s", task.Branch)
|
||||
}
|
||||
if task.AgentModel != "" {
|
||||
core.Print(nil, "agent model: %s", task.AgentModel)
|
||||
}
|
||||
core.Print(nil, "summary: %s", task.Task)
|
||||
}
|
||||
17
pkg/agentic/commands_platform_example_test.go
Normal file
17
pkg/agentic/commands_platform_example_test.go
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
package agentic
|
||||
|
||||
import core "dappco.re/go/core"
|
||||
|
||||
func ExamplePrepSubsystem_cmdFleetRegister() {
|
||||
s := &PrepSubsystem{
|
||||
ServiceRuntime: core.NewServiceRuntime(core.New(), AgentOptions{}),
|
||||
}
|
||||
|
||||
result := s.cmdFleetRegister(core.NewOptions())
|
||||
core.Println(result.OK)
|
||||
// Output:
|
||||
// usage: core-agent fleet register <agent-id> --platform=linux [--models=codex,gpt-5.4] [--capabilities=go,review]
|
||||
// false
|
||||
}
|
||||
65
pkg/agentic/commands_platform_test.go
Normal file
65
pkg/agentic/commands_platform_test.go
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
package agentic
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
core "dappco.re/go/core"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCommandsplatform_CmdFleetRegister_Bad(t *testing.T) {
|
||||
subsystem := testPrepWithPlatformServer(t, nil, "")
|
||||
result := subsystem.cmdFleetRegister(core.NewOptions())
|
||||
assert.False(t, result.OK)
|
||||
}
|
||||
|
||||
func TestCommandsplatform_CmdFleetNodes_Good(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = w.Write([]byte(`{"data":[{"id":1,"agent_id":"charon","platform":"linux","models":["codex"],"status":"online"}],"total":1}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
|
||||
output := captureStdout(t, func() {
|
||||
result := subsystem.cmdFleetNodes(core.NewOptions())
|
||||
assert.True(t, result.OK)
|
||||
})
|
||||
|
||||
assert.Contains(t, output, "charon")
|
||||
assert.Contains(t, output, "total: 1")
|
||||
}
|
||||
|
||||
func TestCommandsplatform_CmdSyncStatus_Good(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = w.Write([]byte(`{"data":{"agent_id":"charon","status":"online","last_push_at":"2026-03-31T08:00:00Z"}}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
|
||||
output := captureStdout(t, func() {
|
||||
result := subsystem.cmdSyncStatus(core.NewOptions(core.Option{Key: "_arg", Value: "charon"}))
|
||||
assert.True(t, result.OK)
|
||||
})
|
||||
|
||||
assert.Contains(t, output, "agent: charon")
|
||||
assert.Contains(t, output, "status: online")
|
||||
}
|
||||
|
||||
func TestCommandsplatform_CmdSubscriptionDetect_Good(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = w.Write([]byte(`{"data":{"providers":{"claude":true},"available":["claude"]}}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
|
||||
output := captureStdout(t, func() {
|
||||
result := subsystem.cmdSubscriptionDetect(core.NewOptions())
|
||||
assert.True(t, result.OK)
|
||||
})
|
||||
|
||||
assert.Contains(t, output, "available: claude")
|
||||
}
|
||||
784
pkg/agentic/platform.go
Normal file
784
pkg/agentic/platform.go
Normal file
|
|
@ -0,0 +1,784 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
package agentic
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
core "dappco.re/go/core"
|
||||
)
|
||||
|
||||
// node := agentic.FleetNode{AgentID: "charon", Platform: "linux", Status: "online"}
|
||||
type FleetNode struct {
|
||||
ID int `json:"id"`
|
||||
AgentID string `json:"agent_id"`
|
||||
Platform string `json:"platform"`
|
||||
Models []string `json:"models,omitempty"`
|
||||
Capabilities []string `json:"capabilities,omitempty"`
|
||||
Status string `json:"status"`
|
||||
ComputeBudget map[string]any `json:"compute_budget,omitempty"`
|
||||
CurrentTaskID int `json:"current_task_id,omitempty"`
|
||||
LastHeartbeatAt string `json:"last_heartbeat_at,omitempty"`
|
||||
RegisteredAt string `json:"registered_at,omitempty"`
|
||||
}
|
||||
|
||||
// task := agentic.FleetTask{ID: 7, Repo: "go-io", Task: "Fix tests", Status: "assigned"}
|
||||
type FleetTask struct {
|
||||
ID int `json:"id"`
|
||||
Repo string `json:"repo"`
|
||||
Branch string `json:"branch,omitempty"`
|
||||
Task string `json:"task"`
|
||||
Template string `json:"template,omitempty"`
|
||||
AgentModel string `json:"agent_model,omitempty"`
|
||||
Status string `json:"status"`
|
||||
Result map[string]any `json:"result,omitempty"`
|
||||
Findings []map[string]any `json:"findings,omitempty"`
|
||||
Changes map[string]any `json:"changes,omitempty"`
|
||||
Report map[string]any `json:"report,omitempty"`
|
||||
StartedAt string `json:"started_at,omitempty"`
|
||||
CompletedAt string `json:"completed_at,omitempty"`
|
||||
}
|
||||
|
||||
// out := agentic.FleetNodesOutput{Total: 2, Nodes: []agentic.FleetNode{{AgentID: "charon"}}}
|
||||
type FleetNodesOutput struct {
|
||||
Total int `json:"total"`
|
||||
Nodes []FleetNode `json:"nodes"`
|
||||
}
|
||||
|
||||
// stats := agentic.FleetStats{NodesOnline: 2, TasksToday: 5}
|
||||
type FleetStats struct {
|
||||
NodesOnline int `json:"nodes_online"`
|
||||
TasksToday int `json:"tasks_today"`
|
||||
TasksWeek int `json:"tasks_week"`
|
||||
ReposTouched int `json:"repos_touched"`
|
||||
FindingsTotal int `json:"findings_total"`
|
||||
ComputeHours int `json:"compute_hours"`
|
||||
}
|
||||
|
||||
// status := agentic.SyncStatusOutput{AgentID: "charon", Status: "online"}
|
||||
type SyncStatusOutput struct {
|
||||
AgentID string `json:"agent_id"`
|
||||
Status string `json:"status"`
|
||||
LastPushAt string `json:"last_push_at,omitempty"`
|
||||
LastPullAt string `json:"last_pull_at,omitempty"`
|
||||
Queued int `json:"queued"`
|
||||
ContextCount int `json:"context_count"`
|
||||
RemoteError string `json:"remote_error,omitempty"`
|
||||
}
|
||||
|
||||
// balance := agentic.CreditBalance{AgentID: "charon", Balance: 12}
|
||||
type CreditBalance struct {
|
||||
AgentID string `json:"agent_id"`
|
||||
Balance int `json:"balance"`
|
||||
Entries int `json:"entries"`
|
||||
}
|
||||
|
||||
// entry := agentic.CreditEntry{ID: 4, TaskType: "fleet-task", Amount: 2}
|
||||
type CreditEntry struct {
|
||||
ID int `json:"id"`
|
||||
TaskType string `json:"task_type"`
|
||||
Amount int `json:"amount"`
|
||||
BalanceAfter int `json:"balance_after"`
|
||||
Description string `json:"description,omitempty"`
|
||||
CreatedAt string `json:"created_at,omitempty"`
|
||||
}
|
||||
|
||||
// out := agentic.CreditsHistoryOutput{Total: 1, Entries: []agentic.CreditEntry{{ID: 1}}}
|
||||
type CreditsHistoryOutput struct {
|
||||
Total int `json:"total"`
|
||||
Entries []CreditEntry `json:"entries"`
|
||||
}
|
||||
|
||||
// caps := agentic.SubscriptionCapabilities{Available: []string{"claude", "openai"}}
|
||||
type SubscriptionCapabilities struct {
|
||||
Providers map[string]bool `json:"providers,omitempty"`
|
||||
Available []string `json:"available,omitempty"`
|
||||
}
|
||||
|
||||
// result := c.Action("agent.sync.status").Run(ctx, core.NewOptions())
|
||||
func (s *PrepSubsystem) handleSyncStatus(ctx context.Context, options core.Options) core.Result {
|
||||
agentID := optionStringValue(options, "agent_id", "agent-id", "_arg")
|
||||
if agentID == "" {
|
||||
agentID = AgentName()
|
||||
}
|
||||
|
||||
output := SyncStatusOutput{
|
||||
AgentID: agentID,
|
||||
Status: "offline",
|
||||
Queued: len(readSyncQueue()),
|
||||
ContextCount: len(readSyncContext()),
|
||||
}
|
||||
|
||||
if s.syncToken() == "" {
|
||||
return core.Result{Value: output, OK: true}
|
||||
}
|
||||
|
||||
path := appendQueryParam("/v1/agent/status", "agent_id", agentID)
|
||||
result := s.platformPayload(ctx, "agent.sync.status", "GET", path, nil)
|
||||
if !result.OK {
|
||||
err, _ := result.Value.(error)
|
||||
if err != nil {
|
||||
output.RemoteError = err.Error()
|
||||
}
|
||||
return core.Result{Value: output, OK: true}
|
||||
}
|
||||
|
||||
data := payloadDataMap(result.Value.(map[string]any))
|
||||
if len(data) == 0 {
|
||||
return core.Result{Value: output, OK: true}
|
||||
}
|
||||
|
||||
output.Status = stringValue(data["status"])
|
||||
output.LastPushAt = stringValue(data["last_push_at"])
|
||||
output.LastPullAt = stringValue(data["last_pull_at"])
|
||||
if output.Status == "" {
|
||||
output.Status = "online"
|
||||
}
|
||||
|
||||
return core.Result{Value: output, OK: true}
|
||||
}
|
||||
|
||||
// result := c.Action("agent.fleet.register").Run(ctx, core.NewOptions(core.Option{Key: "agent_id", Value: "charon"}))
|
||||
func (s *PrepSubsystem) handleFleetRegister(ctx context.Context, options core.Options) core.Result {
|
||||
agentID := optionStringValue(options, "agent_id", "agent-id", "_arg")
|
||||
if agentID == "" {
|
||||
return core.Result{Value: core.E("agent.fleet.register", "agent_id is required", nil), OK: false}
|
||||
}
|
||||
|
||||
platform := optionStringValue(options, "platform")
|
||||
if platform == "" {
|
||||
platform = "unknown"
|
||||
}
|
||||
|
||||
body := map[string]any{
|
||||
"agent_id": agentID,
|
||||
"platform": platform,
|
||||
}
|
||||
if models := optionStringSliceValue(options, "models"); len(models) > 0 {
|
||||
body["models"] = models
|
||||
}
|
||||
if capabilities := optionStringSliceValue(options, "capabilities"); len(capabilities) > 0 {
|
||||
body["capabilities"] = capabilities
|
||||
}
|
||||
|
||||
result := s.platformPayload(ctx, "agent.fleet.register", "POST", "/v1/fleet/register", body)
|
||||
if !result.OK {
|
||||
return result
|
||||
}
|
||||
|
||||
return core.Result{Value: parseFleetNode(payloadDataMap(result.Value.(map[string]any))), OK: true}
|
||||
}
|
||||
|
||||
// result := c.Action("agent.fleet.heartbeat").Run(ctx, core.NewOptions(core.Option{Key: "agent_id", Value: "charon"}))
|
||||
func (s *PrepSubsystem) handleFleetHeartbeat(ctx context.Context, options core.Options) core.Result {
|
||||
agentID := optionStringValue(options, "agent_id", "agent-id", "_arg")
|
||||
status := optionStringValue(options, "status")
|
||||
if agentID == "" || status == "" {
|
||||
return core.Result{Value: core.E("agent.fleet.heartbeat", "agent_id and status are required", nil), OK: false}
|
||||
}
|
||||
|
||||
body := map[string]any{
|
||||
"agent_id": agentID,
|
||||
"status": status,
|
||||
}
|
||||
if budget := optionAnyMapValue(options, "compute_budget", "compute-budget"); len(budget) > 0 {
|
||||
body["compute_budget"] = budget
|
||||
}
|
||||
|
||||
result := s.platformPayload(ctx, "agent.fleet.heartbeat", "POST", "/v1/fleet/heartbeat", body)
|
||||
if !result.OK {
|
||||
return result
|
||||
}
|
||||
|
||||
return core.Result{Value: parseFleetNode(payloadDataMap(result.Value.(map[string]any))), OK: true}
|
||||
}
|
||||
|
||||
// result := c.Action("agent.fleet.deregister").Run(ctx, core.NewOptions(core.Option{Key: "agent_id", Value: "charon"}))
|
||||
func (s *PrepSubsystem) handleFleetDeregister(ctx context.Context, options core.Options) core.Result {
|
||||
agentID := optionStringValue(options, "agent_id", "agent-id", "_arg")
|
||||
if agentID == "" {
|
||||
return core.Result{Value: core.E("agent.fleet.deregister", "agent_id is required", nil), OK: false}
|
||||
}
|
||||
|
||||
result := s.platformPayload(ctx, "agent.fleet.deregister", "POST", "/v1/fleet/deregister", map[string]any{
|
||||
"agent_id": agentID,
|
||||
})
|
||||
if !result.OK {
|
||||
return result
|
||||
}
|
||||
|
||||
return core.Result{Value: map[string]any{
|
||||
"agent_id": agentID,
|
||||
"deregistered": true,
|
||||
}, OK: true}
|
||||
}
|
||||
|
||||
// result := c.Action("agent.fleet.nodes").Run(ctx, core.NewOptions())
|
||||
func (s *PrepSubsystem) handleFleetNodes(ctx context.Context, options core.Options) core.Result {
|
||||
path := "/v1/fleet/nodes"
|
||||
path = appendQueryParam(path, "status", optionStringValue(options, "status"))
|
||||
path = appendQueryParam(path, "platform", optionStringValue(options, "platform"))
|
||||
|
||||
result := s.platformPayload(ctx, "agent.fleet.nodes", "GET", path, nil)
|
||||
if !result.OK {
|
||||
return result
|
||||
}
|
||||
|
||||
return core.Result{Value: parseFleetNodesOutput(result.Value.(map[string]any)), OK: true}
|
||||
}
|
||||
|
||||
// result := c.Action("agent.fleet.task.assign").Run(ctx, core.NewOptions(core.Option{Key: "agent_id", Value: "charon"}))
|
||||
func (s *PrepSubsystem) handleFleetAssignTask(ctx context.Context, options core.Options) core.Result {
|
||||
agentID := optionStringValue(options, "agent_id", "agent-id", "_arg")
|
||||
repo := optionStringValue(options, "repo")
|
||||
task := optionStringValue(options, "task")
|
||||
if agentID == "" || repo == "" || task == "" {
|
||||
return core.Result{Value: core.E("agent.fleet.task.assign", "agent_id, repo, and task are required", nil), OK: false}
|
||||
}
|
||||
|
||||
body := map[string]any{
|
||||
"agent_id": agentID,
|
||||
"repo": repo,
|
||||
"task": task,
|
||||
}
|
||||
if branch := optionStringValue(options, "branch"); branch != "" {
|
||||
body["branch"] = branch
|
||||
}
|
||||
if template := optionStringValue(options, "template"); template != "" {
|
||||
body["template"] = template
|
||||
}
|
||||
if agentModel := optionStringValue(options, "agent_model", "agent-model"); agentModel != "" {
|
||||
body["agent_model"] = agentModel
|
||||
}
|
||||
|
||||
result := s.platformPayload(ctx, "agent.fleet.task.assign", "POST", "/v1/fleet/task/assign", body)
|
||||
if !result.OK {
|
||||
return result
|
||||
}
|
||||
|
||||
return core.Result{Value: parseFleetTask(payloadDataMap(result.Value.(map[string]any))), OK: true}
|
||||
}
|
||||
|
||||
// result := c.Action("agent.fleet.task.complete").Run(ctx, core.NewOptions(core.Option{Key: "agent_id", Value: "charon"}))
|
||||
func (s *PrepSubsystem) handleFleetCompleteTask(ctx context.Context, options core.Options) core.Result {
|
||||
agentID := optionStringValue(options, "agent_id", "agent-id", "_arg")
|
||||
taskID := optionIntValue(options, "task_id", "task-id")
|
||||
if agentID == "" || taskID == 0 {
|
||||
return core.Result{Value: core.E("agent.fleet.task.complete", "agent_id and task_id are required", nil), OK: false}
|
||||
}
|
||||
|
||||
body := map[string]any{
|
||||
"agent_id": agentID,
|
||||
"task_id": taskID,
|
||||
}
|
||||
if resultMap := optionAnyMapValue(options, "result"); len(resultMap) > 0 {
|
||||
body["result"] = resultMap
|
||||
}
|
||||
if findings := optionAnyMapSliceValue(options, "findings"); len(findings) > 0 {
|
||||
body["findings"] = findings
|
||||
}
|
||||
if changes := optionAnyMapValue(options, "changes"); len(changes) > 0 {
|
||||
body["changes"] = changes
|
||||
}
|
||||
if report := optionAnyMapValue(options, "report"); len(report) > 0 {
|
||||
body["report"] = report
|
||||
}
|
||||
|
||||
result := s.platformPayload(ctx, "agent.fleet.task.complete", "POST", "/v1/fleet/task/complete", body)
|
||||
if !result.OK {
|
||||
return result
|
||||
}
|
||||
|
||||
return core.Result{Value: parseFleetTask(payloadDataMap(result.Value.(map[string]any))), OK: true}
|
||||
}
|
||||
|
||||
// result := c.Action("agent.fleet.task.next").Run(ctx, core.NewOptions(core.Option{Key: "agent_id", Value: "charon"}))
|
||||
func (s *PrepSubsystem) handleFleetNextTask(ctx context.Context, options core.Options) core.Result {
|
||||
agentID := optionStringValue(options, "agent_id", "agent-id", "_arg")
|
||||
if agentID == "" {
|
||||
return core.Result{Value: core.E("agent.fleet.task.next", "agent_id is required", nil), OK: false}
|
||||
}
|
||||
|
||||
path := appendQueryParam("/v1/fleet/task/next", "agent_id", agentID)
|
||||
path = appendQuerySlice(path, "capabilities[]", optionStringSliceValue(options, "capabilities"))
|
||||
|
||||
result := s.platformPayload(ctx, "agent.fleet.task.next", "GET", path, nil)
|
||||
if !result.OK {
|
||||
return result
|
||||
}
|
||||
|
||||
data := payloadDataMap(result.Value.(map[string]any))
|
||||
if len(data) == 0 {
|
||||
var task *FleetTask
|
||||
return core.Result{Value: task, OK: true}
|
||||
}
|
||||
|
||||
task := parseFleetTask(data)
|
||||
return core.Result{Value: &task, OK: true}
|
||||
}
|
||||
|
||||
// result := c.Action("agent.fleet.stats").Run(ctx, core.NewOptions())
|
||||
func (s *PrepSubsystem) handleFleetStats(ctx context.Context, options core.Options) core.Result {
|
||||
result := s.platformPayload(ctx, "agent.fleet.stats", "GET", "/v1/fleet/stats", nil)
|
||||
if !result.OK {
|
||||
return result
|
||||
}
|
||||
|
||||
return core.Result{Value: parseFleetStats(payloadDataMap(result.Value.(map[string]any))), OK: true}
|
||||
}
|
||||
|
||||
// result := c.Action("agent.credits.award").Run(ctx, core.NewOptions(core.Option{Key: "agent_id", Value: "charon"}))
|
||||
func (s *PrepSubsystem) handleCreditsAward(ctx context.Context, options core.Options) core.Result {
|
||||
agentID := optionStringValue(options, "agent_id", "agent-id", "_arg")
|
||||
taskType := optionStringValue(options, "task_type", "task-type")
|
||||
amount := optionIntValue(options, "amount")
|
||||
if agentID == "" || taskType == "" || amount == 0 {
|
||||
return core.Result{Value: core.E("agent.credits.award", "agent_id, task_type, and amount are required", nil), OK: false}
|
||||
}
|
||||
|
||||
body := map[string]any{
|
||||
"agent_id": agentID,
|
||||
"task_type": taskType,
|
||||
"amount": amount,
|
||||
}
|
||||
if fleetNodeID := optionIntValue(options, "fleet_node_id", "fleet-node-id"); fleetNodeID > 0 {
|
||||
body["fleet_node_id"] = fleetNodeID
|
||||
}
|
||||
if description := optionStringValue(options, "description"); description != "" {
|
||||
body["description"] = description
|
||||
}
|
||||
|
||||
result := s.platformPayload(ctx, "agent.credits.award", "POST", "/v1/credits/award", body)
|
||||
if !result.OK {
|
||||
return result
|
||||
}
|
||||
|
||||
return core.Result{Value: parseCreditEntry(payloadDataMap(result.Value.(map[string]any))), OK: true}
|
||||
}
|
||||
|
||||
// result := c.Action("agent.credits.balance").Run(ctx, core.NewOptions(core.Option{Key: "agent_id", Value: "charon"}))
|
||||
func (s *PrepSubsystem) handleCreditsBalance(ctx context.Context, options core.Options) core.Result {
|
||||
agentID := optionStringValue(options, "agent_id", "agent-id", "_arg")
|
||||
if agentID == "" {
|
||||
return core.Result{Value: core.E("agent.credits.balance", "agent_id is required", nil), OK: false}
|
||||
}
|
||||
|
||||
path := core.Concat("/v1/credits/balance/", agentID)
|
||||
result := s.platformPayload(ctx, "agent.credits.balance", "GET", path, nil)
|
||||
if !result.OK {
|
||||
return result
|
||||
}
|
||||
|
||||
return core.Result{Value: parseCreditBalance(payloadDataMap(result.Value.(map[string]any))), OK: true}
|
||||
}
|
||||
|
||||
// result := c.Action("agent.credits.history").Run(ctx, core.NewOptions(core.Option{Key: "agent_id", Value: "charon"}))
|
||||
func (s *PrepSubsystem) handleCreditsHistory(ctx context.Context, options core.Options) core.Result {
|
||||
agentID := optionStringValue(options, "agent_id", "agent-id", "_arg")
|
||||
if agentID == "" {
|
||||
return core.Result{Value: core.E("agent.credits.history", "agent_id is required", nil), OK: false}
|
||||
}
|
||||
|
||||
path := core.Concat("/v1/credits/history/", agentID)
|
||||
if limit := optionIntValue(options, "limit"); limit > 0 {
|
||||
path = appendQueryParam(path, "limit", core.Sprint(limit))
|
||||
}
|
||||
|
||||
result := s.platformPayload(ctx, "agent.credits.history", "GET", path, nil)
|
||||
if !result.OK {
|
||||
return result
|
||||
}
|
||||
|
||||
return core.Result{Value: parseCreditsHistoryOutput(result.Value.(map[string]any)), OK: true}
|
||||
}
|
||||
|
||||
// result := c.Action("agent.subscription.detect").Run(ctx, core.NewOptions())
|
||||
func (s *PrepSubsystem) handleSubscriptionDetect(ctx context.Context, options core.Options) core.Result {
|
||||
body := map[string]any{}
|
||||
if apiKeys := optionStringMapValue(options, "api_keys", "api-keys"); len(apiKeys) > 0 {
|
||||
body["api_keys"] = apiKeys
|
||||
}
|
||||
|
||||
result := s.platformPayload(ctx, "agent.subscription.detect", "POST", "/v1/subscription/detect", body)
|
||||
if !result.OK {
|
||||
return result
|
||||
}
|
||||
|
||||
return core.Result{Value: parseSubscriptionCapabilities(payloadDataMap(result.Value.(map[string]any))), OK: true}
|
||||
}
|
||||
|
||||
// result := c.Action("agent.subscription.budget").Run(ctx, core.NewOptions(core.Option{Key: "agent_id", Value: "charon"}))
|
||||
func (s *PrepSubsystem) handleSubscriptionBudget(ctx context.Context, options core.Options) core.Result {
|
||||
agentID := optionStringValue(options, "agent_id", "agent-id", "_arg")
|
||||
if agentID == "" {
|
||||
return core.Result{Value: core.E("agent.subscription.budget", "agent_id is required", nil), OK: false}
|
||||
}
|
||||
|
||||
path := core.Concat("/v1/subscription/budget/", agentID)
|
||||
result := s.platformPayload(ctx, "agent.subscription.budget", "GET", path, nil)
|
||||
if !result.OK {
|
||||
return result
|
||||
}
|
||||
|
||||
return core.Result{Value: payloadDataMap(result.Value.(map[string]any)), OK: true}
|
||||
}
|
||||
|
||||
// result := c.Action("agent.subscription.budget.update").Run(ctx, core.NewOptions(core.Option{Key: "agent_id", Value: "charon"}))
|
||||
func (s *PrepSubsystem) handleSubscriptionBudgetUpdate(ctx context.Context, options core.Options) core.Result {
|
||||
agentID := optionStringValue(options, "agent_id", "agent-id", "_arg")
|
||||
limits := optionAnyMapValue(options, "limits")
|
||||
if agentID == "" || len(limits) == 0 {
|
||||
return core.Result{Value: core.E("agent.subscription.budget.update", "agent_id and limits are required", nil), OK: false}
|
||||
}
|
||||
|
||||
path := core.Concat("/v1/subscription/budget/", agentID)
|
||||
result := s.platformPayload(ctx, "agent.subscription.budget.update", "PUT", path, map[string]any{
|
||||
"limits": limits,
|
||||
})
|
||||
if !result.OK {
|
||||
return result
|
||||
}
|
||||
|
||||
return core.Result{Value: payloadDataMap(result.Value.(map[string]any)), OK: true}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) platformPayload(ctx context.Context, action, method, path string, body any) core.Result {
|
||||
token := s.syncToken()
|
||||
if token == "" {
|
||||
return core.Result{Value: core.E(action, "no platform API key configured", nil), OK: false}
|
||||
}
|
||||
|
||||
bodyString := ""
|
||||
if body != nil {
|
||||
bodyString = core.JSONMarshalString(body)
|
||||
}
|
||||
|
||||
requestResult := HTTPDo(ctx, method, core.Concat(s.syncAPIURL(), path), bodyString, token, "Bearer")
|
||||
if !requestResult.OK {
|
||||
return core.Result{Value: platformResultError(action, requestResult), OK: false}
|
||||
}
|
||||
|
||||
var payload map[string]any
|
||||
parseResult := core.JSONUnmarshalString(requestResult.Value.(string), &payload)
|
||||
if !parseResult.OK {
|
||||
err, _ := parseResult.Value.(error)
|
||||
return core.Result{Value: core.E(action, "failed to parse platform response", err), OK: false}
|
||||
}
|
||||
|
||||
return core.Result{Value: payload, OK: true}
|
||||
}
|
||||
|
||||
func platformResultError(action string, result core.Result) error {
|
||||
if err, ok := result.Value.(error); ok && err != nil {
|
||||
return core.E(action, "platform request failed", err)
|
||||
}
|
||||
|
||||
body := core.Trim(stringValue(result.Value))
|
||||
if body == "" {
|
||||
return core.E(action, "platform request failed", nil)
|
||||
}
|
||||
|
||||
var payload map[string]any
|
||||
if parseResult := core.JSONUnmarshalString(body, &payload); parseResult.OK {
|
||||
if message := stringValue(payload["error"]); message != "" {
|
||||
return core.E(action, message, nil)
|
||||
}
|
||||
}
|
||||
|
||||
return core.E(action, body, nil)
|
||||
}
|
||||
|
||||
func payloadDataMap(payload map[string]any) map[string]any {
|
||||
return anyMapValue(payload["data"])
|
||||
}
|
||||
|
||||
func payloadDataSlice(payload map[string]any) []map[string]any {
|
||||
return anyMapSliceValue(payload["data"])
|
||||
}
|
||||
|
||||
func parseFleetNode(values map[string]any) FleetNode {
|
||||
return FleetNode{
|
||||
ID: intValue(values["id"]),
|
||||
AgentID: stringValue(values["agent_id"]),
|
||||
Platform: stringValue(values["platform"]),
|
||||
Models: listValue(values["models"]),
|
||||
Capabilities: listValue(values["capabilities"]),
|
||||
Status: stringValue(values["status"]),
|
||||
ComputeBudget: anyMapValue(values["compute_budget"]),
|
||||
CurrentTaskID: intValue(values["current_task_id"]),
|
||||
LastHeartbeatAt: stringValue(values["last_heartbeat_at"]),
|
||||
RegisteredAt: stringValue(values["registered_at"]),
|
||||
}
|
||||
}
|
||||
|
||||
func parseFleetTask(values map[string]any) FleetTask {
|
||||
return FleetTask{
|
||||
ID: intValue(values["id"]),
|
||||
Repo: stringValue(values["repo"]),
|
||||
Branch: stringValue(values["branch"]),
|
||||
Task: stringValue(values["task"]),
|
||||
Template: stringValue(values["template"]),
|
||||
AgentModel: stringValue(values["agent_model"]),
|
||||
Status: stringValue(values["status"]),
|
||||
Result: anyMapValue(values["result"]),
|
||||
Findings: anyMapSliceValue(values["findings"]),
|
||||
Changes: anyMapValue(values["changes"]),
|
||||
Report: anyMapValue(values["report"]),
|
||||
StartedAt: stringValue(values["started_at"]),
|
||||
CompletedAt: stringValue(values["completed_at"]),
|
||||
}
|
||||
}
|
||||
|
||||
func parseFleetNodesOutput(payload map[string]any) FleetNodesOutput {
|
||||
nodesData := payloadDataSlice(payload)
|
||||
nodes := make([]FleetNode, 0, len(nodesData))
|
||||
for _, values := range nodesData {
|
||||
nodes = append(nodes, parseFleetNode(values))
|
||||
}
|
||||
|
||||
total := intValue(payload["total"])
|
||||
if total == 0 {
|
||||
total = len(nodes)
|
||||
}
|
||||
|
||||
return FleetNodesOutput{
|
||||
Total: total,
|
||||
Nodes: nodes,
|
||||
}
|
||||
}
|
||||
|
||||
func parseFleetStats(values map[string]any) FleetStats {
|
||||
return FleetStats{
|
||||
NodesOnline: intValue(values["nodes_online"]),
|
||||
TasksToday: intValue(values["tasks_today"]),
|
||||
TasksWeek: intValue(values["tasks_week"]),
|
||||
ReposTouched: intValue(values["repos_touched"]),
|
||||
FindingsTotal: intValue(values["findings_total"]),
|
||||
ComputeHours: intValue(values["compute_hours"]),
|
||||
}
|
||||
}
|
||||
|
||||
func parseCreditEntry(values map[string]any) CreditEntry {
|
||||
return CreditEntry{
|
||||
ID: intValue(values["id"]),
|
||||
TaskType: stringValue(values["task_type"]),
|
||||
Amount: intValue(values["amount"]),
|
||||
BalanceAfter: intValue(values["balance_after"]),
|
||||
Description: stringValue(values["description"]),
|
||||
CreatedAt: stringValue(values["created_at"]),
|
||||
}
|
||||
}
|
||||
|
||||
func parseCreditBalance(values map[string]any) CreditBalance {
|
||||
return CreditBalance{
|
||||
AgentID: stringValue(values["agent_id"]),
|
||||
Balance: intValue(values["balance"]),
|
||||
Entries: intValue(values["entries"]),
|
||||
}
|
||||
}
|
||||
|
||||
func parseCreditsHistoryOutput(payload map[string]any) CreditsHistoryOutput {
|
||||
entriesData := payloadDataSlice(payload)
|
||||
entries := make([]CreditEntry, 0, len(entriesData))
|
||||
for _, values := range entriesData {
|
||||
entries = append(entries, parseCreditEntry(values))
|
||||
}
|
||||
|
||||
total := intValue(payload["total"])
|
||||
if total == 0 {
|
||||
total = len(entries)
|
||||
}
|
||||
|
||||
return CreditsHistoryOutput{
|
||||
Total: total,
|
||||
Entries: entries,
|
||||
}
|
||||
}
|
||||
|
||||
func parseSubscriptionCapabilities(values map[string]any) SubscriptionCapabilities {
|
||||
return SubscriptionCapabilities{
|
||||
Providers: boolMapValue(values["providers"]),
|
||||
Available: listValue(values["available"]),
|
||||
}
|
||||
}
|
||||
|
||||
func appendQueryParam(path, key, value string) string {
|
||||
value = core.Trim(value)
|
||||
if value == "" {
|
||||
return path
|
||||
}
|
||||
|
||||
separator := "?"
|
||||
if core.Contains(path, "?") {
|
||||
separator = "&"
|
||||
}
|
||||
|
||||
return core.Concat(path, separator, key, "=", value)
|
||||
}
|
||||
|
||||
func appendQuerySlice(path, key string, values []string) string {
|
||||
for _, value := range values {
|
||||
path = appendQueryParam(path, key, value)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func optionAnyMapValue(options core.Options, keys ...string) map[string]any {
|
||||
for _, key := range keys {
|
||||
result := options.Get(key)
|
||||
if !result.OK {
|
||||
continue
|
||||
}
|
||||
values := anyMapValue(result.Value)
|
||||
if len(values) > 0 {
|
||||
return values
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func optionAnyMapSliceValue(options core.Options, keys ...string) []map[string]any {
|
||||
for _, key := range keys {
|
||||
result := options.Get(key)
|
||||
if !result.OK {
|
||||
continue
|
||||
}
|
||||
values := anyMapSliceValue(result.Value)
|
||||
if len(values) > 0 {
|
||||
return values
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func anyMapValue(value any) map[string]any {
|
||||
switch typed := value.(type) {
|
||||
case map[string]any:
|
||||
return typed
|
||||
case map[string]string:
|
||||
values := make(map[string]any, len(typed))
|
||||
for key, item := range typed {
|
||||
values[key] = item
|
||||
}
|
||||
return values
|
||||
case string:
|
||||
trimmed := core.Trim(typed)
|
||||
if trimmed == "" {
|
||||
return nil
|
||||
}
|
||||
if core.HasPrefix(trimmed, "{") {
|
||||
var values map[string]any
|
||||
if result := core.JSONUnmarshalString(trimmed, &values); result.OK {
|
||||
return values
|
||||
}
|
||||
var strings map[string]string
|
||||
if result := core.JSONUnmarshalString(trimmed, &strings); result.OK {
|
||||
return anyMapValue(strings)
|
||||
}
|
||||
}
|
||||
values := stringMapValue(trimmed)
|
||||
if len(values) > 0 {
|
||||
return anyMapValue(values)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func anyMapSliceValue(value any) []map[string]any {
|
||||
switch typed := value.(type) {
|
||||
case []map[string]any:
|
||||
return typed
|
||||
case []any:
|
||||
values := make([]map[string]any, 0, len(typed))
|
||||
for _, item := range typed {
|
||||
if mapValue := anyMapValue(item); len(mapValue) > 0 {
|
||||
values = append(values, mapValue)
|
||||
}
|
||||
}
|
||||
return values
|
||||
case string:
|
||||
trimmed := core.Trim(typed)
|
||||
if trimmed == "" {
|
||||
return nil
|
||||
}
|
||||
if core.HasPrefix(trimmed, "[") {
|
||||
var values []map[string]any
|
||||
if result := core.JSONUnmarshalString(trimmed, &values); result.OK {
|
||||
return values
|
||||
}
|
||||
var generic []any
|
||||
if result := core.JSONUnmarshalString(trimmed, &generic); result.OK {
|
||||
return anyMapSliceValue(generic)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func boolMapValue(value any) map[string]bool {
|
||||
switch typed := value.(type) {
|
||||
case map[string]bool:
|
||||
return typed
|
||||
case map[string]any:
|
||||
values := make(map[string]bool, len(typed))
|
||||
for key, item := range typed {
|
||||
switch resolved := item.(type) {
|
||||
case bool:
|
||||
values[key] = resolved
|
||||
case string:
|
||||
values[key] = core.Lower(core.Trim(resolved)) == "true"
|
||||
default:
|
||||
values[key] = intValue(resolved) > 0
|
||||
}
|
||||
}
|
||||
return values
|
||||
case string:
|
||||
trimmed := core.Trim(typed)
|
||||
if trimmed == "" {
|
||||
return nil
|
||||
}
|
||||
if core.HasPrefix(trimmed, "{") {
|
||||
var values map[string]bool
|
||||
if result := core.JSONUnmarshalString(trimmed, &values); result.OK {
|
||||
return values
|
||||
}
|
||||
var generic map[string]any
|
||||
if result := core.JSONUnmarshalString(trimmed, &generic); result.OK {
|
||||
return boolMapValue(generic)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func listValue(value any) []string {
|
||||
switch typed := value.(type) {
|
||||
case map[string]any:
|
||||
values := make([]string, 0, len(typed))
|
||||
for key, item := range typed {
|
||||
if item == true || core.Trim(stringValue(item)) != "" {
|
||||
values = append(values, key)
|
||||
}
|
||||
}
|
||||
return cleanStrings(values)
|
||||
default:
|
||||
return stringSliceValue(value)
|
||||
}
|
||||
}
|
||||
|
||||
func intValue(value any) int {
|
||||
switch typed := value.(type) {
|
||||
case int:
|
||||
return typed
|
||||
case int64:
|
||||
return int(typed)
|
||||
case float64:
|
||||
return int(typed)
|
||||
case string:
|
||||
parsed := parseInt(typed)
|
||||
if parsed != 0 || core.Trim(typed) == "0" {
|
||||
return parsed
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
18
pkg/agentic/platform_example_test.go
Normal file
18
pkg/agentic/platform_example_test.go
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
package agentic
|
||||
|
||||
import "fmt"
|
||||
|
||||
func Example_parseFleetNode() {
|
||||
node := parseFleetNode(map[string]any{
|
||||
"agent_id": "charon",
|
||||
"platform": "linux",
|
||||
"models": []any{"codex", "gpt-5.4"},
|
||||
"capabilities": map[string]any{"go": true, "review": true},
|
||||
"status": "online",
|
||||
})
|
||||
|
||||
fmt.Println(node.AgentID, node.Platform, len(node.Models), len(node.Capabilities))
|
||||
// Output: charon linux 2 2
|
||||
}
|
||||
224
pkg/agentic/platform_test.go
Normal file
224
pkg/agentic/platform_test.go
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
package agentic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
core "dappco.re/go/core"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func testPrepWithPlatformServer(t *testing.T, srv *httptest.Server, token string) *PrepSubsystem {
|
||||
t.Helper()
|
||||
|
||||
root := t.TempDir()
|
||||
t.Setenv("CORE_WORKSPACE", root)
|
||||
t.Setenv("CORE_AGENT_API_KEY", token)
|
||||
t.Setenv("CORE_BRAIN_KEY", "")
|
||||
|
||||
c := core.New()
|
||||
subsystem := &PrepSubsystem{
|
||||
ServiceRuntime: core.NewServiceRuntime(c, AgentOptions{}),
|
||||
brainKey: token,
|
||||
backoff: make(map[string]time.Time),
|
||||
failCount: make(map[string]int),
|
||||
}
|
||||
if srv != nil {
|
||||
subsystem.brainURL = srv.URL
|
||||
}
|
||||
|
||||
return subsystem
|
||||
}
|
||||
|
||||
func TestPlatform_HandleFleetRegister_Good(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, "/v1/fleet/register", r.URL.Path)
|
||||
require.Equal(t, "Bearer secret-token", r.Header.Get("Authorization"))
|
||||
|
||||
bodyResult := core.ReadAll(r.Body)
|
||||
require.True(t, bodyResult.OK)
|
||||
|
||||
var payload map[string]any
|
||||
parseResult := core.JSONUnmarshalString(bodyResult.Value.(string), &payload)
|
||||
require.True(t, parseResult.OK)
|
||||
require.Equal(t, "charon", payload["agent_id"])
|
||||
require.Equal(t, "linux", payload["platform"])
|
||||
|
||||
_, _ = w.Write([]byte(`{"data":{"id":1,"agent_id":"charon","platform":"linux","models":["codex"],"capabilities":["go","review"],"status":"online"}}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
|
||||
result := subsystem.handleFleetRegister(context.Background(), core.NewOptions(
|
||||
core.Option{Key: "agent_id", Value: "charon"},
|
||||
core.Option{Key: "platform", Value: "linux"},
|
||||
core.Option{Key: "models", Value: "codex"},
|
||||
core.Option{Key: "capabilities", Value: "go,review"},
|
||||
))
|
||||
require.True(t, result.OK)
|
||||
|
||||
node, ok := result.Value.(FleetNode)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, "charon", node.AgentID)
|
||||
assert.Equal(t, "linux", node.Platform)
|
||||
assert.Equal(t, []string{"codex"}, node.Models)
|
||||
assert.Equal(t, []string{"go", "review"}, node.Capabilities)
|
||||
}
|
||||
|
||||
func TestPlatform_HandleFleetRegister_Bad(t *testing.T) {
|
||||
subsystem := testPrepWithPlatformServer(t, nil, "")
|
||||
|
||||
result := subsystem.handleFleetRegister(context.Background(), core.NewOptions(
|
||||
core.Option{Key: "agent_id", Value: "charon"},
|
||||
core.Option{Key: "platform", Value: "linux"},
|
||||
))
|
||||
assert.False(t, result.OK)
|
||||
}
|
||||
|
||||
func TestPlatform_HandleFleetRegister_Ugly(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = w.Write([]byte(`{broken json`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
|
||||
result := subsystem.handleFleetRegister(context.Background(), core.NewOptions(
|
||||
core.Option{Key: "agent_id", Value: "charon"},
|
||||
core.Option{Key: "platform", Value: "linux"},
|
||||
))
|
||||
assert.False(t, result.OK)
|
||||
}
|
||||
|
||||
func TestPlatform_HandleFleetNextTask_Good(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, "/v1/fleet/task/next", r.URL.Path)
|
||||
require.Equal(t, "charon", r.URL.Query().Get("agent_id"))
|
||||
require.Equal(t, []string{"go", "review"}, r.URL.Query()["capabilities[]"])
|
||||
_, _ = w.Write([]byte(`{"data":{"id":9,"repo":"core/go-io","branch":"dev","task":"Fix tests","template":"coding","agent_model":"codex:gpt-5.4","status":"in_progress","findings":[{"file":"main.go"}]}}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
|
||||
result := subsystem.handleFleetNextTask(context.Background(), core.NewOptions(
|
||||
core.Option{Key: "agent_id", Value: "charon"},
|
||||
core.Option{Key: "capabilities", Value: `["go","review"]`},
|
||||
))
|
||||
require.True(t, result.OK)
|
||||
|
||||
task, ok := result.Value.(*FleetTask)
|
||||
require.True(t, ok)
|
||||
require.NotNil(t, task)
|
||||
assert.Equal(t, 9, task.ID)
|
||||
assert.Equal(t, "core/go-io", task.Repo)
|
||||
assert.Len(t, task.Findings, 1)
|
||||
}
|
||||
|
||||
func TestPlatform_HandleFleetNextTask_Bad(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
_, _ = w.Write([]byte(`{"error":"queue unavailable"}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
|
||||
result := subsystem.handleFleetNextTask(context.Background(), core.NewOptions(
|
||||
core.Option{Key: "agent_id", Value: "charon"},
|
||||
))
|
||||
assert.False(t, result.OK)
|
||||
}
|
||||
|
||||
func TestPlatform_HandleFleetNextTask_Ugly(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = w.Write([]byte(`{"data":null}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
|
||||
result := subsystem.handleFleetNextTask(context.Background(), core.NewOptions(
|
||||
core.Option{Key: "agent_id", Value: "charon"},
|
||||
))
|
||||
require.True(t, result.OK)
|
||||
|
||||
task, ok := result.Value.(*FleetTask)
|
||||
require.True(t, ok)
|
||||
assert.Nil(t, task)
|
||||
}
|
||||
|
||||
func TestPlatform_HandleSyncStatus_Good(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, "/v1/agent/status", r.URL.Path)
|
||||
require.Equal(t, "charon", r.URL.Query().Get("agent_id"))
|
||||
_, _ = w.Write([]byte(`{"data":{"agent_id":"charon","status":"online","last_push_at":"2026-03-31T08:00:00Z","last_pull_at":"2026-03-31T08:05:00Z"}}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
|
||||
result := subsystem.handleSyncStatus(context.Background(), core.NewOptions(
|
||||
core.Option{Key: "agent_id", Value: "charon"},
|
||||
))
|
||||
require.True(t, result.OK)
|
||||
|
||||
status, ok := result.Value.(SyncStatusOutput)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, "charon", status.AgentID)
|
||||
assert.Equal(t, "online", status.Status)
|
||||
assert.Equal(t, "2026-03-31T08:00:00Z", status.LastPushAt)
|
||||
assert.Empty(t, status.RemoteError)
|
||||
}
|
||||
|
||||
func TestPlatform_HandleCreditsHistory_Good(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, "/v1/credits/history/charon", r.URL.Path)
|
||||
require.Equal(t, "5", r.URL.Query().Get("limit"))
|
||||
_, _ = w.Write([]byte(`{"data":[{"id":1,"task_type":"fleet-task","amount":2,"balance_after":7,"description":"Fleet task completed"}],"total":1}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
|
||||
result := subsystem.handleCreditsHistory(context.Background(), core.NewOptions(
|
||||
core.Option{Key: "agent_id", Value: "charon"},
|
||||
core.Option{Key: "limit", Value: 5},
|
||||
))
|
||||
require.True(t, result.OK)
|
||||
|
||||
output, ok := result.Value.(CreditsHistoryOutput)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, 1, output.Total)
|
||||
require.Len(t, output.Entries, 1)
|
||||
assert.Equal(t, 7, output.Entries[0].BalanceAfter)
|
||||
}
|
||||
|
||||
func TestPlatform_HandleSubscriptionDetect_Good(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, "/v1/subscription/detect", r.URL.Path)
|
||||
bodyResult := core.ReadAll(r.Body)
|
||||
require.True(t, bodyResult.OK)
|
||||
|
||||
var payload map[string]any
|
||||
parseResult := core.JSONUnmarshalString(bodyResult.Value.(string), &payload)
|
||||
require.True(t, parseResult.OK)
|
||||
apiKeys, ok := payload["api_keys"].(map[string]any)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, "k", apiKeys["openai"])
|
||||
|
||||
_, _ = w.Write([]byte(`{"data":{"providers":{"claude":true,"openai":true},"available":["claude","openai"]}}`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
subsystem := testPrepWithPlatformServer(t, server, "secret-token")
|
||||
result := subsystem.handleSubscriptionDetect(context.Background(), core.NewOptions(
|
||||
core.Option{Key: "api_keys", Value: `{"openai":"k"}`},
|
||||
))
|
||||
require.True(t, result.OK)
|
||||
|
||||
capabilities, ok := result.Value.(SubscriptionCapabilities)
|
||||
require.True(t, ok)
|
||||
assert.True(t, capabilities.Providers["claude"])
|
||||
assert.Equal(t, []string{"claude", "openai"}, capabilities.Available)
|
||||
}
|
||||
|
|
@ -113,6 +113,21 @@ func (s *PrepSubsystem) OnStartup(ctx context.Context) core.Result {
|
|||
|
||||
c.Action("agent.sync.push", s.handleSyncPush).Description = "Push completed dispatch state to the platform API"
|
||||
c.Action("agent.sync.pull", s.handleSyncPull).Description = "Pull fleet context from the platform API"
|
||||
c.Action("agent.sync.status", s.handleSyncStatus).Description = "Get fleet sync status from the platform API"
|
||||
c.Action("agent.fleet.register", s.handleFleetRegister).Description = "Register a fleet node with the platform API"
|
||||
c.Action("agent.fleet.heartbeat", s.handleFleetHeartbeat).Description = "Send a heartbeat for a fleet node"
|
||||
c.Action("agent.fleet.deregister", s.handleFleetDeregister).Description = "Deregister a fleet node from the platform API"
|
||||
c.Action("agent.fleet.nodes", s.handleFleetNodes).Description = "List registered fleet nodes"
|
||||
c.Action("agent.fleet.task.assign", s.handleFleetAssignTask).Description = "Assign a fleet task to an agent"
|
||||
c.Action("agent.fleet.task.complete", s.handleFleetCompleteTask).Description = "Complete a fleet task and report results"
|
||||
c.Action("agent.fleet.task.next", s.handleFleetNextTask).Description = "Ask the platform for the next fleet task"
|
||||
c.Action("agent.fleet.stats", s.handleFleetStats).Description = "Get fleet activity statistics"
|
||||
c.Action("agent.credits.award", s.handleCreditsAward).Description = "Award credits to a fleet node"
|
||||
c.Action("agent.credits.balance", s.handleCreditsBalance).Description = "Get credit balance for a fleet node"
|
||||
c.Action("agent.credits.history", s.handleCreditsHistory).Description = "List credit entries for a fleet node"
|
||||
c.Action("agent.subscription.detect", s.handleSubscriptionDetect).Description = "Detect available provider capabilities"
|
||||
c.Action("agent.subscription.budget", s.handleSubscriptionBudget).Description = "Get the compute budget for a fleet node"
|
||||
c.Action("agent.subscription.budget.update", s.handleSubscriptionBudgetUpdate).Description = "Update the compute budget for a fleet node"
|
||||
|
||||
c.Action("agentic.dispatch", s.handleDispatch).Description = "Prep workspace and spawn a subagent"
|
||||
c.Action("agentic.prep", s.handlePrep).Description = "Clone repo and build agent prompt"
|
||||
|
|
@ -165,6 +180,7 @@ func (s *PrepSubsystem) OnStartup(ctx context.Context) core.Result {
|
|||
s.registerCommands(ctx)
|
||||
s.registerWorkspaceCommands()
|
||||
s.registerForgeCommands()
|
||||
s.registerPlatformCommands()
|
||||
return core.Result{OK: true}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue