mirror of
https://github.com/danielmiessler/Fabric.git
synced 2026-01-09 22:38:10 -05:00
Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
703756d0b0 | ||
|
|
50d22f8e77 | ||
|
|
fde2efd4ce | ||
|
|
0150c3a37d | ||
|
|
2a0216b9aa | ||
|
|
a6d14d86b8 | ||
|
|
a9374c128b | ||
|
|
f32b9f81da | ||
|
|
bf3af8e98e | ||
|
|
095c295ee5 | ||
|
|
93ecc9cfea | ||
|
|
e7aaa23fc2 | ||
|
|
197d3454f8 | ||
|
|
50a4f8b491 | ||
|
|
894b4967dd | ||
|
|
9837bd6664 | ||
|
|
6ca1b5dac4 | ||
|
|
c85135c04e | ||
|
|
31e4e42a94 | ||
|
|
196db04fc2 | ||
|
|
b3b1b5a471 | ||
|
|
892439a177 | ||
|
|
ba2e178e03 | ||
|
|
ed298bcedd | ||
|
|
6b04e6e674 | ||
|
|
04c0f6a0a5 | ||
|
|
486ff42b59 | ||
|
|
f7ab484510 | ||
|
|
f50a14305a | ||
|
|
d5f0cd7616 | ||
|
|
67c658f5b4 | ||
|
|
ef3bc03343 | ||
|
|
e31cb2b46a | ||
|
|
6ca7142ea4 | ||
|
|
8b2174897a | ||
|
|
ac5eab0563 | ||
|
|
65414dcc1c | ||
|
|
5db352f5be | ||
|
|
9e7830ff77 | ||
|
|
5945c0e16b | ||
|
|
29ee141822 | ||
|
|
8a69621e87 | ||
|
|
1645b0c4ea | ||
|
|
45205574d5 | ||
|
|
71a5e0394a | ||
|
|
f286936c23 | ||
|
|
9000f92a55 | ||
|
|
8c84d4b3c8 | ||
|
|
1d77afcc44 | ||
|
|
835bc6044b | ||
|
|
ef895a1ab9 | ||
|
|
82039cedaf | ||
|
|
973df61dfd | ||
|
|
661c85d7a6 | ||
|
|
4638f67fb7 | ||
|
|
ab71dbcd4f | ||
|
|
2abdabc100 | ||
|
|
9f78a2c8e1 | ||
|
|
76f78601f2 | ||
|
|
4eaba2dc56 | ||
|
|
2dcd9cb5f7 | ||
|
|
2943872bde | ||
|
|
b901542a48 | ||
|
|
c122ff8960 | ||
|
|
e128d818c4 | ||
|
|
5e9d6d0a91 | ||
|
|
70edf9cbe3 | ||
|
|
e61a0a9391 | ||
|
|
f8ddf98404 | ||
|
|
55219467f3 | ||
|
|
74d4be1ac6 | ||
|
|
9e57f8c6f1 | ||
|
|
3d2903cb47 | ||
|
|
13e9d22ec6 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -58,6 +58,7 @@ coverage.xml
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
coverage.out
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
|
||||
318
Alma.md
318
Alma.md
@@ -1,318 +0,0 @@
|
||||
# SPQA Policy and State for Alma Security
|
||||
|
||||
## Document Purpose
|
||||
|
||||
This document captures the SPQA policy and State for Alma Security, a security startup out of Redwood City, Ca.
|
||||
|
||||
This is part of the SPQA context that will be used to answer questions and create artifacts for the company, e.g., company strategy, security strategy, quarterly security reports (QSRs), project plans, recommendations on which projects to undertake, which investments to take and avoid, and other such decisions.
|
||||
|
||||
A major aspect of the SPQA system is the definition of the company's mission, goals, KPIs, and challenges. These shape everything within the company and thus should be used to shape the recommendations made when asked.
|
||||
|
||||
In addition to the clearly stated goals and other defining characteristics listed above, there will also be a streaming list of updates coming into this system using the Activity document.
|
||||
|
||||
Those will be changes, updates, or modifications to the direction of the company. For example, if Goal number 4 is to build a new datacenter in Boise, Idaho, but we see an update in the Activity section that says we've lost the ability to build in Boise, we should consider goal #4 out of the picture for prioritization and other decision purposes. In other words, the streaming activity log into this document should be considered updates to the core content.
|
||||
|
||||
## Company History
|
||||
|
||||
Alma Security was started by Chris Meyers, who was previously at Sigma Systems as CTO and HPE as a senior security engineer.
|
||||
|
||||
He started the company because, "I saw a gap in the authentication market, where companies were only looking at one or two aspects of one's identity to do authentication. They we're looking at the whole picture and turning that into a continuous authentication story."
|
||||
|
||||
## Company Mission
|
||||
|
||||
The mission of Alma Security is to ensure businesses can continuously authenticate their users using their whole selves.
|
||||
|
||||
## Company Goals (G1 means goal 1, G2 is goal 2, etc. Treat each item (goal/kpi/etc) as half as important as the one before it.)
|
||||
|
||||
NOTE: Some goals are things like project rollout which serve the higher goals. In that case they shouldn't always be considered so much lower priority because one is serving the other.
|
||||
|
||||
## Company Goals
|
||||
|
||||
- G1: Achieve 20% market share by January 2025
|
||||
- G2: Hit 10000 active customers by January 2025
|
||||
- G3: Hit a customer trust score of 90+% by January 2025
|
||||
- G4: Get churn below 5% by August 2024
|
||||
- G5: Launch in Europe by August 2024
|
||||
- G6: Launch in India by November 2024
|
||||
- G7: Launch Mood-monitor integration by February 2024
|
||||
- G8: Launch partnership with Apple Passkeys by June 2024
|
||||
|
||||
## Company KPIs
|
||||
|
||||
- K1: Current market share percentage
|
||||
- K2: Number of active customers
|
||||
- K3: Current churn percentage
|
||||
- K4: Launched_in_Europe (yes/no)
|
||||
- K4: Launched_in_India (yes/no)
|
||||
|
||||
-----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
## Security Team Mission
|
||||
|
||||
- SM1: Protect Alma Security's customers and intellectual property from security and privacy incidents.
|
||||
|
||||
## Security Team Goals
|
||||
|
||||
- SG1: Secure all customer data -- especially biometric -- from security and privacy incidents.
|
||||
- SG2: Protect Alma Security's intellectual property from being captured by unauthorized parties.
|
||||
- SG3: Reach a time to detect malicious behavior of less than 4 minutes by January 2025
|
||||
- SG4: Ensure the public trusts our product, because it's an authentication product we can't survive if people don't trust us.
|
||||
- SG5: Reach a time to remediate critical vulnerabilities on crown jewel systems of less than 16 hours by August 2025
|
||||
- SG6: Reach a time to remediate critical vulnerabilities on all systems of less than 3 days by August 2025
|
||||
- SG5: Reach a time to remediate critical vulnerabilities on crown jewel systems of less than 16 hours by August 2025
|
||||
- SG6: Reach a time to remediate critical vulnerabilities on all systems of less than 3 days by August 2025
|
||||
- SG7: Complete audit of Apple Passkey integration by February 2025
|
||||
- SG8: Complete remediation of Apple Passkey vulnerabilities by February 2025
|
||||
|
||||
## Security Team KPIs (How we measure the team)
|
||||
|
||||
- SK1: TTD: Time to detect malicious behavior (Minutes)
|
||||
- SK1: TTI: Time to begin investigation of malicious behavior (Minutes)
|
||||
- SK3: TTR-CJC: Time to remediate critical vulnerabilities on crown jewel systems (Hours)
|
||||
- SK3: TTR-C: Time to remediate critical vulnerabilities on all systems (Hours)
|
||||
- SK4: PT: Public trust score (Complete, Significant, Moderate, Minimal, Distrust, N/A)
|
||||
|
||||
## Risk Register (The things we're most worried about)
|
||||
|
||||
- R1: Our infrastructure security team is understaffed by 50% after 5 key people left
|
||||
- R2: We are not currently monitoring our external perimeter for attack surface related vulnerabilities like open ports, listening applications, unknown hosts, unknown subdomains pointing to these things, etc. We only do scans once every couple of months and we don't really have anyone to look at the results
|
||||
- R3: It takes us multiple days to investigate potential malicious behavior on our systems.
|
||||
- R4: We lack a full list of our assets, including externally facing hosts, S3 buckets, etc., which make up our attack surface
|
||||
- R5: We have a low public trust score due to the events of 2022.
|
||||
|
||||
## Security Team Narrative
|
||||
|
||||
### Background
|
||||
|
||||
Alma hired a new security team starting in January of 2023 and we have been building out the program since then. The philosophy and approach for the security team is to explicitly articulate what we believe the highest risks are to Alma, to deploy targeted strategies to address those risks, and to use clear, transparent KPIs to show progress towards our goals over time.
|
||||
|
||||
### Current Risks
|
||||
|
||||
So our risk register looks like this:
|
||||
|
||||
1. We are understaffed by 50% after 5 key people left in 2022
|
||||
2. Our perimeter is not being monitored for attack surface related vulnerabilities
|
||||
3. It takes us too long to detect and start investigating malicious behavior on our systems
|
||||
4. We do not have a full list of our assets, which makes it difficult to know what we need to protect
|
||||
5. We have a low public trust score due to the events of 2022
|
||||
|
||||
### Strategies
|
||||
|
||||
As such, our strategies are as follows:
|
||||
|
||||
1. Hire 5 more A-tier security professionals
|
||||
2. Purchase and implement an attack surface management solution
|
||||
3. Invest in our detection and response capabilities
|
||||
4. Purchase an asset inventory system that integrates with our attack surface management tool
|
||||
5. Leverage PR to share as much of our progress as possible with the public to rebuild trust
|
||||
|
||||
### How We're Doing
|
||||
|
||||
We believe being transparent about our progress is key to everything, and for that reason we maintain a limited number of KPIs that we update every quarter. These metrics will not change often. They will remain consistent so that it's easy to track how we're spending our resources and the progress we're making.
|
||||
|
||||
Those KPIs are:
|
||||
|
||||
1. Time to detect malicious behavior
|
||||
2. Time to start investigating malicious behavior
|
||||
3. Time to remediate critical vulnerabilities on crown jewel systems
|
||||
4. Time to remediate critical vulnerabilities on all systems
|
||||
5. Our public trust score
|
||||
|
||||
As of $DATE$, our KPIs for these are currently:
|
||||
|
||||
$GIVE CURRENT KPIs from the Activity section below$
|
||||
|
||||
$INSERT GRAPHS OF KPI PROGRESS OVER TIME HERE$
|
||||
|
||||
## Security Team Strategies
|
||||
|
||||
- STS1: Hire 5 more A-tier security professionals
|
||||
- STS2: Purchase an attack surface management solution
|
||||
- STS3: Invest in our detection and response capabilities
|
||||
- STS4: Purchase an asset inventory system that integrates with our attack surface management tool
|
||||
|
||||
## Infrastructure Notes (a basic description of our tech stack and various context around it)
|
||||
|
||||
- We currently have no WAF protecting our main web app but we're considering adding one
|
||||
- We have had some issues with S3 buckets becoming public, or being set up as public, which has lead to some close calls with customer data almost being exposed.
|
||||
- alma.amazon-domain.com is our primary S3 bucket that contains everything, but it's not public readable or listable
|
||||
- We have a root account for our AWS account that doesn't yet have 2FA on it, but we're working on fixing that within a few weeks (but it's been open for a few months)
|
||||
- We also use Postgres for all our databases.
|
||||
- Developers have root access to the all kubernetes nodes via SSH on port 45,001 using a shared developer key issued during laptop provisioning.
|
||||
- We're a kubernetes shop and do everything through AWS
|
||||
- We're logging most stuff to Cloudtrail and we kind of use Amazon Guarduty, but we don't have a 24/7 team to monitor alerts and logs. We should add that to our list of challenges next time we update our overall policy
|
||||
- We also have a Windows infrastructure because some key personnel came from Microsoft. The DC is hosted in our head office which is in Redwood City, and anyone who works in that office (most of the 300 employees) uses that to log in when they start work. The domain is ALMA.
|
||||
- There's a domain-joined fileserver running Windows 2012 that most people use to upload new ideas and plans for new products. It uses Windows authentication from the domain.
|
||||
- We use a Palo Alto Networks firewall with 2fa using windows authenticator tied to SSO.
|
||||
- The name of the AI system doing all this context creation using SPQA is Alma, which is also the name of the company.
|
||||
- We use Workday for HR stuff. Slack for realtime communications. Outlook 365 as a service. Sentinel One on the workstations and laptops. Servers in AWS are mostly Amazon Linux 2 with a few Ubuntu boxes that are a few years old.
|
||||
- We also primarily use Postgres for all of our systems.
|
||||
|
||||
## Team
|
||||
|
||||
TEAM MEMBER | TEAM ASSIGNED | SKILLS | PAY LEVEL | LOCATION | PROJECTS
|
||||
|
||||
Nadia Khan | Detection and Response | D&R (Expert), AWS (Strong), Python (Expert), Kubernetes (Basic), Postgres (Basic) | $249K | Redwood City
|
||||
Chris Magann | Vulnerability Management | VM (Expert), AWS (Strong), Python (Basic), Postgres (Basic) | $212K | Redwood City
|
||||
Tigan Wang | Vulnerability Management | VM (Expert), AWS (Strong), Python (Basic), Postgres (Basic) | $217K | Redwood City
|
||||
|
||||
## Projects
|
||||
|
||||
PROJECT NAME | PROJECT DESCRIPTION | PROJECT PRIORITY | PROJECT MEMBERS | START DATE | END DATE | STATUS | PROJECT COST
|
||||
|
||||
WAF Install | Install a WAF in front of our main web app | Critical | Nadia Khan | 2024-01-01 - Ongoing | In Progress | $112K one-time, $9K/month
|
||||
|
||||
Multi-Factor Authentication (MFA) Rollout | Implement MFA across all internal and external systems | Critical | Chris Magann | 2024-01-15 | 2024-05-01 | Planned | $80K one-time, $5K/month
|
||||
|
||||
Procure and Implement ASM | Implement continuous monitoring for attack surface vulnerabilities | High | Tigan Wang | 2024-02-15 | 2024-06-15 | Not Started | $75K one-time, $6K/month
|
||||
|
||||
Data Encryption Upgrade | Upgrade encryption protocols for all sensitive data | Medium | Nadia Khan | 2024-04-01 | 2024-08-01 | Planned | $95K one-time
|
||||
|
||||
Incident Response Enhancement | Develop and implement a 24/7 incident response team | High | Nadia Khan | 2024-03-01 | 2024-07-01 | In Progress | $150K one-time, $10K/month
|
||||
|
||||
Cloud Security Optimization | Optimize AWS cloud security configurations and practices | Medium | Tigan Wang | 2024-02-01 | 2024-06-01 | In Progress | $100K one-time, $8K/month
|
||||
|
||||
S3 Bucket Security | Review and secure all S3 buckets to prevent data breaches | High | Chris Magann | 2024-01-10 | 2024-04-10 | In Progress | $70K one-time, $5K/month
|
||||
|
||||
SQL Injection Mitigation | Implement measures to eliminate SQL injection vulnerabilities | High | Tigan Wang | 2024-01-20 | 2024-05-20 | Not Started | $60K one-time
|
||||
|
||||
## SECURITY POSTURE (To be referenced for compliance questions and security questionnaires)
|
||||
|
||||
July 2019
|
||||
Admin accounts still not required to use 2FA.
|
||||
Company laptops distributed to employees, no MDM yet for device management.
|
||||
AWS IAM roles created for engineers, but root access still frequently used.
|
||||
Started basic vulnerability scanning using open-source tools.
|
||||
December 2019
|
||||
|
||||
MFA enforced for all Google Workspace accounts after a phishing attempt.
|
||||
Introduced ClamAV for basic endpoint protection on corporate laptops.
|
||||
AWS GuardDuty enabled for threat detection, but no formal incident response team.
|
||||
First incident response plan table-top exercise conducted, but findings not fully documented.
|
||||
April 2020
|
||||
|
||||
Migrated from Google Workspace to Office 365, with MFA enabled for all users.
|
||||
Rolled out SentinelOne for endpoint protection on 50% of company laptops.
|
||||
Implemented least-privilege access control for AWS IAM roles.
|
||||
First formal vendor risk management review completed for major SaaS providers.
|
||||
August 2020
|
||||
|
||||
Completed full deployment of SentinelOne across all endpoints.
|
||||
Implemented AWS CloudWatch for real-time alerts; however, logs still not monitored 24/7.
|
||||
Began encrypting all AWS S3 buckets at rest using server-side encryption.
|
||||
First internal review of data retention policies, started drafting data disposal policy.
|
||||
January 2021
|
||||
|
||||
Rolled out Jamf MDM for centralized management of macOS devices, enforcing encryption (FileVault) on all laptops.
|
||||
Strengthened Office 365 security by implementing phishing-resistant MFA using authenticator apps.
|
||||
AWS KMS introduced for managing encryption keys; manual key rotation policy documented.
|
||||
Introduced formal onboarding and offboarding processes for employee account management.
|
||||
July 2021
|
||||
|
||||
Conditional access policies introduced for Office 365, restricting access based on geography (US-only).
|
||||
Conducted company-wide security awareness training for the first time, focusing on phishing threats.
|
||||
Completed first backup and disaster recovery (DR) drill with AWS, documenting recovery times.
|
||||
AWS Config deployed to monitor and enforce encryption and access control policies across accounts.
|
||||
December 2021
|
||||
|
||||
Full migration to AWS for all production systems completed.
|
||||
Incident response playbook finalized and shared with the security team; still no 24/7 monitoring.
|
||||
Documented data classification policies for handling sensitive customer data in preparation for SOC 2 audit.
|
||||
First third-party penetration test conducted, critical vulnerabilities identified and remediated within 30 days.
|
||||
March 2022
|
||||
|
||||
Rolled out company-wide 2FA for all critical systems, including Office 365, AWS, GitHub, and Slack.
|
||||
Introduced AWS Secrets Manager for managing sensitive credentials, eliminating hardcoded API keys.
|
||||
Updated all documentation for identity and access management in preparation for SOC 2 Type 1 audit.
|
||||
First external vulnerability scan completed using Qualys, with remediation SLAs established.
|
||||
April 2022
|
||||
|
||||
Updated and consolidated all security policies (incident response, access control, data retention) in preparation for SOC 2 audit.
|
||||
Conducted tabletop exercise for ransomware response, documenting gaps in the incident response process.
|
||||
Implemented Just-In-Time (JIT) access for administrative privileges in AWS, reducing unnecessary persistent access.
|
||||
October 2022
|
||||
|
||||
Passed SOC 2 Type 1 audit, with recommendations to improve monitoring and asset management.
|
||||
Launched quarterly phishing simulations to raise employee awareness and track training effectiveness.
|
||||
Fully enforced encryption for all customer data in transit and at rest using AWS KMS.
|
||||
Extended GuardDuty to cover all AWS regions; started monitoring alerts daily.
|
||||
January 2023
|
||||
|
||||
Hired a dedicated CISO and expanded security team by 30%.
|
||||
Integrated continuous vulnerability scanning across all externally facing assets using Qualys.
|
||||
Conducted first third-party vendor risk assessment to ensure alignment with SOC 2 and internal security standards.
|
||||
Implemented automated patch management for all AWS EC2 instances, reducing time to deploy critical patches.
|
||||
July 2023
|
||||
|
||||
Rolled out continuous attack surface monitoring (ASM) to identify and remediate external vulnerabilities.
|
||||
Performed annual data retention review, ensuring compliance with SOC 2 and GDPR requirements.
|
||||
Conducted a disaster recovery drill for AWS workloads, achieving a recovery time objective (RTO) of under 4 hours.
|
||||
Completed SOC 2 Type 2 readiness assessment, with focus on improving incident response times.
|
||||
November 2023
|
||||
|
||||
Updated incident response documentation and assigned 24/7 monitoring to a third-party SOC provider.
|
||||
Rolled out zero-trust network architecture across the organization, removing reliance on VPN for remote access.
|
||||
Passed SOC 2 Type 2 audit with no major findings; recommendations included improved asset inventory tracking.
|
||||
Conducted full audit of access control policies and JIT access implementation in preparation for ISO 27001 certification.
|
||||
April 2024
|
||||
|
||||
Implemented AI-driven threat detection to reduce time to detect security incidents from 10 hours to under 2 hours.
|
||||
Completed full encryption audit across all databases, ensuring compliance with GDPR, HIPAA, and other privacy regulations.
|
||||
Updated employee training programs to include privacy regulations (GDPR, CCPA) and data handling best practices.
|
||||
Completed internal review and audit of vendor access to critical systems as part of SOC 2 compliance effort.
|
||||
Completed move of all AWS services to us-west-2 and us-east-1 regions for 100% us-based cloud services.
|
||||
October 2024
|
||||
|
||||
Conducted organization-wide review of data retention and disposal policies, implementing automated data deletion for expired data.
|
||||
Implemented continuous compliance monitoring for SOC 2, with automated alerts for deviations in access controls and encryption settings.
|
||||
Finalized implementation of AI-based monitoring and response systems, significantly reducing time to remediate critical vulnerabilities.
|
||||
Passed SOC 2 Type 2 and ISO 27001 audits with zero non-conformities, achieving full compliance across all control areas.March 2018
|
||||
|
||||
Personal Gmail accounts used for internal and external communication.
|
||||
No 2FA enabled on any accounts.
|
||||
AWS accounts shared with engineers, no IAM roles or formal access control policies.
|
||||
No centralized endpoint protection; employees use personal laptops with no security controls.
|
||||
No documented security policies or incident response plan.
|
||||
September 2018
|
||||
|
||||
Initiated migration from personal Gmail to Google Workspace (G Suite) for business email.
|
||||
Password complexity requirements introduced (minimum 8 characters).
|
||||
AWS root credentials still shared among team members, no MFA enabled.
|
||||
No formal logging or monitoring in place for AWS activity.
|
||||
February 2019
|
||||
|
||||
Completed migration to Google Workspace; no email encryption yet.
|
||||
Introduced a basic password manager (LastPass) but no enforcement policy.
|
||||
AWS CloudTrail enabled for logging, but no one is reviewing logs.
|
||||
First draft of the incident response plan created, but not tested.
|
||||
June 2019
|
||||
|
||||
Enforced MFA for Google Workspace admin accounts; standard user
|
||||
|
||||
## CURRENT STATE (KPIs, Metrics, Project Activity Updates, etc.)
|
||||
|
||||
- October 2022: Current time to detect malicious behavior is 81 hours
|
||||
- October 2022: Current time to start investigating malicious behavior is 82 hours
|
||||
- October 2022: Current time to remediate critical vulnerabilities on crown jewel systems is 21 days
|
||||
- October 2022: Current time to remediate critical vulnerabilities on all systems is 51 days
|
||||
- January 2023: Current time to detect malicious behavior is 62 hours
|
||||
- January 2023: Current time to start investigating malicious behavior is 72 hours
|
||||
- January 2023: Current time to remediate critical vulnerabilities on crown jewel systems is 17 days
|
||||
- January 2023: Current time to remediate critical vulnerabilities on all systems is 43 days
|
||||
- July 2023: Current time to detect malicious behavior is 29 hours
|
||||
- July 2023: Current time to start investigating malicious behavior is 41 hours
|
||||
- July 2023: Current time to remediate critical vulnerabilities on crown jewel systems is 12 days
|
||||
- July 2023: Current time to remediate critical vulnerabilities on all systems is 29 days
|
||||
- November 2023: Current time to start detect malicious behavior is 12 hours
|
||||
- November 2023: Current time to start investigating malicious behavior is 16 hours
|
||||
- November 2023: Current time to remediate critical vulnerabilities on crown jewel systems is 9 days
|
||||
- November 2023: Current time to remediate critical vulnerabilities on all systems is 17 days
|
||||
- February 2024: Started attack surface management vendor selection process
|
||||
- January 2024: Current time to start detect malicious behavior is 9 hours
|
||||
- January 2024: Current time to start investigating malicious behavior is 14 hours
|
||||
- January 2024: Current time to remediate critical vulnerabilities on crown jewel systems is 8 days
|
||||
- January 2024: Current time to remediate critical vulnerabilities on all systems is 12 days
|
||||
- March 2024: We're now remediating critical vulnerabilities on crown jewels in less than 6 days
|
||||
- April 2024: We're now remediating all critical vulnerabilities within 11 days
|
||||
- July 2024: critical vulnerabilities are now being fixed in 9 days
|
||||
- On August 5 we got remediation of critical vulnerabilities down to 7 days
|
||||
@@ -1,5 +1,5 @@
|
||||
# Use official golang image as builder
|
||||
FROM golang:1.23.3-alpine AS builder
|
||||
FROM golang:1.24.2-alpine AS builder
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
@@ -1693,8 +1693,87 @@
|
||||
},
|
||||
{
|
||||
"patternName": "extract_wisdom_short",
|
||||
"description": "Extract condensed insightful ideas and recommendations focusing on life wisdom.",
|
||||
"tags": [
|
||||
"EXTRACT",
|
||||
"WISDOM",
|
||||
"SELF"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "analyze_bill",
|
||||
"description": "Analyze a legislative bill and implications.",
|
||||
"tags": [
|
||||
"ANALYSIS",
|
||||
"BILL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "analyze_bill_short",
|
||||
"description": "Consended - Analyze a legislative bill and implications.",
|
||||
"tags": [
|
||||
"ANALYSIS",
|
||||
"BILL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "create_coding_feature",
|
||||
"description": "[Description pending]",
|
||||
"tags": []
|
||||
"tags": [
|
||||
"DEVELOPMENT"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "create_excalidraw_visualization",
|
||||
"description": "Create visualizations using Excalidraw.",
|
||||
"tags": [
|
||||
"VISUALIZATION"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "create_flash_cards",
|
||||
"description": "Generate flashcards for key concepts and definitions.",
|
||||
"tags": [
|
||||
"LEARNING"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "create_loe_document",
|
||||
"description": "Create detailed Level of Effort (LOE) estimation documents.",
|
||||
"tags": [
|
||||
"DEVELOPMENT",
|
||||
"BUSINESS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "extract_domains",
|
||||
"description": "Extract key content and source.",
|
||||
"tags": [
|
||||
"EXTRACT",
|
||||
"ANALYSIS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "extract_main_activities",
|
||||
"description": "Extract and list main events from transcripts.",
|
||||
"tags": [
|
||||
"EXTRACT",
|
||||
"ANALYSIS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "find_female_life_partner",
|
||||
"description": "Clarify and summarize partner criteria in direct language.",
|
||||
"tags": [
|
||||
"SELF"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "youtube_summary",
|
||||
"description": "Summarize YouTube videos with key points and timestamps.",
|
||||
"tags": [
|
||||
"SUMMARIZE"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -823,6 +823,46 @@
|
||||
{
|
||||
"patternName": "extract_wisdom_short",
|
||||
"pattern_extract": "# IDENTITY and PURPOSE You extract surprising, insightful, and interesting information from text content. You are interested in insights related to the purpose and meaning of life, human flourishing, the role of technology in the future of humanity, artificial intelligence and its affect on humans, memes, learning, reading, books, continuous improvement, and similar topics. Take a step back and think step-by-step about how to achieve the best possible results by following the steps below. # STEPS - Extract a summary of the content in 50 words, including who is presenting and the content being discussed into a section called SUMMARY. - Extract 10 to 20 of the most surprising, insightful, and/or interesting ideas from the input in a section called IDEAS:. If there are less than 50 then collect all of them. Make sure you extract at least 20. - Extract 5 to 10 of the best insights from the input and from a combination of the raw input and the IDEAS above into a section called INSIGHTS. These INSIGHTS should be fewer, more refined, more insightful, and more abstracted versions of the best ideas in the content. - Extract 10 TO 15 of the most surprising, insightful, and/or interesting quotes from the input into a section called QUOTES:. Use the exact quote text from the input. - Extract 5 to 10 of the most practical and useful personal habits of the speakers, or mentioned by the speakers, in the content into a section called HABITS. Examples include but aren't limited to: sleep schedule, reading habits, things they always do, things they always avoid, productivity tips, diet, exercise, etc. - Extract 5 to 10 of the most surprising, insightful, and/or interesting valid facts about the greater world that were mentioned in the content into a section called FACTS:. - Extract all mentions of writing, art, tools, projects and other sources of inspiration mentioned by the speakers into a section called REFERENCES. This should include any and all references to something that the speaker mentioned. - Extract the most potent takeaway and recommendation into a section called ONE-SENTENCE TAKEAWAY. This should be a 15-word sentence that captures the most important essence of the content. - Extract the 5 to 10 of the most surprising, insightful, and/or interesting recommendations that can be collected from the content into a section called RECOMMENDATIONS. # OUTPUT INSTRUCTIONS - Only output Markdown. - Write the IDEAS bullets as exactly 16 words. - Write the RECOMMENDATIONS bullets as exactly 16 words. - Write the HABITS bullets as exactly 16 words. - Write the FACTS bullets as exactly 16 words. - Write the INSIGHTS bullets as exactly 16 words. - Extract at least 25 IDEAS from the content. - Extract at least 5 INSIGHTS from the content. - Extract at least 10 items for the other output sections. - Do not give warnings or notes; only output the requested sections. - You use bulleted lists for output, not numbered lists. - Do not repeat ideas, quotes, facts, or"
|
||||
},
|
||||
{
|
||||
"patternName": "analyze_bill",
|
||||
"pattern_extract": "# IDENTITY You are an AI with a 3,129 IQ that specializes in discerning the true nature and goals of a piece of legislation. It captures all the overt things, but also the covert ones as well, and points out gotchas as part of it's summary of the bill. # STEPS 1. Read the entire bill 37 times using different perspectives. 2. Map out all the stuff it's trying to do on a 10 KM by 10K mental whiteboard. 3. Notice all the overt things it's trying to do, that it doesn't mind being seen. 4. Pay special attention to things its trying to hide in subtext or deep in the document. # OUTPUT 1. Give the metadata for the bill, such as who proposed it, when, etc. 2. Create a 24-word summary of the bill and what it's trying to accomplish. 3. Create a section called OVERT GOALS, and list 5-10 16-word bullets for those. 4. Create a section called COVERT GOALS, and list 5-10 16-word bullets for those. 5. Create a conclusion sentence that gives opinionated judgement on whether the bill is mostly overt or mostly dirty with ulterior motives."
|
||||
},
|
||||
{
|
||||
"patternName": "analyze_bill_short",
|
||||
"pattern_extract": "# IDENTITY You are an AI with a 3,129 IQ that specializes in discerning the true nature and goals of a piece of legislation. It captures all the overt things, but also the covert ones as well, and points out gotchas as part of it's summary of the bill. # STEPS 1. Read the entire bill 37 times using different perspectives. 2. Map out all the stuff it's trying to do on a 10 KM by 10K mental whiteboard. 3. Notice all the overt things it's trying to do, that it doesn't mind being seen. 4. Pay special attention to things its trying to hide in subtext or deep in the document. # OUTPUT 1. Give the metadata for the bill, such as who proposed it, when, etc. 2. Create a 16-word summary of the bill and what it's trying to accomplish. 3. Create a section called OVERT GOALS, and list the main overt goal in 8 words and 2 supporting goals in 8-word sentences. 3. Create a section called COVERT GOALS, and list the main covert goal in 8 words and 2 supporting goals in 8-word sentences. 5. Create an 16-word conclusion sentence that gives opinionated judgement on whether the bill is mostly overt or mostly dirty with ulterior motives."
|
||||
},
|
||||
{
|
||||
"patternName": "create_coding_feature",
|
||||
"pattern_extract": "# IDENTITY and PURPOSE You are an elite programmer. You take project ideas in and output secure and composable code using the format below. You always use the latest technology and best practices. Take a deep breath and think step by step about how to best accomplish this goal using the following steps. Input is a JSON file with the following format: Example input: ```json [ { \"type\": \"directory\", \"name\": \".\", \"contents\": [ { \"type\": \"file\", \"name\": \"README.md\", \"content\": \"This is the README.md file content\" }, { \"type\": \"file\", \"name\": \"system.md\", \"content\": \"This is the system.md file contents\" } ] }, { \"type\": \"report\", \"directories\": 1, \"files\": 5 }, { \"type\": \"instructions\", \"name\": \"code_change_instructions\", \"details\": \"Update README and refactor main.py\" } ] ``` The object with `\"type\": \"instructions\"`, and field `\"details\"` contains the for the instructions for the suggested code changes. The `\"name\"` field is always `\"code_change_instructions\"` The `\"details\"` field above, with type `\"instructions\"` contains the instructions for the suggested code changes. ## File Management Interface Instructions You have access to a powerful file management system with the following capabilities: ### File Creation and Modification - Use the **EXACT** JSON format below to define files that you want to be changed - If the file listed does not exist, it will be created - If a directory listed does not exist, it will be created - If the file already exists, it will be overwritten - It is **not possible** to delete files ```plaintext __CREATE_CODING_FEATURE_FILE_CHANGES__ [ { \"operation\": \"create\", \"path\": \"README.md\", \"content\": \"This is the new README.md file content\" }, { \"operation\": \"update\", \"path\": \"src/main.c\", \"content\": \"int main(){return 0;}\" } ] ``` ### Important Guidelines - Always use relative paths from the project root - Provide complete, functional code when creating or modifying files - Be precise and concise in your file operations - Never create files outside of the project root ### Constraints - Do not attempt to read or modify files outside the project root directory. - Ensure code follows best practices and is production-ready. - Handle potential errors gracefully in your code suggestions. - Do not trust external input to applications, assume users are malicious. ### Workflow 1. Analyze the user's request 2. Determine necessary file operations 3. Provide clear, executable file creation/modification instructions 4. Explain the purpose and functionality of proposed changes ## Output Sections - Output a summary of the file changes - Output directory and file changes according to File Management Interface Instructions, in a json array marked by `__CREATE_CODING_FEATURE_FILE_CHANGES__` - Be exact in the `__CREATE_CODING_FEATURE_FILE_CHANGES__` section, and do not deviate from the proposed JSON format. - **never** omit the `__CREATE_CODING_FEATURE_FILE_CHANGES__` section. - If the proposed changes change how the project is built and installed, document these changes in the projects README.md - Implement build configurations changes if needed, prefer ninja if nothing already exists in the project, or is otherwise specified. - Document new dependencies according to best practices for the language used in the project. - Do not output sections that were"
|
||||
},
|
||||
{
|
||||
"patternName": "create_excalidraw_visualization",
|
||||
"pattern_extract": "# IDENTITY You are an expert AI with a 1,222 IQ that deeply understands the relationships between complex ideas and concepts. You are also an expert in the Excalidraw tool and schema. You specialize in mapping input concepts into Excalidraw diagram syntax so that humans can visualize the relationships between them. # STEPS 1. Deeply study the input. 2. Think for 47 minutes about each of the sections in the input. 3. Spend 19 minutes thinking about each and every item in the various sections, and specifically how each one relates to all the others. E.g., how a project relates to a strategy, and which strategies are addressing which challenges, and which challenges are obstructing which goals, etc. 4. Build out this full mapping in on a 9KM x 9KM whiteboard in your mind. 5. Analyze and improve this mapping for 13 minutes. # KNOWLEDGE Here is the official schema documentation for creating Excalidraw diagrams. Skip to main content Excalidraw Logo Excalidraw Docs Blog GitHub Introduction Codebase JSON Schema Frames @excalidraw/excalidraw Installation Integration Customizing Styles API FAQ Development @excalidraw/mermaid-to-excalidraw CodebaseJSON Schema JSON Schema The Excalidraw data format uses plaintext JSON. Excalidraw files When saving an Excalidraw scene locally to a file, the JSON file (.excalidraw) is using the below format. Attributes Attribute Description Value type The type of the Excalidraw schema \"excalidraw\" version The version of the Excalidraw schema number source The source URL of the Excalidraw application \"https://excalidraw.com\" elements An array of objects representing excalidraw elements on canvas Array containing excalidraw element objects appState Additional application state/configuration Object containing application state properties files Data for excalidraw image elements Object containing image data JSON Schema example { // schema information \"type\": \"excalidraw\", \"version\": 2, \"source\": \"https://excalidraw.com\", // elements on canvas \"elements\": [ // example element { \"id\": \"pologsyG-tAraPgiN9xP9b\", \"type\": \"rectangle\", \"x\": 928, \"y\": 319, \"width\": 134, \"height\": 90 /* ...other element properties */ } /* other elements */ ], // editor state (canvas config, preferences, ...) \"appState\": { \"gridSize\": 20, \"viewBackgroundColor\": \"#ffffff\" }, // files data for \"image\" elements, using format `{ [fileId]: fileData }` \"files\": { // example of an image data object \"3cebd7720911620a3938ce77243696149da03861\": { \"mimeType\": \"image/png\", \"id\": \"3cebd7720911620a3938c.77243626149da03861\", \"dataURL\": \"data:image/png;base64,iVBORWOKGgoAAAANSUhEUgA=\", \"created\": 1690295874454, \"lastRetrieved\": 1690295874454 } /* ...other image data objects */ } } Excalidraw clipboard format When copying selected excalidraw elements to clipboard, the JSON schema is similar to .excalidraw format, except it differs in attributes. Attributes Attribute Description Example Value type The type of the Excalidraw document. \"excalidraw/clipboard\" elements An array of objects representing excalidraw elements on canvas. Array containing excalidraw element objects (see example below) files Data for excalidraw image elements. Object containing image data Edit this page Previous Contributing Next Frames Excalidraw files Attributes JSON Schema example Excalidraw clipboard format Attributes Docs Get Started Community Discord Twitter Linkedin More Blog GitHub Copyright © 2023 Excalidraw community. Built with Docusaurus ❤️ # OUTPUT 1. Output the perfect excalidraw schema file that can be directly importted in to Excalidraw. This should have no preamble or follow-on text"
|
||||
},
|
||||
{
|
||||
"patternName": "create_flash_cards",
|
||||
"pattern_extract": "# IDENTITY You are an expert educator AI with a 4,221 IQ. You specialize in understanding the key concepts in a piece of input and creating flashcards for those key concepts. # STEPS - Fully read and comprehend the input and map out all the concepts on a 4KM x 4KM virtual whiteboard. - Make a list of the key concepts, definitions, terms, etc. that are associated with the input. - Create flashcards for each key concept, definition, term, etc. that you have identified. - The flashcard should be a question of 8-16 words and an answer of up to 32 words. # OUTPUT - Output the flashcards in Markdown format using no special characters like italics or bold (asterisks)."
|
||||
},
|
||||
{
|
||||
"patternName": "create_loe_document",
|
||||
"pattern_extract": "# Identity and Purpose You are an expert in software, cloud, and cybersecurity architecture. You specialize in creating clear, well-structured Level of Effort (LOE) documents for estimating work effort, resources, and costs associated with a given task or project. # Goal Given a description of a task or system, provide a detailed Level of Effort (LOE) document covering scope, business impact, resource requirements, estimated effort, risks, dependencies, and assumptions. # Steps 1. Analyze the input task thoroughly to ensure full comprehension. 2. Map out all key components of the task, considering requirements, dependencies, risks, and effort estimation factors. 3. Consider business priorities and risk appetite based on the nature of the organization. 4. Break the LOE document into structured sections for clarity and completeness. --- # Level of Effort (LOE) Document Structure ## Section 1: Task Overview - Provide a high-level summary of the task, project, or initiative being estimated. - Define objectives and expected outcomes. - Identify key stakeholders and beneficiaries. ## Section 2: Business Impact - Define the business problem this task is addressing. - List the expected benefits and value to the organization. - Highlight any business risks or regulatory considerations. ## Section 3: Scope & Deliverables - Outline in-scope and out-of-scope work. - Break down major deliverables and milestones. - Specify acceptance criteria for successful completion. ## Section 4: Resource Requirements - Identify required skill sets and roles (e.g., software engineers, security analysts, cloud architects, scrum master , project manager). - Estimate the number of personnel needed , in tabular format. - List tooling, infrastructure, or licenses required. ## Section 5: Estimated Effort - Break down tasks into granular units (e.g., design, development, testing, deployment). - Provide time estimates per task in hours, days, or sprints, in tabular format. - Aggregate total effort for the entire task or project. - Include buffer time for unforeseen issues or delays. - Use T-shirt sizing (S/M/L/XL) or effort points to classify work complexity. ## Section 6: Dependencies - List external dependencies (e.g., APIs, third-party vendors, internal teams). - Specify hardware/software requirements that may impact effort. ## Section 7: Risks & Mitigations - Identify technical, security, or operational risks that could affect effort. - Propose mitigation strategies to address risks. - Indicate if risks could lead to effort overruns. ## Section 8: Assumptions & Constraints - List key assumptions that influence effort estimates. - Identify any constraints such as budget, team availability, or deadlines. ## Section 9: Questions & Open Items - List outstanding questions or clarifications required to refine the LOE. - Highlight areas needing further input from stakeholders. --- # Output Instructions - Output the LOE document in valid Markdown format. - Do not use bold or italic formatting. - Do not provide commentary or disclaimers, just execute the request. # Input Input: [Provide the specific task or project for estimation here]"
|
||||
},
|
||||
{
|
||||
"patternName": "extract_domains",
|
||||
"pattern_extract": "# IDENTITY and PURPOSE You extract domains and URLs from input like articles and newsletters for the purpose of understanding the sources that were used for their content. # STEPS - For every story that was mentioned in the article, story, blog, newsletter, output the source it came from. - The source should be the central source, not the exact URL necessarily, since the purpose is to find new sources to follow. - As such, if it's a person, link their profile that was in the input. If it's a Github project, link the person or company's Github, If it's a company blog, output link the base blog URL. If it's a paper, link the publication site. Etc. - Only output each source once. - Only output the source, nothing else, one per line # INPUT INPUT:"
|
||||
},
|
||||
{
|
||||
"patternName": "extract_main_activities",
|
||||
"pattern_extract": "# IDENTITY You are an expert activity extracting AI with a 24,221 IQ. You specialize in taking any transcript and extracting the key events that happened. # STEPS - Fully understand the input transcript or log. - Extract the key events and map them on a 24KM x 24KM virtual whiteboard. - See if there is any shared context between the events and try to link them together if possible. # OUTPUT - Write a 16 word summary sentence of the activity. - Create a list of the main events that happened, such as watching media, conversations, playing games, watching a TV show, etc. # OUTPUT INSTRUCTIONS - Output only in Markdown with no italics or bolding."
|
||||
},
|
||||
{
|
||||
"patternName": "find_female_life_partner",
|
||||
"pattern_extract": "# IDENTITY AND PURPOSE You are a relationship and marriage and life happiness expert AI with a 4,227 IQ. You take criteria given to you about what a man is looking for in a woman life partner, and you turn that into a perfect sentence. # PROBLEM People aren't clear about what they're actually looking for, so they're too indirect and abstract and unfocused in how they describe it. They actually don't know what they want, so this analysis will tell them what they're not seeing for themselves that they need to acknowledge. # STEPS - Analyze all the content given to you about what they think they're looking for. - Figure out what they're skirting around and not saying directly. - Figure out the best way to say that in a clear, direct, sentence that answers the question: \"What would I tell people I'm looking for if I knew what I wanted and wasn't afraid.\" - Write the perfect 24-word sentence in these versions: 1. DIRECT: The no bullshit, revealing version that shows the person what they're actually looking for. Only 8 words in extremely straightforward language. 2. CLEAR: A revealing version that shows the person what they're really looking for. 3. POETIC: An equally accurate version that says the same thing in a slightly more poetic and storytelling way. # OUTPUT INSTRUCTIONS - Only output those two sentences, nothing else."
|
||||
},
|
||||
{
|
||||
"patternName": "youtube_summary",
|
||||
"pattern_extract": "# IDENTITY and PURPOSE You are an AI assistant specialized in creating concise, informative summaries of YouTube video content based on transcripts. Your role is to analyze video transcripts, identify key points, main themes, and significant moments, then organize this information into a well-structured summary that includes relevant timestamps. You excel at distilling lengthy content into digestible summaries while preserving the most valuable information and maintaining the original flow of the video. Take a step back and think step-by-step about how to achieve the best possible results by following the steps below. ## STEPS - Carefully read through the entire transcript to understand the overall content and structure of the video - Identify the main topic and purpose of the video - Note key points, important concepts, and significant moments throughout the transcript - Pay attention to natural transitions or segment changes in the video - Extract relevant timestamps for important moments or topic changes - Organize information into a logical structure that follows the video's progression - Create a concise summary that captures the essence of the video - Include timestamps alongside key points to allow easy navigation - Ensure the summary is comprehensive yet concise ## OUTPUT INSTRUCTIONS - Only output Markdown - Begin with a brief overview of the video's main topic and purpose - Structure the summary with clear headings and subheadings that reflect the video's organization - Include timestamps in [HH:MM:SS] format before each key point or section - Keep the summary concise but comprehensive, focusing on the most valuable information - Use bullet points for lists of related points when appropriate - Bold or italicize particularly important concepts or takeaways - End with a brief conclusion summarizing the video's main message or call to action - Ensure you follow ALL these instructions when creating your output. ## INPUT INPUT:"
|
||||
}
|
||||
]
|
||||
}
|
||||
67
README.md
67
README.md
@@ -1,4 +1,7 @@
|
||||
<div align="center">
|
||||
Fabric is graciously supported by…
|
||||
|
||||
[](https://warp.dev/fabric)
|
||||
|
||||
<img src="./images/fabric-logo-gif.gif" alt="fabriclogo" width="400" height="400"/>
|
||||
|
||||
@@ -56,6 +59,10 @@
|
||||
- [Save your files in markdown using aliases](#save-your-files-in-markdown-using-aliases)
|
||||
- [Migration](#migration)
|
||||
- [Upgrading](#upgrading)
|
||||
- [Shell Completions](#shell-completions)
|
||||
- [Zsh Completion](#zsh-completion)
|
||||
- [Bash Completion](#bash-completion)
|
||||
- [Fish Completion](#fish-completion)
|
||||
- [Usage](#usage)
|
||||
- [Our approach to prompting](#our-approach-to-prompting)
|
||||
- [Examples](#examples)
|
||||
@@ -73,15 +80,16 @@
|
||||
- [Clipboard Support](#clipboard-support)
|
||||
- [Meta](#meta)
|
||||
- [Primary contributors](#primary-contributors)
|
||||
- [Contributors](#contributors)
|
||||
|
||||
<br />
|
||||
|
||||
## Updates
|
||||
|
||||
> [!NOTE]
|
||||
> February 24, 2025
|
||||
> April 16, 2025
|
||||
>
|
||||
> - Fabric now supports Sonnet 3.7! Update and use `-S` to select it as your default if you want, or just use the shortcut `-m claude-3-7-sonnet-latest`. Enjoy!
|
||||
> - Fabric now supports Grok (from XAI)! Update and use `-S` to select it as your default if you want, or just use the shortcut `-m grok-3-beta`. Enjoy!
|
||||
|
||||
## What and why
|
||||
|
||||
@@ -407,6 +415,48 @@ The great thing about Go is that it's super easy to upgrade. Just run the same c
|
||||
go install github.com/danielmiessler/fabric@latest
|
||||
```
|
||||
|
||||
### Shell Completions
|
||||
|
||||
Fabric provides shell completion scripts for Zsh, Bash, and Fish
|
||||
shells, making it easier to use the CLI by providing tab completion
|
||||
for commands and options.
|
||||
|
||||
#### Zsh Completion
|
||||
|
||||
To enable Zsh completion:
|
||||
|
||||
```bash
|
||||
# Copy the completion file to a directory in your $fpath
|
||||
mkdir -p ~/.zsh/completions
|
||||
cp completions/_fabric ~/.zsh/completions/
|
||||
|
||||
# Add the directory to fpath in your .zshrc before compinit
|
||||
echo 'fpath=(~/.zsh/completions $fpath)' >> ~/.zshrc
|
||||
echo 'autoload -Uz compinit && compinit' >> ~/.zshrc
|
||||
```
|
||||
|
||||
#### Bash Completion
|
||||
|
||||
To enable Bash completion:
|
||||
|
||||
```bash
|
||||
# Source the completion script in your .bashrc
|
||||
echo 'source /path/to/fabric/completions/fabric.bash' >> ~/.bashrc
|
||||
|
||||
# Or copy to the system-wide bash completion directory
|
||||
sudo cp completions/fabric.bash /etc/bash_completion.d/
|
||||
```
|
||||
|
||||
#### Fish Completion
|
||||
|
||||
To enable Fish completion:
|
||||
|
||||
```bash
|
||||
# Copy the completion file to the fish completions directory
|
||||
mkdir -p ~/.config/fish/completions
|
||||
cp completions/fabric.fish ~/.config/fish/completions/
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Once you have it all set up, here's how to use it.
|
||||
@@ -415,7 +465,7 @@ Once you have it all set up, here's how to use it.
|
||||
fabric -h
|
||||
```
|
||||
|
||||
```bash
|
||||
```plaintext
|
||||
|
||||
Usage:
|
||||
fabric [OPTIONS]
|
||||
@@ -465,6 +515,7 @@ Application Options:
|
||||
--serve Serve the Fabric Rest API
|
||||
--serveOllama Serve the Fabric Rest API with ollama endpoints
|
||||
--address= The address to bind the REST API (default: :8080)
|
||||
--api-key= API key used to secure server routes
|
||||
--config= Path to YAML config file
|
||||
--version Print current version
|
||||
--listextensions List all registered extensions
|
||||
@@ -472,6 +523,8 @@ Application Options:
|
||||
--rmextension= Remove a registered extension by name
|
||||
--strategy= Choose a strategy from the available strategies
|
||||
--liststrategies List all strategies
|
||||
--listvendors List all vendors
|
||||
--shell-complete-list Output raw list without headers/formatting (for shell completion)
|
||||
|
||||
Help Options:
|
||||
-h, --help Show this help message
|
||||
@@ -713,6 +766,14 @@ The Streamlit UI supports clipboard operations across different platforms:
|
||||
<a href="https://github.com/sbehrens"><img src="https://avatars.githubusercontent.com/u/688589?v=4" title="Scott Behrens" width="50" height="50"></a>
|
||||
<a href="https://github.com/agu3rra"><img src="https://avatars.githubusercontent.com/u/10410523?v=4" title="Andre Guerra" width="50" height="50"></a>
|
||||
|
||||
### Contributors
|
||||
|
||||
<a href="https://github.com/danielmiessler/fabric/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=danielmiessler/fabric" />
|
||||
</a>
|
||||
|
||||
Made with [contrib.rocks](https://contrib.rocks).
|
||||
|
||||
`fabric` was created by <a href="https://danielmiessler.com/subscribe" target="_blank">Daniel Miessler</a> in January of 2024.
|
||||
<br /><br />
|
||||
<a href="https://twitter.com/intent/user?screen_name=danielmiessler"></a>
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
# YAML Configuration Support
|
||||
|
||||
## Overview
|
||||
|
||||
Fabric now supports YAML configuration files for commonly used options. This allows users to persist settings and share configurations across multiple runs.
|
||||
|
||||
## Usage
|
||||
|
||||
Use the `--config` flag to specify a YAML configuration file:
|
||||
|
||||
```bash
|
||||
fabric --config ~/.config/fabric/config.yaml "Tell me about APIs"
|
||||
```
|
||||
|
||||
## Configuration Precedence
|
||||
|
||||
1. CLI flags (highest priority)
|
||||
2. YAML config values
|
||||
3. Default values (lowest priority)
|
||||
|
||||
## Supported Configuration Options
|
||||
|
||||
```yaml
|
||||
# Model selection
|
||||
model: gpt-4
|
||||
@@ -36,6 +41,7 @@ raw: false
|
||||
```
|
||||
|
||||
## Rules and Behavior
|
||||
|
||||
- Only long flag names are supported in YAML (e.g., `temperature` not `-t`)
|
||||
- CLI flags always override YAML values
|
||||
- Unknown YAML declarations are ignored
|
||||
@@ -43,12 +49,15 @@ raw: false
|
||||
- The order of YAML declarations doesn't matter
|
||||
|
||||
## Type Conversions
|
||||
|
||||
The following string-to-type conversions are supported:
|
||||
|
||||
- String to number: `"42"` → `42`
|
||||
- String to float: `"42.5"` → `42.5`
|
||||
- String to boolean: `"true"` → `true`
|
||||
|
||||
## Example Config
|
||||
|
||||
```yaml
|
||||
# ~/.config/fabric/config.yaml
|
||||
model: gpt-4
|
||||
@@ -61,8 +70,8 @@ frequencypenalty: 0.2
|
||||
```
|
||||
|
||||
## CLI Override Example
|
||||
|
||||
```bash
|
||||
# Override temperature from config
|
||||
fabric --config ~/.config/fabric/config.yaml --temperature 0.9 "Query"
|
||||
```
|
||||
|
||||
|
||||
19
cli/cli.go
19
cli/cli.go
@@ -93,7 +93,7 @@ func Cli(version string) (err error) {
|
||||
}
|
||||
|
||||
if currentFlags.ListPatterns {
|
||||
err = fabricDb.Patterns.ListNames()
|
||||
err = fabricDb.Patterns.ListNames(currentFlags.ShellCompleteOutput)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -102,17 +102,17 @@ func Cli(version string) (err error) {
|
||||
if models, err = registry.VendorManager.GetModels(); err != nil {
|
||||
return
|
||||
}
|
||||
models.Print()
|
||||
models.Print(currentFlags.ShellCompleteOutput)
|
||||
return
|
||||
}
|
||||
|
||||
if currentFlags.ListAllContexts {
|
||||
err = fabricDb.Contexts.ListNames()
|
||||
err = fabricDb.Contexts.ListNames(currentFlags.ShellCompleteOutput)
|
||||
return
|
||||
}
|
||||
|
||||
if currentFlags.ListAllSessions {
|
||||
err = fabricDb.Sessions.ListNames()
|
||||
err = fabricDb.Sessions.ListNames(currentFlags.ShellCompleteOutput)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -160,7 +160,12 @@ func Cli(version string) (err error) {
|
||||
}
|
||||
|
||||
if currentFlags.ListStrategies {
|
||||
err = registry.Strategies.ListStrategies()
|
||||
err = registry.Strategies.ListStrategies(currentFlags.ShellCompleteOutput)
|
||||
return
|
||||
}
|
||||
|
||||
if currentFlags.ListVendors {
|
||||
err = registry.ListVendors(os.Stdout)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -211,7 +216,9 @@ func Cli(version string) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
messageTools, err = processYoutubeVideo(currentFlags, registry, videoId)
|
||||
if messageTools, err = processYoutubeVideo(currentFlags, registry, videoId); err != nil {
|
||||
return
|
||||
}
|
||||
if !currentFlags.IsChatRequest() {
|
||||
err = currentFlags.WriteOutput(messageTools)
|
||||
return
|
||||
|
||||
@@ -72,6 +72,8 @@ type Flags struct {
|
||||
RemoveExtension string `long:"rmextension" description:"Remove a registered extension by name"`
|
||||
Strategy string `long:"strategy" description:"Choose a strategy from the available strategies" default:""`
|
||||
ListStrategies bool `long:"liststrategies" description:"List all strategies"`
|
||||
ListVendors bool `long:"listvendors" description:"List all vendors"`
|
||||
ShellCompleteOutput bool `long:"shell-complete-list" description:"Output raw list without headers/formatting (for shell completion)"`
|
||||
}
|
||||
|
||||
var debug = false
|
||||
@@ -334,7 +336,6 @@ func (o *Flags) BuildChatRequest(Meta string) (ret *common.ChatRequest, err erro
|
||||
|
||||
func (o *Flags) AppendMessage(message string) {
|
||||
o.Message = AppendMessage(o.Message, message)
|
||||
return
|
||||
}
|
||||
|
||||
func (o *Flags) IsChatRequest() (ret bool) {
|
||||
|
||||
@@ -2,6 +2,8 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
@@ -40,13 +42,43 @@ func (o *GroupsItemsSelector[I]) AddGroupItems(group string, items ...I) {
|
||||
o.GroupsItems = append(o.GroupsItems, &GroupItems[I]{group, items})
|
||||
}
|
||||
|
||||
// getSortedGroupsItems returns a new slice of GroupItems with both groups and their items
|
||||
// sorted alphabetically in a case-insensitive manner. The original GroupsItems are not modified.
|
||||
func (o *GroupsItemsSelector[I]) getSortedGroupsItems() []*GroupItems[I] {
|
||||
// Copy and sort groups (case‑insensitive)
|
||||
sortedGroupsItems := make([]*GroupItems[I], len(o.GroupsItems))
|
||||
copy(sortedGroupsItems, o.GroupsItems)
|
||||
sort.SliceStable(sortedGroupsItems, func(i, j int) bool {
|
||||
return strings.ToLower(sortedGroupsItems[i].Group) < strings.ToLower(sortedGroupsItems[j].Group)
|
||||
})
|
||||
|
||||
// For each group, sort its items
|
||||
for i, groupItems := range sortedGroupsItems {
|
||||
sortedItems := make([]I, len(groupItems.Items))
|
||||
copy(sortedItems, groupItems.Items)
|
||||
sort.SliceStable(sortedItems, func(i, j int) bool {
|
||||
return strings.ToLower(o.GetItemKey(sortedItems[i])) < strings.ToLower(o.GetItemKey(sortedItems[j]))
|
||||
})
|
||||
|
||||
// Create a new GroupItems with the sorted items
|
||||
sortedGroupsItems[i] = &GroupItems[I]{
|
||||
Group: groupItems.Group,
|
||||
Items: sortedItems,
|
||||
}
|
||||
}
|
||||
|
||||
return sortedGroupsItems
|
||||
}
|
||||
|
||||
func (o *GroupsItemsSelector[I]) GetGroupAndItemByItemNumber(number int) (group string, item I, err error) {
|
||||
var currentItemNumber int
|
||||
found := false
|
||||
|
||||
for _, groupItems := range o.GroupsItems {
|
||||
if currentItemNumber+groupItems.Count() < number {
|
||||
currentItemNumber += groupItems.Count()
|
||||
sortedGroupsItems := o.getSortedGroupsItems()
|
||||
|
||||
for _, groupItems := range sortedGroupsItems {
|
||||
if currentItemNumber+len(groupItems.Items) < number {
|
||||
currentItemNumber += len(groupItems.Items)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -59,6 +91,10 @@ func (o *GroupsItemsSelector[I]) GetGroupAndItemByItemNumber(number int) (group
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
@@ -67,19 +103,30 @@ func (o *GroupsItemsSelector[I]) GetGroupAndItemByItemNumber(number int) (group
|
||||
return
|
||||
}
|
||||
|
||||
func (o *GroupsItemsSelector[I]) Print() {
|
||||
fmt.Printf("\n%v:\n", o.SelectionLabel)
|
||||
func (o *GroupsItemsSelector[I]) Print(shellCompleteList bool) {
|
||||
// Only print the section header if not in plain output mode
|
||||
if !shellCompleteList {
|
||||
fmt.Printf("\n%v:\n", o.SelectionLabel)
|
||||
}
|
||||
|
||||
var currentItemIndex int
|
||||
for _, groupItems := range o.GroupsItems {
|
||||
fmt.Println()
|
||||
fmt.Printf("%s\n", groupItems.Group)
|
||||
fmt.Println()
|
||||
sortedGroupsItems := o.getSortedGroupsItems()
|
||||
|
||||
for _, groupItems := range sortedGroupsItems {
|
||||
if !shellCompleteList {
|
||||
fmt.Println()
|
||||
fmt.Printf("%s\n\n", groupItems.Group)
|
||||
}
|
||||
|
||||
for _, item := range groupItems.Items {
|
||||
currentItemIndex++
|
||||
fmt.Printf("\t[%d]\t%s\n", currentItemIndex, o.GetItemKey(item))
|
||||
|
||||
if shellCompleteList {
|
||||
// plain mode: "index key"
|
||||
fmt.Printf("%s\n", o.GetItemKey(item))
|
||||
} else {
|
||||
// formatted mode: "[index] key"
|
||||
fmt.Printf("\t[%d]\t%s\n", currentItemIndex, o.GetItemKey(item))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
111
completions/_fabric
Normal file
111
completions/_fabric
Normal file
@@ -0,0 +1,111 @@
|
||||
#compdef fabric
|
||||
|
||||
# Zsh completion for fabric CLI
|
||||
# Place this file in a directory in your $fpath (e.g. /usr/local/share/zsh/site-functions)
|
||||
|
||||
_fabric_patterns() {
|
||||
local -a patterns
|
||||
patterns=(${(f)"$(fabric --listpatterns --shell-complete-list 2>/dev/null)"})
|
||||
compadd -X "Patterns:" ${patterns}
|
||||
}
|
||||
|
||||
_fabric_models() {
|
||||
local -a models
|
||||
models=(${(f)"$(fabric --listmodels --shell-complete-list 2>/dev/null)"})
|
||||
compadd -X "Models:" ${models}
|
||||
}
|
||||
_fabric_contexts() {
|
||||
local -a contexts
|
||||
contexts=(${(f)"$(fabric --listcontexts --shell-complete-list 2>/dev/null)"})
|
||||
compadd -X "Contexts:" ${contexts}
|
||||
}
|
||||
_fabric_sessions() {
|
||||
local -a sessions
|
||||
sessions=(${(f)"$(fabric --listsessions --shell-complete-list 2>/dev/null)"})
|
||||
compadd -X "Sessions:" ${sessions}
|
||||
}
|
||||
_fabric_strategies() {
|
||||
local -a strategies
|
||||
strategies=(${(f)"$(fabric --liststrategies --shell-complete-list 2>/dev/null)"})
|
||||
compadd -X "Strategies:" ${strategies}
|
||||
}
|
||||
|
||||
_fabric_extensions() {
|
||||
local -a extensions
|
||||
extensions=(${(f)"$(fabric --listextensions --shell-complete-list 2>/dev/null)"})
|
||||
compadd -X "Extensions:" ${extensions}
|
||||
'(-L --listmodels)'{-L,--listmodels}'[List all available models]:list models:_fabric_models' \
|
||||
'(-x --listcontexts)'{-x,--listcontexts}'[List all contexts]:list contexts:_fabric_contexts' \
|
||||
'(-X --listsessions)'{-X,--listsessions}'[List all sessions]:list sessions:_fabric_sessions' \
|
||||
'(--listextensions)--listextensions[List all registered extensions]' \
|
||||
'(--liststrategies)--liststrategies[List all strategies]:list strategies:_fabric_strategies' \
|
||||
'(--listvendors)--listvendors[List all vendors]' \
|
||||
vendors=(${(f)"$(fabric --listvendors 2>/dev/null)"})
|
||||
compadd -X "Vendors:" ${vendors}
|
||||
}
|
||||
|
||||
_fabric() {
|
||||
local curcontext="$curcontext" state line
|
||||
typeset -A opt_args
|
||||
|
||||
_arguments -C \
|
||||
'(-p --pattern)'{-p,--pattern}'[Choose a pattern from the available patterns]:pattern:_fabric_patterns' \
|
||||
'(-v --variable)'{-v,--variable}'[Values for pattern variables, e.g. -v=#role:expert -v=#points:30]:variable:' \
|
||||
'(-C --context)'{-C,--context}'[Choose a context from the available contexts]:context:_fabric_contexts' \
|
||||
'(--session)--session[Choose a session from the available sessions]:session:_fabric_sessions' \
|
||||
'(-a --attachment)'{-a,--attachment}'[Attachment path or URL (e.g. for OpenAI image recognition messages)]:file:_files' \
|
||||
'(-S --setup)'{-S,--setup}'[Run setup for all reconfigurable parts of fabric]' \
|
||||
'(-t --temperature)'{-t,--temperature}'[Set temperature (default: 0.7)]:temperature:' \
|
||||
'(-T --topp)'{-T,--topp}'[Set top P (default: 0.9)]:topp:' \
|
||||
'(-s --stream)'{-s,--stream}'[Stream]' \
|
||||
'(-P --presencepenalty)'{-P,--presencepenalty}'[Set presence penalty (default: 0.0)]:presence penalty:' \
|
||||
'(-r --raw)'{-r,--raw}'[Use the defaults of the model without sending chat options]' \
|
||||
'(-F --frequencypenalty)'{-F,--frequencypenalty}'[Set frequency penalty (default: 0.0)]:frequency penalty:' \
|
||||
'(-l --listpatterns)'{-l,--listpatterns}'[List all patterns]' \
|
||||
'(-L --listmodels)'{-L,--listmodels}'[List all available models]' \
|
||||
'(-x --listcontexts)'{-x,--listcontexts}'[List all contexts]' \
|
||||
'(-X --listsessions)'{-X,--listsessions}'[List all sessions]' \
|
||||
'(-U --updatepatterns)'{-U,--updatepatterns}'[Update patterns]' \
|
||||
'(-c --copy)'{-c,--copy}'[Copy to clipboard]' \
|
||||
'(-m --model)'{-m,--model}'[Choose model]:model:_fabric_models' \
|
||||
'(--modelContextLength)--modelContextLength[Model context length (only affects ollama)]:length:' \
|
||||
'(-o --output)'{-o,--output}'[Output to file]:file:_files' \
|
||||
'(--output-session)--output-session[Output the entire session to the output file]' \
|
||||
'(-n --latest)'{-n,--latest}'[Number of latest patterns to list (default: 0)]:number:' \
|
||||
'(-d --changeDefaultModel)'{-d,--changeDefaultModel}'[Change default model]' \
|
||||
'(-y --youtube)'{-y,--youtube}'[YouTube video or play list URL]:youtube url:' \
|
||||
'(--playlist)--playlist[Prefer playlist over video if both ids are present in the URL]' \
|
||||
'(--transcript)--transcript[Grab transcript from YouTube video and send to chat]' \
|
||||
'(--transcript-with-timestamps)--transcript-with-timestamps[Grab transcript from YouTube video with timestamps]' \
|
||||
'(--comments)--comments[Grab comments from YouTube video and send to chat]' \
|
||||
'(--metadata)--metadata[Output video metadata]' \
|
||||
'(-g --language)'{-g,--language}'[Specify the Language Code for the chat, e.g. -g=en -g=zh]:language:' \
|
||||
'(-u --scrape_url)'{-u,--scrape_url}'[Scrape website URL to markdown using Jina AI]:url:' \
|
||||
'(-q --scrape_question)'{-q,--scrape_question}'[Search question using Jina AI]:question:' \
|
||||
'(-e --seed)'{-e,--seed}'[Seed to be used for LMM generation]:seed:' \
|
||||
'(-w --wipecontext)'{-w,--wipecontext}'[Wipe context]:context:_fabric_contexts' \
|
||||
'(-W --wipesession)'{-W,--wipesession}'[Wipe session]:session:_fabric_sessions' \
|
||||
'(--printcontext)--printcontext[Print context]:context:_fabric_contexts' \
|
||||
'(--printsession)--printsession[Print session]:session:_fabric_sessions' \
|
||||
'(--readability)--readability[Convert HTML input into a clean, readable view]' \
|
||||
'(--input-has-vars)--input-has-vars[Apply variables to user input]' \
|
||||
'(--dry-run)--dry-run[Show what would be sent to the model without actually sending it]' \
|
||||
'(--serve)--serve[Serve the Fabric Rest API]' \
|
||||
'(--serveOllama)--serveOllama[Serve the Fabric Rest API with ollama endpoints]' \
|
||||
'(--address)--address[The address to bind the REST API (default: :8080)]:address:' \
|
||||
'(--api-key)--api-key[API key used to secure server routes]:api-key:' \
|
||||
'(--config)--config[Path to YAML config file]:config file:_files -g "*.yaml *.yml"' \
|
||||
'(--version)--version[Print current version]' \
|
||||
'(--listextensions)--listextensions[List all registered extensions]' \
|
||||
'(--addextension)--addextension[Register a new extension from config file path]:config file:_files -g "*.yaml *.yml"' \
|
||||
'(--rmextension)--rmextension[Remove a registered extension by name]:extension:_fabric_extensions' \
|
||||
'(--strategy)--strategy[Choose a strategy from the available strategies]:strategy:_fabric_strategies' \
|
||||
'(--liststrategies)--liststrategies[List all strategies]' \
|
||||
'(--listvendors)--listvendors[List all vendors]' \
|
||||
'(--shell-complete-list)--shell-complete-list[Output raw list without headers/formatting (for shell completion)]' \
|
||||
'(-h --help)'{-h,--help}'[Show this help message]' \
|
||||
'*:arguments:'
|
||||
}
|
||||
|
||||
_fabric "$@"
|
||||
|
||||
90
completions/fabric.bash
Normal file
90
completions/fabric.bash
Normal file
@@ -0,0 +1,90 @@
|
||||
# Bash completion for fabric CLI
|
||||
#
|
||||
# Installation:
|
||||
# 1. Place this file in a standard completion directory, e.g.,
|
||||
# - /etc/bash_completion.d/
|
||||
# - /usr/local/etc/bash_completion.d/
|
||||
# - ~/.local/share/bash-completion/completions/
|
||||
# 2. Or, source it directly in your ~/.bashrc or ~/.bash_profile:
|
||||
# source /path/to/fabric.bash
|
||||
|
||||
_fabric() {
|
||||
local cur prev words cword
|
||||
_get_comp_words_by_ref -n : cur prev words cword
|
||||
|
||||
# Define all possible options/flags
|
||||
local opts="--pattern -p --variable -v --context -C --session --attachment -a --setup -S --temperature -t --topp -T --stream -s --presencepenalty -P --raw -r --frequencypenalty -F --listpatterns -l --listmodels -L --listcontexts -x --listsessions -X --updatepatterns -U --copy -c --model -m --modelContextLength --output -o --output-session --latest -n --changeDefaultModel -d --youtube -y --playlist --transcript --transcript-with-timestamps --comments --metadata --language -g --scrape_url -u --scrape_question -q --seed -e --wipecontext -w --wipesession -W --printcontext --printsession --readability --input-has-vars --dry-run --serve --serveOllama --address --api-key --config --version --listextensions --addextension --rmextension --strategy --liststrategies --listvendors --shell-complete-list --help -h"
|
||||
|
||||
# Helper function for dynamic completions
|
||||
_fabric_get_list() {
|
||||
fabric "$1" --shell-complete-list 2>/dev/null
|
||||
}
|
||||
|
||||
# Handle completions based on the previous word
|
||||
case "${prev}" in
|
||||
-p | --pattern)
|
||||
COMPREPLY=($(compgen -W "$(_fabric_get_list --listpatterns)" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
-C | --context)
|
||||
COMPREPLY=($(compgen -W "$(_fabric_get_list --listcontexts)" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--session)
|
||||
COMPREPLY=($(compgen -W "$(_fabric_get_list --listsessions)" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
-m | --model)
|
||||
COMPREPLY=($(compgen -W "$(_fabric_get_list --listmodels)" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
-w | --wipecontext)
|
||||
COMPREPLY=($(compgen -W "$(_fabric_get_list --listcontexts)" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
-W | --wipesession)
|
||||
COMPREPLY=($(compgen -W "$(_fabric_get_list --listsessions)" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--printcontext)
|
||||
COMPREPLY=($(compgen -W "$(_fabric_get_list --listcontexts)" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--printsession)
|
||||
COMPREPLY=($(compgen -W "$(_fabric_get_list --listsessions)" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--rmextension)
|
||||
COMPREPLY=($(compgen -W "$(_fabric_get_list --listextensions)" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--strategy)
|
||||
COMPREPLY=($(compgen -W "$(_fabric_get_list --liststrategies)" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
# Options requiring file/directory paths
|
||||
-a | --attachment | -o | --output | --config | --addextension)
|
||||
_filedir
|
||||
return 0
|
||||
;;
|
||||
# Options requiring simple arguments (no specific completion logic here)
|
||||
-v | --variable | -t | --temperature | -T | --topp | -P | --presencepenalty | -F | --frequencypenalty | --modelContextLength | -n | --latest | -y | --youtube | -g | --language | -u | --scrape_url | -q | --scrape_question | -e | --seed | --address | --api-key)
|
||||
# No specific completion suggestions, user types the value
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
# If the current word starts with '-', suggest options
|
||||
if [[ "${cur}" == -* ]]; then
|
||||
COMPREPLY=($(compgen -W "${opts}" -- "${cur}"))
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Default: complete files/directories if no other rule matches
|
||||
# _filedir
|
||||
# Or provide no completions if it's not an option or argument following a known flag
|
||||
COMPREPLY=()
|
||||
|
||||
}
|
||||
|
||||
complete -F _fabric fabric
|
||||
94
completions/fabric.fish
Executable file
94
completions/fabric.fish
Executable file
@@ -0,0 +1,94 @@
|
||||
# Fish shell completion for fabric CLI
|
||||
#
|
||||
# Installation:
|
||||
# Copy this file to ~/.config/fish/completions/fabric.fish
|
||||
# or run:
|
||||
# mkdir -p ~/.config/fish/completions
|
||||
# cp completions/fabric.fish ~/.config/fish/completions/
|
||||
|
||||
# Helper functions for dynamic completions
|
||||
function __fabric_get_patterns
|
||||
fabric --listpatterns --shell-complete-list 2>/dev/null
|
||||
end
|
||||
|
||||
function __fabric_get_models
|
||||
fabric --listmodels --shell-complete-list 2>/dev/null
|
||||
end
|
||||
|
||||
function __fabric_get_contexts
|
||||
fabric --listcontexts --shell-complete-list 2>/dev/null
|
||||
end
|
||||
|
||||
function __fabric_get_sessions
|
||||
fabric --listsessions --shell-complete-list 2>/dev/null
|
||||
end
|
||||
|
||||
function __fabric_get_strategies
|
||||
fabric --liststrategies --shell-complete-list 2>/dev/null
|
||||
end
|
||||
|
||||
function __fabric_get_extensions
|
||||
fabric --listextensions --shell-complete-list 2>/dev/null
|
||||
end
|
||||
|
||||
# Main completion function
|
||||
complete -c fabric -f
|
||||
|
||||
# Flag completions with arguments
|
||||
complete -c fabric -s p -l pattern -d "Choose a pattern from the available patterns" -a "(__fabric_get_patterns)"
|
||||
complete -c fabric -s v -l variable -d "Values for pattern variables, e.g. -v=#role:expert -v=#points:30"
|
||||
complete -c fabric -s C -l context -d "Choose a context from the available contexts" -a "(__fabric_get_contexts)"
|
||||
complete -c fabric -l session -d "Choose a session from the available sessions" -a "(__fabric_get_sessions)"
|
||||
complete -c fabric -s a -l attachment -d "Attachment path or URL (e.g. for OpenAI image recognition messages)" -r
|
||||
complete -c fabric -s t -l temperature -d "Set temperature (default: 0.7)"
|
||||
complete -c fabric -s T -l topp -d "Set top P (default: 0.9)"
|
||||
complete -c fabric -s P -l presencepenalty -d "Set presence penalty (default: 0.0)"
|
||||
complete -c fabric -s F -l frequencypenalty -d "Set frequency penalty (default: 0.0)"
|
||||
complete -c fabric -s m -l model -d "Choose model" -a "(__fabric_get_models)"
|
||||
complete -c fabric -l modelContextLength -d "Model context length (only affects ollama)"
|
||||
complete -c fabric -s o -l output -d "Output to file" -r
|
||||
complete -c fabric -s n -l latest -d "Number of latest patterns to list (default: 0)"
|
||||
complete -c fabric -s y -l youtube -d "YouTube video or play list URL to grab transcript, comments from it"
|
||||
complete -c fabric -s g -l language -d "Specify the Language Code for the chat, e.g. -g=en -g=zh"
|
||||
complete -c fabric -s u -l scrape_url -d "Scrape website URL to markdown using Jina AI"
|
||||
complete -c fabric -s q -l scrape_question -d "Search question using Jina AI"
|
||||
complete -c fabric -s e -l seed -d "Seed to be used for LMM generation"
|
||||
complete -c fabric -s w -l wipecontext -d "Wipe context" -a "(__fabric_get_contexts)"
|
||||
complete -c fabric -s W -l wipesession -d "Wipe session" -a "(__fabric_get_sessions)"
|
||||
complete -c fabric -l printcontext -d "Print context" -a "(__fabric_get_contexts)"
|
||||
complete -c fabric -l printsession -d "Print session" -a "(__fabric_get_sessions)"
|
||||
complete -c fabric -l address -d "The address to bind the REST API (default: :8080)"
|
||||
complete -c fabric -l api-key -d "API key used to secure server routes"
|
||||
complete -c fabric -l config -d "Path to YAML config file" -r -a "*.yaml *.yml"
|
||||
complete -c fabric -l addextension -d "Register a new extension from config file path" -r -a "*.yaml *.yml"
|
||||
complete -c fabric -l rmextension -d "Remove a registered extension by name" -a "(__fabric_get_extensions)"
|
||||
complete -c fabric -l strategy -d "Choose a strategy from the available strategies" -a "(__fabric_get_strategies)"
|
||||
|
||||
# Boolean flags (no arguments)
|
||||
complete -c fabric -s S -l setup -d "Run setup for all reconfigurable parts of fabric"
|
||||
complete -c fabric -s s -l stream -d "Stream"
|
||||
complete -c fabric -s r -l raw -d "Use the defaults of the model without sending chat options"
|
||||
complete -c fabric -s l -l listpatterns -d "List all patterns"
|
||||
complete -c fabric -s L -l listmodels -d "List all available models"
|
||||
complete -c fabric -s x -l listcontexts -d "List all contexts"
|
||||
complete -c fabric -s X -l listsessions -d "List all sessions"
|
||||
complete -c fabric -s U -l updatepatterns -d "Update patterns"
|
||||
complete -c fabric -s c -l copy -d "Copy to clipboard"
|
||||
complete -c fabric -l output-session -d "Output the entire session to the output file"
|
||||
complete -c fabric -s d -l changeDefaultModel -d "Change default model"
|
||||
complete -c fabric -l playlist -d "Prefer playlist over video if both ids are present in the URL"
|
||||
complete -c fabric -l transcript -d "Grab transcript from YouTube video and send to chat"
|
||||
complete -c fabric -l transcript-with-timestamps -d "Grab transcript from YouTube video with timestamps"
|
||||
complete -c fabric -l comments -d "Grab comments from YouTube video and send to chat"
|
||||
complete -c fabric -l metadata -d "Output video metadata"
|
||||
complete -c fabric -l readability -d "Convert HTML input into a clean, readable view"
|
||||
complete -c fabric -l input-has-vars -d "Apply variables to user input"
|
||||
complete -c fabric -l dry-run -d "Show what would be sent to the model without actually sending it"
|
||||
complete -c fabric -l serve -d "Serve the Fabric Rest API"
|
||||
complete -c fabric -l serveOllama -d "Serve the Fabric Rest API with ollama endpoints"
|
||||
complete -c fabric -l version -d "Print current version"
|
||||
complete -c fabric -l listextensions -d "List all registered extensions"
|
||||
complete -c fabric -l liststrategies -d "List all strategies"
|
||||
complete -c fabric -l listvendors -d "List all vendors"
|
||||
complete -c fabric -l shell-complete-list -d "Output raw list without headers/formatting (for shell completion)"
|
||||
complete -c fabric -s h -l help -d "Show this help message"
|
||||
@@ -185,22 +185,26 @@ func (o *Chatter) BuildSession(request *common.ChatRequest, raw bool) (session *
|
||||
}
|
||||
}
|
||||
|
||||
if request.Language != "" {
|
||||
systemMessage = fmt.Sprintf("%s. Please use the language '%s' for the output.", systemMessage, request.Language)
|
||||
// Apply refined language instruction if specified
|
||||
if request.Language != "" && request.Language != "en" {
|
||||
// Refined instruction: Execute pattern using user input, then translate the entire response.
|
||||
systemMessage = fmt.Sprintf("%s\n\nIMPORTANT: First, execute the instructions provided in this prompt using the user's input. Second, ensure your entire final response, including any section headers or titles generated as part of executing the instructions, is written ONLY in the %s language.", systemMessage, request.Language)
|
||||
}
|
||||
|
||||
if raw {
|
||||
if request.Message != nil {
|
||||
if systemMessage != "" {
|
||||
request.Message.Content = systemMessage
|
||||
// system contains pattern which contains user input
|
||||
// In raw mode, combine system message (potentially with strategy) and user message into a single user message
|
||||
if systemMessage != "" {
|
||||
if request.Message != nil {
|
||||
// Prepend system message to user content, ensuring user input is preserved
|
||||
request.Message.Content = fmt.Sprintf("%s\n\n%s", systemMessage, request.Message.Content)
|
||||
request.Message.Role = goopenai.ChatMessageRoleUser // Ensure role is User in raw mode
|
||||
} else {
|
||||
// If no user message, create one with the system content, marked as User role
|
||||
request.Message = &goopenai.ChatCompletionMessage{Role: goopenai.ChatMessageRoleUser, Content: systemMessage}
|
||||
}
|
||||
} else {
|
||||
if systemMessage != "" {
|
||||
request.Message = &goopenai.ChatCompletionMessage{Role: goopenai.ChatMessageRoleSystem, Content: systemMessage}
|
||||
}
|
||||
}
|
||||
} // else: no system message, user message (if any) remains unchanged
|
||||
} else {
|
||||
// Not raw mode, append system message separately if it exists
|
||||
if systemMessage != "" {
|
||||
session.Append(&goopenai.ChatCompletionMessage{Role: goopenai.ChatMessageRoleSystem, Content: systemMessage})
|
||||
}
|
||||
|
||||
@@ -3,9 +3,12 @@ package core
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/danielmiessler/fabric/plugins/ai/exolab"
|
||||
"github.com/danielmiessler/fabric/plugins/strategy"
|
||||
@@ -17,17 +20,12 @@ import (
|
||||
"github.com/danielmiessler/fabric/plugins/ai"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/anthropic"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/azure"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/deepseek"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/dryrun"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/gemini"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/groq"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/litellm"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/lmstudio"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/mistral"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/ollama"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openai"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openrouter"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/siliconcloud"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openai_compatible"
|
||||
"github.com/danielmiessler/fabric/plugins/db/fsdb"
|
||||
"github.com/danielmiessler/fabric/plugins/template"
|
||||
"github.com/danielmiessler/fabric/plugins/tools"
|
||||
@@ -56,27 +54,49 @@ func NewPluginRegistry(db *fsdb.Db) (ret *PluginRegistry, err error) {
|
||||
|
||||
ret.Defaults = tools.NeeDefaults(ret.GetModels)
|
||||
|
||||
ret.VendorsAll.AddVendors(
|
||||
// Create a vendors slice to hold all vendors (order doesn't matter initially)
|
||||
vendors := []ai.Vendor{}
|
||||
|
||||
// Add non-OpenAI compatible clients
|
||||
vendors = append(vendors,
|
||||
openai.NewClient(),
|
||||
ollama.NewClient(),
|
||||
azure.NewClient(),
|
||||
groq.NewClient(),
|
||||
gemini.NewClient(),
|
||||
//gemini_openai.NewClient(),
|
||||
anthropic.NewClient(),
|
||||
siliconcloud.NewClient(),
|
||||
openrouter.NewClient(),
|
||||
lmstudio.NewClient(),
|
||||
mistral.NewClient(),
|
||||
deepseek.NewClient(),
|
||||
exolab.NewClient(),
|
||||
litellm.NewClient(),
|
||||
)
|
||||
|
||||
// Add all OpenAI-compatible providers
|
||||
for providerName := range openai_compatible.ProviderMap {
|
||||
provider, _ := openai_compatible.GetProviderByName(providerName)
|
||||
vendors = append(vendors, openai_compatible.NewClient(provider))
|
||||
}
|
||||
|
||||
// Sort vendors by name for consistent ordering (case-insensitive)
|
||||
sort.Slice(vendors, func(i, j int) bool {
|
||||
return strings.ToLower(vendors[i].GetName()) < strings.ToLower(vendors[j].GetName())
|
||||
})
|
||||
|
||||
// Add all sorted vendors to VendorsAll
|
||||
ret.VendorsAll.AddVendors(vendors...)
|
||||
_ = ret.Configure()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (o *PluginRegistry) ListVendors(out io.Writer) error {
|
||||
vendors := lo.Map(o.VendorsAll.Vendors, func(vendor ai.Vendor, _ int) string {
|
||||
return vendor.GetName()
|
||||
})
|
||||
fmt.Fprint(out, "Available Vendors:\n\n")
|
||||
for _, vendor := range vendors {
|
||||
fmt.Fprintf(out, "%s\n", vendor)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type PluginRegistry struct {
|
||||
Db *fsdb.Db
|
||||
|
||||
@@ -129,10 +149,10 @@ func (o *PluginRegistry) Setup() (err error) {
|
||||
return vendor
|
||||
})...)
|
||||
|
||||
groupsPlugins.AddGroupItems("Tools", o.Defaults, o.PatternsLoader, o.YouTube, o.Language, o.Jina, o.Strategies)
|
||||
groupsPlugins.AddGroupItems("Tools", o.Defaults, o.Jina, o.Language, o.PatternsLoader, o.Strategies, o.YouTube)
|
||||
|
||||
for {
|
||||
groupsPlugins.Print()
|
||||
groupsPlugins.Print(false)
|
||||
|
||||
if answerErr := setupQuestion.Ask("Plugin Number"); answerErr != nil {
|
||||
break
|
||||
|
||||
18
flake.lock
generated
18
flake.lock
generated
@@ -26,11 +26,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1733668782,
|
||||
"narHash": "sha256-tPsqU00FhgdFr0JiQUiBMgPVbl1jbPCY5gbFiJycL3I=",
|
||||
"lastModified": 1742209644,
|
||||
"narHash": "sha256-jMy1XqXqD0/tJprEbUmKilTkvbDY/C0ZGSsJJH4TNCE=",
|
||||
"owner": "nix-community",
|
||||
"repo": "gomod2nix",
|
||||
"rev": "514283ec89c39ad0079ff2f3b1437404e4cba608",
|
||||
"rev": "8f3534eb8f6c5c3fce799376dc3b91bae6b11884",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -41,11 +41,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1736344531,
|
||||
"narHash": "sha256-8YVQ9ZbSfuUk2bUf2KRj60NRraLPKPS0Q4QFTbc+c2c=",
|
||||
"lastModified": 1745234285,
|
||||
"narHash": "sha256-GfpyMzxwkfgRVN0cTGQSkTC0OHhEkv3Jf6Tcjm//qZ0=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "bffc22eb12172e6db3c5dde9e3e5628f8e3e7912",
|
||||
"rev": "c11863f1e964833214b767f4a369c6e6a7aba141",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -100,11 +100,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1736154270,
|
||||
"narHash": "sha256-p2r8xhQZ3TYIEKBoiEhllKWQqWNJNoT9v64Vmg4q8Zw=",
|
||||
"lastModified": 1744961264,
|
||||
"narHash": "sha256-aRmUh0AMwcbdjJHnytg1e5h5ECcaWtIFQa6d9gI85AI=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "13c913f5deb3a5c08bb810efd89dc8cb24dd968b",
|
||||
"rev": "8d404a69efe76146368885110f29a2ca3700bee6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
12
flake.nix
12
flake.nix
@@ -28,6 +28,8 @@
|
||||
let
|
||||
forAllSystems = nixpkgs.lib.genAttrs (import systems);
|
||||
|
||||
getGoVersion = system: nixpkgs.legacyPackages.${system}.go_1_24;
|
||||
|
||||
treefmtEval = forAllSystems (
|
||||
system:
|
||||
let
|
||||
@@ -47,10 +49,14 @@
|
||||
system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
goEnv = gomod2nix.legacyPackages.${system}.mkGoEnv { pwd = ./.; };
|
||||
goVersion = getGoVersion system;
|
||||
goEnv = gomod2nix.legacyPackages.${system}.mkGoEnv {
|
||||
pwd = ./.;
|
||||
go = goVersion;
|
||||
};
|
||||
in
|
||||
import ./nix/shell.nix {
|
||||
inherit pkgs goEnv;
|
||||
inherit pkgs goEnv goVersion;
|
||||
inherit (gomod2nix.legacyPackages.${system}) gomod2nix;
|
||||
}
|
||||
);
|
||||
@@ -59,10 +65,12 @@
|
||||
system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
goVersion = getGoVersion system;
|
||||
in
|
||||
{
|
||||
default = self.packages.${system}.fabric;
|
||||
fabric = pkgs.callPackage ./nix/pkgs/fabric {
|
||||
go = goVersion;
|
||||
inherit (gomod2nix.legacyPackages.${system}) buildGoApplication;
|
||||
};
|
||||
inherit (gomod2nix.legacyPackages.${system}) gomod2nix;
|
||||
|
||||
76
go.mod
76
go.mod
@@ -1,65 +1,67 @@
|
||||
module github.com/danielmiessler/fabric
|
||||
|
||||
go 1.23.4
|
||||
go 1.24.0
|
||||
|
||||
toolchain go1.24.2
|
||||
|
||||
require (
|
||||
github.com/anaskhan96/soup v1.2.5
|
||||
github.com/anthropics/anthropic-sdk-go v0.2.0-alpha.11
|
||||
github.com/anthropics/anthropic-sdk-go v0.2.0-beta.3
|
||||
github.com/atotto/clipboard v0.1.4
|
||||
github.com/gabriel-vasile/mimetype v1.4.8
|
||||
github.com/gabriel-vasile/mimetype v1.4.9
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/go-git/go-git/v5 v5.13.2
|
||||
github.com/go-git/go-git/v5 v5.16.0
|
||||
github.com/go-shiori/go-readability v0.0.0-20250217085726-9f5bf5ca7612
|
||||
github.com/google/generative-ai-go v0.19.0
|
||||
github.com/jessevdk/go-flags v1.6.1
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/ollama/ollama v0.5.12
|
||||
github.com/ollama/ollama v0.6.6
|
||||
github.com/otiai10/copy v1.14.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/samber/lo v1.49.1
|
||||
github.com/sashabaranov/go-openai v1.38.0
|
||||
github.com/sashabaranov/go-openai v1.38.2
|
||||
github.com/stretchr/testify v1.10.0
|
||||
golang.org/x/text v0.22.0
|
||||
google.golang.org/api v0.223.0
|
||||
golang.org/x/text v0.24.0
|
||||
google.golang.org/api v0.230.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.118.3 // indirect
|
||||
cloud.google.com/go/ai v0.10.0 // indirect
|
||||
cloud.google.com/go/auth v0.15.0 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect
|
||||
cloud.google.com/go v0.120.1 // indirect
|
||||
cloud.google.com/go/ai v0.10.2 // indirect
|
||||
cloud.google.com/go/auth v0.16.1 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.6.0 // indirect
|
||||
cloud.google.com/go/longrunning v0.6.4 // indirect
|
||||
cloud.google.com/go/longrunning v0.6.7 // indirect
|
||||
dario.cat/mergo v1.0.1 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.5 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.2.0 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de // indirect
|
||||
github.com/bytedance/sonic v1.12.9 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.3 // indirect
|
||||
github.com/cloudflare/circl v1.6.0 // indirect
|
||||
github.com/bytedance/sonic v1.13.2 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.4 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/gin-contrib/sse v1.0.0 // indirect
|
||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.25.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.26.0 // indirect
|
||||
github.com/go-shiori/dom v0.0.0-20230515143342-73569d674e1c // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
@@ -70,7 +72,7 @@ require (
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/otiai10/mint v1.6.3 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
@@ -83,21 +85,21 @@ require (
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect
|
||||
go.opentelemetry.io/otel v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.34.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.34.0 // indirect
|
||||
golang.org/x/arch v0.14.0 // indirect
|
||||
golang.org/x/crypto v0.35.0 // indirect
|
||||
golang.org/x/net v0.36.0 // indirect
|
||||
golang.org/x/oauth2 v0.27.0 // indirect
|
||||
golang.org/x/sync v0.11.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/time v0.10.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250224174004-546df14abb99 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250224174004-546df14abb99 // indirect
|
||||
google.golang.org/grpc v1.70.0 // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
|
||||
go.opentelemetry.io/otel v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.35.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.35.0 // indirect
|
||||
golang.org/x/arch v0.16.0 // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/net v0.39.0 // indirect
|
||||
golang.org/x/oauth2 v0.29.0 // indirect
|
||||
golang.org/x/sync v0.13.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/time v0.11.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250422160041-2d3770c4ea7f // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250422160041-2d3770c4ea7f // indirect
|
||||
google.golang.org/grpc v1.72.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
)
|
||||
|
||||
170
go.sum
170
go.sum
@@ -1,43 +1,43 @@
|
||||
cloud.google.com/go v0.118.3 h1:jsypSnrE/w4mJysioGdMBg4MiW/hHx/sArFpaBWHdME=
|
||||
cloud.google.com/go v0.118.3/go.mod h1:Lhs3YLnBlwJ4KA6nuObNMZ/fCbOQBPuWKPoE0Wa/9Vc=
|
||||
cloud.google.com/go/ai v0.10.0 h1:hwj6CI6sMKubXodoJJGTy/c2T1RbbLGM6TL3QoAvzU8=
|
||||
cloud.google.com/go/ai v0.10.0/go.mod h1:kvnt2KeHqX8+41PVeMRBETDyQAp/RFvBWGdx/aGjNMo=
|
||||
cloud.google.com/go/auth v0.15.0 h1:Ly0u4aA5vG/fsSsxu98qCQBemXtAtJf+95z9HK+cxps=
|
||||
cloud.google.com/go/auth v0.15.0/go.mod h1:WJDGqZ1o9E9wKIL+IwStfyn/+s59zl4Bi+1KQNVXLZ8=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc=
|
||||
cloud.google.com/go v0.120.1 h1:Z+5V7yd383+9617XDCyszmK5E4wJRJL+tquMfDj9hLM=
|
||||
cloud.google.com/go v0.120.1/go.mod h1:56Vs7sf/i2jYM6ZL9NYlC82r04PThNcPS5YgFmb0rp8=
|
||||
cloud.google.com/go/ai v0.10.2 h1:5NHzmZlRs+3kvlsVdjT0cTnLrjQdROJ/8VOljVfs+8o=
|
||||
cloud.google.com/go/ai v0.10.2/go.mod h1:xZuZuE9d3RgsR132meCnPadiU9XV0qXjpLr+P4J46eE=
|
||||
cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU=
|
||||
cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
|
||||
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
|
||||
cloud.google.com/go/longrunning v0.6.4 h1:3tyw9rO3E2XVXzSApn1gyEEnH2K9SynNQjMlBi3uHLg=
|
||||
cloud.google.com/go/longrunning v0.6.4/go.mod h1:ttZpLCe6e7EXvn9OxpBRx7kZEB0efv8yBO6YnVMfhJs=
|
||||
cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
|
||||
cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=
|
||||
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
|
||||
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4=
|
||||
github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/ProtonMail/go-crypto v1.2.0 h1:+PhXXn4SPGd+qk76TlEePBfOfivE0zkWFenhGhFLzWs=
|
||||
github.com/ProtonMail/go-crypto v1.2.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE=
|
||||
github.com/anaskhan96/soup v1.2.5 h1:V/FHiusdTrPrdF4iA1YkVxsOpdNcgvqT1hG+YtcZ5hM=
|
||||
github.com/anaskhan96/soup v1.2.5/go.mod h1:6YnEp9A2yywlYdM4EgDz9NEHclocMepEtku7wg6Cq3s=
|
||||
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/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||
github.com/anthropics/anthropic-sdk-go v0.2.0-alpha.11 h1:O3/AMObKntZyu1KH6Xks6E0gbE8w6HVaKHE+/vXARzM=
|
||||
github.com/anthropics/anthropic-sdk-go v0.2.0-alpha.11/go.mod h1:GJxtdOs9K4neo8Gg65CjJ7jNautmldGli5/OFNabOoo=
|
||||
github.com/anthropics/anthropic-sdk-go v0.2.0-beta.3 h1:b5t1ZJMvV/l99y4jbz7kRFdUp3BSDkI8EhSlHczivtw=
|
||||
github.com/anthropics/anthropic-sdk-go v0.2.0-beta.3/go.mod h1:AapDW22irxK2PSumZiQXYUFvsdQgkwIWlpESweWZI/c=
|
||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
|
||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||
github.com/bytedance/sonic v1.12.9 h1:Od1BvK55NnewtGaJsTDeAOSnLVO2BTSLOe0+ooKokmQ=
|
||||
github.com/bytedance/sonic v1.12.9/go.mod h1:uVvFidNmlt9+wa31S1urfwwthTWteBgG0hWuoKAXTx8=
|
||||
github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ=
|
||||
github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/bytedance/sonic/loader v0.2.3 h1:yctD0Q3v2NOGfSWPLPvG2ggA2kV6TS6s4wioyEqssH0=
|
||||
github.com/bytedance/sonic/loader v0.2.3/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||
github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
|
||||
github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY=
|
||||
github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
|
||||
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
|
||||
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
|
||||
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
@@ -46,16 +46,16 @@ github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGL
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/elazarl/goproxy v1.4.0 h1:4GyuSbFa+s26+3rmYNSuUVsx+HgPrV1bk1jXI0l9wjM=
|
||||
github.com/elazarl/goproxy v1.4.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ=
|
||||
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
|
||||
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
|
||||
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
|
||||
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||
github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E=
|
||||
github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
|
||||
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
|
||||
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
||||
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
||||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
||||
@@ -66,8 +66,8 @@ github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UN
|
||||
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0=
|
||||
github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A=
|
||||
github.com/go-git/go-git/v5 v5.16.0 h1:k3kuOEpkc0DeY7xlL6NaaNg39xdgQbtH5mwCafHO9AQ=
|
||||
github.com/go-git/go-git/v5 v5.16.0/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
@@ -79,8 +79,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8=
|
||||
github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
|
||||
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
|
||||
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
||||
github.com/go-shiori/dom v0.0.0-20230515143342-73569d674e1c h1:wpkoddUomPfHiOziHZixGO5ZBS73cKqVzZipfrLmO1w=
|
||||
github.com/go-shiori/dom v0.0.0-20230515143342-73569d674e1c/go.mod h1:oVDCh3qjJMLVUSILBRwrm+Bc6RNXGZYtoh9xdvf1ffM=
|
||||
github.com/go-shiori/go-readability v0.0.0-20250217085726-9f5bf5ca7612 h1:BYLNYdZaepitbZreRIa9xeCQZocWmy/wj4cGIH0qyw0=
|
||||
@@ -103,8 +103,8 @@ github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
||||
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
|
||||
github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q=
|
||||
github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
@@ -138,16 +138,16 @@ 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/ollama/ollama v0.5.12 h1:qM+k/ozyHLJzEQoAEPrUQ0qXqsgDEEdpIVwuwScrd2U=
|
||||
github.com/ollama/ollama v0.5.12/go.mod h1:ibdmDvb/TjKY1OArBWIazL3pd1DHTk8eG2MMjEkWhiI=
|
||||
github.com/ollama/ollama v0.6.6 h1:rnCQTSTiRD3Dsvd35dh2j2YB9DlQMFQR/y3XOhWZOmI=
|
||||
github.com/ollama/ollama v0.6.6/go.mod h1:pGgtoNyc9DdM6oZI6yMfI6jTk2Eh4c36c2GpfQCH7PY=
|
||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
github.com/otiai10/copy v1.14.1 h1:5/7E6qsUMBaH5AnQ0sSLzzTg1oTECmcCmT6lvF45Na8=
|
||||
github.com/otiai10/copy v1.14.1/go.mod h1:oQwrEDDOci3IM8dJF0d8+jnbfPDllW6vUjNc3DoZm9I=
|
||||
github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs=
|
||||
github.com/otiai10/mint v1.6.3/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
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/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
|
||||
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
@@ -155,12 +155,12 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
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/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew=
|
||||
github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o=
|
||||
github.com/sashabaranov/go-openai v1.38.0 h1:hNN5uolKwdbpiqOn7l+Z2alch/0n0rSFyg4n+GZxR5k=
|
||||
github.com/sashabaranov/go-openai v1.38.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
|
||||
github.com/sashabaranov/go-openai v1.38.2 h1:akrssjj+6DY3lWuDwHv6cBvJ8Z+FZDM9XEaaYFt0Auo=
|
||||
github.com/sashabaranov/go-openai v1.38.2/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
|
||||
github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
@@ -170,7 +170,6 @@ github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQ
|
||||
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=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
@@ -179,7 +178,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
@@ -201,22 +199,22 @@ github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I=
|
||||
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
|
||||
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
|
||||
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
|
||||
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
|
||||
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ=
|
||||
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
|
||||
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
|
||||
golang.org/x/arch v0.14.0 h1:z9JUEZWr8x4rR0OU6c4/4t6E6jOZ8/QBS2bBYBm4tx4=
|
||||
golang.org/x/arch v0.14.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
|
||||
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
||||
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
||||
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
||||
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
|
||||
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
||||
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
||||
golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U=
|
||||
golang.org/x/arch v0.16.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
|
||||
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.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
@@ -224,10 +222,10 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
||||
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4=
|
||||
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
@@ -244,10 +242,10 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA=
|
||||
golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I=
|
||||
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
|
||||
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
|
||||
golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -255,8 +253,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -273,8 +271,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
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=
|
||||
@@ -284,8 +282,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
|
||||
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
||||
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
|
||||
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -296,10 +294,10 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
|
||||
golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
@@ -307,16 +305,16 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.223.0 h1:JUTaWEriXmEy5AhvdMgksGGPEFsYfUKaPEYXd4c3Wvc=
|
||||
google.golang.org/api v0.223.0/go.mod h1:C+RS7Z+dDwds2b+zoAk5hN/eSfsiCn0UDrYof/M4d2M=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250224174004-546df14abb99 h1:ilJhrCga0AptpJZXmUYG4MCrx/zf3l1okuYz7YK9PPw=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250224174004-546df14abb99/go.mod h1:Xsh8gBVxGCcbV8ZeTB9wI5XPyZ5RvC6V3CTeeplHbiA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250224174004-546df14abb99 h1:ZSlhAUqC4r8TPzqLXQ0m3upBNZeF+Y8jQ3c4CR3Ujms=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250224174004-546df14abb99/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
|
||||
google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
|
||||
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/api v0.230.0 h1:2u1hni3E+UXAXrONrrkfWpi/V6cyKVAbfGVeGtC3OxM=
|
||||
google.golang.org/api v0.230.0/go.mod h1:aqvtoMk7YkiXx+6U12arQFExiRV9D/ekvMCwCd/TksQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250422160041-2d3770c4ea7f h1:tjZsroqekhC63+WMqzmWyW5Twj/ZfR5HAlpd5YQ1Vs0=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250422160041-2d3770c4ea7f/go.mod h1:Cd8IzgPo5Akum2c9R6FsXNaZbH3Jpa2gpHlW89FqlyQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250422160041-2d3770c4ea7f h1:N/PrbTw4kdkqNRzVfWPrBekzLuarFREcbFOiOLkXon4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250422160041-2d3770c4ea7f/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
|
||||
google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
|
||||
google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
lib,
|
||||
buildGoApplication,
|
||||
go,
|
||||
}:
|
||||
|
||||
buildGoApplication {
|
||||
@@ -17,6 +18,8 @@ buildGoApplication {
|
||||
"-w"
|
||||
];
|
||||
|
||||
inherit go;
|
||||
|
||||
meta = with lib; {
|
||||
description = "Fabric is an open-source framework for augmenting humans using AI. It provides a modular framework for solving specific problems using a crowdsourced set of AI prompts that can be used anywhere";
|
||||
homepage = "https://github.com/danielmiessler/fabric";
|
||||
|
||||
@@ -2,23 +2,23 @@ schema = 3
|
||||
|
||||
[mod]
|
||||
[mod."cloud.google.com/go"]
|
||||
version = "v0.118.3"
|
||||
hash = "sha256-y3YHioDLx9/asf2AWuincnq4BVO2S/GQFxpa1dEpxKs="
|
||||
version = "v0.120.1"
|
||||
hash = "sha256-yWaLc06rGXk16K53rix8O4uPSX+AOZDgIpIXf+wlh10="
|
||||
[mod."cloud.google.com/go/ai"]
|
||||
version = "v0.10.0"
|
||||
hash = "sha256-huE2q1HBA6d9FQ152HFQhOe9fX0QlLFVuFO3XAfln8U="
|
||||
version = "v0.10.2"
|
||||
hash = "sha256-bsqvdylG8kk+AHtyvMRMv1TOjUmvONAgJ+14mKcwuzs="
|
||||
[mod."cloud.google.com/go/auth"]
|
||||
version = "v0.15.0"
|
||||
hash = "sha256-N9xjLPDLhG5cqUx94tNccv74Q/fIlukWU6NbWpuNi+I="
|
||||
version = "v0.16.1"
|
||||
hash = "sha256-rMPMNQh/YM/67b9Grfu0BFccWpS1SRhBepubQqXRAyg="
|
||||
[mod."cloud.google.com/go/auth/oauth2adapt"]
|
||||
version = "v0.2.7"
|
||||
hash = "sha256-U+pXaY0kPnSeBzHWxELZ75bZnb74nygwIVZDdXYcP5g="
|
||||
version = "v0.2.8"
|
||||
hash = "sha256-GoXFqAbp1WO1tDj07PF5EyxDYvCBP0l0qwxY2oV2hfc="
|
||||
[mod."cloud.google.com/go/compute/metadata"]
|
||||
version = "v0.6.0"
|
||||
hash = "sha256-E8/cwio4xR8buCryR4HwR7+agb4M3zqgXSm7rBglmIY="
|
||||
[mod."cloud.google.com/go/longrunning"]
|
||||
version = "v0.6.4"
|
||||
hash = "sha256-Q0JtsyxSgVwi91ZhvefpAq8fKbblRrtQ2bQhQYiTY48="
|
||||
version = "v0.6.7"
|
||||
hash = "sha256-9I0Nc2KWAEVoxDngNkqFUdASmZIAySfMEELlPh3Q3xA="
|
||||
[mod."dario.cat/mergo"]
|
||||
version = "v1.0.1"
|
||||
hash = "sha256-wcG6+x0k6KzOSlaPA+1RFxa06/RIAePJTAjjuhLbImw="
|
||||
@@ -26,8 +26,8 @@ schema = 3
|
||||
version = "v0.6.2"
|
||||
hash = "sha256-tVNWDUMILZbJvarcl/E7tpSnkn7urqgSHa2Eaka5vSU="
|
||||
[mod."github.com/ProtonMail/go-crypto"]
|
||||
version = "v1.1.5"
|
||||
hash = "sha256-N5Zn0f/NF3ezyGou2kRw9BwM25feJqnp7TPkRt6oK6I="
|
||||
version = "v1.2.0"
|
||||
hash = "sha256-5fKgWUz6BoyFNNZ1OD9QjhBrhNEBCuVfO2WqH+X59oo="
|
||||
[mod."github.com/anaskhan96/soup"]
|
||||
version = "v1.2.5"
|
||||
hash = "sha256-t8yCyK2y7x2qaI/3Yw16q3zVFqu+3acLcPgTr1MIKWg="
|
||||
@@ -35,8 +35,8 @@ schema = 3
|
||||
version = "v1.3.3"
|
||||
hash = "sha256-jv7ZshpSd7FZzKKN6hqlUgiR8C3y85zNIS/hq7g76Ho="
|
||||
[mod."github.com/anthropics/anthropic-sdk-go"]
|
||||
version = "v0.2.0-alpha.11"
|
||||
hash = "sha256-0wl62e6AVhDY3KkoYrfAHFtBrwNC4nzqrR55iyCJlwk="
|
||||
version = "v0.2.0-beta.3"
|
||||
hash = "sha256-QnR7MWiLPVii9jy7rjrZfg1UDgXCXkc2latdzFurrFM="
|
||||
[mod."github.com/araddon/dateparse"]
|
||||
version = "v0.0.0-20210429162001-6b43995a97de"
|
||||
hash = "sha256-UuX84naeRGMsFOgIgRoBHG5sNy1CzBkWPKmd6VbLwFw="
|
||||
@@ -44,14 +44,14 @@ schema = 3
|
||||
version = "v0.1.4"
|
||||
hash = "sha256-ZZ7U5X0gWOu8zcjZcWbcpzGOGdycwq0TjTFh/eZHjXk="
|
||||
[mod."github.com/bytedance/sonic"]
|
||||
version = "v1.12.9"
|
||||
hash = "sha256-smlXGC4n6fkOiVR+A3VGd71xp+cYo42MSHuWq7H3jew="
|
||||
version = "v1.13.2"
|
||||
hash = "sha256-IF2qmt4IxTwivMWHUJC8sg6d85/ORb2SWvJ54fvoAMI="
|
||||
[mod."github.com/bytedance/sonic/loader"]
|
||||
version = "v0.2.3"
|
||||
hash = "sha256-c0m1nl1jv76LVaUgFFNjZU9jss/hoSWXyCRimhRWYjM="
|
||||
version = "v0.2.4"
|
||||
hash = "sha256-rv9LnePpm4OspSVbfSoVbohXzhu+dxE1BH1gm3mTmTc="
|
||||
[mod."github.com/cloudflare/circl"]
|
||||
version = "v1.6.0"
|
||||
hash = "sha256-a+SVfnHYC8Fb+NQLboNg5P9sry+WutzuNetVHFVAAo0="
|
||||
version = "v1.6.1"
|
||||
hash = "sha256-Dc69V12eIFnJoUNmwg6VKXHfAMijbAeEVSDe8AiOaLo="
|
||||
[mod."github.com/cloudwego/base64x"]
|
||||
version = "v0.1.5"
|
||||
hash = "sha256-MyUYTveN48DhnL8mwAgCRuMExLct98uzSPsmYlfaa4I="
|
||||
@@ -68,11 +68,11 @@ schema = 3
|
||||
version = "v1.0.4"
|
||||
hash = "sha256-c1JKoRSndwwOyOxq9ddCe+8qn7mG9uRq2o/822x5O/c="
|
||||
[mod."github.com/gabriel-vasile/mimetype"]
|
||||
version = "v1.4.8"
|
||||
hash = "sha256-ElqfQtnoGHyVqtN0mJjeWakQ6N5x+nVaX3+uOV7Q5Xk="
|
||||
version = "v1.4.9"
|
||||
hash = "sha256-75uELLqb01djHTe7KdXvUidBK7SuejarYouEUuxaj8Q="
|
||||
[mod."github.com/gin-contrib/sse"]
|
||||
version = "v1.0.0"
|
||||
hash = "sha256-xnaabOxDN+ojnHQC7mHd/876Z9nWFScW+JrMm1HWREw="
|
||||
version = "v1.1.0"
|
||||
hash = "sha256-2VP6zHEsPi0u2ZYpOTcLulwj1Gsmb6oA19qcP2/AzVM="
|
||||
[mod."github.com/gin-gonic/gin"]
|
||||
version = "v1.10.0"
|
||||
hash = "sha256-esJasHrJtuTBwGPGAoc/XSb428J8va+tPGcZ0gTfsgc="
|
||||
@@ -83,8 +83,8 @@ schema = 3
|
||||
version = "v5.6.2"
|
||||
hash = "sha256-VgbxcLkHjiSyRIfKS7E9Sn8OynCrMGUDkwFz6K2TVL4="
|
||||
[mod."github.com/go-git/go-git/v5"]
|
||||
version = "v5.13.2"
|
||||
hash = "sha256-voZQHN2OSYcoQF2bIjsdRrHT5NohZ/8q9RrmY7j2Lbc="
|
||||
version = "v5.16.0"
|
||||
hash = "sha256-01obPHvt1PG3r8XH8TgnNfcOhaYwWEkJ0TR5QGdZqmE="
|
||||
[mod."github.com/go-logr/logr"]
|
||||
version = "v1.4.2"
|
||||
hash = "sha256-/W6qGilFlZNTb9Uq48xGZ4IbsVeSwJiAMLw4wiNYHLI="
|
||||
@@ -98,8 +98,8 @@ schema = 3
|
||||
version = "v0.18.1"
|
||||
hash = "sha256-2/B2qP51zfiY+k8G0w0D03KXUc7XpWj6wKY7NjNP/9E="
|
||||
[mod."github.com/go-playground/validator/v10"]
|
||||
version = "v10.25.0"
|
||||
hash = "sha256-198CQ0f+WC7UNxCCPg6rpogez6c5ivpignJNhx+z0W4="
|
||||
version = "v10.26.0"
|
||||
hash = "sha256-/jMKICp8LTcJVt+b4YRTnJM84r7HK6aT0oqO7Q8SRs8="
|
||||
[mod."github.com/go-shiori/dom"]
|
||||
version = "v0.0.0-20230515143342-73569d674e1c"
|
||||
hash = "sha256-4lm9KZfR2XnfZU9KTG+4jqLYZqbfL74AMO4y3dKpIbg="
|
||||
@@ -125,8 +125,8 @@ schema = 3
|
||||
version = "v1.6.0"
|
||||
hash = "sha256-VWl9sqUzdOuhW0KzQlv0gwwUQClYkmZwSydHG2sALYw="
|
||||
[mod."github.com/googleapis/enterprise-certificate-proxy"]
|
||||
version = "v0.3.4"
|
||||
hash = "sha256-RVHWa0I68CTegjlXnM/GlishoZhmmwG4z+9KBucAJ1A="
|
||||
version = "v0.3.6"
|
||||
hash = "sha256-hPMF0s+X4/ul98GvVuw/ZNOupEXhIDB1yvWymZWYEbU="
|
||||
[mod."github.com/googleapis/gax-go/v2"]
|
||||
version = "v2.14.1"
|
||||
hash = "sha256-iRS/KsAVTePrvTlwA7vKcQnwY6Jz329WdgzFw0hF8wk="
|
||||
@@ -161,8 +161,8 @@ schema = 3
|
||||
version = "v1.0.2"
|
||||
hash = "sha256-+W9EIW7okXIXjWEgOaMh58eLvBZ7OshW2EhaIpNLSBU="
|
||||
[mod."github.com/ollama/ollama"]
|
||||
version = "v0.5.12"
|
||||
hash = "sha256-Uf4GZdD77RZ5KJtz3iYVRDVCHqEh0UEihzquO4/nrss="
|
||||
version = "v0.6.6"
|
||||
hash = "sha256-a2Be14e+pcJo15fM/+0ksE9HVl8I4hW6ujqbpNh9bpA="
|
||||
[mod."github.com/otiai10/copy"]
|
||||
version = "v1.14.1"
|
||||
hash = "sha256-8RR7u17SbYg9AeBXVHIv5ZMU+kHmOcx0rLUKyz6YtU0="
|
||||
@@ -170,8 +170,8 @@ schema = 3
|
||||
version = "v1.6.3"
|
||||
hash = "sha256-/FT3dYP2+UiW/qe1pxQ7HiS8et4+KHGPIMhc+8mHvzw="
|
||||
[mod."github.com/pelletier/go-toml/v2"]
|
||||
version = "v2.2.3"
|
||||
hash = "sha256-fE++SVgnCGdnFZoROHWuYjIR7ENl7k9KKxQrRTquv/o="
|
||||
version = "v2.2.4"
|
||||
hash = "sha256-8qQIPldbsS5RO8v/FW/se3ZsAyvLzexiivzJCbGRg2Q="
|
||||
[mod."github.com/pjbgf/sha1cd"]
|
||||
version = "v0.3.2"
|
||||
hash = "sha256-jdbiRhU8xc1C5c8m7BSCj71PUXHY3f7TWFfxDKKpUMk="
|
||||
@@ -185,8 +185,8 @@ schema = 3
|
||||
version = "v1.49.1"
|
||||
hash = "sha256-xMQS9Sx2Bpvwo/9JvSVkJ4RXYOSHm642WRqWA6y0AnU="
|
||||
[mod."github.com/sashabaranov/go-openai"]
|
||||
version = "v1.38.0"
|
||||
hash = "sha256-p6C/7oTWgnRjZLNrLLdIzaXvm+1WCrUd1fjZkjuiz1s="
|
||||
version = "v1.38.2"
|
||||
hash = "sha256-AnBycaxufzWlLS1YBq7MiHDED+Jqtu9oAySKcoL4HOA="
|
||||
[mod."github.com/sergi/go-diff"]
|
||||
version = "v1.3.2-0.20230802210424-5b0b94c5c0d3"
|
||||
hash = "sha256-UcLU83CPMbSoKI8RLvLJ7nvGaE2xRSL1RjoHCVkMzUM="
|
||||
@@ -221,59 +221,59 @@ schema = 3
|
||||
version = "v1.1.0"
|
||||
hash = "sha256-cA9qCCu8P1NSJRxgmpfkfa5rKyn9X+Y/9FSmSd5xjyo="
|
||||
[mod."go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"]
|
||||
version = "v0.59.0"
|
||||
hash = "sha256-jItb6nG5/urw6Pv3zb8i5ywianqTQfrheyAIsPIQcnY="
|
||||
version = "v0.60.0"
|
||||
hash = "sha256-DkIpL4xUy+UIQBUK6VgbsI79TbZUltaIhXl4UJWym6E="
|
||||
[mod."go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"]
|
||||
version = "v0.59.0"
|
||||
hash = "sha256-zeC30S2MV7W2xxS5rVfPGhZO4jcdPpxxfy3QvBkt/pQ="
|
||||
version = "v0.60.0"
|
||||
hash = "sha256-twGSnNbXzcw5qvRiFc/zz5rS+nhmbgSVPcd5jrZjlDg="
|
||||
[mod."go.opentelemetry.io/otel"]
|
||||
version = "v1.34.0"
|
||||
hash = "sha256-hnuuTSxaf9yMO/23xWdcTGNzvnnJiqUiL4nzYwUV5bc="
|
||||
version = "v1.35.0"
|
||||
hash = "sha256-LHrBtBnyDtvJGtrXHMPIFe7U53B4bZzpePB4u8Xo4Bg="
|
||||
[mod."go.opentelemetry.io/otel/metric"]
|
||||
version = "v1.34.0"
|
||||
hash = "sha256-JklGKJiMf1fpsE9pmnuLUq26g6wVp173v4GWJ7Xp5s4="
|
||||
version = "v1.35.0"
|
||||
hash = "sha256-K9I0LRZqSLrC09Cuk7tp0VEk3cUVDs8S5MGnu9jw92Q="
|
||||
[mod."go.opentelemetry.io/otel/trace"]
|
||||
version = "v1.34.0"
|
||||
hash = "sha256-u11KJ4WTDtcb0tVv7d/HOdhq8Ea+c1QPBO8MbsCQu9Q="
|
||||
version = "v1.35.0"
|
||||
hash = "sha256-HC2+OGDe2rg0+E8WymQbUNoc249NXM1gIBJzK4UhcQE="
|
||||
[mod."golang.org/x/arch"]
|
||||
version = "v0.14.0"
|
||||
hash = "sha256-9akWthLBB+Au/JIg3WKcSx1YAfHEHOCnQF62sJoMJG4="
|
||||
version = "v0.16.0"
|
||||
hash = "sha256-+DMOuIw9GVyhM4VHdYCZepTU/EEHqDfrxJ2F83TOs5k="
|
||||
[mod."golang.org/x/crypto"]
|
||||
version = "v0.35.0"
|
||||
hash = "sha256-XT1VU0+m1nZbhrMYXN2+eaKBlScfiT4bCBgXu4mfa1Q="
|
||||
version = "v0.37.0"
|
||||
hash = "sha256-9NwDEcii1e2JYM/+3y1yNzWnt/ChMm27e9OtfuF39OM="
|
||||
[mod."golang.org/x/net"]
|
||||
version = "v0.36.0"
|
||||
hash = "sha256-2c9AvnizBMCaqKPzwF2IMlRfvjRNDFmxIYhrgZjhOm0="
|
||||
version = "v0.39.0"
|
||||
hash = "sha256-IP29+yGphWKUT7wHTyzqA2rnRT4AJ7oWcT6NKLzkWcM="
|
||||
[mod."golang.org/x/oauth2"]
|
||||
version = "v0.27.0"
|
||||
hash = "sha256-TBKV2c/m0SgPqrJSE0ltJXfImrYPafNuziLN25jgsYY="
|
||||
version = "v0.29.0"
|
||||
hash = "sha256-IzAypzW8cN5ZbQiIdMTcTiVuUNpMSkwuxeFrJZxcDl8="
|
||||
[mod."golang.org/x/sync"]
|
||||
version = "v0.11.0"
|
||||
hash = "sha256-5ZBfDJvNaUBM4Vhk0fgYblCGL3eBxiJL85nIE8LiKl0="
|
||||
version = "v0.13.0"
|
||||
hash = "sha256-CElRNe74Or/ysUkb/m3Wcz/juO/tB5fhQbAaxA5AizY="
|
||||
[mod."golang.org/x/sys"]
|
||||
version = "v0.30.0"
|
||||
hash = "sha256-BuhWtwDkciVioc03rxty6G2vcZVnPX85lI7tgQOFVP8="
|
||||
version = "v0.32.0"
|
||||
hash = "sha256-c9RRnyKQy9Kl8hpbtcgkm1O5H7gOdk9Rv925F8fZS6E="
|
||||
[mod."golang.org/x/text"]
|
||||
version = "v0.22.0"
|
||||
hash = "sha256-kUwLNFk9K/YuWmO5/u2IshrmhT2CCuk+mAShSlTTeZo="
|
||||
version = "v0.24.0"
|
||||
hash = "sha256-qFbmteGOvJfvbLXiOSI8Fsz5Ixt2ZhSYx0/sIqApC7Y="
|
||||
[mod."golang.org/x/time"]
|
||||
version = "v0.10.0"
|
||||
hash = "sha256-vnlAME3gDR6R4cbCmSYAlR1Rjc0yUpkufTOPNvCdf6Q="
|
||||
version = "v0.11.0"
|
||||
hash = "sha256-ImTej/e5iUHbWPZMA4M2GYbsbiiZQxIrgcnYsc7uD68="
|
||||
[mod."google.golang.org/api"]
|
||||
version = "v0.223.0"
|
||||
hash = "sha256-sNLRocS4vcjPj0vsInI/ioZ29rSVdGD0bGz8ZzBSbus="
|
||||
version = "v0.230.0"
|
||||
hash = "sha256-ihEdZnRbQdwpbgj9AZEZLNY14FqHmacFGFocOqExSVY="
|
||||
[mod."google.golang.org/genproto/googleapis/api"]
|
||||
version = "v0.0.0-20250224174004-546df14abb99"
|
||||
hash = "sha256-8er5KyVDLmuuOZEDd8cHHTkpb/JifejdHwcHfqAD83o="
|
||||
version = "v0.0.0-20250422160041-2d3770c4ea7f"
|
||||
hash = "sha256-Y4wbEHh9Un0QKplTl2S5lhWDUha9QThx5DhWJbDG9fo="
|
||||
[mod."google.golang.org/genproto/googleapis/rpc"]
|
||||
version = "v0.0.0-20250224174004-546df14abb99"
|
||||
hash = "sha256-l/2ByVhr10DBqSp5y1d8mtEY3++RUZKg89FCEptT0nQ="
|
||||
version = "v0.0.0-20250422160041-2d3770c4ea7f"
|
||||
hash = "sha256-WK7iDtAhH19NPe3TywTQlGjDawNaDKWnxhFL9PgVUwM="
|
||||
[mod."google.golang.org/grpc"]
|
||||
version = "v1.70.0"
|
||||
hash = "sha256-7SCJx6Y35O/0P3cFtELDXrOSOb+HshxaTQYdzv2gVmg="
|
||||
version = "v1.72.0"
|
||||
hash = "sha256-tqu+ACMfKjhqdCGN3jLEmtaHB5ywgHGaS/eDeDRnf+M="
|
||||
[mod."google.golang.org/protobuf"]
|
||||
version = "v1.36.5"
|
||||
hash = "sha256-isupBiQUrKPEFzK94k5cgzM3Ab5fMXp352/zcsXV1JU="
|
||||
version = "v1.36.6"
|
||||
hash = "sha256-lT5qnefI5FDJnowz9PEkAGylH3+fE+A3DJDkAyy9RMc="
|
||||
[mod."gopkg.in/warnings.v0"]
|
||||
version = "v0.1.2"
|
||||
hash = "sha256-ATVL9yEmgYbkJ1DkltDGRn/auGAjqGOfjQyBYyUo8s8="
|
||||
|
||||
@@ -1 +1 @@
|
||||
"1.4.169"
|
||||
"1.4.186"
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
pkgs,
|
||||
gomod2nix,
|
||||
goEnv,
|
||||
goVersion,
|
||||
}:
|
||||
|
||||
{
|
||||
default = pkgs.mkShell {
|
||||
nativeBuildInputs = [
|
||||
pkgs.go
|
||||
goVersion
|
||||
pkgs.gopls
|
||||
pkgs.gotools
|
||||
pkgs.go-tools
|
||||
|
||||
@@ -52,18 +52,18 @@ type Client struct {
|
||||
defaultRequiredUserMessage string
|
||||
models []string
|
||||
|
||||
client *anthropic.Client
|
||||
client anthropic.Client
|
||||
}
|
||||
|
||||
func (an *Client) configure() (err error) {
|
||||
if an.ApiBaseURL.Value != "" {
|
||||
baseURL := an.ApiBaseURL.Value
|
||||
|
||||
if strings.Contains(baseURL, "-") && !strings.HasSuffix(baseURL, "/v1") {
|
||||
if strings.HasSuffix(baseURL, "/") {
|
||||
baseURL = strings.TrimSuffix(baseURL, "/")
|
||||
}
|
||||
baseURL = baseURL + "/v1"
|
||||
// As of 2.0beta1, using v2 API endpoint.
|
||||
// https://github.com/anthropics/anthropic-sdk-go/blob/main/CHANGELOG.md#020-beta1-2025-03-25
|
||||
if strings.Contains(baseURL, "-") && !strings.HasSuffix(baseURL, "/v2") {
|
||||
baseURL = strings.TrimSuffix(baseURL, "/")
|
||||
baseURL = baseURL + "/v2"
|
||||
}
|
||||
|
||||
an.client = anthropic.NewClient(
|
||||
@@ -87,21 +87,19 @@ func (an *Client) SendStream(
|
||||
|
||||
ctx := context.Background()
|
||||
stream := an.client.Messages.NewStreaming(ctx, anthropic.MessageNewParams{
|
||||
Model: anthropic.F(opts.Model),
|
||||
MaxTokens: anthropic.F(int64(an.maxTokens)),
|
||||
TopP: anthropic.F(opts.TopP),
|
||||
Temperature: anthropic.F(opts.Temperature),
|
||||
Messages: anthropic.F(messages),
|
||||
Model: opts.Model,
|
||||
MaxTokens: int64(an.maxTokens),
|
||||
TopP: anthropic.Opt(opts.TopP),
|
||||
Temperature: anthropic.Opt(opts.Temperature),
|
||||
Messages: messages,
|
||||
})
|
||||
|
||||
for stream.Next() {
|
||||
event := stream.Current()
|
||||
|
||||
switch delta := event.Delta.(type) {
|
||||
case anthropic.ContentBlockDeltaEventDelta:
|
||||
if delta.Text != "" {
|
||||
channel <- delta.Text
|
||||
}
|
||||
// directly send any non-empty delta text
|
||||
if event.Delta.Text != "" {
|
||||
channel <- event.Delta.Text
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,11 +115,11 @@ func (an *Client) Send(ctx context.Context, msgs []*goopenai.ChatCompletionMessa
|
||||
|
||||
var message *anthropic.Message
|
||||
if message, err = an.client.Messages.New(ctx, anthropic.MessageNewParams{
|
||||
Model: anthropic.F(opts.Model),
|
||||
MaxTokens: anthropic.F(int64(an.maxTokens)),
|
||||
TopP: anthropic.F(opts.TopP),
|
||||
Temperature: anthropic.F(opts.Temperature),
|
||||
Messages: anthropic.F(messages),
|
||||
Model: opts.Model,
|
||||
MaxTokens: int64(an.maxTokens),
|
||||
TopP: anthropic.Opt(opts.TopP),
|
||||
Temperature: anthropic.Opt(opts.Temperature),
|
||||
Messages: messages,
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package deepseek
|
||||
|
||||
import (
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openai"
|
||||
)
|
||||
|
||||
func NewClient() (ret *Client) {
|
||||
ret = &Client{}
|
||||
ret.Client = openai.NewClientCompatible("DeepSeek", "https://api.deepseek.com", nil)
|
||||
return
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
*openai.Client
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package deepseek
|
||||
|
||||
// Test generated using Keploy
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewClient_EmbeddedClientNotNil(t *testing.T) {
|
||||
client := NewClient()
|
||||
if client.Client == nil {
|
||||
t.Fatalf("Expected embedded openai.Client to be non-nil, got nil")
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package groq
|
||||
|
||||
import (
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openai"
|
||||
)
|
||||
|
||||
// NewClient initializes and returns a new Groq Client.
|
||||
func NewClient() (ret *Client) {
|
||||
ret = &Client{}
|
||||
ret.Client = openai.NewClientCompatible("Groq", "https://api.groq.com/openai/v1", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// Client wraps the openai.Client to provide additional functionality specific to Groq.
|
||||
type Client struct {
|
||||
*openai.Client
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package groq
|
||||
|
||||
// Test generated using Keploy
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewClientEmbeddedClientNotNil(t *testing.T) {
|
||||
client := NewClient()
|
||||
if client.Client == nil {
|
||||
t.Fatalf("Expected embedded openai.Client to be non-nil, got nil")
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package litellm
|
||||
|
||||
import (
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openai"
|
||||
)
|
||||
|
||||
func NewClient() (ret *Client) {
|
||||
ret = &Client{}
|
||||
ret.Client = openai.NewClientCompatible("LiteLLM", "http://localhost:4000", nil)
|
||||
return
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
*openai.Client
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package mistral
|
||||
|
||||
import (
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openai"
|
||||
)
|
||||
|
||||
func NewClient() (ret *Client) {
|
||||
ret = &Client{}
|
||||
ret.Client = openai.NewClientCompatible("Mistral", "https://api.mistral.ai/v1", nil)
|
||||
return
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
*openai.Client
|
||||
}
|
||||
74
plugins/ai/openai_compatible/providers_config.go
Normal file
74
plugins/ai/openai_compatible/providers_config.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package openai_compatible
|
||||
|
||||
import (
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openai"
|
||||
)
|
||||
|
||||
// ProviderConfig defines the configuration for an OpenAI-compatible API provider
|
||||
type ProviderConfig struct {
|
||||
Name string
|
||||
BaseURL string
|
||||
}
|
||||
|
||||
// Client is the common structure for all OpenAI-compatible providers
|
||||
type Client struct {
|
||||
*openai.Client
|
||||
}
|
||||
|
||||
// NewClient creates a new OpenAI-compatible client for the specified provider
|
||||
func NewClient(providerConfig ProviderConfig) *Client {
|
||||
client := &Client{}
|
||||
client.Client = openai.NewClientCompatible(providerConfig.Name, providerConfig.BaseURL, nil)
|
||||
return client
|
||||
}
|
||||
|
||||
// ProviderMap is a map of provider name to ProviderConfig for O(1) lookup
|
||||
var ProviderMap = map[string]ProviderConfig{
|
||||
"Mistral": {
|
||||
Name: "Mistral",
|
||||
BaseURL: "https://api.mistral.ai/v1",
|
||||
},
|
||||
"LiteLLM": {
|
||||
Name: "LiteLLM",
|
||||
BaseURL: "http://localhost:4000",
|
||||
},
|
||||
"Groq": {
|
||||
Name: "Groq",
|
||||
BaseURL: "https://api.groq.com/openai/v1",
|
||||
},
|
||||
"GrokAI": {
|
||||
Name: "GrokAI",
|
||||
BaseURL: "https://api.x.ai/v1",
|
||||
},
|
||||
"DeepSeek": {
|
||||
Name: "DeepSeek",
|
||||
BaseURL: "https://api.deepseek.com",
|
||||
},
|
||||
"Cerebras": {
|
||||
Name: "Cerebras",
|
||||
BaseURL: "https://api.cerebras.ai/v1",
|
||||
},
|
||||
"OpenRouter": {
|
||||
Name: "OpenRouter",
|
||||
BaseURL: "https://openrouter.ai/api/v1",
|
||||
},
|
||||
"SiliconCloud": {
|
||||
Name: "SiliconCloud",
|
||||
BaseURL: "https://api.siliconflow.cn/v1",
|
||||
},
|
||||
}
|
||||
|
||||
// GetProviderByName returns the provider configuration for a given name with O(1) lookup
|
||||
func GetProviderByName(name string) (ProviderConfig, bool) {
|
||||
provider, found := ProviderMap[name]
|
||||
return provider, found
|
||||
}
|
||||
|
||||
// CreateClient creates a new client for a provider by name
|
||||
func CreateClient(providerName string) (*Client, bool) {
|
||||
providerConfig, found := GetProviderByName(providerName)
|
||||
if !found {
|
||||
return nil, false
|
||||
}
|
||||
return NewClient(providerConfig), true
|
||||
}
|
||||
42
plugins/ai/openai_compatible/providers_config_test.go
Normal file
42
plugins/ai/openai_compatible/providers_config_test.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package openai_compatible
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCreateClient(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
provider string
|
||||
exists bool
|
||||
}{
|
||||
{
|
||||
name: "Existing provider - Mistral",
|
||||
provider: "Mistral",
|
||||
exists: true,
|
||||
},
|
||||
{
|
||||
name: "Existing provider - Groq",
|
||||
provider: "Groq",
|
||||
exists: true,
|
||||
},
|
||||
{
|
||||
name: "Non-existent provider",
|
||||
provider: "NonExistent",
|
||||
exists: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
client, exists := CreateClient(tc.provider)
|
||||
if exists != tc.exists {
|
||||
t.Errorf("Expected exists=%v for provider %s, got %v",
|
||||
tc.exists, tc.provider, exists)
|
||||
}
|
||||
if exists && client == nil {
|
||||
t.Errorf("Expected non-nil client for provider %s", tc.provider)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package openrouter
|
||||
|
||||
import (
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openai"
|
||||
)
|
||||
|
||||
func NewClient() (ret *Client) {
|
||||
ret = &Client{}
|
||||
ret.Client = openai.NewClientCompatible("OpenRouter", "https://openrouter.ai/api/v1", nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
*openai.Client
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
package openrouter
|
||||
@@ -1,15 +0,0 @@
|
||||
package siliconcloud
|
||||
|
||||
import (
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openai"
|
||||
)
|
||||
|
||||
func NewClient() (ret *Client) {
|
||||
ret = &Client{}
|
||||
ret.Client = openai.NewClientCompatible("SiliconCloud", "https://api.siliconflow.cn/v1", nil)
|
||||
return
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
*openai.Client
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/danielmiessler/fabric/plugins"
|
||||
@@ -95,6 +97,9 @@ func (o *VendorsManager) readModels() (err error) {
|
||||
if result.err != nil {
|
||||
fmt.Println(result.vendorName, result.err)
|
||||
} else {
|
||||
sort.Slice(result.models, func(i, j int) bool {
|
||||
return strings.ToLower(result.models[i]) < strings.ToLower(result.models[j])
|
||||
})
|
||||
o.Models.AddGroupItems(result.vendorName, result.models...)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,5 @@ type Storage[T any] interface {
|
||||
Rename(oldName, newName string) (err error)
|
||||
Save(name string, content []byte) (err error)
|
||||
Load(name string) (ret []byte, err error)
|
||||
ListNames() (err error)
|
||||
ListNames(shellCompleteList bool) (err error)
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ func (o *StorageEntity) GetNames() (ret []string, err error) {
|
||||
}
|
||||
|
||||
func (o *StorageEntity) Delete(name string) (err error) {
|
||||
if err = os.Remove(o.BuildFilePathByName(name)); err != nil {
|
||||
if err = os.RemoveAll(o.BuildFilePathByName(name)); err != nil {
|
||||
err = fmt.Errorf("could not delete %s: %v", name, err)
|
||||
}
|
||||
return
|
||||
@@ -100,14 +100,16 @@ func (o *StorageEntity) Load(name string) (ret []byte, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (o *StorageEntity) ListNames() (err error) {
|
||||
func (o *StorageEntity) ListNames(shellCompleteList bool) (err error) {
|
||||
var names []string
|
||||
if names, err = o.GetNames(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(names) == 0 {
|
||||
fmt.Printf("\nNo %v\n", o.Label)
|
||||
if !shellCompleteList {
|
||||
fmt.Printf("\nNo %v\n", o.Label)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -197,12 +197,13 @@ func LoadStrategy(filename string) (*Strategy, error) {
|
||||
}
|
||||
|
||||
// ListStrategies prints available strategies
|
||||
func (sm *StrategiesManager) ListStrategies() error {
|
||||
func (sm *StrategiesManager) ListStrategies(shellCompleteList bool) error {
|
||||
if len(sm.Strategies) == 0 {
|
||||
return fmt.Errorf("no strategies found. Please run 'fabric --setup' to download strategies")
|
||||
}
|
||||
fmt.Print("Available Strategies:\n\n")
|
||||
|
||||
if !shellCompleteList {
|
||||
fmt.Print("Available Strategies:\n\n")
|
||||
}
|
||||
// Get all strategy names for sorting
|
||||
names := []string{}
|
||||
for name := range sm.Strategies {
|
||||
@@ -224,7 +225,11 @@ func (sm *StrategiesManager) ListStrategies() error {
|
||||
formatString := "%-" + fmt.Sprintf("%d", maxNameLength+2) + "s %s\n"
|
||||
for _, name := range names {
|
||||
strategy := sm.Strategies[name]
|
||||
fmt.Printf(formatString, strategy.Name, strategy.Description)
|
||||
if shellCompleteList {
|
||||
fmt.Printf("%s\n", strategy.Name)
|
||||
} else {
|
||||
fmt.Printf(formatString, strategy.Name, strategy.Description)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -117,8 +117,12 @@ func (e *ExtensionExecutor) executeWithFile(cmd *exec.Cmd, ext *ExtensionDefinit
|
||||
// Create context with timeout
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
// Store the original environment
|
||||
originalEnv := cmd.Env
|
||||
// Create a new command with context. This might reset Env, depending on the Go version.
|
||||
cmd = exec.CommandContext(ctx, cmd.Path, cmd.Args[1:]...)
|
||||
cmd.Env = cmd.Env
|
||||
// Restore the environment variables explicitly
|
||||
cmd.Env = originalEnv
|
||||
|
||||
fileConfig := ext.GetFileConfig()
|
||||
if fileConfig == nil {
|
||||
|
||||
@@ -47,7 +47,7 @@ func (o *Defaults) Setup() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
vendorsModels.Print()
|
||||
vendorsModels.Print(false)
|
||||
|
||||
if err = o.Ask(o.Name); err != nil {
|
||||
return
|
||||
|
||||
@@ -34,6 +34,7 @@ type PromptRequest struct {
|
||||
|
||||
type ChatRequest struct {
|
||||
Prompts []PromptRequest `json:"prompts"`
|
||||
Language string `json:"language"` // Add Language field to bind from request
|
||||
common.ChatOptions // Embed the ChatOptions from common package
|
||||
}
|
||||
|
||||
@@ -64,7 +65,8 @@ func (h *ChatHandler) HandleChat(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Received chat request with %d prompts", len(request.Prompts))
|
||||
// Add log to check received language field
|
||||
log.Printf("Received chat request - Language: '%s', Prompts: %d", request.Language, len(request.Prompts))
|
||||
|
||||
// Set headers for SSE
|
||||
c.Writer.Header().Set("Content-Type", "text/readystream")
|
||||
@@ -110,6 +112,7 @@ func (h *ChatHandler) HandleChat(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Pass the language received in the initial request to the common.ChatRequest
|
||||
chatReq := &common.ChatRequest{
|
||||
Message: &goopenai.ChatCompletionMessage{
|
||||
Role: "user",
|
||||
@@ -117,6 +120,7 @@ func (h *ChatHandler) HandleChat(c *gin.Context) {
|
||||
},
|
||||
PatternName: p.PatternName,
|
||||
ContextName: p.ContextName,
|
||||
Language: request.Language, // Pass the language field
|
||||
}
|
||||
|
||||
opts := &common.ChatOptions{
|
||||
|
||||
@@ -45,6 +45,7 @@ func (h *ConfigHandler) GetConfig(c *gin.Context) {
|
||||
"openrouter": "",
|
||||
"silicon": "",
|
||||
"deepseek": "",
|
||||
"grokai": "",
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -65,6 +66,7 @@ func (h *ConfigHandler) GetConfig(c *gin.Context) {
|
||||
"openrouter": os.Getenv("OPENROUTER_API_KEY"),
|
||||
"silicon": os.Getenv("SILICON_API_KEY"),
|
||||
"deepseek": os.Getenv("DEEPSEEK_API_KEY"),
|
||||
"grokai": os.Getenv("GROKAI_API_KEY"),
|
||||
"lmstudio": os.Getenv("LM_STUDIO_API_BASE_URL"),
|
||||
}
|
||||
|
||||
@@ -87,6 +89,7 @@ func (h *ConfigHandler) UpdateConfig(c *gin.Context) {
|
||||
OpenRouterApiKey string `json:"openrouter_api_key"`
|
||||
SiliconApiKey string `json:"silicon_api_key"`
|
||||
DeepSeekApiKey string `json:"deepseek_api_key"`
|
||||
GrokaiApiKey string `json:"grokai_api_key"`
|
||||
LMStudioURL string `json:"lm_studio_base_url"`
|
||||
}
|
||||
|
||||
@@ -105,6 +108,7 @@ func (h *ConfigHandler) UpdateConfig(c *gin.Context) {
|
||||
"OPENROUTER_API_KEY": config.OpenRouterApiKey,
|
||||
"SILICON_API_KEY": config.SiliconApiKey,
|
||||
"DEEPSEEK_API_KEY": config.DeepSeekApiKey,
|
||||
"GROKAI_API_KEY": config.GrokaiApiKey,
|
||||
"LM_STUDIO_API_BASE_URL": config.LMStudioURL,
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
@@ -14,6 +15,7 @@ import (
|
||||
type StrategyMeta struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Prompt string `json:"prompt"`
|
||||
}
|
||||
|
||||
// NewStrategiesHandler registers the /strategies GET endpoint
|
||||
@@ -41,16 +43,17 @@ func NewStrategiesHandler(r *gin.Engine) {
|
||||
}
|
||||
|
||||
var s struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Prompt string `json:"prompt"`
|
||||
}
|
||||
if err := json.Unmarshal(data, &s); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
strategies = append(strategies, StrategyMeta{
|
||||
Name: s.Name,
|
||||
Name: strings.TrimSuffix(file.Name(), ".json"),
|
||||
Description: s.Description,
|
||||
Prompt: s.Prompt,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
(echo "beginning of content input" ; f -u https://danielmiessler.com/p/framing-is-everything ; echo "end of content input"; echo "beginning of AI instructions (prompt)"; cat ~/.config/fabric/patterns/extract_insights/system.md; echo "endof AI instructions (prompt)" ; echo "beginning of AI output" ; f -u https://danielmiessler.com/p/framing-is-everything | f -p extract_insights -m gpt-3.5-turbo; echo "end of AI output. Now you should have all three." ) | f -rp rate_ai_result -m o1-preview-2024-09-12
|
||||
@@ -1,60 +0,0 @@
|
||||
# Rate AI Result
|
||||
|
||||
This is an example of a Fabric Stitch, which is a chained Fabric command that pipes Fabric results into each other to achieve a result. So it's multiple Patterns…*stitched* together.
|
||||
|
||||
## Problem
|
||||
|
||||
The problem we're trying to solve with this Stitch is not being able to tell how smart given AI models are. I want to be able to rate their output vs. the output from a different model with the same instructions.
|
||||
|
||||
## Solution
|
||||
|
||||
What `rate_ai_result` does is run a result using AI 1, and then rate it with AI 2.
|
||||
|
||||
## Functionality
|
||||
|
||||
`rate_ai_result` accomplishes that like so:
|
||||
|
||||
1. Get the input that will be operated on by an AI.
|
||||
2. Get the instruction/pattern/prompt that will be used by the AI.
|
||||
3. Get the result of the instructions running against the AI.
|
||||
4. Combine all three of those together as the input to another Fabric call.
|
||||
4. Send that combined input to the most advanced model you have available to assess the quality of the AI result.
|
||||
|
||||
```
|
||||
(echo "beginning of content input" ; f -u https://danielmiessler.com/p/framing-is-everything ; echo "end ofcontent input"; echo "beginning of AI instructions (prompt)"; cat ~/.config/fabric/patterns/extract_insights/system.md; echo "end of AI instructions (prompt)" ; echo "beginning of AI output" ; f -u https://danielmiessler.com/p/framing-is-everything | f -p extract_insights -m gpt-3.5-turbo ; echo "end of AI output. Now you should have all three." ) | f -rp rate_ai_result -m o1-preview-2024-09-12
|
||||
```
|
||||
In this case we're taking:
|
||||
|
||||
* A blog post as the input
|
||||
* Getting the content of the extract_insights pattern
|
||||
* Capturing the output of extract_insights on the blog post using `gpt-3.5-turbo`
|
||||
* Sending all of that to `o1-preview` using the `rate_ai_result` prompt
|
||||
|
||||
NOTE: `rate_ai_result` is both a Pattern name and the name of this Stitch.
|
||||
|
||||
## Output
|
||||
|
||||
The `rate_ai_result` Pattern is designed to judge the output of another AI on a human sophistication scale that roughly maps to educational and world-state achievement, with the assumption that higher stages require higher cognitive ability as well. These are:
|
||||
|
||||
- Superhuman
|
||||
- Best humans in the world
|
||||
- Ph.D
|
||||
- Masters
|
||||
- Bachelors
|
||||
- High School
|
||||
- Partially Educated
|
||||
- Uneducated
|
||||
|
||||
## How to run it
|
||||
|
||||
To run it, just execute the code in the `rate_ai_result` file in this repository. And adjust the components as desired to change the input, the AI you're testing, and the AI you're using to judge.
|
||||
|
||||
### Blog Post
|
||||
|
||||
Here's a full blog post describing in even more detail.
|
||||
|
||||
[Using the Smartest AI to Rate Other AI](https://danielmiessler.com/p/using-the-smartest-ai-to-rate-other-ai)
|
||||
|
||||
#### Credit
|
||||
|
||||
Created by Daniel Miessler on November 7th, 2024.
|
||||
4
strategies/aot.json
Normal file
4
strategies/aot.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"description": "Atom-of-Thought (AoT) Prompting",
|
||||
"prompt": "To solve this problem, break it down into the smallest independent 'atomic' sub-problems. For each atomic sub-problem: 1. Label it as 'Atom X: [brief description]' 2. Solve that specific subproblem completely 3. Make sure each atom can be solved independently. After solving all atomic sub-problems, provide a synthesis that combines them into a final answer. Return the final answer in the required format."
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
package main
|
||||
|
||||
var version = "v1.4.169"
|
||||
var version = "v1.4.186"
|
||||
|
||||
@@ -305,10 +305,11 @@ async function readFileContent(file: File): Promise<string> {
|
||||
}
|
||||
}
|
||||
|
||||
// Centralized language instruction logic in ChatService.ts; YouTube flow now passes plain transcript and system prompt
|
||||
async function processYouTubeURL(input: string) {
|
||||
console.log('\n=== YouTube Flow Start ===');
|
||||
const originalLanguage = get(languageStore);
|
||||
|
||||
|
||||
try {
|
||||
// Add processing message first
|
||||
messageStore.update(messages => [...messages, {
|
||||
@@ -316,16 +317,11 @@ async function readFileContent(file: File): Promise<string> {
|
||||
content: 'Processing YouTube video...',
|
||||
format: 'loading'
|
||||
}]);
|
||||
|
||||
|
||||
// Get transcript but don't display it
|
||||
const { transcript } = await getTranscript(input);
|
||||
|
||||
// Log system prompt BEFORE createChatRequest
|
||||
console.log('System prompt BEFORE createChatRequest in YouTube flow:', $systemPrompt);
|
||||
|
||||
// Log system prompt BEFORE streamChat
|
||||
console.log(`System prompt BEFORE streamChat in YouTube flow: ${$systemPrompt}`);
|
||||
|
||||
// Pass plain transcript and system prompt; ChatService will handle language instruction
|
||||
const stream = await chatService.streamChat(transcript, $systemPrompt);
|
||||
await chatService.processStream(
|
||||
stream,
|
||||
@@ -447,21 +443,16 @@ async function readFileContent(file: File): Promise<string> {
|
||||
newMessages.splice(loadingIndex, 1);
|
||||
}
|
||||
|
||||
// Add or update the assistant message
|
||||
const assistantIndex = newMessages.findIndex(m => m.role === 'assistant');
|
||||
if (assistantIndex !== -1) {
|
||||
newMessages[assistantIndex].content = content;
|
||||
newMessages[assistantIndex].format = response?.format;
|
||||
} else {
|
||||
newMessages.push({
|
||||
role: 'assistant',
|
||||
content,
|
||||
format: response?.format
|
||||
});
|
||||
}
|
||||
// Always append a new assistant message
|
||||
newMessages.push({
|
||||
role: 'assistant',
|
||||
content,
|
||||
format: response?.format
|
||||
});
|
||||
return newMessages;
|
||||
});
|
||||
},
|
||||
|
||||
(error) => {
|
||||
// Make sure to remove loading message on error
|
||||
messageStore.update(messages =>
|
||||
|
||||
@@ -15,23 +15,31 @@
|
||||
});
|
||||
|
||||
// Watch selectedPreset changes
|
||||
$: if (selectedPreset) {
|
||||
console.log('Pattern selected from dropdown:', selectedPreset);
|
||||
// Always call selectPattern when the dropdown value changes.
|
||||
// The patternAPI.selectPattern function handles empty strings correctly.
|
||||
$: {
|
||||
// Log the change regardless of the value
|
||||
console.log('Dropdown selection changed to:', selectedPreset);
|
||||
try {
|
||||
// Call the function to select the pattern (or reset if selectedPreset is empty)
|
||||
patternAPI.selectPattern(selectedPreset);
|
||||
// Verify the selection
|
||||
|
||||
// Optional: Keep verification logs if helpful for debugging
|
||||
const currentSystemPrompt = get(systemPrompt);
|
||||
const currentPattern = get(selectedPatternName);
|
||||
console.log('After dropdown selection - Pattern:', currentPattern);
|
||||
console.log('After dropdown selection - System Prompt length:', currentSystemPrompt?.length);
|
||||
|
||||
if (!currentPattern || !currentSystemPrompt) {
|
||||
console.error('Pattern selection verification failed:');
|
||||
console.error('- Selected Pattern:', currentPattern);
|
||||
console.error('- System Prompt:', currentSystemPrompt);
|
||||
}
|
||||
|
||||
// Optional: Refine verification logic if needed
|
||||
// For example, only log error if a pattern was expected but not set
|
||||
// if (selectedPreset && (!currentPattern || !currentSystemPrompt)) {
|
||||
// console.error('Pattern selection verification failed:');
|
||||
// console.error('- Selected Pattern:', currentPattern);
|
||||
// console.error('- System Prompt:', currentSystemPrompt);
|
||||
// }
|
||||
} catch (error) {
|
||||
console.error('Error in pattern selection:', error);
|
||||
// Log any errors during the pattern selection process
|
||||
console.error('Error processing pattern selection:', error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ export interface ChatRequest {
|
||||
top_p: number;
|
||||
frequency_penalty: number;
|
||||
presence_penalty: number;
|
||||
language?: string;
|
||||
}
|
||||
|
||||
export interface Message {
|
||||
|
||||
@@ -48,6 +48,8 @@ export class ChatService {
|
||||
promptCount: request.prompts?.length,
|
||||
messageCount: request.messages?.length
|
||||
});
|
||||
// NEW: Log the full payload before sending to backend
|
||||
console.log('Final ChatRequest payload:', JSON.stringify(request, null, 2));
|
||||
|
||||
const response = await fetch('/api/chat', {
|
||||
method: 'POST',
|
||||
@@ -193,10 +195,12 @@ export class ChatService {
|
||||
public async createChatRequest(userInput: string, systemPromptText?: string, isPattern: boolean = false): Promise<ChatRequest> {
|
||||
const prompt = this.createChatPrompt(userInput, systemPromptText);
|
||||
const config = get(chatConfig);
|
||||
|
||||
const language = get(languageStore);
|
||||
|
||||
return {
|
||||
prompts: [prompt],
|
||||
messages: [],
|
||||
language: language, // Add language at the top level for backend compatibility
|
||||
...config
|
||||
};
|
||||
}
|
||||
|
||||
@@ -61,16 +61,16 @@ export const POST: RequestHandler = async ({ request }) => {
|
||||
language: body.language
|
||||
});
|
||||
|
||||
// Ensure language instruction is present
|
||||
if (body.prompts?.[0] && body.language && body.language !== 'en') {
|
||||
const languageInstruction = `. Please use the language '${body.language}' for the output.`;
|
||||
if (!body.prompts[0].userInput?.includes(languageInstruction)) {
|
||||
body.prompts[0].userInput = (body.prompts[0].userInput || '') + languageInstruction;
|
||||
}
|
||||
}
|
||||
// Removed redundant language instruction logic; Go backend handles this
|
||||
// if (body.prompts?.[0] && body.language && body.language !== 'en') {
|
||||
// const languageInstruction = `. Please use the language '${body.language}' for the output.`;
|
||||
// if (!body.prompts[0].userInput?.includes(languageInstruction)) {
|
||||
// body.prompts[0].userInput = (body.prompts[0].userInput || '') + languageInstruction;
|
||||
// }
|
||||
// }
|
||||
|
||||
console.log('2. Language analysis:', {
|
||||
input: body.prompts?.[0]?.userInput?.substring(0, 100),
|
||||
input: body.prompts?.[0]?.userInput?.substring(0, 100), // Note: This input no longer has the instruction appended here
|
||||
hasLanguageInstruction: body.prompts?.[0]?.userInput?.includes('language'),
|
||||
containsFr: body.prompts?.[0]?.userInput?.includes('fr'),
|
||||
containsEn: body.prompts?.[0]?.userInput?.includes('en'),
|
||||
|
||||
@@ -1693,8 +1693,87 @@
|
||||
},
|
||||
{
|
||||
"patternName": "extract_wisdom_short",
|
||||
"description": "Extract condensed insightful ideas and recommendations focusing on life wisdom.",
|
||||
"tags": [
|
||||
"EXTRACT",
|
||||
"WISDOM",
|
||||
"SELF"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "analyze_bill",
|
||||
"description": "Analyze a legislative bill and implications.",
|
||||
"tags": [
|
||||
"ANALYSIS",
|
||||
"BILL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "analyze_bill_short",
|
||||
"description": "Consended - Analyze a legislative bill and implications.",
|
||||
"tags": [
|
||||
"ANALYSIS",
|
||||
"BILL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "create_coding_feature",
|
||||
"description": "[Description pending]",
|
||||
"tags": []
|
||||
"tags": [
|
||||
"DEVELOPMENT"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "create_excalidraw_visualization",
|
||||
"description": "Create visualizations using Excalidraw.",
|
||||
"tags": [
|
||||
"VISUALIZATION"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "create_flash_cards",
|
||||
"description": "Generate flashcards for key concepts and definitions.",
|
||||
"tags": [
|
||||
"LEARNING"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "create_loe_document",
|
||||
"description": "Create detailed Level of Effort (LOE) estimation documents.",
|
||||
"tags": [
|
||||
"DEVELOPMENT",
|
||||
"BUSINESS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "extract_domains",
|
||||
"description": "Extract key content and source.",
|
||||
"tags": [
|
||||
"EXTRACT",
|
||||
"ANALYSIS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "extract_main_activities",
|
||||
"description": "Extract and list main events from transcripts.",
|
||||
"tags": [
|
||||
"EXTRACT",
|
||||
"ANALYSIS"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "find_female_life_partner",
|
||||
"description": "Clarify and summarize partner criteria in direct language.",
|
||||
"tags": [
|
||||
"SELF"
|
||||
]
|
||||
},
|
||||
{
|
||||
"patternName": "youtube_summary",
|
||||
"description": "Summarize YouTube videos with key points and timestamps.",
|
||||
"tags": [
|
||||
"SUMMARIZE"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
[
|
||||
{ "name": "aot", "description": "Atom-of-Thought (AoT)" },
|
||||
{ "name": "cod", "description": "Chain-of-Draft (CoD)" },
|
||||
{ "name": "cot", "description": "Chain-of-Thought (CoT) Prompting" },
|
||||
{ "name": "ltm", "description": "Least-to-Most Prompting" },
|
||||
|
||||
Reference in New Issue
Block a user