entropy-machine 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,20 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Python
3
+
4
+ """Copyright (c) Alexander Fedotov.
5
+ This source code is licensed under the license found in the
6
+ LICENSE file in the root directory of this source tree.
7
+ """
8
+ from .config import Config
9
+ from .machine import machine
10
+ from .githf import fetch_instructions
11
+ from .utilities import (plato_text_to_muj,
12
+ plato_text_to_mpuj,
13
+ llm_soup_to_text,
14
+ new_plato_text)
15
+
16
+ __all__ = [
17
+ 'machine',
18
+ 'fetch_instructions',
19
+ 'Config'
20
+ ]
entropy_machine/cli.py ADDED
@@ -0,0 +1,159 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Python
3
+
4
+ """Copyright (c) Alexander Fedotov.
5
+ This source code is licensed under the license found in the
6
+ LICENSE file in the root directory of this source tree.
7
+ """
8
+ import os
9
+ import sys
10
+ import select
11
+ import fileinput
12
+ import argparse
13
+ import syslog
14
+ from .config import Config
15
+ from .utilities import new_plato_text
16
+
17
+
18
+ def options_and_arguments():
19
+ # Initialize the parser
20
+ parser = argparse.ArgumentParser(
21
+ description="Entropy-Machine thinks for you about the meanings.",
22
+ epilog="Example: entropy-machine input_text.txt > output_text.txt"
23
+ # thinking-machine -a multilogue.txt > tmp && mv tmp multilogue.txt
24
+ )
25
+
26
+ # Give the access key and token, or set the environment variables in advance.
27
+ parser.add_argument('-p', '--provider-api-key',
28
+ default=os.getenv('PROVIDER_API_KEY', 'no_key'),
29
+ help="LLM provider API key (defaults to $PROVIDER_API_KEY)")
30
+ parser.add_argument('-g', '--github-token',
31
+ default=os.getenv('GITHUB_TOKEN', 'no_token'),
32
+ help="GitHub API token (defaults to $GITHUB_TOKEN)")
33
+
34
+ parser.add_argument('-a', '--append',
35
+ action='store_true',
36
+ help="Append the utterance to the input.")
37
+
38
+ parser.add_argument('-d', '--debug',
39
+ action='store_true',
40
+ help="Debug flag.")
41
+
42
+ # Add the interactive flag
43
+ # parser.add_argument('-i', '--interactive',
44
+ # action='store_true',
45
+ # help="Enable interactive mode (defaults to False)")
46
+
47
+ # Positional arguments (files)
48
+ # '*' captures zero or more arguments into a list, nargs='+' one or more.
49
+ parser.add_argument('filenames',
50
+ nargs='*',
51
+ help="Zero (when text comes though a pipe) or more files to process.")
52
+ return parser
53
+
54
+
55
+ def run():
56
+ """
57
+ $ text | entropy-machine # Accepts text from the pipe
58
+ $ echo "...<text>..." | entropy-machine #
59
+
60
+ $ entropy-machine multilogue.txt new_turn.txt # ...or files.
61
+ """
62
+
63
+ args = options_and_arguments().parse_args()
64
+
65
+ # If no files are provided AND no data is being piped in - exit.
66
+ if not args.filenames:
67
+ # Check if stdin (fd 0) is ready to be read
68
+ readable, _, _ = select.select([sys.stdin], [], [], 0.1)
69
+ if not readable:
70
+ print("Error: No input files or piped text stream.")
71
+ options_and_arguments().print_help()
72
+ sys.exit(1)
73
+
74
+ config = Config()
75
+
76
+ if args.provider_api_key:
77
+ if args.provider_api_key.startswith('sk-'):
78
+ if args.provider_api_key.startswith('sk-proj-'):
79
+ config.provider = 'OpenAI'
80
+ os.environ['OPENAI_API_KEY'] = args.provider_api_key
81
+ elif args.provider_api_key.startswith('sk-ant-'):
82
+ config.provider = 'Anthropic'
83
+ os.environ['ANTHROPIC_API_KEY'] = args.provider_api_key
84
+ else:
85
+ config.provider = 'DepSek'
86
+ os.environ['DEPSEK_API_KEY'] = args.provider_api_key
87
+ elif args.provider_api_key.startswith('AIzaSy'):
88
+ config.provider = 'Gemini'
89
+ os.environ['GEMINI_API_KEY'] = args.provider_api_key
90
+ elif args.provider_api_key.startswith('gsk_'):
91
+ config.provider = 'Groq'
92
+ os.environ['GROQ_API_KEY'] = args.provider_api_key
93
+ elif args.provider_api_key.startswith('xai-'):
94
+ config.provider = 'XAI'
95
+ os.environ['XAI_API_KEY'] = args.provider_api_key
96
+ elif args.provider_api_key.startswith('LLM'):
97
+ config.provider = 'MetAI'
98
+ os.environ['METAI_API_KEY'] = args.provider_api_key
99
+ elif args.provider_api_key == 'no_provider_key':
100
+ sys.stderr.write(f'No provider key!\n')
101
+ sys.stderr.flush()
102
+ sys.exit(1)
103
+ else:
104
+ if config.provider == '':
105
+ raise ValueError(f"Unrecognized API key prefix and no provider specified.")
106
+ else:
107
+ if config.provider == 'Baseten':
108
+ os.environ['BASETEN_API_KEY'] = args.provider_api_key
109
+ elif config.provider == 'Fireworks':
110
+ os.environ['FIREWORKS_API_KEY'] = args.provider_api_key
111
+ else:
112
+ raise ValueError(f"Unsupported provider specified.")
113
+
114
+ config.provider_api_key = args.provider_api_key
115
+
116
+ if args.github_token:
117
+ config.github_token = args.github_token
118
+ os.environ['GITHUB_TOKEN'] = args.github_token
119
+
120
+ # Ingest files line by line. Join is here for long files.
121
+ lines = []
122
+ for line in fileinput.input(files=args.filenames or ['-'], encoding="utf-8"):
123
+ lines.append(line)
124
+ raw_input = "".join(lines)
125
+
126
+ from .machine import machine
127
+
128
+ try:
129
+ thoughts, text = machine(raw_input, config)
130
+ output = new_plato_text(thoughts, text, config.name)
131
+ if args.append:
132
+ output = raw_input +'\n\n' + output
133
+ sys.stdout.write(output)
134
+ sys.stdout.flush()
135
+
136
+ # Assesment and signals.
137
+ utterance = "My answer is ready"
138
+ # Open syslog connection
139
+ syslog.openlog(
140
+ ident="entropy-machine",
141
+ logoption=syslog.LOG_NDELAY,
142
+ facility=syslog.LOG_USER
143
+ )
144
+ # Signal (single line less than 4096 only!)
145
+ syslog.syslog(syslog.LOG_INFO, f"entropy-machine: {utterance}.")
146
+ syslog.closelog()
147
+
148
+ except Exception as e:
149
+ if args.debug:
150
+ import traceback
151
+ traceback.print_exc()
152
+ else:
153
+ sys.stderr.write(f'Machine did not work {e}\n')
154
+ sys.stderr.flush()
155
+ sys.exit(1)
156
+
157
+
158
+ if __name__ == '__main__':
159
+ run()
@@ -0,0 +1,32 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Python
3
+
4
+ """Copyright (c) Alexander Fedotov.
5
+ This source code is licensed under the license found in the
6
+ LICENSE file in the root directory of this source tree.
7
+ """
8
+ from os import environ
9
+ from dataclasses import dataclass, field, asdict
10
+
11
+
12
+ @dataclass
13
+ class Config:
14
+ github_token: str = field(default_factory=lambda: environ.get('GITHUB_TOKEN', ''))
15
+ github_name: str = field(default_factory=lambda: environ.get('GITHUB_NAME', ''))
16
+ github_email: str = field(default_factory=lambda: environ.get('GITHUB_EMAIL', ''))
17
+ provider_api_key: str = field(default_factory=lambda: environ.get('PROVIDER_API_KEY', ''))
18
+ provider: str = field(default_factory=lambda: environ.get('PROVIDER', ''))
19
+ machine_organization_name: str = field(default_factory=lambda: environ.get('MACHINE_ORGANIZATION_NAME', 'entropy-machine'))
20
+ private_repo_with_text: str = field(default_factory=lambda: environ.get('PRIVATE_REPO_WITH_TEXT','entropy_machine'))
21
+ system_prompt_file: str = field(default_factory=lambda: environ.get('SYSTEM_PROMPT_FILE', 'machina.yaml'))
22
+ name: str = ''
23
+ instructions: str = ''
24
+ verb: str = ''
25
+
26
+ def to_dict(self):
27
+ return asdict(self)
28
+
29
+ def update_from_dict(self, data: dict):
30
+ for key, value in data.items():
31
+ if hasattr(self, key):
32
+ setattr(self, key, value)
@@ -0,0 +1,69 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Python
3
+
4
+ """Copyright (c) Alexander Fedotov.
5
+ This source code is licensed under the license found in the
6
+ LICENSE file in the root directory of this source tree.
7
+ """
8
+ import sys
9
+ from os import path
10
+ import yaml
11
+ import urllib.request
12
+ import urllib.error
13
+
14
+
15
+ def download_github_file(owner, repo, file_path, token):
16
+ """
17
+ Downloads a file from a GitHub repository using the GitHub REST API.
18
+ We request the raw content by using the 'application/vnd.github.v3.raw' accept header.
19
+ """
20
+ url = f"https://api.github.com/repos/{owner}/{repo}/contents/{file_path}"
21
+
22
+ headers = {
23
+ "Authorization": f"token {token}",
24
+ "Accept": "application/vnd.github.v3.raw",
25
+ "User-Agent": "Entropy-Machine"
26
+ }
27
+
28
+ req = urllib.request.Request(url, headers=headers)
29
+
30
+ try:
31
+ with urllib.request.urlopen(req, timeout=10) as response:
32
+ return response.read()
33
+ except urllib.error.HTTPError as e:
34
+ print(f"HTTP Error {e.code}: {e.reason}")
35
+ error_info = e.read().decode('utf-8')
36
+ print(f"Details: {error_info}")
37
+ return None
38
+ except urllib.error.URLError as e:
39
+ print(f"URL Error: {e.reason}")
40
+ return None
41
+
42
+
43
+ def fetch_instructions(config):
44
+ """Retrieve the system prompt from a private GitHub repo.
45
+ Falls back to the local machina.yaml if GitHub is unreachable.
46
+ Returns the 'name' of the Machine in dashed format.
47
+ Returns the 'description' field from the YAML as the system prompt string.
48
+ """
49
+ try:
50
+ raw_yaml = download_github_file(
51
+ owner=config.machine_organization_name,
52
+ repo=config.private_repo_with_text,
53
+ file_path=config.system_prompt_file,
54
+ token=config.github_token
55
+ )
56
+ except Exception as e:
57
+ print(f"Warning: could not fetch the instructions from GitHub: {e}",
58
+ file=sys.stderr)
59
+ local_path = path.join(path.dirname(__file__), 'machina.yaml')
60
+ with open(local_path, 'r') as f:
61
+ raw_yaml = f.read()
62
+
63
+ # Parse
64
+ parsed = yaml.safe_load(raw_yaml)
65
+ name = parsed.get('name')
66
+ config.name = name
67
+ instructions = parsed.get('description', 'You are a helpful assistant.')
68
+ config.instructions = instructions
69
+ return name, instructions
@@ -0,0 +1,7 @@
1
+ # Copyright (c) Alexander Fedotov, 2026. All rights reserved.
2
+ name: Entropy-Machine
3
+ description: The Assistant is Entropy-Machine. Entropy-Machine does its best to understand
4
+ the conversation that it is participating in and answers in a most thoughtful way possible
5
+ the questions that it is being asked.
6
+ Entropy-Machine responds in plain text without any markdown, emphasis or lists. All
7
+ paragraphs except the first should begin with a newline and tab.
@@ -0,0 +1,217 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Python
3
+
4
+ """Copyright (c) Alexander Fedotov.
5
+ This source code is licensed under the license found in the
6
+ LICENSE file in the root directory of this source tree.
7
+ """
8
+ import sys
9
+ from os import environ, path
10
+ from .githf import fetch_instructions
11
+ from .utilities import (plato_text_to_muj,
12
+ plato_text_to_mpuj,
13
+ plato_text_to_cmj,
14
+ llm_soup_to_text)
15
+
16
+
17
+ def machine(plato_text, config, **kwargs):
18
+ """
19
+ """
20
+ # Fetch the confidential system prompt, name is for a checkup.
21
+ name, system_prompt = fetch_instructions(config)
22
+
23
+ # Load an appropriate library and query the API.
24
+ provider = config.provider
25
+ api_key = config.provider_api_key
26
+
27
+ if provider == 'OpenAI':
28
+ # Transform plato_text to MUJ format
29
+ messages = plato_text_to_muj(plato_text=plato_text,
30
+ machine_name=name)
31
+ # Call OpenAI API
32
+ environ['OPENAI_API_KEY'] = api_key
33
+ try:
34
+ from .providers import openai
35
+ except ImportError:
36
+ print("openai module is missing.", file=sys.stderr)
37
+ sys.exit(1)
38
+
39
+ thoughts, text = openai.respond(
40
+ messages=messages,
41
+ instructions=system_prompt,
42
+ **kwargs
43
+ )
44
+
45
+ thoughts = llm_soup_to_text(thoughts)
46
+ return thoughts, text
47
+
48
+ elif provider == 'Gemini':
49
+ # Transform plato_text to MPUJ format
50
+ messages = plato_text_to_mpuj(plato_text=plato_text,
51
+ machine_name=name)
52
+ # Call Gemini API
53
+ environ['GEMINI_API_KEY'] = api_key
54
+ try:
55
+ from .providers import castor_pollux
56
+ except ImportError:
57
+ print("No module castor-pollux", file=sys.stderr)
58
+ sys.exit(1)
59
+
60
+ thoughts, text = castor_pollux.respond(
61
+ messages=messages,
62
+ instructions=system_prompt,
63
+ **kwargs
64
+ )
65
+
66
+ thoughts = llm_soup_to_text(thoughts)
67
+ return thoughts, text
68
+
69
+ elif provider == 'Anthropic':
70
+ # Transform plato_text to MUJ format
71
+ messages = plato_text_to_muj(plato_text=plato_text,
72
+ machine_name=name)
73
+
74
+ # Call the Anthropic API via electroid
75
+ environ['ANTHROPIC_API_KEY'] = api_key
76
+ try:
77
+ from .providers import electroid
78
+ except ImportError:
79
+ print("no electroid module", file=sys.stderr)
80
+ sys.exit(1)
81
+
82
+ text, thoughts = electroid.respond(
83
+ messages=messages,
84
+ instructions=system_prompt,
85
+ **kwargs
86
+ )
87
+ return text, thoughts
88
+
89
+ elif provider == 'Groq':
90
+ # Transform plato_text to MUJ format
91
+ messages = plato_text_to_muj(plato_text=plato_text,
92
+ machine_name=name)
93
+ # Call OpenAI API via opehaina
94
+ environ['GROQ_API_KEY'] = api_key
95
+ try:
96
+ from .providers import qrog
97
+ except ImportError:
98
+ print("openai module is missing.", file=sys.stderr)
99
+ sys.exit(1)
100
+
101
+ thoughts, text = qrog.respond(
102
+ messages=messages,
103
+ instructions=system_prompt,
104
+ **kwargs
105
+ )
106
+
107
+ thoughts = llm_soup_to_text(thoughts)
108
+ return thoughts, text
109
+
110
+ elif provider == 'Xai':
111
+ # Transform plato_text to MUJ format
112
+ messages = plato_text_to_muj(plato_text=plato_text,
113
+ machine_name=name)
114
+ # Call OpenAI API via opehaina
115
+ environ['XAI_API_KEY'] = api_key
116
+ try:
117
+ from .providers import strangelove
118
+ except ImportError:
119
+ print("openai module is missing.", file=sys.stderr)
120
+ sys.exit(1)
121
+
122
+ thoughts, text = strangelove.respond(
123
+ messages=messages,
124
+ instructions=system_prompt,
125
+ **kwargs
126
+ )
127
+
128
+ thoughts = llm_soup_to_text(thoughts)
129
+ return thoughts, text
130
+
131
+ elif provider == 'DepSek':
132
+ # Transform plato_text to CMJ format
133
+ messages = plato_text_to_cmj(plato_text=plato_text,
134
+ machine_name=name)
135
+ # Call OpenAI API via opehaina
136
+ environ['DEPSEK_API_KEY'] = api_key
137
+ try:
138
+ from .providers import depsek
139
+ except ImportError:
140
+ print("openai module is missing.", file=sys.stderr)
141
+ sys.exit(1)
142
+
143
+ thoughts, text = depsek.respond(
144
+ messages=messages,
145
+ instructions=system_prompt,
146
+ **kwargs
147
+ )
148
+
149
+ thoughts = llm_soup_to_text(thoughts)
150
+ return thoughts, text
151
+
152
+ elif provider == 'Baseten':
153
+ # Transform plato_text to CMJ format
154
+ messages = plato_text_to_cmj(plato_text=plato_text,
155
+ machine_name=name)
156
+ # Call OpenAI API via opehaina
157
+ environ['BASETEN_API_KEY'] = api_key
158
+ try:
159
+ from .providers import basta
160
+ except ImportError:
161
+ print("openai module is missing.", file=sys.stderr)
162
+ sys.exit(1)
163
+
164
+ thoughts, text = basta.respond(
165
+ messages=messages,
166
+ instructions=system_prompt,
167
+ **kwargs
168
+ )
169
+
170
+ thoughts = llm_soup_to_text(thoughts)
171
+ return thoughts, text
172
+
173
+ elif provider == 'MetAI':
174
+ # Transform plato_text to CMJ format
175
+ messages = plato_text_to_cmj(plato_text=plato_text,
176
+ machine_name=name)
177
+ # Call OpenAI API via opehaina
178
+ environ['METAI_API_KEY'] = api_key
179
+ try:
180
+ from .providers import metai
181
+ except ImportError:
182
+ print("metai module is missing.", file=sys.stderr)
183
+ sys.exit(1)
184
+
185
+ thoughts, text = metai.respond(
186
+ messages=messages,
187
+ instructions=system_prompt,
188
+ **kwargs
189
+ )
190
+
191
+ thoughts = llm_soup_to_text(thoughts)
192
+ return thoughts, text
193
+
194
+ if provider == 'Fireworks':
195
+ # Transform plato_text to MUJ format
196
+ messages = plato_text_to_muj(plato_text=plato_text,
197
+ machine_name=name)
198
+ # Call OpenAI API via opehaina
199
+ environ['FIREWORKS_API_KEY'] = api_key
200
+ try:
201
+ from .providers import illuminati
202
+ except ImportError:
203
+ print("illuminati module is missing.", file=sys.stderr)
204
+ sys.exit(1)
205
+
206
+ thoughts, text = illuminati.respond(
207
+ messages=messages,
208
+ instructions=system_prompt,
209
+ **kwargs
210
+ )
211
+
212
+ thoughts = llm_soup_to_text(thoughts)
213
+ return thoughts, text
214
+
215
+
216
+ if __name__ == '__main__':
217
+ print('You have launched main')
@@ -0,0 +1,7 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Python
3
+
4
+ """Copyright (c) Alexander Fedotov.
5
+ This source code is licensed under the license found in the
6
+ LICENSE file in the root directory of this source tree.
7
+ """
@@ -0,0 +1,82 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Python
3
+
4
+ """Copyright (c) Alexander Fedotov.
5
+ This source code is licensed under the license found in the
6
+ LICENSE file in the root directory of this source tree.
7
+ """
8
+ import urllib.request
9
+ import urllib.error
10
+ import json
11
+ from os import environ
12
+
13
+
14
+ def respond(messages, instructions, **kwargs):
15
+ """
16
+ """
17
+ api_key = environ.get("BASETEN_API_KEY")
18
+ api_base = environ.get("BASETEN_API_BASE", "https://inference.baseten.co/v1")
19
+ default_model = environ.get("BASETEN_DEFAULT_MODEL", "deepseek-ai/DeepSeek-V4-Pro")
20
+
21
+ instruction = kwargs.get('system_instruction', instructions)
22
+ first_message = [dict(role='system', content=instruction)] if instruction else []
23
+
24
+ # add contents and user text to the first (instruction) message
25
+ first_message.extend(messages)
26
+ instruction_and_contents = first_message
27
+
28
+ # Define the payload
29
+ payload = {
30
+ "model": kwargs.get("model", default_model),
31
+ "messages": instruction_and_contents,
32
+ "max_tokens": kwargs.get("max_tokens", 32000),
33
+ "temperature": kwargs.get("temperature", 1.0),
34
+ "reasoning_effort": kwargs.get("reasoning_effort", "max"),
35
+ "thinking": {
36
+ "type": "enabled"
37
+ }
38
+ }
39
+
40
+ # Convert data dictionary to JSON and encode it to bytes
41
+ data_bytes = json.dumps(payload).encode('utf-8')
42
+
43
+ # Set the mandatory headers
44
+ headers = {
45
+ "Content-Type": "application/json",
46
+ "Authorization": f"Api-Key {api_key}",
47
+ "User-Agent": "Entropy-Machine"
48
+ }
49
+
50
+ # Create the Request object
51
+ req = urllib.request.Request(
52
+ f'{api_base}/chat/completions',
53
+ data=data_bytes,
54
+ headers=headers,
55
+ method="POST")
56
+
57
+ try:
58
+ # Execute the request
59
+ with urllib.request.urlopen(req, timeout=300) as response:
60
+ response_data = response.read().decode('utf-8')
61
+ output = json.loads(response_data)
62
+ message = output['choices'][0]['message']
63
+ text = message['content']
64
+ thoughts = message['reasoning_content']
65
+
66
+ return thoughts, text
67
+
68
+ except urllib.error.HTTPError as e:
69
+ # Handle HTTP errors (e.g., 401 Unauthorized, 400 Bad Request)
70
+ error_info = e.read().decode('utf-8', errors='ignore')
71
+ print(f"HTTP Error {e.code}: {e.reason}")
72
+ print(f"Error Details: {error_info}")
73
+ return '', ''
74
+
75
+ except urllib.error.URLError as e:
76
+ # Handle network/connection errors
77
+ print(f"Failed to reach the server: {e.reason}")
78
+ return '', ''
79
+
80
+
81
+ if __name__ == '__main__':
82
+ ...