From ce6fd1b4a0eb1306355703101090147425efab5a Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Thu, 22 May 2025 23:40:01 +0200 Subject: [PATCH 1/4] add option for port and https + example for ollama usage and setting --- src/LLM-API/LLMAPI.class.st | 89 +++++++++++++++++++++++++++------ src/LLM-API/LLMAPIChat.class.st | 22 ++++++++ 2 files changed, 95 insertions(+), 16 deletions(-) diff --git a/src/LLM-API/LLMAPI.class.st b/src/LLM-API/LLMAPI.class.st index 841eb16..669154c 100644 --- a/src/LLM-API/LLMAPI.class.st +++ b/src/LLM-API/LLMAPI.class.st @@ -6,11 +6,14 @@ Class { 'port', 'client', 'content', - 'apiKey' + 'apiKey', + 'https' ], #classInstVars : [ 'apiKey', - 'host' + 'host', + 'port', + 'https' ], #category : 'LLM-API', #package : 'LLM-API' @@ -52,6 +55,18 @@ LLMAPI class >> host: anObject [ host := anObject ] +{ #category : 'accessing' } +LLMAPI class >> https [ + + ^ https +] + +{ #category : 'accessing' } +LLMAPI class >> https: aBoolean [ + + https := aBoolean +] + { #category : 'as yet unclassified' } LLMAPI class >> llmSettingOn: aBuilder [ @@ -60,18 +75,41 @@ LLMAPI class >> llmSettingOn: aBuilder [ parent: #tools; name: 'LLM API'; with: [ - (aBuilder setting: #apiKey) - order: -100000; - label: 'LLM API Key'; - target: self; - default: ''; - ghostHelp: 'My key'. - (aBuilder setting: #host) - order: 0; - label: 'LLM host'; - target: self; - default: 'api.mistral.ai'; - ghostHelp: 'api.mistral.ai' ] + (aBuilder setting: #apiKey) + order: -100000; + label: 'LLM API Key'; + target: self; + default: ''; + ghostHelp: 'My key'. + (aBuilder setting: #host) + order: 0; + label: 'LLM host'; + target: self; + default: 'api.mistral.ai'; + ghostHelp: 'api.mistral.ai'. + (aBuilder setting: #port) + order: 0; + label: 'LLM port'; + target: self; + default: 443; + ghostHelp: '443'. + (aBuilder setting: #https) + order: 0; + label: 'LLM host uses ssl (https)'; + target: self; + default: true ] +] + +{ #category : 'accessing' } +LLMAPI class >> port [ + + ^ port +] + +{ #category : 'accessing' } +LLMAPI class >> port: aPortNumber [ + + port := aPortNumber ] { #category : 'accessing' } @@ -122,6 +160,18 @@ LLMAPI >> host: anObject [ host := anObject ] +{ #category : 'accessing' } +LLMAPI >> https [ + + ^ https +] + +{ #category : 'accessing' } +LLMAPI >> https: aBoolean [ + + https := aBoolean +] + { #category : 'initialization' } LLMAPI >> initialize [ @@ -129,6 +179,9 @@ LLMAPI >> initialize [ client := ZnClient new. self apiKey: LLMAPI apiKey. self host: LLMAPI host. + self port: LLMAPI port. + self https: LLMAPI https. + ] { #category : 'accessing' } @@ -176,7 +229,11 @@ LLMAPI >> prepareRequest [ self apiKey ifNotNil: [ :_apiKey | client setBearerAuthentication: _apiKey ]. client forJsonREST. - client https. + self https + ifTrue: [ client https ] + ifFalse: [ client http ]. client host: self host. - client path: self path + client port: self port. + client path: self path. + ] diff --git a/src/LLM-API/LLMAPIChat.class.st b/src/LLM-API/LLMAPIChat.class.st index 2df7f40..fedd537 100644 --- a/src/LLM-API/LLMAPIChat.class.st +++ b/src/LLM-API/LLMAPIChat.class.st @@ -1,3 +1,25 @@ +" +# Example with ollama + +```st +api := LLMAPI chat. +api host: '127.0.0.1'. +api port: 11434. +api apiKey: nil. + +api payload + temperature: 0.5; + model: 'devstral'; + top_p: 1; + max_tokens: 250; + messages: { + LLMAPIChatObjectMessage role: 'system' content: 'You are a usefull assistant'. + LLMAPIChatObjectMessage role: 'user' content: 'How to write hello world in Pharo?'. + }. + +result := api performRequest. +``` +" Class { #name : 'LLMAPIChat', #superclass : 'LLMAPI', From dc20e33f144baabc7f2b3d8702d5488326d16dd5 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Fri, 23 May 2025 10:21:27 +0200 Subject: [PATCH 2/4] feat(test): add LLM-API-Tests package with initial tests for LLMAPIChat and LLMAPIFim - Added 'Mocketry' as a dependency in BaselineOfLLMAPI. - Introduced the 'LLM-API-Tests' package requiring 'LLM-API' and 'Mocketry'. - Implemented test cases for LLMAPIChatTest and LLMAPIFimTest, verifying instance creation. --- .../BaselineOfLLMAPI.class.st | 7 ++++- src/LLM-API-Tests/LLMAPIChatTest.class.st | 26 +++++++++++++++++++ src/LLM-API-Tests/LLMAPIFimTest.class.st | 23 ++++++++++++++++ src/LLM-API-Tests/package.st | 1 + 4 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/LLM-API-Tests/LLMAPIChatTest.class.st create mode 100644 src/LLM-API-Tests/LLMAPIFimTest.class.st create mode 100644 src/LLM-API-Tests/package.st diff --git a/src/BaselineOfLLMAPI/BaselineOfLLMAPI.class.st b/src/BaselineOfLLMAPI/BaselineOfLLMAPI.class.st index 2e2c7f3..b60f91a 100644 --- a/src/BaselineOfLLMAPI/BaselineOfLLMAPI.class.st +++ b/src/BaselineOfLLMAPI/BaselineOfLLMAPI.class.st @@ -20,7 +20,11 @@ BaselineOfLLMAPI >> defineDependencies: spec [ spec baseline: 'NeoJSON' - with: [ spec repository: 'github://svenvc/NeoJSON/repository' ] + with: [ spec repository: 'github://svenvc/NeoJSON/repository' ]. + + spec + baseline: 'Mocketry' + with: [ spec repository: 'github://dionisiydk/Mocketry' ] ] { #category : 'baselines' } @@ -31,6 +35,7 @@ BaselineOfLLMAPI >> defineGroups: spec [ BaselineOfLLMAPI >> definePackages: spec [ spec package: 'LLM-API' with: [ spec requires: #( 'NeoJSON' ) ]. + spec package: 'LLM-API-Tests' with: [ spec requires: #( 'LLM-API' 'Mocketry' ) ]. spec package: 'LLM-API-Example' with: [ spec requires: #( 'LLM-API' ) ]. spec package: 'LLM-Spec' with: [ spec requires: #( 'LLM-API' ) ] ] diff --git a/src/LLM-API-Tests/LLMAPIChatTest.class.st b/src/LLM-API-Tests/LLMAPIChatTest.class.st new file mode 100644 index 0000000..ca43b89 --- /dev/null +++ b/src/LLM-API-Tests/LLMAPIChatTest.class.st @@ -0,0 +1,26 @@ +" +A LLMAPIChatTest is a test class for testing the behavior of LLMAPIChat +" +Class { + #name : 'LLMAPIChatTest', + #superclass : 'TestCase', + #instVars : [ + 'api' + ], + #category : 'LLM-API-Tests', + #package : 'LLM-API-Tests' +} + +{ #category : 'running' } +LLMAPIChatTest >> setUp [ + + super setUp. + + api := LLMAPI chat +] + +{ #category : 'running' } +LLMAPIChatTest >> testCorrectInstance [ + + self assert: api class equals: LLMAPIChat +] diff --git a/src/LLM-API-Tests/LLMAPIFimTest.class.st b/src/LLM-API-Tests/LLMAPIFimTest.class.st new file mode 100644 index 0000000..64505f5 --- /dev/null +++ b/src/LLM-API-Tests/LLMAPIFimTest.class.st @@ -0,0 +1,23 @@ +Class { + #name : 'LLMAPIFimTest', + #superclass : 'TestCase', + #instVars : [ + 'api' + ], + #category : 'LLM-API-Tests', + #package : 'LLM-API-Tests' +} + +{ #category : 'running' } +LLMAPIFimTest >> setUp [ + + super setUp. + + api := LLMAPI fim +] + +{ #category : 'running' } +LLMAPIFimTest >> testCorrectInstance [ + + self assert: api class equals: LLMAPIFim +] diff --git a/src/LLM-API-Tests/package.st b/src/LLM-API-Tests/package.st new file mode 100644 index 0000000..206696e --- /dev/null +++ b/src/LLM-API-Tests/package.st @@ -0,0 +1 @@ +Package { #name : 'LLM-API-Tests' } From ac8bee1b0d99bf0dcc2fb1066170b29f666259a4 Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Fri, 23 May 2025 10:33:55 +0200 Subject: [PATCH 3/4] feat(LLM-API): add model check and error handling in request preparation --- src/LLM-API-Tests/LLMAPIChatTest.class.st | 6 ++++++ src/LLM-API-Tests/LLMAPIFimTest.class.st | 6 ++++++ src/LLM-API/LLMAPI.class.st | 9 ++++++--- src/LLM-API/LLMPayloadNoModelError.class.st | 13 +++++++++++++ 4 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 src/LLM-API/LLMPayloadNoModelError.class.st diff --git a/src/LLM-API-Tests/LLMAPIChatTest.class.st b/src/LLM-API-Tests/LLMAPIChatTest.class.st index ca43b89..7b26e95 100644 --- a/src/LLM-API-Tests/LLMAPIChatTest.class.st +++ b/src/LLM-API-Tests/LLMAPIChatTest.class.st @@ -19,6 +19,12 @@ LLMAPIChatTest >> setUp [ api := LLMAPI chat ] +{ #category : 'running' } +LLMAPIChatTest >> testCheckModelExist [ + + self should: [ api performRequest ] raise: LLMPayloadNoModelError +] + { #category : 'running' } LLMAPIChatTest >> testCorrectInstance [ diff --git a/src/LLM-API-Tests/LLMAPIFimTest.class.st b/src/LLM-API-Tests/LLMAPIFimTest.class.st index 64505f5..30ae864 100644 --- a/src/LLM-API-Tests/LLMAPIFimTest.class.st +++ b/src/LLM-API-Tests/LLMAPIFimTest.class.st @@ -16,6 +16,12 @@ LLMAPIFimTest >> setUp [ api := LLMAPI fim ] +{ #category : 'running' } +LLMAPIFimTest >> testCheckModelExist [ + + self should: [ api performRequest ] raise: LLMPayloadNoModelError +] + { #category : 'running' } LLMAPIFimTest >> testCorrectInstance [ diff --git a/src/LLM-API/LLMAPI.class.st b/src/LLM-API/LLMAPI.class.st index 669154c..8a481e2 100644 --- a/src/LLM-API/LLMAPI.class.st +++ b/src/LLM-API/LLMAPI.class.st @@ -225,15 +225,18 @@ LLMAPI >> port: anObject [ { #category : 'accessing' } LLMAPI >> prepareRequest [ + "check some properties" + (self payload model isNil or: [ self payload model isEmpty ]) + ifTrue: [ LLMPayloadNoModelError signal ]. + "Prepare request" self apiKey ifNotNil: [ :_apiKey | client setBearerAuthentication: _apiKey ]. client forJsonREST. - self https + (self https isNil or: [ self https ]) ifTrue: [ client https ] ifFalse: [ client http ]. client host: self host. client port: self port. - client path: self path. - + client path: self path ] diff --git a/src/LLM-API/LLMPayloadNoModelError.class.st b/src/LLM-API/LLMPayloadNoModelError.class.st new file mode 100644 index 0000000..4803d39 --- /dev/null +++ b/src/LLM-API/LLMPayloadNoModelError.class.st @@ -0,0 +1,13 @@ +Class { + #name : 'LLMPayloadNoModelError', + #superclass : 'Error', + #category : 'LLM-API', + #package : 'LLM-API' +} + +{ #category : 'default' } +LLMPayloadNoModelError >> defaultDescription [ + "Return a textual description of the exception." + + ^ 'No model set in the payload. Add a model before calling the API.' +] From 7f7f3bb94179f95da5555a18671d932a166174db Mon Sep 17 00:00:00 2001 From: Benoit Verhaeghe Date: Fri, 23 May 2025 13:41:19 +0200 Subject: [PATCH 4/4] Refactor: categorize `accessing` to `api` in LLM-API's performRequest --- src/LLM-API/LLMAPIChat.class.st | 2 +- src/LLM-API/LLMAPIFim.class.st | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LLM-API/LLMAPIChat.class.st b/src/LLM-API/LLMAPIChat.class.st index fedd537..9bbf317 100644 --- a/src/LLM-API/LLMAPIChat.class.st +++ b/src/LLM-API/LLMAPIChat.class.st @@ -38,7 +38,7 @@ LLMAPIChat >> payloadClass [ ^ LLMAPIChatObjectPayload ] -{ #category : 'accessing' } +{ #category : 'api' } LLMAPIChat >> performRequest [ | intermediateResult | diff --git a/src/LLM-API/LLMAPIFim.class.st b/src/LLM-API/LLMAPIFim.class.st index eddccd5..3ca049c 100644 --- a/src/LLM-API/LLMAPIFim.class.st +++ b/src/LLM-API/LLMAPIFim.class.st @@ -16,7 +16,7 @@ LLMAPIFim >> payloadClass [ ^ LLMAPIFimObjectPayload ] -{ #category : 'accessing' } +{ #category : 'api' } LLMAPIFim >> performRequest [ self prepareRequest.