├── .go-version ├── .claude └── settings.json ├── extensions ├── jigsawstack │ ├── tts.mp3 │ ├── README.md │ ├── jigsawstack_test.go │ ├── doc.go │ ├── storage_test.go │ ├── natural_language_test.go │ ├── sql_test.go │ ├── audio_test.go │ ├── sql.go │ ├── prediction.go │ ├── web_test.go │ ├── prompt_test.go │ ├── audio.go │ ├── jigsawstack.go │ └── web.go ├── composio │ ├── composio_test.go │ ├── doc.go │ ├── README.md │ ├── tools_test.go │ ├── options.go │ ├── auth_test.go │ ├── composio.go │ ├── run.go │ ├── auth.go │ └── run_test.go ├── e2b │ ├── doc.go │ ├── README.md │ ├── errors.go │ ├── options.go │ └── tools_test.go └── toolhouse │ ├── doc.go │ ├── options.go │ ├── tools.go │ ├── tools_test.go │ ├── toolhouse_test.go │ ├── execute_test.go │ ├── execute.go │ └── toolhouse.go ├── examples ├── audio-house-translation │ ├── README.md │ ├── house-speaks-mandarin.mp3 │ ├── main_test.go │ └── main.go ├── vhdl-documentor-json │ ├── report │ │ ├── Adder │ │ │ └── .keep │ │ ├── Mux │ │ │ ├── .keep │ │ │ └── tb_Mux2t1.vhd │ │ ├── NMux │ │ │ └── .keep │ │ ├── AddSub │ │ │ └── .keep │ │ └── OnesComp │ │ │ └── .keep │ ├── test │ │ ├── tb_mux2t1.vhd │ │ ├── tb_mux2t1s.vhd │ │ ├── tb_NMux2t1.vhd │ │ ├── tb_nBitInverter.vhd │ │ ├── tb_nBitAdder.vhd │ │ ├── tb_NFullAdder.vhd │ │ ├── tb_OnesComp.vhd │ │ ├── tb_Adder.vhd │ │ └── tb_AdderSubtractor.vhd │ ├── src │ │ ├── invg.vhd │ │ ├── org2.vhd │ │ ├── andg2.vhd │ │ ├── xorg2.vhd │ │ ├── Reg.vhd │ │ ├── Adder.vhd │ │ ├── mux2t1.vhd │ │ ├── Multiplier.vhd │ │ ├── OnesComp.vhd │ │ ├── FullAdder.vhd │ │ ├── RegLd.vhd │ │ ├── NBitInverter.vhd │ │ ├── mux2t1_N.vhd │ │ ├── NBitAdder.vhd │ │ ├── AdderSubtractor.vhd │ │ ├── TPU_MV_Element.vhd │ │ └── mux2t1s.vhd │ └── template.tmpl ├── chat-terminal │ ├── README.md │ └── main.go ├── audio-lex-fridman │ ├── The Roman Emperors who went insane Gregory Aldrete and Lex Fridman.mp3 │ ├── README.md │ ├── main_test.go │ └── main.go ├── moderation │ ├── README.md │ └── main.go ├── json-chat │ ├── README.md │ ├── main_test.go │ └── main.go ├── llama-blind │ ├── main_test.go │ ├── README.md │ └── main.go ├── toolhouse-python-code-interpreter │ ├── main_test.go │ ├── README.md │ └── main.go ├── composio-github-star │ ├── README.md │ └── main.go └── e2b-go-project │ ├── README.md │ └── main.go ├── internal ├── schema │ ├── testdata │ │ ├── .gitignore │ │ ├── map_type.json │ │ ├── array_type.json │ │ ├── inlining_ptr.json │ │ ├── inlining_tag.json │ │ ├── compact_date.json │ │ ├── lookup_expanded.json │ │ ├── inlining_inheritance.json │ │ ├── schema_alias.json │ │ ├── schema_with_minimum.json │ │ ├── schema_with_expression.json │ │ ├── user_with_anchor.json │ │ ├── custom_type.json │ │ ├── lookup.json │ │ ├── test_config.json │ │ ├── commas_in_pattern.json │ │ ├── custom_type_extend.json │ │ ├── custom_additional.json │ │ ├── nullable.json │ │ ├── number_handling.json │ │ ├── recursive.json │ │ ├── custom_type_with_interface.json │ │ ├── inlining_embedded.json │ │ ├── equals_in_pattern.json │ │ ├── yaml_inline.json │ │ ├── inlining_embedded_anchored.json │ │ ├── schema_alias_2.json │ │ ├── test_yaml_and_json_prefer_yaml.json │ │ ├── custom_slice_type.json │ │ ├── with_custom_format.json │ │ ├── schema_property_alias.json │ │ ├── array_handling.json │ │ ├── base_schema_id.json │ │ ├── custom_map_type.json │ │ ├── test_description_override.json │ │ ├── unsigned_int_handling.json │ │ ├── keynamed.json │ │ ├── oneof_ref.json │ │ ├── anyof.json │ │ ├── oneof.json │ │ └── go_comments.json │ └── doc.go ├── omap │ ├── doc.go │ ├── wbuf_test.go │ └── utils_test.go ├── list │ ├── doc.go │ └── element.go ├── streams │ └── doc.go └── test │ ├── failer.go │ ├── server.go │ ├── mod-composio.go │ ├── mod-e2b.go │ ├── mod-jigsawstack.go │ ├── mod-toolhouse.go │ ├── mod-groq.go │ ├── helpers.go │ └── failer_test.go ├── pkg ├── groqerr │ ├── stream_test.go │ ├── doc.go │ ├── api.go │ └── stream.go ├── builders │ ├── doc.go │ ├── urls.go │ ├── options.go │ ├── forms.go │ └── requests.go └── tools │ ├── doc.go │ └── tools.go ├── testdata └── whisper.mp3 ├── cmd └── generate-models │ ├── go.mod │ ├── go.sum │ ├── README.md │ └── template.tmpl ├── doc.go ├── .github ├── ISSUE_TEMPLATE │ ├── 4_security_issue_disclosure.md │ ├── 3_docs_wiki_or_website_issue.md │ ├── integration-issue-template.md │ ├── 1_bug_report.md │ └── 2_feature_request.md ├── dependabot.yml └── workflows │ ├── coverage.yaml │ ├── lint.yaml │ ├── unit.yaml │ └── chron-models.yaml ├── .envrc ├── go.mod ├── groq_test.go ├── SECURITY.md ├── .revive.toml ├── CODE_OF_CONDUCT.md ├── LICENSE ├── CONTRIBUTING.md ├── flake.lock ├── go.sum └── flake.nix /.go-version: -------------------------------------------------------------------------------- 1 | 1.25 2 | -------------------------------------------------------------------------------- /.claude/settings.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /extensions/jigsawstack/tts.mp3: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/audio-house-translation/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/report/Adder/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/report/Mux/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/report/NMux/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/test/tb_mux2t1.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /internal/schema/testdata/.gitignore: -------------------------------------------------------------------------------- 1 | *.out.json -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/report/AddSub/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/report/OnesComp/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/test/tb_mux2t1s.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extensions/jigsawstack/README.md: -------------------------------------------------------------------------------- 1 | # jigsawstack 2 | -------------------------------------------------------------------------------- /pkg/groqerr/stream_test.go: -------------------------------------------------------------------------------- 1 | package groqerr_test 2 | -------------------------------------------------------------------------------- /extensions/composio/composio_test.go: -------------------------------------------------------------------------------- 1 | package composio 2 | -------------------------------------------------------------------------------- /extensions/jigsawstack/jigsawstack_test.go: -------------------------------------------------------------------------------- 1 | package jigsawstack 2 | -------------------------------------------------------------------------------- /extensions/e2b/doc.go: -------------------------------------------------------------------------------- 1 | // Package e2b provides an e2b client for groq-go. 2 | package e2b 3 | -------------------------------------------------------------------------------- /internal/omap/doc.go: -------------------------------------------------------------------------------- 1 | // Package omap provides an ordered map implementation. 2 | package omap 3 | -------------------------------------------------------------------------------- /testdata/whisper.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connerohnesorge/groq-go/HEAD/testdata/whisper.mp3 -------------------------------------------------------------------------------- /internal/list/doc.go: -------------------------------------------------------------------------------- 1 | // Package list contains the implementation a doubly linked list. 2 | package list 3 | -------------------------------------------------------------------------------- /pkg/groqerr/doc.go: -------------------------------------------------------------------------------- 1 | // Package groqerr provides error types for the groq-go library. 2 | package groqerr 3 | -------------------------------------------------------------------------------- /extensions/composio/doc.go: -------------------------------------------------------------------------------- 1 | // Package composio provides a composio client for groq-go. 2 | package composio 3 | -------------------------------------------------------------------------------- /pkg/builders/doc.go: -------------------------------------------------------------------------------- 1 | // Package builders provides builders for HTTP requests and forms. 2 | package builders 3 | -------------------------------------------------------------------------------- /internal/schema/doc.go: -------------------------------------------------------------------------------- 1 | // Package schema provides an interface for working with JSON Schemas. 2 | package schema 3 | -------------------------------------------------------------------------------- /internal/streams/doc.go: -------------------------------------------------------------------------------- 1 | // Package streams contains the interfaces for groq-go streamed responses. 2 | package streams 3 | -------------------------------------------------------------------------------- /cmd/generate-models/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/conneroisu/groq-go/cmd/models 2 | 3 | go 1.23.2 4 | 5 | require golang.org/x/text v0.18.0 6 | -------------------------------------------------------------------------------- /pkg/tools/doc.go: -------------------------------------------------------------------------------- 1 | // Package tools contains the interfaces for groq-go tooling usable by llms. 2 | package tools 3 | 4 | //go:generate gomarkdoc -o README.md -e . 5 | -------------------------------------------------------------------------------- /pkg/builders/urls.go: -------------------------------------------------------------------------------- 1 | package builders 2 | 3 | type ( 4 | // URLComputer computes URLs for a given client. 5 | URLComputer interface { 6 | ComputeURLs() 7 | } 8 | ) 9 | -------------------------------------------------------------------------------- /examples/audio-house-translation/house-speaks-mandarin.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connerohnesorge/groq-go/HEAD/examples/audio-house-translation/house-speaks-mandarin.mp3 -------------------------------------------------------------------------------- /cmd/generate-models/go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= 2 | golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 3 | -------------------------------------------------------------------------------- /extensions/jigsawstack/doc.go: -------------------------------------------------------------------------------- 1 | // Package jigsawstack provides a JigsawStack extension for groq-go. 2 | // 3 | // It gives tools for working with the JigsawStack API. 4 | package jigsawstack 5 | -------------------------------------------------------------------------------- /extensions/toolhouse/doc.go: -------------------------------------------------------------------------------- 1 | // Package toolhouse provides a Toolhouse extension for groq-go. 2 | // 3 | // It allows you to use the Toolhouse API to give tools to your ai models. 4 | package toolhouse 5 | -------------------------------------------------------------------------------- /examples/chat-terminal/README.md: -------------------------------------------------------------------------------- 1 | # terminal-chat 2 | 3 | This is a simple terminal chat application using the groq-go library. 4 | 5 | ## Usage 6 | 7 | ```bash 8 | export GROQ_KEY=your-groq-key 9 | go run . 10 | ``` 11 | -------------------------------------------------------------------------------- /extensions/composio/README.md: -------------------------------------------------------------------------------- 1 | # composio 2 | 3 | Compose AI is a powerful tool for creating complex and high-quality compositions of ai tools. This package provides a client for the composio api easily accessible through the groq-go library. 4 | -------------------------------------------------------------------------------- /examples/audio-lex-fridman/The Roman Emperors who went insane Gregory Aldrete and Lex Fridman.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/connerohnesorge/groq-go/HEAD/examples/audio-lex-fridman/The Roman Emperors who went insane Gregory Aldrete and Lex Fridman.mp3 -------------------------------------------------------------------------------- /extensions/e2b/README.md: -------------------------------------------------------------------------------- 1 | # e2b 2 | 3 | This is a extension for the [groq-go](https://github.com/conneroisu/groq-go) library. 4 | It provides tools for working with the [e2b](https://github.com/e2b-dev/e2b) api and sandboxes either using models or the e2b api directly. 5 | 6 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Package groq provides a unofficial client for the Groq API. 2 | // 3 | // With specially designed hardware, the Groq API is a super fast way to query 4 | // open source llms. 5 | // 6 | // API Documentation: https://console.groq.com/docs/quickstart 7 | package groq 8 | -------------------------------------------------------------------------------- /internal/schema/testdata/map_type.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/map-type", 4 | "$ref": "#/$defs/MapType", 5 | "$defs": { 6 | "MapType": { 7 | "type": "object" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /examples/moderation/README.md: -------------------------------------------------------------------------------- 1 | # moderation 2 | 3 | This is an example of using groq-go to create a chat moderation using the llama-3BGuard model. 4 | 5 | ## Usage 6 | 7 | Make sure you have a groq key set in the environment variable `GROQ_KEY`. 8 | 9 | ```bash 10 | export GROQ_KEY=your-groq-key 11 | go run . 12 | ``` 13 | -------------------------------------------------------------------------------- /examples/json-chat/README.md: -------------------------------------------------------------------------------- 1 | # json-chat 2 | 3 | This is an example of using groq-go to create a chat application using the the ChatCompletionsJson Method. 4 | 5 | ## Usage 6 | 7 | Make sure you have a groq key set in the environment variable `GROQ_KEY`. 8 | 9 | ```bash 10 | export GROQ_KEY=your-groq-key 11 | go run . 12 | ``` 13 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/src/invg.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | 3 | use IEEE.std_logic_1164.all; 4 | 5 | entity invg is 6 | 7 | port( 8 | i_A : in std_logic; 9 | o_F : out std_logic 10 | ); 11 | 12 | end invg; 13 | 14 | architecture dataflow of invg is 15 | begin 16 | 17 | o_F <= not i_A; 18 | 19 | end dataflow; 20 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/src/org2.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | 3 | use IEEE.std_logic_1164.all; 4 | 5 | entity org2 is 6 | 7 | port( 8 | i_A : in std_logic; 9 | i_B : in std_logic; 10 | o_F : out std_logic 11 | ); 12 | 13 | end org2; 14 | 15 | architecture dataflow of org2 is 16 | begin 17 | 18 | o_F <= i_A or i_B; 19 | 20 | end dataflow; 21 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/src/andg2.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | 3 | use IEEE.std_logic_1164.all; 4 | 5 | entity andg2 is 6 | 7 | port( 8 | i_A : in std_logic; 9 | i_B : in std_logic; 10 | o_F : out std_logic 11 | ); 12 | 13 | end andg2; 14 | 15 | architecture dataflow of andg2 is 16 | begin 17 | 18 | o_F <= i_A and i_B; 19 | 20 | end dataflow; 21 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/src/xorg2.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | 3 | use IEEE.std_logic_1164.all; 4 | 5 | entity xorg2 is 6 | 7 | port( 8 | i_A : in std_logic; 9 | i_B : in std_logic; 10 | o_F : out std_logic 11 | ); 12 | 13 | end xorg2; 14 | 15 | architecture dataflow of xorg2 is 16 | begin 17 | 18 | o_F <= i_A xor i_B; 19 | 20 | end dataflow; 21 | -------------------------------------------------------------------------------- /internal/schema/testdata/array_type.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/array-type", 4 | "$ref": "#/$defs/ArrayType", 5 | "$defs": { 6 | "ArrayType": { 7 | "items": { 8 | "type": "string" 9 | }, 10 | "type": "array" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/4_security_issue_disclosure.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F513 Security issue disclosure" 3 | about: Report a security issue in fxamacker/cbor 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 17 | -------------------------------------------------------------------------------- /examples/llama-blind/main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | "testing" 8 | ) 9 | 10 | func TestJsonChat(t *testing.T) { 11 | if len(os.Getenv("UNIT")) < 1 { 12 | t.Skip("Skipping JsonChat test") 13 | } 14 | ctx := context.Background() 15 | err := run(ctx) 16 | if err != nil { 17 | fmt.Println(err) 18 | os.Exit(1) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3_docs_wiki_or_website_issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F4DA Docs, wiki, or website issue" 3 | about: Report an issue regarding documentation, wiki, or website 4 | title: 'docs: ' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **What is the URL of the content?** 11 | 12 | 13 | **Please describe the problem.** 14 | 15 | 16 | **Screenshot (if applicable).** 17 | -------------------------------------------------------------------------------- /examples/audio-lex-fridman/README.md: -------------------------------------------------------------------------------- 1 | # audio-lex-fridman 2 | 3 | This is an example of using groq-go to create an audio transcription using the whisper-large-v3 model. 4 | 5 | ## Usage 6 | 7 | Make sure you have a groq key set in the environment variable `GROQ_KEY`, and that the `cwd` is the directory of this file. 8 | 9 | ```bash 10 | export GROQ_KEY=your-groq-key 11 | go run . 12 | ``` 13 | -------------------------------------------------------------------------------- /examples/json-chat/main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | "testing" 8 | ) 9 | 10 | func TestAudioLexFridman(t *testing.T) { 11 | if len(os.Getenv("UNIT")) < 1 { 12 | t.Skip("Skipping AudioLexFridman test") 13 | } 14 | ctx := context.Background() 15 | err := run(ctx) 16 | if err != nil { 17 | fmt.Println(err) 18 | os.Exit(1) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/audio-lex-fridman/main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | "testing" 8 | ) 9 | 10 | func TestAudioLexFridman(t *testing.T) { 11 | if len(os.Getenv("UNIT")) < 1 { 12 | t.Skip("Skipping AudioLexFridman test") 13 | } 14 | ctx := context.Background() 15 | err := run(ctx) 16 | if err != nil { 17 | fmt.Println(err) 18 | os.Exit(1) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/toolhouse-python-code-interpreter/main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "os" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestMain(t *testing.T) { 12 | if len(os.Getenv("UNIT")) < 1 { 13 | t.Skip("Skipping integration test") 14 | } 15 | a := assert.New(t) 16 | ctx := context.Background() 17 | err := run(ctx) 18 | a.NoError(err) 19 | } 20 | -------------------------------------------------------------------------------- /examples/audio-house-translation/main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | "testing" 8 | ) 9 | 10 | func TestAudioHouseTranslation(t *testing.T) { 11 | if len(os.Getenv("UNIT")) < 1 { 12 | t.Skip("Skipping AudioHouseTranslation test") 13 | } 14 | ctx := context.Background() 15 | err := run(ctx) 16 | if err != nil { 17 | fmt.Println(err) 18 | os.Exit(1) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/llama-blind/README.md: -------------------------------------------------------------------------------- 1 | # llama-blind 2 | 3 | This is an example of using groq-go to create a chat completion using the llama 3.2 11B multimodal vision preview model. 4 | 5 | ## Usage 6 | 7 | Make sure you have a groq key set in the environment variable `GROQ_KEY`. 8 | 9 | Also make sure that you are in the same directory as the `main.go` file. 10 | 11 | ```bash 12 | export GROQ_KEY=your-groq-key 13 | go run . 14 | ``` 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/integration-issue-template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Integration Issue Template 3 | about: 'Describe an external integration that this library should have. ' 4 | title: "[Extension]" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | # External Description 11 | 12 | 13 | # Links 14 | 15 | -------------------------------------------------------------------------------- /internal/schema/testdata/inlining_ptr.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/outer-ptr", 4 | "properties": { 5 | "Foo": { 6 | "type": "string" 7 | }, 8 | "Text": { 9 | "type": "string" 10 | } 11 | }, 12 | "additionalProperties": false, 13 | "type": "object", 14 | "required": [ 15 | "Foo" 16 | ] 17 | } -------------------------------------------------------------------------------- /internal/schema/testdata/inlining_tag.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/outer-inlined", 4 | "properties": { 5 | "text": { 6 | "type": "string" 7 | }, 8 | "Foo": { 9 | "type": "string" 10 | } 11 | }, 12 | "additionalProperties": false, 13 | "type": "object", 14 | "required": [ 15 | "Foo" 16 | ] 17 | } -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/src/Reg.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | 3 | use IEEE.std_logic_1164.all; 4 | 5 | entity Reg is 6 | 7 | port( 8 | iCLK : in std_logic; 9 | iD : in integer; 10 | oQ : out integer 11 | ); 12 | 13 | end Reg; 14 | 15 | architecture behavior of Reg is 16 | begin 17 | 18 | process(iCLK, iD) 19 | begin 20 | if rising_edge(iCLK) then 21 | oQ <= iD; 22 | end if; 23 | end process; 24 | 25 | end behavior; 26 | -------------------------------------------------------------------------------- /internal/schema/testdata/compact_date.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/compact-date", 4 | "$ref": "#/$defs/CompactDate", 5 | "$defs": { 6 | "CompactDate": { 7 | "type": "string", 8 | "pattern": "^[0-9]{4}-[0-1][0-9]$", 9 | "title": "Compact Date", 10 | "description": "Short date that only includes year and month" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | if ! has nix_direnv_version || ! nix_direnv_version 3.0.6; then 2 | source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.6/direnvrc" "sha256-zelF0vLbEl5uaqrfIzbgNzJWGmLzCmYAkInj/LNxvKs=" 3 | fi 4 | 5 | watch_file flake.nix 6 | watch_file flake.lock 7 | if ! use flake . --no-pure-eval 8 | then 9 | echo "devenv could not be built. The devenv environment was not loaded. Make the necessary changes to devenv.nix and hit enter to try again." >&2 10 | fi 11 | -------------------------------------------------------------------------------- /internal/schema/testdata/lookup_expanded.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://example.com/schemas/lookup-user", 4 | "$anchor": "LookupUser", 5 | "properties": { 6 | "name": { 7 | "$ref": "https://example.com/schemas/lookup-name" 8 | }, 9 | "alias": { 10 | "type": "string" 11 | } 12 | }, 13 | "additionalProperties": false, 14 | "type": "object", 15 | "required": [ 16 | "name" 17 | ] 18 | } -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/src/Adder.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | 3 | use IEEE.std_logic_1164.all; 4 | 5 | entity Adder is 6 | 7 | port( 8 | iCLK : in std_logic; 9 | iA : in integer; 10 | iB : in integer; 11 | oC : out integer 12 | ); 13 | 14 | end Adder; 15 | 16 | architecture behavior of Adder is 17 | begin 18 | 19 | process(iCLK, iA, iB) 20 | begin 21 | if rising_edge(iCLK) then 22 | oC <= iA + iB; 23 | end if; 24 | end process; 25 | 26 | end behavior; 27 | -------------------------------------------------------------------------------- /cmd/generate-models/README.md: -------------------------------------------------------------------------------- 1 | # generate-models 2 | 3 | This is a script to generate the models for the groq-go library. 4 | 5 | ## Usage 6 | 7 | Make sure you have a groq key set in the environment variable `GROQ_KEY`. 8 | 9 | Also, make sure to run this from the root of the groq-go project. 10 | ```bash 11 | export GROQ_KEY=your-groq-key 12 | go run ./cmd/generate-models 13 | ``` 14 | 15 | Or you can run it automatically with `go generate` at the root of the project: 16 | ```bash 17 | go generate 18 | ``` 19 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/src/mux2t1.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | 3 | use IEEE.std_logic_1164.all; 4 | 5 | entity mux2t1 is 6 | 7 | port ( 8 | i_D0, i_D1, i_S : in std_logic; 9 | o_O : out std_logic 10 | ); 11 | 12 | end mux2t1; 13 | 14 | architecture behaviour of mux2t1 is 15 | begin 16 | 17 | process (i_D0, i_D1, i_S) 18 | begin 19 | if i_s = '0' then 20 | o_O <= i_D0; 21 | else 22 | o_O <= i_D1; 23 | end if; 24 | end process; 25 | 26 | end behaviour; 27 | -------------------------------------------------------------------------------- /internal/schema/testdata/inlining_inheritance.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/outer", 4 | "properties": { 5 | "TextNamed": { 6 | "type": "string" 7 | }, 8 | "Text": { 9 | "type": "string" 10 | }, 11 | "Foo": { 12 | "type": "string" 13 | } 14 | }, 15 | "additionalProperties": false, 16 | "type": "object", 17 | "required": [ 18 | "TextNamed", 19 | "Foo" 20 | ] 21 | } -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/src/Multiplier.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | 3 | use IEEE.std_logic_1164.all; 4 | 5 | entity Multiplier is 6 | 7 | port( 8 | iCLK : in std_logic; 9 | i_A : in integer; 10 | i_B : in integer; 11 | o_P : out integer 12 | ); 13 | 14 | end Multiplier; 15 | 16 | architecture behavior of Multiplier is 17 | begin 18 | 19 | process(iCLK, i_A, i_B) 20 | begin 21 | if rising_edge(iCLK) then 22 | o_P <= i_A * i_B; 23 | end if; 24 | end process; 25 | 26 | end behavior; 27 | -------------------------------------------------------------------------------- /internal/schema/testdata/schema_alias.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/alias-object-b", 4 | "$ref": "#/$defs/AliasObjectA", 5 | "$defs": { 6 | "AliasObjectA": { 7 | "properties": { 8 | "prop_a": { 9 | "type": "string" 10 | } 11 | }, 12 | "additionalProperties": false, 13 | "type": "object", 14 | "required": [ 15 | "prop_a" 16 | ] 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/conneroisu/groq-go 2 | 3 | go 1.25 4 | 5 | require ( 6 | github.com/buger/jsonparser v1.1.1 7 | github.com/gorilla/websocket v1.5.3 8 | github.com/stretchr/testify v1.10.0 9 | ) 10 | 11 | require ( 12 | github.com/davecgh/go-spew v1.1.1 // indirect 13 | github.com/kr/pretty v0.3.0 // indirect 14 | github.com/pmezard/go-difflib v1.0.0 // indirect 15 | github.com/rogpeppe/go-internal v1.8.1 // indirect 16 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect 17 | gopkg.in/yaml.v3 v3.0.1 // indirect 18 | ) 19 | -------------------------------------------------------------------------------- /groq_test.go: -------------------------------------------------------------------------------- 1 | package groq_test 2 | 3 | import ( 4 | "log/slog" 5 | "net/http" 6 | "testing" 7 | 8 | groq "github.com/conneroisu/groq-go" 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | // TestClient tests the creation of a new client. 13 | func TestClient(t *testing.T) { 14 | a := assert.New(t) 15 | client, err := groq.NewClient( 16 | "test", 17 | groq.WithBaseURL("http://localhost/v1"), 18 | groq.WithClient(http.DefaultClient), 19 | groq.WithLogger(slog.Default()), 20 | ) 21 | a.NoError(err) 22 | a.NotNil(client) 23 | } 24 | -------------------------------------------------------------------------------- /internal/schema/testdata/schema_with_minimum.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/min-value", 4 | "$ref": "#/$defs/MinValue", 5 | "$defs": { 6 | "MinValue": { 7 | "properties": { 8 | "value4": { 9 | "type": "integer", 10 | "minimum": 0 11 | } 12 | }, 13 | "additionalProperties": false, 14 | "type": "object", 15 | "required": [ 16 | "value4" 17 | ] 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /internal/schema/testdata/schema_with_expression.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/expression", 4 | "$ref": "#/$defs/Expression", 5 | "$defs": { 6 | "Expression": { 7 | "properties": { 8 | "value": { 9 | "type": "integer", 10 | "foo": "bar=='baz'" 11 | } 12 | }, 13 | "additionalProperties": false, 14 | "type": "object", 15 | "required": [ 16 | "value" 17 | ] 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /internal/schema/testdata/user_with_anchor.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/user-with-anchor", 4 | "$ref": "#/$defs/UserWithAnchor", 5 | "$defs": { 6 | "UserWithAnchor": { 7 | "properties": { 8 | "name": { 9 | "$anchor": "Name", 10 | "type": "string" 11 | } 12 | }, 13 | "additionalProperties": false, 14 | "type": "object", 15 | "required": [ 16 | "name" 17 | ] 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /internal/schema/testdata/custom_type.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/custom-type-field", 4 | "$ref": "#/$defs/CustomTypeField", 5 | "$defs": { 6 | "CustomTypeField": { 7 | "properties": { 8 | "CreatedAt": { 9 | "type": "string", 10 | "format": "date-time" 11 | } 12 | }, 13 | "additionalProperties": false, 14 | "type": "object", 15 | "required": [ 16 | "CreatedAt" 17 | ] 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "gomod" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /internal/schema/testdata/lookup.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://example.com/schemas/lookup-user", 4 | "$ref": "#/$defs/LookupUser", 5 | "$defs": { 6 | "LookupUser": { 7 | "properties": { 8 | "name": { 9 | "$ref": "https://example.com/schemas/lookup-name" 10 | }, 11 | "alias": { 12 | "type": "string" 13 | } 14 | }, 15 | "additionalProperties": false, 16 | "type": "object", 17 | "required": [ 18 | "name" 19 | ] 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /internal/schema/testdata/test_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/config", 4 | "$ref": "#/$defs/Config", 5 | "$defs": { 6 | "Config": { 7 | "properties": { 8 | "name": { 9 | "type": "string" 10 | }, 11 | "count": { 12 | "type": "integer" 13 | } 14 | }, 15 | "additionalProperties": false, 16 | "type": "object", 17 | "required": [ 18 | "name", 19 | "count" 20 | ] 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /examples/toolhouse-python-code-interpreter/README.md: -------------------------------------------------------------------------------- 1 | # python-code-interpreter 2 | 3 | This is an example of using groq-go to create a chat completion using the llama-3.1-70B-8192-tool-use-preview model. 4 | 5 | It interacts with the [Toolhouse](https://app.toolhouse.ai/) API to run the code interpreter. 6 | 7 | ## Usage 8 | 9 | Make sure you have a groq key set in the environment variable `GROQ_KEY`. 10 | Also, make sure you have a toolhouse api key set in the environment variable `TOOLHOUSE_API_KEY`. 11 | ```bash 12 | export GROQ_KEY=your-groq-key 13 | export TOOLHOUSE_API_KEY=your-toolhouse-api-key 14 | go run . 15 | ``` 16 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/src/OnesComp.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.STD_LOGIC_1164.all; 4 | 5 | entity OnesComp is 6 | 7 | generic ( 8 | N : integer := 8 9 | ); 10 | port ( 11 | Input : in std_logic_vector(N-1 downto 0); 12 | Output : out std_logic_vector(N-1 downto 0) 13 | ); 14 | 15 | end OnesComp; 16 | 17 | architecture Behavioral of OnesComp is 18 | begin 19 | 20 | Complement_Process : process(Input) 21 | begin 22 | for i in 0 to N-1 loop 23 | Output(i) <= not Input(i); 24 | end loop; 25 | end process; 26 | 27 | end Behavioral; 28 | -------------------------------------------------------------------------------- /internal/schema/testdata/commas_in_pattern.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/pattern-test", 4 | "$ref": "#/$defs/PatternTest", 5 | "$defs": { 6 | "PatternTest": { 7 | "properties": { 8 | "with_pattern": { 9 | "type": "string", 10 | "maxLength": 50, 11 | "minLength": 1, 12 | "pattern": "[0-9]{1,4}" 13 | } 14 | }, 15 | "additionalProperties": false, 16 | "type": "object", 17 | "required": [ 18 | "with_pattern" 19 | ] 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/src/FullAdder.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | 3 | use IEEE.STD_LOGIC_1164.all; 4 | 5 | entity FullAdder is 6 | 7 | port ( 8 | i_A : in std_logic; 9 | i_B : in std_logic; 10 | Cin : in std_logic; 11 | Sum : out std_logic; 12 | Cout : out std_logic 13 | ); 14 | 15 | end FullAdder; 16 | 17 | architecture Structural of FullAdder is 18 | signal s_Adder, s_C1, s_C2 : std_logic; 19 | begin 20 | 21 | s_Adder <= i_A xor i_B; 22 | s_C1 <= i_A and i_B; 23 | 24 | Sum <= s_Adder xor Cin; 25 | s_C2 <= s_Adder and Cin; 26 | 27 | Cout <= s_C1 or s_C2; 28 | 29 | end Structural; 30 | -------------------------------------------------------------------------------- /internal/schema/testdata/custom_type_extend.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/schema-extend-test", 4 | "$ref": "#/$defs/SchemaExtendTest", 5 | "$defs": { 6 | "SchemaExtendTest": { 7 | "properties": { 8 | "LastName": { 9 | "type": "string", 10 | "description": "some extra words" 11 | }, 12 | "middle_name": { 13 | "type": "string" 14 | } 15 | }, 16 | "additionalProperties": false, 17 | "type": "object", 18 | "required": [ 19 | "LastName" 20 | ] 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1_bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41E Bug report" 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | teambition/rrule-go version: v1.x.x 12 | A clear and concise description of what the bug is. 13 | 14 | **To Reproduce** 15 | Code to reproduce the behavior: 16 | ```go 17 | // your code. 18 | ``` 19 | **Expected behavior** 20 | A clear and concise description of what you expected to happen. 21 | 22 | **Screenshots** 23 | If applicable, add screenshots to help explain your problem. 24 | 25 | **Additional context** 26 | Add any other context about the problem here. 27 | -------------------------------------------------------------------------------- /internal/schema/testdata/custom_additional.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/grandfather-type", 4 | "$ref": "#/$defs/GrandfatherType", 5 | "$defs": { 6 | "GrandfatherType": { 7 | "properties": { 8 | "family_name": { 9 | "type": "string" 10 | }, 11 | "ip_addr": { 12 | "type": "string", 13 | "format": "ipv4" 14 | } 15 | }, 16 | "additionalProperties": false, 17 | "type": "object", 18 | "required": [ 19 | "family_name", 20 | "ip_addr" 21 | ] 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /internal/schema/testdata/nullable.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/test-nullable", 4 | "$ref": "#/$defs/TestNullable", 5 | "$defs": { 6 | "TestNullable": { 7 | "properties": { 8 | "child1": { 9 | "oneOf": [ 10 | { 11 | "type": "string" 12 | }, 13 | { 14 | "type": "null" 15 | } 16 | ] 17 | } 18 | }, 19 | "additionalProperties": false, 20 | "type": "object", 21 | "required": [ 22 | "child1" 23 | ] 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /internal/schema/testdata/number_handling.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/number-handler", 4 | "$ref": "#/$defs/NumberHandler", 5 | "$defs": { 6 | "NumberHandler": { 7 | "properties": { 8 | "int64": { 9 | "type": "integer", 10 | "default": 12 11 | }, 12 | "float32": { 13 | "type": "number", 14 | "default": 12.5 15 | } 16 | }, 17 | "additionalProperties": false, 18 | "type": "object", 19 | "required": [ 20 | "int64", 21 | "float32" 22 | ] 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /internal/schema/testdata/recursive.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/recursive-example", 4 | "$ref": "#/$defs/RecursiveExample", 5 | "$defs": { 6 | "RecursiveExample": { 7 | "properties": { 8 | "text": { 9 | "type": "string" 10 | }, 11 | "children": { 12 | "items": { 13 | "$ref": "#/$defs/RecursiveExample" 14 | }, 15 | "type": "array" 16 | } 17 | }, 18 | "additionalProperties": false, 19 | "type": "object", 20 | "required": [ 21 | "text" 22 | ] 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2_feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F4A1 Feature request" 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /examples/composio-github-star/README.md: -------------------------------------------------------------------------------- 1 | # composio-github-star 2 | 3 | Adapted from the [quickstart](https://docs.composio.dev/introduction/intro/quickstart) guide. 4 | 5 | Install the `composio` CLI and login to your account (also add github to your account if you haven't already) 6 | 7 | ```bash 8 | pip install -U composio_core composio_openai 9 | 10 | composio login 11 | 12 | #Connect your Github so agents can use it 13 | composio add github 14 | ``` 15 | 16 | Congratulations! You’ve just: 17 | 18 | 🔐 Authenticated your GitHub account with Composio 19 | 🛠 Fetched GitHub tools for the llm 20 | ⭐ Instructed the AI to star the conneroisu/groq-go repository 21 | ✅ Successfully executed the action on GitHub 22 | -------------------------------------------------------------------------------- /.revive.toml: -------------------------------------------------------------------------------- 1 | ignoreGeneratedHeader = false 2 | severity = "warning" 3 | confidence = 0.8 4 | errorCode = 0 5 | warningCode = 0 6 | 7 | [rule.blank-imports] 8 | [rule.context-as-argument] 9 | [rule.context-keys-type] 10 | [rule.dot-imports] 11 | [rule.empty-block] 12 | [rule.error-naming] 13 | [rule.error-return] 14 | [rule.error-strings] 15 | [rule.errorf] 16 | [rule.exported] 17 | [rule.increment-decrement] 18 | [rule.indent-error-flow] 19 | [rule.package-comments] 20 | [rule.range] 21 | [rule.receiver-naming] 22 | [rule.redefines-builtin-id] 23 | [rule.superfluous-else] 24 | [rule.time-naming] 25 | [rule.unexported-return] 26 | [rule.unreachable-code] 27 | [rule.unused-parameter] 28 | [rule.var-declaration] 29 | [rule.var-naming] 30 | -------------------------------------------------------------------------------- /internal/schema/testdata/custom_type_with_interface.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/custom-type-field-with-interface", 4 | "$ref": "#/$defs/CustomTypeFieldWithInterface", 5 | "$defs": { 6 | "CustomTimeWithInterface": { 7 | "type": "string", 8 | "format": "date-time" 9 | }, 10 | "CustomTypeFieldWithInterface": { 11 | "properties": { 12 | "CreatedAt": { 13 | "$ref": "#/$defs/CustomTimeWithInterface" 14 | } 15 | }, 16 | "additionalProperties": false, 17 | "type": "object", 18 | "required": [ 19 | "CreatedAt" 20 | ] 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /internal/schema/testdata/inlining_embedded.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/outer-named", 4 | "$defs": { 5 | "Inner": { 6 | "properties": { 7 | "Foo": { 8 | "type": "string" 9 | } 10 | }, 11 | "additionalProperties": false, 12 | "type": "object", 13 | "required": [ 14 | "Foo" 15 | ] 16 | } 17 | }, 18 | "properties": { 19 | "text": { 20 | "type": "string" 21 | }, 22 | "inner": { 23 | "$ref": "#/$defs/Inner" 24 | } 25 | }, 26 | "additionalProperties": false, 27 | "type": "object", 28 | "required": [ 29 | "inner" 30 | ] 31 | } -------------------------------------------------------------------------------- /internal/schema/testdata/equals_in_pattern.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/pattern-equals-test", 4 | "$ref": "#/$defs/PatternEqualsTest", 5 | "$defs": { 6 | "PatternEqualsTest": { 7 | "properties": { 8 | "WithEquals": { 9 | "type": "string", 10 | "pattern": "foo=bar" 11 | }, 12 | "WithEqualsAndCommas": { 13 | "type": "string", 14 | "pattern": "foo,=bar" 15 | } 16 | }, 17 | "additionalProperties": false, 18 | "type": "object", 19 | "required": [ 20 | "WithEquals", 21 | "WithEqualsAndCommas" 22 | ] 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/src/RegLd.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | 3 | use IEEE.std_logic_1164.all; 4 | 5 | entity RegLd is 6 | 7 | port( 8 | iCLK : in std_logic; 9 | iD : in integer; 10 | iLd : in integer; 11 | oQ : out integer 12 | ); 13 | 14 | end RegLd; 15 | 16 | architecture behavior of RegLd is 17 | signal s_Q : integer; 18 | begin 19 | 20 | 21 | process(iCLK, iLd, iD) 22 | begin 23 | if rising_edge(iCLK) then 24 | if (iLd = 1) then 25 | s_Q <= iD; 26 | else 27 | s_Q <= s_Q; 28 | end if; 29 | end if; 30 | end process; 31 | 32 | oQ <= s_Q; -- connect internal storage signal with final output 33 | 34 | end behavior; 35 | -------------------------------------------------------------------------------- /internal/schema/testdata/yaml_inline.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft/2020-12/schema", 3 | "$ref": "#/$defs/TestYamlInline", 4 | "definitions": { 5 | "Inner": { 6 | "required": ["foo"], 7 | "properties": { 8 | "foo": { 9 | "type": "string" 10 | } 11 | }, 12 | "additionalProperties": false, 13 | "type": "object" 14 | }, 15 | "TestYamlInline": { 16 | "required": [ 17 | "Inlined" 18 | ], 19 | "properties": { 20 | "Inlined": { 21 | "$schema": "http://json-schema.org/draft-04/schema#", 22 | "$ref": "#/definitions/Inner" 23 | } 24 | }, 25 | "additionalProperties": false, 26 | "type": "object" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | The groq-go code of conduct is derived from the Ladybird code of conduct which is derived from [The Ruby Community Conduct Guideline](https://www.ruby-lang.org/en/conduct/). 4 | 5 | - Participants will be tolerant of opposing views. 6 | - Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks. 7 | - When interpreting the words and actions of others, participants should always assume good intentions. 8 | - Behavior that can be reasonably considered harassment will not be tolerated. 9 | - Feedback should be constructive, respectful, and provided with the intent of improving the project. 10 | - All interactions should reflect a high standard of professionalism and courtesy. 11 | -------------------------------------------------------------------------------- /internal/schema/testdata/inlining_embedded_anchored.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/outer-named", 4 | "$anchor": "OuterNamed", 5 | "$defs": { 6 | "Inner": { 7 | "$anchor": "Inner", 8 | "properties": { 9 | "Foo": { 10 | "type": "string" 11 | } 12 | }, 13 | "additionalProperties": false, 14 | "type": "object", 15 | "required": [ 16 | "Foo" 17 | ] 18 | } 19 | }, 20 | "properties": { 21 | "text": { 22 | "type": "string" 23 | }, 24 | "inner": { 25 | "$ref": "#/$defs/Inner" 26 | } 27 | }, 28 | "additionalProperties": false, 29 | "type": "object", 30 | "required": [ 31 | "inner" 32 | ] 33 | } -------------------------------------------------------------------------------- /extensions/jigsawstack/storage_test.go: -------------------------------------------------------------------------------- 1 | package jigsawstack_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/conneroisu/groq-go/extensions/jigsawstack" 8 | "github.com/conneroisu/groq-go/internal/test" 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | // TestJigsawStack_FileAdd tests the FileAdd method of the JigsawStack client. 13 | func TestJigsawStack_FileAdd(t *testing.T) { 14 | if !test.IsIntegrationTest() { 15 | t.Skip("Skipping unit test") 16 | } 17 | a := assert.New(t) 18 | ctx := context.Background() 19 | apiKey, err := test.GetAPIKey("JIGSAWSTACK_API_KEY") 20 | a.NoError(err) 21 | j, err := jigsawstack.NewJigsawStack(apiKey) 22 | a.NoError(err) 23 | resp, err := j.FileAdd(ctx, "test", "text/plain", "hello world") 24 | a.NoError(err) 25 | a.NotEmpty(resp) 26 | } 27 | -------------------------------------------------------------------------------- /internal/schema/testdata/schema_alias_2.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/alias-object-c", 4 | "$ref": "#/$defs/AliasObjectC", 5 | "$defs": { 6 | "AliasObjectA": { 7 | "properties": { 8 | "prop_a": { 9 | "type": "string" 10 | } 11 | }, 12 | "additionalProperties": false, 13 | "type": "object", 14 | "required": [ 15 | "prop_a" 16 | ] 17 | }, 18 | "AliasObjectC": { 19 | "properties": { 20 | "obj_b": { 21 | "$ref": "#/$defs/AliasObjectA" 22 | } 23 | }, 24 | "additionalProperties": false, 25 | "type": "object", 26 | "required": [ 27 | "obj_b" 28 | ] 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /.github/workflows/coverage.yaml: -------------------------------------------------------------------------------- 1 | name: Test & Coverage 2 | on: [push, pull_request] 3 | jobs: 4 | test: 5 | name: Test with Coverage 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Set up Go 9 | uses: actions/setup-go@v3 10 | with: 11 | go-version: '1.23.2' 12 | - name: Check out code 13 | uses: actions/checkout@v3 14 | - name: Install dependencies 15 | run: | 16 | go mod download 17 | - name: Run Tests 18 | run: | 19 | go test -race -covermode atomic -coverprofile=covprofile ./... 20 | - name: Install goveralls 21 | run: go install github.com/mattn/goveralls@latest 22 | - name: Send coverage 23 | env: 24 | COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} 25 | run: goveralls -coverprofile=covprofile -service=github 26 | -------------------------------------------------------------------------------- /internal/schema/testdata/test_yaml_and_json_prefer_yaml.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/test-yaml-and-json", 4 | "$ref": "#/$defs/TestYamlAndJson", 5 | "$defs": { 6 | "TestYamlAndJson": { 7 | "properties": { 8 | "first_name": { 9 | "type": "string" 10 | }, 11 | "LastName": { 12 | "type": "string" 13 | }, 14 | "age": { 15 | "type": "integer" 16 | }, 17 | "middle_name": { 18 | "type": "string" 19 | } 20 | }, 21 | "additionalProperties": false, 22 | "type": "object", 23 | "required": [ 24 | "first_name", 25 | "LastName", 26 | "age" 27 | ] 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /extensions/toolhouse/options.go: -------------------------------------------------------------------------------- 1 | package toolhouse 2 | 3 | import ( 4 | "log/slog" 5 | "net/http" 6 | ) 7 | 8 | // WithBaseURL sets the base URL for the Toolhouse extension. 9 | func WithBaseURL(baseURL string) Options { 10 | return func(e *Toolhouse) { e.baseURL = baseURL } 11 | } 12 | 13 | // WithClient sets the client for the Toolhouse extension. 14 | func WithClient(client *http.Client) Options { 15 | return func(e *Toolhouse) { e.client = client } 16 | } 17 | 18 | // WithMetadata sets the metadata for the get tools request. 19 | func WithMetadata(metadata map[string]any) Options { 20 | return func(r *Toolhouse) { r.metadata = metadata } 21 | } 22 | 23 | // WithLogger sets the logger for the Toolhouse extension. 24 | func WithLogger(logger *slog.Logger) Options { 25 | return func(r *Toolhouse) { r.logger = logger } 26 | } 27 | -------------------------------------------------------------------------------- /internal/schema/testdata/custom_slice_type.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/custom-slice-outer", 4 | "$ref": "#/$defs/CustomSliceOuter", 5 | "$defs": { 6 | "CustomSliceOuter": { 7 | "properties": { 8 | "slice": { 9 | "$ref": "#/$defs/CustomSliceType" 10 | } 11 | }, 12 | "additionalProperties": false, 13 | "type": "object", 14 | "required": [ 15 | "slice" 16 | ] 17 | }, 18 | "CustomSliceType": { 19 | "oneOf": [ 20 | { 21 | "type": "string" 22 | }, 23 | { 24 | "items": { 25 | "type": "string" 26 | }, 27 | "type": "array" 28 | } 29 | ] 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /extensions/jigsawstack/natural_language_test.go: -------------------------------------------------------------------------------- 1 | package jigsawstack_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/conneroisu/groq-go/extensions/jigsawstack" 8 | "github.com/conneroisu/groq-go/internal/test" 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestJigsawStack_Sentiment(t *testing.T) { 13 | if !test.IsIntegrationTest() { 14 | t.Skip("Skipping integration test") 15 | } 16 | a := assert.New(t) 17 | apiKey, err := test.GetAPIKey("JIGSAWSTACK_API_KEY") 18 | a.NoError(err) 19 | j, err := jigsawstack.NewJigsawStack(apiKey) 20 | a.NoError(err) 21 | resp, err := j.Sentiment(context.Background(), "I am a happy person") 22 | a.NoError(err) 23 | a.True(resp.Success) 24 | a.Equal(jigsawstack.EmotionHappiness, resp.Sentiment.Emotion) 25 | a.Equal("positive", resp.Sentiment.Sentiment) 26 | } 27 | -------------------------------------------------------------------------------- /internal/schema/testdata/with_custom_format.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/with-custom-format", 4 | "$ref": "#/$defs/WithCustomFormat", 5 | "$defs": { 6 | "WithCustomFormat": { 7 | "properties": { 8 | "dates": { 9 | "items": { 10 | "type": "string", 11 | "format": "date" 12 | }, 13 | "type": "array" 14 | }, 15 | "odds": { 16 | "items": { 17 | "type": "string", 18 | "format": "odd" 19 | }, 20 | "type": "array" 21 | } 22 | }, 23 | "additionalProperties": false, 24 | "type": "object", 25 | "required": [ 26 | "dates", 27 | "odds" 28 | ] 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/src/NBitInverter.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | 3 | use IEEE.STD_LOGIC_1164.all; 4 | 5 | entity NBitInverter is 6 | 7 | generic ( 8 | N : integer := 4 -- N is the width of the input/output 9 | ); 10 | port ( 11 | Input : in std_logic_vector(N-1 downto 0); -- Input vector 12 | Output : out std_logic_vector(N-1 downto 0) -- Output vector 13 | ); 14 | 15 | end NBitInverter; 16 | 17 | architecture Behavioral of NBitInverter is 18 | begin 19 | 20 | Complement_Process : process(Input) 21 | begin 22 | for i in 0 to N-1 loop 23 | if Input(i) = '1' then 24 | Output(i) <= '0'; 25 | else 26 | Output(i) <= '1'; 27 | end if; 28 | end loop; 29 | end process; 30 | 31 | end Behavioral; 32 | -------------------------------------------------------------------------------- /internal/schema/testdata/schema_property_alias.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/alias-property-object-base", 4 | "$ref": "#/$defs/AliasPropertyObjectBase", 5 | "$defs": { 6 | "AliasObjectA": { 7 | "properties": { 8 | "prop_a": { 9 | "type": "string" 10 | } 11 | }, 12 | "additionalProperties": false, 13 | "type": "object", 14 | "required": [ 15 | "prop_a" 16 | ] 17 | }, 18 | "AliasPropertyObjectBase": { 19 | "properties": { 20 | "object": { 21 | "$ref": "#/$defs/AliasObjectA" 22 | } 23 | }, 24 | "additionalProperties": false, 25 | "type": "object", 26 | "required": [ 27 | "object" 28 | ] 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /examples/e2b-go-project/README.md: -------------------------------------------------------------------------------- 1 | # e2b-go-project 2 | 3 | This is an example of using groq-go to create a simple golang project using the e2b and groq api powered by the groq-go library. 4 | 5 | ## Usage 6 | 7 | Make sure you have a groq key set in the environment variable `GROQ_KEY`. 8 | Also, make sure that you have a e2b api key set in the environment variable `E2B_API_KEY`. 9 | 10 | ```bash 11 | export GROQ_KEY=your-groq-key 12 | export E2B_API_KEY=your-e2b-api-key 13 | go run . 14 | ``` 15 | 16 | ### System Prompt 17 | 18 | ```txt 19 | Given the tools given to you, create a golang project with the following files: 20 | 21 | 22 | main.go 23 | utils.go 24 | 25 | 26 | The main function should call the `utils.run() error` function. 27 | 28 | The project should, when run, print the following: 29 | 30 | 31 | Hello, World! 32 | 33 | ``` 34 | -------------------------------------------------------------------------------- /pkg/builders/options.go: -------------------------------------------------------------------------------- 1 | package builders 2 | 3 | import "net/url" 4 | 5 | // WithBody sets the body for a request. 6 | func WithBody(body any) RequestOption { 7 | return func(args *requestOptions) { 8 | args.body = body 9 | } 10 | } 11 | 12 | // WithContentType sets the content type for a request. 13 | func WithContentType(contentType string) RequestOption { 14 | return func(args *requestOptions) { 15 | args.header.Set("Content-Type", contentType) 16 | } 17 | } 18 | 19 | type ( 20 | // Querier is an interface for a request querier. 21 | // 22 | // It allows for modifying the URL before it is sent. 23 | Querier interface { 24 | URLQuery(url *url.URL) 25 | } 26 | ) 27 | 28 | // WithQuerier sets the querier for a request. 29 | func WithQuerier(querier Querier) RequestOption { 30 | return func(args *requestOptions) { 31 | args.querier = querier 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/audio-house-translation/main.go: -------------------------------------------------------------------------------- 1 | // Package main is an example of using the groq-go library to create a 2 | // transcription/translation using the whisper-large-v3 model. 3 | package main 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "os" 9 | 10 | "github.com/conneroisu/groq-go" 11 | ) 12 | 13 | func main() { 14 | if err := run(context.Background()); err != nil { 15 | fmt.Println(err) 16 | os.Exit(1) 17 | } 18 | } 19 | 20 | func run( 21 | ctx context.Context, 22 | ) error { 23 | client, err := groq.NewClient(os.Getenv("GROQ_KEY")) 24 | if err != nil { 25 | return err 26 | } 27 | response, err := client.Translate(ctx, groq.AudioRequest{ 28 | Model: groq.ModelWhisperLargeV3, 29 | FilePath: "./house-speaks-mandarin.mp3", 30 | Prompt: "english and mandarin", 31 | }) 32 | if err != nil { 33 | return err 34 | } 35 | fmt.Println(response.Text) 36 | return nil 37 | } 38 | -------------------------------------------------------------------------------- /internal/test/failer.go: -------------------------------------------------------------------------------- 1 | // Package test contains test helpers. 2 | package test 3 | 4 | // ErrTestErrorAccumulatorWriteFailed is the error returned by the failing 5 | // error buffer. 6 | type ErrTestErrorAccumulatorWriteFailed struct{} 7 | 8 | func (e ErrTestErrorAccumulatorWriteFailed) Error() string { 9 | return "test error accumulator failed" 10 | } 11 | 12 | // FailingErrorBuffer is a buffer that always fails to write. 13 | type FailingErrorBuffer struct{} 14 | 15 | // Write always fails. 16 | // 17 | // It is used to test the behavior of the error accumulator. 18 | func (b *FailingErrorBuffer) Write(_ []byte) (n int, err error) { 19 | return 0, ErrTestErrorAccumulatorWriteFailed{} 20 | } 21 | 22 | // Len always returns 0. 23 | func (b *FailingErrorBuffer) Len() int { 24 | return 0 25 | } 26 | 27 | // Bytes always 28 | func (b *FailingErrorBuffer) Bytes() []byte { 29 | return []byte{} 30 | } 31 | -------------------------------------------------------------------------------- /examples/moderation/main.go: -------------------------------------------------------------------------------- 1 | // Package main is an example of using groq-go to create a chat moderation 2 | // using the llama-3BGuard model. 3 | package main 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "os" 9 | 10 | "github.com/conneroisu/groq-go" 11 | ) 12 | 13 | func main() { 14 | ctx := context.Background() 15 | if err := run(ctx); err != nil { 16 | fmt.Println(err) 17 | os.Exit(1) 18 | } 19 | } 20 | 21 | func run( 22 | ctx context.Context, 23 | ) error { 24 | key := os.Getenv("GROQ_KEY") 25 | client, err := groq.NewClient(key) 26 | if err != nil { 27 | return err 28 | } 29 | response, err := client.Moderate(ctx, 30 | []groq.ChatCompletionMessage{ 31 | { 32 | Role: groq.RoleUser, 33 | Content: "I want to kill them.", 34 | }, 35 | }, 36 | groq.ModelLlamaGuard38B, 37 | ) 38 | if err != nil { 39 | return err 40 | } 41 | fmt.Println(response) 42 | return nil 43 | } 44 | -------------------------------------------------------------------------------- /internal/schema/testdata/array_handling.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/array-handler", 4 | "$ref": "#/$defs/ArrayHandler", 5 | "$defs": { 6 | "ArrayHandler": { 7 | "properties": { 8 | "min_len": { 9 | "items": { 10 | "type": "string", 11 | "minLength": 2 12 | }, 13 | "type": "array", 14 | "default": [ 15 | "qwerty" 16 | ] 17 | }, 18 | "min_val": { 19 | "items": { 20 | "type": "number", 21 | "minimum": 2.5 22 | }, 23 | "type": "array" 24 | } 25 | }, 26 | "additionalProperties": false, 27 | "type": "object", 28 | "required": [ 29 | "min_len", 30 | "min_val" 31 | ] 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /extensions/toolhouse/tools.go: -------------------------------------------------------------------------------- 1 | package toolhouse 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/conneroisu/groq-go/pkg/builders" 8 | "github.com/conneroisu/groq-go/pkg/tools" 9 | ) 10 | 11 | // GetTools returns a list of tools that the extension can use. 12 | func (e *Toolhouse) GetTools( 13 | ctx context.Context, 14 | ) ([]tools.Tool, error) { 15 | e.logger.Debug("Getting tools from Toolhouse extension") 16 | url := e.baseURL + getToolsEndpoint 17 | req, err := builders.NewRequest( 18 | ctx, 19 | e.header, 20 | http.MethodPost, 21 | url, 22 | builders.WithBody( 23 | request{ 24 | Bundle: "default", 25 | Provider: "openai", 26 | Metadata: e.metadata, 27 | }), 28 | ) 29 | if err != nil { 30 | return nil, err 31 | } 32 | var tooling []tools.Tool 33 | err = e.sendRequest(req, &tooling) 34 | if err != nil { 35 | return nil, err 36 | } 37 | return tooling, nil 38 | } 39 | -------------------------------------------------------------------------------- /extensions/jigsawstack/sql_test.go: -------------------------------------------------------------------------------- 1 | package jigsawstack_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/conneroisu/groq-go/extensions/jigsawstack" 8 | "github.com/conneroisu/groq-go/internal/test" 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | // TestJigsawStack_TextToSQL tests the TextToSQL method of the JigsawStack client. 13 | func TestJigsawStack_TextToSQL(t *testing.T) { 14 | if !test.IsIntegrationTest() { 15 | t.Skip("Skipping unit test") 16 | } 17 | a := assert.New(t) 18 | ctx := context.Background() 19 | apiKey, err := test.GetAPIKey("JIGSAWSTACK_API_KEY") 20 | a.NoError(err) 21 | j, err := jigsawstack.NewJigsawStack(apiKey) 22 | a.NoError(err) 23 | resp, err := j.TextToSQL(ctx, "select all users", ` 24 | CREATE TABLE users ( 25 | id INT PRIMARY KEY, 26 | name VARCHAR(255), 27 | email VARCHAR(255), 28 | age INT 29 | ); 30 | `) 31 | a.NoError(err) 32 | a.NotEmpty(resp.SQL) 33 | } 34 | -------------------------------------------------------------------------------- /internal/schema/testdata/base_schema_id.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://example.com/schemas/lookup-user", 4 | "$ref": "#/$defs/LookupUser", 5 | "$defs": { 6 | "LookupName": { 7 | "properties": { 8 | "first": { 9 | "type": "string" 10 | }, 11 | "surname": { 12 | "type": "string" 13 | } 14 | }, 15 | "additionalProperties": false, 16 | "type": "object", 17 | "required": [ 18 | "first", 19 | "surname" 20 | ] 21 | }, 22 | "LookupUser": { 23 | "properties": { 24 | "name": { 25 | "$ref": "#/$defs/LookupName" 26 | }, 27 | "alias": { 28 | "type": "string" 29 | } 30 | }, 31 | "additionalProperties": false, 32 | "type": "object", 33 | "required": [ 34 | "name" 35 | ] 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /examples/audio-lex-fridman/main.go: -------------------------------------------------------------------------------- 1 | // Package main is an example of using groq-go to create a transcription 2 | // using the whisper model. 3 | package main 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "os" 9 | 10 | "github.com/conneroisu/groq-go" 11 | ) 12 | 13 | func main() { 14 | if err := run(context.Background()); err != nil { 15 | fmt.Println(err) 16 | os.Exit(1) 17 | } 18 | } 19 | 20 | func run( 21 | ctx context.Context, 22 | ) error { 23 | key := os.Getenv("GROQ_KEY") 24 | if key == "" { 25 | return fmt.Errorf("GROQ_KEY is required") 26 | } 27 | client, err := groq.NewClient(key) 28 | if err != nil { 29 | return err 30 | } 31 | response, err := client.Transcribe(ctx, groq.AudioRequest{ 32 | Model: groq.ModelWhisperLargeV3, 33 | FilePath: "./The Roman Emperors who went insane Gregory Aldrete and Lex Fridman.mp3", 34 | }) 35 | if err != nil { 36 | return err 37 | } 38 | fmt.Println(response.Text) 39 | return nil 40 | } 41 | -------------------------------------------------------------------------------- /internal/schema/testdata/custom_map_type.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/custom-map-outer", 4 | "$ref": "#/$defs/CustomMapOuter", 5 | "$defs": { 6 | "CustomMapOuter": { 7 | "properties": { 8 | "my_map": { 9 | "$ref": "#/$defs/CustomMapType" 10 | } 11 | }, 12 | "additionalProperties": false, 13 | "type": "object", 14 | "required": [ 15 | "my_map" 16 | ] 17 | }, 18 | "CustomMapType": { 19 | "items": { 20 | "properties": { 21 | "key": { 22 | "type": "string" 23 | }, 24 | "value": { 25 | "type": "string" 26 | } 27 | }, 28 | "type": "object", 29 | "required": [ 30 | "key", 31 | "value" 32 | ] 33 | }, 34 | "type": "array" 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | logLevel: 6 | description: 'Log level' 7 | required: true 8 | default: 'warning' 9 | tags: 10 | description: 'Run only on tags' 11 | required: true 12 | default: 'true' 13 | pull_request: 14 | branches: 15 | - main 16 | 17 | permissions: 18 | contents: read 19 | 20 | jobs: 21 | golangci: 22 | name: lint 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v4 26 | - uses: actions/setup-go@v5 27 | with: 28 | go-version: '1.23.2' 29 | cache: true 30 | - name: Install requirements 31 | id: install-lint-requirements 32 | run: | 33 | go mod download 34 | go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest 35 | - name: Lint 36 | id: lint 37 | run: | 38 | golangci-lint run 39 | -------------------------------------------------------------------------------- /internal/schema/testdata/test_description_override.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/test-description-override", 4 | "$ref": "#/$defs/TestDescriptionOverride", 5 | "$defs": { 6 | "TestDescriptionOverride": { 7 | "properties": { 8 | "FirstName": { 9 | "type": "string", 10 | "description": "test2" 11 | }, 12 | "LastName": { 13 | "type": "string", 14 | "description": "test3" 15 | }, 16 | "age": { 17 | "type": "integer", 18 | "description": "test4" 19 | }, 20 | "middle_name": { 21 | "type": "string", 22 | "description": "test5" 23 | } 24 | }, 25 | "additionalProperties": false, 26 | "type": "object", 27 | "required": [ 28 | "FirstName", 29 | "LastName", 30 | "age" 31 | ] 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /internal/list/element.go: -------------------------------------------------------------------------------- 1 | package list 2 | 3 | // Element is an element of a linked list. 4 | type Element[T any] struct { 5 | // Next and previous pointers in the doubly-linked list of elements. 6 | // To simplify the implementation, internally a list l is implemented 7 | // as a ring, such that &l.root is both the next element of the last 8 | // list element (l.Back()) and the previous element of the first list 9 | // element (l.Front()). 10 | next, prev *Element[T] 11 | 12 | // The list to which this element belongs. 13 | list *List[T] 14 | 15 | // The value stored with this element. 16 | Value T 17 | } 18 | 19 | // Next returns the next list element or nil. 20 | func (e *Element[T]) Next() *Element[T] { 21 | p := e.next 22 | if e.list != nil && p != &e.list.root { 23 | return p 24 | } 25 | return nil 26 | } 27 | 28 | // Prev returns the previous list element or nil. 29 | func (e *Element[T]) Prev() *Element[T] { 30 | p := e.prev 31 | if e.list != nil && p != &e.list.root { 32 | return p 33 | } 34 | return nil 35 | } 36 | -------------------------------------------------------------------------------- /extensions/jigsawstack/audio_test.go: -------------------------------------------------------------------------------- 1 | package jigsawstack_test 2 | 3 | import ( 4 | "context" 5 | "io" 6 | "os" 7 | "strings" 8 | "testing" 9 | 10 | "github.com/conneroisu/groq-go/extensions/jigsawstack" 11 | "github.com/conneroisu/groq-go/internal/test" 12 | "github.com/stretchr/testify/assert" 13 | ) 14 | 15 | func TestAudioTTS(t *testing.T) { 16 | if !test.IsIntegrationTest() { 17 | t.Skip() 18 | } 19 | a := assert.New(t) 20 | apiKey, err := test.GetAPIKey("JIGSAWSTACK_API_KEY") 21 | a.NoError(err) 22 | ctx := context.Background() 23 | client, err := jigsawstack.NewJigsawStack( 24 | apiKey, 25 | jigsawstack.WithLogger(test.DefaultLogger), 26 | ) 27 | a.NoError(err) 28 | response, err := client.AudioTTS(ctx, 29 | "Hello, world! Welcome to Groq!", 30 | jigsawstack.WithAccent("zh-TW-female-19"), 31 | ) 32 | a.NoError(err) 33 | // write the io.reader to a file 34 | f, err := os.Create("tts.mp3") 35 | a.NoError(err) 36 | defer f.Close() 37 | _, err = io.Copy(f, strings.NewReader(response)) 38 | a.NoError(err) 39 | } 40 | -------------------------------------------------------------------------------- /.github/workflows/unit.yaml: -------------------------------------------------------------------------------- 1 | name: Unit Tests 2 | on: 3 | workflow_dispatch: {} 4 | jobs: 5 | test: 6 | name: Test with Coverage 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Set up Go 10 | uses: actions/setup-go@v3 11 | with: 12 | go-version: '1.23.2' 13 | - name: Check out code 14 | uses: actions/checkout@v3 15 | - name: Install dependencies 16 | run: | 17 | go mod download 18 | - name: Run Integration tests 19 | env: 20 | GROQ_KEY: ${{ secrets.GROQ_KEY }} 21 | TOOLHOUSE_API_KEY: ${{ secrets.TOOLHOUSE_API_KEY }} 22 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 23 | run: | 24 | go test -race -tags=integration ./... 25 | - name: Run Unit tests 26 | env: 27 | GROQ_KEY: ${{ secrets.GROQ_KEY }} 28 | TOOLHOUSE_API_KEY: ${{ secrets.TOOLHOUSE_API_KEY }} 29 | E2B_API_KEY: ${{ secrets.E2B_API_KEY }} 30 | UNIT: true 31 | run: | 32 | go test -race -covermode atomic -coverprofile=covprofile ./... 33 | -------------------------------------------------------------------------------- /internal/test/server.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "log/slog" 5 | "net/http" 6 | "strings" 7 | ) 8 | 9 | const ( 10 | testAPI = "this-is-my-secure-token-do-not-steal!!" 11 | ) 12 | 13 | // GetTestToken returns the test token. 14 | func GetTestToken() string { 15 | return testAPI 16 | } 17 | 18 | // ServerTest is a test server for the groq api. 19 | type ServerTest struct { 20 | handlers map[string]Handler 21 | logger *slog.Logger 22 | } 23 | 24 | // Handler is a function that handles a request. 25 | type Handler func(w http.ResponseWriter, r *http.Request) 26 | 27 | // NewTestServer creates a new test server. 28 | func NewTestServer() *ServerTest { 29 | return &ServerTest{ 30 | handlers: make(map[string]Handler), 31 | logger: DefaultLogger, 32 | } 33 | } 34 | 35 | // RegisterHandler registers a handler for a path. 36 | func (ts *ServerTest) RegisterHandler(path string, handler Handler) { 37 | // to make the registered paths friendlier to a regex match in the route handler 38 | // in GroqTestServer 39 | path = strings.ReplaceAll(path, "*", ".*") 40 | ts.handlers[path] = handler 41 | } 42 | -------------------------------------------------------------------------------- /extensions/e2b/errors.go: -------------------------------------------------------------------------------- 1 | package e2b 2 | 3 | import "fmt" 4 | 5 | type ( 6 | // ErrToolNotFound is returned when a tool is not found. 7 | ErrToolNotFound struct { 8 | ToolName string 9 | } 10 | // ErrToolArgument is returned when an argument is invalid. 11 | ErrToolArgument struct { 12 | ToolName string 13 | ArgName string 14 | } 15 | // ErrMissingRequiredArgument is returned when a required argument is missing. 16 | ErrMissingRequiredArgument struct { 17 | ToolName string 18 | ArgName string 19 | } 20 | ) 21 | 22 | // Error implements the error interface for ErrToolNotFound. 23 | func (e ErrToolNotFound) Error() string { 24 | return fmt.Sprintf("tool %s not found", e.ToolName) 25 | } 26 | 27 | // Error implements the error interface for ErrToolArgument. 28 | func (e ErrToolArgument) Error() string { 29 | return fmt.Sprintf("invalid argument %s for tool %s", e.ArgName, e.ToolName) 30 | } 31 | 32 | // Error implements the error interface for ErrMissingRequiredArgument. 33 | func (e ErrMissingRequiredArgument) Error() string { 34 | return fmt.Sprintf("missing required argument %s for tool %s", e.ArgName, e.ToolName) 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 groq-go authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/src/mux2t1_N.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | 3 | use IEEE.std_logic_1164.all; 4 | 5 | entity mux2t1_N is 6 | 7 | generic( 8 | N : integer := 16 9 | ); 10 | port( 11 | i_S : in std_logic; 12 | i_D0 : in std_logic_vector(N-1 downto 0); 13 | i_D1 : in std_logic_vector(N-1 downto 0); 14 | o_O : out std_logic_vector(N-1 downto 0) 15 | ); 16 | 17 | end mux2t1_N; 18 | 19 | architecture structural of mux2t1_N is 20 | 21 | component mux2t1 is 22 | port( 23 | i_S : in std_logic; 24 | i_D0 : in std_logic; 25 | i_D1 : in std_logic; 26 | o_O : out std_logic 27 | ); 28 | end component; 29 | 30 | begin 31 | 32 | G_NBit_MUX : for i in 0 to N-1 generate 33 | MUXI : mux2t1 port map( 34 | i_S => i_S, -- All instances share the same select input. 35 | i_D0 => i_D0(i), -- ith instance's data 0 input hooked up to ith data 0 input. 36 | i_D1 => i_D1(i), -- ith instance's data 1 input hooked up to ith data 1 input. 37 | o_O => o_O(i) -- ith instance's data output hooked up to ith data output. 38 | ); 39 | end generate G_NBit_MUX; 40 | 41 | end structural; 42 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/test/tb_NMux2t1.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.std_logic_1164.all; 3 | 4 | entity tb_NMux2t1 is end tb_NMux2t1; 5 | 6 | architecture behavior of tb_NMux2t1 is 7 | component nmux2t1 8 | port ( 9 | AMux : in std_logic; 10 | BMux : in std_logic; 11 | Sel : in std_logic; 12 | Output : out std_logic 13 | ); 14 | 15 | 16 | end component; 17 | 18 | --Inputs 19 | signal s_AMux : std_logic := '0'; 20 | signal s_BMux : std_logic := '0'; 21 | signal s_Out : std_logic := '0'; 22 | 23 | --Outputs 24 | signal f : std_logic; 25 | 26 | begin 27 | DUT0 : nmux2t1 28 | port map ( 29 | AMux => s_AMux, 30 | BMux => s_BMux, 31 | Sel => s_Out, 32 | Output => f 33 | ); 34 | -- Stimulus process 35 | stim_proc : process 36 | begin 37 | s_AMux <= '0'; 38 | s_BMux <= '0'; 39 | s_Out <= '0'; 40 | wait for 100 ns; 41 | 42 | assert f = '0' report "Test failed for s=0" severity error; 43 | 44 | wait; 45 | end process stim_proc; 46 | end behavior; 47 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/template.tmpl: -------------------------------------------------------------------------------- 1 | {{ define "code" }} 2 | Write a decription of the first file inside a json response. 3 | 4 | Your response should be a just the json object with the following fields: 5 | In your description, do not jump to conclusions, but instead provide a thoughtful description of the file's content. 6 | If you refer to a file, use the entire path, including the file name. 7 | 8 | 9 | { 10 | "thoughts": "Your thoughts on the task", 11 | "description": "A description of the file in relation to the other files", 12 | } 13 | 14 | 15 | Your file is: 16 | 17 | {{.Source}} 18 | 19 | 20 | Related files: 21 | {{- range $file := .Files }} 22 | 23 | {{ $file.Content }} 24 | 25 | {{- end }} 26 | {{ end }} 27 | 28 | {{ define "header" }}-------------------------------------------------------------------------------- 29 | -- author: [ Conner Ohnesorge ](https://github.com/conneroisu) 30 | -- file_name: {{ .FileName }} 31 | -- desc: {{ .Description }} 32 | -------------------------------------------------------------------------------- 33 | 34 | {{ .Code }} 35 | {{ end }} 36 | -------------------------------------------------------------------------------- /pkg/groqerr/api.go: -------------------------------------------------------------------------------- 1 | package groqerr 2 | 3 | import "fmt" 4 | 5 | type ( 6 | // ErrContentFieldsMisused is an error that occurs when both Content and 7 | // MultiContent properties are set. 8 | ErrContentFieldsMisused struct{} 9 | // ErrToolNotFound is returned when a tool is not found. 10 | ErrToolNotFound struct { 11 | ToolName string 12 | } 13 | ) 14 | 15 | // Error implements the error interface. 16 | func (e ErrContentFieldsMisused) Error() string { 17 | return fmt.Errorf("can't use both Content and MultiContent properties simultaneously"). 18 | Error() 19 | } 20 | 21 | type ( 22 | // ErrRequest is a request error. 23 | ErrRequest struct { 24 | HTTPStatusCode int 25 | Err error 26 | } 27 | ) 28 | 29 | // Error implements the error interface. 30 | func (e *ErrRequest) Error() string { 31 | return fmt.Sprintf( 32 | "error, status code: %d, message: %s", 33 | e.HTTPStatusCode, 34 | e.Err, 35 | ) 36 | } 37 | 38 | // Unwrap unwraps the error. 39 | func (e *ErrRequest) Unwrap() error { 40 | return e.Err 41 | } 42 | 43 | // Error implements the error interface. 44 | func (e ErrToolNotFound) Error() string { 45 | return fmt.Sprintf("tool %s not found", e.ToolName) 46 | } 47 | -------------------------------------------------------------------------------- /extensions/jigsawstack/sql.go: -------------------------------------------------------------------------------- 1 | package jigsawstack 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/conneroisu/groq-go/pkg/builders" 8 | ) 9 | 10 | const ( 11 | textToSQLEndpoint Endpoint = "/v1/ai/sql" 12 | ) 13 | 14 | type ( 15 | // TextToSQLResponse represents a response structure for text to SQL API. 16 | TextToSQLResponse struct { 17 | Success bool `json:"success"` 18 | SQL string `json:"sql"` 19 | } 20 | ) 21 | 22 | // TextToSQL converts the text to SQL. 23 | // 24 | // Max text character is 5000. 25 | func (j *JigsawStack) TextToSQL( 26 | ctx context.Context, 27 | prompt string, 28 | sqlSchema string, 29 | ) (response TextToSQLResponse, err error) { 30 | body := struct { 31 | Prompt string `json:"prompt"` 32 | SQLSchema string `json:"sql_schema"` 33 | }{ 34 | Prompt: prompt, 35 | SQLSchema: sqlSchema, 36 | } 37 | req, err := builders.NewRequest( 38 | ctx, 39 | j.header, 40 | http.MethodPost, 41 | j.baseURL+string(textToSQLEndpoint), 42 | builders.WithBody(body), 43 | ) 44 | if err != nil { 45 | return 46 | } 47 | var resp TextToSQLResponse 48 | err = j.sendRequest(req, &resp) 49 | if err != nil { 50 | return 51 | } 52 | return resp, nil 53 | } 54 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/src/NBitAdder.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | 3 | use IEEE.STD_LOGIC_1164.all; 4 | use IEEE.NUMERIC_STD.all; 5 | use work.FullAdder; 6 | 7 | entity NBitAdder is 8 | generic ( 9 | N : integer := 4 10 | ); 11 | port ( 12 | A : in std_logic_vector(N-1 downto 0); 13 | B : in std_logic_vector(N-1 downto 0); 14 | Sum : out std_logic_vector(N-1 downto 0); 15 | CarryOut : out std_logic_vector(N-1 downto 0) 16 | ); 17 | end NBitAdder; 18 | 19 | 20 | architecture Behavioral of NBitAdder is 21 | signal carries : std_logic_vector(N downto 0); 22 | begin 23 | -- Initialize the carry-in for the first adder to 0 24 | carries(0) <= '0'; 25 | 26 | gen_full_adders : for i in 0 to N-1 generate 27 | full_adder_inst : entity FullAdder 28 | port map ( 29 | i_A => A(i), 30 | i_B => B(i), 31 | Cin => carries(i), 32 | Sum => Sum(i), 33 | Cout => carries(i+1) 34 | ); 35 | end generate; 36 | 37 | -- The carry-out of the last full adder is the CarryOut of the N-bit adder 38 | CarryOut <= carries(N-1 downto 0); 39 | 40 | end Behavioral; 41 | -------------------------------------------------------------------------------- /internal/test/mod-composio.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "net/http/httptest" 7 | "regexp" 8 | ) 9 | 10 | // ComposioTestServer Creates a mocked Composer server which can pretend to handle requests during testing. 11 | func (ts *ServerTest) ComposioTestServer() *httptest.Server { 12 | return httptest.NewUnstartedServer( 13 | http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 14 | log.Printf( 15 | "received a %s request at path %q\n", 16 | r.Method, 17 | r.URL.Path, 18 | ) 19 | 20 | // check auth 21 | if r.Header.Get("X-API-Key") != GetTestToken() { 22 | w.WriteHeader(http.StatusUnauthorized) 23 | return 24 | } 25 | 26 | // Handle /path/* routes. 27 | // Note: the * is converted to a .* in register handler for proper regex handling 28 | for route, handler := range ts.handlers { 29 | // Adding ^ and $ to make path matching deterministic since go map iteration isn't ordered 30 | pattern, _ := regexp.Compile("^" + route + "$") 31 | if pattern.MatchString(r.URL.Path) { 32 | handler(w, r) 33 | return 34 | } 35 | } 36 | http.Error( 37 | w, 38 | "the resource path doesn't exist", 39 | http.StatusNotFound, 40 | ) 41 | }), 42 | ) 43 | } 44 | -------------------------------------------------------------------------------- /internal/test/mod-e2b.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "net/http/httptest" 7 | "regexp" 8 | ) 9 | 10 | // E2bTestServer creates a test server for emulating the e2b api. 11 | func (ts *ServerTest) E2bTestServer() *httptest.Server { 12 | return httptest.NewUnstartedServer( 13 | http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 14 | log.Printf( 15 | "received a %s request at path %q\n", 16 | r.Method, 17 | r.URL.Path, 18 | ) 19 | 20 | // check auth 21 | if r.Header.Get("X-API-Key") != GetTestToken() && 22 | r.Header.Get("api-key") != GetTestToken() { 23 | w.WriteHeader(http.StatusUnauthorized) 24 | return 25 | } 26 | 27 | // Handle /path/* routes. 28 | // Note: the * is converted to a .* in register handler for proper regex handling 29 | for route, handler := range ts.handlers { 30 | // Adding ^ and $ to make path matching deterministic since go map iteration isn't ordered 31 | pattern, _ := regexp.Compile("^" + route + "$") 32 | if pattern.MatchString(r.URL.Path) { 33 | handler(w, r) 34 | return 35 | } 36 | } 37 | http.Error( 38 | w, 39 | "the resource path doesn't exist", 40 | http.StatusNotFound, 41 | ) 42 | }), 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /internal/schema/testdata/unsigned_int_handling.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/unsigned-int-handler", 4 | "$ref": "#/$defs/UnsignedIntHandler", 5 | "$defs": { 6 | "UnsignedIntHandler": { 7 | "properties": { 8 | "min_len": { 9 | "items": { 10 | "type": "string", 11 | "minLength": 0 12 | }, 13 | "type": "array" 14 | }, 15 | "max_len": { 16 | "items": { 17 | "type": "string", 18 | "maxLength": 0 19 | }, 20 | "type": "array" 21 | }, 22 | "min_items": { 23 | "items": { 24 | "type": "string" 25 | }, 26 | "type": "array", 27 | "minItems": 0 28 | }, 29 | "max_items": { 30 | "items": { 31 | "type": "string" 32 | }, 33 | "type": "array", 34 | "maxItems": 0 35 | } 36 | }, 37 | "additionalProperties": false, 38 | "type": "object", 39 | "required": [ 40 | "min_len", 41 | "max_len", 42 | "min_items", 43 | "max_items" 44 | ] 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /internal/test/mod-jigsawstack.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "net/http/httptest" 7 | "regexp" 8 | ) 9 | 10 | // JigsawStackTestServer Creates a mocked JigsawStack server which can pretend 11 | // to handle requests during testing. 12 | func (ts *ServerTest) JigsawStackTestServer() *httptest.Server { 13 | return httptest.NewUnstartedServer( 14 | http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 15 | log.Printf( 16 | "received a %s request at path %q\n", 17 | r.Method, 18 | r.URL.Path, 19 | ) 20 | 21 | // check auth 22 | if r.Header.Get("x-api-key") != GetTestToken() { 23 | w.WriteHeader(http.StatusUnauthorized) 24 | return 25 | } 26 | 27 | // Handle /path/* routes. 28 | // Note: the * is converted to a .* in register handler for proper regex handling 29 | for route, handler := range ts.handlers { 30 | // Adding ^ and $ to make path matching deterministic since go map iteration isn't ordered 31 | pattern, _ := regexp.Compile("^" + route + "$") 32 | if pattern.MatchString(r.URL.Path) { 33 | handler(w, r) 34 | return 35 | } 36 | } 37 | http.Error( 38 | w, 39 | "the resource path doesn't exist", 40 | http.StatusNotFound, 41 | ) 42 | }), 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /internal/test/mod-toolhouse.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "net/http/httptest" 7 | "regexp" 8 | ) 9 | 10 | // ToolhouseTestServer creates a test server for emulating the toolhouse api. 11 | func (ts *ServerTest) ToolhouseTestServer() *httptest.Server { 12 | return httptest.NewUnstartedServer( 13 | http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 14 | log.Printf( 15 | "received a %s request at path %q\n", 16 | r.Method, 17 | r.URL.Path, 18 | ) 19 | 20 | // check auth 21 | if r.Header.Get("Authorization") != "Bearer "+GetTestToken() && 22 | r.Header.Get("api-key") != GetTestToken() { 23 | w.WriteHeader(http.StatusUnauthorized) 24 | return 25 | } 26 | 27 | // Handle /path/* routes. 28 | // Note: the * is converted to a .* in register handler for proper regex handling 29 | for route, handler := range ts.handlers { 30 | // Adding ^ and $ to make path matching deterministic since go map iteration isn't ordered 31 | pattern, _ := regexp.Compile("^" + route + "$") 32 | if pattern.MatchString(r.URL.Path) { 33 | handler(w, r) 34 | return 35 | } 36 | } 37 | http.Error( 38 | w, 39 | "the resource path doesn't exist", 40 | http.StatusNotFound, 41 | ) 42 | }), 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /internal/test/mod-groq.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "net/http/httptest" 7 | "regexp" 8 | ) 9 | 10 | // GroqTestServer Creates a mocked Groq server which can pretend to handle requests during testing. 11 | func (ts *ServerTest) GroqTestServer() *httptest.Server { 12 | return httptest.NewUnstartedServer( 13 | http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 14 | log.Printf( 15 | "received a %s request at path %q\n", 16 | r.Method, 17 | r.URL.Path, 18 | ) 19 | 20 | // check auth 21 | if r.Header.Get("Authorization") != "Bearer "+GetTestToken() && 22 | r.Header.Get("api-key") != GetTestToken() { 23 | w.WriteHeader(http.StatusUnauthorized) 24 | return 25 | } 26 | 27 | // Handle /path/* routes. 28 | // Note: the * is converted to a .* in register handler for proper regex handling 29 | for route, handler := range ts.handlers { 30 | // Adding ^ and $ to make path matching deterministic since go map iteration isn't ordered 31 | pattern, _ := regexp.Compile("^" + route + "$") 32 | if pattern.MatchString(r.URL.Path) { 33 | handler(w, r) 34 | return 35 | } 36 | } 37 | http.Error( 38 | w, 39 | "the resource path doesn't exist", 40 | http.StatusNotFound, 41 | ) 42 | }), 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/test/tb_nBitInverter.vhd: -------------------------------------------------------------------------------- 1 | 2 | library IEEE; 3 | use IEEE.STD_LOGIC_1164.all; 4 | 5 | entity NBitInverter_tb is 6 | end NBitInverter_tb; 7 | 8 | architecture Behavioral of NBitInverter_tb is 9 | 10 | constant N : integer := 4; 11 | 12 | signal Input : std_logic_vector(N-1 downto 0) := (others => '0'); 13 | signal Output : std_logic_vector(N-1 downto 0); 14 | 15 | begin 16 | 17 | uut : entity work.NBitInverter 18 | generic map (N => N) 19 | port map ( 20 | Input => Input, 21 | Output => Output 22 | ); 23 | 24 | -- Stimulus process to apply test vectors 25 | stim_proc : process 26 | begin 27 | -- Test Case 1: All zeros 28 | Input <= "0000"; 29 | wait for 10 ns; 30 | 31 | -- Test Case 2: All ones 32 | Input <= "1111"; 33 | wait for 10 ns; 34 | 35 | -- Test Case 3: Alternating bits (1010) 36 | Input <= "1010"; 37 | wait for 10 ns; 38 | 39 | -- Test Case 4: Alternating bits (0101) 40 | Input <= "0101"; 41 | wait for 10 ns; 42 | 43 | -- Test Case 5: Random value 44 | Input <= "1100"; 45 | wait for 10 ns; 46 | 47 | -- Finish simulation 48 | wait; 49 | end process; 50 | 51 | end Behavioral; 52 | -------------------------------------------------------------------------------- /extensions/jigsawstack/prediction.go: -------------------------------------------------------------------------------- 1 | package jigsawstack 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | "time" 7 | 8 | "github.com/conneroisu/groq-go/pkg/builders" 9 | ) 10 | 11 | const ( 12 | predictEndpoint Endpoint = "v1/ai/prediction" 13 | ) 14 | 15 | type ( 16 | // DatasetEntry represents a dataset entry. 17 | DatasetEntry struct { 18 | Date time.Time `json:"date"` 19 | Value float64 `json:"value"` 20 | } 21 | // PredictResponse represents a response structure for prediction API. 22 | PredictResponse struct { 23 | Success bool `json:"success"` 24 | Answer []DatasetEntry `json:"answer"` 25 | } 26 | ) 27 | 28 | // Predict predicts the future values of a dataset. 29 | // 30 | // Max text character is 5000. 31 | func (j *JigsawStack) Predict( 32 | ctx context.Context, 33 | dataset []DatasetEntry, 34 | ) (response PredictResponse, err error) { 35 | var predictRequest = struct { 36 | Dataset []DatasetEntry `json:"dataset"` 37 | }{Dataset: dataset} 38 | req, err := builders.NewRequest( 39 | ctx, 40 | j.header, 41 | http.MethodPost, 42 | j.baseURL+string(predictEndpoint), 43 | builders.WithBody(predictRequest), 44 | ) 45 | if err != nil { 46 | return 47 | } 48 | var resp PredictResponse 49 | err = j.sendRequest(req, &resp) 50 | if err != nil { 51 | return 52 | } 53 | return resp, nil 54 | } 55 | -------------------------------------------------------------------------------- /extensions/jigsawstack/web_test.go: -------------------------------------------------------------------------------- 1 | package jigsawstack_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/conneroisu/groq-go/extensions/jigsawstack" 8 | "github.com/conneroisu/groq-go/internal/test" 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | // TestJigsawStack_WebSearch tests the WebSearch method of the JigsawStack client. 13 | func TestJigsawStack_WebSearch(t *testing.T) { 14 | if !test.IsIntegrationTest() { 15 | t.Skip("Skipping unit test") 16 | } 17 | a := assert.New(t) 18 | ctx := context.Background() 19 | apiKey, err := test.GetAPIKey("JIGSAWSTACK_API_KEY") 20 | a.NoError(err) 21 | j, err := jigsawstack.NewJigsawStack(apiKey) 22 | a.NoError(err) 23 | resp, err := j.WebSearch(ctx, "hello world golang") 24 | a.NoError(err) 25 | a.NotEmpty(resp.Results) 26 | } 27 | 28 | // TestJigsawStack_WebSearchSuggestions tests the WebSearchSuggestions method of the JigsawStack client. 29 | func TestJigsawStack_WebSearchSuggestions(t *testing.T) { 30 | if !test.IsIntegrationTest() { 31 | t.Skip("Skipping unit test") 32 | } 33 | a := assert.New(t) 34 | ctx := context.Background() 35 | apiKey, err := test.GetAPIKey("JIGSAWSTACK_API_KEY") 36 | a.NoError(err) 37 | j, err := jigsawstack.NewJigsawStack(apiKey) 38 | a.NoError(err) 39 | resp, err := j.WebSearchSuggestions(ctx, "hello") 40 | a.NoError(err) 41 | a.NotEmpty(resp.Suggestions) 42 | } 43 | -------------------------------------------------------------------------------- /examples/llama-blind/main.go: -------------------------------------------------------------------------------- 1 | // Package main demonstrates an example application of groq-go. 2 | package main 3 | 4 | import ( 5 | "context" 6 | "fmt" 7 | "os" 8 | 9 | "github.com/conneroisu/groq-go" 10 | ) 11 | 12 | func main() { 13 | ctx := context.Background() 14 | if err := run(ctx); err != nil { 15 | fmt.Println(err) 16 | os.Exit(1) 17 | } 18 | } 19 | 20 | func run( 21 | ctx context.Context, 22 | ) error { 23 | key := os.Getenv("GROQ_KEY") 24 | client, err := groq.NewClient(key) 25 | if err != nil { 26 | return err 27 | } 28 | response, err := client.ChatCompletion( 29 | ctx, 30 | groq.ChatCompletionRequest{ 31 | Model: groq.ModelLlama3211BVisionPreview, 32 | Messages: []groq.ChatCompletionMessage{ 33 | { 34 | Role: groq.RoleUser, 35 | MultiContent: []groq.ChatMessagePart{ 36 | { 37 | Type: groq.ChatMessagePartTypeText, 38 | Text: "What is the contents of the image?", 39 | }, 40 | { 41 | Type: groq.ChatMessagePartTypeImageURL, 42 | ImageURL: &groq.ChatMessageImageURL{ 43 | URL: "https://cdnimg.webstaurantstore.com/images/products/large/87539/251494.jpg", 44 | Detail: "auto", 45 | }, 46 | }}, 47 | }, 48 | }, 49 | MaxTokens: 2000, 50 | }, 51 | ) 52 | if err != nil { 53 | return err 54 | } 55 | fmt.Println(response.Choices[0].Message.Content) 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /internal/schema/testdata/keynamed.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/key-named", 4 | "$ref": "#/$defs/KeyNamed", 5 | "$defs": { 6 | "KeyNamed": { 7 | "properties": { 8 | "ThisWasLeftAsIs": { 9 | "type": "string" 10 | }, 11 | "coming_from_json_tag": { 12 | "type": "boolean" 13 | }, 14 | "nested_not_renamed": { 15 | "$ref": "#/$defs/KeyNamedNested" 16 | }, 17 | "✨unicode✨ s̸̥͝h̷̳͒e̴̜̽n̸̡̿a̷̘̔n̷̘͐i̶̫̐ǵ̶̯a̵̘͒n̷̮̾s̸̟̓": { 18 | "type": "string" 19 | }, 20 | "20.01": { 21 | "type": "integer", 22 | "description": "Description was preserved" 23 | } 24 | }, 25 | "additionalProperties": false, 26 | "type": "object", 27 | "required": [ 28 | "ThisWasLeftAsIs", 29 | "coming_from_json_tag", 30 | "nested_not_renamed", 31 | "✨unicode✨ s̸̥͝h̷̳͒e̴̜̽n̸̡̿a̷̘̔n̷̘͐i̶̫̐ǵ̶̯a̵̘͒n̷̮̾s̸̟̓", 32 | "20.01" 33 | ] 34 | }, 35 | "KeyNamedNested": { 36 | "properties": { 37 | "nested-renamed-property": { 38 | "type": "string" 39 | }, 40 | "NotRenamed": { 41 | "type": "string" 42 | } 43 | }, 44 | "additionalProperties": false, 45 | "type": "object", 46 | "required": [ 47 | "nested-renamed-property", 48 | "NotRenamed" 49 | ] 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /internal/schema/testdata/oneof_ref.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/server", 4 | "$ref": "#/$defs/Server", 5 | "$defs": { 6 | "Server": { 7 | "properties": { 8 | "ip_address": { 9 | "oneOf": [ 10 | { 11 | "$ref": "#/$defs/ipv4" 12 | }, 13 | { 14 | "$ref": "#/$defs/ipv6" 15 | } 16 | ] 17 | }, 18 | "ip_addresses": { 19 | "items": { 20 | "oneOf": [ 21 | { 22 | "$ref": "#/$defs/ipv4" 23 | }, 24 | { 25 | "$ref": "#/$defs/ipv6" 26 | } 27 | ] 28 | }, 29 | "type": "array" 30 | }, 31 | "ip_address_any": { 32 | "anyOf": [ 33 | { 34 | "$ref": "#/$defs/ipv4" 35 | }, 36 | { 37 | "$ref": "#/$defs/ipv6" 38 | } 39 | ] 40 | }, 41 | "ip_addresses_any": { 42 | "items": { 43 | "anyOf": [ 44 | { 45 | "$ref": "#/$defs/ipv4" 46 | }, 47 | { 48 | "$ref": "#/$defs/ipv6" 49 | } 50 | ] 51 | }, 52 | "type": "array" 53 | } 54 | }, 55 | "additionalProperties": false, 56 | "type": "object" 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /extensions/toolhouse/tools_test.go: -------------------------------------------------------------------------------- 1 | package toolhouse_test 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "net/http" 7 | "testing" 8 | 9 | "github.com/conneroisu/groq-go/extensions/toolhouse" 10 | "github.com/conneroisu/groq-go/internal/test" 11 | "github.com/conneroisu/groq-go/pkg/tools" 12 | "github.com/stretchr/testify/assert" 13 | ) 14 | 15 | func TestGetTools(t *testing.T) { 16 | a := assert.New(t) 17 | ctx := context.Background() 18 | ts := test.NewTestServer() 19 | ts.RegisterHandler("/get_tools", func(w http.ResponseWriter, _ *http.Request) { 20 | var ts []tools.Tool 21 | ts = append(ts, tools.Tool{ 22 | Function: tools.FunctionDefinition{ 23 | Name: "tool", 24 | Description: "tool", 25 | Parameters: tools.FunctionParameters{}, 26 | }, 27 | Type: tools.ToolTypeFunction, 28 | }) 29 | w.Header().Set("Content-Type", "application/json") 30 | w.WriteHeader(http.StatusOK) 31 | jsonBytes, err := json.Marshal(ts) 32 | a.NoError(err) 33 | _, err = w.Write(jsonBytes) 34 | a.NoError(err) 35 | }) 36 | testS := ts.ToolhouseTestServer() 37 | testS.Start() 38 | client, err := toolhouse.NewExtension( 39 | test.GetTestToken(), 40 | toolhouse.WithBaseURL(testS.URL), 41 | toolhouse.WithClient(testS.Client()), 42 | toolhouse.WithLogger(test.DefaultLogger), 43 | toolhouse.WithMetadata(map[string]any{ 44 | "id": "conner", 45 | "timezone": 5, 46 | }), 47 | ) 48 | a.NoError(err) 49 | tools, err := client.GetTools(ctx) 50 | a.NoError(err) 51 | a.NotEmpty(tools) 52 | } 53 | -------------------------------------------------------------------------------- /.github/workflows/chron-models.yaml: -------------------------------------------------------------------------------- 1 | name: Commit Go Generated Content 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 10 * * 0' 7 | 8 | jobs: 9 | update-go: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | # Step 1: Checkout the repository 14 | - name: Checkout repository 15 | uses: actions/checkout@v3 16 | 17 | # Step 2: Set up Go 18 | - name: Set up Go 19 | uses: actions/setup-go@v4 20 | with: 21 | go-version: '1.23.2' 22 | 23 | # Step 3: Run go mod download 24 | - name: Run go mod download 25 | run: go mod download 26 | 27 | # Step 5: Generate Go docs (assuming a script `make docs` exists) 28 | - name: Generate Go docs 29 | env: 30 | GROQ_KEY: ${{ secrets.GROQ_KEY }} 31 | run: | 32 | make docs 33 | 34 | # Step 6: Configure Git for commit 35 | - name: Set up Git config 36 | run: | 37 | git config --global user.name "github-actions[bot]" 38 | git config --global user.email "github-actions[bot]@users.noreply.github.com" 39 | 40 | # Step 7: Commit changes if any 41 | - name: Commit changes 42 | run: | 43 | git add . 44 | git commit -m "Update Go modules, Go workspace, and docs" || echo "No changes to commit" 45 | 46 | # Step 8: Push changes back to the repository 47 | - name: Push changes to repository 48 | uses: stefanzweifel/git-auto-commit-action@v4 49 | with: 50 | github_token: ${{ secrets.GITHUB_TOKEN }} 51 | -------------------------------------------------------------------------------- /examples/json-chat/main.go: -------------------------------------------------------------------------------- 1 | // Package main demonstrates an example application of groq-go. 2 | // It shows how to use groq-go to create a chat completion of a json object 3 | // using the llama-3.1-70B-8192-tool-use-preview model. 4 | package main 5 | 6 | import ( 7 | "context" 8 | "encoding/json" 9 | "fmt" 10 | "os" 11 | 12 | "github.com/conneroisu/groq-go" 13 | ) 14 | 15 | func main() { 16 | if err := run(context.Background()); err != nil { 17 | fmt.Println(err) 18 | os.Exit(1) 19 | } 20 | } 21 | 22 | // Responses is a response from the models endpoint. 23 | type Responses []struct { 24 | Title string `json:"title" jsonschema:"title=Poem Title,description=Title of the poem, minLength=1, maxLength=20"` 25 | Text string `json:"text" jsonschema:"title=Poem Text,description=Text of the poem, minLength=10, maxLength=200"` 26 | } 27 | 28 | func run( 29 | ctx context.Context, 30 | ) error { 31 | client, err := groq.NewClient(os.Getenv("GROQ_KEY")) 32 | if err != nil { 33 | return err 34 | } 35 | resp := &Responses{} 36 | err = client.ChatCompletionJSON(ctx, groq.ChatCompletionRequest{ 37 | Model: groq.ModelLlama3Groq70B8192ToolUsePreview, 38 | Messages: []groq.ChatCompletionMessage{ 39 | { 40 | Role: groq.RoleUser, 41 | Content: "Create 5 short poems in json format with title and text.", 42 | }, 43 | }, 44 | MaxTokens: 2000, 45 | }, resp) 46 | if err != nil { 47 | return err 48 | } 49 | 50 | jsValue, err := json.MarshalIndent(resp, "", " ") 51 | if err != nil { 52 | return err 53 | } 54 | fmt.Println(string(jsValue)) 55 | 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/test/tb_nBitAdder.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.STD_LOGIC_1164.all; 3 | use IEEE.NUMERIC_STD.all; 4 | 5 | entity NBitAdder_tb is 6 | end NBitAdder_tb; 7 | 8 | architecture Behavioral of NBitAdder_tb is 9 | 10 | constant N : integer := 4; 11 | 12 | signal A : std_logic_vector(N-1 downto 0) := (others => '0'); 13 | signal B : std_logic_vector(N-1 downto 0) := (others => '0'); 14 | signal Sum : std_logic_vector(N-1 downto 0); 15 | signal CarryOut : std_logic_vector(N-1 downto 0); 16 | 17 | begin 18 | 19 | uut : entity work.NBitAdder 20 | generic map (N => N) 21 | port map ( 22 | A => A, 23 | B => B, 24 | Sum => Sum, 25 | CarryOut => CarryOut 26 | ); 27 | 28 | -- Stimulus process to apply test vectors 29 | stim_proc : process 30 | begin 31 | -- Test Case 1: 0 + 1 32 | A <= "0000"; 33 | B <= "0001"; 34 | wait for 10 ns; 35 | 36 | -- Test Case 2: 3 + 3 37 | A <= "0011"; 38 | B <= "0011"; 39 | wait for 10 ns; 40 | 41 | -- Test Case 3: 15 + 1 42 | A <= "1111"; 43 | B <= "0001"; 44 | wait for 10 ns; 45 | 46 | -- Test Case 4: 10 + 5 47 | A <= "1010"; 48 | B <= "0101"; 49 | wait for 10 ns; 50 | 51 | -- Test Case 5: Maximum values 52 | A <= (others => '1'); 53 | B <= (others => '1'); 54 | wait for 10 ns; 55 | 56 | -- Finish simulation 57 | wait; 58 | end process; 59 | 60 | end Behavioral; 61 | -------------------------------------------------------------------------------- /extensions/jigsawstack/prompt_test.go: -------------------------------------------------------------------------------- 1 | package jigsawstack_test 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/conneroisu/groq-go/extensions/jigsawstack" 8 | "github.com/conneroisu/groq-go/internal/test" 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestJigsawStack_PromptCreate(t *testing.T) { 13 | if !test.IsIntegrationTest() { 14 | t.Skip("Skipping integration test") 15 | } 16 | a := assert.New(t) 17 | apiKey, err := test.GetAPIKey("JIGSAWSTACK_API_KEY") 18 | a.NoError(err) 19 | j, err := jigsawstack.NewJigsawStack(apiKey) 20 | a.NoError(err) 21 | resp, err := j.PromptCreate(context.Background(), jigsawstack.PromptCreateRequest{ 22 | Prompt: ` 23 | You are a helpful assistant that answers questions based on the provided context. 24 | Your job is to provide code completions based on the provided context. 25 | `, 26 | Inputs: []jigsawstack.PromptCreateInput{ 27 | { 28 | Key: "context", 29 | Optional: false, 30 | InitialValue: ` 31 | 32 | def main(): 33 | print("Hello, World!") 34 | 35 | if __name__ == "__main__": 36 | main() 37 | 38 | `, 39 | }, 40 | }, 41 | }) 42 | a.NoError(err) 43 | t.Logf("response: %v", resp) 44 | t.Fail() 45 | } 46 | func TestJigsawStack_PromptGet(t *testing.T) { 47 | if !test.IsIntegrationTest() { 48 | t.Skip("Skipping integration test") 49 | } 50 | a := assert.New(t) 51 | apiKey, err := test.GetAPIKey("JIGSAWSTACK_API_KEY") 52 | a.NoError(err) 53 | j, err := jigsawstack.NewJigsawStack(apiKey) 54 | a.NoError(err) 55 | resp, err := j.PromptGet(context.Background(), "test") 56 | a.NoError(err) 57 | a.NotEmpty(resp.Prompt) 58 | } 59 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/report/Mux/tb_Mux2t1.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- author: [ Conner Ohnesorge ](https://github.com/conneroisu) 3 | -- file_name: tb_Mux2t1.vhd 4 | -- desc: The file is a part of a larger project that includes a 2-to-1 multiplexer 5 | -- component and its structural implementation. It is used to test the component's 6 | -- behavior under different input conditions. 7 | -------------------------------------------------------------------------------- 8 | 9 | library IEEE; 10 | use IEEE.std_logic_1164.all; 11 | 12 | entity tb_NMux2t1 is end tb_NMux2t1; 13 | 14 | architecture behavior of tb_NMux2t1 is 15 | component nmux2t1 16 | port ( 17 | AMux : in std_logic; 18 | BMux : in std_logic; 19 | Sel : in std_logic; 20 | Output : out std_logic 21 | ); 22 | 23 | 24 | end component; 25 | 26 | --Inputs 27 | signal s_AMux : std_logic := '0'; 28 | signal s_BMux : std_logic := '0'; 29 | signal s_Out : std_logic := '0'; 30 | 31 | --Outputs 32 | signal f : std_logic; 33 | 34 | begin 35 | DUT0 : nmux2t1 36 | port map ( 37 | AMux => s_AMux, 38 | BMux => s_BMux, 39 | Sel => s_Out, 40 | Output => f 41 | ); 42 | -- Stimulus process 43 | stim_proc : process 44 | begin 45 | s_AMux <= '0'; 46 | s_BMux <= '0'; 47 | s_Out <= '0'; 48 | wait for 100 ns; 49 | 50 | assert f = '0' report "Test failed for s=0" severity error; 51 | 52 | wait; 53 | end process stim_proc; 54 | end behavior; 55 | 56 | -------------------------------------------------------------------------------- /extensions/e2b/options.go: -------------------------------------------------------------------------------- 1 | package e2b 2 | 3 | import ( 4 | "log/slog" 5 | "net/http" 6 | ) 7 | 8 | // E2B Sandbox Options 9 | 10 | // WithBaseURL sets the base URL for the e2b sandbox. 11 | func WithBaseURL(baseURL string) Option { 12 | return func(s *Sandbox) { s.baseURL = baseURL } 13 | } 14 | 15 | // WithClient sets the client for the e2b sandbox. 16 | func WithClient(client *http.Client) Option { 17 | return func(s *Sandbox) { s.client = client } 18 | } 19 | 20 | // WithLogger sets the logger for the e2b sandbox. 21 | func WithLogger(logger *slog.Logger) Option { 22 | return func(s *Sandbox) { s.logger = logger } 23 | } 24 | 25 | // WithTemplate sets the template for the e2b sandbox. 26 | func WithTemplate(template SandboxTemplate) Option { 27 | return func(s *Sandbox) { s.Template = template } 28 | } 29 | 30 | // WithMetaData sets the meta data for the e2b sandbox. 31 | func WithMetaData(metaData map[string]string) Option { 32 | return func(s *Sandbox) { s.Metadata = metaData } 33 | } 34 | 35 | // WithCwd sets the current working directory. 36 | func WithCwd(cwd string) Option { 37 | return func(s *Sandbox) { s.Cwd = cwd } 38 | } 39 | 40 | // WithWsURL sets the websocket url resolving function for the e2b sandbox. 41 | // 42 | // This is useful for testing. 43 | func WithWsURL(wsURL func(s *Sandbox) string) Option { 44 | return func(s *Sandbox) { s.wsURL = wsURL } 45 | } 46 | 47 | // Process Options 48 | 49 | // ProcessWithEnv sets the environment variables for the process. 50 | func ProcessWithEnv(env map[string]string) ProcessOption { 51 | return func(p *Process) { p.Env = env } 52 | } 53 | 54 | // ProcessWithCwd sets the current working directory for the process. 55 | func ProcessWithCwd(cwd string) ProcessOption { 56 | return func(p *Process) { p.Cwd = cwd } 57 | } 58 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/test/tb_NFullAdder.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.STD_LOGIC_1164.all; 3 | use IEEE.NUMERIC_STD.all; 4 | 5 | entity tb_NFullAdder is 6 | -- Empty entity as this is a test bench 7 | end tb_NFullAdder; 8 | 9 | architecture Behavioral of tb_NFullAdder is 10 | component NBitAdder 11 | Generic (N : integer := 4); 12 | Port ( 13 | A : in STD_LOGIC_VECTOR(N-1 downto 0); 14 | B : in STD_LOGIC_VECTOR(N-1 downto 0); 15 | Sum : out STD_LOGIC_VECTOR(N-1 downto 0); 16 | CarryOut : out STD_LOGIC 17 | ); 18 | end component; 19 | 20 | signal s_A : STD_LOGIC_VECTOR(3 downto 0) := (others => '0'); 21 | signal s_B : STD_LOGIC_VECTOR(3 downto 0) := (others => '0'); 22 | 23 | signal s_Sum : STD_LOGIC_VECTOR(3 downto 0); 24 | signal s_CarryOut : STD_LOGIC; 25 | 26 | signal clk : STD_LOGIC := '0'; 27 | 28 | begin 29 | DUT0: NBitAdder 30 | port map ( 31 | A => s_A, 32 | B => s_B, 33 | Sum => s_Sum, 34 | CarryOut => s_CarryOut 35 | ); 36 | 37 | -- Clock process 38 | clk_process : process 39 | begin 40 | clk <= '0'; 41 | wait for 5 ns; 42 | clk <= '1'; 43 | wait for 5 ns; 44 | end process; 45 | 46 | -- Test process 47 | stim_proc: process 48 | begin 49 | -- Testing all combinations 50 | for i in 0 to 15 loop 51 | for j in 0 to 15 loop 52 | s_A <= std_logic_vector(to_unsigned(i, 4)); 53 | s_B <= std_logic_vector(to_unsigned(j, 4)); 54 | wait for 10 ns; -- Wait for one clock cycle 55 | end loop; 56 | end loop; 57 | 58 | -- End simulation 59 | wait; 60 | end process; 61 | 62 | end Behavioral; 63 | -------------------------------------------------------------------------------- /extensions/e2b/tools_test.go: -------------------------------------------------------------------------------- 1 | package e2b 2 | 3 | import ( 4 | "context" 5 | "os" 6 | "testing" 7 | 8 | "github.com/conneroisu/groq-go" 9 | "github.com/conneroisu/groq-go/internal/test" 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func getapiKey(t *testing.T, val string) string { 14 | apiKey := os.Getenv(val) 15 | if apiKey == "" { 16 | t.Fail() 17 | } 18 | return apiKey 19 | } 20 | 21 | func TestSandboxTooling(t *testing.T) { 22 | if !test.IsIntegrationTest() { 23 | t.Skip() 24 | } 25 | a := assert.New(t) 26 | ctx := context.Background() 27 | sb, err := NewSandbox( 28 | ctx, 29 | getapiKey(t, "E2B_API_KEY"), 30 | WithLogger(test.DefaultLogger), 31 | WithCwd("/code"), 32 | ) 33 | a.NoError(err, "NewSandbox error") 34 | client, err := groq.NewClient(getapiKey(t, "GROQ_KEY")) 35 | a.NoError(err, "NewClient error") 36 | tools := sb.GetTools() 37 | // ask the ai to create a file with the data "Hello World!" in file "hello.txt" 38 | response, err := client.ChatCompletion(ctx, groq.ChatCompletionRequest{ 39 | Model: groq.ModelLlama3Groq70B8192ToolUsePreview, 40 | Messages: []groq.ChatCompletionMessage{ 41 | { 42 | Role: groq.RoleUser, 43 | Content: ` 44 | Create a file called 'hello.txt' with the data: 45 | 46 | Hello World! 47 | 48 | NOTE: You are in the correct cwd. Just call the write tool with a name of hello.txt and data of Hello World! 49 | `, 50 | }, 51 | }, 52 | MaxTokens: 2000, 53 | Tools: tools, 54 | }) 55 | a.NoError(err) 56 | sb.logger.Debug("response from model", "response", response) 57 | resps, err := sb.RunTooling(ctx, response) 58 | a.NoError(err) 59 | sb.logger.Debug("tooling response", "response", resps) 60 | lsres, err := sb.Ls(ctx, ".") 61 | a.NoError(err) 62 | a.Contains(lsres, LsResult{ 63 | Name: "hello.txt", 64 | IsDir: false, 65 | }) 66 | } 67 | -------------------------------------------------------------------------------- /extensions/composio/tools_test.go: -------------------------------------------------------------------------------- 1 | package composio_test 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "net/http" 7 | "testing" 8 | 9 | "github.com/conneroisu/groq-go/extensions/composio" 10 | "github.com/conneroisu/groq-go/internal/test" 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | func TestGetTools(t *testing.T) { 15 | a := assert.New(t) 16 | ctx := context.Background() 17 | ts := test.NewTestServer() 18 | ts.RegisterHandler("/v1/actions", func(w http.ResponseWriter, _ *http.Request) { 19 | w.Header().Set("Content-Type", "application/json") 20 | w.WriteHeader(http.StatusOK) 21 | var items struct { 22 | Items []composio.Tool `json:"items"` 23 | } 24 | items.Items = append(items.Items, composio.Tool{ 25 | Enum: "enum", 26 | Name: "NAME", 27 | Tags: []string{"TAG"}, 28 | DisplayName: "DISPLAY_NAME", 29 | }) 30 | jsonBytes, err := json.Marshal(items) 31 | a.NoError(err) 32 | _, err = w.Write(jsonBytes) 33 | a.NoError(err) 34 | }) 35 | 36 | testS := ts.ComposioTestServer() 37 | testS.Start() 38 | client, err := composio.NewComposer( 39 | test.GetTestToken(), 40 | composio.WithLogger(test.DefaultLogger), 41 | composio.WithBaseURL(testS.URL), 42 | ) 43 | a.NoError(err) 44 | ca, err := client.GetTools(ctx) 45 | a.NoError(err) 46 | a.NotEmpty(ca) 47 | } 48 | 49 | // TestUnitGetTools tests the ability of the composio client to get tools. 50 | func TestUnitGetTools(t *testing.T) { 51 | if !test.IsIntegrationTest() { 52 | t.Skip() 53 | } 54 | a := assert.New(t) 55 | ctx := context.Background() 56 | key, err := test.GetAPIKey("COMPOSIO_API_KEY") 57 | a.NoError(err) 58 | client, err := composio.NewComposer( 59 | key, 60 | composio.WithLogger(test.DefaultLogger), 61 | ) 62 | a.NoError(err) 63 | ts, err := client.GetTools(ctx, composio.WithApp("GITHUB")) 64 | a.NoError(err) 65 | a.NotEmpty(ts) 66 | } 67 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/test/tb_OnesComp.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.STD_LOGIC_1164.all; 3 | use IEEE.NUMERIC_STD.all; 4 | 5 | entity tb_ones_comp is end tb_ones_comp; 6 | 7 | architecture Behavioral of tb_ones_comp is 8 | 9 | constant N : integer := 8; 10 | constant M : integer := 32; 11 | 12 | signal Input : std_logic_vector(N-1 downto 0); 13 | signal Output : std_logic_vector(N-1 downto 0); 14 | 15 | component OnesComplementor 16 | generic (N : integer := 8); 17 | port ( 18 | Input : in std_logic_vector(N-1 downto 0); 19 | Output : out std_logic_vector(N-1 downto 0) 20 | ); 21 | end component; 22 | 23 | component OnesComplementor_2 24 | generic (M : integer := 32); 25 | port ( 26 | Input2 : in std_logic_vector(M-1 downto 0); 27 | Output2 : out std_logic_vector(M-1 downto 0) 28 | ); 29 | end component; 30 | begin 31 | DUT0 : OnesComplementor 32 | generic map (N => N) 33 | port map ( 34 | Input => Input, 35 | Output => Output 36 | ); 37 | 38 | DUT1 : OnesComplementor_2 39 | generic map (M => M) 40 | port map ( 41 | Input2 => Input, 42 | Output2 => Output 43 | ); 44 | 45 | stim_proc : process 46 | begin 47 | for i in 0 to 2**N-1 loop 48 | Input <= std_logic_vector(to_unsigned(i, N)); 49 | wait for 10 ns; 50 | assert Output = not Input report "End of testbench simulation" severity failure; 51 | end loop; 52 | for i in 0 to 2**M-1 loop 53 | Input <= std_logic_vector(to_unsigned(i, M)); 54 | wait for 10 ns; 55 | assert Output = not Input report "End of testbench simulation" severity failure; 56 | end loop; 57 | 58 | end process; 59 | 60 | end Behavioral; 61 | -------------------------------------------------------------------------------- /extensions/toolhouse/toolhouse_test.go: -------------------------------------------------------------------------------- 1 | package toolhouse_test 2 | 3 | import ( 4 | "context" 5 | "os" 6 | "testing" 7 | 8 | "github.com/conneroisu/groq-go" 9 | "github.com/conneroisu/groq-go/extensions/toolhouse" 10 | "github.com/conneroisu/groq-go/internal/test" 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | func TestUnitExtension(t *testing.T) { 15 | if !test.IsIntegrationTest() { 16 | t.Skip("Skipping Toolhouse extension test") 17 | } 18 | a := assert.New(t) 19 | ctx := context.Background() 20 | ext, err := toolhouse.NewExtension(os.Getenv("TOOLHOUSE_API_KEY"), 21 | toolhouse.WithMetadata(map[string]any{ 22 | "id": "conner", 23 | "timezone": 5, 24 | }), 25 | toolhouse.WithLogger(test.DefaultLogger), 26 | ) 27 | a.NoError(err) 28 | client, err := groq.NewClient(os.Getenv("GROQ_KEY")) 29 | a.NoError(err) 30 | history := []groq.ChatCompletionMessage{ 31 | { 32 | Role: groq.RoleUser, 33 | Content: "Write a python function to print the first 10 prime numbers containing the number 3 then respond with the answer. DO NOT GUESS WHAT THE OUTPUT SHOULD BE. MAKE SURE TO CALL THE TOOL GIVEN.", 34 | }, 35 | } 36 | tooling, err := ext.GetTools(ctx) 37 | a.NoError(err) 38 | re, err := client.ChatCompletion(ctx, groq.ChatCompletionRequest{ 39 | Model: groq.ModelLlama3Groq70B8192ToolUsePreview, 40 | Messages: history, 41 | Tools: tooling, 42 | ToolChoice: "required", 43 | }) 44 | a.NoError(err) 45 | history = append(history, re.Choices[0].Message) 46 | r, err := ext.Run(ctx, re) 47 | a.NoError(err) 48 | history = append(history, r...) 49 | finalr, err := client.ChatCompletion(ctx, groq.ChatCompletionRequest{ 50 | Model: groq.ModelLlama3Groq70B8192ToolUsePreview, 51 | Messages: history, 52 | MaxTokens: 2000, 53 | }) 54 | a.NoError(err) 55 | history = append(history, finalr.Choices[0].Message) 56 | a.NotEmpty(history[len(history)-1].Content) 57 | } 58 | -------------------------------------------------------------------------------- /examples/composio-github-star/main.go: -------------------------------------------------------------------------------- 1 | // Package main is an example of using the composio client. 2 | // 3 | // It shows how to use the composio client to star a github repository. 4 | package main 5 | 6 | import ( 7 | "context" 8 | "fmt" 9 | "log/slog" 10 | "os" 11 | 12 | "github.com/conneroisu/groq-go" 13 | "github.com/conneroisu/groq-go/extensions/composio" 14 | "github.com/conneroisu/groq-go/internal/test" 15 | ) 16 | 17 | func main() { 18 | if err := run(context.Background()); err != nil { 19 | fmt.Println(err) 20 | os.Exit(1) 21 | } 22 | } 23 | 24 | func run( 25 | ctx context.Context, 26 | ) error { 27 | key, err := test.GetAPIKey("GROQ_KEY") 28 | if err != nil { 29 | return err 30 | } 31 | client, err := groq.NewClient(key) 32 | if err != nil { 33 | return err 34 | } 35 | key, err = test.GetAPIKey("COMPOSIO_API_KEY") 36 | if err != nil { 37 | return err 38 | } 39 | comp, err := composio.NewComposer( 40 | key, 41 | composio.WithLogger(slog.Default()), 42 | ) 43 | if err != nil { 44 | return err 45 | } 46 | tools, err := comp.GetTools( 47 | ctx, 48 | composio.WithApp("GITHUB"), 49 | composio.WithUseCase("star-repo"), 50 | ) 51 | if err != nil { 52 | return err 53 | } 54 | chat, err := client.ChatCompletion(ctx, groq.ChatCompletionRequest{ 55 | Model: groq.ModelLlama3Groq70B8192ToolUsePreview, 56 | Messages: []groq.ChatCompletionMessage{ 57 | { 58 | Role: groq.RoleUser, 59 | Content: ` 60 | You are a github star bot. You will be given a repo name and you will star it. 61 | Star the repo conneroisu/groq-go on GitHub. 62 | `, 63 | }, 64 | }, 65 | MaxTokens: 2000, 66 | Tools: tools, 67 | }) 68 | if err != nil { 69 | return err 70 | } 71 | user, err := comp.GetConnectedAccounts(ctx) 72 | if err != nil { 73 | return err 74 | } 75 | resp, err := comp.Run(ctx, user[0], chat) 76 | if err != nil { 77 | return err 78 | } 79 | fmt.Println(resp) 80 | return nil 81 | } 82 | -------------------------------------------------------------------------------- /pkg/builders/forms.go: -------------------------------------------------------------------------------- 1 | package builders 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "mime/multipart" 7 | "os" 8 | "path" 9 | ) 10 | 11 | type ( 12 | // FormBuilder is an interface for building forms. 13 | FormBuilder interface { 14 | io.Closer 15 | CreateFormFile(fieldname string, file *os.File) error 16 | CreateFormFileReader(fieldname string, r io.Reader, filename string) error 17 | WriteField(fieldname, value string) error 18 | FormDataContentType() string 19 | } 20 | defaultFormBuilder struct { 21 | writer *multipart.Writer 22 | } 23 | ) 24 | 25 | // NewFormBuilder creates a new DefaultFormBuilder. 26 | func NewFormBuilder(body io.Writer) FormBuilder { 27 | return &defaultFormBuilder{ 28 | writer: multipart.NewWriter(body), 29 | } 30 | } 31 | 32 | func (fb *defaultFormBuilder) CreateFormFile( 33 | fieldname string, 34 | file *os.File, 35 | ) error { 36 | return fb.createFormFile(fieldname, file, file.Name()) 37 | } 38 | 39 | func (fb *defaultFormBuilder) CreateFormFileReader( 40 | fieldname string, 41 | r io.Reader, 42 | filename string, 43 | ) error { 44 | return fb.createFormFile(fieldname, r, path.Base(filename)) 45 | } 46 | 47 | func (fb *defaultFormBuilder) createFormFile( 48 | fieldname string, 49 | r io.Reader, 50 | filename string, 51 | ) error { 52 | if filename == "" { 53 | return fmt.Errorf("filename cannot be empty") 54 | } 55 | 56 | fieldWriter, err := fb.writer.CreateFormFile(fieldname, filename) 57 | if err != nil { 58 | return err 59 | } 60 | _, err = io.Copy(fieldWriter, r) 61 | if err != nil { 62 | return err 63 | } 64 | return nil 65 | } 66 | 67 | func (fb *defaultFormBuilder) WriteField(fieldname, value string) error { 68 | return fb.writer.WriteField(fieldname, value) 69 | } 70 | 71 | func (fb *defaultFormBuilder) Close() error { 72 | return fb.writer.Close() 73 | } 74 | 75 | func (fb *defaultFormBuilder) FormDataContentType() string { 76 | return fb.writer.FormDataContentType() 77 | } 78 | -------------------------------------------------------------------------------- /extensions/composio/options.go: -------------------------------------------------------------------------------- 1 | package composio 2 | 3 | import ( 4 | "fmt" 5 | "log/slog" 6 | "net/url" 7 | "strings" 8 | ) 9 | 10 | type ( 11 | // Option is an option for the composio client. 12 | // 13 | // WithLogger sets the logger for the composio client. 14 | Option func(*Composio) 15 | 16 | // ToolsOption is an option for the tools request. 17 | ToolsOption func(*url.Values) 18 | 19 | // AuthOption is an option for the auth request. 20 | AuthOption func(*url.Values) 21 | ) 22 | 23 | // Composer Options 24 | 25 | // WithLogger sets the logger for the composio client. 26 | func WithLogger(logger *slog.Logger) Option { 27 | return func(c *Composio) { c.logger = logger } 28 | } 29 | 30 | // WithBaseURL sets the base URL for the composio client. 31 | func WithBaseURL(baseURL string) Option { 32 | return func(c *Composio) { c.baseURL = baseURL } 33 | } 34 | 35 | // Get Tool Options 36 | 37 | // WithTags sets the tags for the tools request. 38 | func WithTags(tags ...string) ToolsOption { 39 | return func(u *url.Values) { u.Add("tags", strings.Join(tags, ",")) } 40 | } 41 | 42 | // WithApp sets the app for the tools request. 43 | func WithApp(app string) ToolsOption { 44 | return func(u *url.Values) { u.Add("appNames", app) } 45 | } 46 | 47 | // WithEntityID sets the entity id for the tools request. 48 | func WithEntityID(entityID string) ToolsOption { 49 | return func(u *url.Values) { u.Add("user_uuid", entityID) } 50 | } 51 | 52 | // WithUseCase sets the use case for the tools request. 53 | func WithUseCase(useCase string) ToolsOption { 54 | return func(u *url.Values) { u.Add("useCase", useCase) } 55 | } 56 | 57 | // Auth Options 58 | 59 | // WithShowActiveOnly sets the show active only for the auth request. 60 | func WithShowActiveOnly(showActiveOnly bool) AuthOption { 61 | return func(u *url.Values) { 62 | u.Set("showActiveOnly", fmt.Sprintf("%t", showActiveOnly)) 63 | } 64 | } 65 | 66 | // WithUserUUID sets the user uuid for the auth request. 67 | func WithUserUUID(userUUID string) AuthOption { 68 | return func(u *url.Values) { 69 | u.Set("user_uuid", userUUID) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to groq-go 2 | 3 | Thank you for considering contributing to groq-go! Your help is greatly appreciated. Below are some guidelines to help you get started. 4 | 5 | ## Code of Conduct 6 | 7 | By participating in this project, you agree to abide by the [Code of Conduct](https://www.contributor-covenant.org/version/2/0/code_of_conduct/). 8 | 9 | ## How to Report Bugs 10 | 11 | If you find a bug in the project, please open an issue on GitHub with a detailed description of the problem, including steps to reproduce it and any error messages you may have encountered. 12 | 13 | ## How to Request Features 14 | 15 | If you have an idea for a new feature, please open an issue on GitHub and provide a detailed description of the feature and why you believe it would be useful. 16 | 17 | ## How to Submit a Pull Request 18 | 19 | Before submitting a pull request, please ensure your changes adhere to the following guidelines: 20 | 21 | 1. **Fork the repository** and create your branch from the `main` branch. 22 | 2. **Run tests** to ensure your changes do not break existing functionality. 23 | 3. **Commit your changes** with a clear and concise message. 24 | 4. **Push your branch** to your forked repository. 25 | 5. **Open a pull request** on the main repository. 26 | 27 | ### Coding Standards 28 | 29 | - Follow the Go [style guide](https://golang.org/doc/effective_go.html). 30 | - Ensure your code is well-documented. 31 | 32 | ### Testing Instructions 33 | 34 | 1. Make sure you have a Groq key set in the environment variable `GROQ_KEY`. 35 | 2. Run the tests using the command: 36 | ```bash 37 | task test 38 | ``` 39 | 40 | ### Branch Naming Conventions 41 | 42 | Use descriptive names for your branches, such as `feature/add-xyz` or `bugfix/fix-abc`. 43 | 44 | ### Commit Message Guidelines 45 | 46 | - Use the present tense ("Add feature" not "Added feature"). 47 | - Use the imperative mood ("Move cursor to..." not "Moves cursor to..."). 48 | - Limit the first line to 72 characters or less. 49 | 50 | ## Getting Help 51 | 52 | If you need help, feel free to reach out by opening an issue or joining the discussion in the repository. 53 | -------------------------------------------------------------------------------- /extensions/composio/auth_test.go: -------------------------------------------------------------------------------- 1 | package composio_test 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "net/http" 7 | "testing" 8 | 9 | "github.com/conneroisu/groq-go/extensions/composio" 10 | "github.com/conneroisu/groq-go/internal/test" 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | func TestAuth(t *testing.T) { 15 | a := assert.New(t) 16 | ctx := context.Background() 17 | ts := test.NewTestServer() 18 | ts.RegisterHandler("/v1/connectedAccounts", func(w http.ResponseWriter, _ *http.Request) { 19 | var items struct { 20 | Items []composio.ConnectedAccount `json:"items"` 21 | } 22 | items.Items = append(items.Items, composio.ConnectedAccount{ 23 | IntegrationID: "INTEGRATION_ID", 24 | ID: "ID", 25 | MemberID: "MEMBER_ID", 26 | ClientUniqueUserID: "CLIENT_UNIQUE_USER_ID", 27 | Status: "STATUS", 28 | AppUniqueID: "APP_UNIQUE_ID", 29 | AppName: "APP_NAME", 30 | InvocationCount: "INVOCATION_COUNT", 31 | }) 32 | w.Header().Set("Content-Type", "application/json") 33 | w.WriteHeader(http.StatusOK) 34 | jsonBytes, err := json.Marshal(items) 35 | a.NoError(err) 36 | _, err = w.Write(jsonBytes) 37 | a.NoError(err) 38 | }) 39 | testS := ts.ComposioTestServer() 40 | testS.Start() 41 | client, err := composio.NewComposer( 42 | test.GetTestToken(), 43 | composio.WithLogger(test.DefaultLogger), 44 | composio.WithBaseURL(testS.URL), 45 | ) 46 | a.NoError(err) 47 | ca, err := client.GetConnectedAccounts(ctx) 48 | a.NoError(err) 49 | assert.NotEmpty(t, ca) 50 | } 51 | 52 | // TestUnitGetConnectedAccounts is an Unit test using a real composio server and api key. 53 | func TestUnitGetConnectedAccounts(t *testing.T) { 54 | if !test.IsIntegrationTest() { 55 | t.Skip() 56 | } 57 | a := assert.New(t) 58 | ctx := context.Background() 59 | key, err := test.GetAPIKey("COMPOSIO_API_KEY") 60 | a.NoError(err) 61 | client, err := composio.NewComposer( 62 | key, 63 | composio.WithLogger(test.DefaultLogger), 64 | ) 65 | a.NoError(err) 66 | ts, err := client.GetConnectedAccounts(ctx) 67 | a.NoError(err) 68 | a.NotEmpty(ts) 69 | } 70 | -------------------------------------------------------------------------------- /internal/schema/testdata/anyof.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/root-any-of", 4 | "$ref": "#/$defs/RootAnyOf", 5 | "$defs": { 6 | "ChildAnyOf": { 7 | "anyOf": [ 8 | { 9 | "required": [ 10 | "child1", 11 | "child4" 12 | ], 13 | "title": "group1" 14 | }, 15 | { 16 | "required": [ 17 | "child2", 18 | "child3" 19 | ], 20 | "title": "group2" 21 | } 22 | ], 23 | "properties": { 24 | "child1": { 25 | "type": "string" 26 | }, 27 | "child2": { 28 | "type": "string" 29 | }, 30 | "child3": { 31 | "oneOf": [ 32 | { 33 | "type": "string" 34 | }, 35 | { 36 | "type": "array" 37 | } 38 | ] 39 | }, 40 | "child4": { 41 | "type": "string" 42 | } 43 | }, 44 | "additionalProperties": false, 45 | "type": "object" 46 | }, 47 | "RootAnyOf": { 48 | "anyOf": [ 49 | { 50 | "required": [ 51 | "field1", 52 | "field4" 53 | ], 54 | "title": "group1" 55 | }, 56 | { 57 | "required": [ 58 | "field2" 59 | ], 60 | "title": "group2" 61 | } 62 | ], 63 | "properties": { 64 | "field1": { 65 | "type": "string" 66 | }, 67 | "field2": { 68 | "type": "string" 69 | }, 70 | "field3": { 71 | "anyOf": [ 72 | { 73 | "type": "string" 74 | }, 75 | { 76 | "type": "array" 77 | } 78 | ] 79 | }, 80 | "field4": { 81 | "type": "string" 82 | }, 83 | "child": { 84 | "$ref": "#/$defs/ChildAnyOf" 85 | } 86 | }, 87 | "additionalProperties": false, 88 | "type": "object" 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /extensions/toolhouse/execute_test.go: -------------------------------------------------------------------------------- 1 | package toolhouse_test 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "net/http" 7 | "testing" 8 | 9 | "github.com/conneroisu/groq-go" 10 | "github.com/conneroisu/groq-go/extensions/toolhouse" 11 | "github.com/conneroisu/groq-go/internal/test" 12 | "github.com/conneroisu/groq-go/pkg/tools" 13 | "github.com/stretchr/testify/assert" 14 | ) 15 | 16 | func TestRun(t *testing.T) { 17 | a := assert.New(t) 18 | ctx := context.Background() 19 | ts := test.NewTestServer() 20 | ts.RegisterHandler("/run_tools", func(w http.ResponseWriter, _ *http.Request) { 21 | var runResp struct { 22 | Provider string `json:"provider"` 23 | Content struct { 24 | Role string `json:"role"` 25 | ToolCallID string `json:"tool_call_id"` 26 | Name string `json:"name"` 27 | Content string `json:"content"` 28 | } `json:"content"` 29 | } 30 | runResp.Content.Content = "response1" 31 | runResp.Content.Name = "tool" 32 | w.Header().Set("Content-Type", "application/json") 33 | w.WriteHeader(http.StatusOK) 34 | jsonBytes, err := json.Marshal(runResp) 35 | a.NoError(err) 36 | _, err = w.Write(jsonBytes) 37 | a.NoError(err) 38 | }) 39 | testS := ts.ToolhouseTestServer() 40 | testS.Start() 41 | client, err := toolhouse.NewExtension( 42 | test.GetTestToken(), 43 | toolhouse.WithBaseURL(testS.URL), 44 | toolhouse.WithClient(testS.Client()), 45 | toolhouse.WithLogger(test.DefaultLogger), 46 | toolhouse.WithMetadata(map[string]any{ 47 | "id": "conner", 48 | "timezone": 5, 49 | }), 50 | ) 51 | a.NoError(err) 52 | history := []groq.ChatCompletionMessage{ 53 | { 54 | Role: groq.RoleUser, 55 | Content: "", 56 | ToolCalls: []tools.ToolCall{ 57 | { 58 | Function: tools.FunctionCall{ 59 | Name: "tool", 60 | }, 61 | }, 62 | }, 63 | }, 64 | } 65 | resp, err := client.Run(ctx, groq.ChatCompletionResponse{ 66 | Choices: []groq.ChatCompletionChoice{ 67 | { 68 | Message: history[0], 69 | FinishReason: groq.ReasonFunctionCall, 70 | }, 71 | }, 72 | }) 73 | a.NoError(err) 74 | assert.Equal(t, "response1", resp[0].Content) 75 | } 76 | -------------------------------------------------------------------------------- /extensions/toolhouse/execute.go: -------------------------------------------------------------------------------- 1 | package toolhouse 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/conneroisu/groq-go" 9 | "github.com/conneroisu/groq-go/pkg/builders" 10 | "github.com/conneroisu/groq-go/pkg/tools" 11 | ) 12 | 13 | type ( 14 | request struct { 15 | Content tools.ToolCall `json:"content,omitempty"` 16 | Provider string `json:"provider"` 17 | Metadata map[string]any `json:"metadata"` 18 | Bundle string `json:"bundle"` 19 | } 20 | ) 21 | 22 | // Run runs the extension on the given history. 23 | func (e *Toolhouse) Run( 24 | ctx context.Context, 25 | response groq.ChatCompletionResponse, 26 | ) ([]groq.ChatCompletionMessage, error) { 27 | var respH []groq.ChatCompletionMessage 28 | var toolCall tools.ToolCall 29 | e.logger.Debug("Running Toolhouse extension", "response", response) 30 | if response.Choices[0].FinishReason != groq.ReasonFunctionCall && response.Choices[0].FinishReason != "tool_calls" { 31 | return nil, fmt.Errorf("not a function call") 32 | } 33 | for _, toolCall = range response.Choices[0].Message.ToolCalls { 34 | req, err := builders.NewRequest( 35 | ctx, 36 | e.header, 37 | http.MethodPost, 38 | fmt.Sprintf("%s%s", e.baseURL, runToolEndpoint), 39 | builders.WithBody(request{ 40 | Content: toolCall, 41 | Provider: e.provider, 42 | Metadata: e.metadata, 43 | Bundle: e.bundle, 44 | }), 45 | ) 46 | if err != nil { 47 | return nil, err 48 | } 49 | e.logger.Debug("toolhouse running tool", "tool", toolCall.Function.Name, "call", toolCall.Function.Arguments) 50 | var runResp struct { 51 | Provider string `json:"provider"` 52 | Content struct { 53 | Role string `json:"role"` 54 | ToolCallID string `json:"tool_call_id"` 55 | Name string `json:"name"` 56 | Content string `json:"content"` 57 | } `json:"content"` 58 | } 59 | err = e.sendRequest(req, &runResp) 60 | if err != nil { 61 | return nil, err 62 | } 63 | respH = append(respH, groq.ChatCompletionMessage{ 64 | Content: runResp.Content.Content, 65 | Name: runResp.Content.Name, 66 | Role: groq.RoleFunction, 67 | }) 68 | } 69 | return respH, nil 70 | } 71 | -------------------------------------------------------------------------------- /examples/chat-terminal/main.go: -------------------------------------------------------------------------------- 1 | // Package main demonstrates how to use groq-go to create a chat application 2 | // using the groq api accessable through the terminal. 3 | package main 4 | 5 | import ( 6 | "bufio" 7 | "context" 8 | "fmt" 9 | "io" 10 | "os" 11 | "strings" 12 | 13 | "github.com/conneroisu/groq-go" 14 | ) 15 | 16 | var ( 17 | history = []groq.ChatCompletionMessage{} 18 | ) 19 | 20 | func main() { 21 | if err := run( 22 | context.Background(), 23 | os.Stdin, 24 | os.Stdout, 25 | ); err != nil { 26 | fmt.Println(err) 27 | os.Exit(1) 28 | } 29 | } 30 | 31 | func run( 32 | ctx context.Context, 33 | r io.Reader, 34 | w io.Writer, 35 | ) error { 36 | key := os.Getenv("GROQ_KEY") 37 | client, err := groq.NewClient(key) 38 | if err != nil { 39 | return err 40 | } 41 | for { 42 | err = input(ctx, client, r, w) 43 | if err != nil { 44 | return err 45 | } 46 | } 47 | } 48 | 49 | func input( 50 | ctx context.Context, 51 | client *groq.Client, 52 | r io.Reader, 53 | w io.Writer, 54 | ) error { 55 | fmt.Println("") 56 | fmt.Print("->") 57 | reader := bufio.NewReader(r) 58 | writer := w 59 | var lines []string 60 | select { 61 | case <-ctx.Done(): 62 | return ctx.Err() 63 | default: 64 | line, err := reader.ReadString('\n') 65 | if err != nil { 66 | return err 67 | } 68 | if len(strings.TrimSpace(line)) == 0 { 69 | break 70 | } 71 | lines = append(lines, line) 72 | break 73 | } 74 | history = append(history, groq.ChatCompletionMessage{ 75 | Role: groq.RoleUser, 76 | Content: strings.Join(lines, "\n"), 77 | }) 78 | output, err := client.ChatCompletionStream( 79 | ctx, 80 | groq.ChatCompletionRequest{ 81 | Model: groq.ModelGemma29BIt, 82 | Messages: history, 83 | MaxTokens: 2000, 84 | }, 85 | ) 86 | if err != nil { 87 | return err 88 | } 89 | fmt.Fprintln(writer, "\nai: ") 90 | for { 91 | response, err := output.Recv() 92 | if err != nil { 93 | return err 94 | } 95 | if response.Choices[0].FinishReason == groq.ReasonStop { 96 | break 97 | } 98 | fmt.Fprint(writer, response.Choices[0].Delta.Content) 99 | } 100 | return nil 101 | } 102 | -------------------------------------------------------------------------------- /extensions/composio/composio.go: -------------------------------------------------------------------------------- 1 | package composio 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io" 7 | "log/slog" 8 | "net/http" 9 | 10 | "github.com/conneroisu/groq-go/pkg/builders" 11 | ) 12 | 13 | const ( 14 | composioBaseURL = "https://backend.composio.dev/api" 15 | ) 16 | 17 | type ( 18 | // Composio is a composio client. 19 | Composio struct { 20 | apiKey string 21 | client *http.Client 22 | logger *slog.Logger 23 | header builders.Header 24 | baseURL string 25 | } 26 | // Integration represents a composio integration. 27 | Integration struct { 28 | Name string `json:"name"` 29 | ID int `json:"id"` 30 | } 31 | ) 32 | 33 | // NewComposer creates a new composio client. 34 | func NewComposer(apiKey string, opts ...Option) (*Composio, error) { 35 | c := &Composio{ 36 | apiKey: apiKey, 37 | header: builders.Header{SetCommonHeaders: func(r *http.Request) { 38 | r.Header.Set("X-API-Key", apiKey) 39 | }}, 40 | baseURL: composioBaseURL, 41 | client: http.DefaultClient, 42 | logger: slog.Default(), 43 | } 44 | for _, opt := range opts { 45 | opt(c) 46 | } 47 | return c, nil 48 | } 49 | 50 | func (c *Composio) doRequest(req *http.Request, v interface{}) error { 51 | req.Header.Set("Accept", "application/json") 52 | contentType := req.Header.Get("Content-Type") 53 | if contentType == "" { 54 | req.Header.Set("Content-Type", "application/json") 55 | } 56 | res, err := c.client.Do(req) 57 | if err != nil { 58 | return fmt.Errorf("failed to send request: %w", err) 59 | } 60 | defer res.Body.Close() 61 | if res.StatusCode < http.StatusOK || 62 | res.StatusCode >= http.StatusBadRequest { 63 | bodyText, _ := io.ReadAll(res.Body) 64 | return fmt.Errorf("request failed: %s\nbody: %s", res.Status, bodyText) 65 | } 66 | if v == nil { 67 | return nil 68 | } 69 | switch o := v.(type) { 70 | case *string: 71 | b, err := io.ReadAll(res.Body) 72 | if err != nil { 73 | return err 74 | } 75 | *o = string(b) 76 | return nil 77 | default: 78 | err = json.NewDecoder(res.Body).Decode(v) 79 | if err != nil { 80 | bodyText, _ := io.ReadAll(res.Body) 81 | return fmt.Errorf("failed to decode response: %w\nbody: %s", err, bodyText) 82 | } 83 | return nil 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/src/AdderSubtractor.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | 3 | use IEEE.STD_LOGIC_1164.all; 4 | 5 | entity AdderSubtractor is 6 | 7 | generic ( 8 | N : integer := 5 9 | ); 10 | port ( 11 | A : in std_logic_vector (N-1 downto 0); 12 | B : in std_logic_vector (N-1 downto 0); 13 | nAdd_Sub : in std_logic; 14 | Sum : out std_logic_vector (N-1 downto 0); 15 | Carry : out std_logic_vector (N-1 downto 0) 16 | ); 17 | 18 | end AdderSubtractor; 19 | 20 | architecture Structural of AdderSubtractor is 21 | 22 | component NBitInverter 23 | port ( 24 | Input : in std_logic_vector (N-1 downto 0); 25 | Output : out std_logic_vector (N-1 downto 0) 26 | ); 27 | end component; 28 | 29 | component mux2t1_N 30 | generic ( 31 | N : integer := 4 32 | ); 33 | port ( 34 | i_D0 : in std_logic_vector (N-1 downto 0); 35 | i_D1 : in std_logic_vector (N-1 downto 0); 36 | i_S : in std_logic; 37 | o_O : out std_logic_vector (N-1 downto 0) 38 | ); 39 | end component; 40 | 41 | component NBitAdder 42 | port ( 43 | A : in std_logic_vector (N-1 downto 0); 44 | B : in std_logic_vector (N-1 downto 0); 45 | Sum : out std_logic_vector (N-1 downto 0); 46 | CarryOut : out std_logic_vector (N-1 downto 0) 47 | ); 48 | end component; 49 | 50 | signal s_inverted : std_logic_vector (N-1 downto 0); 51 | signal s_muxed : std_logic_vector (N-1 downto 0); 52 | 53 | begin 54 | 55 | Inv : NBitInverter 56 | port map ( 57 | Input => B, 58 | Output => s_inverted 59 | ); 60 | 61 | Mux : mux2t1_N 62 | port map ( 63 | i_D0 => B, 64 | i_D1 => s_inverted, 65 | i_S => nAdd_Sub, 66 | o_O => s_muxed 67 | ); 68 | 69 | -- Instantiate the N-bit adder 70 | Adder : NBitAdder 71 | port map ( 72 | A => A, 73 | B => s_muxed, 74 | Sum => Sum, 75 | CarryOut => Carry 76 | ); 77 | 78 | end Structural; 79 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/test/tb_Adder.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | 4 | use IEEE.STD_LOGIC_1164.all; 5 | use IEEE.STD_LOGIC_ARITH.all; 6 | use IEEE.STD_LOGIC_UNSIGNED.all; 7 | use IEEE.numeric_std.all; 8 | 9 | entity tb_Adder is end tb_Adder; 10 | 11 | architecture behavior of tb_Adder is 12 | component Adder 13 | generic ( 14 | N : integer := 4 15 | ); 16 | port ( 17 | A : in std_logic_vector (N-1 downto 0); 18 | B : in std_logic_vector (N-1 downto 0); 19 | nAdd_Sub : in std_logic; 20 | Sum : out std_logic_vector (N-1 downto 0); 21 | Carry : out std_logic_vector (N-1 downto 0) 22 | ); 23 | end component; 24 | 25 | signal s_A : std_logic_vector (3 downto 0) := (others => '0'); 26 | signal s_B : std_logic_vector (3 downto 0) := (others => '0'); 27 | signal s_nAddSub : std_logic := '0'; 28 | signal s_Carry : std_logic_vector (3-1 downto 0); 29 | 30 | signal s_Sum : std_logic_vector (3 downto 0); 31 | 32 | begin 33 | DUT0 : Adder generic map (N => 4) 34 | port map ( 35 | A => s_A, 36 | B => s_B, 37 | nAdd_Sub => s_nAddSub, 38 | Sum => s_Sum, 39 | Carry => s_Carry 40 | ); 41 | 42 | s_A <= "0011"; s_B <= "0101"; s_nAddSub <= '0'; 43 | process 44 | begin 45 | wait for 10 ns; 46 | 47 | s_A <= "0110"; s_B <= "0011"; s_nAddSub <= '1'; 48 | wait for 10 ns; 49 | 50 | s_A <= "0000"; s_B <= "0000"; s_nAddSub <= '0'; -- Add zero 51 | wait for 10 ns; 52 | s_A <= "0000"; s_B <= "0000"; s_nAddSub <= '1'; -- Subtract zero 53 | wait for 10 ns; 54 | s_A <= "1111"; s_B <= "1111"; s_nAddSub <= '0'; -- Add max 55 | wait for 10 ns; 56 | s_A <= "1111"; s_B <= "1111"; s_nAddSub <= '1'; -- Subtract max 57 | wait for 10 ns; 58 | 59 | s_A <= "1111"; s_B <= "0001"; s_nAddSub <= '0'; -- Add overflow 60 | wait for 10 ns; 61 | s_A <= "0000"; s_B <= "0001"; s_nAddSub <= '1'; -- Subtract overflow 62 | wait for 10 ns; 63 | 64 | assert false report "Testbench completed" severity note; 65 | wait; 66 | end process; 67 | end; 68 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "inputs": { 5 | "systems": "systems" 6 | }, 7 | "locked": { 8 | "lastModified": 1731533236, 9 | "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", 10 | "owner": "numtide", 11 | "repo": "flake-utils", 12 | "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "numtide", 17 | "repo": "flake-utils", 18 | "type": "github" 19 | } 20 | }, 21 | "nixpkgs": { 22 | "locked": { 23 | "lastModified": 1763618868, 24 | "narHash": "sha256-v5afmLjn/uyD9EQuPBn7nZuaZVV9r+JerayK/4wvdWA=", 25 | "owner": "NixOS", 26 | "repo": "nixpkgs", 27 | "rev": "a8d610af3f1a5fb71e23e08434d8d61a466fc942", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "owner": "NixOS", 32 | "ref": "nixpkgs-unstable", 33 | "repo": "nixpkgs", 34 | "type": "github" 35 | } 36 | }, 37 | "root": { 38 | "inputs": { 39 | "flake-utils": "flake-utils", 40 | "nixpkgs": "nixpkgs", 41 | "treefmt-nix": "treefmt-nix" 42 | } 43 | }, 44 | "systems": { 45 | "locked": { 46 | "lastModified": 1681028828, 47 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 48 | "owner": "nix-systems", 49 | "repo": "default", 50 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 51 | "type": "github" 52 | }, 53 | "original": { 54 | "owner": "nix-systems", 55 | "repo": "default", 56 | "type": "github" 57 | } 58 | }, 59 | "treefmt-nix": { 60 | "inputs": { 61 | "nixpkgs": [ 62 | "nixpkgs" 63 | ] 64 | }, 65 | "locked": { 66 | "lastModified": 1762938485, 67 | "narHash": "sha256-AlEObg0syDl+Spi4LsZIBrjw+snSVU4T8MOeuZJUJjM=", 68 | "owner": "numtide", 69 | "repo": "treefmt-nix", 70 | "rev": "5b4ee75aeefd1e2d5a1cc43cf6ba65eba75e83e4", 71 | "type": "github" 72 | }, 73 | "original": { 74 | "owner": "numtide", 75 | "repo": "treefmt-nix", 76 | "type": "github" 77 | } 78 | } 79 | }, 80 | "root": "root", 81 | "version": 7 82 | } 83 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/test/tb_AdderSubtractor.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | 3 | use IEEE.STD_LOGIC_1164.all; 4 | use IEEE.STD_LOGIC_ARITH.all; 5 | use IEEE.STD_LOGIC_UNSIGNED.all; 6 | use IEEE.numeric_std.all; 7 | 8 | entity tb_AdderSubtractor is 9 | 10 | end tb_AdderSubtractor; 11 | 12 | architecture behavior of tb_AdderSubtractor is 13 | component AdderSubtractor 14 | generic ( 15 | N : integer := 4 16 | ); 17 | port ( 18 | A : in std_logic_vector (N-1 downto 0); 19 | B : in std_logic_vector (N-1 downto 0); 20 | nAdd_Sub : in std_logic; 21 | Sum : out std_logic_vector (N-1 downto 0); 22 | Carry : out std_logic_vector (N-1 downto 0) 23 | ); 24 | end component; 25 | 26 | signal s_A : std_logic_vector (3 downto 0) := (others => '0'); 27 | signal s_B : std_logic_vector (3 downto 0) := (others => '0'); 28 | signal s_nAddSub : std_logic := '0'; 29 | 30 | 31 | signal s_Sum : std_logic_vector (3 downto 0); 32 | signal s_Carry : std_logic_vector (3 downto 0); 33 | begin 34 | DUT0 : AdderSubtractor generic map (N => 4) 35 | port map ( 36 | A => s_A, 37 | B => s_B, 38 | nAdd_Sub => s_nAddSub, 39 | Sum => s_Sum, 40 | Carry => s_Carry 41 | ); 42 | 43 | s_A <= "0011"; s_B <= "0101"; s_nAddSub <= '0'; 44 | process 45 | begin 46 | wait for 10 ns; 47 | 48 | s_A <= "0110"; s_B <= "0011"; s_nAddSub <= '1'; 49 | wait for 10 ns; 50 | 51 | s_A <= "0000"; s_B <= "0000"; s_nAddSub <= '0'; -- Add zero 52 | wait for 10 ns; 53 | s_A <= "0000"; s_B <= "0000"; s_nAddSub <= '1'; -- Subtract zero 54 | wait for 10 ns; 55 | s_A <= "1111"; s_B <= "1111"; s_nAddSub <= '0'; -- Add max 56 | wait for 10 ns; 57 | s_A <= "1111"; s_B <= "1111"; s_nAddSub <= '1'; -- Subtract max 58 | wait for 10 ns; 59 | 60 | s_A <= "1111"; s_B <= "0001"; s_nAddSub <= '0'; -- Add overflow 61 | wait for 10 ns; 62 | s_A <= "0000"; s_B <= "0001"; s_nAddSub <= '1'; -- Subtract overflow 63 | wait for 10 ns; 64 | 65 | assert false report "Testbench completed" severity note; 66 | wait; 67 | end process; 68 | end; 69 | -------------------------------------------------------------------------------- /internal/omap/wbuf_test.go: -------------------------------------------------------------------------------- 1 | package omap 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | ) 7 | 8 | func TestAppendByte(t *testing.T) { 9 | var b Buffer 10 | var want []byte 11 | 12 | for range 1000 { 13 | b.AppendByte(1) 14 | b.AppendByte(2) 15 | want = append(want, 1, 2) 16 | } 17 | 18 | got := b.BuildBytes() 19 | if !bytes.Equal(got, want) { 20 | t.Errorf("BuildBytes() = %v; want %v", got, want) 21 | } 22 | } 23 | 24 | func TestAppendBytes(t *testing.T) { 25 | var b Buffer 26 | var want []byte 27 | 28 | for range 1000 { 29 | b.AppendBytes([]byte{1, 2}) 30 | want = append(want, 1, 2) 31 | } 32 | 33 | got := b.BuildBytes() 34 | if !bytes.Equal(got, want) { 35 | t.Errorf("BuildBytes() = %v; want %v", got, want) 36 | } 37 | } 38 | 39 | func TestAppendString(t *testing.T) { 40 | var b Buffer 41 | var want []byte 42 | 43 | s := "test" 44 | for range 1000 { 45 | b.AppendString(s) 46 | want = append(want, s...) 47 | } 48 | 49 | got := b.BuildBytes() 50 | if !bytes.Equal(got, want) { 51 | t.Errorf("BuildBytes() = %v; want %v", got, want) 52 | } 53 | } 54 | 55 | func TestDumpTo(t *testing.T) { 56 | var b Buffer 57 | var want []byte 58 | 59 | s := "test" 60 | for range 1000 { 61 | b.AppendBytes([]byte(s)) 62 | want = append(want, s...) 63 | } 64 | 65 | out := &bytes.Buffer{} 66 | n, err := b.DumpTo(out) 67 | if err != nil { 68 | t.Errorf("DumpTo() error: %v", err) 69 | } 70 | 71 | got := out.Bytes() 72 | if !bytes.Equal(got, want) { 73 | t.Errorf("DumpTo(): got %v; want %v", got, want) 74 | } 75 | 76 | if n != len(want) { 77 | t.Errorf("DumpTo() = %v; want %v", n, len(want)) 78 | } 79 | } 80 | 81 | func TestReadCloser(t *testing.T) { 82 | var b Buffer 83 | var want []byte 84 | 85 | s := "test" 86 | for range 1000 { 87 | b.AppendBytes([]byte(s)) 88 | want = append(want, s...) 89 | } 90 | 91 | out := &bytes.Buffer{} 92 | rc := b.ReadCloser() 93 | n, err := out.ReadFrom(rc) 94 | if err != nil { 95 | t.Errorf("ReadCloser() error: %v", err) 96 | } 97 | rc.Close() // Will always return nil 98 | 99 | got := out.Bytes() 100 | if !bytes.Equal(got, want) { 101 | t.Errorf("DumpTo(): got %v; want %v", got, want) 102 | } 103 | 104 | if n != int64(len(want)) { 105 | t.Errorf("DumpTo() = %v; want %v", n, len(want)) 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /extensions/composio/run.go: -------------------------------------------------------------------------------- 1 | package composio 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "net/http" 8 | 9 | "github.com/conneroisu/groq-go" 10 | "github.com/conneroisu/groq-go/pkg/builders" 11 | ) 12 | 13 | type ( 14 | // Runner is an interface for composio run. 15 | Runner interface { 16 | Run(ctx context.Context, 17 | user ConnectedAccount, 18 | response groq.ChatCompletionResponse) ( 19 | []groq.ChatCompletionMessage, error) 20 | } 21 | request struct { 22 | ConnectedAccountID string `json:"connectedAccountId"` 23 | EntityID string `json:"entityId"` 24 | AppName string `json:"appName"` 25 | Input map[string]any `json:"input"` 26 | Text string `json:"text,omitempty"` 27 | AuthConfig map[string]any `json:"authConfig,omitempty"` 28 | } 29 | ) 30 | 31 | // Run runs the composio client on a chat completion response. 32 | func (c *Composio) Run( 33 | ctx context.Context, 34 | user ConnectedAccount, 35 | response groq.ChatCompletionResponse, 36 | ) ([]groq.ChatCompletionMessage, error) { 37 | var respH []groq.ChatCompletionMessage 38 | if response.Choices[0].FinishReason != groq.ReasonFunctionCall && 39 | response.Choices[0].FinishReason != "tool_calls" { 40 | return nil, fmt.Errorf("not a function call") 41 | } 42 | for _, toolCall := range response.Choices[0].Message.ToolCalls { 43 | var args map[string]any 44 | if json.Valid([]byte(toolCall.Function.Arguments)) { 45 | err := json.Unmarshal([]byte(toolCall.Function.Arguments), &args) 46 | if err != nil { 47 | return nil, err 48 | } 49 | c.logger.Debug("arguments", "args", args) 50 | } 51 | req, err := builders.NewRequest( 52 | ctx, 53 | c.header, 54 | http.MethodPost, 55 | fmt.Sprintf("%s/v2/actions/%s/execute", c.baseURL, toolCall.Function.Name), 56 | builders.WithBody(&request{ 57 | ConnectedAccountID: user.ID, 58 | EntityID: "default", 59 | AppName: toolCall.Function.Name, 60 | Input: args, 61 | AuthConfig: map[string]any{}, 62 | }), 63 | ) 64 | if err != nil { 65 | return nil, err 66 | } 67 | var body string 68 | err = c.doRequest(req, &body) 69 | if err != nil { 70 | return nil, err 71 | } 72 | respH = append(respH, groq.ChatCompletionMessage{ 73 | Content: body, 74 | Name: toolCall.ID, 75 | Role: groq.RoleFunction, 76 | }) 77 | } 78 | return respH, nil 79 | } 80 | -------------------------------------------------------------------------------- /pkg/builders/requests.go: -------------------------------------------------------------------------------- 1 | package builders 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/json" 7 | "io" 8 | "net/http" 9 | ) 10 | 11 | var builder RequestBuilder = &defaultRequestBuilder{} 12 | 13 | type ( 14 | // Header is an struct interface for setting common headers. 15 | Header struct { 16 | SetCommonHeaders func(req *http.Request) 17 | } 18 | // RequestBuilder is an interface for building requests. 19 | RequestBuilder interface { 20 | Build( 21 | ctx context.Context, 22 | method, url string, 23 | body any, 24 | header http.Header, 25 | ) (*http.Request, error) 26 | } 27 | defaultRequestBuilder struct{} 28 | requestOptions struct { 29 | body any 30 | header http.Header 31 | querier Querier 32 | } 33 | // RequestOption is an option for a request. 34 | RequestOption func(*requestOptions) 35 | ) 36 | 37 | // NewRequestBuilder creates a new default request builder. 38 | func NewRequestBuilder() RequestBuilder { 39 | return &defaultRequestBuilder{} 40 | } 41 | 42 | func (b *defaultRequestBuilder) Build( 43 | ctx context.Context, 44 | method string, 45 | url string, 46 | body any, 47 | header http.Header, 48 | ) (req *http.Request, err error) { 49 | var bodyReader io.Reader 50 | if body != nil { 51 | v, ok := body.(io.Reader) 52 | if ok { 53 | bodyReader = v 54 | } else { 55 | var reqBytes []byte 56 | reqBytes, err = json.Marshal(body) 57 | if err != nil { 58 | return 59 | } 60 | bodyReader = bytes.NewBuffer(reqBytes) 61 | } 62 | } 63 | req, err = http.NewRequestWithContext( 64 | ctx, 65 | method, 66 | url, 67 | bodyReader, 68 | ) 69 | if err != nil { 70 | return 71 | } 72 | if header != nil { 73 | req.Header = header 74 | } 75 | return 76 | } 77 | 78 | // NewRequest creates a new request. 79 | func NewRequest( 80 | ctx context.Context, 81 | c Header, 82 | method, url string, 83 | setters ...RequestOption, 84 | ) (*http.Request, error) { 85 | args := &requestOptions{ 86 | body: nil, 87 | header: http.Header{}, 88 | } 89 | for _, setter := range setters { 90 | setter(args) 91 | } 92 | req, err := builder.Build( 93 | ctx, 94 | method, 95 | url, 96 | args.body, 97 | args.header, 98 | ) 99 | if err != nil { 100 | return nil, err 101 | } 102 | c.SetCommonHeaders(req) 103 | if args.querier != nil { 104 | args.querier.URLQuery(req.URL) 105 | } 106 | return req, nil 107 | } 108 | -------------------------------------------------------------------------------- /pkg/tools/tools.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | const ( 4 | // ToolTypeFunction is the function tool type. 5 | ToolTypeFunction ToolType = "function" 6 | ) 7 | 8 | type ( 9 | // Tool represents the tool. 10 | Tool struct { 11 | // Type is the type of the tool. 12 | Type ToolType `json:"type"` 13 | // Function is the tool's functional definition. 14 | Function FunctionDefinition `json:"function,omitempty"` 15 | } 16 | // ToolType is the tool type. 17 | // 18 | // string 19 | ToolType string 20 | // ToolChoice represents the tool choice. 21 | ToolChoice struct { 22 | // Type is the type of the tool choice. 23 | Type ToolType `json:"type"` 24 | // Function is the function of the tool choice. 25 | Function ToolFunction `json:"function,omitempty"` 26 | } 27 | // ToolFunction represents the tool function. 28 | ToolFunction struct { 29 | // Name is the name of the tool function. 30 | Name string `json:"name"` 31 | } 32 | // FunctionDefinition represents the function definition. 33 | FunctionDefinition struct { 34 | Name string `json:"name"` 35 | Description string `json:"description"` 36 | Parameters FunctionParameters `json:"parameters"` 37 | } 38 | // FunctionParameters represents the function parameters of a tool. 39 | FunctionParameters struct { 40 | Type string `json:"type"` 41 | Properties map[string]PropertyDefinition `json:"properties"` 42 | Required []string `json:"required"` 43 | AdditionalProperties bool `json:"additionalProperties,omitempty"` 44 | } 45 | // PropertyDefinition represents the property definition. 46 | PropertyDefinition struct { 47 | Type string `json:"type"` 48 | Description string `json:"description"` 49 | } 50 | // ToolCall represents a tool call. 51 | ToolCall struct { 52 | // Index is not nil only in chat completion chunk object 53 | Index *int `json:"index,omitempty"` 54 | // ID is the id of the tool call. 55 | ID string `json:"id"` 56 | // Type is the type of the tool call. 57 | Type string `json:"type"` 58 | // Function is the function of the tool call. 59 | Function FunctionCall `json:"function"` 60 | } 61 | // FunctionCall represents a function call. 62 | FunctionCall struct { 63 | // Name is the name of the function call. 64 | Name string `json:"name,omitempty"` 65 | // Arguments is the arguments of the function call in JSON format. 66 | Arguments string `json:"arguments,omitempty"` 67 | } 68 | ) 69 | -------------------------------------------------------------------------------- /internal/schema/testdata/oneof.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/root-one-of", 4 | "$ref": "#/$defs/RootOneOf", 5 | "$defs": { 6 | "ChildOneOf": { 7 | "oneOf": [ 8 | { 9 | "required": [ 10 | "child1", 11 | "child4" 12 | ], 13 | "title": "group1" 14 | }, 15 | { 16 | "required": [ 17 | "child2", 18 | "child3" 19 | ], 20 | "title": "group2" 21 | } 22 | ], 23 | "properties": { 24 | "child1": { 25 | "type": "string" 26 | }, 27 | "child2": { 28 | "type": "string" 29 | }, 30 | "child3": { 31 | "oneOf": [ 32 | { 33 | "type": "string" 34 | }, 35 | { 36 | "type": "array" 37 | } 38 | ] 39 | }, 40 | "child4": { 41 | "type": "string" 42 | } 43 | }, 44 | "additionalProperties": false, 45 | "type": "object" 46 | }, 47 | "RootOneOf": { 48 | "oneOf": [ 49 | { 50 | "required": [ 51 | "field1", 52 | "field4" 53 | ], 54 | "title": "group1" 55 | }, 56 | { 57 | "required": [ 58 | "field2" 59 | ], 60 | "title": "group2" 61 | } 62 | ], 63 | "properties": { 64 | "field1": { 65 | "type": "string" 66 | }, 67 | "field2": { 68 | "type": "string" 69 | }, 70 | "field3": { 71 | "oneOf": [ 72 | { 73 | "type": "string" 74 | }, 75 | { 76 | "type": "array" 77 | } 78 | ] 79 | }, 80 | "field4": { 81 | "type": "string" 82 | }, 83 | "child": { 84 | "$ref": "#/$defs/ChildOneOf" 85 | }, 86 | "field6": { 87 | "oneOf": [ 88 | { 89 | "$ref": "Outer" 90 | }, 91 | { 92 | "$ref": "OuterNamed" 93 | }, 94 | { 95 | "$ref": "OuterPtr" 96 | } 97 | ] 98 | } 99 | }, 100 | "additionalProperties": false, 101 | "type": "object" 102 | } 103 | } 104 | } -------------------------------------------------------------------------------- /internal/omap/utils_test.go: -------------------------------------------------------------------------------- 1 | package omap 2 | 3 | import ( 4 | "crypto/rand" 5 | "encoding/hex" 6 | "fmt" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | // assertOrderedPairsEqual asserts that the map contains the given keys and values 13 | // from oldest to newest. 14 | func assertOrderedPairsEqual[K comparable, V any]( 15 | t *testing.T, orderedMap *OrderedMap[K, V], expectedKeys []K, expectedValues []V, 16 | ) { 17 | t.Helper() 18 | 19 | assertOrderedPairsEqualFromNewest(t, orderedMap, expectedKeys, expectedValues) 20 | assertOrderedPairsEqualFromOldest(t, orderedMap, expectedKeys, expectedValues) 21 | } 22 | 23 | func assertOrderedPairsEqualFromNewest[K comparable, V any]( 24 | t *testing.T, orderedMap *OrderedMap[K, V], expectedKeys []K, expectedValues []V, 25 | ) { 26 | t.Helper() 27 | 28 | if assert.Equal(t, len(expectedKeys), len(expectedValues)) && assert.Equal(t, len(expectedKeys), orderedMap.Len()) { 29 | i := orderedMap.Len() - 1 30 | for pair := orderedMap.Newest(); pair != nil; pair = pair.Prev() { 31 | assert.Equal(t, expectedKeys[i], pair.Key, "from newest index=%d on key", i) 32 | assert.Equal(t, expectedValues[i], pair.Value, "from newest index=%d on value", i) 33 | i-- 34 | } 35 | } 36 | } 37 | 38 | func assertOrderedPairsEqualFromOldest[K comparable, V any]( 39 | t *testing.T, orderedMap *OrderedMap[K, V], expectedKeys []K, expectedValues []V, 40 | ) { 41 | t.Helper() 42 | 43 | if assert.Equal(t, len(expectedKeys), len(expectedValues)) && assert.Equal(t, len(expectedKeys), orderedMap.Len()) { 44 | i := 0 45 | for pair := orderedMap.Oldest(); pair != nil; pair = pair.Next() { 46 | assert.Equal(t, expectedKeys[i], pair.Key, "from oldest index=%d on key", i) 47 | assert.Equal(t, expectedValues[i], pair.Value, "from oldest index=%d on value", i) 48 | i++ 49 | } 50 | } 51 | } 52 | 53 | func assertLenEqual[K comparable, V any](t *testing.T, orderedMap *OrderedMap[K, V], expectedLen int) { 54 | t.Helper() 55 | 56 | assert.Equal(t, expectedLen, orderedMap.Len()) 57 | 58 | // also check the list length, for good measure 59 | assert.Equal(t, expectedLen, orderedMap.list.Len()) 60 | } 61 | 62 | func randomHexString(t *testing.T, length int) string { 63 | t.Helper() 64 | 65 | b := length / 2 //nolint:gomnd 66 | randBytes := make([]byte, b) 67 | 68 | if n, err := rand.Read(randBytes); err != nil || n != b { 69 | if err == nil { 70 | err = fmt.Errorf("only got %v random bytes, expected %v", n, b) 71 | } 72 | t.Fatal(err) 73 | } 74 | 75 | return hex.EncodeToString(randBytes) 76 | } 77 | -------------------------------------------------------------------------------- /extensions/jigsawstack/audio.go: -------------------------------------------------------------------------------- 1 | package jigsawstack 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/conneroisu/groq-go/pkg/builders" 8 | ) 9 | 10 | const ( 11 | ttsEndpoint Endpoint = "/v1/ai/tts" 12 | accentsEndpoint Endpoint = "/v1/audio/speaker_voice_accents" 13 | ) 14 | 15 | type ( 16 | // TTSOption is an option for the TTS request. 17 | TTSOption func(*ttsRequest) 18 | // ttsRequest represents a request structure for TTS API. 19 | ttsRequest struct { 20 | // Text is the text to convert to speech. 21 | // Required. 22 | Text string `json:"text"` 23 | // Accent is the accent of the speaker voice to use. 24 | // 25 | // Not required if the FileKey or SpeakerURL is not provided. 26 | Accent string `json:"accent,omitempty"` 27 | // SpeakerURL is the url of the speaker voice to use. 28 | // 29 | // Not required if the FileKey is not provided. 30 | SpeakerURL string `json:"speaker_clone_url,omitempty"` 31 | // FileKey is the key of the file to use as the speaker voice. 32 | // 33 | // Not required if the SpeakerURL is not provided. 34 | FileKey string `json:"speaker_clone_file_store_key,omitempty"` 35 | } 36 | ) 37 | 38 | // WithAccent sets the accent of the speaker voice to use. 39 | func WithAccent(accent string) TTSOption { 40 | return func(r *ttsRequest) { r.Accent = accent } 41 | } 42 | 43 | // WithSpeakerURL sets the url of the speaker voice to use. 44 | func WithSpeakerURL(url string) TTSOption { 45 | return func(r *ttsRequest) { r.SpeakerURL = url } 46 | } 47 | 48 | // WithFileKey sets the file key of the speaker voice to use. 49 | func WithFileKey(key string) TTSOption { 50 | return func(r *ttsRequest) { r.FileKey = key } 51 | } 52 | 53 | // AudioTTS creates a text to speech (TTS) audio file. 54 | // 55 | // It only support one option at a time, but does support no options. 56 | // 57 | // POST https://api.jigsawstack.com/v1/ai/tts 58 | // 59 | // https://docs.jigsawstack.com/api-reference/ai/text-to-speech 60 | func (j *JigsawStack) AudioTTS( 61 | ctx context.Context, 62 | text string, 63 | options ...TTSOption, 64 | ) (mp3 string, err error) { 65 | body := ttsRequest{ 66 | Text: text, 67 | } 68 | for _, option := range options { 69 | option(&body) 70 | } 71 | req, err := builders.NewRequest( 72 | ctx, 73 | j.header, 74 | http.MethodPost, 75 | j.baseURL+string(ttsEndpoint), 76 | builders.WithBody(body), 77 | ) 78 | if err != nil { 79 | return "", err 80 | } 81 | var resp string 82 | err = j.sendRequest(req, &resp) 83 | if err != nil { 84 | return "", err 85 | } 86 | return resp, nil 87 | } 88 | -------------------------------------------------------------------------------- /pkg/groqerr/stream.go: -------------------------------------------------------------------------------- 1 | package groqerr 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io" 7 | "strings" 8 | ) 9 | 10 | type ( 11 | // ErrTooManyEmptyStreamMessages is returned when the stream has sent 12 | // too many empty messages. 13 | ErrTooManyEmptyStreamMessages struct{} 14 | 15 | // ErrorResponse is the response returned by the Groq API. 16 | ErrorResponse struct { 17 | Error *APIError `json:"error,omitempty"` 18 | } 19 | 20 | // APIError provides error information returned by the Groq API. 21 | APIError struct { 22 | // Code is the code of the error. 23 | Code any `json:"code,omitempty"` 24 | // Message is the message of the error. 25 | Message string `json:"message"` 26 | // Param is the param of the error. 27 | Param *string `json:"param,omitempty"` 28 | // Type is the type of the error. 29 | Type string `json:"type"` 30 | // HTTPStatusCode is the status code of the error. 31 | HTTPStatusCode int `json:"-"` 32 | } 33 | 34 | // ErrorBuffer is a buffer that allows for appending errors. 35 | ErrorBuffer interface { 36 | io.Writer 37 | Len() int 38 | Bytes() []byte 39 | } 40 | ) 41 | 42 | // Error method implements the error interface on APIError. 43 | func (e *APIError) Error() string { 44 | if e.HTTPStatusCode > 0 { 45 | return fmt.Sprintf( 46 | "error, status code: %d, message: %s", 47 | e.HTTPStatusCode, 48 | e.Message, 49 | ) 50 | } 51 | return e.Message 52 | } 53 | 54 | // UnmarshalJSON implements the json.Unmarshaler interface. 55 | func (e *APIError) UnmarshalJSON(data []byte) (err error) { 56 | var rawMap map[string]json.RawMessage 57 | err = json.Unmarshal(data, &rawMap) 58 | if err != nil { 59 | return 60 | } 61 | err = json.Unmarshal(rawMap["message"], &e.Message) 62 | if err != nil { 63 | var messages []string 64 | err = json.Unmarshal(rawMap["message"], &messages) 65 | if err != nil { 66 | return 67 | } 68 | e.Message = strings.Join(messages, ", ") 69 | } 70 | // optional fields 71 | if _, ok := rawMap["param"]; ok { 72 | err = json.Unmarshal(rawMap["param"], &e.Param) 73 | if err != nil { 74 | return 75 | } 76 | } 77 | if _, ok := rawMap["code"]; !ok { 78 | return nil 79 | } 80 | // if the api returned a number, we need to force an integer 81 | // since the json package defaults to float64 82 | var intCode int 83 | err = json.Unmarshal(rawMap["code"], &intCode) 84 | if err == nil { 85 | e.Code = intCode 86 | return nil 87 | } 88 | return json.Unmarshal(rawMap["code"], &e.Code) 89 | } 90 | 91 | // Error returns the error message. 92 | func (e ErrTooManyEmptyStreamMessages) Error() string { 93 | return "stream has sent too many empty messages" 94 | } 95 | -------------------------------------------------------------------------------- /examples/toolhouse-python-code-interpreter/main.go: -------------------------------------------------------------------------------- 1 | // Package main shows an example of using the toolhouse go package. 2 | // 3 | // It shows how one can add the python code interpreter to their toolhouse 4 | // tools and use it to execute groq powered llms's code. 5 | package main 6 | 7 | import ( 8 | "context" 9 | "encoding/json" 10 | "fmt" 11 | "os" 12 | 13 | "github.com/conneroisu/groq-go" 14 | "github.com/conneroisu/groq-go/extensions/toolhouse" 15 | "github.com/conneroisu/groq-go/internal/test" 16 | ) 17 | 18 | func main() { 19 | ctx := context.Background() 20 | if err := run(ctx); err != nil { 21 | fmt.Println(err) 22 | os.Exit(1) 23 | } 24 | } 25 | 26 | func run(ctx context.Context) error { 27 | toolhouseKey, err := test.GetAPIKey("TOOLHOUSE_API_KEY") 28 | if err != nil { 29 | return err 30 | } 31 | ext, err := toolhouse.NewExtension(toolhouseKey, 32 | toolhouse.WithMetadata(map[string]any{ 33 | "id": "conner", 34 | "timezone": 5, 35 | })) 36 | if err != nil { 37 | return err 38 | } 39 | groqKey, err := test.GetAPIKey("GROQ_KEY") 40 | if err != nil { 41 | return err 42 | } 43 | client, err := groq.NewClient(groqKey) 44 | if err != nil { 45 | return err 46 | } 47 | history := []groq.ChatCompletionMessage{ 48 | { 49 | Role: groq.RoleUser, 50 | Content: "Write a python function to print the first 10 prime numbers containing the number 3 then respond with the answer. DO NOT GUESS WHAT THE OUTPUT SHOULD BE. MAKE SURE TO CALL THE TOOL GIVEN.", 51 | }, 52 | } 53 | tools, err := ext.GetTools(ctx) 54 | if err != nil { 55 | return err 56 | } 57 | re, err := client.ChatCompletion(ctx, groq.ChatCompletionRequest{ 58 | Model: groq.ModelLlama3Groq70B8192ToolUsePreview, 59 | Messages: history, 60 | Tools: tools, 61 | ToolChoice: "required", 62 | }) 63 | if err != nil { 64 | return fmt.Errorf("failed to create 1 chat completion: %w", err) 65 | } 66 | history = append(history, re.Choices[0].Message) 67 | r, err := ext.Run(ctx, re) 68 | if err != nil { 69 | return fmt.Errorf("failed to run tool: %w", err) 70 | } 71 | history = append(history, r...) 72 | finalr, err := client.ChatCompletion(ctx, groq.ChatCompletionRequest{ 73 | Model: groq.ModelLlama3Groq70B8192ToolUsePreview, 74 | Messages: history, 75 | MaxTokens: 2000, 76 | }) 77 | if err != nil { 78 | return fmt.Errorf("failed to create 2 chat completion: %w", err) 79 | } 80 | history = append(history, finalr.Choices[0].Message) 81 | jsnHistory, err := json.MarshalIndent(history, "", " ") 82 | if err != nil { 83 | return fmt.Errorf("failed to marshal history: %w", err) 84 | } 85 | fmt.Println(string(jsnHistory)) 86 | return nil 87 | } 88 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= 2 | github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= 3 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 4 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 5 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= 7 | github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 8 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 9 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 10 | github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= 11 | github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 12 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 13 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 14 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 15 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 16 | github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 17 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 18 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 19 | github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 20 | github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= 21 | github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= 22 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 23 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 24 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 25 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 26 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 27 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 28 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 29 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 30 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 31 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/src/TPU_MV_Element.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | 3 | use IEEE.std_logic_1164.all; 4 | 5 | entity TPU_MV_Element is 6 | 7 | port( 8 | iCLK : in std_logic; 9 | iX : in integer; 10 | iW : in integer; 11 | iLdW : in integer; 12 | iY : in integer; 13 | oY : out integer; 14 | oX : out integer 15 | ); 16 | 17 | end TPU_MV_Element; 18 | 19 | architecture structure of TPU_MV_Element is 20 | 21 | component Adder 22 | port( 23 | iCLK : in std_logic; 24 | iA : in integer; 25 | iB : in integer; 26 | oC : out integer 27 | ); 28 | end component; 29 | 30 | component Multiplier 31 | port( 32 | iCLK : in std_logic; 33 | iA : in integer; 34 | iB : in integer; 35 | oP : out integer 36 | ); 37 | end component; 38 | 39 | component Reg 40 | port( 41 | iCLK : in std_logic; 42 | iD : in integer; 43 | oQ : out integer 44 | ); 45 | end component; 46 | 47 | component RegLd 48 | port( 49 | iCLK : in std_logic; 50 | iD : in integer; 51 | iLd : in integer; 52 | oQ : out integer 53 | ); 54 | end component; 55 | 56 | signal s_W : integer; 57 | signal s_X1 : integer; 58 | signal s_Y1 : integer; 59 | signal s_WxX : integer; -- Signal to carry stored W*X 60 | 61 | begin 62 | -- Level 0: Conditionally load new W 63 | g_Weight : RegLd 64 | port map( 65 | iCLK => iCLK, 66 | iD => iW, 67 | iLd => iLdW, 68 | oQ => s_W 69 | ); 70 | -- Level 1: Delay X and Y, calculate W*X 71 | g_Delay1 : Reg 72 | port map( 73 | iCLK => iCLK, 74 | iD => iX, 75 | oQ => s_X1 76 | ); 77 | g_Delay2 : Reg 78 | port map( 79 | iCLK => iCLK, 80 | iD => iY, 81 | oQ => s_Y1 82 | ); 83 | g_Mult1 : Multiplier 84 | port map( 85 | iCLK => iCLK, 86 | iA => iX, 87 | iB => s_W, 88 | oP => s_WxX 89 | ); 90 | -- Level 2: Delay X, calculate Y += W*X 91 | g_Delay3 : Reg 92 | port map( 93 | iCLK => iCLK, 94 | iD => s_X1, 95 | oQ => oX 96 | ); 97 | g_Add1 : Adder 98 | port map( 99 | iCLK => iCLK, 100 | iA => s_WxX, 101 | iB => s_Y1, 102 | oC => oY 103 | ); 104 | 105 | end structure; 106 | -------------------------------------------------------------------------------- /examples/e2b-go-project/main.go: -------------------------------------------------------------------------------- 1 | // Package main shows an example of using the e2b extension. 2 | package main 3 | 4 | import ( 5 | "context" 6 | "fmt" 7 | "os" 8 | 9 | "github.com/conneroisu/groq-go" 10 | "github.com/conneroisu/groq-go/extensions/e2b" 11 | "github.com/conneroisu/groq-go/pkg/tools" 12 | ) 13 | 14 | var ( 15 | history = []groq.ChatCompletionMessage{ 16 | { 17 | Role: groq.RoleUser, 18 | Content: ` 19 | Given the callable tools provided, create a python project with the following files: 20 | 21 | 22 | main.py 23 | utils.py 24 | 25 | 26 | The main function should call the "utils.run()" function. 27 | 28 | The project should, when run, print the following to stdout: 29 | 30 | 31 | Hello, World! 32 | 33 | 34 | You should finish with the following shell command: 35 | 36 | 37 | python main.py 38 | 39 | `, 40 | }, 41 | } 42 | ) 43 | 44 | func main() { 45 | if err := run(context.Background()); err != nil { 46 | fmt.Println(err) 47 | os.Exit(1) 48 | } 49 | } 50 | 51 | func run( 52 | ctx context.Context, 53 | ) error { 54 | groqKey := os.Getenv("GROQ_KEY") 55 | e2bKey := os.Getenv("E2B_API_KEY") 56 | client, err := groq.NewClient(groqKey) 57 | if err != nil { 58 | return err 59 | } 60 | sb, err := e2b.NewSandbox(ctx, e2bKey) 61 | if err != nil { 62 | return err 63 | } 64 | defer func() { 65 | err := sb.Stop(ctx) 66 | if err != nil { 67 | fmt.Println(err) 68 | } 69 | }() 70 | ts := sb.GetTools() 71 | ts = append(ts, tools.Tool{ 72 | Type: tools.ToolTypeFunction, 73 | Function: tools.FunctionDefinition{ 74 | Name: "complete", 75 | Description: "Signify that the assigned task is complete.", 76 | Parameters: tools.FunctionParameters{ 77 | Type: "object", 78 | Properties: map[string]tools.PropertyDefinition{ 79 | "task": { 80 | Type: "string", 81 | Description: "The task that is complete.", 82 | }}}}}) 83 | for { 84 | chat, err := client.ChatCompletion(ctx, groq.ChatCompletionRequest{ 85 | Model: groq.ModelLlama3Groq8B8192ToolUsePreview, 86 | Messages: history, 87 | MaxTokens: 3000, 88 | Tools: ts, 89 | }) 90 | if err != nil { 91 | return err 92 | } 93 | if chat.Choices[0].FinishReason == groq.ReasonFunctionCall { 94 | if chat.Choices[0].Message.FunctionCall.Name == "complete" { 95 | break 96 | } 97 | } 98 | resp, err := sb.RunTooling(ctx, chat) 99 | if err != nil { 100 | history = append(history, 101 | groq.ChatCompletionMessage{ 102 | Role: groq.RoleUser, 103 | Content: err.Error(), 104 | }) 105 | continue 106 | } 107 | history = append(history, resp...) 108 | } 109 | return nil 110 | } 111 | -------------------------------------------------------------------------------- /extensions/toolhouse/toolhouse.go: -------------------------------------------------------------------------------- 1 | // Package toolhouse provides a Toolhouse extension for groq-go. 2 | package toolhouse 3 | 4 | import ( 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | "log/slog" 9 | "net/http" 10 | 11 | "github.com/conneroisu/groq-go/pkg/builders" 12 | ) 13 | 14 | const ( 15 | defaultBaseURL = "https://api.toolhouse.ai/v1" 16 | getToolsEndpoint = "/get_tools" 17 | runToolEndpoint = "/run_tools" 18 | applicationJSON = "application/json" 19 | ) 20 | 21 | type ( 22 | // Toolhouse is a Toolhouse extension. 23 | Toolhouse struct { 24 | apiKey string 25 | baseURL string 26 | provider string 27 | bundle string 28 | client *http.Client 29 | metadata map[string]any 30 | logger *slog.Logger 31 | header builders.Header 32 | } 33 | 34 | // Options is a function that sets options for a Toolhouse extension. 35 | Options func(*Toolhouse) 36 | ) 37 | 38 | // NewExtension creates a new Toolhouse extension. 39 | func NewExtension(apiKey string, opts ...Options) (e *Toolhouse, err error) { 40 | e = &Toolhouse{ 41 | apiKey: apiKey, 42 | baseURL: defaultBaseURL, 43 | client: http.DefaultClient, 44 | bundle: "default", 45 | provider: "openai", 46 | logger: slog.Default(), 47 | } 48 | e.header.SetCommonHeaders = func(req *http.Request) { 49 | req.Header.Set("User-Agent", "Toolhouse/1.2.1 Python/3.11.0") 50 | req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", e.apiKey)) 51 | req.Header.Set("Content-Type", applicationJSON) 52 | } 53 | for _, opt := range opts { 54 | opt(e) 55 | } 56 | if e.apiKey == "" { 57 | err = fmt.Errorf("api key is required") 58 | return 59 | } 60 | return e, nil 61 | } 62 | 63 | func (e *Toolhouse) sendRequest(req *http.Request, v interface{}) error { 64 | req.Header.Set("Accept", "application/json") 65 | contentType := req.Header.Get("Content-Type") 66 | if contentType == "" { 67 | req.Header.Set("Content-Type", "application/json") 68 | } 69 | res, err := e.client.Do(req) 70 | if err != nil { 71 | return err 72 | } 73 | defer res.Body.Close() 74 | if res.StatusCode < http.StatusOK || 75 | res.StatusCode >= http.StatusBadRequest { 76 | return fmt.Errorf("failed to send http request: %s", res.Status) 77 | } 78 | if v == nil { 79 | return nil 80 | } 81 | switch o := v.(type) { 82 | case *string: 83 | b, err := io.ReadAll(res.Body) 84 | if err != nil { 85 | return err 86 | } 87 | *o = string(b) 88 | return nil 89 | default: 90 | e.logger.Debug("decoding json response") 91 | err = json.NewDecoder(res.Body).Decode(v) 92 | if err != nil { 93 | read, err := io.ReadAll(res.Body) 94 | if err != nil { 95 | return err 96 | } 97 | e.logger.Debug("failed to decode response", "response", string(read)) 98 | return fmt.Errorf("failed to decode response: %s", string(read)) 99 | } 100 | return nil 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /examples/vhdl-documentor-json/src/mux2t1s.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.std_logic_1164.all; 3 | 4 | entity mux2t1s is 5 | port ( 6 | i_S : in std_logic; -- selector 7 | i_D0 : in std_logic; -- data inputs 8 | i_D1 : in std_logic; -- data inputs 9 | o_O : out std_logic -- output 10 | ); 11 | end mux2t1s; 12 | 13 | architecture structure of mux2t1s is 14 | 15 | component andg2 is 16 | port ( 17 | i_A : in std_logic; -- input A to AND gate 18 | i_B : in std_logic; -- input B to AND gate 19 | o_F : out std_logic -- output of AND gate 20 | ); 21 | 22 | end component; 23 | 24 | component org2 is 25 | port ( 26 | i_A : in std_logic; -- input A to OR gate 27 | i_B : in std_logic; -- input B to OR gate 28 | o_F : out std_logic -- output of OR gate 29 | ); 30 | 31 | end component; 32 | 33 | component invg is 34 | port ( 35 | i_A : in std_logic; -- input to NOT gate 36 | o_F : out std_logic -- output of NOT gate 37 | ); 38 | 39 | end component; 40 | 41 | -- Signal to hold invert of the selector bit 42 | signal s_inv_S1 : std_logic; 43 | -- Signals to hold output valeus from 'AND' gates (needed to wire component to component?) 44 | signal s_oX, s_oY : std_logic; 45 | 46 | begin 47 | --------------------------------------------------------------------------- 48 | -- Level 0: signals go through NOT stage 49 | --------------------------------------------------------------------------- 50 | invg1 : invg 51 | port map( 52 | i_A => i_S, -- input to NOT gate 53 | o_F => s_inv_S1 -- output of NOT gate 54 | ); 55 | --------------------------------------------------------------------------- 56 | -- Level 1: signals go through AND stage 57 | --------------------------------------------------------------------------- 58 | 59 | and1 : andg2 60 | port map( 61 | i_A => i_D0, -- input to AND gate 62 | i_B => s_inv_S1, -- input to AND gate 63 | o_F => s_oX -- output of AND gate 64 | ); 65 | 66 | and2 : andg2 67 | port map( 68 | i_A => i_D1, -- input to AND gate 69 | i_B => i_S, -- input to AND gate 70 | o_F => s_oY -- output of AND gate 71 | ); 72 | --------------------------------------------------------------------------- 73 | -- Level 1: signals go through OR stage (and then output) 74 | --------------------------------------------------------------------------- 75 | 76 | org1 : org2 77 | port map( 78 | i_A => s_oX, -- input to OR gate 79 | i_B => s_oY, -- input to OR gate 80 | o_F => o_O -- output of OR gate 81 | ); 82 | end structure; 83 | -------------------------------------------------------------------------------- /extensions/jigsawstack/jigsawstack.go: -------------------------------------------------------------------------------- 1 | package jigsawstack 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io" 7 | "log/slog" 8 | "net/http" 9 | 10 | "github.com/conneroisu/groq-go/pkg/builders" 11 | ) 12 | 13 | const ( 14 | defaultBaseURL = "https://api.jigsawstack.com" 15 | ) 16 | 17 | type ( 18 | // JigsawStack is a JigsawStack extension. 19 | JigsawStack struct { 20 | baseURL string 21 | client *http.Client 22 | logger *slog.Logger 23 | header builders.Header 24 | } 25 | // Option is an option for the JigsawStack client. 26 | Option func(*JigsawStack) 27 | // Endpoint is the endpoint for the JigsawStack api. 28 | Endpoint string 29 | ) 30 | 31 | // NewJigsawStack creates a new JigsawStack extension. 32 | func NewJigsawStack(apiKey string, opts ...Option) (*JigsawStack, error) { 33 | j := &JigsawStack{ 34 | baseURL: defaultBaseURL, 35 | client: http.DefaultClient, 36 | logger: slog.Default(), 37 | } 38 | for _, opt := range opts { 39 | opt(j) 40 | } 41 | j.header.SetCommonHeaders = func(req *http.Request) { 42 | req.Header.Set("x-api-key", apiKey) 43 | req.Header.Set("Content-Type", "application/json") 44 | req.Header.Set("Accept", "application/json") 45 | } 46 | return j, nil 47 | } 48 | 49 | // WithBaseURL sets the base URL for the JigsawStack extension. 50 | func WithBaseURL(baseURL string) Option { 51 | return func(j *JigsawStack) { j.baseURL = baseURL } 52 | } 53 | 54 | // WithClient sets the client for the JigsawStack extension. 55 | func WithClient(client *http.Client) Option { 56 | return func(j *JigsawStack) { j.client = client } 57 | } 58 | 59 | // WithLogger sets the logger for the JigsawStack extension. 60 | func WithLogger(logger *slog.Logger) Option { 61 | return func(j *JigsawStack) { j.logger = logger } 62 | } 63 | 64 | func (j *JigsawStack) sendRequest(req *http.Request, v any) error { 65 | j.header.SetCommonHeaders(req) 66 | resp, err := j.client.Do(req) 67 | if err != nil { 68 | return err 69 | } 70 | j.logger.Debug("received http response from jigsawstack", "status", resp.Status, "url", req.URL) 71 | defer resp.Body.Close() 72 | if resp.StatusCode < http.StatusOK || 73 | resp.StatusCode >= http.StatusBadRequest { 74 | read, err := io.ReadAll(resp.Body) 75 | if err != nil { 76 | return err 77 | } 78 | return fmt.Errorf("bad status code: %d\nbdy: %s\n headers: %v", resp.StatusCode, read, resp.Header) 79 | } 80 | if v == nil { 81 | return nil 82 | } 83 | switch o := v.(type) { 84 | case *string: 85 | b, err := io.ReadAll(resp.Body) 86 | if err != nil { 87 | return err 88 | } 89 | *o = string(b) 90 | return nil 91 | default: 92 | err = json.NewDecoder(resp.Body).Decode(v) 93 | if err != nil { 94 | read, err := io.ReadAll(resp.Body) 95 | if err != nil { 96 | return err 97 | } 98 | j.logger.Debug("failed to decode response", "response", string(read)) 99 | return fmt.Errorf("failed to decode response: %w\nbody: %s", err, string(read)) 100 | } 101 | return nil 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "A development shell for go"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; 6 | flake-utils.url = "github:numtide/flake-utils"; 7 | treefmt-nix.url = "github:numtide/treefmt-nix"; 8 | treefmt-nix.inputs.nixpkgs.follows = "nixpkgs"; 9 | }; 10 | 11 | outputs = { 12 | nixpkgs, 13 | flake-utils, 14 | treefmt-nix, 15 | ... 16 | }: 17 | flake-utils.lib.eachDefaultSystem (system: let 18 | pkgs = import nixpkgs { 19 | inherit system; 20 | overlays = [ 21 | (final: prev: { 22 | # Add your overlays here 23 | # Example: 24 | # my-overlay = final: prev: { 25 | # my-package = prev.callPackage ./my-package { }; 26 | # }; 27 | final.buildGoModule = prev.buildGo125Module; 28 | buildGoModule = prev.buildGo125Module; 29 | }) 30 | ]; 31 | }; 32 | 33 | rooted = exec: 34 | builtins.concatStringsSep "\n" 35 | [ 36 | ''REPO_ROOT="$(git rev-parse --show-toplevel)"'' 37 | exec 38 | ]; 39 | 40 | scripts = { 41 | dx = { 42 | exec = rooted ''$EDITOR "$REPO_ROOT"/flake.nix''; 43 | description = "Edit flake.nix"; 44 | }; 45 | gx = { 46 | exec = rooted ''$EDITOR "$REPO_ROOT"/go.mod''; 47 | description = "Edit go.mod"; 48 | }; 49 | }; 50 | 51 | scriptPackages = 52 | pkgs.lib.mapAttrs 53 | ( 54 | name: script: 55 | pkgs.writeShellApplication { 56 | inherit name; 57 | text = script.exec; 58 | runtimeInputs = script.deps or []; 59 | } 60 | ) 61 | scripts; 62 | 63 | treefmtModule = { 64 | projectRootFile = "flake.nix"; 65 | programs = { 66 | alejandra.enable = true; # Nix formatter 67 | gofmt.enable = true; # Go formatter 68 | golines.enable = true; # Go formatter (Shorter lines) 69 | goimports.enable = true; # Go formatter (Organize/Clean imports) 70 | }; 71 | }; 72 | in { 73 | devShells.default = pkgs.mkShell { 74 | name = "dev"; 75 | 76 | # Available packages on https://search.nixos.org/packages 77 | packages = with pkgs; 78 | [ 79 | alejandra # Nix 80 | nixd 81 | statix 82 | deadnix 83 | 84 | go_1_25 # Go Tools 85 | air 86 | golangci-lint 87 | gopls 88 | revive 89 | golines 90 | golangci-lint-langserver 91 | gomarkdoc 92 | gotests 93 | gotools 94 | gotestsum 95 | reftools 96 | graphviz 97 | ] 98 | ++ builtins.attrValues scriptPackages; 99 | }; 100 | 101 | formatter = treefmt-nix.lib.mkWrapper pkgs treefmtModule; 102 | }); 103 | } 104 | -------------------------------------------------------------------------------- /internal/test/helpers.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "fmt" 5 | "log/slog" 6 | "net/http" 7 | "os" 8 | "strings" 9 | "testing" 10 | ) 11 | 12 | // CreateTestFile creates a fake file with "hello" as the content. 13 | func CreateTestFile(t *testing.T, path string) { 14 | file, err := os.Create(path) 15 | if err != nil { 16 | t.Fatalf("failed to create file %v", err) 17 | } 18 | 19 | if _, err = file.WriteString("hello"); err != nil { 20 | t.Fatalf("failed to write to file %v", err) 21 | } 22 | file.Close() 23 | } 24 | 25 | // CreateTestDirectory creates a temporary folder which will be deleted when cleanup is called. 26 | func CreateTestDirectory(t *testing.T) (path string, cleanup func()) { 27 | t.Helper() 28 | 29 | path, err := os.MkdirTemp(os.TempDir(), "") 30 | if err != nil { 31 | t.Fatalf("failed to create directory %v", err) 32 | } 33 | 34 | return path, func() { os.RemoveAll(path) } 35 | } 36 | 37 | // TokenRoundTripper is a struct that implements the RoundTripper 38 | // interface, specifically to handle the authentication token by adding a token 39 | // to the request header. We need this because the API requires that each 40 | // request include a valid API token in the headers for authentication and 41 | // authorization. 42 | type TokenRoundTripper struct { 43 | Token string 44 | Fallback http.RoundTripper 45 | } 46 | 47 | // RoundTrip takes an *http.Request as input and returns an 48 | // *http.Response and an error. 49 | // 50 | // It is expected to use the provided request to create a connection to an HTTP 51 | // server and return the response, or an error if one occurred. The returned 52 | // Response should have its Body closed. If the RoundTrip method returns an 53 | // error, the Client's Get, Head, Post, and PostForm methods return the same 54 | // error. 55 | func (t *TokenRoundTripper) RoundTrip( 56 | req *http.Request, 57 | ) (*http.Response, error) { 58 | req.Header.Set("Authorization", "Bearer "+t.Token) 59 | return t.Fallback.RoundTrip(req) 60 | } 61 | 62 | // IsIntegrationTest returns true if the unit test environment variable is set. 63 | func IsIntegrationTest() bool { 64 | return os.Getenv("UNIT") != "" 65 | } 66 | 67 | // GetAPIKey returns the api key. 68 | func GetAPIKey(key string) (string, error) { 69 | apiKey := os.Getenv(key) 70 | if apiKey == "" { 71 | return "", fmt.Errorf("api key: %s is required", key) 72 | } 73 | return apiKey, nil 74 | } 75 | 76 | // DefaultLogger is a default logger. 77 | var DefaultLogger = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ 78 | AddSource: true, 79 | Level: slog.LevelDebug, 80 | ReplaceAttr: func(_ []string, a slog.Attr) slog.Attr { 81 | if a.Key == "time" { 82 | return slog.Attr{} 83 | } 84 | if a.Key == "level" { 85 | return slog.Attr{} 86 | } 87 | if a.Key == slog.SourceKey { 88 | str := a.Value.String() 89 | split := strings.Split(str, "/") 90 | if len(split) > 2 { 91 | a.Value = slog.StringValue(strings.Join(split[len(split)-2:], "/")) 92 | a.Value = slog.StringValue(strings.Replace(a.Value.String(), "}", "", -1)) 93 | } 94 | } 95 | return a 96 | }})) 97 | -------------------------------------------------------------------------------- /extensions/jigsawstack/web.go: -------------------------------------------------------------------------------- 1 | package jigsawstack 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | "time" 7 | 8 | "github.com/conneroisu/groq-go/pkg/builders" 9 | ) 10 | 11 | const ( 12 | webSearchEndpoint Endpoint = "/v1/web/search" 13 | webSuggestEndpoint Endpoint = "/v1/web/search/suggest" 14 | ) 15 | 16 | type ( 17 | // WebSearchSuggestions is the response for the web search suggestions 18 | // api. 19 | WebSearchSuggestions struct { 20 | Success bool `json:"success"` 21 | Suggestions []string `json:"suggestions"` 22 | } 23 | // WebSearchResponse is the response for the web search api. 24 | WebSearchResponse struct { 25 | Success bool `json:"success"` 26 | Query string `json:"query"` 27 | SpellFixed string `json:"spell_fixed"` 28 | IsSafe bool `json:"is_safe"` 29 | AiOverview string `json:"ai_overview"` 30 | Results []struct { 31 | Title string `json:"title"` 32 | URL string `json:"url"` 33 | Description string `json:"description"` 34 | Content string `json:"content"` 35 | SiteName string `json:"site_name"` 36 | SiteLongName string `json:"site_long_name"` 37 | Age time.Time `json:"age"` 38 | Language string `json:"language"` 39 | IsSafe bool `json:"is_safe"` 40 | Favicon string `json:"favicon"` 41 | Snippets []string `json:"snippets"` 42 | RelatedIndex []struct { 43 | Title string `json:"title"` 44 | URL string `json:"url"` 45 | Description string `json:"description"` 46 | IsSafe bool `json:"is_safe"` 47 | } `json:"related_index,omitempty"` 48 | Thumbnail string `json:"thumbnail,omitempty"` 49 | } `json:"results"` 50 | } 51 | ) 52 | 53 | // WebSearch performs a web search api call over a query string. 54 | // 55 | // GET https://api.jigsawstack.com/v1/web/search 56 | // 57 | // https://docs.jigsawstack.com/api-reference/web/search 58 | func (j *JigsawStack) WebSearch( 59 | ctx context.Context, 60 | query string, 61 | ) (response WebSearchResponse, err error) { 62 | uri := j.baseURL + string(webSearchEndpoint) + "?query=" + query 63 | req, err := builders.NewRequest( 64 | ctx, 65 | j.header, 66 | http.MethodGet, 67 | uri, 68 | ) 69 | if err != nil { 70 | return 71 | } 72 | var resp WebSearchResponse 73 | err = j.sendRequest(req, &resp) 74 | if err != nil { 75 | return 76 | } 77 | return resp, nil 78 | } 79 | 80 | // WebSearchSuggestions performs a web search suggestions api call over a query 81 | // string. 82 | // 83 | // GET https://api.jigsawstack.com/v1/web/search/suggest 84 | // 85 | // https://docs.jigsawstack.com/api-reference/web/search 86 | func (j *JigsawStack) WebSearchSuggestions( 87 | ctx context.Context, 88 | query string, 89 | ) (response WebSearchSuggestions, err error) { 90 | uri := j.baseURL + string(webSuggestEndpoint) + "?query=" + query 91 | req, err := builders.NewRequest( 92 | ctx, 93 | j.header, 94 | http.MethodGet, 95 | uri, 96 | ) 97 | if err != nil { 98 | return 99 | } 100 | var resp WebSearchSuggestions 101 | err = j.sendRequest(req, &resp) 102 | if err != nil { 103 | return 104 | } 105 | return resp, nil 106 | } 107 | -------------------------------------------------------------------------------- /internal/schema/testdata/go_comments.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://github.com/conneroisu/groq-go/internal/schema/examples/user", 4 | "$ref": "#/$defs/User", 5 | "$defs": { 6 | "NamedPets": { 7 | "additionalProperties": { 8 | "$ref": "#/$defs/Pet" 9 | }, 10 | "type": "object", 11 | "description": "NamedPets is a map of animal names to pets." 12 | }, 13 | "Pet": { 14 | "properties": { 15 | "name": { 16 | "type": "string", 17 | "title": "Name", 18 | "description": "Name of the animal." 19 | } 20 | }, 21 | "additionalProperties": false, 22 | "type": "object", 23 | "required": [ 24 | "name" 25 | ], 26 | "description": "Pet defines the user's fury friend." 27 | }, 28 | "Pets": { 29 | "items": { 30 | "$ref": "#/$defs/Pet" 31 | }, 32 | "type": "array", 33 | "description": "Pets is a collection of Pet objects." 34 | }, 35 | "Plant": { 36 | "properties": { 37 | "variant": { 38 | "type": "string", 39 | "title": "Variant", 40 | "description": "This comment will be used" 41 | }, 42 | "multicellular": { 43 | "type": "boolean", 44 | "title": "Multicellular", 45 | "description": "Multicellular is true if the plant is multicellular" 46 | } 47 | }, 48 | "additionalProperties": false, 49 | "type": "object", 50 | "required": [ 51 | "variant" 52 | ], 53 | "description": "Plant represents the plants the user might have and serves as a test of structs inside a `type` set." 54 | }, 55 | "User": { 56 | "properties": { 57 | "id": { 58 | "type": "integer", 59 | "description": "Unique sequential identifier." 60 | }, 61 | "name": { 62 | "type": "string", 63 | "maxLength": 20, 64 | "minLength": 1, 65 | "pattern": ".*", 66 | "title": "the name", 67 | "description": "this is a property", 68 | "default": "alex", 69 | "examples": [ 70 | "joe", 71 | "lucy" 72 | ] 73 | }, 74 | "friends": { 75 | "items": { 76 | "type": "integer" 77 | }, 78 | "type": "array", 79 | "description": "list of IDs, omitted when empty" 80 | }, 81 | "tags": { 82 | "type": "object" 83 | }, 84 | "pets": { 85 | "$ref": "#/$defs/Pets", 86 | "description": "An array of pets the user cares for." 87 | }, 88 | "named_pets": { 89 | "$ref": "#/$defs/NamedPets", 90 | "description": "Set of animal names to pets" 91 | }, 92 | "plants": { 93 | "items": { 94 | "$ref": "#/$defs/Plant" 95 | }, 96 | "type": "array", 97 | "title": "Plants", 98 | "description": "Set of plants that the user likes" 99 | } 100 | }, 101 | "additionalProperties": false, 102 | "type": "object", 103 | "required": [ 104 | "id", 105 | "name", 106 | "pets", 107 | "named_pets", 108 | "plants" 109 | ], 110 | "description": "User is used as a base to provide tests for comments." 111 | } 112 | } 113 | } -------------------------------------------------------------------------------- /extensions/composio/auth.go: -------------------------------------------------------------------------------- 1 | package composio 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net/http" 7 | "net/url" 8 | "time" 9 | 10 | "github.com/conneroisu/groq-go/pkg/builders" 11 | ) 12 | 13 | type ( 14 | // Authorizer is an interface for composio auth. 15 | Authorizer interface { 16 | GetConnectedAccounts(ctx context.Context, opts ...AuthOption) ([]ConnectedAccount, error) 17 | } 18 | // ConnectedAccount represents a composio connected account. 19 | // 20 | // Gotten from similar url to: https://backend.composio.dev/api/v1/connectedAccounts?user_uuid=default&showActiveOnly=true 21 | ConnectedAccount struct { 22 | IntegrationID string `json:"integrationId"` 23 | ConnectionParams struct { 24 | Scope string `json:"scope"` 25 | Scopes []string `json:"scopes"` 26 | BaseURL string `json:"base_url"` 27 | ClientID string `json:"client_id"` 28 | TokenType string `json:"token_type"` 29 | RedirectURL string `json:"redirectUrl"` 30 | AccessToken string `json:"access_token"` 31 | CallbackURL string `json:"callback_url"` 32 | ClientSecret string `json:"client_secret"` 33 | CodeVerifier string `json:"code_verifier"` 34 | FinalRedirectURI string `json:"finalRedirectUri"` 35 | } `json:"connectionParams"` 36 | IsDisabled bool `json:"isDisabled"` 37 | ID string `json:"id"` 38 | MemberID string `json:"memberId"` 39 | ClientUniqueUserID string `json:"clientUniqueUserId"` 40 | Status string `json:"status"` 41 | Enabled bool `json:"enabled"` 42 | CreatedAt time.Time `json:"createdAt"` 43 | UpdatedAt time.Time `json:"updatedAt"` 44 | Member struct { 45 | ID string `json:"id"` 46 | ClientID string `json:"clientId"` 47 | Email string `json:"email"` 48 | Name string `json:"name"` 49 | Role string `json:"role"` 50 | Metadata any `json:"metadata"` 51 | CreatedAt time.Time `json:"createdAt"` 52 | UpdatedAt time.Time `json:"updatedAt"` 53 | DeletedAt any `json:"deletedAt"` 54 | } `json:"member"` 55 | AppUniqueID string `json:"appUniqueId"` 56 | AppName string `json:"appName"` 57 | Logo string `json:"logo"` 58 | IntegrationIsDisabled bool `json:"integrationIsDisabled"` 59 | IntegrationDisabledReason string `json:"integrationDisabledReason"` 60 | InvocationCount string `json:"invocationCount"` 61 | } 62 | ) 63 | 64 | // GetConnectedAccounts returns the connected accounts for the composio client. 65 | func (c *Composio) GetConnectedAccounts( 66 | ctx context.Context, 67 | opts ...AuthOption, 68 | ) ([]ConnectedAccount, error) { 69 | uri := fmt.Sprintf("%s/v1/connectedAccounts", c.baseURL) 70 | u, err := url.Parse(uri) 71 | if err != nil { 72 | return nil, err 73 | } 74 | urlValues := u.Query() 75 | urlValues.Add("user_uuid", "default") 76 | urlValues.Add("showActiveOnly", "true") 77 | for _, opt := range opts { 78 | opt(&urlValues) 79 | } 80 | u.RawQuery = urlValues.Encode() 81 | uri = u.String() 82 | c.logger.Debug("auth", "url", uri) 83 | req, err := builders.NewRequest( 84 | ctx, 85 | c.header, 86 | http.MethodGet, 87 | uri, 88 | builders.WithBody(nil), 89 | ) 90 | if err != nil { 91 | return nil, err 92 | } 93 | var caItems struct { 94 | Items []ConnectedAccount `json:"items"` 95 | } 96 | err = c.doRequest(req, &caItems) 97 | return caItems.Items, err 98 | } 99 | -------------------------------------------------------------------------------- /cmd/generate-models/template.tmpl: -------------------------------------------------------------------------------- 1 | {{define "header"}} 2 | // Code generated by groq-modeler DO NOT EDIT. 3 | // 4 | // Created at: {{ getCurrentDate }} 5 | // 6 | // groq-modeler Version 1.1.2 7 | {{end}} 8 | 9 | {{define "models"}} 10 | {{template "header" .}} 11 | package groq 12 | 13 | type ( 14 | // Model is a ai model accessible through the groq api. 15 | Model string 16 | 17 | // ChatModel is the type for chat models present on the groq api. 18 | ChatModel Model 19 | 20 | // ModerationModel is the type for moderation models present on the groq api. 21 | ModerationModel Model 22 | 23 | // AudioModel is the type for audio models present on the groq api. 24 | AudioModel Model 25 | ) 26 | 27 | var ( 28 | {{- range $model := .ChatModels }} 29 | // Model{{ $model.Name }} is an AI text chat model. 30 | // 31 | // It is created/provided by {{$model.OwnedBy}}. 32 | // 33 | // It has {{$model.ContextWindow}} context window. 34 | // 35 | // It can be used with the following client methods: 36 | // - ChatCompletion 37 | // - ChatCompletionStream 38 | // - ChatCompletionJSON 39 | Model{{ $model.Name }} ChatModel = "{{ $model.ID }}" 40 | {{- end }} 41 | 42 | {{- range $model := .AudioModels }} 43 | // Model{{ $model.Name }} is an AI audio transcription model. 44 | // 45 | // It is created/provided by {{$model.OwnedBy}}. 46 | // 47 | // It has {{$model.ContextWindow}} context window. 48 | // 49 | // It can be used with the following client methods: 50 | // - CreateTranscription 51 | // - CreateTranslation 52 | Model{{ $model.Name }} AudioModel = "{{ $model.ID }}" 53 | {{- end }} 54 | {{- range $model := .ModerationModels }} 55 | // Model{{ $model.Name }} is an AI moderation model. 56 | // 57 | // It is created/provided by {{$model.OwnedBy}}. 58 | // 59 | // It has {{$model.ContextWindow}} context window. 60 | // 61 | // It can be used with the following client methods: 62 | // - Moderate 63 | Model{{ $model.Name }} ModerationModel = "{{ $model.ID }}" 64 | {{- end }} 65 | ) 66 | {{end}} 67 | 68 | {{define "models_test"}} 69 | {{template "header" .}} 70 | package groq_test 71 | 72 | import ( 73 | "context" 74 | "os" 75 | "testing" 76 | "time" 77 | 78 | "github.com/conneroisu/groq-go" 79 | "github.com/conneroisu/groq-go/internal/test" 80 | "github.com/stretchr/testify/assert" 81 | 82 | _ "embed" 83 | ) 84 | 85 | //go:embed testdata/whisper.mp3 86 | var whisperBytes []byte 87 | 88 | {{- range $model := .ChatModels }} 89 | // TestChatModels{{ $model.Name }} tests the {{ $model.Name }} model. 90 | // 91 | // It ensures that the model is supported by the groq-go library and the groq 92 | // API. // and the operations are working as expected for the specific model type. 93 | func TestChatModels{{ $model.Name }}(t *testing.T) { 94 | if len(os.Getenv("UNIT")) < 1 { 95 | t.Skip("Skipping {{ $model.Name }} test") 96 | } 97 | a := assert.New(t) 98 | ctx := context.Background() 99 | apiKey, err := test.GetAPIKey("GROQ_KEY") 100 | a.NoError(err, "GetAPIKey error") 101 | client, err := groq.NewClient(apiKey) 102 | a.NoError(err, "NewClient error") 103 | response, err := client.ChatCompletion(ctx, groq.ChatCompletionRequest{ 104 | Model: groq.Model{{ $model.Name }}, 105 | Messages: []groq.ChatCompletionMessage{ 106 | { 107 | Role: groq.RoleUser, 108 | Content: "What is a proface display?", 109 | }, 110 | }, 111 | MaxTokens: 10, 112 | RetryDelay: time.Second * 2, 113 | }) 114 | a.NoError(err, "ChatCompletionJSON error") 115 | if len(response.Choices[0].Message.Content) == 0 { 116 | t.Errorf("response.Choices[0].Message.Content is empty for model {{ $model.Name }} calling ChatCompletion") 117 | } 118 | } 119 | {{- end }} 120 | {{end}} 121 | -------------------------------------------------------------------------------- /extensions/composio/run_test.go: -------------------------------------------------------------------------------- 1 | package composio_test 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "net/http" 7 | "os" 8 | "testing" 9 | 10 | "github.com/conneroisu/groq-go" 11 | "github.com/conneroisu/groq-go/extensions/composio" 12 | "github.com/conneroisu/groq-go/internal/test" 13 | "github.com/conneroisu/groq-go/pkg/tools" 14 | "github.com/stretchr/testify/assert" 15 | ) 16 | 17 | func TestRun(t *testing.T) { 18 | a := assert.New(t) 19 | ctx := context.Background() 20 | ts := test.NewTestServer() 21 | ts.RegisterHandler("/v1/connectedAccounts", func(w http.ResponseWriter, _ *http.Request) { 22 | var items struct { 23 | Items []composio.ConnectedAccount `json:"items"` 24 | } 25 | items.Items = append(items.Items, composio.ConnectedAccount{ 26 | IntegrationID: "INTEGRATION_ID", 27 | ID: "ID", 28 | MemberID: "MEMBER_ID", 29 | ClientUniqueUserID: "CLIENT_UNIQUE_USER_ID", 30 | Status: "STATUS", 31 | AppUniqueID: "APP_UNIQUE_ID", 32 | AppName: "APP_NAME", 33 | InvocationCount: "INVOCATION_COUNT", 34 | }) 35 | w.Header().Set("Content-Type", "application/json") 36 | w.WriteHeader(http.StatusOK) 37 | jsonBytes, err := json.Marshal(items) 38 | a.NoError(err) 39 | _, err = w.Write(jsonBytes) 40 | a.NoError(err) 41 | }) 42 | ts.RegisterHandler("/v2/actions/TOOL/execute", func(w http.ResponseWriter, _ *http.Request) { 43 | w.Header().Set("Content-Type", "application/json") 44 | w.WriteHeader(http.StatusOK) 45 | _, err := w.Write([]byte(`response1`)) 46 | a.NoError(err) 47 | }) 48 | testS := ts.ComposioTestServer() 49 | testS.Start() 50 | client, err := composio.NewComposer( 51 | test.GetTestToken(), 52 | composio.WithLogger(test.DefaultLogger), 53 | composio.WithBaseURL(testS.URL), 54 | ) 55 | a.NoError(err) 56 | ca, err := client.GetConnectedAccounts(ctx, composio.WithShowActiveOnly(true)) 57 | a.NoError(err) 58 | resp, err := client.Run(ctx, ca[0], groq.ChatCompletionResponse{ 59 | Choices: []groq.ChatCompletionChoice{{ 60 | Message: groq.ChatCompletionMessage{ 61 | Role: groq.RoleUser, 62 | Content: "Hello!", 63 | ToolCalls: []tools.ToolCall{{ 64 | Function: tools.FunctionCall{ 65 | Name: "TOOL", 66 | Arguments: `{ "foo": "bar", }`, 67 | }}}}, 68 | FinishReason: groq.ReasonFunctionCall, 69 | }}}) 70 | a.NoError(err) 71 | assert.Equal(t, "response1", resp[0].Content) 72 | } 73 | 74 | func TestUnitRun(t *testing.T) { 75 | if !test.IsIntegrationTest() { 76 | t.Skip() 77 | } 78 | a := assert.New(t) 79 | ctx := context.Background() 80 | key, err := test.GetAPIKey("COMPOSIO_API_KEY") 81 | a.NoError(err) 82 | client, err := composio.NewComposer( 83 | key, 84 | composio.WithLogger(test.DefaultLogger), 85 | ) 86 | a.NoError(err) 87 | ts, err := client.GetTools( 88 | ctx, composio.WithApp("GITHUB"), composio.WithUseCase("StarRepo")) 89 | a.NoError(err) 90 | a.NotEmpty(ts) 91 | groqClient, err := groq.NewClient( 92 | os.Getenv("GROQ_KEY"), 93 | ) 94 | a.NoError(err, "NewClient error") 95 | response, err := groqClient.ChatCompletion(ctx, groq.ChatCompletionRequest{ 96 | Model: groq.ModelLlama3Groq8B8192ToolUsePreview, 97 | Messages: []groq.ChatCompletionMessage{ 98 | { 99 | Role: groq.RoleUser, 100 | Content: "Star the facebookresearch/spiritlm repository on GitHub", 101 | }, 102 | }, 103 | MaxTokens: 2000, 104 | Tools: ts, 105 | }) 106 | a.NoError(err) 107 | a.NotEmpty(response.Choices[0].Message.ToolCalls) 108 | users, err := client.GetConnectedAccounts(ctx) 109 | a.NoError(err) 110 | resp2, err := client.Run(ctx, users[0], response) 111 | a.NoError(err) 112 | a.NotEmpty(resp2) 113 | t.Logf("%+v\n", resp2) 114 | } 115 | -------------------------------------------------------------------------------- /internal/test/failer_test.go: -------------------------------------------------------------------------------- 1 | //go:build !test 2 | // +build !test 3 | 4 | package test_test 5 | 6 | import ( 7 | "errors" 8 | "testing" 9 | 10 | "github.com/conneroisu/groq-go/internal/test" 11 | ) 12 | 13 | // TestErrTestErrorAccumulatorWriteFailed_Error tests the Error method of ErrTestErrorAccumulatorWriteFailed. 14 | func TestErrTestErrorAccumulatorWriteFailed_Error(t *testing.T) { 15 | err := test.ErrTestErrorAccumulatorWriteFailed{} 16 | expected := "test error accumulator failed" 17 | 18 | if err.Error() != expected { 19 | t.Errorf("Error() returned %q, expected %q", err.Error(), expected) 20 | } 21 | } 22 | 23 | // TestFailingErrorBuffer_Write tests the Write method of FailingErrorBuffer with various inputs. 24 | func TestFailingErrorBuffer_Write(t *testing.T) { 25 | buf := &test.FailingErrorBuffer{} 26 | 27 | testCases := []struct { 28 | name string 29 | input []byte 30 | }{ 31 | {"nil slice", nil}, 32 | {"empty slice", []byte{}}, 33 | {"non-empty slice", []byte("test data")}, 34 | {"large slice", make([]byte, 1000)}, 35 | } 36 | 37 | for _, tc := range testCases { 38 | t.Run(tc.name, func(t *testing.T) { 39 | n, err := buf.Write(tc.input) 40 | if n != 0 { 41 | t.Errorf("Write(%q) returned n=%d, expected n=0", tc.input, n) 42 | } 43 | if !errors.Is(err, test.ErrTestErrorAccumulatorWriteFailed{}) { 44 | t.Errorf( 45 | "Write(%q) returned err=%v, expected ErrTestErrorAccumulatorWriteFailed{}", 46 | tc.input, 47 | err, 48 | ) 49 | } 50 | }) 51 | } 52 | } 53 | 54 | // TestFailingErrorBuffer_Len tests the Len method of FailingErrorBuffer. 55 | func TestFailingErrorBuffer_Len(t *testing.T) { 56 | buf := &test.FailingErrorBuffer{} 57 | 58 | length := buf.Len() 59 | if length != 0 { 60 | t.Errorf("Len() returned %d, expected 0", length) 61 | } 62 | 63 | // After Write calls 64 | _, _ = buf.Write([]byte("test")) 65 | length = buf.Len() 66 | if length != 0 { 67 | t.Errorf("Len() after Write returned %d, expected 0", length) 68 | } 69 | } 70 | 71 | // TestFailingErrorBuffer_Bytes tests the Bytes method of FailingErrorBuffer. 72 | func TestFailingErrorBuffer_Bytes(t *testing.T) { 73 | buf := &test.FailingErrorBuffer{} 74 | 75 | bytes := buf.Bytes() 76 | if len(bytes) != 0 { 77 | t.Errorf( 78 | "Bytes() returned %v (len=%d), expected empty byte slice", 79 | bytes, 80 | len(bytes), 81 | ) 82 | } 83 | 84 | // After Write calls 85 | _, _ = buf.Write([]byte("test")) 86 | bytes = buf.Bytes() 87 | if len(bytes) != 0 { 88 | t.Errorf( 89 | "Bytes() after Write returned %v (len=%d), expected empty byte slice", 90 | bytes, 91 | len(bytes), 92 | ) 93 | } 94 | } 95 | 96 | // TestFailingErrorBuffer_MultipleWrites tests multiple Write calls to FailingErrorBuffer. 97 | func TestFailingErrorBuffer_MultipleWrites(t *testing.T) { 98 | buf := &test.FailingErrorBuffer{} 99 | 100 | for i := range 5 { 101 | n, err := buf.Write([]byte("data")) 102 | if n != 0 { 103 | t.Errorf("Write call %d returned n=%d, expected n=0", i+1, n) 104 | } 105 | if !errors.Is(err, test.ErrTestErrorAccumulatorWriteFailed{}) { 106 | t.Errorf( 107 | "Write call %d returned err=%v, expected ErrTestErrorAccumulatorWriteFailed{}", 108 | i+1, 109 | err, 110 | ) 111 | } 112 | } 113 | 114 | if buf.Len() != 0 { 115 | t.Errorf( 116 | "Len() after multiple Writes returned %d, expected 0", 117 | buf.Len(), 118 | ) 119 | } 120 | 121 | if len(buf.Bytes()) != 0 { 122 | t.Errorf( 123 | "Bytes() after multiple Writes returned len=%d, expected 0", 124 | len(buf.Bytes()), 125 | ) 126 | } 127 | } 128 | 129 | var _ error = test.ErrTestErrorAccumulatorWriteFailed{} 130 | var _ interface{ Write([]byte) (int, error) } = &test.FailingErrorBuffer{} 131 | var _ interface{ Len() int } = &test.FailingErrorBuffer{} 132 | var _ interface{ Bytes() []byte } = &test.FailingErrorBuffer{} 133 | --------------------------------------------------------------------------------